Pub Quiz Platform
Build Plan — Project (cross-cutting)
| Status | Live checklist |
| Scope | Project (cross-cutting) |
| Generated | 2026-05-13 |
| Source of truth | .claude/context/knowledgebase/build-plan.md |
The implementation work that delivers the spec. Every section carries a phase tag and one or more app-scope chips: project for cross-cutting work, or one or more of designer, host, client, remote.
Mirrored into Azure DevOps as User Stories (one per ## section) and Tasks (one per - [ ] bullet) by /sync-build-plan. ADO IDs are stored inline as HTML comments on each heading / bullet.
Definition of Done for every item:
- TDD followed (failing test first, then implementation, then refactor) per Testing.
- End-to-end automated test exists for any user-facing feature the item touches, in the test layer specified by Testing — Where each kind of test lives.
- Lint and format pass; coding standards followed.
Foundation MVP project 3 / 6
- Initialize repo with four Unity projects (
Quiz.Host,Quiz.Client,Quiz.Remote,Quiz.Preview) plus the .NET MAUI BlazorQuiz.Designer.csprojplus shared local UPM packages (com.quiz.corepure C# /.NET Standard 2.1,com.quiz.runtimeUnity-aware,com.quiz.shared-assets). 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 project 0 / 23
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 / Catalyst SDKs, Unity Editor + license, 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-designer.yml— .NET MAUI build fornet8.0-windows*(Microsoft-hosted) +net8.0-maccatalyst+net8.0-ios(Mac mini); bundles the publishedquiz-preview-webglartefact underwwwroot/; runs Razor / xUnit unit tests..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 project management setup MVP project 0 / 11
Per Project Management. The PRD is the locked-in requirements artefact; Epics / Features / Stories / Issues are decomposed from it after sign-off.
- ADO project provisioned (or existing project repurposed) with Boards, Repos, Pipelines, and Wiki enabled.
- Sprint board configured with the six columns: To Do, Blocked, In Development, Ready For Test, In Testing, Done.
- Sprint length agreed with the team (default candidate: two-week sprints) and configured in Iteration Paths.
- Work-item types in use: Epic, Feature, User Story, Issue. Customisations applied if the default templates need adjusting (e.g. adding "Acceptance criteria" + "Definition of done" fields where missing).
- Wiki provisioned and pointed at the auto-generated knowledgebase mirror produced by the
docsskill.
Decompose the PRD into Epics / Features / Stories / Issues
- Walk the signed-off PRD; create one Epic per major area (typically corresponding to a
## Sectionin this build plan tagged[MVP]or[Alpha]). - Decompose each Epic into Features (shippable user-facing capability).
- Decompose each Feature into User Stories (sprint-sized) and Issues (technical task / bug).
- Each Story / Issue has acceptance criteria + Definition of Done filled in per Testing + the
development-standardsskill. - Backlog prioritised; first sprint's items pulled into the Sprint Backlog.
- Build-plan items linked to ADO work items so completion in ADO ticks the corresponding
- [ ]here.
MAUI Blazor Designer setup MVP designer 0 / 10
Per Designer Shell. Single .NET MAUI Blazor Hybrid .csproj, desktop only (Windows + macOS Catalyst).
- Create
Quiz.Designer/as a .NET MAUI Blazor Hybrid.csprojtargetingnet8.0-windows*andnet8.0-maccatalyst. - Reference
Quiz.Coreas a project / package reference. - Wire a
BlazorWebViewinto the MAUI shell with a root Razor component. - Add
MudBlazorNuGet reference; register inMauiProgramviabuilder.Services.AddMudServices(); add<MudThemeProvider />,<MudPopoverProvider />,<MudDialogProvider />,<MudSnackbarProvider />to the root Razor layout. - Override Material primary / secondary / surface tokens in a custom
MudThemeto match the Design Specification palette. - Mac Catalyst multi-window config: add
SceneDelegate.cstoPlatforms/MacCatalyst/(subclassingMauiUISceneDelegate); addUIApplicationSceneManifest(UIApplicationSupportsMultipleScenes = true,UISceneDelegateClassName = SceneDelegate) toPlatforms/MacCatalyst/Info.plist. - WebView2 user-data-folder workaround on Windows: in
Platforms/Windows/App.xaml.cs(or the MAUI app constructor), setWEBVIEW2_USER_DATA_FOLDERenv var to a writable path underFileSystem.AppDataDirectorybefore any WebView control is initialised. Required when the app is installed underProgram Files. - Bundle the WebGL output of
Quiz.Preview/as static content served byBlazorWebViewunderwwwroot/and load it as a<canvas>via the Unity loader. - First JS bridge round-trip: Razor →
unityInstance.SendMessage→ WebGL Unity → JS callback → Razor. - Smoke-test launch on Windows and macOS Catalyst — splash → main shell with embedded preview canvas visible.
Quiz.Preview Unity setup MVP designer 0 / 6
Sibling Unity project, WebGL-only build target. No editing UI; pure render target driven by JS messages from the Razor 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.
Per-Unity-project scaffolding MVP projecthostclientremote 0 / 15
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.
Universal projecthostclientremote
- 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.
Host host
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.
Client client
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.
Remote remote
Scenes/MainMenu/MainMenu.unity— discovery + pairing (list visible Hosts, pair via manual confirm or QR, 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.
Load-bearing prototype MVP projecthostclient 0 / 5
- In-process C# WebSocket server runs in the Host (library pick — see Open Questions). 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 (library pick — see Open Questions)
- 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
Shared schema MVP project 0 / 9
- Quiz manifest, slide, canvas, and element schemas in the shared C# class library (per Quiz Package Format)
- Round (slide-grouping) schema in the shared C# class library (title, scoring metadata, contiguous slide range)
- Per-slide host-notes field in the slide schema (used by F-DE-19 and rendered by the Remote — both MVP)
- Per-element reveal-trigger field in the element schema (on slide entry / on quizmaster trigger / after delay) — F-DE-20
- Per-slide timing config: lock-on-time-up, late-submission rule, quizmaster-override-allowed (F-DE-10)
- WebSocket message envelope schema (typed, validated) with extension hooks for object-type-specific messages, distinct families for Designer transfer / Client live-play / Remote control
- Schema version field on quiz packages, validation on load (F-X-2)
- Object-type registry interface in the shared C# class library — declares type id, schema version, and the surface contracts referenced by the apps
- Round-trip serialization tests for every schema
Object-type plugin contract MVP projectdesignerhostclient 0 / 8
IObjectTypeinterface in the shared C# class library (type id, schema version, schema accessor) — see Object-Type Architecture- Designer editor-surface contract (Razor component + view-model in the MAUI Blazor Designer; declares 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
- 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
MVP object-type cohort MVP designerhostclient 0 / 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 (MAUI Blazor) architecture skeletons MVP designer 0 / 31
The architectural skeleton the Designer authoring features sit on top of. Top-level shape in Designer Shell. Each skeleton item lands minimally first (just enough to compile and route events) and grows as feature items below consume it. Subsystem-level pages will be authored once these skeletons settle — they replace the previous Unity-only architecture/designer/* subdirectory pages.
Historical note: an earlier set of skeleton items targeted Unity subsystems (
_Game/Authoring/,_Game/State/,_Game/Commands/, etc.) inside the previous UnityQuiz.Designer/project. Those tasks are obsolete — the Designer is now MAUI Blazor — and have been replaced by the items below. The original list is recoverable from git history if any of its detail (autosave cadence, tiered backup slots, atomic write protocol) needs porting forward.
Project + composition root designer
- Top-level folders under
Quiz.Designer/:Components/(Razor components),Services/(DI-registered services likeIPersistenceService,ILibraryService,IPreviewBridge),State/(Quiz Model + undo stack),Commands/(undoable operations),Wwwroot/(static assets including the bundledQuiz.Preview/WebGL output) - Composition root:
MauiProgram.csregisters every service in DI;App.razormounts the Razor component tree - Razor
_Imports.razorreferences the chosen component library (e.g.@using MudBlazoronce the library is picked) - Single
Quiz.Designer.csprojwithnet8.0-windows10.0.x,net8.0-maccatalyst,net8.0-iostarget frameworks; conditional<ItemGroup>for platform-only chrome
State + commands designer
AuthoringSessionC# class inState/:ActiveQuiz,Selection,IsDirty, plus explicit C# events (QuizChanged,SelectionChanged,DirtyChanged). Razor components subscribe via injection.ICommandinterface + dispatcher inCommands/:Execute()+ inverse-Undo()contract; undo/redo stack lives here. First two concrete commands —CreateNewQuizCommand,ReplaceActiveQuizCommand— validate the contract end-to-end.- Razor components mutate state only through commands so every change is undoable.
Persistence + autosave designer
IPersistenceService(DI singleton) —.quizsave / load viaQuiz.Coreserialisation; recent-files index in platform-appropriate app-data folder (Environment.SpecialFolder.LocalApplicationDataon desktop, MAUIFileSystem.AppDataDirectoryon iPad).- Atomic write protocol for every disk write —
<target>.tmp→ fsync → rename. Stranded.tmpGC on launch. - Autosave timer + per-fire sequence — debounced (8 s after last edit, 30 s ceiling). For quizzes with a SourcePath: conditional pre-write backup (copy SourcePath to app-data
AutoSaves/<quizId>/<timestampISO>.quizonly if the freshest existing backup is ≥ 5 min old) → atomic write the new state to SourcePath → prune. For never-saved quizzes: write a draft snapshot toAutoSaves/<sessionId>/<timestampISO>.quiz. - Tiered slot retention — pool capped at 6 backups per quizId pinned to exponentially-spaced anchor ages: now (< 5 min), 5 min (≥ 5 min), 1 hour, 6 hours, 1 day, 7 days. Pruning algorithm walks the pool newest → oldest and assigns each backup to the smallest remaining anchor it fits; everything else is evicted.
- File → Restore from backup… — Razor dialog showing the surviving slot backups for the active quiz. Each entry shows the slot label, a friendly relative time, and the backup's file size. Picking a backup loads it as
ActiveQuizwithIsDirty = true. - Corruption detection on Open — when a
.quizfails to load, prompt "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-exitmarker written on shutdown; absence on next launch routes through the recovery banner. - 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.
Library + file pickers designer
ILibraryService(DI singleton) — device-wide media catalog at platform app-data folder; content-hash SHA-256 de-dup;LibraryAssetrecord.IFilePickerService(DI singleton) — wraps MAUI'sFilePicker.PickAsyncandMediaPicker.PickPhotoAsync/PickVideoAsyncfor cross-platform native pickers (Win + macOS + iPad in one API).- iOS / iPad
Info.plist:NSPhotoLibraryUsageDescription,NSDocumentsFolderUsageDescriptionpermission strings (English + on-brand copy). - macOS Catalyst entitlements /
Info.plistfor file access (sandbox + user-selected files).
Quiz.Preview JS bridge designer
IPreviewBridge(DI singleton) — abstraction over the JS interop that pushes slide state to the embeddedQuiz.PreviewWebGL canvas viaunityInstance.SendMessageand receives ready / rendered / error events back via JS callbacks → Razor event invocation.- 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.
Object types (Designer side) designer
IObjectTypeRegistry(DI singleton) — editor-surface registry on the Designer side of the plugin contract fromQuiz.Core. First registered type iscore.text(paired with the cross-cutting Object-type plugin contract section above).- First Razor properties-inspector component for
core.text, bound to the type's view-model.
Transfer skeleton designer
ITransferService(DI singleton) — thin Designer wrapper around the WebSocket + mDNS code inQuiz.Core(orQuiz.Runtimeif Unity-aware bits are required; ideally Designer side stays inQuiz.Core-only territory). The full Designer→Host transfer flow is tracked in the section below; this skeleton item lands just the DI wiring + a stubbedPushAsyncthat fails fast.
Input + shortcuts designer
- Keyboard shortcut handling in the Razor shell — Cmd/Ctrl-S / O / Z / Shift-Z / A / Delete / arrows wired through
JSInteropkeydownlisteners in the root component, dispatched as commands. Long-press touch substitute for multi-select on iPad. - Drag-drop into the design surface — Blazor's drag-and-drop API for asset picker → canvas, plus iPad-friendly long-press-to-drag fallback.
UI / Razor component skeletons designer
- Stub Razor components:
Shell.razor,SlideList.razor,Palette.razor,PropertiesInspector.razor,LibraryPanel.razor,PushToHostDialog.razor,LibraryPickerDialog.razor,RestoreFromBackupDialog.razor. Bodies are first-pass placeholders pending a UI review pass by the user (mockups in docs/ui-mockups/designer/ are the visual targets).
Designer→Host transfer MVP designerhost 0 / 7
- Designer can save a quiz to disk as a
.quizfile (manifest + slides + resources) — Razor command, atomic write viaIPersistenceService(F-DE-12) - Designer can re-open an existing
.quizfile from disk — native file picker viaIFilePickerService(F-DE-13) - Designer discovers Hosts on the local network via Bonjour/mDNS —
Quiz.Corediscovery layer surfaced throughITransferService(F-DE-14) - Designer can push a saved
.quizfile to a chosen Host over the WebSocket transport — uses .NETSystem.Net.WebSocketsfrom the MAUI 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 authoring features MVP designer 0 / 12
- Create new quiz with title, description, tags (F-DE-2)
- Add, edit, reorder, delete slides (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) - Embedded
Quiz.PreviewWebGL canvas reflects the slide live as it is edited — every state mutation pushes JSON to the canvas viaIPreviewBridge(F-DE-11) - 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 (manifest declares object types + versions; no runtime code) (F-DE-18)
Host live-session features MVP host 0 / 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)
Client team-play features MVP client 0 / 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)
Remote app — minimum viable controls MVP remotehost 0 / 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 (manual confirm on Host or QR-code pairing — pick during the prototype) (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
Cross-platform validation MVP projectdesignerhostclientremote 0 / 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 Catalyst); iPad and Android tablet authoring are Stretch. Linux is out of scope.
- Designer (MAUI Blazor) validated on Windows —
Quiz.PreviewWebGL canvas embedded, JS bridge round-trip, multi-window via MAUIWindowAPI - Designer (MAUI Blazor) validated on macOS (Catalyst) — same surface as Windows; multi-window
- 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 projectdesignerhostclient 0 / 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
Designer additions for Alpha Alpha designer0 / 1
- Object-type palette includes the Alpha cohort (audio, image, video, drawing, buzzer)
Reliability and performance Alpha projecthostclientremote0 / 4
- 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)
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
Mini-game framework Beta hostclient0 / 3
- Mini-game framework (native Unity) and a
core.mini-gameelement (F-CL-7) - First mini-game shipped as a built-in
- Second mini-game shipped as a built-in
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)
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)
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
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
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#4
- Internet-based live play relay (Cloudflare Durable Objects or similar) — see OQ#3