home/ modules/ debugging-and-panic-recovery-in-hydra

Debugging and panic recovery in Hydra

  • learner can recognise and fix the five silent-failure patterns in Hydra: missing `.out()`, bare reactive values, unclamped FFT reads, feedback gain at-or-above 1, and wrong output-buffer selection
  • learner can trace any Hydra failure to one of two error surfaces — throw to `#err` or silent black/frozen/blown-out canvas — and choose the correct diagnostic step for each
  • learner can work within the rig's 4-bin Strudel shim: tag patterns with `.analyze('hydra')`, stay within `a.fft[0..3]`, and substitute band thresholding for absent onset/RMS/centroid features
  • learner can recover a crashed or blown-out sketch live using the panic-safe pattern, and explain why frame buffers survive across re-evals while JS state does not

Take a deliberately broken Hydra file seeded with one bug from each silent-failure class: (1) a chain that never renders because `.out()` is missing; (2) a reactive `a.fft` value baked in because its `() =>` thunk is missing; (3) a `src(o0)` feedback loop that whites out because gain is not contracted below 1; (4) an out-of-range `a.fft[5]` read returning NaN; (5) a Strudel voice missing its `.analyze('hydra')` tag so every bin reads zero; (6) a buffer object (`o0`/`s0`) chained bare instead of wrapped in `src(...)`; (7) a chain rendered to `o1` that never appears because `render(o1)` was not called; (8) a `.rotate().kaleid()` vs `.kaleid().rotate()` transform-order mistake; and (9) an array argument the author expected to ramp smoothly but that steps once per BPM cycle. Without looking up solutions, diagnose each failure using the two-surface model — check `#err` first, and where it is empty read the canvas (black / frozen / blown-out) and match it to its pattern class — then fix all nine bugs. Because the rig shim exposes no onset/RMS/centroid, add one audio-reactive element that derives a pseudo-onset from a threshold on `a.fft[0]`. Finally, from memory, write a panic sketch satisfying all four safety constraints (guaranteed `.out()`, every reactive value in a `() =>` thunk, FFT reads clamped to 0..3, non-zero base terms), and — leaning on the fact that re-eval runs `hush()` then re-evaluates the whole file on the same GL context so frame buffers survive — verify it recovers the canvas live in under five seconds. Deliver one annotated Hydra file naming, per bug, the error class and the canvas symptom that led you there, and labelling each panic-sketch line with the safety constraint it satisfies.

This module is built around a single professional reality: in an algorave or club set, a Hydra crash does not give you a dialog box or a stack trace. It gives you a black screen, a frozen frame, or a canvas washed out to white — and an audience. The ability to read that canvas like a diagnostic display, trace the failure to its class, fix it in seconds, and keep the set alive is what separates a working Hydra performer from someone who stops and restarts.

The twenty atoms here fall into two interlocking layers. The first layer (L1 gotchas) covers the bugs you hit on day one: chains that silently build textures into the void without .out(), reactive values that bake in as constants because the thunk wrapper is missing, FFT reads that return NaN because the index is out of the rig’s 4-bin range, feedback that races to white because gain is not contracted below 1, and buffers rendered to o1..o3 that never appear because render() was not called. These are not conceptually subtle — they are mechanical invariants the rig enforces silently — so the first drills are simple recognition-and-fix pairs timed under two minutes each.

