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 = /]*)>([\s\S]*)<\/svg>/i.exec(t); + const vb = m ? (/viewBox="([^"]*)"/.exec(m[1]!)?.[1] ?? "0 0 144 150") : "0 0 144 150"; + cache.set(href, { vb, inner: m?.[2] ?? "" }); + }) + .catch(() => cache.delete(href)); + } + + + + +{#if isSvg} + {#if entry && entry !== "pending"} + + {#if title}{title}{/if} + + {@html entry.inner} + + {/if} +{:else} + + {#if title}{title}{/if} + +{/if}