From 7c5d484da9efe5f6d344ef02c8ed7bd7f0afe5fb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 29 Sep 2026 20:48:12 -0400 Subject: [PATCH 1/3] Chart standards: blog posts use ```chart blocks, not Plotly The standards still listed Plotly JSON as the way blog posts embed charts. Since #1231 and #1232 posts use ```chart blocks rendered with Recharts and the ui-kit chart defaults. Document the block types, the CI parse check, the tw: prefix caveat, and screenshotting the live chart for email images. Co-Authored-By: Claude Opus 5.5 --- docs/engineering/skills/chart-standards.md | 39 +++++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/docs/engineering/skills/chart-standards.md b/docs/engineering/skills/chart-standards.md index bda6ac1b7..6085e996b 100644 --- a/docs/engineering/skills/chart-standards.md +++ b/docs/engineering/skills/chart-standards.md @@ -5,7 +5,8 @@ This skill ensures consistent chart styling across PolicyEngine visualizations. ## Chart libraries - **Recharts** (default) — used for all standard charts (bar, line, area, stacked bar) -- **Plotly** (exceptions only) — choropleth maps, hexagonal maps, waterfall charts, blog/notebook embedded JSON +- **Plotly** (exceptions only) — choropleth maps, hexagonal maps, waterfall charts, notebook embedded JSON, and legacy blog posts +- **Blog posts on policyengine.org** — ` ```chart ` blocks, rendered by the website with Recharts and the ui-kit chart defaults (see [Blog post charts](#blog-post-charts)) ## Recharts chart pattern @@ -210,14 +211,14 @@ const description = ( These charts remain on Plotly (`react-plotly.js`): -| Chart | Reason | -| ------------------------------------- | ---------------------------------------------- | -| `USDistrictChoroplethMap.tsx` | No Recharts geo support | -| `HexagonalMap.tsx` | Custom scatter with hex markers | -| `BudgetaryImpactSubPage.tsx` | Waterfall chart (no native Recharts waterfall) | -| `BudgetaryImpactByProgramSubPage.tsx` | Waterfall chart | -| `MarkdownFormatter.tsx` | Blog posts embed native Plotly JSON | -| `NotebookRenderer.tsx` | Notebooks embed native Plotly JSON | +| Chart | Reason | +| ------------------------------------- | ------------------------------------------------------------------------ | +| `USDistrictChoroplethMap.tsx` | No Recharts geo support | +| `HexagonalMap.tsx` | Custom scatter with hex markers | +| `BudgetaryImpactSubPage.tsx` | Waterfall chart (no native Recharts waterfall) | +| `BudgetaryImpactByProgramSubPage.tsx` | Waterfall chart | +| `MarkdownFormatter.tsx` | Legacy posts embed native Plotly JSON; new posts use ` ```chart ` blocks | +| `NotebookRenderer.tsx` | Notebooks embed native Plotly JSON | For these files, continue using the Plotly patterns: @@ -237,6 +238,26 @@ import { />; ``` +## Blog post charts + +Posts draw charts as ` ```chart ` fenced blocks holding a JSON spec. The website's +`website/src/components/blog/BlogChart.tsx` renders them with Recharts, Inter, the +`--chart-*` color tokens, the shared axis, grid, tooltip and legend styles, and the +PolicyEngine watermark. Types: `bar`, `waterfall` (`BlogWaterfallChart.tsx`) and `stateMap` +(`BlogStateMap.tsx`); each file's header comment documents its spec. + +- Put data and labels in the spec, never styling. Pick series colors by token name + (`primary` … `quinary`). +- Do not add matplotlib PNGs or Plotly JSON to new posts. +- `website/src/__tests__/components/blog-chart-posts.test.ts` fails CI when a post's chart + block does not parse. Keep the chart's numbers identical to the tables and text beside it. +- The website builds Tailwind with the `tw:` prefix, so ui-kit components that rely on + unprefixed utility classes render unstyled there. Style blog chart parts inline with the + `:root` token variables (`--chart-1`, `--foreground`, `--muted-foreground`, `--border`, + `--font-sans`). +- For a newsletter or social image of a chart, screenshot the chart as the live post renders + it (headless Chromium at 2x) instead of re-plotting it. + ## Anti-patterns ```tsx From acd6250e1a2f44e38f44633bfdefc6e6a575a996 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 29 Sep 2026 21:00:08 -0400 Subject: [PATCH 2/3] Chart standards: describe stateMap's tile grid, color names, missing types (review) Co-Authored-By: Claude Opus 5.5 --- docs/engineering/skills/chart-standards.md | 43 +++++++++++++--------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/docs/engineering/skills/chart-standards.md b/docs/engineering/skills/chart-standards.md index 6085e996b..258f7db8a 100644 --- a/docs/engineering/skills/chart-standards.md +++ b/docs/engineering/skills/chart-standards.md @@ -6,7 +6,7 @@ This skill ensures consistent chart styling across PolicyEngine visualizations. - **Recharts** (default) — used for all standard charts (bar, line, area, stacked bar) - **Plotly** (exceptions only) — choropleth maps, hexagonal maps, waterfall charts, notebook embedded JSON, and legacy blog posts -- **Blog posts on policyengine.org** — ` ```chart ` blocks, rendered by the website with Recharts and the ui-kit chart defaults (see [Blog post charts](#blog-post-charts)) +- **Blog posts on policyengine.org** — ` ```chart ` blocks, rendered by the website with the ui-kit chart defaults (see [Blog post charts](#blog-post-charts)) ## Recharts chart pattern @@ -211,14 +211,14 @@ const description = ( These charts remain on Plotly (`react-plotly.js`): -| Chart | Reason | -| ------------------------------------- | ------------------------------------------------------------------------ | -| `USDistrictChoroplethMap.tsx` | No Recharts geo support | -| `HexagonalMap.tsx` | Custom scatter with hex markers | -| `BudgetaryImpactSubPage.tsx` | Waterfall chart (no native Recharts waterfall) | -| `BudgetaryImpactByProgramSubPage.tsx` | Waterfall chart | -| `MarkdownFormatter.tsx` | Legacy posts embed native Plotly JSON; new posts use ` ```chart ` blocks | -| `NotebookRenderer.tsx` | Notebooks embed native Plotly JSON | +| Chart | Reason | +| --------------------------------------------------- | ------------------------------------------------------------------------ | +| `USDistrictChoroplethMap.tsx` | No Recharts geo support | +| `HexagonalMap.tsx` | Custom scatter with hex markers | +| `BudgetaryImpactSubPage.tsx` | Waterfall chart (no native Recharts waterfall) | +| `BudgetaryImpactByProgramSubPage.tsx` | Waterfall chart | +| `website/src/components/blog/MarkdownFormatter.tsx` | Legacy posts embed native Plotly JSON; new posts use ` ```chart ` blocks | +| `NotebookRenderer.tsx` | Notebooks embed native Plotly JSON | For these files, continue using the Plotly patterns: @@ -240,17 +240,24 @@ import { ## Blog post charts -Posts draw charts as ` ```chart ` fenced blocks holding a JSON spec. The website's -`website/src/components/blog/BlogChart.tsx` renders them with Recharts, Inter, the -`--chart-*` color tokens, the shared axis, grid, tooltip and legend styles, and the -PolicyEngine watermark. Types: `bar`, `waterfall` (`BlogWaterfallChart.tsx`) and `stateMap` -(`BlogStateMap.tsx`); each file's header comment documents its spec. - -- Put data and labels in the spec, never styling. Pick series colors by token name - (`primary` … `quinary`). -- Do not add matplotlib PNGs or Plotly JSON to new posts. +Posts draw charts as ` ```chart ` fenced blocks holding a JSON spec. +`website/src/components/blog/BlogChart.tsx` parses each block and wraps it in a figure with +title, subtitle, watermark and source line. `bar` (in `BlogChart.tsx`) and `waterfall` +(`BlogWaterfallChart.tsx`) draw with Recharts, Inter, the `--chart-*` tokens and ui-kit's +shared axis, grid, tooltip and legend styles. `stateMap` (`BlogStateMap.tsx`) draws an 11 by +8 tile grid shaded from `--background` to `--primary`. Each file's header comment documents +its spec. + +- Put data and labels in the spec, never styling. Pick series colors by token name: + `primary`, `secondary`, `tertiary`, `quaternary`, `quinary` or `negative`. `positive` maps + to `--success`, which the website does not define, so it falls back to the series palette. +- Do not add matplotlib PNGs or Plotly JSON to new posts. When a post needs a chart type the + website lacks (a line or scatter chart, say), add the type to `website/src/components/blog/` + with tests before the post uses it. - `website/src/__tests__/components/blog-chart-posts.test.ts` fails CI when a post's chart block does not parse. Keep the chart's numbers identical to the tables and text beside it. +- The legacy `app/src/components/blog/MarkdownFormatter.tsx` renders only ` ```plotly ` + blocks; a ` ```chart ` block shows there as raw code. - The website builds Tailwind with the `tw:` prefix, so ui-kit components that rely on unprefixed utility classes render unstyled there. Style blog chart parts inline with the `:root` token variables (`--chart-1`, `--foreground`, `--muted-foreground`, `--border`, From 5f64da717eed4364d801a01d24313a77f8d3296b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 29 Sep 2026 21:04:21 -0400 Subject: [PATCH 3/3] Chart standards: precise legacy formatter note (review nit) Co-Authored-By: Claude Opus 5.5 --- docs/engineering/skills/chart-standards.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/engineering/skills/chart-standards.md b/docs/engineering/skills/chart-standards.md index 258f7db8a..aacb75ac7 100644 --- a/docs/engineering/skills/chart-standards.md +++ b/docs/engineering/skills/chart-standards.md @@ -256,8 +256,8 @@ its spec. with tests before the post uses it. - `website/src/__tests__/components/blog-chart-posts.test.ts` fails CI when a post's chart block does not parse. Keep the chart's numbers identical to the tables and text beside it. -- The legacy `app/src/components/blog/MarkdownFormatter.tsx` renders only ` ```plotly ` - blocks; a ` ```chart ` block shows there as raw code. +- The legacy `app/src/components/blog/MarkdownFormatter.tsx` draws charts only from + ` ```plotly ` blocks; a ` ```chart ` block shows there as a JSON code block labeled `chart`. - The website builds Tailwind with the `tw:` prefix, so ui-kit components that rely on unprefixed utility classes render unstyled there. Style blog chart parts inline with the `:root` token variables (`--chart-1`, `--foreground`, `--muted-foreground`, `--border`,