1import type { SceneCtx } from "./scene.ts";23/** Keep letter shortcuts out of text editing and select controls. */4export function editingControl(target: EventTarget | null): boolean {5 return target instanceof HTMLElement &&6 (target.isContentEditable ||7 target.closest("input, textarea, select") !== null);8}910/** Shared controls for both run modes. The simulation pauses while the11 * camera can still orbit, and sharing always copies the complete seed URL. */12export function installRunControls(ctx: SceneCtx): void {13 const pause = document.getElementById("pause-run")!;14 const paused = document.getElementById("paused-label")!;15 const fullscreen = document.getElementById("fullscreen")!;16 const share = document.getElementById("share-run")!;17 const status = document.getElementById("share-status")!;18 let messageTimer: ReturnType<typeof setTimeout>;19 const message = (text: string) => {20 clearTimeout(messageTimer);21 status.textContent = text;22 messageTimer = setTimeout(() => status.textContent = "", 3500);23 };24 const setPaused = (value: boolean) => {25 ctx.paused = value;26 pause.textContent = ctx.paused ? "Resume" : "Pause";27 pause.setAttribute("aria-pressed", String(ctx.paused));28 paused.hidden = !ctx.paused;29 };30 const togglePause = () => setPaused(!ctx.paused);31 document.getElementById("new-track")?.addEventListener(32 "click",33 () => setPaused(false),34 );35 const toggleFullscreen = async () => {36 try {37 if (document.fullscreenElement) await document.exitFullscreen();38 else await document.documentElement.requestFullscreen();39 } catch {40 message("Full screen is unavailable in this browser.");41 }42 };43 document.addEventListener("fullscreenchange", () => {44 const active = !!document.fullscreenElement;45 fullscreen.textContent = active ? "Exit full screen" : "Full screen";46 fullscreen.setAttribute("aria-pressed", String(active));47 });48 pause.addEventListener("click", togglePause);49 fullscreen.addEventListener("click", toggleFullscreen);50 share.addEventListener("click", async () => {51 try {52 await navigator.clipboard.writeText(location.href);53 message("World link copied. Send someone the same adventure.");54 } catch {55 message("Copy the address bar to share this world.");56 }57 });58 addEventListener("keydown", (e) => {59 if (60 editingControl(e.target) || e.repeat || e.metaKey || e.ctrlKey || e.altKey61 ) return;62 if (e.code === "KeyK") {63 e.preventDefault();64 togglePause();65 } else if (e.code === "KeyF") {66 e.preventDefault();67 void toggleFullscreen();68 }69 });70}