Files
TheLastGarden/.planning/research/SUMMARY.md
T

34 KiB
Raw Blame History

Project Research Summary

Project: The Last Garden Domain: Browser-based narrative idle game (cozy + narrative + idle Venn) — 7-Season prestige arc with AI-assisted asset pipeline, solo/small-team production Researched: 2026-05-08 Confidence: HIGH (stack, features, architecture, save/persistence pitfalls); MEDIUM (AI-pipeline practice, monetization timing, modding posture)


Stack at a Glance

Decisive, opinionated answer. Do not re-litigate in later phases.

Concern Choice Rationale (one line)
Engine Phaser 4 (v4.1.0+ "Salusa") Active stable line in 2026; rebuilt WebGL renderer; ships an official npm create @phaserjs/game@latest React + Vite + TypeScript template that removes ~6 months of "build the engine before the game" work.
Language TypeScript 5.6+ A 7-Season game with save migrations across years is TypeScript-mandatory.
Bundler / Dev Server Vite 6.x (Vite 8 + Rolldown when it lands) ~1.2s cold start vs Webpack ~7s; ships in Phaser 4's official template.
UI Framework React 19 (DOM overlay, owns the chrome) Narrative-cozy audience uses screen readers, copy-paste, browser zoom — canvas-native text fights all of it. Phaser owns the canvas; React owns the UI shell.
State Bridge Zustand 5.x Single canonical state tree; framework-agnostic; ~1KB; no Redux ceremony. Bridges Phaser scenes ↔ React UI.
Numbers break_eternity.js 2.1.3 TypeScript-native, drop-in successor to break_infinity, supports very small values. Choose day one — retrofitting BigNumber after Season 2 is misery.
Narrative Tooling Ink + inkjs Writer authors .ink in the free Inky editor; runtime streams compiled JSON. Battle-tested for browser narrative (80 Days, Heaven's Vault). Highest-leverage decision in the content pipeline.
Save Format IndexedDB (via idb) primary + localStorage fallback, lz-string compressed, versioned {schemaVersion, payload, checksum} Idle saves grow with fragments; multi-layer write survives Safari periodic eviction and Chrome storage-pressure eviction. Always-on navigator.storage.persist().
Audio Howler.js 2.2.4 for music + ambience crossfade; Phaser's native audio for SFX Splits the persistent cello/ambience bed (Howler) from per-scene SFX (Phaser). Howler abstracts the iOS-Safari "must touch first" gotcha.
Content Pipeline YAML + Markdown+frontmatter (gray-matter) + .ink files in /content/, Zod-validated, compiled per-Season at build time Writers work in plain text; build fails on schema violations; per-Season chunks lazy-loaded at runtime. Scales to thousands of fragments without a CMS.
AI Asset Pipeline Pinned model + locked checkpoint + persisted provenance per asset ({model_id, checkpoint_hash, prompt, seed, sampler, params}) + locked 1020 painting "north star" reference set + mandatory human curation gate Style drift across a 7-Season multi-year project is near-certain without this discipline.
Animation Frame-sequence PNG atlases (TexturePacker) for ~all plants; Spine + spine-phaser 4.2 only for the 3 named characters if skeletal becomes necessary Watercolor washes don't rig well; image sequences are honest with the medium. Don't add Spine in v1 unless a specific scene demands it.
Persistence Backup Save export/import (Base64 text) shipped at v1 Cheapest insurance against browser eviction; standard idle-genre expectation.
Monetization Backend Cloudflare Worker + KV (or Supabase) + Stripe Checkout, server-authoritative entitlements Defer until v1.x — ship the game first, monetization second.
Cloud Save Defer to v1.x (PocketBase if/when needed) Lineage games shipped without cloud saves; local-first is fine for launch.
Tests Vitest for sim/economy/migrations; Playwright for e2e smoke The non-rendering parts of an idle game must be unit-tested.

Reconciled Conflict: Rendering Layer

STACK.md and ARCHITECTURE.md examples disagreed on the canvas tech (Phaser vs PixiJS). Resolution: Phaser 4 wins, decisively. STACK.md was more deeply versioned and made the stronger case (active stable line, official React+Vite+TS template, framework-not-just-renderer, Spine-Phaser 4 runtime, mature audio/asset/scene/tween systems out of the box). ARCHITECTURE.md's three-layer firewall pattern (simulation → application → presentation) is renderer-agnostic and survives the swap intact. Read its PixiJS examples as illustrative; substitute Phaser 4 throughout.

Operative rule for all future phases:

  • Phaser owns the canvas — garden, plants, weather, particles, watercolor post-process, Memory Storms.
  • React 19 owns the UI shell — HUD, journal, dialogue overlays, fragment viewer, settings, shop, Keeper's Journal.
  • Zustand bridges them.
  • The simulation core is rendering-agnosticsrc/sim/ does not import from src/render/ or src/ui/. Enforce with ESLint boundaries.

If a specific watercolor shader needs more than Phaser 4's filter system supports, an auxiliary PixiJS render layer is allowed (Phaser 4's renderer is PixiJS-compatible at the WebGL level), but this is an escape hatch, not the plan.


