Skip to content

hash(x) and noise(x) — seeded randomness

Two functions give a preset variety no arithmetic can fake. Both are pure: the result depends on the argument and on the preset’s seed, and on nothing else. Call either twice with the same argument in the same frame and you get the same number — they are dice you rolled once, not dice you keep rolling.

shapereach for it when
hash(x)a scatter in [0, 1) — neighbouring arguments are unrelatedyou want something different per beat, per bar, per element
noise(x)a wander in [0, 1] — smooth, changing over one unit of xyou want a parameter to drift organically instead of cycling
[params]
# A wander that never repeats — one call replacing a sum of detuned sines.
# The coefficient is the speed: 0.3 moves noticeably, 0.03 is a slow tide.
hue = "noise(time * 0.3)"
# A different value twice a second: floor(time * 2) steps to a new integer
# every 0.5 s, and hash turns each of those into an unrelated number.
burst = "0.4 + hash(floor(time * 2)) * 0.6"
# Scatter a per-element readout so it stops looking combed (see `index`).
thickness = "2 + hash(index * 64) * 3"

Layer noise for a richer wander. One call is one octave — smooth and a bit plain. Sum two or three at different rates and amplitudes and you get something that reads as organic:

noise(time * 0.11) * 0.6 + noise(time * 0.43) * 0.3 + noise(time * 1.7) * 0.1

Give the calls different arguments, not just different multipliers of the same one, if you want two parameters to wander independently — noise(time * 0.2) and noise(time * 0.2 + 50) are two unrelated wanders at the same speed.

The seed

[generator] seed decides the scatter. It has been accepted (and ignored) since the L-system landed; it now salts hash/noise for any system, so a preset that is not an L-system can carry a [generator] table containing nothing else:

[generator]
seed = 12 # any non-negative integer: the same look, every time
# seed = "random" # a different look every time the preset loads
  • No seed means seed 0 — a perfectly good scatter, and what every preset had before this existed.
  • A number makes the preset reproducible: same audio, same picture, forever. Two presets with the same expression and different seeds look different.
  • "random" draws a fresh seed each time the preset loads — app start, and every hot reload of the preset folder, so it re-rolls on each save while you are editing. It is drawn once, at load — never per frame.

"random" and captures. Every capture path — shot, the golden baselines, --report, the behavioral gates — forces the numeric seed (0) so its output stays reproducible. So a seed = "random" preset’s captured frame is not the frame you saw live: same statistics, different instance. Tune with a number, switch to "random" at the end if you want the surprise.

Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.