All 35 Waves

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.

idx name formula harsh = breaks rhythm closing = periodic at 2π·n T = measured period (— = no clean close)

Pure sine

The reference shapes. Smooth, periodic, easy to predict.

00
classic sine
sin(x*.1)*.4
gentleclosingT 62.83
01
sine
sin(x*.2)*.25
gentleclosingT 31.42
02
sharp peaks
abs(sin(x*.1))*.5
gentleclosingT 31.42
33
smooth solid sine
sin(x*3.1)*.25
gentleclosingT 2.03

Peaks & valleys

Modulated sines that emphasise crests or troughs.

06
mountain peaks
abs(cos(x*.1))*.35 + sin(x*.1)*.25
gentleclosingT 62.83
07
valleys
abs(cos(x*.1))*-.35 + sin(x*.1)*.25
gentleclosingT 62.83
09
batman
sin(x*.1)*.7 % .4
gentleclosingT 62.83
10
offset sine
ceil(cos(x*.1))*.25 − sin(x*.1)*.25
gentleclosingT 62.83

Stepped & pulses

Quantised waves: ceil/round/modulo carve smooth shapes into plateaus.

05
stepped sine
ceil(sin(x*.1))*.25
gentleclosingT 62.60
11
steps down
ceil(tan(x*.1))*.25
harshclosingT 31.42
12
steps
round(sin(−x*.1))*.25
gentleclosingT 62.82
08
zig-zag sine
sin(x*.2)*.4 % .12
gentleclosingT 31.42
03
square
(x*.025)%1 < .5 ? −.5 : .5
gentleT 40
04
pulse
(x*.5)%20 < 1 ? −.5 : .5
gentleT 40

Layered & modulated

Two or more sines multiplied, added, or modulated. More personality, still smooth.

13
squared sine
sq(sin(x*.1))*.25
gentleclosingT 31.42
14
bumpy sine
sin(x*.1)*.25 + sin(x*.5)*.1
gentleclosingT 62.83
15
wobble sine
sin(x*.1)*cos(x*.2)*.5
gentleclosingT 62.83
17
meta sine
sin(x*.45 + radians(x))*cos(x*.4)*.5
gentleT —
31
round linked sine
sin(x*.1)*cos(x*1)*.5
gentleclosingT 62.83
29
ramp up sine
sin(x)*(x*.01%.5)
gentleT —
30
triangle sine
sin(x)*(x*.01%1−.5)
gentleT —
32
half sine
sin(x*.05)*(x*.1%.5)
harshT —

Linear & saw

No trig, just modulo and absolute value. Sharp, predictable.

18
triangle
abs((x*.03) % 1 − .5)
gentleT 33.33
19
ramp
−(x*.02%1) + .5
gentleT 50
20
saw down
x*.03 % .5
gentleT 16.67
21
saw up
−x*.03 % .5
gentleT 16.67

Chaos & special

Things break loose: tangents, noise, logarithm, random. Most are flagged harsh: they use a seeded PRNG or a non-trig function with surprising spikes.

16
up down noise
x*sin(x*.1) % .5
harshT —
22
shake out
sin(log(sq(min(abs(x)%62.8319,62.8319-abs(x)%62.8319))+1)*3)*.5
gentleclosingT 62.83
23
grow random
random(x*.003)
harshT —
24
noise
noise(x*.1) − .5
harshT —
25
fuzzy pulse
tan(x*20)*.05
harshT 17.75
26
up down pulse
tan(x*.1)*.05
harshclosingT 31.42
27
bald patch
sq(x*.05) % .5
harshT —
28
fuzzy peak sine
sin(x*.1) < 0 ? random(−.2, .2) : sin(x*.1)*.5
harshT —
34
spike sine
sq(sq(sin(x*.1)))*sin(x*.1)*.5
gentleclosingT 62.83

Periodicity

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.

Closed-shape recipe

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);

Quick lookup

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

How to read the result

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.