mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
5c2981d066
commit
8bf939043f
+14
-2
@@ -226,8 +226,17 @@
|
||||
|
||||
function hfApplyStageConfig(data, durationS) {
|
||||
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
|
||||
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
|
||||
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
|
||||
// Mirror the published validator's <=8192 bound defensively — the
|
||||
// validator is an optional pre-flight, and an unbounded stage size
|
||||
// would OOM render workers.
|
||||
var W = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
|
||||
);
|
||||
var H = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
|
||||
);
|
||||
var root = document.getElementById(HF_ROOT_ID);
|
||||
[document.documentElement, document.body, root].forEach(function (el) {
|
||||
el.style.width = W + "px";
|
||||
@@ -420,6 +429,9 @@
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
// minSize is a hard floor returned unverified below — self-heal
|
||||
// accepts residual overflow at the floor (clipped by the stage)
|
||||
// rather than shrinking below legibility.
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
|
||||
+29
-23
@@ -229,8 +229,17 @@
|
||||
|
||||
function hfApplyStageConfig(data, durationS) {
|
||||
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
|
||||
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
|
||||
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
|
||||
// Mirror the published validator's <=8192 bound defensively — the
|
||||
// validator is an optional pre-flight, and an unbounded stage size
|
||||
// would OOM render workers.
|
||||
var W = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
|
||||
);
|
||||
var H = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
|
||||
);
|
||||
var root = document.getElementById(HF_ROOT_ID);
|
||||
[document.documentElement, document.body, root].forEach(function (el) {
|
||||
el.style.width = W + "px";
|
||||
@@ -532,6 +541,9 @@
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
// minSize is a hard floor returned unverified below — self-heal
|
||||
// accepts residual overflow at the floor (clipped by the stage)
|
||||
// rather than shrinking below legibility.
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
@@ -605,24 +617,16 @@
|
||||
}
|
||||
|
||||
function shadowForColor(color) {
|
||||
var hex = color.replace("#", "");
|
||||
var r = parseInt(hex.slice(0, 2), 16);
|
||||
var g = parseInt(hex.slice(2, 4), 16);
|
||||
var b = parseInt(hex.slice(4, 6), 16);
|
||||
// color-mix handles ANY CSS color (hex of either length, rgb()/hsl(),
|
||||
// named colors) — the old hex-pair slicing was why brand colors were
|
||||
// gated behind a strict 6-digit regex, silently dropping payloads the
|
||||
// sibling templates accept.
|
||||
return (
|
||||
"0 4px 8px rgba(0,0,0,0.7), 0 0 2px rgba(" +
|
||||
r +
|
||||
"," +
|
||||
g +
|
||||
"," +
|
||||
b +
|
||||
",1), 0 0 8px rgba(" +
|
||||
r +
|
||||
"," +
|
||||
g +
|
||||
"," +
|
||||
b +
|
||||
",0.6)"
|
||||
"0 4px 8px rgba(0,0,0,0.7), 0 0 2px " +
|
||||
color +
|
||||
", 0 0 8px color-mix(in srgb, " +
|
||||
color +
|
||||
" 60%, transparent)"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -689,12 +693,14 @@
|
||||
stage.style.bottom = Math.round(80 * layout.scaleY) + "px";
|
||||
|
||||
var rootEl = document.getElementById(HF_ROOT_ID);
|
||||
// Any non-empty CSS color is honored (mirrors caption-pill-karaoke) —
|
||||
// shadowForColor no longer needs parseable hex, so the old 6-digit
|
||||
// gate (which silently dropped #fff / rgb() / named colors that the
|
||||
// sibling templates accept) is gone.
|
||||
var primary = getComputedStyle(rootEl).getPropertyValue("--hf-caption-primary").trim();
|
||||
var accent = getComputedStyle(rootEl).getPropertyValue("--hf-caption-accent").trim();
|
||||
hfPrimaryColor = /^#[0-9a-f]{6}$/i.test(primary) ? primary : "#FFFFFF";
|
||||
hfAccentColors = /^#[0-9a-f]{6}$/i.test(accent)
|
||||
? [accent]
|
||||
: ["#FF76FF", "#FF0002", "#B2F7FF"];
|
||||
hfPrimaryColor = primary || "#FFFFFF";
|
||||
hfAccentColors = accent ? [accent] : ["#FF76FF", "#FF0002", "#B2F7FF"];
|
||||
|
||||
var WORDS = normalizeWords(words);
|
||||
var GROUPS = makeGroups(WORDS);
|
||||
|
||||
@@ -132,6 +132,9 @@
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
// minSize is a hard floor returned unverified below — self-heal
|
||||
// accepts residual overflow at the floor (clipped by the stage)
|
||||
// rather than shrinking below legibility.
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
@@ -235,8 +238,17 @@
|
||||
|
||||
function hfApplyStageConfig(data, durationS) {
|
||||
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
|
||||
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
|
||||
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
|
||||
// Mirror the published validator's <=8192 bound defensively — the
|
||||
// validator is an optional pre-flight, and an unbounded stage size
|
||||
// would OOM render workers.
|
||||
var W = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
|
||||
);
|
||||
var H = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
|
||||
);
|
||||
var root = document.getElementById(HF_ROOT_ID);
|
||||
[document.documentElement, document.body, root].forEach(function (el) {
|
||||
el.style.width = W + "px";
|
||||
|
||||
@@ -235,8 +235,17 @@
|
||||
|
||||
function hfApplyStageConfig(data, durationS) {
|
||||
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
|
||||
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
|
||||
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
|
||||
// Mirror the published validator's <=8192 bound defensively — the
|
||||
// validator is an optional pre-flight, and an unbounded stage size
|
||||
// would OOM render workers.
|
||||
var W = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
|
||||
);
|
||||
var H = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
|
||||
);
|
||||
var root = document.getElementById(HF_ROOT_ID);
|
||||
[document.documentElement, document.body, root].forEach(function (el) {
|
||||
el.style.width = W + "px";
|
||||
@@ -464,6 +473,9 @@
|
||||
|
||||
function fontSizeForGroup(words) {
|
||||
var size = BASE_FONT_SIZE;
|
||||
// MIN_FONT_SIZE is a hard floor returned unverified below — self-heal
|
||||
// accepts residual overflow at the floor (clipped by the stage)
|
||||
// rather than shrinking below legibility.
|
||||
while (size > MIN_FONT_SIZE && !fitsInTwoLinesAtSize(words, size)) {
|
||||
size -= 2;
|
||||
}
|
||||
|
||||
@@ -221,8 +221,17 @@
|
||||
|
||||
function hfApplyStageConfig(data, durationS) {
|
||||
var res = (data && data.resolution) || HF_DEFAULT_RESOLUTION;
|
||||
var W = Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width));
|
||||
var H = Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height));
|
||||
// Mirror the published validator's <=8192 bound defensively — the
|
||||
// validator is an optional pre-flight, and an unbounded stage size
|
||||
// would OOM render workers.
|
||||
var W = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.width) || HF_DEFAULT_RESOLUTION.width)),
|
||||
);
|
||||
var H = Math.min(
|
||||
8192,
|
||||
Math.max(1, Math.round(Number(res.height) || HF_DEFAULT_RESOLUTION.height)),
|
||||
);
|
||||
var root = document.getElementById(HF_ROOT_ID);
|
||||
[document.documentElement, document.body, root].forEach(function (el) {
|
||||
el.style.width = W + "px";
|
||||
@@ -345,6 +354,9 @@
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
// minSize is a hard floor returned unverified below — self-heal
|
||||
// accepts residual overflow at the floor (clipped by the stage)
|
||||
// rather than shrinking below legibility.
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
@@ -401,7 +413,11 @@
|
||||
if (
|
||||
group.words.length === 1 &&
|
||||
out.length > 0 &&
|
||||
out[out.length - 1].words.length < MAX_WORDS_PER_GROUP
|
||||
out[out.length - 1].words.length < MAX_WORDS_PER_GROUP &&
|
||||
// makeGroups guards every addition with fitsInTwoLines; this
|
||||
// second-pass merge must too, or it can produce a group that
|
||||
// splitLines cannot fit within MAX_LINE_WIDTH.
|
||||
fitsInTwoLines(out[out.length - 1].words.concat(group.words))
|
||||
) {
|
||||
out[out.length - 1] = makeGroup(out[out.length - 1].words.concat(group.words));
|
||||
} else {
|
||||
@@ -411,10 +427,18 @@
|
||||
|
||||
for (var i = 0; i < out.length; i++) {
|
||||
if (out[i].words.length !== 1) continue;
|
||||
if (i + 1 < out.length && out[i + 1].words.length < MAX_WORDS_PER_GROUP) {
|
||||
if (
|
||||
i + 1 < out.length &&
|
||||
out[i + 1].words.length < MAX_WORDS_PER_GROUP &&
|
||||
fitsInTwoLines(out[i].words.concat(out[i + 1].words))
|
||||
) {
|
||||
out[i] = makeGroup(out[i].words.concat(out[i + 1].words));
|
||||
out.splice(i + 1, 1);
|
||||
} else if (i > 0 && out[i - 1].words.length < MAX_WORDS_PER_GROUP) {
|
||||
} else if (
|
||||
i > 0 &&
|
||||
out[i - 1].words.length < MAX_WORDS_PER_GROUP &&
|
||||
fitsInTwoLines(out[i - 1].words.concat(out[i].words))
|
||||
) {
|
||||
out[i - 1] = makeGroup(out[i - 1].words.concat(out[i].words));
|
||||
out.splice(i, 1);
|
||||
i--;
|
||||
@@ -464,13 +488,24 @@
|
||||
function buildCaptions(groups) {
|
||||
var stage = document.getElementById("caption-stage");
|
||||
groups.forEach(function (group, groupIndex) {
|
||||
var groupText = group.words
|
||||
.map(function (w) {
|
||||
return w.text.toLowerCase();
|
||||
})
|
||||
.join(" ");
|
||||
// Fit the WIDEST split line, not the joined group text: the group
|
||||
// renders across up to two lines, so sizing against the joined
|
||||
// string shrank two-line groups that already fit at full size.
|
||||
var widestLineText = "";
|
||||
var widestLineWidth = -1;
|
||||
group.lines.forEach(function (line) {
|
||||
var lineWidth = measureLineWidth(line.words);
|
||||
if (lineWidth > widestLineWidth) {
|
||||
widestLineWidth = lineWidth;
|
||||
widestLineText = line.words
|
||||
.map(function (w) {
|
||||
return w.text.toLowerCase();
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
});
|
||||
var computedSize = fitFontSize(
|
||||
groupText,
|
||||
widestLineText,
|
||||
CAPTION_FONT_SIZE,
|
||||
"700",
|
||||
"Montserrat",
|
||||
|
||||
Reference in New Issue
Block a user