From 2f46fea52ac01c7dc01d81cde4a5f1f7a7ae68ea Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 31 Mar 2026 06:46:48 +0200 Subject: [PATCH] Add interaction prompt handling in RunnerCanvas --- src/runner-web/RunnerCanvas.tsx | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/runner-web/RunnerCanvas.tsx b/src/runner-web/RunnerCanvas.tsx index d63a91a3..10b69a00 100644 --- a/src/runner-web/RunnerCanvas.tsx +++ b/src/runner-web/RunnerCanvas.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from "react"; import type { FirstPersonTelemetry } from "../runtime-three/navigation-controller"; import { RuntimeHost } from "../runtime-three/runtime-host"; +import type { RuntimeInteractionPrompt } from "../runtime-three/runtime-interaction-system"; import type { RuntimeNavigationMode, RuntimeSceneDefinition } from "../runtime-three/runtime-scene-build"; import { createWorldBackgroundStyle } from "../shared-ui/world-background-style"; @@ -10,17 +11,20 @@ interface RunnerCanvasProps { navigationMode: RuntimeNavigationMode; onRuntimeMessageChange(message: string | null): void; onFirstPersonTelemetryChange(telemetry: FirstPersonTelemetry | null): void; + onInteractionPromptChange(prompt: RuntimeInteractionPrompt | null): void; } export function RunnerCanvas({ runtimeScene, navigationMode, onRuntimeMessageChange, - onFirstPersonTelemetryChange + onFirstPersonTelemetryChange, + onInteractionPromptChange }: RunnerCanvasProps) { const containerRef = useRef(null); const hostRef = useRef(null); const [runnerMessage, setRunnerMessage] = useState(null); + const [interactionPrompt, setInteractionPrompt] = useState(null); useEffect(() => { const container = containerRef.current; @@ -43,20 +47,26 @@ export function RunnerCanvas({ runtimeHost.mount(container); runtimeHost.setRuntimeMessageHandler(onRuntimeMessageChange); runtimeHost.setFirstPersonTelemetryHandler(onFirstPersonTelemetryChange); + runtimeHost.setInteractionPromptHandler((prompt) => { + setInteractionPrompt(prompt); + onInteractionPromptChange(prompt); + }); setRunnerMessage( hasWebGl ? null : "WebGL is unavailable in this browser environment. The runner shell is visible, but runtime rendering is disabled." ); return () => { + onInteractionPromptChange(null); runtimeHost.dispose(); hostRef.current = null; }; } catch (error) { const message = error instanceof Error ? error.message : "Runner initialization failed."; setRunnerMessage(`Runner initialization failed: ${message}`); + onInteractionPromptChange(null); return; } - }, [onFirstPersonTelemetryChange, onRuntimeMessageChange]); + }, [onFirstPersonTelemetryChange, onInteractionPromptChange, onRuntimeMessageChange]); useEffect(() => { hostRef.current?.loadScene(runtimeScene); @@ -74,6 +84,18 @@ export function RunnerCanvas({ aria-label="Built-in scene runner" style={createWorldBackgroundStyle(runtimeScene.world.background)} > + {navigationMode === "firstPerson" ?