diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 120cc86..e1bfc3a 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -15,7 +15,7 @@ Requirements for initial release. Each maps to roadmap phases. - [ ] **CORE-04**: Ball speed increases gradually over the course of a match - [ ] **CORE-05**: Player scores a point when ball passes opponent's paddle - [ ] **CORE-06**: Match ends when a player reaches the target score (first to N points) -- [ ] **CORE-07**: Player 1 controls paddle with keyboard (W/S keys) +- [x] **CORE-07**: Player 1 controls paddle with keyboard (W/S keys) - [ ] **CORE-08**: Player 2 controls paddle with keyboard (Up/Down arrow keys) ### AI Opponent @@ -38,7 +38,7 @@ Requirements for initial release. Each maps to roadmap phases. - [ ] **VFX-02**: Ball leaves a fading motion trail behind it - [ ] **VFX-03**: Particles burst from ball impact point when ball hits paddle or wall - [ ] **VFX-04**: Screen shakes briefly when a player scores a point -- [ ] **VFX-05**: Canvas renders sharply on Retina/HiDPI displays (devicePixelRatio aware) +- [x] **VFX-05**: Canvas renders sharply on Retina/HiDPI displays (devicePixelRatio aware) ### Power-Ups @@ -104,7 +104,7 @@ Which phases cover which requirements. Updated during roadmap creation. | CORE-04 | 1 | Pending | | CORE-05 | 2 | Pending | | CORE-06 | 2 | Pending | -| CORE-07 | 1 | Pending | +| CORE-07 | 1 | Complete | | CORE-08 | 2 | Pending | | AI-01 | 2 | Pending | | AI-02 | 2 | Pending | @@ -118,7 +118,7 @@ Which phases cover which requirements. Updated during roadmap creation. | VFX-02 | 4 | Pending | | VFX-03 | 4 | Pending | | VFX-04 | 4 | Pending | -| VFX-05 | 1 | Pending | +| VFX-05 | 1 | Complete | | PWR-01 | 4 | Pending | | PWR-02 | 4 | Pending | | PWR-03 | 4 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a3e06d7..4e86ece 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -38,7 +38,7 @@ **Plans:** 2 plans Plans: -- [ ] 01-01-PLAN.md — HTML scaffold, HiDPI canvas, Renderer, GameLoop, Input, Player 1 paddle +- [x] 01-01-PLAN.md — HTML scaffold, HiDPI canvas, Renderer, GameLoop, Input, Player 1 paddle - [ ] 01-02-PLAN.md — Ball physics: movement, wall bounce, zone-based deflection, speed increment --- @@ -137,7 +137,7 @@ Plans: | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. Foundation | 0/2 | Planned | — | +| 1. Foundation | 1/2 | In Progress | — | | 2. Core Gameplay | 0/? | Not started | — | | 3. Complete Experience | 0/? | Not started | — | | 4. Polish & Depth | 0/? | Not started | — | diff --git a/.planning/STATE.md b/.planning/STATE.md index 9eee1ac..35179b5 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,7 +2,7 @@ **Project Reference** - **Core Value:** Pong reimagined with juice and depth — spectacular visuals, rich mechanics, complete game experience -- **Current Focus:** Roadmap created, ready for Phase 1 planning +- **Current Focus:** Phase 1 — executing plans - **Key Constraint:** Coarse granularity (5 phases max), HTML5 Canvas + vanilla JS, static deployment --- @@ -11,13 +11,13 @@ | Attribute | Value | |-----------|-------| -| **Phase** | Planning complete, ready to plan Phase 1 | -| **Plan** | None active yet | -| **Status** | Roadmap finalized, 37/37 requirements mapped | -| **Progress** | 0% (0 phases complete) | +| **Phase** | 01-foundation | +| **Plan** | Plan 2/2 (01-02 next) | +| **Status** | Plan 01-01 complete — scaffold, HiDPI canvas, game loop, Player 1 input done | +| **Progress** | 5% (1/2 plans complete in Phase 1) | ``` -[ ] 0% — Roadmap → Phase 1 planning +[= ] 5% — Phase 1: Plan 1/2 complete ``` --- @@ -29,6 +29,7 @@ | **Phase Coverage** | 100% (37/37 requirements mapped) | ✓ Complete | | **Success Criteria** | 2-5 per phase | ✓ Complete | | **Dependency Chain** | Linear (P1 → P2 → P3 → P4 → P5) | ✓ Validated | +| **01-01 Duration** | — | 1 min (2 tasks, 1 file) | --- @@ -52,6 +53,14 @@ - Phase 4: Power-up balance - Phase 5: Performance, memory leaks, cross-browser +4. **deltaTime Cap at 50ms:** Game loop caps deltaTime to prevent physics explosion when tab loses focus and resumes — without this a single large delta would fling the ball off screen. + +5. **Logical vs Bitmap Coordinate Separation:** canvas.width/height = logical * devicePixelRatio; ctx.scale(dpr, dpr) makes all game draw calls use logical pixels — correct HiDPI approach for sharp rendering on Retina displays. + +6. **Module-Object Pattern Established:** GameLoop, Renderer, Input, Physics, GameState are plain JS objects with init() methods in a single script tag. No classes, no modules, no build step — runs directly from filesystem. + +7. **e.code over e.key for Input:** Using e.code === 'KeyW' makes W/S detection layout-independent (works on AZERTY and other non-QWERTY keyboards). + ### Coverage Validation **Total v1 Requirements:** 37 @@ -80,22 +89,24 @@ ### What Just Happened -Roadmap derived from 37 v1 requirements organized into 5 phases, each with 2-5 observable success criteria. Granularity set to coarse; 10-phase research recommendation compressed by grouping related technical work. +Plan 01-01 executed: Created index.html with full-window HiDPI canvas, Renderer (devicePixelRatio aware), GameLoop (requestAnimationFrame + deltaTime), Input (W/S keys), Physics skeleton (paddle movement + clamping), and GameState. Player 1 paddle is visible and responsive. Requirements VFX-05 and CORE-07 satisfied. ### What Comes Next -1. `/gsd:plan-phase 1` — Decompose Phase 1 into executable plans -2. Continue through phases 2-5 -3. Execute plans in dependency order -4. Validate success criteria at each phase completion +1. Execute Plan 01-02 — Ball physics: movement, wall bounce, zone-based angle deflection, per-hit speed increment +2. Continue through phases 2-5 after Phase 1 complete ### Known Blockers -None. All context available, all requirements mapped, roadmap ready for planning. +None. ### Decisions Pending -None. Roadmap finalized; awaiting user approval before phase planning begins. +None. + +### Last Session + +Stopped at: Completed 01-01-PLAN.md (2026-03-10) --- diff --git a/.planning/phases/01-foundation/01-01-SUMMARY.md b/.planning/phases/01-foundation/01-01-SUMMARY.md new file mode 100644 index 0000000..34f10ca --- /dev/null +++ b/.planning/phases/01-foundation/01-01-SUMMARY.md @@ -0,0 +1,112 @@ +--- +phase: 01-foundation +plan: 01 +subsystem: ui +tags: [canvas, hidpi, game-loop, requestAnimationFrame, devicePixelRatio, vanilla-js] + +# Dependency graph +requires: [] +provides: + - "index.html with full-window HiDPI-aware canvas" + - "Renderer object with devicePixelRatio scaling and logical/bitmap coordinate separation" + - "GameLoop object using requestAnimationFrame with deltaTime capping" + - "Input object with keydown/keyup state tracking for W/S keys" + - "Physics skeleton with paddle movement and canvas-bounds clamping" + - "GameState object holding mutable paddle1 and ball state" +affects: [01-02, Phase 2, Phase 3, Phase 4, Phase 5] + +# Tech tracking +tech-stack: + added: [HTML5 Canvas API, requestAnimationFrame, devicePixelRatio, performance.now] + patterns: + - "Module-object pattern: all systems are plain JS objects with init() methods" + - "Logical vs bitmap coordinate separation for HiDPI rendering" + - "deltaTime game loop with 50ms cap to prevent physics explosion on tab resume" + - "State centralized in GameState; systems mutate GameState, never each other directly" + +key-files: + created: [index.html] + modified: [] + +key-decisions: + - "Single HTML file — no build step, runs directly from filesystem" + - "deltaTime capped at 50ms (0.05s) to prevent ball teleporting on tab resume or focus loss" + - "Logical vs bitmap pixels: canvas.width/height set to logical*dpr, ctx.scale(dpr,dpr) so all game draw calls use logical coords" + - "Minimum 4:3 aspect ratio enforced by constraining logicalHeight when window is taller than 4:3" + - "Physics.onResize called from Renderer.resize() with existence guard (typeof Physics !== undefined)" + - "Input uses e.code (KeyW/KeyS) not e.key for layout-independent key detection" + +patterns-established: + - "Object initialization order: Renderer.init() → Physics.init() → Input.init() → GameLoop.start()" + - "Renderer.drawRect/drawCircle use Math.round() to prevent sub-pixel blurriness" + - "GameLoop.main() re-registers itself first, then updates physics, then renders" + - "Physics.update() takes deltaTime in seconds; speeds defined as logical pixels/second" + +requirements-completed: [VFX-05, CORE-07] + +# Metrics +duration: 1min +completed: 2026-03-10 +--- + +# Phase 1 Plan 01: HTML Scaffold, HiDPI Canvas, and Game Loop Summary + +**Single-file HTML5 Pong scaffold with devicePixelRatio-aware canvas, requestAnimationFrame game loop, and W/S paddle input — Player 1 visible and responsive** + +## Performance + +- **Duration:** 1 min +- **Started:** 2026-03-10T13:45:27Z +- **Completed:** 2026-03-10T13:46:34Z +- **Tasks:** 2 +- **Files modified:** 1 + +## Accomplishments +- Full-window black canvas with HiDPI scaling via devicePixelRatio; renders sharply on Retina displays +- requestAnimationFrame game loop at device refresh rate with 50ms deltaTime cap for safety +- W/S keyboard input with instantaneous keydown/keyup state tracking (no OS key-repeat lag) +- White paddle visible on left side (~x=30), white ball dot at center; both correctly positioned on init + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: HTML scaffold, HiDPI canvas, and full-window Renderer** - `e43b82b` (feat) +2. **Task 2: GameLoop, Input module, and Player 1 paddle rendering** - `e43b82b` (feat — included in Task 1 commit as file was written complete) + +**Plan metadata:** (docs commit follows) + +_Note: Both tasks target the same new file (index.html). The file was authored complete in a single write and committed once with all objects present._ + +## Files Created/Modified +- `/home/dabit/projects/gijs/index.html` - Complete game scaffold: HTML5 structure, embedded CSS, Renderer, GameState, Input, Physics skeleton, GameLoop, and initialization block + +## Decisions Made +- **deltaTime cap at 50ms:** Prevents physics explosion when the browser tab loses focus and resumes — a single large delta without this cap would fling the ball off screen. +- **Logical vs bitmap coordinate system:** All game logic uses logical pixels (window.innerWidth/innerHeight). Canvas bitmap dimensions are logical * devicePixelRatio; ctx.scale(dpr, dpr) makes draw calls transparent to this split. This is the correct HiDPI approach. +- **Minimum 4:3 aspect ratio:** When window is taller than 4:3, logicalHeight is clamped to `floor(logicalWidth / 1.333)`. Canvas CSS height tracks logicalHeight, so the canvas never becomes taller than 4:3. The area below the canvas is body background (#000), which is invisible. +- **e.code over e.key:** Using `e.code === 'KeyW'` instead of `e.key === 'w'` makes input work regardless of keyboard layout (AZERTY, etc.). +- **Physics.onResize existence guard:** `typeof Physics !== 'undefined'` in Renderer.resize() allows Renderer.init() to be called before Physics is defined, eliminating init-order fragility. + +## Deviations from Plan + +None - plan executed exactly as written. Both tasks implemented together since they target the same new file; no functional deviation from specified behavior. + +## Issues Encountered + +None. Fresh project with no dependencies — no install steps, no auth gates, no external services. + +## User Setup Required + +None - no external service configuration required. Open index.html directly in any modern browser. + +## Next Phase Readiness + +- index.html is the foundation for Plan 01-02 (ball physics: movement, wall bounce, zone-based deflection, speed increment) +- Physics.update() currently only moves paddle1; Plan 01-02 adds ball velocity, wall bouncing, and paddle collision +- GameState.ball has vx/vy/speed fields initialized to 0 — Plan 01-02 will set initial ball velocity +- All objects (GameLoop, Renderer, Physics, Input, GameState) are in global script scope, accessible for extension without refactoring + +--- +*Phase: 01-foundation* +*Completed: 2026-03-10*