↖ lab

GALLERY // PAINTED WORKSPACES

Desk Paintings

The cozy desk, painted instead of CSS’d — generated with Nano Banana Pro (gemini-3-pro-image, 2K). Every scene keeps the same props: a beige CRT (badged YOUNG, rechristened COMPY 386 in round 3), the Foundation trilogy, a calculator stuck on 80085, and a mug that says “You just got LITT up!” “Dark screen” panels leave the tube blank on purpose, so live content can be composited into the glass later.

Round 10 back to close · firefly summer

Round 9’s review settled it: right cast, wrong distance — the keeper composition has been rounds 3–7’s all along, the monitor dominating the frame. So round 10 re-generates that room fresh (never editing the shipped painting), six takes in two flavors: three tethered to the v4b painting as a composition reference, three rebuilt fresh from round 3’s prompt language. Every take keeps the jewel cases and the reference-drawn fairy, swaps the window to firefly summer, and splits the palette between the room’s warm lofi amber and the green summer dark. All six came out straight-on. The fairy stayed small in five — and on the two best takes the 4K zoom caught her growing tiny dot eyes anyway. The winner gets them erased.

Firefly den · tether A
Firefly den · tether Av base candidatedark screenThe shipped v4b painting rode along as a composition reference ('repaint, don't copy'), and it shows: same camera, same posts, everything where the pipeline expects it — now with fireflies past the glass, the warm room shading into summer-night purple, and the three jewel cases dealt onto the desk's front edge. Mug print correct. The natural machine V base; its fix-up list is one garbled LCD and one secret the 4K zoom told: the fairy grew tiny dot eyes again. An erasure will take them.
Firefly den · tether B
Firefly den · tether Bdark screenSame tether, second sample — and the fairy walked out of the recess to stand front and centre with her toothpick staff, twice her brief size. Round 5's problem, faithfully reproduced. Lovely village dark outside; disqualified all the same.
Firefly den · tether C
Firefly den · tether Cdark screenThe best window of the tethers — moonlit leaves thick with fireflies, the green night pressing right up against the glass. The fairy again drifted centreward and mid-sized; the calculator invented a new number.
Firefly den · fresh A
Firefly den · fresh Adark screenNo composition reference — just round 3's close-up language rebuilt from scratch. The strongest remix: FOUNDATION stack flat like a riser, Pochita out in the open, the fairy small and winged by a calculator that actually reads 80085, big tree and hut-lights out the window. If V wants a bolder redraw instead of continuity, it's this one.
Firefly den · fresh B
Firefly den · fresh Bdark screenDeep-forest green night, a StarCraft disc out of its case, the fairy properly small at the base. One book spine gave up mid-word. The most 'lofi stream at 3am' of the six.
Firefly den · fresh C
Firefly den · fresh Cdark screenJake stopped sitting and DRAPED himself over the corner, one arm hanging down the bezel — nobody asked and he's completely right. Calculator honest, mug right, village night glowing. If this pose wins, his idle loop becomes a slow tail flick instead of leg swings.

Round 9 the machine V base hunt

Round 8’s verdict: fun universes, wrong direction — the ask was more rounds 2 and 3: the actual room, fresh vibes, generated from scratch. So round 9 is six new window-worlds on the full current cast, each a candidate base for machine V, with two reference images riding along: the gyoza fairy’s anime design sheet (the one character the model never gets right unaided) and the actual wedge-shaped Compy 386 from Homestar Runner. New desk clutter: CD jewel cases of StarCraft Brood War, Diablo II and Final Fantasy VII. Five of six landed straight-on; the fairy came out on-model in five of six. Nothing is edited in place — the winner gets its fix-up pass when V is built.

Summer storm
Summer stormdark screenFat rain on the glass, one lightning fork in the clouds. Dead straight-on, correct cast top to bottom — and the fairy is finally HER: pleated gyoza head, tiny wings, no face, drawn from the anime design sheet riding along as a reference image. The three jewel cases make their debut in the front corner.
First snow
First snowdark screenSilent midnight snowfall, rooftops going soft. The model broke the straight-on rule — the tube sits at a 3/4 angle, which disqualifies it as a base — but the stacked jewel-case spines (StarCraft Brood War / Diablo / Final Fantasy VII) are the cleanest of the set, and the fairy carries her toothpick staff.
Ember hour
Ember hourdark screenBurnt-orange sunset, telephone wires, leaves adrift. The mug's two-line print lands with LITT in red, the sticky reads right — and one desk note faithfully transcribes a stray shard of the prompt ('omeletty old ballpoint'). The model giveth.
Aurora night
Aurora nightdark screenGreen-violet ribbons over snow hills, and the banker's lamp swaps to the LEFT — the first fresh furniture arrangement in nine rounds. Fairy on-model, games piled loose, calculator honest.
Blue hour
Blue hourdark screenPre-dawn slate, a crescent going down. The second reference image earned its seat here: the case finally reads as the actual wedge-shaped Compy 386 rather than a generic CRT wearing its badge, and the jewel-case stack is legible down to the DIABLO II numeral.
Firefly summer
Firefly summerdark screenVillage night, fireflies in the garden, a disc out of its case. Also the round's cautionary tale: the fairy grew a face against direct orders, LITT forgot to be red, and two sticky notes transcribe prompt fragments. Gorgeous, and disqualified three ways.

Round 7 shipped · The Machine IV

The remaster, then the reckoning. Everything re-rendered at 4K with the halftone prompted away, and the whole cast peeled off the painting into animated cutout layers — rattles, kicks, wags, a ducking fairy. On review, all of it read as puppetry except one thing, so one thing shipped: Pochita blinks. He and the fairy moved into the recess under the monitor instead, where the lean-in view can actually see them. Striking the glass powers the tube down and rips reality itself.

Compy B, 4K remaster
Compy B, 4K remasterthe machine IV roomdark screenThe shipped room: a 5504×3072 re-render with an explicit 'NO halftone dots, NO screentone' clause — which worked, retiring the descreen filter — then a feedback pass on top: Pochita and the gyoza fairy moved into the dark recess UNDER the monitor (so lean-in actually contains them), the fairy lost her face (plain dough, as canon demands) and a size class, the books got un-distressed, and the sticky went from calligraphy to quick faded print.
Deck mirror IV
Deck mirror IVdark screenThe cyberdeck mirror at 4K — armored Compy, cyan banker's lamp, neon megacity, both peekers still under the tube. Striking the chipped glass powers the CRT down, then a WebGL pass rips the whole ROOM open onto this.
Compy B, portrait
Compy B, portraitdark screenThe phone composition. Its screen quad taught the roughest lesson of the round: the first measurement stopped at the bright window reflection painted ON the glass and shipped a desktop 13% too narrow — walk luminance profiles past reflections before trusting an edge.
The room with nobody in it
The room with nobody in itdark screenThe character-free plate: every character erased, the erase renders clipped back in through the characters' own diff masks (scripts/assemble-plates.mjs). Built for a full idle-animation pass — see the layers below — and kept as the staging ground for moving Pochita and the fairy under the monitor.

The benched layers, on a checker so the alpha shows. These were fully wired — pose patches on CSS clocks, the fairy ducking inside a clipping rect — and then reviewed honestly: frame-swap puppetry reads as puppetry. Only the blink survived into the machine. The cutouts stay here as working artifacts of the technique.

Kodama cutout layer
kodama rest cutout + head-rattle patch
Jake the Dog cutout layer
jake rest cutout + leg-kick patch
Pochita cutout layer
pochita rest cutout + blink + tail-wag patches
Gyoza fairy cutout layer
gyoza fairy one cutout, clipped — she just ducks

Round 8 six other universes

Same cast, same props, same straight-on dark-screen rule — six new visual worlds, generated fresh instead of edited. Nothing here ships; that’s the point. Same room, different painter every time.

'86 OVA cel
'86 OVA celdark screenHand-painted cel shading, airbrushed sunset through venetian blinds, film grain. The kodama and Jake hold their posts.
Ink & flat color
Ink & flat colordark screenThick confident outlines, flat mid-century palette, screen-print feel. The most poster-like of the set.
Gouache dusk
Gouache duskdark screenChunky brushstrokes, dusty pink-and-teal, wobbly soft edges. Pochita melts into the shadow under the tube.
Rain against the glass
Rain against the glassdark screenThe room lit only by the green lamp and neon bleed; rain streaking the window. The moodiest take — and the fairy stands right out in the open for once.
Watercolor morning
Watercolor morningdark screenLow sun, dust motes, pencil under loose washes. The gentlest of the six.
The felt diorama
The felt dioramadark screenEverything as handmade plush: stitched spines, felt CRT, button-eyed cast, tilt-shift depth. Absurd and somehow completely coherent.

Round 6 The Machine III

The previous shipped room, now remastered by round 7. A tiny fairy, a clean sticky note, a mug whose print bends around the cylinder — and no more halftone, courtesy of an adaptive notch filter. One companion moved: Pochita blinked. Everything else was paint.

Compy B, descreened
Compy B, descreenedthe machine III roomdark screenThe gyoza fairy shrinks to a cameo, peeking out of the wedge the leaning SECOND FOUNDATION makes; the sticky note drops its 'pwd:'; the mug print is wrapped around the cylinder for real. Then the whole painting goes through an adaptive notch filter that lifts the model's halftone screen off it.
Deck mirror III
Deck mirror IIIdark screenThe corrected room re-mirrored: armored black Compy, neon megacity, cyan lamp, everyone still at their posts — including the fairy, still the size of a dumpling. Strike the glass and the room swaps to this.
Compy B, portrait
Compy B, portraitdark screenThe phone composition, second cut: the top FOUNDATION no longer has a torn cover with another book under it, and the fairy peeks around the monitor's base instead of sprawling across the books.

Round 5 the first feedback pass

Round 4 under a magnifying glass: an accurate gyoza fairy (painted from the official design), a deterministic mug, a legible 80085, and a first 9:16 portrait. This round also animated the kodama’s head and Jake’s legs. Both read as puppetry and were cut.

Compy B, alive
Compy B, alivedark screenThe first feedback pass: gyoza fairy redrawn from the official anime design, calculator legible, painted toad out (a real one moved in at runtime) — and after the model typeset 'LITT' / 'UP!' on separate rows three generations running, the mug print was blanked and set in SVG. Superseded by round 6.
Compy B, portrait I
Compy B, portrait Idark screenFirst phone composition: the monitor riding a riser of stacked FOUNDATION paperbacks, the banker's lamp peeking over its top edge. Everything right except the fairy and the top book's cover.

Round 4 Compy B, alive

Take B won on palette, so round 4 edits it piecemeal instead of re-rolling: new cast members, a canon mug, a password you can actually read — plus a full cyberdeck mirror of the room.

Compy B, edited
Compy B, editeddark screenFour surgical edits on take B: the Suits mug, a password sticky note — omelette du fromage — a gyoza fairy in the books, and Hypnotoad behind the lamp. The point of the round was to stop re-rolling and start editing.
Compy B, deck mirror
Compy B, deck mirrordark screenFirst take of the cyberpunk mirror: armored black Compy, neon megacity, everyone still at their posts.

Round 3 the pick, pushed in close · COMPY 386

Lofi study beats won round 2, so round 3 leans in: the monitor dominates the frame, the bezel now reads COMPY 386 (pour one out for Strong Bad’s), kodama and Jake sit on top of the case — and the third panel re-composes take A to 9:16 for phones, using the landscape as an image reference.

Compy close-up · A
Compy close-up · Aportrait refdark screenThe pick, pushed in tight: COMPY 386 on the bezel, kodama and Jake up top, everything shoulder-to-shoulder at the base.
Compy close-up · B
Compy close-up · Bdark screenSecond take of the same brief — a touch more room around the tube, glowing kodama, bigger nameplate.
Compy, portrait
Compy, portraitdark screenThe mobile answer: take A handed back to the model as an image reference and re-composed to 9:16 — same room, same friends, moon window up top.

Round 2 straight-on framing · fan cameos

Six vibes, one rule from round 1: the CRT faces the viewer dead-on. Cameos in every scene — Jake the Dog, a kodama, Pochita.

Neon rain II
Neon rain IIdark screenThe winner's framing, now with the full cast — Jake on the shelf, Pochita front-left, kodama by the sticky notes.
Lofi study beats II
Lofi study beats IIdark screenFlat lofi-girl linework, banker's lamp, Jake perched on the Foundation stack, kodama on the sill.
Ghibli-ish morning
Ghibli-ish morningdark screenWatercolor countryside, laundry on the line, the kodama exactly where a kodama belongs.
'97 bedroom
'97 bedroomdark screenWood panelling, a station wagon at the curb — and the streetlight and hoop reflected in the tube.
Cyber den
Cyber dendark screenA megacity out the window; the Sprawl's cousin. Pochita guards the cables.
Golden dawn
Golden dawndark screenPastel sunrise and sun rays; the softest of the set.

Round 1 three styles × two screens

First contact: lofi, gouache and neon-rain takes, each painted twice — once with the childhood photo playing on the tube, once dark. Companions here are original stand-ins.

Lofi study beats
Lofi study beatsphoto on tubeThe washing-bike photo playing on the tube, scanlines and all — original stand-in companions.
Lofi study beats
Lofi study beatsdark screenSame room with the tube left dark, ready for real content to be composited in.
Gouache storybook
Gouache storybookphoto on tubeHand-painted picture-book take; brushy, earthy, the photo glowing warm in the dusk.
Gouache storybook
Gouache storybookdark screenThe storybook desk at rest — moon over the rooftops, screen waiting.
Neon night rain
Neon night rainphoto on tubeTeal-and-magenta city rain against the warm lamp; the photo holds up on the glass.
Neon night rain
Neon night rainframing pickdark screenThe one that set the rule: a dead straight-on CRT, its screen a clean dark rectangle. Round 2 locks this framing.

Notes how all of this was actually made

Every image here came out of gemini-3-pro-image (“Nano Banana Pro”), driven by scripts/gen-desk.mjs — a plain generateContent POST with a text part and zero or more reference images. Rounds 1–6 rendered at 2K (~$0.13, 25–40s apiece); round 7 asks for imageSize: "4K" and gets 5504×3072 (~$0.24, 40–90s). Everything the model wouldn’t do, five other scripts do. Open a section.

4K, and the halftone fix was askingv4 · gen-desk.mjs

Two quality complaints drove round 7: the rooms read fuzzy near 1:1 on retina glass, and the baked-in screentone needed a custom notch filter to remove. Both fixes turned out to be embarrassingly direct. The fuzz: the 2K masters were being upscaled by big displays, so round 7 re-renders at 4K (the API accepts imageSize: "4K", uppercase K — and has been caught silently ignoring it, so the script’s callers verify the returned dimensions). The dots: one clause in the remaster prompt —

the no-halftone clause…but with finer, crisper painterly detail everywhere: confident clean brushwork, sharp edges where the painting has edges, smooth continuous paint elsewhere. NO halftone dots, NO screentone, NO dither or print texture anywhere — the surface is smooth digital paint.

— and the screentone simply isn’t painted. A 2× zoom on any flat region comes back smooth, the descreen filter retired undefeated, and the diff-based sprite pipeline got dramatically easier (no more drifting carrier phase lighting up 30% of every diff). The remaster is a re-render of the descreened v3 room used as a reference image, so the composition survived within a quarter percent — the screen quad moved from (30.09, 23.24) to (30.11, 23.24).

Bonus: the clean 4K paint compresses absurdly well. The shipped 3520px-wide webp weighs 259 KB — smaller than the 2200px jpeg it replaces.

Characters as layersv4 · assemble-plates.mjs

Round 7’s big idea: stop asking the model to re-paint a character mid-pose into the room, and instead take the characters off the room. Each one gets a zoomed crop-edit in the one phrasing the model always obeys — an erasure (“REMOVE the small yellow dog… paint the casing and the night window that were behind him”). The erase renders reconstruct what was behind beautifully: Jake’s lamp stem and hanging pull-chain came back intact, Pochita’s spine text continued correctly on the second try.

Pasting those renders back as whole rectangles failed, though: every re-render drifts its color grade a little, and on a flat night sky that reads as a hard blue box — one paste clipped the moon’s halo. The fix is to clip each paste to the character’s own diff mask (threshold, opening by reconstruction, dilate, feather — the sprite recipe): the plate stays pixel-identical to the painting everywhere except under the character outline, and whatever tone drift remains hides exactly beneath the character’s rest cutout, which is cut from the same diff.

The cast then returns as webp layers: a rest cutout per character (diff of painting vs empty plate — the whole character, alpha feathered) plus pose patches (diff of a pose re-render vs the painting — just what moved). Patches ride CSS clocks on top of the rest layers: two wag bursts and a blink-single-then-double for Pochita, lazy kicks for Jake, a quick stilted rattle for the kodama. The fairy needed no frames at all — her cutout slides down inside an overflow: hidden rect whose bottom edge is exactly where the books start occluding her, so she just… ducks.

The verdict (v4b): reviewed on the real machine, every idle loop except the blink read as puppetry — two poses swapping is a flipbook with too few pages, however clean the masks. So the layers were benched, the characters were painted back in, and the round’s real win got kept instead: Pochita and the fairy were moved — erased from their old spots via the plates and re-added peeking out of the dark recess under the monitor, where both orientations can actually see them. One blink patch ships. The erase→plate→cutout machinery earned its keep as an editing tool, not an animation rig.

The reality ripv4 · RealityRip.tsx

v3 swapped worlds with a screen-space glitch. v4 treats the whole room as the screen: both paintings become WebGL textures and a fragment shader plays one of three warps from the exact point where you struck the glass. RIP ripples the room outward (a damped sine on the distance field, RGB sampled at three phase offsets), then tears it open along a seam perturbed by fbm noise — the far world shows through the widening tear behind a hot rim, then settles flat. SHOCK is a single chromatic shockwave; MELT drops the room in 68 lagged strips, Doom-style.

The choreography contract is what makes it seamless: the DOM keeps showing the old world underneath, the canvas mounts transparent (no black flash while textures load), and the shader’s final frame is a plain cover-fit render of the destination — so the DOM swap at the end changes nothing visible. The cozy-side texture is composited on the fly from the empty plate plus every rest cutout, so nobody vanishes mid-rip. Cover-fit math in the shader mirrors the CSS; reduced-motion users skip straight to the swap; the v3 glitch survives as a bar option.

The animation researchv4 · what else was on the table

The brief asked: could the characters be generated some other way so they can really animate? The survey, for the record. Video generation — Veo 3.1 does image-to-video through the same Gemini API key (Lite at ~$0.03–0.05/s, Fast at ~$0.15/s, 8-second clips); Runway, Kling and Pika are the same idea on other stacks. Great for clips, wrong for this: you get 720p+ video of the whole scene re-interpreted, camera and paint included, and extracting a loopable, alpha-matted, style-locked sprite out of that is harder than the problem it solves.

Cutout tools — rembg (with its isnet-anime model) and BiRefNet are the standard background removers, and for a character on a plain ground they’re excellent. But they guess a matte from appearance. The diff-alpha approach here gets the matte from evidence: the same room rendered with and without the character differs in exactly the character’s pixels, registration-perfect, in-style, free.

So the shipped mechanism is: pose variants via the image model’s keep-clause edits (one thing changes per render), masks via morphological diff, playback via CSS clocks — plus the clip-rect trick for the fairy’s duck, which is pure geometry. Frame-swap puppetry at 2–3 poses per character reads as an idle loop; the earlier attempt to swap whole characters between renders shimmered (bodies drift between generations), which is why the patches are minimal diffs against the very painting they sit on.

The reflection that ate 13% of the screenv4b · measure-quad

The portrait remaster shipped with the live desktop visibly narrower than the drawn glass, and the cause took a magnifying glass to find: the quad-measuring walk stops when the luminance turns “bright,” and the painting has a bright window reflection painted ON the glass, right of centre. The walk hit the reflection’s highlight, called it the bezel, and reported a screen 48.6% wide when the true dark glass runs 61.2% — so the desktop rendered 13% too narrow.

The fix is to read full luminance profiles through the screen instead of trusting a single threshold walk: glass sits at 35–65, the reflection ramps to ~185 and falls back to 53, and only then comes the true bezel at 160–205 behind an ink line. Same story on the deck mirror, whose right edge had been called 12% early. Every quad now gets a red-rectangle render over the painting before it ships.

Portrait lean-in still cuts the painting into three slices with only the tube stretching — and now that Pochita and the fairy live in the recess directly under the screen, the bottom slice shows them immediately: characters up top, readable desktop, peekers below. No skipping required.

The promptsgen-desk.mjs

Six rounds, each one narrowing. Round 1 explored style. Round 2 locked the rule that made the whole project possible — the CRT must face the viewer dead-on, so its screen is an undistorted rectangle a live desktop can be composited into:

round 2 · the framing ruleThe monitor faces the viewer PERFECTLY straight-on and level, near the centre of the composition: its screen is an undistorted upright rectangle parallel to the picture plane, no perspective tilt, no rotation — as if photographed head-on at screen height. The CRT is switched on but its screen is blank dark glass with only a faint window reflection and a subtle sheen — no picture on the screen.

Rounds 3–6 stopped generating and started editing. A single sentence — call it the keep-clause — front-loads every edit prompt, and the changes are numbered after it:

the keep-clauseReproduce the attached image EXACTLY — same composition, same camera, same objects, same characters, same lighting, same lofi illustration style, same colors — with ONLY these changes: … Everything else stays pixel-identical to the attached image.

The cyberdeck mirror is the same room re-lit, generated from the finished cozy painting so the screen lands in the same rectangle:

the deck mirrorTransform the attached cozy scene into its cyberpunk mirror-world version, keeping the SAME room, same camera angle, same composition and same object placement. The beige COMPY 386 monitor becomes a matte-black military cyberdeck CRT terminal … but its glass screen stays EXACTLY the same size and position in the frame. All the little companions stay in their exact same spots, at their exact same sizes, in their exact same poses — just re-lit by the neon.
What the model refuses to docrops.mjs

There’s a sharp line through what a whole-image edit will obey. Erasing works every time: remove the toad, remove the duplicate fairy, remove all print from the mug. Retypesetting never works. Asked to move “UP!” up a line, the model just hands back the original glyphs — three separate generations, including one on a zoomed crop of nothing but the mug. The sticky note did the same thing: told to drop its pwd: label, it reproduced it faithfully.

The trick is to hand it a zoomed square crop with exactly one instruction, phrased as an erasure. crops.mjs cut takes the square out; crops.mjs paste puts the edited one back through a feathered alpha (a white rect inset and blurred), so the middle is the model’s new pixels and the rim melts into the original. Gemini returns a 512² crop as 2048², so the paste always resizes.

It also cuts the other way. The sticky-note crop happened to contain the calculator, which came back with a scribble across its LCD, so the original calculator gets pasted straight back over it.

The mug: three refusals, then geometrypatch-mug.mjs

After the model wouldn’t fit LITT UP! on one line, the mug was blanked (an erasure — it obliged instantly) and the print typeset by hand. Not painted on flat, though: wrapped.

Model the mug as a vertical cylinder seen slightly from above. A horizontal circle on it projects to an ellipse with semi-axes (a, b), measured off the blank mug’s own rim and base — a = 127px, b = 26px in the landscape painting. A point at angle θ from dead-centre lands at

the wrapX = cx + a·sin θ Y = ytop + h + b·cos θ

So the print sags toward the middle (that b·cos θ peaks at θ=0) and compresses toward the rim (dX/dθ = a·cos θ). Both fall out of inverting that map per output pixel and sampling a flat text strip whose x axis is θ, 3×3 samples off a 4× strip so the squeezed edge glyphs stay clean. Multiply-blend it on and the painted ceramic shading shows through the ink. The line ends up ~10px higher than its middle — exactly the sag of the mug’s own base.

The halftone nobody asked fordescreen.mjs

This lofi style comes with a fine screentone baked in: a checkerboard of dots on a diagonal lattice. On these gallery cards it’s invisible. Behind The Machine III the room is drawn near 1:1 on a retina display, and it reads as a grid laid over everything but the CRT glass.

The obvious fix — average each pixel over its cell in a 5×5 lattice and subtract — fails completely. A 2D DFT on a flat patch says why: the carrier period is 5.12px, not 5.00, so the dots slide out of phase with any integer pixel grid. Measured, the phase-average cancels to ~0.25 grey levels while the local dots swing ±18.

What works is an adaptive notch — complex demodulation, the standard way to pull a narrowband carrier with drifting amplitude out of a signal. Find the carrier, lowpass img · e^(-i2πk·x) to recover its slowly-varying complex amplitude, then subtract that band back out. The lowpass is a tent, so the notch is narrow: the dots die, the linework (broadband) lives. A dot lattice rings at every reciprocal-lattice point m·k₁ + n·k₂, so all of those get notched too.

The carrier is found coarsely by DFT on the flattest 256² window and then refined on the whole image from the phase ramp of the demodulated signal — a wrong k shows up as a linear phase drift, so correct and repeat. Tuning the notch width is a straight trade: at radius 6 the dot band drops 87% while broadband detail (book-spine linework) loses 2%.

Making a painting blinkmake-sprites.mjs

Pochita’s blink is a second whole painting, generated from the first, in which only his eyes changed. Overlaying a rectangle cut from it doesn’t work — the model repaints everything a little, so the books behind him visibly shift each time he blinks.

Instead the frame is masked down to only the pixels that actually changed: channel-max diff against the base, threshold, then an opening by reconstruction (erode to find seed blobs, regrow each seed inside the raw threshold) — a plain morphological open eats thin real strokes along with the noise, reconstruction doesn’t, because noise has no surviving seed. Dilate, feather, bbox, bake the mask into the webp’s alpha. The blink ships as 3.4 KB.

This only works on descreened images. Against the raw paintings the drifting halftone lights up ~30% of any region with diffs up to 247 — the change is invisible underneath it.

Two other bits of morphology went in the bin along the way: sharp’s chained .blur().threshold() calls don’t execute in sequence (they’re pipeline parameters — the later call silently overrides the earlier), and .blur() on a large sparse single-channel raw buffer returned all zeros. Everything here is hand-rolled separable min/max filters.

Phones: two paintings, three slicesMachine3.tsx

A 16:9 painting on a phone is a stripe. So portrait gets its own painting, recomposed vertically: the monitor rides a riser of stacked FOUNDATION paperbacks, the banker’s lamp peeks over its top edge, moon window above. Each orientation also has its own deck mirror and its own blink sprite, since every rect is in painting-percent coordinates.

The screen rectangle can’t be eyeballed — a live desktop sits in it. measure-quad.mjs finds it from the pixels by walking outward from a seed until the luminance stops being dark glass. Two thresholds, because the two edges differ: left and right run into the bright bezel face, so a high threshold there walks straight past the window reflection painted on the glass; top and bottom meet the bezel’s inner lip, which is only mid-grey itself, so those need a low one or the walk leaps the lip and lands on the dark outer trim 20px too far. Five parallel probes, median.

Leaning in on a phone would still leave a letterbox, so the painting is cut into three horizontal slices: the strip above the tube, the tube itself, and the desk below. Only the middle one stretches. The outer two are hard-capped (22% and 14% of the viewport) so the screen wins the height, and the top slice is anchored to its bottom edge — what survives the cap is the strip right above the tube, so the kodama and Jake stay perched on it. The live desktop inside never distorts; it keeps a uniform pixel scale and simply gains logical height.

Things that were built and then cutthe honest part

The kodama’s clockwork head. A circular crop of the painting itself, positioned over its own head so rotating it turned the face like clock hands with no seam — 12s of ticked wind-up, spring release, damped wobble, all in CSS keyframes, no asset. It was technically the nicest thing here. It looked like a puppet.

Jake’s swinging legs. Three generations in a row swung the same leg no matter how the prompt described the other one, so the cycle became rest → low swing → high swing → rest. Also cut.

Hypnotoad. The real broadcast toad, a transparent 15-frame gif from the show, looping under a still frame that lifted for ~2.6s every 11s so he only spasmed at long intervals. He never appeared on phones and he never belonged in this room.

The running cracks. The chipped corner still generates its radial hairlines; they’re simply not drawn. A clean bite reads as a chip. Hairlines shooting across the desktop read as a broken monitor.

44 paintings (+ frame variants, erase plates, mug blanks and crop patches) · gemini-3-pro-image @ 2K, remastered @ 4K · full-size originals in art/desk-explorations/ · pipeline in scripts/ · they boot Phillip XP as The Machine II ↗, The Machine III ↗ and The Machine IV ↗