The second layer (L5 debug) teaches you to use the rig’s error surface systematically. Hydra errors split into two classes: those that throw a JavaScript exception (visible in the on-page #err element, canvas frozen on the previous frame) and those that produce no throw at all (canvas goes black, frozen, or blown-out, #err stays empty). This matters because the debugging procedure is different for each: a throw tells you what broke; a silent failure tells you what the canvas is doing, and you must reason backward to the cause from the five known patterns. “Check #err first; if empty, read the canvas and match it to the pattern” is the complete diagnostic loop.

The rig-specific FFT layer introduces a constraint that most Hydra tutorials ignore: the a object here is a 4-bin shim fed from Strudel, not a native microphone FFT. Native tutorials that call a.setBins(8) and read a.fft[7] silently return undefined → NaN, blanking the output. The fix is enforcing the 0..3 range contract and tagging the Strudel pattern with .analyze('hydra') — without which all bins read zero regardless of what the audio is doing. Higher-level features (onset, tempo/beat-phase, RMS, spectral centroid) are absent from the shim; a performer who needs them must synthesize an approximation from the four bins, for example using a threshold on a.fft[0] as a pseudo-onset.

Re-eval semantics enter here because they explain why the panic recovery works the way it does. Each save calls hush() then re-evaluates the whole file on the same GL context — there is no page reload. Frame buffers o0..o3 survive across evals (which is why feedback loops keep running after you edit the file), but JS state does not. A JS syntax error throws and freezes the canvas on the last frame, which means that even a broken file is recoverable: fix the syntax and save to resume. The panic pattern exploits this — the minimal solid(0.05, 0.05, 0.08).out() can always be typed or pasted in under five seconds and will always succeed, resetting the canvas to a dark, non-erroring state from which the performer can rebuild.

The capstone exercises all four objectives together under no-scaffold conditions. The learner receives a seeded bug file (available in context/L5-debug/hydra-bugfile.hydra), works through the diagnostic loop without hints, and must write their own panic sketch from memory. The annotation requirement forces explicit reasoning: the learner names the error class for each bug, states which canvas symptom led them there, and labels each line of the panic sketch with the safety constraint it satisfies. This documentation doubles as a personal recovery protocol the performer can revisit before any set.

Atoms in this module

Required — these gate the capstone

A Hydra chain without `.out()` builds a texture that is never rendered — no error, just black
Misconception L1 Foundations H
In Hydra, live/reactive values must be wrapped in a thunk `() => …` — bare values are baked at eval time
Concept L1 Foundations H
In this rig, Hydra's `a` object is a 4-bin shim fed from Strudel, not the native mic FFT
Fact L1 Foundations HJ
Hydra FFT bins stay at 0 until a Strudel pattern is tagged `.analyze('hydra')`
Fact L1 Foundations HJ
The Hydra rig shim exposes only 4 FFT bins — onset, tempo, RMS and spectral centroid do not exist
Fact L1 Foundations HJ
Hydra feedback with `src(o0)` blows out to white if the fed-back signal is added or scaled ≥ 1
Principle L1 Foundations H
A Hydra array argument sequences values one per BPM cycle, not a smooth ramp or average
Concept L1 Foundations H
Hydra transform order matters — `.rotate().kaleid()` differs from `.kaleid().rotate()`
Principle L1 Foundations H
Hydra values are unclamped GL floats — pushing one parameter huge blows out or locks the GPU
Principle L1 Foundations H
Each Hydra save runs `hush()` then re-evals the whole file on the same GL context — frame buffers survive
Fact L1 Foundations H
Hydra buffer objects (`s0`, `o0`) are not chainable sources — they must be wrapped in `src(...)`
Fact L1 Foundations H
Hydra errors either throw to the #err element or silently render a black/frozen/blown-out canvas
Concept L5 Voice H
Every Hydra chain must end with .out() or .out(oN) to be visible on the canvas
Fact L5 Voice H
Hydra reactive values must be wrapped in () => thunks; bare expressions are evaluated once at boot
Misconception L5 Voice H
Hydra's audio FFT array has exactly 4 bands (indices 0..3); reading index 4 or higher produces NaN
Fact L5 Voice HJ
Strudel voices must call .analyze('hydra') for audio data to reach Hydra's a.fft array
Fact L5 Voice HJ
Hydra feedback with too much gain causes whiteout; add decay terms or reduce feedback amount
Concept L5 Voice H
Array arguments in Hydra step at the global bpm rather than animating smoothly
Concept L5 Voice H
A Hydra chain rendered to o1..o3 stays invisible unless that buffer is selected with render()
Fact L5 Voice H
The Hydra panic default is a bounded, reactive osc sketch with non-zero base terms and clamped FFT reads
Procedure L5 Voice H

Supporting — enrichment, not gating

Hydra models analog video synthesis: each function is a box that generates or transforms a signal
Concept L1 Foundations HG
Hydra organises all its operations into five types: source, geometry, color, blend, and modulate
Concept L1 Foundations H
Hydra's a.fft array holds per-bin amplitude values produced by FFT analysis of the microphone input
Concept L2 First instrument JH
a.setScale() and a.setCutoff() map FFT bin values to 0–1 via a noise gate and a ceiling threshold
Concept L2 First instrument JH
a.setSmooth() prevents strobe artifacts by exponentially averaging consecutive FFT frames in Hydra
Concept L2 First instrument JH