import "./style.css"; import type { Color } from "./game/state"; import { PERSONALITIES, getPersonality } from "./game/personalities"; import { PIECE_SETS } from "./board/pieces"; import { TIME_CONTROLS, timeControl } from "./game/clock"; import { loadPrefs, savePrefs, type Prefs } from "./util/storage"; import { fenFromUrl, routeFromUrl, goto } from "./util/url"; const app = document.querySelector("#app")!; let prefs = loadPrefs(); function main() { window.addEventListener("hashchange", render); render(); } function render() { prefs = loadPrefs(); const route = routeFromUrl(); const startFen = fenFromUrl(); if (route === "play" || startFen) return renderSetup(startFen); if (route === "settings") return renderSettings(); if (route === "about") return renderAbout(); renderHome(); } function renderHome() { app.innerHTML = `

a quiet game of kings

`; app.querySelectorAll("[data-go]").forEach((b) => { b.onclick = () => goto(b.dataset.go!); }); } function renderSetup(startFen: string | null) { let side = prefs.side; let personality = prefs.personality; let clockId = prefs.clock; const opponentRows = PERSONALITIES.map( (p) => ` ` ).join(""); const timeButtons = [...TIME_CONTROLS, { id: "custom", label: "custom" }] .map((t) => ``) .join(""); app.innerHTML = `

new game

${opponentRows}
${timeButtons}
`; app.querySelector("[data-back]")!.onclick = () => goto("home"); pressGroup("#sides button", (b) => (side = b.dataset.side as Prefs["side"])); pressGroup("#opps .row", (b) => (personality = b.dataset.id!)); pressGroup("#times button", (b) => { clockId = b.dataset.tc!; app.querySelector("#custom")!.classList.toggle("hidden", clockId !== "custom"); }); app.querySelector("#start")!.onclick = async () => { const base = (Number((app.querySelector("#cbase") as HTMLInputElement).value) || 5) * 60; const inc = Number((app.querySelector("#cinc") as HTMLInputElement).value) || 0; const text = (app.querySelector("#load") as HTMLTextAreaElement).value; prefs = { ...prefs, side, personality, clock: clockId, clockBase: base, clockInc: inc }; savePrefs(prefs); const human: Color = side === "random" ? (Math.random() < 0.5 ? "w" : "b") : side; const tc = timeControl(clockId, { base, inc }); const { startGame } = await import("./play"); const err = await startGame(human, getPersonality(personality), tc, text); if (err) { const box = app.querySelector("#loaderr"); if (box) box.textContent = err; } }; } function pressGroup(selector: string, onPick: (b: HTMLButtonElement) => void) { const buttons = app.querySelectorAll(selector); buttons.forEach((b) => { b.onclick = () => { onPick(b); buttons.forEach((c) => c.setAttribute("aria-pressed", String(c === b))); }; }); } function renderSettings() { const setRows = PIECE_SETS.map( (s) => `` ).join(""); app.innerHTML = `

settings

${setRows}
`; app.querySelector("[data-back]")!.onclick = () => goto("home"); app.querySelectorAll("#sets button").forEach((b) => { b.onclick = () => { prefs = { ...prefs, pieceSet: b.dataset.set as Prefs["pieceSet"] }; savePrefs(prefs); app.querySelectorAll("#sets button").forEach((c) => c.setAttribute("aria-pressed", String(c === b))); }; }); app.querySelectorAll("[data-flag]").forEach((b) => { const key = b.dataset.flag as keyof Prefs; b.onclick = () => { prefs = { ...prefs, [key]: !prefs[key] }; savePrefs(prefs); b.setAttribute("aria-pressed", String(prefs[key])); }; }); } function renderAbout() { app.innerHTML = `

about

Emchess is a small chess game you play in your browser. No accounts, no ads, nothing to install. Just a board, a good opponent, and some quiet.

Emchess
Created by Pablo Murad
pablomurad@pm.me

Kill the king — MMXXVI

`; app.querySelector("[data-back]")!.onclick = () => goto("home"); } main();