@sken-ds/fonts
v0.3.1
Published
Font mechanism + presets for the Sken Design System. Default preset: Inter (sans) + Geist Mono (mono), both OFL-1.1, self-hosted variable WOFF2 with full Latin/Latin-Ext/Cyrillic/Cyrillic-Ext/Vietnamese/Turkish coverage.
Readme
@sken-ds/fonts
Font mechanism + presets for the Sken Design System.
The DS does not decide which typeface a product uses. This package
provides the mechanism (a CSS contract around family names) and
opinionated presets (Inter + Geist Mono, by default). A consumer
that needs a different typeface registers its own @font-face and
overrides the --sken-font-family-* variables — no code change
required.
Architecture
@sken-ds/fonts (this package)
├── public/fonts.css Core mechanism: documents the contract
│ and the override pattern. Declares no
│ @font-face. Ships no font files.
│
├── presets/
│ └── default/ Default. Inter + Geist Mono. OFL-1.1.
│ ├── font-faces.css
│ ├── Inter-Variable.woff2
│ ├── Inter-Variable-Italic.woff2
│ ├── GeistMono-Variable.woff2
│ ├── GeistMono-Italic-Variable.woff2
│ ├── LICENSE-Inter.txt
│ └── LICENSE-GeistMono.txt
│
└── (future) presets/<other>/ Adding a new preset is a folder:
a WOFF2, a font-faces.css, a
license file, and a README. The
system does not pick the brand;
the consumer adds a layer on top.Usage in a consumer
// main.ts — default preset
import '@sken-ds/fonts/css' // core mechanism (no-op for now,
// but documents the override contract)
import '@sken-ds/fonts/presets/default/css' // Inter + Geist Mono @font-face/* In CSS */
body {
font-family: var(--font-family-sans);
}
code,
pre,
kbd,
samp {
font-family: var(--font-family-mono);
}The --font-family-sans and --font-family-mono tokens live in
@sken-ds/tokens (typography.json). They are emitted as --sken-family-sans
as their first slot, so the preset's @font-face and the typography
token always agree on the family name.
Using a custom typeface
/* somewhere early in the cascade */
@font-face {
font-family: 'Acumin Pro Wide';
src: url('/fonts/acumin-pro-wide.woff2') format('woff2');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
:root {
--sken-family-sans: 'Acumin Pro Wide', system-ui, sans-serif;
--sken-family-mono: 'Source Code Pro', ui-monospace, monospace;
}The typography tokens will pick up the new family automatically. You
do not need to import a preset in this case — only register the
@font-face and override the variables.
Why this design
- The DS does not pick a brand typeface. Fonts are a brand decision, made by the consumer (or the consumer's brand team). The DS offers an opinionated default (Inter + Geist Mono) and a clean escape hatch.
- The default covers the worst case. Inter has Greek + Cyrillic + Vietnamese. Geist Mono adds Latin-Ext, Cyrillic-Ext, Turkish on top. We do not ship a preset that silently fails on those scripts, because the failure mode is a blank glyph in a production UI.
- Adding a preset is local. No CSS variable remapping, no token
migration. Drop a folder, declare a
@font-facethat references the same--sken-family-*variables, ship.
Why not Acumin Pro (Legrand's marketing web font)
Acumin Pro is the typeface on legrand.com, but it is a paid Adobe /
Paratype license. Legrand's web license does not cover redistribution
in our own apps or design system. Reusing their WOFF2 directly would
be a license / IP risk. Inter is the open-source UI equivalent and is
the choice the Legrand Care UX team is already using in their
designs (per conversation 2026-07-15).
See also
presets/default/README.mdfor per-preset rationale.docs/FONT-COVERAGE.mdfor the script-coverage matrix and the subsetting strategy.docs/adr/0003-font-presets.mdfor the architecture decision.
