67 lines
2.8 KiB
TypeScript
67 lines
2.8 KiB
TypeScript
// file: Web/game-snake-poc/frontend/ts/main.ts
|
|
// version: 3
|
|
|
|
import ResizeObserver from "resize-observer-polyfill";
|
|
import "simplebar";
|
|
import { loadSnakeWebAssets } from "./assets";
|
|
import { startGame } from "./game";
|
|
import { bindInputs } from "./input";
|
|
import { bindBrowserLifecycle } from "./lifecycle";
|
|
import { webError, webInfo } from "./logging";
|
|
|
|
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
|
|
|
|
function requireElement<T extends Element>(selector: string): T {
|
|
const element = document.querySelector<T>(selector);
|
|
if (element === null) {
|
|
throw new Error(`Élément frontend requis absent : ${selector}`);
|
|
}
|
|
return element;
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const canvas = requireElement<HTMLCanvasElement>("#game");
|
|
const stage = requireElement<HTMLElement>(".game-stage");
|
|
const score = requireElement<HTMLOutputElement>("#score");
|
|
const length = requireElement<HTMLOutputElement>("#length");
|
|
const provenance = requireElement<HTMLOutputElement>("#runtime-provenance");
|
|
const assets = requireElement<HTMLOutputElement>("#asset-status");
|
|
const status = requireElement<HTMLSpanElement>("#runtime-status");
|
|
const error = requireElement<HTMLParagraphElement>("#startup-error");
|
|
const buttons = Array.from(document.querySelectorAll<HTMLButtonElement>("[data-direction]"));
|
|
|
|
status.textContent = "Chargement assets…";
|
|
const assetMetadata = await loadSnakeWebAssets();
|
|
assets.value = `${assetMetadata.gameKind} / engine-v${assetMetadata.engineGeneration}`;
|
|
webInfo("snake-web-assets", "runtime_assets_loaded", {
|
|
engineGeneration: assetMetadata.engineGeneration,
|
|
game: assetMetadata.game,
|
|
gameKind: assetMetadata.gameKind,
|
|
});
|
|
|
|
status.textContent = "Chargement WASM…";
|
|
const session = await startGame(canvas, score, length, provenance);
|
|
bindInputs(session, buttons);
|
|
bindBrowserLifecycle(session, stage);
|
|
status.className = "badge text-bg-success";
|
|
status.textContent = "Prêt";
|
|
error.hidden = true;
|
|
canvas.focus();
|
|
webInfo("snake-web-main", "runtime_ready");
|
|
}
|
|
|
|
void main().catch(caughtError => {
|
|
const status = document.querySelector<HTMLSpanElement>("#runtime-status");
|
|
const error = document.querySelector<HTMLParagraphElement>("#startup-error");
|
|
const message = caughtError instanceof Error ? caughtError.stack ?? caughtError.message : String(caughtError);
|
|
if (status !== null) {
|
|
status.className = "badge text-bg-danger";
|
|
status.textContent = "Erreur";
|
|
}
|
|
if (error !== null) {
|
|
error.textContent = `Impossible de démarrer Snake : ${message}`;
|
|
error.hidden = false;
|
|
}
|
|
webError("snake-web-main", "runtime_start_failed", { message });
|
|
});
|