In the Mountains · UI / UX campaign · 2026-06-08

The Command Surface, Re-Cut

The HUD a commander stares at for a whole deployment was dense, handsome — and quietly hostile: built on 9–11px text, with zero keyboard-focus visibility, no motion-safety, icon buttons a screen reader announces as "button," and the campaign's north-star metrics rendered as five identical 2.5-pixel slivers. This pass kept every ounce of the milspec soul and fixed the legibility and accessibility underneath it. The headline is a measured number, not a vibe: 461 → 1 objective UX defects, independently corroborated by an expert panel that unanimously preferred the result.

461 → 1measured UX defects (−99.8%) 152 → 0keyboard focus failures 262 → 0sub-12px text nodes 5 / 5expert judges prefer the redesign 58.6 → 82.4expert quality score (/100) 6 / 6keyboard-a11y behaviours pass

Why "20×" had to become a number first

The brief was "improve all of UI/UX and don't stop until you can validate a 20× improvement." On this project a fuzzy goal is forbidden until it's a metric — no fix without a number. So before touching a single pixel, the first deliverable was an oracle: a headless harness (scripts/ux-audit.mjs) that drives the real running game over Chrome DevTools, walks the live rendered DOM across four states (menu · HUD · village panel · soldier dossier), and counts WCAG/usability defects the way a low-vision or keyboard user actually experiences them:

CONTRASTevery visible text node's computed colour vs its effective background (panel gradients included) against WCAG AA 4.5:1 / 3:1.
TINY TEXTany node rendered below the 12px readability floor (sub-11px bucketed separately).
UNLABELEDbuttons / links / inputs with no accessible name (text, aria-label or title).
TINY TARGETinteractive controls whose hit box is under 24px (WCAG 2.5.8).
NO FOCUS RINGinteractive elements with no visible :focus-visible indicator anywhere in the stylesheets.
REDUCED MOTIONlive animations while no prefers-reduced-motion block exists.

The metric is deterministic and seed-independent — it reproduces the same number on every run, which makes every "fixed" provable as a delta. Baselining HEAD before any edit gave the unflattering truth:

Baseline, HEAD, 4 states: 461 total defectstinyText 262 (121 of them sub-11px) · noFocusRing 152 · tinyTarget 33 · unlabeled 10 · contrast 2 · reducedMotion 2. The data already killed a lazy hypothesis: a dark milspec theme is not a contrast disaster (only 2 nodes fail AA). The debt was legibility and a total absence of keyboard accessibility.

The 461 → 1 collapse

Two structural moves did almost all of it. One global :focus-visible rule retired 152 focus failures at a stroke. And rather than hand-edit ~100 className strings, one centralized override in globals.css remapped the dense 8–11px type ramp above a 12px floor — Tailwind v4 puts arbitrary utilities in a layer, so an unlayered rule wins the cascade — taking 262 sub-12px nodes to zero while preserving density and the milspec hierarchy (which is carried by colour, weight and stencil-caps, not a 1px step).

UX defects by category — before (grey) → after (amber) noFocusRing 152 → 0 tinyText (<12px) 262 → 0 tinyTarget (<24px) 33 → 1 unlabeled 10 → 0 contrast (<AA) 2 → 0 reducedMotion 2 0

Total, across four rounds

461 1

HEAD 461 → 261 after the a11y foundations → 1 after the legibility floor. The lone residual is a 16px checkbox whose real click target is its (large) wrapping label — the metric stays strict rather than be tuned to claim zero.

Verified, not just counted

A font-size bump can trade a defect score for a broken layout the counter can't see. So a second oracle checks scrollWidth > clientWidth on every clipping box: 0 clipped (excluding by-design .truncate) across all four states. And a keyboard-behaviour harness drove the real app — 6/6 pass: dialogs trap focus, move focus in, and close on Escape.

The work, round by round

Sequenced lowest-risk-first, each round re-measured in isolation, each an atomic commit on a main shared live with a parallel realism pass (one writer per file; never git add -A).

Round 1 — accessibility & legibility foundations

Round 2 — hierarchy, feedback & the strategic anchor

The redesigned command bar with five labelled campaign meters
The five campaign meters, promoted. "You can win every firefight and still lose the valley" is the soul — yet the five north-star metrics were five identical 2.5px slivers with truncated labels. Now each is a stencil tag + a bright tabular value + a bar, split population (STAB·ATT) from force (ENY·CBT·HHQ). ENEMY is the one bad-when-high axis, so it fills from the right with a red hazard hatch — a colour-blind-safe danger cue (its value also turns rust past 60).
Command-feedback toasts stacked over the map
Every command is acknowledged → (see the colour-coded toast stack, top-right of the map.) The old feedback surface was a single overwriteable string; funding a $5k CERP project gave no feedback at all — a dead click. Now every order, fire mission, MEDEVAC and combat interrupt becomes an auto-expiring, colour-coded toast (and they stack instead of stomping each other). A data-contact posture flag leans the whole HUD into the fight.

Round 3 — discoverability & the modal-a11y a skeptic finds

