Pre-Flight & Review
The Iron Law: never ship the first version. Build it, then run these checks with fresh, critical eyes. Sources: emil (review format + checklist) and taste-skill (pre-flight matrix).
Review Format (required when reviewing UI code)
When reviewing UI code, you MUST use a markdown table with Before/After columns. Do NOT use a list with “Before:” and “After:” on separate lines. Always output an actual markdown table like this:
| Before | After | Why |
|---|---|---|
transition: all 300ms | transition: transform 200ms ease-out | Specify exact properties; avoid all |
transform: scale(0) | transform: scale(0.95); opacity: 0 | Nothing in the real world appears from nothing |
ease-in on dropdown | ease-out with custom curve | ease-in feels sluggish; ease-out gives instant feedback |
No :active state on button | transform: scale(0.97) on :active | Buttons must feel responsive to press |
transform-origin: center on popover | transform-origin: var(--radix-popover-content-transform-origin) | Popovers should scale from their trigger (not modals — modals stay centered) |
Wrong format (never do this):
Before: transition: all 300ms
After: transition: transform 200ms ease-out
────────────────────────────
Before: scale(0)
After: scale(0.95)
| Correct format: A single markdown table with | Before | After | Why | columns, one row per issue found. The “Why” column briefly explains the reasoning. |
Motion Review Checklist (from emil)
When reviewing UI code, check for:
| Issue | Fix |
|---|---|
transition: all | Specify exact properties: transition: transform 200ms ease-out |
scale(0) entry animation | Start from scale(0.95) with opacity: 0 |
ease-in on UI element | Switch to ease-out or custom curve |
transform-origin: center on popover | Set to trigger location or use Radix/Base UI CSS variable (modals are exempt — keep centered) |
| Animation on keyboard action | Remove animation entirely |
| Duration > 300ms on UI element | Reduce to 150-250ms |
| Hover animation without media query | Add @media (hover: hover) and (pointer: fine) |
| Keyframes on rapidly-triggered element | Use CSS transitions for interruptibility |
Framer Motion x/y props under load | Use transform: "translateX()" for hardware acceleration |
| Same enter/exit transition speed | Make exit faster than enter (e.g., enter 2s, exit 200ms) |
| Elements all appear at once | Add stagger delay (30-80ms between items) |
Full Pre-Flight Matrix (from taste-skill)
Run this matrix before outputting code. This is the last filter.
THIS IS NOT OPTIONAL. Run every box. If any box fails, the output is not done.
- Brief inference declared (Section 0.B one-liner)?
- Dial values explicit and reasoned from the brief, not silently using baseline?
- Design system chosen from Section 2 if applicable, or aesthetic labeled honestly?
- Redesign mode detected and audit performed (if applicable, Section 11)?
- ZERO em-dashes (
—) anywhere on the page. Headlines, eyebrows, pills, body, quotes, attribution, captions, buttons, alt text. Zero. (Section 9.G - non-negotiable.) - Page Theme Lock: ONE theme (light, dark, or auto) for the whole page. No section flips to inverted mode mid-page (Section 4.11)?
- Color Consistency Lock: one accent color used identically across all sections (Section 4.2)?
- Shape Consistency Lock: one corner-radius system applied consistently (Section 4.4)?
- Button Contrast Check: every CTA text is readable against its background (no white-on-white, WCAG AA 4.5:1)?
- CTA Button Wrap: no CTA label wraps to 2+ lines at desktop?
- Form Contrast Check: form inputs, placeholders, focus rings, labels all pass WCAG AA against the section background?
- Serif discipline: if a serif is used, it is NOT Fraunces or Instrument_Serif (or it is, with explicit brand justification)? Different serif from your previous project?
- Premium-consumer palette check: if the brief is premium-consumer (cookware / wellness / artisan / luxury), the palette is NOT the AI-default beige+brass+oxblood+espresso family? Different family from your previous premium-consumer project?
- Italic descender clearance: every italic word with
y g j p qhasleading-[1.1]min +pb-1reserve? - Hero fits the viewport: headline ≤ 2 lines, subtext ≤ 20 words AND ≤ 4 lines, CTA visible without scroll, font scale planned around image?
- Hero top padding: max
pt-24at desktop, hero content does not float halfway down the viewport? - Hero stack discipline: max 4 text elements in hero (eyebrow OR brand strip, headline, subtext, CTAs)? No tiny tagline below CTAs, no trust micro-strip in hero?
- EYEBROW COUNT (mechanical): count instances of
uppercase trackingmicro-labels above section headlines across all components. Count ≤ ceil(sectionCount / 3)? Hero counts as 1. - Split-Header Ban: no “left big headline + right small explainer paragraph” pattern as a section header (vertical stack instead)?
- Zigzag Alternation Cap: no 3+ consecutive sections with the same image+text-split layout?
- No Duplicate CTA Intent: no two CTAs with the same intent (“Get in touch” + “Let’s talk” both on page = Fail)?
- Logo wall = logo only: no industry / category labels printed below logos?
- Bento Background Diversity: at least 2-3 bento cells have real visual variation (image, gradient, pattern), not all white-on-white text cards?
- “Used by / Trusted by” logo wall lives UNDER the hero, not inside it, uses REAL SVG logos (Simple Icons / devicon) or generated SVG marks, NOT plain text wordmarks?
- Copy Self-Audit: every visible string re-read, no grammatically-broken or AI-hallucinated phrases (“free on its past” type) shipped?
- Motion motivated: every animation can be justified in one sentence (hierarchy / storytelling / feedback / state transition), no GSAP-for-show?
- Marquee max-one-per-page: no two horizontal marquees on the same page?
- Navigation on ONE line at desktop, height ≤ 80px?
- Section-Layout-Repetition check: no two sections share the same layout family (at least 4 different families across 8 sections)?
- Bento has rhythm AND exact cell count (N items → N cells, no empty cells in middle or at end)?
- Long lists use the right UI component (not default
<ul>withdivide-yfor > 5 items - see Section 4.9 alternatives)? - Real images used (gen-tool first, then Picsum-seed, then explicit placeholder slots) - NO div-based fake screenshots, NO hand-rolled decorative SVGs, NO pure-text minimalism?
- No pills/labels overlaid on images (no
Plate · Brand, noField notes - journal)? - No photo-credit captions as decoration (
Field study no. 12 · Ines Caetano)? - No version footers (
v1.4.2,Build 0048) on marketing pages? - No micro-meta-sentences under eyebrows (“Each of these is a feature we ship today…”)?
- No decoration text strip at hero bottom (
BRAND. MOTION. SPATIAL.)? - No floating top-right sub-text in section headings?
- No scoring/progress bars with filled background tracks as comparison visuals?
- No locale / city-name / time / weather strips unless brief is genuinely globally-distributed or place-focused?
- No scroll cues (
Scroll,↓ scroll,Scroll to explore)? - No version labels in hero (V0.6, BETA, INVITE-ONLY) unless the brief is a launch?
- No section-numbering eyebrows (
00 / INDEX,001 · Capabilities,06 · how it works)? - No decorative dots (zero by default, only for real semantic state)?
- No
border-t+border-bon every row of long lists / spec tables? - Content density sane: no 20-row data tables, no fake-precise specs without justification, ≤ 25-word sub-paragraphs by default?
- Quotes ≤ 3 lines of body, attribution clean (no em-dash)?
- Motion claimed = motion shown: if
MOTION_INTENSITY > 4, page actually animates, not just claimed? - GSAP sticky-stack / horizontal-pan implemented per Section 5.A / 5.B canonical skeleton (
start: "top top",pin: true, correct scrub)? - No
window.addEventListener('scroll')- using MotionuseScroll()/ ScrollTrigger / IntersectionObserver / CSS scroll-driven animations only? - Reduced motion wrapped for everything
MOTION_INTENSITY > 3? - Dark mode tokens defined and tested in both modes?
- Mobile collapse explicit (
w-full,px-4,max-w-7xl mx-auto) for high-variance layouts? - Viewport stability:
min-h-[100dvh], neverh-screen? useEffectanimations have strict cleanup functions?- Empty / loading / error states provided?
- Cards omitted in favor of spacing where possible?
- Icons from an allowed library only (Phosphor / HugeIcons / Radix / Tabler), no hand-rolled SVG paths?
- Motion isolated in client-leaf components with
'use client'at the top, memoized? - No AI Tells from Section 9 (Inter as default, AI-purple, three-equal cards, Jane Doe, Acme, “Quietly in use at”)?
- Core Web Vitals plausibly hit (LCP < 2.5s, INP < 200ms, CLS < 0.1)?
- One design system per project (no Material + shadcn mixed)?
If a single checkbox cannot be honestly ticked, the page is not done. Fix it before delivering.