00
classic sine
sin(x*.1)*.4
gentleclosingT 62.83
Each wave is a deterministic function: pass a number in, get a number back. The output range is roughly [−0.5, +0.5] before you scale it. Live previews are rendered by p5.js + p5.waves (JS); processing.waves (Java) produces numerically identical output.
The reference shapes. Smooth, periodic, easy to predict.
Modulated sines that emphasise crests or troughs.
Quantised waves: ceil/round/modulo carve smooth shapes into plateaus.
Two or more sines multiplied, added, or modulated. More personality, still smooth.
No trig, just modulo and absolute value. Sharp, predictable.
Things break loose: tangents, noise, logarithm, random. Most are flagged harsh: they use a seeded PRNG or a non-trig function with surprising spikes.
A wave is periodic when there is a distance T such that
wave(x) == wave(x + T) for every x. That distance is
the wave's period. Knowing the period lets you close curved
shapes cleanly: sample a wave around a circle over an integer number of periods,
and the last vertex lands on the first one — endShape(CLOSE) draws
a zero-length line, no ugly seam.
Why 62.83 and not 360?
Waves.wave(x) treats x as a generic coordinate -
the same mental model as noise(x) — not an angle in degrees
or radians. Frequencies are tuned for character, not for round numbers.
Ten of the 35 waves are not sine-based at all
(square, triangle, ramp,
noise...) so radians would be meaningless for them.
Use this table as your lookup instead of reaching for TWO_PI.
Every period value was measured, not derived: the
periodicity harness
in the p5.waves repo samples each wave, searches for the smallest T
where the mean error between wave(x) and wave(x + T)
stays below 0.002, then confirms with multiples. processing.waves produces
numerically identical output, so the same periods hold here.
The integer lobes is the only thing you tune — anything from 1 upward works. Full Java code (including the shift-proof .group("closing") variant) lives in the guide.
// Draw a closed wobble ring. No visible seam.
float period = 62.83f; // from the table below (classic sine)
int lobes = 8; // how many bumps around the ring
int steps = 240; // resolution (does not affect closing)
float sweep = lobes * period; // integer multiple = clean close
WaveOpts o = new WaveOpts().wave("classic sine").amplitude(20);
beginShape();
for (int i = 0; i < steps; i++) {
float u = i / (float)steps;
float a = u * TWO_PI;
float r = 140 + Waves.wave(u * sweep, o);
vertex(r * cos(a), r * sin(a));
}
endShape(CLOSE);
25 waves close cleanly, 10 don't. Each card above also shows its measured period.
| Period T | Waves |
|---|---|
| 2.03 | 33 smooth solid sine |
| 16.67 | 20 saw down, 21 saw up |
| 17.75 | 25 fuzzy pulse (valid close, not the fundamental) |
| 31.42 | 1 sine, 2 sharp peaks, 8 zig-zag sine, 11 steps down, 13 squared sine, 26 up down pulse |
| 33.33 | 18 triangle |
| 40 | 3 square, 4 pulse |
| 50 | 19 ramp |
| 62.83 | 0 classic sine, 5 stepped sine, 6 mountain peaks, 7 valleys, 9 batman, 10 offset sine, 12 steps, 14 bumpy sine, 15 wobble sine, 22 shake out, 31 round linked sine, 34 spike sine |
| — | no clean close: 16 up down noise, 17 meta sine, 23 grow random, 24 noise, 27 bald patch, 28 fuzzy peak sine, 29 ramp up sine, 30 triangle sine, 32 half sine |
CLOSE.
Want a shape that stays closed while shifting between formulas? Use
.group("closing") — a pool of 19 waves that all share the base period
62.8319 — and read the sweep from sampler.period().
See Closing curved shapes in the guide.