Files
chart-sins/README.md
T
Claude 2e17f8fa59 Scaffold Chart Sins site with Astro + build-time Vega-Lite
Set up the static-site tech stack: Astro 5 with Markdown content
collections, Vega-Lite specs rendered to static SVG at build time
(zero client JS), plain scoped CSS, and a GitHub Pages deploy workflow.

Includes three sample sins (truncated y-axis, dual-axis deception,
pie chart overload), each with a bad and fixed chart spec, plus a
gallery index and per-sin detail pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPEvmMbac2fCvKXpQcovj8
2026-08-05 12:00:29 +00:00

3.4 KiB

Chart Sins

A catalogue of data-visualization sins — for each one: the chart that misleads, why it fools the eye, and the honest version that fixes it.

Built with Astro. Charts are authored as Vega-Lite specs and rendered to static SVG at build time, so pages ship with zero client-side JavaScript.

Tech stack

Concern Choice
Framework Astro 5 (static output)
Content Markdown/MDX via Astro Content Collections
Charts Vega-Lite specs → SVG at build (headless Vega)
Styling Plain scoped CSS + one global stylesheet
Hosting GitHub Pages (via GitHub Actions)
Language TypeScript

Project layout

src/
├── content.config.ts        # typed frontmatter schema for a "sin"
├── content/sins/            # one Markdown file per sin
├── charts/                  # Vega-Lite JSON specs (bad + fixed)
├── components/VegaChart.astro   # build-time Vega-Lite → SVG renderer
├── layouts/BaseLayout.astro
├── lib/charts.ts            # spec lookup + severity helper
├── pages/
│   ├── index.astro          # the gallery
│   └── sins/[...slug].astro # a sin's detail page
└── styles/global.css

Adding a new sin

  1. Author two Vega-Lite specs in src/charts/, e.g. my-sin-bad.json and my-sin-fixed.json.

    Omit $schema, config, and outer width/height tuning you don't need — keep specs focused on the data and encoding.

  2. Create src/content/sins/my-sin.md with frontmatter:

    ---
    title: "My Sin"
    summary: "One-line description shown on the gallery."
    category: "Misleading Scales"
    severity: 3            # 1 (venial) … 5 (mortal)
    tags: ["bar chart"]
    badChart: "my-sin-bad"      # basename in src/charts/, no .json
    fixedChart: "my-sin-fixed"
    date: 2026-08-05
    ---
    
    Prose explaining the sin, why it deceives, and the repentance.
    
  3. npm run dev and check it. The typed schema will flag a mistyped field or a missing chart spec at build time.

Making a chart interactive (opt-in)

Charts are static SVG by default. To make one interactive, render it client-side with vega-embed in a small Astro island (client:visible) on that page only, instead of using <VegaChart>. This keeps the default fast while allowing hover/zoom where a specific sin benefits from it.

Commands

Command Action
npm install Install dependencies
npm run dev Start the dev server at localhost:4321
npm run build Build the static site to ./dist
npm run preview Preview the production build locally

Deployment

Pushing to main triggers .github/workflows/deploy.yml, which builds the site and publishes it to GitHub Pages. Enable it once under Settings → Pages → Build and deployment → Source: GitHub Actions.

The site is configured for the project path https://olehomelchenko.github.io/chart-sins (site + base in astro.config.mjs). If you move to a custom domain, set site to it and remove base.