Project: Signal Processing Puzzle Game Date: 2026-02-04 Stack: Canvas 2D + React 19 + Zustand + TypeScript + Vite
The original game is fully implemented. A comprehensive UX redesign has been planned and architectured. Architecture validation (Step 1) and epic/story updates (Step 2) are complete. The next step is to check implementation readiness (Step 3) and then begin sprint planning (Step 4).
All 4 epics are complete. 505 tests passing across 34 test suites.
Nodes, wires, Canvas rendering, palette, waveform visualization, WTS timing.
Puzzle loading, continuous validation, formula baking, completion ceremony, baked node runtime.
Zoom navigation, zoom transitions, breadcrumbs, utility nodes, library sync.
45+ levels across 4 arcs, save/load, undo/redo, progression system.
| Module | Files | Status |
|---|---|---|
engine/ |
21 | Complete -- nodes, graph, baking |
puzzle/ |
23 | Complete -- levels, validation, waveform generators |
store/ |
21 | Complete -- 9 Zustand slices, persistence, hot-replace |
gameboard/ |
12 | Complete -- Canvas rendering, hit-testing |
shared/ |
9 | Complete -- types, math, logger, Result |
wts/ |
7 | Complete -- clock, tick scheduler |
ui/ |
8 | Complete -- controls, puzzle UI, navigation |
palette/ |
3 | Complete -- panel, node definitions |
simulation/ |
1 | Complete -- simulation controller |
debug/, validation/, persistence/, progression/, assets/styles/
These have directory structures but no files. Their functionality either lives inline in store slices or is deferred to the redesign.
The redesign replaces the sidebar-based UI with a full-screen immersive experience. No new npm dependencies. Everything is pure TS + Canvas 2D + CSS Modules on the existing stack.
| # | Decision | Summary |
|---|---|---|
| 1 | Auto-Routing | A* pathfinding on 64x36 grid (H/V/45-degree only) |
| 2 | Analog Meters | Three-channel Canvas meters with circular buffer |
| 3 | Lid Animation | Vertical clamshell double-door zoom transition |
| 4 | Token Cache | Flat typed object, CSS vars read once per theme switch |
| 5 | Wire Rendering | Polarity color gradient + peak glow beyond +/-75 |
| 6 | Viewport | 16:9 locked, 64x36 grid (doubled density), letterboxed |
| Module | Purpose |
|---|---|
shared/grid/ |
Grid/pixel coordinate types + conversion |
shared/tokens/ |
ThemeTokens type + cache builder |
shared/routing/ |
A* auto-router + occupancy helpers |
gameboard/meters/ |
Three-channel analog meter rendering |
gameboard/animation/ |
Lid, ceremony, zoom draw functions |
gameboard/interaction/ |
Mouse, keyboard, focus, placement ghost |
gameboard/canvas/render-grid.ts |
Grid zone rendering |
assets/styles/tokens.css |
CSS custom properties (source of truth) |
assets/styles/theme-dark.css |
Signal Bench theme |
assets/styles/theme-light.css |
Studio Monitor theme |
assets/styles/animations.css |
Animation tokens (reduced-motion aware) |
store/slices/overlay-slice.ts |
activeOverlay discriminated union |
store/slices/animation-slice.ts |
Lid + ceremony state machines |
store/slices/meter-slice.ts |
Meter state + circular buffer refs |
store/slices/routing-slice.ts |
Wire paths, reroute triggers |
ui/overlays/ |
Modals, popovers, context menus |
ui/layout/GameLayout.tsx |
Top-level layout + overlay host |
All planning documents live in _bmad-output/.
| Document | Location | Status |
|---|---|---|
| Game Design Document | signal_puzzle_game_design.md (root) |
Complete |
| Original Architecture | _bmad-output/game-architecture.md |
Complete |
| Project Context | _bmad-output/project-context.md |
Complete (34 rules) |
| Epics & Stories | _bmad-output/planning-artifacts/epics.md |
Updated (redesign epics 5-7 added) |
| Architecture Validation | _bmad-output/planning-artifacts/architecture-validation-report.md |
Pass (3 moderate, 4 minor) |
| UX Design Spec | _bmad-output/planning-artifacts/ux-design-specification.md |
Complete |
| UX Validation Report | _bmad-output/planning-artifacts/ux-validation-report.md |
Pass |
| Redesign Architecture | _bmad-output/planning-artifacts/architecture.md |
Complete |
| Interactive Demos | _bmad-output/planning-artifacts/architecture-explorations.html |
Complete |
The project is at the boundary between Phase 3 (Solutioning) and Phase 4 (Implementation). The redesign architecture is validated, and epics/stories are updated with redesign scope. Implementation readiness must be verified before sprint planning begins.
Run each workflow in a fresh context window.
Architecture validated. Report at _bmad-output/planning-artifacts/architecture-validation-report.md.
Verdict: PASS with 3 moderate migration-scope findings (Wire type, NodeState position, render layer rewrite)
and 4 minor notes. No changes needed to the architecture document itself.
Epics updated at _bmad-output/planning-artifacts/epics.md. Added:
- 15 new redesign FRs (FR34-FR48), 2 new NFRs (NFR11-12), 6 new ARs (AR14-19)
- Epic 5: Redesign Foundation (5 stories: grid, tokens, type migrations, render loop, grid zones)
- Epic 6: Redesign Signal Visualization (4 stories: meters, auto-routing, wire rendering, node rendering)
- Epic 7: Redesign Interaction & Navigation (5 stories: overlays, palette/popover/context, lid animation, ceremony, keyboard/a11y)
- Redesign impact notes on 8 original stories (1.5, 1.6, 1.7, 1.8, 2.1, 2.2, 2.4, 4.4)
- FR20 updated: victory threshold 2 cycles -> 1 cycle
- Full dependency graph for redesign stories
Implementation readiness assessed. Report at _bmad-output/planning-artifacts/implementation-readiness-report.md.
Verdict: READY with 4 minor advisories (no blockers).
- 100% FR coverage (48/48 FRs mapped to epics/stories)
- 0 forward dependencies, 0 unresolved contradictions
- 4 resolved cross-document contradictions (breadcrumbs, victory threshold, lid animation, Return to Puzzle)
- Advisories: Stories 5.3, 7.2, 7.5 oversized (split during sprint planning); Epic 5 infrastructure-framed
Sprint status generated at _bmad-output/implementation-artifacts/sprint-status.yaml.
- 7 epics, 32 stories total (18 done from original, 14 backlog for redesign)
- Epics 1-4 preserved as done; Epics 5-7 added as backlog
- Recommended 8-sprint sequence respecting dependency graph
- Sprint 1 starts with Stories 5.1 (Grid System) + 5.2 (Token System)
For each story in the sprint plan:
-
Create Story --
/bmad-bmm-create-storyPrepare the story with full implementation details. -
Validate Story (optional) --
/bmad-bmm-create-story(Validate Mode) Independent review of story readiness. -
Dev Story --
/bmad-bmm-dev-storyImplement the story. Write code and tests. -
Code Review (optional) --
/bmad-bmm-code-reviewReview implementation quality. -
Repeat for next story, or run Retrospective at epic boundaries.
Story file: _bmad-output/implementation-artifacts/5-1-grid-coordinate-system-viewport.md
- Created
src/shared/grid/module (types, conversions, constants, viewport, barrel export) - GameboardCanvas: 16:9 viewport lock, letterbox centering, cellSize ref, rAF-debounced resize, too-small warning
- render-loop: getCellSize callback, derives dimensions from GRID_COLS/ROWS * cellSize
- 25 new tests, 530 total passing, zero regressions, TypeScript clean
Story file: _bmad-output/implementation-artifacts/5-2-design-token-system-dual-themes.md
- Created 4 CSS files: tokens.css (27 vars), theme-dark.css (Signal Bench), theme-light.css (Studio Monitor), animations.css (reduced-motion aware)
- Created
src/shared/tokens/module: TOKEN_KEYS (27 keys), TokenKey type, ThemeTokens type, buildThemeTokens(), theme-manager (initTheme/setTheme/getThemeTokens + reduced-motion listener) - Updated main.tsx: imports CSS, calls initTheme('dark') before render
- 21 new tests, 551 total passing, zero regressions, TypeScript clean
Story file: _bmad-output/implementation-artifacts/5-3-core-type-migrations-connection-point-configuration.md
- Wire type migrated: from/to → source/target, signals → signalBuffer ring buffer (16 entries) + writeHead, added path: GridPoint[]
- NodeState.position: Vec2 → GridPoint; all render functions accept cellSize for grid→pixel conversion
- Occupancy grid (boolean[32][18]) added to gameboard slice, maintained on add/remove node
- ConnectionPointConfig type + builder functions for puzzle and custom node gameboards
- VICTORY_CYCLES updated 2→1, Signal type removed, tick scheduler rewritten for ring buffer
- 16 new tests, 568 total passing across 38 suites, zero TypeScript errors
- All 5 draw functions refactored to
(ctx, tokens, stateSlice, ...params)signature - render-loop.ts is sole Zustand bridge: single
getState()+getThemeTokens()per frame - All
COLORSconstants replaced withThemeTokensacross all render files useGameStoreremoved from all draw files (render-nodes, render-wires, render-connection-points, render-waveforms, render-wire-preview)- New files:
render-types.ts(typed state-slice interfaces),render-draw-signatures.test.ts(32 contract tests) - 32 new tests, 600 total passing across 39 suites, zero TypeScript errors
Story file: _bmad-output/implementation-artifacts/5-5-grid-zone-background-rendering.md
- Created
src/gameboard/canvas/render-grid.tswithdrawGrid(ctx, tokens, state, cellSize) - Renders 3 zone backgrounds: playable area (gridArea), left meter zone (meterHousing), right meter zone (meterHousing)
- Draws vertical grid lines in playable area (cols 3-28) and horizontal lines across full gameboard
- Supports gridOpacity for zoom animation dimming; restores globalAlpha after draw
- Integrated into render-loop.ts as first draw call (lowest z-order, after canvas clear)
- Added RenderGridState interface to render-types.ts
- 21 new tests (16 unit + 5 contract), 621 total passing across 40 suites, zero TypeScript errors
All 5 stories in Epic 5 (Redesign Foundation) are done. Next: Epic 6 (Redesign Signal Visualization).
- Created
src/gameboard/meters/module: meter-types.ts (constants, types, MeterKey), circular-buffer.ts (Float64Array(128) ring buffer), barrel index.ts - 5 render functions: render-waveform-channel.ts (scrolling polarity-colored fill with 3-stop opacity), render-level-bar.ts (center-outward bar), render-needle.ts (glow line), render-target-overlay.ts (dashed stroke), render-meter.ts (compositor with channel layout ratios)
- Created
src/store/slices/meter-slice.ts: MeterSlice with initializeMeters, setMeterVisualState, resetMeters actions - Integrated into store/index.ts (GameStore union), simulation-controller.ts (meter buffer init/record/clear + initializeMeters call), render-loop.ts (meter drawing after grid with derived confirming/mismatch visual states)
- Added RenderMetersState to render-types.ts; extended contract tests in render-draw-signatures.test.ts
- 22 new tests (8 circular-buffer, 7 meter-slice, 5 render-meter, 2 contract), 643 total passing across 43 suites, zero TypeScript errors
- Created
src/shared/routing/module: grid-graph.ts (8-direction constrained graph, passability, Chebyshev heuristic), auto-router.ts (A* pathfinding with direction-tracking state space, binary min-heap PQ, turn penalty, horizontal entry/exit enforcement), barrel index.ts - A* state space is (col, row, direction) -- 8 directions x 576 cells. Only 0-degree and 45-degree turns allowed per step; 90-degree and wider turns impossible by construction.
getPortGridAnchor(node, side, portIndex)computes grid cell for any port (regular nodes: 1 cell outside bounding box; connection points: at playable area boundary cols 3/28)- Created
src/store/slices/routing-slice.ts:routeAllWires()action computes A* paths for all wires in a single batch update viaupdateWires() initRouting()subscriber auto-triggers routing ongraphVersionoractiveBoardIdchanges- Integrated into store/index.ts (GameStore union, initRouting call after initHistory)
- 46 new tests (20 grid-graph, 19 auto-router, 7 routing-slice), 689 total passing across 46 suites, zero TypeScript errors
- Rewrote
render-wires.ts: bezier curves replaced with polyline rendering alongwire.pathgrid routes - Three-pass rendering recipe per wire: neutral base (0.4 alpha) → glow halo (|signal|>75, shadowBlur 0→12) → polarity color per segment
- Color interpolation: hexToRgb + lerpColor helpers; neutral→polarity gradient over signal range 0–75, clamped beyond
- Ring buffer → segment mapping: 16-sample buffer mapped proportionally across path segments (source=newest, target=oldest)
- Export renamed
renderWires→drawWires(ctx, tokens, wires, cellSize); render-loop call site updated - 31 new tests, 722 total passing across 47 suites, zero TypeScript errors
- Three node size categories: Fundamental (3x2), Puzzle (3x dynamic rows), Utility (5x3)
getNodeGridSize(node)computes per-node grid footprint;canPlaceNodeaccepts explicit cols/rowsNODE_CONFIGreplaced with ratio-basedNODE_STYLE(all dimensions scaled to cellSize at render time)render-nodes.tsfully rewritten: gradient fills, drop shadows, visual states (default/hover/selected), two-pass draw order- Port positions, hit-testing, and auto-router updated for variable node dimensions
- Added
hoveredNodeIdto interaction slice + wired into GameboardCanvas mouse move hexToRgb/lerpColorduplicated inline in render-nodes (same as render-wires)- 31 new tests (12 render-nodes, 5 port-positions, 5 hit-testing, 9 occupancy), 753 total passing across 50 suites, zero TypeScript errors
All 4 stories in Epic 6 (Redesign Signal Visualization) are done. Next: Epic 7 (Redesign Interaction & Navigation).
- Created
src/store/slices/overlay-slice.ts:ActiveOverlaydiscriminated union (7 variants),ContextTargettype,openOverlay/closeOverlay/isOverlayEscapeDismissible/hasActiveOverlayactions,ESCAPE_IMMUNEset for save-dialog and unsaved-changes - Created
src/gameboard/interaction/module:focus-manager.ts(singleton focus context tracking, save/restore, Tab trap),escape-handler.ts(pure 5-level escape cascade function), barrelindex.ts - Wired overlay slice into
store/index.ts(GameStore union), updated 5 test files with full slice composition GameboardCanvas.tsx: Escape handler replaced withhandleEscape()cascade, overlay guards on mouse/keyboard handlers, undo/redo gated byhasActiveOverlay()render-loop.ts: wire preview suppressed during overlay, semi-transparent dim (rgba(0,0,0,0.15)) drawn over canvas when overlay active- 39 new tests (14 overlay-slice, 11 focus-manager, 14 escape-handler), 792 total passing across 53 suites, zero TypeScript errors
- Replaced sidebar-based UI (PalettePanel, NodeControls) with overlay-based components
- Created
src/shared/grid/cell-size-ref.ts(module-level getter/setter for cellSize, singleton pattern) - Extended hit-testing with wire hit detection (point-to-segment distance, ~6px threshold)
- Added
getNodeGridSizeFromType()for placement validation without full NodeState - Created
src/gameboard/canvas/render-placement-ghost.ts: semi-transparent grid-snapped preview with occupancy validation (red tint if invalid), clamped to playable area - Created
src/ui/overlays/module: PaletteModal (search + sections + keyboard nav), ContextMenu (node/wire/empty targets), ParameterPopover (mix select, delay select, threshold range) - Created pure-logic builders:
palette-items.ts(build + filter),context-menu-items.ts(per-target items),popover-position.ts(4-side flip logic) - Updated
GameboardCanvas.tsx: N/Space opens palette, Enter opens parameter popover, right-click context menu (node → menu, wire → menu, empty → palette), occupancy validation on placement, setCellSize on resize - Updated
App.tsx: removed PalettePanel/NodeControls sidebar, full-screen canvas layout with overlay components - 43 new tests (10 palette-items, 10 context-menu-items, 8 popover-position, 9 render-placement-ghost, 6 wire hit-testing), 835 total passing across 57 suites, zero TypeScript errors
- Created
src/store/slices/animation-slice.ts:LidAnimationStatediscriminated union (idle | opening | closing), actions:startLidOpen,startLidClose,setLidProgress,endLidAnimation; only one animation at a time (idle guard) - Created
src/gameboard/animation/module:lid-animation.tswithdrawLidAnimation(ctx, tokens, state, progress, canvasW, canvasH),computeProgress(startTime, now, durationMs),parseDurationMs(token), ease-in-out cubic easing, shadow gradients on inner edges - Opening effect: parent board snapshot splits vertically at center, left/right halves compress toward edges revealing live child board behind
- Closing effect: child board snapshot shrinks from center, revealing live parent board behind
- Updated
render-loop.ts: lid animation progress computed from rAF timestamp +animZoomDurationtoken, animation overlay drawn on top of live board, auto-completes at progress 1.0 - Refactored
escape-handler.ts: separatedgetEscapeAction()(pure) fromexecuteEscapeAction()for pre-flight snapshot capture - Updated
GameboardCanvas.tsx: escape-key zoom-out captures OffscreenCanvas snapshot + callsstartLidClosebeforezoomOut() - Updated
ContextMenu.tsx: "Edit" and "Inspect" actions capture OffscreenCanvas + callstartLidOpenbefore board switch (replaces oldstartZoomTransitionCSS approach) - Reduced motion:
parseDurationMs("0ms")→ 0,computeProgressreturns 1 instantly → animation completes in single frame - 38 new tests (17 animation-slice, 21 lid-animation), 873 total passing across 59 suites, zero TypeScript errors
- Multi-phase ceremony animation: streak → victory-burst → name-reveal → zoom-out → inactive
ValidationCeremonyStatediscriminated union added to animation-slice.ts with 7 guarded actions (startCeremonyStreak, advanceCeremonyStreak, breakCeremonyStreak, startVictoryBurst, startNameReveal, startCeremonyZoomOut, endCeremony)- Created
src/gameboard/animation/validation-ceremony.ts: drawVictoryBurst (radial gradient flash), drawNameReveal (centered text fade-in + scale-up), drawStreakCounter (progress bar near bottom) - Ceremony tokens:
animCeremonyBurstDuration(300ms),animCeremonyRevealDuration(500ms), both 0ms for reduced motion - render-loop.ts: ceremony phases auto-advance, streakPulseAlpha enhances meter confirming borders during streak, zoom-out reuses drawLidAnimation with synthesized closing state
- simulation-controller.ts: validateTick drives streak animation (start/advance/break), triggerCeremony defers palette addition to handleCeremonyCompletion in render-loop
- render-meter.ts: streakPulseAlpha field on RenderMeterState, drawConfirmingBorder uses pulsing alpha + shadowBlur glow when > 0.7
- 35 new tests (18 animation-slice ceremony, 15 validation-ceremony, 2 token), 908 total passing across 60 suites, zero TypeScript errors
- Created
src/gameboard/interaction/keyboard-focus.ts: module-level singleton trackingfocusTarget(node/port/connection-point/wire) andfocusVisibleflag,computeTabOrder()(sorted by row/col, expanded node splices ports/wires, connection points appended),computeValidWiringTargets(),advanceFocus()with wrap-around - Created
src/gameboard/interaction/keyboard-handler.ts: puregetKeyboardAction()+executeKeyboardAction()pattern (matching escape-handler), handles Tab/Shift+Tab, arrow keys, Enter (context-dependent: enter-node, open-params, start-wiring, complete-wiring, place-node), Delete/Backspace, N/Space, Ctrl+Z/Ctrl+Shift+Z - Added
keyboard-wiringinteraction mode tointeraction-slice.tswithstartKeyboardWiring,cycleWiringTarget,cancelKeyboardWiring,keyboardGhostPosition,setKeyboardGhostPositionactions - Created
src/gameboard/canvas/render-focus.ts: dashed focus ring for nodes (roundRect 5px offset), ports (circle), connection points (circle), wires (dashed polyline path); wiring target highlights (0.3-alpha for all, 1.0 + wire preview for active) - Updated
GameboardCanvas.tsx: inline handleKeyDown replaced with keyboard-handler dispatch, mouse move hides focus ring, canvas hastabIndex={0}+aria-label="Gameboard", keyboard-wiring cursor - Updated
render-loop.ts: focus ring drawn after nodes before wire preview, reduced motion static streakPulseAlpha (0.8) - Updated
render-placement-ghost.ts:keyboardGhostPositiontakes priority over mouse snap, clamped to playable area - Updated
escape-handler.ts:keyboard-wiringadded to cancel-wiring priority,cancelKeyboardWiringon EscapeHandlerState interface - Reduced motion audit:
render-needle.ts(shadowBlur 0),render-waveform-channel.ts(uniform alpha 0.8),render-meter.ts(static globalAlpha 0.8, shadowBlur 0 in confirming border) - 68 new tests (15 keyboard-focus, 40 keyboard-handler, 9 render-focus, 4 existing escape-handler adapted), 976 total passing across 66 suites, zero TypeScript errors
Epic 7 Complete. All redesign epics (5, 6, 7) are done.
Added a "Creative Mode" sandbox that bypasses puzzle progression:
- Created
src/store/slices/creative-slice.ts:isCreativeModeflag,creativeWaveformstuple (3 WaveformDefs),enterCreativeMode,exitCreativeMode,setCreativeWaveform,setCreativeWaveformShapeactions - Added
waveform-selectoroverlay type tooverlay-slice.ts - Created
src/ui/overlays/WaveformSelectorOverlay.tsx: modal with 10 waveform shape options (sine, square, triangle, sawtooth, constant, 5 rectified variants), mini SVG preview icons - Extended
hitTestMeter()inhit-testing.ts: detects clicks on meter waveform channel area (~59% left side of meter) - Updated
GameboardCanvas.tsx: in creative mode, clicking input meter waveform opens waveform selector - Updated
simulation-controller.ts: connection-input nodes usecreativeWaveformswhenisCreativeMode, meter recording uses creative waveforms,validateTick()skips validation in creative mode - Updated
App.tsx: starts in creative mode with 6 active meters (3 inputs, 3 outputs), simulation auto-starts - Updated
palette-items.ts:isCreativeModeparameter unlocks all puzzle nodes regardless ofcompletedLevels - 10 new tests for creative-slice, 986 total passing across 64 suites, zero TypeScript errors
Features:
- All 6 meters active on startup
- All puzzle nodes available in palette (if any exist)
- No victory condition -- validation skipped
- Click input meter waveform to select different waveform shape
- Output meters are read-only (no selector)
- Default waveforms: Input 1 = Sine, Input 2 = Square, Input 3 = Triangle
Doubled grid resolution from 32×18 to 64×36 for finer node positioning:
GRID_COLS: 32 → 64,GRID_ROWS: 18 → 36- Meter zones doubled: left 0-5 (6 cols), playable 6-57 (52 cols), right 58-63 (6 cols)
METER_GRID_ROWS: 6 → 12,METER_GRID_COLS: 3 → 6 (same visual size)MIN_CELL_SIZE: 32 → 16 (cells now half the visual size)- Node grid sizes unchanged (visually smaller, finer port spacing)
- All 993 tests passing, zero regressions
Implemented 5 interconnected changes to the node system:
- Added
NodeRotationtype (0 | 90 | 180 | 270) tosrc/shared/types/index.ts - Added
rotation?: NodeRotationfield toNodeStateinterface - Added 'constant' to
FundamentalNodeType - Created
src/shared/grid/rotation.ts:getRotatedPortSide(),getRotatedSize(),getPortApproachDirection(),getPortOffset() - 12 new rotation tests
- Added
NODE_STYLE.BODY_OFFSET = 0.5constant (half-cell visual offset) - Updated
getNodeGridSize()to apply rotation when determining dimensions - Updated
getNodePortPosition()to handle rotated port positions - Added
getNodeBodyPixelRect()for offset body rendering - Updated
render-nodes.ts,render-placement-ghost.ts,hit-testing.tsfor body offset
- Added
dragging-nodemode toInteractionModewith offset tracking - Added
rotatePlacement()action to cycle rotation 0→90→180→270→0 - Added
moveNode()action togameboard-slice.ts - Added drag detection to
GameboardCanvas.tsx(5px threshold or 150ms delay) - Added 'R' key handler for rotation during placement/drag
- Updated
auto-router.ts:getPortGridAnchor()now uses rotation to determine anchor positions - Added
getPortWireDirection()andportSideToWireDirection()for direction-aware routing - Updated
findPath()to accept custom start/end directions (instead of hardcoded East) - Updated
routing-slice.tsto pass correct directions based on node rotations - 23 new routing tests
Result: Nodes can be rotated with R key during placement/drag. Ports move to correct sides based on rotation. Wire routing adapts to rotated port positions. All 1115 tests passing.
| What | Where |
|---|---|
| Redesign architecture | _bmad-output/planning-artifacts/architecture.md |
| UX spec (drives redesign) | _bmad-output/planning-artifacts/ux-design-specification.md |
| Original architecture | _bmad-output/game-architecture.md |
| Epics & Stories | _bmad-output/planning-artifacts/epics.md |
| Readiness report | _bmad-output/planning-artifacts/implementation-readiness-report.md |
| Sprint status | _bmad-output/implementation-artifacts/sprint-status.yaml |
| Interactive demos | _bmad-output/planning-artifacts/architecture-explorations.html |
| Story 5.1 (Grid/Viewport) | _bmad-output/implementation-artifacts/5-1-grid-coordinate-system-viewport.md |
| Story 5.2 (Tokens/Themes) | _bmad-output/implementation-artifacts/5-2-design-token-system-dual-themes.md |
| Story 5.3 (Type Migrations) | _bmad-output/implementation-artifacts/5-3-core-type-migrations-connection-point-configuration.md |
| Story 5.4 (Render Refactor) | _bmad-output/implementation-artifacts/5-4-render-loop-draw-function-refactor.md |
| Story 5.5 (Grid Zones) | _bmad-output/implementation-artifacts/5-5-grid-zone-background-rendering.md |
| Story 6.1 (Analog Meters) | src/gameboard/meters/ (9 files) |
| Story 6.2 (Auto-Routing) | src/shared/routing/ (3 files) + src/store/slices/routing-slice.ts |
| Story 6.3 (Wire Signal Rendering) | src/gameboard/canvas/render-wires.ts + render-wires.test.ts |
| Story 6.4 (Node Rendering) | src/gameboard/canvas/render-nodes.ts + tests |
| Story 7.1 (Overlay/Focus) | src/store/slices/overlay-slice.ts + src/gameboard/interaction/ |
| Story 7.2 (Palette/Popover/Menu) | src/ui/overlays/ (13 files) + src/gameboard/canvas/render-placement-ghost.ts |
| Story 7.3 (Lid Animation) | src/store/slices/animation-slice.ts + src/gameboard/animation/ |
| Story 7.4 (Ceremony Animation) | src/gameboard/animation/validation-ceremony.ts + animation-slice ceremony state |
| Story 7.5 (Keyboard/a11y) | src/gameboard/interaction/keyboard-focus.ts + keyboard-handler.ts + src/gameboard/canvas/render-focus.ts |
| Creative Mode | src/store/slices/creative-slice.ts + src/ui/overlays/WaveformSelectorOverlay.tsx |
| Node System (rotation/drag) | src/shared/grid/rotation.ts + src/shared/routing/auto-router.ts + interaction-slice.ts |
| Test suite | npm test (1115 tests, 74 suites) |
| Playtest plan | _bmad-output/playtest-plan.md |
Implemented full puzzle authoring workflow allowing users to create and play custom puzzles:
- Created
src/ui/screens/StartScreen.tsx: Full-screen entry with "Level Select" and "Creative Mode" buttons - Added 'start-screen', 'level-select', 'trim-dialog', 'save-puzzle-dialog' to
ActiveOverlayunion - Created
src/ui/overlays/LevelSelectOverlay.tsx: Shows built-in puzzles + custom puzzles section
- Extended
CreativeSlotState.directionto support 'off' (hidden meter) - Added "Off (hidden)" option to
WaveformSelectorOverlaywith X icon - Updated
gameboard-slice.tswithaddCreativeSlotNodeaction for off→active transitions - Meter visibility updates when slot direction changes
- Created
src/store/slices/authoring-slice.ts:OutputRingBufferclass (480 samples ~30 sec),authoringPhasestate machine (idle→trimming→saving) - Updated
simulation-controller.tsto push output samples to authoring buffers in creative mode - Added "Save as Puzzle" button to
SimulationControls(creative mode only)
- Created
src/ui/overlays/TrimDialog.tsx: Canvas-based waveform display with draggable start/end handles for loop selection - Created
src/ui/overlays/SavePuzzleDialog.tsx: Title/description input with puzzle configuration summary
- Created
src/store/slices/custom-puzzle-slice.ts:CustomPuzzletype with slots, targetSamples, serialized nodes/wires - Created
src/store/custom-puzzle-persistence.ts: Separate localStorage key, auto-save on changes - Added 'samples' shape to
WaveformShapeunion for recorded waveform playback - Updated
waveform-generators.tsto handle samples shape (looping playback)
- Implemented
loadCustomPuzzle()with full gameboard/meter setup - Custom puzzles appear in LevelSelect under "Custom Puzzles" section
- WaveformSelectorOverlay closes immediately in puzzle mode (no changes allowed)
Workflow:
- Launch → Start Screen with "Creative Mode" / "Level Select"
- Creative Mode: Configure inputs (waveforms) and outputs, build nodes, let simulation run
- Click "Save as Puzzle" → Trim dialog with last ~30 sec of output buffered
- Drag handles to select loop region → Continue
- Enter title/description → Save
- Return to Level Select → Custom puzzle appears under "Custom Puzzles"
- Load custom puzzle → Same mechanics as built-in puzzles
Files Created:
src/ui/screens/StartScreen.tsx+ CSS modulesrc/ui/overlays/LevelSelectOverlay.tsx+ CSS modulesrc/ui/overlays/TrimDialog.tsx+ CSS modulesrc/ui/overlays/SavePuzzleDialog.tsx+ CSS modulesrc/store/slices/authoring-slice.tssrc/store/slices/custom-puzzle-slice.tssrc/store/custom-puzzle-persistence.ts
Files Modified:
src/App.tsx: Start screen integration, new overlay importssrc/store/index.ts: Added authoring/custom-puzzle slicessrc/store/slices/overlay-slice.ts: 4 new overlay typessrc/store/slices/creative-slice.ts: 'off' direction supportsrc/store/slices/gameboard-slice.ts: addCreativeSlotNode actionsrc/ui/overlays/WaveformSelectorOverlay.tsx: Off option, puzzle mode guardsrc/ui/controls/SimulationControls.tsx: "Save as Puzzle" buttonsrc/simulation/simulation-controller.ts: Output buffer recordingsrc/puzzle/types.ts: 'samples' WaveformShapesrc/puzzle/waveform-generators.ts: samples shape handling
All 1115 tests passing, zero TypeScript errors.