game browser module

This commit is contained in:
Chris Wanstrath 2025-09-27 19:05:29 -07:00
parent 22cdd68184
commit 2c9f8a563e
2 changed files with 57 additions and 52 deletions

56
app/src/js/game.ts Normal file
View File

@ -0,0 +1,56 @@
import { type Message, Context } from "../shared/types.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"
let oldMode = "cinema"
export async function handleGameStart(msg: Message) {
const msgId = msg.id as string
const name = msg.data as string
const game = await import(`/command/${name}`)
const id = randomId()
let stopGame = false
addOutput(msgId, { html: `<canvas id="${id}" class="game active" height="540" width="960" tabindex="0"></canvas>` })
if (document.body.dataset.mode === "tall") {
browserCommands.mode?.()
oldMode = "tall"
}
setStatus(msgId, "ok")
const canvas = $(id) as HTMLCanvasElement
const ctx = new Context(canvas.getContext("2d")!)
canvas.focus()
canvas.addEventListener("keydown", e => {
e.preventDefault()
if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) {
stopGame = true
if (oldMode === "tall") browserCommands.mode?.()
canvas.classList.remove("active")
canvas.style.height = canvas.height / 2 + "px"
canvas.style.width = canvas.width / 2 + "px"
focusInput()
}
})
let last = 0
function loop(ts: number) {
if (stopGame) return
const delta = ts - last
if (delta >= 1000 / 30) {
if (game.update) game.update(delta)
if (game.draw) game.draw(ctx)
last = ts
}
requestAnimationFrame(loop)
}
requestAnimationFrame(loop)
}

View File

@ -2,14 +2,12 @@
// The shell runs on the server and processes input, returning output.
import type { Message, CommandResult, CommandOutput } from "../shared/types.js"
import { Context } from "../shared/types.js"
import { addInput, setStatus, addOutput, appendOutput, replaceOutput } from "./scrollback.js"
import { send } from "./websocket.js"
import { randomId } from "../shared/utils.js"
import { addToHistory } from "./history.js"
import { focusInput } from "./focus.js"
import { browserCommands, cacheCommands } from "./commands.js"
import { $ } from "./dom.js"
import { handleGameStart } from "./game.js"
export function runCommand(input: string) {
if (!input.trim()) return
@ -84,52 +82,3 @@ function handleStreamReplace(msg: Message) {
function handleStreamEnd(_msg: Message) {
}
let oldMode = "cinema"
async function handleGameStart(msg: Message) {
const msgId = msg.id as string
const name = msg.data as string
const game = await import(`/command/${name}`)
const id = randomId()
let stopGame = false
addOutput(msgId, { html: `<canvas id="${id}" class="game active" height="540" width="960" tabindex="0"></canvas>` })
if (document.body.dataset.mode === "tall") {
browserCommands.mode?.()
oldMode = "tall"
}
setStatus(msgId, "ok")
const canvas = $(id) as HTMLCanvasElement
const ctx = new Context(canvas.getContext("2d")!)
canvas.focus()
canvas.addEventListener("keydown", e => {
e.preventDefault()
if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) {
stopGame = true
if (oldMode === "tall") browserCommands.mode?.()
canvas.classList.remove("active")
canvas.style.height = canvas.height / 2 + "px"
canvas.style.width = canvas.width / 2 + "px"
focusInput()
}
})
let last = 0
function loop(ts: number) {
if (stopGame) return
const delta = ts - last
if (delta >= 1000 / 30) {
if (game.update) game.update(delta)
if (game.draw) game.draw(ctx)
last = ts
}
requestAnimationFrame(loop)
}
requestAnimationFrame(loop)
}