On the machine

Gone in 60 Frames

Nobody talks about what frontier-model UI demos cost your machine. This time, it's personal.

toolsagentic-codingwslgithub-actionsengineering

Every week there is a new wave of UI demos made with the latest frontier model. Not the 872,632nd SaaS dashboard. The creative ones: a photorealistic water surface with ripples and caustics, in a single HTML file, from Opus 5.5. A viewer’s bizarre solar-system theory turned into an interactive 3D model by Fable 5.1, live on a stream. A Pacific Rim mecha battle, playable, one-shotted by GPT-6 Astra. A Star Wars pod-racer in voxels from a one-line prompt to Kimi K3. They look effortless, and the post always credits the model.

Three things never make it into the post.

The prompt. The brief for my next Lab piece, a cartoon map of Bengaluru, is 3,273 words long. It sits on a 29,000-word fact file, a 117-row register of places, and 71 reference photographs, before a single line is drawn.

The scaffolding. Project rules, QA skills, a seek contract so every frame can be reproduced, a motion checker, a log of every review round. The Gupta Empire piece went through forty-nine rounds of QA for four minutes of scrolling. And the tools that almost every polished piece quietly needs: an image model with a custom style for the art, a vector tracer, ImageMagick and ffmpeg for every asset and every film, real map data, and a headless browser for every single QA round.

The toll on your computer. Nobody posts the Task Manager screenshot.

The first two deserve a post of their own. This one is about the third, because goddamn, it’s personal.


What I was doing

I was working on two of my Lab experiments that move: How the Solar System Formed and The Gupta Empire, in Cut Paper. Each page showed an eight-second loop. I wanted the full film on the page, the whole three or four minutes, playable in place.

The films come from a frame-exact recorder. It seeks the piece to a frame, takes a screenshot, and pipes the picture into ffmpeg. No screen recording, no dropped frames: every frame is exactly what the piece draws at that moment.

The Solar film is 3 minutes 11 seconds at 30 frames a second. That is 5,730 frames at 1080p.

Here is the part nobody warns you about. Inside WSL, headless Chrome has no graphics card. Every WebGL frame, with sixty thousand particles and a moon being assembled from debris, is drawn by the CPU in software. My laptop managed one frame roughly every eight seconds.

5,730 frames at eight seconds each is twelve and a half hours.

”What if we ran four?”

Claude, doing the rendering, had an idea: split the Gupta film into four quarters and record them in parallel. Four times faster.

All four recorders timed out before drawing a single frame. Loading the piece takes most of a minute on its own, and four at once took longer than the recorder was willing to wait. Claude staggered the starts and tried again.

Then the terminal died. I was out, connected to the laptop from my phone over Tailscale, and the session simply stopped answering.

Two walls at once

When I got home and looked properly, the laptop had run into two walls at the same time.

Memory. WSL gets 7.6 GB of RAM. Two Solar recorders, each with a software-rendered Chrome and a video encoder, left 82 MB free. One encoder alone had grown to about a gigabyte. The first recorder froze at frame 100 and stopped moving.

Storage. The C: drive was at 100%, with 2.5 GB free. I had not been paying attention to this, because WSL hides it well. The whole Linux disk is a single file on C:, called ext4.vhdx. Mine was 115.6 GB. That file grows whenever Linux needs space, and it does not shrink on its own. When Windows runs out of room, the file cannot grow, WSL’s writes fail, and everything running inside it can fall over.

Two recorders writing video, Chrome writing caches, and a disk with nowhere left to go. That is my best guess for the terminal.

The fixes that half-worked

Inside Linux, the biggest things on the disk were caches. uv, the Python package manager, was holding 18.2 GB. Puppeteer had four old copies of Chrome, 2.4 GB. Both are safe to clear; they download again when needed.

That freed about 20 GB inside Linux, and gave exactly zero bytes back to Windows. Linux reuses freed space before growing the disk file again, which stops the bleeding. But the file on C: keeps its size until you compact it:

# In WSL: tell the disk which blocks are free
sudo fstrim -av

# In PowerShell, as administrator: stop WSL
wsl --shutdown

# Compact the disk file
diskpart
select vdisk file="...\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit

# From now on, shrink automatically
wsl --manage Ubuntu --set-sparse true

The last line is the one I wish I had known about a year ago. With sparse mode on, the disk file gives space back to Windows as Linux frees it.

Frame 500

With one recorder and some breathing room, Solar started again. Slowly, but steadily.

Then Claude, in the same session, started an unrelated design audit of this site. It built the site and took screenshots of every page in a headless browser. On the same laptop. While the recorder was running.

One frame took longer than thirty seconds, the recorder’s limit. The run aborted at frame 500 of 5,730, and nobody noticed for three hours.

Groundhog Reboot

By now the machine was barely usable. File Explorer would not open. So I restarted.

