---
title: Imperium UI Replicate - reference screenshot to premium Imperium component
tags:
  - "brand"
  - "frontend"
type: skill
status: active
created: 2026-07-27
description: "Replicate any premium UI reference screenshot pixel-faithfully in HTML/CSS, then re-theme it into the Imperium brand (console greens) with interactivity and choreographed motion. Use when Alex gives a UI screenshot/dribbble shot and says \"replicate this\", \"make this in Imperium colours\", \"copy this component\", \"this style for the dashboard\", \"premium component like the revenue-flow card\". Produces a live interactive HTML component + renders, not a static image. Do this in ONE response: the iteration loop runs internally."
name: imperium-ui-replicate
---

> **PORTABILITY NOTE (added 2026-07-27).** This process doc is published from Imperium's
> internal operating system. The METHOD is fully portable: prompts, model choices and
> parameters, CSS/SVG recipes, QA gates, and cost discipline all work anywhere. Paths that
> start with `~/.claude/`, `<repo-root>/`, `presentations/`, `scripts/`, or `memory/` are
> internal conveniences on the author's machine; substitute your own equivalents (any
> headless-browser screenshot loop, any image toolchain). Same for internal distribution
> steps (Google Drive folder IDs, Telegram bots) and `<your-vercel-team>` deploy scopes:
> use your own storage, messaging, and hosting. Working style anchors ship WITH this kit
> in `../cards/`, `../console/`, and `../folder/` — start from those, not from zero.

# Imperium UI Replicate

Reference screenshot in, premium Imperium-branded interactive component out, one response.
Proven on the Revenue Flow card 2026-07-27: `assets/ui-lab/revenue-flow/` (orange reference →
89.8% pixel replica → `revenue-flow-imperium.html`, the quality bar every run must hit).

## Non-negotiables — these are GATES, not guidance

0. **The reference must be a FILE ON DISK before any code is written.** A chat-attached image
   cannot be saved to disk or measured by scripts — building from it means eyeballing, which is
   the documented failure mode (savings-gauge 2026-07-27: no reference file → skipped measurement
   → wrong radii/stroke/spacing/fonts, invented elements). Drop folder: `assets/ui-lab/inbox/`.
   If Alex only attached the image in chat: ask him to save it there (one line, wait) OR use any
   path he named. NEVER proceed to build without the file. Copy it into the working dir as
   `reference.png` first thing.
1. Load `assets/imperium/brand-v5/` (BRAND-BOOK.md + imperium-tokens.css) BEFORE styling (rule 21).
2. Run the whole loop silently in one turn: measure → build → screenshot → diff → fix, 6-10 rounds.
   Alex sees the finished component, not the iterations.
3. Never eyeball. Measure the reference numerically. The premium feel comes from measured geometry,
   not taste. This is the difference from "vibe-coded AI UI".
4. **Nothing invented, nothing dropped.** Before coding, write an ELEMENT CENSUS of the reference
   (every element AND every effect — see checklist below). The replica contains every census item
   and NOTHING that is not in the census. Do not import components from earlier examples (pills,
   tabs, logos) and do not add "premium improvements" the reference doesn't have — unless Alex
   explicitly asked for them (interactivity is the standing exception). Substituting a brand logo
   for a reference prop only if Alex asks.
5. Deliverables: live `.html` (interactive), PNG renders of 2+ states, `file://` links for all
   (rule 29), commit+push (rule 8), quality gate (AGENTS.md §4). The working folder must contain
   `reference.png`, `diff-heat.png`, `side-by-side.png` as proof the loop ran — a folder without
   them means the skill was not followed.

### Element census checklist (measure each, per element)
Corner radii (card AND every child) · stroke widths and cap style (rounded/butt) · glow structure
(core + bloom layers, their radii) · edge rim lights — WHICH edges carry a bright hairline/beam,
its gradient direction and length (e.g. a lit segment along the top-right border) · background
texture (grid, perspective floor, noise) and its vanishing geometry · 3D props/symbols · dividers ·
font sizes from text bboxes (width AND height) · letter-spacing · spacing between stacked groups.

## Stage 1 — Pixel replica of the reference (MANDATORY, in ORIGINAL colors)

Build the replica in the reference's own palette FIRST and pixel-compare it against reference.png
until ≥85% of pixels are within 12/255 (or a documented plateau). Only a scored replica may enter
Stage 2. Collapsing Stage 1 into the brand transfer is how details die — the score is only
computable against the original colors.

Full protocol: `references/pixel-replica.md` (ships with this kit, next to this file). Tools
(also shipped, in `scripts/`; work in any repo):
- `shot.sh page.html out.png WxH` — exact-size screenshot (chrome-headless-shell; plain Chrome hangs)
- `pixel-compare.py ref.png render.png` — score + worst cells + diff-heat.png (ghost text = offset,
  halo = size/radius off, bright field = gradient off)
