Skip to content

Documentation Improve a template's design

Improve a template's design

Polish a Designer template with a critic, a developer and a blind reviewer — from your coding agent or from the terminal.

designer-improve takes a template that is already good and makes it ship-quality. It does not ask one AI to "make it nicer" over and over. It runs a small design team against the real rendered page:

critic → developer → screenshot → blind reviewer → keep or revert → repeat

It can also change the design first — a little, a fair amount or a lot — and then polish the result: see Change the design first.

  • The critic only looks. It returns up to five concrete issues — what is wrong, where, and what to change — and never writes code.
  • The developer gets those issues and nothing else. It makes the smallest change that fixes them.
  • The reviewer compares two screenshots labelled X and Y without being told which is newer, and says which is better.
  • Only a verdict of better is kept, as a commit. Anything else is saved as a patch and undone.

Each role is a separate, fresh AI session, so the one that wrote a change never grades it. Everything else — screenshots, measurements, diffs, checks, commits — is done by a script, polish.mjs, that never judges a design.

Before you start

You need:

  • Node 18 or newer, Python 3 and git.
  • A template folder that is its own git repository, with nothing uncommitted. Accepted changes become commits on a new polish/<date> branch; your main branch is not touched until you merge.
  • A running preview of the template. Designer Studio's local previewer serves a template folder at /template/<slug> when the app's .env has STUDIO_TEMPLATE_PREVIEW_PATH pointing at your templates folder.
  • A coding agent on the command line, signed in: Claude Code (claude) or Codex (codex). This is what plays the three roles.

Install the screenshot browser once:

P=.claude/skills/designer-improve/scripts/polish.mjs
node $P setup

Tell the tool where your templates and preview are. Either set environment variables:

export DESIGNER_TEMPLATES=~/code/my-templates
export DESIGNER_PREVIEW_URL="http://myapp.test/template/{slug}"

or put them in <templates>/.polish/config.json, which the whole team can share:

{
  "previewUrl": "http://myapp.test/template/{slug}",
  "authorMatch": "acme"
}

authorMatch is optional: when set, a run refuses to start unless the template repository's git email matches it. Without DESIGNER_TEMPLATES, the tool looks for a templates folder where you are standing.

Run it from your agent

In Claude Code, the skill is a slash command:

/designer-improve beacon
/designer-improve beacon header hero footer
/designer-improve http://myapp.test/template/beacon --desktop-only
/designer-improve beacon --change medium

In Codex, skills are called by name rather than with a slash:

$designer-improve beacon header hero footer

The first word is the template — its folder name or its preview address. Any further words limit the run to those parts: header, hero, footer, or a section's name such as pricing-teaser. With none, it reviews the page as a whole first, then works header → hero → footer, then every other section from the lowest score up, then does it all again at phone width. --desktop-only skips the phone pass.

--change small, medium or large changes the design before polishing it — see Change the design first. Without it, nothing is redesigned.

It runs unattended and ends by handing you a before-and-after page and one question: would you pick After over Before? Nothing is merged until you say so.

Change the design first

By default the loop only refines what is there: the critic may not redesign, the developer makes the smallest fix, and the reviewer does not reward difference. When you like a template but want it moved, add --change:

Level What changes A visitor would say
none (default) Nothing is redesigned. Polish only.
small One to a third of the sections, one or two moves each: an element added, retired, moved or restyled. Compositions stay. "The same design, adjusted."
medium A third to three quarters of the sections, three to five moves each. A section's layout may change. "The same site — that section was redesigned."
large Nearly every section, five to eight moves each, including a new layout. "A new layout for the same brand."

A change pass runs before the polish loop, with one more role. A designer looks at the page and writes a plan — one idea and the moves that serve it, each an add, remove, move, restyle or recompose. It may draw on any other design skills you have installed, for ideas only. A developer builds the whole plan. The reviewer is still blind, and is told even less than usual — not the plan, not the level — and answers two things: which design is better, and how different the two read (none, small, medium or large). A change is kept when it is no worse and reads as the level you asked for; it is undone when it is worse, when it overshoots by two levels, or when it changes too little and gains nothing. Each section gets two tries. Then the polish loop refines the new design as if it had always been there.

At every level the brand stays: the palette, the fonts, the copy voice, the list of sections and their order. So does the template's data — "remove" never deletes a field a site owner could have filled in; it puts the element behind a toggle that defaults to off, and "add" creates a new field with a default.

Named parts are changed directly: /designer-improve beacon hero pricing --change large redesigns those two and polishes them.

Run it from the terminal

The same loop, one command at a time, using a fresh CLI process for each role. This is an alternative to the dedicated Codex skill’s native subagent workflow. The terminal commands below use the CLI helper in .claude/skills/.

P=.claude/skills/designer-improve/scripts/polish.mjs

# 1. Open a run: branches the template repo and takes the first screenshots
node $P start beacon

# 2. Ask a critic to look at one part of the page
node $P role beacon critic hero --engine codex --effort high

# 3. Carry out one full iteration on it:
#    developer → screenshots → diff → blind reviewer → keep or revert
node $P iterate beacon hero --engine codex

# 4. See where things stand, and whether to go again
node $P status beacon

To change the design first, open the run with a level and use the designer in place of the critic:

node $P start beacon --change medium
node $P role beacon designer page --engine codex       # which sections change, and a direction for each
node $P role beacon designer pricing --engine codex    # the plan for one of them
node $P iterate beacon pricing --mode change --engine codex
node $P status beacon                                   # landed · go again · stop, per section

Repeat steps 2 and 3 while status says continue. Move to the next part of the page when it says done or stop. For the phone layout, add --width 390 to both commands.

When you are finished:

