Skip to content

The Operators

midi-sink never solves a fluid on a grid. Grid advection diffuses, and diffusion turns crisp suminagashi rings into mud within seconds. Instead the ink is an area-preserving, continuous deformation of the sheet, evaluated by inverse lookup: for every output pixel PP the engine asks where that water came from, Psrc=f−1(P)P_{src} = f^{-1}(P), and reads the ink there. Two half-float textures hold the accumulated pre-image coordinates (u,v)(u, v) plus the ink phase and a per-drop hue selector; each gesture is one more pass that reads one texture and writes the other. This is Aubrey Jaffer’s mathematical marbling (Lu, Jaffer, Jin, Zhao & Mao, 2012), extended with two of his own later closed-form fields and a few of ours — see the citations.

Every operator page follows the same shape:

  • The formula, exactly as the shader evaluates it, in aspect-corrected normalized coordinates (non-square canvases are corrected before the mathematics, or rings become ellipses; distances are in canvas heights).
  • Invariants — why it preserves area, its class — exact at any magnitude, or sub-stepped to stay away from a fold — and what composes with what. Every operator declares its class and passes the same four-part conservation gate (the desktop bench’s --soak: area, mass, the pre-image’s wander, fabrication as a rate); the composite is gated per backend.
  • Ownership — which MIDI dimension or gesture drives it, and the one-consumer rule: a MIDI dimension has exactly one consumer at a time (bend_mode, press_mode, slide_mode choose it) so two operators never fight over one stream.
  • A live demo — the release wasm, the same engine bytes every platform ships, embedded through the scene API. The sliders are the formula’s symbols. There is no second implementation anywhere on this site.

Two conventions run through every demo. The scenes are paced — the ⏱ slider is the number of frames between steps, and the operators that compose exactly are applied as a run of small passes, so you watch the transformation happen rather than see only its result (set it to 0 for the result alone). And every scene works on two ring clusters, top-left and bottom-right, so one operator can show two orientations or two signs at once: a horizontal and a vertical tine, two counter-rotating vortices, perpendicular fold axes, a drop beside a pressure feed. A third: every scene carries the medium toggle (M) — flip it to 1 and the same script runs from its first strike as the Anod discharge: every strike in a scene is the medium’s, so under Anod the ring clusters are struck as sparks on their charge, as a tap is in the app, and the deformation is read as strain instead of bands. The toggle is permanent for the run, never a switch at the end.

The drop, the first operator: six expansions on each cluster, one per step.open full size ↗
OperatorKindClassDriven by
Drop — and the pressure feedexpansionexactstrike, pressure feed, breath
Tineshearexact (Jacobian 1)per-note bend (glide), master bend
Vortex — exponential, Rankine, torsionrotationexact at any anglemod wheel / Airwave CC (exponential), two-finger twist (Rankine)
Wake — inviscid doublet, viscous Stokesletpotential-flow doublet · 2-D Stokes impulsesub-stepped ≤ a/4every stylus stroke; a wind legato (the sounding drop dragged to the next note)
Pinch — saddle, crossed tinesHamiltonian saddleexact (det = 1)CC 74 with Slide → Pinch, pen azimuth, two-finger pinch
Ripplesine shearexact (Jacobian 1)per-note bend with Per-note bend → Ripple, CC 102/103
Swirl — Lamb–Oseenviscous rotationexact at any anglepoly pressure 0xA0, channel pressure with Channel pressure → Swirl
Scrolltranslation with ingressexactthe piano-roll layouts’ tempo

The second medium, Anod, reads the same field as a discharge and brought five operators with it — every one of them a shear or a rotation composed from the first nine’s lemmas, and every one of them playable under suminagashi too:

OperatorKindClassDriven by
Wave torsionoscillating rotation by θ(r)exact at any amplitudethe vortex routes with the Torsion profile; the note-on sweep; Anod’s press
Chladni — an eddy in every keyexact disc rotations on the layout’s cells · the inverse Chladni’s summed flowexact (discs) · first-order (inverse)the stir and balance CCs 106/107; Anod’s per-note bend
Burst — the viscous multipole, m ≥ 2time-integrated impulsive multipolesub-stepped (first-order, under the wake’s criterion)the gesture; the middle piece of the Anod strike
Spark — the composed strikedrop + burst + jagged shearsexact shears; sub-stepped by inheritancethe Anod strike on its charge; the slide (CC 74) its frequency
Chirikov — the standard mapsinusoidal kick + linear driftexact; capped at K = 1.25 per stepthe throw: CC 109, Anod’s mod wheel

The two media and their look — the washi and the glass, the three palettes of each and the palette model behind them — are the medium guide’s.

Continuous feeds are deltas. Pressure, breath, swirl and pinch arrive as absolute controller values, but the operators consume rates: a pass per frame whose magnitude is the smoothed value × Δt. Feeding an absolute value integrates into runaway strain; a delta relaxes when the hand relaxes.

Paper is screen-locked. The washi fibre and grain are sampled in screen space, never through the deformed field. Ink moves; the paper it sits on does not. If fibres ever drift with a tine, that invariant has been broken.

midi-sink 2.0.0-rc.5 · AGPL-3.0 · source