docs: complete project research synthesis

Synthesized 4 parallel research efforts into comprehensive SUMMARY.md:
- STACK.md: Vanilla Canvas 2D, fixed timestep, Web Audio, no dependencies
- FEATURES.md: MVP features + v1.x enhancements + defer list
- ARCHITECTURE.md: Game loop + state machine + entity patterns, 10-phase build order
- PITFALLS.md: 8 critical pitfalls with prevention strategies

Key recommendations:
- Use fixed timestep accumulator (60 Hz physics, variable rendering)
- Implement 10 phases from game loop foundation to cross-browser testing
- Address critical pitfalls early (tunneling, timing, DPI, autoplay, AI, power-ups, lag, memory)
- MVP ships with core Pong + AI + menus + basic polish
- v1.x adds particles, trails, power-ups, arenas

All research backed by official sources (MDN, web.dev, Chrome docs) and established patterns.
Confidence: HIGH. Ready for requirements definition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dabit
2026-03-10 14:18:11 +01:00
parent 7035b20ac9
commit 28f86d781c
5 changed files with 2011 additions and 0 deletions

328
.planning/research/STACK.md Normal file
View File

@@ -0,0 +1,328 @@
# Stack Research: HTML5 Canvas Arcade Game (Super Pong Next Gen)
**Domain:** Vanilla HTML5 Canvas arcade game
**Researched:** 2026-03-10
**Confidence:** HIGH
## Recommended Stack
### Core Technologies
| Technology | Version | Purpose | Why Recommended |
|------------|---------|---------|-----------------|
| HTML5 Canvas 2D Context | Built-in | Game rendering and graphics | Native to all modern browsers, perfect for 2D arcade games. Canvas 2D is the standard choice for sprite/particle-based games like Pong with excellent CPU performance and full control over pixel rendering. WebGL adds complexity (requires GLSL shaders and 3D math) without benefit for 2D arcade games. |
| Vanilla JavaScript (ES6+) | Latest | Game logic, input handling, game loop | No framework overhead. Direct Canvas API control. ES6+ provides async/await, arrow functions, and classes for clean game code. This is the standard for shipping static HTML5 games. |
| requestAnimationFrame (RAF) API | Built-in | Main game loop timing | Standard for browser games since 2011. RAF automatically syncs with monitor refresh rate (60 Hz or 120 Hz depending on display), pauses in background tabs (saves battery), and eliminates timing issues with setTimeout/setInterval. All modern browsers support it natively. |
| Fixed Timestep Accumulator Pattern | Custom implementation | Consistent game physics and gameplay | Decouples game simulation (fixed 60 Hz physics) from rendering (variable frame rate). Ensures Pong ball physics, paddle collision, and scoring behave identically across devices with different monitor refresh rates. Prevents "spiral of death" on low-end hardware. Accumulator pattern is the gold standard since Gaffer on Games established it in 2006. |
| Web Audio API | Built-in | Sound effects and music | Native support across all modern browsers. Handles unlimited simultaneous sounds (no 32-sound limit like old <audio> tags). Precise timing control needed for paddle hits, scoring, and power-up sounds. Avoids HTML <audio> tag bloat and pre-loading issues. |
### Supporting Libraries
| Library | Version | Purpose | When to Use |
|---------|---------|---------|-------------|
| GSAP (TweenLite) | v3 | Easing, tweening, animations | Optional for smooth UI animations (menu transitions, score popups, power-up indicators). Only needed if you want sophisticated easing curves beyond linear interpolation. ~20 KB minified. Can be omitted if easing is written manually. |
| None (write particle effects from scratch) | — | Particle effects (screen shake, paddle hits, power-up bursts) | Vanilla JavaScript particle system is only ~200 lines of code. Creates a simple emitter system with velocity, gravity, alpha fade. Gives full control over visual style and performance. Pre-built particle libraries add 10-50 KB for minimal benefit in a 2D arcade game. |
| None (write collision detection from scratch) | — | Collision detection (paddle-ball, ball-wall) | For Pong, only AABB (Axis-Aligned Bounding Box) and circle-rectangle collision needed. Simple math functions (~50 lines total). Physics libraries like Cannon.js are overkill and add 100+ KB. |
### Development Tools
| Tool | Purpose | Notes |
|------|---------|-------|
| Live Server / Python -m http.server | Local development | No build step required. Run `python3 -m http.server` or use VS Code Live Server extension. Canvas and Web Audio require HTTP (not file://) due to CORS and security. |
| Browser DevTools (Chrome/Firefox) | Debugging and profiling | Built-in. Use Performance tab to measure frame rate (aim for 60 fps consistent). Use Network tab to verify static file loads instantly. Use Console for logging game state. |
| No build tools (webpack, vite, esbuild) | Single static file delivery | Avoid build complexity. Ship as `index.html` with inline `<script>` or separate `.js` file. This is the greenfield constraint and strength of this approach. |
## Architecture Patterns
### Game Loop Structure (Recommended Implementation)
```javascript
// Fixed timestep with variable rendering
let lastTime = 0;
let accumulator = 0;
const FIXED_TIMESTEP = 1 / 60; // 60 Hz physics
function gameLoop(currentTime) {
const deltaTime = (currentTime - lastTime) / 1000; // Convert to seconds
lastTime = currentTime;
// Cap deltaTime to prevent spiral of death (max 3 frames worth)
const clampedDelta = Math.min(deltaTime, 3 * FIXED_TIMESTEP);
accumulator += clampedDelta;
// Fixed timestep updates
while (accumulator >= FIXED_TIMESTEP) {
update(FIXED_TIMESTEP); // Physics, collisions, AI
accumulator -= FIXED_TIMESTEP;
}
// Variable rate rendering
render(); // Draw to canvas
requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);
```
**Why this pattern:**
- Physics runs at fixed 60 Hz → identical gameplay on 60 Hz and 144 Hz monitors
- Rendering runs as fast as hardware allows → smooth visuals
- Accumulator prevents frame skipping and ensures no physics updates are missed
- Capped deltaTime prevents "spiral of death" when a frame takes too long
### Particle System Pattern
```javascript
class Particle {
constructor(x, y, vx, vy) {
this.x = x; this.y = y;
this.vx = vx; this.vy = vy;
this.life = 1.0; // Alpha
this.decay = 0.02; // Life per frame
}
update(dt) {
this.x += this.vx * dt;
this.y += this.vy * dt;
this.life -= this.decay * dt;
}
draw(ctx) {
ctx.globalAlpha = this.life;
ctx.fillStyle = 'rgba(255, 200, 0, 1)';
ctx.fillRect(this.x - 2, this.y - 2, 4, 4);
ctx.globalAlpha = 1.0;
}
}
class ParticleEmitter {
constructor() {
this.particles = [];
}
emit(x, y, count = 10) {
for (let i = 0; i < count; i++) {
const angle = (Math.PI * 2 * i) / count;
const speed = 100 + Math.random() * 50;
this.particles.push(
new Particle(x, y, Math.cos(angle) * speed, Math.sin(angle) * speed)
);
}
}
update(dt) {
this.particles = this.particles.filter(p => {
p.update(dt);
return p.life > 0;
});
}
draw(ctx) {
this.particles.forEach(p => p.draw(ctx));
}
}
```
**Why custom:** No external library needed, ~100 lines total, full control over visuals and performance, can emit thousands of particles without hiccup.
### Collision Detection (AABB for Paddles/Ball)
```javascript
// Axis-Aligned Bounding Box collision
function checkAABBCollision(rect1, rect2) {
return rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y;
}
// Circle-Rectangle collision (ball hitting paddle edge)
function checkCircleRectCollision(circle, rect) {
const closestX = Math.max(rect.x, Math.min(circle.x, rect.x + rect.width));
const closestY = Math.max(rect.y, Math.min(circle.y, rect.y + rect.height));
const distX = circle.x - closestX;
const distY = circle.y - closestY;
return (distX * distX + distY * distY) < (circle.radius * circle.radius);
}
```
**Why custom:** These are 10-15 lines of simple math. Physics libraries like Cannon.js add 100+ KB for zero benefit in Pong.
## Alternatives Considered
| Recommended | Alternative | When to Use Alternative |
|-------------|-------------|-------------------------|
| Vanilla JS | Three.js or Babylon.js (WebGL) | Only if game needs 3D rotation, lighting, or 10,000+ on-screen objects. Arcade Pong is 2D, simple geometry → Canvas 2D is faster and easier. |
| Canvas 2D | WebGL 2.0 | Only if game needs advanced shaders, real-time shadow casting, or HDR rendering. For "juicy" 2D arcade effects (particles, glow, screen shake) Canvas 2D is sufficient. |
| Fixed timestep accumulator | Variable timestep (frame-by-frame) | Only for turn-based games where gameplay doesn't depend on consistent physics timing. Pong requires consistent ball physics across all refresh rates → fixed timestep is mandatory. |
| Web Audio API | HTML <audio> tag | Only for narration/long-form audio where streaming is needed. Web Audio is superior for game SFX: no pre-loading, unlimited simultaneous sounds, precise timing, no browser quirks. |
| Custom particle system | Pixi.js (2D rendering library) | Only if game needs 100,000+ animated sprites with sophisticated batching. Pong has <50 particles at once → custom system is overkill. Pixi adds 150+ KB. |
| GSAP (optional) | Manual easing functions | Only if UI animations are sophisticated. For power-up indicators or simple score popups, hand-written easing (ease-in, ease-out) is 5 lines of code. |
## What NOT to Use
| Avoid | Why | Use Instead |
|-------|-----|-------------|
| Phaser, Babylon.js, Cocos2d, Unity WebGL | Overkill for 2D arcade game. Adds 500 KB-2 MB bundle size, build complexity, learning curve, and abstraction layers that make low-level control harder. | Vanilla Canvas 2D + requestAnimationFrame. This is greenfield—ship single HTML file. |
| Webpack, Vite, esbuild, rollup | Build tool complexity defeats purpose of "single static file." Game runs fine without transpilation (ES6+ is supported in all modern browsers since 2015). | Ship as plain HTML + vanilla JS. Keep file structure flat: index.html, styles.css (optional), game.js. |
| Three.js / WebGL | Adds 3D complexity (GLSL shaders, matrix math, GPU programming) for no visual benefit. Pong is 2D rectangles + particles. Canvas 2D renders these faster on CPU. | Stay with Canvas 2D. If you ever need 3D, migrate then (unlikely). |
| Cannon.js, Rapier (Physics engines) | Pong physics is trivial: ball bounces off walls and paddles with simple reflection math. Physics engine overhead (100+ KB, collision manifolds, impulse resolution) is wasted. | Implement ball reflection logic in 20 lines: `ballVx *= -1` for wall hits, angle-based bounce for paddle hits. |
| npm dependencies for utilities | Every npm package adds build friction and bundle size. Helper functions (color conversion, easing, vector math) are simpler to write inline than to manage as dependencies. | Write custom utilities inline. A 2D vector helper is 30 lines. An easing function is 5 lines. |
| Persistent leaderboards / Backend | Out of scope (no server in requirements). Adds deployment complexity and API security concerns. | Store scores in localStorage for local play session only. No remote persistence needed for v1. |
## Stack Patterns by Variant
**If you want polished particle effects and screen shake:**
- Use Web Audio API for impact sounds timed with physics (paddle hit → sfx + particle burst)
- Implement custom ParticleEmitter class (~100 lines)
- Add screen shake via simple canvas translate: `ctx.translate(Math.random() - 0.5, Math.random() - 0.5)`
- This is the path for "visually juicy" requirements in PROJECT.md
**If you want to minimize code and polish:**
- Strip to: Canvas 2D, RAF, Web Audio API (built-in), no particles, basic shapes only
- Trade visual juice for ~500 lines of code
- Not recommended given PROJECT.md emphasis on "makes someone say whoa"
**If you want to add difficulty scaling (AI opponent):**
- Implement AI as simple state machine: track ball, move paddle toward it, add reaction delay
- Use fixed timestep to ensure AI behaves consistently across devices
- AI decision logic lives in update loop, no separate AI library needed
## Version Compatibility
| Package | Version | Notes |
|---------|---------|-------|
| Canvas 2D API | All modern browsers (ES5+) | No version to pin. Available everywhere. |
| requestAnimationFrame | All modern browsers (ES5+) | No version. Standard since 2011. IE 10+ supported. |
| Web Audio API | All modern browsers (2012+) | No version. Safari, Chrome, Firefox, Edge all current versions support it fully. |
| GSAP TweenLite (if used) | v3+ | v3 is lightweight (~40 KB minified). Can be loaded from CDN or skipped entirely. No peer dependencies. |
| JavaScript language | ES6+ | Modern syntax. All deployment targets support ES6+ (Chrome 51+, Firefox 54+, Safari 10+, Edge 15+). No transpilation needed. |
## Installation (No Build Required)
```html
<!-- Minimal setup: index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Super Pong Next Gen</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { margin: 0; overflow: hidden; background: #111; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<!-- Optional: GSAP TweenLite for UI animations -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<!-- Game code -->
<script src="game.js"></script>
</body>
</html>
```
**To run locally (no build step):**
```bash
# Option 1: Python (built-in)
python3 -m http.server 8000
# Option 2: Node.js (if installed)
npx http-server
# Option 3: VS Code Live Server extension (GUI click)
```
Then open `http://localhost:8000` in browser.
**No npm, no build tools, no transpilation needed.** The constraint is a feature—maximizes portability and minimizes deployment surface area.
## Critical Decisions
### Canvas 2D, Not WebGL
**Decision:** Use Canvas 2D API exclusively.
**Reasoning:**
- Pong is pure 2D (rectangles, circles, particles)
- Canvas 2D has zero startup cost, WebGL requires GLSL shader compilation
- Canvas 2D draws millions of pixels per frame efficiently on CPU
- WebGL overkill: no 3D transforms, no complex lighting, no real-time shadow maps
- Canvas 2D is familiar to JavaScript devs (no GPU programming knowledge needed)
- Performance: Canvas 2D renders 2D arcade games faster than WebGL on mid-range hardware
**Outcome:** Single canvas element, 2D context. All graphics drawn with fillRect, fillCircle, drawImage (if sprites).
### Fixed Timestep Over Variable Timestep
**Decision:** Implement fixed 60 Hz physics timestep with variable rendering refresh rate.
**Reasoning:**
- Ensures ball physics are identical on 60 Hz monitors and 144 Hz monitors
- Prevents "bounce randomness" that breaks game feel
- Accumulator pattern handles frame skipping without losing physics updates
- Is the standard for physics-based games since 2006 (Gaffer on Games)
- Prevents "spiral of death" on low-end hardware (capped deltaTime)
**Outcome:** Game loop uses accumulator. Physics updates in fixed increments, rendering as fast as hardware allows.
### Web Audio API, Not HTML <audio>
**Decision:** Use Web Audio API for all sound.
**Reasoning:**
- No pre-loading required (unlike <audio> tags which need preload attributes and suffer quirks)
- Unlimited simultaneous sounds (no 32-sound limit)
- Precise timing control needed for game feel (paddle hit → instant sfx feedback)
- Single API handles both sound effects and dynamic music
- Works offline and in Service Workers
**Outcome:** Create AudioContext, use Web Audio nodes for synthesis or sample playback.
### No External Game Engine or Physics Library
**Decision:** Custom implementation of game loop, collision detection, and particle effects.
**Reasoning:**
- Phaser/Babylon.js add 500 KB-2 MB for features Pong doesn't use
- Collision detection is trivial (AABB + circle-rect = 20 lines)
- Particle system is 100 lines of simple code
- Keeping code hand-written gives full control, understanding, and minimum bundle
- Greenfield constraint: single static file = no build toolchain
**Outcome:** ~1000-1500 lines of game code total. No dependencies. Portable everywhere.
## Deployment Constraints
- **Single file delivery:** HTML file can inline CSS and JavaScript or load them as separate files
- **No server required:** Can be hosted on GitHub Pages, Netlify, or any static host
- **No build step:** Can edit game.js, reload browser, see changes instantly
- **Browser compatibility:** Target modern browsers (Chrome 90+, Firefox 88+, Safari 14+, Edge 90+)
## Sources
- [MDN Canvas API & 2D Context](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API) — Core Canvas rendering specification
- [MDN requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) — Game loop timing standard
- [MDN Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) — Game sound implementation
- [Gaffer on Games: Fix Your Timestep](https://gafferongames.com/post/fix_your_timestep/) — Fixed timestep pattern (2004, still standard)
- [MDN 2D Collision Detection](https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection) — AABB and circle collision algorithms
- [Animation and Game Development with HTML5 Canvas](https://medium.com/@TechnologyDiaries/animation-and-game-development-with-html5-canvas-f0c599312a00) — 2025 Canvas best practices (Medium)
- [Create a Proper Game Loop](https://spicyyoghurt.com/tutorials/html5-javascript-game-development/create-a-proper-game-loop-with-requestanimationframe) — Game loop implementation patterns
- [Taming Time in Game Engines](https://andreleite.com/posts/2025/game-loop/fixed-timestep-game-loop/) — 2025 fixed timestep deep dive
- [GSAP Documentation](https://gsap.com/docs/v3/GSAP/Tween/) — Tweening library (optional for UI)
- [WebGL vs Canvas: Best Choice](https://altersquare.io/webgl-vs-canvas-best-choice-for-browser-based-cad-tools/) — Canvas 2D vs WebGL decision framework
- [I Built 120 HTML5 Games Using Pure Canvas](https://dev.to/cannan_david/i-built-120-html5-games-using-pure-canvas-no-frameworks-gdm) — Real-world evidence of vanilla Canvas viability
- [MDN 2D Breakout Game Tutorial](https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript) — Step-by-step vanilla Canvas game example
---
*Stack research for: Super Pong Next Gen (HTML5 Canvas arcade game)*
*Researched: 2026-03-10*
*Confidence: HIGH*