spinodal

Inside the Math · Spinodal

Teaching Wax to Unmix

Tap the glass and the wax goes milky, curdles into a labyrinth, beads, and clears again in about twenty seconds. One equation does most of that. The rest is heat that travels with the wax, and rules we wrote where a grid 60 cells wide can't resolve the physics or where a lamp should behave a particular way. These are eleven things we learned building Spinodal, most of them by getting something wrong first.

Ember
The lamp one second after a tap, in Ember
Glacier
The lamp one second after a tap, in Glacier
Lagoon
The lamp one second after a tap, in Lagoon
Orchid
The lamp one second after a tap, in Orchid
Amethyst
The lamp one second after a tap, in Amethyst
Aurora
The lamp one second after a tap, in Aurora
One second after a tap mid-glass, in each of the lamp's six waxes. The state is the same in all six; only the colours change. Each section below wears one of them. Every frame on this page is the lamp's own solver, stepped by a script on a fixed clock and drawn with the app's renderer, so each figure can be regenerated exactly (scripts/essay/filmstrips.mjs).

Contents

  1. 01The lamp is one number per cell
  2. 02Inside the spinodal, mixing undoes itself
  3. 03A shake breaks the wax. The cloud keeps time
  4. 04Heat belongs to the wax
  5. 05A lamp is a relaxation oscillator
  6. 06Every contact was a merge
  7. 07Conserve the wax, or the lamp lies
  8. 08Pressure is the slow part
  9. 09Sound shakes the lamp. Music plays it
  10. 10The camera looks for crossings
  11. 11What we got wrong, and what is next

Three kinds of rule

Spinodal is part physics and part design, and the essay keeps them apart. Each section is tagged with the kinds of rule it covers.

Physics
What the equations do with nothing added: wax separating from liquid, surfaces pulling tight, warm wax rising and cool wax sinking, big blobs growing at small ones' expense.
Design
Rules we wrote, either because the grid is too coarse to resolve the real effect or because the lamp should behave a certain way. The pattern a tap draws, the haze's one-minute memory, the film's two-second drain, the thread rule, fog return and the mass correction, the coil's ceiling and the fast cooling under the cap, the nanites, and the camera.
Rendering
What makes the fields visible. In the app, that is the renderer and its camera. In these figures it is also two cross-sections, which colour the spinodal band cyan and the wax by its temperature.

The equations come with a plain sentence first, saying what each one is for. The symbol key is in section 1, and the implementation notes are for readers who want the code.

01Ember wax
  • Physics
  • Rendering

The lamp is one number per cell.

Blobs split, merge and change shape all the time. If each blob were an object with a surface of its own, every split and every merge would need surgery on that surface. So the lamp doesn't keep track of blobs at all. On a phone the chamber is a grid of 60 × 132 × 60 cells, and each cell holds one number, ψ (psi): −1 is clear liquid, +1 is wax, and anything between is a mix of the two. A blob is a region where ψ is near +1, its surface is wherever ψ crosses 0, and a split is just ψ changing.

The lamp
The lamp running, 30 s after a warm start, in Ember
ψ, the mix
The mid-plane cross-section of psi at the same moment
Temperature
The mid-plane cross-section of the wax's temperature at the same moment
Figure 1a. One moment of a running lamp. Left: the lamp as the app draws it. Middle: ψ on the vertical plane through the lamp's axis, with liquid dark, wax in Ember, and cells inside the spinodal band (section 2) cyan, so a surface shows as a thin cyan rim. Right: the same plane with the wax coloured by its temperature, from cold (violet) through neutral (red, 0.6) to the coil's ceiling (white, 1.6). The later figures use both cross-sections to show what the lamp's surface hides.
Symbol key
ψ
The mix in a cell: −1 clear liquid, +1 wax, 0 half and half.
c
Wax fraction, (ψ + 1)/2, from 0 to 1.
f(ψ)
The energy a cell pays for being mixed.
ε
How wide a surface is: 1.3 cells.
μ
Chemical potential, the slope of that energy. Wax flows from high μ to low.
M
Mobility, how fast wax answers μ: 0.0055 per substep.
u
The liquid's velocity, in cells per substep.
k, λ
A ripple's wavenumber and wavelength, λ = 2π/k.
ω(k)
How fast a ripple grows (positive) or dies away (negative).
f″
How the energy curve bends: negative inside the spinodal band.
T, e
The wax's temperature in the lamp's units (neutral at 0.6), and the heat it carries, e = cT.
L
The shake level, from 0 to 1.
H, τ
Haze, and the time it takes to fade by a factor of e: 52 lamp seconds.
σ
How hard a surface pushes on the flow: 0.015.
substep
One step of the solver. 240 substeps make one lamp second.

Two rules turn that number into wax. First, mixing has to cost something, or wax and liquid would blend like ink in water. Each cell pays an energy for being mixed, lowest when it is pure liquid or pure wax:

f(ψ) = ¼ (ψ² − 1)²

