Data viz: the chart rules Ledger and Almanac practiced become house law

references/data-viz.md: form heuristic first (one value = stat tile never
a one-bar chart, > 7 categories = a table, parts-of-whole = stacked bar
never pie/donut/gauge), hand-built SVG construction specs (bars <= 24px
baseline-zero, 2px lines, 1px solid gridlines never dashed, ONE y-axis
never dual), colour adapted to the one-accent discipline (lightness ramp
on the accent for multi-series, fixed order never cycled; labels never
wear the data colour), honesty riding gate 46 (zero baselines, annotated
zooms, internally consistent sample data), the dark note, and the
dashboard bar: one figure, one chart, one table - the six-gauge KPI wall
is the tell this file kills. Stat-Led, Ledger, Sport, and Almanac point
at it; SKILL.md loads it conditionally.
This commit is contained in:
Youssef
2026-07-31 12:20:15 +01:00
parent e071b5572f
commit dea57c4cbb
6 changed files with 53 additions and 5 deletions
+1 -1
View File
@@ -236,7 +236,7 @@ A custom system is complete (palette + pairing + axes), never a colour swap; its
**Every build:** [`references/typography.md`](references/typography.md) · [`references/color.md`](references/color.md) · [`references/layout-and-space.md`](references/layout-and-space.md) · [`references/motion.md`](references/motion.md) · [`references/copy.md`](references/copy.md) · [`references/anti-patterns.md`](references/anti-patterns.md).
**Conditionally (be honest, no defensive pre-loads):** [`references/microinteractions.md`](references/microinteractions.md) when anything is interactive (most pages); [`references/interaction-and-states.md`](references/interaction-and-states.md) for stateful UI; [`references/responsive.md`](references/responsive.md) when mobile is in scope; [`references/structure.md`](references/structure.md) only when deviating from a named macrostructure; [`references/assets.md`](references/assets.md) only when an enrichment needs an external asset; [`references/texture.md`](references/texture.md) only when the picked theme earns texture (Riso, Carnival, Arcade, faint Newsprint) or a custom draw has print lineage; [`references/scroll-choreography.md`](references/scroll-choreography.md) only when the brief asks for scroll story / cinematic pacing or the macro is Feature-stack / Narrative Workflow; [`references/dark-mode.md`](references/dark-mode.md) only when the user asks for both modes; [`references/custom-theme.md`](references/custom-theme.md) only on the custom route; [`references/design-md.md`](references/design-md.md) only when the user asks to lock the system; [`references/preview-examples.md`](references/preview-examples.md) only if the Step 5 spec is not scaffolding enough.
**Conditionally (be honest, no defensive pre-loads):** [`references/microinteractions.md`](references/microinteractions.md) when anything is interactive (most pages); [`references/interaction-and-states.md`](references/interaction-and-states.md) for stateful UI; [`references/responsive.md`](references/responsive.md) when mobile is in scope; [`references/structure.md`](references/structure.md) only when deviating from a named macrostructure; [`references/assets.md`](references/assets.md) only when an enrichment needs an external asset; [`references/texture.md`](references/texture.md) only when the picked theme earns texture (Riso, Carnival, Arcade, faint Newsprint) or a custom draw has print lineage; [`references/scroll-choreography.md`](references/scroll-choreography.md) only when the brief asks for scroll story / cinematic pacing or the macro is Feature-stack / Narrative Workflow; [`references/dark-mode.md`](references/dark-mode.md) only when the user asks for both modes; [`references/data-viz.md`](references/data-viz.md) when the brief involves charts / data / dashboards or the macro is Stat-Led / Workbench; [`references/custom-theme.md`](references/custom-theme.md) only on the custom route; [`references/design-md.md`](references/design-md.md) only when the user asks to lock the system; [`references/preview-examples.md`](references/preview-examples.md) only if the Step 5 spec is not scaffolding enough.
**At the end only:** [`references/slop-test.md`](references/slop-test.md) strictly at Step 7 (pre-loading it costs thousands of tokens for nothing; `anti-patterns.md` is the pre-emit list); [`references/contract.md`](references/contract.md) at handoff; [`references/export-formats.md`](references/export-formats.md) only on `design.md` projects.
+48
View File
@@ -0,0 +1,48 @@
# Data viz - charts that read as set, not generated
Loaded when the brief involves charts/data/dashboards or the macro is Stat-Led / Workbench. Generalizes what Ledger, Almanac, and Sport already practice: the tabular spine, hairline grids, one quiet series, and the standing ban on decorative dashboards ("no donut walls, no gauge rows, no confetti of KPIs").
## Form first (before any drawing)
| The data is | The form is |
| --- | --- |
| one value | a stat tile (big figure + worded qualifier) - NEVER a one-bar chart |
| 2-5 values compared | a stat row, or horizontal bars |
| a series over time | a line, or a sparkline when it rides inside another component |
| more than ~7 categories | a table (Almanac's home turf) - more colours is not an answer |
| parts of a whole | a stacked horizontal bar - never pie, donut, or gauge (house ban) |
The most underused form is EMPHASIS: one accent series, everything else neutral. If every series is loud, none is.
## Construction (hand-built inline SVG, no chart library)
- **Bars**: <= 24px thick, 2-4px gaps, baseline at ZERO always; rounded only at the data end, <= 2px.
- **Lines**: 2px stroke; markers only at annotated points (>= 6px); a sparkline may fade-fill to transparent (the Ledger move), which is the ONE sanctioned gradient near a chart.
- **Gridlines**: 1px solid `--color-rule`, never dashed, fewer than you think (3-5 horizontal lines); axis lines can be the grid's first line, not a heavier stroke.
- **One y-axis.** Never dual axes - the classic way to fake a correlation. Two series with different units get two small charts (small multiples) instead.
- **No mark shadows, no 3D, no gradients in marks** (the sparkline fade-fill excepted).
- Sparklines inside components: no axes, no grid, no second colour (ledger-01 is the register).
## Colour
Adapted to Hallmark's one-accent discipline (an 8-hue categorical palette would fight everything else on the page):
- **Single series**: the accent.
- **Multi-series**: a LIGHTNESS ramp on the accent hue (L steps of ~12-15%, chroma constant), assigned in a fixed order, never cycled; context/reference series in `--color-muted`.
- **A second hue** only under Full-palette posture, from the declared roles, never invented mid-chart.
- **Text never wears the data colour.** Labels, values, and axis text are `--color-ink` / `--color-muted`; a series is identified by a swatch beside its label, not by dyeing the words.
- **tabular-nums on every numeric surface** (values, axes, tables) - the finish tier checks it.
## Honesty (gate 46 binds here hardest)
- Real numbers, or the labelled-placeholder treatment ("metric to confirm" + a grey block); a fabricated series is worse than an empty slot.
- Bars start at zero; a truncated axis that exaggerates a delta is the numeric version of an invented metric. Annotate a zoomed view explicitly ("axis starts at 94%") when the data genuinely lives in a narrow band.
- Sample data in examples is plausible and internally consistent (totals sum, dates sequence); the stamp notes `data: sample` when it is.
## Dark
Marks re-derive like accents in [`dark-mode.md`](dark-mode.md) (chroma down, L up); gridlines from the dark `--color-rule`; the fade-fill drops to half opacity on dark grounds.
## The dashboard bar
A Workbench/dashboard build shows FEWER, truer figures: one hero figure (stat tile), one supporting chart, one table. The KPI wall with six gauges is the tell this file exists to kill.
@@ -6,7 +6,7 @@ The hero is a giant number — a metric, a count, a percentage. Everything that
- **Body:** sections each anchored by a supporting stat or chart.
- **Divider:** hairline rules between stat blocks; tabular-nums everywhere.
- **Button:** outlined chip aligned beneath the qualifier.
- **Image:** charts and small data-viz; no photography.
- **Image:** charts and small data-viz per [`data-viz.md`](../data-viz.md) (form heuristic + mark specs); no photography.
- **Reveal:** number-tick on the hero figure — counter from 0 to target over ~500 ms.
Reach for it when the brief is "we have proof in numbers" — enterprise/B2B, fundraising platforms, climate or impact pages.
+1 -1
View File
@@ -29,7 +29,7 @@ Works in Progress · Our World in Data · Stripe Press · Low-Tech Magazine · W
1. **Cool slate stock, never `#fff`** - `oklch(84% 0.012 245)`, with `paper-2` (`81%`) for alternating table rows and `paper-3` (`77%`) for the side-rail well and callout blocks. Ink is cool near-black `oklch(16% 0.020 245)`, never `#000` (11.9:1 on the stock); muted meta sits at `oklch(42% 0.016 245)`.
2. **Tables and figures are the hero** - the almanac *is* its data. Hairline-ruled tables with `font-variant-numeric: tabular-nums`, right-aligned numerics, decimals that line up, units in mono. Lead with a data block, an index, or a spec table - never a photograph.
2. **Tables and figures are the hero** - the almanac *is* its data. Hairline-ruled tables with `font-variant-numeric: tabular-nums`, right-aligned numerics, decimals that line up, units in mono (charts, when a table earns one: [`data-viz.md`](../data-viz.md)). Lead with a data block, an index, or a spec table - never a photograph.
3. **Two rule weights, used deliberately** - light hairline `--color-rule` (`oklch(74% 0.012 240)`) draws the grid and row separators; the dark `--color-rule-2` (`oklch(38% 0.018 240)`) draws the one emphatic line under a section head or table `thead`. **No boxed cards, no shadows.** Depth is rules, not blur.
+1 -1
View File
@@ -62,7 +62,7 @@ Composed and near-still. The `LIVE` dot pulses (opacity 1 → 0.4, `2.4s`). Ledg
- **No proportional numerals on figures.** Every balance, amount, and spec value is `tabular-nums` mono; columns align or the theme breaks.
- **No pill / gradient CTAs.** One solid teal button at `--radius-input` (8px) + ghost buttons and `.tlink` typographic links. Name the destination (`Open an account`).
- **No centred-everything hero, no 3-equal-icon feature grid.** Title-left / panel-right; features are a dense datasheet, how-it-works a numbered 01/02/03 trio.
- **No fake dashboard clutter** - one sparkline, one ledger, real-looking sample numbers. No donut walls, no gauge rows, no confetti of KPIs.
- **No fake dashboard clutter** - one sparkline, one ledger, real-looking sample numbers. No donut walls, no gauge rows, no confetti of KPIs. (Chart construction beyond the sparkline: [`data-viz.md`](../data-viz.md).)
## Macrostructure affinity
+1 -1
View File
@@ -33,7 +33,7 @@ The aesthetic: the clinical performance grid, the race-bib crop, the standings t
3. **One blaze-orange signal, < 5% of any viewport.** `oklch(58% 0.190 35)` marks the race-bib number, the one primary CTA, the active fixture, a link underline, the focus ring, the single lane stripe. Everything else is cool grey + ink. Orange-as-text uses `--color-accent-ink`.
4. **The scoreboard: mono tabular numerals, set large.** JetBrains Mono with `font-variant-numeric: tabular-nums` for times, splits, scores, distances, dates. The number is the content and outsizes its label. The stopwatch / standings voice.
4. **The scoreboard: mono tabular numerals, set large** (chart construction, when a figure grows one: [`data-viz.md`](../data-viz.md))**.** JetBrains Mono with `font-variant-numeric: tabular-nums` for times, splits, scores, distances, dates. The number is the content and outsizes its label. The stopwatch / standings voice.
5. **Two-weight rule system, never boxed cards.** Hairline `--color-rule oklch(78% 0.008 250)` at `--rule-hair 1px` rules table rows and fine grids; heavy `--color-rule-2 oklch(36% 0.060 255)` at `--rule-fine 2px` frames the scoreboard and breaks sections. Depth from rules, never soft shadows or card-in-card.