vois-dataviz
Picks the right chart, then builds or reviews dashboards you can trust.
What it does
Vois Dataviz decides how data should look on a screen: which chart, which colors, how filters and date ranges behave, and what the empty, loading and error states say. It builds new charts and dashboards from a decision tree and reviews existing ones against 114 rules, each with a do and a don't. Everything is machine-readable, so an agent can check its own work before anyone else has to.
What you give it
- Screen, ticket, or data question
A dashboard brief, a chart you need to choose a type for, or a plain question like what the viewer needs to see. Say who reads it: an executive, an analyst, or someone watching live state.
- Existing chart or dashboard
A screenshot, a Figma frame, or chart code to review and improve. The skill lists what it could not check from the format you gave it.
What you get back
- Chart spec and form choice
For each visualization: the question it answers, the form the decision tree lands on with alternatives considered, the color job, and a spec checked against the rules before any code is written.
- Dashboard structure and states
A dashboard template, one filter row with date presets and a named comparison, and the loading, four kinds of empty, error, and partial states for every card.
- Review findings
Failures and warnings in a fixed JSON shape, ordered by what excludes or misleads people first, each with the rule, what is wrong on this screen, and the concrete fix.
How to use it
Load the vois-dataviz skill. I'm working on [a dashboard / a chart / a KPI row]. The audience is [executive / analyst / operator]. Pick the right forms and build it, or review this existing screen: [attach screenshot or code].
How it connects
Skills that call into or pair with this one. Click a node to open it. Expand the reference files node to browse them on GitHub.
Get this skill
Download the SKILL.md file and install it in Claude or Cursor.
How to install
- Download the SKILL.md file using the button above.
- Open claude.ai and go to Settings.
- Select Skills from the sidebar.
- Click Add skill and upload the SKILL.md file.
- Give the skill a name and save. Claude loads it automatically when relevant.
Skills installed in Claude persist across conversations. Claude reads the skill when the trigger conditions match your message.
Full skill reference
Vois Data Visualization Skill
A chart is read by people and built by you. This skill makes the result right by construction: it picks the form from the viewer’s job, assigns color by the job it does, builds the states most dashboards forget, and gives you something to check against.
It answers “what should this data look like, and is it honest and usable?” Page structure is vois-patterns, container components are vois-components, token values and motion are vois-tokens, and every word on the screen is righter.
Two modes. BUILD: you’re creating a visualization or dashboard. REVIEW: you’re evaluating or improving an existing one. The steps differ; the rules are the same.
BUILD: the order of work
- Write the spec. One per visualization, following
data/chart-spec.schema.json: the question it answers, the audience, the job, the form. If you can’t write the question, the chart shouldn’t exist[DV-PURPOSE-001]. - Walk the decision tree (below, in full in
references/decision-tree.md). Land on a result node and a form id fromdata/chart-catalog.json. - Check the spec:
node scripts/check-spec.mjs spec.json. Fix every FAIL before you write code.--tree <job>lists the forms a job can reach. - Record the choice. If a
vois_record_component_choicetool is available, call it withjob(the viewer’s question),componentName(such asChartContainer + LineChart),alternativesConsidered(other forms from the tree) andreasoning(the tree result id, e.g.CHART-R-LINE-MULTI). If nothing in the tree fits andvois_report_pattern_gapis available, call it with the closest result asattemptedFallback; otherwise say so in your answer. - Get tokens. Get the chart roles in
references/implementation.mdfrom the workspace tokens (vois_get_tokensif available). Never write a color value, and never invent a missing role: report the gap. - Build from one typed config
[DV-SUSTAIN-001], followingreferences/implementation.md. Build the dashboard fromDASH-*templates and pieces (references/dashboard-patterns.md). - Build the states: skeleton, four kinds of empty, error, refetch, partial
[DV-STATE-001]through[DV-STATE-007]. Copy goes throughrighter. - Check the code:
node scripts/detect.mjs <files>. Then look at it at 320, 640 and 1280px, light and dark, with a keyboard. - Record usage (optional): if
vois_record_rule_usageis available, call it with theDV-*ids you applied (violatedorambiguouswhere they weren’t met). These calls are telemetry; if one is missing or errors, carry on.
REVIEW: the order of work
Follow references/review-protocol.md: inventory, infer each job, check the form against the tree, run the mechanical checks, run the judgment checks in triage order, check the page as a whole, propose the upgrade, report in data/review-output.schema.json. data/review-checklist.json has a symptom to fix playbook for the 20 most common problems. Don’t flag what passes, and list what you couldn’t check.
Decision tree, at a glance
Start with the viewer’s job, not the chart. Full tree with every branch: references/decision-tree.md and data/decision-tree.json.
| The viewer needs to… | Default form | Branch |
|---|---|---|
| Read one number | Stat tile with delta, sparkline if the trend matters. Meter if it’s a ratio against a limit | CHART-Q-SINGLE |
| See change over time | Line (continuous), column (12 or fewer discrete periods), area (volume, zero baseline), step (holds between events) | CHART-Q-TIME |
| Compare or rank categories | Sorted horizontal bar. Top 10 plus Other past about 12 | CHART-Q-COMPARE |
| See parts of a whole | Donut for 3 to 6 parts, stacked bar to compare across groups, sorted bar past 6 | CHART-Q-PART |
| See how two measures relate | Scatter, heatmap for two categories | CHART-Q-RELATE |
| See spread or outliers | Histogram for general audiences; box plot only for analysts | CHART-Q-DIST |
| See stages or flows | Funnel as aligned bars with step conversion; Sankey for 15 or fewer nodes | CHART-Q-FLOW |
| See where | Choropleth for rates only; ranked bar for counts | CHART-Q-GEO |
| Look up exact values | Table, with inline sparklines or bars | CHART-R-TABLE |
Then run the gates on the result: audience, simpler form, series count, scale, table twin, volume.
Quick reference
| Situation | Use | Not |
|---|---|---|
| A single current number | Stat tile with a named delta | A one-bar chart, a 2-slice pie [DV-FORM-003] |
| 2 to 4 series, same unit | Multi-line with a legend and end labels | Dual axis [DV-HONEST-002] |
| Different units or scales | Small multiples with a shared crosshair | Two y-axes on one plot |
| 6 or more series and one is the story | Emphasis: one accent, rest gray [DV-COLOR-009] | Eight hues competing |
| More than 8 groups | Top 8 plus Other, table for the tail [DV-FILTER-007] | A 16-hue stack with ‘+11 more’ |
| Part-to-whole, 3 to 6 parts | Donut with the total in the hole | A 9-slice pie [DV-FORM-004] |
| Bars | Zero baseline, one color for one series [DV-HONEST-001] [DV-COLOR-007] | A truncated axis, a hue per bar |
| Line that curves | Monotone or linear; step for state [DV-HONEST-005] | Natural spline overshoot |
| Current period still open | Hatched bar or dashed line, labeled [DV-HONEST-004] | A cliff that is just an unfinished day |
| Delta on a KPI | Arrow, sign, number, named baseline [DV-CONTEXT-002] | A bare percent, color-only meaning |
| Value is zero because nothing was collected | A ‘collecting data’ state [DV-STATE-002] | A flat zero line [DV-HONEST-008] |
| Trend inside a table row | Axisless muted sparkline [DV-FORM-008] | A mini chart with axes and a legend |
| Date range | Presets first, comparison beside, timezone shown [DV-FILTER-002] | A calendar only |
| Every chart needs reading without sight or color | Text alternative, accessibilityLayer, Chart or Table toggle [DV-A11Y-003] [DV-A11Y-004] | A tooltip as the only readout [DV-A11Y-006] |
Which dashboard?
Walk DASH-Q-TYPE in references/dashboard-patterns.md.
| Reader | Template |
|---|---|
| A leader scanning in 30 seconds | DASH-EXEC |
| An operator watching live state | DASH-MONITOR |
| An analyst asking new questions | DASH-EXPLORER |
| A weekly or monthly narrative that gets exported | DASH-REPORT |
| Users assembling their own widgets | DASH-BUILDER |
| Someone who drilled into one metric | DASH-METRIC-DETAIL |
Reusable pieces: DASH-KPI-TILE, DASH-CHART-CARD, DASH-FILTER-BAR, DASH-DATE-RANGE, DASH-STATE-MATRIX, DASH-TABLE-SPARK, DASH-DRILLDOWN, DASH-TOOLTIP.
The 14 principles
Each one has a full do and don’t list in references/principles.md. The headline:
| Principle | One line | Do | Don’t |
|---|---|---|---|
| DV-PURPOSE Question and audience | One question, one reader | Write the question before the form | Add a chart because the data exists |
| DV-FORM Simplest form | The viewer’s job picks the form | Walk the tree; stat tile for one number | Pie to compare close values; 22-type pickers |
| DV-HONEST Truthful | One honest axis, marked partials | Zero baseline for bars; hatch the open period | Dual axes, spline overshoot, flat zero for missing |
| DV-CLARITY Data, not ink | Remove what doesn’t help reading | Label the end and the extreme | A number on every point; truncated axis titles |
| DV-COLOR Color by job | Identity, magnitude, polarity, status | Tokens in fixed order; entity keeps its color | Hex values; a hue per bar; a 9th hue |
| DV-CONSIST Consistent | Same metric, same look everywhere | One formatter and one period per filter | $1.2M here, 1,200,000 there |
| DV-CONTEXT Framed | Compare, scope, date | Delta against a named period; labeled targets | A bare number; a hidden chart filter |
| DV-A11Y Accessible | Works without color, mouse, sight, motion | Text alternative, table twin, 3:1 marks | Tooltip as the only readout; red and green alone |
| DV-INTERACT Interactive | Crosshair, shared tooltip, legend toggle | Visible click affordance, one card menu | Needing to hit a 2px line |
| DV-FILTER One slice | One row of filters above the cards | Presets, comparison, URL state | Per-card pickers; skeleton flash on refetch |
| DV-STATE Every state | Loading, empty (4 kinds), error, stale | Skeleton in final geometry | Full-page spinner; one generic ‘No data’ |
| DV-LAYOUT Hierarchy | Filters, hero KPIs, trend, breakdowns, table | One card anatomy | A grid of equal-weight cards |
| DV-SUSTAIN Built for live data | Typed config, ugly cases handled | One config feeds chart, table and export | Hardcoded demo data |
| DV-IMPL Vois stack | Primitives, tokens, accessibility defaults | shadcn Chart with a typed config | Inline colors, fixed pixel widths |
Non-negotiables
These are required rules a reviewer will FAIL. Everything else is a WARN with a fix.
- One y-axis per chart
[DV-HONEST-002]; bars and areas start at zero[DV-HONEST-001]. - Categorical hues in fixed order, never cycled, eight at most
[DV-COLOR-003]; chart colors are tokens[DV-COLOR-001]; an entity keeps its color[DV-COLOR-004]. - Color is never the only signal
[DV-A11Y-001]; marks 3:1 and text 4.5:1[DV-A11Y-002]. - Every chart has a text alternative and a table view
[DV-A11Y-003][DV-A11Y-004]; tooltips enhance and never gate[DV-A11Y-006]. - Partial periods, forecasts and missing data look different from the real thing
[DV-HONEST-004][DV-HONEST-008]. - Every KPI has a delta against a named period
[DV-CONTEXT-002]. - One filter row above what it scopes, and every card obeys it
[DV-FILTER-001][DV-FILTER-004]. - Skeleton in final geometry on first load, held frame on refetch, errors isolated to the card
[DV-STATE-001][DV-FILTER-008][DV-STATE-003]. - No hardcoded data in a chart component
[DV-SUSTAIN-005].
Taste dials
When the project defines the three taste dials in VOIS.md or DESIGN.md: DENSITY moves the per-view cap from about 6 to 8 up to 10 visualizations and allows analyst forms for analyst audiences; MOTION never exceeds 300ms and always yields to reduced motion [DV-A11Y-008]; VARIANCE can vary card composition but never the form choice or any honesty rule. Dials tune within the rules, never against them.
Reference files
Generated from data/*.json by scripts/build-reference.mjs, so they can’t drift:
| File | Use it for |
|---|---|
references/principles.md | Do’s and don’ts for each principle, and all 114 rules with do, don’t, check and evidence |
references/decision-tree.md | The full chart-selection tree with a diagram per branch and the gates |
references/chart-catalog.md | 48 forms: when to use, when not, baseline, limits, color job, build hint |
references/dashboard-patterns.md | Six page templates and eight reusable pieces |
references/evidence.md | 57 real-product screens from Mobbin: what to adopt, what to avoid |
Written by hand:
| File | Use it for |
|---|---|
references/implementation.md | Chart token roles, shadcn Chart and Recharts code, states, table twin, MCP calls |
references/review-protocol.md | How to review and improve existing work, with a worked example |
references/sources.md | What each source contributed, and what wasn’t read |
Structured data (query these instead of scanning prose)
| File | Keyed by | Holds |
|---|---|---|
data/dataviz-rules.json | DV-<AREA>-NNN | 14 principles and 114 rules: severity, enforcement, do, don’t, check, sources, evidence |
data/decision-tree.json | question and result node ids | The tree as a graph, job entry points, gates |
data/chart-catalog.json | FORM-* | 48 forms with fit, audience, baseline, color job, build hint |
data/dashboard-patterns.json | DASH-* | Templates and pieces: structure, components, rules, evidence |
data/evidence.json | MOB-NN | Mobbin observations with lesson and rule ids |
data/review-checklist.json | Review steps, severity map, triage order, fix playbook, the loop checklist | |
data/chart-spec.schema.json | The spec you fill in before coding | |
data/review-output.schema.json | The shape of a review |
Source of truth. The JSON is canonical and the generated references restate it. scripts/dataviz.test.mjs fails CI if an ID in prose has no JSON entry or the reverse.
Scripts
| Script | Does |
|---|---|
scripts/check-spec.mjs <spec.json> | Checks a chart spec: the 9 spec rules plus form-versus-job reachability in the tree |
scripts/check-spec.mjs --tree <job> | Lists every form a job can reach |
scripts/detect.mjs <files> | Finds the 15 auto rules in chart code (13 detectors). Add // dataviz-allow: <detector> for a deliberate exception |
scripts/build-reference.mjs [--check] | Regenerates, or checks, the generated references |
scripts/dataviz.test.mjs | 58 tests: detectors, spec checker, data integrity |
Relationship to other skills
vois-patterns first. It decides that the screen is a dashboard or contains data. Come here for what’s inside it.
vois-components (JOB-VISUALIZE-DATA) routes data jobs here, then picks the containers: Card, Tabs, Popover, Calendar, Table, Skeleton.
vois-tokens supplies live token values, motion and hit-area rules. This skill adds chart roles on top and cites DS-A11Y-001, DS-A11Y-002, DS-ANIMATION-001 and DS-ANIMATION-004.
righter writes every title, subtitle, tooltip label, empty state and error. This skill says what the state is, never the words.
metrics-tagging instruments chart interactions (range change, legend toggle, drill-down, export) when asked.
design-rationale explains why a form or color choice is right when someone pushes back.
Checklist before handoff
- Spec written for each visualization and
check-spechas no FAIL - Form reached through the tree (and
vois_record_component_choicecalled, if available) - Colors are chart tokens in fixed order, checked per mode
- Text alternative,
accessibilityLayer, table view, keyboard path - Tooltip and crosshair, legend for 2 or more series, drill-down affordance
- One filter row with date presets and a named comparison
- Skeleton, four empty cases, error, refetch and partial states built
-
detect.mjsrun and clean, or each finding justified - Checked at 320, 640 and 1280px, light and dark
-
vois_record_rule_usagecalled, if available