$npx -y skills add elvisun/newsjack --skill design-systemTurn an eval study's numbers into on-brand, publish-ready figures using the Newsjack chart room (the eval design system), then validate them with Playwright. For producing the charts in a published eval/data study.
| 1 | # Eval Graphics — the chart room |
| 2 | |
| 3 | > **Internal tooling, not a product skill.** This lives in `eval/design-system/` |
| 4 | > and is used by maintainers to publish eval studies. It is **not** a Newsjack |
| 5 | > user skill, must **never** be installed into `skills/`, and is never loaded at |
| 6 | > product runtime. Do not confuse it with the main skills folder. |
| 7 | |
| 8 | You produce **figures** for an eval study: standalone HTML that renders the |
| 9 | Newsjack house chart style, validated by Playwright and screenshotted to PNGs you |
| 10 | drop into a writeup. One grammar — newsprint paper, ink, a single vermilion mark |
| 11 | — across every figure, so a study reads like one publication. |
| 12 | |
| 13 | ## Files you work with |
| 14 | |
| 15 | - `assets/colors_and_type.css` — design tokens (palette, type, spacing). Never |
| 16 | edit; always link. |
| 17 | - `charts.css` — the chart primitives (`.bar-primary`, `.line-base`, `.fig`, |
| 18 | `.stat`, heatmap classes, masthead/section/colophon scaffold). Never edit; |
| 19 | always link. |
| 20 | - `chart-room.html` — the **specimen gallery** of all 9 figure types with |
| 21 | placeholder data. This is your copy-paste source: find the figure that fits |
| 22 | your data, lift its block, swap the geometry and labels. |
| 23 | - `scripts/validate.mjs` — Playwright validator + screenshotter. |
| 24 | |
| 25 | ## The grammar (non-negotiable brand rules) |
| 26 | |
| 27 | These come straight from the design system. Breaking one means the figure is |
| 28 | off-brand: |
| 29 | |
| 30 | - **One chroma.** Vermilion `#E05A47` is the only colour. The highlighted / |
| 31 | winning series is accent; every other series is quiet grey (`--c-base`, |
| 32 | `#E4E0D8`) or an ink wash. **If you reach for a second colour, you've gone |
| 33 | wrong.** No gradients. No emoji. Ever. |
| 34 | - **Paper, not white.** Background is `--nj-page` `#F9F8F6`. Borders are the |
| 35 | hairline `rgba(26,26,26,0.10)`. Cards are 0-radius with a faint editorial |
| 36 | shadow. |
| 37 | - **Type roles.** Figure titles: Newsreader **italic**. Axis ticks, value |
| 38 | labels, legends, eyebrows: IBM Plex Mono, ALL CAPS, ≥0.12em tracking. |
| 39 | Descriptive captions: DM Sans. |
| 40 | - **Value labels float above the bar** (mono, centered over the column). |
| 41 | - **Headline figures are one consistent colour** — the whole numeral *and* its |
| 42 | symbol in the accent (e.g. `+38%`, `4.2×` fully vermilion), via |
| 43 | `<span class="accent">`. |
| 44 | - **Section pattern:** top hairline → mono number + lowercase-italic title (left) |
| 45 | + mono subtitle (right) → content. |
| 46 | |
| 47 | ### Accent strategy — set on `<body>` |
| 48 | |
| 49 | | `data-accent` | Use | |
| 50 | |---|---| |
| 51 | | `winner` (default) | best/highlighted series = accent, others grey. The standard comparison look. | |
| 52 | | `single` | comparisons go all-grey; accent is reserved for one hero mark (a donut, one bar). | |
| 53 | | `mono` | everything ink, no chroma — for a sober, neutral data study. | |
| 54 | |
| 55 | Also `data-grid="on|off"` (gridlines) and `data-barstyle="solid|outline"`. |
| 56 | |
| 57 | ## Pick the figure to fit the data |
| 58 | |
| 59 | | Data shape | Figure (block in `chart-room.html`) | |
| 60 | |---|---| |
| 61 | | Two series across a few benchmarks | **FIG.01 grouped bars** — the flagship | |
| 62 | | One series, ranked by category | **FIG.02 single-series bars** | |
| 63 | | Before → after on sparse metrics | **FIG.03 dumbbell / lollipop** | |
| 64 | | A value over time / scale / versions | **FIG.04 line / scaling curve** | |
| 65 | | Two-axis tradeoff, one point highlighted | **FIG.05 scatter / quadrant** | |
| 66 | | Composition / share across rows | **FIG.06 100% stacked bars** | |
| 67 | | One number that deserves the frame | **FIG.07 donut** | |
| 68 | | Model × task (or any) matrix | **FIG.08 heatmap** (data-driven JS) | |
| 69 | | 2–4 punchy single numbers, no axes | **FIG.09 big-stat callouts** | |
| 70 | |
| 71 | ## How to compute geometry (filling an SVG template) |
| 72 | |
| 73 | The SVGs use plain coordinates inside a `viewBox`. The mapping math you need: |
| 74 | |
| 75 | **Vertical bars (FIG.01/02).** Choose a baseline `yBase` (value 0) and a top |
| 76 | `yTop` (max value). `scale = (yBase - yTop) / maxVal`. For a value `v`: |
| 77 | `barHeight = v * scale`, `barY = yBase - barHeight`, value label at |
| 78 | `y = barY - 12`. (Specimen FIG.01: `yBase=500`, `100→y=120`, so `scale=3.8`.) |
| 79 | |
| 80 | **Dumbbell (FIG.03).** Horizontal axis from `xMin` (value 0) to `xMax` (value |
| 81 | 100). `x(v) = xMin + (v/ (maxVal)) * (xMax - xMin)`. Draw a `.stem` line from |
| 82 | `x(before)` to `x(after)`, a `.dot-base` at before, a `.dot-primary` at after. |
| 83 | |
| 84 | **Line (FIG.04).** `y(v) = yBase - v*scale`; evenly space x across the points; |
| 85 | `.line-primary` for focal, `.line-base` (dashed) for baseline; optional |
| 86 | `.area-primary` polygon closes down to `yBase`. |
| 87 | |
| 88 | **Donut (FIG.07).** `C = 2 * π * r` (specimen `r=104` → `C≈653.45`). For percent |
| 89 | `p`: `d |