Detail 15 · AI
Directing an AI agent
How this site was built with an AI coding agent: what I decided, what it did, and how I kept the craft mine. 6 minutes, 1 demo.
Proximity
Letters that swell as the cursor passes.
No rules: what an agent builds unprompted
01 · The idea
The taste is mine
This site was built with an AI coding agent. It wrote most of the code. What it couldn’t do was decide what the site should be: what each part should feel like, and what to throw away. That part stayed with me, and this detail is about how.
An agent left to itself builds the average of everything it has seen. Ask for a card and you get a card: system type, a bright blue, a rounded box with a shadow. Fine, and like every other site. The work is in steering it somewhere specific, and keeping it there for months.
02 · The rules
A design system the agent reads
The project has a rules file the agent reads at the start of every session. It’s a design system written as sentences: the ember rule, pencil instead of boxes, nothing pops, which font does which job, what to check before saying something is done. Below is one card, as an agent builds it unprompted, with those rules switched on one at a time.
Proximity
Letters that swell as the cursor passes.
No rules: what an agent builds unprompted
## Design rules
- **Ember rule:** the accent (`--color-accent`, #d2633d) is only for what matters: the active state, the thing being studied, key annotations. Structure stays white pencil (low-opacity white strokes).
- **Pencil, not boxes:** frames, dividers, rulers, highlights and boxes are hand-drawn SVG (`ui/pencilRuler.js`, `wireframe/sketch.js`, `ui/PencilBox.jsx`, `craft/SketchedFrame.jsx`). Seed randomness (`seedFrom(text)`) so a sketch is the same on every render.
- **Nothing pops:** anything a control adds or removes animates in and out (springs, wipes, blur fades). Use `AnimatePresence`, motion values and springs.
- **Text that changes morphs:** anywhere in the app a piece of text swaps for another (a label, a status, a title, a counter), render it with `ui/TextMorph`: shared letters slide to their new places, the rest blur out and in. Never swap text instantly. If it might not fit one line, split it into lines that each morph.
- **You can sketch on the page:** with a mouse, a drag on empty space draws in pencil (`layout/SketchLayer.jsx`, with the sound of pencil on paper in `layout/pencilSound.js`); a stroke stays a second, fades and is never kept. Words, links, controls, anything with a `role` or `tabindex`, and `figure`s (demos, code) never draw; mark anything else that must never draw with `data-no-sketch`. The system cursor stays (a custom one was tried and dropped; chalk was tried before pencil).
- **Micro-interactions on every control:** hover, focus-visible and tap states, the same spring feel across controls.
- **Springs by job:** every animated change uses a spring from `ui/springs.js`, picked by what it's doing: `SPRING.press` (controls), `swap` (content changing in place), `morph` (shapes changing or travelling), `playful` (a flourish meant to be noticed), `glide` (values, bars, progress). Don't write a new spring literal; only springs that follow an input (pointer, scroll) and the per-letter text springs are tuned locally. Detail 04 ("How things move") teaches this.
- **Restraint:** at most ~3 annotations (underline / circle) per lesson; one quiet label, a title, one line of summary at the top of a page.The rules are short on purpose. Each one is a decision I’d otherwise make again in every session, and each says why, so it can be applied to things the rule never mentions. “The accent is only for what matters” covers a hundred cases that “make the button orange” doesn’t.
03 · The loop
Every correction becomes a rule
Work goes round the same loop: a short brief, the agent builds, I check it in the browser, I correct it. The last step is the one that matters over months. When a correction would apply again, it goes into the rules, so it’s the last time I have to make it.
1.Brief
What it should feel like and why, often a screenshot drawn over. Short, and about the result, not the code.
why?2.Build
The agent writes it, reading the project's rules first, and reusing the kit that's already there.
CLAUDE.md3.Check
In the browser, on a phone, a tablet and a desktop, slowed down. Anything not checked is said out loud.
375 · 820 · 15364.Correct
Keep it, change it, or throw it out. A lot gets thrown out.
5.Write the rule
If a correction would apply again, it goes into the rules, so it's the last time it's needed.
+ 1 line
“Nothing pops” is one of those. Early demos had switches that made things appear and disappear instantly, and I asked for them to animate instead. Now it’s a rule: anything a control adds or removes animates in and out, and it no longer needs saying.
The same goes for how the agent works, not only how the site looks. It doesn’t commit; I do, after reading the change. It checks its work in the browser, and when it couldn’t check something, it has to say so rather than call it done.
04 · What stays mine
Deciding, and saying no
The agent is fast at making things. So the scarce part is deciding which of them should exist. Some examples from this site:
- The résumé island first had three ways to open the résumé: a curtain, a sketch, and the grow. All three were built and tried. I kept the grow; the other two were deleted.
- This case study was first planned as 33 lessons. I cut it to the details particular to this site, and then cut one more when two overlapped, which is how it got to 13. It’s 15 now: the design system needed its motion half, and the case study’s page became a book that earned a detail of its own.
- The copy here is drafted with the agent, then read through and rewritten in my own words before it’s final.
The running to-do list lives in the repo, where both of us read it. The agent ticks off what it finishes and adds what it finds; I decide the order. That’s most of directing it: keeping the next step small and clear, and checking each one before the next.
05 · Decisions
Why it’s built this way
Rules, not reminders
A decision written down once is applied in every session after it. A decision only said once is forgotten by the next one.
Say why
A rule with its reason covers cases it never names. A rule without one gets followed to the letter, and no further.
Checked, or said so
Done means seen working in the browser. Anything that wasn’t checked is named, never assumed.
I commit
Nothing goes into the history without being read first. The agent writes; I sign it.
06 · Takeaways
What to keep
- An agent builds the average by default: the craft is in steering it somewhere specific, and keeping it there.
- Write your design decisions as short rules with reasons, where the agent reads them every time.
- Turn every repeated correction into a rule, check everything in the browser, and keep the deciding for yourself.
Every detail in the book was built this way. Pick any detail and look for the rules at work.