"use client"; import { useRef } from "react"; import { usePinballInstance, type RomSelection } from "@/lib/pinball/usePinballInstance"; import { useTouchControls } from "@/lib/pinball/useTouchControls"; import CoinDoorHud from "@/components/hud/CoinDoorHud"; import type { TableInfo } from "@/lib/pinball/types"; export interface PinballCanvasImplProps { tableData?: ArrayBuffer; rom?: RomSelection; tableInfo: TableInfo; } export default function PinballCanvasImpl({ tableData, rom, tableInfo }: PinballCanvasImplProps) { const canvasRef = useRef(null); const containerRef = useRef(null); const { status, progress, error, loadTimeMs, instanceRef, start } = usePinballInstance( canvasRef, tableData, rom, ); useTouchControls(containerRef, status === "running"); return (
{/* SDL3's Emscripten backend resolves its own window/GL-context target via document.querySelector("#canvas") independently of Module.canvas — the id is required or context creation silently no-ops (findCanvasEventTarget returns null, emscripten_webgl_create_context returns handle 0, and the engine crashes later reading an unset GL context). */} {(status === "ready" || status === "running") && ( )} {status === "loading" && (
LOADING TABLE
{Math.round(progress * 100)}%
)} {status === "error" && (
TABLE NOT LOADING

{error}

)} {status === "ready" && (
{/* Most tables gate Start Game behind having a credit, same as a real coin-op cabinet — pressing 1 alone does nothing until a credit is added. Surfaced here since it's the first thing anyone hits and easy to mistake for the app not responding. */}

If Start doesn't respond: press 4 to insert a coin, then{" "} 1 to start.

)} {status === "starting" && (
STARTING TABLE
)}
); }