render-as-html · design system

Canonical reference for the render-as-html skill. Components, patterns, and the principles behind them. Copy patterns from here rather than re-deriving CSS — generated artifacts should feel like one system.

Philosophy

Apple-quality typography and color, Linear/Stripe density.

Wide. Dense. Opinionated. Studio Displays exist; narrow centered columns waste them. 14-16px body, 1.45-1.55 line-height, tight padding. Information density is a feature.

The medium is the source of truth. Thariq: "there is almost no set of information that Claude can read that you cannot fairly efficiently represent with HTML." Lean into tables, SVG, CSS-as-data, and interaction. If flattening the artifact loses nothing but a diagram, the artifact is probably still too close to static prose.

The real reason for all this: staying in the loop. As Claude does more work, the temptation is to skim-and-approve plans you'd otherwise read carefully. A well-built HTML artifact pulls you back in. You actually read it, poke at the controls, push state back via copy-as-prompt. The doc becomes a conversation surface, not a deliverable to rubber-stamp.

Page shapes

Different content wants different bones. Pick the shape FIRST from content signals, then design inside it.

dashboard default for data

Ops console for tabular/system data. Wide, multi-column, dense.

Pick when: network scans, device explorers, ops audits, anything with >5 tables of similar shape. Max-width: 1280px. Body: 14px.

document default for prose

Reading-shape for plans, specs, briefings. Single column with sticky TOC.

Pick when: plans, specs, essays, meeting notes, anything prose-heavy you'd read paragraph-to-paragraph. Max-width: 880px. Body: 16px. Required: sticky TOC, per-section copy, footnote pattern.

timeline spec'd

Chronological event spine for diaries, logs, retros, trip journals.

May 11 May 8 May 3 Apr 22
Pick when: dated logs, diaries, retros, project histories, trip journals. Required: vertical spine + date markers + search + date-range filter.

runbook spec'd

Sequential procedure being executed — DR, deploy, machine rebuild.

3/7 Step 1 · pull latest backup Step 4 · run migration ⎘ copy Step 5 · verify health
Pick when: the user is *doing* the procedure, not reading about it. Required: step cards with checkboxes, per-code-block copy buttons, sticky progress bar, "stuck" copy-as-prompt.

comparison spec'd

Weighted decision matrix. Items as columns, criteria as rows.

Opt A Opt B Opt C cost ⚖ 3 speed ⚖ 5 UX ⚖ 4 ∑ score 22 28 24
Pick when: "which one do I pick" questions. The axis flip: items go on the X axis as columns, criteria on Y as rows. Required: weight inputs, live winner highlight, aggregate score row.

triage-board spec'd

Drag-between-buckets editor — GTD reorg, inbox triage, re-prioritization.

NOW NEXT LATER CUT
Pick when: bucketing items across 3-5 named columns. Required: HTML5 drag, live column counts, pre-sorted suggested distribution, copy-as-prompt export.

developer spec'd

PR explainer, code review, "explain this code" — annotated diff with severity findings.

files ▸ api.ts router.go cache.go CRITICAL unguarded null deref @ L42 + if err != nil { - return return err }
Pick when: reviewing or explaining code. Required: syntax-highlighted diffs (+/− gutters), severity-coded findings (critical/warn/nit), file navigator rail, inline margin annotations.

network-map spec'd

Entity graph — people, relationships, brain backlinks, dependencies.

detail
Pick when: the *connections* matter, not just the entities. Required: SVG graph canvas, click-to-focus, hover-edge-highlight, right-rail detail card, filter chips.

The 8 information dimensions (Thariq)

HTML can express state, interaction, layout, and visual relationships inside the file itself. Aim for at least 4 of these dimensions; if you only used 1-2, redesign before saving.

Tables
Real rows & columns
Design
Color, type, spacing as info
Illustrations
Inline SVG diagrams
{ }
Code
Highlighted snippets
Interaction
Sliders, toggles, JS
Workflows
Boxes, arrows, flow
Spatial
Coords & positions
Images
Embedded figures

The bar (read this every time)

If I flattened this HTML to static text, what would be impossible to preserve?

If the only answer is "the SVG diagram," it's styled prose, not an HTML artifact. A passing artifact has 3+ HTML-native features:

  • Live filter / search input
  • Clickable elements that cross-highlight other content
  • Inline SVG charts generated from data
  • Spatial layouts (floor plans, zone maps)
  • Color swatches showing real colors
  • Toggle controls (show/hide columns, dark/light)
  • Side-by-side visual diffs
  • Click-to-copy / sortable headers
  • Copy-as-prompt buttons that round-trip state back to the HTML file ← Thariq's killer pattern

Color tokens

All colors via CSS variables; both modes via prefers-color-scheme. Text-use colors meet WCAG AA on light backgrounds.

--bg
#fafaf7 · #141413
--surface
#ffffff · #1c1c1a
--surface-2
#f3f1ea · #25251f
--text
#1a1a1a · #f0eee8
--accent
coral · #c74438
--ok
#2f7d44
--warn
#9b641d
--note
#2f6fb3
--purple
#7650b3
--teal
#047f6d
--pink
#a83f78

Typography

One display, one body, one mono. Display and body use the system font stack, so generated artifacts stay self-contained.