plus a cost for sharp changes between neighbours, ε²|∇ψ|²/2, which acts as surface tension: it keeps a surface a few cells wide instead of a ragged step. Second, wax has to move so as to pay less. It flows from where the chemical potential μ, the slope of that energy, is high to where it is low. Without this, nothing would pull a smeared blob back into shape:

μ = ψ³ − ψ − ε²∇²ψ     ∂ψ/∂t + u·∇ψ = M ∇²μ

That is the Cahn-Hilliard equation (Cahn & Hilliard 1958), with a term that carries ψ along with the flow u. Its right-hand side is a divergence, which means wax only ever moves from a cell to its neighbour. With walls that let nothing through, the total of ψ can't change, so the equation by itself neither makes nor destroys wax. Some of the rules added on top of it do, and section 7 is about how the lamp keeps count. At rest, a surface settles into a tanh profile whose width is set by ε. At ε = 1.3 cells, ψ goes from −0.8 to +0.8 across about four cells (Figure 1b).

−1 liquid +1 wax 0 spinodal |ψ| < 0.577 ψ, the cell's mix free energy f(ψ) +1 −1 -6-3036 2.4 cells distance across the surface, cells
Figure 1b. Left: the energy per cell, with its two minima at pure liquid and pure wax. The shaded band is the spinodal region, |ψ| < 1/√3 ≈ 0.577, where the curve bends downward (section 2). Right: ψ across a surface at rest, tanh(x / (√2 ε)) with ε = 1.3 cells. The surface passes through the band in 2.4 cells.
02Orchid wax
  • Physics
  • Design

Inside the spinodal, mixing undoes itself.

We named the app after spinodal decomposition before we had checked that the lamp does it. Where the energy curve bends downward, between ψ = −0.577 and +0.577, a mix is unstable: any small ripple in it lowers the energy by growing, so wax runs toward the places that already have more wax. Diffusion runs backwards. That is spinodal decomposition (Cahn 1961).

Which ripples grow, and how fast, decides the size of the pattern that forms. Linearising the equation around a mix ψ₀ gives the growth rate of a ripple with wavenumber k:

ω(k) = −M k² ( f″(ψ₀) + ε²k² )

Inside the band f″ = 3ψ₀² − 1 is negative, so long ripples grow and short ones, held back by the ε² term, decay. One wavelength grows fastest, λ = 2π√2 ε / √(−f″). For the mix a tap makes, ψ₀ = −0.05, that is 11.6 cells. Outside the band a mix is metastable: small ripples die out, and separating needs a nucleus to start from. That difference comes back in section 7.

To test the name we tap the glass, and the tap does more than stir. It is a design choice: for 0.4 seconds it pulls the wax in a ball 12 cells in radius toward a smooth random pattern, with features 5 to 10 cells across, close to the wavelength that grows fastest, and a mean of ψ = −0.05, inside the band. So the labyrinth in the first frames below is drawn by the tap. Grown from small noise, the fastest ripple would take about 5 lamp seconds to grow by a factor of e, too slow for a lamp that should answer a finger. What happens after the tap lets go is the equation's own.

Half a second after the tap, 57 % of the cells within its radius sit inside the band. The equation then separates them (Figures 2a and 2b): a cloud of mixed wax at +1 s, beads and drops by +3.5 s, and by +10 s only 16 % of the tap's cells are left in the band, about what the surfaces of the blobs passing through it account for.

−0.5 s
The lamp after a tap at −0.5 sMid-plane cross-section at −0.5 s
—
+0.5 s
The lamp after a tap at +0.5 sMid-plane cross-section at +0.5 s
57 % in band
+1 s
The lamp after a tap at +1 sMid-plane cross-section at +1 s
49 % in band
+2 s
The lamp after a tap at +2 sMid-plane cross-section at +2 s
43 % in band
+3.5 s
The lamp after a tap at +3.5 sMid-plane cross-section at +3.5 s
41 % in band
+6 s
The lamp after a tap at +6 sMid-plane cross-section at +6 s
29 % in band
+10 s
The lamp after a tap at +10 sMid-plane cross-section at +10 s
16 % in band
+21 s
The lamp after a tap at +21 sMid-plane cross-section at +21 s
17 % in band
Figure 2a. A tap mid-glass on a running lamp, at 20 lamp seconds. Top: the lamp. Below: the vertical cross-section through the lamp's axis, with liquid dark, wax in Orchid's pink, and cells inside the spinodal band cyan, strongest at ψ = 0. A surface shows as a thin cyan rim; mixed wax shows as a broad cyan wash. Under each frame: the share of cells within the tap's 12-cell radius that are inside the band.
+0.5 s
Close-up of the tap's cross-section at +0.5 s
57 % in band
+1 s
Close-up of the tap's cross-section at +1 s
49 % in band
+2 s
Close-up of the tap's cross-section at +2 s
43 % in band
+3.5 s
Close-up of the tap's cross-section at +3.5 s
41 % in band
+6 s
Close-up of the tap's cross-section at +6 s
29 % in band
+10 s
Close-up of the tap's cross-section at +10 s
16 % in band
Figure 2b. The same cross-section, 28 cells square around the tap, at 12 pixels a cell.
tap 0 % 20 % 40 % 60 % -2 0 4 8 12 16 20 24 seconds after the tap share of the tap’s cells in the band haze
Figure 2c. Inside the tap's radius, every half lamp-second: the share of cells inside the spinodal band (cyan), and the haze the tap sheds into the liquid (amber, section 3), as a share of fully clouded. After about +12 s the band share rises again as blobs drifting through the tap's region bring their surfaces with them.
03Glacier wax
  • Physics
  • Design

