Files
idlegame/docs/architecture.md
T

102 lines
4.0 KiB
Markdown

# Architecture
Idlegame is split into four layers.
## Engine
`src/engine/` contains deterministic gameplay logic:
- `tickLoop.ts`: fixed-timestep accumulator. Large elapsed deltas, including
offline catch-up, drain through the same tick path as active play.
- `game.ts`: core game state, action queue, costs/unlocks on start, completion-driven
queue advancement (actions do not auto-repeat when the queue is empty).
- `save.ts`: versioned save schema, serialized export/import strings, and
offline elapsed calculation.
- `story.ts`: story graph traversal, triggers (boot, actionComplete,
minResources), choices, outcomes.
- `num.ts`: branded numeric boundary and human-readable formatting.
The engine must stay pure. It does not import React, Zustand, browser APIs,
storage, requestAnimationFrame, or Date scheduling.
## Content
`src/content/` contains authored definitions validated by Zod. M0 includes one
resource and one timed action. M1 expands this into real resources, actions,
story nodes, automation unlocks, and prestige definitions.
Each action carries a behavior `kind` (`instant`, `loop`, `timed`, `story`,
`context`) and a `group` (`{ id, label }`) used for UI layout. The schema
enforces kind-specific invariants: `timed`/`loop` require `durationMs`, `timed`
requires at least one yield, and `story` requires a `storyChoiceId` linking the
action to a choice on the current story node.
## State
`src/state/` owns environment coupling:
- persistence backend selection: IndexedDB via `idb-keyval`, with localStorage
fallback
- load-on-boot and autosave orchestration
- requestAnimationFrame loop and lifecycle hooks
- mapping engine state to view models
- Zustand store updates for React
- `storyOrchestration.ts`: evaluates triggers after boot/publish/action
completion; maps prefs to panel auto-open.
- Player prefs (`prefs.ts`) in localStorage — not in save v1.
## UI
`src/ui/` renders the view model and calls runtime commands. Components should
not implement gameplay rules.
### Shell layout
PR3 replaces the M0/PR2 single-column overlay with a three-region shell
(`AppShell.tsx`): a left **nav rail** (Play / Story / Settings / About), a
**center** panel for the active tab, and a **right rail** shown on Play
(resources, an inventory placeholder, and an optional event log gated by the
`showEventLog` pref). `store.activePanel` selects the center panel; there is no
modal overlay. New story beats raise a nav badge (`storyHasUnread`), and
`storyOpenMode: auto` switches to the Story tab instead of opening an overlay.
### Action kinds
Play organizes actions into **columns by behavior kind**, ordered
`instant → loop → timed → story → context`, with collapsible theme **groups**
inside each column (collapse state persists in `prefs.collapsedActionGroups`).
The pure engine dispatches each kind through `performAction` (`game.ts`):
`instant` applies costs/yields immediately, `timed` enqueues, `loop` toggles an
entry in `enabledLoopActionIds` (an idle runner starts the highest-priority
affordable loop only when the queue is empty and only during live ticks, never
offline), and `story` applies the linked choice. Story forks are taken **only**
through Story-kind actions; the Story tab itself is read-only.
### Story tab
`StoryView.tsx` is a read-only 60/40 split: a branching `StoryTree` built from
the story graph's choice/trigger edges (seen paths emphasized, unseen dimmed) and
a scrollable `StoryProseLog` with no choice buttons. The boot intro shows a
single Continue affordance that advances `boot_intro → fork_choice`; thereafter
progression is driven by Story-kind actions.
The full design lives in `docs/superpowers/specs/2026-06-11-m1-pr3-shell-ui-design.md`.
## Verification
Run the full local gate before pushing:
```powershell
pnpm typecheck
pnpm lint
pnpm test:coverage
pnpm build
```
Rendered checks for the walking skeleton:
- app loads without framework overlay or console errors
- starting the timed action increments Gold after completion
- reload preserves saved state
- reopening after time away credits offline progress