Opening case file…
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..9a9d99a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,34 @@ +name: Bug report +description: Something doesn't work as expected +labels: [bug] +body: + - type: dropdown + id: area + attributes: + label: Where + options: [TV app (Vega), Phone app, Server, AI suspects / voices, A case's content, Docs] + validations: + required: true + - type: textarea + id: steps + attributes: + label: Steps to reproduce + placeholder: "1. Create a room on the TV\n2. Join from a phone\n3. …" + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected vs actual + validations: + required: true + - type: input + id: env + attributes: + label: Environment + placeholder: "Fire TV Stick 4K Max / Vega Virtual Device; phone browser; commit" + - type: textarea + id: logs + attributes: + label: Logs or screenshots + description: Please remove any API keys. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..09ab370 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Security issue + url: https://github.com/perhaps-aksh/RoomRiddle/security/advisories/new + about: Please report vulnerabilities privately. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..89ff465 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,18 @@ +name: Feature or case idea +description: Suggest a feature, an improvement or a new mystery +labels: [enhancement] +body: + - type: textarea + id: idea + attributes: + label: The idea + validations: + required: true + - type: textarea + id: why + attributes: + label: Who it helps and why + - type: textarea + id: notes + attributes: + label: Anything else (sketches, references) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..49328bd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ +## What + + +## How + + +## Checks +- [ ] `npm run check` passes +- [ ] TV changes: `apps/tv/scripts/wsl-check.sh` passes (and checked on the Vega Virtual Device if it changes what's on screen) +- [ ] No case-specific logic in the engine or UI; content stays in `packages/mystery-data` +- [ ] No secrets, keys or `.env` files +- [ ] Docs updated (README, `docs/`, friction log) where relevant + +## Screenshots + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..feece30 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + check: + name: Typecheck and test (engine, content, server, phone) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run check + env: + AI_DISABLED: "1" + VOICES_DISABLED: "1" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..69057e3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +All notable changes, newest first. The project follows [Conventional Commits](https://www.conventionalcommits.org/); see `git log` for every commit. + +## [Unreleased]: public release prep +- **Brand:** the app is now "Room Riddle", with a launcher icon on the TV and a favicon and web manifest on the phone. +- **Docs:** showcase README with screenshots; technical reference moved to `docs/system-design.md`; contributing guide, code of conduct, security policy, credits, `.env.example`, CI and issue/PR templates. + +## 2026-10-12: Voices on the TV +- AI suspect voices play on Vega: the server converts clips to fragmented-MP4 AAC and the TV streams them through Media Source (Vega refuses plain `http://` media; FL-014). +- The speech bubble sits above the footer. + +## 2026-10-10: AI suspects and five cases +- **AI questioning (server):** prompts built only from unlocked truth-table facts, a reply guard for spoilers, answers and character breaks, authored fallbacks, a question budget, cooldowns and caching. Groq first. +- **Voices:** free Edge neural voices, with Groq Orpheus as a second provider; one voice per character. +- **Phone Question tab:** pick a suspect, ask in your own words, show found evidence. +- **TV speech bubble:** "is thinking…", then the reply with voice and subtitles. +- **Content:** truth tables; *The Hollow Manor*, *Signal Lost*, *The Forgotten Temple* and *The Yaksha's Three Questions* are playable; the library fits five cases. +- Technical README and market research. + +## 2026-10-06 to 10-09: Audio and polish (Phase 7) +- Data-driven audio: music states, ambience layers, cues and voice ducking; pooled effect players; saved settings. +- Audio diagnostics; the emulator crackle was traced to the emulator itself (FL-013). +- World fixes: real clock faces, focus tags, remote focus that follows the layout; Play Again in a room. + +## 2026-09-29 to 10-05: Design system and 2.5D world (Phases 5 and 6) +- Design tokens shared by TV and phone; redesigned TV and phone screens; connection overlays; reduced motion. +- 2.5D world: asset registry, camera and parallax, director and timelines, rain, fog, steam, lightning, the train and the detective. +- Vega WebSocket messages that arrive in pieces are reassembled (FL-011). + +## 2026-09-27 to 09-29: Foundation (Phases 0 to 4) +- Monorepo, development rules, Vega app generated and running on the Vega Virtual Device. +- TV shell with D-pad navigation. +- Deterministic game engine and *The Last Train*, playable end to end. +- Authoritative WebSocket server: rooms, QR join, reconnection, host pause. Phone web app and a shared protocol client. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..1d7f82d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,7 @@ +# Code of Conduct + +Room Riddle follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). + +In short: be welcoming and respectful, assume good intent, give and accept constructive feedback gracefully, and keep discussions about the work. Harassment, insults, and personal or political attacks are not accepted. + +To report unacceptable behaviour, open a private [security advisory](https://github.com/perhaps-aksh/RoomRiddle/security/advisories/new) or contact the maintainer through their GitHub profile. Reports are handled confidentially. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..14d7d06 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,44 @@ +# Contributing to Room Riddle + +Thanks for your interest. Room Riddle started as a hackathon project and welcomes issues, fixes and new cases. + +## Ground rules +Read [AGENTS.md](AGENTS.md) first: it is the rulebook for humans and coding agents alike. The short version: + +- **The server is authoritative.** Clients send intents ("my answer is 1147"), never results. +- **The engine is pure and mystery-agnostic.** No I/O, no `Date.now()`, no case ids in engine or UI code. +- **Content is data.** Everything about a case lives in `packages/mystery-data`. +- **The TV works with a remote only.** Every focusable element has a visible focus state; Back never destroys progress without asking. +- **AI is optional and guarded.** It may only voice facts the room has unlocked, and the game must play without it. +- **No secrets in git.** Keys go in `apps/server/.env` (see `.env.example`). + +## Setup +```bash +npm install +npm run check # must pass before every commit +npm run serve # server + phone app on :4000 +``` +TV app setup (Vega SDK, WSL2 on Windows): [docs/development.md](docs/development.md). + +## Workflow +1. Open an issue describing the bug or idea (templates are provided). +2. Branch from `main`: `feat/…`, `fix/…`, `docs/…`. +3. Keep changes small and tested. Add tests next to the code (`*.test.ts`, or `apps/tv/test/*.spec.tsx`). +4. Run `npm run check` (and `apps/tv/scripts/wsl-check.sh` for TV changes). +5. Commit with [Conventional Commits](https://www.conventionalcommits.org/): `feat(tv): …`, `fix(server): …`, `docs: …`. +6. Open a pull request and fill in the template. CI must be green. + +## Writing a new case +1. Copy an existing case folder in `packages/mystery-data/src/` (for example `the-forgotten-temple/`). +2. Fill in the `MysteryDefinition`: summary and audience, intro, scenes, clues, puzzles (each with accepted answers and exactly three hints), endings, scoring. +3. Add the **truth table**: each character's persona, public claims and secrets with `unlockedBy`, plus guarded spoiler terms. +4. Register it in `packages/mystery-data/src/index.ts`. +5. Run `npm run check`. The catalog tests validate every reference and **play the case to the end automatically**; they fail if a clue can't be found or a spoiler can never unlock. + +Cultural or religious source material must be original, respectful, and never presented as scripture; worship is never a puzzle. + +## Reporting Vega / Fire TV friction +Real problems with the Vega SDK, the emulator or tooling go in [docs/friction-log.md](docs/friction-log.md), with steps, expected and actual results, and the workaround. Only verified facts. + +## Code of conduct +This project follows the [Contributor Covenant](CODE_OF_CONDUCT.md). diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 0000000..f095ae0 --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,24 @@ +# Credits + +**Design, code and story:** Chitraksh Kumar ([@perhaps-aksh](https://github.com/perhaps-aksh)). + +## Art +- App icon, banner and concept art: AI-assisted illustration, art-directed and edited by the author. Released with the project under the MIT licence. +- TV scenes in the current build use code-drawn placeholder shapes; painted plates and character art are being added through the asset system. +- Screenshots in `docs/images` were captured from the Vega Virtual Device and a phone browser. + +## Audio +- Current music, ambience and effects are **placeholders synthesized for development** (`apps/tv/scripts/gen-placeholder-audio.py`). They will be replaced by licensed or CC0 recordings, which will be listed here with their sources. +- Detective narration lines: Microsoft Edge neural voice `en-GB-RyanNeural`, generated for development. +- Live suspect voices are generated at runtime by Microsoft Edge neural TTS (via [`msedge-tts`](https://www.npmjs.com/package/msedge-tts)) and Groq-hosted [Orpheus](https://console.groq.com/docs/text-to-speech) by Canopy Labs. + +## Services and libraries +- [Amazon Vega SDK](https://developer.amazon.com/docs/vega/) and React Native for Vega. +- [Groq](https://groq.com/) free tier: `openai/gpt-oss-120b` (OpenAI open-weight model) for suspect dialogue. +- [`ws`](https://github.com/websockets/ws), [esbuild](https://esbuild.github.io/), [tsx](https://github.com/privatenumber/tsx), [ffmpeg](https://ffmpeg.org/) and the React Native Testing Library. + +## Fonts +The TV uses Vega's built-in system fonts (Bookerly, Amazon Ember, Amazon Ember Mono); none are bundled. + +## Inspiration +*The Yaksha's Three Questions* is inspired by the *Yaksha Prashna* episode of the Mahabharata. The case is an original story and puzzles, not a retelling of scripture. diff --git a/README.md b/README.md index c8b8bf8..cb5efc3 100644 --- a/README.md +++ b/README.md @@ -1,632 +1,265 @@ -# RoomRiddle - -**Gather. Investigate. Unravel the Mystery.** - -RoomRiddle is a cinematic, cooperative mystery game for **Amazon Fire TV on Vega OS**. The TV is the crime scene and the game master. Phones are each player's private notebook and controller. An authoritative server keeps everyone in one synchronized investigation, a deterministic engine decides every answer, and AI-voiced suspects answer questions, but only with what the room has earned. - -> Built for the *Build, Ship, Shape: Amazon Developer Hackathon*, Fire TV track (family entertainment, multi-modal UX). - ---- - -## Contents -1. [What it does](#1-what-it-does) -2. [Status](#2-status) -3. [System architecture](#3-system-architecture) -4. [Repository layout](#4-repository-layout) -5. [The game engine](#5-the-game-engine) -6. [Mystery content model and truth tables](#6-mystery-content-model-and-truth-tables) -7. [Multiplayer](#7-multiplayer) -8. [TV app on Vega OS](#8-tv-app-on-vega-os) -9. [Audio system](#9-audio-system) -10. [AI layer](#10-ai-layer) -11. [Expandable mystery library](#11-expandable-mystery-library) -12. [Security and privacy](#12-security-and-privacy) -13. [Testing and quality](#13-testing-and-quality) -14. [Setup and running](#14-setup-and-running) -15. [Performance](#15-performance) -16. [Known limitations](#16-known-limitations) -17. [Documentation index](#17-documentation-index) +
+
+
+
+
+ How it plays · + The cases · + AI suspects · + Quick start · + Architecture · + Docs +
+ +> Built for the **Build, Ship, Shape: Amazon Developer Hackathon** (Fire TV track: family entertainment, multi-modal UX). --- -## 1. What it does +## ✦ How it plays -1. The TV opens a room and shows a 4-digit code and a QR code. -2. Players scan it with their phones. No app install, no account. -3. The case opens on the TV: a cinematic scene (for example, a storm-lashed railway platform at 11:52 PM). -4. Players explore with the remote or their phones, inspect objects, discover evidence and solve puzzles together. -5. Players question suspects. Each suspect answers in character, but can only reveal what the room's evidence allows. -6. The group submits its final theory. The engine decides which ending the evidence supports. +
+
+
Asking Inspector Voss a question from a phone. He answers on the TV, in character and in his own voice.
+
|
|
+| **Home:** create or join a room with the remote | **Library:** five complete cases |
+|
|
|
+| **Lobby:** scan the QR code, see who's in | **The world:** a layered 2.5D scene you explore with the remote |
----
+### Your phone is your notebook
-## 2. Status
+
+
+
Join in seconds · examine evidence · question suspects · solve puzzles with three-step hints
+

