mirror of
https://github.com/olehomelchenko/chart-sins.git
synced 2026-08-08 02:22:43 +00:00
458ccaeb17
Titles are scanned in the gallery and recognized in a link, so they should say what the sin is rather than pun about it. Retitles the three published sins and the backlog's working titles, and records the rule in CLAUDE.md: the title names the problem, the poke carries the voice. Filenames are untouched, so existing URLs still resolve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ULE5RRxdQE1ebwefEd2eCM
5.7 KiB
5.7 KiB
Chart Sins — working notes
Conventions and gotchas for anyone (human or agent) working in this repo. Keep this current when a convention changes.
What this is
Chart Sins is "nohello.net for bad charts." The unit of value is a single, linkable, cited page you send someone instead of re-explaining, for the hundredth time, why their chart misleads. The gallery is secondary; the per-sin page is the product.
Each sin page follows one shape: poke → proof → why → the fix → receipts → share.
Voice & content conventions
- The title names the problem plainly; the poke carries the voice. A title is a label someone scans in the gallery and recognizes in a link — write "Truncated Y-Axis on a Bar Chart," not "The Truncated Temptation." Use the field's standard term for the sin where one exists. Save the wit for the poke; that's what it's for.
- The poke names the general sin, never the sample's specifics. A visitor didn't "start the axis at 90" — they mis-set the baseline. Write "Your bars don't start at zero…", not the numbers from our example data.
- Tone: cheeky, not moralizing. "Caught — here are the receipts," not "repent." Poke the mistake, keep it light.
- Same numbers, both charts. The bad and fixed charts must share one dataset so the page proves dishonest-vs-honest by construction. Charts are authored as Vega-Lite specs and rendered at build time — never screenshots.
- The bad chart is intentionally wrong; the fixed chart must obey the rules.
(e.g. the dual-axis "sin" deliberately breaks the one-axis rule; its fix uses
separate honest panels.) When picking chart colors or building a new chart,
run the
datavizskill and validate the palette with its validator. - Citations are core. Every sin cites the canon (
src/lib/references.ts) under "Don't take our word for it." Don't invent authority — point at it. - Internal build decisions stay out of visitor-facing content and the DOM. The design system (Carbon), the typeface (IBM Plex), and the inspiration (nohello.net) are engineering choices — they must not appear in page copy, the footer, meta tags, or CSS class names on the public site. (They were scrubbed once already; keep them out.) Naming them here, in repo docs, is fine.
Adding a sin
- Author two Vega-Lite specs in
src/charts/, e.g.my-sin-bad.jsonandmy-sin-fixed.json. Same underlying data in both. Omit$schema/config; explicitwidth/heightare fine. The bad one breaks a rule on purpose; the fixed one is correct. - Add
src/content/sins/my-sin.mdwith frontmatter (schema insrc/content.config.ts):title, summary, poke, category, severity (1–5), tags[], badChart, fixedChart, date, draft, citations: [{ key, note }]badChart/fixedChartare the spec basenames (no.json).citations[].keymust exist insrc/lib/references.ts(build throws otherwise). - New reference? Add it once to
src/lib/references.ts, then cite its key. npm run devand check. The OG card for the sin is generated automatically.
Design & rendering
- Astro 5, static output, zero client JS — the one exception is the small progressive-enhancement copy-link script on the sin page.
- Styling is a token layer (
src/styles/global.css) built on Carbon design tokens: layered light/dark themes, 8px spacing scale, IBM Plex (self-hosted via@fontsource), square geometry, a 2px focus ring. Class prefix issite-(notcds-). - Charts render to static SVG at build via the shared pipeline in
src/lib/renderChart.ts(used by both the on-page component and the OG generator, so they stay identical). Charts sit on a fixed light canvas (--chart-canvas) in both themes so the single baked SVG keeps AA contrast. - The categorical palette is Carbon's data-vis palette, validated for colorblind-safety/contrast on the chart surface. Re-validate if you change it.
OpenGraph cards
- Per-sin 1200×630 cards are generated at build time — no browser.
src/lib/og.tscomposes withsatori, rasterizes with@resvg/resvg-js; endpoints aresrc/pages/og/[slug].png.tsandog/default.png.ts. - Card content stays lean: poke + before/after charts + severity + category. No citation list on the card (that lives on the page).
- Fonts: three IBM Plex TTF weights are committed under
src/og/fonts/(satori and resvg need real font files; the@fontsourcewoff2 won't do). - satori gotchas (all learned the hard way): empty
<div>s in a flex row each need their owndisplay:flex; don't put a quotedfont-familyin an inlinestyle(it breaks the style parse — set the default font via satori'sfontsinstead); trim the markup so there's a single root node; give<img>dimensions in thestyleas px; cap charts by height so tall vconcat charts don't overflow.
Deploy & ops
- GitHub Pages via
.github/workflows/deploy.yml, triggered on push tomain(plusworkflow_dispatch). Project path is configured inastro.config.mjs(site+base→/chart-sins). - Known gotcha — the default branch. The repo's default branch is currently
the feature branch (it was the first branch pushed into the empty repo). The
auto-created
github-pagesenvironment only allows deploys from the default branch, so a push tomainbuilds but the deploy job is rejected. Until this is fixed we deploy by dispatching the workflow on the default branch. Fix: set the default branch tomain(Settings → General); then plain pushes tomaindeploy normally and this note can go away. - Pages had to be enabled manually once (Settings → Pages → Source: GitHub Actions) — the Actions token can't create the Pages site itself.