Retour aux skills
himself65/finance-skillsContrôle réussi

SKILL DETAIL

generative-ui

himself65/finance-skills/generative-ui

Design system and guidelines for Claude's built-in generative UI — the show_widget tool that renders interactive HTML/SVG widgets inline in claude.ai conversations. This skill provides the complete Anthropic "Imagine" design system so Claude produces high-quality widgets without needing to call read_me first. Use this skill whenever the user asks to visualize data, create an interactive chart, build a dashboard, render a diagram, draw a flowchart, show a mockup, create an interactive explainer, or produce any visual content beyond plain text or markdown. Triggers include: "show me", "visualize", "draw", "chart", "dashboard", "diagram", "flowchart", "widget", "interactive", "mockup", "illustrate", "explain how X works" (with visual), or any request for visual/interactive output. Also triggers when the user wants to display financial data visually, create comparison grids, or build tools with sliders, toggles, or live-updating displays.

Installations · 98Voir la source

Installation

npx skills add https://github.com/himself65/finance-skills --skill generative-ui

Fichiers du skill

SKILL.md

Dernière synchronisation · 6 sept. 2026

README.md
# generative-ui

Design system and guidelines for Claude's built-in generative UI — the `show_widget` tool that renders interactive HTML/SVG widgets inline in claude.ai conversations.

## What it does

Provides the complete Anthropic "Imagine" design system so Claude produces high-quality widgets without needing to call `read_me` first. Covers:

- **Charts** — Chart.js line, bar, area charts with interactive controls
- **Diagrams** — SVG flowcharts, structural diagrams, illustrative diagrams
- **Dashboards** — metric cards, comparison grids, data displays
- **Interactive explainers** — sliders, toggles, live-updating calculations
- **Design tokens** — CSS variables, color palette (light/dark), typography, spacing

## Key design principles

- **Seamless** — widgets blend with the host UI
- **Flat** — no gradients, shadows, or decorative effects
- **Compact** — show the essential inline, explain in text
- **Dark mode mandatory** — all colors work in both light and dark mode via CSS variables

## Triggers

- "show me", "visualize", "draw", "chart", "dashboard"
- "diagram", "flowchart", "widget", "interactive", "mockup"
- "explain how X works" (with visual), "illustrate"
- Any request for visual/interactive output beyond plain text or markdown

## Platform

Works on **Claude.ai** (built-in `show_widget` tool).

## Setup

```bash
# Choose finance-ui-tools when prompted.
npx plugins add himself65/finance-skills

# Or install just this skill
npx skills add himself65/finance-skills --skill generative-ui
```

See the [main README](../../../../README.md) for more installation options.

## Reference files

- `references/design_system.md` — Complete color palette, CSS variables, UI component patterns, metric cards, layout rules
- `references/svg_and_diagrams.md` — SVG viewBox setup, font calibration, pre-built classes, diagram patterns with examples
- `references/chart_js.md` — Chart.js configuration, script load ordering, canvas sizing, legend patterns, dashboard layout
references/chart_js.md
# Chart.js Reference

Extracted from Claude's actual `visualize:read_me` guidelines.

---

## Basic Setup

```html
<div style="position: relative; width: 100%; height: 300px;">
  <canvas id="myChart"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.js" onload="initChart()"></script>
<script>
  function initChart() {
    new Chart(document.getElementById('myChart'), {
      type: 'bar',
      data: { labels: ['Q1','Q2','Q3','Q4'], datasets: [{ label: 'Revenue', data: [12,19,8,15] }] },
      options: { responsive: true, maintainAspectRatio: false }
    });
  }
  if (window.Chart) initChart();
</script>
```

---

## Rules

### Canvas Sizing
- Set height ONLY on the wrapper div, never on the canvas element itself
- Use `position: relative` on the wrapper
- Use `responsive: true, maintainAspectRatio: false` in Chart.js options
- Never set CSS height directly on canvas — causes wrong dimensions, especially for horizontal bar charts
- For horizontal bar charts: wrapper div height = at least `(number_of_bars × 40) + 80` pixels

### Script Load Ordering
- Load UMD build via `<script src="https://cdnjs.cloudflare.com/ajax/libs/...">` — sets `window.Chart` global
- Follow with plain `<script>` (no `type="module"`)
- CDN scripts may not be loaded when the next `<script>` runs (especially during streaming)
- **Always use `onload="initChart()"` on the CDN script tag**
- Define your chart init in a named function
- Add `if (window.Chart) initChart();` as fallback at end of inline script
- This guarantees charts render regardless of load order

### Canvas and CSS Variables
- Canvas cannot resolve CSS variables. Use hardcoded hex or Chart.js defaults
- Multiple charts: use unique IDs (`myChart1`, `myChart2`). Each gets its own canvas+div pair

