Daniel VinersarGet in touch

How the demo outputs were made

The demo ("Same prompt. Two systems.") shows one representative output per prompt and system. Every output was generated by a model; none was written or edited by hand. This file records exactly how, so anyone can check or repeat it.

Setup

  • Model: Claude Opus 5.5 (claude-opus-5-5), run as Claude Code subagents.
  • Runs: 3 prompts × 2 systems × 3 runs = 18 runs, on 2026-10-06 between 13:10:29Z and 13:11:45Z.
  • Prompts (from demo/model.ts, identical for both systems):
    • pricing-card: "Create a pricing card for our Pro plan: €29 per month, billed annually, with four features and a primary call to action to start a free trial. Mark it as the most popular plan."
    • settings-form: "Build a notification settings form with an email digest frequency, a product updates toggle, a security alerts toggle that is always on, and a save button."
    • dashboard-empty-state: "Design the empty state for the Invoices dashboard when a new user has no invoices yet. Explain what goes here, with a primary action to create the first invoice and a secondary option to import from CSV."

The two systems

Both were frozen before any run, and are published unchanged, with every run, in the public repository.

  • Unstructured system (demo/systems/unstructured, imported as @shared/ui, frozen before any run): a realistic legacy UI library. Value-named tokens (blue-500, gray-300, …; the brand teal is present but not marked as the brand), undocumented components, a duplicate primary button (Button and an older PrimaryButton), numeric spacing props, no empty-state pattern. The rule when writing it: it may lack intent and documentation, never quality. It has real buttons, a labelled toggle, a select and layout helpers.
  • AI-ready system (demo/systems/ai-ready, imported as @acme/ui, frozen before any run): semantic tokens (acme.color.action.primary, acme.space.lg, …), components that document when to use them, and patterns such as EmptyState. The last change before the runs only removed header comments that mentioned the demo. Disclosure: EmptyState's copy rule ("sentence case, no exclamation marks or emoji") was added while an earlier hand-written draft of the demo existed (see below).

Isolation

  • Every run was a fresh subagent with no memory of other runs.
  • Each run got its own folder containing only TASK.md and a copy of its own system (system/). It never saw the other system, the site, CLAUDE.md, the annotations, the earlier draft, or any hint of a comparison. Both systems were scanned for words that could leak the purpose ("comparison", "demo", "AI-ready", …) before the runs.
  • The repo's CLAUDE.md (which describes the demo) was moved out of the repo for the duration of the runs and restored afterwards. No user-level CLAUDE.md or memory existed.
  • Audit: all 18 transcripts were checked for file paths or commands outside the run's folder: 0 found.
  • Limitation: subagents had filesystem tools; isolation was by instruction and folder layout, verified by the audit, not enforced by a sandbox.

The instruction given to each subagent (only the folder path differed per run):

Your working directory for this task is <run folder>. Read TASK.md and every file in system/ in that directory, then write output.tsx in that directory as TASK.md describes. Work only inside that directory: don't read, list or search any file outside it, and don't run commands that touch other paths. When you're done, reply with the single word: done.

TASK.md, identical for both systems except {{ALIAS}} (@shared/ui or @acme/ui) and {{PROMPT}}:

markdown
# Task

You're a frontend engineer on a product team. Build the UI described below as a React component.

## Request

{{PROMPT}}

## Your team's UI library

Your team's UI library is in `./system/`. Read it before you start. It's importable as `{{ALIAS}}`.

## File requirements

Write exactly one file: `./output.tsx` (TypeScript + React).

- `export default` one component that takes no props.
- `export const styles` must be a plain CSS string with any styles the component needs (it can be empty). It's injected into a Shadow DOM root that wraps your component; `:host` is that root. The UI library's own styles are already injected.
- No Tailwind, CSS modules or global CSS. Use system font stacks only.
- The component renders in a container 320–600px wide: use `@container` queries, not `@media`.
- No data fetching and no browser APIs during render. Local state is fine. Use static ids, not `useId`.

Every run, unedited

demo/runs/<prompt>/<system>/run-N.tsx: byte-identical to what each subagent wrote (checked with cmp).

Choosing the representative run

Rule, written at 2026-10-06T13:11:24Z, while runs were in progress and before any output was opened:

For each prompt × system, the representative run is the run that shares the most structural decisions with the other two runs of the same combination: which library components it uses (or rebuilds by hand); how it styles (library classes/tokens vs. its own CSS values); layout and element structure; accessibility-relevant choices. Not the best-looking and not the worst. Ties go to the lowest run number.

