Files
Youssef aedca8cb03 Refactor · move SKILL.md + references/ to repo root so 'npx skills add nutlope/hallmark' works
The published install command in the README — npx skills add nutlope/hallmark — was failing for users because the skills CLI looks for SKILL.md at the repo root, not at skill/SKILL.md where Hallmark kept it. The clone succeeded but the CLI reported "No skills found." Manual cp was the only working install path.

Flattened the layout:
- skill/SKILL.md            → SKILL.md
- skill/references/         → references/
- (skill/ directory removed; was empty after moves)

git mv preserved rename history for all 76+ files (SKILL.md + 28 reference files + 21 macrostructures + 46 components + 7 verb/genre subfolders).

Updated every cross-reference (36 occurrences across 9 files):
- README.md — 4 links (SKILL.md + references/ + the install snippet still reads the same)
- ROADMAP.md — 4 links to reference files
- package.json — "files" field + "skill" entry/references paths
- site/js/main.js — 3 source comments
- references/design-md.md — one broken link (was pointing skill/references/export-formats.md from inside references/ — now just export-formats.md as a sibling)
- site/_tests/verbs/study/notes.md, diagnosis.md and verbs/audit/audit-report.md, custom/README.md — test-artifact relative paths shortened by one segment (e.g. ../../../skill/SKILL.md → ../../../SKILL.md)

No skill content changes. After this lands, 'npx skills add nutlope/hallmark' should clone + install correctly without any manual cp fallback.
2026-05-19 12:12:45 +01:00

14 KiB
Raw Permalink Blame History

Stop letting your agents ship ugly UIs.

How to build well-designed UIs with AI agents.

Hassan El Mghari · Together AI · AI Engineer World's Fair · 2026


About this deck — this is a general playbook for any AI engineer, not a product pitch. Hallmark is mentioned once, on slide 15, as one open-source example our team built. The seven fixes apply to v0, Lovable, Bolt, Cursor, Claude Code, or any agent you're building yourself.

Visual style — dark slate #0b1117, off-white ink #e6edf3, GitHub-cool-blue accent #58a6ff. Inter for type, Roboto Mono for code. Every slide chrome-free: no eyebrow labels, no decorative hairlines. Footer is the Together AI logo bottom-left and a page number bottom-right.

Cadence — 17 slides, 18 minutes. ~60 seconds per slide. Section opener (S05) is a 10-second beat. S08 (wireframes), S11 (eight states), S13 (system prompt) want a moment.


01 · Cover

Stop letting your agents ship ugly UIs.

How to build well-designed UIs with AI agents.

— Hassan El Mghari · Together AI · AI Engineer World's Fair · 2026

Speaker: I'm Hassan, I lead DX at Together AI. Most of you have built an AI app this year and watched it ship a UI you'd never put on your portfolio. This talk is about why that happens, and seven concrete things that fix it — for any agent you use.


02 · The problem

Here's what your agent ships today.

(Visual: the real DevForge screenshot — a generated developer-conference landing page. Purple-cyan gradient on the headline, centered hero, four-column stat row, Inter on Inter.)

Vanilla prompt. Same shape every time.

Speaker: I gave the same prompt to a dozen agents — "build me a landing page for a developer conference, dark theme, in Brooklyn." This is roughly what every one of them returned. Different models, different stacks, same page.


03 · The promise

It could ship this instead.

(Visual: the Hyperlane screenshot — same brief, rebuilt. Big sans-serif headline with an italic-serif accent, asymmetric layout, single warm accent, monospace meta.)

Same brief. One missing layer added.

Speaker: Same brief. Same agent. The difference is the layer between the prompt and the output. We'll spend the rest of the talk on that layer.


04 · Why

Models ship the mean of their training set.

Every SaaS site since 2019 trained on the same shape. Without external steering, the agent regresses to it.

Every part of this is fixable with prompting and a small amount of structure.

Speaker: This isn't a model failure. Claude can render anything you describe. It's that "make me a landing page" maps to a region of the manifold where every SaaS site since 2019 lives. The good news: every fix from here is something you can do today, with any agent.


05 · Section opener

Seven things that fix it.

Tool-agnostic. Works with v0, Lovable, Bolt, Cursor, Claude Code, or your own agent.

Speaker: Each one of these closes a class of slop. Each one works today.


06 · Fix 01 — Use a real component library

Use a real component library.

shadcn/ui is the lingua franca of generated UI. Every major AI tool is trained on it. Linear, Vercel and Stripe ship it. Adopt it and your agent's output gets 80% better on day one.

