mirror of
https://github.com/Nutlope/hallmark.git
synced 2026-08-14 12:35:33 +02:00
365 lines
14 KiB
Markdown
365 lines
14 KiB
Markdown
# 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.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
$ 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.
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* 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 1–5. 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.
|
|||
|
|
|
|||
|
|
```md
|
|||
|
|
# 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 1–5.
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
- ["shadcn/ui March 2026 Update: CLI v4, AI Agent Skills and Design System Presets"](https://medium.com/@nakranirakesh/shadcn-ui-march-2026-update-cli-v4-ai-agent-skills-and-design-system-presets-d30cf200b0e9)
|
|||
|
|
- ["AI-First UIs: Why shadcn/ui's Model is Leading the Pack" — Refine](https://refine.dev/blog/shadcn-blog/)
|
|||
|
|
- ["Design Systems for the Vibe-Coding Era" — Anna Arteeva, Design Systems Collective](https://www.designsystemscollective.com/design-systems-for-the-vibe-coding-era-42282e1affef)
|
|||
|
|
- [Anthropic — "Improving frontend design through Skills"](https://claude.com/blog/improving-frontend-design-through-skills)
|
|||
|
|
- ["v0 by Vercel — Complete Guide 2026"](https://www.nxcode.io/resources/news/v0-by-vercel-complete-guide-2026)
|
|||
|
|
- ["The Vibe-Coder's Prompting Guide" — Anna Arteeva, Medium](https://annaarteeva.medium.com/the-vibe-coders-prompting-guide-e04ba0295a18)
|
|||
|
|
- ["Choosing your AI prototyping stack: Lovable, v0, Bolt, Replit, Cursor, Magic Patterns" — Anna Arteeva, Medium](https://annaarteeva.medium.com/choosing-your-ai-prototyping-stack-lovable-v0-bolt-replit-cursor-magic-patterns-compared-9a5194f163e9)
|
|||
|
|
- [AI Engineer World's Fair 2026 — Jun 29 – Jul 2](https://www.ai.engineer/worldsfair)
|
|||
|
|
- [Hassan El Mghari · DX at Together AI](https://www.nutlope.com/)
|