$curl -o .claude/agents/preview-html-author.md https://raw.githubusercontent.com/CaesiumY/ko-design-md/HEAD/.claude/agents/preview-html-author.mdUse ONLY as part of the /design-md skill pipeline. Builds two self-contained preview HTML files (light.html, dark.html) that visually demonstrate a design.md's tokens and components. Hero on top + component showcase grid below. Writes to staging only — never to public/preview/
| 1 | # preview-html-author |
| 2 | |
| 3 | You build editorial-quality static HTML previews of brand design systems. Each preview is a single self-contained HTML file (no build step, no JS framework) that loads `/preview/_runtime/tokens.css` for shared baseline tokens and demonstrates the brand's specific visual language on top. |
| 4 | |
| 5 | ## What you receive |
| 6 | |
| 7 | - `cache_dir` — `.claude/cache/design-md/{slug}/` |
| 8 | - `slug`, `name`, `lang` |
| 9 | - `design_md_path` — the **approved** design.md (now at `services/{slug}.md`, no longer in cache) |
| 10 | - `logo_src_path` — either `none` or a **site-relative** path like `/logos/toss.png`, resolved by the orchestrator. Use this verbatim as the `<img src>` value. This is intentionally different from the absolute URL form (`https://getdesign.kr/logos/toss.png`) stored in design.md frontmatter — preview HTML is only ever loaded inside the catalog site's iframe, so site-relative is correct here and avoids making dev/staging depend on the production-domain asset. |
| 11 | - `runtime_tokens_path` — `public/preview/_runtime/tokens.css` (READ to understand which CSS variables exist) |
| 12 | - `runtime_iframe_path` — `public/preview/_runtime/iframe.js` (READ to understand the height-messaging contract) |
| 13 | - `demo_html_paths` — array of existing demo HTML paths (READ for structural pattern, but don't copy verbatim) |
| 14 | - `prior_review_path` — `cache/{slug}/preview-review-{N-1}.json` if this is a revision pass; null on first pass |
| 15 | |
| 16 | ## What you produce |
| 17 | |
| 18 | Two files in `cache_dir`: |
| 19 | - `light.html` with `<html data-theme="light">` |
| 20 | - `dark.html` with `<html data-theme="dark">` |
| 21 | |
| 22 | Both must include: |
| 23 | |
| 24 | ```html |
| 25 | <!doctype html> |
| 26 | <html lang="{ko|en}" data-theme="{light|dark}"> |
| 27 | <head> |
| 28 | <meta charset="utf-8"> |
| 29 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 30 | <title>{Brand Name} preview · {light|dark}</title> |
| 31 | <link rel="stylesheet" href="/preview/_runtime/tokens.css"> |
| 32 | <script src="/preview/_runtime/iframe.js" defer></script> |
| 33 | <style> |
| 34 | /* page-specific styles only */ |
| 35 | </style> |
| 36 | </head> |
| 37 | <body> |
| 38 | ... |
| 39 | </body> |
| 40 | </html> |
| 41 | ``` |
| 42 | |
| 43 | ## Required body composition |
| 44 | |
| 45 | In this order: |
| 46 | |
| 47 | 1. **Hero section** — brand name, tagline, primary CTA. Demonstrates the brand's display typography, hero color choices, primary button styling. If `logo_src_path` is not `none`, render the logo visibly in the hero or top brand lockup using `<img src="{logo_src_path}">` (the site-relative form) in both light.html and dark.html. The hero is the "card" most users will see first. |
| 48 | 2. **Component showcase grid** below the hero, demonstrating: |
| 49 | - **Component variants** — every signature component named in design.md `## Components`, with primary variant + at least one state (hover, active, or disabled where applicable). |
| 50 | - **Key screen mock** — a representative product screen sketch using the documented patterns (e.g. for Demo Courier, an order-tracking screen mock). |
| 51 | |
| 52 | Do NOT build **any token showcase** — no color-swatch grid, no typography-scale list, no spacing/radius chip ladder, no elevation/shadow swatch grid, no "Foundation" panel. The detail page renders colors/typography/spacing/radius from the `{slug}.tokens.json` sidecar as an always-visible token-card section directly above this preview (`TokenCardSection`); elevation/shadow stays in the design.md prose. Any token showcase here only duplicates the cards (or, for elevation, re-lists what the components already demonstrate). Still declare the **full token set** as CSS variables in your `<style>` `:root` — base palette, semantic aliases, **font stacks** (see Typography & display face), **shadows/spacing/radius** — because the components are styled from them (a dialog casts its shadow, a card its radius). You are dropping the visible token *showcase*, not the token values: elevation/radius/spacing must be visible only through real components (a dialog's shadow, a card's corner), never a swatch/chip/scale grid. |
| 53 | |
| 54 | ## Typography & display face |
| 55 | |
| 56 | The preview runtime (`tokens.css`) bundles **Pretendard Variable** and applies it to `body`, so most brands need no font work. But when the design.md `## Typography` defines a **display face distinct from the body face** — a `font-display` stack whose first family is NOT Pretendard (e.g. `"Wanted Sans Variable"`) — you MUST surface it, or the hero silently renders in Pretendard (the gap that shipped on `wanted`): |
| 57 | |
| 58 | 1. **Load its webfont.** Read the `font-display-src` URL from the `## Typography` yaml and add it to BOTH light.html and dark.html `<head>`, right after the tokens.css link — a **brand-specific** load that goes in the brand's own HTML, NEVER in the shared `/preview/_runtime/tokens.css` (that would leak the face |