Chart theming: user font upload (FontFace-from-IndexedDB) + variable-font weight support

This commit is contained in:
2026-06-16 21:41:04 +03:00
parent 713f396c5c
commit 5d3aba608a
20 changed files with 1191 additions and 40 deletions
+22 -4
View File
@@ -162,10 +162,20 @@ ships, it is an explicit per-font user action, never automatic.
subset of the UI Plex Sans/Mono, and runtime-caches the rest (latin-ext + non-latin)
CacheFirst so a script works offline after first use. Roster picked from a visual
specimen. Not done here: theme↔font pairing metadata (a suggestion nicety, deferred).
6. **User font upload** — FontFace-from-IndexedDB tier; theme entity's `fonts` field
carries `{ family, source: 'file' }`.
7. **Deferred** — Google Fonts opt-in tier; SVG export font embedding; built-in
expressive preset gallery ("Editorial", "Terminal", "Sketch") showcasing the roster.
6. **User font upload** ✅ (2026-06-16) — `FontAsset` (`core/font-asset.ts`) + the `fonts`
store @ DB v3, registered as a `FontFace` at startup so the render gate resolves user
faces like the roster (full entity-store stack: adapter/migration, `FontStore`,
`font-persistence`, `services/fonts`; arch 05 → User-uploaded fonts). The Type panel
offers uploads ahead of the roster. **Variable fonts** are supported: `parseFontAxes`
reads `fvar` (uncompressed ttf/otf) and the face registers with `wght`/`wdth` ranges, so
one file drives the whole weight range — only weight/width survive Vega's text rendering
(no `font-variation-settings` hook). No `CustomTheme.fonts` field: a used face is derived
by scanning configs/specs (`collectFontFamilies`) — the config is the
source of truth, and snippets use fonts with no theme to carry a field. Not done here:
embedding font bytes into the §08 export + SVG export (shared base64 machinery, with item 7).
7. **Deferred** — Google Fonts opt-in tier; SVG export font embedding (+ §08 font-byte
round-trip, shared machinery); built-in expressive preset gallery ("Editorial",
"Terminal", "Sketch") showcasing the roster.
**Rejected:** per-snippet theme field (2026-06-12 — `spec.config` + merge/extract covers
it without a second mechanism).
@@ -224,6 +234,14 @@ the app standardizes on v6.
## 6. Status log
- **2026-06-16 (slice 6)** — **user font upload + variable-font weight support.** New
`FontAsset` entity (instance #4 of the entity-store kind, confirmed by an eng-council
pre-build consult): `fonts` store @ DB v3, adapter/migration, `FontStore`,
`font-persistence`, `services/fonts`, and the `font-faces` `FontFace`-registration seam
wired into `startup`. Type panel gains an upload control + a managed list; user fonts lead
the dropdown. Variable fonts parse `fvar` and register with `wght`/`wdth` ranges (weight
is the only axis Vega's text rendering can drive). Font dependencies are derived from the
config at export, not stored on the theme. Deferred: font bytes in the §08/SVG exports.
- **2026-06-14 (Color panel bugfix)** — **scheme picks rendered blank.** A named scheme
was written into `config.range.*` as a bare string, which vega-lite compiles but Vega
rejects at render ("Unrecognized scale range value") — silently caught by the gallery's