A shake breaks the wax. The cloud keeps time.

The shake was the picture behind the name: shake the lamp and it clouds, then separates. So we measured one. A full shake rocks the chamber with two rolling flows, one in each vertical plane, plus a lattice of small random pushes redrawn every substep. Both rolls are divergence-free, so they move the liquid without compressing it, which matters in sections 7 and 8. Held for two seconds, a shake breaks the wax apart: the separate pieces off the pool go from 18 to 75 in 3.5 s, and 80 s after the shake began there are 13 (Figure 3a).

It barely mixes it. Across the whole lamp, the share of cells inside the spinodal band goes from 7.2 % before the shake to a peak of 10.3 %, 2 s in. A shake makes an emulsion, wax broken into pieces that stay wax, and the separation that follows is mostly pieces finding each other again. One reviewer on the naming jury asked whether the name was earned. These two measurements answer it. The tap is spinodal decomposition, and the shake mostly isn't.

The milkiness has a different source, and it is designed. Haze is a second field, shed wherever wax meets liquid in proportion to the square of the shake's strength, carried by the flow, and fading by 1/12,500 of itself each substep. Real wax doesn't cloud like this. We gave the lamp a memory and chose its length, a time constant of 52 lamp seconds, so that a glance tells you how busy the room has been over the last minute or so. In short, each shake adds haze, and all of it fades by the same fraction every second:

H(t) ≈ Σi k Li² e−(t − ti)/τ,   τ = 52 s

In Figure 3, haze peaks at 33 % of the lamp 4 s after the shake began, is down to half of that 34 s later, and is 7.0 % at 80 s.

−0.5 s
The lamp after a full shake at −0.5 sMid-plane cross-section at −0.5 s
haze 0.0 %
+1 s
The lamp after a full shake at +1 sMid-plane cross-section at +1 s
haze 12.7 %
+2.5 s
The lamp after a full shake at +2.5 sMid-plane cross-section at +2.5 s
haze 30.1 %
+5 s
The lamp after a full shake at +5 sMid-plane cross-section at +5 s
haze 32.3 %
+10 s
The lamp after a full shake at +10 sMid-plane cross-section at +10 s
haze 29.1 %
+20 s
The lamp after a full shake at +20 sMid-plane cross-section at +20 s
haze 23.5 %
+40 s
The lamp after a full shake at +40 sMid-plane cross-section at +40 s
haze 15.6 %
+80 s
The lamp after a full shake at +80 sMid-plane cross-section at +80 s
haze 7.0 %
Figure 3a. A full shake from 15 lamp seconds, held for 2 s and then left to fade with the shake's own time constant of 1.4 s. Top: the lamp, where the haze shows as milk in the liquid. Below: the cross-section, with liquid dark, wax in Glacier's white, and the spinodal band cyan. Under each frame: the lamp's mean haze.
held 0 % 10 % 20 % 30 % 40 % 50 % 0 10 20 30 40 50 60 70 80 seconds after the shake began share of the lamp ψ in the band haze, lamp mean
Figure 3b. The same run, every half lamp-second: the lamp's mean haze (amber), and the share of the lamp's cells inside the spinodal band (cyan). The shaded strip is the 2 s the shake is held.
04Amethyst wax
  • Physics
  • Design

Heat belongs to the wax.

The first heat model had one temperature field for wax and liquid together, carried on the shared velocity. A rising blob's warm skin was stripped off by the liquid flowing around it, and blobs turned back at half height however the heat exchange was set.

Now the wax carries its heat as enthalpy, e = c T, where c = (ψ + 1)/2 is the cell's wax fraction. Enthalpy moves with exactly the same limited face fluxes as the wax, so heat leaves a blob only through the terms written for it: conduction between wax cells, slow exchange with the liquid in transit, and fast exchange under the cap. In the build these figures come from, a blob in transit loses its excess heat with a time constant of about 139 lamp seconds, and under the cap in about 0.5 seconds. The fast cooling under the cap is a design choice: it turns blobs back at the top of the glass rather than part way up (section 11). The liquid is simplified by design too: it holds a fixed temperature profile, warmer at the bottom, and has no buoyancy of its own.

