fix(registry): encapsulate caption template runtimes in IIFEs

caption-highlight was already IIFE-wrapped; the other four leaked their
runtime (hfAttach/hfBuild/...) as script-scope globals. Harmless when boot
was synchronous, but the data-driven retrofit defers attach behind
fonts.ready + the sibling fetch — with two caption components pasted into
one composition document, every script finishes before any deferred boot
runs, the last script's definitions win the shared scope, and the first
component never registers its timeline (a renderer waiting on it hangs to
timeout). Wrapping each template's script keeps its internals private so
each boot attaches its own component. window.__HF_CAPTION_ATTACH__ remains
intentionally window-scoped (last-defined-wins).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
vanceingalls
2026-07-24 05:25:41 +00:00
co-authored by Claude Fable 5
parent 4f69947191
commit e2846eb7cc
4 changed files with 2129 additions and 2071 deletions
@@ -122,6 +122,11 @@
</div>
<script>
// IIFE: keep every template's runtime private to itself so two caption
// components pasted into one composition document can't clobber each
// other's hfAttach/hfBuild via shared script-scope names (boot is async,
// so collisions surface AFTER all scripts have executed).
(function () {
var HF_COMPOSITION_ID = "caption-editorial-emphasis";
var HF_ROOT_ID = "editorial-emphasis";
var HF_GROUP_SELECTOR = ".caption-block";
@@ -237,7 +242,13 @@
} else {
root.style.removeProperty("--hf-caption-accent");
}
return { W: W, H: H, scaleX: W / 1920, scaleY: H / 1080, fontScale: Math.min(W, H) / 1080 };
return {
W: W,
H: H,
scaleX: W / 1920,
scaleY: H / 1080,
fontScale: Math.min(W, H) / 1080,
};
}
function hfPublishStatus(status) {
@@ -686,6 +697,7 @@
start(json || HF_DEMO_DATA);
});
})();
})();
</script>
</body>
</html>
@@ -125,6 +125,11 @@
</div>
<script>
// IIFE: keep every template's runtime private to itself so two caption
// components pasted into one composition document can't clobber each
// other's hfAttach/hfBuild via shared script-scope names (boot is async,
// so collisions surface AFTER all scripts have executed).
(function () {
var HF_COMPOSITION_ID = "caption-emoji-pop";
var HF_ROOT_ID = "emoji-pop";
var HF_GROUP_SELECTOR = ".caption-group";
@@ -240,7 +245,13 @@
} else {
root.style.removeProperty("--hf-caption-accent");
}
return { W: W, H: H, scaleX: W / 1920, scaleY: H / 1080, fontScale: Math.min(W, H) / 1080 };
return {
W: W,
H: H,
scaleX: W / 1920,
scaleY: H / 1080,
fontScale: Math.min(W, H) / 1080,
};
}
function hfPublishStatus(status) {
@@ -496,7 +507,9 @@
return words.map(function (word, index) {
var clean = word.text.toLowerCase().replace(/[^a-z]/g, "");
if (hfIsEmphasisWord(word.text)) {
var ci = Math.floor(seededRandom(groupIndex * 23 + index * 31) * hfAccentColors.length);
var ci = Math.floor(
seededRandom(groupIndex * 23 + index * 31) * hfAccentColors.length,
);
return hfAccentColors[ci];
}
if (HF_STOPWORDS.has(clean)) return hfPrimaryColor;
@@ -718,7 +731,13 @@
tl.set(groupEl, { opacity: 0, scaleX: 0.8, scaleY: 1 }, visibleStart);
tl.to(
groupEl,
{ opacity: 1, scaleX: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
{
opacity: 1,
scaleX: 1,
duration: ENTRY_DURATION,
ease: "power3.out",
force3D: true,
},
visibleStart,
);
tl.to(
@@ -789,6 +808,7 @@
start(json || HF_DEMO_DATA);
});
})();
})();
</script>
</body>
</html>
@@ -131,6 +131,11 @@
</div>
<script>
// IIFE: keep every template's runtime private to itself so two caption
// components pasted into one composition document can't clobber each
// other's hfAttach/hfBuild via shared script-scope names (boot is async,
// so collisions surface AFTER all scripts have executed).
(function () {
var HF_COMPOSITION_ID = "caption-pill-karaoke";
var HF_ROOT_ID = "pill-karaoke";
var HF_GROUP_SELECTOR = ".caption-group";
@@ -246,7 +251,13 @@
} else {
root.style.removeProperty("--hf-caption-accent");
}
return { W: W, H: H, scaleX: W / 1920, scaleY: H / 1080, fontScale: Math.min(W, H) / 1080 };
return {
W: W,
H: H,
scaleX: W / 1920,
scaleY: H / 1080,
fontScale: Math.min(W, H) / 1080,
};
}
function hfPublishStatus(status) {
@@ -354,7 +365,9 @@
function measureLineWidth(words, fontSize) {
return words.reduce(function (total, word, index) {
return (
total + measureWordWidth(word.text.toLowerCase(), fontSize) + (index ? WORD_SPACING : 0)
total +
measureWordWidth(word.text.toLowerCase(), fontSize) +
(index ? WORD_SPACING : 0)
);
}, 0);
}
@@ -604,6 +617,7 @@
start(json || HF_DEMO_DATA);
});
})();
})();
</script>
</body>
</html>
@@ -117,6 +117,11 @@
</div>
<script>
// IIFE: keep every template's runtime private to itself so two caption
// components pasted into one composition document can't clobber each
// other's hfAttach/hfBuild via shared script-scope names (boot is async,
// so collisions surface AFTER all scripts have executed).
(function () {
var HF_COMPOSITION_ID = "caption-weight-shift";
var HF_ROOT_ID = "weight-shift";
var HF_GROUP_SELECTOR = ".caption-group";
@@ -232,7 +237,13 @@
} else {
root.style.removeProperty("--hf-caption-accent");
}
return { W: W, H: H, scaleX: W / 1920, scaleY: H / 1080, fontScale: Math.min(W, H) / 1080 };
return {
W: W,
H: H,
scaleX: W / 1920,
scaleY: H / 1080,
fontScale: Math.min(W, H) / 1080,
};
}
function hfPublishStatus(status) {
@@ -623,6 +634,7 @@
start(json || HF_DEMO_DATA);
});
})();
})();
</script>
</body>
</html>