# Conway Life Demo Implementation Plan > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Build a direct-open Conway's Game of Life demo page with a modern visualization style, preset patterns, canvas-based simulation, and a clean teaching-plus-exploration flow. **Architecture:** Keep the page build-free and local-file friendly: semantic markup in `index.html`, visual styling in `styles.css`, and a single browser script in `app.js`. Put Conway engine logic and state helpers in testable pure functions exported from `app.js`, while the DOM/controller layer wires those functions to the canvas UI. **Tech Stack:** HTML5, CSS3, vanilla JavaScript, Canvas API, Node.js built-in test runner (`node --test`) --- Note: this workspace is not a git repository, so commit steps are intentionally omitted. ## File Structure - Create: `index.html` - page structure, content sections, script/style includes - Create: `styles.css` - theme variables, layout, cards, control panel, responsive styling, animation polish - Create: `app.js` - Conway engine, preset definitions, state helpers, canvas rendering, UI events - Create: `tests/life-demo.test.js` - Node tests for pure simulation and state logic ## Chunk 1: Build and test the Conway engine ### Task 1: Create the failing engine tests **Files:** - Create: `tests/life-demo.test.js` - Test: `tests/life-demo.test.js` - [ ] **Step 1: Write the failing test** ```js const test = require('node:test'); const assert = require('node:assert/strict'); const { createEmptyGrid, stepGrid, stampPattern, PATTERNS, } = require('../app.js'); test('blinker rotates after one generation', () => { const grid = createEmptyGrid(5, 5); grid[2][1] = 1; grid[2][2] = 1; grid[2][3] = 1; const next = stepGrid(grid); assert.deepEqual(next[1], [0, 0, 1, 0, 0]); }); ``` - [ ] **Step 2: Run test to verify it fails** Run: `node --test tests/life-demo.test.js` Expected: FAIL because `app.js` or the exported functions do not exist yet. - [ ] **Step 3: Write minimal implementation** ```js function createEmptyGrid(rows, cols) { return Array.from({ length: rows }, () => Array(cols).fill(0)); } ``` Implement the smallest export set needed to pass: - `createEmptyGrid(rows, cols)` - `countLiveNeighbors(grid, row, col)` - `stepGrid(grid)` - `stampPattern(grid, pattern, offsetRow, offsetCol)` - `PATTERNS` for `glider`, `pulsar`, and `gosperGliderGun` - [ ] **Step 4: Run test to verify it passes** Run: `node --test tests/life-demo.test.js` Expected: PASS for the engine tests. ## Chunk 2: Add state helpers and page shell ### Task 2: Add failing tests for state helpers **Files:** - Modify: `tests/life-demo.test.js` - Modify: `app.js` - Create: `index.html` - Create: `styles.css` - [ ] **Step 1: Write the failing test** Add tests for: ```js test('createInitialState seeds the default preset and starts paused', () => { const state = createInitialState({ rows: 20, cols: 20, defaultPattern: 'pulsar', }); assert.equal(state.running, false); assert.equal(state.selectedPattern, 'pulsar'); assert.equal(state.generation, 0); assert.ok(state.liveCount > 0); }); ``` - [ ] **Step 2: Run test to verify it fails** Run: `node --test tests/life-demo.test.js` Expected: FAIL because `createInitialState` is not implemented yet. - [ ] **Step 3: Write minimal implementation** Implement pure helpers: - `cloneGrid(grid)` - `countLiveCells(grid)` - `createInitialState({ rows, cols, defaultPattern })` - `randomizeGrid(grid, probability)` - `toggleCell(grid, row, col, forcedValue)` At the same time, scaffold: - `index.html` with Hero, Lab, Rules, and Presets sections - `styles.css` with the modern visualization theme variables and responsive grid - [ ] **Step 4: Run test to verify it passes** Run: `node --test tests/life-demo.test.js` Expected: PASS for the new state-helper tests. ## Chunk 3: Wire controls, canvas rendering, and preset switching ### Task 3: Add failing tests for UI-facing state transitions **Files:** - Modify: `tests/life-demo.test.js` - Modify: `app.js` - Modify: `index.html` - Modify: `styles.css` - [ ] **Step 1: Write the failing test** Add tests for: ```js test('applyPreset replaces the grid, pauses playback, and resets generation', () => { const state = { ...createInitialState({ rows: 25, cols: 25, defaultPattern: 'glider' }), running: true, generation: 12, }; const next = applyPreset(state, 'gosperGliderGun'); assert.equal(next.running, false); assert.equal(next.generation, 0); assert.equal(next.selectedPattern, 'gosperGliderGun'); assert.ok(next.liveCount > state.liveCount); }); ``` - [ ] **Step 2: Run test to verify it fails** Run: `node --test tests/life-demo.test.js` Expected: FAIL because `applyPreset` is not implemented yet. - [ ] **Step 3: Write minimal implementation** Implement: - `applyPreset(state, patternName)` - `advanceState(state)` - `setSpeed(state, speed)` - `getSpeedLabel(speed)` Then wire browser behavior: - draw the grid on a `canvas` - support play/pause, step, clear, randomize, reset preset, and speed controls - support click and drag painting on the canvas - update status text, generation count, live-count, and active preset styling - [ ] **Step 4: Run test to verify it passes** Run: `node --test tests/life-demo.test.js` Expected: PASS for the state-transition tests. ## Chunk 4: Polish visual details and run end-to-end verification ### Task 4: Finish presentation details and verify manually **Files:** - Modify: `index.html` - Modify: `styles.css` - Modify: `app.js` - Test: `tests/life-demo.test.js` - [ ] **Step 1: Refine the visuals** Complete: - luminous background gradients and grid accents - polished cards and control panel surfaces - hover/focus states - responsive stacking for smaller screens - subtle canvas/section entrance motion - [ ] **Step 2: Run automated tests** Run: `node --test tests/life-demo.test.js` Expected: PASS with zero failures. - [ ] **Step 3: Run manual verification** Open: `index.html` Verify: - page opens directly without a dev server - pulsar loads by default and the simulation starts paused - controls behave correctly - each preset loads and pauses correctly - editing by click/drag works - desktop and narrow layouts both remain usable - [ ] **Step 4: Record any gaps** If a browser-only issue appears, fix it and rerun: - `node --test tests/life-demo.test.js` - manual browser verification of `index.html`