fix(registry): centre mk-callout-highlight with flex instead of a script-time measurement (#5118)

* fix(registry): centre mk-callout-highlight with flex instead of a script-time measurement

The text box becomes a flex item of a full-frame wrapper (#mk-ch-center),
so its position is laid out by the browser rather than read from a
getBoundingClientRect() taken at script time. That measurement depends on
which font faces are loaded when the script runs; the fonts gate covers only
faces that static markup already uses, so script-built text measures
against the fallback face (#5112). A non-null CONFIG.x / CONFIG.y becomes a
margin offset on that axis. The GSAP y entrance stays on the box, which
carries no CSS transform.

Also drops the scene-exit visibility tail (the runtime hides the clip at
its window end; the 0.02 s tail never reached a frame at 30 fps) and
removes data-layout-allow-occlusion from #mk-ch-box: nothing beneath the
block is text, and the attribute made the contrast audit skip the block's
own words whenever a later full-frame host answered the hit-test probe.

Renders are bit-identical to the measured version when the face is loaded
(nine-scene project at v0.8.135, 1380/1380 frames). CONFIG and the sweep
mechanic are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(registry): keep only the flex centring in mk-callout-highlight

Address review: restore the scene-exit visibility tail and the layout
occlusion attribute, which belong to family-wide conventions and are out
of scope here, and note the x + maxWidth clip edge in CONFIG.

Refs #5112

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
jbernard077
2026-10-24 00:43:31 +00:00
committed by GitHub
co-authored by Claude Fable 5.1
parent 0648f1ed8d
commit e6fba28b66
@@ -30,8 +30,20 @@
overflow: hidden;
background: transparent; /* overlays footage or mk-background */
}
#mk-ch-box {
#mk-ch-center {
/* CSS centring. The box is a flex item of this full-frame wrapper, so its
place is laid out by the browser rather than measured from a DOM rect
taken before web fonts are ready. An explicit CONFIG.x / CONFIG.y turns
that axis into an edge offset (see the script). No pointer-events:none
here: it inherits to the word spans and the contrast audit skips them. */
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
#mk-ch-box {
flex: none; /* max-content width, clamped by max-width; never shrunk */
font-family: var(--mk-font);
font-weight: 500;
letter-spacing: -0.015em;
@@ -50,7 +62,9 @@
data-width="1920"
data-height="1080"
>
<div id="mk-ch-box" data-layout-allow-occlusion></div>
<div id="mk-ch-center">
<div id="mk-ch-box" data-layout-allow-occlusion></div>
</div>
<div
id="mk-ch-drv"
class="clip"
@@ -74,7 +88,9 @@
fontSize: 60,
lineHeight: 1.3,
maxWidth: 700, // px; sentence wraps inside this
x: 1030, // box left edge; null = centered horizontally
x: 1030, // box left edge; null = centered horizontally. Keep x + maxWidth <= 1920:
// the box never shrinks (flex: none), so past the frame edge it is clipped
// by the root's overflow instead of wrapping earlier.
y: null, // box top edge; null = centered vertically
align: "left",
sweep: { start: 1.2, end: 6.2 }, // block-local seconds, linear
@@ -107,12 +123,19 @@
wordEls.push(span);
});
/* position (measure after building) */
var rect = box.getBoundingClientRect();
box.style.left =
(CONFIG.x === null ? Math.round((1920 - rect.width) / 2) : CONFIG.x) + "px";
box.style.top =
(CONFIG.y === null ? Math.round((1080 - rect.height) / 2) : CONFIG.y) + "px";
/* position: #mk-ch-center centres the box with flex (no measurement, so the
placement does not depend on font timing). A non-null CONFIG.x / CONFIG.y
switches that axis to an edge offset: the box keeps its content width
(clamped by maxWidth) and is pushed from the frame edge by a margin. */
var center = document.getElementById("mk-ch-center");
if (CONFIG.x !== null) {
center.style.justifyContent = "flex-start";
box.style.marginLeft = CONFIG.x + "px";
}
if (CONFIG.y !== null) {
center.style.alignItems = "flex-start";
box.style.marginTop = CONFIG.y + "px";
}
/* state proxy: GSAP animates st.p, render derives every word color from it */
var st = { p: 0 };
@@ -127,6 +150,9 @@
var tl = gsap.timeline({ paused: true });
/* entrance / exit motion stays a GSAP transform on the box itself: the box
carries no CSS transform (centring is flex on the parent), so there is
nothing for the tween to fight. */
if (CONFIG.animationIn) {
gsap.set(box, { opacity: 0, y: 24 });
tl.to(box, { opacity: 1, y: 0, duration: 0.7, ease: "power3.out" }, 0.3);