How it works
Layers that can each be swapped: where a target comes from, what draws it, what edits it, what reads it, and what records it.
The motor: Hands
Hands (Russell's engine at parallaxmetrology/hands) is vendored as a read-only snapshot in vendor/hands/. A hand is a learned vocabulary of marks: width, length, pressure, softness, how a mark follows the form, whether it hatches. hand/run.mjs looks at a target, then lays strokes greedily on a real canvas: a stroke is kept only when it lowers the drawing's error by more than it costs. Restraint makes open paper worth something. --init continues an existing canvas; --absolute keeps a target's own darks (see Tests).


Value plans: compose.py
A target is assembled, never pasted: place (an oval crop, optionally blurred and cut to a few values: a block-in), mass and blob (authored value shapes), lighten, squint, quiet (a busy field made into a slow even tone) and from_canvas (outside a box, the target is the current drawing, so continued drawing works only inside it). The base can be an image or blank paper.



The still-life stage: scene.py
A small signed-distance raymarcher: a table, an optional wall, apples (squashed spheres with a dimple and a stem, which can lean), cups (tapered and hollow with a floor and a handle, or capped), boxes; one directional light with soft shadows, ambient occlusion and an optional pool of light. It gives authored geometry with correct cast shadows, a source of form that is not a generator. hand/thumbs.py draws a whole set from scene files and makes caption-free contact sheets.






Taking back: lift.py
A kneaded eraser in broad soft passes across a box; the paper's tooth keeps dust in its valleys, so a lifted passage leaves a ghost. The passes are recorded like marks.
Intentions: intend.mjs
A critic's note is translated into a kernel: a loss measured on the canvas inside a region. The machine proposes native actions (Hands vocabulary marks, eraser strokes, a stump), renders each on a copy, rejects any that break a guard, and commits the one that lowers the loss most for the least change; then it looks again. Nothing here decides what the drawing needs; the job does.
| kernel | loss | actions | guard |
|---|---|---|---|
| reserve-paper | ink above a ceiling in a region | eraser strokes | region, protected boxes, change cap |
| connect-mass | ink below a floor along a corridor (5 probes across) | broad mark, hatch patch, or a loose cluster of mid-width strokes | softness: no new step across the corridor (a mass, not a stripe) |
| soften-edge | contrast across an edge above a ceiling | paired feather: lift on the dark side, deposit on the light side | edge integrity: no new light pocket, the boundary moves at most n px |
| break-edge | a ruled boundary: too little wander from its own straight line | push (a cluster of the hand's strokes outside the edge) or pull (eraser inside) | no station moves more than maxShift |
| even-tone | cells of a masked field off a target tone, or too busy inside | broad flat marks into light cells, eraser through dark cells, a stump through busy cells | mask: no change outside the field |
Intentions run in order on one canvas; after each, every earlier one is re-measured and the new one is reverted if it undid an earlier commitment. The committed commands are replayed from the source and must match exactly, or nothing is written.







The critic
From the the paint simulator build: critic/read.py runs the VTL Full Readout notebook (frozen verbatim, hash recorded), a tonal reader (value zones, anchors, focus, visibility, edges), a mark reader (energy, direction, stratification), Russell's colour analyser, and Protocol v8 routing. Every number carries what it computes, what it may say and what it cannot say; a guard checks written critiques against the packet. The engine passes (RIDP, Sketcher, Artist's Lens, Marrowline, Handoff) read it in order. In this build the passes were written by the orchestrating assistant, which is recorded in each critique.


Every reader sheet in this build

















The translator: propose.py
A deterministic step from the critic's reading to an intention job: no committed black, a ruled edge (side scans of the smoothed mass), a mass floating near the main one. Each proposal cites the number that fired it, and the job is drawn over the canvas so it can be read before it runs.

Sources: museum.py
Searches open-access collections for public-domain works (the Art Institute of Chicago answers; the Met's API returned HTTP 410 from this machine) and downloads one object at a time on request, with a sidecar record. A reference is a target or a study, like any other source. The searches run so far (catalogue records only; nothing has been downloaded yet):
Museum search results
| key | artist | title | date | search |
|---|---|---|---|---|
| aic:87 | Salvator Rosa Italian, 1615-1673 | A warrior sits on a block and gestures; two figure are behind him, from Figurine series | n.d. | figure from behind drawing |
| aic:164 | Attributed to a Member of the Earlier Mannerist Group Greek; Athens | Column-Krater (Mixing Bowl) | about 460 BCE | figure from behind drawing |
| aic:162 | Attributed to a painter of the Leagros group Greek; Athens | Hydria (Water Jar) | about 515-500 BCE | figure from behind drawing |
| aic:246 | Attributed to the Mattinata Painter Greek; Apulia, Italy | Oinochoe (Pitcher) | end of 4th century BCE | figure from behind drawing |
| aic:615 | Attributed to the Euaion Painter Greek; Athens | Pyxis (Container for Personal Objects) | 450-440 BCE | figure from behind drawing |
| aic:616 | Greek; Athens | Pyxis (Container for Personal Objects) | 430-420 BCE | figure from behind drawing |
| aic:65244 | Roman | Statue of a Seated Woman | 2nd century | Kollwitz seated woman |
| aic:40599 | Antonis Mor (Netherlandish, c. 1517–c. 1576) | Portrait of a Seated Woman | c. 1565 | Kollwitz seated woman |
| aic:15860 | Paul Gauguin French, 1848-1903 | Seated Breton Woman | 1886 | Kollwitz seated woman |
| aic:150773 | Georges Seurat French, 1859-1891 | Seated Woman with a Parasol (study for La Grande Jatte) | 1884/85 | Kollwitz seated woman |
| aic:246 | Attributed to the Mattinata Painter Greek; Apulia, Italy | Oinochoe (Pitcher) | end of 4th century BCE | Kollwitz seated woman |
| aic:35381 | China | Seated Woman Holding Mirror | Tang dynasty (A.D. 618–907), first half of 8th century | Kollwitz seated woman |
| aic:4 | Lawrence Carmichael Earle | Priest and Boy | n.d. | Kollwitz |
| aic:93 | Jean François Millet | Geese in a Farmyard | c. 1871 | Kollwitz |
| aic:149032 | Alessandro Magnasco | Study Sheet with Seated Figures | 1705/15 | seated figure |
| aic:46468 | Jean Baptiste Carpeaux (French, 1827-1875) | Back View of Seated Figure, Lifting Left Arm | n.d. | seated figure |
| aic:210894 | Herman Saftleven | A Forest Interior, with a Seated Figure | n.d. | seated figure |
| aic:81690 | Follower of Michelangelo Buonarroti | Male Figure Study, with Slight Sketch of Seated Figure | 1540/50 | seated figure |
| aic:7120 | Giovanni Francesco Grimaldi | Figures Seated by a River | n.d. | seated figure |
| aic:96181 | Sir Edward Burne-Jones | Seated Female Figure | 1873 | seated figure |
| aic:112804 | Niccolò Circignani, called Il Pomarancio | Study for the Duel between Heraclius and Khosrau (recto); Sketches of Seated Figure (verso) | 1582 | seated figure |
| aic:95697 | Attributed to Vincenzo Tamagni | Sketches of Virgin and Child, Seated Figure, and Landscape | c. 1530 | seated figure |
The record: step.py and lineage_video.py
The ledger writes one line per move: tool, platform, inputs and outputs with checksums, the prompt verbatim, and who made the call; --show lays the chain out as a page. The lineage video shows every full-image state in order, with a tree: the spine is the line kept, side branches were tried and not carried forward, each with its reason.

Parked: the first PyTorch build
Before Hands, the machine was built from scratch in PyTorch: a dry-media material (tooth, graphite grades, compressed charcoal reaching L* 9), a motor with characters, and a FRIDA-style planner calibrated against the real motor. The residual halved over nine rounds, but it did not read as hands. It is parked, not deleted.



