Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export default defineConfig({
{ text: "Matches", link: "/matches" },
{ text: "Map Veto Format", link: "/map-veto" },
{ text: "Scrim Finder", link: "/scrim-finder" },
{ text: "Player Cameras", link: "/player-cameras" },
],
},
{
Expand Down Expand Up @@ -131,6 +132,7 @@ export default defineConfig({
base: "/features",
items: [
{ text: "Teams, Lobbies & Chat", link: "/social" },
{ text: "Voice Chat", link: "/voice-chat" },
{ text: "Steam Presence", link: "/steam-presence" },
{ text: "Moderation & Sanctions", link: "/moderation" },
{ text: "News", link: "/news" },
Expand Down Expand Up @@ -352,6 +354,10 @@ export default defineConfig({
text: "Faceit Integration",
link: "/faceit-integration",
},
{
text: "Web Push Notifications",
link: "/web-push",
},
{
text: "HashiCorp Vault",
link: "/vault",
Expand Down
51 changes: 51 additions & 0 deletions advanced/web-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Web Push Notifications

Web Push lets 5stack notify players on their phone or desktop **when the app isn't open** — a match going live, an invite, a scrim request, a new message.

It is enabled out of the box and needs no configuration. Players turn it on per device under **Settings → Notification Preferences**, where they can also mute individual categories and set **quiet hours** — a window in which push stays silent while the notifications still land in the in-app alert bell. Application settings → **Integrations → Web Push** shows whether it's active and how many devices are subscribed.

## No service, no keys to buy

A common assumption is that push notifications need a paid provider like Firebase, OneSignal or Pusher. **They don't.**

Every browser vendor runs its own push service, free, with no account and no API key:

| Browser | Push service |
| ----------------------------- | ------------------------------- |
| Chrome, Edge, Brave | Google's push endpoints |
| Firefox | Mozilla autopush |
| Safari (macOS 16+, iOS 16.4+) | Apple Push Notification service |

When a player enables notifications, their browser hands 5stack a subscription URL pointing at its own vendor's service. 5stack sends notifications to that URL directly.

The one piece of configuration is a **VAPID keypair**, which identifies your panel to those services. It is self-signed and registered with nobody, so 5stack generates it for you on install.

::: tip Why people think it costs money
The old **GCM** protocol did require a Firebase project and a server key. It was replaced by the **VAPID** standard, which needs neither. If a guide tells you to paste a Firebase key, it's describing the deprecated flow.
:::

## Requirements and limitations

These are constraints of the Web Push standard and the browsers, not of 5stack.

**HTTPS is required.** Service workers only run on a secure origin. A panel served over plain HTTP cannot deliver push notifications at all.

**iOS requires the app be installed to the home screen.** On iPhone and iPad, Safari has no notification support in a normal tab. Players must open 5stack in Safari, tap Share → _Add to Home Screen_, and enable notifications from the installed app. This needs iOS 16.4 or newer. The settings page shows this hint automatically on iOS.

**The permission prompt is one-shot.** A browser only asks once. If a player dismisses or blocks it, 5stack cannot ask again — they have to re-enable notifications in their browser or OS settings.

**Delivery is best-effort.** There are no delivery or read receipts. Push services may delay, batch, or drop notifications for a device that has been offline for a long time — the spec makes no guarantees. The in-app alert bell is the reliable record; push is the nudge.

**Subscriptions expire on their own.** Clearing site data, uninstalling the PWA, or a long period of inactivity ends a subscription. 5stack deletes those rows automatically, so the subscriber count reflects reality.

**Payloads are small** — roughly 4KB, so bodies are trimmed to a short preview. Tapping through opens the relevant page in the app.

**Content passes through the vendor's infrastructure** encrypted, but avoid putting anything in a notification title or body you wouldn't want on a lock screen.

## Troubleshooting

**A player sees "Push notifications aren't supported in this browser".** They're on iOS in a Safari tab (see above), on an old browser, or the panel is being served over HTTP.

**The toggle does nothing and no prompt appears.** Notifications are blocked for the site at the browser or OS level. It has to be re-enabled there first; the page will say so when it detects this.

**Notifications stopped for everyone at once.** The signing keys were rotated — every device has to re-enable notifications. Only rotate if the private key has leaked.
3 changes: 2 additions & 1 deletion features/admin/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ Roles are assigned from the [player directory](/features/admin/roles-and-players
performance, backups, and the render queue.

The admin controls for [demo settings](/features/demos), [highlights](/features/highlights),
and [streaming](/features/live-streaming) are covered on those feature pages.
[streaming](/features/live-streaming), [player cameras](/features/player-cameras),
and [voice chat](/features/voice-chat) are covered on those feature pages.
7 changes: 7 additions & 0 deletions features/admin/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ link their own Steam match history from their personal settings.
## Chat

Set the chat **message TTL**, how long chat messages are retained (seconds).

## Web Push

Whether push notifications are active, how many devices are subscribed, and where
the signing keys came from, plus a **regenerate keys** action for the case where a
private key leaks (it unsubscribes every device). Nothing to sign up for and no
third-party provider, see [Web Push Notifications](/advanced/web-push).
14 changes: 11 additions & 3 deletions features/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Pages linked below go deeper on the bigger features.
match rules (knife, overtime, pauses, best-of, coaches, and more).
- **[Scrim Finder](/features/scrim-finder)**: advertise when your team plays,
set who you'll play, and negotiate scrims without a Discord thread.
- **[Player Cameras](/features/player-cameras)**: require a webcam from every
player, watch the feeds from the panel, auto-pause when one drops, and put the
spectated player's camera on the broadcast.
- **Custom Map Pools**: curated pools for every format (1v1, 2v2, 5v5),
including workshop maps.

Expand Down Expand Up @@ -65,8 +68,10 @@ Pages linked below go deeper on the bigger features.

## Community

- **[Teams, Lobbies & Chat](/features/social)**: teams, friends, parties, and
smart, context-aware chat that bridges the web app and in-server.
- **[Teams, Lobbies & Chat](/features/social)**: teams, friends, parties, direct
messages, and smart, context-aware chat that bridges the web app and in-server.
- **[Voice Chat](/features/voice-chat)**: party and team voice on 5Stack's own
relay, with device pickers, a mic check, and voice-activity transmission.
- **[Steam Presence](/features/steam-presence)**: see what friends are playing,
in 5Stack and outside it.
- **[Moderation & Sanctions](/features/moderation)**: bans, mutes, gags, and
Expand All @@ -93,6 +98,9 @@ Pages linked below go deeper on the bigger features.

- **Installable app (PWA)**: add 5Stack to your home screen or desktop for an
app-like experience, with offline-aware caching.
- **[Push notifications](/advanced/web-push)**: per-category, per-device alerts
that reach players when the app isn't open, with no third-party push service to
sign up for.
- **[17 languages](/features/languages)**: the interface *and* the in-game
plugin are fully localized, with automatic detection of your browser language.
- **Embeds & popouts**: drop a live, auto-cycling tournament bracket onto a
Expand Down Expand Up @@ -126,7 +134,7 @@ Pages linked below go deeper on the bigger features.

Several features are optional and can be switched on or off instance-wide from
**Settings → Application**: matchmaking, leagues, seasons, events, news, the
Scrim Finder, plugins, and linked accounts.
Scrim Finder, voice chat, plugins, and linked accounts.

::: tip Rendering features need a GPU
Highlights, in-browser demo playback, and live streaming are all rendered on a
Expand Down
10 changes: 10 additions & 0 deletions features/live-streaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ The Stream Deck is the broadcaster's control panel:
- **Spectator grid**: CT/T player slots fed by live game state; click a slot to
spectate that player.
- **Autodirector** toggle for automatic spectator camera work.
- **Player webcams inside the spectator slots**, when the match requires them, so
the box you read to pick a target is the box you click. See
[Player Cameras](/features/player-cameras).
- GPU availability and active stream count so you know your capacity.

## Scoreboard overlay
Expand All @@ -34,6 +37,13 @@ every map in the series. It has a compact mode for small windows.
Streams play over **WebRTC (WHEP)** for ultra-low latency, and you can **pop a
match out** into its own chromeless window to drag onto a second monitor.

## Face cams

If a match [requires player cameras](/features/player-cameras), the camera of the
player currently being spectated is composited onto the stream through the
existing overlay, no second capture, no extra encoder, and nothing for the
broadcaster to wire up.

## Picture-in-picture

Start watching, then keep browsing. A live stream **detaches into a floating,
Expand Down
8 changes: 8 additions & 0 deletions features/matches.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ Tune the match to the occasion: **knife round, overtime** (rounds and bomb timer
ready-up, default player models, and more. Game-mode presets apply sensible
defaults in one click.

## Player cameras

A match can **require a webcam** from every player: they connect one from their
PC or by scanning a QR code with a phone, the server details stay hidden until
they do, and the match pauses automatically if a feed drops. Officials watch the
feeds from the panel, and the spectated player's camera can appear on the
broadcast. See [Player Cameras](/features/player-cameras).

## Watching live

While a match is live you can follow the score and action in real time, jump in
Expand Down
130 changes: 130 additions & 0 deletions features/player-cameras.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Player Cameras

Matches can require every player to publish a **webcam** for the duration of the
game. Officials watch the feeds from the panel, and the camera of whoever is
being spectated can appear on the [broadcast](/features/live-streaming) — the
face-cam grid you see on a LAN stream, without the LAN.

## Turning it on

Cameras are a **per-match option**, set when the match is created or edited:

- **Require Webcam**: players must connect a camera before the server details are
shown, and the match pauses automatically if a feed drops.
- **Teammates Can Watch**: let players see the cameras of their _own_ team. The
opposing team is never included.

Instance-wide defaults for both live under
**Settings → Application → Cameras & Microphones → Match Defaults**. They only
decide what a newly created match starts with; an organizer can still change
either one per match, and existing matches are unaffected.

## Connecting a camera

When a match requires a webcam, a panel appears on the match page and on the
check-in button in a [draft lobby](/features/draft-lobbies). A player has two
ways in:

- **Use this computer**: opens the camera page in a popup on the machine they're
already on.
- **Scan the QR code**: publishes from a phone instead, which is how most players
will do it — the phone becomes the camera and the PC stays untouched.

The camera page previews before it publishes. The feed starts local-only, so a
player can pick a device, frame themselves, and only then connect — one
permission prompt, no dead air:

- **Pick a camera** when the device has more than one; phones and tablets also
get a **flip** button for front/back.
- **Reframe** the shot: scroll or pinch to zoom, drag to re-centre. The crop is
applied to the **published** feed, not just the local preview, and is
remembered per camera.
- **Hide the preview** mid-match to give the resources back. The camera stays on
and stays published.
- Permission denied, no camera, or a camera already in use each explain
themselves in place, with a retry.

The one rule that matters: **keep the page open for the rest of the match.**
Closing it stops the feed, which is the same as unplugging the camera.

The setup panel can be dismissed to get at the rest of the match page, but the
requirement doesn't go with it: a banner stays pinned to the top of the page, and
clicking it brings the panel back. Check-in stays blocked until a camera is live.

## Who can watch

Watching is scoped on the server, not hidden in the browser — a feed a viewer
isn't entitled to is never sent to them at all.

| Viewer | Sees |
| ----------------------------------------------- | ----------------------------------------------------------- |
| Organizer or admin **not** playing in the match | Both lineups |
| A player in the match | Their own lineup, and only if **Teammates Can Watch** is on |
| The opposing team | Nothing, ever |

A match organizer who is also playing is a competitor first: a live view of the
other side is exactly the advantage cameras exist to prevent. Site
administrators keep full access so the feature can be exercised end to end.

## Watching from the panel

- **Watch Cameras** on the match page opens the grid, and doubles as the summary
— it carries a live count like _7 of 10 live_.
- Each tile shows the player the way the rest of the app does, with a
**connected / stalled / not connected** state. A quiet grid means everything is
fine; only a problem tile draws the eye.
- **Listen to a player** from any tile without starting a call.
- **Video call** a player from their tile. Their camera page shows you in a small
picture-in-picture, so you can talk to them face to face — an actual check that
a person is there, which no automated test of a video feed can give you.
- **Camera dots** on the lineup rows give organizers per-player state at a glance
without opening the grid.
- On the [Stream Deck](/features/live-streaming#stream-deck), player cameras
render **inside the observer-target slots**, so the box you read to pick a
spectate target is the box you click. Feeds start muted.

## Enforcement

5Stack keeps checking, rather than checking once at the door:

- Feeds are polled continuously and classified **live**, **stalled**, or
**down** from whether video is actually arriving.
- A drop gets a **30-second grace period**, long enough to ride out a WiFi blip
or a reconnect.
- Past that, the game server is told to **pause the match** with a named reason.
The pause blocks `.resume` until the camera is back, and the scoreboard shows
who the match is waiting on. Players can ask the server for their own status
with `.cam`.
- Resume is **announced, never silent**, and an admin can override.
- If the relay itself is unreachable, nothing changes — the check **fails open**,
so an infrastructure problem never pauses a match.

## On the broadcast

While a player is being spectated, their camera can be composited onto the live
stream through the existing overlay — no extra capture, no second encoder, and
nothing for a broadcaster to set up.

## Requirements & limits

**HTTPS is required.** Browsers only grant camera access on a secure origin. A
panel served over plain HTTP cannot publish cameras at all.

**Feeds are relayed, not recorded.** 5Stack passes camera video through its own
WebRTC relay and stores none of it. A camera that appears on a broadcast is, of
course, part of whatever that broadcast records.

**Cameras are deliberately small.** A published feed is capped at 360p and 24fps
(portrait on a phone), roughly 350 kbps, so publishing from mobile data is
realistic and a full ten-player lineup costs your server a few Mbps rather than
ten HD streams.

**A camera proves a feed is flowing, not that a person is being watched.** A
virtual camera looping a video passes every automated check there is. That is
what the video-call button is for — treat cameras as a deterrent and a broadcast
feature, and use a call when you need certainty.

::: tip Cameras use the same relay as voice and live streaming
No third-party video service is involved, and there is no per-player cost. See
[Voice Chat](/features/voice-chat).
:::
30 changes: 30 additions & 0 deletions features/social.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ who's currently in the room.
5Stack chat bridges the **web app and in-server**, so conversations stay
connected whether players are in the browser or in the game.

Every conversation you're in, match, team, lobby, tournament, or organizers,
becomes a **tab** in the chat rail, with an unread badge that counts from the
moment you sign in rather than from the moment you open the panel.

## Direct messages

Message a friend one-to-one from their **player page** or straight from your
friends list. A direct message opens as its own chat tab, showing the person's
avatar instead of a channel icon.

Direct messages are limited to **accepted friends** in both directions, so
nobody can be cold-messaged, and an incoming message opens its tab without
yanking you out of the conversation you're reading. They're also kept far longer
than room chatter, 30 days rather than the shared chat TTL, because a
conversation you can't scroll back through isn't much of a conversation.

## Voice chat

Talk to your party in a lobby, or to your team on the match page, with
[voice chat](/features/voice-chat) built into the panel: device pickers, a mic
check you can run before anyone hears you, voice-activity or open-mic
transmission, and noise suppression.

## Connect Discord

Link your Discord account to 5Stack to unlock the bot, create matches, manage
Expand All @@ -50,3 +73,10 @@ lobbies, get match updates, and have your roles synced, without leaving Discord.
Chat and match sounds are context-aware: they automatically quiet down when
you're **in a game** or the tab is **hidden**, so you're never spammed mid-round.
You can pick your own notification sounds and set the volume.

**Settings → Notification Preferences** decides what reaches you and where.
Categories, matches, chat, invites, tournaments, scrims, leagues, teams, events,
seasons, account, and news, can be muted individually on the in-app alert bell,
and turned on per device as [web push notifications](/advanced/web-push) that
arrive even when 5Stack isn't open. **Quiet hours** keep push silent during a
window you set; those notifications still land in the alert bell.
Loading