Files
vpinball-wasm/examples/basic/index.html
T
valknarandClaude Sonnet 5 ad66bbf6be
CI / Build wasm engine (push) Successful in 9m32s
Rename package from @valknar/vpinball-wasm to vpinball-wasm
Unscoped, matching this project's other Gitea-published package
(triggershell) - the registry is already scoped to the right owner via
publishConfig.registry's URL path (.../valknar/npm/), so an npm scope
on the package name itself is redundant. The old @valknar/vpinball-wasm
package published under the previous name is being removed manually.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 19:06:44 +02:00

109 lines
3.9 KiB
HTML

<!doctype html>
<!--
Full usage example for vpinball-wasm: loading progress, a
user-gesture "Start" button (required for audio autoplay and fullscreen
to work), an optional file picker for a self-contained .vpx table, touch
controls on touch-capable devices, and a fullscreen button.
Serve this directory alongside a built dist/ (see scripts/dev-server.sh)
and adjust the import paths below if dist/ isn't a sibling directory.
-->
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<title>vpinball-wasm example</title>
<style>
html, body { margin: 0; height: 100%; background: #111; overflow: hidden; }
#stage { position: relative; width: 100vw; height: 100vh; }
canvas { display: block; width: 100%; height: 100%; padding: 0; border: 0; }
#overlay {
position: absolute; inset: 0; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 16px;
background: #111; color: #eee; font-family: sans-serif;
}
#overlay.hidden { display: none; }
#progress-track { width: 280px; height: 8px; background: #333; border-radius: 4px; overflow: hidden; }
#progress-bar { width: 0%; height: 100%; background: #4ade80; transition: width 0.1s linear; }
#start-button {
padding: 12px 32px; font-size: 18px; border-radius: 8px; border: none;
background: #4ade80; color: #111; cursor: pointer;
}
#start-button:disabled { opacity: 0.4; cursor: default; }
#file-picker { color: #aaa; font-size: 13px; }
#fullscreen-button {
position: absolute; top: 12px; right: 12px; z-index: 10;
padding: 8px 14px; border-radius: 6px; border: none;
background: rgba(255,255,255,0.15); color: #eee; cursor: pointer;
}
#fullscreen-button.hidden { display: none; }
</style>
</head>
<body>
<div id="stage">
<canvas id="canvas"></canvas>
<div id="overlay">
<div id="progress-track"><div id="progress-bar"></div></div>
<div id="file-picker">
<label>Optional: play your own table (self-contained .vpx only) <input type="file" id="table-file" accept=".vpx" /></label>
</div>
<button id="start-button" disabled>Loading...</button>
</div>
<button id="fullscreen-button" class="hidden">Fullscreen</button>
</div>
<script type="module">
import { loadPinball, attachTouchControls } from '../../dist/index.js';
const canvas = document.getElementById('canvas');
const overlay = document.getElementById('overlay');
const progressBar = document.getElementById('progress-bar');
const startButton = document.getElementById('start-button');
const fileInput = document.getElementById('table-file');
const fullscreenButton = document.getElementById('fullscreen-button');
let uploadedTableData;
fileInput.addEventListener('change', async () => {
const file = fileInput.files?.[0];
if (file) uploadedTableData = await file.arrayBuffer();
});
const pinball = await loadPinball({
canvas,
baseUrl: '../../dist',
onProgress: (fraction) => {
progressBar.style.width = `${Math.round(fraction * 100)}%`;
},
});
window.pinball = pinball; // for console access (e.g. pinball.evalScript(...))
startButton.disabled = false;
startButton.textContent = 'Start';
startButton.addEventListener('click', () => {
if (uploadedTableData) {
pinball.loadTable(uploadedTableData);
}
pinball.start();
overlay.classList.add('hidden');
fullscreenButton.classList.remove('hidden');
// Touch controls are additive UI for touch-capable devices - not
// required for desktop mouse+keyboard play.
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
attachTouchControls({ container: document.getElementById('stage') });
}
});
fullscreenButton.addEventListener('click', () => {
pinball.requestFullscreen().catch(() => {
// Fullscreen can be rejected (e.g. already fullscreen, or the
// browser denies it) - nothing to recover from here.
});
});
</script>
</body>
</html>