Figure 4 is a cold start: the pool lies solid on the floor, the bulb comes up with an 18 s time constant, and the coil heats only the floor's bottom layer. The first piece of wax leaves at 12.5 s, a single plume from the middle of the pool whose head pinches off; 24 s in, 9 pieces are in flight. A rising blob stays hot (white) to above half height and has cooled (violet) by the time it reaches the top.

1 s
The lamp starting cold at 1 sMid-plane cross-section at 1 s
0 in flight
5 s
The lamp starting cold at 5 sMid-plane cross-section at 5 s
0 in flight
9 s
The lamp starting cold at 9 sMid-plane cross-section at 9 s
0 in flight
11 s
The lamp starting cold at 11 sMid-plane cross-section at 11 s
0 in flight
12.5 s
The lamp starting cold at 12.5 sMid-plane cross-section at 12.5 s
1 in flight
14 s
The lamp starting cold at 14 sMid-plane cross-section at 14 s
1 in flight
17 s
The lamp starting cold at 17 sMid-plane cross-section at 17 s
2 in flight
24 s
The lamp starting cold at 24 sMid-plane cross-section at 24 s
9 in flight
Figure 4. A cold start. Top: the lamp. Below: the cross-section through the axis, here coloured by the wax's temperature, from cold (violet) through the neutral temperature (red, 0.6) to the coil's ceiling (white, 1.6); the liquid is dark. Under each frame: separate pieces of wax off the pool.
05Aurora wax
  • Physics
  • Design

A lamp is a relaxation oscillator.

At first, blobs hovered. In the lamp's units, cold wax is denser than the liquid by 0.06 and loses 0.10 of density per unit of temperature, so wax and liquid weigh the same at a temperature of 0.6. The liquid sits at 0.2 to 0.3, so wax at the liquid's temperature always sinks. Every version that heated the wax smoothly with depth gave slow wax a height to hover at: the place where it had warmed to neutral.

The cycle needed a threshold. Heat enters only a thin layer at the floor, and floor wax holds to the coil until it reaches 1.1, well past neutral. That grip is a design rule, and it gives the pool a definite point to charge to, where smooth heating gave none. The pool's bottom charges slowly under a cold, heavy lid. When it lets go, a light layer under a heavy one breaks out as a plume (Taylor 1950). The plume crosses the liquid almost without losing heat, cools under the cap, sinks, and lands in the pool to be heated again.

Slow charge, a threshold, a fast discharge and a reset: it has the same shape as a dripping tap or an integrate-and-fire neuron. From cold, the first discharge comes at 12.5 s (Figure 4). In a running lamp about ten of these cycles run at once, out of phase, so the highest wax only moves between 0.50 and 1.00 of the glass over two lamp minutes and never shows one cycle. Figure 5a follows two blobs instead. A is rising out of the pool at 1.11 when the readings start, 0.32 of the way up, and reaches 0.97 of the glass 13 s later, cooling past neutral on the way at 12 s. It sits under the cap until it has cooled to 0.22, starts down at 29 s, and at 44 s merges with another blob at 0.77 of the height, where the tracker loses it: after a merge, nothing says which wax was whose. B, followed from 20 s, sinks from 0.75 into the pool in 26 s, at 0.33. Across every reading, 75 % of the wax above the pool is cooler than neutral, on its way back down.

0.000.250.500.751.00 height, floor 0 to cap 1 A rises at 1.11A mergesBB lands 0.61.1 neutral lets go AB temperature 020406080100120 lamp seconds, left alone coldneutral 0.6lets go 1.11.6 wax temperature
Figure 5a. A running lamp left alone for two lamp minutes, artist off. Top: every piece of wax of 30 cells or more, once a lamp second, at its height (floor 0, cap 1), sized by its volume and coloured by its mean temperature; the pool sits along the bottom. Two blobs are followed, each by taking the nearest piece in the next reading: A (solid) from the pool to the cap, until it merges on the way down, and B (dashed) from under the cap into the pool. Bottom: their temperatures on the same clock. No single piece could be followed for a whole cycle in this run, because blobs merge and split under the cap.
10 s
The lamp running on its own at 10 sMid-plane cross-section at 10 s
top 0.96
25 s
The lamp running on its own at 25 sMid-plane cross-section at 25 s
top 1.00
40 s
The lamp running on its own at 40 sMid-plane cross-section at 40 s
top 1.00
55 s
The lamp running on its own at 55 sMid-plane cross-section at 55 s
top 0.72
70 s
The lamp running on its own at 70 sMid-plane cross-section at 70 s
top 0.57
85 s
The lamp running on its own at 85 sMid-plane cross-section at 85 s
top 0.60
100 s
The lamp running on its own at 100 sMid-plane cross-section at 100 s
top 0.74
120 s
The lamp running on its own at 120 sMid-plane cross-section at 120 s
top 0.87
Figure 5b. The same run every 15 lamp seconds, with the cross-section coloured by the wax's temperature as in Figure 4. Under each frame: the highest wax.
06Lagoon wax
  • Physics
  • Design

Every contact was a merge.

