diff --git a/art/sprites/README.md b/art/sprites/README.md index 1ffe1bd..f65ebf4 100644 --- a/art/sprites/README.md +++ b/art/sprites/README.md @@ -18,3 +18,4 @@ Sprite reference boards: the hero sheet (approved) and the animation, enemy, ite | [![FX · falling leaves](images/fx-leaves-preview.png)](fx-leaves.md)
**[FX · falling leaves](fx-leaves.md)** | [![FX · footstep puffs](images/fx-ground-preview.png)](fx-ground.md)
**[FX · footstep puffs](fx-ground.md)** | | [![FX · pond ripples and lily pad](images/fx-water-preview.png)](fx-water.md)
**[FX · pond ripples and lily pad](fx-water.md)** | [![Dexter · prologue additions](images/dexter-prologue-preview.png)](dexter-prologue.md)
**[Dexter · prologue additions](dexter-prologue.md)** | | [![Menu · the Hidden Garden at first light](images/menu-key-preview.png)](menu-key.md)
**[Menu · the Hidden Garden at first light](menu-key.md)** | [![Props · the storm drain's IT details](images/it-props-preview.png)](it-props.md)
**[Props · the storm drain's IT details](it-props.md)** | +| [![Secret · the rubber chicken](images/rubber-chicken-preview.png)](rubber-chicken.md)
**[Secret · the rubber chicken](rubber-chicken.md)** | | diff --git a/art/sprites/boards.json b/art/sprites/boards.json index e17c134..8b22525 100644 --- a/art/sprites/boards.json +++ b/art/sprites/boards.json @@ -1170,6 +1170,33 @@ ] }, "review": "🟨 Awaiting Alexander's review (25 Oct). First draw: three distinct props in the food sheet's look. The board's 1 px balloon string broke up when crushed, so the game draws the string; the eyes are two pieces per frame (\"parts\": 2). Sizes per animation: balloon about 18 px, eyes 7 px, boat 9 px against the 76 px hero. In the drain: previews/it-props-in-drain.png." + }, + { + "id": "rubber-chicken", + "title": "Secret · the rubber chicken", + "factor": 2, + "inputs": [ + "repo:art/sprites/images/mensa-food-preview.png", + "repo:art/direction/images/style-master-preview.png" + ], + "prompt": "On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground shadows, no dust under the objects), with NO text at all - no titles, no captions, no frame numbers, no labels, no readable words or logos: Image 1 is an approved prop sheet from this game: draw this sheet in exactly that pixel-art look - small detailed props on magenta, the same pixel grain and the same soft warm rim light. Prop sprite sheet of ONE classic squeaky RUBBER CHICKEN toy - the long-necked plucked yellow rubber chicken with a red comb, an open orange beak, tiny closed eyes, skinny dangling legs - lying on its side on the ground, side view, slightly worn and dusty as if it had been lost in a garden for a while. 1 row, exactly 2 frames: frame 1 resting, frame 2 the same chicken squeezed in the middle, its body pinched thin and its beak wide open mid-squeak, neck stretched. Both frames at the SAME pixel scale, standing on the SAME invisible ground line, evenly spaced with a wide clear magenta gap between them. Draw distinct key poses. Count the frames: the row has EXACTLY 2. No people, no hands, no scenery.", + "atlas": { + "height": 9, + "rows": [ + [ + { + "anim": "rest", + "frames": 1 + }, + { + "anim": "squeak", + "frames": 1, + "loop": false + } + ] + ] + }, + "review": "🟨 Awaiting Alexander's review (25 Oct). Playtest T2 (Lex): the rubber chicken must be in the game. First draw, two frames (resting, squeezed mid-squeak); about 34 x 9 px in the game, a little bigger than a real one so it reads next to the 76 px hero." } ] } diff --git a/art/sprites/boss-jenny-2.md b/art/sprites/boss-jenny-2.md index f0693e3..521ba86 100644 --- a/art/sprites/boss-jenny-2.md +++ b/art/sprites/boss-jenny-2.md @@ -1,7 +1,7 @@ # Boss · Jenny, stunned and debris -[← Boss · Jenny, attacks](boss-jenny.md) · [Sprite boards](README.md) · **17 / 28** · [Item · pocket computer →](pocket-computer.md) +[← Boss · Jenny, attacks](boss-jenny.md) · [Sprite boards](README.md) · **17 / 29** · [Item · pocket computer →](pocket-computer.md) ![Boss · Jenny, stunned and debris](images/boss-jenny-2-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/boss-jenny-2.png` · rebuild: `python scripts/make_boards.py draw boss-jenny-2 --redo --config art/sprites/boards.json` -[← Boss · Jenny, attacks](boss-jenny.md) · [Sprite boards](README.md) · **17 / 28** · [Item · pocket computer →](pocket-computer.md) +[← Boss · Jenny, attacks](boss-jenny.md) · [Sprite boards](README.md) · **17 / 29** · [Item · pocket computer →](pocket-computer.md) diff --git a/art/sprites/boss-jenny.md b/art/sprites/boss-jenny.md index ea99c18..f03ded6 100644 --- a/art/sprites/boss-jenny.md +++ b/art/sprites/boss-jenny.md @@ -1,7 +1,7 @@ # Boss · Jenny, attacks -[← FX · black fluid](fx.md) · [Sprite boards](README.md) · **16 / 28** · [Boss · Jenny, stunned and debris →](boss-jenny-2.md) +[← FX · black fluid](fx.md) · [Sprite boards](README.md) · **16 / 29** · [Boss · Jenny, stunned and debris →](boss-jenny-2.md) ![Boss · Jenny, attacks](images/boss-jenny-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/boss-jenny.png` · rebuild: `python scripts/make_boards.py draw boss-jenny --redo --config art/sprites/boards.json` -[← FX · black fluid](fx.md) · [Sprite boards](README.md) · **16 / 28** · [Boss · Jenny, stunned and debris →](boss-jenny-2.md) +[← FX · black fluid](fx.md) · [Sprite boards](README.md) · **16 / 29** · [Boss · Jenny, stunned and debris →](boss-jenny-2.md) diff --git a/art/sprites/chair-block.md b/art/sprites/chair-block.md index d1a77c7..f3fdbc1 100644 --- a/art/sprites/chair-block.md +++ b/art/sprites/chair-block.md @@ -1,7 +1,7 @@ # Chair · block -[← Chair · overhead slam](chair-overhead.md) · [Sprite boards](README.md) · **11 / 28** · [Enemy · drone →](enemy-drone.md) +[← Chair · overhead slam](chair-overhead.md) · [Sprite boards](README.md) · **11 / 29** · [Enemy · drone →](enemy-drone.md) ![Chair · block](images/chair-block-preview.png) @@ -30,5 +30,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/chair-block.png` · rebuild: `python scripts/make_boards.py draw chair-block --redo --config art/sprites/boards.json` -[← Chair · overhead slam](chair-overhead.md) · [Sprite boards](README.md) · **11 / 28** · [Enemy · drone →](enemy-drone.md) +[← Chair · overhead slam](chair-overhead.md) · [Sprite boards](README.md) · **11 / 29** · [Enemy · drone →](enemy-drone.md) diff --git a/art/sprites/chair-overhead.md b/art/sprites/chair-overhead.md index 04c3eb2..4b9385c 100644 --- a/art/sprites/chair-overhead.md +++ b/art/sprites/chair-overhead.md @@ -1,7 +1,7 @@ # Chair · overhead slam -[← Chair · side sweep](chair-side.md) · [Sprite boards](README.md) · **10 / 28** · [Chair · block →](chair-block.md) +[← Chair · side sweep](chair-side.md) · [Sprite boards](README.md) · **10 / 29** · [Chair · block →](chair-block.md) ![Chair · overhead slam](images/chair-overhead-preview.png) @@ -31,5 +31,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/chair-overhead.png` · rebuild: `python scripts/make_boards.py draw chair-overhead --redo --config art/sprites/boards.json` -[← Chair · side sweep](chair-side.md) · [Sprite boards](README.md) · **10 / 28** · [Chair · block →](chair-block.md) +[← Chair · side sweep](chair-side.md) · [Sprite boards](README.md) · **10 / 29** · [Chair · block →](chair-block.md) diff --git a/art/sprites/chair-side.md b/art/sprites/chair-side.md index 1ddcd98..83e3229 100644 --- a/art/sprites/chair-side.md +++ b/art/sprites/chair-side.md @@ -1,7 +1,7 @@ # Chair · side sweep -[← The student · ladder top and bottom](hero-ladder.md) · [Sprite boards](README.md) · **9 / 28** · [Chair · overhead slam →](chair-overhead.md) +[← The student · ladder top and bottom](hero-ladder.md) · [Sprite boards](README.md) · **9 / 29** · [Chair · overhead slam →](chair-overhead.md) ![Chair · side sweep](images/chair-side-preview.png) @@ -30,5 +30,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/chair-side.png` · rebuild: `python scripts/make_boards.py draw chair-side --redo --config art/sprites/boards.json` -[← The student · ladder top and bottom](hero-ladder.md) · [Sprite boards](README.md) · **9 / 28** · [Chair · overhead slam →](chair-overhead.md) +[← The student · ladder top and bottom](hero-ladder.md) · [Sprite boards](README.md) · **9 / 29** · [Chair · overhead slam →](chair-overhead.md) diff --git a/art/sprites/coffee-machine.md b/art/sprites/coffee-machine.md index 6c766d5..576d057 100644 --- a/art/sprites/coffee-machine.md +++ b/art/sprites/coffee-machine.md @@ -1,7 +1,7 @@ # Prop · coffee machine (save point) -[← Mensa · food pickups](mensa-food.md) · [Sprite boards](README.md) · **20 / 28** · [Dexter · moves →](dexter.md) +[← Mensa · food pickups](mensa-food.md) · [Sprite boards](README.md) · **20 / 29** · [Dexter · moves →](dexter.md) ![Prop · coffee machine (save point)](images/coffee-machine-preview.png) @@ -27,5 +27,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/coffee-machine.png` · rebuild: `python scripts/make_boards.py draw coffee-machine --redo --config art/sprites/boards.json` -[← Mensa · food pickups](mensa-food.md) · [Sprite boards](README.md) · **20 / 28** · [Dexter · moves →](dexter.md) +[← Mensa · food pickups](mensa-food.md) · [Sprite boards](README.md) · **20 / 29** · [Dexter · moves →](dexter.md) diff --git a/art/sprites/dexter-acts.md b/art/sprites/dexter-acts.md index 2d07461..dbba39d 100644 --- a/art/sprites/dexter-acts.md +++ b/art/sprites/dexter-acts.md @@ -1,7 +1,7 @@ # Dexter · gestures -[← Dexter · moves](dexter.md) · [Sprite boards](README.md) · **22 / 28** · [FX · falling leaves →](fx-leaves.md) +[← Dexter · moves](dexter.md) · [Sprite boards](README.md) · **22 / 29** · [FX · falling leaves →](fx-leaves.md) ![Dexter · gestures](images/dexter-acts-preview.png) @@ -30,5 +30,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/dexter-acts.png` · rebuild: `python scripts/make_boards.py draw dexter-acts --redo --config art/sprites/boards.json` -[← Dexter · moves](dexter.md) · [Sprite boards](README.md) · **22 / 28** · [FX · falling leaves →](fx-leaves.md) +[← Dexter · moves](dexter.md) · [Sprite boards](README.md) · **22 / 29** · [FX · falling leaves →](fx-leaves.md) diff --git a/art/sprites/dexter-prologue.md b/art/sprites/dexter-prologue.md index ab4b37f..3feda47 100644 --- a/art/sprites/dexter-prologue.md +++ b/art/sprites/dexter-prologue.md @@ -1,7 +1,7 @@ # Dexter · prologue additions -[← FX · pond ripples and lily pad](fx-water.md) · [Sprite boards](README.md) · **26 / 28** · [Menu · the Hidden Garden at first light →](menu-key.md) +[← FX · pond ripples and lily pad](fx-water.md) · [Sprite boards](README.md) · **26 / 29** · [Menu · the Hidden Garden at first light →](menu-key.md) ![Dexter · prologue additions](images/dexter-prologue-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/dexter-prologue.png` · rebuild: `python scripts/make_boards.py draw dexter-prologue --redo --config art/sprites/boards.json` -[← FX · pond ripples and lily pad](fx-water.md) · [Sprite boards](README.md) · **26 / 28** · [Menu · the Hidden Garden at first light →](menu-key.md) +[← FX · pond ripples and lily pad](fx-water.md) · [Sprite boards](README.md) · **26 / 29** · [Menu · the Hidden Garden at first light →](menu-key.md) diff --git a/art/sprites/dexter.md b/art/sprites/dexter.md index 39e0854..46db0a2 100644 --- a/art/sprites/dexter.md +++ b/art/sprites/dexter.md @@ -1,7 +1,7 @@ # Dexter · moves -[← Prop · coffee machine (save point)](coffee-machine.md) · [Sprite boards](README.md) · **21 / 28** · [Dexter · gestures →](dexter-acts.md) +[← Prop · coffee machine (save point)](coffee-machine.md) · [Sprite boards](README.md) · **21 / 29** · [Dexter · gestures →](dexter-acts.md) ![Dexter · moves](images/dexter-preview.png) @@ -30,5 +30,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/dexter.png` · rebuild: `python scripts/make_boards.py draw dexter --redo --config art/sprites/boards.json` -[← Prop · coffee machine (save point)](coffee-machine.md) · [Sprite boards](README.md) · **21 / 28** · [Dexter · gestures →](dexter-acts.md) +[← Prop · coffee machine (save point)](coffee-machine.md) · [Sprite boards](README.md) · **21 / 29** · [Dexter · gestures →](dexter-acts.md) diff --git a/art/sprites/enemy-crab.md b/art/sprites/enemy-crab.md index 8487f8a..38906db 100644 --- a/art/sprites/enemy-crab.md +++ b/art/sprites/enemy-crab.md @@ -1,7 +1,7 @@ # Enemy · crab -[← Enemy · rover](enemy-rover.md) · [Sprite boards](README.md) · **14 / 28** · [FX · black fluid →](fx.md) +[← Enemy · rover](enemy-rover.md) · [Sprite boards](README.md) · **14 / 29** · [FX · black fluid →](fx.md) ![Enemy · crab](images/enemy-crab-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/enemy-crab.png` · rebuild: `python scripts/make_boards.py draw enemy-crab --redo --config art/sprites/boards.json` -[← Enemy · rover](enemy-rover.md) · [Sprite boards](README.md) · **14 / 28** · [FX · black fluid →](fx.md) +[← Enemy · rover](enemy-rover.md) · [Sprite boards](README.md) · **14 / 29** · [FX · black fluid →](fx.md) diff --git a/art/sprites/enemy-drone.md b/art/sprites/enemy-drone.md index 404cf3b..4d2b4b1 100644 --- a/art/sprites/enemy-drone.md +++ b/art/sprites/enemy-drone.md @@ -1,7 +1,7 @@ # Enemy · drone -[← Chair · block](chair-block.md) · [Sprite boards](README.md) · **12 / 28** · [Enemy · rover →](enemy-rover.md) +[← Chair · block](chair-block.md) · [Sprite boards](README.md) · **12 / 29** · [Enemy · rover →](enemy-rover.md) ![Enemy · drone](images/enemy-drone-preview.png) @@ -30,5 +30,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/enemy-drone.png` · rebuild: `python scripts/make_boards.py draw enemy-drone --redo --config art/sprites/boards.json` -[← Chair · block](chair-block.md) · [Sprite boards](README.md) · **12 / 28** · [Enemy · rover →](enemy-rover.md) +[← Chair · block](chair-block.md) · [Sprite boards](README.md) · **12 / 29** · [Enemy · rover →](enemy-rover.md) diff --git a/art/sprites/enemy-rover.md b/art/sprites/enemy-rover.md index dea7a5e..8976818 100644 --- a/art/sprites/enemy-rover.md +++ b/art/sprites/enemy-rover.md @@ -1,7 +1,7 @@ # Enemy · rover -[← Enemy · drone](enemy-drone.md) · [Sprite boards](README.md) · **13 / 28** · [Enemy · crab →](enemy-crab.md) +[← Enemy · drone](enemy-drone.md) · [Sprite boards](README.md) · **13 / 29** · [Enemy · crab →](enemy-crab.md) ![Enemy · rover](images/enemy-rover-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/enemy-rover.png` · rebuild: `python scripts/make_boards.py draw enemy-rover --redo --config art/sprites/boards.json` -[← Enemy · drone](enemy-drone.md) · [Sprite boards](README.md) · **13 / 28** · [Enemy · crab →](enemy-crab.md) +[← Enemy · drone](enemy-drone.md) · [Sprite boards](README.md) · **13 / 29** · [Enemy · crab →](enemy-crab.md) diff --git a/art/sprites/fx-ground.md b/art/sprites/fx-ground.md index 0b10d87..717f2cb 100644 --- a/art/sprites/fx-ground.md +++ b/art/sprites/fx-ground.md @@ -1,7 +1,7 @@ # FX · footstep puffs -[← FX · falling leaves](fx-leaves.md) · [Sprite boards](README.md) · **24 / 28** · [FX · pond ripples and lily pad →](fx-water.md) +[← FX · falling leaves](fx-leaves.md) · [Sprite boards](README.md) · **24 / 29** · [FX · pond ripples and lily pad →](fx-water.md) ![FX · footstep puffs](images/fx-ground-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/fx-ground.png` · rebuild: `python scripts/make_boards.py draw fx-ground --redo --config art/sprites/boards.json` -[← FX · falling leaves](fx-leaves.md) · [Sprite boards](README.md) · **24 / 28** · [FX · pond ripples and lily pad →](fx-water.md) +[← FX · falling leaves](fx-leaves.md) · [Sprite boards](README.md) · **24 / 29** · [FX · pond ripples and lily pad →](fx-water.md) diff --git a/art/sprites/fx-leaves.md b/art/sprites/fx-leaves.md index 2a8b0df..f6b0423 100644 --- a/art/sprites/fx-leaves.md +++ b/art/sprites/fx-leaves.md @@ -1,7 +1,7 @@ # FX · falling leaves -[← Dexter · gestures](dexter-acts.md) · [Sprite boards](README.md) · **23 / 28** · [FX · footstep puffs →](fx-ground.md) +[← Dexter · gestures](dexter-acts.md) · [Sprite boards](README.md) · **23 / 29** · [FX · footstep puffs →](fx-ground.md) ![FX · falling leaves](images/fx-leaves-preview.png) @@ -29,5 +29,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/fx-leaves.png` · rebuild: `python scripts/make_boards.py draw fx-leaves --redo --config art/sprites/boards.json` -[← Dexter · gestures](dexter-acts.md) · [Sprite boards](README.md) · **23 / 28** · [FX · footstep puffs →](fx-ground.md) +[← Dexter · gestures](dexter-acts.md) · [Sprite boards](README.md) · **23 / 29** · [FX · footstep puffs →](fx-ground.md) diff --git a/art/sprites/fx-water.md b/art/sprites/fx-water.md index d768b26..0955222 100644 --- a/art/sprites/fx-water.md +++ b/art/sprites/fx-water.md @@ -1,7 +1,7 @@ # FX · pond ripples and lily pad -[← FX · footstep puffs](fx-ground.md) · [Sprite boards](README.md) · **25 / 28** · [Dexter · prologue additions →](dexter-prologue.md) +[← FX · footstep puffs](fx-ground.md) · [Sprite boards](README.md) · **25 / 29** · [Dexter · prologue additions →](dexter-prologue.md) ![FX · pond ripples and lily pad](images/fx-water-preview.png) @@ -28,5 +28,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/fx-water.png` · rebuild: `python scripts/make_boards.py draw fx-water --redo --config art/sprites/boards.json` -[← FX · footstep puffs](fx-ground.md) · [Sprite boards](README.md) · **25 / 28** · [Dexter · prologue additions →](dexter-prologue.md) +[← FX · footstep puffs](fx-ground.md) · [Sprite boards](README.md) · **25 / 29** · [Dexter · prologue additions →](dexter-prologue.md) diff --git a/art/sprites/fx.md b/art/sprites/fx.md index 0d222fb..c445175 100644 --- a/art/sprites/fx.md +++ b/art/sprites/fx.md @@ -1,7 +1,7 @@ # FX · black fluid -[← Enemy · crab](enemy-crab.md) · [Sprite boards](README.md) · **15 / 28** · [Boss · Jenny, attacks →](boss-jenny.md) +[← Enemy · crab](enemy-crab.md) · [Sprite boards](README.md) · **15 / 29** · [Boss · Jenny, attacks →](boss-jenny.md) ![FX · black fluid](images/fx-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/fx.png` · rebuild: `python scripts/make_boards.py draw fx --redo --config art/sprites/boards.json` -[← Enemy · crab](enemy-crab.md) · [Sprite boards](README.md) · **15 / 28** · [Boss · Jenny, attacks →](boss-jenny.md) +[← Enemy · crab](enemy-crab.md) · [Sprite boards](README.md) · **15 / 29** · [Boss · Jenny, attacks →](boss-jenny.md) diff --git a/art/sprites/hero-air.md b/art/sprites/hero-air.md index 641c4a8..cd605b5 100644 --- a/art/sprites/hero-air.md +++ b/art/sprites/hero-air.md @@ -1,7 +1,7 @@ # The student · jump, fall, climb -[← The student · death](hero-death.md) · [Sprite boards](README.md) · **7 / 28** · [The student · ladder top and bottom →](hero-ladder.md) +[← The student · death](hero-death.md) · [Sprite boards](README.md) · **7 / 29** · [The student · ladder top and bottom →](hero-ladder.md) ![The student · jump, fall, climb](images/hero-air-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-air.png` · rebuild: `python scripts/make_boards.py draw hero-air --redo --config art/sprites/boards.json` -[← The student · death](hero-death.md) · [Sprite boards](README.md) · **7 / 28** · [The student · ladder top and bottom →](hero-ladder.md) +[← The student · death](hero-death.md) · [Sprite boards](README.md) · **7 / 29** · [The student · ladder top and bottom →](hero-ladder.md) diff --git a/art/sprites/hero-death.md b/art/sprites/hero-death.md index e5155bf..50b1c8e 100644 --- a/art/sprites/hero-death.md +++ b/art/sprites/hero-death.md @@ -1,7 +1,7 @@ # The student · death -[← The student · hurt and interact](hero-hurt.md) · [Sprite boards](README.md) · **6 / 28** · [The student · jump, fall, climb →](hero-air.md) +[← The student · hurt and interact](hero-hurt.md) · [Sprite boards](README.md) · **6 / 29** · [The student · jump, fall, climb →](hero-air.md) ![The student · death](images/hero-death-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-death.png` · rebuild: `python scripts/make_boards.py draw hero-death --redo --config art/sprites/boards.json` -[← The student · hurt and interact](hero-hurt.md) · [Sprite boards](README.md) · **6 / 28** · [The student · jump, fall, climb →](hero-air.md) +[← The student · hurt and interact](hero-hurt.md) · [Sprite boards](README.md) · **6 / 29** · [The student · jump, fall, climb →](hero-air.md) diff --git a/art/sprites/hero-hurt.md b/art/sprites/hero-hurt.md index 544a68a..6204a09 100644 --- a/art/sprites/hero-hurt.md +++ b/art/sprites/hero-hurt.md @@ -1,7 +1,7 @@ # The student · hurt and interact -[← The student · run](hero-run.md) · [Sprite boards](README.md) · **5 / 28** · [The student · death →](hero-death.md) +[← The student · run](hero-run.md) · [Sprite boards](README.md) · **5 / 29** · [The student · death →](hero-death.md) ![The student · hurt and interact](images/hero-hurt-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-hurt.png` · rebuild: `python scripts/make_boards.py draw hero-hurt --redo --config art/sprites/boards.json` -[← The student · run](hero-run.md) · [Sprite boards](README.md) · **5 / 28** · [The student · death →](hero-death.md) +[← The student · run](hero-run.md) · [Sprite boards](README.md) · **5 / 29** · [The student · death →](hero-death.md) diff --git a/art/sprites/hero-idle.md b/art/sprites/hero-idle.md index abcd584..e67d68e 100644 --- a/art/sprites/hero-idle.md +++ b/art/sprites/hero-idle.md @@ -1,7 +1,7 @@ # The student · idle variants -[← The student · walk](hero-move.md) · [Sprite boards](README.md) · **3 / 28** · [The student · run →](hero-run.md) +[← The student · walk](hero-move.md) · [Sprite boards](README.md) · **3 / 29** · [The student · run →](hero-run.md) ![The student · idle variants](images/hero-idle-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-idle.png` · rebuild: `python scripts/make_boards.py draw hero-idle --redo --config art/sprites/boards.json` -[← The student · walk](hero-move.md) · [Sprite boards](README.md) · **3 / 28** · [The student · run →](hero-run.md) +[← The student · walk](hero-move.md) · [Sprite boards](README.md) · **3 / 29** · [The student · run →](hero-run.md) diff --git a/art/sprites/hero-ladder.md b/art/sprites/hero-ladder.md index 35fffed..7f5fa05 100644 --- a/art/sprites/hero-ladder.md +++ b/art/sprites/hero-ladder.md @@ -1,7 +1,7 @@ # The student · ladder top and bottom -[← The student · jump, fall, climb](hero-air.md) · [Sprite boards](README.md) · **8 / 28** · [Chair · side sweep →](chair-side.md) +[← The student · jump, fall, climb](hero-air.md) · [Sprite boards](README.md) · **8 / 29** · [Chair · side sweep →](chair-side.md) ![The student · ladder top and bottom](images/hero-ladder-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-ladder.png` · rebuild: `python scripts/make_boards.py draw hero-ladder --redo --config art/sprites/boards.json` -[← The student · jump, fall, climb](hero-air.md) · [Sprite boards](README.md) · **8 / 28** · [Chair · side sweep →](chair-side.md) +[← The student · jump, fall, climb](hero-air.md) · [Sprite boards](README.md) · **8 / 29** · [Chair · side sweep →](chair-side.md) diff --git a/art/sprites/hero-move.md b/art/sprites/hero-move.md index cd0e74d..b710510 100644 --- a/art/sprites/hero-move.md +++ b/art/sprites/hero-move.md @@ -1,7 +1,7 @@ # The student · walk -[← The student · hero design](hero.md) · [Sprite boards](README.md) · **2 / 28** · [The student · idle variants →](hero-idle.md) +[← The student · hero design](hero.md) · [Sprite boards](README.md) · **2 / 29** · [The student · idle variants →](hero-idle.md) ![The student · walk](images/hero-move-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-move.png` · rebuild: `python scripts/make_boards.py draw hero-move --redo --config art/sprites/boards.json` -[← The student · hero design](hero.md) · [Sprite boards](README.md) · **2 / 28** · [The student · idle variants →](hero-idle.md) +[← The student · hero design](hero.md) · [Sprite boards](README.md) · **2 / 29** · [The student · idle variants →](hero-idle.md) diff --git a/art/sprites/hero-run.md b/art/sprites/hero-run.md index e361ba3..8987cd1 100644 --- a/art/sprites/hero-run.md +++ b/art/sprites/hero-run.md @@ -1,7 +1,7 @@ # The student · run -[← The student · idle variants](hero-idle.md) · [Sprite boards](README.md) · **4 / 28** · [The student · hurt and interact →](hero-hurt.md) +[← The student · idle variants](hero-idle.md) · [Sprite boards](README.md) · **4 / 29** · [The student · hurt and interact →](hero-hurt.md) ![The student · run](images/hero-run-preview.png) @@ -26,5 +26,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero-run.png` · rebuild: `python scripts/make_boards.py draw hero-run --redo --config art/sprites/boards.json` -[← The student · idle variants](hero-idle.md) · [Sprite boards](README.md) · **4 / 28** · [The student · hurt and interact →](hero-hurt.md) +[← The student · idle variants](hero-idle.md) · [Sprite boards](README.md) · **4 / 29** · [The student · hurt and interact →](hero-hurt.md) diff --git a/art/sprites/hero.md b/art/sprites/hero.md index d63239e..2580a90 100644 --- a/art/sprites/hero.md +++ b/art/sprites/hero.md @@ -1,7 +1,7 @@ # The student · hero design -[← Sprite boards](README.md) · [Sprite boards](README.md) · **1 / 28** · [The student · walk →](hero-move.md) +[← Sprite boards](README.md) · [Sprite boards](README.md) · **1 / 29** · [The student · walk →](hero-move.md) ![The student · hero design](images/hero-preview.png) @@ -21,5 +21,5 @@ Keep the body, height (6 ft adult), proportions, pose, backpack, grey slim jeans Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/hero.png` · rebuild: `python scripts/make_boards.py draw hero --redo --config art/sprites/boards.json` -[← Sprite boards](README.md) · [Sprite boards](README.md) · **1 / 28** · [The student · walk →](hero-move.md) +[← Sprite boards](README.md) · [Sprite boards](README.md) · **1 / 29** · [The student · walk →](hero-move.md) diff --git a/art/sprites/images/rubber-chicken-preview.png b/art/sprites/images/rubber-chicken-preview.png new file mode 100644 index 0000000..5fc8421 Binary files /dev/null and b/art/sprites/images/rubber-chicken-preview.png differ diff --git a/art/sprites/images/rubber-chicken.png b/art/sprites/images/rubber-chicken.png new file mode 100644 index 0000000..e0bf7b7 Binary files /dev/null and b/art/sprites/images/rubber-chicken.png differ diff --git a/art/sprites/it-props.md b/art/sprites/it-props.md index c0e0b0f..ce3b0a7 100644 --- a/art/sprites/it-props.md +++ b/art/sprites/it-props.md @@ -1,7 +1,7 @@ # Props · the storm drain's IT details -[← Menu · the Hidden Garden at first light](menu-key.md) · [Sprite boards](README.md) · **28 / 28** · [Sprite boards →](README.md) +[← Menu · the Hidden Garden at first light](menu-key.md) · [Sprite boards](README.md) · **28 / 29** · [Secret · the rubber chicken →](rubber-chicken.md) ![Props · the storm drain's IT details](images/it-props-preview.png) @@ -27,5 +27,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/it-props.png` · rebuild: `python scripts/make_boards.py draw it-props --redo --config art/sprites/boards.json` -[← Menu · the Hidden Garden at first light](menu-key.md) · [Sprite boards](README.md) · **28 / 28** · [Sprite boards →](README.md) +[← Menu · the Hidden Garden at first light](menu-key.md) · [Sprite boards](README.md) · **28 / 29** · [Secret · the rubber chicken →](rubber-chicken.md) diff --git a/art/sprites/mensa-food.md b/art/sprites/mensa-food.md index ba4f631..adb77e1 100644 --- a/art/sprites/mensa-food.md +++ b/art/sprites/mensa-food.md @@ -1,7 +1,7 @@ # Mensa · food pickups -[← Item · pocket computer](pocket-computer.md) · [Sprite boards](README.md) · **19 / 28** · [Prop · coffee machine (save point) →](coffee-machine.md) +[← Item · pocket computer](pocket-computer.md) · [Sprite boards](README.md) · **19 / 29** · [Prop · coffee machine (save point) →](coffee-machine.md) ![Mensa · food pickups](images/mensa-food-preview.png) @@ -30,5 +30,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/mensa-food.png` · rebuild: `python scripts/make_boards.py draw mensa-food --redo --config art/sprites/boards.json` -[← Item · pocket computer](pocket-computer.md) · [Sprite boards](README.md) · **19 / 28** · [Prop · coffee machine (save point) →](coffee-machine.md) +[← Item · pocket computer](pocket-computer.md) · [Sprite boards](README.md) · **19 / 29** · [Prop · coffee machine (save point) →](coffee-machine.md) diff --git a/art/sprites/menu-key.md b/art/sprites/menu-key.md index 6e54ef4..15974b5 100644 --- a/art/sprites/menu-key.md +++ b/art/sprites/menu-key.md @@ -1,7 +1,7 @@ # Menu · the Hidden Garden at first light -[← Dexter · prologue additions](dexter-prologue.md) · [Sprite boards](README.md) · **27 / 28** · [Props · the storm drain's IT details →](it-props.md) +[← Dexter · prologue additions](dexter-prologue.md) · [Sprite boards](README.md) · **27 / 29** · [Props · the storm drain's IT details →](it-props.md) ![Menu · the Hidden Garden at first light](images/menu-key-preview.png) @@ -22,5 +22,5 @@ Key art for the game's title menu, a full 16:9 picture in exactly the hi-bit pix Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/menu-key.png` · rebuild: `python scripts/make_boards.py draw menu-key --redo --config art/sprites/boards.json` -[← Dexter · prologue additions](dexter-prologue.md) · [Sprite boards](README.md) · **27 / 28** · [Props · the storm drain's IT details →](it-props.md) +[← Dexter · prologue additions](dexter-prologue.md) · [Sprite boards](README.md) · **27 / 29** · [Props · the storm drain's IT details →](it-props.md) diff --git a/art/sprites/pocket-computer.md b/art/sprites/pocket-computer.md index 2958bb4..c77a836 100644 --- a/art/sprites/pocket-computer.md +++ b/art/sprites/pocket-computer.md @@ -1,7 +1,7 @@ # Item · pocket computer -[← Boss · Jenny, stunned and debris](boss-jenny-2.md) · [Sprite boards](README.md) · **18 / 28** · [Mensa · food pickups →](mensa-food.md) +[← Boss · Jenny, stunned and debris](boss-jenny-2.md) · [Sprite boards](README.md) · **18 / 29** · [Mensa · food pickups →](mensa-food.md) ![Item · pocket computer](images/pocket-computer-preview.png) @@ -28,5 +28,5 @@ On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground sh Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/pocket-computer.png` · rebuild: `python scripts/make_boards.py draw pocket-computer --redo --config art/sprites/boards.json` -[← Boss · Jenny, stunned and debris](boss-jenny-2.md) · [Sprite boards](README.md) · **18 / 28** · [Mensa · food pickups →](mensa-food.md) +[← Boss · Jenny, stunned and debris](boss-jenny-2.md) · [Sprite boards](README.md) · **18 / 29** · [Mensa · food pickups →](mensa-food.md) diff --git a/art/sprites/previews/rubber-chicken-in-garden.png b/art/sprites/previews/rubber-chicken-in-garden.png new file mode 100644 index 0000000..b35b291 Binary files /dev/null and b/art/sprites/previews/rubber-chicken-in-garden.png differ diff --git a/art/sprites/rubber-chicken.md b/art/sprites/rubber-chicken.md new file mode 100644 index 0000000..79a705d --- /dev/null +++ b/art/sprites/rubber-chicken.md @@ -0,0 +1,24 @@ +# Secret · the rubber chicken + + +[← Props · the storm drain's IT details](it-props.md) · [Sprite boards](README.md) · **29 / 29** · [Sprite boards →](README.md) + + +![Secret · the rubber chicken](images/rubber-chicken-preview.png) + +**Review:** 🟨 Awaiting Alexander's review (25 Oct). Playtest T2 (Lex): the rubber chicken must be in the game. First draw, two frames (resting, squeezed mid-squeak); about 34 x 9 px in the game, a little bigger than a real one so it reads next to the 76 px hero. + +## Brief + +On a flat, solid, pure magenta #FF00FF background (no paper colour, no ground shadows, no dust under the objects), with NO text at all - no titles, no captions, no frame numbers, no labels, no readable words or logos: Image 1 is an approved prop sheet from this game: draw this sheet in exactly that pixel-art look - small detailed props on magenta, the same pixel grain and the same soft warm rim light. Prop sprite sheet of ONE classic squeaky RUBBER CHICKEN toy - the long-necked plucked yellow rubber chicken with a red comb, an open orange beak, tiny closed eyes, skinny dangling legs - lying on its side on the ground, side view, slightly worn and dusty as if it had been lost in a garden for a while. 1 row, exactly 2 frames: frame 1 resting, frame 2 the same chicken squeezed in the middle, its body pinched thin and its beak wide open mid-squeak, neck stretched. Both frames at the SAME pixel scale, standing on the SAME invisible ground line, evenly spaced with a wide clear magenta gap between them. Draw distinct key poses. Count the frames: the row has EXACTLY 2. No people, no hands, no scenery. + +## Inputs + +- [mensa-food-preview.png](images/mensa-food-preview.png) +- [style-master-preview.png](../direction/images/style-master-preview.png) + +Model `gpt-image-2.5-sunburst` · pixel factor 2 · source image `images/rubber-chicken.png` · rebuild: `python scripts/make_boards.py draw rubber-chicken --redo --config art/sprites/boards.json` + + +[← Props · the storm drain's IT details](it-props.md) · [Sprite boards](README.md) · **29 / 29** · [Sprite boards →](README.md) + diff --git a/art/stages/hidden-garden/hg-0-0.clean.collision.json b/art/stages/hidden-garden/hg-0-0.clean.collision.json index d2f3acf..caaa643 100644 --- a/art/stages/hidden-garden/hg-0-0.clean.collision.json +++ b/art/stages/hidden-garden/hg-0-0.clean.collision.json @@ -129,6 +129,15 @@ "h": 76, "note": "at the fallen birch: Dexter hops onto it and looks back", "act": "wait" + }, + { + "id": "rubber-chicken", + "kind": "rubber-chicken", + "x": 28, + "y": 434, + "w": 44, + "h": 30, + "note": "A secret (playtest T2): the rubber chicken, lost behind the gate pillar, left of where you start. It squeaks." } ], "spawn": [ diff --git a/docs/07-ASSET-MANIFEST.md b/docs/07-ASSET-MANIFEST.md index 36e1fb7..05a9d6f 100644 --- a/docs/07-ASSET-MANIFEST.md +++ b/docs/07-ASSET-MANIFEST.md @@ -65,7 +65,7 @@ Frame lists approved as they are (A14). ## Audio (synthesized in code) -Footsteps (girder, grass), chair whoosh + hit, rover motor, crab servos, drone hum, Jenny engine + crash, fluid absorb, crash-dialog "ding", one ambient loop per region, one boss loop. +Footsteps (girder, grass), chair whoosh + hit, rover motor, crab servos, drone hum, Jenny engine + crash, fluid absorb, crash-dialog "ding", rubber squeak, one ambient loop per region, one boss loop. Every sound is **synthesized at runtime with Web Audio** – no audio files, so nothing to license and nothing that breaks decision 14 (no audio in Git). Recipes are plain data in `game/src/fx/sound/recipes.ts` (effects) and `loops.ts` (Hidden Garden, Rusty Creek, Jenny); the `Audio` scene plays them. Game code calls `sound.play('chair-whoosh')` / `sound.loop('boss-jenny')`; hits, defeats, the boss and region turns are wired to the game events, and the anomaly state plays the region loop slightly flat. M mutes. diff --git a/docs/meetings/playtest-24-oct.md b/docs/meetings/playtest-24-oct.md index 695474a..e8ebb02 100644 --- a/docs/meetings/playtest-24-oct.md +++ b/docs/meetings/playtest-24-oct.md @@ -55,7 +55,7 @@ Vatsal and Lex played the live slice on 24 Oct and recorded what to fix ([A15](t | # | What | Status | | --- | --- | --- | | T1 | The jam theme **"It's spooky outside"** must show | ✅ under the title ("DEGDEV 3 - It's spooky outside."), as the loader's last line ("WARNING: It's spooky outside.") and in the credits | -| T2 | The **rubber chicken** must be in the game somehow | ❓ smallest version: a rubber chicken prop as a secret pickup or on Dexter's bench; it squeaks | +| T2 | The **rubber chicken** must be in the game somehow | ✅ a secret: lost behind the garden's gate pillar, left of where you start; walk into it and it squeaks (sprite board `rubber-chicken`, synthesized squeak) | ## Scale – hero against the world diff --git a/game/public/assets/sprites/rubber-chicken.anims.json b/game/public/assets/sprites/rubber-chicken.anims.json new file mode 100644 index 0000000..e81ba92 --- /dev/null +++ b/game/public/assets/sprites/rubber-chicken.anims.json @@ -0,0 +1,12 @@ +{ + "rest": { + "frames": 1, + "fps": 12, + "loop": true + }, + "squeak": { + "frames": 1, + "fps": 12, + "loop": false + } +} diff --git a/game/public/assets/sprites/rubber-chicken.json b/game/public/assets/sprites/rubber-chicken.json new file mode 100644 index 0000000..1d1f896 --- /dev/null +++ b/game/public/assets/sprites/rubber-chicken.json @@ -0,0 +1,62 @@ +{ + "frames": { + "rest-00": { + "frame": { + "x": 0, + "y": 0, + "w": 44, + "h": 14 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 44, + "h": 14 + }, + "sourceSize": { + "w": 44, + "h": 14 + }, + "pivot": { + "x": 0.5, + "y": 1 + } + }, + "squeak-00": { + "frame": { + "x": 0, + "y": 16, + "w": 44, + "h": 14 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 44, + "h": 14 + }, + "sourceSize": { + "w": 44, + "h": 14 + }, + "pivot": { + "x": 0.5, + "y": 1 + } + } + }, + "meta": { + "app": "scripts/export_atlas.py", + "image": "rubber-chicken.png", + "format": "RGBA8888", + "size": { + "w": 44, + "h": 30 + }, + "scale": "1" + } +} diff --git a/game/public/assets/sprites/rubber-chicken.png b/game/public/assets/sprites/rubber-chicken.png new file mode 100644 index 0000000..9584315 Binary files /dev/null and b/game/public/assets/sprites/rubber-chicken.png differ diff --git a/game/src/core/scaffold.ts b/game/src/core/scaffold.ts index 7918cdb..79e8c59 100644 --- a/game/src/core/scaffold.ts +++ b/game/src/core/scaffold.ts @@ -14,6 +14,7 @@ import { BODY_WIDTH } from '../player/body'; import { Triggers } from '../stage/triggers'; import { Rooms } from '../stage/rooms'; import { Props } from '../stage/props'; +import { addChickens } from '../stage/chicken'; import { DebugOverlay, type EnemyLike, type JennyLike, type DexterLike } from '../stage/debugOverlay'; import { fallCapture } from '../stage/fallCapture'; import { GameMenu } from '../ui/menu'; @@ -65,6 +66,7 @@ export class Stage extends Phaser.Scene { this.triggers = new Triggers(data.collisions, data.manifest.region); this.rooms = new Rooms(this, this.player, data.collisions, data.manifest.region); this.props = new Props(this, data.collisions, () => this.player?.body, data.state); + addChickens(this, data.collisions); this.follow = import.meta.env.DEV && new URLSearchParams(location.search).has('inspect') ? undefined : cameraFollow(this, data.manifest); this.overlay = new DebugOverlay(this, stage, legend, data.collisions, { diff --git a/game/src/fx/sound/recipes.ts b/game/src/fx/sound/recipes.ts index 329a4fe..738bf80 100644 --- a/game/src/fx/sound/recipes.ts +++ b/game/src/fx/sound/recipes.ts @@ -27,7 +27,8 @@ export type SoundId = | 'rover-motor' | 'crab-servo' | 'drone-hum' | 'jenny-engine' | 'jenny-crash' | 'fluid-absorb' | 'crash-ding' - | 'player-hurt' | 'enemy-defeated'; + | 'player-hurt' | 'enemy-defeated' + | 'rubber-squeak'; export const RECIPES: Record = { 'footstep-girder': [ @@ -79,6 +80,11 @@ export const RECIPES: Record = { { wave: 'square', from: 600, to: 150, dur: 0.18, gain: 0.2 }, { wave: 'noise', dur: 0.1, gain: 0.18, filter: { type: 'lowpass', from: 2000 } }, ], + // The rubber chicken (playtest T2): squeezed, a rising squeal through the narrow beak, let go, a falling one. + 'rubber-squeak': [ + { wave: 'sawtooth', from: 620, to: 1500, dur: 0.16, attack: 0.02, gain: 0.22, filter: { type: 'bandpass', from: 1300, q: 5 } }, + { wave: 'sawtooth', from: 1450, to: 760, start: 0.17, dur: 0.22, attack: 0.02, gain: 0.18, filter: { type: 'bandpass', from: 1100, q: 5 } }, + ], }; /** The loudest a recipe can get: every voice's peak at once. Kept under 0.9 so nothing clips. */ diff --git a/game/src/fx/sound/sound.test.ts b/game/src/fx/sound/sound.test.ts index c8ff3eb..72e910e 100644 --- a/game/src/fx/sound/sound.test.ts +++ b/game/src/fx/sound/sound.test.ts @@ -13,6 +13,7 @@ const MANIFEST: [string, SoundId[]][] = [ ['Jenny engine + crash', ['jenny-engine', 'jenny-crash']], ['fluid absorb', ['fluid-absorb']], ['ding', ['crash-ding']], + ['rubber squeak', ['rubber-squeak']], ]; describe('synthesized sound', () => { diff --git a/game/src/stage/boards.json b/game/src/stage/boards.json index a2e846a..f7125f3 100644 --- a/game/src/stage/boards.json +++ b/game/src/stage/boards.json @@ -8,5 +8,5 @@ "boss-jenny", "boss-jenny-2", "coffee-machine", "dexter", "dexter-acts", "dexter-prologue", "pocket-computer", "mensa-food" ], - "optional": ["it-props"] + "optional": ["it-props", "rubber-chicken"] } diff --git a/game/src/stage/chicken.ts b/game/src/stage/chicken.ts new file mode 100644 index 0000000..2a6ee6d --- /dev/null +++ b/game/src/stage/chicken.ts @@ -0,0 +1,30 @@ +import type Phaser from 'phaser'; +import { gameEvents } from '../core/events'; +import { sound } from '../fx/sound/Audio'; +import type { CollisionChunk } from './collision'; +import { chickenFrame, chickens } from './chickenModel'; +import { PROP_DEPTH } from './depth'; + +const BOARD = 'rubber-chicken'; + +/** Draws the region's rubber chickens and squeezes them (model: `chickenModel.ts`). */ +export function addChickens(scene: Phaser.Scene, chunks: CollisionChunk[]): void { + const boxes = chickens(chunks); + if (!boxes.length || !scene.textures.exists(BOARD)) return; + const sprites = new Map(boxes.map(box => [box.id, scene.add.sprite(box.x + box.w / 2, box.y + box.h, BOARD, 'rest-00') + .setOrigin(0.5, 1).setDepth(PROP_DEPTH)])); + const squeezed = new Map(); + const off = gameEvents.on('trigger-entered', ({ kind, id }) => { + if (kind !== 'rubber-chicken') return; + squeezed.set(id, scene.time.now); + sound.play('rubber-squeak'); + }); + const update = () => { + for (const [id, sprite] of sprites) { + const at = squeezed.get(id); + sprite.setFrame(chickenFrame(at === undefined ? undefined : scene.time.now - at)); + } + }; + scene.events.on('update', update); + scene.events.once('shutdown', () => { off(); scene.events.off('update', update); }); +} diff --git a/game/src/stage/chickenModel.test.ts b/game/src/stage/chickenModel.test.ts new file mode 100644 index 0000000..1c1e4f3 --- /dev/null +++ b/game/src/stage/chickenModel.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { chickenFrame, chickens, SQUEEZE_MS } from './chickenModel'; +import type { Geometry } from './collision'; +import garden from '../../../art/stages/hidden-garden/hg-0-0.clean.collision.json'; + +const world = (interact: Geometry['interact']) => ({ world: { interact } as Geometry }); + +describe('the rubber chicken', () => { + it('is hidden in the garden, left of where you start', () => { + const [chicken] = chickens([world(garden.interact as Geometry['interact'])]); + const start = garden.spawn.find(s => s.kind === 'player')!; + expect(chicken.id).toBe('rubber-chicken'); + expect(chicken.x + chicken.w).toBeLessThan(start.x); + }); + it('shows its squeezed frame for a moment after each squeeze', () => { + expect(chickenFrame(undefined)).toBe('rest-00'); + expect(chickenFrame(0)).toBe('squeak-00'); + expect(chickenFrame(SQUEEZE_MS)).toBe('rest-00'); + }); +}); diff --git a/game/src/stage/chickenModel.ts b/game/src/stage/chickenModel.ts new file mode 100644 index 0000000..59269e8 --- /dev/null +++ b/game/src/stage/chickenModel.ts @@ -0,0 +1,15 @@ +import type { Box, CollisionChunk } from './collision'; + +/** + * The rubber chicken (playtest T2, a jam requirement): a secret, lost behind the Hidden Garden's gate pillar, left + * of where you start. It is an `interact` box of kind `rubber-chicken`; walking into it squeezes it – the squeak + * and its squeezed frame – every time. Nothing else: no pickup, no words. + */ +export const SQUEEZE_MS = 260; + +/** The chicken boxes of a region. */ +export const chickens = (chunks: Pick[]): Box[] => + chunks.flatMap(chunk => chunk.world.interact).filter(box => box.kind === 'rubber-chicken'); + +/** Which frame shows, `since` ms after the last squeeze (undefined: never squeezed). */ +export const chickenFrame = (since: number | undefined) => since !== undefined && since < SQUEEZE_MS ? 'squeak-00' : 'rest-00';