0014. Icon packs, project assets and the asset lock
Status: accepted (icons-and-assets change, 10 October 2026)
Context
Section titled “Context”icon "<pack>:<name>" was accepted but nothing drew it. The proposal asks for icons referenced by
stable names or by aliases of installed packs, with optical scale, margins and position next to the
label normalised, and measured before layout. It also asks the catalog to keep the version, origin
and licence of every collection, for provider icons to keep their own terms, and for fonts to carry
distribution and embedding permissions. Projects hold assets/icons/, assets/fonts/,
assets/licenses.json and assets.lock.json, and imported SVG must be sanitised and size-limited.
Decision
Section titled “Decision”-
A host-neutral package,
@meltemi/diagrams-assets, holds the parts: icon packs, an SVG sanitiser built on a small strict XML reader, path geometry, the lock format and a portable SHA-256. -
The built-in pack is Tabler (
@tabler/icons3.48.0, MIT), read from its node JSON. Filled variants take a-filledsuffix. Hosts without a file system pass the same JSON through a reader. -
Project packs are Iconify JSON files (
assets/icons/<prefix>.json) or SVG folders (assets/icons/<prefix>/).project.jsonmaps aliases to packs. -
The sanitiser keeps an allow-list:
- shapes, groups and transforms;
- local linear and radial gradients;
- paint, opacity and fill rule;
- limited
style.
It refuses scripts, external references, DTDs and the other elements, and enforces size and complexity limits. Shapes become path data, so renderers only draw paths.
-
Normalisation is per pack. Each pack’s median content share of the view box is scaled to Tabler’s 20 of 24 units, and icons stay centred on their own grid. Per-icon content centring is not used, because it unbalances grid-designed icons.
-
Icons sit left of or above the text (
iconPosition, a token and a style property), before group titles, tag and note text, and in relation label pills. Boxes and overflow checks count them. Monochrome icons takeiconColoror the text colour. -
Every project pack and font needs a licence, from its own metadata or
assets/licenses.json, with aredistributeflag for provider terms. -
Fonts in
assets/fonts/join a project’s font library.OS/2 fsTyperestricted embedding keeps a font for measurement only. -
assets.lock.jsonrecords versions, sources, licences and integrity hashes. When it exists, drift is a warning, which--strictturns into a failure. -
Project compilation checks icon references when the host provides asset services: unknown packs and icons are errors at the written value.
Alternatives considered
Section titled “Alternatives considered”- Bundling Iconify’s full collection: not approved for download, mixed licences, and megabytes of JSON for the few icons a diagram uses.
<use>or<image>references in the SVG: not portable to office applications, and external references are refused by the proposal.- Normalising each icon to its own content box: breaks the balance of icons designed on a grid.
- Hashing assets on every run without a lock: the lock is opt-in, so projects that do not pin assets pay nothing.
Consequences
Section titled “Consequences”ProjectHostgainsreadBinary, and memory hosts accept bytes.- The scene gains radial gradients, gradient units and transforms, and path transforms, opacity and fill rule; the renderer writes them.
- Corpus fonts are generated by
test-support/synthetic-font.ts(CC0), so no third-party font file is added for tests. - Icons of one’s own are added from the editor as a project pack, with its licence and its library entry, since decision 0054.