docs(01-01): complete HTML scaffold plan — HiDPI canvas, game loop, Player 1 input
- Created 01-01-SUMMARY.md documenting objects built, decisions, patterns - Updated STATE.md: position advanced to plan 2/2 in Phase 1 - Updated ROADMAP.md: Phase 1 plan 1/2 complete (in progress) - Marked CORE-07 and VFX-05 requirements as complete in REQUIREMENTS.md
This commit is contained in:
112
.planning/phases/01-foundation/01-01-SUMMARY.md
Normal file
112
.planning/phases/01-foundation/01-01-SUMMARY.md
Normal file
@@ -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*
|
||||
Reference in New Issue
Block a user