---
name: card-studio
description: Create beautiful marketing/category/article card sets - code-built card chrome (HTML/CSS gradients, noise, typography, buttons) + AI-generated 3D props with transparent backgrounds, composited and verified with a screenshot loop. Trigger whenever Alex asks to "create a card", "beautiful cards", "category cards", "article cards", "feature cards", "hero card", a "card set with 3D icons/objects", to replicate a card design from a reference image, OR whenever a card is the heading of a big/important section: dashboard section headers, website sections, marketing material, presentation slides, any information-dense highlight card. If the card is prominent enough that it should stand out, this skill is the default approach. Imperium-branded cards additionally follow assets/imperium/brand-v5. Proven 2026-07-27 on the Fey-style article cards (89% pixel match) and the 4-card sports grid.
---

> **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.

# Card Studio — beautiful card sets, code chrome + generated props

Two-layer split, and it is the whole method: **code owns the card, a model owns the prop.**
Code is deterministic (exact text, gradients, radii, consistency across the set); image models
own photoreal 3D objects but drift — so props are generated as isolated objects, cut out, and
composited. Never let an image model draw the card itself (text garbles, layouts drift).

Sibling skill: `mockup-studio` (pixel-replicating full UIs, GPT finishing). Reuse its scripts —
they ship with this kit in `scripts/` next to this file: `serve.mjs` (local server),
`gpt-finish.mjs` (GPT Image 2 edit calls), screenshot notes in `references/pipeline.md`
(also shipped, in `references/`).

**Reference gallery (open it before building anything):** the kit's `../cards/` folder IS the
gallery — every proven Imperium card as standalone HTML with its props and fonts. Open any
card file to lift working CSS verbatim. `card-studio-portable-prompt.md` (next to this file)
is a self-contained prompt for recreating this method in a chat without this skill.

## Imperium branding (Alex OS)

When the card is for Imperium (website, dashboard, deck, marketing): FIRST invoke the
`imperium-brand` skill and load `assets/imperium/brand-v5/` (BRAND-BOOK.md + tokens). Colors
come from the brand (greens only, primary #11462C, vivid Mint #4CB782/#D8EBDD, Ember #E23A28
as the single action accent), type is Emilio (display) + Switzer (UI) with the explicit weight
presets, radius 40px (locked; see Unified standards below), and positioning language is
SME-focused, never "enterprise". The locked prop style block should be re-tinted to the brand
(e.g. porcelain white objects with mint holographic accents on deep-green gradients) but keep
the same material/lighting discipline so sets stay consistent.

**Photographic grounds (sanctioned variant).** The default card ground is a brand gradient +
grain (card-anatomy.svg). A photographic shallow-DoF ground (the rec-f "warm office" look) is
ALSO sanctioned: build the code card as normal, generate the environment plate separately per
BRAND-BOOK §5b (real-world scene, one upper-left light, no sci-fi) using the exact prompts in
MOCKUPS.md's worked examples, then either (a) composite the transparent card over the plate in
code, or (b) run GPT Image 2 edit on the flat composite with a layout guard (mockup-studio
finishing ladder). Doctrine §5b and the §4 quality gate apply either way. Generation defaults
when unstated: `nano_banana_2`, square 1:1 for props / native aspect for plates, batch of 2 and
pick the winner, no seed pinning.

**Canvas defaults (when the brief names no size):** hero/article card 1492x712 · category card
811x440 · square social 1080x1080 · portrait social 1080x1350 · all R40. **Copy rule:** card
headlines, stats, and CTA labels come from the brief — if absent, ASK; never fabricate claims
or numbers (same rule as slides).

## Stage A — Card chrome (HTML/CSS, always code)

- One standalone HTML file per set at exact target resolution (1:1 px, no zoom), fonts bundled
  locally as woff2 (`@font-face`; Google Fonts is blocked in sandboxes). DM Sans latin variable
  proved the best free Circular-substitute (beat Figtree on measured glyph diff).
- **Replicating a reference?** Measure, don't eyeball: PIL-sample gradient stops on a grid
  (median of 9x9 patches kills grain), landmark bboxes for every text block/button (threshold +
  centroid), corner radius by fitting a circle to the traced edge arc. Then iterate
  render→measure→nudge; sub-4px offsets are findable with a ±5px shift-sweep against the
  reference (see mockup-studio's fit loop; `scripts/compare.py` scores candidate vs reference
  with per-region % + heatmap).
- Gradient recipes that earned their place (from the measured Fey card):
  - base = 4-5 stop `linear-gradient` fitted to sampled values; corner/edge glows = SMALL
    tight `radial-gradient`s at the corners (big soft radials wash the whole card — measured
    failure), plus an optional bottom "rim light" strip (`linear-gradient(0deg, ...)` over 60px).
  - film grain: inline SVG `feTurbulence` data-URI tile, `opacity .07-.10`, `mix-blend-mode:
    overlay`.
  - soft reference edges: inset feather ring `box-shadow: inset 0 0 18px 4px rgba(bg,0.7)`.
  - accent glows per card theme (e.g. dark boxing card = `radial-gradient(55% 90% at 108% 60%,
    rgba(60,120,80,.55), transparent)` over near-black).
- Buttons/arrows: inline SVG paths, stroke ~7.5/52 viewBox, round caps. Tracked uppercase
  labels for LEARN-MORE rows (`letter-spacing: 3px`).

## Stage B — Props (generated, transparent)

