aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGene Pasquet <dev@etenil.net>2026-04-05 17:28:27 +0100
committerGene Pasquet <dev@etenil.net>2026-04-05 17:28:27 +0100
commit927f37639a3d5a0d881a5c8709f2cf577aadb15e (patch)
treee15dbd416ec2f0ed35846088f2b12558c9d64407
parentce948bd4b2a16cd0ee6f6a1f2115c52e1f83fce4 (diff)
docs: add demo games design spec
5 demos covering all engine systems: platformer, shmup, topdown, audio showcase, physics sandbox. Shared demo/assets/ copied from macroknight. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--docs/superpowers/specs/2026-04-05-demos-design.md223
1 files changed, 223 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-04-05-demos-design.md b/docs/superpowers/specs/2026-04-05-demos-design.md
new file mode 100644
index 0000000..f51f260
--- /dev/null
+++ b/docs/superpowers/specs/2026-04-05-demos-design.md
@@ -0,0 +1,223 @@
+# Downstroke Demo Games Design
+
+**Date:** 2026-04-05
+**Status:** Approved
+**Scope:** `demo/` folder, 5 demo games, Makefile `make demos` target, CLAUDE.md update
+
+---
+
+## Goal
+
+Provide 5 small self-contained demo games in `demo/` that collectively exercise every engine system. Each demo compiles to its own executable (`bin/demo-*`). They replace the macroknight integration test for Milestone 8 and serve as living documentation of the engine API.
+
+---
+
+## File Layout
+
+```
+demo/
+ assets/ ← copied from macroknight/assets (not symlinked)
+ monochrome-transparent.png ← tileset spritesheet
+ monochrome_transparent.tsx ← tileset metadata (TSX)
+ level-0.tmx ← level used by platformer, topdown, sandbox
+ DejaVuSans.ttf ← font for audio demo text
+ jump.wav ← sound effect (platformer jump, shmup shoot)
+ theme.ogg ← music (audio demo)
+ platformer.scm
+ shmup.scm
+ topdown.scm
+ audio.scm
+ sandbox.scm
+```
+
+**Omitted from copy:** `prefabs.scm`, `macroknight.tiled-project`, `macroknight.tiled-session` — macroknight-specific files not needed by any demo.
+
+---
+
+## Build
+
+### Makefile additions
+
+```makefile
+DEMO_NAMES := platformer shmup topdown audio sandbox
+DEMO_BINS := $(patsubst %,bin/demo-%,$(DEMO_NAMES))
+
+demos: engine $(DEMO_BINS)
+
+bin/demo-%: demo/%.scm $(OBJECT_FILES) | bin
+ csc demo/$*.scm $(OBJECT_FILES) -o bin/demo-$* -I bin
+```
+
+- `make` — builds engine modules only (unchanged)
+- `make demos` — builds all 5 demo executables; depends on engine being built first
+- Demos are compiled as programs (not units), linked against all engine `.o` files
+
+### CLAUDE.md update
+
+Add to the Build & Test section:
+
+> `make demos` must always succeed. A demo that fails to compile is a build failure. Run `make && make demos` to verify both engine and demos build cleanly.
+
+---
+
+## Demo Code Pattern
+
+Every demo follows this ~30-line structure:
+
+```scheme
+(import (prefix sdl2 "sdl2:")
+ (prefix sdl2-ttf "ttf:")
+ (prefix sdl2-image "img:")
+ downstroke/engine
+ downstroke/world
+ downstroke/tilemap
+ downstroke/renderer
+ downstroke/input
+ downstroke/physics
+ downstroke/assets)
+
+(define *game*
+ (make-game
+ title: "Demo: <Name>" width: 600 height: 400
+ preload: (lambda (game) ...) ;; load tilemap, tileset texture, sounds
+ create: (lambda (game) ...) ;; build scene, place entities
+ update: (lambda (game dt) ...) ;; input dispatch, physics calls
+ render: (lambda (game) ...))) ;; HUD overlay (optional)
+
+(game-run! *game*)
+```
+
+Tile IDs in entity plists are placeholder values — to be adjusted visually after first run.
+
+---
+
+## The 5 Demos
+
+### 1. `demo/platformer.scm` — Platformer
+
+**Systems exercised:** `input`, `physics` (gravity + tile collision), `renderer` (tilemap + entities), `world`/scene, camera follow, audio (sound effect)
+
+**Mechanics:**
+- Player entity with gravity, left/right movement, jump
+- Tile collision via `apply-physics` from `physics.scm`
+- Camera follows player horizontally
+- Jump sound via macroknight's `sound.scm` (or direct SDL_mixer call)
+- Level: `demo/assets/level-0.tmx`
+- Tile IDs: placeholder (user adjusts)
+
+**Key entity plist:**
+```scheme
+(list #:type 'player
+ #:x 100 #:y 50
+ #:width 16 #:height 16
+ #:vx 0 #:vy 0
+ #:gravity? #t
+ #:on-ground? #f
+ #:tile-id 1)
+```
+
+**Update logic:** read input → set `#:vx` from left/right → jump sets `#:vy` → call physics step → update camera x to follow player x.
+
+---
+
+### 2. `demo/shmup.scm` — Shoot-em-up
+
+**Systems exercised:** `entity` (spawning/removal), entity-entity collision via `physics.scm`, `input`, `renderer`, `world`/scene (no tilemap)
+
+**Mechanics:**
+- Player ship at bottom, moves left/right
+- Space bar fires bullet upward (new entity added to scene)
+- Enemies spawn from top at random x positions every N frames, move downward
+- Bullet-enemy collision: both entities removed from scene
+- No tilemap — plain background (black/SDL clear)
+- No gravity on any entity
+- `jump.wav` plays on shoot
+
+**Key entity plists:**
+```scheme
+;; player
+(list #:type 'player #:x 280 #:y 360 #:width 16 #:height 16 #:vx 0 #:vy 0 #:tile-id 2)
+;; bullet
+(list #:type 'bullet #:x px #:y 340 #:width 4 #:height 8 #:vx 0 #:vy -5 #:tile-id 3)
+;; enemy
+(list #:type 'enemy #:x rx #:y 0 #:width 16 #:height 16 #:vx 0 #:vy 2 #:tile-id 4)
+```
+
+**Update logic:** move entities by vx/vy each frame → AABB collision check between bullets and enemies → filter dead entities from scene → spawn new enemy every 60 frames → read input for player movement and shoot.
+
+---
+
+### 3. `demo/topdown.scm` — Top-down explorer
+
+**Systems exercised:** `input` (8-directional), `renderer` (tilemap + entity), `world`/scene, camera follow (both axes), `physics` (no gravity)
+
+**Mechanics:**
+- Player entity moves in 8 directions (WASD or arrows)
+- No gravity (`#:gravity? #f`)
+- Camera follows player on both x and y axes
+- Level: `demo/assets/level-0.tmx` (same tilemap, different movement feel)
+- No audio
+
+**Update logic:** read input → set `#:vx` and `#:vy` from direction keys → apply tile collision (no gravity component) → update camera to center on player.
+
+---
+
+### 4. `demo/audio.scm` — Audio showcase
+
+**Systems exercised:** audio (sound effects + music), `renderer` (text via `draw-ui-text`), `input`, `assets`
+
+**Mechanics:**
+- Static screen with text instructions rendered via `draw-ui-text`
+- Press **J** → play `jump.wav`
+- Press **M** → toggle `theme.ogg` music on/off
+- Press **Escape** → quit
+- No tilemap, no physics, no moving entities
+- Uses `DejaVuSans.ttf` for text
+- Audio calls via macroknight's `sound.scm` functions (`load-sounds!`, `play-sound!`, `load-music!`, `play-music!`, `stop-music!`) — or direct SDL_mixer FFI if sound.scm is not available
+
+**Display:** colored rectangle background + text labels for each key binding.
+
+---
+
+### 5. `demo/sandbox.scm` — Physics sandbox
+
+**Systems exercised:** `physics` (gravity + tile collision + entity-entity collision), `renderer`, `world`/scene, no player input
+
+**Mechanics:**
+- 10 entities spawned at random x positions near the top of the screen
+- All have `#:gravity? #t`
+- Physics step runs each frame (gravity accelerates, tile collision stops them)
+- Entities rest on floor tiles or bounce (depending on physics.scm behavior)
+- No player — pure observation of physics pipeline
+- Level: `demo/assets/level-0.tmx`
+- After all entities settle (or after 10 seconds), loop: despawn all, respawn at new random positions
+
+---
+
+## Systems Coverage Matrix
+
+| System / Module | platformer | shmup | topdown | audio | sandbox |
+|---|---|---|---|---|---|
+| `engine` (make-game, game-run!) | ✓ | ✓ | ✓ | ✓ | ✓ |
+| `input` | ✓ | ✓ | ✓ | ✓ | — |
+| `physics` (gravity) | ✓ | — | — | — | ✓ |
+| `physics` (tile collision) | ✓ | — | ✓ | — | ✓ |
+| `physics` (entity collision) | — | ✓ | — | — | ✓ |
+| `renderer` (tilemap) | ✓ | — | ✓ | — | ✓ |
+| `renderer` (entities) | ✓ | ✓ | ✓ | — | ✓ |
+| `renderer` (text) | — | — | — | ✓ | — |
+| `world` / scene | ✓ | ✓ | ✓ | — | ✓ |
+| `assets` registry | ✓ | ✓ | ✓ | ✓ | ✓ |
+| audio (sound) | ✓ | ✓ | — | ✓ | — |
+| audio (music) | — | — | — | ✓ | — |
+| camera follow | ✓ (x) | — | ✓ (xy) | — | — |
+
+---
+
+## Out of Scope
+
+- Animation state machine (`animation.scm`) — not yet extracted to downstroke
+- AI (`ai.scm`) — not yet extracted
+- Prefab system — not yet extracted
+- Scene transitions — Milestone 9
+- Asset-type-specific load helpers (`game-load-tilemap!` etc.) — Milestone 6