Cahn-Hilliard joins two blobs as soon as their surfaces overlap, and at this grid a surface is about three cells thick. Every touch became a merge, and the lamp coarsened into one lump holding 97 % of its wax. Real drops squash and bounce first: the liquid between them has to drain before they join.

The first attempt lowered the surface force, so blobs would stretch further before touching. It gave 1.5 to 1.7 times as many blobs at first, and the lamp still ended as one lump: every contact was still a merge. A grid this coarse can't resolve a film of liquid draining from between two drops, so a rule stands in for it. A liquid cell with wax within three cells on both sides of it, along any axis, is a film between two bodies. Its chemical potential is raised, so the equation drains wax out of it and the surface force pushes the two surfaces apart. After 2 lamp seconds the film gives way and the blobs merge. That 2 seconds is a timer we chose, not a computed drainage time. Without the timer, a strong film left grapes of blobs pressed against the glass. The rule is off in the pool, so falling wax still lands and rejoins it.

At two lamp minutes, the lamp with the film has 17 pieces in flight and its largest piece holds 21 % of the wax. Without it there are no pieces in flight and the largest holds 99 %. At one minute it was 11 pieces and 31 % with the film, against 3 and 95 % without. The film doesn't prevent every merge: at 90 s the lamp with it was down to 4 pieces, the largest holding 87 %, before it broke up again.

30 s
On
The lamp with the film rule on at 30 s
16 in flight
largest 14 %
Off
The lamp with the film rule off at 30 s
3 in flight
largest 87 %
60 s
On
The lamp with the film rule on at 60 s
11 in flight
largest 31 %
Off
The lamp with the film rule off at 60 s
3 in flight
largest 95 %
90 s
On
The lamp with the film rule on at 90 s
4 in flight
largest 87 %
Off
The lamp with the film rule off at 90 s
3 in flight
largest 93 %
120 s
On
The lamp with the film rule on at 120 s
17 in flight
largest 21 %
Off
The lamp with the film rule off at 120 s
0 in flight
largest 99 %
Figure 6. Two runs from the same warm start, artist off, with the film rule on (the default) and off (?phys=film:0), paired at the same lamp second and cropped to the glass. Under each frame: separate pieces of wax off the pool, and the largest piece's share of all the wax.

Threads have the opposite problem. A column of liquid is unstable to ripples longer than its circumference and pinches into drops (Rayleigh 1878), which is why a thin stream from a tap breaks into beads. A neck a few cells wide is too coarse for the grid to resolve that, so columns stayed joined to the pool for up to 14 seconds. The thread rule, also design, finds wax that is thin across two axes and continues along the third, and raises its chemical potential so the wax drains toward the thicker ends. A sphere is thin across its poles but doesn't continue past them, and a small blob is thin in all three directions, so neither counts. The rule is off while the nanites hold a model: a torus's tube is a thread too.

07Ember wax
  • Physics
  • Design

Conserve the wax, or the lamp lies.

Blobs got smaller on every trip, and the total of ψ said nothing was missing. The amount of wax is the one thing a viewer can check over time, so this mattered. The transport is written in flux form: each face between two cells computes one flux, which leaves one cell and enters the other, so with walls closed to wax the total is exact to rounding. A limiter (van Leer 1974) keeps surfaces sharp without overshooting, and the speed cap keeps |u| + |v| + |w| under one cell per substep, the stability condition for this kind of step (Courant, Friedrichs & Lewy 1928).

The wax was leaving the blobs without leaving the total. Advection smears a moving blob into its wake, and the smear sits at ψ ≈ −0.9, outside the spinodal band. Section 2 explains what that means: dilute wax is metastable and never separates again. At this grid a small blob is also in equilibrium with slightly richer liquid than a big one, which is Ostwald ripening, the slow diffusion of material from small drops to large ones (Lifshitz & Slyozov 1961). Blobs dissolved into invisible fog at 2.5 % a second.

The first fix made it worse. A collector deleted the fog, and a correction added the lost total back to every wax cell. Blobs lost wax in proportion to their surface and got it back in proportion to their volume, so the biggest blob grew at the others' expense. The lamp had built a second coarsening engine on top of the physical one. The fix that held sends fog back toward wax: each dilute cell hands part of its excess to its richest neighbour, so the fog climbs back up the gradient it smeared down. A smear trails the blob that left it, so the nearest richer wax is usually that blob, but the rule doesn't know which blob a cell came from, and we haven't measured how often it gets home. The correction still covers what fog return can't.

60 s
Return on
Fog cross-section, fog return return on, at 60 s
Return off
Fog cross-section, fog return return off, at 60 s
120 s
Return on
Fog cross-section, fog return return on, at 120 s
Return off
Fog cross-section, fog return return off, at 120 s
Figure 7a. The fog made visible: the vertical plane through the lamp's axis, with wax dim and any liquid that holds wax at all, from 0.4 % to 30 % on a log scale, in white. In each pair, fog return on (the default) and the old collector (?fogreturn=0), which deletes dilute wax and leaves the mass correction to put it back, from the same warm start. The glow hugging each blob is its own surface, a few cells wide; fog is the haze away from any blob.
0 6.3k 12.5k 18.8k 25k 0 20 40 60 80 100 120 lamp seconds wax put back, cells return off return on
Figure 7b. Wax the mass correction has put back since the start, in the same two runs.

