nibbles
nibbles · sourcesA playable QBasic-Nibbles snake game rendered as a patchable video source. The classic snake roams an 80x50 grid (CPU-rasterised to a 320x200 frame with a gentle CRT scanline darken) eating one pellet at a time, growing its body, and dying on a wall or self collision. Drive it two ways: open the module's faceplate, click the game screen to focus it and steer with the arrow keys, or flip AUTO on to let the built-in greedy bot self-play (it walks toward the pellet, avoiding its own tail, with no foresight so it eventually traps and dies — then auto-restarts). Arrow keys are ignored while AUTO is on, so the two drivers never fight. The game advances at the rate set by Tick. Beyond the video frame, the snake's life becomes control voltage and sound: gate pulses fire on pellet/death/direction-change, a length CV tracks how long the snake has grown, and two square-wave audio outs are pitched by the snake's length (length 4 = A2/110 Hz, every +12 length = +1 octave). Patch the gates into envelopes/triggers and the length CV into pitch or filter cutoff to sonify the game. The faceplate's game screen carries three controls of its own, overlaid on its corners. SCREEN collapses the picture to reclaim its space WITHOUT stopping anything — the snake keeps moving and every gate, CV and audio output keeps firing, because the game ticks inside the module's own draw. SCALE cycles the 320x200 source through 1x / 2x / 3x / 4x zoom (image-rendering: pixelated, so it stays crisp); above 1x the picture scrolls inside its own box rather than widening the plate. Both are per-view preferences stored on the node, so they survive a collapse, an eviction and a reload. RESET starts a fresh game immediately — a new snake at length 4, a newly-placed pellet, the length CV and both pitches re-derived — independent of AUTO, writing nothing to the patch and not undoable, because the game is the module's own internal state and is deliberately never persisted.
the faceplate
outputs
| id | cable | what it does |
|---|---|---|
out | video | Video output — the 320x200 rasterised game frame (dark-slate board, red pellet, lime head, green body) with every other scanline dimmed ~15% for a mild CRT look. RGB video stream |
pellet | gate | Gate output — a 10 ms HIGH pulse fired each time the snake eats a pellet. Patch into an envelope trigger to sound an eat hit. gate / trigger; trigger — fires once per rising edge |
death | gate | Gate output — a 10 ms HIGH pulse fired when the snake dies (wall or self collision). One pulse per death; in AUTO mode the game then auto-restarts. gate / trigger; trigger — fires once per rising edge |
dir_change | gate | Gate output — a 10 ms HIGH pulse on every accepted direction change (human arrow press or AUTO bot decision); repeated presses of the same direction do not pulse. gate / trigger; trigger — fires once per rising edge |
length_cv | cv | CV output — the snake length mapped bipolar to about [-1, +1] (mid = NIBBLES_MAX_LENGTH/2 = 59.5; length 119+ clamps to +1). Steps are smoothed with a ~20 ms ramp at the game-tick rate. Patch into pitch or filter cutoff. control voltage (CV) |
snake | audio | Audio output — a continuous square wave whose pitch tracks the live snake length (length 4 = A2/110 Hz, +12 length = +1 octave), at ~0.2 amplitude. Always on while the module lives. audio signal |
gated | audio | Audio output — the same length-pitched square wave routed through an envelope (15 ms attack, 100 ms plateau, exponential decay tail) that fits inside a 500 ms total window and retriggers on every pellet eat, so it sounds only when the snake feeds. audio signal |
params
| id | label | range | default | curve |
|---|---|---|---|---|
auto | Auto | 0..1 | — | discrete |
tick_ms | Tick | 40..200 | — | linear |
controls
| control | what it does |
|---|---|
| Auto | Auto — a two-state switch. When ON, the built-in greedy bot drives the snake and auto-restarts it on death; arrow-key steering is ignored. When OFF, you steer with the arrow keys (the game screen must hold focus — click it). Flipping it ON also clears the bot's remembered heading so a freshly-enabled AUTO re-decides on the very next tick instead of stalling. |
| Tick | Tick — the game-tick period in milliseconds (40-200, default 80; ~12 ticks per second at default). Lower is a faster snake; clamped to the 40-200 ms window. It is read every frame, so a change lands on the next tick, and because every gate, the length CV step rate and the envelope retrigger are clocked by it, it is the module's tempo control. |
source
nibbles.ts on GitHub.