mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-15 22:08:03 +00:00
fix(skills): stop a near-neutral color from being promoted to a brand accent
semanticColors() ranked every leftover preset color by chroma to pick accent/accent2, with no floor. A preset with only one real accent (e.g. broadside's fire-orange) still handed back an accents[1]: its next-highest leftover, often a near-neutral grey text tone (broadside's cream-muted, chroma 8). build-frame.mjs's remix then treated that as an exact accent2 match and repainted it with the brand's literal accent2 hex, turning a muted grey text color into a saturated amber. Add a chroma>=16 floor before a color counts as a real accent candidate, matching the neutral cutoff the remix itself already uses to keep a grey ladder grey. Below the floor, accent2 falls back to the primary accent.
This commit is contained in:
@@ -70,7 +70,7 @@
|
||||
"files": 30
|
||||
},
|
||||
"product-launch-video": {
|
||||
"hash": "2c3d5d90b2b181a0",
|
||||
"hash": "3f16091b195233bb",
|
||||
"files": 31
|
||||
},
|
||||
"remotion-to-hyperframes": {
|
||||
|
||||
@@ -74,3 +74,11 @@ test("a light-ground preset (capsule) onto a light-mode brand is not inverted",
|
||||
const { stdout } = runBuildFrame("capsule", LIGHT_BRAND_TOKENS);
|
||||
assert.doesNotMatch(stdout, /INVERTED/);
|
||||
});
|
||||
|
||||
test("broadside's cream-muted stays a neutral grey, not the brand's saturated accent", () => {
|
||||
const { frameMd } = runBuildFrame("broadside", DARK_BRAND_TOKENS);
|
||||
const m = /cream-muted:\s*"(#[0-9A-Fa-f]{6})"/.exec(frameMd);
|
||||
assert.ok(m, "cream-muted key missing from frame.md");
|
||||
// #FFB800 is the brand's literal accent2 — forced in before the fix.
|
||||
assert.notEqual(m[1].toUpperCase(), "#FFB800");
|
||||
});
|
||||
|
||||
@@ -181,12 +181,17 @@ export function semanticColors(colors, md) {
|
||||
byLum[byLum.length - 1] ?? colors[colors.length - 1],
|
||||
);
|
||||
const accents = colors
|
||||
// A candidate must clear a neutral chroma floor to count as a real accent — otherwise a
|
||||
// preset with only one genuine accent hands back a near-neutral leftover (e.g. a grey text
|
||||
// tone at chroma ~8) as accent2, which then gets an exact-match repaint downstream. 16
|
||||
// matches the neutral cutoff the remix itself already uses to keep a grey ladder grey.
|
||||
.filter(
|
||||
([k, v]) =>
|
||||
v !== ink &&
|
||||
v !== canvas &&
|
||||
!UA_DEFAULT_COLORS.has(String(v).toUpperCase()) &&
|
||||
!STATUS_ROLE_KEY.test(k), // a status red/green carries meaning by hue — never an accent
|
||||
!STATUS_ROLE_KEY.test(k) && // a status red/green carries meaning by hue — never an accent
|
||||
chroma(v) >= 16,
|
||||
)
|
||||
.sort((a, b) => chroma(b[1]) - chroma(a[1]))
|
||||
.map(([, v]) => v);
|
||||
|
||||
@@ -122,3 +122,18 @@ test("every shipped preset's detected ground polarity matches its declared regis
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("semanticColors keeps a near-neutral 'second accent' neutral instead of promoting it", () => {
|
||||
// broadside's cream-muted (#888880, chroma 8) is a muted grey text tone, not a real second
|
||||
// brand accent — it must not win accent2 over the neutral chroma floor.
|
||||
const colors = [
|
||||
["ink-black", "#111111"],
|
||||
["fire-orange", "#E85D26"],
|
||||
["cream", "#F0ECE5"],
|
||||
["cream-muted", "#888880"],
|
||||
];
|
||||
const roles = semanticColors(colors);
|
||||
assert.equal(roles.accent, "#E85D26");
|
||||
assert.notEqual(roles.accent2, "#888880");
|
||||
assert.equal(roles.accent2, "#E85D26"); // no 2nd real accent — falls back to the primary
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user