Live Quiz Platform
Build Plan — Combined
| Status | Live checklist |
| Generated | 2026-06-05 |
| Source of truth | .claude/context/knowledgebase/build-plan/ (5 files: project + per-app) |
Implementation work organised across one file per app plus a cross-cutting project file. Each app's content is collapsible below — project starts expanded; per-app sections start collapsed. Within each app, sections are grouped by phase (MVP → Alpha → Beta → Production → Stretch) and ordered by build dependency.
Definition of Done for every item: TDD followed (failing test first, then implementation, then refactor); end-to-end automated test exists for any user-facing feature the item touches; lint and format pass; coding standards followed.
Progress
Project (cross-cutting)15 / 217
Foundation MVP project4 / 6
- Initialize repo with four Unity projects (
Quiz.Host,Quiz.Client,Quiz.Remote,Quiz.Preview) plus theQuiz.Designer/Tauri 2 + Angular 21 workspace plus shared local UPM packages (com.quiz.corepure C# /.NET Standard 2.1,com.quiz.runtimeUnity-aware,com.quiz.shared-assets) plus theschemas/JSON Schema source-of-truth tree. On-disk layout in Repository Layout. - Seed each Unity project from the shared Wildfire game template (
com.wildfiregames.coreUPM +_Game/scaffold with Setup/MainMenu/Play scenes, persistent systems, save system, audio). - Coplay Unity MCP package pinned in every project's
Packages/manifest.json; root.mcp.jsonregisters theUnityMCPserver. Routing protocol in AI Tooling — Unity MCP. - Shared C# class library consumed by all four Unity projects via UPM — local
file:packages wired into every project'sPackages/manifest.json. Schema content tracked under Shared schema. - DOTween installed via UPM in every Unity project (Host, Client, Remote, Quiz.Preview) and verified with a smoke-test tween
- Pre-commit hooks for C# format and analyzer
Azure DevOps CI / CD pipelines MVP project0 / 24
Per CI / CD. Pipelines are YAML at .azure-pipelines/, owned in-repo and reviewed in PR. Trunk-based branching; pr-validation.yml is a required check on main.
Agent + service connections
- Self-hosted Mac mini agent provisioned: latest macOS, current Xcode + iOS / macOS SDKs, Unity Editor + license, Rust toolchain + Tauri prerequisites, signing certificates and provisioning profiles in macOS Keychain. Registered in ADO under agent pool
MacMini. - Microsoft-hosted
Azure Pipelinesagent pool authorised for the project (default for any pipeline not pinned toMacMini). - Unity service connection holding the activation file; activation file cached on the Mac mini agent.
- Apple Developer account credentials + App Store Connect API keys stored as ADO secret variables for
release.yml. - Azure Repos remote configured; repository's default branch set to
main; branch policies set: 1 reviewer minimum,pr-validation.ymlrequired, no direct pushes tomain.
Pipelines
.azure-pipelines/pr-validation.yml— runs on every pull request. Triggers per-area pipelines on the agent pool that can build them; aggregates pass/fail..azure-pipelines/quiz-core.yml—dotnet testforpackages/com.quiz.core/Tests/. Microsoft-hosted; no Unity license..azure-pipelines/quiz-runtime.yml— Unity edit-mode + play-mode tests underpackages/com.quiz.runtime/Tests/. Mac mini..azure-pipelines/quiz-host.yml— Unity Player builds for Windows (Microsoft-hosted) + macOS / iOS (Mac mini); play-mode tests..azure-pipelines/quiz-client.yml— Unity Player builds for the configured Client platforms; play-mode tests..azure-pipelines/quiz-remote.yml— Unity Player builds for the configured Remote platforms; play-mode tests..azure-pipelines/quiz-preview-webgl.yml— Unity WebGL Player build ofQuiz.Preview/on the Mac mini; output published as a pipeline artefact forquiz-designer.ymlto consume..azure-pipelines/quiz-schemas.yml— schema codegen (NJsonSchema → C# intocom.quiz.core/Runtime/Generated/; quicktype + ajv → TypeScript intoQuiz.Designer/src/app/generated/); publishes both drops as pipeline artefacts..azure-pipelines/quiz-designer.yml— consumes the TS schema artefact and the Quiz.Preview WebGL artefact; on Microsoft-hosted Windows runsnpm ci+ng build+ng test(Jest) + Playwright screenshot pass againstng serve+tauri buildto produce the signed Windows installer; on the Mac mini runs the samenpm ci+ng build+tauri buildto produce the signed + notarised macOS DMG..azure-pipelines/release.yml— manual or git-tag triggered. Signs, packages, and publishes installers to the configured store / distribution channels. Dry-run nightly onmain(no publish).
Caching + reporting
- NuGet package cache keyed by
**/packages.lock.jsonenabled across pipelines. - Unity
Library/cached per-project per-agent so re-imports skip on incremental builds. - Test results published as JUnit XML so the ADO test report aggregates across pipelines.
- Code coverage published as Cobertura XML; coverage ratchet enforced (no decrease).
End-to-end pipeline tests
- PR-validation green path: open a PR with a one-line readme change, confirm
pr-validation.ymlruns and passes on every relevant pipeline. - PR-validation red path: open a PR with a deliberately failing test, confirm
pr-validation.ymlfails and blocks merge per the branch policy. - Mac mini cold start: clear the
MacMiniagent's caches, confirm a full pipeline run completes within a target wall-clock budget (TBD at first measure). - Quiz.Preview → Quiz.Designer artefact handoff:
quiz-preview-webgl.ymlpublishes the WebGL bundle andquiz-designer.ymlconsumes it; round-trip works onmain. release.ymldry run: produces signed installers for every configured channel without publishing.
Azure DevOps repos + wiki setup MVP project2 / 2
ADO hosts source control + the wiki mirror + CI pipelines. No Boards / work-item usage — this build plan is the task list.
- ADO project provisioned (or existing project repurposed) with Repos, Pipelines, and Wiki enabled.
- Wiki provisioned and pointed at the auto-generated knowledgebase mirror produced by the
docsskill.
Object-type plugin contract MVP projectdesignerhostclient0 / 9
IObjectTypeinterface incom.quiz.core(type id, schema version, schema accessor) — see Object-Type Architecture- Designer editor-surface contract (Angular standalone component + view-model service in
Quiz.Designer/src/app/object-types/;DesignerEditor<TData>descriptor declares palette icon + group + the inputs the properties inspector binds to) - Host runtime-surface contract (UGUI prefab + behaviour binding)
- Client runtime-surface contract (UGUI prefab + behaviour binding)
- Optional protocol-extension contract for object-type-specific messages
- Per-element statefulness declaration on
IObjectType— types that own live-session state (timer countdown, accumulated answers, reveal index) flag themselves stateful and expose a serialiser the Host's crash-recovery snapshot captures. Stateless types (static text, image) skip the snapshot path. See Object-Type Contract — Statefulness. - Built-in registry implementation in each app — types register themselves on app startup
- First built-in object type —
core.text— implementing every contract end-to-end as the reference example - End-to-end test: a quiz containing only a
core.textelement on each canvas renders correctly across Designer preview, Host, and Client
Schemas + codegen MVP projectdesigner1 / 6
Per Repository Layout — Cross-language contract. The schemas/ tree is the single source of truth for every data shape that crosses the Designer ↔ Unity boundary; codegen produces C# types into com.quiz.core and TypeScript types + ajv validators into the Angular workspace.
- Establish
schemas/directory layout:package-format/,live-play/,transfer/,object-types/,fixtures/; commit existing manifest / slide / canvas / element / envelope schemas as JSON Schema draft 2020-12. schemas/codegen.config.jsondeclares inputs, output paths, and naming conventions for both codegen targets.- C# codegen target —
NJsonSchema.CodeGeneration.CSharpproduces records intopackages/com.quiz.core/Runtime/Generated/. Output is git-ignored; build invokes codegen before compile. - TypeScript codegen target —
quicktypeproduces interfaces;ajvproduces compiled validators; both land inQuiz.Designer/src/app/generated/. Output is git-ignored;npm run schema:genis invoked byng buildand on watch. - Shared semantic-fixture suite under
schemas/fixtures/— paired NUnit / Jest harnesses assert TS and C# validators agree on every input. - CI pipeline
.azure-pipelines/quiz-schemas.ymlpublishes both code drops as artefacts.
Per-Unity-project scaffolding — Universal MVP project0 / 3
Each Unity project (Host, Client, Remote, Quiz.Preview) converges on the shape captured in Per-App Scaffolding. Apply changes per-editor by routing through the AI Tooling — Unity MCP set_active_instance protocol; verify with read_console after each compile.
- Set
companyNametoQuizCompanyin every project'sProjectSettings/ProjectSettings.asset. - Verify
Active Input HandlingisInput System Package;_Global/Configuration/InputActions.inputactionsin place. - One asmdef per app, named
Quiz.{App}.Game.asmdef, root namespaceQuiz.{App}.Game.
Load-bearing prototype MVP projecthostclient0 / 5
- In-process C# WebSocket server runs in the Host using
SimpleWebTransportper Tech Stack. Server must support all three message families from MVP: Designer transfer, Client live-play, Remote control. The MVP control-message envelope must reserve room for the Alpha rich-command set so adding it is purely additive. - Host advertises itself via Bonjour/mDNS using
Makaretu.Dns.Multicast.Newper Tech Stack - Client discovers the Host via Bonjour/mDNS
- Typed ping/pong message exchanged between Host and Client
- End-to-end test: Client discovers Host and round-trips a message
Remote app — minimum viable controls MVP remotehost0 / 9
The fourth Unity app — see Applications — Remote. MVP delivers the minimum viable controls (discovery, pairing, mirror, host-notes, live state, advance/go-back). The richer command set is in the Alpha section below.
- Remote discovers Hosts via Bonjour (F-RE-1)
- Pairing UX — Host displays both a short numeric code AND a QR; Remote can either type the code manually or scan (F-RE-2)
- Remote opens control-message-family WebSocket to paired Host (F-RE-3)
- Remote renders the scaled-down mirror streamed from the Host (F-RE-4)
- Remote displays the per-slide host-notes for the current slide (F-RE-5)
- Remote displays live session state — scores, timer remaining, slide index (F-RE-6)
- Remote sends core navigation commands to the Host — advance, go-back (F-RE-7)
- Remote handles disconnection and reconnection (Wi-Fi blip recovery; rejoins same paired Host) (F-RE-8)
- End-to-end test: Remote pairs with Host, sees the mirror + host-notes + live state, drives a full quiz session through advance/go-back
MVP object-type cohort MVP designerhostclient0 / 6
The remaining MVP object types beyond core.text. Each implements the full plugin contract with end-to-end tests covering Designer authoring, Host rendering, and (where applicable) Client rendering and input.
core.multiple-choice-inputend-to-end (Client canvas; tap-to-select; submit)core.free-text-inputend-to-end (Client canvas; text entry; submit)core.numeric-inputend-to-end (Client canvas; numeric validation; closest-wins scoring; tiebreaker support)core.true-false-inputend-to-end (Client canvas; binary ✓ / ✗ tap targets; submit)core.timerend-to-end (either canvas; countdown / elapsed; Host-authoritative; configurable lock-on-time-up + late-submission rule + quizmaster override)core.leaderboardend-to-end (either canvas; per-team standings; trigger-driven reveal — on slide entry / on quizmaster trigger / after delay; reveal animation: full table / row-by-row / bottom-up)
Designer→Host transfer MVP designerhost0 / 7
- Designer can save a quiz to disk as a
.quizfile (manifest + slides) —SaveQuizCommandbundlesAuthoringSessionstate into aQuizPackage;PersistenceService.saveAsyncatomic-writes the ZIP via the Tauri fs command. Resource bundling lands with the bundle-on-save item. (F-DE-12) - Designer can re-open an existing
.quizfile from disk —MenuActions.openAsync→PlatformAdapter.pickFile→PersistenceService.openAsync→ReplaceActiveQuizcommand. (F-DE-13) - Designer discovers Hosts on the local network via mDNS — Tauri
mdns-sdRust command surfaced throughTransferService(F-DE-14) - Designer can push a saved
.quizfile to a chosen Host over the WebSocket transport — uses the standard browserWebSocketAPI (viarxjs/webSocket) from the Angular process (F-DE-14) - Host accepts incoming
.quiztransfers, validates the manifest against its built-in registry, and stores the file locally on operator confirm (F-HO-4, F-HO-7) - Host UI manual-confirm prompt for every incoming transfer ("Designer X wants to send 'My Quiz' (50 MB). Accept?")
- End-to-end test: Designer saves → Designer pushes to Host → operator accepts → Host loads → Host can start a session
Designer Run-from-slide subprocess [MVP — deferred] designerhost0 / 3
Deferred to the end of the MVP feature work. Ctrl+F5's spawnHost Tauri command currently throws notInTauri; the renderer-side shortcut is wired, the backend implementation lands here once the Host build is signable + bundled as externalBin.
- Wire
tauri-plugin-shell+bundle.externalBinintauri.conf.jsonso the Designer ships with the Host binary inside its app bundle. TauriPlatformAdapter.spawnHostinvokes the bundled binary with{quizPath, startSlide}as CLI args (the Host's bootstrap reads them).- End-to-end: Ctrl+F5 on a saved
.quizlaunches the local Host with the active slide pre-selected.
Cross-platform validation MVP projectdesignerhostclientremote0 / 15
Cross-platform from day one — every platform stood up during MVP rather than expanded into post-MVP. Each item below is a check that the corresponding feature works on the named platform end-to-end (build, network discovery, transfer, live play). Not separate engineering work, but separate validation runs. Designer ships desktop only in MVP (Windows + macOS); iPad and Android tablet authoring are Stretch. Linux is out of scope.
- Designer (Tauri + Angular) validated on Windows —
Quiz.PreviewWebGL canvas embedded, JS bridge round-trip, multi-window via TauriWebviewWindowAPI, custom titlebar with Win 11 Mica, Run from slide subprocess spawn end-to-end - Designer (Tauri + Angular) validated on macOS — same surface as Windows; multi-window; macOS traffic-light titlebar overlay; Run from slide subprocess spawn end-to-end
- Host validated on macOS
- Host validated on Windows
- Host validated on iPad
- Host validated on Android tablet
- Client validated on iPhone
- Client validated on Android phone
- Client validated on iPad
- Client validated on Android tablet
- Remote validated on iPhone
- Remote validated on Android phone
- Remote validated on iPad
- Remote validated on Android tablet
- Per-platform Bonjour/mDNS validated
End-to-end vertical slice MVP projectdesignerhostclient0 / 2
- Automated end-to-end test: Designer authors a quiz (with per-slide host-notes) → Designer pushes to Host over LAN → Host loads → Clients join (eager push) → quizmaster pairs a Remote → quizmaster advances slides from the Remote → answers tally → leaderboard reveals on slide-entry → leaderboard finalises
- Manual playthrough of a multi-round quiz (text + multiple-choice + free-text + numeric + timer + leaderboard) on a real Wi-Fi network on every supported platform combination, with the quizmaster walking the room and driving advance/go-back from a paired Remote
First rich object types Alpha designerhostclient0 / 3
core.audio-clipelement (Host canvas) — paired withcore.free-text-inputmakes a music round- End-to-end test exercising a slide composed of audio + free-text answer
- Document the object-type plugin contract as a new knowledgebase page once it has stabilized across the Alpha cohort
Additional content object types Alpha designerhostclient0 / 5
core.imageelement (display on either canvas)core.videoelement (display on Host canvas)core.drawing-inputelement (Client capture, Host display, live mirror; touch-only in v1)core.buzzer-inputelement (first-press semantics across multiple Clients)core.ranking-inputelement (Client canvas; drag-to-reorder; items text / image / both; all-or-nothing or per-position partial credit)
Crash recovery Alpha hostclient0 / 7
- Host snapshots session state to disk after every scoring event and every slide advance (F-HO-18)
- Snapshot format: JSON DTOs in the shared class library; same shape as live message envelopes
- Host on launch detects a saved session matching the loaded
.quizand prompts the operator to resume or start fresh (F-HO-19) - Resume restores slide pointer, team list, scores, per-element state; Host re-advertises on Bonjour
- Client persists its team identity (Host-issued stable token) to local storage (F-CL-10)
- Client reconnect path attaches as the original team using the stored token, whether the Host disconnect was Wi-Fi or crash
- End-to-end test: simulated Host crash mid-session → relaunch → resume → all Clients reconnect with scores intact
Remote app — rich control commands Alpha remotehost0 / 6
Layered onto the MVP minimum viable controls — the rich command set that turns the Remote from "advance the deck" into "fully run the room from your pocket". F-RE-9 (Remote side) and F-HO-24 (Host side).
- Remote rich command: jump to a specific slide (F-RE-9, F-HO-24)
- Remote rich command: trigger element reveals (e.g. show the leaderboard, show the answer) (F-RE-9, F-HO-24)
- Remote rich command: lock / unlock Client input (F-RE-9, F-HO-24)
- Remote rich command: extend / skip the timer (F-RE-9, F-HO-24)
- Remote rich command: override scoring per team (F-RE-9, F-HO-24)
- End-to-end test: Remote drives a full quiz session using the rich command set — including a triggered leaderboard reveal mid-slide and a live scoring override
Reliability and performance Alpha projecthostclientremote0 / 5
- Reliability soak test: client disconnect storms, host backgrounding, Wi-Fi flap, simulated Host crash + recovery
- Performance: 60 fps animation budget verified on iPhone 12 / equivalent Android (measured in the Unity runtime build)
- Element answer-submit round-trip latency < 200 ms on local Wi-Fi (verified)
- Remote control-message round-trip latency < 200 ms on local Wi-Fi (verified)
- mDNS reliability on real devices. Validate
Makaretu.Dns.Multicast.Newadvertisement + discovery on iOS 16+, Android 12+, Windows 10/11, macOS 12+ over a typical pub-grade Wi-Fi router. If the pure-C# multicast proves unreliable on any platform (advertisement drops, discovery misses Hosts, multicast blocked by the OS), implement the native fallback bridge for that platform —NSNetService(iOS) orNsdManager(Android) — and route the Unity-side discovery API through the bridge. Native bridges held as a contingency per Tech Stack. Conditional work — only landed if validation flags it.
Categories question type Beta designerhostclient0 / 1
core.categories-inputend-to-end (Client canvas; multi-line entry; per-line scoring; "Name 5 X" format)
Match-pairs question type Beta designerhostclient0 / 1
core.match-pairs-inputend-to-end (Client canvas; drag/connect pairing UX; left + right columns; items text / image / both; per-pair scoring)
Image-reveal question type Beta designerhostclient0 / 2
core.image-reveal-inputend-to-end (Host canvas: image obscured by author-picked shader filter — pixelate / blur / mosaic — clearing over the question duration; Client canvas: multiple-choice submit; earlier-correct scoring via configurable speed-bonus curve)- Inspector fields: reveal curve (linear / ease-out / stepped), filter type, filter start/end intensity, points-vs-time function
Word-scramble buzzer question type Beta designerhostclient0 / 2
core.word-scramble-buzzerend-to-end (Host canvas: animated scrambled-letter tiles with drift / swap motion; Client canvas: buzzer-style first-press + text submit; first correct team scores)- Inspector fields: target word, scramble difficulty (animation intensity + hint cadence), wrong-answer penalty, per-team buzzer cooldown after wrong attempt
Multiple-choice elimination + speed-bonus extensions Beta designerhostclient0 / 3
- Extend
core.multiple-choice-inputconfig with optional elimination schedule (incorrect options vanish on an author-configured timeline — e.g. 4 → 2 over the question duration) - Extend
core.multiple-choice-inputconfig with optional speed-bonus curve (more points for earlier correct submissions) - Both fields default off; inspector reveals them under an "advanced" disclosure
Brand-true polish Beta projectdesignerhostclientremote2 / 6
- Shared design language: typography, palette, motion vocabulary per Design Specification applied across Designer, Host, Client, and Remote (F-X-3)
- Final font picks locked: Bebas Neue (display + numerals), Inter (body), JetBrains Mono (mono)
- Final brand colours locked from
branding.jpgsampling: magenta#FF009F, electric-blue#16B2EB, deep-purple#961EEF, white#FFFFFF, near-black#0F0B1A - Mascot animation rig — rigged once in the shared assets package; pose library callable from any of the four apps
- Brand-true reveal/transition motion replaces the Alpha first-pass
- Final product/brand name locked (apps referred to by their engineering project names — Quiz.Designer / Quiz.Host / Quiz.Client / Quiz.Remote — until then)
Theme system Beta designerhostclientremote0 / 5
- Designer chrome ships dark + light themes; author choice persisted in app settings (F-DE-25)
- Quiz manifest gains a
themefield (dark/light/ brand presets) (F-DE-26) - Host renders each loaded quiz against the manifest's declared theme (F-X-4)
- Client renders each loaded quiz against the manifest's declared theme (F-X-4)
- Remote renders the host-mirror in the manifest's declared theme (F-X-4)
Per-team theming Beta designerclienthost0 / 4
- Author defines a palette of team colours and an avatar set in the quiz (F-DE-21)
- Team picks colour + avatar at join (F-CL-12)
- Team identity (colour + avatar) renders consistently across every Client surface
- Per-team Host moments (leaderboard rows, team callouts) use the chosen colour and avatar
Mini-game framework Beta hostclient0 / 5
- Mini-game framework (native Unity) and a
core.mini-gameelement (F-CL-7) - Mini-game registry (id → mini-game module) resolved by the
core.mini-gameelement at slide load mini-game.internal-clockshipped as a built-in (Host runs a hidden countdown; teams press to stop their own clock with no visible number; closer to configurable target time scores more; overshoot scores zero by default; inspector fields: target time, points-vs-error curve, overshoot policy, per-team retry rule)mini-game.team-shootshipped as a built-in (Host flashes a team name; that team races a configured opponent — named team or next-fastest — to tap their Client; wrong-team presses lose configurable points; inspector fields: match-up rule, win/lose points, wrong-team penalty per team, reaction window)mini-game.spin-wheel-modifiershipped as a built-in (post-answer flourish; spinning wheel with± valuesegments; lands on a segment that applies the modifier to the configured target teams; inspector fields: segment list, spin duration, target rule, parent-question linkage)
Sound design Beta projecthostclientremote0 / 5
Full audio language per Design Specification — sound design (F-X-5).
- Source / commission stings: correct, incorrect, lock, time-up, big reveal, end of round, end of quiz
- Source / commission transition motifs: slide-advance whoosh, leaderboard reveal swell, round-change motif
- Optional ambient music bed (light, between-rounds), author-controllable per quiz
- Audio asset licensing decided (royalty-free pack, commissioned, or hybrid)
- Audio mix tuned for venue — stings cut through pub ambient noise without being intrusive
Quiz UK pilot Beta project0 / 4
- At least one real Quiz UK pub night runs successfully on the Beta build
- Real-device testing across all platforms — modern + older device on each side of iOS / Android
- Performance and latency targets re-verified on older test devices
- Hardware/OS minimum versions confirmed against real devices and Unity's Editor and Player support matrix.
Pre-release Production project0 / 9
Confirmed distribution channels: iOS App Store, Google Play Store, Microsoft Store, macOS App Store, macOS direct DMG.
- iOS App Store: signing, packaging, submission flow, update mechanism
- Google Play Store: signing, packaging, submission flow, update mechanism
- Microsoft Store: signing, packaging, submission flow, update mechanism
- macOS App Store: signing, packaging, submission flow, update mechanism
- macOS direct DMG: notarization, distribution, update mechanism
- Sign in with Apple wired up (only relevant if cloud auth Stretch ships first)
- Privacy policy drafted and published
- Store listings drafted (descriptions, screenshots, age rating, accessibility statements)
- Crash reporting / telemetry decisions made
Stretch goals Stretch projectdesignerhostclientremote0 / 38
These items deliver the cloud-backed authoring path sketched in Backend Schema and Authentication, plus other Stretch work. None are in v1 scope.
Cloud-backed authoring
- Pick cloud vendor (managed Postgres + object storage) and provision the project
profiles,quizzes,quiz_versionstables (F-DE-15)- RLS policies on tables (
owner_id = auth.uid()) - Storage RLS scoped to
quizzes/{owner_id}/... - Version pruning job (latest 20 + pinned)
- Email magic link sign-in on Designer (F-DE-1)
- Email magic link sign-in on Host (F-HO-1)
- Designer: save quiz to cloud, version history, restore (F-DE-15)
- Designer: soft-delete + trash view (F-DE-16)
- Designer: pin a version to protect from pruning
- Host: list quizzes from the cloud library, mark which are downloaded (F-HO-2)
- Host: download and cache a quiz package from the cloud (F-HO-2)
Additional question types
core.hotspot-input(tap on image coordinates; map / anatomy / geography rounds)
AI-aided quiz authoring (F-DE-22)
- LLM integration in Designer with verification UX (every generated artefact requires explicit author confirmation)
- Generation modes: question on a topic, multiple-choice distractors, host-notes draft from a question + answer
- Privacy posture decision: third-party API vs local model
Broadcast / streaming-friendly Host view (F-HO-22)
- Alternative Host display mode: subdued backgrounds, boosted overlay contrast, in-room-only chrome suppressed
- Toggleable from the Host (and via the Remote) without restarting the session
Recurring teams across sessions (F-HO-23, F-CL-13)
- Team-identity store keyed by quizmaster + venue (depends on cloud auth)
- Team-claim UX on Client join ("Are you returning team X?")
- Privacy and data-protection posture documented alongside
Tournaments / leagues
- Season schema in the cloud library (depends on recurring teams + cloud-backed authoring)
- Cross-session scoring rules
- League standings UI on Designer/Host
Quiz templates / starter packs (F-DE-23)
- Cloud library exposes templates as a distinct kind of quiz
- Designer "clone from template" flow makes a private, editable copy
Question bank / reusable questions (F-DE-24)
- Question schema decoupled from a specific quiz (cloud library)
- Designer "pull from question bank" flow into any quiz
Speed-round mode
- Round-level config: very short timer, no inter-slide pause, no countdown UI
- Could be promoted to Alpha as a small extension to round timing schema
Other stretch
- Bundle-supplied object types loader (signing, sandboxing, install UX — see OQ#1)
- Apple Pencil sketching/annotation in Designer (F-DE-17)
- Equivalent stylus support on non-Apple tablets (F-DE-17)
- Per-individual identity within a team — would change the eager-push model and join screen
- Multi-Remote support (co-quizmasters, conflict resolution, override semantics)
- Faster-cadence Host crash recovery (per-message snapshots; multi-instance Host failover)
- Cross-quiz analytics — see OQ#3
- Internet-based live play relay (Cloudflare Durable Objects or similar) — see OQ#2
Designer55 / 69
Tauri 2 + Angular Designer setup MVP designer8 / 8
Per Designer Shell. Single Tauri 2 workspace hosting an Angular 21 application; desktop only (Windows + macOS).
- Create
Quiz.Designer/as a Tauri 2 + Angular 21 workspace (pnpm create tauri-appthenng newinto the same root, or scaffold by hand per Repository Layout — Designer project graph). Angular CLI workspace targets ES2022; Tauri Rust shell targets Rust 1.78+. - Pin Angular to the latest stable major (21.x at time of MVP; check
npm view @angular/core dist-tagsand use the latest); pin Tauri to 2.x stable. - Configure
src-tauri/tauri.conf.jsonwithdecorations: false,titleBarStyle: "Overlay"on macOS,windowEffects: { effects: ["mica"] }on Windows 11, an initial window size matching the mockups, and aQuiz.Designerapp identifier. - Wire
tauri-plugin-dialog,tauri-plugin-fs,tauri-plugin-process,tauri-plugin-menu, and themdns-sdRust crate via Tauri commands undersrc-tauri/src/commands/. - Bootstrap the Angular workspace under
Quiz.Designer/src/with Angular Material + Angular CDK + RxJS; configure standalone-components architecture, signal-based reactivity, and zoneless change detection. - Override Angular Material primary / secondary / surface tokens in a custom CSS-variable theme that mirrors the Studio chrome surface tokens defined in Design Specification — Studio. Showtime brand colours stay inside the embedded
Quiz.Previewcanvas only. - Splash + boot-sequence window. Tauri opens a borderless 720 × 480
splashWebviewWindowfirst, loading the AngularSplashComponent. Splash pre-warms async services (schema codegen check, library index hydration,Quiz.Previewready event, mDNS listener init) and reports stage events to the splash UI. On all-ready, Tauri opens the main shell window at the saved size, focuses it, and fade-closes the splash (~120 ms). Splash is brand-locked Showtime and ignores the Studio chrome theme — identical visual in light and dark. Per Designer Shell — Boot sequence. - Custom Angular titlebar component (
<app-titlebar>) implements the Rider-style strip: logomark + wordmark + File / Edit / View / Help dropdowns + doc title + dirty dot + Undo / Redo + autosave badge + Run-from-slide CTA.-webkit-app-region: dragfor the drag region;setTrafficLightPositionfor macOS traffic-light placement; right-edge padding on Windows to clear the OS caption buttons. Per Designer Shell — Custom titlebar.
Designer composition + service layer MVP designer6 / 6
The Angular DI graph and the platform-adapter layer that lets the same code run under Tauri today and the browser later.
PlatformAdapterinterface insrc/app/platform/declares file-dialog, filesystem, mDNS, subprocess-spawn, and OS-menu capabilities.TauriPlatformAdapterimplementation wires each capability to the matching Tauri command.AuthoringSessionAngular service —activeQuiz,selection,isDirtyexposed as signals + observables;QuizChanged/SelectionChanged/DirtyChangedevents.CommandDispatcherAngular service —execute()+undo()pipeline; per-quiz undo / redo stacks. First two concrete commands —CreateNewQuizandReplaceActiveQuiz— validate the contract end-to-end.PropertyDispatcherhelper that batches keystroke edits in inspector components and emits commands at commit boundaries — per Designer Shell — Undo / redo granularity.- DI bootstrap registers
AuthoringSession,CommandDispatcher,ObjectTypeRegistry(seeded withcore.textinitially), and the platform adapter.
Designer persistence + autosave MVP designer11 / 11
PersistenceServiceAngular service —.quizsave / load viaTauriPlatformAdapter's fs commands + thezipRust crate; recent-files index in the platform app-data folder.- Atomic write protocol for every disk write —
<target>.tmp→ fsync → rename, implemented on the Rust side and exposed as a single Tauri command. Stranded.tmpGC on launch. - Autosave timer — debounced (8 s after last edit, 30 s ceiling); RxJS-driven scheduler with injectable clock for headless tests.
- Tiered slot retention — keep snapshots at anchor ages (now / 5 min / 1 hour / 6 hours / 1 day / 7 days); evict the rest.
- File → Restore from backup… Angular dialog listing surviving slot backups for the active quiz. Picking a backup loads it as
activeQuizwithisDirty = true. - Corruption detection on Open — when a
.quizfails to load, surface a banner "Couldn't open. The most recent backup is from - Recovery flow on launch with no quiz arg — empty-state banner listing orphaned drafts ("
drafts from an earlier session"). - Crash detection — clean-exit marker written on shutdown; absence on next launch indicates an unclean exit.
- Snapshot GC pass on launch — cleans stranded
.tmpfiles, evicts past-cap backups, removesAutoSaves/<quizId>/folders whose source has not been opened in 60 days, removesAutoSaves/<sessionId>/draft folders older than 30 days. - Persistent autosave-failure banner ("Autosave failed 3× — your work is at risk") after 3 consecutive backup-or-write failures within 2 minutes. Backup failure aborts the autosave write — never write the new state without a backup.
- Bundle-on-save / unbundle-on-load logic spanning Persistence + Library: Save copies referenced library bytes into the
.quizarchive'sresources/; Open content-hash-de-dupes archive resources against the local library. Round-trip test verifies a saved-then-opened quiz preserves every resource id and bytes match.
Designer library + file pickers MVP designer4 / 4
LibraryServiceAngular service — device-wide media catalog at platform app-data folder; SHA-256 content-hash de-dup (Web Crypto API in the renderer);LibraryAssetrecord.- File-picker capability on
PlatformAdapter— Tauri impl wrapstauri-plugin-dialog. - macOS entitlements /
Info.plistfor file access — declareapp-sandbox,network.client,network.server,files.user-selected.read-write. - Windows installer manifest opts the app out of
Program Filesplacement constraints that would block library writes.
Designer object types (Designer side) MVP designer2 / 2
ObjectTypeRegistryAngular service — editor-surface registry on the Designer side of the plugin contract. First registered type iscore.text(paired with the cross-cutting Object-type plugin contract section in project.md).- First Angular properties-inspector component for
core.text, bound to the type's view-model service via thePropertyDispatcherhelper.
Designer transfer skeleton MVP designer1 / 1
TransferServiceAngular service — wraps the LAN-discovery + WebSocket push path. Skeleton lands asStubTransferServicethat throws onpushAsync/discoverHostsAsync; the real impl lands with the Designer→Host transfer chunk in project.md.
Designer input + shortcuts MVP designer3 / 3
- Global keyboard-shortcut router — Angular service installs a
keydownlistener that routes Ctrl/Cmd-Z / Shift-Z / S / O / Delete / arrows toCommandDispatcheror component event outputs. Ignores keypresses inside inputs / contentEditable so typing into the inspector still works. - PowerPoint-style preview shortcuts:
F5enters Extended Preview mode from slide 1,Shift+F5enters from the current slide,Ctrl+F5triggers Run-on-Host subprocess spawn. - Drag-drop into the design surface — Angular CDK drag-drop wires palette → canvas and slide-list reorder. Touch fallback via long-press gesture.
Designer UI / component skeletons MVP designer1 / 1
- Stub Angular standalone components:
ShellComponent(3-column layout via CDK),SlideListComponent,PaletteComponent,PropertiesInspectorComponent,LibraryPanelComponent,PushToHostDialogComponent,LibraryPickerDialogComponent,RestoreFromBackupDialogComponent. Each subscribes to the matching service event (AuthoringSession.QuizChanged/SelectionChanged,LibraryService.Changed) and cleans up subscriptions viaDestroyRef.
Designer panel layout — resize, move, pop-out MVP designer5 / 5
Per the Designer Shell, the v1 shell needs operator-customisable layout — panels that resize, drag-reorder, and detach into separate windows.
- Column splitters — draggable splitter handles between the slide-list / canvas / right-rail columns. Drag clamps each column to a min / max range; double-click resets to the mockup default. Remaining: widths persist to a
PreferencesServiceslice keyedquiz.designer.layout.v1(the service lands alongside the autosave-retention chunk). - Pane registry —
LayoutStateenumerates the panes (slide-list,canvas,right-rail) and the dock zones (left/center/right/popped); aPaneHostComponentresolves a pane id to its component. The shell renders each zone fromLayoutService.stateso panels are re-homed by moving ids, not by rewriting layout markup. - Drag-reorder between dock zones — each pane carries a drag grip; dropping it on another dock zone calls
LayoutService.movePane. Layout changes are workspace state, deliberately not routed through the quizCommandDispatcher(a panel move should not sit on the document undo stack alongside slide edits — consistent with Designer Shell — Undo / redo granularity treating workspace operations as session, not authoring, actions). Persistence viaPreferencesServicelands alongside the autosave-retention chunk. - Pop-out to a separate window — pane header has a "↗ pop out" button. Tauri shell binds this to
WebviewWindow.new("pane-<id>", { url: "/pane/<id>" })via thepop_out_panecommand; closing the pop-out re-docks the pane to its previous slot via thepane:redockevent the backend emits onWindowEvent::Destroyed. Web-shell binding towindow.openlands with the BrowserPlatformAdapter (Web Designer Stretch). - Layout reset — the titlebar
View → Reset Layoutmenu item callsLayoutService.reset, restoring the defaultslide-list/canvas/right-railshape; the reset is persisted so it survives a restart. Preview pop-out as the first concrete use is deferred alongside the rest of the Quiz.Preview chunks below.
Designer authoring features MVP designer14 / 14
- Create new quiz —
CreateNewQuizCommandis wired to the slide-rail+ New quizbutton + the File menu. (F-DE-2) - New-quiz title / description / tags entry dialog so the user picks an identity instead of
CreateNewQuizCommandhard-coding "Untitled". (F-DE-2) - Add, edit, reorder, delete slides —
AddSlideCommand+DeleteSlideCommand+ click-to-select + CDK drag-reorder viaReorderSlidesCommandare wired intoSlideList. (F-DE-3) - Per-slide rename — inline-edit affordance on each slide-list row, dispatching
SetSlideTitleCommanddirectly throughCommandDispatcher(blur / Enter commits; Escape cancels). (F-DE-3) - Group slides into rounds; reorder, ungroup (F-DE-4)
- Place / move / configure / delete elements on the Host canvas (F-DE-5)
- Place / configure / delete elements on the Client canvas (F-DE-6)
- Object-type palette listing built-in types — initially
core.text, expanded as the MVP cohort lands (F-DE-7) - Configure scoring per slide and per round, including late-submission rules (F-DE-9)
- Configure timing per slide: duration, lock-on-time-up, late-submission rule, quizmaster-override-allowed (F-DE-10)
- Per-element reveal trigger UI: choose on-slide-entry / on-quizmaster-trigger / after-delay (F-DE-20)
- Per-slide host-notes editor (free-form text, rendered only on the Remote during play) (F-DE-19)
- Package as canonical
.quizformat —Quiz.Core.Packaging.QuizPackage{Reader,Writer}write + read the ZIP (manifest.json + slides/*.json), data-only, no runtime code. (F-DE-18) - Auto-derive the manifest's
objectTypes[]registry on save from the element type-ids actually used across the slide tree, so the Host can refuse / upgrade packages whose declared cohort doesn't match its built-in registry. (F-DE-18)
Designer Quiz.Preview JS bridge [MVP — deferred] designer0 / 7
Deferred to the end of the MVP feature work. The static DOM Host / Client canvas inside the Designer's main canvas panel is enough to author a .quiz package against — the WebGL preview only shows how the slide will look once it lands on the Host + Client runtimes, so it can land last without blocking the rest of the authoring surface.
- Bundle the WebGL output of
Quiz.Preview/underQuiz.Designer/src/assets/preview/(consumed from the CI artefact at build time) and load it inline as a<canvas>via the standard Unity WebGL loader. PreviewBridgeAngular service — pushes slide JSON to the embeddedQuiz.Previewcanvas viaunityInstance.SendMessage; subscribes to ready / rendered / error JS callbacks invoked by the WebGL build.- First end-to-end push: load a placeholder
core.textslide, push state, observe re-render in the embedded canvas, log therenderedcallback. - Reconnect strategy: if the canvas reports
erroror fails to load, retry with backoff and surface a banner. - Embedded
Quiz.PreviewWebGL canvas reflects the slide live as it is edited — every state mutation pushes JSON to the canvas viaPreviewBridge(F-DE-11) - Preview pop-out is the first concrete use of the multi-window pane framework — preview canvas lives in its own pane so authors can run it on a second monitor while they edit. Default keyboard shortcut:
Ctrl/Cmd + Shift + P. - Smoke-test launch via
tauri devon Windows and macOS — splash → main shell with embedded preview canvas visible and a Quiz.Preview ready event observed.
Quiz.Preview Unity setup [MVP — deferred] designer0 / 6
Deferred alongside the Quiz.Preview JS bridge. Sibling Unity project, WebGL-only build target. No editing UI; pure render target driven by JS messages from the Angular shell.
- Create
Quiz.Preview/as a Unity project with WebGL set as the only build target. - Add
Scenes/Preview/Preview.unity— single render scene with the slide canvas + camera; entry point for WebGL boot. - Add
Scripts/PreviewBoot.cs— listens for JS messages (LoadSlide,UpdateProperty,SetSelection); calls back via[DllImport("__Internal")]for ready / rendered / error events. - Reference
com.quiz.shared-assets,com.quiz.runtime,com.quiz.coreviaPackages/manifest.json. - Player Settings:
defaultScreenWidth/Heightflexible (canvas size driven by host page); tuneWebGLMemorySizefor the largest expected scene. - Smoke-test: WebGL build loads in a plain HTML page, accepts a
LoadSlideJS call, renders a placeholder slide, emits arenderedcallback.
Designer additions for Alpha Alpha designer0 / 1
- Object-type palette includes the Alpha cohort (audio, image, video, drawing, buzzer)
Host0 / 21
Per-Unity-project scaffolding — Host MVP host0 / 4
Scenes/MainMenu/MainMenu.unity— pre-quiz lobby (load.quiz, accept Designer transfers, list connected teams, start session).Scenes/Play/Play.unity— slide-driven runner that advances through the quiz, dispatches element behaviours, and runs the live session.- Player Settings:
defaultScreenOrientation: 3(LandscapeLeft); disable portrait autorotates;defaultScreenWidth/Height: 1920/1080(TV / projector target). - Smoke-test in Editor: Host launches, MainMenu and Play scenes load without errors, orientation is landscape.
Host live-session features MVP host0 / 15
- Open WebSocket server, advertise on local network via Bonjour/mDNS (F-HO-3)
- Load
.quizfrom local FS via file picker (in addition to Designer push) (F-HO-5) - Loaded packages remain available offline (F-HO-6)
- Resolve every object type the loaded package declares; refuse on missing or version-incompatible types (F-HO-7)
- Start a session from a loaded package (F-HO-8)
- Join screen lists connected teams (one Client device per team) with team names (F-HO-9)
- On Client connect, eagerly push Client-canvas content + Client-side resources for the whole quiz (F-HO-10)
- Advance through slides; render each slide's Host canvas at the connected display's resolution (F-HO-11)
- Receive answers (via element protocol extensions), apply scoring (including late-submission rules), render leaderboard on triggered reveal (F-HO-14)
- Host is authoritative on timer state; emits "time-remaining" tick and "lock" message (F-HO-16)
- Host operator can override timer live for the current slide (extend / skip / lock / unlock) (F-HO-17)
- Handle Client disconnect/reconnect without ending the session (F-HO-15)
- Host accepts a paired Remote on the control-message-family WebSocket; pairing UX (manual confirm or QR-code — pick during the prototype) (F-HO-20)
- Host streams a periodic mirror of its current display, the current slide's host-notes, and live state (scores, timer remaining, slide index) to the paired Remote (F-HO-21)
- Host accepts core navigation commands from the paired Remote: advance, go-back (F-HO-21)
First-pass animation Alpha host0 / 2
- Animated reveals and transitions on Host slides — first pass, not yet brand-true (F-HO-13)
- Leaderboard reveal animations — first pass
Client0 / 15
Per-Unity-project scaffolding — Client MVP client0 / 4
Scenes/MainMenu/MainMenu.unity— discovery + join (list visible Hosts, enter team name, join).Scenes/Play/Play.unity— render the current slide's Client canvas, dispatch input elements, show score.- Player Settings:
defaultScreenOrientation: 4(AutoRotation) — Client supports portrait and landscape on phones and tablets. - Smoke-test in Editor: Client launches, MainMenu and Play scenes load without errors.
Client team-play features MVP client0 / 11
- Discover hosts via Bonjour (F-CL-1)
- Enter team name and join — one shared device per team; no per-individual identity (F-CL-2)
- Receive eager push from Host on join; cache slide content + resources for the session (F-CL-3)
- Late-join progress UI + jump-to-current-slide on completion (F-CL-3)
- Resolve every object type the package declares; report a fatal mismatch to the host on missing or version-incompatible types (F-CL-4)
- Render the current slide's Client canvas with its responsive layout (F-CL-5)
core.multiple-choice-inputelement: tap input, submit answer (F-CL-6)core.free-text-inputelement: text entry, submit answer (F-CL-6)- Render Host's authoritative timer state; lock input on Host "lock" message (F-CL-11)
- Show team score and standings (F-CL-8)
- Reconnect after a disconnect (F-CL-9)
Remote0 / 4
Per-Unity-project scaffolding — Remote MVP remote0 / 4
Scenes/MainMenu/MainMenu.unity— discovery + pairing (list visible Hosts, pair via short numeric code OR QR scan per F-RE-2, connect).Scenes/Play/Play.unity— render the mirrored Host canvas + host-notes + live state, send control commands.- Player Settings:
defaultScreenOrientation: 1(Portrait); disable landscape autorotates. - Smoke-test in Editor: Remote launches in portrait orientation, MainMenu and Play scenes load without errors.