---
title: "Runny, sticky and oily"
description: "How ketchup stands, honey runs, oil floats and soap sends colours flying on milk in Professor Oops, from one table of material numbers and a few shared rules."
source_name: "Game Tailors"
source_url: "https://professoroops.com/en/inside/liquids/"
site_home: "https://professoroops.com/"
source_description: "The drawing app where the paper is real. No ads. No accounts. No personal data: only anonymous counts, which you can switch off."
locale: "en"
legal:
  - "Game Tailors · Schieweg 15Y-40, 2627 AN Delft (NL)"
  - "KvK 92437702 · VAT NL866044474B01"
  - "info@gametailors.com · +31 6 4227 5919"
copyright: "© 2026 Game Tailors"
published_at: "2026-11-10T12:04:08.648Z"
modified_at: "2026-11-10T12:04:08.648Z"
---

# Runny, sticky and oily

## Ketchup stands, honey runs and oil floats, with no code for any one liquid

Squeeze ketchup and it keeps its bead. Pour honey and it creeps out flat. Oil floats on water, beaten into egg yolk it turns into mayonnaise, and soap on milk sends the colours flying. Nobody wrote a special effect for any of these. Each spot of the page stores what lies there, and every liquid follows the same few rules with its own numbers.

[For engineers](<#hood-engineers>)

![Painted illustration of the painter shaking a jar, beside a jar of golden oil floating on blue water, a jar of creamy mayonnaise, an egg yolk and mustard](<https://professoroops.com/_assets/entity_GoWMQgBhpNIaT3dJh7Dy.webp>)

## How runny a sauce is and how steep a slope it can hold decide whether it stands or spreads

Everything thick on the page, from paint to mud, is stored as a depth in each tiny square, about half a millimetre across. Many times a second, each square compares its height with its four neighbours and passes some of itself downhill. How much it passes comes from two numbers in the material's row of one shared table: how runny it is, and how steep a slope it can hold before it gives way. That second number is its yield.

Ketchup has a high yield. A step of nearly a whole square's height between neighbours stays put, so ketchup keeps a bead about 42° steep. Mustard holds 45°, mud 39°, tube paint 37°. Honey has no yield at all. It is only slow, and it keeps creeping until it is too thin to flow.

Testing a slope square by square has a catch. Each square looked at its four sides separately, so along a diagonal a slope could be √2 steeper before anything moved, and heaps came to rest as diamonds. next update Pastes now test how steep the whole slope is, whichever way it falls, and heaps come to rest round.

Thin liquids get one more change. next update Milk, ink, juice and drinks keep their way as they run, through four pipes per square that remember what went each way, slowed by the liquid's real viscosity. A hand dragged through milk leaves a track that is half full again in under half a second. In the released game that takes 1.7 s, and milk closes up more like syrup.

Ketchup stands, honey runs and oil floats, with no code for any one liquid

For engineers

### Ketchup stands, honey runs and oil floats, with no code for any one liquid

Each cell \(about 0.5 mm; 512 × 384 on a full sheet, 288 × 216 on a phone\) stacks a water film, a goop layer and a floating layer. Goop moves by explicit height diffusion with a yield dead zone, at 60 Hz, every constant read from one shared material table. Layering follows from a few properties each material has and a density comparison. The code that moves liquids contains no material id at all.

[Under the hood](<#hood-yield>)

How runny a sauce is and how steep a slope it can hold

Under the hood

### How runny a sauce is and how steep a slope it can hold

Each cell keeps a depth, a colour stored as absorbance times height \(so goops mix like paint and nothing is made or lost\), how much of it has set, and one material. The surface each cell compares includes the paper's own dents and cockle, so the paper's bumps steer every run.

The released rule is a height diffusion with a dead zone: past the material's yield, flow grows with the excess slope, scaled by its runniness, and below a thin film nothing flows. A stability cap keeps the explicit step from overshooting. Mobility falls as a goop sets and its yield rises, so a drying sauce stiffens by the same rule.

next update Pastes test the slope's magnitude instead of each side alone. Straight down one side this is the old rule, and a cheap early exit keeps cells at rest nearly free. A test holds heaps of melted ice cream, egg white and slime round to within a few per cent, where a diamond would be √2 out. Fats on the paper and the floating layer still test per side.

next update Thin liquids run in virtual pipes with water's real g and a viscous hold that follows Poiseuille flow in a thin film. The push is capped for stability, and for a clean liquid the cap wins, so g doesn't set the speed: a real wave on 3 mm of water runs at about 17 cm/s, the game's much slower. Viscosity does slow them. Pipes as a technique are consistent with <sup>[O'Brien 1995](<https://professoroops.com/en/inside/research-simulation/#obrien-1995>)</sup>; the yield idea was informed by <sup>[Liu 1989](<https://professoroops.com/en/inside/research-simulation/#liu-1989>)</sup>, a Bingham-like paste in a height field.

Try it: drop heaps of sauce The game's own ruleKetchup on the left, honey on the right, run by the game's flow rule with their own table numbers. Pick a sauce and tap the paper to drop a heap, or press Drop a heap. **What to look for:** ketchup stops almost at once, honey never quite does. Then pick melted ice cream, drop it, and switch the yield test: per side it settles toward a diamond, by slope it comes out round. The roundness readout is the test's own measure \(1 is round, 1.41 a diamond\).

![Heaps of ketchup and honey on paper, settling by the game flow rule](<https://professoroops.com/_assets/entity_Ia5Cd04GYPB8m3Z3mTcM.png>)

Tap to dropketchupmustardtube paintegg yolkegg whitemelted ice creamhoneyYield testeach side \(released\)whole slope \(next update\)

Time-lapse×4

yield of the sauce you drop—

as a slope—

last heap roundness—

simulated—

![A ketchup zigzag still standing in a raised bead beside a honey puddle that has spread flat](<https://professoroops.com/_assets/entity_NfpEHj4tIkOksOsU2vrh.webp>)

**In the game.** The same two rows of the table on a real page: the ketchup zigzag still stands, the honey has spread flat.

How fast each thing spreads in the game \(log scale\)The whole range is narrow, and honey is only a few times slower than oil. In a kitchen honey is thousands of times thicker than water. On the next update, thin liquids also carry momentum, so this rate is only their ooze.

Drink spreads at 13.8 cells² a second, milk 12, oil 10.8, ketchup 6, mud 4.2, paint 3.6, honey 1.5 and dough 0.72.

Data table

How fast each thing spreads in the game \(log scale\)

|  | spreading rate |
| --- | --- |
| drink | 13.8 |
| milk | 12 |
| oil | 10.8 |
| ketchup | 6 |
| mud | 4.2 |
| paint | 3.6 |
| honey | 1.5 |
| dough | 0.72 |

Source: Runniness from the game's own material table \(paint is tube paint\), as a spreading rate.

## Oil floats because it's light and shuns water, and the code never names oil

Each square can hold three things stacked: a film of water, a layer of goop, and a floating layer on top. Whenever something lands, one function decides where it goes by asking its row three questions. Does it shun water? Is it lighter than water and runny? Is it soft goop at all, and not grains or a lump?

Two soft things stay apart when one of them floats and only one of them shuns water. Then the lighter one lies on top. Oil on ketchup floats. Honey poured onto oil goes under it, and the oil comes up on top. Oil on melted chocolate stirs in: for its cocoa butter, chocolate's row puts it right on the line where a thing counts as oily. Melted cheese sits just under that line, so by the same rule oil floats on it.

Search the code that moves liquids for the name of any material and you find none. The rows of the table are typed in by hand, though, and a few sit exactly on a line because that gives the right result: chocolate and marbling ink both sit right on the line for shunning water. So the fair claim is that the code never names a material, and the table decides.

Because the layers are real state, everything else can read them. A paper towel dabbed on oily water takes the oil on the first dab and the water on the second. A thin film of oil stops a puddle drying: after 50 s the bare puddle is down to under 10 %, the oiled one still over half.

[Under the hood](<#hood-layers>)

Oil floats because it's light and shuns water

Under the hood

### Oil floats because it's light and shuns water

Three properties are worked out once from each row of the table: is it oily, is it soft, does it float. Two soft things stay apart when at least one floats and they differ on oily. Everything that lands goes through one layering function, and by these rules cooking oil, butter, wax and marbling ink are the things that float. Density is only ever compared: there's no buoyancy force and no ordering among things that mix.

Readers pick a layer by two rules. A touch from above meets the top first once the film is thick enough to cover, and an emulsion covers nothing. Evaporation is scaled by how open the water is to the air, so even a sheen of oil seals it. A test pins that a film of oil keeps a puddle from drying.

The floating layer has its own flow: the same rule, slowed where it is beaten into what lies under it, and quicker and thinner-spreading over a liquid than on paper \(a test checks it covers clearly more area there\). A page with no oil skips all of it, tile by tile; a test checks that the renderer then gets byte-for-byte what it got before.

### One square, from the side

#### Floating layer

oil · wax · butter

Thick: covers. A sheen: seals. A towel, wind, a flame meet the top.

#### Goop layer

depth · colour · set

One material.

#### Water film

Can hold oil. Deep: lifts it.

#### Paper

Dent, cockle.

Up to three things stack in one square, each with its own fields: on top what shuns water and is light, under it one goop with its colours mixed, and under that the paper's own water. The notes are the rules that decide which layer a towel or the wind meets first, and when oil seals the water from the air. The water and the goop use different units on purpose.

Who floats on whom? The game's own ruleSlide to pick what you pour and what it lands on. The answer comes from the same three properties and density comparison the game uses, from each material's row. **Try:** oil onto melted chocolate, then oil onto melted cheese.

![What you pour lying on top of, going under, or mixing into what it lands on, by the game's layering rule](<https://professoroops.com/_assets/entity_3s7jFeRYwPIMjfyD0F0T.png>)

Pour7

you pour—

onto1

onto—

what you pour—

rule—

poured: shuns water—

→—

density—

floats—

below: shuns water—

→—

density—

floats—

![A puddle of blue water with a golden film of cooking oil spread over it, thickest towards the edge, the blue showing through the gold in the middle, dry paper around](<https://professoroops.com/_assets/entity_6OyufyVmvMoJqTm1H2bX.webp>)

**In the game.** Cooking oil poured onto a puddle of blue water spreads over it as a golden film of its own. Where the film is thin the blue shows through; the oil lies on top and doesn't mix in.

## Beat oil into egg yolk and it stays mayonnaise, beat it into vinegar and it clears

Pour oil onto egg yolk and leave it, and it stays a layer on top. Only working it mixes them: a finger whisking, a blow, drops splashing in. Then the two cloud together, and what happens next depends on what's in the bowl.

Yolk carries an emulsifier, and a little yolk can hold several times its own amount of oil. Beaten, it goes creamy and stays that way: a test checks it is still creamy two minutes later. Once there is clearly more oil than yolk, fully beaten, the oil is packed so tight that it stands up like mayonnaise. Vinegar has no emulsifier. Beaten, it clouds over, and in about two minutes it has cleared again. Soap counts as an emulsifier too, and soapy water worked over a grease spot lifts the fat out of the paper.

There are no droplets in the simulation. Each square keeps one number: the share of its oil beaten into what lies under it. The oil stays counted as oil and the water as water, so nothing can go missing when it separates again.

[Under the hood](<#hood-emulsions>)

Beat oil into egg yolk and it stays mayonnaise

Under the hood

### Beat oil into egg yolk and it stays mayonnaise

Per cell, one number holds the share of the floating oil that is beaten into the layer under it. Anything that works the page \(a finger, wind, a splash\) leaves a record of how hard it was stirred, and the share climbs toward what the water present can take, faster where an emulsifier is on hand. How much emulsifier there is, from the yolk, the oil's own row or soap, sets how much oil it can hold. Where it can't hold it all, the share relaxes back at a steady rate, faster the further short it falls.

Stiffness comes from the share of oil, φ = oil/\(oil \+ water\), in the bottom layer's flow: past a certain packing the emulsion runs less and less freely, and fully packed it stands. That is the same jamming that makes real mayonnaise stiff, reduced to one ramp.

Automated tests pin both ends: stirred yolk and oil stay creamy for two minutes with almost no oil lost, vinegar and oil clear, oil left on yolk unbeaten stays a layer, a little oil in milk still slumps and a lot of it stands. Standing is tested on milk with the emulsion set by the test; no test beats a yolk and then measures it standing.

Try it: whisk oil into a bowl The game's own ruleThe bowl opens being whisked. Drag across it to whisk more, or press Whisk, then watch. **What to look for:** with egg yolk the cream stays; with vinegar or milk it goes back to streaks of oil within a couple of minutes \(raise the time-lapse\). Add oil until the readout says it stands. The emulsion rule is the game's; how it evens out across the bowl is a simple blur here.

![A bowl of oil on egg yolk being whisked into an emulsion](<https://professoroops.com/_assets/entity_EicH26I8GHfMqvkOpzOX.png>)

In the bowlegg yolkvinegarmilk

Oil, parts to one2.0

Time-lapse×1

oil beaten in—

emulsifier holds—

it—

since whisking—

After beating: what stays mixedA test checks yolk is still creamy after two minutes and vinegar clears.

Egg yolk stays fully mixed; with half the emulsifier it needs, 22 % is still mixed after two minutes, and beaten vinegar is down to 5 %.

- egg yolk \(holds fully\)
- half the emulsifier it needs
- vinegar \(none\)

Data table

After beating: what stays mixed

| seconds after you stop | egg yolk \(holds fully\) | half the emulsifier it needs | vinegar \(none\) |
| --- | --- | --- | --- |
| 0 | 1 | 1 | 1 |
| 3 | 1 | 0.9632 | 0.9277 |
| 6 | 1 | 0.9277 | 0.8607 |
| 9 | 1 | 0.8936 | 0.7985 |
| 12 | 1 | 0.8607 | 0.7408 |
| 15 | 1 | 0.829 | 0.6873 |
| 18 | 1 | 0.7985 | 0.6376 |
| 21 | 1 | 0.7691 | 0.5916 |
| 24 | 1 | 0.7408 | 0.5488 |
| 27 | 1 | 0.7136 | 0.5092 |
| 30 | 1 | 0.6873 | 0.4724 |
| 33 | 1 | 0.662 | 0.4382 |
| 36 | 1 | 0.6376 | 0.4066 |
| 39 | 1 | 0.6142 | 0.3772 |
| 42 | 1 | 0.5916 | 0.3499 |
| 45 | 1 | 0.5698 | 0.3247 |
| 48 | 1 | 0.5488 | 0.3012 |
| 51 | 1 | 0.5286 | 0.2794 |
| 54 | 1 | 0.5092 | 0.2592 |
| 57 | 1 | 0.4904 | 0.2405 |
| 60 | 1 | 0.4724 | 0.2231 |
| 63 | 1 | 0.455 | 0.207 |
| 66 | 1 | 0.4382 | 0.192 |
| 69 | 1 | 0.4221 | 0.1782 |
| 72 | 1 | 0.4066 | 0.1653 |
| 75 | 1 | 0.3916 | 0.1534 |
| 78 | 1 | 0.3772 | 0.1423 |
| 81 | 1 | 0.3633 | 0.132 |
| 84 | 1 | 0.3499 | 0.1225 |
| 87 | 1 | 0.3371 | 0.1136 |
| 90 | 1 | 0.3247 | 0.1054 |
| 93 | 1 | 0.3127 | 0.0978 |
| 96 | 1 | 0.3012 | 0.0907 |
| 99 | 1 | 0.2901 | 0.0842 |
| 102 | 1 | 0.2794 | 0.0781 |
| 105 | 1 | 0.2691 | 0.0724 |
| 108 | 1 | 0.2592 | 0.0672 |
| 111 | 1 | 0.2497 | 0.0623 |
| 114 | 1 | 0.2405 | 0.0578 |
| 117 | 1 | 0.2317 | 0.0537 |
| 120 | 1 | 0.2231 | 0.0498 |
| 123 | 1 | 0.2149 | 0.0462 |
| 126 | 1 | 0.207 | 0.0429 |
| 129 | 1 | 0.1994 | 0.0398 |
| 132 | 1 | 0.192 | 0.0369 |
| 135 | 1 | 0.185 | 0.0342 |
| 138 | 1 | 0.1782 | 0.0317 |
| 141 | 1 | 0.1716 | 0.0295 |
| 144 | 1 | 0.1653 | 0.0273 |
| 147 | 1 | 0.1592 | 0.0253 |
| 150 | 1 | 0.1534 | 0.0235 |
| 153 | 1 | 0.1477 | 0.0218 |
| 156 | 1 | 0.1423 | 0.0202 |
| 159 | 1 | 0.137 | 0.0188 |
| 162 | 1 | 0.132 | 0.0174 |
| 165 | 1 | 0.1271 | 0.0162 |
| 168 | 1 | 0.1225 | 0.015 |
| 171 | 1 | 0.1179 | 0.0139 |
| 174 | 1 | 0.1136 | 0.0129 |
| 177 | 1 | 0.1094 | 0.012 |
| 180 | 1 | 0.1054 | 0.0111 |

Source: The game's separation rule: an emulsion short of emulsifier relaxes back at a steady rate, faster the further short it falls.

More oil, stiffer emulsionMarks: oil to milk 1 : 5 and 4 : 1, the two cases a test checks \(a fifth as much oil as milk runs; four times as much stands\).

Up to a share of oil of 0.35 it runs freely; from 0.35 to 0.6 it stiffens, and past 0.6 it stands.

Data table

More oil, stiffer emulsion

| share of oil, φ | how freely it runs |
| --- | --- |
| 0 | 1 |
| 0.01 | 1 |
| 0.02 | 1 |
| 0.03 | 1 |
| 0.04 | 1 |
| 0.05 | 1 |
| 0.06 | 1 |
| 0.07 | 1 |
| 0.08 | 1 |
| 0.09 | 1 |
| 0.1 | 1 |
| 0.11 | 1 |
| 0.12 | 1 |
| 0.13 | 1 |
| 0.14 | 1 |
| 0.15 | 1 |
| 0.16 | 1 |
| 0.17 | 1 |
| 0.18 | 1 |
| 0.19 | 1 |
| 0.2 | 1 |
| 0.21 | 1 |
| 0.22 | 1 |
| 0.23 | 1 |
| 0.24 | 1 |
| 0.25 | 1 |
| 0.26 | 1 |
| 0.27 | 1 |
| 0.28 | 1 |
| 0.29 | 1 |
| 0.3 | 1 |
| 0.31 | 1 |
| 0.32 | 1 |
| 0.33 | 1 |
| 0.34 | 1 |
| 0.35 | 1 |
| 0.36 | 0.96 |
| 0.37 | 0.92 |
| 0.38 | 0.88 |
| 0.39 | 0.84 |
| 0.4 | 0.8 |
| 0.41 | 0.76 |
| 0.42 | 0.72 |
| 0.43 | 0.68 |
| 0.44 | 0.64 |
| 0.45 | 0.6 |
| 0.46 | 0.56 |
| 0.47 | 0.52 |
| 0.48 | 0.48 |
| 0.49 | 0.44 |
| 0.5 | 0.4 |
| 0.51 | 0.36 |
| 0.52 | 0.32 |
| 0.53 | 0.28 |
| 0.54 | 0.24 |
| 0.55 | 0.2 |
| 0.56 | 0.16 |
| 0.57 | 0.12 |
| 0.58 | 0.08 |
| 0.59 | 0.04 |
| 0.6 | 0 |
| 0.61 | 0 |
| 0.62 | 0 |
| 0.63 | 0 |
| 0.64 | 0 |
| 0.65 | 0 |
| 0.66 | 0 |
| 0.67 | 0 |
| 0.68 | 0 |
| 0.69 | 0 |
| 0.7 | 0 |
| 0.71 | 0 |
| 0.72 | 0 |
| 0.73 | 0 |
| 0.74 | 0 |
| 0.75 | 0 |
| 0.76 | 0 |
| 0.77 | 0 |
| 0.78 | 0 |
| 0.79 | 0 |
| 0.8 | 0 |
| 0.81 | 0 |
| 0.82 | 0 |
| 0.83 | 0 |
| 0.84 | 0 |
| 0.85 | 0 |
| 0.86 | 0 |
| 0.87 | 0 |
| 0.88 | 0 |
| 0.89 | 0 |
| 0.9 | 0 |
| 0.91 | 0 |
| 0.92 | 0 |
| 0.93 | 0 |
| 0.94 | 0 |
| 0.95 | 0 |
| 0.96 | 0 |
| 0.97 | 0 |
| 0.98 | 0 |
| 0.99 | 0 |
| 1 | 0 |

Source: The game's stiffness ramp: past a certain packing of oil the emulsion jams.

## Soap on milk pulls the surface away, and the show ends when the soap is used up

Drop food colouring on milk, touch it with soap, and the colours burst away from the soap. That's the Marangoni effect <sup>[Scriven 1960](<https://professoroops.com/en/inside/research-simulation/#scriven-1960>)</sup>. Soap lowers the surface's tension, and the clean surface around it, pulling harder, draws the surface toward itself, carrying the colours along.

In the game soap lies on the surface as an amount per square. The surface moves as a sheet of blocks four squares across, each pulled toward where the tension is higher. Milk's fat matters twice. It makes the surface answer harder, so milk pulls far harder than water. And it binds the soap and is spent doing so. The motion eases by itself as the soap is used up and evened out, with no timer anywhere.

The same moving surface carries whatever rides on it. Soap on a puddle sprinkled with pepper sends the pepper fleeing at once. Soap on wet watercolour pushes the paint into a ring round a pale hole.

In the released game the colours burst outward and curl a little at the edges. next update They really swirl. Cream isn't spread evenly through milk, so along the soap's front the pull is stronger in one stretch than the next, and the two shear past each other. That difference spins the surface, and the spin goes on for seconds after the push has eased.

[Under the hood](<#hood-milk>)

Soap on milk pulls the surface away

Under the hood

### Soap on milk pulls the surface away

The surface sheet runs at a lower rate than the liquids, only while something moves, and only over a box round the soap. It is coarser than the page: each block covers a small patch of squares.

Soap lowers the tension along a saturating curve, so a little soap does most of the work and more soap on a soapy spot adds little. The surface pull follows the tension's slope, grows with the milk's fat, and ignores slopes too faint to matter. The sheet's velocity relaxes toward that pull, carried along by itself semi-Lagrangian, as in the air <sup>[Stam 1999](<https://professoroops.com/en/inside/research-simulation/#stam-1999>)</sup>, and kept curling by vorticity confinement, consistent with <sup>[Fedkiw 2001](<https://professoroops.com/en/inside/research-simulation/#fedkiw-2001>)</sup>, under a speed limit. There's no pressure projection: the sheet may bunch and thin. Soap slowly sinks out of the surface and is bound by free fat, which spends the fat; that is what ends the show.

next update The swirl: the fat varies over the milk in a smooth noise seeded by the paper, much more than in the released game. The curl of the pull spins up vorticity, which decays over seconds; a stream function is solved from it each step by a few warm-started over-relaxation sweeps, and the surface moves round its contours. A test checks that uneven fat turns the surface and even fat barely does.

An automated test pins the burst: it opens fast in the first second, is still moving more than ten seconds later, never leaps, and at last rests. The WebAssembly twin keeps every colour and the milk to within rounding. The finite, easing clearing is consistent in kind with <sup>[Roché 2014](<https://professoroops.com/en/inside/research-simulation/#roche-2014>)</sup>; nothing was fitted to it.

Try it: soap on milk The game's own ruleA soap drop lands in the middle soon after it opens. Tap to add more soap, or switch to colour and tap to add drops; the buttons add them too. **What to look for:** the burst, then the slow easing as fat binds the soap. A second soap drop on a soapy spot does little; on clean milk, a lot. Switch to the next update's milk for the swirl. The surface sheet follows the game's rule; here soap and colours ride it by a simpler method than the game's, and both keep every drop.

![Food colouring on milk bursting away from a drop of soap](<https://professoroops.com/_assets/entity_aqJghnR7ybnHrCFTaYjP.png>)

Tap addssoapcolourMilkreleased gamenext update

fastest—

soap on the surface—

most fat spent in a square—

time—

![Milk with red, blue, yellow and green food colouring bursting away from a touch of soap](<https://professoroops.com/_assets/entity_R7CSzH5UHHVvTqHXSB8K.webp>)

**In the game.** Four drops of food colouring on milk, a moment after a drop of dish soap in the middle.

A little soap does almost everythingThe soap axis is logarithmic: −5 is 0.00001, 0 is 1. A test checks that a drop on a spot already soapy does little; on clean milk, a lot.

Tension is half gone at 0.005 of soap; by 0.05, where a spot counts as already soapy, it is down to 0.09.

Data table

A little soap does almost everything

| soap on the surface, as a power of ten | surface tension σ |
| --- | --- |
| −5 | 0.998 |
| −4.9375 | 0.9977 |
| −4.875 | 0.9973 |
| −4.8125 | 0.9969 |
| −4.75 | 0.9965 |
| −4.6875 | 0.9959 |
| −4.625 | 0.9953 |
| −4.5625 | 0.9946 |
| −4.5 | 0.9937 |
| −4.4375 | 0.9927 |
| −4.375 | 0.9916 |
| −4.3125 | 0.9904 |
| −4.25 | 0.9889 |
| −4.1875 | 0.9872 |
| −4.125 | 0.9852 |
| −4.0625 | 0.983 |
| −4 | 0.9804 |
| −3.9375 | 0.9774 |
| −3.875 | 0.974 |
| −3.8125 | 0.9701 |
| −3.75 | 0.9657 |
| −3.6875 | 0.9605 |
| −3.625 | 0.9547 |
| −3.5625 | 0.9481 |
| −3.5 | 0.9405 |
| −3.4375 | 0.9319 |
| −3.375 | 0.9222 |
| −3.3125 | 0.9113 |
| −3.25 | 0.8989 |
| −3.1875 | 0.8851 |
| −3.125 | 0.8696 |
| −3.0625 | 0.8524 |
| −3 | 0.8333 |
| −2.9375 | 0.8124 |
| −2.875 | 0.7895 |
| −2.8125 | 0.7645 |
| −2.75 | 0.7377 |
| −2.6875 | 0.7089 |
| −2.625 | 0.6783 |
| −2.5625 | 0.6461 |
| −2.5 | 0.6126 |
| −2.4375 | 0.5779 |
| −2.375 | 0.5425 |
| −2.3125 | 0.5066 |
| −2.25 | 0.4707 |
| −2.1875 | 0.435 |
| −2.125 | 0.4 |
| −2.0625 | 0.366 |
| −2 | 0.3333 |
| −1.9375 | 0.3022 |
| −1.875 | 0.2727 |
| −1.8125 | 0.2451 |
| −1.75 | 0.2195 |
| −1.6875 | 0.1958 |
| −1.625 | 0.1741 |
| −1.5625 | 0.1544 |
| −1.5 | 0.1365 |
| −1.4375 | 0.1204 |
| −1.375 | 0.106 |
| −1.3125 | 0.0931 |
| −1.25 | 0.0817 |
| −1.1875 | 0.0715 |
| −1.125 | 0.0625 |
| −1.0625 | 0.0546 |
| −1 | 0.0476 |
| −0.9375 | 0.0415 |
| −0.875 | 0.0361 |
| −0.8125 | 0.0314 |
| −0.75 | 0.0273 |
| −0.6875 | 0.0238 |
| −0.625 | 0.0206 |
| −0.5625 | 0.0179 |
| −0.5 | 0.0156 |
| −0.4375 | 0.0135 |
| −0.375 | 0.0117 |
| −0.3125 | 0.0102 |
| −0.25 | 0.0088 |
| −0.1875 | 0.0076 |
| −0.125 | 0.0066 |
| −0.0625 | 0.0057 |
| 0 | 0.005 |

Source: The game's tension curve: a chosen saturating shape, not a fitted isotherm.

Fat makes the surface pull harderThe game has one milk: skimmed exists only in a test that changes the table, where it bursts clearly less far.

Water pulls at 180, skimmed milk \(in a test\) at 250 and whole milk at 547 cells a second per unit of σ slope.

Data table

Fat makes the surface pull harder

|  | pull |
| --- | --- |
| water | 180 |
| skimmed \(test\) | 250 |
| whole milk | 547 |

Source: The game's pull with even fat, from milk's row in the material table.

## A hand, a toothpick and a drop of ink move liquid without making or losing any

Drag a palm through paint and the paste heaps up in front of it while runny stuff closes in behind. A soft palm doesn't wipe the paper clean. It rides on part of the paste and leaves a thinner layer behind, faintly streaked along the stroke. The same code serves a palm, a paw, a wheel, a ball and a squeegee. They differ in footprint, hardness, how flat their face is and how much they slip.

Strike oobleck with a hammer and it doesn't splash; press it slowly and you sink in. The faster a push is for its size, the more the cornflour jams.

A toothpick works differently. It drags what is near it along, and what is further out flows back the other way, the way a stick swirls colour on shaving foam. The flow is built so that whatever goes into a square comes out of it. The colour is drawn into veins and none is lost.

Marbling ink shows this most clearly. A new drop on water spreads at once into a thin film and pushes every earlier ring outward by exactly as much as makes room for itself. Drop after drop in one spot makes rings inside rings, each colour kept. Comb them and you get feathers. The result barely depends on how you move: combing in one long swipe or in tiny moves comes out within 15 % on shape.

[Under the hood](<#hood-marbling>)

A hand, a toothpick and a drop of ink move liquid

Under the hood

### A hand, a toothpick and a drop of ink move liquid

Any drag becomes a row of small pushes along the stroke. Each push takes a share of what lies under the footprint, more near its middle and more from soft stuff, and sets it down a little ahead, spread smoothly over neighbouring cells so a slanted stroke doesn't staircase. A flat face ploughs only what holds its shape. A soft face rides on part of the film, depending on how hard it is and how well the stuff clings, and leaves faint streaks along the stroke. Afterwards a paste slumps back to a slope its yield can hold. Oobleck jams by how fast the push is for its size, so a hammer meets a solid and a slow press sinks in. A test checks that the film left behind depends on the material, that its streaks run along the stroke, and that none is made or lost. Height-field pushing like this was informed by <sup>[Sumner 1999](<https://professoroops.com/en/inside/research-simulation/#sumner-1999>)</sup>.

A point moves the liquid with a stream function along its path: it drags what is near and sends a gentle return flow further out. Each face's flow is a difference of the stream function at its corners, so it is divergence-free by construction, and nothing can pile up or vanish. A marbling drop uses the point source of mathematical marbling: every spot of the film at radius r moves out to √\(r² \+ a\), where a is the drop's own area over π, so the old rings make exactly the room the new drop needs. A test checks the rings stay concentric with their colours kept, and that combing keeps each spot's main colour with very little mud.

Try it: drop and comb marbling ink The game's own ruleDrops land in the middle, then a toothpick combs across. Tap to drop ink, or switch to the toothpick and drag; Drop ink and Comb across do the same from the keyboard. **What to look for:** each new drop pushes the old rings out without mixing them, and combing makes feathers. The readout compares the film's area with what the drops put in: combing never changes it. The rings here are outlines moved by the game's own formulas; the game moves the film cell by cell.

![Marbling ink drops pushed into rings and combed with a toothpick](<https://professoroops.com/_assets/entity_NLDEmTpDdf9K1kau5IyC.png>)

Tap or dragink droptoothpick

Drop radius10 cells

drops—

film area—

drops put in—

![A band of blue tube paint after one palm stroke from left to right: a raised ridge of paint where the hand stopped, a flatter, faintly streaked layer in the track behind](<https://professoroops.com/_assets/entity_xbdSLQ4LGvNXzGy2QdJS.webp>)

**In the game.** One palm stroke through tube paint, left to right: the paste piles up in a ridge where the hand stopped, and the track behind keeps a thinner layer, faintly streaked along the stroke.

![Rings of blue, red and yellow marbling ink on water, combed by a toothpick into pointed feathers](<https://professoroops.com/_assets/entity_i9S2uDyApyuz4TdBTqtD.webp>)

**In the game.** Marbling inks dropped in one spot, blue, red and yellow twice over, then combed with a toothpick three times across.

## Butter leaves a see-through spot, soapy water froths and mud cracks as it dries

**Grease.** Melt butter on paper and it leaves a see-through spot that widens slowly to an edge and stops. Water and a sponge won't shift it. Add dish soap to the water and it washes out without scrubbing. Wet paper won't take fat in, and greasy paper keeps most water out, so whichever came first wins. Fat washed out always comes up as cooking oil, whatever went in: the paper keeps one number for fat, not a recipe.

**Foam.** Soapy water rubbed or splashed froths up into foam; still water on soap stays still. The foam itself is a stiff goop that never flows, and the bubbles on it are drawn objects with timers, up to a fixed number. They swell, pop and leave the paper a little damp. No gas is tracked.

**Mud.** Mud is just another row in the table, like ketchup: fairly stiff, holding a slope nearly as well as ketchup, and it forms a crust as it dries. A splat of it comes with pebbles and twigs. Leave it six hours or bake it, and it cracks into plates a few millimetres across. The cracks are a pattern laid down at the end of the wait. No stress is worked out, and nothing cracks while you play.

next update Stones lie on mud as a layer of their own and sink as the mud under them slumps, and froth bursts within seconds unless soap holds it up.

[Under the hood](<#hood-grease>)

Butter leaves a see-through spot, soapy water froths and mud cracks

Under the hood

### Butter leaves a see-through spot, soapy water froths and mud cracks

Grease: paper holds a limited amount of fat in its fibres. Fat goes in only as far as there's room and the paper isn't wet, and greasy paper soaks water more slowly in turn. Every so often the fat spreads by neighbour diffusion of what is above a held amount, so a spot widens to an edge and stops; once it is still, the code stops looking at it. It's drawn see-through in proportion to how full the paper is. Soapy water worked over it lifts some out each time. The oven reruns the same rule many times over. An automated test pins how it washes out.

Lather is made a few times a second, only where soap is worked and water is there; strong wind counts as working it. Bubbles have a random size, and their chance of popping grows with age and is higher for small ones, so the small ones go first.

Mud: a Voronoi pattern is applied once after a wait of six hours or more, or the oven; thin gaps crack, edges curl and the plates go paler. Crusting loses water only, so the colour per unit stays and deepens; a skin holds a light touch, and a palm breaks it where a fingertip doesn't.

Try it: a grease spot, a heap of suds, a mud pie The game's own rulePick one and tap the paper, or press Add one. **What to look for:** the butter spot widens fast, then slower, and stops at an edge \(the readout says when it's at rest\). The small bubbles go first and the heap thins out over a minute. The mud dries for six hours in a few seconds, then cracks into plates all at once. Each runs on the game's numbers: the grease spot on its own spreading rule, the bubbles on their own pop chance, the cracks on mud's plate size and gap. The drawing is simpler than the game's.

![A butter spot spreading in paper, a heap of suds popping, or mud drying and cracking, by the game rules](<https://professoroops.com/_assets/entity_BcTq7hsbWIx3tUXmmsge.png>)

Tap addsmelted buttersoap sudsmud

spot across—

fat—

bubbles—

popped—

in play—

drying—

plates—

## Most of the page sits still, so the tablet only works where something moves

A full page is about 200,000 squares, and most of them aren't moving at any moment. The page is cut into small tiles that sleep when nothing in them changes, wake when something lands, and make up the time they slept when they get their turn. On a page with no oil the floating layer's work is skipped. The soap-on-milk surface only runs while something moves, and only round the soap.

The busiest loops also run as WebAssembly, written by hand and checked against the plain code square by square, most of them to the last bit. The [engineering chapter](<https://professoroops.com/en/inside/speed/>) tells that story.

[Under the hood](<#hood-speed>)

Most of the page sits still, so the tablet only works where something moves

Under the hood

### Most of the page sits still, so the tablet only works where something moves

Tiles are awake, creeping or settled. Creeping tiles are worked less often, settled ones only looked at now and then, and empty ones hardly ever, within a per-frame tile budget that shrinks with the detail level. Slow local work \(soaking, staining, drying\) catches up in closed form when a tile gets its turn; a test holds ketchup's stain at the lightest detail close to what full detail gives.

WebAssembly twins of the goop, floating-layer, Marangoni and pushing loops, written by hand in AssemblyScript and working in the simulation's own memory. Goop, pushing and Marangoni are bit-exact with their JavaScript, each pinned by its own test; the floating layer agrees to within rounding. Measured when each landed: pushing 2.6–2.9× faster than JS with oil on the page; the floating layer 2.2–2.4× less time, 30–35 % less a tick in all; Marangoni on milk with 12 drops and 2 of soap, 2.8–3.0 ms a tick down to 1.5–1.7 ms at 432 × 324. Of these four, in the released game only the floating layer uses SIMD. Time skips run the same flow passes in slices, on the same tile budget on every device, so a slow tablet gets the same page.

3

things can stack in one square: a water film, a goop layer and a floating layer.

0

material names in the five files that move liquids. The table decides.

512 × 384

squares on a full page, each about half a millimetre, most of them asleep until something moves near them.

2 min

for beaten vinegar and oil to clear again. Beaten egg yolk stays creamy.

4

liquid loops with a hand-written WebAssembly twin; three of them bit-exact with the plain code.

2.6–2.9×

faster pushing through oily goop with the WebAssembly twin than in plain JavaScript.

## Fire, wind and the dog meet the same oil and milk, because they all read the same layers

The fire, the wind and the dog read and write the same fields as the liquids, and the effects below come out of that. Each is pinned by a test.

Shared: floating layer over water · air contact

### Pour a little oil on one of two puddles and wait

The bare puddle dries; the oiled one is still there.

*[Water in paper](<https://professoroops.com/en/inside/water/>)*

Shared: water under the floating layer · heat

### Drip water on burning oil

It flashes to steam and throws the burning oil up. On hot oil it only spits; on cold oil it slides under.

*[Heat and fire](<https://professoroops.com/en/inside/heat/>)*

Shared: wind · the top layer

### Blow a hair dryer over oil lying on a sauce

The oil film blows along; the sauce under it barely moves, held by its yield.

*[Air that really moves](<https://professoroops.com/en/inside/air/>)*

Shared: the top layer · what paws carry

### Let the dog walk through oily water

It leaves oily paw prints wherever it goes next.

*[Animals with their own minds](<https://professoroops.com/en/inside/creatures/>)*

Shared: acid element in goop

### Brush lemon juice into milk

With enough of it, the milk curdles into curd and whey.

*[Chemistry and pH](<https://professoroops.com/en/inside/chemistry/>)*

Shared: surfactant · wet paper's film

### Touch wet watercolour with soap

The surface pulls away and pushes the paint into a ring round a pale hole.

*[How colours mix](<https://professoroops.com/en/inside/colour/>)*

## Ketchup stands and honey runs on a tablet because the game gives up splashing and sloshing

A child on a tablet needs ketchup that stands and honey that runs, sixty times a second, on 200,000 squares. Each shortcut below keeps a behaviour a child can see, and gives up something nobody at that scale would notice.

**In real life.** Liquids are three-dimensional and carry momentum.

**In the game.** A height field: one depth, one colour, one material per layer per square. Pastes have no velocity at all.

**Why that's enough.** It runs on a phone. Lost: overhangs, folding and sloshing; ketchup never splashes back.

**In real life.** A yield-stress paste holds where its weight on the slope is below its yield, so a thicker layer holds a gentler slope.

**In the game.** A slope threshold per material, with no depth in it. Only the separate slide rule on a tilted page looks at depth.

**Why that's enough.** One number gives the bead. Heaps rest as straight-sided cones, not domes, and the threshold isn't a stress: it has no units.

**In real life.** Viscosities span thousands to one between water and honey.

**In the game.** Runniness spans a narrow range. Honey is only a few times slower than oil.

**Why that's enough.** An explicit step is only stable below a limit, and anything much slower looks stuck. Speed is a feel here, not a measurement.

**In real life.** Thin films flow as depth cubed.

**In the game.** Paste flow grows with the slope past the yield, independent of depth; below a thin film nothing flows.

**Why that's enough.** Stable and cheap. A thick pool and a thin film creep at the same rate until the film is thin enough to stop.

**In real life.** Liquids sort into towers by density.

**In the game.** Two layers and a water film. Density is compared only for things that don't mix.

**Why that's enough.** A few extra numbers a square, and no work for them on a page with no oil. No density tower: honey in milk just mixes.

**In real life.** Two liquids in one spot blend their properties.

**In the game.** Colours average by amount; the material is winner-takes-all, the biggest stream coming in.

**Why that's enough.** One material a square. A honey and ketchup mix behaves as one or the other, square by square.

**In real life.** An emulsion is droplets of many sizes.

**In the game.** One share per square, a stiffness ramp as the oil gets packed, and a steady rate of separating.

**Why that's enough.** Oil is conserved by construction. Droplet size is gone; the rate and the ramp are tuned to read right.

**In real life.** Soap lowers tension along a measured curve, and the surface drags the liquid under it.

**In the game.** σ falls along one saturating curve, the same for water and milk; a coarse sheet relaxes toward the pull, with no projection.

**Why that's enough.** Only the slope of σ drives the flow, and the shape is right in kind. The strength of the pull is tuned, and the milk's depth plays no part.

**In real life.** Foam coarsens as gas moves between bubbles; mud cracks by stress as it shrinks.

**In the game.** Bubbles are circles with timers; cracks are a Voronoi pattern laid down at the end of a long wait.

**Why that's enough.** Both look right for the cost of almost nothing. Neither changes during play the way the real thing would.