### Scale Padding
- For bubble and scatter charts: bubble radii extend past center points, so points near axis boundaries get clipped
- Pad the scale range — set `scales.y.min` and `scales.y.max` ~10% beyond data range
- Or use `layout: { padding: 20 }` as a blunt fallback

### X-Axis Labels
- Chart.js auto-skips x-axis labels when they'd overlap
- For ≤12 categories where all labels must be visible (waterfall, monthly), set `scales.x.ticks: { autoSkip: false, maxRotation: 45 }`

---

## Number Formatting

Negative values are `-$5M` not `$-5M` — sign before currency symbol.

Use a formatter:
```js
(v) => (v < 0 ? '-' : '') + '$' + Math.abs(v) + 'M'
```

---

## Legends

Always disable Chart.js default and build custom HTML:

```js
plugins: { legend: { display: false } }
```

```html
<div style="display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 8px; font-size: 12px; color: var(--color-text-secondary);">
  <span style="display: flex; align-items: center; gap: 4px;">
    <span style="width: 10px; height: 10px; border-radius: 2px; background: #3266ad;"></span>Chrome 65%
  </span>
  <span style="display: flex; align-items: center; gap: 4px;">
    <span style="width: 10px; height: 10px; border-radius: 2px; background: #73726c;"></span>Safari 18%
  </span>
</div>
```

Include the value/percentage in each label when the data is categorical (pie, donut, single-series bar). Position the legend above the chart (`margin-bottom`) or below (`margin-top`) — not inside the canvas.

---

## Dashboard Layout

Wrap summary numbers in metric cards above the chart:

```html
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 1rem;">
  <div style="background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem;">
    <div style="font-size: 13px; color: var(--color-text-secondary);">Revenue</div>
    <div style="font-size: 24px; font-weight: 500;">$2.4M</div>
  </div>
  <div style="background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem;">
    <div style="font-size: 13px; color: var(--color-text-secondary);">Growth</div>
    <div style="font-size: 24px; font-weight: 500; color: var(--color-text-success);">+12%</div>
  </div>
</div>

<div style="position: relative; width: 100%; height: 300px;">
  <canvas id="revenueChart"></canvas>
</div>
```

Chart canvas flows below without a card wrapper. Use `sendPrompt()` for drill-down: `sendPrompt('Break down Q4 by region')`.

---

## ERD / Database Schemas (mermaid.js)

Use mermaid.js `erDiagram`, not Chart.js or SVG:

