PURPOSE

Renders the compact rounded “damage-tag pill” — a small labeled badge that marks a card or weapon entry with its damage type (bullet, energy, fire, bomb). One consistent pill shape is used across every reward card and weapon list so the player recognizes damage type at a glance. Also exposes a solid accent color for non-pill UI that just needs a tag color swatch.

OWNS

  • The damage-tag visual identity: gradient palette (TAG_GRADIENT) and solid accent palette (TAG_SOLID), keyed by DamageTag.
  • Pill geometry constants at uiScale = 1: PILL_HEIGHT_BASE, PILL_PADDING_BASE, FONT_SIZE_BASE.
  • The pill path geometry helper _pillPath (rounded rectangle clamped so the corner radius never exceeds half the height/width).
  • The pill render itself: gradient fill, thin black border, white label with black stroke outline, font set to 700 <size>px 'Space Grotesk',sans-serif, label uppercased.
  • Explicit canvas shadow reset inside ctx.save()/restore() so the pill never inherits a drop shadow from the surrounding card render.

READS FROM

  • DamageTag type (../../data/weapons/_types) — the discriminator that keys both palettes.
  • The caller’s CanvasRenderingContext2D for measuring label width and drawing.
  • The caller-provided uiScale multiplier (scales height, padding, font size, border line width, and label stroke width).

PUSHES TO

  • The caller’s canvas: gradient-filled rounded pill, border stroke, stroked-then-filled label centered at (cx, cy + 0.5).
  • Returns { width, height } measured in scaled pixels so callers can lay out adjacent elements (icon, name, stats) next to the pill.

DOES NOT

  • Does not own layout: the caller picks (cx, cy) and uiScale; the pill draws centered on that anchor and reports its size back.
  • Does not cache gradients, paths, or measured widths — every call rebuilds the linear gradient and re-measures the label.
  • Does not clip, translate, or scale the caller’s transform — only saves/restores shadow and text/stroke state.
  • Does not pick the damage tag — the caller passes it in; the function assumes the tag exists in both palette records.
  • Does not handle missing/unknown tags defensively (a tag absent from TAG_GRADIENT would crash on the gradient lookup — by-design strict on internal data).
  • Does not draw icons or any text other than the uppercased tag name.

Signals

  • Pure render module. No events emitted, no store subscriptions, no telemetry.
  • damageTagColor(tag) is the read-only accent-color signal for other UI (returns a hex string from TAG_SOLID).

Entry points

  • damageTagColor(tag: DamageTag): string — solid hex color for a tag, matched to the pill’s top gradient stop so pill and non-pill UI read consistently.
  • drawDamageTagPill(ctx, cx, cy, tag, uiScale): { width, height } — draws the pill centered at (cx, cy) and returns its rendered size in scaled pixels.

Pattern notes

  • Two palettes deliberately decoupled: TAG_GRADIENT (top/bottom stops, drives the pill fill) and TAG_SOLID (single color, drives non-pill swatches). TAG_SOLID is documented as matching each TAG_GRADIENT.top so the two surfaces stay visually aligned.
  • Gradient is built in screen-space (createLinearGradient(0, y, 0, y + h)) — vertical top-to-bottom, no transform-awareness.
  • Corner radius is set to h / 2 (full-pill rounding), and _pillPath clamps further to min(r, h/2, w/2) so very narrow pills degrade gracefully.
  • Label is drawn twice: a black stroke pass (lineWidth = max(2, 2 * uiScale), lineJoin = 'round', miterLimit = 2) followed by a white fill pass — gives the readable outline rule the game uses for all on-canvas text.
  • All sizing is multiplicative on uiScale; lineWidth for the border uses Math.max(1, uiScale) to guarantee at least one pixel on small scales.
  • The explicit shadow reset (shadowColor='transparent', shadowBlur=0, both offsets 0) inside save/restore is the historical fix called out in the file header — without it, the pill inherits a card’s drop shadow and the label blurs.
  • Constants are intentionally named with _BASE suffix to flag that they are pre-uiScale values.