h1
New Home Network
h2
Surveillance & security
body
Default body copy. 15-16px depending on shape, 1.45-1.55 line-height. cv11 & ss01 features on for the right "g" and "1".
mono
192.168.1.225 · d4:6a:91:18:8b:b2

Static components

Read-only display primitives. None of these are clickable — for interactive editing use the controls in the next section.

Stat tiles

50+
Devices
2.7 Gbps
core link
8
Zones
42
Models

Status pills — display only, NEVER interactive

done open low note danger
Anti-pattern. Do not put click handlers on pills. They read as static information labels — making them interactive is invisible and inscrutable. If a status needs to be editable, put a real checkbox or button next to it; the pill stays read-only.

Callouts

Accent. For the one important pointer on the page.
Note. Background info, not actionable.
Warning. Real risk or a deliberate decision.

Use sparingly — every callout dilutes the rest. 2-3 per artifact is plenty.

Visual diff (old → new)

Subnet192.168.68.0/24192.168.1.0/24
core linkWi-Fi2.5 GbE wired

Dense table

IPDeviceMACNotes
.254BGW620-700gateway · multigig WAN
.225core · M2 Ultraa4:fc:14:xx:xx:xx2.5 GbE wired

Real controls for real actions

If the user is supposed to toggle, edit, pick, or trigger something, use a control that LOOKS like a control. Never invent gestures on decorative elements.

Search input

Filter chips — every filter needs a visible clear path

All categories visible.

Click to toggle. When ≥1 chip is OFF, an explicit "× clear" affordance appears nearby. Never rely on double-click / escape / click-outside to reset.

Native checkboxes — the editing affordance

  • Camera HTTP creds obtained
  • core on wired Ethernet
  • Decide: Luma NVR vs SecuritySpy
  • Prune stale Tailscale nodes

For TODO-shaped data, use the universal checklist affordance. Anyone gets it in 0 seconds. Paired with copy-as-prompt below, you have a real editing surface.

Toggle buttons

Copy-as-prompt — the killer pattern

Thariq's two-way loop: tune values in the browser → click a button → paste-able prompt for Claude Code that applies the changes back to the HTML artifact. Try the live demo below.

controls
11°
78%
61%
12px
preview
--accent
pattern code (the 20 lines that make this work)
// Read state from your controls, format as instruction
async function copyPrompt() {
  const h = +$('#hue').value, s = +$('#sat').value, l = +$('#lig').value;
  const prompt = `In ${ARTIFACT_PATH}, update --accent to hsl(${h} ${s}% ${l}%)`;
  $('#prompt-output').value = prompt;
  try {
    await navigator.clipboard.writeText(prompt);
  } catch {
    $('#prompt-output').focus();
    $('#prompt-output').select();
  }
}
$('#copy-btn').onclick = copyPrompt;

// The prompt MUST:
// - name the HTML artifact file (so Claude knows what to edit)
// - state deltas, not the full HTML
// - read naturally when pasted as a user message
// - remain selectable when clipboard access is blocked

Per-section copy — document-shape pattern

For document-shape artifacts, every h2 should have a quiet "copy section" button that lands the section's HTML on the clipboard for reuse or follow-up edits.

Implementation: copy the section's HTML directly from the DOM, and reveal the button on h2 hover via CSS opacity. Keep a visible fallback text area for browsers that block clipboard writes.

pattern code
<section id="workstreams">
  <h2>Workstreams <button class="copy-section" data-section="workstreams">copy section</button></h2>
  ...
</section>
<textarea id="copy-fallback" hidden readonly></textarea>

$$('.copy-section').forEach(btn => btn.onclick = () => {
  const html = $('#' + btn.dataset.section).outerHTML;
  navigator.clipboard.writeText(html).catch(() => {
    $('#copy-fallback').hidden = false;
    $('#copy-fallback').value = html;
    $('#copy-fallback').focus();
    $('#copy-fallback').select();
  });
});

Charts & diagrams

All hand-written inline SVG. No chart libraries — they cost weight and produce generic-looking output.

Donut chart

100
Infrastructure35
Surveillance20
IoT15
A/V30
donut math — circumference-100 trick
<!-- r=15.9 → circumference ≈ 100, so stroke-dasharray uses percentages directly -->
<circle r="15.9" cx="21" cy="21" fill="transparent"
        stroke="var(--accent)" stroke-width="6"
        stroke-dasharray="20 80"   <!-- 20% slice -->
        stroke-dashoffset="-10"/> <!-- offset after previous slice -->

Topology / workflow pattern

A B (core) C (infra) D (A/V) E (IoT)

Solid = wired/sync, dashed = wireless/async. Fill = category soft, border = category full. Make nodes clickable to cross-highlight rows in the data table.

Anti-patterns

Using this file

Before generating a new artifact:

  1. Pick the page shape from content signals — dashboard for data, document for prose. If unclear, ask.
  2. Copy the :root + dark-mode block as starting CSS
  3. Pattern-match components from this gallery — don't re-derive
  4. Plan the HTML-native features — write down 3+ before opening the editor
  5. Add copy-as-prompt if there's mutable state worth round-tripping
  6. Validate against the bar — what would die outside HTML? If <3, redesign.