On today's lamp, over two lamp minutes, the mass correction put back 5,817 cells of wax with fog return, against 23,314 with the collector, 4 times as much. At two minutes the largest piece held 21 % of the wax with fog return and 31 % without. On the build where fog return was found, at film 4, the difference was tenfold: about 41,000 cells against 4,200 (docs/REALISM_AUDIT.md).

So the lamp keeps count by design rather than by the equation alone. Three things change the total of ψ: the tap's relaxation (section 2), fog that fades where it has nowhere uphill to go, and the clamp at ±1.5. The mass correction puts back what they take, once every 120 substeps.

08Orchid wax
  • Physics

Pressure is the slow part, and fixing it moved the film.

An incompressible liquid needs a pressure solve every step: forces push the velocity, and pressure removes whatever part of the push would compress the liquid (Chorin 1968). The lamp first did this with 30 Jacobi sweeps, each averaging every cell with its neighbours. A sweep removes only about 2π²/3L² of an error with a wavelength of L cells, so 30 sweeps leave about 14 % of a 10-cell error, the size of a blob, and 60 % of a 20-cell one, for the next step to inherit.

A multigrid V-cycle (Brandt 1977) solves each wavelength on a grid where it is short: 60 × 132 × 60, then 30 × 66 × 30, 15 × 33 × 15 and 8 × 17 × 8. It cuts the remaining error to about 0.3 per cycle at any size, for about the cost of six sweeps. The wax also moves on the velocities at cell faces, as in a staggered grid (Harlow & Welch 1965). Averaging two cells' corrected velocities onto a face had left divergence the solve never saw, the term Rhie & Chow (1983) corrected for.

Divergence the wax sees, cells per substep (RMS)CalmShake held
30 Jacobi sweeps, face values averaged from cells1.6 × 10⁻⁴1.6 × 10⁻³
One multigrid V-cycle, face velocities4.5 × 10⁻⁵4.9 × 10⁻⁴

The better solve cost the lamp blobs. In the second minute it held about 1.4 fewer, with no overlap between three runs of each, and raising the film from 3 to 4 brought them back: 9.7 to 11.4 blobs, against Jacobi's 8.1 to 9.2. That fix didn't last. When fog return arrived (section 7), film 4 made a snow globe, up to 24 small blobs at once, and the film went back to 3.

Our explanation for the first effect is not yet tested. The film's push reaches the flow through −σψ∇μ, a force that is mostly a gradient, and a converged projection removes gradients, so the better solve may simply remove more of the push. Two measurements would settle it: how much of the film's force survives the projection under each solve, and whether a film written as a force with no gradient part keeps its blobs under both. On the build these figures come from, with fog return on, one run of each from the same warm start: the second minute averaged 11.6 blobs under Jacobi at film 3, 9.7 under multigrid at film 3, and 19.4 under multigrid at film 4 (Figure 8). The better solve still costs about 1.9 blobs on today's lamp, and film 4 still overshoots; one run each can show the direction, not settle the mechanism.

second minute 0 10 20 30 40 0 20 40 60 80 100 120 lamp seconds blobs multigrid, film 4 Jacobi, film 3 multigrid, film 3
Figure 8. Blobs in the lamp, smoothed over 2.5 lamp seconds, under the old pressure setup (30 Jacobi sweeps every substep, face values averaged from cells: ?solver=jacobi&mac=0&pstep=1) and today's multigrid at film 3 (the default) and film 4 (?phys=film:4). One run of each from the same warm start, so the lines are single samples, not averages; the shaded half is the second minute.

The rule that survives is narrower than "retune the film": a force that is mostly a gradient depends on the pressure solve, and its setting has to be checked again whenever the solve, or anything that feeds the blob count, changes.

09Glacier wax
  • Design

Sound shakes the lamp. Music plays it.

The room reaches the lamp through the shake. Each sensor reduces its input to one number per tick and discards the raw audio or image in the same tick. The number is compared with a floor that falls quickly to a quieter room and rises slowly to a louder one, so silence is the reference and a steady hum stops counting. What rises above the floor is an impulse; impulses add into the shake level, which saturates at 1 and fades with a 1.4 s time constant, and the shake drives the rolls, the pushes and the haze of section 3.

-60-40-20 dBFS doorsteady soundfour clapsa clap after quiet floor 0.35 0 shake 0102030405060 seconds
Figure 9. A scripted minute of room sound, fed through the app's own microphone code (MicLevels in activity.ts, 20 readings a second) and into the lamp's shake, which fades with a 1.4 s time constant. Top: the level (thin) and the floor the app learns from it (thick), in dBFS. Bottom: the shake. The door and the clap after quiet each land in full, at the microphone's cap of 0.35. The steady sound counts only as it starts, until the floor folds it in. The four claps over it land smaller, because they stand less far above the floor and each recent shake divides the next (habituation). The levels are scripted (scripts/essay/sound.mjs); everything after them is the shipped code.