PromptSystemShownWhy
pricing-cardunstructuredrun 1Runs 1 and 2 are nearly identical (Button blue, blue Tag, hand-built list); run 1 also shares the blue check icon with run 3. Run 3 alone used PrimaryButton.
pricing-cardAI-readyrun 1All three use Card/Badge/CheckList/Button; run 1 shares the CTA position with run 2 and the header row with run 3. Run 3 alone moved the CTA to the bottom.
settings-formunstructuredrun 2Shares the tag-in-title and status line with run 1, and the label-above-select field with run 3.
settings-formAI-readyrun 2Runs 2 and 3 are structurally identical; run 1 differs only in the footer. Tie → run 2.
dashboard-empty-stateunstructuredrun 3Shares the numbered steps list and hint line with run 1, and PrimaryButton, the 72px icon badge and the centered layout with run 2.
dashboard-empty-stateAI-readyrun 1All three use EmptyState; run 1 shares the upload icon on the link with run 2, and the page copy and container width with run 3.

Edits to wire outputs in

  • Output files: none. demo/outputs/<prompt>/<system>.tsx are byte-identical copies of the runs above. They compiled and rendered without changes.
  • demo/registry.ts: the unstructured system's styles are now injected into unstructured panels, as @acme/ui's already were for AI-ready ones. This is infrastructure, not output.
  • Display only: "View code" shows the component before the styles export (displaySource in demo/load-sources.ts), and the preview pane has padding around each output (DemoPanel). The file content is unchanged.
  • Run switcher: each panel can show any of its three saved runs (rendered from demo/runs). The representative run is the default and is labeled "typical"; the comments refer to the typical runs only.

The earlier hand-written draft

Before these runs, the demo showed six outputs written by hand to illustrate typical failures. They were discarded and replaced by the generated runs above. Several of their claims did not survive contact with real output, and the comments were rewritten from the runs only:

  • A clickable div CTA, div toggles without labels, an "Always on" setting shown as an off toggle, emoji and gradients, "No invoices yet!": none of these appeared in any generated run. The legacy library's real components absorbed most accessibility issues.

What actually differed

Ordered from the strongest difference to the smallest; the demo's tabs follow this order. Every claim below was checked against all three runs, not just the one shown.

  • pricing-card:
    • Brand: all 3 unstructured runs made the CTA and the "most popular" tag blue (blue-500/blue-600), never the brand teal; all 3 AI-ready runs used Button variant="primary" (teal).
    • Reuse: all 3 unstructured runs hand-built the feature list and drew their own check icon; all 3 AI-ready runs used CheckList.
    • Values: the unstructured runs typed numbers (padding={24}, gap={20}, 36px/40px/48px prices); the AI-ready runs used scale names, except two values copied from the heading style (font-weight: 650, letter-spacing: -0.02em).
    • Emphasis: all 3 AI-ready runs used Card emphasis="highlighted"; only 1 of 3 unstructured runs emphasized the card.
  • dashboard-empty-state:
    • Pattern: all 3 AI-ready runs used EmptyState (9–16 lines of their own CSS).
    • Invented layouts: each unstructured run designed its own layout, with a how-it-works list nobody asked for, in 75–102 lines of CSS.
    • Duplicate button: 2 of 3 unstructured runs used the duplicate PrimaryButton.
    • Brand: the icon art is blue in all 3 unstructured runs.
    • Copy: sentence case on both sides; no emoji anywhere.
  • settings-form: the smallest difference of the three.
    • Both are accessible. In both, security alerts is a disabled control with an explanation.
    • Doubled labels: all 3 unstructured runs passed a label to the legacy Toggle and wrote their own row title; Toggle renders its label visibly, so every setting reads twice.
    • Brand: all 3 unstructured save buttons are blue; the AI-ready ones are teal.
    • Spacing: unstructured gaps are typed numbers that mostly match the legacy scale (24/20/4), with gap={6} and 2px in one run; AI-ready gaps are scale names.
  • Consistency: the 3 AI-ready runs of each prompt are near-identical; the unstructured runs vary more (e.g. which primary button, which extra list).

Reproduce

  1. Clone the public repository. Its systems/ folders are the inputs; runs/ holds every output; tasks/ holds every TASK.md exactly as given.
  2. For each prompt and system, create a folder with TASK.md (template above) and a copy of that system as system/.
  3. Give a fresh Claude Opus 5.5 agent the instruction above, three times per folder.