Skip to content

Theme overhaul: 10 ICP-driven templates, curated font picker, theme-editor contract - #811

Merged
rob-gordon merged 6 commits into
devfrom
robgordon/theme-overhaul
Jul 24, 2026
Merged

Theme overhaul: 10 ICP-driven templates, curated font picker, theme-editor contract#811
rob-gordon merged 6 commits into
devfrom
robgordon/theme-overhaul

Conversation

@rob-gordon

@rob-gordon rob-gordon commented Jul 24, 2026

Copy link
Copy Markdown
Member

What this is

Replaces all 13 templates with 10 job-shaped themes built around the diagrams people most often make with Flowchart Fun — decision trees, SOPs/process flows with role lanes, system architecture, knowledge maps, org charts, sitemaps, timelines, and branching narratives. Everything renders through modern stock-Cytoscape techniques (corner-radius cards, round-taxi elbows, underlay shadows/glows, label pills, SVG icon classes, gradient nodes) expressed as pure template data — the parse→render pipeline is untouched.

The lineup

default (also the new sandbox first-load look) · decision-tree (auto-tinted questions, Yes/No edges self-color, merged-outcome pills) · process-lanes (containers as tinted role lanes) · blueprint (dark systems diagrams w/ right-click icon_* classes) · ink-mindmap · constellation · org-chart · sitemap · timeline · storyline

Fonts

  • Picker curated to 8 self-hosted families (all open-license, all woff2 — 1.9MB → <1MB) with SVG-path previews so no font loads until chosen; the closed control shows the selection in its own face.
  • Retired names (IBM Plex Sans, Kalam, …) move to legacyFonts: out of the picker, still loadable — existing charts have them baked into metadata.

Fixes found along the way

  • toTheme: round-taxi now receives taxi-direction like taxi.
  • Font picker submitted the theme-editor form (<button> defaulted to type=submit) — every font pick was a full GET-navigation reload. Pre-existing; fixed.
  • Template CSS can silently pin FFTheme knobs (Cytoscape resolves ties by rule order, not specificity). New theme-editor contract test: 10 templates × 22 knobs against a headless Cytoscape instance — any template rule that breaks a Theme-tab knob fails CI with the knob's name.