node $P report beacon --inline      # one self-contained before/after page you can send to anyone
node $P finish beacon --merge       # or --keep-branch, or --discard

finish --merge fast-forwards your original branch. It never pushes.

Choosing who plays each role

Option What it does
--engine codex or --engine claude Which agent CLI plays the role. Set POLISH_ENGINE to make one the default.
--review-engine claude On iterate: let a different AI judge than the one that made the change. A reviewer from another model family is less inclined to like its own work.
--model <name> Pass a specific model to the agent CLI.
--effort low|medium|high Codex reasoning effort. Critics and reviewers find more at high.
--mode change On iterate and role … developer: build the section's change plan instead of a critic's issues.
--change small|medium|large On start: the level for the run. On role … designer: a different level for that one plan.
--width 390 Work on the phone layout. The desktop layout is then required to stay pixel-identical.
--trailer "Co-Authored-By: …" On iterate: a line appended to each commit message. POLISH_TRAILER sets a default.

Critics and reviewers run in a read-only sandbox with the screenshots attached; they cannot change a file. A developer may write inside the template folder and nowhere else. The script — not the developer — then runs the checks and takes the new screenshots.

What is checked before a change is kept

A reviewer only sees pixels, so several things are verified mechanically on every accept:

  • A blind review said "better." Without one on record, accept refuses. (In a change pass: "no worse, and as different as was asked".) The exception is a change that is invisible by design — a larger tap area, for example — which is accepted only if not one pixel changed at any width and a measured problem count went down (--mechanical).
  • The template lint passes with zero findings, the page does not scroll sideways, and the browser reports no new console or network errors.
  • The template's data is intact. In a Designer template every heading, link, image and list is a field a site owner can edit. A hard-coded string looks identical to the field it replaced, so the tool compares the template's bindings before and after: every field and collection value that was rendered is still rendered, no field or collection key was removed, no default text was pasted into the markup, and no toggle lost the element it switches.
  • Nothing else moved. Every section is pixel-compared at every width. A change in a section nobody asked to change is shown to the reviewer as well.

Every command

Command What it does
setup Installs Playwright and its browser into <templates>/.polish/.
start <slug> [--change small|medium|large] Refuses a repository with uncommitted changes. Creates the polish/<date> branch, takes the first screenshots at 1440 and 390 pixels wide, and measures how much the page changes between two identical captures so animation is not mistaken for a design change. Options: --url, --page /pricing, --widths 1440,390, --settle 1500.
role <slug> critic|designer|developer|reviewer [<part>] --engine … Runs one role as a fresh, sandboxed agent process and files its result. A designer plans a change; it needs a change level.
iterate <slug> <part> --engine … One whole iteration, as in step 3 above. Needs a critique on record — or, with --mode change, a change plan.
status <slug> Scores so far for each part of the page and width, and whether to continue.
report <slug> [--inline] Writes improvements.html: every kept change with the issues it answered and a draggable before/after, then the whole page and every changed section from start to now, then what was tried and undone. It is rewritten after every decision.
finish <slug> --merge|--keep-branch|--discard Ends the run.
capture <slug> <label> Takes a full set of screenshots and measurements by hand.
compare <slug> <label> --target <part> Pixel-compares a capture with the last accepted one and builds the blind X/Y packet for a reviewer.
brief · prompt Print what a role would be given for one part of the page — useful for seeing exactly what an AI was asked.
record · accept · reject The bookkeeping role and iterate do for you: file a role's answer, commit a kept change, undo a rejected one.
guard <slug> [--since <commit>] Runs the data check on its own.
calibrate <slug> Re-measures animation noise, if a part of the page nobody touched keeps showing as changed.

Run node $P with no arguments for the full option list.

Where things are saved

Everything about a run is kept in <templates>/.polish/<slug>/<run-id>/, outside the template itself:

Path Contents
shots/<label>/ Screenshots for each capture: the whole page, the first screen, and for every part of the page a crop, a wider crop showing the sections above and below it, and the header at rest, scrolled, with its menu open. manifest.json holds the measurements.
shots/<label>/ab/ The blind X/Y images a reviewer saw.
shots/<label>/rejected.patch A change that was undone, in case you want it back.
roles/ The exact prompt, reply and log of every AI session.
plans/ Every change plan a designer wrote (only with --change).
critiques/ · reviews/ · log.jsonl Every critique, every verdict, and the order it all happened in.
improvements.html The before-and-after page.

When it stops

For each part of the page and each width, the loop stops when a critic finds nothing a designer would notice, when two attempts in a row are rejected, or after five iterations on the header, hero or footer and three on any other section. A critic is told that fewer issues is a better answer when fewer are real, and that an empty list is a valid one — it is not asked to find five problems every time.

In a change pass, a section stops when its change has landed, or after two tries.

If something goes wrong

You see What to do
… answered 404 or nothing on start The preview is not serving that template. Check the app is running and STUDIO_TEMPLATE_PREVIEW_PATH points at your templates folder, or pass --url.
playwright not found Run node $P setup.
… has uncommitted changes Commit or discard them first; the loop undoes a rejected change by resetting to the last commit.
… is already on polish/… A run is still open on that template. Carry on with status, or end it with finish.
Nothing changed on screen The developer's edit had no visible effect. iterate undoes it unless a measured problem improved.
this run was started without a change level role … designer needs to know how far to go. Pass --change small|medium|large to it, or start the run with one.
undershoot or overshoot as a reject reason The reviewer read the change as smaller, or much larger, than the level asked. status says whether to go again.
GATES FAILED or NOT accepted The lint or the data check refused the change, and says why. Run the iteration again for a fresh attempt, or reject it.
codex could not run / claude could not run That agent CLI is not installed or not signed in.
A section nobody touched shows as changed Something on the page animates continuously. Run calibrate.