```html
<style>
#erd svg.erDiagram .row-rect-odd path,
#erd svg.erDiagram .row-rect-odd rect,
#erd svg.erDiagram .row-rect-even path,
#erd svg.erDiagram .row-rect-even rect { stroke: none !important; }
</style>
<div id="erd"></div>
<script type="module">
import mermaid from 'https://esm.sh/mermaid@11/dist/mermaid.esm.min.mjs';
const dark = matchMedia('(prefers-color-scheme: dark)').matches;
await document.fonts.ready;
mermaid.initialize({
  startOnLoad: false,
  theme: 'base',
  themeVariables: {
    darkMode: dark,
    fontSize: '13px',
    lineColor: dark ? '#9c9a92' : '#73726c',
    textColor: dark ? '#c2c0b6' : '#3d3d3a',
  },
});
const { svg } = await mermaid.render('erd-svg', `erDiagram
  USERS ||--o{ POSTS : writes
  POSTS ||--o{ COMMENTS : has`);
document.getElementById('erd').innerHTML = svg;
</script>
```
references/design_system.md
# Generative UI Design System

Extracted from Claude's actual `visualize:read_me` guidelines (Imagine — Visual Creation Suite).

---

## Color Palette

9 color ramps, each with 7 stops from lightest to darkest. 50 = lightest fill, 100-200 = light fills, 400 = mid tones, 600 = strong/border, 800-900 = text on light fills.

| Class | Ramp | 50 | 100 | 200 | 400 | 600 | 800 | 900 |
|---|---|---|---|---|---|---|---|---|
| `c-purple` | Purple | #EEEDFE | #CECBF6 | #AFA9EC | #7F77DD | #534AB7 | #3C3489 | #26215C |
| `c-teal` | Teal | #E1F5EE | #9FE1CB | #5DCAA5 | #1D9E75 | #0F6E56 | #085041 | #04342C |
| `c-coral` | Coral | #FAECE7 | #F5C4B3 | #F0997B | #D85A30 | #993C1D | #712B13 | #4A1B0C |
| `c-pink` | Pink | #FBEAF0 | #F4C0D1 | #ED93B1 | #D4537E | #993556 | #72243E | #4B1528 |
| `c-gray` | Gray | #F1EFE8 | #D3D1C7 | #B4B2A9 | #888780 | #5F5E5A | #444441 | #2C2C2A |
| `c-blue` | Blue | #E6F1FB | #B5D4F4 | #85B7EB | #378ADD | #185FA5 | #0C447C | #042C53 |
| `c-green` | Green | #EAF3DE | #C0DD97 | #97C459 | #639922 | #3B6D11 | #27500A | #173404 |
| `c-amber` | Amber | #FAEEDA | #FAC775 | #EF9F27 | #BA7517 | #854F0B | #633806 | #412402 |
| `c-red` | Red | #FCEBEB | #F7C1C1 | #F09595 | #E24B4A | #A32D2D | #791F1F | #501313 |

### How to Assign Colors

Color encodes **meaning**, not sequence. Don't cycle through colors like a rainbow.

- Group nodes by **category** — all nodes of the same type share one color
- Use **gray for neutral/structural** nodes (start, end, generic steps)
- Use **2-3 colors per diagram**, not 6+. More = more visual noise
- **Prefer purple, teal, coral, pink** for general categories. Reserve blue, green, amber, red for semantic meaning (info, success, warning, error)

### Text on Colored Backgrounds

Always use the 800 or 900 stop from the same ramp as the fill. Never use black, gray, or `--color-text-primary` on colored fills.

When a box has both a title and a subtitle, use two different stops:
- **Light mode**: 50 fill + 600 stroke + 800 title / 600 subtitle
- **Dark mode**: 800 fill + 200 stroke + 100 title / 200 subtitle

Example: text on Blue 50 (#E6F1FB) must use Blue 800 (#0C447C) or 900 (#042C53), not black.

---

## CSS Variables

**Backgrounds**: `--color-background-primary` (white), `-secondary` (surfaces), `-tertiary` (page bg), `-info`, `-danger`, `-success`, `-warning`

**Text**: `--color-text-primary` (black), `-secondary` (muted), `-tertiary` (hints), `-info`, `-danger`, `-success`, `-warning`

**Borders**: `--color-border-tertiary` (0.15α, default), `-secondary` (0.3α, hover), `-primary` (0.4α), semantic `-info/-danger/-success/-warning`

**Typography**: `--font-sans`, `--font-serif`, `--font-mono`

**Layout**: `--border-radius-md` (8px), `--border-radius-lg` (12px — preferred for most components), `--border-radius-xl` (16px)

All auto-adapt to light/dark mode. For custom colors in HTML, use CSS variables. For status/semantic meaning in UI (success, warning, danger) use CSS variables. For categorical coloring in both diagrams and UI, use the color ramps.

---

## UI Component Patterns

### Aesthetic

Flat, clean, white surfaces. Minimal 0.5px borders. Generous whitespace. No gradients, no shadows (except functional focus rings). Everything should feel native to the host UI.

### Tokens

- Borders: always `0.5px solid var(--color-border-tertiary)` (or `-secondary` for emphasis)
- Corner radius: `var(--border-radius-md)` for most elements, `var(--border-radius-lg)` for cards
- Cards: white bg (`var(--color-background-primary)`), 0.5px border, radius-lg, padding 1rem 1.25rem
- Form elements (input, select, textarea, button, range slider) are pre-styled — write bare tags
- Buttons: transparent bg, 0.5px border-secondary, hover bg-secondary, active scale(0.98). If it triggers `sendPrompt`, append a ↗ arrow
- Spacing: use rem for vertical rhythm (1rem, 1.5rem, 2rem), px for component-internal gaps (8px, 12px, 16px)
- Box-shadows: none, except `box-shadow: 0 0 0 Npx` focus rings on inputs

### Metric Cards

For summary numbers (revenue, count, percentage):

```html
<div style="background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem;">
  <div style="font-size: 13px; color: var(--color-text-secondary);">Label</div>
  <div style="font-size: 24px; font-weight: 500;">$1,234</div>
</div>
```

Use in grids of 2-4 with `gap: 12px`. Distinct from raised cards (which have white bg + border).

### Layout Patterns

- **Editorial** (explanatory content): no card wrapper, prose flows naturally
- **Card** (bounded objects like a contact record, receipt): single raised card wraps the whole thing
- Don't put tables in widgets — output them as markdown in your response text

**Grid overflow**: `grid-template-columns: 1fr` has `min-width: auto` by default. Use `minmax(0, 1fr)` to clamp.

### Interactive Explainer

Sliders, buttons, live state displays, charts. Keep prose explanations in your response text. No card wrapper. Whitespace is the container.

```html
<div style="display: flex; align-items: center; gap: 12px; margin: 0 0 1.5rem;">
  <label style="font-size: 14px; color: var(--color-text-secondary);">Years</label>
  <input type="range" min="1" max="40" value="20" id="years" style="flex: 1;" />
  <span style="font-size: 14px; font-weight: 500; min-width: 24px;" id="years-out">20</span>
</div>
```

### Comparison Grid

Side-by-side card grid. Highlight differences with semantic colors. Use `repeat(auto-fit, minmax(160px, 1fr))` for responsive columns. When one option is recommended, accent its card with `border: 2px solid var(--color-border-info)` (the only exception to the 0.5px rule).

### Data Record

Wrap in a single raised card. Example:

```html
<div style="background: var(--color-background-primary); border-radius: var(--border-radius-lg); border: 0.5px solid var(--color-border-tertiary); padding: 1rem 1.25rem;">
  <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
    <div style="width: 44px; height: 44px; border-radius: 50%; background: var(--color-background-info); display: flex; align-items: center; justify-content: center; font-weight: 500; font-size: 14px; color: var(--color-text-info);">MR</div>
    <div>
      <p style="font-weight: 500; font-size: 15px; margin: 0;">Maya Rodriguez</p>
      <p style="font-size: 13px; color: var(--color-text-secondary); margin: 0;">VP of Engineering</p>
    </div>
  </div>
</div>
```

---

## Complexity Budget (Hard Limits)

- Box subtitles: ≤5 words
- Colors: ≤2 ramps per diagram
- Horizontal tier: ≤4 boxes at full width (~140px each). 5+ boxes → shrink to ≤110px OR wrap to 2 rows OR split into overview + detail diagrams
references/svg_and_diagrams.md
# SVG Setup and Diagram Patterns

Extracted from Claude's actual `visualize:read_me` guidelines.

---

## SVG Setup

**ViewBox**: `<svg width="100%" viewBox="0 0 680 H">` — 680px wide, flexible height. Set H to fit content tightly (last element's bottom edge + 40px padding). Safe area: x=40 to x=640, y=40 to y=(H-40). Background transparent.

**The 680 in viewBox is load-bearing — do not change it.** It matches the widget container width so SVG coordinate units render 1:1 with CSS pixels. If your diagram content is naturally narrow, keep viewBox width at 680 and center the content — do not shrink the viewBox.

**Do not wrap the SVG in a container `<div>` with a background color** — the widget host provides the card container and background. Output the raw `<svg>` element directly.

### ViewBox Safety Checklist

Before finalizing any SVG, verify:
1. Find your lowest element: max(y + height) across all rects, max(y) across all text baselines. Set viewBox height = that value + 40px buffer
2. Find your rightmost element: max(x + width) across all rects. All content must stay within x=0 to x=680
3. For text with `text-anchor="end"`, the text extends LEFT from x. If x=118 and text is 200px wide, it starts at x=-82 — outside the viewBox
4. Never use negative x or y coordinates. The viewBox starts at 0,0
5. For every pair of boxes in the same row, check that left box's (x + width) < right box's x by at least 20px

### Font Size Calibration

| Text | Chars | Weight | Size | Rendered Width |
|---|---|---|---|---|
| Authentication Service | 22 | 500 | 14px | 167px |
| Background Job Processor | 24 | 500 | 14px | 201px |
| Detects and validates incoming tokens | 37 | 400 | 14px | 279px |
| forwards request to | 19 | 400 | 12px | 123px |

Before placing text in a box: does (text width + 2×padding) fit the container? Box width formula: `rect_width = max(title_chars × 8, subtitle_chars × 7) + 24`.

SVG `<text>` never auto-wraps. Every line break needs an explicit `<tspan x="..." dy="1.2em">`.

### Pre-built Classes

Already loaded in SVG widget context:

- `class="t"` = sans 14px primary text
- `class="ts"` = sans 12px secondary text
- `class="th"` = sans 14px medium (500) heading text
- `class="box"` = neutral rect (bg-secondary fill, border stroke)
- `class="node"` = clickable group with hover effect (cursor pointer, slight dim on hover)
- `class="arr"` = arrow line (1.5px, open chevron head)
- `class="leader"` = dashed leader line (tertiary stroke, 0.5px, dashed)
- `class="c-{ramp}"` = colored node. Apply to `<g>` or shape element (rect/circle/ellipse), NOT to paths. Sets fill+stroke on shapes, auto-adjusts child text classes, dark mode automatic
- Short aliases: `var(--p)`, `var(--s)`, `var(--t)`, `var(--bg2)`, `var(--b)`

**`c-{ramp}` nesting**: These classes use direct-child selectors. Nest a `<g>` inside a `<g class="c-blue">` and inner shapes become grandchildren — they lose the fill and render BLACK. Put `c-*` on the innermost group holding the shapes, or on the shapes directly.

### Arrow Marker (always include)

```svg
<defs>
  <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
    <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
  </marker>
</defs>
```

Use `marker-end="url(#arrow)"` on lines. The head uses `context-stroke` — inherits the color of whichever line it sits on.

### Style Rules

- Every `<text>` element must carry one of: `t`, `ts`, `th`
- Use only two font sizes: 14px (node labels) and 12px (subtitles, descriptions, arrow labels)
- No decorative step numbers or oversized headings
- No icons or illustrations inside boxes — text only
- Sentence case on all labels
- Stroke width: 0.5px for diagram borders and edges
- Connector paths need `fill="none"` (SVG defaults to `fill: black`)
- `rx="4"` for subtle corners, `rx="8"` max for emphasized rounding
- One SVG per tool call — never leave an abandoned or partial SVG

---

## Diagram Types

### Flowchart

For sequential processes, cause-and-effect, decision trees.

**Planning**: Size boxes to fit text generously. At 14px, each character is ~8px wide. A label like "Load Balancer" (13 chars) needs at least 140px wide rect.

**Spacing**: 60px minimum between boxes, 24px padding inside boxes, 12px between text and edges. Leave 10px gap between arrowheads and box edges. Two-line boxes need at least 56px height with 22px between lines.

**Vertical text placement**: Every `<text>` inside a box needs `dominant-baseline="central"`, with y set to the center of its slot. Formula: for text centered in a rect at (x, y, w, h), use `<text x={x+w/2} y={y+h/2} text-anchor="middle" dominant-baseline="central">`.

**Layout**: Prefer single-direction flows. Max 4-5 nodes per diagram. The widget is narrow (~680px).

**Single-line node** (44px tall):
```svg
<g class="node c-blue" onclick="sendPrompt('Tell me more about T-cells')">
  <rect x="100" y="20" width="180" height="44" rx="8" stroke-width="0.5"/>
  <text class="th" x="190" y="42" text-anchor="middle" dominant-baseline="central">T-cells</text>
</g>
```

**Two-line node** (56px tall):
```svg
<g class="node c-blue" onclick="sendPrompt('Tell me more about dendritic cells')">
  <rect x="100" y="20" width="200" height="56" rx="8" stroke-width="0.5"/>
  <text class="th" x="200" y="38" text-anchor="middle" dominant-baseline="central">Dendritic cells</text>
  <text class="ts" x="200" y="56" text-anchor="middle" dominant-baseline="central">Detect foreign antigens</text>
</g>
```

**Connector** (no label):
```svg
<line x1="200" y1="76" x2="200" y2="120" class="arr" marker-end="url(#arrow)"/>
```

**Arrows**: Must not cross any other box or label. If the direct path crosses something, route around with an L-bend: `<path d="M x1 y1 L x1 ymid L x2 ymid L x2 y2"/>`.

**Cycles**: Don't draw as rings. Build a stepper in HTML instead: one panel per stage, dots showing position (● ○ ○), Next wraps from last stage to first.

**Over budget prompts**: If user lists 6+ components, decompose into a stripped overview + one diagram per interesting sub-flow, each with 3-4 nodes.

### Structural Diagram

For concepts where physical or logical containment matters.

**Container rules**:
- Outermost: large rounded rect, rx=20-24, lightest fill (50 stop), 0.5px stroke (600 stop). Label at top-left, 14px bold
- Inner regions: medium rounded rects, rx=8-12, next shade fill (100-200 stop). Different color ramp if semantically different
- 20px minimum padding inside every container
- Max 2-3 nesting levels

**Example** (horizontal layout with two inner regions):
```svg
<defs>
  <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
    <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
  </marker>
</defs>
<g class="c-green">
  <rect x="120" y="30" width="560" height="260" rx="20" stroke-width="0.5"/>
  <text class="th" x="400" y="62" text-anchor="middle">Library branch</text>
  <text class="ts" x="400" y="80" text-anchor="middle">Main floor</text>
</g>
<g class="c-teal">
  <rect x="150" y="100" width="220" height="160" rx="12" stroke-width="0.5"/>
  <text class="th" x="260" y="130" text-anchor="middle">Circulation desk</text>
  <text class="ts" x="260" y="148" text-anchor="middle">Checkouts, returns</text>
</g>
<g class="c-amber">
  <rect x="450" y="100" width="210" height="160" rx="12" stroke-width="0.5"/>
  <text class="th" x="555" y="130" text-anchor="middle">Reading room</text>
  <text class="ts" x="555" y="148" text-anchor="middle">Seating, reference</text>
</g>
<text class="ts" x="410" y="175" text-anchor="middle">Books</text>
<line x1="370" y1="185" x2="448" y2="185" class="arr" marker-end="url(#arrow)"/>
```

**Color in structural diagrams**: Nested regions need distinct ramps. Same class on parent and child gives identical fills and flattens the hierarchy. Pick a related ramp for inner structures and a contrasting ramp for functionally different regions.

**Database schemas / ERDs**: Use mermaid.js, not SVG.

### Illustrative Diagram

For building *intuition*. Draw the mechanism, not a diagram *about* the mechanism.

**Two flavors**:
- **Physical subjects**: simplified cross-sections, cutaways, schematics (a water heater is a tank with a burner)
- **Abstract subjects**: spatial metaphors (a transformer is stacked slabs with attention threads, a hash function is a funnel scattering into buckets)

**What changes from flowchart rules**:
- Shapes are freeform: `<path>`, `<ellipse>`, `<circle>`, `<polygon>`, curved lines
- Layout follows the subject's geometry, not a grid
- Color encodes intensity, not category (warm = active/high-weight, cool = dormant)
- Layering and overlap are encouraged for shapes (but never let a stroke cross text)
- Small shape-based indicators are allowed (triangles for flames, circles for bubbles)
- One gradient per diagram is permitted — only for continuous physical properties
- CSS `@keyframes` animation permitted (only `transform` and `opacity`, wrap in `@media (prefers-reduced-motion: no-preference)`)

**Prefer interactive over static**: if the real-world system has a control, give the diagram that control. Use `show_widget` with inline SVG + HTML controls.

**Label placement**: Place labels outside the drawn object with thin leader lines (0.5px dashed). Reserve at least 140px of horizontal margin on the label side.

**Composition approach**:
1. Main object's silhouette — largest shape, centered
2. Internal structure: chambers, pipes, membranes
3. External connections: pipes, arrows, input/output labels
4. State indicators last: color fills, small animated elements
5. Leave generous whitespace around the object for labels

### Routing Decisions

| User says | Type | What to draw |
|---|---|---|
| "how do LLMs work" | Illustrative | Token row, stacked layers, attention threads |
| "transformer architecture" | Structural | Labelled boxes: embedding, attention, FFN |
| "how does attention work" | Illustrative | One query token, fan of lines to every key |
| "what are the training steps" | Flowchart | Forward → loss → backward → update |
| "explain the Krebs cycle" | HTML stepper | Click through stages. Never a ring |
| "draw the database schema" | mermaid.js | `erDiagram` syntax |

The illustrative route is the default for "how does X work" — don't default to a flowchart because it feels safer.

---

## Art and Illustration

For "draw me a sunset" / "create a geometric pattern":

- Fill the canvas — art should feel rich, not sparse
- Bold colors: mix `--color-text-*` categories for variety
- Art is the one place custom `<style>` color blocks are fine — freestyle colors
- Layer overlapping opaque shapes for depth
- Organic forms with `<path>` curves, `<ellipse>`, `<circle>`
- Texture via repetition (parallel lines, dots, hatching) not raster effects
- Geometric patterns with `<g transform="rotate()">` for radial symmetry
SKILL.md
---
name: generative-ui
description: >
  Design system and guidelines for Claude's built-in generative UI — the show_widget tool that renders
  interactive HTML/SVG widgets inline in claude.ai conversations. This skill provides the complete
  Anthropic "Imagine" design system so Claude produces high-quality widgets without needing to call
  read_me first. Use this skill whenever the user asks to visualize data, create an interactive chart,
  build a dashboard, render a diagram, draw a flowchart, show a mockup, create an interactive explainer,
  or produce any visual content beyond plain text or markdown. Triggers include: "show me", "visualize",
  "draw", "chart", "dashboard", "diagram", "flowchart", "widget", "interactive", "mockup", "illustrate",
  "explain how X works" (with visual), or any request for visual/interactive output. Also triggers
  when the user wants to display financial data visually, create comparison grids, or build tools
  with sliders, toggles, or live-updating displays.
---

# Generative UI Skill

This skill contains the complete design system for Claude's built-in `show_widget` tool — the generative UI feature that renders interactive HTML/SVG widgets inline in claude.ai conversations. The guidelines below are the actual Anthropic "Imagine — Visual Creation Suite" design rules, extracted so you can produce high-quality widgets directly without needing the `read_me` setup call.

**How it works**: On claude.ai, Claude has access to the `show_widget` tool which renders raw HTML/SVG fragments inline in the conversation. This skill provides the design system, templates, and patterns to use it well.

---

## Step 1: Pick the Right Visual Type

Route on the **verb**, not the noun. Same subject, different visual depending on what was asked:

| User says | Type | Format |
|---|---|---|
| "how does X work" | Illustrative diagram | SVG |
| "X architecture" | Structural diagram | SVG |
| "what are the steps" | Flowchart | SVG |
| "explain compound interest" | Interactive explainer | HTML |
| "compare these options" | Comparison grid | HTML |
| "show revenue chart" | Chart.js chart | HTML |
| "create a contact card" | Data record | HTML |
| "draw a sunset" | Art/illustration | SVG |

---

## Step 2: Build the Widget

### Structure (strict order)

```
<style>  →  HTML content  →  <script>
```

Output streams token-by-token. Styles must exist before the elements they target, and scripts must run after the DOM is ready.

### Philosophy

- **Seamless**: Users shouldn't notice where the host UI ends and your widget begins
- **Flat**: No gradients, mesh backgrounds, noise textures, or decorative effects. Clean flat surfaces
- **Compact**: Show the essential inline. Explain the rest in text
- **Text goes in your response, visuals go in the tool** — all explanatory text, descriptions, and summaries must be written as normal response text OUTSIDE the tool call. The tool output should contain ONLY the visual element

### Core Rules

- No `<!-- comments -->` or `/* comments */` (waste tokens, break streaming)
- No font-size below 11px
- No emoji — use CSS shapes or SVG paths
- No gradients, drop shadows, blur, glow, or neon effects
- No dark/colored backgrounds on outer containers (transparent only — host provides the bg)
- **Typography**: two weights only: 400 regular, 500 medium. Never use 600 or 700. Headings: h1=22px, h2=18px, h3=16px — all font-weight 500. Body text=16px, weight 400, line-height 1.7
- **Sentence case** always. Never Title Case, never ALL CAPS
- No mid-sentence bolding — entity names go in `code style` not **bold**
- No `<!DOCTYPE>`, `<html>`, `<head>`, or `<body>` — just content fragments
- No `position: fixed` — use normal-flow layouts
- No tabs, carousels, or `display: none` sections during streaming
- No nested scrolling — auto-fit height
- Corners: `border-radius: var(--border-radius-lg)` for cards, `var(--border-radius-md)` for elements
- No rounded corners on single-sided borders (border-left, border-top)
- **Round every displayed number** — use `Math.round()`, `.toFixed(n)`, or `Intl.NumberFormat`

### CDN Allowlist (CSP-enforced)

External resources may ONLY load from:
- `cdnjs.cloudflare.com`
- `cdn.jsdelivr.net`
- `unpkg.com`
- `esm.sh`

All other origins are blocked — the request silently fails.

### CSS Variables

**Backgrounds**: `--color-background-primary` (white), `-secondary` (surfaces), `-tertiary` (page bg), `-info`, `-danger`, `-success`, `-warning`
**Text**: `--color-text-primary` (black), `-secondary` (muted), `-tertiary` (hints), `-info`, `-danger`, `-success`, `-warning`
**Borders**: `--color-border-tertiary` (0.15α, default), `-secondary` (0.3α, hover), `-primary` (0.4α), semantic `-info/-danger/-success/-warning`
**Typography**: `--font-sans`, `--font-serif`, `--font-mono`
**Layout**: `--border-radius-md` (8px), `--border-radius-lg` (12px), `--border-radius-xl` (16px)

All auto-adapt to light/dark mode.

**Dark mode is mandatory** — every color must work in both modes:
- In HTML: always use CSS variables for text. Never hardcode colors like `color: #333`
- In SVG: use pre-built color classes (`c-blue`, `c-teal`, etc.) — they handle light/dark automatically
- Mental test: if the background were near-black, would every text element still be readable?

### `sendPrompt(text)`

A global function that sends a message to chat as if the user typed it. Use it when the user's next step benefits from Claude thinking. Handle filtering, sorting, toggling, and calculations in JS instead.

---

## Step 3: Render with `show_widget`

The `show_widget` tool is built into claude.ai — no activation needed. Pass your widget code directly:

```json
{
  "title": "snake_case_widget_name",
  "widget_code": "<style>...</style>\n<div>...</div>\n<script>...</script>"
}
```

| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | Yes | Snake_case identifier for the widget |
| `widget_code` | string | Yes | HTML or SVG code. For SVG: start with `<svg>`. For HTML: content fragment |

For SVG output: start `widget_code` with `<svg` — it will be auto-detected and wrapped appropriately.

---

## Step 4: Chart.js Template

For charts, use `onload` callback pattern to handle script load ordering:

```html
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px;">
  <div style="background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem;">
    <div style="font-size: 13px; color: var(--color-text-secondary);">Label</div>
    <div style="font-size: 24px; font-weight: 500;" id="stat1">—</div>
  </div>
</div>

<div style="position: relative; width: 100%; height: 300px; margin-top: 1rem;">
  <canvas id="myChart"></canvas>
</div>

<div style="display: flex; align-items: center; gap: 12px; margin-top: 1rem;">
  <label style="font-size: 14px; color: var(--color-text-secondary);">Parameter</label>
  <input type="range" min="0" max="100" value="50" id="param" step="1" style="flex: 1;" />
  <span style="font-size: 14px; font-weight: 500; min-width: 32px;" id="param-out">50</span>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.js" onload="initChart()"></script>
<script>
function initChart() {
  const slider = document.getElementById('param');
  const out = document.getElementById('param-out');
  let chart = null;

  function update() {
    const val = parseFloat(slider.value);
    out.textContent = val;
    document.getElementById('stat1').textContent = val.toFixed(1);

    const labels = [], data = [];
    for (let x = 0; x <= 100; x++) {
      labels.push(x);
      data.push(x * val / 100);
    }

    if (chart) chart.destroy();
    chart = new Chart(document.getElementById('myChart'), {
      type: 'line',
      data: { labels, datasets: [{ data, borderColor: '#7F77DD', borderWidth: 2, pointRadius: 0, fill: false }] },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { display: false } },
        scales: { x: { grid: { display: false } } }
      }
    });
  }

  slider.addEventListener('input', update);
  update();
}
if (window.Chart) initChart();
</script>
```

**Chart.js rules:**
- Canvas cannot resolve CSS variables — use hardcoded hex
- Set height ONLY on the wrapper div, never on canvas itself
- Always `responsive: true, maintainAspectRatio: false`
- Always disable default legend, build custom HTML legends
- Number formatting: `-$5M` not `$-5M` (negative sign before currency symbol)
- Use `onload="initChart()"` on CDN script tag + `if (window.Chart) initChart();` as fallback

---

## Step 5: SVG Diagram Template

For flowcharts and diagrams, use SVG with pre-built classes:

```svg
<svg width="100%" viewBox="0 0 680 H">
  <defs>
    <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </marker>
  </defs>

  <!-- Single-line node (44px tall) -->
  <g class="node c-blue" onclick="sendPrompt('Tell me more about this')">
    <rect x="250" y="40" width="180" height="44" rx="8" stroke-width="0.5"/>
    <text class="th" x="340" y="62" text-anchor="middle" dominant-baseline="central">Step one</text>
  </g>

  <!-- Connector arrow -->
  <line x1="340" y1="84" x2="340" y2="120" class="arr" marker-end="url(#arrow)"/>

  <!-- Two-line node (56px tall) -->
  <g class="node c-teal" onclick="sendPrompt('Explain this step')">
    <rect x="230" y="120" width="220" height="56" rx="8" stroke-width="0.5"/>
    <text class="th" x="340" y="140" text-anchor="middle" dominant-baseline="central">Step two</text>
    <text class="ts" x="340" y="158" text-anchor="middle" dominant-baseline="central">Processes the input</text>
  </g>
</svg>
```

**SVG rules:**
- ViewBox always 680px wide (`viewBox="0 0 680 H"`). Set H to fit content + 40px padding
- Safe area: x=40 to x=640, y=40 to y=(H-40)
- Pre-built classes: `t` (14px), `ts` (12px secondary), `th` (14px medium 500), `box`, `node`, `arr`, `c-{color}`
- Every `<text>` element must carry a class (`t`, `ts`, or `th`)
- Use `dominant-baseline="central"` for vertical text centering in boxes
- Connector paths need `fill="none"` (SVG defaults to `fill: black`)
- Stroke width: 0.5px for borders and edges
- Make all nodes clickable: `onclick="sendPrompt('...')"`

---

## Step 6: Interactive Explainer Template

For interactive explainers (sliders, live calculations, inline SVG):

```html
<div style="display: flex; align-items: center; gap: 12px; margin: 0 0 1.5rem;">
  <label style="font-size: 14px; color: var(--color-text-secondary);">Years</label>
  <input type="range" min="1" max="40" value="20" id="years" style="flex: 1;" />
  <span style="font-size: 14px; font-weight: 500; min-width: 24px;" id="years-out">20</span>
</div>

<div style="display: flex; align-items: baseline; gap: 8px; margin: 0 0 1.5rem;">
  <span style="font-size: 14px; color: var(--color-text-secondary);">$1,000 →</span>
  <span style="font-size: 24px; font-weight: 500;" id="result">$3,870</span>
</div>

<div style="margin: 2rem 0; position: relative; height: 240px;">
  <canvas id="chart"></canvas>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.1/chart.umd.js" onload="initChart()"></script>
<script>
function initChart() {
  // slider logic, chart rendering, sendPrompt() for follow-ups
}
if (window.Chart) initChart();
</script>
```

Use `sendPrompt()` to let users ask follow-ups: `sendPrompt('What if I increase the rate to 10%?')`

---

## Step 7: Respond to the User

After rendering the widget, briefly explain:
1. What the widget shows
2. How to interact with it (which controls do what)
3. One key insight from the data

Keep it concise — the widget speaks for itself.

---

## Reference Files

- `references/design_system.md` — Complete color palette (9 ramps × 7 stops), CSS variables, UI component patterns, metric cards, layout rules
- `references/svg_and_diagrams.md` — SVG viewBox setup, font calibration, pre-built classes, flowchart/structural/illustrative diagram patterns with examples
- `references/chart_js.md` — Chart.js configuration, script load ordering, canvas sizing, legend patterns, dashboard layout

Read the relevant reference file when you need specific design tokens, SVG coordinate math, or Chart.js configuration details.