diff --git a/presentations/making-games/assets/captures.json b/presentations/making-games/assets/captures.json index b49ecf4..b97beac 100644 --- a/presentations/making-games/assets/captures.json +++ b/presentations/making-games/assets/captures.json @@ -1,6 +1,16 @@ { "sourceSha256": "c2ed572c63a5cf8d4935104a1df49251239306182b9686eb08e66ae6ca688373", "captures": [ + { + "file": "garden-title.png", + "description": "Actual title scene of the finished game.", + "displayBackend": "WebGL2", + "sceneBackend": "WebGL shader", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "width": 900, + "height": 900, + "sha256": "87b278c70c12d432aa3e8930d2c7113b428b9f069317d56f5c3267d3e1562e52" + }, { "file": "garden-start.png", "description": "Finished game starts with no planted flowers.", @@ -61,6 +71,16 @@ "height": 900, "sha256": "7de9abb9d67b6ff1f99b83d8d5d25c6bc2dd04ad5ebde726ff8f81973cc53533" }, + { + "file": "garden-planting.png", + "description": "Actual seed-catching and planting checkpoint, before clouds and HUD.", + "displayBackend": "WebGL2", + "sceneBackend": "WebGL shader", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "width": 900, + "height": 900, + "sha256": "267fdee5f98168cb959c8b00e45ced23bf2e086b81632d0fbfec27920b903737" + }, { "file": "display-angles.png", "description": "Geometry example using real Dream Garden assets.", @@ -90,6 +110,16 @@ "width": 900, "height": 900, "sha256": "4bba014d74818400a154f16fb488c697ef7a779e634aa203c8c172021f4638f1" + }, + { + "file": "display-arxels.png", + "description": "Geometry example using real Dream Garden assets.", + "displayBackend": "WebGL2", + "sceneBackend": "WebGL shader", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "width": 900, + "height": 900, + "sha256": "80790b1752dbaaec7f5c44f150d333db422bd725b6214316542ab7e6e45f28d7" } ] } diff --git a/presentations/making-games/assets/catalog-captures.json b/presentations/making-games/assets/catalog-captures.json new file mode 100644 index 0000000..850178a --- /dev/null +++ b/presentations/making-games/assets/catalog-captures.json @@ -0,0 +1,122 @@ +[ + { + "file": "catalog-vyruss.png", + "slug": "alecu.vyruss_vs2", + "title": "Vyruss VS2", + "displayBackend": "WebGL2", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "runtime": { + "adapterName": "MicroPython WASM", + "adapterSource": "wasm", + "editorOpen": false, + "pollingHalted": false, + "currentButtons": 0, + "currentInput": { + "joy1": 0, + "joy2": 0, + "extra": 0 + } + }, + "sha256": "dc3980d6624726b3a6596b5c9b2b9f698e36a79e03c7328649c51fb6542e19af" + }, + { + "file": "catalog-ventap.png", + "slug": "alecu.ventap", + "title": "Ventap", + "displayBackend": "WebGL2", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "runtime": { + "adapterName": "MicroPython WASM", + "adapterSource": "wasm", + "editorOpen": false, + "pollingHalted": false, + "currentButtons": 0, + "currentInput": { + "joy1": 0, + "joy2": 0, + "extra": 0 + } + }, + "sha256": "c64c3e698922340c331ada397cc590a23211926fffb078904e05ddf8310296f8" + }, + { + "file": "catalog-vixeous.png", + "slug": "alecu.vixeous", + "title": "Vixeous", + "displayBackend": "WebGL2", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "runtime": { + "adapterName": "MicroPython WASM", + "adapterSource": "wasm", + "editorOpen": false, + "pollingHalted": false, + "currentButtons": 0, + "currentInput": { + "joy1": 0, + "joy2": 0, + "extra": 0 + } + }, + "sha256": "be0a150acc9a03495fd89bdd86b0e74871b34aeeb82b8d0b29276eab9bddef86" + }, + { + "file": "catalog-vortris.png", + "slug": "vsjam-may25.vortris", + "title": "Vortris", + "displayBackend": "WebGL2", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "runtime": { + "adapterName": "MicroPython WASM", + "adapterSource": "wasm", + "editorOpen": false, + "pollingHalted": false, + "currentButtons": 0, + "currentInput": { + "joy1": 0, + "joy2": 0, + "extra": 0 + } + }, + "sha256": "e0d64e2e764daebc0cfd81d7b2eac02acf2bf13d4b7c70f94e05e793dabb7095" + }, + { + "file": "catalog-fanphibious.png", + "slug": "vsjam-oct25.fanphibious_danger", + "title": "Fanphibious Danger", + "displayBackend": "WebGL2", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "runtime": { + "adapterName": "MicroPython WASM", + "adapterSource": "wasm", + "editorOpen": false, + "pollingHalted": false, + "currentButtons": 0, + "currentInput": { + "joy1": 0, + "joy2": 0, + "extra": 0 + } + }, + "sha256": "ca751a383212fc0524721c00581fe4caab3a10c0bab6755267180248fe885b8e" + }, + { + "file": "catalog-vzumaki.png", + "slug": "vsjam-may25.vzumaki", + "title": "Vzumaki", + "displayBackend": "WebGL2", + "gpu": "ANGLE (Intel, ANGLE Metal Renderer: Intel(R) Iris(TM) Plus Graphics, Unspecified Version)", + "runtime": { + "adapterName": "MicroPython WASM", + "adapterSource": "wasm", + "editorOpen": false, + "pollingHalted": false, + "currentButtons": 0, + "currentInput": { + "joy1": 0, + "joy2": 0, + "extra": 0 + } + }, + "sha256": "408e91b13fdc53bfbd3471216b97926ca7114218c211817875073b359c486ec8" + } +] diff --git a/presentations/making-games/assets/catalog-fanphibious.png b/presentations/making-games/assets/catalog-fanphibious.png new file mode 100644 index 0000000..31141b5 Binary files /dev/null and b/presentations/making-games/assets/catalog-fanphibious.png differ diff --git a/presentations/making-games/assets/catalog-ventap.png b/presentations/making-games/assets/catalog-ventap.png new file mode 100644 index 0000000..2020c07 Binary files /dev/null and b/presentations/making-games/assets/catalog-ventap.png differ diff --git a/presentations/making-games/assets/catalog-vixeous.png b/presentations/making-games/assets/catalog-vixeous.png new file mode 100644 index 0000000..77dc56e Binary files /dev/null and b/presentations/making-games/assets/catalog-vixeous.png differ diff --git a/presentations/making-games/assets/catalog-vortris.png b/presentations/making-games/assets/catalog-vortris.png new file mode 100644 index 0000000..4d83c4b Binary files /dev/null and b/presentations/making-games/assets/catalog-vortris.png differ diff --git a/presentations/making-games/assets/catalog-vyruss.png b/presentations/making-games/assets/catalog-vyruss.png new file mode 100644 index 0000000..ed2b739 Binary files /dev/null and b/presentations/making-games/assets/catalog-vyruss.png differ diff --git a/presentations/making-games/assets/catalog-vzumaki.png b/presentations/making-games/assets/catalog-vzumaki.png new file mode 100644 index 0000000..28cb3cf Binary files /dev/null and b/presentations/making-games/assets/catalog-vzumaki.png differ diff --git a/presentations/making-games/assets/cybercirujas.jpg b/presentations/making-games/assets/cybercirujas.jpg new file mode 100644 index 0000000..def2fdf Binary files /dev/null and b/presentations/making-games/assets/cybercirujas.jpg differ diff --git a/presentations/making-games/assets/display-arxels.png b/presentations/making-games/assets/display-arxels.png new file mode 100644 index 0000000..dec7d4e Binary files /dev/null and b/presentations/making-games/assets/display-arxels.png differ diff --git a/presentations/making-games/assets/garden-planting.png b/presentations/making-games/assets/garden-planting.png new file mode 100644 index 0000000..ed49c80 Binary files /dev/null and b/presentations/making-games/assets/garden-planting.png differ diff --git a/presentations/making-games/assets/garden-title.png b/presentations/making-games/assets/garden-title.png new file mode 100644 index 0000000..820c1cf Binary files /dev/null and b/presentations/making-games/assets/garden-title.png differ diff --git a/presentations/making-games/deck.js b/presentations/making-games/deck.js index 940e7ff..7898739 100644 --- a/presentations/making-games/deck.js +++ b/presentations/making-games/deck.js @@ -16,7 +16,7 @@ Reveal.initialize({ controlsTutorial: false, progress: true, slideNumber: 'c/t', - totalTime: 45 * 60, + totalTime: 27 * 60, pdfSeparateFragments: false, pdfMaxPagesPerSlide: 1, highlight: { highlightOnLoad: true }, diff --git a/presentations/making-games/examples/dream-garden-guide.md b/presentations/making-games/examples/dream-garden-guide.md index 43cebe9..84c8cda 100644 --- a/presentations/making-games/examples/dream-garden-guide.md +++ b/presentations/making-games/examples/dream-garden-guide.md @@ -9,7 +9,10 @@ The festival's [Dream No Return theme](https://www.sickhouse.nl/festival/dream-n inspired a garden whose players can choose a slower pace. This is an original sample game, not a festival commission or an official festival game. -[Download the complete game](dream-garden.zip). While these changes are under review, use the SDK branch `feat/dream-garden-clouds`. Extract the archive at the root of that SDK checkout to create `games/demos/dream_garden/`. The source, packed assets, audio and rebuilding recipes are included, along with `tests/test_dream_garden.py` so the checks below also work when installing into a current SDK checkout. After merging, the same archive works in an updated main checkout. +[Download the complete game](dream-garden.zip). Use an up-to-date SDK main +checkout. Extract the archive at its root to create `games/demos/dream_garden/`. +The source, packed assets, audio and rebuilding recipes are included, along with +`tests/test_dream_garden.py`. [Small first-game starter](first_game.py) · [Back to the slides](../) @@ -81,29 +84,25 @@ base and never go into the rotor ROM. The sample follows the repository's GPLv3 license. [Artwork sources and rebuilding](artwork.html) record the new art and original sound synthesis. The general SDK tutorial remains a separate example. -## Build this garden step by step - -Each stage is a complete, cumulative source file inside the download at -`code/checkpoints/`. The slides explain the changes and launch the matching -version in the web emulator. The last stage matches `code/dream_garden.py` exactly. - -| Stage | Adds | -| --- | --- | -| 01-steering | One pink dreamer moving around the rim | -| 02-poses | Leaning and sleeping poses | -| 03-pools | Reserved seed and flower slots | -| 04-timer | Periodic random seed spawning | -| 05-flowers | Collisions, directional planting and inward flower drift | -| 06-tiles | Fluffy clouds in the middle layer, behind seeds | -| 07-scroll | Steady scrolling clouds, slower outward seeds | -| 08-hud | Seed-only RELAX and a label that slides out | -| 09-scenes | Title and voluntary rest, preserving flowers | -| 10-shared | A second player, independent planting sequences and random seed glow | -| 11-audio | Default-on lullaby and bloom sounds, timed NOISY/QUIET notices | - -A new garden starts without flowers. The planting direction follows movement, -then alternates after stopping. Every stage keeps the same packed artwork, -with unused strips available for the later steps. +## Three stages for the short talk + +The presentation launches three complete, cumulative versions. Their sources +are inside the download at `code/checkpoints/`. + +| Stage | Source | Adds | +| --- | --- | --- | +| 1 | `01-steering.py` | One pink dreamer around the rim | +| 2 | `05-flowers.py` | Timed seeds, catching, directional planting and inward flower drift | +| 3 | `11-audio.py` | The completed shared cloud garden, HUD, scenes, glow and audio | + +The final stage matches `code/dream_garden.py` exactly. Additional fine-grained +checkpoints remain available in the SDK for independent study. The short talk +shows only these three launchable progressions. + +A new garden starts without flowers. Planting follows movement, then alternates +after stopping. All stages use the same packed artwork, with unused strips +available for later features. + ## Checks diff --git a/presentations/making-games/handout.html b/presentations/making-games/handout.html index cdfd8d7..dab3c33 100644 --- a/presentations/making-games/handout.html +++ b/presentations/making-games/handout.html @@ -1,8 +1,8 @@ --- layout: presentation-page -title: Making games for Ventilastation — reading view +title: Ventilastation — reading view ---
-A 45-minute English presentation for Overkill Festival 2026, building Dream Garden. Each slide includes its pacing and speaker notes below.
+A 12-minute introduction for everyone, followed by 15 minutes of coding and three Dream Garden stages. Each slide includes pacing and speaker notes.
{% capture content %}{% include_relative slides.md %}{% endcapture %} {{ content | replace: 'Notes:', '### Speaker notes' | markdownify }} diff --git a/presentations/making-games/index.html b/presentations/making-games/index.html index 1b3cfbb..0fc3fd9 100644 --- a/presentations/making-games/index.html +++ b/presentations/making-games/index.html @@ -1,6 +1,6 @@ --- layout: null -title: Making games for Ventilastation +title: Ventilastation — Circular Arcades --- @@ -9,7 +9,7 @@ - +Spinning LEDs form the display.
-An ESP32-S3 runs your MicroPython game.
-The project is open source and open hardware.
+An Argentine collective that repairs and recirculates technology.
+Shared knowledge, free software and resistance to planned obsolescence.
+Ventilastation is part of that community.
+
A moving LED arm paints each angular column at a different instant.
-Persistence of vision joins those columns into a disc.
-The game tick and physical rotation are separate clocks.
+A rotating LED arm draws a circular screen.
+An ESP32-S3 runs the game in MicroPython.
+Built in Argentina. Open source and open hardware.
Each column spans an angle, rather than a fixed horizontal distance.
-The same angular step is wider at the rim and narrower near the centre.
-Moving around the disc also rotates the artwork.
+The arm paints a different slice at each angle.
+Our eyes join the slices into a disc.
+The image has a centre and a rim, with no corners.
+
Drift around the rim and catch seeds to grow flowers.
-Either player can hold A to slow the shared seed flow.
-Passing seeds do no harm. Watching is welcome.
-Inspired by Dream No Return
-
+An arxel is a tiny arc of light.
+The same angle covers a wider arc at the rim.
+Near the centre, arxels get narrower and details crowd together.
-
+
Dreamers and flowers below. Clouds and seeds above.
- Notes: -**7:45–8:30.** Show the original artwork sheet before explaining its runtime format. The top row has four pink poses and the same four poses in mint for player two. Below are four seed frames, four flower species with two frames each, and eight sparse garden details. The source atlas was generated for this game and is included in the download. The preparation script crops its cells, corrects the leaning pose order, resizes them with nearest-neighbour sampling, makes alpha binary and packs horizontal strips. The fourth row is unused in this experiment; a separate six-cloud atlas supplies the flying layer. The dreamers become 19 × 19 pixel frames. Keep the artwork legible at that final size, especially on the moving physical display. +**3:50–5:00.** Arxel combines arc and pixel. These three blocks use the same eight angular columns and eight radial LEDs. Their angular width stays constant, but their physical width shrinks at the smaller radii. Radial LED spacing stays fixed. Distinguish the size of a light cell from an actor shrinking through a tunnel projection. The image uses the HUD projection to isolate the radial geometry. Explain why small lettering and fine artwork become hard to read near the centre. No maths is needed here. -Source: [Artwork provenance and preparation](examples/artwork.html). Images: Dream Garden's original source and cloud atlases, included unchanged. +Source: [Current display geometry](../../docs/vs2/tutorial/display.html). Image: actual font block cells rendered through the WebGL display backend. --- - + -## PNGs become indexed image strips - -Run this checkpoint +## Ordinary artwork bends around the discpalettegroups:
- garden:
- - strip: dreamer.png
- frames: 8
-Equally sized frames, arranged horizontally.
-256 colours per palette group.
+
+PNG artwork becomes curved on the display.
+It stretches along the rim, compresses inward and turns with its angle.
+
./vs-emu.sh --game myname.mygame
A / D drift around the rim.
-Positive X turns left at the bottom.
-Desktop demonstration
-
+





TUNNEL
Y is depth, 0–255. Objects shrink inward.
HUD
Y is an LED index, 0–53.
FULLSCREEN
A centred image. X rotates it.
+


if sleeping:
- dreamer.frame = ASLEEP
-elif direction > 0:
- dreamer.frame = LEFT_POSE
-elif direction < 0:
- dreamer.frame = RIGHT_POSE
-else:
- dreamer.frame = AWAKE
-Frame changes reuse the same sprite.
-Flowers alternate between paired frames.
-Golden seeds wait a random interval, then run a short glow sequence.
+Layers choose what draws on top.
+Sprites are movable pictures.
+Tilemaps assemble repeated picture cells.
+Labels turn font cells into text.
+Full-screen images cover the disc with one picture.
Starts 14 October 2026
-```python -# In build(), before creating the dreamer: -self.flowers = self.world.sprite_pool( - "flowers.png", count=24, on_empty=vs2.RECYCLE -) -self.seeds = self.world.sprite_pool("seed.png", count=16) - -# During play: -seed = self.seeds.spawn(x=100, y=160) -if seed is None: - return # this seed waits for another opportunity -``` +Games will meet players at The Overkill, **26–29 November**. + +Artists, musicians, writers, programmers and curious playtesters are welcome. -A full flower pool reuses its oldest live flower. +[itch.io/jam/ventilastation-overkill-jam](https://itch.io/jam/ventilastation-overkill-jam) Notes: -**18:15–19:45.** Reservation happens once in build. Flowers begin hidden, so the garden starts empty. Create the dreamer after the flowers to draw the player above the planted garden. The flying layer comes at the next step. Spawn reveals and positions a reserved sprite. A full seed pool returns None and drops that particular spawn. Flowers instead recycle their oldest live slot, so new growth continues without an ever-growing graph. Both choices are part of the design: the garden can keep changing, yet nothing demands a perfect catch rate. Pools count at their full reserved size, including hidden slots. Iteration visits live sprites and supports retiring the current one. Pooling renderer objects does not remove all unrelated Python allocations. Use the Run this checkpoint button to open this stage in the browser; it contains only the features covered so far. +**11:10–12:00.** Close the introduction with the invitation, so people who leave before the code still know how to join. The jam page lists October 14 through November 11 for submissions. Link to it for the authoritative times and current instructions rather than adding a timezone guess. The resulting games are intended for the real console at The Overkill in late November. Find collaborators with different skills. The next fifteen minutes show enough code to begin experimenting. -Source: [Sprite pools](../../docs/vs2/tutorial/pools.html), [sample source](examples/dream_garden.py). +Sources: [Official jam page](https://itch.io/jam/ventilastation-overkill-jam), [Sickhouse’s November 26–29 festival announcement](https://www.sickhouse.nl/events/the-overkill-festival-2026). --- - + -## A timer controls the seed rhythm - -Run this checkpoint - -```python -from urandom import randrange +## A game is a folder on your laptop -# At the end of build(): -self.call_later(self.spawn_ms, self.spawn_seed) +```text +games/myname/mygame/ + code/mygame.py + images/ # PNG strips and __images__.yaml + sounds/ # optional MP3s + menu.png + meta.json +``` -def spawn_seed(self): - self.seeds.spawn( - x=randrange(vs2.display.width), y=160 - ) - self.call_later(self.spawn_ms, self.spawn_seed) +```sh +./vs-emu.sh --game myname.mygame ``` -A seed every 1.8 seconds. RELAX changes the gap later. +MicroPython runs your app or game in the desktop emulator. Notes: -**19:45–21:00.** The callback rearms itself with the current gap. This checkpoint uses 1800 ms. At the HUD checkpoint, held A changes spawn_ms to 4000 ms, but a seed that is already scheduled keeps its deadline. The next gap uses the slower rhythm. Seed movement reacts immediately in update. This avoids rebuilding or continually replacing timer records while a button is held. A full pool simply skips a spawn. Scene-owned timers disappear when the scene closes or suspends, so an old callback cannot plant into the rest screen. Timers suit occasional events, not the animation loop. Use the Run this checkpoint button to open this stage in the browser; it contains only the features covered so far. +**12:00–13:15.** Start the coding section at minute twelve. Use an up-to-date SDK main checkout, where Dream Garden is already included. Dependencies should be installed before the session; link to the desktop guide rather than spending the fifteen minutes on setup. Windows uses vs-emu.bat. Explain the folder name, matching Python module and images manifest. main() returns the starting scene. Metadata declares api: vs2 and api_revision: 2. The menu icon is 64×30. Artists can edit the PNGs without changing game logic, and audio lives as MP3s on the host or console base. The complete Garden download includes the assets and runnable code. -Sources: [Scene timers](../../docs/vs2/reference/scene.html), [sample spawn_seed](examples/dream_garden.py). +Sources: [Desktop setup](../../docs/guides/desktop.html), [complete Garden download](examples/dream-garden.zip). --- - + -## A collision grows a flower +## Stage 1: one creature around the rim -Run this checkpoint +Play stage 1 ```python -# In build(), in this order: -self.world = self.layer("world", projection=vs2.TUNNEL) -self.air = self.layer("air", projection=vs2.TUNNEL) -self.flowers = self.world.sprite_pool( - "flowers.png", count=24, on_empty=vs2.RECYCLE -) -self.dreamer = self.world.sprite("dreamer.png", y=0) -self.seeds = self.air.sprite_pool("seed.png", count=16) - -# In the seed movement loop: -if seed.overlaps(self.dreamer): - self.bloom(seed) -``` - -Flowers below players. Flying seeds above both. - -Notes: -**21:00–22:30.** Collision tests use axis-aligned bounds in a layer's circular coordinate system. They understand the angular seam, so a dreamer crossing zero can still catch a seed without a duplicate actor. They are not pixel-perfect physical tests on the fan. The actual loop first decreases seed depth, then checks either active dreamer. Bloom retires the seed and plants a flower at the dreamer’s depth. Its centre is displaced by 75% of the dreamer’s width. Moving catches plant in the current direction. After stopping, the first catch uses that direction, then later catches alternate sides. Moving again resets the sequence, separately for each player. Opposite inputs count as stopping. Before moving, the first catch defaults to left. The later planting slide shows the helper that implements this rule. Flowers drift toward the centre at only 8% of normal seed speed. A missed seed retires after passing the rim. The response changes the garden without ending play or recording failure. This is a small code change with a large effect on the experience. Use the Run this checkpoint button to open this stage in the browser; it contains only the features covered so far. - -Sources: [Collision API](../../docs/vs2/tutorial/sprites.html), [Dream Garden's move_seeds and bloom](examples/dream_garden.py). - ---- - - -## Planting follows the player's movement +import vs2 +from vs2.controls import LEFT, RIGHT, joy1 -Run this checkpoint +class Game(vs2.Scene): + def build(self): + world = self.layer("world", projection=vs2.TUNNEL) + self.dreamer = world.sprite("dreamer.png", y=0, x=-9) + def update(self): + steer = joy1.held(LEFT) - joy1.held(RIGHT) + self.dreamer.x = (self.dreamer.x + steer) % 256 -```python -# Movement resets the next planting side. -self.moving = bool(steer) -if steer: - self.plant_side = steer - -# In bloom(): -centre = self.dreamer.x + self.dreamer.width // 2 -centre += self.plant_side * self.dreamer.width * 0.75 -self.flowers.spawn( - x=(centre - self.image("flowers.png").width // 2) % 256, - y=self.dreamer.y, frame=randrange(4) * 2 -) -if not self.moving: - self.plant_side = -self.plant_side +def main(): + return Game() ``` -Stopped catches alternate sides until movement resumes. +A / D steer. Crossing column zero stays continuous. Notes: -**22:30–23:45.** This checkpoint has one player. Movement resets plant_side every tick. Once stationary, bloom flips it after each catch, so the first follows the last movement and subsequent catches alternate. When we add the second player, the finished source keeps separate plant_side1 and plant_side2 values. Catching plants at the same Y as that player, displaced by 75% of its width. The checkpoint starts without flowers. The 24-slot flower pool recycles the oldest when full, and missed seeds disappear harmlessly beyond the rim. Test catches across the angular seam as well as in the middle of a sprite. The player stays above the flowers because its sprite was created after the flower pool. +**13:15–15:45.** This is the whole starter’s behaviour, with x=-9 centring the 19-pixel dreamer at angle zero. The downloadable starter derives that offset from its width. The runnable stage uses the same result. Explain the unusual part: X is an angular position and wraps, while Y zero sits at the outer rim. Held directions are stable controller states; opposite directions cancel. Open stage one in its own tab, move across the seam and return to the deck. Reserve about one minute for this demonstration. The packed dreamer image and current metadata complete the folder. Everyone can replace its artwork; programmers can change the movement. -Sources: [Allocation and target checks](../../docs/vs2/tutorial/budgets.html), [sample source](examples/dream_garden.py). +Sources: [Starter source](examples/first_game.py), [display model](../../docs/vs2/tutorial/display.html). --- - - -## Fluffy clouds can span several tiles + -Run this checkpoint +## Angle and depth replace screen X and Yself.ground = self.air.tilemap(
- "clouds.png",
- columns=16, rows=22,
- view_width=256,
- view_height=160
-)
-# A large cloud uses frames 3–8 in a 3×2 block.
-self.ground[11, 4] = 3
-self.ground[12, 4] = 4
-# Reserve seeds after the clouds:
-self.seeds = self.air.sprite_pool("seed.png", count=16)
-1×1, 2×1 or 3×2 cells. Seeds draw above clouds.
+X wraps through 256 angles.
+TUNNEL Y is depth from 0 to 255. Increasing it moves inward and shrinks the picture.
+HUD Y selects one of 54 radial LED positions.
+
slow = slow1 or slow2 # either active player
-# Arm held-A after releasing the start press.
-self.speed = 0.12 if slow else 0.45 # seeds only
-self.spawn_ms = 4000 if slow else 1800
-Either player can relax the shared seed flow.
+for seed in self.seeds:
+ seed.y -= self.speed * 0.85
+ if seed.overlaps(self.dreamer):
+ self.bloom(seed)
+The overlap test understands the angular seam.
+Flowers start at the player’s depth and drift inward.
+
+
+PNG strips hold frames. Palette groups hold up to 256 colours.
Notes: -**33:15–34:30.** Forty-two sprites means two reserved dreamers, sixteen seeds and twenty-four flowers. Hidden player two and empty pool slots still count. The cloud tilemap, RELAX label and audio notice use three tilemap records. The lower layer draws planted flowers then dreamers; the middle draws clouds then seeds; the HUD paints above both. Five strips include the full font shared by the other scenes. Layers and records are separate resources. VS2 checks the graph at entry and reports the layers contributing to an exceeded budget. Tilemaps can be costly even when their record count is low. Random seed glow uses a small state entry per live seed, removed on retirement. Our bounded garden can run indefinitely without growing its renderer graph. Target timing and heap still need measurement on the console. +**21:15–22:55.** Keep both atlases from the original presentation, but reduce the asset pipeline to what matters here. The runtime builds an indexed image ROM from the PNG strips and YAML manifest. Dreamers and flowers share one palette group; clouds have another so they can stay subdued. Animated frames have equal dimensions and sit side by side in a strip. The large clouds become adjacent 16-pixel cells, so one shape can span two cells or a three-by-two block. Original art stays separate from code and can be replaced. Point artists at the downloadable files. Test the result on the disc, because rectangular art changes proportions and details compress near the centre. Leave conversion scripts and frame-count minutiae to the guide. -Sources: [Resource limits](../../docs/vs2/reference/services.html#vs2-limits), [sample build](examples/dream_garden.py). +Source: [Artwork and rebuild recipes](examples/artwork.html). Images: the original source atlases, unchanged. --- - + -## The disc decides what is readable +## Depth, draw order and readable text -Text belongs near the rim.
-Dark space keeps the seeds visible.
-Check timing and intensity on hardware.
-
-./vs-emu.sh --game demos.dream_garden
Catch a seed, invite a friend, hold A.
-B rests with the flowers. A begins again.
-Desktop demonstration
+Invite a second player into the same garden.
+Hold A to relax the seed flow. Clouds keep moving.
+N toggles music and sounds. B keeps the flowers in a resting scene.
+