Skip to content

Commit 8bf9390

Browse files
vanceingallsclaude
andcommitted
fix(registry): liberal emoji-pop brand colors, weight-shift fit fixes, 8192 clamp
- caption-emoji-pop: shadowForColor now builds its glow via color-mix() instead of hex-pair slicing, so the strict 6-digit brand-color gate is gone — any CSS color the sibling templates accept (#fff, rgb(), named) now renders instead of silently falling back to the default palette - caption-weight-shift: fitFontSize now sizes against the WIDEST split line rather than the joined group text (two-line groups no longer shrink unnecessarily), and avoidSingleWordGroups' merges re-check fitsInTwoLines like makeGroups' first pass does (merged groups can no longer overflow the split budget) - all 5: hfApplyStageConfig clamps resolution to the published validator's <=8192 bound (validator is optional pre-flight; unbounded stages OOM render workers), and fit floors carry a comment documenting that the minimum size is returned unverified by design Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 5c2981d commit 8bf9390

5 files changed

Lines changed: 117 additions & 40 deletions

File tree

registry/components/caption-editorial-emphasis/caption-editorial-emphasis.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,17 @@
226226

227227
function hfApplyStageConfig(data, durationS) {
228228
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
229-
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
230-
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
229+
// Mirror the published validator's <=8192 bound defensively — the
230+
// validator is an optional pre-flight, and an unbounded stage size
231+
// would OOM render workers.
232+
var W = Math.min(
233+
8192,
234+
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
235+
);
236+
var H = Math.min(
237+
8192,
238+
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
239+
);
231240
var root = document.getElementById(HF_ROOT_ID);
232241
[document.documentElement, document.body, root].forEach(function (el) {
233242
el.style.width = W + "px";
@@ -420,6 +429,9 @@
420429
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
421430
var size = baseFontSize;
422431
var minSize = Math.floor(baseFontSize * 0.45);
432+
// minSize is a hard floor returned unverified below — self-heal
433+
// accepts residual overflow at the floor (clipped by the stage)
434+
// rather than shrinking below legibility.
423435
while (size > minSize) {
424436
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
425437
if (_fitCtx.measureText(text).width <= maxWidth) return size;

registry/components/caption-emoji-pop/caption-emoji-pop.html

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,17 @@
229229

230230
function hfApplyStageConfig(data, durationS) {
231231
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
232-
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
233-
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
232+
// Mirror the published validator's <=8192 bound defensively — the
233+
// validator is an optional pre-flight, and an unbounded stage size
234+
// would OOM render workers.
235+
var W = Math.min(
236+
8192,
237+
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
238+
);
239+
var H = Math.min(
240+
8192,
241+
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
242+
);
234243
var root = document.getElementById(HF_ROOT_ID);
235244
[document.documentElement, document.body, root].forEach(function (el) {
236245
el.style.width = W + "px";
@@ -532,6 +541,9 @@
532541
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
533542
var size = baseFontSize;
534543
var minSize = Math.floor(baseFontSize * 0.45);
544+
// minSize is a hard floor returned unverified below — self-heal
545+
// accepts residual overflow at the floor (clipped by the stage)
546+
// rather than shrinking below legibility.
535547
while (size > minSize) {
536548
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
537549
if (_fitCtx.measureText(text).width <= maxWidth) return size;
@@ -605,24 +617,16 @@
605617
}
606618

607619
function shadowForColor(color) {
608-
var hex = color.replace("#", "");
609-
var r = parseInt(hex.slice(0, 2), 16);
610-
var g = parseInt(hex.slice(2, 4), 16);
611-
var b = parseInt(hex.slice(4, 6), 16);
620+
// color-mix handles ANY CSS color (hex of either length, rgb()/hsl(),
621+
// named colors) — the old hex-pair slicing was why brand colors were
622+
// gated behind a strict 6-digit regex, silently dropping payloads the
623+
// sibling templates accept.
612624
return (
613-
"0 4px 8px rgba(0,0,0,0.7), 0 0 2px rgba(" +
614-
r +
615-
"," +
616-
g +
617-
"," +
618-
b +
619-
",1), 0 0 8px rgba(" +
620-
r +
621-
"," +
622-
g +
623-
"," +
624-
b +
625-
",0.6)"
625+
"0 4px 8px rgba(0,0,0,0.7), 0 0 2px " +
626+
color +
627+
", 0 0 8px color-mix(in srgb, " +
628+
color +
629+
" 60%, transparent)"
626630
);
627631
}
628632

@@ -689,12 +693,14 @@
689693
stage.style.bottom = Math.round(80 * layout.scaleY) + "px";
690694

691695
var rootEl = document.getElementById(HF_ROOT_ID);
696+
// Any non-empty CSS color is honored (mirrors caption-pill-karaoke) —
697+
// shadowForColor no longer needs parseable hex, so the old 6-digit
698+
// gate (which silently dropped #fff / rgb() / named colors that the
699+
// sibling templates accept) is gone.
692700
var primary = getComputedStyle(rootEl).getPropertyValue("--hf-caption-primary").trim();
693701
var accent = getComputedStyle(rootEl).getPropertyValue("--hf-caption-accent").trim();
694-
hfPrimaryColor = /^#[0-9a-f]{6}$/i.test(primary) ? primary : "#FFFFFF";
695-
hfAccentColors = /^#[0-9a-f]{6}$/i.test(accent)
696-
? [accent]
697-
: ["#FF76FF", "#FF0002", "#B2F7FF"];
702+
hfPrimaryColor = primary || "#FFFFFF";
703+
hfAccentColors = accent ? [accent] : ["#FF76FF", "#FF0002", "#B2F7FF"];
698704

699705
var WORDS = normalizeWords(words);
700706
var GROUPS = makeGroups(WORDS);

registry/components/caption-highlight/caption-highlight.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@
132132
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
133133
var size = baseFontSize;
134134
var minSize = Math.floor(baseFontSize * 0.45);
135+
// minSize is a hard floor returned unverified below — self-heal
136+
// accepts residual overflow at the floor (clipped by the stage)
137+
// rather than shrinking below legibility.
135138
while (size > minSize) {
136139
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
137140
if (_fitCtx.measureText(text).width <= maxWidth) return size;
@@ -235,8 +238,17 @@
235238

236239
function hfApplyStageConfig(data, durationS) {
237240
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
238-
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
239-
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
241+
// Mirror the published validator's <=8192 bound defensively — the
242+
// validator is an optional pre-flight, and an unbounded stage size
243+
// would OOM render workers.
244+
var W = Math.min(
245+
8192,
246+
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
247+
);
248+
var H = Math.min(
249+
8192,
250+
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
251+
);
240252
var root = document.getElementById(HF_ROOT_ID);
241253
[document.documentElement, document.body, root].forEach(function (el) {
242254
el.style.width = W + "px";

registry/components/caption-pill-karaoke/caption-pill-karaoke.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,17 @@
235235

236236
function hfApplyStageConfig(data, durationS) {
237237
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
238-
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
239-
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
238+
// Mirror the published validator's <=8192 bound defensively — the
239+
// validator is an optional pre-flight, and an unbounded stage size
240+
// would OOM render workers.
241+
var W = Math.min(
242+
8192,
243+
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
244+
);
245+
var H = Math.min(
246+
8192,
247+
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
248+
);
240249
var root = document.getElementById(HF_ROOT_ID);
241250
[document.documentElement, document.body, root].forEach(function (el) {
242251
el.style.width = W + "px";
@@ -464,6 +473,9 @@
464473

465474
function fontSizeForGroup(words) {
466475
var size = BASE_FONT_SIZE;
476+
// MIN_FONT_SIZE is a hard floor returned unverified below — self-heal
477+
// accepts residual overflow at the floor (clipped by the stage)
478+
// rather than shrinking below legibility.
467479
while (size > MIN_FONT_SIZE && !fitsInTwoLinesAtSize(words, size)) {
468480
size -= 2;
469481
}

registry/components/caption-weight-shift/caption-weight-shift.html

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,17 @@
221221

222222
function hfApplyStageConfig(data, durationS) {
223223
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
224-
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
225-
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
224+
// Mirror the published validator's <=8192 bound defensively — the
225+
// validator is an optional pre-flight, and an unbounded stage size
226+
// would OOM render workers.
227+
var W = Math.min(
228+
8192,
229+
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
230+
);
231+
var H = Math.min(
232+
8192,
233+
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
234+
);
226235
var root = document.getElementById(HF_ROOT_ID);
227236
[document.documentElement, document.body, root].forEach(function (el) {
228237
el.style.width = W + "px";
@@ -345,6 +354,9 @@
345354
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
346355
var size = baseFontSize;
347356
var minSize = Math.floor(baseFontSize * 0.45);
357+
// minSize is a hard floor returned unverified below — self-heal
358+
// accepts residual overflow at the floor (clipped by the stage)
359+
// rather than shrinking below legibility.
348360
while (size > minSize) {
349361
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
350362
if (_fitCtx.measureText(text).width <= maxWidth) return size;
@@ -401,7 +413,11 @@
401413
if (
402414
group.words.length === 1 &&
403415
out.length > 0 &&
404-
out[out.length - 1].words.length < MAX_WORDS_PER_GROUP
416+
out[out.length - 1].words.length < MAX_WORDS_PER_GROUP &&
417+
// makeGroups guards every addition with fitsInTwoLines; this
418+
// second-pass merge must too, or it can produce a group that
419+
// splitLines cannot fit within MAX_LINE_WIDTH.
420+
fitsInTwoLines(out[out.length - 1].words.concat(group.words))
405421
) {
406422
out[out.length - 1] = makeGroup(out[out.length - 1].words.concat(group.words));
407423
} else {
@@ -411,10 +427,18 @@
411427

412428
for (var i = 0; i < out.length; i++) {
413429
if (out[i].words.length !== 1) continue;
414-
if (i + 1 < out.length && out[i + 1].words.length < MAX_WORDS_PER_GROUP) {
430+
if (
431+
i + 1 < out.length &&
432+
out[i + 1].words.length < MAX_WORDS_PER_GROUP &&
433+
fitsInTwoLines(out[i].words.concat(out[i + 1].words))
434+
) {
415435
out[i] = makeGroup(out[i].words.concat(out[i + 1].words));
416436
out.splice(i + 1, 1);
417-
} else if (i > 0 && out[i - 1].words.length < MAX_WORDS_PER_GROUP) {
437+
} else if (
438+
i > 0 &&
439+
out[i - 1].words.length < MAX_WORDS_PER_GROUP &&
440+
fitsInTwoLines(out[i - 1].words.concat(out[i].words))
441+
) {
418442
out[i - 1] = makeGroup(out[i - 1].words.concat(out[i].words));
419443
out.splice(i, 1);
420444
i--;
@@ -464,13 +488,24 @@
464488
function buildCaptions(groups) {
465489
var stage = document.getElementById("caption-stage");
466490
groups.forEach(function (group, groupIndex) {
467-
var groupText = group.words
468-
.map(function (w) {
469-
return w.text.toLowerCase();
470-
})
471-
.join(" ");
491+
// Fit the WIDEST split line, not the joined group text: the group
492+
// renders across up to two lines, so sizing against the joined
493+
// string shrank two-line groups that already fit at full size.
494+
var widestLineText = "";
495+
var widestLineWidth = -1;
496+
group.lines.forEach(function (line) {
497+
var lineWidth = measureLineWidth(line.words);
498+
if (lineWidth > widestLineWidth) {
499+
widestLineWidth = lineWidth;
500+
widestLineText = line.words
501+
.map(function (w) {
502+
return w.text.toLowerCase();
503+
})
504+
.join(" ");
505+
}
506+
});
472507
var computedSize = fitFontSize(
473-
groupText,
508+
widestLineText,
474509
CAPTION_FONT_SIZE,
475510
"700",
476511
"Montserrat",

0 commit comments

Comments
 (0)