---
name: varick-charts
description: >
  Build clean, editorial data charts for articles and blogs and deliver them as a
  high-resolution PNG (print/static embeds) or a self-contained interactive HTML
  file (blogs, so charts stay hoverable and toggleable). Use whenever the user
  wants a chart, graph, data viz, leaderboard, standings, benchmark comparison,
  or to "make this data look good" — even without the word "chart" — or pastes
  benchmark numbers/results tables to visualize, or references a prior style
  ("like the FrontierCode charts"). Produces bar, line, area, scatter, donut,
  stacked-bar, ranked-standings charts and tabbed dashboards, plus gradient
  treatments: gradient-stroke lines, area fills, and "gradient-fade" bars with
  lit caps and a threshold pill (the navy re-color of the pink/glowing-bar look),
  and a stacked-vs-gradient toggle. Also fits "make this less plain", "add a
  gradient", or "glowing bars". TYPOGRAPHY IS FIXED: every
  character is Helvetica Neue, Regular (400) or Medium (500) only — never bold,
  never a mono or serif face.
---

# Varick Charts

A skill for turning data into publication-quality charts for articles and blogs.
The look is quiet and editorial: navy-on-white, hairline borders, generous
whitespace, restrained motion. Emphasis comes from **color, weight difference
(400 vs 500), and space** — never from decoration, drop shadows, gradients
(except the one soft area-fill), or heavy chrome.

Two deliverables, one template:

- **PNG** — a static, high-resolution raster (2× by default) for print, slide
  decks, or static blog images. Rendered by screenshotting the HTML, so it is
  pixel-identical to the interactive version.
- **HTML** — a single self-contained file that stays interactive (hover
  tooltips, tab switching, clickable standings rows). This is the default for
  blogs. It has no build step and no local dependencies.

If the user doesn't say which, ask once: "PNG or interactive HTML?" — unless the
context makes it obvious (a blog → HTML; a slide/print asset → PNG).

## The one rule that has no exceptions: typography

**All text is Helvetica Neue, weight 400 or 500 only.** This overrides any other
font habit (including the usual Varick Geist rule). Concretely:

- `font-family: "Helvetica Neue", Helvetica, Arial, sans-serif` everywhere —
  axis ticks, labels, tooltips, legends, titles, numbers, everything.
- `font-weight` is only ever `400` (Regular) or `500` (Medium). **Never** 600,
  700, bold, or `font-weight:bold`. Titles/values use 500; body/sub-labels use
  400. That weight difference is the whole hierarchy.
- **Never** a monospace face. Earlier chart artifacts used a mono face for
  labels and numeric values — do not carry that over. Where you want the
  "label" look, use Helvetica Neue 400, uppercase, with `letter-spacing:0.04em`.
  For aligned numbers use `font-variant-numeric: tabular-nums` (this is a
  numeral feature, not a different font, so it's allowed).
- `font-synthesis: none` so no environment fakes a bold/italic.

If a request seems to need bold for emphasis, express it with color (navy vs
grey) or the 400→500 step instead. Do not reach for 600/700.

## Workflow

1. **Read `references/chart-spec.md`.** It holds the exact tokens, the data
   schema each chart type expects, the full list of chart types with when to use
   each, and the interaction/motion rules. It is the source of truth.
2. **Pick the chart type** from the user's data and intent (see the selection
   guide in the spec). When comparing models/items on one metric → ranked
   **standings** bars. Trend over time → line or area. Distribution → column
   histogram. Two numeric dims → scatter. Parts of a whole → donut. Several
   grouped metrics → grouped/stacked bars. Multiple related views the reader
   should switch between → a **tabbed dashboard** (see the Tabs rule below).
3. **Copy the template** at `assets/chart-template.html` to your working
   directory. It is self-contained: it loads React + Recharts from cdnjs and is
   written in `React.createElement` (no JSX, no Babel), so it runs under strict
   CSP, in any blog, and inside the headless renderer with no eval. It already
   contains the tokens, the Helvetica-Neue-only styling, the Card and Tabs
   components, tooltip/legend/standings primitives, and one worked example of
   every chart type. Replace the `DATA` and `CONFIG` blocks and delete the
   examples you don't need. Edit the marked `EDIT` regions, not the tokens.
