The OG image generators in core/images.py (create_branded_og_image, create_og_collage, create_compare_image, _draw_branded_header) still use the old visual identity — flat light background ANYPLOT_BG = "#f8f9fa", plain logo strip, no link to the design language we now use across /, /specs, /palette, /map.
These OG images are what shows up when an anyplot URL is shared on Slack / Twitter / LinkedIn / WhatsApp, so they should match the rest of the brand.
Affected endpoints (in api/routers/og_images.py)
GET /og/home.png — currently serves the static api/static/og-image.png
GET /og/plots.png — same static fallback
GET /og/{spec_id}/{language}/{library}.png — branded single-implementation card via create_branded_og_image
GET /og/{spec_id}.png — multi-library collage via create_og_collage
- (compare/diff variants via
create_compare_image)
What "new style" means here
The patterns we've settled on across the React app:
- Background / ink tokens matching the site theme — the cream
#FFFDF6 / dark #0a0a08 surface, var(--ink) / var(--ink-soft) for type
- Okabe-Ito palette (
#009E73, #D55E00, #0072B2, #CC79A7, #E69F00, #56B4E9, #F0E442 + ink) for any colored chips / accents — same CLUSTER_COLORS we use on /map
- Typography: serif for the lede / titles (Domine), MonoLisa for code-shaped labels (
spec-id, library.method()-style hints) — already loaded server-side
- Layout idioms that the site uses:
❯ section chevron, library.foo() method chips with the colored 8x8 square, dotted-underline links in body copy
- Spec/lib labels as method-call style chips (e.g.
matplotlib.scatter() rather than the current header strip)
Things to decide while implementing
- Should the static fallback
api/static/og-image.png be regenerated from the new template or stay as a hardcoded asset?
- Cache invalidation: existing OGs are cached by
cache_key — bumping a version in the cache key should be enough to force a refresh after deploy.
- Make sure the compare-image variant (used by
/og/{spec_id}/{language}/{library}.png?) reads consistently with the rest.
Done when
- All five
/og/*.png endpoints render in the new visual style on a fresh request
core/images.py exposes the same public function signatures (no router changes needed)
- Manual smoke: paste a few anyplot URLs into a Slack DM / X post, confirm the cards look on-brand
- Cache key bumped so the deploy cycles old images out
The OG image generators in
core/images.py(create_branded_og_image,create_og_collage,create_compare_image,_draw_branded_header) still use the old visual identity — flat light backgroundANYPLOT_BG = "#f8f9fa", plain logo strip, no link to the design language we now use across/,/specs,/palette,/map.These OG images are what shows up when an anyplot URL is shared on Slack / Twitter / LinkedIn / WhatsApp, so they should match the rest of the brand.
Affected endpoints (in
api/routers/og_images.py)GET /og/home.png— currently serves the staticapi/static/og-image.pngGET /og/plots.png— same static fallbackGET /og/{spec_id}/{language}/{library}.png— branded single-implementation card viacreate_branded_og_imageGET /og/{spec_id}.png— multi-library collage viacreate_og_collagecreate_compare_image)What "new style" means here
The patterns we've settled on across the React app:
#FFFDF6/ dark#0a0a08surface,var(--ink)/var(--ink-soft)for type#009E73,#D55E00,#0072B2,#CC79A7,#E69F00,#56B4E9,#F0E442+ ink) for any colored chips / accents — sameCLUSTER_COLORSwe use on/mapspec-id,library.method()-style hints) — already loaded server-side❯ sectionchevron,library.foo()method chips with the colored 8x8 square, dotted-underline links in body copymatplotlib.scatter()rather than the current header strip)Things to decide while implementing
api/static/og-image.pngbe regenerated from the new template or stay as a hardcoded asset?cache_key— bumping a version in the cache key should be enough to force a refresh after deploy./og/{spec_id}/{language}/{library}.png?) reads consistently with the rest.Done when
/og/*.pngendpoints render in the new visual style on a fresh requestcore/images.pyexposes the same public function signatures (no router changes needed)