# Idlegame — M1 Vertical Slice Plan (handoff artifact for superpowers) > **How to use this file:** the M1 brainstorm is complete; everything below is locked (approved by ginnoir 2026-06-11). Hand this plan to superpowers for execution. Tasks are grouped into **four phased PR batches** plus a **Phase 0 vault gate** for story content. Each phase ends at a browser-playable checkpoint. One tool per branch; everything lands via PR. > > **Canonical location:** `docs/plans/2026-06-11-m1-vertical-slice.md` in the working dir. ## Context M0 is complete (2026-06-11). The repo ships a walking skeleton: one resource, one timed action, fixed-timestep tick loop with offline catch-up, versioned saves (v1, reject-on-mismatch), Zustand bridge, minimal React shell, CI + internal playtest deploy at `https://idlegame.ginnoir.com/`. Vault notes exist: `Idlegame/GDD.md`, `Idlegame/Decisions.md`, `Idlegame/Story/Outline.md` (beat skeleton placeholder — prose TBD). **M1 scope:** turn the skeleton into the first playable vertical slice — one short story arc through the first prestige reset, with a meaningful branching choice, one automation unlock, offline progress, and save/load (including migration scaffolding). Ten Gitea issues (#3–#12) under milestone **M1 Vertical Slice** map to this plan. **Execution mode (locked):** phased PR batches with playable checkpoints after each merge — not one mega-run, not one-PR-per-issue. ## M1 success criteria A player on the internal playtest build can: 1. Queue multiple timed actions and watch resources accrue with costs/unlocks respected. 2. Read story passages and make a branching choice where routes A and B produce visibly different outcomes (flags, resources, or event-log entries). 3. Unlock automation for at least one action after completing it manually once. 4. Finish the opening arc and trigger the first prestige reset, retaining knowledge for catch-up on the next run. 5. Reload, export/import a save, and play comfortably on a phone viewport. ## Locked M1 decisions (brainstorm, 2026-06-11) | Decision | Choice | |---|---| | Phase structure | **Approach 1 — playable-first ladder:** 4 PRs + Phase 0 vault work | | Story timing | Phase 0 outline runs **in parallel** with PR1–2; stub prose proves branch mechanics; **ginnoir review gate** before PR3 merges real content | | Stub content | Placeholder names/prose allowed in PR1–2; replaced entirely in PR3 | | Prestige depth | First reset only — within-layer catch-up (knowledge flags, fast-forward); **no new mechanics between layers** (post-M1) | | Save version | Bump to v2 in PR4 when story/queue/automation/prestige fields land; v1→v2 migration required | | Balance | Tunable constants in content defs; notes filed in vault during T4.3 | Design pillars unchanged from M0 — see `Idlegame/GDD.md` and `docs/plans/2026-06-11-m0-bootstrap.md` §Locked design pillars. ## Starting codebase state ``` src/engine/ game.ts (single active action, no queue) tickLoop.ts (accumulator + maxTicks cap) save.ts (SAVE_VERSION=1, reject mismatch) num.ts src/content/ one resource (gold), one action (forage) src/state/ runtime (RAF loop), persistence (idb + localStorage) src/ui/ ResourceBar, ActionPanel, EventLog stubs ``` Architecture boundaries unchanged — see `docs/architecture.md`. ## Phase map | Phase | Branch | Closes Gitea | Playable checkpoint | |---|---|---|---| | **0** | *(vault, no PR)* | prep for #11 | Opening arc beats outlined; prose drafted for ginnoir review | | **1** | `feat/m1-foundations` | #3, #4 | Queue 3+ actions; multi-resource costs/unlocks work | | **2** | `feat/m1-playable-loop` | #5, #6 | Stub story branch — pick A vs B, outcomes differ | | **3** | `feat/m1-progression` | #7, #8, #11 | Full arc → prestige; second run catches up | | **4** | `feat/m1-polish` | #9, #10, #12 | Mobile-ready; save export/import UX; balance tuned; M1 closed | ## Dependency graph ```text Phase 0 (outline) ──────────────────────────────┐ │ gate before PR3 content PR1 foundations ──► PR2 story+queue UI ──► PR3 progression ──► PR4 polish │ │ │ └─ stub content └─ stub story graph └─ real content replaces stubs ``` PR1 must merge before PR2 (story graph assumes expanded game state + queue). PR3 requires Phase 0 approval for T3.3. PR4 assumes all gameplay systems exist. --- ## Phase 0 — Story outline (vault, parallel with PR1–2) **Tool:** Claude Code (+ ginnoir review in chat/Cursor) **Work:** 1. Fill `Idlegame/Story/Outline.md` §M1 arc beat skeleton: Hook → First loop → Branch (routes A/B) → Automation beat → Prestige climax. 2. Draft passage prose for each beat; ginnoir reviews/edits in vault. 3. Record any new design decisions in `Idlegame/Decisions.md`. **Gate:** ginnoir approves the outline before PR3 branch `feat/m1-progression` merges. Does **not** block PR1 or PR2. **Verify:** vault note has all five beats populated; ginnoir sign-off recorded in session log or Decisions. --- ## PR1 — Foundations (`feat/m1-foundations`) **Primary tool:** Codex (GPT-5.5-Codex medium). Alt: Cursor agent (Composer 2.5). **Gitea closes:** #3 Engine tick and offline hardening, #4 Resource and action definition set. ### T1.1 — Engine tick and offline hardening (#3) - Expand determinism regression tests: same elapsed wall time → same tick count and game state regardless of `advance()` chunking. - Document offline behavior: tick loop `maxTicks` batching vs save-layer `DEFAULT_MAX_OFFLINE_MS` clamp (already in `save.ts`). - Add/extend engine purity guard: no React/DOM imports under `src/engine/` (test or lint rule if lightweight). - Keep `tickGame` pure; queue logic lands in T1.3. *Verify:* `pnpm test:coverage` green; engine ≥80%; determinism test passes. ### T1.2 — Content schema expansion (#4) - Extend Zod schemas in `src/content/`: action **costs** (deduct on **start**; reject enqueue/start if unaffordable), **unlock conditions** (resource thresholds and/or story flags placeholder field for PR2), optional multi-yield. Record in `Idlegame/Decisions.md` as D-0010 if not already covered. - Validation tests for malformed defs. *Verify:* schema tests green; invalid content rejected at load boundary. ### T1.3 — Action queue engine - Extend `GameState`: `actionQueue: string[]` (ordered action ids), retain `activeActionId` + `actionElapsedMs`. - API: `enqueueAction`, `cancelQueuedAction(index)`, `clearQueue` (if scoped); on action completion, auto-start next queued action. - `tickGame` unchanged semantics for active action; completion handler dequeues. - Unit tests: queue ordering, cancel, auto-advance, empty queue idle. *Verify:* queue tests green; no UI required yet. ### T1.4 — Stub content pack - Replace walking-skeleton defs with M1-shaped placeholder set: **2 resources**, **4–5 timed actions** with costs/unlocks (generic names like "Supplies", "Scout the path"). - Keep human-readable durations (seconds-scale for dev; balance in PR4). *Verify:* action completion + cost/unlock accrual tests green. ### PR1 integration verify ```powershell pnpm typecheck pnpm lint pnpm test:coverage pnpm build ``` Manual playtest: enqueue 3 actions → they run sequentially → resources reflect costs/yields → reload preserves queue state. **PR:** conventional commits, link `Closes #3`, `Closes #4` in merge commit or PR body. --- ## PR2 — Playable loop (`feat/m1-playable-loop`) **Primary tools:** Codex (T2.1–T2.2 engine), Antigravity (T2.3–T2.5 UI + browser verify). **Gitea closes:** #5 Action queue UI, #6 Story graph and first branch. ### T2.1 — Story graph engine (#6) - New module `src/engine/story.ts` (or `storyGraph.ts`): traverse nodes, evaluate choice requirements, apply outcomes (set flags, grant/consume resources, route to next node). - Extend `GameState`: `storyFlags: Record`, `currentStoryNodeId: string`, `seenStoryNodeIds: string[]` (for prestige catch-up in PR3). - Emit story events for the event log (pure data — UI renders). - Unit tests: linear traversal, branch by choice, gated node blocked until requirements met. *Verify:* story traversal tests green; engine stays React-free. ### T2.2 — Story content schema - Zod-validated story node defs in `src/content/`: id, prose, choices (label, requirements, outcomes, target node), auto-advance nodes optional. - Wire into content loader alongside resources/actions. *Verify:* schema validation tests; invalid graph (dangling node id) fails at load. ### T2.3 — Action queue UI (#5) - Upgrade `ActionPanel`: enqueue button per unlocked action, visible queue list, cancel queued item, active action progress bar (extend M0 pattern). - Disabled state when action locked or unaffordable. *Verify:* browser — queue 2+ actions, cancel one, watch order respected. ### T2.4 — Story panel UI - New component: current passage prose, choice buttons when node has choices, integrate with runtime commands. - Event log receives story transition entries. *Verify:* browser — story panel renders; choice click advances node. ### T2.5 — Stub story graph - ~6 nodes, **one branching choice** (routes A/B), placeholder prose proving mechanics. - Hook stub graph to stub actions (e.g., branch unlocks different actions). *Verify:* browser — complete route A vs route B → different flags/resources/log entries. ### PR2 integration verify Full pre-PR chain + desktop browser smoke. Stub prose is explicitly temporary. **PR:** link `Closes #5`, `Closes #6`. --- ## PR3 — Progression (`feat/m1-progression`) **Gate:** Phase 0 outline approved by ginnoir. **Primary tools:** Claude Code (T3.3 content encode + prose fidelity), Codex (T3.1–T3.2 engine). **Gitea closes:** #7 Automation unlock, #8 First prestige reset, #11 Opening arc content. ### T3.1 — Automation unlock (#7) - Track per-action manual completion count in `GameState`. - After first manual completion, action becomes **automatable** (toggle or auto-enqueue repeat — pick enqueue-repeat for M1 simplicity). - Automation respects costs; stops if unaffordable (document behavior). - In-fiction story beat references automation (content in T3.3). *Verify:* tests — locked before first completion, unlocked after; automated repeats fire. ### T3.2 — First prestige reset (#8) - Prestige trigger: story node or dedicated action at arc end. - Reset: clear run resources, queue, active action; **retain** `prestigeLayer`, `knowledgeFlags` / `seenStoryNodeIds`, automation unlocks. - Catch-up: known story nodes fast-forward (skip prose or abbreviated passage — implement minimal fast-forward for M1). - `prestigeCount` increment; new prestige/story fields added to runtime + save payload in PR3 (still `SAVE_VERSION=1` until PR4); PR4 bumps version and ships v1→v2 migration. *Verify:* tests — reset clears run state, retains knowledge; second run skips/fast-forwards seen nodes; browser full arc → prestige → new run starts faster. ### T3.3 — Opening arc content (#11) - Replace stub resources/actions/story graph with vault-approved opening arc from `Idlegame/Story/Outline.md`. - Encode prose into `src/content/` story defs; link vault note in PR description. - Branch choice must **matter** (different content, not flavor-only — per GDD). *Verify:* content schema tests; ginnoir in-app text review; vault cross-link present. ### PR3 integration verify Full pre-PR chain. Playtest: start → branch → automation unlock → prestige → second run with catch-up. File brief playtest notes in vault. **PR:** link `Closes #7`, `Closes #8`, `Closes #11`. --- ## PR4 — Polish & close (`feat/m1-polish`) **Primary tools:** Codex (T4.1 save), Antigravity (T4.2 mobile), Claude Code + ginnoir (T4.3 balance). **Gitea closes:** #9 Save migrations and import/export UX, #10 Mobile layout pass, #12 Balance pass. ### T4.1 — Save migrations and import/export UX (#9) - Bump `SAVE_VERSION` to 2; implement v1→v2 migration (add new fields with sane defaults). - Migration registry pattern for future versions. - Settings UI: export save string (copy), import with validation + explicit confirm (overwrite). - Tampered import rejected with user-visible error. *Verify:* migration unit tests; tamper rejection; browser export → clear storage → import → state restored. ### T4.2 — Mobile layout pass (#10) - 375px viewport: no clipping/overlap; touch targets adequate; story panel + queue usable one-handed. - Desktop unchanged unless fixes apply globally. *Verify:* Antigravity screenshots desktop + mobile; core flow works on mobile viewport. ### T4.3 — Balance pass (#12) - Tune action durations, resource rates, choice cadence, time-to-first-prestige for semi-active pacing (~few-minute choice cadence target from GDD). - Document tuning rationale in vault (`Idlegame/Decisions.md` or new `Idlegame/Balance/M1.md`). *Verify:* timed playtest observations recorded; ginnoir sign-off on feel. ### T4.4 — Milestone close - Update `Idlegame/_Claude.md` session log; GDD milestone map (M1 complete, M2 TBD). - Close Gitea milestone **M1 Vertical Slice**; ensure #3–#12 closed. - README current-scope blurb → M1 complete. *Verify:* vault updated; Gitea milestone closed; `main` deploy green. ### PR4 integration verify Full pre-PR chain. Final playtest on `idlegame.ginnoir.com`. **PR:** link `Closes #9`, `Closes #10`, `Closes #12`. --- ## AI tool routing (M1) One tool per branch at a time. Default: phase owner merges before next phase starts. | Phase / task | Tool | Model tier | Why | |---|---|---|---| | Phase 0 outline + prose | Claude Code | Opus 4.8 | Story/design lane | | PR1 T1.x | Codex | GPT-5.5-Codex medium | Scoped engine + TDD | | PR2 T2.1–T2.2 | Codex | GPT-5.5-Codex medium | Story graph engine | | PR2 T2.3–T2.5 | Antigravity | Gemini 3 Pro | Browser verification | | PR3 T3.1–T3.2 | Codex | GPT-5.5-Codex highest | Prestige = state integrity surface | | PR3 T3.3 | Claude Code | Opus 4.8 | Vault prose → content defs | | PR4 T4.1 | Codex | GPT-5.5-Codex medium | Save migration discipline | | PR4 T4.2 | Antigravity | Gemini 3 Pro | Mobile screenshots | | PR4 T4.3 | Claude Code + ginnoir | Opus 4.8 / chat | Balance + playtest feel | | Ginnoir review gates | Cursor / chat | Composer 2.5 | Phase 0 prose, balance sign-off | Cursor is the interactive lane for scoped tweaks anytime ginnoir is driving. ## Error handling expectations - Invalid saves, content, or import strings: **fail explicitly** at boundary with clear errors (existing M0 pattern). - Unknown action/story node ids: throw in engine API (dev-time content errors, not player-facing soft-fail). - Migration failure: reject load, preserve prior save if possible, surface message in UI. ## Testing expectations - New engine behavior: unit tests required; maintain ≥80% coverage on `src/engine/`. - UI phases: browser smoke required (Antigravity or manual); Playwright deferred post-M1. - Each PR runs the full pre-PR verification chain before merge. ## Out of scope (M1) - Playwright E2E suite - Second prestige layer or new mechanics between layers - Cloud saves / accounts - Public playtest (internal-only Caddy remains) - Art pipeline, battle screen, i18n - Steam/Tauri / Capacitor wraps ## Gitea issue index | Issue | Title | Phase | |---|---|---| | #3 | Engine tick and offline hardening | PR1 | | #4 | Resource and action definition set | PR1 | | #5 | Action queue UI | PR2 | | #6 | Story graph and first branch | PR2 | | #7 | Automation unlock | PR3 | | #8 | First prestige reset | PR3 | | #11 | Opening arc content | PR3 | | #9 | Save migrations and import/export UX | PR4 | | #10 | Mobile layout pass | PR4 | | #12 | Balance pass | PR4 | Plane epics (Vertical Slice, Game Design) link these issues by URL — no Plane task duplication required during execution. --- *Brainstorm approved by ginnoir 2026-06-11. Next step after spec review: invoke `writing-plans` for task-level implementation plans per PR if desired, or begin Phase 0 / PR1 directly via `executing-plans`.*