Keith & Claude teach a screen to paint with random dots — July 2026
Every picture below is a live program. Press RUN and it computes in your browser.
This page is drawn from a real working conversation between Keith Stein and Claude.
The idea was simple: control every pixel of a 707 × 300 screen with one BASIC-style
command — PSET x, y, r, g, b — pick points at random, colour each by a rule,
and see what worlds emerge. The dialogue is abridged; the programs are the originals.
1 · A circle from dice
KEITH:x = RND*200-100 : y = RND*200-100 : R = SQR(x^2+y^2) —
if R < 80 then PSET red, else PSET blue. Loop till keypress. I'm hoping for a red circle
of radius 80 on a blue square, centred on 0,0.
CLAUDE:
Your program's sound — and note your own colour formulas do more than you asked:
the red brightens outward (R×3), the blue fades outward (255−R). Watch it stipple in.
0 points
Monte Carlo painting: no line of code ever “draws a circle” — the circle is a statistical fact about 200,000 independent dice rolls.
2 · Time enters: rippling rings
KEITH:
If I want to change colour with time, can I use Ti for seconds from start?
Then let's try g = 100*SIN(R − 4*Ti) + 110.
CLAUDE:
Constant colour follows R = 4·Ti + const — green crests marching outward at 4 pixels
per second. And a subtlety of the random-dot method: a pixel only changes when the dice
revisit it, so instead of rings gliding smoothly you get a churning, shimmering wavefront —
like sunlight on rippled water.
Ti = 0.0 s
Red disc, radius 80; green gun rippling with time; blue fading with radius. Three guns, three different functions, one screen.
3 · The DJ deck: your pointer, your clicks, your line 160
KEITH:
Can one of the sources follow my mouse? And when I click, I want a large step change.
CLAUDE:
Two ripple sources, waves added: A = SIN(R1·K − S·Ti) + SIN(R2·K − S·Ti).
Your pointer is source 1. A click is a drum hit: wavelength K, speed S, palette and the
second source all jump to new random values — but the screen doesn't jump, the new picture
soaks in through the old at the repaint rate.
KEITH:
First thing I tried was multiplying the sines instead of adding. The patterns
remind me of magnetic fields — what does multiplying represent physically?
CLAUDE:
Sum is interference; product is modulation. sin A·sin B =
½[cos(A−B) − cos(A+B)]: the first term freezes into stationary hyperbolae
(the fringe skeleton), the second travels along ellipses sharing the same two foci —
and confocal ellipses and hyperbolae always cross at right angles. Your eye recognised the
orthogonal grid of a field diagram before the algebra did. It's also how every radio mixer
has worked since the 1920s.
Try: SIN(R1*K - S*Ti) * SIN(R2*K - S*Ti) (Keith's discovery) ·
SIN((R1-R2)*0.2) · SIN(SQR(ABS(x*y))*0.3 - 2*Ti).
Mistype and the last good line keeps running.
4 · The Longest Day
KEITH:
Next a horizon: IF y > 10 THEN sky blue ELSE green. Then Claude offered a sun,
depth-shaded grass, a sky gradient, a sunset… I said put them all in, eh!
CLAUDE:
A complete day in Monte Carlo dots. Everything is still just IF-tests on each random
pixel: sun first (clipped by the horizon — occlusion for the price of moving an IF),
then sky with a sunset term that peaks when the sun's altitude nears zero, then ground
brightest at your feet, and 120 fixed stars painted only when daylight fades.
60s
Watch a sunset: for a few seconds the orange sky, the reddened sun and the first stars all coexist in the churning dots.
5 · Into 3D: ripples on water, in perspective
KEITH:
Instead of grass I want flat WATER stretching to the horizon — and those 2D ripples on it,
seen in 3D. I'm thinking about transferring our 2D skills to 3D. And my pointer drops the pebble.
CLAUDE:
The classic graphics leap. Every screen pixel below the horizon maps to a point on the flat
water by perspective inversion: depth Z = 3000/(horizon − y). The wave physics stays
exactly 2D — same sin(kR − ωt) — only the viewpoint changed. Circular ripples become
flattened ellipses, tighter toward the horizon, just as a standing eye sees a pond.
Skate your pointer near the horizon and feel the nonlinearity: tiny screen moves, huge
world distances.
you: X=−60 Z=120
Screen → world → physics → screen. The same in/compute/out architecture as a planetary ephemeris.
6 · Solid geometry: the cube convoy
KEITH:
A cube of side 10 at the origin, viewed from wherever I say. Then colour its visible faces
with light at a known position, while it rotates. Then ten of them, spinning on one steady
axis, moving away…
CLAUDE:
Everything runs on the four Judy Number operations: subtraction and modulus aim the
camera, a cross product builds its screen axes, one dot product culls faces
turned away, another is Lambert's law — brightness = N·L. With ten cubes the painter's
algorithm sorts far-to-near so near paint lands on top, and each cube's dot ration scales
as 1/Z² to match its screen area. Sunlight here is directional — uniform everywhere — so
the convoy stays legible right down to the last few pixels.
cubes: 0/10
Six coloured faces read the rotation for you. A new cube launches every 2.5 s; each recycles from the deep at Z = 1800.
7 · Fractals: the deepest picture from the shortest program
KEITH:
I want a fractal program written in a few lines of BASIC, with the crucial line editable.
And zoom on the mouse wheel — and the changes gradual, the clicked point gliding slowly
to the centre.
CLAUDE:
Line 60 is the whole universe — z → z² + c written in real and imaginary parts:
XN = x*x − y*y + CX : YN = 2*x*y + CY. Everything else is bookkeeping.
Each pixel asks: starting from zero and applying that line over and over, do I escape to
infinity or stay bounded? The black interior never escapes; the coloured bands record how
fast each point fled — contour lines of escape time, crowding infinitely toward the boundary.
KEITH:
Wondering if writing the whole screen from Xmin to Xmax in one double loop might beat
our random dots, which are bound to take longer…
CLAUDE:
Dead right — random darts pay the coupon-collector's tax, about 15 visits per pixel to
cover them all, and fractal pixels are expensive. The systematic sweep visits each
exactly once. And with the formula hard-wired (no editable line), the browser's compiler
fuses the loop into machine code — the whole 212,000-pixel screen repaints tens of times
a second. Scan for stills and speed; dice for shimmer. The Lab keeps both.
First the thoroughbred — fixed formula, full screen every frame.
Wheel to zoom in fine steps, click to glide there, rotate and spin at will.
Keith's green gun, G = 120 + 120*COS(n*π), zebra-stripes every contour of
the escape count:
90°zoom 1× · – ms
Zoom to ~10¹³× and the picture goes blocky, then trembles: you have reached the floor of the machine's
16-digit arithmetic — the number line, as the computer knows it, is not a continuum.
And the tinkerer's version — slower, because every iteration passes
through your editable lines, but lines 60 and 100 are yours. Ti (seconds since RUN) works
in all of them:
60 XN =: YN =
100 R =: G =: B =
Ti = 0.0 s · zoom 1× · wheel zooms, click glides
The default line breathes — COS(Ti/50) sweeps the whole family of related fractals,
returning to the true Mandelbrot every ~5 minutes. Try the Burning Ship:
YN = 2*ABS(x*y) + CY — one ABS, and the depths fill with straight-line rigging.
Cubic: XN = x*x*x - 3*x*y*y + CX, YN = 3*x*x*y - y*y*y + CY.
Rotate 90°: XN = x*x - y*y - CY, YN = 2*x*y + CX.
What the Lab taught us, in one paragraph. Two ways to spend the dice:
pick a random screen pixel and ask “what's here?” (scenes 1–5), or pick a random
point on an object and project it to the screen (scene 6) — ray-tracing's outlook
versus the graphics card's. Perspective is two lines: Z from height, X from Z. Occlusion is
an IF. Lighting is a dot product. And the whole 3D engine — camera, culling, shading —
is subtraction, modulus, dot and cross on Judy Numbers J = x + iy + jz.
And one iterated line — z² + c — holds infinite depth, until the machine's own
sixteen digits run out beneath you.