From 8f151e38b40e79b0243d16f8c0e5cf792203875d Mon Sep 17 00:00:00 2001 From: ddidderr Date: Tue, 21 Jul 2026 20:00:07 +0200 Subject: [PATCH] docs(launcher): add Call to Play specification and design reference Extend the launcher design specification and prototype reference with the "Call to Play" multiplayer coordination feature and clean up top-bar chrome. Key additions and changes: - Spec & Roadmap: Document Call to Play mechanics in SPEC.md, including Play Now / Scheduled call flavors, 15-minute check-in windows, top-bar button with active count badge, quick-bar ticker stack above grid, overlay modal, and per-call group chat. Update design/README.md. - Components & Logic: Add calltoplay.jsx and ctp-chat.jsx components for call creation, status progression, and chat. Extend data.jsx with a mock peer roster (PEERS) and helper functions for peer install count tracking. - Top-bar Cleanup: Move game-folder configuration from top bar into Settings -> Library, freeing top-bar space for the Call to Play action button. - Styling & Layout: Add CTP quick-bar, ticker, badge, card, and chat styles to styles.css, and integrate CTP components into launcher.jsx, components.jsx, and SoftLAN Launcher.html. Test Plan: - `git diff --cached --check` -- passed (no trailing whitespace or conflict markers) - `cargo check --workspace` -- passed cleanly - Manual review of staged diff across 9 design/launcher files -- confirmed clean staging --- design/README.md | 13 +- design/launcher/SPEC.md | 167 +++- .../design_reference/SoftLAN Launcher.html | 72 +- .../launcher/design_reference/calltoplay.jsx | 814 ++++++++++++++++++ .../launcher/design_reference/components.jsx | 11 + design/launcher/design_reference/ctp-chat.jsx | 86 ++ design/launcher/design_reference/data.jsx | 30 + design/launcher/design_reference/launcher.jsx | 19 + design/launcher/design_reference/styles.css | 629 +++++++++++++- 9 files changed, 1831 insertions(+), 10 deletions(-) create mode 100644 design/launcher/design_reference/calltoplay.jsx create mode 100644 design/launcher/design_reference/ctp-chat.jsx diff --git a/design/README.md b/design/README.md index a8452f4..aa955a5 100644 --- a/design/README.md +++ b/design/README.md @@ -23,9 +23,11 @@ design_handoff_softlan_launcher/ │ └── design_reference/ the working prototype the spec describes │ ├── SoftLAN Launcher.html open this to see all screens/variants │ ├── styles.css -│ ├── data.jsx mock catalog + format helpers +│ ├── data.jsx mock catalog + LAN peer roster + format helpers │ ├── components.jsx Icon set, cards, modals, Settings dialog -│ └── launcher.jsx composes chrome + grid + modals +│ ├── ctp-chat.jsx Call-to-Play chat panel + shared helpers +│ ├── calltoplay.jsx Call-to-Play: quick bars, overlay, create form +│ └── launcher.jsx composes chrome + grid + modals + Call to Play │ └── logo/ ← THE BRAND MARK ├── INTEGRATION.md how to ship the logo (component + assets + lockup) @@ -75,8 +77,11 @@ placeholder for it. ## Status - **Launcher:** high-fidelity, decisions locked. Variant **A** is the chosen - chrome. Open questions (empty/error states, logs viewer, keyboard grid nav, - German strings, "server running" state) are listed at the end of `SPEC.md`. + chrome. Includes **Call to Play** (rally the LAN around a game + time — live + or scheduled, with RSVP, check-in window, and per-call chat). Open questions + (empty/error states, logs viewer, keyboard grid nav, German strings, "server + running" state, real-time transport for Call to Play) are listed at the end + of `SPEC.md`. - **Logo:** final. Live component + static assets + horizontal lockup (dark and light) all included. diff --git a/design/launcher/SPEC.md b/design/launcher/SPEC.md index 90d6dbf..9e02f99 100644 --- a/design/launcher/SPEC.md +++ b/design/launcher/SPEC.md @@ -32,6 +32,20 @@ The HTML mock includes two chrome variants — **A (single-row)** and **B (two-r --- +## Changes since v4 + +- **Call to Play added.** A whole new coordination layer on top of the library: + rally the LAN around a game and a time. Two flavors — **Play now** (give + people N minutes to ready up) and **Scheduled** ("Among Us at 20:00", collect + "I'm in" RSVPs, then a **check-in window** opens 15 min before start). Every + call carries a small group **chat**. Surfaced in three places: a **Call to + Play button** in the top bar (with an active-call badge), a persistent stack + of **quick bars** above the grid, and a full **overlay** with per-call cards + and a create form. Full spec in the new **"Call to Play"** section below. + New source files: `calltoplay.jsx`, `ctp-chat.jsx`. New data: a mock LAN + **peer roster** (`PEERS`) in `data.jsx`. New icons: `flag`, `chat`, `send`, + `clock`, `caretUp`, `caretDown`. + ## Changes since v3 - **Game-folder button removed from the top bar.** Setting the games directory is a one-time action — it doesn't deserve permanent real estate in the chrome. The button is gone from both top-bar variants, freeing the right zone for the kebab menu alone (variant A) / the storage meter + kebab pair (variant B). @@ -84,6 +98,7 @@ The default screen. A grid of game cards over a dark, gradient-tinted background - **Right zone (col 3, flex space-between with two sub-groups):** - **Sort menu** (pinned left, hugging search) — 36 px button, same surface style as search. Label `Sort: ` plus 13 px sort-bars icon and 11 px chevron. Click reveals dropdown menu below. Options: `Name (A–Z)`, `Size (largest)`, `Recently Played`, `Status`. This is the only thing on the *left* side of the right zone — it's part of the search cluster, so it hugs the search. - **Kebab menu** (`⋮`, pinned far-right) — 36×36 button with same surface as search. Menu items: `Settings` (opens Settings dialog), `Refresh library`, separator, `Unpack logs`, `About SoftLAN`. This is the only "app-level" control left in the top bar; the game-folder picker has moved into Settings. + - **Call to Play button** (`.ctp-btn`, sits just left of the kebab in the far-right sub-group) — 36 px pill, flag icon + `Call to Play` label. Carries an accent-filled **badge** with the count of active (non-started) calls. Opens the Call to Play overlay. See the **"Call to Play"** section for the full feature. In variant B it lives in row 1's right group, between the storage meter and the kebab. **Narrow-window fallback** (container width < 1100 px): the grid is replaced by a single `display: flex; flex-wrap: nowrap; gap: 16px` row. All items align left-to-right in source order (brand → filter → search → sort → kebab). The search field becomes `flex: 1 1 auto` so it absorbs remaining slack. The geometric centering is abandoned at narrow widths because there isn't enough horizontal slack for it to read cleanly. Implement via container query (`@container launcher (max-width: 1100px)`) on the launcher root; a viewport media query is an acceptable fallback if you're not using container queries yet. @@ -416,6 +431,144 @@ Dot uses the live accent so it visually ties to the progress fill. --- +## Call to Play + +A coordination layer that sits on top of the library: **rally the people on the +LAN around a specific game at a specific time.** It answers the actual social +question at a LAN party ("what are we all playing, and when?") that a plain +library grid can't. + +Source: `calltoplay.jsx` (the feature) + `ctp-chat.jsx` (per-call chat + shared +`ctpAvatarColor` / `ctpFmtClock` helpers). Styles are the `ctp-*` classes in +`styles.css`. Backed by the mock LAN **peer roster** `PEERS` in `data.jsx`. + +### Two flavors of call + +| | **Play now** | **Scheduled** | +|---|---|---| +| Set up with | game + max players + **duration** (5/10/15/30/60 min) | game + max players + **clock time** (24h, + which day) | +| Others respond | `Ready now` or `+N minutes` | `I'm in` (RSVP), then check in later | +| Resolves | when the roster fills **or** the timer runs out | at the scheduled time, after a check-in window | +| Who starts it | the **caller** decides the actual launch | the **caller**, once people have checked in | + +**Check-in window.** `CHECKIN_LEAD_MS = 15 min`. A scheduled call sits in the +`scheduled` phase collecting RSVPs until 15 minutes before its start time, then +flips into the `checkin` phase: it lights up everywhere and everyone who said +"I'm in" is nudged to answer with the same `Ready now` / `+N minutes` states as +a play-now call. A play-now call is effectively "always in its check-in window." + +**Every call carries a small group chat** (see "Per-call chat" below). + +### Three surfaces + +1. **Top-bar button** (`CallToPlayButton` / `.ctp-btn`) — flag icon + label + + an accent badge counting active (non-`started`) calls. Opens the overlay. +2. **Quick bars** (`CallToPlayTicker` / `.ctp-ticker-stack`) — a persistent + stack rendered at the top of the grid area, **one row per active call**. + Sorted **ready → starting-soon → the rest**, ties broken by whichever + resolves/starts soonest (`TICKER_RANK` = ready 0, soon 1, call/scheduled 2; + then by `deadline`). Clicking a row opens the overlay focused on that call. +3. **Overlay** (`CallToPlayOverlay`) — a modal (same scrim/panel treatment as + the other dialogs) with a header, a **Call a new match** button, the create + form, and a list of **nomination cards** (started calls sink to the bottom). + +### Status model + +Two derived values drive everything (`calltoplay.jsx`): + +- `phaseOf(call)` → `'now'` (no `scheduledFor`) · `'scheduled'` (>15 min out) · + `'checkin'` (within the 15-min lead). +- `statusOf(call)` (quick-bar/label status) → `'started'` · `'ready'` + (`readyCount >= maxPlayers`, or state `done`) · `'soon'` (`deadline - now ≤ + 15 min`) · `'scheduled'` (has a clock time) · `'call'` (a plain play-now call). + +Quick-bar labels + LED colors: **SCHEDULED**, **CALL TO PLAY**, **STARTING +SOON**, **READY** (`TICKER_LABEL`), each with its own dot color via +`.ctp-ticker-dot[data-status]`. + +**Per-participant ready state:** `ready` (explicitly readied, or their `readyAt` +countdown has elapsed) · `in` (RSVP'd to a scheduled call but not checked in +yet) · `pending` (checked in with a `+N minutes` buffer, counting down). Shown +as compact **ready-bubbles** in the quick bars (`MiniBubbles`: initials + +green ring/check when ready, `+Nm` tag when pending, dimmed when just "in") and +as larger `AvatarChip`s in the nomination card roster. + +### Nomination card (`NominationCard`) + +Top to bottom: + +1. **Header** — square game cover + title + a sub-line: `Called by · N/M peers have it installed` (or `Scheduled by · starts at HH:MM · …`), and a **timer** on the right: a live `M:SS` countdown for play-now/check-in, the **clock time + "in N min"** for a scheduled call, `Ready`, or `Launching…`. Countdown urgency (`data-urgency` high/mid/low) tints it as time runs low. +2. **Check-in note** — only in the `checkin` phase: a clock icon + "Starting soon — check-in is open" (or a personalized nudge if you RSVP'd). +3. **Progress bar** — time remaining as a fill (accent, → green when done); hidden while a call is still in the far-out `scheduled` phase. +4. **Roster** — `readyCount/maxPlayers ready` (scheduled shows `N in · up to M players`; check-in adds `· K not checked in yet`), then avatar chips for each participant plus empty slots up to `maxPlayers`. +5. **Actions** — context-dependent on your role (**creator** / **participant** / **outsider**) and phase: `Ready now` + `+5/10/15/30m` buffer buttons, `I'm in` (RSVP), `Start now` / `Add 5 more minutes` (creator once resolved), `Leave` / `Can't make it`, or a status note. +6. **Chat** — the collapsible per-call chat panel. +7. **Cancel** — creators get a `Cancel this call` link with an inline confirm. + +### Create form (`CreateNominationForm`) + +Game search (typeahead over the catalog) → on pick, max-players defaults to the +game's parsed player cap (`parseMaxPlayers`). **When** toggles `Now` vs +`Schedule`. `Now` reveals the **Give people** duration chips. `Schedule` reveals +a **24-hour time picker** (hour/minute steppers **and** a "Type a time" free-text +field accepting `20:00` / `2000` / `9:30`) plus **day chips** (Today + next two +days). The confirm button reads `Call it — ` or `Schedule it — · +