And here is the part that is nobody’s fault. I run my coding sessions under herdr, which keeps agents alive across restarts. It is a genuinely useful feature. On a normal day, you reboot and your work is exactly where you left it.

On this day, every restart brought back all eleven Claude Code sessions. Idle, but hungry: 3.6 GB of RAM and two and a half CPU cores between them, before anything had even started. Plus a recorder resuming its film. Like Bill Murray waking up to the same song, I restarted three times in an hour and got the same morning every time.

Two smaller indignities, for the record. Claude’s own pkill commands, meant to stop the background jobs, matched the shell they were running in and killed it. And for a stretch of the evening, Claude Code’s auto-mode permission checker kept failing to return a verdict, so no command could run at all.

Stop everything

The message I finally sent was short:

STOP EVERY BACKGROUND PROCESS RIGHT NOW

Everything that Claude had started went: the recorder, its Chrome, its encoder, the local web servers, the dev server. Then, instead of guessing, it looked at what was left.

What was left was not Claude’s. It was the eleven sessions. I closed the ones I did not need, one by one, and checked after each round.

Available RAMLoad (12 cores)
Two recorders running0.8 GB (82 MB free)not measured
Everything stopped, 11 sessions4.2 GB4.9
Down to 5 sessions5.5 GB0.9

Load 0.9 on twelve cores is a laptop that has stopped suffering.

Calling in a consultant

The obvious question was what to do next time, and the next time after that. I did not want the answer from the session that had just set my laptop on fire, reasoning inside a very long and very tired conversation.

So I used the pattern Anthropic describes for Claude Code: hand the research to a subagent, and keep the main conversation for decisions. The consultant was a Fable subagent, with one hard constraint in its instructions: read-only. Read the scripts, read the workflow, recommend. Do not build, render, or open a browser.

It came back two minutes later with a design:

  • A separate repo just for the films. The builds, the recorder, and a workflow, nothing else.
  • Render on GitHub Actions, never on the laptop.
  • Fingerprint each build, and put the fingerprint in the film’s address, so a stale film is obvious.
  • Render only when a piece is final. Every change to a piece syncs its copies; only “this is done” spends a render.
  • Always a short test render first, and a check that its frames match the laptop’s.

Moving the render farm

The new repo is lab-films. It contains nothing useful for almost anyone on Earth, and it is public only because public is free. :D The workflow counts the film’s frames, splits them into sixteen chunks, records each chunk on its own GitHub machine, then joins them without re-encoding and checks the frame count before publishing the film.

laptop build only lab-films git push GitHub Actions join + check 5,730 frames
Sixteen chunks, sixteen machines, one film. The laptop only builds and pushes.

GitHub’s machines draw a Solar frame in about 2.6 seconds, three times faster than my laptop, and sixteen of them work at once.

The test render, 120 frames, came back in five minutes. Were the frames the same as the laptop’s? I compared the same frame from each: a PSNR of 48.6 dB on frame 0, and 45.8 dB on frame 100. That is video-encoder noise, invisible to the eye. Same type, same disk, same particles.

Then the maths. GitHub’s free plan includes 2,000 Actions minutes a month for private repositories. A full Solar film costs about 300 of them: sixteen machines, a quarter of an hour each, plus setup. That is six or seven films a month, total, and I was already wondering whether I would need a different host.

Then I read the rest of the billing page. Standard runners are free in public repositories. And the builds in that repo are the same static files this site serves publicly anyway. So lab-films is now public, and the render farm costs nothing.

Writing it down

The last step was making sure the next session does not repeat any of this. Claude Code has three places for that, and I used all three:

  • A memory note, with the facts: where each copy of a piece lives, what a render costs, which record wins.
  • A skill, lab-release, with the procedure: what happens on every change, what happens only when a piece is final, and the rules nobody gets to skip.
  • A user-level rule, so it applies in every project, not just this site: no film renders on the laptop, no batches of screenshots, at most one browser at a time, never alongside a build. Ask before anything long. And the last line, which I wrote with feeling:

If the owner says the machine is slow, stop every background job you started, immediately, and report what you stopped.

After

The laptop is quiet. File Explorer opens. The Solar film rendered on sixteen machines I will never see, while I wrote this post.

It took 47 minutes, not the twenty I had been promised. The chunks are not equal. Twelve seconds of the Moon’s giant impact, with two planets deforming into each other, took 44 minutes. The twelve seconds right after it, the giant planets settling, took 11. In total that was 363 machine-minutes, which is exactly the kind of number you want to be spending on someone else’s computer. All 5,730 frames arrived, checked and joined.

The demo is what people post. Under it sit a prompt nobody reads, scaffolding nobody sees, and a machine nobody asks about. Mine asked, loudly, three times in an hour. Next time, the frames are gone to someone else’s computer.

If you found this useful, or have opinions, I would love to hear them. EmailLinkedIn