@emyrk/wow-tooltip-renderer
v0.1.0
Published
Pure TypeScript resolver and formatters for World of Warcraft spell/item tooltips from DBC-style records. No React, no fetch, no styling.
Readme
@emyrk/wow-tooltip-renderer
Pure TypeScript renderer for World of Warcraft spell and item tooltips built from DBC-style records. No React, no fetch, no styling — data in, strings (and hex colors) out. The React tooltip components and data fetching live in a separate package / the consuming app.
Why
Chronicle and Chronicle Wiki both render tooltips from spell/item records whose
text contains template variables ($s1, $o1, $d, $23455s1, $lpoint:points;,
${$m1*3}, …). This package owns the deterministic resolution of those templates
and the static game-data lookup tables, so consumers don't hand-roll their own.
Install
Published to npm as @emyrk/wow-tooltip-renderer:
pnpm add @emyrk/wow-tooltip-rendererInside this monorepo the Chronicle frontend consumes the package source directly
via a path alias (see frontend/chronicle/vite.config.ts), so it always tracks
the working tree. External consumers (e.g. Chronicle Wiki) install the published
build. Releases are cut by bumping version in package.json and merging to
main — see .github/workflows/release-renderer.yml.
Usage
import {
extractReferencedSpellIds,
resolveSpellDescription,
} from "@emyrk/wow-tooltip-renderer";
// 1. Find cross-spell references the template needs.
const refIds = extractReferencedSpellIds(template); // e.g. [23455]
// 2. The app fetches those spells (app owns tenant-aware API base URLs) and
// builds a Map<number, WoWSpell>.
// 3. Resolve. The resolver never fetches.
const text = resolveSpellDescription(spell, template, referencedSpells, 60);Item tooltips use the same spell resolver for Use/Equip/Chance-on-hit effects, socket bonuses, and set bonuses, plus pure formatters/constants:
import {
formatItemStat, // (statType, value) -> { text, green }
calculateDPS, // (damageRange, delayMs) -> number | null
getQualityColor, // quality level -> hex
STAT_DISPLAY, INVENTORY_TYPE_TEXT, SOCKET_INFO, /* ... */
} from "@emyrk/wow-tooltip-renderer";Design rules
- The resolver is pure and deterministic; it never fetches.
- The consuming app owns tenant-aware API base URLs and data fetching.
- Colors are exported as hex values, not CSS-framework classes.
- Missing cross-referenced spells leave the placeholder visible (for diagnosis).
Template grammar
The resolver is a single left-to-right pass (see src/spell/resolver.ts for the
documented grammar). Supported escapes:
| Variable | Meaning |
| --- | --- |
| $s1/$m1, $s2, $s3 | Effect value (single or min to max range) |
| $o1/$o2/$o3 | Periodic total over the spell duration |
| $d, $dN | Duration |
| $t, $tN | Tick interval (seconds) |
| $a1 | AOE radius |
| $r, $n, $h, $u, $v, $x1, $b1, $e1 | range / charges / proc chance / stacks / etc. |
| $NNNNs1 | Cross-spell reference (e.g. $23455s1) |
| $*N;s1, $/N;s1 | Multiply / divide a value |
| ${expr} | Inline arithmetic (variables resolve first, then evaluate) |
| $lsingular:plural; | Pluralization (uses the most recent number) |
| $gmale:female; | Gender (defaults to male — no caster gender at tooltip time) |
Tests
pnpm install
pnpm test # unit + golden fixture tests
pnpm typecheckThe Chronicle frontend consumes this package through a thin shim at
frontend/chronicle/src/api/wowdb.ts, which re-exports the resolver, formatters,
constants, and WoWSpell type (this package is the source of truth) and adds the
few app-specific helpers that depend on Chronicle's runtime (tenant icon CDN,
Tailwind theme classes). The frontend's golden tests
(frontend/chronicle/src/api/wowdb.test.ts) run real generated DBC vectors
through the shim — and therefore this package — for all servers.
The rewrite from the previous regex resolver to this parser was validated with a differential parity test asserting byte-for-byte identical output across every DBC vector for all 7 servers before the old implementation was removed.