` plays a scripted game alongside you.
---
-## 9. Audio system
+## ✦ Architecture
```mermaid
flowchart LR
- subgraph Data["mystery-data"]
- MAN["Audio manifests
(id → file, channel, volume, loop)"]
- DIRN["Audio direction
music states, ambience per set, cues, moments"]
- end
- subgraph Logic["packages/scene"]
- AD["AudioDirector
music state machine, crossfades,
ambient layers, voice ducking (music to 40%)"]
+ subgraph Home["Living room"]
+ TV["📺 Fire TV · Vega OS
React Native for Vega"]
+ P["📱 Phones
(browser, no install)"]
end
- subgraph TVa["apps/tv/audio"]
- AP["AudioProvider
place, events, settings"]
- BE["w3cBackend
players, pooling, lifecycle counters"]
+ subgraph Server["Game server · Node.js + TypeScript"]
+ WS["WebSocket gateway"]
+ GS["Rooms + GameSession"]
+ ENG["Game engine
(pure, deterministic)"]
+ MD["Mystery data
+ truth tables"]
+ AI["Guarded AI + voices"]
end
- GSt["GameState + world place"] --> AP
- MAN & DIRN --> AD
- AP --> AD --> BE --> SPK["W3C media player"]
- SET["Settings: master, music, effects, voice, subtitles"] --> AP
+ TV <-->|"intents / state"| WS
+ P <-->|"intents / state"| WS
+ WS --> GS --> ENG --> MD
+ GS --> AI
+ AI -.-> LLM["Groq · Edge TTS
(free tiers)"]
```
-- No component names a file: everything is an id resolved through the manifest.
-- Effective volume = master × channel × sound volume (× duck for music under voice).
-- A missing file never blocks play: it is logged once (`[AUDIO_MISSING]` with id, reason and scene), voice lines keep their subtitles, music and ambience skip.
-- A development trace (`[AUDIO_TRACE]`) logs every command and its cause; `apps/tv/scripts/trace-sink.js` collects it from the device.
-- Jest journey tests drive the real provider, director and backend through a whole case and assert order, ducking, cleanup and player counts.
-
----
-
-## 10. AI layer
+**Ground rules**
+- **Data flows one way:** mystery data → game engine → game state → UI.
+- **The engine is mystery-agnostic and does no I/O.** Time is passed in, so any game can be replayed from its action log.
+- **Presentation is not logic.** The 2.5D world, audio and AI react to the game state; they never decide anything.
+- **The protocol lives in one place** (`packages/shared-types`) and is shared by the TV, the phones and the server.
-**Status: interrogation is live on the server** (`apps/server/src/ai/`); the phone/TV interface, hints, narration and voices come next. Keys live only in `apps/server/.env` (git-ignored). The game remains fully playable without AI.
+### Repository layout
-### 10.1 What the AI does
-1. **Interrogation:** players pick a suspect on their phone and ask anything (typed, or spoken and transcribed). The suspect answers in character on the TV, with voice and subtitles.
-2. **Adaptive hints:** the AI rephrases the next authored hint level for the group's situation. It cannot go beyond that level.
-3. **Narration:** the narrator (detective, curator or Yaksha) reacts to discoveries and theories.
-
-### 10.2 What the AI can never do
-- Decide whether an answer is correct, unlock anything, or change score or state. Only the engine does.
-- See a fact the room has not unlocked. Locked facts are never in the prompt.
-- Say a guarded term early. Every reply is checked with `spoilersIn` before anyone sees it.
-- Invent evidence. Replies are limited to speakable facts and clues already found.
-
-### 10.3 Interrogation flow
-
-```mermaid
-sequenceDiagram
- autonumber
- participant P as Phone
- participant S as Server (GameSession)
- participant G as Truth gates (engine)
- participant A as AI gateway
- participant M as Gemini / Groq
- participant T as TV
- P->>S: ASK_CHARACTER {characterId, question, evidenceClueId?}
- S->>S: per-room budget, per-player cooldown, length cap
- S->>T: CHARACTER_THINKING
- S->>G: speakableFacts(character, state), activeGuardedTerms(state)
- G-->>S: allowed facts, banned terms
- S->>A: persona + allowed facts + found clues + question
- A->>M: generate (short, in character)
- alt provider error or limit
- A->>M: next provider
- end
- M-->>A: reply
- A->>G: spoilersIn(reply) + length + off-limits check
- alt unsafe, or every provider failed
- A-->>S: authored fallback line
- else safe
- A-->>S: reply
- end
- S->>T: CHARACTER_REPLY {characterId, text, audio}
- S->>P: CHARACTER_REPLY
```
-
-### 10.4 Cost and reliability
-- Free tiers only, in `AI_ORDER` (default Groq `openai/gpt-oss-120b`, measured 0.5–1.2 s per line, then Gemini), then authored lines. Players never pay and never see a key.
-- A per-room question budget (30 per playthrough), a per-player cooldown (4 s), short outputs, a 6 s timeout per provider and reply caching keep usage inside free limits. A rate-limited provider rests for a minute; a denied key rests for ten.
-- `npx tsx apps/server/scripts/voice-samples.ts ` writes one sample per character to audition the casting.
-- `npm run ai-smoke -w @roomriddle/server [groq|gemini]` asks real suspects with the real keys and prints which source answered.
-
-### 10.5 Code map
-| File | Role |
-| --- | --- |
-| `ai/prompt.ts` | Builds the prompt from persona, unlocked facts (minus any holding a live spoiler) and found clue titles. Player text is fenced. |
-| `ai/providers.ts` | Gemini and Groq REST clients (key in headers, never in URLs). |
-| `ai/guard.ts` | Strips stage directions, caps at three sentences, rejects spoilers, unsolved typed answers and out-of-character lines. |
-| `ai/fallback.ts` | Authored replies from unlocked first-person facts, or a deflection in a tone suited to the case. |
-| `ai/voice.ts` | Spoken replies: Edge neural voices (free, no key) via `msedge-tts`, content-addressed in-memory cache, `CHARACTER_VOICE` after the text so subtitles never wait. Each character's voice is data (`CharacterTruth.voice`). |
-| `ai/CharacterService.ts` | Budget, cooldown, cache, provider chain, history (last three exchanges per character). Never changes game state. |
-
-### 10.6 Server settings
-| Variable | Default | Meaning |
-| --- | --- | --- |
-| `GROQ_API_KEY`, `GEMINI_API_KEY` | none | Free-tier keys, in `apps/server/.env` only. |
-| `AI_ORDER` | `groq,gemini` | Provider order. |
-| `GROQ_MODEL` / `GEMINI_MODEL` | `openai/gpt-oss-120b` / `gemini-3.8-flash` | Models. |
-| `AI_DISABLED` | unset | `1` = authored lines only (offline demo). |
-| `VOICES_DISABLED` | unset | `1` = subtitles only. |
-| `AI_TIMEOUT_MS`, `AI_MAX_QUESTIONS`, `AI_COOLDOWN_MS` | 6000, 30, 4000 | Limits. |
-- Voice: server-side free TTS, one fixed voice per character, subtitles always shown. Speech input via Groq Whisper from the phone microphone.
-
----
-
-## 11. Expandable mystery library
-
-**Status: planned.** Downloaded code cannot safely be executed on the TV, so a mystery pack is **data only**: it describes a case using puzzle types, interactions and effects the installed engine already supports.
-
-```mermaid
-flowchart LR
- subgraph Authoring
- AU["Author writes case
(TypeScript data)"] --> VAL["validateMysteryDefinition
+ asset check + playthrough test"]
- VAL --> PK["Pack: manifest.json + assets
id, version, engineVersion, checksums"]
- end
- PK --> CDN["Object storage / CDN"]
- PK --> CAT["Catalogue API + DB
(cases, versions, entitlements)"]
- subgraph Device
- LIB["Library screen"] --> CAT
- LIB --> DL["Downloader
resume, checksum, engine compatibility"]
- DL --> CACHE["Local pack cache"]
- CACHE --> RUN["Engine + world + audio
(same runtime as built-in cases)"]
- end
- CDN --> DL
- STORE["Amazon Appstore IAP"] --> CAT
+apps/
+ tv/ Fire TV app: React Native for Vega (RN 0.83), TypeScript
+ player/ Phone app: plain TypeScript + DOM, bundled with esbuild, served by the server
+ server/ Authoritative game server: HTTP + WebSocket, rooms, AI and voice gateway
+packages/
+ shared-types/ Protocol, game state, mystery schema, world and audio types
+ game-engine/ Pure rules: applyAction(mystery, state, action) → { state, events }
+ mystery-data/ The five cases: scenes, clues, puzzles, hints, endings, truth tables
+ scene/ Camera, director, layout, asset registry, audio director
+ client/ Protocol client shared by the TV and phones (reconnects, message reassembly)
+ ui/ Design tokens: colour, type, spacing, motion
+docs/ System design, development, testing, game design, friction log, research
```
-- The server loads the same pack version as the TV before a room starts, so it stays authoritative.
-- Packs declare a minimum engine version; incompatible packs are hidden, not crashed.
-- Purchases are entitlements verified with the store, separate from downloaded files.
+The full technical reference is in **[docs/system-design.md](docs/system-design.md)**: the engine, the truth-table model, the multiplayer protocol, the 2.5D renderer, audio and the AI layer.
----
+### Built with
-## 12. Security and privacy
-
-- Answer keys, hint text, clue descriptions and truth tables never reach a client before they are earned (`PublicMystery` + `GameReveals`).
-- Every client frame is shape-validated; unknown fields are dropped; oversize frames are refused; per-connection rate limits apply.
-- Session tokens are random 32 bytes, compared in constant time.
-- No accounts and no personal data: a player is a nickname for the life of a room. Rooms live in memory.
-- API keys are server-side only (`.env`, git-ignored). Questions go to the AI provider without names or identifiers.
+| Layer | Technology |
+|---|---|
+| TV | React Native for Vega 0.83 · Vega SDK · `@amazon-devices/react-native-w3cmedia` (audio + Media Source) · Async Storage |
+| Phone | TypeScript · DOM · esbuild · QR join |
+| Server | Node.js · TypeScript · `ws` · ffmpeg (voice clips to fragmented MP4) |
+| AI | Groq `openai/gpt-oss-120b` · Groq Orpheus TTS · Microsoft Edge neural TTS (`msedge-tts`) |
+| Quality | `node:test` + `tsx` · Jest + React Native Testing Library · ESLint · GitHub Actions |
---
-## 13. Testing and quality
+## ✦ Quality
-| Suite | Runner | Covers |
-|---|---|---|
-| `packages/*`, `apps/server`, `apps/player` | `node:test` via `tsx` (`npm run check`) | Engine rules, scoring, validation, playable cases end to end, content validation, scene/camera/director/audio director, protocol, rooms, reconnection |
-| `apps/tv` | Jest + React Native Testing Library (`wsl-check.sh`) | Navigation, screens, world, settings, full audio journey through the real game (69 tests) |
-| Device | Vega Virtual Device scripts | `vvd-shot.sh` (remote keys + screenshots), `vvd-load.sh` (CPU), audio capture to WAV (`vvd-wav-start.sh`), audio trace sink |
-| Lint / types | `tsc --noEmit`, ESLint | All workspaces |
-
-About 270 automated tests run before every commit. See `docs/testing.md`.
+- **About 320 automated tests:** 58 engine, 22 content, 52 scene, 19 client, 4 UI tokens, 78 server, 11 phone and 75 TV.
+- **Every case is played to the end automatically.** Content validation fails the build on unreachable scenes, broken references, puzzles that need clues from later scenes, and spoilers that could never unlock.
+- **Spoiler-attack tests** run against the AI guard and the prompt builder.
+- **Scripted device QA:** the Vega Virtual Device is driven with remote key presses and screenshots, with an audio trace sink.
+- CI runs the root checks on every push and pull request.
---
-## 14. Setup and running
-
-### Requirements
-- Node.js ≥ 22, npm ≥ 10.
-- TV app: Vega SDK on Ubuntu 20.04+ or macOS 10.15+ (this project also runs it under WSL2 on Windows 11; see `docs/development.md`).
+## ✦ Status
-### Server + phones (Windows, macOS or Linux)
-```bash
-npm install
-npm run check # typecheck + all package tests
-npm run serve # build the phone app, start the server on 0.0.0.0:4000
-```
-Optional AI configuration in `apps/server/.env` (never commit it):
-```
-GEMINI_API_KEY=...
-GROQ_API_KEY=...
-```
-
-### TV app
-```bash
-# inside Ubuntu (or WSL2) with the Vega SDK
-source ~/vega/env
-bash apps/tv/scripts/wsl-check.sh # tsc + eslint + jest
-bash apps/tv/scripts/wsl-build.sh # build the .vpkg in an ext4 mirror
-bash apps/tv/scripts/wsl-install.sh # install and launch on the VVD
-```
-- On the VVD the app reaches the server at `ws://10.0.2.2:4000/ws` through `apps/tv/scripts/vvd-bridge.js`.
-- On a physical Fire TV, set `apps/tv/src/config/server.ts` to `ws://:4000/ws`.
-
-### Play
-1. TV: **Create Room**.
-2. Phones on the same Wi-Fi: scan the QR code.
-3. TV: **Start**.
-
-Without a TV: `npm run fake-tv -w @roomriddle/server`, then `npm run play-bots -w @roomriddle/server -- ` plays a scripted game.
+| Area | State |
+|---|---|
+| Game engine, five playable cases, truth tables | ✅ Done, tested |
+| Multiplayer server: rooms, QR join, reconnection, host pause | ✅ Done, tested |
+| Phone app: Scene, Evidence and Question tabs | ✅ Done, tested |
+| TV app: screens, lobby, settings, library, 2.5D world, audio | ✅ Done, verified on the Vega Virtual Device |
+| AI suspect questioning with voices on the TV | ✅ Done, verified on the Vega Virtual Device |
+| Painted art, video loops and final audio | 🎨 In progress (assets in production) |
+| UI redesign to the final art direction | 🎨 In progress |
+| AI hints and narrator | 🔜 Next |
+| Validation on Fire TV Stick hardware | 🔜 Next |
+| Playable web demo | 🔜 Planned |
+
+**Known limitations:** server state is in memory, so a restart ends all rooms. Audio on the Vega Virtual Device crackles on our development machine; this comes from the emulator, not the app (see [FL-013](docs/friction-log.md)).
---
-## 15. Performance
-
-Measured on the Vega Virtual Device (4 vCPU, software rendering), so these are upper bounds:
+## ✦ Documentation
-| Situation | System CPU |
+| Document | What's inside |
|---|---|
-| Idle VVD | ~13% |
-| Static screen, reduced motion | ~5% |
-| World exploration | 56–62% |
-| Arrival cinematic | ~75% |
-| Memory | ~600 MB of 3.9 GB |
-
-Every animation uses the native driver and the frame loop runs only while something moves. Real hardware composites on the GPU and will be measured on a Fire TV Stick.
+| [docs/system-design.md](docs/system-design.md) | Architecture, engine, content model, protocol, TV renderer, audio, AI, security |
+| [docs/development.md](docs/development.md) | Environment setup, Vega SDK under WSL2, the daily loop |
+| [docs/testing.md](docs/testing.md) | Test strategy, suites and commands |
+| [docs/game-design.md](docs/game-design.md) | Game design notes |
+| [docs/architecture.md](docs/architecture.md) | Design decisions, phase by phase |
+| [docs/friction-log.md](docs/friction-log.md) | Verified problems we hit with Vega, the emulator and tooling, with workarounds |
+| [docs/research/market-research.md](docs/research/market-research.md) | Audience, family impact, market and validation plan |
+| [CONTRIBUTING.md](CONTRIBUTING.md) | How to contribute, conventions, and how to write a new case |
+| [CHANGELOG.md](CHANGELOG.md) | What changed, milestone by milestone |
+| [CREDITS.md](CREDITS.md) | Art, voices, fonts and third-party services |
---
-## 16. Known limitations
+## ✦ License
-- Emulator audio on the development PC crackles and lags; this is the VVD/WSLg pipeline, not the app (FL-013). Clean audio must be confirmed on hardware.
-- Art and sounds are placeholders until the asset pass lands.
-- Server state is in memory; a restart ends all rooms.
-- The AI layer and cases 2–5 are in progress.
+[MIT](LICENSE) © 2026 Chitraksh Kumar.
----
-
-## 17. Documentation index
-
-| Document | Contents |
-|---|---|
-| `docs/architecture.md` | Detailed design decisions per phase |
-| `docs/development.md` | Environment setup, Vega under WSL2, daily loop |
-| `docs/testing.md` | Test strategy and commands |
-| `docs/game-design.md` | Game design notes |
-| `docs/friction-log.md` | Verified problems with Vega, the VVD and tooling (product feedback) |
-| `docs/research/market-research.md` | Market, audience, family impact, monetization, validation plan |
-| `AGENTS.md` | Rules for every contributor |
-
-## License
-[MIT](LICENSE)
+Fire TV, Vega OS and Amazon are trademarks of Amazon.com, Inc. or its affiliates. Room Riddle is an independent hackathon project and is not endorsed by Amazon.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..3f1c4d2
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,17 @@
+# Security Policy
+
+## Reporting a vulnerability
+Please **do not open a public issue**. Use GitHub's private reporting: [Report a vulnerability](https://github.com/perhaps-aksh/RoomRiddle/security/advisories/new). Expect a reply within a few days.
+
+## What matters most here
+- Anything that lets a client read answer keys, hints, clue text or truth-table facts before the room has earned them.
+- A client changing game state without a valid intent (forged results, another player's seat, session hijacking).
+- Prompt injection that makes an AI suspect reveal a guarded spoiler or break character.
+- Leaks of server-side API keys.
+
+## Design notes
+- Keys live only in `apps/server/.env` (git-ignored) and never reach a client.
+- Every client frame is shape-validated and rate-limited; session tokens are 32 random bytes compared in constant time.
+- There are no accounts and no stored personal data: a player is a nickname for the life of a room, and rooms live in memory.
+
+See [docs/system-design.md](docs/system-design.md#security-and-privacy).
diff --git a/apps/player/public/icon-192.png b/apps/player/public/icon-192.png
new file mode 100644
index 0000000..20154c6
Binary files /dev/null and b/apps/player/public/icon-192.png differ
diff --git a/apps/player/public/icon-512.png b/apps/player/public/icon-512.png
new file mode 100644
index 0000000..5d2ac76
Binary files /dev/null and b/apps/player/public/icon-512.png differ
diff --git a/apps/player/public/index.html b/apps/player/public/index.html
index e98de8a..f023142 100644
--- a/apps/player/public/index.html
+++ b/apps/player/public/index.html
@@ -5,13 +5,17 @@
- RoomRiddle · Join the investigation
+ Room Riddle · Join the investigation
+
+
+
+
Opening case file…
-
+