3.3 KiB
DECISIONS.md — Iron Requiem Architecture Tradeoffs
This document records the "Why" behind the technical and design choices.
1. Phaser CANVAS vs WEBGL
Decision: Phaser.CANVAS (Primary) with Phaser.WEBGL (Fallback).
Rationale: To achieve a strict, crisp pixel-art look without sub-pixel blurring or bleeding, CANVAS is more predictable. WEBGL is kept as a fallback for high-projectile counts if the CPU-bound CANVAS renderer hits a bottleneck.
2. Top-Down vs Side-Scroller
Decision: Top-Down. Rationale: The "Tank-as-Character" feel (separate hull/turret movement) and the bullet-hell dodging patterns are natively suited for a 2D plane. Side-scrolling would simplify the tactical positioning and the periscope vision mechanic.
3. IndexedDB vs localStorage
Decision: IndexedDB.
Rationale: localStorage is synchronous and limited to ~5MB. Ghost crew data, detailed run stats, and narrative flags will grow beyond this. IndexedDB allows asynchronous, structured storage that doesn't block the main game loop.
4. Static Hosting vs Backend Server
Decision: Static Assets Only (HTML/JS/Sprites/Audio). Rationale: Zero server costs and maximum availability. By pushing all state to the client (IndexedDB), the game removes the need for user accounts, database management, and API latency.
5. Internal Resolution (640x360 vs 480x270)
Decision: 640x360. Rationale: Provides a better balance between the "lo-fi" pixel aesthetic and the need for tactical visibility. Scale to 720p/1080p is a clean integer multiplier (2x/3x), preventing shimmering.
6. Hull/Turret as Separate Arcade.Sprites vs Single Sprite
Decision: Separate Arcade.Sprites.
Rationale: Decoupling allows independent rotation logic and physics for the hull, while the turret simply follows the hull center. This simplifies the "feel" of a 25-ton machine and avoids complex frame-by-frame sprite sheets for every possible turret angle.
7. Canvas Mask vs CSS clip-path for Periscope
Decision: Phaser Graphics Mask.
Rationale: CSS clip-paths are performed outside the game loop and are difficult to synchronize with the game's internal coordinate system and rotation. A Phaser mask keeps everything within the rendering pipeline.
8. Tea CLI vs GitHub CLI for Gitea
Decision: Tea CLI.
Rationale: GitHub CLI (gh) does not natively support Gitea's API without brittle workarounds. tea is purpose-built for Gitea and already configured on this machine (~/.config/tea/config.yml) with a working API token. Use tea for all milestone, issue, label, and repo management operations against git.homelab.local. Git operations (clone/push) use embedded token in remote URL.
9. Docker + Traefik vs Baremetal Nginx
Decision: Docker + Traefik. Rationale: Ensures parity between the developer's local environment and the home-server production environment. Traefik provides automated SSL and routing via Cloudflare Tunnels without manual config files.
10. Object Pooling vs Dynamic Create/Destroy for Projectiles
Decision: Phaser.Physics.Arcade.Group (Object Pooling).
Rationale: In a bullet hell, creating/destroying 200+ projectiles per second would trigger frequent Garbage Collection (GC) pauses, causing "stutter" (jank). Pooling keeps memory stable and ensures a consistent 60fps.