Show a spinner while the table is starting
instance.start() runs synchronously and blocks the main thread for a noticeable moment on heavy WASM init, so pressing "Tap to Start" would freeze on the old screen with no feedback until the HUD suddenly appeared. Add a "starting" status between "ready" and "running", and defer the actual start() call by a nested rAF so the browser gets a chance to paint the spinner before the blocking call runs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,13 @@ export default function PinballCanvasImpl({ tableData, rom, tableInfo }: Pinball
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{status === "starting" && (
|
||||||
|
<div className="absolute inset-0 flex flex-col items-center justify-center gap-4 bg-ink/90 text-paper">
|
||||||
|
<div className="h-12 w-12 animate-spin rounded-full border-4 border-chrome/20 border-t-marquee" />
|
||||||
|
<div className="font-display text-2xl tracking-wide text-marquee">STARTING TABLE</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { hasWebGL2 } from "./webglSupport";
|
|||||||
// outside webpack's module graph (see scripts/copy-engine-assets.mjs).
|
// outside webpack's module graph (see scripts/copy-engine-assets.mjs).
|
||||||
const ENGINE_BASE_URL = "/vendor/vpinball-wasm";
|
const ENGINE_BASE_URL = "/vendor/vpinball-wasm";
|
||||||
|
|
||||||
export type PinballStatus = "idle" | "loading" | "ready" | "running" | "error";
|
export type PinballStatus = "idle" | "loading" | "ready" | "starting" | "running" | "error";
|
||||||
|
|
||||||
interface EngineModule {
|
interface EngineModule {
|
||||||
loadPinball(options: LoadPinballOptions): Promise<PinballInstance>;
|
loadPinball(options: LoadPinballOptions): Promise<PinballInstance>;
|
||||||
@@ -114,8 +114,18 @@ export function usePinballInstance(
|
|||||||
|
|
||||||
const start = useCallback(() => {
|
const start = useCallback(() => {
|
||||||
if (!instanceRef.current) return;
|
if (!instanceRef.current) return;
|
||||||
instanceRef.current.start();
|
setStatus("starting");
|
||||||
setStatus("running");
|
// instance.start() runs synchronously and blocks the main thread for a
|
||||||
|
// noticeable moment (heavy WASM init) — a nested rAF lets the browser
|
||||||
|
// paint the "starting" spinner from the state update above before that
|
||||||
|
// block hits, instead of the UI freezing on the old screen mid-click.
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (disposedRef.current || !instanceRef.current) return;
|
||||||
|
instanceRef.current.start();
|
||||||
|
setStatus("running");
|
||||||
|
});
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return { status, progress, error, loadTimeMs, instanceRef, start };
|
return { status, progress, error, loadTimeMs, instanceRef, start };
|
||||||
|
|||||||
Reference in New Issue
Block a user