Guide
Working with a critic.
The design check is deterministic. It reads the tokens in DESIGN.md and fails when a font, a colour, a gradient or a glow drifts from them. What it cannot tell you is whether the result is any good. A page can pass every check and still look like every other page.
That part needs a critic. Not the model that built the page, and not the same conversation. A separate context that sees only the screenshots, ranks them against real work, and says what is missing.
Why a fresh context
A model that just wrote the code will defend it. It knows what it tried, it knows why the spacing is the way it is, and it will grade its own homework generously. Ask it to critique its work and you get a list of things it already decided were fine.
A critic that has never seen the code has none of that. It gets screenshots and references, and it has to judge what is on screen. That is also how a design review works between people: nobody reads the CSS first.
The setup
Every pack installs a prompt for this at .dmiu/critic.md. The loop goes:
- Build against the contract and run
npx dontmakeitugly checkuntil the report has zero errors. The critic does not run before this. There is no point asking about taste while the fonts are wrong. - Start a subagent in a fresh context. Hand it the critic prompt, the screenshot paths the report lists, and the reference previews from the pack. Nothing else: no code, no diff, no story about what was tried.
- The critic ranks the screenshots and the references together, from most to least polished, and names the three biggest gaps. Then it stops.
- The implementer applies the three gaps, runs the check again, and goes back to the critic. At most twice. Then a person looks.
Split the models. A cheap, fast one does the implementation, because most of that is moving pixels. The strongest one you have does the critique, because that is the part that needs taste. The critic never sees the code, so it can be any model with vision.
Why there is no score
The obvious version of this is a loop that runs until the critic says nine out of ten. It is also the version that burns a night of tokens on the last point, because the number was never anchored to anything. A model asked for a score gives you one; it does not give you a standard.
A ranking against real references is anchored. If the page sits below every reference, the gaps are the reasons why. If it sits between two of them, you can see what it would take to move up. Three gaps and a reason each is more useful than a number, and it ends.
What the critic does not do
- It does not block. The check is the gate; the critic is advice. The agent can finish with the critic unhappy, as long as a person has seen the result.
- It does not suggest fonts, colours or effects outside the contract. The gap is never “add a gradient”.
- It does not write code. It names what is wrong on screen and what would close it; the implementer decides how.
- It does not run inside the CLI. Your agent runs it, with whatever model you already pay for. No account, no key, no hosted service.
Where this comes from
The screenshot-only critic, the model split and the warning about score-chasing loops come from Anshu Chimala’s post on Lenny’s Newsletter, How to turn your AI into a world-class designer. The argument there is that models design blandly because the safest next token is the safest layout, and that variety and taste have to come from outside the model. The contract keeps the agent inside the lines. The critic is how it gets better within them.
Every pack ships the critic prompt. Start with one.
npx dontmakeitugly init <pack>