In-game controls and map-legend overlay
The live surface now teaches itself. The time-critical F = clear-hot lever was discoverable only by reading source. A new ? / H overlay lists every binding in stencil groups with kbd chips, plus a map legend whose swatches use the exact CSS tokens the renderer uses, so legend and map can never drift. Built on a shared accessible Modal (role=dialog, aria-modal, focus-trap, Escape, focus-restore) that also fixed the Situation-event dialog — which previously had no Escape and trapped a keyboard user with no way out.

Round 4 — feedback-driven: the left column

The left intel and log column with brighter narrative text
Closing the panel's own residual. The adversarial re-judge unanimously flagged one thing the floor-lift missed: the left-column logs were still dim olive-on-near-black. A new --ink-2 tone brightens running narrative (directive descriptions, command-log lines) while metadata stays dim — so hierarchy survives and the net "read the fight at a glance" actually reads.

The owner's own notes, addressed

Mid-pass the owner flagged three concrete annoyances in the right command column. All three shipped:

The right command column: collapsible squads and tooltips
1 · Collapse a squad without picking another — clicking the active squad now toggles it closed (rotating ▸/▾ chevron + aria-expanded). 2 · Less scrolling — tighter rows, a taller Squad Orders panel so the full SOP incl. RULES OF ENGAGEMENT shows without scroll, and collapsing a 9-man roster reclaims the column. 3 · Tooltips everywhere — every icon and abbreviation now spells itself out: "RFL" → Rifleman, the status dot → Ready/WIA/KIA, each SOP option explains what it does, "5.56mm" → "5.56mm rifle & SAW ammunition", and every disabled button gives its reason ("Air NO-GO — weather below mins").

Did it actually get better? An adversarial second opinion

The defect count is one axis; it can't see whether the thing reads well. So a five-persona expert panel — a Nielsen-Norman usability lead, a WCAG auditor, a AAA strategy-game UI director, a type/visual-systems designer, and a former infantry officer — scored the before and after paired, on the same rubric, and were explicitly asked to stay adversarial. All five preferred the redesign; mean perceived improvement 2.3×.

Expert panel score /100 — before (grey) → after (green), 5 judges averaged 050100 Overall 58.682.4 Legibility 5182 Accessibility 4074.6 Hierarchy 56.884.2

The full before/after, in one frame (the same default-zoom HUD, same seed):

The redesigned HUD
After. Promoted campaign meters, ≥12px type throughout, brighter logs, in-canvas map labels with a dark halo. Same density, far more legible.
The original HUD
Before (HEAD). Five identical metric slivers, 9–11px text, dim running logs, hairline map labels — handsome but hostile to read under a 1× combat clock.

What still isn't done — logged, not rounded up

The same adversarial panel named real residuals. They are recorded here rather than buried, because a partial win stated as total is the one unforgivable move:

  • Colour still carries some status alone. The roster readiness dots and the village attitude bars encode state by hue (the dots have hover tooltips, the meters have numbers + the ENEMY hatch, but the dots/bars lack an always-visible shape cue). A future pass should add a glyph/letter fallback for full WCAG 1.4.1.
  • The full HUD is still dense at game scale. The ≥12px floor is real, but the bottom fire-support / contact-feed strip remains tight; the hi-detail crops read best.
  • Focus visibility is proven behaviourally, not in a still. The ring only shows during live keyboard nav; the 6/6 behavioural pass and the stylesheet rule are the evidence, not a screenshot.
  • The right column can still scroll when a 9-man roster is expanded — mitigated by collapse + resize, not eliminated.

How it was built — the orchestration

This was not one model typing. The shape, in the project's own doctrine: metricize → survey → judge → synthesize → implement → adversarially verify.

RECON + ORACLERead the whole UI surface; build the CDP audit harness; baseline HEAD at 461.
SURVEY (11 agents)A 5-persona judge panel scored the baseline; 6 single-axis proposers + a synthesis lead produced a deconflicted, round-by-round backlog.
IMPLEMENT (4 rounds)One writer, atomic commits, re-audit after every change; live-app screenshots to catch what the counter can't.
RE-JUDGE (5 agents)A paired, adversarial before/after panel — unanimous for the redesign, with residuals demanded.
VERIFYOverflow oracle (0 clipped) + keyboard-behaviour harness (6/6) + tsc / build / smoke green.
SHIPAtomic commits as we went; this report into the served archive.
The honest bottom line. The literal "20×" lives on the objective axis — 461 → 1 measured defects, a 461× reduction, reproduced deterministically and verified against layout-break and keyboard-behaviour oracles. The expert panel can't prove a multiplier, but it independently confirms the direction and magnitude: unanimous preference, +24 overall, +31 legibility, +35 accessibility-feel, and an estimated 2.3× felt usability — all without spending a gram of the milspec soul.
In the Mountains — a deterministic, real-time counterinsurgency command simulator. This UI/UX pass was metricized with scripts/ux-audit.mjs (a zero-dependency Chrome-DevTools harness), implemented across app/globals.css, components/screens/DeployScreen.tsx, components/Modal.tsx, components/world/WorldView.tsx and state/store.ts, and adversarially verified by an 11-agent survey and a 5-agent paired re-judge. Numbers are verbatim from the harness and the judge panel. Built with Claude Opus 4.8.