Files
idlegame/docs/plans/2026-06-11-m1-vertical-slice.md
ginnoir 203478268c
CI / verify (push) Successful in 1m31s
CI / verify (pull_request) Successful in 1m2s
docs(m1): add PR3 shell UI spec and implementation plans
Capture the PR3 UX brainstorm: three-region shell, action columns by kind, story-via-actions, Story tab tree+log, and universal automation with shareable recipes. Includes T3.0/T3.1 implementation plans and M1 vertical slice plan. Also ignore local .worktrees/.
2026-06-11 20:01:30 -05:00

343 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 PR12; stub prose proves branch mechanics; **ginnoir review gate** before PR3 merges real content |
| Stub content | Placeholder names/prose allowed in PR12; 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 PR12)
**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**, **45 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.1T2.2 engine), Antigravity (T2.3T2.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<string, boolean>`, `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.1T3.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.1T2.2 | Codex | GPT-5.5-Codex medium | Story graph engine |
| PR2 T2.3T2.5 | Antigravity | Gemini 3 Pro | Browser verification |
| PR3 T3.1T3.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`.*