$  npx shadcn@latest add button card dialog input table

drop the components in. Now every AI generation composes from a real system, not from invented primitives.

Speaker: This is the cheapest, highest-leverage move. Most AI engineers know about shadcn/ui. Fewer actually adopt it. v0 ships it natively. Cursor reads it. Claude Code reads it. The model has seen millions of examples of these components — it knows how to compose them.


07 · Fix 02 — Pin a design system

Pin a design system.

A single file at the root the agent reads on every render. One palette, one type pairing, one scale. No mid-render improvisation.

/* DESIGN.md  or  app/globals.css  —  Tailwind v4  @theme block */

@theme {
   --color-paper:    oklch(0.13 0.01 250);   /* one surface, not five */
   --color-ink:      oklch(0.93 0.01 250);   /* one ink */
   --color-accent:   oklch(0.65 0.18 250);   /* one accent, under 5% */
   --font-display:   "Inter Tight", sans-serif;
   --font-body:      "Inter", sans-serif;
   --space-1:        0.25rem;                /* 4-pt scale */
   --ease-out:       cubic-bezier(.2,0,0,1);
}

Speaker: Tailwind v4 made this easier than it used to be. One @theme block, OKLCH for color, semantic names. Drop a DESIGN.md next to it that describes the brand in plain English — what the brand sounds like, what it isn't. The agent reads both on every run.


08 · Fix 03 — Ask for a shape

Ask for a shape, not a list of features.

Stop saying "hero with three features." Say marquee. bento. long-document. stat-led.

(Visual: four abstract wireframes drawn in Figma showing each shape.)

  • MARQUEE · one editorial idea, biased left
  • LONG DOCUMENT · reads like a letter, no marketing chrome
  • BENTO · many entries, irregular grid
  • STAT-LED · product is the headline; numbers carry it

Speaker: This is the move that breaks the "every page looks like a SaaS landing" attractor. Don't enumerate features. Pick a category of page. The same way Linear's home and Stripe's home don't share a shape — they share a category.


09 · Fix 04 — Show a reference

Paste a screenshot. Don't describe it.

AI sees more than it reads. A reference image carries more taste than a paragraph of adjectives.

→  pick a real site you admire.
→  ask the agent to extract the structure, not copy the pixels.
→  name the role of the type ("italic editorial serif"), not the font.

