@m4rsh/zilker-fonts
v0.0.1
Published
Small font-subsetting input folder for Zilker
Readme
zilker-fonts
A small Zilker input for self-hosted font families. Each inputs/fonts/*.js module declares its sources, faces, and readable character subsets; the input builds matching WOFF2 assets with subset-font.
Outputs
An inputs/fonts/TradeWinds.js module has UID TradeWinds. Its individual artifacts use fonts:TradeWinds#…; group artifacts use fonts:#….
Each
assets/— a directory object of WOFF2 files, one per face × subset.regular/latin.woff2export const outputs = [ ({ fonts }) => ({ 'public/fonts/TradeWinds/': fonts.get('TradeWinds').then(font => font['assets/']), }), ] // → public/fonts/TradeWinds/regular/latin.woff2metadata.json— serialized family, faces, subsets, and asset URLs.{ "family": "Trade Winds", "path": "TradeWinds", "publicPath": "/fonts/TradeWinds", "faces": [{ "name": "regular", "weight": 400, "style": "normal", "display": "swap" }], "subsets": [{ "name": "latin", "charset": "…", "unicodeRange": "U+20-3B, …" }], "assets": [{ "face": "regular", "subset": "latin", "file": "regular/latin.woff2", "url": "/fonts/TradeWinds/regular/latin.woff2" }] }metadata.js— the same metadata as a default JavaScript export.import TradeWinds from 'fonts:TradeWinds#metadata.js' const critical = TradeWinds.assets.filter(asset => ( asset.face === 'regular' && asset.subset === 'latin' ))preload.js— a default function returning a Zilkhtmlsnippet of preload links.import { html } from 'zilk' import TradeWindsPreload from 'fonts:TradeWinds#preload.js' html`<head>${TradeWindsPreload()}</head>` html`<head>${TradeWindsPreload({ baseUrl: '/type/trade-winds' })}</head>`styles.js— a default function returning a Zilkcsssnippet with@font-faceandunicode-rangerules.import { css } from 'zilk' import TradeWindsStyles from 'fonts:TradeWinds#styles.js' css`${TradeWindsStyles()}` css`${TradeWindsStyles({ baseUrl: '/type/trade-winds' })}`The default
baseUrlis the familypublicPath.
Group
assets/— all family assets under their configuredpath.export const outputs = [ ({ fonts }) => ({ 'public/type/': fonts['assets/'] }), ]With
path: 'trade-winds', this writespublic/type/trade-winds/regular/latin.woff2.metadata.js— a UID-keyedfamiliesobject; valid UIDs are also named exports.import { html } from 'zilk' import families, { TradeWinds } from 'fonts:#metadata.js' const critical = Object.values(families).flatMap(family => family.assets .filter(asset => asset.subset === 'latin' && ['regular', 'roman'].includes(asset.face)) ) const preloads = critical.map(asset => html` <link rel="preload" href=${asset.url} as="font" type="font/woff2" crossorigin> `) TradeWinds.assetsstyles.js— a default function returning CSS for all families, plus astylesobject of individual helpers.import { css } from 'zilk' import FontStyles, { styles } from 'fonts:#styles.js' css`${FontStyles()}` // Override selected family URLs by UID. css`${FontStyles({ baseUrls: { TradeWinds: '/type/trade-winds' } })}` css`${styles.TradeWinds({ baseUrl: '/type/trade-winds' })}`
Inputs
Fonts() scans only inputs/fonts/**/*.js. A module filename becomes its UID;
adjacent TTF/OTF files are imported as local dependencies, not separate Zilker
inputs. Register the input in zilker.js:
import { Fonts } from 'zilker-fonts'
export const inputs = { fonts: Fonts() }Then declare a family in inputs/fonts/RadioCanada.js:
import romanSource from './RadioCanada-VariableFont_wdth,wght.ttf' with { type: 'file' }
import italicSource from './RadioCanada-Italic-VariableFont_wdth,wght.ttf' with { type: 'file' }
export default {
family: 'Radio Canada', // Required CSS family name.
path: 'radio-canada', // Asset directory; defaults to the UID.
publicPath: '/type/radio-canada', // URL in metadata/CSS; defaults to /fonts/<path>.
subsets: {
latin: [
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz',
'0123456789 .,;:!?',
],
},
options: {}, // Optional subset-font options shared by every face.
faces: {
regular: {
font: romanSource,
weight: 400,
style: 'normal', // Defaults to normal.
display: 'swap', // Defaults to swap.
options: { variationAxes: { wght: 400 } },
},
italic: {
font: italicSource,
weight: 400,
style: 'italic',
options: { variationAxes: { wght: 400 } },
},
},
}family, faces, and a non-empty subsets object are required. Face and
subset names become path segments, so keep them URL-safe. A subset is one
character string or an array of strings; the plugin joins it and derives CSS
unicode-range from the actual characters. Name independent sets latin,
cyrillic, or symbols when they should generate separate files.
face.font accepts a Bun { type: 'file' } import (recommended), a Buffer,
an ArrayBuffer, or an object with arrayBuffer(). File sources are read by
the plugin and deduplicated within a family, so multiple faces can share one
variable font source. weight accepts a number or a CSS range such as
'100 800'; pin a variable instance with face options, for example
{ variationAxes: { wght: 700 } }. Family options are applied first and
face options override them; both pass through to subset-font.
The generated format is WOFF2. Every face × subset combination creates one
asset, so keep character sets deliberate and avoid overlap unless duplicate
glyphs are intentional. Ensure publicPath matches the URL where the chosen
assets/ output is published.
See examples/simple for the smallest setup and examples/full for static, variable, group, and manual-preload usage.