Executive Summary

The Last Garden is three games stacked in a trenchcoat — an idle simulation with offline catch-up, a content-heavy narrative with hundreds of authored fragments and three character arcs, and a watercolor-and-cello aesthetic surface. The job of the architecture and stack is to keep these concerns from colonizing each other. All four researchers converged independently on the same broad shape: a pure, headless, deterministic simulation core that knows nothing about the renderer or DOM, a reactive store (Zustand) bridging simulation and presentation, authored content as a build artifact (not code) validated by Zod schemas and compiled per-Season, and multi-layer versioned saves with mandatory navigator.storage.persist() and migration framework day one. The recommended stack — Phaser 4 + React 19 + Vite + TypeScript + Zustand + Ink + Howler + break_eternity.js + IndexedDB — is the only combination that satisfies all four pulls (rendering fidelity, narrative density, idle-loop discipline, AI-friendly content pipeline) without inventing infrastructure.

The single biggest risk is scope: a solo / small-team commitment to seven authored Seasons over multiple calendar years. PITFALLS.md flags this as the project-killer ahead of every technical concern. Closely behind: the structural risk that the story ends but the idle loop doesn'tA Dark Room and Universal Paperclips succeeded specifically because they ended; the temptation to graft "endless prestige" onto a finite story will undermine the thematic argument the game exists to make. Other critical risks cluster into a small, well-understood set: save persistence fragility in browsers (Safari eviction, Chrome storage-pressure, private-browsing failures), system-clock cheating that fast-forwards through authored content, AI-asset style drift across model generations, FOMO mechanics that violate cozy tone, the Web Audio user-gesture requirement breaking the cello at first impression, and the canonical content/code divergence trap for narrative games.

The roadmap implication is unanimous across all four researchers: Phase 1 must be foundation infrastructure — engine bootstrap + versioned save persistence + content pipeline + AI asset pipeline discipline + tonal doctrine — before any Season-content authoring scales. Save versioning, fragment IDs, asset provenance, and the anti-FOMO doctrine are all retrofit-hostile decisions; they cost ~10 lines on day one and weeks of recovery work after Season 2 ships. The recommended escape hatch on the 7-Season scope commitment is to ship Season 1 publicly as a free, complete-feeling standalone experience that earns the budget and audience for Seasons 27 — PROJECT.md commits to v1 having all 7 Seasons but does not preclude shipping Season 1 first as a free prologue. Use that loophole.


Key Findings

See Stack at a Glance above for the full opinionated table. Confidence is HIGH on engine + numeric + audio + bundler + state + narrative tooling; MEDIUM on the specific animation runtime (Spine vs PNG sequences — defaulting to PNG for v1) and exact content-pipeline tools (gray-matter is interchangeable; the shape is the recommendation); LOW on cloud-save backend choice (defer to v1.x).

