Icons
8-BitQuest ships two icon systems, and the split is deliberate. <Icon> is a large, general-purpose line-icon registry — 571 icons behind one typed component. <PixelIcon> is a small hand-ported pixel-art set used where the retro identity needs a chunky, crisp-edged glyph. Both are inlined at build time, so no icon bytes reach client JavaScript, and both follow the same primitive contract as the rest of the UI library.
<Icon> — the main registry
src/components/svg/icons/ holds one auto-generated registry of 571 icons (~450 KB of markup) behind a single component. The bulk are Stratis UI line icons across a dozen categories, with an 18-mark filled social/brand set on top. icons.ts is generated and marked “do not edit by hand”; the component’s own README.md is the regeneration runbook.
---
import { Icon } from "@components/svg/icons";
---
<Icon name="arrow-right" />
<Icon name="mail" size="lg" class="text-primary" />
<Icon name="check" title="Complete" />
Four things govern its use:
- Typed names.
nameis the generatedIconNameunion, so an illegal name failsastro checkand every icon autocompletes. There is no way to reference an icon that does not exist. - Sizes.
sizeissm/md/lg/xl, mapping tosize-4throughsize-8, defaulting tomd. Or pass asize-*class directly for an off-scale size. - Colour is
currentColor. Recolour with token utilities —text-primary,text-error,text-success— so dark mode is free. The brand marks are filled silhouettes with knockout negative space, so they theme the same way (one tone, not brand colours). - Accessibility. An icon is decorative by default (
aria-hidden). Pass atitleand it flips torole="img"with a<title>, giving it an accessible name.
The barrel exports Icon, the bare icon recipe, iconNames (for iterating) and the IconName type.
<PixelIcon> — the retro sibling
src/components/svg/pixel-icons/ is a second, much smaller registry of 18 pixel-art glyphs — socials, brand marks and tech-stack icons (arrow-left, arrow-right, code, component, email, flash, git-branch, github, globe, linkedin, meteor, moon, package, rss, server, twitter, type, youtube). It renders on real pages — the home Tech Stack chips, the About skill tree, the footer socials, the ThemeToggle’s meteor/moon flip — so it is not dev-only and not redundant with <Icon>.
The two registries differ in a way that matters:
<Icon>is stroke-based on a fixed 24×24 viewBox and sizes bysize-*(equal width and height).<PixelIcon>is fill-based (fill="currentColor"plusshape-rendering="crispEdges"to keep the pixels sharp), and each glyph sits on its own native, often non-square viewBox. Because the glyphs are not square, it sizes by height plusw-auto—sm/md/lg/xlmap toh-4throughh-8— so the aspect ratio is preserved. Merging the two would squash the non-square glyphs likeyoutubeandemail, which is exactly why they stay separate.
Otherwise it follows the same contract: an exported pixelIcon recipe, data-slot="pixel-icon", typed PixelIconName names, and the same decorative-by-default accessibility (title promotes it to role="img"). The barrel exports PixelIcon, the pixelIcon recipe, pixelIconNames and the PixelIconName type.
Build-time only
Both registries map each name to inline SVG markup, which the component inlines with <Fragment set:html>. Everything happens at build — no icon bytes reach client JavaScript. The registry’s own note names the ceiling: importing it from a client <script> would ship the whole ~450 KB set, so if you ever need icons at runtime, the upgrade path is per-file .svg imports or a sprite, not a client import of the registry.
Adding an icon
For a pixel glyph, add a hand-authored entry to pixelIcons.ts following the existing shape (the source note at the top of the file records the community set it was ported from) — the PixelIconName type picks it up automatically.
For a line icon, the icons.ts registry is generated from Figma via an MCP pipeline documented in svg/icons/README.md; regenerate rather than hand-editing the generated file. If you only need one or two extra line icons, the simplest path is to add them to that pipeline’s manifest and regenerate.
Seeing them all
/examples/ui has an Icons section that iterates the registry and shows every icon with its name and a live count — the fastest way to find the name you want rather than guessing.