# AKLABS MEGADEMO '85 A demoscene production for akbasic, written as if it were 1985 and this dialect were the machine under the tree. Code and FX by Tachikoma, dedicated to GameCube, megagreetz to starfort. ```sh ./build-akgl/basic examples/megademo/megademo.bas ``` Q or ESC quits. Six scenes: a title card, a Lissajous braid, a spinning wireframe cube and octahedron — which drift together, ignite a pulsing origin point strobing the next scene's colours, swallow the camera as the perspective scale outgrows the window, and split that origin into the first two raster bars — then the raster bars proper, the sprite bank going supernova — the letters fall into the middle, a fireball throws them at the walls, and a black hole drags everything back into the centre as the transition out — and a finale that composes all of it. A sawtooth chiptune in A minor throughout, with a noise drum break, if a SID answers. ## What it leans on This is a tour of the interpreter's edges, on purpose: - **No `RND`** — it carries Chapter 17's LCG, seeded from `TI#`. - **No palette writes** — the "colour cycle" on the logo is an honest redraw of the same strokes in the next colour, and the raster bars are erased and redrawn two scanlines at a time. The palette is sixteen fixed colours and the demo says so on screen. - **Eight sprites** — so the lettering *is* the sprite bank. Each letter of GAMECUBE is drawn with the stroke font from `examples/breakout`, captured with `SSHAPE`, installed with `SPRSAV`, and tinted with `SPRITE`. - **`SOLID` walls and `COLLISION 2`** — the supernova registers four rectangles and reverses a bearing per `RCOLLISION(n, 7)`. The interpreter does the physics; BASIC does one subtraction. The letters leave the blast on `MOVSPR`'s continuous form, eight bearings fanned evenly around the compass. - **The black hole is `RSPPOS` plus one rotation** — read each letter's position back, rotate the offset from centre, shrink it by 0.86, put it there. Thirty-four frames later everything is in the middle. The screen goes with it: an iris of collapsing black `CIRCLE`s, which works because the drawing verbs clip silently at the window edge — a fireball and an iris can both start bigger than the screen. - **The camera is a multiplier** — the wireframe zoom-through is nothing but the perspective scale growing fourteen percent a frame until the solids' edges leave the window, which the silent clipping permits. The pulsing origin point strobes through the bar ramp table because it *is* the next scene: it splits, rides the Y axis to the band edges, and stretches into the first two raster bars in place. - **3D with no matrices** — the wireframe scene rotates fourteen pooled vertices through two composed axis rotations and a perspective divide, all of it `SIN`, `COS` and one division, with the float kept on the left of every product because the left operand decides the arithmetic. Erase is the raster bars' trick: redraw the previous frame's twenty-four edges in black. - **`PLAY` is one queue** — every note holds it for its length and the whole batch plays on one instrument, so three `V` tracks come out end to end, not layered. The soundtrack is therefore beeper music, the way single-channel tracker tunes were written: sixteenths that take turns being the kick (an `O1` root), the pumping bass (`O2`/`O3` octaves) and the rolling arpeggio (`O4` and up), two alternating eight-beat batches — Am F C G, then Am F Dm E with the G sharp — and every third batch a bar of noise drums. Noise is real: `ENVELOPE`'s sixth argument is a waveform, 0 to 3, which Chapter 7 forgot to mention. Voice 1 carries the tune so the collision blips (voice 2) and scene sweeps (voice 3) never steal its channel. It also probes for its hardware like a proper boot loader, with one `TRAP` per device: no graphics refuses by name and exits, no audio mutes the soundtrack, no text grid drops the status row, and a host that never sets the clock — which is exactly what `tools/screenshot.c` is — renders each scene as a still and leaves the finale as the picture. The same file runs everywhere; nothing hangs. ## The ones that bit **A scalar first assigned inside a `GOSUB` dies with that call's scope.** The first cut computed text centring in a subroutine and read the result after `RETURN`; every line of text rendered flush left, because the variable read back as a fresh zero. Reads climb the scope chain, so a nested subroutine can *use* your globals — but a write to a name that exists nowhere creates it in the current scope, and the scope is not coming back. That is why Chapter 18's listings predeclare. **Then the predeclaring bit back.** The obvious lesson — predeclare everything — ran the 128-slot variable pool dry the moment the wireframes arrived: `Maximum runtime variables reached`. A predeclared scratch variable occupies a slot forever; a scoped one gives its slot back at `RETURN`. So the rule is narrower than it first looks: predeclare a subroutine's *outputs* and nothing else. This program predeclares four. **And the raster wait strangled the SID.** The `VSYNC` label used to spin on `TI#` until the jiffy turned — romantic, and fatal. The host releases at most one queued `PLAY` note per frame, and a frame of 256 *executed* spin statements is slow enough to drop the release rate below the tune's fifteen notes a second. The queue never reclaims slots until it drains completely, so the backlog compounded quietly for two scenes and then `PLAY queue is full` killed the show. `VSYNC` now sleeps a frame — `SLEEP` holds at no per-step cost — and `TUNE` traps the overflow on hosts slower than this one, dropping a bar instead of the whole demo. `TODO.md` §4 carries the measurement. ## What it wanted and could not have Recorded properly in `TODO.md` §4, "What a demoscene program wanted and could not have": `RND` as a real function, palette writes, `GSHAPE` XOR stamping, a way to ask whether `PLAY` has drained, per-voice `PLAY` queues so three voices can actually sound together, and a frame-edge wait that is not a busy loop. None of them blocked the demo; all of them left a routine behind that every future game will carry too.