Core technologies (one line each):

  • Phaser 4 — Canvas/WebGL framework: scenes, asset loader, tweens, particles, audio, input. Removes ~6 months of "build the engine before the game" work.
  • React 19 — UI shell for narrative chrome (HUD, journal, dialogue, settings). Required for accessibility, screen readers, and copy-paste of fragments.
  • Vite 6 + TypeScript 5.6 — Dev server with ~1.2s cold start; type-safety mandatory for save migrations and content schemas.
  • Zustand 5 — Single store bridging Phaser scenes and React UI. Tiny, framework-agnostic, no boilerplate.
  • break_eternity.js — Big-number library for prestige economies. Pick day one; retrofitting after Season 2 is rewriting every formula.
  • Ink + inkjs — Branching narrative scripting language with mature web runtime. Writer-friendly authoring tool (Inky), engineering-friendly compiled-JSON runtime.
  • Howler.js — Layered, crossfading music + ambience. Handles iOS Safari autoplay-policy gotchas the cello cannot afford to trip.
  • IndexedDB (via idb) + lz-string + Zod — Multi-layer compressed versioned saves with runtime schema validation. The single most defensive system in the project.

Expected Features

Must have (table stakes — players bounce or one-star without these):

  • Core idle loop (plant / wait / harvest memory fragments)
  • Offline progression simulation with sensible cap (24h recommended)
  • "While you were away" return screen — delivered as a letter from the garden, not a stat dump (tonal differentiator on a baseline feature)
  • Save persistence (IndexedDB primary, localStorage fallback, multi-layer, versioned, navigator.storage.persist() called)
  • Save export / import (Base64 text) — non-negotiable for browser idle games
  • Settings menu with separate music / SFX / ambient sliders, master mute keybind, reduced-motion respect
  • Tab visibility-aware tick logic (elapsed-time-based progression, not setInterval ticking)
  • Multi-buy (x1 / x10 / x100 / Max) for any scaling purchase
  • Numeric formatting (K / M / B / scientific notation)
  • FTUE that respects the player (A Dark Room rule: one button at start, expand only when ready)
  • Accessibility baseline: keyboard nav, text scaling, color-blindness icon redundancy, reduced motion
  • Tab title / favicon as background indicator
  • All 7 authored Seasons of content (PROJECT.md commitment)
  • Three character arcs (Lura, Nameless Man, Archivist) and the final binary choice
  • Roothold prestige currency (story-bible-locked)
  • Watercolor + cello aesthetic, palette-shifted by Season

Should have (differentiators — the moat):

  • Mechanic-as-metaphor design discipline (composting = letting go, prestige = grief, Roothold = what survives)
  • Discovery-driven progression with no roadmap (A Dark Room / Paperclips lineage)
  • Authored memory fragment system (every harvest = a piece of writing)
  • Place-memory vignettes (Season 3+) — short interactive scenes
  • Memory Storms (Season 4+) — event mechanic with narrative weight
  • Cross-pollination + ecosystem planting (Season 5+) — true late-Season depth curve
  • Letter-style "while you were away" return narration
  • Episodic free additive content patches post-launch (Hollow Knight model)

Defer to v1.x (genuine value, not launch-gating):

  • Cosmetic monetization catalog (planters, walls, gates, tool skins) — requires asset pipeline maturity; ship game first
  • Premium Keeper's Journal (annotations layer)
  • Season acceleration purchase
  • PWA / installability + opt-in push notifications for Memory Storms only
  • Cloud save sync

