const BROWSER_SUPPORT_ADAPTERS = [ { activation: 'bundled-module', description: 'Reference glTF renderer and viewer module wired into the first-party browser runtime.', id: '1e-gltf-sample-renderer', phase: '1E', repo: 'KhronosGroup/glTF-Sample-Renderer', sourcePathHint: '.external/glTF-Sample-Renderer' }, { activation: 'native-sidecar', description: 'Native/OpenCV solver adjunct retained as a browser-shell fallback lane rather than a direct npm package.', id: '1g-tentone-native-solver', phase: '1G', repo: 'tentone/rubix-solver', sourcePathHint: '.external/rubix-solver' }, { activation: 'source-sidecar', description: 'Rust donor retained as a source-sidecar surface for follow-up browser spatial composition.', id: '1h-code-vr', phase: '1H', repo: 'NuiLab/code-vr', sourcePathHint: '.external/code-vr' }, { activation: 'prebuilt-script', description: 'Prebuilt ClayGL runtime script bridged into the browser shell for viewer and QA surfaces.', id: '1h-claygl', phase: '1H', repo: 'pissang/claygl', sourcePathHint: '.external/claygl/dist/claygl.js' }, { activation: 'prebuilt-script', description: 'Prebuilt Clay Viewer shell loaded beside ClayGL for bounded browser inspection.', id: '1h-clay-viewer', phase: '1H', repo: 'pissang/clay-viewer', sourcePathHint: '.external/clay-viewer/dist/clay-viewer.js' }, { activation: 'bundled-module', description: 'Three.js post-processing core bundled into the runtime module graph.', id: '1h-postprocessing', phase: '1H', repo: 'pmndrs/postprocessing', sourcePathHint: '.external/postprocessing' }, { activation: 'bundled-module', description: 'React bridge for post-processing loaded into the browser spatial stack.', id: '1h-react-postprocessing', phase: '1H', repo: 'pmndrs/react-postprocessing', sourcePathHint: '.external/react-postprocessing' }, { activation: 'bundled-module', description: 'Drei helper surface bundled for browser-spatial utility composition.', id: '1h-drei', phase: '1H', repo: 'pmndrs/drei', sourcePathHint: '.external/drei' }, { activation: 'bundled-module', description: 'World-anchored UI kit bundled for browser-spatial HUD and control surfaces.', id: '1h-uikit', phase: '1H', repo: 'pmndrs/uikit', sourcePathHint: '.external/uikit' }, { activation: 'bundled-module', description: 'Three.js helper library bundled for browser runtime support.', id: '1h-three-stdlib', phase: '1H', repo: 'pmndrs/three-stdlib', sourcePathHint: '.external/three-stdlib' }, { activation: 'bundled-module', description: 'Animation and math helper pack bundled into the runtime.', id: '1h-maath', phase: '1H', repo: 'pmndrs/maath', sourcePathHint: '.external/maath' }, { activation: 'bundled-module', description: 'State-store runtime bundled for browser shell state and derived panel demos.', id: '1h-zustand', phase: '1H', repo: 'pmndrs/zustand', sourcePathHint: '.external/zustand' }, { activation: 'bundled-module', description: 'Parameter-control runtime bundled for future tuning overlays.', id: '1h-leva', phase: '1H', repo: 'pmndrs/leva', sourcePathHint: '.external/leva' }, { activation: 'bundled-module', description: 'Gesture capture hooks bundled for browser interaction surfaces.', id: '1h-use-gesture', phase: '1H', repo: 'pmndrs/use-gesture', sourcePathHint: '.external/use-gesture' }, { activation: 'bundled-module', description: 'Motion and interpolation runtime bundled for browser spatial transitions.', id: '1h-react-spring', phase: '1H', repo: 'pmndrs/react-spring', sourcePathHint: '.external/react-spring' }, { activation: 'bundled-module', description: '2D render engine bundled beneath the analytics surface.', id: '1i-zrender', phase: '1I', repo: 'ecomfe/zrender', sourcePathHint: '.external/zrender' }, { activation: 'bundled-module', description: '3D analytics extension bundled beneath the ECharts runtime.', id: '1i-echarts-gl', phase: '1I', repo: 'ecomfe/echarts-gl', sourcePathHint: '.external/echarts-gl' }, { activation: 'bundled-module', description: 'Model Viewer web component bundled into the browser shell.', id: '1j-model-viewer', phase: '1J', repo: 'google/model-viewer/packages/model-viewer', sourcePathHint: '.external/model-viewer/packages/model-viewer' }, { activation: 'bundled-module', description: 'Effects package bundled beside model-viewer for decorated previews.', id: '1j-model-viewer-effects', phase: '1J', repo: 'google/model-viewer/packages/model-viewer-effects', sourcePathHint: '.external/model-viewer/packages/model-viewer-effects' }, { activation: 'editor-sidecar', description: 'Editor-oriented inspection UI retained as a sidecar instead of a default runtime export.', id: '1j-space-opera', phase: '1J', repo: 'google/model-viewer/packages/space-opera', sourcePathHint: '.external/model-viewer/packages/space-opera' }, { activation: 'qa-sidecar', description: 'Renderer comparison and fidelity tooling kept in the QA lane rather than loaded by default.', id: '1j-render-fidelity-tools', phase: '1J', repo: 'google/model-viewer/packages/render-fidelity-tools', sourcePathHint: '.external/model-viewer/packages/render-fidelity-tools' } ]; const BUNDLED_ADAPTER_ACTIVATIONS = new Set(['bundled-module', 'prebuilt-script']); function resolveFallbackBootState() { const ExistingBootState = window.HyperTwistBrowserBootState; if (ExistingBootState && typeof ExistingBootState === 'object') { return ExistingBootState; } const BootState = {}; window.HyperTwistBrowserBootState = BootState; return BootState; } function getUnrealBridgeHandle() { const Candidate = window.ue; if (!Candidate || typeof Candidate !== 'object') { return null; } const HyperTwistBridge = Candidate.hypertwist; return HyperTwistBridge && typeof HyperTwistBridge === 'object' ? HyperTwistBridge : null; } function tryParseJsonPayload(Value) { if (typeof Value !== 'string') { return Value; } try { return JSON.parse(Value); } catch { return Value; } } function createElement(TagName, ClassName, TextContent) { const Element = document.createElement(TagName); if (ClassName) { Element.className = ClassName; } if (typeof TextContent === 'string') { Element.textContent = TextContent; } return Element; } function serializePretty(Payload) { if (typeof Payload === 'string') { return Payload; } try { return JSON.stringify(Payload, null, 2); } catch { return String(Payload); } } function createSectionHeader(Title, Note) { const Header = createElement('div', 'section-header'); Header.append( createElement('h2', 'section-title', Title), createElement('p', 'section-note', Note) ); return Header; } function dispatchToListeners(Listeners, Payload) { Listeners.forEach((Listener) => Listener(Payload)); } function createFallbackBridge(BootState) { const CommandListeners = new Set(); const ShellStateListeners = new Set(); let LastCommandPayload; let LastShellStatePayload; let HasLastCommandPayload = false; let HasLastShellStatePayload = false; function postEnvelope(Type, Payload) { const Envelope = { type: Type, payload: Payload, emittedAtUtc: new Date().toISOString() }; const SerializedEnvelope = JSON.stringify(Envelope); const UnrealBridgeHandle = getUnrealBridgeHandle(); let DeliveredToUnreal = false; if (UnrealBridgeHandle && typeof UnrealBridgeHandle.notifyEnvelope === 'function') { UnrealBridgeHandle.notifyEnvelope(SerializedEnvelope); DeliveredToUnreal = true; } if (Type === 'hypertwist-state' && UnrealBridgeHandle && typeof UnrealBridgeHandle.notifyState === 'function') { UnrealBridgeHandle.notifyState(JSON.stringify(Payload)); DeliveredToUnreal = true; } if (DeliveredToUnreal) { return; } if (window.parent && typeof window.parent.postMessage === 'function') { window.parent.postMessage(Envelope, '*'); } } window.addEventListener('message', function onBridgeMessage(Event) { const Envelope = Event.data; if (!Envelope || typeof Envelope !== 'object') { return; } if (Envelope.type === 'hypertwist-command') { Bridge.receiveCommand(Envelope.payload); } else if (Envelope.type === 'hypertwist-shell-state') { Bridge.setShellState(Envelope.payload); } }); const Bridge = { onCommand(Listener) { CommandListeners.add(Listener); if (HasLastCommandPayload) { Listener(LastCommandPayload); } return function unsubscribeCommand() { CommandListeners.delete(Listener); }; }, onShellState(Listener) { ShellStateListeners.add(Listener); if (HasLastShellStatePayload) { Listener(LastShellStatePayload); } return function unsubscribeShellState() { ShellStateListeners.delete(Listener); }; }, receiveCommand(Payload) { LastCommandPayload = tryParseJsonPayload(Payload); HasLastCommandPayload = true; BootState.commandReceiveCount = (BootState.commandReceiveCount || 0) + 1; BootState.lastCommandReceivedAtUtc = new Date().toISOString(); dispatchToListeners(CommandListeners, LastCommandPayload); }, setShellState(Payload) { LastShellStatePayload = tryParseJsonPayload(Payload); HasLastShellStatePayload = true; BootState.shellStateReceiveCount = (BootState.shellStateReceiveCount || 0) + 1; BootState.lastShellStateReceivedAtUtc = new Date().toISOString(); dispatchToListeners(ShellStateListeners, LastShellStatePayload); }, sendState(Payload) { postEnvelope('hypertwist-state', Payload); }, notifyRuntimeReady(Payload) { const UnrealBridgeHandle = getUnrealBridgeHandle(); if (UnrealBridgeHandle && typeof UnrealBridgeHandle.notifyRuntimeReady === 'function') { UnrealBridgeHandle.notifyRuntimeReady(JSON.stringify(Payload)); return; } postEnvelope('hypertwist-runtime-ready', Payload); } }; return Bridge; } async function loadAdapter(AdapterId) { const Adapter = BROWSER_SUPPORT_ADAPTERS.find((Candidate) => Candidate.id === AdapterId); if (!Adapter) { throw new Error('Unknown browser support adapter: ' + AdapterId); } if (BUNDLED_ADAPTER_ACTIVATIONS.has(Adapter.activation)) { return { details: ['Clean checkout fallback is active; build the browser bundle to exercise this adapter in-browser.'], id: AdapterId, note: 'Fallback runtime is active, so bundled browser modules are advertised but not loaded from source checkout state.', status: 'deferred' }; } return { details: [Adapter.sourcePathHint], id: AdapterId, note: 'Adapter is intentionally represented as a sidecar in the plain-JS fallback shell.', status: 'loaded' }; } function createHeroSection(BootState) { const HeroElement = createElement('section', 'hero'); HeroElement.append( createElement('h1', undefined, 'HyperTwist Browser Runtime'), createElement( 'p', undefined, 'This clean-checkout fallback keeps the embedded browser lane truthful and runnable. When the built runtime bundle is present the authoritative shell upgrades automatically; when it is absent, the shell still renders, bridges Unreal state, and surfaces which adapters remain bundled or sidecar-only.' ) ); const HeroMetrics = createElement('div', 'hero-grid'); [ { label: 'Runtime mode', value: 'plain-js fallback' }, { label: 'Fallback reason', value: BootState.fallbackReason || 'bundle unavailable' }, { label: 'Adapters surfaced', value: String(BROWSER_SUPPORT_ADAPTERS.length) } ].forEach(function appendMetric(Metric) { const MetricElement = createElement('div', 'metric'); MetricElement.append( createElement('strong', undefined, Metric.label), createElement('span', undefined, Metric.value) ); HeroMetrics.appendChild(MetricElement); }); HeroElement.appendChild(HeroMetrics); return HeroElement; } function createLogPanel() { const LogPanel = createElement('section', 'panel'); LogPanel.append( createElement('h2', undefined, 'Runtime Log'), createElement( 'p', 'runtime-note', 'Bridge and adapter events stay inspectable here during clean-checkout fallback mode.' ) ); const LogList = createElement('div', 'log-list'); LogPanel.appendChild(LogList); return { appendLog(Title, Message) { const Entry = createElement('div', 'log-entry'); Entry.append( createElement('strong', undefined, Title), createElement('div', undefined, Message) ); LogList.prepend(Entry); }, panel: LogPanel }; } function buildRuntimeStatusSnapshot(BootState, Counters) { return { runtimeStatusId: BootState.runtimeStatusId || 'runtime-ready', runtimeMode: BootState.runtimeMode || 'unknown', bootstrapStartedAtUtc: BootState.bootstrapStartedAtUtc || 'pending', runtimeReadyAtUtc: BootState.runtimeReadyAtUtc || 'pending', shellAuthority: BootState.shellAuthority || 'Content/Browser/index.html', adapterCount: BootState.adapterCount || BROWSER_SUPPORT_ADAPTERS.length, queuedCommandCountAtRuntimeReady: BootState.queuedCommandCountAtRuntimeReady || 0, queuedShellStateCountAtRuntimeReady: BootState.queuedShellStateCountAtRuntimeReady || 0, commandReceiveCount: Counters.commandReceiveCount, shellStateReceiveCount: Counters.shellStateReceiveCount, lastCommandReceivedAtUtc: BootState.lastCommandReceivedAtUtc || 'none', lastShellStateReceivedAtUtc: BootState.lastShellStateReceivedAtUtc || 'none', bridgeTrafficStatus: Counters.shellStateReceiveCount > 0 ? 'shell-state-live' : Counters.commandReceiveCount > 0 ? 'command-only-live' : 'awaiting-unreal-traffic', fallbackReason: BootState.fallbackReason || null }; } function createRuntimeStatusPanel(BootState, Counters, UEBridge, AppendLog) { const StatusPanel = createElement('section', 'panel'); StatusPanel.append( createElement('h2', undefined, 'Browser Runtime Status'), createElement( 'p', 'runtime-note', 'The clean-checkout fallback shell now exposes first-party runtime mode, retained startup queue carryover, and live Unreal bridge traffic in one compact status surface.' ) ); const StatusActions = createElement('div', 'solver-actions'); const SendStatusButton = createElement('button', undefined, 'Send Runtime Status'); const StatusData = createElement('div', 'data-block'); const StatusPre = createElement('pre'); StatusData.appendChild(StatusPre); StatusActions.appendChild(SendStatusButton); StatusPanel.append(StatusActions, StatusData); function refresh() { StatusPre.textContent = serializePretty(buildRuntimeStatusSnapshot(BootState, Counters)); } SendStatusButton.addEventListener('click', function onSendStatus() { UEBridge.sendState({ type: 'browser-runtime-status', source: 'browser-runtime-fallback', status: buildRuntimeStatusSnapshot(BootState, Counters) }); AppendLog('Browser Runtime Status', 'Sent the current browser runtime status envelope to Unreal.'); }); return { panel: StatusPanel, refresh }; } function createStatePanel() { const StatePanel = createElement('section', 'panel'); StatePanel.append( createElement('h2', undefined, 'Browser Shell State'), createElement( 'p', 'runtime-note', 'Unreal can push shell-state and command envelopes into the fallback runtime exactly like the bundled runtime.' ) ); const StateData = createElement('div', 'data-block'); const StatePre = createElement('pre'); StatePre.textContent = '{\n "status": "waiting-for-unreal-shell-state"\n}'; StateData.appendChild(StatePre); StatePanel.appendChild(StateData); return { panel: StatePanel, setPayload(Payload) { StatePre.textContent = serializePretty(Payload); } }; } function createAdapterCard(Adapter, UEBridge, AppendLog) { const CardElement = createElement('article', 'card'); const CardHeader = createElement('div', 'card-header'); const CardTitleBlock = createElement('div'); CardTitleBlock.append( createElement('span', 'phase-chip', Adapter.phase), createElement('h2', undefined, Adapter.repo) ); const StatusChip = createElement('span', 'status-chip', 'idle'); StatusChip.dataset.status = 'idle'; CardHeader.append(CardTitleBlock, StatusChip); const ActivationChip = createElement('span', 'activation-chip', Adapter.activation); const Description = createElement('p', undefined, Adapter.description); const SourceCode = createElement('code', undefined, Adapter.sourcePathHint); const Actions = createElement('div', 'card-actions'); const LoadButton = createElement('button', undefined, 'Resolve Adapter'); const EnvelopeButton = createElement('button', 'secondary', 'Send Envelope'); LoadButton.addEventListener('click', async function onLoadAdapter() { StatusChip.dataset.status = 'loading'; StatusChip.textContent = 'loading'; try { const Result = await loadAdapter(Adapter.id); StatusChip.dataset.status = Result.status === 'loaded' ? 'ready' : 'idle'; StatusChip.textContent = Result.status; AppendLog( Adapter.repo, Result.note || ('Resolved ' + Adapter.id + '.') ); } catch (Error) { StatusChip.dataset.status = 'error'; StatusChip.textContent = 'error'; AppendLog(Adapter.repo, Error instanceof Error ? Error.message : 'Unknown load failure.'); } }); EnvelopeButton.addEventListener('click', function onSendEnvelope() { UEBridge.sendState({ source: 'browser-runtime-fallback', adapterId: Adapter.id, repo: Adapter.repo, activation: Adapter.activation, runtimeMode: 'fallback-js' }); AppendLog(Adapter.repo, 'Sent adapter envelope to Unreal.'); }); Actions.append(LoadButton, EnvelopeButton); CardElement.append(CardHeader, ActivationChip, Description, SourceCode, Actions); return CardElement; } function createAdapterSection(UEBridge, AppendLog) { const AdapterSection = createElement('section', 'section'); AdapterSection.appendChild( createSectionHeader( 'Adapter Surface', 'Adapters remain visible in clean checkout state. Bundled browser modules are marked deferred until `npm run build` produces the browser runtime bundle.' ) ); const AdapterGrid = createElement('div', 'stack-grid'); BROWSER_SUPPORT_ADAPTERS.forEach(function appendAdapter(Adapter) { AdapterGrid.appendChild(createAdapterCard(Adapter, UEBridge, AppendLog)); }); AdapterSection.append(AdapterGrid); return AdapterSection; } function createSolverPanel(UEBridge, AppendLog) { const SolverPanel = createElement('section', 'panel'); SolverPanel.append( createElement('h2', undefined, 'Tentone Native Solver Request'), createElement( 'p', 'runtime-note', 'The OpenCV donor remains a native-sidecar lane. This fallback shell sends a first-party solver request envelope instead of pretending to import the donor in-browser.' ) ); const SolverField = createElement('label', 'field'); SolverField.appendChild(createElement('span', undefined, 'Classic facelet string')); const SolverInput = createElement('textarea'); SolverInput.value = 'UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB'; SolverField.appendChild(SolverInput); const SolverActions = createElement('div', 'solver-actions'); const SolverButton = createElement('button', undefined, 'Send Solver Request'); SolverButton.addEventListener('click', function onSolve() { UEBridge.sendState({ type: 'tentone-native-solver-request', source: 'browser-runtime-fallback', faceletString: SolverInput.value.trim() }); AppendLog('Tentone Native Solver', 'Sent a solver request envelope to Unreal.'); }); SolverActions.appendChild(SolverButton); SolverPanel.append(SolverField, SolverActions); return SolverPanel; } function createUtilitySection(BootState, Counters, UEBridge) { const UtilitySection = createElement('section', 'section'); UtilitySection.appendChild( createSectionHeader( 'Fallback Utilities', 'The plain-JS runtime keeps state bridging and native-sidecar requests live even when bundled browser modules have been cleaned after validation.' ) ); const { appendLog, panel: LogPanel } = createLogPanel(); const { panel: StatusPanel, refresh: RefreshRuntimeStatus } = createRuntimeStatusPanel( BootState, Counters, UEBridge, appendLog ); const StatePanel = createStatePanel(); const UtilityGrid = createElement('div', 'panel-grid'); UtilityGrid.append( StatusPanel, createSolverPanel(UEBridge, appendLog), StatePanel.panel, LogPanel ); UtilitySection.appendChild(UtilityGrid); return { appendLog, refreshRuntimeStatus: RefreshRuntimeStatus, section: UtilitySection, setShellStatePayload: StatePanel.setPayload }; } function synchronizeCommandCounter(BootState, Counters) { Counters.commandReceiveCount = BootState.commandReceiveCount || (Counters.commandReceiveCount + 1); } function synchronizeShellStateCounter(BootState, Counters) { Counters.shellStateReceiveCount = BootState.shellStateReceiveCount || (Counters.shellStateReceiveCount + 1); } function wireBridgeSubscriptions(BootState, Counters, UEBridge, AppendLog, RefreshRuntimeStatus, SetShellStatePayload) { UEBridge.onCommand(function onCommand(Payload) { synchronizeCommandCounter(BootState, Counters); RefreshRuntimeStatus(); AppendLog('UE Command', serializePretty(Payload)); }); UEBridge.onShellState(function onShellState(Payload) { synchronizeShellStateCounter(BootState, Counters); SetShellStatePayload(Payload); RefreshRuntimeStatus(); AppendLog('Browser Shell State', 'Received fresh shell state from Unreal.'); }); } function createBrowserShell(RootElement, BootState, UEBridge) { RootElement.innerHTML = ''; const Counters = { commandReceiveCount: BootState.commandReceiveCount || 0, shellStateReceiveCount: BootState.shellStateReceiveCount || (BootState.lastShellStateReceivedAtUtc ? 1 : 0) }; const ShellElement = createElement('div', 'shell'); const HeroElement = createHeroSection(BootState); const UtilitySection = createUtilitySection(BootState, Counters, UEBridge); const AdapterSection = createAdapterSection(UEBridge, UtilitySection.appendLog); ShellElement.append(HeroElement, AdapterSection, UtilitySection.section); RootElement.appendChild(ShellElement); UtilitySection.refreshRuntimeStatus(); wireBridgeSubscriptions( BootState, Counters, UEBridge, UtilitySection.appendLog, UtilitySection.refreshRuntimeStatus, UtilitySection.setShellStatePayload ); } function createFallbackRuntimeApi(BootState, UEBridge) { return { adapters: BROWSER_SUPPORT_ADAPTERS, listAdapters() { return BROWSER_SUPPORT_ADAPTERS.slice(); }, loadAdapter, receiveCommand(Payload) { UEBridge.receiveCommand(Payload); }, setShellState(Payload) { UEBridge.setShellState(Payload); }, renderShell(RootElement) { createBrowserShell(RootElement, BootState, UEBridge); }, sendState(Payload) { UEBridge.sendState(Payload); } }; } function replayPendingBridgeTraffic(BootState, RuntimeApi) { const PendingCommands = Array.isArray(BootState.pendingCommands) ? BootState.pendingCommands.slice() : []; BootState.queuedCommandCountAtRuntimeReady = PendingCommands.length; BootState.pendingCommands = []; PendingCommands.forEach(function replayPendingCommand(Payload) { RuntimeApi.receiveCommand(Payload); }); const PendingShellStates = Array.isArray(BootState.pendingShellStates) ? BootState.pendingShellStates.slice() : []; BootState.queuedShellStateCountAtRuntimeReady = PendingShellStates.length; BootState.pendingShellStates = []; PendingShellStates.forEach(function replayPendingShellState(Payload) { RuntimeApi.setShellState(Payload); }); } function notifyFallbackRuntimeReady(BootState, UEBridge) { UEBridge.notifyRuntimeReady({ status: 'ready', runtime: 'hypertwist-browser-runtime-fallback', mode: 'fallback-js', fallbackReason: BootState.fallbackReason || 'bundle unavailable', adapterCount: BootState.adapterCount, shellAuthority: BootState.shellAuthority, queuedCommandCountAtRuntimeReady: BootState.queuedCommandCountAtRuntimeReady, queuedShellStateCountAtRuntimeReady: BootState.queuedShellStateCountAtRuntimeReady }); } function mountFallbackShell(RuntimeApi) { const RootElement = document.getElementById('app'); if (RootElement instanceof HTMLElement) { RuntimeApi.renderShell(RootElement); } } function bootstrapHyperTwistBrowserFallbackRuntime() { const BootState = resolveFallbackBootState(); BootState.runtimeMode = 'fallback-js'; BootState.runtimeReadyAtUtc = new Date().toISOString(); BootState.runtimeStatusId = 'runtime-ready'; BootState.adapterCount = BROWSER_SUPPORT_ADAPTERS.length; BootState.shellAuthority = 'Content/Browser/index.html'; const UEBridge = createFallbackBridge(BootState); const RuntimeApi = createFallbackRuntimeApi(BootState, UEBridge); window.HyperTwistBrowserRuntime = RuntimeApi; mountFallbackShell(RuntimeApi); replayPendingBridgeTraffic(BootState, RuntimeApi); notifyFallbackRuntimeReady(BootState, UEBridge); } bootstrapHyperTwistBrowserFallbackRuntime();