aboutsummaryrefslogtreecommitdiff
path: root/docs/superpowers/specs/2026-04-05-demos-design.md
blob: f51f260fd88b3ea31816a8d59f0ebd5f69c98111 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
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