Funday play screen — visual cheat sheet

Plain-language map of what you see on /play/[gameId] and how the pieces talk to each other.


One screen, four layers (bottom → top)

🧱 Game (iframe or native Svelte game)
→ lives in the big rectangle; this is the actual title you launched.

📊 HUD (optional small overlay)
→ tiny status chips when the game reports something (mode, latency, etc.).

🗂️ Right drawer / Bottom sheet (desktop right panel, mobile bottom overlay)
→ multiplayer lobby list, match card, start/leave, and chat.
→ Nakama socket + match logic mostly live behind this panel.

🚢 Bottom dock (full-width bar)
→ Lobby button (opens drawer), game-specific actions (restart, howto, …), leaderboard peek, feedback, fullscreen, exit.

🧭 Top navbar (site chrome)
→ not part of the game; play area starts below it (--nav-h).


Visual layout (desktop, drawer open)

---
config:
  theme: forest
  look: handDrawn
---
flowchart TB
  %% 🎨 Severity hints on concepts
  classDef regular fill:#bbf7d0,stroke:#166534,color:#14532d
  classDef watch fill:#fde68a,stroke:#b45309,color:#78350f
  classDef hot fill:#fecaca,stroke:#b91c1c,color:#7f1d1d

  NAV["🧭 Navbar<br/>site chrome"]:::regular
  subgraph MAIN["🖼️ Play column (insets when drawer open)"]
    VP["🧱 GameViewport<br/>iframe / native"]:::regular
    HUD["📊 GameHUD<br/>optional chips"]:::regular
  end
  DR["🗂️ GameDrawer<br/>lobby · match · chat"]:::watch
  DK["🚢 GameDock<br/>icons + platform"]:::regular

  NAV --> MAIN
  MAIN --> DK
  DR -. overlaps right .- MAIN

  TOK["📐 Tokens<br/>--nav-h --dock-h --drawer-w"]:::hot
  TOK -.-> MAIN
  TOK -.-> DK
  TOK -.-> DR

On small phones the drawer converts into a bottom sheet overlay; it does not squeeze the main column.


CSS variables (geometry only)

These are ruler marks the layout uses; you do not need to memorize them.

📏 --nav-h — space reserved under the navbar (default 64px).
📏 --dock-h — height of the bottom dock; GameDock measures itself and writes this so the game is not hidden behind the bar.
📏 --drawer-w — width of the right drawer (default 24rem). When the drawer is open on tablet/desktop, the main column and the dock shrink from the right by this amount so nothing sits under the drawer.


Mental model: two “remote controls”

🎮 Game → Host (SvelteKit)
postMessage bridge: the iframe sends things like funday:dock:set to add buttons to the dock.

🏠 Host → Game
the shell can send session, match state, fullscreen hints, etc.

So: dock buttons are often “declared” by the game, then rendered by GameDock.svelte.

---
config:
  theme: forest
  look: handDrawn
---
sequenceDiagram
  autonumber
  participant G as 🎮 Game embed
  participant B as 🔌 Bridge
  participant C as 📦 gameContext
  participant D as 🚢 GameDock
  participant W as 🗂️ GameDrawer
  participant N as 🌐 Nakama

  G->>B: funday:dock:set {actions}
  B->>C: merge actions
  C->>D: render icon buttons + title tooltip
  D->>W: openDrawer('lobby') on Lobby click
  W->>N: list / join / match data
  N-->>W: presences, chat
  W->>G: funday:match-state (via postToGame)

Lobby vs match vs chat (inside the drawer)

🟦 Lobby phase — you see open matches / create / join (or dedicated-server flows).
Chat channel name is scoped to the game lobby.

🟩 In a match, not playing yet — match card, host can start when rules allow.
Chat can stay “lobby” until someone toggles or the game goes playing.

🟥 Match playing — chat can auto-switch to “match room” so talk is per-session; header toggles let you force lobby vs match context.

---
config:
  theme: forest
  look: handDrawn
---
stateDiagram-v2
  [*] --> Closed: load /play

  Closed --> OpenLobby: 🖱️ tap Lobby on dock<br/>or auto-open MP
  OpenLobby --> Closed: ✖ close drawer<br/>match stays connected

  OpenLobby --> OpenLobby: drawer shows<br/>lobby list + chat

  note right of OpenLobby
    Lobby BUTTON stays on bottom dock (left area).
    CONTENT of lobby lives in the right drawer.
    Visual link: active / pressed state on Lobby
    while open (recommended polish).
  end note

Z-order (who paints on top)

Rough stacking: game at the back → HUD → dock (mid) → drawer higher → modals/toasts highest.
If something looks “under” something else, it is almost always a z-index or pointer-events issue, not game logic.


Single-player vs multiplayer

🧍 max players ≤ 1 → Lobby action is removed from the dock (no matchmaking UI needed).
👥 max players > 1 → Lobby is the primary dock button; drawer may auto-open on first load (some games are excluded, e.g. scribblaz, splix).


Quick debugging checklist

🔌 Socket not ready → drawer actions that need Nakama may stall; check auth / socketStore.ready.
📬 ?join= / ?autostart= on URL → play page opens drawer and consumes params (invite / solo / practice flows).
📐 Game canvas clipped at bottom → --dock-h should be non-zero after dock mounts; if zero, the dock may not be measuring.
↔️ Drawer open but dock looks wrong on desktop → dock and play-root should both inset with --drawer-w (aligned layout).