- **From scratch (new designs):** Higgsfield `generate_image`, model `nano_banana_2` (step up
  to `nano_banana_pro` on hard cases — see the routing table in AGENTS.md §3), one
  **locked style block** shared verbatim across every prompt in the set — only the object
  clause changes. This is what makes a SET read as one family. Example block:
  "Minimalist premium 3D render ... matte white porcelain material with soft satin sheen and
  subtle grey ambient-occlusion shading, soft diffused studio lighting from the upper left,
  gentle rim light, floating at a dynamic angle, solid flat medium-grey background, centered
  with generous margins, no text, no watermark, high-end app category illustration aesthetic".
  Generate on a flat mid-grey background (clean cutouts), 1:1.
- Then Higgsfield `remove_background` (accepts the generation job_id directly as media_id —
  no re-upload), download rawUrl → true-alpha PNG.
- Text ON a prop (receipts, labels): image models hold ~5-word blocks reliably; spell every
  string in the prompt and zoom-inspect character by character. If it must be exact and long,
  generate the object blank and overlay the text as warped SVG in code.
- **Replicating an existing prop:** GPT Image 2 edit mode with the cropped reference region as
  input ("reproduce exactly, sharper") — the only generative route near pixel-identity — then
  low-frequency color-grade-match toward the reference (blur-radius 8-12 subtraction transfer).
  Pure from-scratch generation cannot pixel-match a fixed image; say so up front.
- **Never** use Higgsfield (or any model) to render/finish a UI screenshot — tested 2026-07-03,
  garbles text. GPT Image 2 cannot output alpha (verified 2026-07-26); for transparency always
  go Higgsfield remove_background or generate-on-matching-background + CSS mask fade.
- Cutout hygiene: `python3 scripts/cutout_hygiene.py prop.png --edge-fade right:70
  --band-clean bottom:90` — kills halo pixels, matte fringe, and baked-shadow seams.

## Unified standards (locked with Alex 2026-07-27)

- **Corner radius = 40px, locked (Alex 2026-07-27 after a 20/40/48/72 A/B).** All marketing,
  hero, category, and article cards at any canvas size. Exceptions: pixel-replicas keep their
  reference's radius; small product-UI controls keep the brand 10px step.
- **Props read smaller than you think.** Size 70-85% of card width (small objects like
  shuttlecocks/gloves sit at the TOP of that range), bleed off 1-2 edges.
- **Shadows stronger than you think.** Tinted drop-shadow alpha 0.4-0.55 on dark cards,
  0.35-0.45 on light; offsets ~20-34px, blur ~30-40px. A prop without a visible cast shadow
  looks pasted.

## Card anatomy (locked with Alex 2026-07-27 — see brand-v5 card-anatomy.svg)

Every Imperium card follows one blueprint: **R40 corners** at any canvas size · a **1u padding
unit** (title starts 1u in from top-left, CTA sits 1u up from bottom-left) · display line in
Emilio Light · **CTA icon + tracked-caps label in the SAME colour** (mint #4CB782 on dark,
#11462C on light — never mismatched, never a circle/pill behind the arrow icon) · porcelain
prop 70-85% card width bleeding 1-2 edges · **glass edge treatment on every card**: conic rim
(2px, brightest at 45°/315°, bone-tinted on dark / white+ink on light) + top-right glint arc +
spark. Icons come from the brand icon set (brand-v5/icons: 16x16 viewBox, filled paths,
`fill="currentColor"`, VS Code codicon source only — never hand-drawn, never invent a second
icon style). Props read straighter than you think: upright
front/side views beat dynamic angles unless the card's motion demands it (Alex 2026-07-27).

## Stage C — Composite

- Props as absolutely-positioned `<img>` in the card, `overflow:hidden` clips to the rounded
  corners for free. Let props BLEED off 1-2 card edges (reference-grade dynamism), sized per
  the unified standards above.
- Ground each prop with a drop-shadow TINTED to its card: `filter: contrast(1.07)
  brightness(.985) drop-shadow(22px 32px 38px rgba(<bg-dark-tone>, .4-.55))`.
- Prop patches that keep a baked background (edit-mode replicas): blend with
  `mask-image: linear-gradient(...)` fades so the patch dissolves into the code gradient —
  no hard matting, no halos.

## Stage D — Verify + deliver

- Serve (`node scripts/serve.mjs <dir> 8799` — ships with this kit next to this file), screenshot
  headless at exact size (superpowers-chrome `use_browser`: set_viewport → navigate →
  screenshot; re-set the viewport after any Chrome auto-restart).
- Replicas: `python3 scripts/compare.py render.png reference.png --blur 1.6 --heatmap d.png`
  → fix worst region → repeat until improvement <0.2%/iteration. Report the % honestly with
  its floors (font substitute, reference blur, regenerated prop texture).
- Generative sets: visual pass at full size + zoomed crops; check style consistency across
  props (same material/light direction), edge bleed, shadow grounding.
- Deliverables per card: standalone HTML + transparent rounded PNG via
  `python3 scripts/alpha_card.py flat.png card.png <w> <h> <radius>` (verifies alpha). Link
  every image in chat (author-machine convenience: markdown + raw file:// URLs in a code
  block; externally, deliver per AGENTS.md §4 — one folder in the working directory).

## Failure modes already paid for

- Big soft corner radials → washed card (fit small tight ones to sampled corner values).
- Letter-spacing drifts per line length: fix per-line with spans, not one h1 value.
- Metric blur can't hide glyph-shape mismatch: if blur doesn't lift the score, it's geometry.
- Two props from different generation lineages will NOT match in style — same batch, same
  locked block, same model, or don't expect a family.
- remove_background keeps baked cast-shadow rectangles — fade that edge (`cutout_hygiene.py`).