Defer to v2+:

  • Steam port
  • Mobile native ports
  • Localization (defer the translation; do NOT defer string externalization)
  • Garden visiting / limited social
  • Voiced moments (only if cello-and-silence soundscape benefits)
  • Modding (architecture leaves the door open; don't promise it)

Anti-features (do NOT build, hard thematic constraints): Gacha, lootboxes, narrative gating behind purchase, Season skipping (vs accelerating), daily login bonuses, streaks, energy/stamina, rewarded ads, push-notification spam, lore codex / encyclopedia, generic fantasy flora, combat / boss fights, multiplayer/social/leaderboards (v1), voiced dialogue (v1), always-online, named/personality-rich Keeper, hint system / objective tracker, time-skip purchases that bypass real-time-as-metaphor.

Architecture Approach

Three-layer firewall: Simulation Core (pure, headless, renderer-agnostic) → Application Layer (Zustand store + command bus + event bus) → Presentation Layer (Phaser canvas for the diegetic world + React DOM for the UI chrome), with a fourth crosscutting Data/Persistence Layer (Content Repository, Save Repository, Asset Manifest, Telemetry, Entitlements) and a build-time Content Pipeline (YAML/Ink/Markdown → Zod validation → compiled per-Season JSON).

Major components:

  1. Tick Scheduler + Offline Catch-up Engine — Fixed-timestep accumulator at 410 Hz. The same simulate(state, dtMs, commands) → {state, events} function runs live ticks and offline catch-up (capped at 24h, with silent: true flag to suppress per-tick audio/particles during catch-up).
  2. Garden Sim / Economy / Season-Prestige State Machine / Memory Fragment Selector / Story Trigger Engine — Pure modules of typed state and pure functions. No DOM, no Pixi, no fetch. This is the architectural firewall.
  3. Game Store (Zustand) — Reactive snapshot of simulation state. UI binds via selectors. Receives state, never owns logic.
  4. Command Bus + Event Bus (mitt) — Commands flow down (user action → next-tick simulation); events flow laterally (simulation emits → audio + particles + story triggers + telemetry subscribe).
  5. Render layer (Phaser scenes) — Garden, plants, particles, watercolor post-process, ambient effects.
  6. UI layer (React DOM overlay) — HUD, fragment journal, dialogue cutscene player, shop, settings, accessibility menu.
  7. Story Cutscene Player + inkjs runtime — Drives modal dialogue from compiled Ink JSON; sets simulationPaused flag during cutscenes; tied to Zustand variables so narrative branches react to game state.
  8. Audio Manager (Howler.js) — Music bus (cello), ambient bus (garden / Pale silence), SFX bus. Crossfades across Season transitions.
  9. Save Repository — Debounced multi-layer writes (IndexedDB primary, localStorage fallback). Format: {schemaVersion, payload, checksum}. Forward-migration chain migrate_v1_to_v2 → .... Snapshot-before-migrate backups (last 3 retained).
  10. Content Repository + Build Pipeline — Authored sources in /content/, schema-validated with Zod, compiled to per-Season JSON, lazy-loaded at runtime.
  11. Entitlements (server-authoritative, deferred) — Cloudflare Worker + Stripe webhooks. v1.x.

The persistence model is event-sourced internally (events drive subscribers), snapshot-stored externally (saves are world snapshots, not event logs) — pure event sourcing replays years of history; pure snapshot loses the rich event stream that decouples audio/UI/story.

Critical Pitfalls

The full ranked list lives in PITFALLS.md (14 critical pitfalls). The five most dangerous structural risks, surfaced for ongoing carry-forward:

  1. The story ends but the idle loop doesn'tThe most dangerous structural pitfall in the entire project. Decide before writing economy code: this game rests like a finished album you can replay; it does not extend with infinite prestige tiers. Author the Season 7 end state first. Cap Roothold to a finite ceiling tied to the narrative argument ("you cannot understand infinitely many things"). Build a credits/coda experience for players who reach the end. Banner concern for every phase.
  2. 7-Season scope eats the solo developer alive — Documented failure mode. PROJECT.md commits to "Full 7 Seasons at v1" but does not preclude shipping Season 1 first as a free standalone prologue that earns the budget and audience for the rest. Use that loophole. Cap Season-introduced mechanics (≤1 new system per Season). Quarterly mandatory kill list. Pre-write all authored content in plain text before serious engineering. Plan personal/financial runway around 57 calendar years.
  3. Save format becomes untenable mid-project — Versioned saves day one. Migration registry. Multi-layer write (IndexedDB + localStorage). navigator.storage.persist() on first save. Snapshot-before-migrate backups. Save export/import as core feature, not power-user feature.
  4. AI-generated asset style drift across Seasons — Pin the model + checkpoint + sampler + library version. Persist provenance per asset. Lock a 1020 painting "north star" reference set hand-selected by the art lead. Mandatory human curation gate on every shipped asset. Visual regression testing across the full library before any model migration.
  5. Players grind past story beats — Story-gate progression, not just currency-gate it. Pace fragments by reading time, not by harvest count. Defend "acceleration ≠ skipping" ruthlessly when economic pressure arises. Show the garden, not the optimization metrics — if the UI surfaces "fragments per hour," players will optimize; if it surfaces "what Lura said yesterday," they'll inhabit.

Watch Out For (Top Pitfalls Banner)

Surfaced for the roadmapper and every downstream phase. Carry these forward:

  • Save persistence fragility in browsers — Safari periodic eviction (WebKit bug 266559), Chrome storage-pressure eviction, private-browsing silent failures, browser-update wipes. Multi-layer + persist() + export feature is the minimum honest answer.
  • System-clock cheating trivializes idle progression — Cap offline progression at 24h. Monotonic timestamp checks; refuse negative deltas. Story beats gate on tick count, not wall time. In a narrative idle, fast-forwarding ruins the story experience itself, not just monetization.
  • AI asset style drift across model generations — A 7-Season project will span model rotations. Pinned models + provenance metadata + locked reference set + curation gate, or the watercolor consistency that the project's premise depends on will fracture irrecoverably.
  • FOMO mechanics violate cozy tone — Anti-pattern doctrine in writing: no daily login bonuses, no streaks, no limited-time content, no nag notifications, no loss-aversion copy. Most pressure to add FOMO comes from monetization anxiety; PROJECT.md already locks the monetization scope — defend it.
  • Web Audio gesture requirement — Cello will not play without a user gesture. First screen must be a hand-painted "Tend the garden" / "Begin" gate that satisfies the gesture and explicitly calls AudioContext.resume(). iOS Safari (including low-power mode) tested before launch. Audio bootstrap is a 1-day fix when planned and a 1-week fire when discovered at launch.
  • Tab throttling breaks setInterval-driven progression — Don't simulate progression with timers. Use elapsed-time clock (f(elapsed_real_time), not f(number_of_ticks_received)). Save on visibilitychange to hidden, beforeunload, and Season transitions. Identical behavior between "tab backgrounded" and "tab closed".
  • Tonal failure — "cozy with weight" becomes "depressing slog" — Each Season requires explicit warm/quiet/heavy/lift pacing beats. External readers (2+) sign off on every Season's tonal balance before integration. Lura is the warmth anchor — write her as the contrast, not a co-griever. Endings matter more than middles; Season 7 must land redemptive, not pyrrhic.
  • Authored content diverges from code — Single source of truth in /content/ in YAML/Ink/Markdown. Stable string IDs (season3.canopy.lura_07.vignette, never fragment_274). All player-visible strings externalized day one — the translation can be deferred to v2; externalization cannot.

Implications for Roadmap

All four researchers converged on the same phase ordering. The cross-file consensus: Phase 1 must be foundation (engine bootstrap + save persistence + content pipeline + AI asset pipeline discipline + tonal doctrine) BEFORE any Season-content authoring scales. Versioning, fragment IDs, asset provenance, and anti-FOMO doctrine are all retrofit-hostile.

Phase 1: Foundations & Doctrine

Rationale: Every later phase is blocked without these. Save versioning, content pipeline, AI provenance, and anti-FOMO doctrine are retrofit-hostile decisions that cost ~10 lines on day one and weeks of recovery work later. Architecture firewall (src/sim/src/render/) must be enforced before any code grows around it. Delivers: Phaser 4 + React + Vite + TypeScript scaffold; ESLint boundaries enforcing the simulation/presentation firewall; versioned save framework with migration registry, multi-layer write, navigator.storage.persist(), and Base64 export/import; content pipeline (YAML/Ink/Markdown → Zod → per-Season compiled JSON); AI asset pipeline (pinned model, provenance metadata, locked north-star reference set, curation gate); written anti-FOMO doctrine; written Season 7 end-state design. Addresses: Save persistence (table stakes), accessibility baseline scaffolding, content-as-data, AI-assisted production constraint from PROJECT.md. Avoids: Pitfall 1 (story-ends-but-loop-doesn't, by deciding the end state up front), Pitfall 3 (save format untenable), Pitfall 5 (AI style drift), Pitfall 8 (storage eviction), Pitfall 9 (FOMO doctrine), Pitfall 10 (content/code divergence), Pitfall 13 (engine choice validated against Season-5 plant-count prototype).

Phase 2: Vertical Slice — Season 1 Core Loop

Rationale: The first Season's economy is the contract for all subsequent Seasons. If Phase 2 ships pure currency-gating, Phases 39 inherit the flaw and retrofit is expensive. Validate the content pipeline end-to-end with real fragments. The simulation-core firewall is stress-tested here. Delivers: Pure deterministic simulation core with fixed-timestep accumulator (410 Hz); offline catch-up engine capped at 24h with silent: true flag; break_eternity.js wrapped in a typed BigQty abstraction; monotonic clock check (refuse negative deltas, system-clock cheat defense); first Season's authored fragments + memory fragment selector; story-gating and currency-gating on progression; first dialogue arc (Lura's introduction) via inkjs; minimal Phaser garden render + React HUD + Zustand store binding; "tend the garden" begin-gesture screen with explicit AudioContext.resume(); Howler.js music + ambient + SFX three-bus mixer; save-on-visibilitychange and on Season transitions; "while you were away" letter-style return screen. Uses: Phaser 4, React 19, Vite, TypeScript, Zustand, break_eternity.js, inkjs, Howler.js, idb + lz-string, Zod, mitt. Implements: Tick Scheduler, Offline Catch-up, Garden Sim, Economy, Memory Fragment Selector, Story Trigger Engine, Game Store, Command/Event Bus, basic Phaser render scene, basic React UI shell, Audio Manager. Avoids: Pitfall 2 (grind past story — story-gating built in from day one), Pitfall 4 (clock cheating — cap + monotonic check shipped together), Pitfall 7 (BigNumber overflow — wrapped abstraction from first economy commit), Pitfall 11 (audio context blocked — begin gate + resume()), Pitfall 12 (tab throttling — elapsed-time clock, no setInterval progression).

Phase 3: Season-Prestige State Machine + Roothold

Rationale: First major test of save migration and content lazy-loading colliding with simulation state machine. PITFALLS.md and ARCHITECTURE.md both flag this as where most things break in practice. Plan for it to take longer than expected. Validates that v1 → v2 save migrations work on real player data shape. Delivers: Explicit 7-Season state machine; Roothold preservation across resets; first save schema migration (Season 1 saves migrate cleanly into Season 2-aware shape); per-Season content lazy-loading; Season transition tonal/audio crossfade; finite Roothold ceiling implementation matching the design-doc end state. Implements: Season/Prestige State Machine, save migration framework activation, per-Season content chunking. Avoids: Pitfall 1 (finite ceiling enforced in code, not just design doc), Pitfall 3 (real first migration shipped and tested).

Phase 4: Watercolor + Cello Polish (Aesthetic Layer)

Rationale: Visual + audio polish layer once the core loop is visible and stable. Don't block earlier phases on shaders. The aesthetic is the moat per FEATURES.md. Delivers: Watercolor post-process shader (Phaser 4 filter system); particle systems for memory motes, growth animations, ambient drift; per-Season palette + audio bed crossfading; Pale rendered as overexposed white silence with high-tone audio; texture-atlas-packed plant sprites; reduced-motion option respecting prefers-reduced-motion. Avoids: Pitfall 13 (DOM-heavy garden — confirmed Phaser canvas is in use everywhere it should be), Pitfall 14 (tonal calibration — palette and audio shifts shipped per Season's pacing schedule).

Phase 5: Seasons 27 Content Authoring + Mid-Season Mechanics

Rationale: Content production is its own track once the pipeline is proven through Season 1. Each Season adds at most ONE new mechanic per the scope-defense doctrine. Parallelizable with later engineering tracks. Delivers: Authored fragments and dialogue for Seasons 27; place-memory vignettes (Season 3+); Memory Storms (Season 4+); cross-pollination + ecosystem planting (Season 5+); Lura/Nameless Man/Archivist arc completion; final binary narrative choice (Season 7); credits/coda rest-state experience. Avoids: Pitfall 6 (scope death — quarterly kill list active, mechanics capped), Pitfall 14 (tonal failure — external reader gate before each Season's integration).

Phase 6: Monetization + Backend (v1.x)

Rationale: Independent system; cosmetics don't affect core loop. Ship the game first per FEATURES.md guidance — monetization at launch breeds distrust in the cozy-narrative audience. Server-authoritative entitlements are mandatory (localStorage entitlements = DevTools makes everything free). Delivers: Cloudflare Worker + Stripe Checkout + webhooks → entitlements DB; cosmetic catalog (planters, walls, gates, tool skins — garden-coherent only); Premium Keeper's Journal with annotation layer; Season acceleration purchase (accelerates waiting, never skips content). Avoids: Pitfall 9 (FOMO — cosmetic catalog with fixed prices, never gacha; Season acceleration cannot bypass real-time-as-metaphor).

Phase 7: PWA + Cloud Save + Polish (v1.x)

Rationale: "Live with it" affordances after launch validates demand. Cloud save resolves the cross-device gap once a real audience exists. Delivers: PWA manifest + service worker; opt-in push notifications limited to Memory Storm events only; PocketBase (or equivalent) cloud save sync; additional place-memory vignettes as free additive content patches (Hollow Knight model).

Phase 8: Accessibility Audit + Performance + Optional Web Worker Offload

Rationale: Polish, validate, ship beyond v1. The simulation core was designed pure/headless precisely so this offload is a one-day refactor when needed. Delivers: Accessibility audit (keyboard nav, screen reader, contrast, motion); performance profiling (Season-5 plant count at 60fps on oldest target hardware); Web Worker offload for the simulation if profiler demands it; mobile testing on actual iOS Safari + Android Chrome devices.

Phase Ordering Rationale

  • Save/load (Phase 1) before render (Phase 2's render slice): Counterintuitive, but you don't want to discover save bugs after building three Seasons of art. The simulation can be validated headlessly.
  • Content pipeline (Phase 1) before Season 1 fragments (Phase 2): Same reason. If the schema is wrong, every Season's content needs rework.
  • AI asset pipeline discipline (Phase 1) before any production-volume asset generation: Style drift is irreversible at scale; the discipline must precede the volume.
  • Tonal doctrine + Season 7 end-state (Phase 1) before any economy code: PITFALLS.md ranks the "story ends but loop doesn't" pitfall as the most dangerous structural risk. Must be designed first.
  • Vertical slice (Phase 2) before Season machine (Phase 3): Validate the loop and the contract before generalizing to 7 Seasons.
  • Aesthetic polish (Phase 4) after the core loop works: The watercolor shader is the moat, but it's not what makes the loop function — sprite-flat-color is fine for Phases 13 if it lets the simulation get right.
  • Content authoring (Phase 5) parallelizable with later engineering tracks: Once the pipeline is proven, the writer can run independently.
  • Monetization (Phase 6) deferred: Ship the game first; monetization second. PROJECT.md and FEATURES.md both endorse this.
  • PWA + cloud save (Phase 7) deferred: Demand validation first; infrastructure second.

Confidence Assessment

Area Confidence Notes
Stack HIGH Engine, language, state, numbers, audio, narrative tooling all decided with strong source coverage. MEDIUM only on animation runtime (Spine vs PNG sequences — defaulting to PNG for v1) and exact content-pipeline tool names (gray-matter is interchangeable; the shape is the recommendation). LOW on cloud-save backend (deferred to v1.x by design).
Features HIGH Genre conventions are well-codified; PROJECT.md is unusually opinionated about tone, which makes the differentiator-vs-anti-feature line unusually clear. The load-bearing judgment was tonal alignment, which the source material strongly supports.
Architecture HIGH Idle-game patterns (pure sim, fixed timestep, snapshot persistence, event bus) are well-documented; narrative-engine integration patterns (Ink runtime + cutscene player) are well-documented. The combination is opinionated extrapolation — MEDIUM on the specific bridge between Phaser scenes and React UI, but the broad shape is settled.
Pitfalls HIGH Save/persistence/browser pitfalls are HIGH (well-documented post-mortems and platform docs). Idle game balance pitfalls are HIGH (codified in incremental-game community). Narrative-idle pacing is MEDIUM-HIGH (small-N genre, but specific evidence). AI-pipeline pitfalls are MEDIUM (rapidly evolving practice, fewer post-mortems). Cozy-tone and solo-scope pitfalls are HIGH.

Overall confidence: HIGH. The stack is decisive, the architecture is defensible, the feature scope is bounded by an unusually clear PROJECT.md, and the pitfalls are concrete enough to gate against in roadmap design.

Gaps to Address During Planning

  • Specific AI asset model + licensing: STACK.md and PITFALLS.md agree on the shape (pinned model, provenance, curation, locked reference set) but the specific vendor (Stable Diffusion fine-tune, Scenario, Layer, Midjourney with a licensed agreement, custom-trained LoRA) needs research and legal review during Phase 1.
  • Exact tick rate (410 Hz range): ARCHITECTURE.md recommends 410 Hz; the right value depends on Season-5 plant-count prototype performance. Pin during Phase 1 prototype.
  • Cloud save backend choice: PocketBase recommended if ≤10K MAU; Supabase if scaling further. Decide based on real player data — local-only is fine for v1 launch.
  • Spine vs PNG sequences for the 3 named characters: Default is PNG sequences for v1 (watercolor doesn't rig well). Reconsider per-character if a specific scene demands skeletal motion.
  • Ethical Season acceleration UX: The line between "accelerates waiting" and "skips content" needs concrete UI specification before Phase 6. Get a doctrine doc before code.
  • Anti-FOMO doctrine: Drafted in PITFALLS.md as a list; needs to be written into a project doctrine document in Phase 1 and referenced at every monetization / engagement design review.
  • Telemetry: Plausible vs PostHog: Either works. Plausible is the cozier-genre fit; PostHog if funnels are needed. Defer until launch nears.

Sources

Primary (HIGH confidence)

Stack: Phaser 4 release notes (v4.1.0 "Salusa", Apr 2026); Phaser CLI / @phaserjs/create-game template; break_eternity.js v2.1.3; Howler.js v2.2.4; inkjs; Spine-Phaser 4 runtime.

Architecture: Fix Your Timestep! (Gaffer On Games); The Idle Game Illusion: How Delta-Time Powers Progress; Anatomy of a video game (MDN); Use Web Workers off the main thread (web.dev); Inkle Ink; Zustand; Event Sourcing (Martin Fowler).

Features: A Dark Room design philosophy (Wikipedia, TV Tropes); Universal Paperclips (stages wiki); Cookie Clicker prestige system; Future of Idle Games (gamertagguru).

Pitfalls: The Math of Idle Games, Part III (Kongregate); WebKit Bug 266559 (Safari periodically erasing storage); Heavy throttling of chained JS timers in Chrome 88; Web Audio Autoplay Policy and Games (Chrome for Developers); Why Scope Is the Most Dangerous Enemy of Indie Games; Scope Creep: The Silent Killer of Solo Indie Game Development.

Secondary (MEDIUM confidence)

Vite / Webpack 2026 benchmarks; State management 2026 comparisons; PocketBase / Supabase comparison; Cuphead frame-sequence pipeline reference (cited for pattern, not engine); Plausible vs PostHog comparison; Game-localization retrofit cost discussions; Scenario / Layer / Sloyd writeups on AI-asset style drift.

Tertiary (LOW confidence)

Modding for browser idle games is rare in the wild; recommendations are "leave the door open without paying for it" rather than empirically validated. Specific cloud-save backend choice deferred to post-launch validation against real player numbers. Exact tick-rate within the 410 Hz recommended range will require Phase 1 prototype confirmation.


Research completed: 2026-05-08 Ready for roadmap: yes