diff --git a/url-to-frame-md/POLISH-LOG.md b/url-to-frame-md/POLISH-LOG.md new file mode 100644 index 0000000000..aa354c1e36 --- /dev/null +++ b/url-to-frame-md/POLISH-LOG.md @@ -0,0 +1,425 @@ +# Showcase polish log + +Reviewer-driven iteration on the URL → frame.md → showcase pipeline. Each cycle = one +verified increment. Canonical toolkit home: experiment-framework PR #41000 — push these +source changes there when reviewed. + +## Cycle 12 — SVG density on bare beats + avatar frames + +Reviewer + user feedback: frames 1-3 were bare (wordmark / big text / lone number) — unrealistic for a video-agent — and there were no avatar frames. + +- cover -> SVG system emblem; claim -> oversized SVG quote-mark; stat -> real SVG area chart (grid + area + line + points), not a lone number. +- New **avatar-support** (presenter as ground + supporting bar-viz) and **avatar-overlay** (PiP bug + lower-third over a stat beat), from a bundled brand-agnostic portrait, accent-tinted per site. +- Sheet now 12 frames. All 15 verify+render green. + +## Cycle 1 — ground inversion, font poison, swatch legibility + +Reviewers (opus/linear/snowflake/elevenlabs, comparing `showcase.png` vs +`screenshots/contact-sheet-1.jpg` vs `frame.md`) flagged three systemic showcase bugs. +All three fixed and verified across all 11 sites (verify-green; visual spot-check on +stripe/elevenlabs/snowflake=light, opus/linear=dark). + +1. **Italic font poisoning** (`lib/fonts.mjs`). Linear ships `InterVariable-Regular.woff2` + whose _content is italic_ (manifest `style: italic`) plus the true upright + `InterVariable.woff2`. Two-layer fix: + - skip italic files on read (`isItalicFile`: manifest style or /italic|oblique/ name); + - **stage with an unconditional copy** — the old `if (!existsSync)` guard let a stale + poisoned clean-named file from an earlier run survive forever (staging writes into + the same dir it reads). Re-copying the correctly-chosen source each run is idempotent + for good files and self-heals poisoned slots. + → Linear display/hero now upright Inter. + +2. **Gallery ground inversion** (`render-showcase.mjs`). The doc chrome was hardcoded + `#0e0e0e`, so light-first brands (ElevenLabs cream, Snowflake/Stripe white) rendered as + a dark board. Now derived from brand luminance: `darkGallery = lumOf(canvas) < 128`; + light brands get `shade(canvas,-8%)` ground + dark doc text; dark brands keep `#0e0e0e`. + Section heads, rails, frame shadows, and the Chrome `--default-background-color` all + follow the same polarity. + +3. **Invisible swatches + muddy labels** (`render-showcase.mjs`). Every `.sw .chip` now + gets a luminance-aware inset hairline (dark-on-dark / white-on-white chips were + vanishing). Muted label opacities bumped .5→.68/.7 (`.sm code`, `.tmeta span`, + `.cnote`, rail attrs). + +## Cycle 2 — gradient/mesh capture (engine) + accent proportion + offline re-extract harness + +All 5 reviewers (stripe/elevenlabs/opus/heygen/snowflake) converged: the #1 essence loss is the +site's signature **gradient/mesh background** (flat spec-sheet vs. brand color wash), and #2 is the +**accent overstatement** (giant stat numbers in accent). Both fixed end-to-end; all 11 verify-green. + +1. **Engine gradient capture** (`designStyleExtractor.ts` + `types.ts`). `getStyles` now records + gradient `backgroundImage` (url()/none dropped) and `backdropFilter`; button/card/nav keep those + in their dedup keys so a gradient/frosted variant survives. New page-level collector scans large + elements **+ `::before`/`::after` pseudo-elements** (hero orbs are often pseudo) and returns the + top washes ranked by **chroma-weighted area** (a vivid brand wash beats a bigger neutral scrim). + Result: Stripe's signature `radial-gradient(circle,#7F7DFC,#F44BCC 33%,#E5EDF5 66%)` mesh is + captured and now grounds the cover — instantly reads as Stripe. + +2. **Offline re-extraction harness** (`reextract-design.mjs`). Dependency-free Chrome DevTools + Protocol client (Node 22 global `WebSocket`/`fetch`) that re-runs the _actual_ engine script + (sourced from `designStyleExtractor.ts`, single source of truth) against the saved + `extracted/page.html` — validates engine changes across all 11 captures with **no live network**. + **MERGE-ONLY**: it writes back only `backgrounds`. Hard lesson: an early version overwrote the + whole `design-styles.json`, and offline typography _degrades_ (the saved "stable HTML" lacks some + runtime styling, so unstyled elements inherit headless Chrome's default face → "PingFang SC" / + stray non-brand fonts leaked into 3 sites and failed verify). Gradients read from inline + `background-image` and ARE offline-faithful; typography is not. (Verified: stripe offline + typography is byte-identical to its live backup — the leak only hits roles the saved CSS didn't + style.) + +3. **Generator** (`build-frame-from-capture.mjs`). Emits a `gradients:` token block (verbatim, + CSS-valid, trailing `, none` layer stripped). New font guard: any typography font **not in the + captured brand set** is normalized to the brand primary (was only catching CSS generics) — fixes + the offline fallback leak _and_ is a genuine robustness win (a role in a system font isn't + brand-meaningful). Keeps frame.md fonts ⊆ captured, so verify's L2 font gate holds. + +4. **Renderer** (`render-showcase.mjs`). Paints the cover ground with the most chromatic captured + gradient; adds a "Backgrounds" proof strip (shows exactly which washes were captured); stat + numbers now render in **ink** (accent reserved for eyebrow + one emphasized word), per all 5 + reviewers. `run-all.sh` = canonical refresh (re-extract → generate → render → verify). + +Honest limits this cycle: ElevenLabs/HeyGen hero _auras_ are canvas/WebGL (or below the area +floor), not CSS gradients — their captured washes are faint edge-scrims/glass fills, so no dramatic +cover ground (correct, not forced). Opus/DoorDash are genuinely flat (0 gradients). `backdrop-filter` +came back empty because the frosted panels aren't in the card/nav selectors (see backlog). + +## Cycle 3 — primary-CTA identity + card elevation + alpha-drop fix + +All 5 reviewers' #1 gap was an **inverted primary CTA**: the generator picked the wrong button as +`button-primary`. No cycle-2 regressions (gradient cover + accent dial-back confirmed good). All 11 +verify-green; CTA fixed on 5/6 flagged sites (visually confirmed). + +Root causes + fixes: + +1. **Primary CTA chosen by "closest to accent"** — fails for brands whose CTA is a high-contrast + _neutral_ pill (ElevenLabs black, Opus white, HeyGen dark) rather than the accent hue. + → Generator: `fillProminence` ranks by `max(accent-closeness, canvas-contrast)` among solid fills, + with a pill-radius tie-break and gradient fills scored top. `radiusRef`/dedup now key on pill-vs- + square so a pill and a same-fill square stay distinct (Opus's white pill no longer collapses). + +2. **Primary CTA lived in the nav/header** (`Sign up`, `Start for free`) — the engine dropped all + `