| name | visualize |
| description | Turn data, concepts, or processes into a polished standalone visualization — chart, table, diagram, dashboard, KPI scorecard, timeline, or explainer — written as self-contained code, saved locally, and exported to an image at a 16:9 aspect ratio by default (any ratio on request). Use whenever the user wants to visualize, chart, graph, plot, diagram, or "show" numbers / metrics / a report / a comparison / a breakdown / a trend / a timeline / a flow; pastes a report or table and wants it turned into a graphic; or asks for an infographic, dashboard, scorecard, or a shareable picture of data. Also use for "make this a visual", "render this", "turn this into a chart/graph", or "export a diagram". Do NOT use for editing existing raster images (photo retouching), for a plain in-conversation markdown table with no image export, for live embedded app UI components (use a frontend skill), or for full slide decks (use pptx). |
Visualize
Turn an input — pasted data, a report, a set of numbers, a concept, or a process — into a single, polished visualization, saved as self-contained code and exported to an image at 16:9 by default (any aspect ratio on request).
The design ethos is borrowed from generative UI: read the input, pick the right representation (don't default to a bar chart for everything), and render one self-contained artifact that looks intentional, not auto-generated.
What every run produces
Inside ./visualizations/<slug>/ (relative to the user's working directory unless they give a path):
index.html — the self-contained source (open in any browser, edit by hand)
<slug>.png — the rendered image, 1600×900 (16:9) at 2× scale by default
Always end by telling the user both paths and surfacing the PNG.
Workflow
Follow these in order. Each step links to detail only where you need it.
1. Read the input and choose the representation
Match the input to a representation using the decision matrix below. The single most common mistake is reaching for a bar chart when the data wants something else — a few big numbers want a KPI scorecard, a part-to-whole wants a donut, a ranking wants horizontal bars, a process wants a diagram, raw rows want a styled table. Pick deliberately.
| The input is… | Best representation | How to build it |
|---|
| A few headline numbers / metrics | KPI scorecard (big-number cards) | HTML + CSS |
| Categories compared in size / a ranking | Bar chart (vertical or horizontal) | inline SVG |
| A value changing over time / a trend | Line or area chart | inline SVG |
| Parts of a whole (≤6 slices) | Donut / pie + legend | inline SVG |
| Several series across periods (daily/weekly/monthly) | Grouped bars or small multiples, or a scorecard + bars combo | inline SVG + CSS grid |
| Rows of structured records | Styled data table | HTML + CSS |
| A two-variable relationship | Scatter / bubble | inline SVG |
| A process, flow, pipeline, or architecture | Diagram (nodes + connectors) | inline SVG |
| A sequence of dated events | Timeline | inline SVG + CSS |
| Hierarchy / nesting | Treemap or indented tree | inline SVG |
| An abstract concept needing explanation | Annotated explainer (labels + arrows over a diagram) | HTML + SVG |
| Genuinely interactive code deliverable, or 100+ data points | Chart.js (escalation) | CDN, see recipes |
| 3D scene | Three.js (escalation) | CDN, see recipes |
When the input has multiple natural cuts (e.g. the social-analytics example with Daily / Weekly / Monthly across platforms), prefer one composed layout — a header KPI row plus a small set of comparison charts — over three disconnected charts. A dashboard reads as one artifact; three loose charts read as three.
Default to inline SVG + HTML/CSS. It renders pixel-crisp at any resolution, needs no network, and never half-draws during export. Only escalate to Chart.js / Three.js when interactivity in the openable HTML or sheer data volume genuinely calls for it (see references/recipes.md).
2. Set up the output folder
Pick a short kebab-case <slug> from the subject (e.g. social-analytics, q4-revenue, auth-flow). Create ./visualizations/<slug>/.
3. Author index.html
Start from the template — it gives you a correct 16:9 stage, light/dark theming, web-safe typography, and the export-ready signal already wired:
cp <this-skill>/assets/stage.html ./visualizations/<slug>/index.html
Then fill it in (the template has labelled FILL: regions):
- Title / subtitle / source — a real headline, not "Chart". Include the period or date range if the data has one. Put any attribution in the footer slot.
- The viz — replace the
#viz region with your representation. Build charts as inline SVG using the recipes; lay out scorecards/tables with CSS grid/flex.
- The data — transcribe the user's numbers exactly. Double-check every figure against the input; wrong numbers make the whole artifact worthless. Don't invent data to fill space.
- Signal ready — call
vizReady() once the final frame is painted (the template auto-calls it after fonts load + two animation frames, so you only need to call it manually if you draw asynchronously, e.g. a Chart.js onComplete).
Design bar (see references/recipes.md for the full checklist and snippets):
- Fill the stage — no large empty margins, no tiny chart marooned in a sea of background.
- Type scales with the stage using
clamp() / cqmin units (already set up), so it stays legible at any export size.
- A restrained palette: one accent hue + neutrals, or the provided categorical ramp. Avoid rainbow defaults.
- Label directly where you can (value labels on bars, end-of-line labels) instead of forcing the eye to a distant axis.
- Whitespace, alignment, and a clear visual hierarchy (title → key numbers → supporting detail) do most of the work.
4. Export to an image
From the visualization folder (or anywhere, with absolute paths):
node <this-skill>/scripts/render.mjs --in index.html --out <slug>.png
Default output is 1600×900 @2× (16:9). The aspect ratio is fully modifiable:
# A square for Instagram
node <this-skill>/scripts/render.mjs --in index.html --out sq.png --aspect 1:1 --width 1080
# A tall story / phone frame
node <this-skill>/scripts/render.mjs --in index.html --out story.png --aspect 9:16 --width 1080
# Exact pixels
node <this-skill>/scripts/render.mjs --in index.html --out big.png --width 2560 --height 1440
# Transparent background, dark theme
node <this-skill>/scripts/render.mjs --in index.html --out t.png --bg transparent --theme dark
Flags: --aspect (16:9 default, 4:3, 1:1, 9:16, 21:9, 3:2, 2:1), --width/--height (px; give either with --aspect, or both for exact), --scale (DPI multiplier, default 2), --theme (light|dark), --bg (white|transparent|#hex). Full reference: references/recipes.md.
The stage fills the viewport, so one index.html exports cleanly at any ratio. For a drastically different ratio (e.g. designing for 16:9 then exporting 9:16), glance at the result and re-tune the layout if elements crowd or strand — don't assume a 16:9 composition is automatically good as a vertical.
5. Deliver
Confirm the PNG was written, then report the saved index.html and .png paths and surface the image to the user. If the render step failed, see Troubleshooting before reporting success — never claim an image exists without confirming the file.
Troubleshooting the render
render.mjs tries, in order: Playwright with installed Chrome/Edge, then Playwright's bundled Chromium, then a system Chrome/Chromium/Edge/Brave binary directly. One of these is present on most machines. If all fail it prints the exact fix; relay it. The usual one-time install:
npm i -D playwright && npx playwright install chromium
If a chart exports half-drawn or blank, the ready signal didn't fire before capture — make sure asynchronous drawing calls vizReady() on completion, or pass --wait 8000 to give it more time.
Reference
references/recipes.md — copy-paste SVG/CSS recipes (bar, line, area, donut, scatter, KPI cards, table, diagram, timeline), the Chart.js / Three.js escalation patterns, the full design checklist, and every render.mjs flag.
assets/stage.html — the 16:9 stage template you copy in step 3.