- `fit-gradient.py ref.png --region ... --exclude <each element box> --origin <container xy>` —
  fits complex gradients as rotated Gaussian light lobes, emits CSS. USE THIS for any beam/glow/mesh
  background; hand-tuned radials plateau ~50% accuracy, the fitter reaches ~80% and discovers the
  diagonal beam angles automatically.

Key traps (each cost a round once): container-relative vs page coords (subtract the card offset);
fonts (Google-Sans-look → bundle Roboto woff2 locally, fit size to measured text bbox); single-pixel
color samples lie (average regions); trust the numbers over your eyes when they disagree.

## Stage 2 — Imperium brand transfer

Keep ALL geometry, alphas, and gradient structure. Swap only colors, by ROLE:

| Reference role | Imperium token |
|---|---|
| Page ground | near-black with deep-green vignette: `radial-gradient(... #0A130E, #050907, #010201)` |
| Card/panel ground | Console Ground `#0C1712` |
| Hot light core (was yellow) | Mint 100 `#D8EBDD` |
| Main light lobes (was orange) | Mint 300 `#4CB782`, secondary Bali 400 `#3FA085` |
| Broad dim wash | Racing 400 `#2E6A4C` at same alpha |
| Accent bar / highlight / active label | Mint 300 gradient → fades to ground (`#4CB782 → #35A06D → #227A50 → #124630 → ground`) |
| Primary button / pill | SOLID Racing 700 `#11462C`, Bone `#F4F1EA` text, Mint dot (Alex 2026-07-27: solid, no outline ring) |
| Big numbers / values | Bone `#F4F1EA` |
| Muted meta text | Racing 300 `#5E8C74`; neutral greys get a green cast (`#6F7873`) |
| Glass panels | `rgba(23,40,31,.72-.8)` + `backdrop-filter: blur(50px)` + inset Bone rims at 5-8% |
| Alert / negative only | Ember `#E23A28` — NEVER for highlights/peaks (brand rule: one Ember max, alerts only) |

Type: Switzer (Regular/Medium/Semibold woff2 from `assets/imperium/brand-v5/fonts/`) — the console
surface spec. Emilio is for marketing surfaces, not dashboards.

Known brand-book tension: the book bans decorative gradients/glow floods on console. Alex has
explicitly approved the beam treatment for these premium components (2026-07-27). Don't relitigate;
don't cite the ban as a reason to flatten the design.

## Stage 3 — The premium layer (what makes it not look AI-generated)

**Light.** One light source, obeyed everywhere: fitted beam lobes (plus-lighter additive divs) +
2-3 thin rotated light shafts (110-150px wide, blur 10px, alpha .1-.2, angles from the fit) +
feTurbulence smoke (multiply, opacity ~.14, masked to the lit corner) + light SPILLS outside the
card on the opposite side (blurred warm strips, alpha ~.15) + a soft glow pool on the axis under
the active element.

**Surfaces.** Opaque grounds; glass only INSIDE over solid base. Layered shadows: tight contact
(`0 16px 40px rgba(0,0,0,.5)`) + long ambient (`0 50px 140px rgba(0,0,0,.65)`) + 1px inset rim
highlights top (`inset 0 2px 0` bone at 3-8%). One radius system (reference-derived; big card 108,
bars 22-30, glass 60-64, pill full).

**Numbers.** Odometer cash-roll: each digit a 0-9 strip in an overflow-hidden column (width .6em),
`translateY(-digit*10%)`, transition 900ms, **55ms stagger left→right** (the stagger is what reads
as mechanical/premium). Static chars ($ ,) don't move. Rebuild only when the format shape changes. Key numbers on console surfaces get the mint text-glow (see recipe library).

