Working with icons
Search the ~2,850-icon library, match packs to domains, and understand why cloud packs are fetched rather than shipped.
Every device needs an icon, and the ID must exist. There is no fallback and
no fuzzy matching at build time — a wrong ID is a validation error.
Search before you write. Never invent an icon ID. Icon names are not
guessable: it's affinity/tile/switch-multilayer, not
affinity/tile/l3-switch; cisco/switches/layer-3-switch, not
cisco/switch/l3.
Searching
npm run marrow -- icons search firewall
npm run marrow -- icons search "layer 3 switch"
npm run marrow -- icons search wireless --max 40
npm run marrow -- icons search router --json # for scripts and agentsOutput is id — Label (category):
affinity/symbol/firewall — Firewall (symbol)
affinity/tile/firewall — Firewall (tile)
aws/security-identity/aws-network-firewall — AWS Network Firewall (security-identity)
azure/networking/azure-firewall-manager — Azure Firewall Manager (networking)
cisco/capability/firewall — Firewall (capability)Check what's installed:
npm run marrow -- icons packs
# packs root: /path/to/icon-packs
# icons loaded: 2854The ID shape
affinity / tile / switch-multilayer
────┬─── ─┬── ────────┬────────
pack category nameFilenames become the search keywords, which is why descriptive names matter when you add your own pack.
The packs
| Pack | Icons | In repo? | Use for |
|---|---|---|---|
cisco | 973 | yes (Apache-2.0) | On-prem network gear — the default for routers, switches, firewalls |
aws | ~790 | fetched | AWS services and resources |
azure | ~710 | fetched | Azure services |
gcp | ~235 | fetched | Google Cloud — current style lives under gcp/current/… |
k8s | 33 | yes (CC-BY-4.0) | Kubernetes components |
affinity | 107 | yes (MIT) | Vendor-neutral symbols — symbol/ plain, tile/ blue tile |
generic | 5 | yes | Fallback shapes |
Full licensing detail is in Icon packs.
Installing the vendor packs
npm run marrow -- icons fetch # all three, with a consent prompt
npm run marrow -- icons fetch aws --yes # one pack, non-interactiveThese download from AWS's, Microsoft's, and Google's own servers, once per clone. They are gitignored because the vendors permit using the icons in diagrams but not redistributing the libraries — so Marrow can't ship them, and your built HTML files (which embed the icons you actually used) are fine to share. That's the granted use.
If a topology references a pack that isn't installed, validate tells you
exactly that: "pack not installed — run marrow icons fetch <pack>".
Matching packs to domains
The pack you choose is a statement about what kind of thing the device is. Mixing arbitrarily makes a diagram look like a clip-art collage.
- On-prem network gear →
cisco. It has the deepest coverage of real network hardware, and the shapes are the visual language network engineers already read. - Cloud zones → the matching vendor pack. An AWS VPC drawn with Cisco routers is actively misleading.
- Whitebox, mixed vendor, or vendor-neutral →
affinity. Pick eithersymbol/ortile/and stay consistent within a diagram — mixing the two styles looks like an accident. - Kubernetes →
k8s.
Common Cisco picks:
cisco/switches/layer-3-switch
cisco/switches/workgroup-switch
cisco/routers/router
cisco/security/firewall
cisco/servers/file-server
cisco/servers/host
cisco/endpoints/laptopYour own icons
Drop SVGs into icon-packs/<pack>/svg/<Category>/<name>.svg and run npm run marrow -- icons index.
Discovery is automatic — icons index scans every folder under icon-packs/, builds its
manifest.json, and indexes all categories without requiring any configuration edits.
Full walkthrough: Adding an icon pack.
Juniper and Fortinet publish stencils only in Visio format (.vss/.vssx).
Convert via draw.io — import the stencil, export SVG — then drop the results
in. Palo Alto has no public icon library.
Icons in the output
Only the icons a topology actually uses are inlined into its built HTML, as sprite definitions. A diagram with 12 distinct icons carries 12, not 2,850. The output stays self-contained and offline; nothing is fetched when the file opens.