diff --git a/packages/web/src/Board.svelte b/packages/web/src/Board.svelte
index 29ad938..11e08b6 100644
--- a/packages/web/src/Board.svelte
+++ b/packages/web/src/Board.svelte
@@ -3,6 +3,7 @@
import type { Side } from "@wizwar/engine";
import { colorIndexOf as sharedColorIndex, wizardColor } from "./colors";
import { tokenArt } from "./art";
+ import TokenArt from "./TokenArt.svelte";
import { FX_SPRITES } from "./fx-sprites";
const CELL = 48;
@@ -275,12 +276,11 @@
{@const tx = t.position.x * CELL + CELL / 2 + (group.length > 1 ? (ti - (group.length - 1) / 2) * CELL * 0.3 : 0)}
{@const ty = t.position.y * CELL + CELL * 0.72}
{#if USE_TOKEN_ART}
-
{:else}
@@ -298,12 +298,11 @@
{@const sx = Number(key.split(",")[0])}
{@const sy = Number(key.split(",")[1])}
{#if USE_TOKEN_ART && TERRAIN_ART[content.kind]}
-
{:else if content.kind === "stone"}
@@ -328,11 +327,11 @@
{#each view.dimWarps as w, wi (wi)}
{#each [w.a, w.b] as tok, i (i)}
{#if USE_TOKEN_ART}
-
{:else}
{#if USE_TOKEN_ART}
{@const half = CELL * 0.3 * wizardScale(p.id)}
-
{}}
>
{#if USE_TOKEN_ART && CREATURE_ART[c.kind]}
-
- {c.kind} ({c.controllerId}) — {c.damage}/{Number.isFinite(c.maxDamage) ? c.maxDamage : "∞"} dmg
-
+ cls={`token-art hit${c.id === selectedCreatureId ? " selected-art" : ""}`}
+ title={`${c.kind} (${c.controllerId}) — ${c.damage}/${Number.isFinite(c.maxDamage) ? c.maxDamage : "∞"} dmg`}
+ />
+ import { SvelteMap } from "svelte/reactivity";
+
+ // SVG art must be INLINED to stay vector: an svg referenced through an
+ // element is rasterized once at its layout size in user units and
+ // scales as a bitmap — blurry the moment the board zooms. Fetched files
+ // are cached per URL, with their ids namespaced so 45 tokens' worth of
+ // filter/pattern defs cannot collide in one document.
+ type Entry = { vb: string; inner: string };
+ const cache = new SvelteMap();
+
+ function load(href: string): void {
+ if (cache.has(href)) return;
+ cache.set(href, "pending");
+ fetch(href)
+ .then((r) => r.text())
+ .then((text) => {
+ const ns = href.replace(/[^a-zA-Z0-9]/g, "");
+ const t = text
+ .replace(/id="([^"]+)"/g, (_, id) => `id="${id}-${ns}"`)
+ .replace(/url\(#([^)]+)\)/g, (_, id) => `url(#${id}-${ns})`)
+ .replace(/href="#([^"]+)"/g, (_, id) => `href="#${id}-${ns}"`);
+ const m = /