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.

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 agents

Output 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: 2854

The ID shape

  affinity / tile / switch-multilayer
  ────┬───   ─┬──   ────────┬────────
   pack     category      name

Filenames become the search keywords, which is why descriptive names matter when you add your own pack.

The packs

PackIconsIn repo?Use for
cisco973yes (Apache-2.0)On-prem network gear — the default for routers, switches, firewalls
aws~790fetchedAWS services and resources
azure~710fetchedAzure services
gcp~235fetchedGoogle Cloud — current style lives under gcp/current/…
k8s33yes (CC-BY-4.0)Kubernetes components
affinity107yes (MIT)Vendor-neutral symbols — symbol/ plain, tile/ blue tile
generic5yesFallback 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-interactive

These 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 gearcisco. 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-neutralaffinity. Pick either symbol/ or tile/ and stay consistent within a diagram — mixing the two styles looks like an accident.
  • Kubernetesk8s.

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/laptop

Your own icons

Drop SVGs into icon-packs/<pack>/svg/<Category>/<name>.svg, add the pack to the gen:icons script in package.json, and run npm run gen:icons. Discovery is automatic — every directory under icon-packs/ with a manifest.json is loaded. Full walkthrough: Adding an icon pack.

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.