About
Pass a number in, get a number back. Behind that one promise lives a curated set of 34 wave shapes: smooth sines and sharp sawteeth, gentle bumps and noise-flecked chaos, each one a tiny formula tuned to drive motion, color, shape, or pattern in a sketch.
A Java twin
processing.waves is the Java sibling of p5.waves, a p5.js library originally built for the browser side of generative coding. The Java port carries the same vocabulary across to Processing 4: same names, same indices, same numerical output. If you sketch in p5.js today and in Processing tomorrow, you bring the same building blocks with you.
Processing 4 has been a home for creative coders for two decades. It runs offline, exports to native apps, and handles pixel-by-pixel work without browser overhead. Artists, educators and students live there. Until now, the wave vocabulary from p5.waves stopped at the JavaScript boundary; this port hands those users the same set of shapes, behaving the same way, in the language they already use.
The challenge of a faithful port
Porting between two languages with similar surface syntax is usually a chore: rename, retype, recompile. Making the output of two implementations match is something else entirely. Floating-point math is full of subtle traps: signed vs unsigned 32-bit ints, hash functions that wrap differently across languages, pseudo-random sequences that drift apart by the fifth decimal. processing.waves takes those traps seriously:
FNV-1a 32-bit hash, returning the unsigned uint32 as a Java
longso the subsequent float math matches JS's unsigned-Number semantics.mulberry32 PRNG, ported bit-for-bit. A given seed produces the same sequence on both sides of the language border.
double-precision internal math, narrowed to
floatonly at the public API boundary, matching JS Numbers exactly where it counts and meeting the Processing convention everywhere else.
Trust, then verify
To prove the port works, the repo ships a numerical validator. It runs the JS reference (loaded via Node), captures 35 input/output pairs across all 34 waves and every code path, then runs the Java port over the same inputs and asserts equality within tolerance.
| Metric | Value |
|---|---|
| Cases | 35 (covers all 34 waves + 1 shift case) |
| Stable-mode tolerance | 1e-3 |
| Wild-mode tolerance | 0.5 |
| Current status | 35 / 35 pass |
Wild mode's looser tolerance is intentional: noise modulation amplifies tiny float-vs-double differences. The wave envelope still matches across the languages; only the per-sample chaos detail diverges within the noise budget. Visually you cannot tell them apart.
34 shapes, three temperaments
Every wave has a character. The library splits them into three groups so you can lean into the one you want:
Gentle: pure functions of x. Deterministic, repeatable, made of sines, cosines and modulos. The dependable section.
Harsh: noise-driven or tangent-spiked. They pull from a seeded PRNG, so they jitter and surprise within the wave's envelope.
Closing: a small set whose period divides 2π·n cleanly. A shape drawn over a full cycle joins back to itself without a seam, which is what you want when you sweep a wave around a circle.
You don't have to pick by hand. Ask the library for "a gentle one" and let a seed decide. Ask for a specific name. Ask for two names and crossfade between them with mix. Flip shift on and watch the library cycle through random formulas at a tempo you set. All from one function call.
How it differs from its parent
Fluent builder instead of object literal. Java doesn't have JS-style options objects, so
WaveOptsuses chained setters:new WaveOpts().wave("triangle").amplitude(80).No runtime string evaluator. JS p5.waves uses
new Function(algoString)internally to compile each wave's formula. Java replaces this with hand-written lambdas, one per wave. The string-eval feature was never exposed via the public API, so there's no surface-level difference.Pure math, no browser glue. No DOM, no canvas wrappers, no event handlers. The library plugs into Processing's draw loop like any other math utility.
License & credits
processing.waves is MIT, like its parent. The original p5.waves library lives at seb-prjcts-be/p5.waves.
Bug reports, sketches built with the library, and pull requests are all welcome on GitHub.
Makers & Contributors
Maker
Contributors (wave formula dataset)
tw@GenerativePunk - original dataset contributor
gh@ffd8 (Ted Davis) - original dataset contributor, Oscillation Sandbox
References
titanwolf.org - pulse / rectangular wave formulas
p5.js editor - jeremydouglass triangle sketch