fix(core): auto-detect three.js asset readiness via adapter contract (#1543)

Replaces the original `window.__hyperframesReady` authored API with an internal adapter contract: `RuntimeDeterministicAdapter.getReadyPromise?: () => PromiseLike | null`. The Three.js adapter implements it by hooking `THREE.DefaultLoadingManager.onStart/onLoad`; the runtime collects promises from every adapter and gates `window.__renderReady = true` on them. Zero authoring burden — composition authors write plain Three.js, framework handles async asset gating automatically.

Also keeps the orthogonal `htmlDocument.ts` script-stripping refactor (substring → regex for simple flag assignments), which fixes the bug where authored scripts referencing readiness flags were stripped despite never assigning them.

Stamped by Magi and Miguel; CI green; tests 33/33 pass.
This commit is contained in:
James Russo
2026-06-17 18:47:48 -07:00
committed by GitHub
parent e57e75b9b4
commit bb5f5f8c5c
6 changed files with 273 additions and 3 deletions
+19 -2
View File
@@ -13,9 +13,13 @@ const RUNTIME_INLINE_MARKERS = [
"__hyperframeRuntimeBootstrapped",
"__hyperframeRuntime",
"__hyperframeRuntimeTeardown",
"__HF_EXPORT_RENDER_SEEK_CONFIG",
"window.__player =",
"window.__playerReady",
"window.__renderReady",
];
const SIMPLE_RUNTIME_FLAG_ASSIGNMENTS = [
/^window\.__playerReady\s*=\s*(?:true|false)\s*;?$/,
/^window\.__renderReady\s*=\s*(?:true|false)\s*;?$/,
];
/**
@@ -115,9 +119,22 @@ function shouldStripRuntimeScriptBlock(block: string): boolean {
for (const marker of RUNTIME_INLINE_MARKERS) {
if (block.includes(marker)) return true;
}
const scriptSource = getScriptSource(block).trim();
for (const pattern of SIMPLE_RUNTIME_FLAG_ASSIGNMENTS) {
if (pattern.test(scriptSource)) return true;
}
return false;
}
function getScriptSource(block: string): string {
const startTagEnd = findTagEnd(block, 1);
if (startTagEnd === -1) return "";
const loweredBlock = block.toLowerCase();
const closeTagStart = loweredBlock.lastIndexOf("</script");
const end = closeTagStart === -1 ? block.length : closeTagStart;
return block.slice(startTagEnd + 1, end);
}
function isTagBoundary(char: string): boolean {
return char === "" || char === ">" || char === "/" || isHtmlWhitespace(char);
}