**Motion choreography** (Alex-tuned 2026-07-27 — start from these, they are the calibration):
| Element | Duration | Easing |
|---|---|---|
| Digit roll | 900ms (700 in tooltip) | cubic-bezier(.24,1.06,.3,1) + 55ms/digit stagger |
| Marker/check/pool glide | 480ms | cubic-bezier(.26,1.08,.32,1) |
| Tooltip glide to anchor | 620ms | same soft spring |
| Active gradient crossfade | 420ms (opacity on ::before overlay — gradients can't transition) |
| Label color | 300ms | ease |
| Hover feedback (lift 4px + brighten) | 150-180ms | immediate; feedback is the one thing that stays fast |
| Check pop | 520ms scale to 1.07 | slight overshoot |
Slight-overshoot springs are the brand motion language (book §5). The impeccable hook flags them
as bounce-easing; classify intentional, cite the book. Nothing except hover feedback under 300ms —
"too fast = spontaneous = cheap" (Alex).

**Interaction pattern.** Hover targets = full-height slots (not the bars). One ACTIVE month/item;
`activate(i)` moves marker+line+pool, rolls all numbers, crossfades tooltip title, updates header.
Tooltip: FIXED anchor per item (beside it, flip side near edges, clamped) gliding between anchors —
NOT cursor-following (tried, Alex rejected). Support `?m=N` query param so states can be
screenshotted headlessly for verification.

### Rim-light recipe (the card-edge beam Alex wants from the get-go)
A lit hairline along part of the card border (e.g. top-right in the gauge reference):
an absolutely-positioned pseudo-element clipped to the card radius carrying a 1-2px stroke whose
color is a linear gradient fading in/out along the edge (transparent → mint/white 60% → transparent),
plus a blurred (6-10px) duplicate underneath at ~40% alpha for the bloom. Same trick for lit
segments on straight dividers. Detect them in the census by scanning the reference's border pixels
for bright runs.

## Recipe library — extracted from APPROVED components (use these first-shot)

Source code: `assets/ui-lab/revenue-flow/revenue-flow-imperium.html` (bars) and
`assets/ui-lab/savings-gauge/savings-gauge-imperium.html` (gauge). When a reference contains one
of these patterns, implement it with the approved recipe below — do not re-derive from scratch.

**Gauge / progress arc (SVG stroke, not CSS).** One `<path>` arc drawn THREE times stacked:
main stroke + two blurred copies behind it (feGaussianBlur filters, opacity ~.55 and ~.35) — that
IS the bloom. Progress via `stroke-dasharray/dashoffset` with the standard 900ms bezier. Track =
same path in dark green (#26312A). Flat `butt` caps with small rounded "caplet" overlays. The knob
rides a rotating `.arm` div centered on the arc center (`transform:rotate()` same 900ms bezier) —
knob = dark fill circle + Bone ring + outer mint glow.

**Arc inner highlight (the streak that sells it).** A thin white arc (`stroke:rgba(248,252,249,.6)`
7px + a wider .22 5px layer, both slightly blurred) along the inner-top portion of the lit arc.
Same idea as a rim light: light catches the top-inside edge.

**Hot endpoint.** The start of the lit arc is near-white (#F8FCF9 core fading to mint within
~80px) — one end of any lit path is always hotter than the rest.

**Glowing text (console default).** Key numbers and lit labels carry
`filter:drop-shadow(0 0 Npx rgba(76,183,130,A))` — big hero number N=34 A≈.28, header values
N=16 A≈.35, secondary lines N=14 A≈.22. Subtle, never a neon halo.

**Card edge rim beam (approved implementation).** A `.rim` overlay div: `inset:0; padding:2px;`
with a conic-gradient background (bright mint/bone segment over ~40-70° of the circumference,
transparent elsewhere) masked to the border ring
(`-webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite:xor`)
— gives the lit segment along one edge (top-right in the gauge). Add a blurred duplicate for bloom.

**Glass brand mark.** Logo/prop top-left overlapping the card corner:
`filter:drop-shadow(0 0 22px mint .45) drop-shadow(0 22px 28px black .55)` + a slow ambient bob
(`@keyframes` translateY -5px→7px w/ ±1.5° rotate, alternate, ~6s) for life.

**Geometry-derived text alignment.** Center text blocks align to the COMPONENT's geometry, not
the card: the hero % centers between the arc ends; the caption line sits on the arc's chord
(baseline level with the arc bottom caps). Compute from the arc's center/radius, don't eyeball.

**Changing text that isn't a number.** Numbers roll (odometer). Words/labels crossfade
`opacity` 240ms out → swap → in. Nothing ever hard-swaps.

**No-jank init (also fixes blank screenshots).** On load: set transitions to 'none', apply the
initial state, then double-`requestAnimationFrame` before re-enabling transitions. Never run the
entrance choreography on first paint of a static render, and never let a fade timer leave text
blank at screenshot time.

## Verify before delivering

- Screenshot 2+ states (`shot.sh file.html out.png` and `file.html?m=N`), eyeball both, and check
  text presence numerically if a timer/fade could blank it at load (a first-load crossfade once
  blanked the tooltip title in screenshots).
- If replicating first then theming: pixel-compare the un-themed replica against the reference
  (85%+ within-12 before brand transfer).
- z-order: glass panels above bars/marker (bars z1, marker z2, glass z3). Backdrop-filter needs it.

## The prompt Alex gives to trigger this

1. Save the screenshot into `assets/ui-lab/inbox/` (any name).
2. Prompt: "Reference: assets/ui-lab/inbox/<name>.png — replicate it exactly, then Imperium theme.
   Interactive, premium motion."
Optional dials: which element is the highlight, data/range, hover behavior, still vs interactive.
If the image is only attached in chat with no file anywhere, the agent MUST stop and ask for the
file before building — that is compliance, not friction.