Where to read code (when you are ready)

frontend/src/routes/play/[id]/+page.svelte — stacks viewport, HUD, dock, drawer.
frontend/src/lib/components/games/GameDock.svelte — bottom bar + --dock-h.
frontend/src/lib/components/games/GameDrawer.svelte — desktop right panel / mobile bottom sheet + match + chat.
frontend/src/lib/components/games/GameViewport.svelte — iframe/native + bridge.
frontend/src/lib/stores/gameDrawer.svelte.ts — open/close/mode/pending join.
frontend/src/lib/stores/gameContext + lobbyState.svelte.ts — shared shell state.


One-sentence summary

The play route is a picture frame: game in the middle, shell chrome on bottom and right (desktop), with measured spacers (--dock-h, --drawer-w) so the game always stays visible and aligned.


Severity color code (issues & ideas)

🟢 Regular — polish, consistency, docs; safe to schedule anytime.
🟡 Pressing — layout confusion, discoverability, two sources of truth; fix next sprint.
🔴 Hot — breaks trust or gameplay (chat wrong channel, dock under drawer, clipped canvas); fix before shipping features on top.

---
config:
  theme: forest
  look: handDrawn
---
pie showData
  title 🌡️ Where UX pain clusters (conceptual)
  "🟢 Clear icon + tooltip pattern" : 35
  "🟡 Drawer / dock / fullscreen edge cases" : 40
  "🔴 Chat SSOT across game + shell" : 25

Shared dock UI (many games expect the same icons)

🌍 Icons are international; always pair icon with title / tooltip (aria-label + visible data-tip on hover).
🏠 Lobby — opens the drawer (list + chat). The button stays on the bottom dock (left cluster); the panel slides in. Recommended polish: Lobby looks “pressed” or primary while the drawer is open.
🔁 Restart / Reset — round or full reset; games declare via funday:dock:set.
ℹ️ Howto / Help — rules overlay.
🔊 Volume — mute / unmute.
⚙️ Settings — in-game options.
⛶ Fullscreen — browser fullscreen + optional game:fullscreen to the embed.
✖ Exit — leave play route.

---
config:
  theme: forest
  look: handDrawn
---
mindmap
  root((🚢 Universal dock))
    🏠 Lobby
      opens right drawer
      icon Clipboard
    🔁 Restart / Reset
      confirm destructive
    ℹ️ Howto / Help
      modal or overlay
    🌐 Online / Reconnect
      network sanity
    🔊 Volume
      mute toggle
    ⚙️ Settings
      per-game prefs
    🏆 Leaderboard
      platform mini LB
    💬 Feedback
      bugs / praise
    ⛶ Fullscreen
      immersive shell
    ✖ Exit
      history.back

“Lobby location” — what actually moves

The lobby UI lives in the drawer, which is anchored to the right edge on desktop and bottom edge on mobile. The Lobby control on the dock does not need to physically move to follow it: users learn “tap bottom-left-of-bar → panel appears.” Optional upgrade (🟡): add a slim vertical “Lobby” tab on the right edge (desktop) when the drawer is closed, aligned with where the drawer opens (stronger spatial affordance).


Player journey (find multiplayer)

---
config:
  theme: forest
  look: handDrawn
---
journey
  title 🎯 Get into a match
  section Land
    Open game from catalog: 5: Player
  section Dock
    See 🏠 Lobby icon + tooltip: 4: Player
    Tap Lobby: 5: Player
  section Drawer
    New / Join / Refresh: 4: Player
    Read lobby chat: 3: Player
  section Match
    Host starts: 5: Player
    Match chat auto: 4: Player

Immersive / Scribblaz-style fullscreen (vision)

🎯 Goal: maximum canvas; chrome appears only on intent.
↖️ Top-left: menu icon restores top navbar.
↘️ Bottom-right: avatar strip or compact chat handle; tap expands transient bubbles.
📌 Pinned drawer: optional mode — drawer stays open as a semi-transparent rail; unpinned = overhang overlay.
💭 Chat bubbles that fade: good for guess-heavy games; still keep one Nakama SSOT (match vs lobby channel) in the shell — the game only renders decorative bubbles, not a second chat backend.

---
config:
  theme: forest
  look: handDrawn
---
flowchart LR
  classDef regular fill:#bbf7d0,stroke:#166534
  classDef watch fill:#fde68a,stroke:#b45309
  classDef hot fill:#fecaca,stroke:#b91c1c

  FS["⛶ Fullscreen / minimal chrome"]:::watch

  FS --> TL["↖️ Top-left<br/>☰ reopen top bar<br/>icon only"]:::regular
  FS --> BR["↘️ Bottom-right<br/>👤 / 💬 strip<br/>peek chat"]:::regular
  FS --> PIN["📌 Pin drawer<br/>opaque vs glass"]:::hot
  FS --> CHAT["💭 Bubbles fade<br/>Scribblaz guesses"]:::hot

  CHAT -. SSOT .- N["🌐 Nakama channels<br/>lobby vs match"]:::regular

Ask Docs

AI assistant to help answer questions about the documentation. Answers are read-only and cite docs/source.

Hi! How can I help you with the documentation today? Answers are read-only and cite docs/source.

Ctrl+Enter to send