import type { Message, InputState } from "../shared/types.js" import { GameContext } from "../shared/game.js" import { focusInput } from "./focus.js" import { $ } from "./dom.js" import { randomId } from "../shared/utils.js" import { setStatus, addOutput } from "./scrollback.js" import { browserCommands } from "./commands.js" const FPS = 30 let oldMode = "cinema" let running = false let canvas: HTMLCanvasElement type Game = { init?: () => void, update?: (delta: number, input: InputState) => void, draw?: (ctx: GameContext) => void } const pressedStack = new Set() let pressed: InputState = { key: "", shift: false, ctrl: false, meta: false, pressed: pressedStack } export async function handleGameStart(msg: Message) { const msgId = msg.id as string const name = msg.data as string let game try { game = await import(`/command/${name}`) } catch (err: any) { setStatus(msgId, "error") addOutput(msgId, `Error: ${err.message ? err.message : err}`) return } const canvasId = randomId() addOutput(msgId, { html: `` }) if (document.body.dataset.mode === "tall") { browserCommands.mode?.() oldMode = "tall" } canvas = $(canvasId) as HTMLCanvasElement canvas.focus() setStatus(msgId, "ok") canvas.addEventListener("keydown", handleKeydown) canvas.addEventListener("keyup", handleKeyup) gameLoop(new GameContext(canvas.getContext("2d")!), game) } function handleKeydown(e: KeyboardEvent) { pressedStack.add(e.key) e.preventDefault() if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) { running = false if (oldMode === "tall") browserCommands.mode?.() canvas.classList.remove("active") canvas.style.height = canvas.height / 2 + "px" canvas.style.width = canvas.width / 2 + "px" focusInput() } else { pressed.key = e.key pressed.ctrl = e.ctrlKey pressed.shift = e.shiftKey pressed.meta = e.metaKey } } function handleKeyup(e: KeyboardEvent) { pressedStack.delete(e.key) if (pressedStack.size === 0) { pressed.key = "" pressed.ctrl = false pressed.shift = false pressed.meta = false } } function gameLoop(ctx: GameContext, game: Game) { running = true let last = 0 if (game.init) game.init() function loop(ts: number) { if (!running) return const delta = ts - last if (delta >= 1000 / FPS) { if (game.update) game.update(delta, pressed) if (game.draw) game.draw(ctx) last = ts } requestAnimationFrame(loop) } requestAnimationFrame(loop) }