One square, four folds. Each fold hides clean cloth inside, where only other clean cloth can touch it. Open it one fold at a time and every wipe gets a fresh surface — from a sixteenth, up to the whole inner square.
The animation is not a texture trick. It is a cloth of area 16s² cut into a 4×4 grid, each cell a rigid square of side s, each square having two faces. That is 16 panels × 2 sides = 32 faces, and the sequence uses each one exactly once.
Put the cloth in the plane as the square [0, 4s] × [0, 4s]. Panel (c, r) with column c ∈ {0,1,2,3} and row r ∈ {0,1,2,3} occupies
Call the ivory side inner (the f face in the code) and the hemmed side outer (b). Unfolded, inner faces up. A point of the cloth is a triple (x, y, side).
Fold k is a hinge. Half of the current packet turns by an angle θ about a crease line lying in the cloth. A rotation about the line x = a is a plain rotation moved to the crease and back:
In CSS that is translateX(a) rotateY(θ) translateX(−a); horizontal creases use translateY and rotateX. At θ = π, seen from above, the hinge is the reflection x ↦ 2a − x plus a swap of sides of the cloth. So every fold is an involution: doing it twice is the identity.
The four creases, in order, always fold toward the bottom-right cell:
Every fold lays half the packet onto the other half, so after n folds the packet covers 24−n cells and every stack in it is L = 2n layers deep. Fully folded: one cell, sixteen layers, two exposed faces.
The first fold is the important one. Rotating the left half about x = 2s sends
It lands exactly on the right half, whose inner side is facing up. So inner is pressed against inner, and the whole ivory side is sealed against itself in that instant. It doesn’t come out again until f₁ is opened. Later folds move those sealed pairs around together, and only outer faces ever end up on the outside of the packet. That is the rule store clean inside, written as an isometry.
The code stores a state vector (f₁, f₂, f₃, f₄, flip) ∈ {0,1}5. Folds are always closed in order, so the state is fixed by n = f₁+f₂+f₃+f₄. Once, at load, SIM folds the cloth on paper and records each cell’s landing spot, which side is up, and its layer height z. A cell on the moving side of a crease gets its order reversed and is placed on top of the other half:
Then exposure() simply reads the stacks. The top face is the up side of the layer at z = L − 1, the bottom face is the down side of the layer at z = 0, and flip swaps them:
Each time you open a fold you double the number of faces looking at you, and they are exactly the faces that were pressed together inside that crease. So the wipes are forced by the geometry:
That is: a sixteenth for the left cheek, and another sixteenth (the underside, after a flip) for the right cheek. Then an eighth, a 1×2 strip, for the nose, and a quarter, the 2×2 block, for eating. Then a half, a 2×4 rectangle that is the nose strip scaled by 2, for the hands. Last, the whole inner square for the face. Each unfold doubles the exposed set, so the areas are powers of two.
Which cells swing at each crease: f₁ moves columns 0–1 and f₂ rows 0–1. f₃ moves columns 1 and 2, the two that f₁ stacked next to the crease x = 3s. f₄ moves rows 1 and 2 in the same way. In binary, f₃ moves a column exactly when its two bits differ, which is the Gray code.
The sixteen squares are siblings. Each one gets a single transform: its own spot in the grid, then the four hinges in folding order, then a small lift so the layers stack in the right order. Let ak(c, r) ∈ {0,1} say whether that cell is on the moving side at crease k (recorded by SIM). Then
A transform list is applied right to left, so crease 1 acts first and crease 4 last, all about fixed lines in the cloth’s own frame. Every hinge is its own rotateX/rotateY term, so when you open or close one fold, the browser only swings that one angle. The rest of the packet travels with it rigidly, which is what real cloth does.
The packet would drift toward the bottom-right as it shrinks, so a translation recenters it. After the folds it covers [2s f₁ + s f₃, 4s] × [2s f₂ + s f₄, 4s], and the shifter moves by minus its centre:
A wipe uses exactly the faces at z = L − 1, the ones facing you. They always form one rectangle R of the cloth, with centre (cₓ, cy) and half-sizes (wₓ, wy). Each face draws its own piece of one ellipse centred on R, with radii (kₓ wₓ, ky wy). As a percentage of the face:
The folded packet is a reflected copy of R, and a centred ellipse looks the same when reflected. So each wipe lands as one blob in the middle of whatever is facing you, whichever way it was folded.
That is the whole machine: sixteen rigid squares, four involutions, a layer count, a bit of centering, and a partition of the 32 faces into 1, 1, 2, 4, 8, 16.