From f232eb329425feae1553bb7a5db2c45b5f61fffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Sat, 11 Jul 2026 08:12:48 +0000 Subject: [PATCH] fix(product-launch): preserve brand font and accent roles --- .../scripts/build-frame.mjs | 5 +--- .../scripts/lib/tokens.mjs | 16 +++++------- .../scripts/lib/tokens.test.mjs | 26 +++++++++++++++++++ 3 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 skills/product-launch-video/scripts/lib/tokens.test.mjs diff --git a/skills/product-launch-video/scripts/build-frame.mjs b/skills/product-launch-video/scripts/build-frame.mjs index fb34793977..269b605299 100644 --- a/skills/product-launch-video/scripts/build-frame.mjs +++ b/skills/product-launch-video/scripts/build-frame.mjs @@ -32,6 +32,7 @@ import { fileURLToPath } from "node:url"; import { brandRolesFromStats, chroma, + isIconFont, lum, parseColors, parseFonts, @@ -163,10 +164,6 @@ let brandFontWeights = []; // weights the brand text font actually ships (tokens let brandColorStats = []; // rich per-color usage stats (areaBg / interactiveBg / textCount …) // Icon/glyph fonts capture surfaces as "fonts" — they are never the brand text face // (webflow-icons, Font Awesome, icomoon …) and must not become display/body or contribute weights. -const isIconFont = (name) => - /(?:^|[\s_-])icons?(?:[\s_-]|$)|icomoon|font\s*-?awesome|glyphicons?|material\s*icons|feather\s*icons/i.test( - String(name), - ); if (existsSync(tokensPath)) { try { const t = JSON.parse(readFileSync(tokensPath, "utf8")); diff --git a/skills/product-launch-video/scripts/lib/tokens.mjs b/skills/product-launch-video/scripts/lib/tokens.mjs index f604c4d3a7..dea0447199 100644 --- a/skills/product-launch-video/scripts/lib/tokens.mjs +++ b/skills/product-launch-video/scripts/lib/tokens.mjs @@ -48,6 +48,12 @@ export const UA_DEFAULT_COLORS = new Set( ["#0000EE", "#0000FF", "#0000CC", "#1A0DAB", "#551A8B", "#EE0000"].map((c) => c.toUpperCase()), ); +export function isIconFont(name) { + return /(?:^|[\s_-])icons?(?:[\s_-]|$)|icomoon|font\s*-?awesome|glyphicons?|material\s*icons|feather\s*icons|(?:icon|glyph).*font|font.*(?:icon|glyph)|font$/i.test( + String(name), + ); +} + // Semantic STATUS roles (green "positive", red "negative"/"error", amber "warning" …). Their HUE // carries the meaning, so they are never a brand ACCENT — a status red is frequently the most // chromatic color in a palette (e.g. #dc2626 chroma 182 beats a deep-blue accent #1E40AF chroma @@ -127,15 +133,7 @@ export function brandRolesFromStats(stats, colorsInOrder) { .find((s) => Math.abs((lum(s.hex) ?? 0) - cl) > 64)?.hex ?? (cl > 128 ? "#000000" : "#FFFFFF"); const accent2 = - v - .filter( - (s) => - ![canvas, ink, accent].includes(s.hex) && - (s.interactiveBg || 0) > 0 && - chroma(s.hex) > 40 && - !UA_DEFAULT_COLORS.has(s.hex.toUpperCase()), - ) - .sort((a, b) => (b.interactiveBg || 0) - (a.interactiveBg || 0))[0]?.hex ?? accent; + pickAccent(v, colorsInOrder ?? v.map((s) => s.hex), [canvas, ink, accent]) ?? accent; return { ink, canvas, accent, accent2 }; } diff --git a/skills/product-launch-video/scripts/lib/tokens.test.mjs b/skills/product-launch-video/scripts/lib/tokens.test.mjs new file mode 100644 index 0000000000..e0f62bf8a5 --- /dev/null +++ b/skills/product-launch-video/scripts/lib/tokens.test.mjs @@ -0,0 +1,26 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { brandRolesFromStats, isIconFont } from "./tokens.mjs"; + +test("recognizes brand-specific icon font names", () => { + assert.equal(isIconFont("vidaXLfont"), true); + assert.equal(isIconFont("BrandGlyphFont"), true); + assert.equal(isIconFont("Poppins"), false); +}); + +test("preserves a prominent second accent used outside interactive backgrounds", () => { + const colors = ["#FFFFFF", "#2D1238", "#F3E62B", "#111111"]; + const stats = [ + { hex: "#FFFFFF", areaBg: 1000, maxArea: 1000 }, + { hex: "#2D1238", textCount: 4, interactiveBg: 3 }, + { hex: "#F3E62B", textCount: 3, interactiveBg: 0 }, + { hex: "#111111", textCount: 20 }, + ]; + + assert.deepEqual(brandRolesFromStats(stats, colors), { + canvas: "#FFFFFF", + ink: "#111111", + accent: "#F3E62B", + accent2: "#2D1238", + }); +});