Backward compatibility

  • Existing charts are untouched (themes are baked into doc metadata at creation).
  • Documents that predate baked theme metadata get their fallback from a frozen copy of the old default (legacyDefaultTheme.ts), not the evolving default — they keep rendering exactly as their owners last saw them, including on public /p/ links. A freeze-guard test enforces this.
  • Legacy delimiter handling untouched; old /fonts/*.css files kept (old docs @import them directly).

Verification

  • 567 unit tests green (incl. 220 contract assertions + font/legacy guards), app+api typecheck clean.
  • Visual-regression goldens + frozen fixtures regenerated for the new lineup (local suite, two stable runs).
  • E2E specs audited: no assertions on template names, fonts, or default content.
  • Verified in-browser: theme-editor font changes restyle the graph live (the original regression), no reloads, woff2 loads through the FontFace pipeline.

Deploy note: app + api/prompt/choose-template must ship together (template enum comes from shared) — atomic Vercel deploys handle this.

🤖 Generated with Claude Code

rob-gordon and others added 6 commits July 23, 2026 13:58
Rebuilds all templates from a study of the paying customer base
(decision trees + process flows = 78% of payers; swimlane and
timeline demand hand-faked across every persona):

- default (new sandbox first-load look), decision-tree, process-lanes,
  blueprint, ink-mindmap, constellation, org-chart, sitemap, timeline,
  storyline
- modern cytoscape techniques as pure template data: corner-radius
  cards, round-taxi elbows, underlay shadows/glows, edge label pills,
  data-URI SVG icon classes, gradient star nodes
- 7 self-hosted open-license font families (app/public/fonts) wired
  into fonts.ts and the theme editor font picker
- toTheme: round-taxi now receives taxi-direction like taxi
- screenshot script honors E2E_START_URL
- visual regression goldens + frozen fixtures regenerated for the new
  lineup; toTheme characterization baselines updated deliberately

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cytoscape resolves style ties by rule order, not specificity, so a
template cytoscapeStyle rule that sets an FFTheme-controlled property
on a broad selector (node/:childless/edge/:parent) silently pins it and
breaks the matching Theme-tab knob — e.g. changing the font did nothing
because every template shipped a 'node { font-family: ... }' rule.

- remove the node font metric rules (render-neutral: measured sizes are
  only consumed by the [w]/[h] selectors)
- stop overriding parent background-color and edge text-background-color
  in bare rules (the background knob owns these); lane/zone tints remain
  via :parent.color_* classes applied in starter content
- constellation: express star size, border, text color and margin
  through the theme object (useFixedHeight 26, nodeForeground, etc.)
  instead of pinning them in css; drop curve-style override

Adds themeEditorContract.test.ts: for all templates x 22 FFTheme knobs,
composes the full pipeline stylesheet exactly like the app and asserts
against a headless cytoscape instance that changing the knob changes
the computed style of a plain node/edge/parent. Class- and
special-selector styling (color_*, icon_*, degree/label selectors)
stays exempt by construction. Visual goldens, frozen fixtures and
template screenshots regenerated; verified in-browser that picking a
font in the Theme tab restyles the graph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… fonts

- fonts.ts split: 'fonts' (picker: the 7 repertoire sans + Skriva) vs
  'legacyFonts' (IBM Plex Sans, Inclusive Sans, Space Grotesk, Onest,
  Overpass, Kalam, Nanum Pen Script, REM). Legacy names leave the picker
  but stay loadable via allFonts — existing customer charts have them
  baked into meta.themeEditor and must keep rendering unchanged.
- Skriva (single handwritten voice) replaces Kalam + Nanum Pen Script:
  self-hosted otf + css. NOTE: Skriva is a licensed family — confirm the
  webfont license before this deploys publicly.
- font picker previews: scripts/generate-font-previews.mjs
  (pnpm -F app font:previews) pre-renders each picker font's name to an
  SVG path via opentype.js; the dropdown shows the preview image
  (dark-mode via invert) so no font file loads until a font is chosen.
- fonts.test.ts guards the contract: every picker font has a preview +
  css asset; every historical font name still resolves its @import
  through toTheme; no picker/legacy overlap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…load

Three fixes found while polishing the picker:

1. The closed control now overlays the selected font's SVG preview
   (input text goes transparent while not editing), so the selection is
   shown in its own face instead of the UI font. Typing custom font
   names still works — the overlay yields to plain text on focus.

2. Pre-existing bug: FontpickerButton had no type attribute, so picking
   a font SUBMITTED the surrounding theme-editor <form> as a GET
   navigation — a full page reload on every font choice (the change only
   survived via localStorage). Now type="button", plus a preventDefault
   guard on the form itself.

3. generate-font-previews serializes glyph paths by hand: opentype.js'
   Path.toPathData() emitted a literal NaN at certain offsets (Skriva's
   'i' dot), and one bad token makes SVG parsers drop the rest of the
   path — Skriva's preview rendered as 'Skri'. Also composes previews
   glyph-by-glyph (string shaping routed through GSUB alternates that
   opentype.js can't extract) and uses static Satoshi Regular for the
   preview so it isn't rendered from the variable file's heavy default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two mitigations for shipping the theme overhaul:

1. Shipped fonts converted to woff2 (1.9MB of otf/ttf -> 968KB; e.g.
   Satoshi 128KB ttf -> 44KB woff2). The otf/ttf sources stay in
   public/fonts as inputs for generate-font-previews (opentype.js can't
   read woff2) but nothing references them at runtime. fonts.test.ts now
   also verifies every binary referenced by a font css file exists.

2. ~1,700 hosted charts (513 owned by active subscribers) predate baked
   theme metadata; prepareChart backfills a default theme for them on
   open. That fallback is now a FROZEN copy of the pre-overhaul default
   (legacyDefaultTheme.ts) instead of the current default template, so
   existing documents keep rendering exactly as their owners last saw
   them — including on public /p/ links. New documents are unaffected
   (getDefaultChart bakes the current theme at creation). A freeze-guard
   test fails if the fallback is ever re-pointed at the evolving default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Skriva is a commercial family we can't license right now; Shantell Sans
is SIL Open Font License with genuine handwriting character — zero
licensing blockers for deploy.

Self-hosted from the google/fonts repo, instanced down to the weight
axis only (the BNCE/INFM/SPAC novelty axes tripled the file): 2.1MB
source -> 208KB woff2. The weight-instanced ttf stays in public/fonts
as the preview-generator source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flowchart-fun Ready Ready Preview, Comment Jul 24, 2026 12:30am

Request Review

@rob-gordon
rob-gordon added this pull request to the merge queue Jul 24, 2026
Merged via the queue into dev with commit 242a88c Jul 24, 2026
5 checks passed
@rob-gordon
rob-gordon deleted the robgordon/theme-overhaul branch July 24, 2026 00:35
@rob-gordon rob-gordon mentioned this pull request Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant