Compare commits
2
Commits
d7ea38d8ee
...
44504c718d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44504c718d | ||
|
|
53c8ea03ac |
@@ -64,11 +64,8 @@ export default function CoinDoorHud({ instanceRef, tableInfo, loadTimeMs }: Coin
|
||||
};
|
||||
|
||||
const handleEject = () => {
|
||||
// dispose() (called by usePinballInstance's unmount cleanup, triggered by
|
||||
// this navigation) tears the instance down immediately. Calling stop()
|
||||
// here too raced it — stop() defers teardown to the engine's next
|
||||
// internal step, and dispose() freeing WASM memory before that step runs
|
||||
// hung the tab.
|
||||
// usePinballInstance's unmount cleanup (triggered by this navigation)
|
||||
// handles stop()+dispose() itself, sequenced to avoid hanging the tab.
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
|
||||
@@ -74,6 +74,13 @@ export default function PinballCanvasImpl({ tableData, rom, tableInfo }: Pinball
|
||||
</p>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { hasWebGL2 } from "./webglSupport";
|
||||
// outside webpack's module graph (see scripts/copy-engine-assets.mjs).
|
||||
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 {
|
||||
loadPinball(options: LoadPinballOptions): Promise<PinballInstance>;
|
||||
@@ -104,8 +104,20 @@ export function usePinballInstance(
|
||||
|
||||
return () => {
|
||||
disposedRef.current = true;
|
||||
instanceRef.current?.dispose();
|
||||
const instance = instanceRef.current;
|
||||
instanceRef.current = null;
|
||||
if (instance) {
|
||||
// stop() halts the engine's render loop, but only takes effect on
|
||||
// its next internal step rather than immediately. Calling dispose()
|
||||
// synchronously right after — freeing WASM memory before that step
|
||||
// runs — is what hangs the tab. Give it a couple of frames first.
|
||||
instance.stop();
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
instance.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
// Intentionally run once: PlayView mounts a fresh PinballCanvasImpl
|
||||
// (via `key`) per table rather than swapping tableData in place.
|
||||
@@ -114,8 +126,18 @@ export function usePinballInstance(
|
||||
|
||||
const start = useCallback(() => {
|
||||
if (!instanceRef.current) return;
|
||||
setStatus("starting");
|
||||
// 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 };
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@valknar/vpinball-wasm": "0.3.2",
|
||||
"@valknar/vpinball-wasm": "0.3.3",
|
||||
"next": "16.3.2",
|
||||
"react": "19.2.8",
|
||||
"react-dom": "19.2.8"
|
||||
|
||||
Generated
+5
-5
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@valknar/vpinball-wasm':
|
||||
specifier: 0.3.2
|
||||
version: 0.3.2
|
||||
specifier: 0.3.3
|
||||
version: 0.3.3
|
||||
next:
|
||||
specifier: 16.3.2
|
||||
version: 16.3.2(@babel/core@7.29.7(supports-color@7.2.0))(@types/node@20.19.43)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
@@ -754,8 +754,8 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@valknar/vpinball-wasm@0.3.2':
|
||||
resolution: {integrity: sha512-52vkjVzev92khiO8a50N2afYIviX1hHCMzTilN24Pe/7pu5m9LlSQVS3o11rRdItSF5h1RVmTLpoh1ENYrLQJw==, tarball: https://dev.pivoine.art/api/packages/valknar/npm/%40valknar%2Fvpinball-wasm/-/0.3.2/vpinball-wasm-0.3.2.tgz}
|
||||
'@valknar/vpinball-wasm@0.3.3':
|
||||
resolution: {integrity: sha512-It2VO8FrmBa7u+aom4m+JCWaVv6ZOhRn0x8BqqrFbGo2ptTb64G8SgqRXuGU8GldhIvgl3/ug+PsSg3EhETZpg==, tarball: https://dev.pivoine.art/api/packages/valknar/npm/%40valknar%2Fvpinball-wasm/-/0.3.3/vpinball-wasm-0.3.3.tgz}
|
||||
|
||||
acorn-jsx@5.3.2:
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
@@ -2645,7 +2645,7 @@ snapshots:
|
||||
'@unrs/resolver-binding-win32-x64-msvc@1.12.2':
|
||||
optional: true
|
||||
|
||||
'@valknar/vpinball-wasm@0.3.2': {}
|
||||
'@valknar/vpinball-wasm@0.3.3': {}
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.18.0):
|
||||
dependencies:
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@ allowBuilds:
|
||||
sharp: false
|
||||
unrs-resolver: false
|
||||
minimumReleaseAgeExclude:
|
||||
- '@valknar/vpinball-wasm@0.2.0 || 0.3.1 || 0.3.2'
|
||||
- '@valknar/vpinball-wasm@0.2.0 || 0.3.1 || 0.3.2 || 0.3.3'
|
||||
updateNotifier: false
|
||||
|
||||
Reference in New Issue
Block a user