Skip to content

Commit 2b46565

Browse files
miguel-heygenclaude
andcommitted
fix(runtime): hold external sub-compositions in render mode
PR #917 fixed visibility clamping for external sub-compositions in preview mode by checking data-composition-src. However, the producer's htmlCompiler strips that attribute during inlining without setting the data-composition-file marker that the core bundler sets. This caused the runtime to still clamp duration to Math.min(authored, live) in rendered output. Two fixes: - Runtime: also check data-composition-file (set by the core bundler after inlining) - Producer: set data-composition-file before removing data-composition-src, matching the core bundler's behavior Closes #911 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3f976d4 commit 2b46565

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

packages/core/src/runtime/init.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,43 @@ describe("initSandboxRuntimeModular", () => {
211211
expect(child.style.visibility).toBe("visible");
212212
});
213213

214+
it("keeps compiled external composition hosts visible through their authored duration", async () => {
215+
const root = document.createElement("div");
216+
root.setAttribute("data-composition-id", "main");
217+
root.setAttribute("data-root", "true");
218+
root.setAttribute("data-start", "0");
219+
root.setAttribute("data-width", "1920");
220+
root.setAttribute("data-height", "1080");
221+
document.body.appendChild(root);
222+
223+
const child = document.createElement("div");
224+
child.setAttribute("data-composition-id", "sub");
225+
child.setAttribute("data-composition-file", "compositions/sub.html");
226+
child.setAttribute("data-start", "0");
227+
child.setAttribute("data-duration", "3");
228+
child.innerHTML = '<div id="hold-marker">HOLD ME</div>';
229+
root.appendChild(child);
230+
231+
(window as Window & { __timelines?: Record<string, RuntimeTimelineLike> }).__timelines = {
232+
main: createMockTimeline(3),
233+
sub: createMockTimeline(1),
234+
};
235+
236+
initSandboxRuntimeModular();
237+
await new Promise<void>((resolve) => window.setTimeout(resolve, 0));
238+
239+
const player = (
240+
window as Window & {
241+
__player?: { renderSeek: (timeSeconds: number) => void };
242+
}
243+
).__player;
244+
expect(player).toBeDefined();
245+
246+
player?.renderSeek(2);
247+
248+
expect(child.style.visibility).toBe("visible");
249+
});
250+
214251
it("pads the root timeline to the authored composition schedule before seeking visibility", () => {
215252
const root = document.createElement("div");
216253
root.setAttribute("data-composition-id", "main");

packages/core/src/runtime/init.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1335,7 +1335,9 @@ export function initSandboxRuntimeModular(): void {
13351335
}
13361336
}
13371337

1338-
const usesExternalCompositionSlot = rawNode.hasAttribute("data-composition-src");
1338+
const usesExternalCompositionSlot =
1339+
rawNode.hasAttribute("data-composition-src") ||
1340+
rawNode.hasAttribute("data-composition-file");
13391341

13401342
// Generic child compositions retain legacy behavior and respect both
13411343
// the authored parent clip window and the live child timeline duration.

packages/producer/src/services/htmlCompiler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ function inlineSubCompositions(
689689
host.innerHTML = contentDoc.toString();
690690
}
691691

692+
host.setAttribute("data-composition-file", srcPath);
692693
host.removeAttribute("data-composition-src");
693694

694695
// Set explicit pixel dimensions on the host element so children using

0 commit comments

Comments
 (0)