4. **Deliver.**
   - **HTML:** hand over the edited `.html` directly. It works offline-capable
     except for the two cdnjs `<script>` tags; if the user needs a fully
     offline file, see "Fully self-contained HTML" in the spec.
   - **PNG:** render it with the bundled script, then hand over the `.png`:
     ```bash
     python scripts/render_png.py my-chart.html my-chart.png --selector "#capture" --scale 2
     ```
     The script uses Playwright/Chromium (`pip install playwright --break-system-packages`
     then `python -m playwright install chromium` if missing). `--selector`
     defaults to `#capture`, the wrapper the template puts around the chart, so
     the PNG is tightly cropped to the chart with no page margin. `--scale 2`
     gives a retina-crisp raster; use `--scale 3` for print.

## Tabs and Cards (required pattern for multi-view charts)

When a visualization has more than one view the reader should toggle between
(e.g. Overview / Analytics / Reports, or Score / Pass rate, or per-subset
leaderboards), use the **shadcn Tabs + Card** pattern. In a React
codebase, that is literally:

```tsx
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

<Tabs defaultValue="overview">
  <TabsList>
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="analytics">Analytics</TabsTrigger>
  </TabsList>
  <TabsContent value="overview"><Card>…chart…</Card></TabsContent>
  <TabsContent value="analytics"><Card>…chart…</Card></TabsContent>
</Tabs>
```

The standalone HTML template ships a **faithful vanilla re-implementation** of
that same `Tabs`/`TabsList`/`TabsTrigger`/`TabsContent` + `Card`/`CardHeader`/
`CardTitle`/`CardDescription`/`CardContent` structure (same DOM roles, same
`data-value`/active semantics, same visual treatment) so the blog version and
the React version look and behave identically. Use it — do not invent a
different toggle. `assets/chart-primitives.jsx` contains the JSX version to drop
into a real React project that already has shadcn `ui/tabs` and `ui/card`.

## Deciding React (.jsx) vs standalone HTML

- The user is embedding in **their own React app** → give them
  `assets/chart-primitives.jsx` adapted with their data, using the real
  `@/components/ui/tabs` + `@/components/ui/card` imports. This matches the
  three prior chart artifacts.
- The user wants a **blog embed or a file they can open** → standalone HTML.
- The user wants a **PNG** → standalone HTML rendered through `render_png.py`.

## Common mistakes to avoid

- **Any bold text, or any mono/serif font.** This is the cardinal error. Re-read
  the typography rule. Hierarchy is 400 vs 500 and navy vs grey, full stop.
- Adding a second accent color beyond the `--chart-*` ramp, gradients, shadows,
  or rounded "card-in-card" nesting. Keep it flat and hairline.
- Animating on every re-render. Enter animation runs once on mount
  (`scaleX`/draw-in), 280–900ms, `cubic-bezier(0.23,1,0.32,1)` or `ease-out`;
  respect `prefers-reduced-motion`. Never animate a keyboard-triggered tab
  switch.
- Fabricating data. If the user gives partial numbers, chart exactly those and
  mark any filled-in values clearly (a `note` on the card), as the FrontierCode
  reconstruction did.

## Files in this skill

- `references/chart-spec.md` — tokens, per-type data schemas, selection guide,
  interaction + motion rules, offline-HTML instructions. Read first.
- `assets/chart-template.html` — self-contained interactive template (React +
  Recharts via cdnjs, `createElement`, no Babel). Copy and fill. One example of
  every chart type + a tabbed dashboard. Includes `GradientLineExample`
  (gradient stroke + fade fill), `GradientBarExample` (fade bars + navy cap +
  TOP 1% pill positioned in the right margin so it never overlaps bars),
  `StackedBarExample`, plus the two McKinsey-style examples:
  `StackedLabeledExample` (segmented columns with inline value+share% labels and
  totals above) and `BubbleExample` (revenue-sized bubbles, category colors, and
  a shaded "golden quadrant").
- `assets/chart-primitives.jsx` — JSX version for real React projects using
  shadcn `ui/tabs` + `ui/card`. Includes the ChartContainer/Tooltip/Legend/
  Standings primitives from the prior artifacts.
- `scripts/render_png.py` — screenshots an HTML chart to a high-res PNG.
