/** * pixelarticons (npm `pixelarticons`) — SVG icon loader. * * The package ships ~400 icons each with a "sharp" twin variant (~800 * SVGs total). We surface the regular set only — the sharp variants are * a stylistic alternative that doubles bundle size for marginal value * in our context. Each SVG is ~150B, so the regular set lands around * 60KB raw / ~15KB gzipped — small enough to bundle eagerly so the * picker can search/grid without lazy-loading round trips. * * Icon scheme: we encode a chosen pixelart icon as the string `pi:name` * (kebab-case). The {@link SkillIcon} renderer detects this prefix and * inlines the SVG at render time. */ // Eager glob into node_modules — Vite resolves `?raw` text imports for // SVGs the same as any other asset. We exclude the `*-sharp.svg` files // at the glob level so they never enter the bundle. const modules = import.meta.glob( '../../node_modules/pixelarticons/svg/!(*-sharp).svg', { query: '?raw', import: 'default', eager: true }, ) /** * Map from kebab-case icon name → raw SVG markup. * Built once at module load; ~400 entries. */ export const pixelartIcons: Record = (() => { const out: Record = {} for (const [path, raw] of Object.entries(modules)) { const name = path.split('/').pop()!.replace(/\.svg$/, '') out[name] = raw } return out })() /** * Sorted list of icon names — drives the picker grid. Cached because the * picker reads it on every keystroke (search filter). */ export const pixelartIconNames: string[] = Object.keys(pixelartIcons).sort() /** * Encode a pixelart icon name into the persisted icon string. * Symmetric with {@link parseIconValue}. */ export function encodePixelartIcon(name: string): string { return `pi:${name}` } export type ParsedIcon = | { kind: 'pixelart'; name: string; svg: string | null } | { kind: 'url'; url: string } | { kind: 'emoji'; value: string } | { kind: 'empty' } /** * Plain-text icon glyph for hosts that can't render components — chiefly * `