(Visual right: a real screenshot of calendly.com — the reference you'd actually paste.)

example · pasted calendly.com to the agent

Speaker: Designers have always done this — "make it feel like this." Until recently your agent had no equivalent. Now it does. Don't describe taste. Show it. And ask the model to extract structure, not pixels — what you want is the rhythm, not a knock-off.


10 · Fix 05 — Ban the tells

Tell it what you DON'T want.

Constraints beat instructions. Put these in your system prompt:

  • ✕ Purple → blue gradient hero
  • ✕ Inter / Roboto as display AND body
  • ✕ Three equal columns with icon-above-heading
  • min-height: 100vh, everything centered
  • ✕ Cards inside cards (no semantic reason)
  • background-clip text gradients on headlines
  • ✕ Pure #000 or pure #fff as a surface
  • ✕ Invented metrics, testimonials, or logos

Speaker: Counterintuitive but true: telling the model what NOT to do is stronger than describing what you want. These eight tells are the fingerprints of AI-generated UI. Ban them and the model has to reach somewhere else.


11 · Fix 06 — Eight states

Every interactive element ships eight states.

If the agent emits two, your UI ships broken.

(Visual: eight actual buttons in a 4-by-2 grid, each visibly in a different state — default, hover, focus-visible, active, disabled, loading, error, success.)

state what makes it different
default the resting style
hover one shade lighter
:focus-visible a 2px accent ring, instant (no fade-in)
:active inverted ink, accent fill
disabled 50% opacity, no pointer
loading · · · working
error red border, ⚠ retry
success green border, ✓ saved

Speaker: This is the single fastest "real or vibes" test you can run on AI output. Tab into the page. Disable a field. Make something load. If three of the eight states are unstyled, the agent shipped a screenshot, not a component.


12 · Fix 07 — Critique before emit

Make the agent grade its own work — first.

One line in the system prompt forces a critical pass before output. Two passes is normal.

  • DISTINCTIVENESS · does this look like THIS brief — or any brief
  • HIERARCHY · can a reader tell first / second / third in 2 seconds
  • EXECUTION · are the details right (rules, spacing, focus rings)
  • RESTRAINT · cut what doesn't earn its place

Score each 15. Anything below 3 → revision pass.

Speaker: The trick isn't the rubric — it's forcing the model to look at its own output critically before it returns. Two passes is normal. Three passes means the brief is too vague.


13 · The whole playbook

You can fit the whole playbook in one paragraph.

# system_prompt.md

You are a designer, not a templater. Before you write code:

  1. use shadcn/ui — never re-invent a primitive that already exists.
  2. read  DESIGN.md  for tokens. Use only those.
  3. pick ONE page shape (marquee, long-document, bento, stat-led, manifesto, catalogue).
  4. ban: purple-cyan gradients, Inter on Inter, 3-col icon grids, 100vh centered hero,
     card-in-card, background-clip text, pure #000 / #fff, invented metrics.
  5. ship 8 states for every interactive element.
  6. score  Distinctiveness · Hierarchy · Execution · Restraint  on 15.
     anything <3 triggers a revision pass.

Speaker: That's it. Seven lines. Drop this in any agent's system prompt — Cursor .mdc, Claude Code skill, v0 project instructions. Feel the difference on the next render.


14 · Tools

Pick your weapon.

Same seven fixes. Different surfaces.

v0 shadcn / Tailwind playground best UI quality out of the box
Lovable full-stack chat-and-build edit visually, ship live
Bolt fast prototyping in StackBlitz speed
Cursor in-IDE assistant lives in your editor
Claude Code agent loop · file-aware · skills longest-context coder

Speaker: All of these can do beautiful work if you put the seven fixes in. Pick the one that matches your stack.


15 · Hallmark — one example our team open-sourced

Hallmark.

One example our team open-sourced.

A Claude Code skill that bakes all seven fixes in.

github.com/nutlope/hallmark

(Visual: the Hallmark OG image — "The best landing pages built with AI" with three real example pages baked in.)

Speaker: We packaged the seven fixes into a Claude Code skill for ourselves at Together AI, then open-sourced it. It's one approach — there are others (Anthropic's frontend-design skill, Taste, Impeccable, others). The principle is the same: stop letting the agent invent the rules. Hand it a system.


16 · The big idea

Design taste is a layer in the agent stack.

MODELS
TOOLS
MEMORY
RAG
EVALS
TASTE   ← here
ORCHESTRATION

If you don't put it in the stack, the model picks the mean.

Speaker: We treat eval as a first-class layer because we know models will optimize for the wrong thing without it. Taste is the same — not a polish step you add at the end. A layer. Same stack you already build with. New row.


17 · Thanks

Thanks.

github.com/nutlope/hallmark
together.ai

@nutlope @YoussefXLM

(Visual right: a real QR code linking to the Hallmark repo.)

scan to install

Speaker: Thanks. The skill is open today. I'd love to see what you build with it — and what fixes you'd add to your own agent's stack.


Designer / production notes

Chrome — kept minimal on purpose

  • No eyebrow labels at the top of slides.
  • No decorative hairlines, dividers, or accent rules.
  • Footer is two elements only: the Together AI logo bottom-left (32×32), and the slide number bottom-right.
  • Functional rectangles (code-block surfaces, button shapes on S11, axis cards on S12) are kept — they carry content.

Palette — locked

  • BG #0b1117 (deep slate)
  • Surface #161b22 (code blocks, cards)
  • Ink primary #e6edf3
  • Ink secondary #7d8590
  • Accent #58a6ff (GitHub cool blue — links, key labels, accent fills)
  • Alert #f85149 (only on Fix 05 ban list and Fix 06 error button)
  • Success #3fb950 (only on Fix 06 success button)

Type

  • Display: Inter (Black / Bold weights at huge sizes)
  • Body: Inter Regular / Light
  • Code & mono labels: Roboto Mono

Pacing

17 slides for an 18-minute slot ≈ 60 seconds per slide. The section opener (S05) is a 10-second beat. The system-prompt slide (S13) wants a moment for Hassan to read it out loud. The Hallmark slide (S15) is intentionally quiet — read the label, don't dwell.

If running long

In order: S04 (Why — can fold into S02 narration), S16 (the stack diagram — can be one sentence after S15). Never drop S05, S08, S09, S11.

If running short

Add a live demo after S09. Paste a screenshot of a designed site, run the agent, show the output. 90 seconds max.

The markdown deliverable

This file (docs/talk-slides.md) is the canonical copy. If the Figma file gets reorganized, this stays authoritative.


Sources