Music should not dissolve the wax, so the v1 build listens twice. A gate first asks whether the sound is music at all, from how consistently its energy gathers on the twelve pitch classes. Room noise keeps shaking the lamp. Music instead plays the nanites, the steering units Spinodal already has: jets pulse on the beat, a build gathers the wax, the downbeat after a build forms it into a shape and holds it for eight bars, and bass attacks rock the glass. This is choreography, not physics, and it is allowed to break the physics, because the nanites aren't wax.

The listening is shared across the family. Spinodal carries a copy of Protoplasm's music stack, which is itself a port of Psychodeli+'s: onsets, a tempo found by harmonic voting, a beat grid with downbeats, and the gate. Synesthetic Audio Reactivity explains that listening; what is different here is the material it acts on.

10Amethyst wax
  • Design
  • Rendering

The camera looks for crossings.

The first camera twitched. It re-aimed twice a second and chased each new aim at a fixed speed, so the view jumped and stopped. A turning lamp shows its depth through motion alone: near blobs slide across the view faster than far ones (Rogers & Graham 1979), and a turning shape is seen as solid from its motion (Wallach & O'Connell 1953). A crossing, one blob passing in front of another, adds occlusion, which settles which one is nearer (Kaplan 1969). Depth doesn't need crossings, but they are the moments worth turning for, so the camera composes its moves around them.

The fix was to plan moves instead of aiming. The camera plays candidate sweeps of 20° to 109° forward against where the blobs are heading, scores each for one blob passing in front of another, and runs the best one from rest to rest on a minimum-jerk path (Flash & Hogan 1985), the smooth profile people's own reaching movements follow. Then it holds still for 5 seconds.

30 s into a warm lamp, the director's best move from the blobs it saw was a 109° sweep over 12.7 s, during which it predicted 16 pairs would pass one in front of the other. The pair it scored highest, ringed in Figure 10a, overlaps about 2.8 s in. Filmed about every two lamp seconds, the view turns 3° in the first step, 37° in the largest, and 4° in the last, at up to 16° a second.

+0 s
The lamp at 20 degrees, 0 s into the move
20° · 0°/s
+2 s
The lamp at 17 degrees, 2 s into the move
17° · 5°/s
+4 s
The lamp at 0 degrees, 4 s into the move
0° · 12°/s
+6.5 s
The lamp at -37 degrees, 6.5 s into the move
-37° · 16°/s
+8.5 s
The lamp at -66 degrees, 8.5 s into the move
-66° · 13°/s
+10.5 s
The lamp at -84 degrees, 10.5 s into the move
-84° · 5°/s
+12.5 s
The lamp at -89 degrees, 12.5 s into the move
-89° · 0°/s
Figure 10a. One move by the app's camera director (artist/camera.ts), planned from the blobs at that moment and filmed about every two lamp seconds while the lamp runs on. The rings mark the pair the move was planned around, 1 solid and 2 dashed. The easing shows in the spacing: small turns at the ends, the largest in the middle. Under each frame: the view's angle and how fast it is turning.
12 start end
Figure 10b. The same move from above, at its start: the chamber, its blobs sized by volume, the ringed pair, and the arc the view travels.
Over 90 secondsAiming twice a secondPlanned sweeps
Worst turning acceleration10.9 rad/s²0.7 rad/s²
Reversals11.3 a minute0.7 a minute
Crossings per radian turned2.94.3
Time spent turning97 %58 %
11Aurora wax

What we got wrong, and what is next.

  • One lumpFor most of the first day, a viewer saw one blob: every contact merged. The film rule took the second minute from one visible blob to about ten.
  • The engine we builtThe fog collector and the mass correction together moved wax from small blobs to big ones. Fog return cut the corrected wax by four to ten times, depending on the build (section 7).
  • Wall-clock timeThe bulb warmed on wall-clock time, so whenever frames dropped it warmed faster than the wax could. Everything that times the lamp now counts substeps.
  • The nameWe named the app after spinodal decomposition before we had measured it. The tap's figures in section 2 are that measurement. The shake, which was the original picture, is mostly an emulsion.
  • The capWax turned back where the cap's cooling began, at 0.85 of the height, not at the cap. The build these figures come from starts the cooling at 0.93 and cools twice as fast, so blobs reach the cap.
  • NextLate columns of 5 to 9 seconds when the pool holds 35 to 45 % of the wax. The 2D slice's heat model, which still carries one temperature. Droplets for wax smaller than the grid, which work and conserve wax but add only about one visible blob. A long run on a phone, for heat. A second cue beside the gate for music it misreads. The two measurements that would say why the better pressure solve weakened the film (section 8).
0.00 0.25 0.50 0.75 1.00 0 20 40 60 80 100 120 lamp seconds highest wax from 0.93 cooling from 0.85
Figure 11. The highest wax in the lamp, as a share of its height (floor 0, cap 1), over two lamp minutes, with the cap's cooling as it was (from 0.85 of the height: ?phys=capStart:0.85,capRelax:0.004) and as it is (from 0.93, twice as fast). One run of each from the same warm start, on today's lamp.

On today's lamp the old cap still holds wax down. Over two lamp minutes, with the cooling from 0.85, the highest wax reached 0.94 of the height and spent 13 % of the time above 0.9; with the cooling from 0.93 it reached 1.00 and spent 32 % of the time above 0.9 (Figure 11). Neither keeps wax at the top all the time: when the blobs happen to fall together, today's lamp had nothing above 0.50 at 81 s.

When it works, none of this shows. A shaken lamp clouds, and twenty seconds later it is a lamp again, with the room's last minute still faintly in the liquid.

Shake the lamp →

It needs WebGPU: Safari 26 or a recent Chrome. Tap the glass to dissolve the wax there; drag to shake the lamp.

Sources

  1. Brandt, A. (1977). Multi-level adaptive solutions to boundary-value problems. Mathematics of Computation, 31(138), 333–390. doi:10.1090/S0025-5718-1977-0431719-X
  2. Cahn, J. W. (1961). On spinodal decomposition. Acta Metallurgica, 9(9), 795–801. doi:10.1016/0001-6160(61)90182-1
  3. Cahn, J. W., & Hilliard, J. E. (1958). Free energy of a nonuniform system. I. Interfacial free energy. The Journal of Chemical Physics, 28(2), 258–267. doi:10.1063/1.1744102
  4. Chorin, A. J. (1968). Numerical solution of the Navier-Stokes equations. Mathematics of Computation, 22(104), 745–762. doi:10.1090/S0025-5718-1968-0242392-2
  5. Courant, R., Friedrichs, K., & Lewy, H. (1928). Über die partiellen Differenzengleichungen der mathematischen Physik. Mathematische Annalen, 100, 32–74. doi:10.1007/BF01448839
  6. Flash, T., & Hogan, N. (1985). The coordination of arm movements: an experimentally confirmed mathematical model. The Journal of Neuroscience, 5(7), 1688–1703. doi:10.1523/JNEUROSCI.05-07-01688.1985
  7. Harlow, F. H., & Welch, J. E. (1965). Numerical calculation of time-dependent viscous incompressible flow of fluid with free surface. The Physics of Fluids, 8(12), 2182–2189. doi:10.1063/1.1761178
  8. Jacqmin, D. (1999). Calculation of two-phase Navier–Stokes flows using phase-field modeling. Journal of Computational Physics, 155(1), 96–127. doi:10.1006/jcph.1999.6332
  9. Kaplan, G. A. (1969). Kinetic disruption of optical texture: the perception of depth at an edge. Perception & Psychophysics, 6(4), 193–198. doi:10.3758/BF03207015
  10. Lifshitz, I. M., & Slyozov, V. V. (1961). The kinetics of precipitation from supersaturated solid solutions. Journal of Physics and Chemistry of Solids, 19(1–2), 35–50. doi:10.1016/0022-3697(61)90054-3
  11. Rayleigh, Lord (1878). On the instability of jets. Proceedings of the London Mathematical Society, s1-10(1), 4–13. doi:10.1112/plms/s1-10.1.4
  12. Rhie, C. M., & Chow, W. L. (1983). Numerical study of the turbulent flow past an airfoil with trailing edge separation. AIAA Journal, 21(11), 1525–1532. doi:10.2514/3.8284
  13. Rogers, B., & Graham, M. (1979). Motion parallax as an independent cue for depth perception. Perception, 8(2), 125–134. doi:10.1068/p080125
  14. Stam, J. (1999). Stable fluids. Proceedings of SIGGRAPH '99, 121–128. doi:10.1145/311535.311548
  15. Taylor, G. I. (1950). The instability of liquid surfaces when accelerated in a direction perpendicular to their planes. I. Proceedings of the Royal Society of London A, 201(1065), 192–196. doi:10.1098/rspa.1950.0052
  16. van Leer, B. (1974). Towards the ultimate conservative difference scheme. II. Monotonicity and conservation combined in a second-order scheme. Journal of Computational Physics, 14(4), 361–370. doi:10.1016/0021-9991(74)90019-9
  17. Wallach, H., & O'Connell, D. N. (1953). The kinetic depth effect. Journal of Experimental Psychology, 45(4), 205–217. doi:10.1037/h0056880

Figures and the measured numbers in the text: built from feat/v1-ui at a80d60e on 2026-11-06, by scripts/essay/filmstrips.mjs, written into this page by scripts/essay/fragments.mjs. Lamp time is substeps ÷ 240. Numbers quoted from earlier probes cite the docs they come from: docs/SOLVER_3D.md, docs/REALISM_AUDIT.md and the README.