{"version":3,"file":"index.umd.cjs","sources":["../src/registry.ts","../src/modal.ts","../src/render.ts","../src/games/pong.ts","../src/games/minesweeper.ts","../src/games/snake.ts","../src/index.ts"],"sourcesContent":["import type { Game } from './types';\n\n/** A game's stable key for registry / config lookups. */\nexport function gameId(game: Game): string {\n  return game.id ?? game.name;\n}\n\nexport class GameRegistry {\n  private games = new Map<string, Game>();\n\n  add(game: Game): boolean {\n    if (!game || typeof game.name !== 'string' || !game.name) {\n      console.warn('[arcade-shelf] game missing name:', game);\n      return false;\n    }\n    if (typeof game.init !== 'function') {\n      console.warn(`[arcade-shelf] game \"${game.name}\" missing init()`);\n      return false;\n    }\n    const key = gameId(game);\n    if (this.games.has(key)) {\n      console.warn(\n        `[arcade-shelf] duplicate game id \"${key}\" — registration ignored`,\n      );\n      return false;\n    }\n    this.games.set(key, game);\n    return true;\n  }\n\n  remove(id: string): boolean {\n    return this.games.delete(id);\n  }\n\n  get(id: string): Game | undefined {\n    return this.games.get(id);\n  }\n\n  list(): Game[] {\n    return Array.from(this.games.values());\n  }\n\n  clear(): void {\n    this.games.clear();\n  }\n}\n","import type { Game, GameHandle } from './types';\n\nconst DEFAULT_SIZE = { width: 380, height: 280 };\n\nconst FOCUSABLE_SELECTOR =\n  'a[href], area[href], button:not([disabled]), input:not([disabled]), ' +\n  'select:not([disabled]), textarea:not([disabled]), iframe, ' +\n  '[tabindex]:not([tabindex=\"-1\"])';\n\nexport interface OpenedModal {\n  close(): void;\n}\n\nfunction isFocusable(el: Element | null): el is HTMLElement {\n  return !!el && el instanceof HTMLElement && typeof el.focus === 'function' && el.tabIndex !== -1;\n}\n\n/**\n * Open a modal containing a canvas, call game.init(canvas), and start it.\n * Returns a handle with close() that stops the game and removes the modal.\n */\nexport function openGameModal(game: Game, triggerElement?: HTMLElement | null): OpenedModal {\n  const size = game.canvasSize ?? DEFAULT_SIZE;\n  // document.activeElement defaults to <body> when nothing is focused; body.focus()\n  // is a no-op unless tabindex is set, so only keep activeElement if it's actually focusable.\n  const activeEl = document.activeElement;\n  const fallbackFocus = isFocusable(activeEl) && activeEl !== document.body ? activeEl : null;\n  const lastFocus = triggerElement ?? fallbackFocus;\n\n  const overlay = document.createElement('div');\n  overlay.className = 'arcade-shelf-modal-overlay';\n\n  const dialog = document.createElement('div');\n  dialog.className = 'arcade-shelf-modal';\n  dialog.setAttribute('role', 'dialog');\n  dialog.setAttribute('aria-modal', 'true');\n  dialog.setAttribute('aria-label', `Playing: ${game.name}`);\n\n  const header = document.createElement('div');\n  header.className = 'arcade-shelf-modal-header';\n\n  const title = document.createElement('span');\n  title.className = 'arcade-shelf-modal-title';\n  title.textContent = game.name;\n  header.appendChild(title);\n\n  const closeBtn = document.createElement('button');\n  closeBtn.className = 'arcade-shelf-modal-close';\n  closeBtn.type = 'button';\n  closeBtn.setAttribute('aria-label', 'Close');\n  closeBtn.textContent = '×';\n  header.appendChild(closeBtn);\n\n  const canvas = document.createElement('canvas');\n  canvas.className = 'arcade-shelf-canvas';\n  canvas.width = size.width;\n  canvas.height = size.height;\n\n  dialog.appendChild(header);\n  dialog.appendChild(canvas);\n\n  // Read once — `footer` may be a getter that constructs a fresh element per call.\n  const footerContent = game.footer;\n  if (footerContent) {\n    const footer = document.createElement('div');\n    footer.className = 'arcade-shelf-modal-footer';\n    if (typeof footerContent === 'string') {\n      footer.textContent = footerContent;\n    } else {\n      footer.appendChild(footerContent);\n    }\n    dialog.appendChild(footer);\n  }\n\n  overlay.appendChild(dialog);\n  document.body.appendChild(overlay);\n\n  // Lock background scroll while the modal is open. Record the prior value so\n  // we restore it (some hosts set their own overflow, e.g. during nav transitions).\n  const prevBodyOverflow = document.body.style.overflow;\n  document.body.style.overflow = 'hidden';\n\n  let handle: GameHandle | null = null;\n  try {\n    handle = game.init(canvas);\n    handle.start();\n  } catch (e) {\n    console.error(`[arcade-shelf] game \"${game.name}\" init/start failed:`, e);\n  }\n\n  let closed = false;\n  function close(): void {\n    if (closed) return;\n    closed = true;\n\n    if (handle) {\n      try {\n        handle.stop();\n      } catch (e) {\n        console.warn(`[arcade-shelf] game \"${game.name}\" stop() threw:`, e);\n      }\n    }\n\n    overlay.removeEventListener('click', onOverlayClick);\n    closeBtn.removeEventListener('click', close);\n    document.removeEventListener('keydown', onKeyDown);\n    document.removeEventListener('visibilitychange', onVisibilityChange);\n    window.removeEventListener('resize', onResize);\n    overlay.remove();\n\n    document.body.style.overflow = prevBodyOverflow;\n\n    if (isFocusable(lastFocus)) {\n      lastFocus.focus();\n    }\n  }\n\n  function onOverlayClick(e: MouseEvent): void {\n    if (e.target === overlay) close();\n  }\n\n  // Forward tab visibility so games can suspend their RAF / timers. Hooks\n  // are opt-in: a game that doesn't implement them simply keeps running.\n  function onVisibilityChange(): void {\n    if (!handle) return;\n    try {\n      if (document.hidden) handle.pause?.();\n      else handle.resume?.();\n    } catch (e) {\n      console.warn(`[arcade-shelf] game \"${game.name}\" pause/resume threw:`, e);\n    }\n  }\n\n  // Forward window resize so games can re-cache layout-dependent state\n  // (e.g. getBoundingClientRect for input → game coord translation). The\n  // canvas pixel size is unchanged; we just signal that the *displayed*\n  // size may have shifted.\n  function onResize(): void {\n    if (!handle) return;\n    try {\n      handle.resize?.(canvas.width, canvas.height);\n    } catch (e) {\n      console.warn(`[arcade-shelf] game \"${game.name}\" resize threw:`, e);\n    }\n  }\n\n  // Focus trap: keep Tab / Shift+Tab cycling inside the dialog. Without this,\n  // keyboard users can tab back into the underlying page while a modal is open.\n  function onKeyDown(e: KeyboardEvent): void {\n    if (e.key === 'Escape') {\n      e.preventDefault();\n      close();\n      return;\n    }\n    if (e.key !== 'Tab') return;\n\n    const focusables = Array.from(\n      dialog.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n    ).filter((el) => !el.hasAttribute('disabled') && el.offsetParent !== null);\n\n    if (focusables.length === 0) {\n      // Nothing focusable inside — just trap on the dialog itself.\n      e.preventDefault();\n      return;\n    }\n\n    const first = focusables[0]!;\n    const last = focusables[focusables.length - 1]!;\n    const active = document.activeElement as HTMLElement | null;\n\n    if (e.shiftKey && (active === first || !dialog.contains(active))) {\n      e.preventDefault();\n      last.focus();\n    } else if (!e.shiftKey && (active === last || !dialog.contains(active))) {\n      e.preventDefault();\n      first.focus();\n    }\n  }\n\n  overlay.addEventListener('click', onOverlayClick);\n  closeBtn.addEventListener('click', close);\n  document.addEventListener('keydown', onKeyDown);\n  document.addEventListener('visibilitychange', onVisibilityChange);\n  window.addEventListener('resize', onResize);\n\n  // Autofocus close button so Esc/Enter work immediately.\n  closeBtn.focus();\n\n  return { close };\n}\n","import type { Game, ShelfOptions } from './types';\nimport { gameId } from './registry';\nimport { openGameModal, type OpenedModal } from './modal';\n\ninterface RenderDeps {\n  getGames(): Game[];\n  getGame(id: string): Game | undefined;\n  options: ShelfOptions;\n  /**\n   * Called by render whenever it opens a modal, so the owning shelf can\n   * close it on unmount. Returning undefined leaves the modal unmanaged.\n   */\n  onModalOpen?(modal: OpenedModal): void;\n}\n\ninterface RenderedShelf {\n  root: HTMLElement;\n  destroy(): void;\n}\n\nfunction resolveContainer(target: HTMLElement | string): HTMLElement | null {\n  if (typeof target === 'string') {\n    return document.querySelector<HTMLElement>(target);\n  }\n  return target ?? null;\n}\n\nfunction sortGames(games: Game[], options: ShelfOptions): Game[] {\n  const { whitelist, order } = options;\n\n  let list = games;\n  if (whitelist && whitelist.length > 0) {\n    const allow = new Set(whitelist);\n    list = list.filter((g) => allow.has(gameId(g)));\n  }\n\n  const orderIndex = new Map<string, number>();\n  if (order) {\n    order.forEach((id, i) => orderIndex.set(id, i));\n  }\n\n  return list.slice().sort((a, b) => {\n    const ai = orderIndex.get(gameId(a));\n    const bi = orderIndex.get(gameId(b));\n    if (ai !== undefined && bi !== undefined) return ai - bi;\n    if (ai !== undefined) return -1;\n    if (bi !== undefined) return 1;\n\n    const ao = a.order ?? Number.POSITIVE_INFINITY;\n    const bo = b.order ?? Number.POSITIVE_INFINITY;\n    if (ao !== bo) return ao - bo;\n    return a.name.localeCompare(b.name);\n  });\n}\n\nexport function renderShelf(deps: RenderDeps): RenderedShelf {\n  const { getGames, getGame, options, onModalOpen } = deps;\n  const container = resolveContainer(options.container);\n  if (!container) {\n    throw new Error('[arcade-shelf] container not found');\n  }\n\n  const card = document.createElement('div');\n  card.className = 'arcade-shelf-card';\n\n  const header = document.createElement('div');\n  header.className = 'arcade-shelf-card-header';\n\n  const title = document.createElement('span');\n  title.className = 'arcade-shelf-card-title';\n  title.textContent = options.title ?? \"Let's play!\";\n\n  header.appendChild(title);\n\n  const list = document.createElement('ul');\n  list.className = 'arcade-shelf-list';\n  list.setAttribute('role', 'list');\n\n  const games = sortGames(getGames(), options);\n  for (const game of games) {\n    const item = document.createElement('li');\n    item.className = 'arcade-shelf-list-item';\n\n    const btn = document.createElement('button');\n    btn.className = 'arcade-shelf-list-btn';\n    btn.type = 'button';\n    btn.dataset.gameId = gameId(game);\n    if (game.description) {\n      btn.title = game.description;\n      btn.setAttribute('aria-label', `${game.name} — ${game.description}`);\n    } else {\n      btn.setAttribute('aria-label', game.name);\n    }\n\n    if (game.icon) {\n      const ic = document.createElement('span');\n      ic.className = 'arcade-shelf-list-icon';\n      ic.textContent = game.icon;\n      ic.setAttribute('aria-hidden', 'true');\n      btn.appendChild(ic);\n    }\n\n    const label = document.createElement('span');\n    label.className = 'arcade-shelf-list-label';\n    label.textContent = game.name;\n    btn.appendChild(label);\n\n    item.appendChild(btn);\n    list.appendChild(item);\n  }\n\n  card.appendChild(header);\n  card.appendChild(list);\n  container.appendChild(card);\n\n  function onClick(e: MouseEvent): void {\n    const target = e.target as HTMLElement | null;\n    const btn = target?.closest<HTMLButtonElement>('.arcade-shelf-list-btn');\n    if (!btn) return;\n    const id = btn.dataset.gameId;\n    if (!id) return;\n    const game = getGame(id);\n    if (!game) return;\n    const modal = openGameModal(game, btn);\n    onModalOpen?.(modal);\n  }\n\n  list.addEventListener('click', onClick);\n\n  function destroy(): void {\n    list.removeEventListener('click', onClick);\n    card.remove();\n  }\n\n  return { root: card, destroy };\n}\n","import type { Game, GameHandle } from '../types';\n\n/*\n * Pong — classic two-paddle, ball bounces off paddles and walls.\n *\n * Velocity units: \"pixels per 60fps frame\". The step() function multiplies\n * motion by a deltaTime (dt) ratio so a 144Hz display doesn't run 2.4× faster\n * than a 60Hz one. Authors tune numbers against the 60fps baseline and dt\n * handles the rest.\n */\nexport const pong: Game = {\n  name: 'Pong',\n  icon: '🎾',\n  description: 'Classic two-paddle — track the ball, beat the AI.',\n  order: 1,\n  canvasSize: { width: 380, height: 280 },\n\n  init(canvas: HTMLCanvasElement): GameHandle {\n    const ctxMaybe = canvas.getContext('2d');\n    if (!ctxMaybe) throw new Error('[arcade-shelf/pong] 2D context unavailable');\n    // Rebind with a non-nullable type so nested closures below don't need `!` assertions.\n    const ctx: CanvasRenderingContext2D = ctxMaybe;\n\n    // Board geometry — W/H are the canvas's internal pixel size, NOT its CSS\n    // size. setPlayerY() below scales mouse coords from CSS space into this.\n    const W = canvas.width;\n    const H = canvas.height;\n    const PADDLE_W = 8;\n    const PADDLE_H = 50;\n    const BALL = 7;\n    const PLAYER_X = 12;\n    const AI_X = W - 12 - PADDLE_W;\n    // 60fps baseline: one \"frame\" at 60Hz is ~16.67ms. dt = elapsed / FRAME_MS.\n    const FRAME_MS = 1000 / 60;\n\n    // Mutable game state. Kept in closure so start/stop share it without a class.\n    let playerY = (H - PADDLE_H) / 2;\n    let aiY = (H - PADDLE_H) / 2;\n    let ballX = W / 2;\n    let ballY = H / 2;\n    let vx = 0;\n    let vy = 0;\n    let scoreP = 0;\n    let scoreA = 0;\n    let started = false; // has the player ever clicked to serve?\n    let running = false; // is the RAF loop live right now?\n    let raf: number | null = null;\n    let lastTs = 0; // timestamp of previous step(), for dt calc\n    let rect: DOMRect | null = null; // cached canvas bounds, for mouse→game coords\n\n    // getBoundingClientRect() is expensive on every mousemove, so cache it.\n    // Refreshed on start() and on resize (layout can shift the canvas).\n    function refreshRect(): void {\n      rect = canvas.getBoundingClientRect();\n    }\n\n    // Serve the ball toward `dir` (+1 = right / toward AI, -1 = left / toward player).\n    // Small random vertical component so consecutive serves aren't identical.\n    function resetBall(dir: number): void {\n      ballX = W / 2;\n      ballY = H / 2;\n      const angle = Math.random() * 0.6 - 0.3; // radians, ~±17°\n      const speed = 3.2;\n      vx = Math.cos(angle) * speed * dir;\n      vy = Math.sin(angle) * speed;\n    }\n\n    function draw(): void {\n      // Full repaint every frame — cheaper than partial invalidation for a board this size.\n      ctx.fillStyle = '#000';\n      ctx.fillRect(0, 0, W, H);\n\n      // Dashed center line.\n      ctx.strokeStyle = '#333';\n      ctx.setLineDash([5, 5]);\n      ctx.beginPath();\n      ctx.moveTo(W / 2, 0);\n      ctx.lineTo(W / 2, H);\n      ctx.stroke();\n      ctx.setLineDash([]); // reset so other strokes don't inherit it\n\n      ctx.fillStyle = '#fff';\n      ctx.font = 'bold 22px monospace';\n      ctx.textAlign = 'center';\n      ctx.fillText(String(scoreP), W / 2 - 28, 28);\n      ctx.fillText(String(scoreA), W / 2 + 28, 28);\n\n      ctx.fillRect(PLAYER_X, playerY, PADDLE_W, PADDLE_H);\n      ctx.fillRect(AI_X, aiY, PADDLE_W, PADDLE_H);\n      // Ball is drawn from its top-left, but ballX/ballY track its center.\n      ctx.fillRect(ballX - BALL / 2, ballY - BALL / 2, BALL, BALL);\n\n      if (!started) {\n        ctx.font = '12px sans-serif';\n        ctx.fillText('Click / tap to start', W / 2, H - 14);\n      }\n    }\n\n    function step(ts: number): void {\n      if (!running) return;\n\n      // dt is \"how many 60fps frames' worth of time has passed since last step\".\n      // First frame: lastTs=0, use dt=1 (one baseline frame) to avoid a huge jump.\n      // Clamp to 32ms (~2 frames) so a backgrounded tab returning after 5s\n      // doesn't teleport the ball through a paddle.\n      const dt = lastTs === 0 ? 1 : Math.min(32, ts - lastTs) / FRAME_MS;\n      lastTs = ts;\n\n      ballX += vx * dt;\n      ballY += vy * dt;\n\n      // Top/bottom wall bounce. Snap position back inside the wall before\n      // flipping vy — otherwise a fast ball could \"stick\" outside the bound.\n      if (ballY < BALL / 2) {\n        ballY = BALL / 2;\n        vy = -vy;\n      }\n      if (ballY > H - BALL / 2) {\n        ballY = H - BALL / 2;\n        vy = -vy;\n      }\n\n      // Player paddle collision. The `vx < 0` guard is critical: without it,\n      // once the ball overlaps the paddle, every subsequent frame re-flips vx\n      // and traps the ball inside (tunneling artifact).\n      if (\n        ballX - BALL / 2 < PLAYER_X + PADDLE_W &&\n        ballX > PLAYER_X &&\n        ballY > playerY &&\n        ballY < playerY + PADDLE_H &&\n        vx < 0\n      ) {\n        vx = -vx * 1.05; // 5% speedup per hit → rallies get harder\n        // Angle reflection: hitting the paddle's top/bottom edge sends the\n        // ball off at up to ±4 units/frame vertical; hitting dead center → 0.\n        // rel ∈ [-1, 1], so vy ∈ [-4, 4].\n        const rel = (ballY - (playerY + PADDLE_H / 2)) / (PADDLE_H / 2);\n        vy = rel * 4;\n      }\n\n      // AI paddle collision — mirror of the player check. `vx > 0` guard for\n      // the same tunneling reason.\n      if (\n        ballX + BALL / 2 > AI_X &&\n        ballX < AI_X + PADDLE_W &&\n        ballY > aiY &&\n        ballY < aiY + PADDLE_H &&\n        vx > 0\n      ) {\n        vx = -vx * 1.05;\n        const rel = (ballY - (aiY + PADDLE_H / 2)) / (PADDLE_H / 2);\n        vy = rel * 4;\n      }\n\n      // AI tracks the ball's y-position, but at a capped speed the player can\n      // outpace — otherwise the AI is unbeatable. Dead zone of 6px prevents\n      // jitter when the ball is directly in line with the paddle center.\n      const aiCenter = aiY + PADDLE_H / 2;\n      const diff = ballY - aiCenter;\n      const aiSpeed = 2.4;\n      if (Math.abs(diff) > 6) aiY += Math.sign(diff) * aiSpeed * dt;\n      // Clamp so the paddle can't leave the board.\n      aiY = Math.max(0, Math.min(H - PADDLE_H, aiY));\n\n      // Score + serve toward the loser (classic Pong rules).\n      if (ballX < 0) {\n        scoreA++;\n        resetBall(1);\n      }\n      if (ballX > W) {\n        scoreP++;\n        resetBall(-1);\n      }\n\n      draw();\n      // Re-queue ourselves. RAF is not recursive in the stack-eating sense —\n      // each call schedules the next ~16ms later; no stack frame is retained.\n      raf = requestAnimationFrame(step);\n    }\n\n    // Translate a viewport Y (mouse/touch clientY) into the canvas's internal\n    // pixel space. Canvas CSS height may differ from canvas.height (e.g.\n    // responsive layout), so scale by H/rect.height.\n    function setPlayerY(clientY: number): void {\n      if (!rect) refreshRect();\n      if (!rect) return;\n      const y = (clientY - rect.top) * (H / rect.height);\n      // Center the paddle on the cursor, then clamp inside the board.\n      playerY = Math.max(0, Math.min(H - PADDLE_H, y - PADDLE_H / 2));\n    }\n\n    function onMouseMove(e: MouseEvent): void {\n      setPlayerY(e.clientY);\n    }\n    function onTouchMove(e: TouchEvent): void {\n      const t = e.touches[0];\n      if (t) setPlayerY(t.clientY);\n    }\n    // First tap serves the ball; subsequent taps while running are no-ops.\n    // preventDefault stops the browser from treating a canvas tap as a\n    // scroll/zoom gesture on mobile.\n    function onStart(e: Event): void {\n      e.preventDefault();\n      if (!started) {\n        started = true;\n        resetBall(Math.random() > 0.5 ? 1 : -1);\n      }\n      if (!running) {\n        running = true;\n        lastTs = 0; // force the dt=1 first-frame path\n        raf = requestAnimationFrame(step);\n      }\n    }\n\n    return {\n      start(): void {\n        refreshRect();\n        canvas.addEventListener('mousemove', onMouseMove);\n        // passive:true lets the browser scroll without waiting on our handler,\n        // which is the right call here since we never preventDefault on move.\n        canvas.addEventListener('touchmove', onTouchMove, { passive: true });\n        canvas.addEventListener('click', onStart);\n        canvas.addEventListener('touchstart', onStart);\n        draw(); // paint the initial \"click to start\" frame\n      },\n      stop(): void {\n        // Order matters: flip `running` first so an in-flight step() bails\n        // instead of queuing another RAF after we cancel the current one.\n        running = false;\n        if (raf !== null) cancelAnimationFrame(raf);\n        raf = null;\n        canvas.removeEventListener('mousemove', onMouseMove);\n        canvas.removeEventListener('touchmove', onTouchMove);\n        canvas.removeEventListener('click', onStart);\n        canvas.removeEventListener('touchstart', onStart);\n      },\n      // Suspend the RAF loop when the tab is hidden. Without this, a\n      // backgrounded game would still try to step, then return with the\n      // dt clamp kicking in and a visible jump.\n      pause(): void {\n        if (!running) return;\n        running = false;\n        if (raf !== null) cancelAnimationFrame(raf);\n        raf = null;\n      },\n      resume(): void {\n        // Only resume if the player has actually served — pre-serve, we sit\n        // on the \"click to start\" frame and don't need RAF.\n        if (running || !started) return;\n        running = true;\n        lastTs = 0;\n        raf = requestAnimationFrame(step);\n      },\n      // Modal forwards window resize here so we re-cache the bounding rect.\n      // Args unused: canvas pixel dims don't change, only its CSS size.\n      resize(): void {\n        refreshRect();\n      },\n    };\n  },\n};\n","import type { Game, GameHandle } from '../types';\n\n/*\n * Minesweeper — left-click to reveal, right-click (or long-press on touch) to flag.\n *\n * Ported from a Java/Swing implementation (https://github.com/shixuan/minesweeper). \n * Preserved from the original: cell state model, three difficulty presets, mine\n * placement via random-retry, right-click flag with minesLeft counter, win = all\n * non-mine cells revealed.\n *\n * Notable additions over the original:\n *   - First-click safety: mines are placed AFTER the first reveal, excluding\n *     the clicked cell and its 8 neighbours. Original could lose on move 1.\n *   - Flood fill uses a BFS queue instead of recursion. Java's recursive\n *     MSGui.showBlank could stack-overflow on large blank regions.\n *   - Canvas 2D rendering with classic Win95 raised/sunken borders, LED\n *     counter, smiley face, difficulty bar.\n *   - Touch support: 450ms long-press triggers flag (original was mouse-only).\n */\n\ninterface Cell {\n  isMine: boolean;\n  revealed: boolean;\n  flagged: boolean;\n  adjacent: number;\n}\n\ninterface Difficulty {\n  label: string;\n  cols: number;\n  rows: number;\n  mines: number;\n}\n\ntype GameState = 'idle' | 'playing' | 'won' | 'lost';\n\nexport const minesweeper: Game = {\n  name: 'Minesweeper',\n  icon: '💣',\n  description:\n    'Left-click to reveal, right-click to flag. First click is always safe.',\n  order: 2,\n  canvasSize: { width: 380, height: 420 },\n\n  // Attribution footer. Built lazily so that importing this module in a\n  // non-DOM environment (SSR, tests) doesn't blow up on `document`.\n  get footer(): HTMLElement | undefined {\n    if (typeof document === 'undefined') return undefined;\n    const a = document.createElement('a');\n    a.href = 'https://github.com/shixuan/minesweeper';\n    a.textContent = 'Ported from my Java version →';\n    a.target = '_blank';\n    a.rel = 'noopener';\n    return a;\n  },\n\n  init(canvas: HTMLCanvasElement): GameHandle {\n    const ctxMaybe = canvas.getContext('2d');\n    if (!ctxMaybe) throw new Error('[arcade-shelf/minesweeper] 2D context unavailable');\n    // Rebind non-null so closures below don't need `!` assertions.\n    const ctx: CanvasRenderingContext2D = ctxMaybe;\n\n    const W = canvas.width;\n    const H = canvas.height;\n\n    const TOOLBAR_H = 50;\n    const DIFF_H = 32;\n    const MARGIN = 10;\n    const GRID_W = W - MARGIN * 2;\n    const GRID_H = H - TOOLBAR_H - DIFF_H;\n\n    const DIFFS: Difficulty[] = [\n      { label: 'Easy', cols: 9, rows: 9, mines: 10 },\n      { label: 'Normal', cols: 12, rows: 12, mines: 20 },\n      { label: 'Hard', cols: 16, rows: 16, mines: 30 },\n    ];\n\n    // Classic minesweeper number colours (index 0 unused, matches \"adjacent\" count).\n    const NUM_COLORS: readonly string[] = [\n      '',\n      '#1565C0',\n      '#2E7D32',\n      '#C62828',\n      '#4527A0',\n      '#6D4C41',\n      '#00838F',\n      '#000000',\n      '#546E7A',\n    ];\n\n    let diffIdx = 0;\n    let grid: Cell[][] = [];\n    let cellSize = 0;\n    let offX = 0;\n    let offY = 0;\n    let minesLeft = 0;\n    let gameState: GameState = 'idle';\n    let timer = 0;\n    let timerInterval: number | null = null;\n    let firstClick = true;\n    let longPressTimer: number | null = null;\n    let longPressTriggered = false;\n\n    // diffIdx is maintained in [0, DIFFS.length) by all setters, so this is always defined.\n    function currentDiff(): Difficulty {\n      return DIFFS[diffIdx] as Difficulty;\n    }\n\n    // ── Game logic ────────────────────────────────────────────\n\n    function initGame(): void {\n      const { cols, rows, mines } = currentDiff();\n      if (timerInterval !== null) clearInterval(timerInterval);\n      timerInterval = null;\n      timer = 0;\n      minesLeft = mines;\n      firstClick = true;\n      gameState = 'idle';\n\n      grid = Array.from({ length: rows }, () =>\n        Array.from(\n          { length: cols },\n          (): Cell => ({ isMine: false, revealed: false, flagged: false, adjacent: 0 }),\n        ),\n      );\n\n      cellSize = Math.floor(Math.min(GRID_W / cols, GRID_H / rows));\n      offX = MARGIN + Math.floor((GRID_W - cellSize * cols) / 2);\n      offY = TOOLBAR_H + DIFF_H + Math.floor((GRID_H - cellSize * rows) / 2);\n\n      draw();\n    }\n\n    function cellAtRC(r: number, c: number): Cell {\n      // Callers already bounds-check r/c against the current difficulty's rows/cols.\n      return grid[r]![c]!;\n    }\n\n    function placeMines(safeR: number, safeC: number): void {\n      const { cols, rows, mines } = currentDiff();\n      let placed = 0;\n      while (placed < mines) {\n        const r = Math.floor(Math.random() * rows);\n        const c = Math.floor(Math.random() * cols);\n        const cell = cellAtRC(r, c);\n        // Exclude the first-click cell AND its 8 neighbours so move 1 is always safe\n        // and usually opens a reasonable flood.\n        if (\n          !cell.isMine &&\n          !(Math.abs(r - safeR) <= 1 && Math.abs(c - safeC) <= 1)\n        ) {\n          cell.isMine = true;\n          placed++;\n        }\n      }\n      for (let r = 0; r < rows; r++) {\n        for (let c = 0; c < cols; c++) {\n          const cell = cellAtRC(r, c);\n          if (cell.isMine) continue;\n          let n = 0;\n          for (let dr = -1; dr <= 1; dr++) {\n            for (let dc = -1; dc <= 1; dc++) {\n              const nr = r + dr;\n              const nc = c + dc;\n              if (\n                nr >= 0 &&\n                nr < rows &&\n                nc >= 0 &&\n                nc < cols &&\n                cellAtRC(nr, nc).isMine\n              ) {\n                n++;\n              }\n            }\n          }\n          cell.adjacent = n;\n        }\n      }\n    }\n\n    function revealBFS(startR: number, startC: number): void {\n      const { cols, rows } = currentDiff();\n      const queue: Array<[number, number]> = [[startR, startC]];\n      while (queue.length) {\n        const next = queue.shift()!;\n        const [r, c] = next;\n        const cell = cellAtRC(r, c);\n        if (cell.revealed || cell.flagged) continue;\n        cell.revealed = true;\n        if (cell.adjacent === 0) {\n          for (let dr = -1; dr <= 1; dr++) {\n            for (let dc = -1; dc <= 1; dc++) {\n              const nr = r + dr;\n              const nc = c + dc;\n              if (\n                nr >= 0 &&\n                nr < rows &&\n                nc >= 0 &&\n                nc < cols &&\n                !cellAtRC(nr, nc).revealed\n              ) {\n                queue.push([nr, nc]);\n              }\n            }\n          }\n        }\n      }\n    }\n\n    function checkWin(): boolean {\n      const { cols, rows } = currentDiff();\n      for (let r = 0; r < rows; r++) {\n        for (let c = 0; c < cols; c++) {\n          const cell = cellAtRC(r, c);\n          if (!cell.isMine && !cell.revealed) return false;\n        }\n      }\n      return true;\n    }\n\n    function revealMines(): void {\n      const { cols, rows } = currentDiff();\n      for (let r = 0; r < rows; r++) {\n        for (let c = 0; c < cols; c++) {\n          const cell = cellAtRC(r, c);\n          if (cell.isMine) cell.revealed = true;\n        }\n      }\n    }\n\n    // ── Drawing ───────────────────────────────────────────────\n\n    function draw(): void {\n      ctx.clearRect(0, 0, W, H);\n      ctx.fillStyle = '#c0c0c0';\n      ctx.fillRect(0, 0, W, H);\n      drawToolbar();\n      drawDiffBar();\n      drawGrid();\n    }\n\n    function drawToolbar(): void {\n      ctx.fillStyle = '#c0c0c0';\n      ctx.fillRect(0, 0, W, TOOLBAR_H);\n      raised3D(0, 0, W, TOOLBAR_H, 3, false);\n\n      // Mines counter (floor at -99 so the 3-digit LED never overflows).\n      drawLED(MARGIN + 4, 10, Math.max(-99, minesLeft));\n      // Elapsed seconds (cap at 999 to fit 3 digits).\n      drawLED(W - MARGIN - 4 - 40, 10, Math.min(999, timer));\n\n      const sx = W / 2;\n      const sy = TOOLBAR_H / 2;\n      const sr = 13;\n      ctx.beginPath();\n      ctx.arc(sx, sy, sr, 0, Math.PI * 2);\n      ctx.fillStyle = '#FFD700';\n      ctx.fill();\n      ctx.strokeStyle = '#999';\n      ctx.lineWidth = 1;\n      ctx.stroke();\n\n      ctx.fillStyle = '#222';\n      ctx.lineWidth = 1.5;\n      ctx.strokeStyle = '#222';\n\n      if (gameState === 'won') {\n        // Shades + big smile.\n        ctx.fillRect(sx - 9, sy - 5, 7, 5);\n        ctx.fillRect(sx + 2, sy - 5, 7, 5);\n        ctx.fillRect(sx - 9, sy - 5, 18, 2);\n        ctx.beginPath();\n        ctx.arc(sx, sy + 2, 6, 0.1, Math.PI - 0.1);\n        ctx.stroke();\n      } else if (gameState === 'lost') {\n        // X eyes + frown.\n        ctx.font = 'bold 7px sans-serif';\n        ctx.textAlign = 'center';\n        ctx.textBaseline = 'middle';\n        ctx.fillText('×', sx - 4, sy - 3);\n        ctx.fillText('×', sx + 4, sy - 3);\n        ctx.textBaseline = 'alphabetic';\n        ctx.beginPath();\n        ctx.arc(sx, sy + 8, 4, Math.PI, Math.PI * 2);\n        ctx.stroke();\n      } else {\n        // Dot eyes + smile.\n        ctx.beginPath();\n        ctx.arc(sx - 4, sy - 3, 1.5, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.beginPath();\n        ctx.arc(sx + 4, sy - 3, 1.5, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.beginPath();\n        ctx.arc(sx, sy + 2, 5, 0.1, Math.PI - 0.1);\n        ctx.stroke();\n      }\n    }\n\n    function drawLED(x: number, y: number, value: number): void {\n      const text = String(Math.abs(value)).padStart(3, '0');\n      const prefix = value < 0 ? '-' : '';\n      ctx.fillStyle = '#200';\n      ctx.fillRect(x, y, 40, 22);\n      raised3D(x, y, 40, 22, 1, true); // sunken\n      ctx.fillStyle = '#f00';\n      ctx.font = \"bold 17px 'Courier New', monospace\";\n      ctx.textAlign = 'left';\n      ctx.textBaseline = 'top';\n      ctx.fillText(prefix + text, x + 3, y + 3);\n      ctx.textBaseline = 'alphabetic';\n    }\n\n    function drawDiffBar(): void {\n      const btnW = Math.floor(GRID_W / DIFFS.length);\n      DIFFS.forEach((d, i) => {\n        const x = MARGIN + i * btnW;\n        const y = TOOLBAR_H + 4;\n        const bw = i === DIFFS.length - 1 ? GRID_W - i * btnW : btnW;\n        const bh = DIFF_H - 8;\n        const active = i === diffIdx;\n\n        ctx.fillStyle = active ? '#1976D2' : '#e0e0e0';\n        ctx.fillRect(x + 2, y, bw - 4, bh);\n        raised3D(x + 2, y, bw - 4, bh, 2, active);\n\n        ctx.fillStyle = active ? '#fff' : '#333';\n        ctx.font = 'bold 11px sans-serif';\n        ctx.textAlign = 'center';\n        ctx.textBaseline = 'middle';\n        ctx.fillText(d.label, x + bw / 2, y + bh / 2);\n        ctx.textBaseline = 'alphabetic';\n      });\n    }\n\n    function drawGrid(): void {\n      if (grid.length === 0) return;\n      const { cols, rows } = currentDiff();\n      for (let r = 0; r < rows; r++) {\n        for (let c = 0; c < cols; c++) {\n          drawCell(r, c);\n        }\n      }\n    }\n\n    function drawCell(r: number, c: number): void {\n      const x = offX + c * cellSize;\n      const y = offY + r * cellSize;\n      const s = cellSize;\n      const cell = cellAtRC(r, c);\n\n      if (cell.revealed) {\n        ctx.fillStyle = cell.isMine ? '#ff5252' : '#bdbdbd';\n        ctx.fillRect(x, y, s, s);\n        ctx.strokeStyle = '#999';\n        ctx.lineWidth = 0.5;\n        ctx.strokeRect(x + 0.5, y + 0.5, s - 1, s - 1);\n\n        if (cell.isMine) {\n          drawMineIcon(x + s / 2, y + s / 2, s * 0.3);\n        } else if (cell.adjacent > 0) {\n          ctx.fillStyle = NUM_COLORS[cell.adjacent] ?? '#000';\n          ctx.font = `bold ${Math.max(8, Math.floor(s * 0.55))}px sans-serif`;\n          ctx.textAlign = 'center';\n          ctx.textBaseline = 'middle';\n          ctx.fillText(String(cell.adjacent), x + s / 2, y + s / 2 + 1);\n          ctx.textBaseline = 'alphabetic';\n        }\n      } else {\n        ctx.fillStyle = '#c0c0c0';\n        ctx.fillRect(x, y, s, s);\n        raised3D(x, y, s, s, Math.max(1, Math.floor(s * 0.1)), false);\n        if (cell.flagged) drawFlagIcon(x + s / 2, y + s / 2, s * 0.3);\n      }\n    }\n\n    function raised3D(\n      x: number,\n      y: number,\n      w: number,\n      h: number,\n      t: number,\n      sunken: boolean,\n    ): void {\n      const light = sunken ? '#808080' : '#ffffff';\n      const dark = sunken ? '#ffffff' : '#808080';\n      ctx.fillStyle = light;\n      ctx.fillRect(x, y, w, t);\n      ctx.fillRect(x, y, t, h);\n      ctx.fillStyle = dark;\n      ctx.fillRect(x, y + h - t, w, t);\n      ctx.fillRect(x + w - t, y, t, h);\n    }\n\n    function drawMineIcon(cx: number, cy: number, r: number): void {\n      ctx.fillStyle = '#111';\n      ctx.beginPath();\n      ctx.arc(cx, cy, r, 0, Math.PI * 2);\n      ctx.fill();\n      ctx.strokeStyle = '#111';\n      ctx.lineWidth = Math.max(1, r * 0.3);\n      for (let i = 0; i < 8; i++) {\n        const a = (i / 8) * Math.PI * 2;\n        ctx.beginPath();\n        ctx.moveTo(cx + Math.cos(a) * r * 0.8, cy + Math.sin(a) * r * 0.8);\n        ctx.lineTo(cx + Math.cos(a) * r * 1.6, cy + Math.sin(a) * r * 1.6);\n        ctx.stroke();\n      }\n      ctx.fillStyle = 'rgba(255,255,255,0.55)';\n      ctx.beginPath();\n      ctx.arc(cx - r * 0.3, cy - r * 0.3, r * 0.28, 0, Math.PI * 2);\n      ctx.fill();\n    }\n\n    function drawFlagIcon(cx: number, cy: number, r: number): void {\n      ctx.strokeStyle = '#111';\n      ctx.lineWidth = Math.max(1, r * 0.25);\n      ctx.beginPath();\n      ctx.moveTo(cx, cy + r);\n      ctx.lineTo(cx, cy - r);\n      ctx.stroke();\n      ctx.fillStyle = '#e53935';\n      ctx.beginPath();\n      ctx.moveTo(cx, cy - r);\n      ctx.lineTo(cx + r * 1.1, cy - r * 0.35);\n      ctx.lineTo(cx, cy + r * 0.1);\n      ctx.closePath();\n      ctx.fill();\n      ctx.fillStyle = '#111';\n      ctx.fillRect(\n        cx - r * 0.7,\n        cy + r - Math.max(1, r * 0.25),\n        r * 1.4,\n        Math.max(1, r * 0.25),\n      );\n    }\n\n    // ── Hit testing ───────────────────────────────────────────\n\n    function canvasXY(clientX: number, clientY: number): { x: number; y: number } {\n      // Always re-query: modal CSS transitions can shift the canvas after\n      // start() runs, so a cached rect would be stale.\n      const rect = canvas.getBoundingClientRect();\n      return {\n        x: (clientX - rect.left) * (W / rect.width),\n        y: (clientY - rect.top) * (H / rect.height),\n      };\n    }\n\n    function cellAt(x: number, y: number): { r: number; c: number } | null {\n      const { cols, rows } = currentDiff();\n      const c = Math.floor((x - offX) / cellSize);\n      const r = Math.floor((y - offY) / cellSize);\n      if (r >= 0 && r < rows && c >= 0 && c < cols) return { r, c };\n      return null;\n    }\n\n    function onSmiley(x: number, y: number): boolean {\n      const dx = x - W / 2;\n      const dy = y - TOOLBAR_H / 2;\n      return Math.sqrt(dx * dx + dy * dy) <= 16;\n    }\n\n    function diffBarIdx(x: number, y: number): number {\n      if (y < TOOLBAR_H + 4 || y > TOOLBAR_H + DIFF_H - 4) return -1;\n      const btnW = Math.floor(GRID_W / DIFFS.length);\n      const i = Math.floor((x - MARGIN) / btnW);\n      return i >= 0 && i < DIFFS.length ? i : -1;\n    }\n\n    // ── Actions ───────────────────────────────────────────────\n\n    function reveal(r: number, c: number): void {\n      if (gameState === 'won' || gameState === 'lost') return;\n      const cell = cellAtRC(r, c);\n      if (cell.revealed || cell.flagged) return;\n\n      if (firstClick) {\n        firstClick = false;\n        placeMines(r, c);\n        gameState = 'playing';\n        timerInterval = window.setInterval(() => {\n          timer++;\n          draw();\n        }, 1000);\n      }\n\n      if (cell.isMine) {\n        cell.revealed = true;\n        gameState = 'lost';\n        if (timerInterval !== null) clearInterval(timerInterval);\n        timerInterval = null;\n        revealMines();\n      } else {\n        revealBFS(r, c);\n        if (checkWin()) {\n          gameState = 'won';\n          if (timerInterval !== null) clearInterval(timerInterval);\n          timerInterval = null;\n          minesLeft = 0;\n        }\n      }\n      draw();\n    }\n\n    function flag(r: number, c: number): void {\n      if (gameState === 'won' || gameState === 'lost') return;\n      const cell = cellAtRC(r, c);\n      if (cell.revealed) return;\n      cell.flagged = !cell.flagged;\n      minesLeft += cell.flagged ? -1 : 1;\n      draw();\n    }\n\n    // ── Listeners ─────────────────────────────────────────────\n\n    function onClick(e: MouseEvent): void {\n      // Long-press fires a flag on touchstart; the subsequent click should be swallowed\n      // so it doesn't also reveal the cell the player just flagged.\n      if (longPressTriggered) {\n        longPressTriggered = false;\n        return;\n      }\n      const { x, y } = canvasXY(e.clientX, e.clientY);\n\n      if (onSmiley(x, y)) {\n        initGame();\n        return;\n      }\n\n      const di = diffBarIdx(x, y);\n      if (di >= 0) {\n        diffIdx = di;\n        initGame();\n        return;\n      }\n\n      const pos = cellAt(x, y);\n      if (pos) reveal(pos.r, pos.c);\n    }\n\n    function onContextMenu(e: MouseEvent): void {\n      e.preventDefault();\n      const { x, y } = canvasXY(e.clientX, e.clientY);\n      const pos = cellAt(x, y);\n      if (pos) flag(pos.r, pos.c);\n    }\n\n    function onTouchStart(e: TouchEvent): void {\n      const touch = e.touches[0];\n      if (!touch) return;\n      const { clientX, clientY } = touch;\n      longPressTimer = window.setTimeout(() => {\n        longPressTriggered = true;\n        const { x, y } = canvasXY(clientX, clientY);\n        const pos = cellAt(x, y);\n        if (pos) flag(pos.r, pos.c);\n      }, 450);\n    }\n\n    function cancelLongPress(): void {\n      if (longPressTimer !== null) clearTimeout(longPressTimer);\n      longPressTimer = null;\n    }\n\n    // Suppress the mobile long-press callout / text selection so our own\n    // long-press flag handler is the one that fires.\n    const TOUCH_CSS: Record<string, string> = {\n      userSelect: 'none',\n      webkitUserSelect: 'none',\n      webkitTouchCallout: 'none',\n      touchAction: 'none',\n    };\n    const savedCss: Record<string, string> = {};\n\n    return {\n      start(): void {\n        initGame();\n        for (const k of Object.keys(TOUCH_CSS)) {\n          savedCss[k] = (canvas.style as unknown as Record<string, string>)[k] ?? '';\n          (canvas.style as unknown as Record<string, string>)[k] = TOUCH_CSS[k]!;\n        }\n        canvas.addEventListener('click', onClick);\n        canvas.addEventListener('contextmenu', onContextMenu);\n        canvas.addEventListener('touchstart', onTouchStart, { passive: true });\n        canvas.addEventListener('touchend', cancelLongPress);\n        canvas.addEventListener('touchmove', cancelLongPress, { passive: true });\n      },\n      stop(): void {\n        if (timerInterval !== null) clearInterval(timerInterval);\n        timerInterval = null;\n        cancelLongPress();\n        for (const k of Object.keys(TOUCH_CSS)) {\n          (canvas.style as unknown as Record<string, string>)[k] = savedCss[k] ?? '';\n        }\n        canvas.removeEventListener('click', onClick);\n        canvas.removeEventListener('contextmenu', onContextMenu);\n        canvas.removeEventListener('touchstart', onTouchStart);\n        canvas.removeEventListener('touchend', cancelLongPress);\n        canvas.removeEventListener('touchmove', cancelLongPress);\n      },\n      // Freeze the wall-clock timer when the tab hides. Without this, a\n      // tab left open overnight would show a 30000-second game.\n      pause(): void {\n        if (timerInterval !== null) {\n          clearInterval(timerInterval);\n          timerInterval = null;\n        }\n        cancelLongPress();\n      },\n      resume(): void {\n        // Only re-arm the timer if a game is actually in progress — idle / won\n        // / lost states never ran a timer to begin with.\n        if (gameState === 'playing' && timerInterval === null) {\n          timerInterval = window.setInterval(() => {\n            timer++;\n            draw();\n          }, 1000);\n        }\n      },\n    };\n  },\n};\n","import type { Game, GameHandle } from '../types';\n\n/*\n * Snake — classic grid snake.\n *\n * Controls: arrow keys / WASD to turn, Space to restart after game over.\n * Board wraps at the edges (toroidal) — only running into yourself is fatal.\n *\n * This was added in v0.2 primarily as a keyboard-input integration test for\n * the modal: modal listens on `document` (Esc, Tab focus trap) while the game\n * listens on `window`. Bubble phase fires document handler before window, so\n * Esc / Tab are intercepted by the modal and arrow keys fall through to the\n * game — no Game-contract extension needed.\n *\n * Fixed-step simulation with a dt accumulator (not \"one tick per RAF\") so the\n * apparent speed is framerate-independent.\n */\n\ntype Point = { x: number; y: number };\ntype Dir = 'up' | 'down' | 'left' | 'right';\n\nconst CELL = 20;\nconst STEP_MS = 160;\n\nexport const snake: Game = {\n  name: 'Snake',\n  icon: '🐍',\n  description: 'Arrow keys / WASD or swipe to move. Space / tap to restart.',\n  order: 3,\n  canvasSize: { width: 380, height: 380 },\n\n  init(canvas: HTMLCanvasElement): GameHandle {\n    const ctxMaybe = canvas.getContext('2d');\n    if (!ctxMaybe) throw new Error('[arcade-shelf/snake] 2D context unavailable');\n    const ctx: CanvasRenderingContext2D = ctxMaybe;\n\n    const W = canvas.width;\n    const H = canvas.height;\n    const COLS = Math.floor(W / CELL);\n    const ROWS = Math.floor(H / CELL);\n    const OFFSET_X = Math.floor((W - COLS * CELL) / 2);\n    const OFFSET_Y = Math.floor((H - ROWS * CELL) / 2);\n\n    let body: Point[] = [];\n    let dir: Dir = 'right';\n    // Buffered turn: we validate against `pendingDir`, not `dir`, so that two\n    // fast presses (right -> up -> left) are rejected as a reversal chain.\n    let pendingDir: Dir = 'right';\n    let apple: Point = { x: 0, y: 0 };\n    let score = 0;\n    let over = false;\n    let acc = 0;\n    let lastTs = 0;\n    let raf: number | null = null;\n\n    function placeApple(): void {\n      // Random rejection sampling. Grid is small and rarely > 50% full,\n      // so the expected retry count is tiny.\n      for (;;) {\n        const x = Math.floor(Math.random() * COLS);\n        const y = Math.floor(Math.random() * ROWS);\n        if (!body.some((p) => p.x === x && p.y === y)) {\n          apple = { x, y };\n          return;\n        }\n      }\n    }\n\n    function reset(): void {\n      const cx = Math.floor(COLS / 2);\n      const cy = Math.floor(ROWS / 2);\n      body = [\n        { x: cx - 2, y: cy },\n        { x: cx - 1, y: cy },\n        { x: cx, y: cy },\n      ];\n      dir = 'right';\n      pendingDir = 'right';\n      score = 0;\n      over = false;\n      acc = 0;\n      lastTs = 0;\n      placeApple();\n    }\n\n    function setDir(next: Dir): void {\n      // Compare against the most recent intent, not the currently-executing\n      // direction, so rapid keypresses can't sneak in a reversal.\n      if (next === 'up' && pendingDir === 'down') return;\n      if (next === 'down' && pendingDir === 'up') return;\n      if (next === 'left' && pendingDir === 'right') return;\n      if (next === 'right' && pendingDir === 'left') return;\n      pendingDir = next;\n    }\n\n    function step(): void {\n      if (over) return;\n      dir = pendingDir;\n      const head = body[body.length - 1]!;\n      let nx = head.x;\n      let ny = head.y;\n      if (dir === 'up') ny--;\n      else if (dir === 'down') ny++;\n      else if (dir === 'left') nx--;\n      else nx++;\n\n      // Wrap at the edges (toroidal board) — only self-collision is fatal.\n      if (nx < 0) nx = COLS - 1;\n      else if (nx >= COLS) nx = 0;\n      if (ny < 0) ny = ROWS - 1;\n      else if (ny >= ROWS) ny = 0;\n\n      if (body.some((p) => p.x === nx && p.y === ny)) {\n        over = true;\n        return;\n      }\n      body.push({ x: nx, y: ny });\n      if (nx === apple.x && ny === apple.y) {\n        score++;\n        placeApple();\n      } else {\n        body.shift();\n      }\n    }\n\n    function draw(): void {\n      ctx.fillStyle = '#111';\n      ctx.fillRect(0, 0, W, H);\n\n      // Subtle grid\n      ctx.strokeStyle = 'rgba(255,255,255,0.04)';\n      ctx.lineWidth = 1;\n      for (let i = 0; i <= COLS; i++) {\n        ctx.beginPath();\n        ctx.moveTo(OFFSET_X + i * CELL + 0.5, OFFSET_Y);\n        ctx.lineTo(OFFSET_X + i * CELL + 0.5, OFFSET_Y + ROWS * CELL);\n        ctx.stroke();\n      }\n      for (let i = 0; i <= ROWS; i++) {\n        ctx.beginPath();\n        ctx.moveTo(OFFSET_X, OFFSET_Y + i * CELL + 0.5);\n        ctx.lineTo(OFFSET_X + COLS * CELL, OFFSET_Y + i * CELL + 0.5);\n        ctx.stroke();\n      }\n\n      // Apple\n      ctx.fillStyle = '#e8635a';\n      ctx.beginPath();\n      ctx.arc(\n        OFFSET_X + apple.x * CELL + CELL / 2,\n        OFFSET_Y + apple.y * CELL + CELL / 2,\n        CELL / 2 - 2,\n        0,\n        Math.PI * 2,\n      );\n      ctx.fill();\n\n      // Snake — head a bit brighter than tail\n      for (let i = 0; i < body.length; i++) {\n        const p = body[i]!;\n        ctx.fillStyle = i === body.length - 1 ? '#b7e88a' : '#7fd07f';\n        ctx.fillRect(\n          OFFSET_X + p.x * CELL + 1,\n          OFFSET_Y + p.y * CELL + 1,\n          CELL - 2,\n          CELL - 2,\n        );\n      }\n\n      // Score overlay\n      ctx.fillStyle = '#fff';\n      ctx.font = '13px system-ui, -apple-system, sans-serif';\n      ctx.textAlign = 'left';\n      ctx.textBaseline = 'top';\n      ctx.fillText(`Score: ${score}`, 8, 6);\n\n      if (over) {\n        ctx.fillStyle = 'rgba(0,0,0,0.7)';\n        ctx.fillRect(0, 0, W, H);\n        ctx.fillStyle = '#fff';\n        ctx.textAlign = 'center';\n        ctx.textBaseline = 'middle';\n        ctx.font = 'bold 24px system-ui, -apple-system, sans-serif';\n        ctx.fillText('Game Over', W / 2, H / 2 - 10);\n        ctx.font = '14px system-ui, -apple-system, sans-serif';\n        ctx.fillText(`Score: ${score} · Space or tap to restart`, W / 2, H / 2 + 18);\n      }\n    }\n\n    function tick(ts: number): void {\n      if (lastTs === 0) lastTs = ts;\n      // Clamp so a backgrounded tab doesn't fast-forward 100 steps on return.\n      const dt = Math.min(1000, ts - lastTs);\n      lastTs = ts;\n      acc += dt;\n      while (acc >= STEP_MS) {\n        step();\n        acc -= STEP_MS;\n      }\n      draw();\n      raf = requestAnimationFrame(tick);\n    }\n\n    function onKeyDown(e: KeyboardEvent): void {\n      switch (e.key) {\n        case 'ArrowUp':\n        case 'w':\n        case 'W':\n          e.preventDefault();\n          setDir('up');\n          return;\n        case 'ArrowDown':\n        case 's':\n        case 'S':\n          e.preventDefault();\n          setDir('down');\n          return;\n        case 'ArrowLeft':\n        case 'a':\n        case 'A':\n          e.preventDefault();\n          setDir('left');\n          return;\n        case 'ArrowRight':\n        case 'd':\n        case 'D':\n          e.preventDefault();\n          setDir('right');\n          return;\n        case ' ':\n        case 'Spacebar': // legacy IE/Edge name; harmless to keep\n          // Swallow even when not over, so Space never scrolls the page\n          // while the modal has focus.\n          e.preventDefault();\n          if (over) reset();\n          return;\n      }\n    }\n\n    // Touch: swipe on canvas sets direction; tap-on-gameover restarts.\n    // Threshold is in CSS pixels so it scales with device zoom.\n    const SWIPE_MIN = 18;\n    let touchStartX = 0;\n    let touchStartY = 0;\n    let touchStartId: number | null = null;\n\n    function onTouchStart(e: TouchEvent): void {\n      if (touchStartId !== null) return;\n      const t = e.changedTouches[0];\n      if (!t) return;\n      touchStartId = t.identifier;\n      touchStartX = t.clientX;\n      touchStartY = t.clientY;\n    }\n\n    function onTouchMove(e: TouchEvent): void {\n      // Suppress page scroll while the finger is on the canvas.\n      if (touchStartId !== null) e.preventDefault();\n    }\n\n    function onTouchEnd(e: TouchEvent): void {\n      if (touchStartId === null) return;\n      let end: Touch | null = null;\n      for (let i = 0; i < e.changedTouches.length; i++) {\n        const t = e.changedTouches[i]!;\n        if (t.identifier === touchStartId) {\n          end = t;\n          break;\n        }\n      }\n      touchStartId = null;\n      if (!end) return;\n\n      const dx = end.clientX - touchStartX;\n      const dy = end.clientY - touchStartY;\n      const adx = Math.abs(dx);\n      const ady = Math.abs(dy);\n\n      if (adx < SWIPE_MIN && ady < SWIPE_MIN) {\n        // Treat as a tap — only meaningful when game is over (restart).\n        if (over) reset();\n        return;\n      }\n\n      if (adx > ady) setDir(dx > 0 ? 'right' : 'left');\n      else setDir(dy > 0 ? 'down' : 'up');\n    }\n\n    reset();\n    draw();\n\n    return {\n      start(): void {\n        window.addEventListener('keydown', onKeyDown);\n        canvas.addEventListener('touchstart', onTouchStart, { passive: true });\n        canvas.addEventListener('touchmove', onTouchMove, { passive: false });\n        canvas.addEventListener('touchend', onTouchEnd);\n        canvas.addEventListener('touchcancel', onTouchEnd);\n        raf = requestAnimationFrame(tick);\n      },\n      stop(): void {\n        window.removeEventListener('keydown', onKeyDown);\n        canvas.removeEventListener('touchstart', onTouchStart);\n        canvas.removeEventListener('touchmove', onTouchMove);\n        canvas.removeEventListener('touchend', onTouchEnd);\n        canvas.removeEventListener('touchcancel', onTouchEnd);\n        if (raf !== null) cancelAnimationFrame(raf);\n        raf = null;\n        lastTs = 0;\n      },\n      // Suspend RAF when the tab hides. Resetting lastTs on resume avoids a\n      // dt accumulator burst — we'd otherwise process many queued steps the\n      // moment the player comes back.\n      pause(): void {\n        if (raf !== null) cancelAnimationFrame(raf);\n        raf = null;\n        lastTs = 0;\n      },\n      resume(): void {\n        if (raf !== null) return; // already running\n        raf = requestAnimationFrame(tick);\n      },\n    };\n  },\n};\n","import type { Game, Shelf, ShelfOptions } from './types';\nimport { GameRegistry } from './registry';\nimport { renderShelf } from './render';\nimport type { OpenedModal } from './modal';\nimport './style.css';\n\nexport type {\n  CanvasSize,\n  Game,\n  GameHandle,\n  Shelf,\n  ShelfOptions,\n} from './types';\n\nexport { openGameModal, type OpenedModal } from './modal';\nexport { pong } from './games/pong';\nexport { minesweeper } from './games/minesweeper';\nexport { snake } from './games/snake';\n\nexport function createShelf(options: ShelfOptions): Shelf {\n  const registry = new GameRegistry();\n  let rendered: { destroy(): void } | null = null;\n  // Track the currently-open modal (one at a time — the shelf renders a\n  // single list, and opening a second game would just reuse the same\n  // modal slot). On unmount we close it so the game inside stops and\n  // releases its RAF / listeners.\n  let activeModal: OpenedModal | null = null;\n\n  function render(): void {\n    if (rendered) rendered.destroy();\n    rendered = renderShelf({\n      getGames: () => registry.list(),\n      getGame: (id) => registry.get(id),\n      options,\n      onModalOpen(modal) {\n        // If a previous modal is somehow still tracked, close it first —\n        // shouldn't normally happen, but cheap and avoids orphan handles.\n        if (activeModal) activeModal.close();\n        activeModal = modal;\n      },\n    });\n  }\n\n  const shelf: Shelf = {\n    register(game: Game) {\n      const ok = registry.add(game);\n      // If already mounted, re-render so the new game shows up immediately.\n      // Cheap: the list is usually single-digit entries.\n      if (ok && rendered) render();\n      return shelf;\n    },\n    mount() {\n      render();\n      return shelf;\n    },\n    unmount() {\n      if (activeModal) {\n        activeModal.close();\n        activeModal = null;\n      }\n      if (rendered) {\n        rendered.destroy();\n        rendered = null;\n      }\n    },\n  };\n\n  return shelf;\n}\n"],"names":["gameId","game","GameRegistry","key","id","DEFAULT_SIZE","FOCUSABLE_SELECTOR","isFocusable","el","openGameModal","triggerElement","size","activeEl","fallbackFocus","lastFocus","overlay","dialog","header","title","closeBtn","canvas","footerContent","footer","prevBodyOverflow","handle","e","closed","close","onOverlayClick","onKeyDown","onVisibilityChange","onResize","_a","focusables","first","last","active","resolveContainer","target","sortGames","games","options","whitelist","order","list","allow","g","orderIndex","i","b","ai","bi","ao","bo","renderShelf","deps","getGames","getGame","onModalOpen","container","card","item","btn","ic","label","onClick","modal","destroy","pong","ctxMaybe","ctx","W","H","PADDLE_W","PADDLE_H","BALL","PLAYER_X","AI_X","FRAME_MS","playerY","aiY","ballX","ballY","vx","vy","scoreP","scoreA","started","running","raf","lastTs","rect","refreshRect","resetBall","dir","angle","speed","draw","step","ts","dt","aiCenter","diff","setPlayerY","clientY","y","onMouseMove","onTouchMove","t","onStart","minesweeper","a","TOOLBAR_H","DIFF_H","MARGIN","GRID_W","GRID_H","DIFFS","NUM_COLORS","diffIdx","grid","cellSize","offX","offY","minesLeft","gameState","timer","timerInterval","firstClick","longPressTimer","longPressTriggered","currentDiff","initGame","cols","rows","mines","cellAtRC","r","c","placeMines","safeR","safeC","placed","cell","n","dr","dc","nr","nc","revealBFS","startR","startC","queue","next","checkWin","revealMines","drawToolbar","drawDiffBar","drawGrid","raised3D","drawLED","sx","sy","sr","x","value","text","prefix","btnW","d","bw","bh","drawCell","s","drawMineIcon","drawFlagIcon","w","h","sunken","light","dark","cx","cy","canvasXY","clientX","cellAt","onSmiley","dx","dy","diffBarIdx","reveal","flag","di","pos","onContextMenu","onTouchStart","touch","cancelLongPress","TOUCH_CSS","savedCss","k","CELL","STEP_MS","snake","COLS","ROWS","OFFSET_X","OFFSET_Y","body","pendingDir","apple","score","over","acc","placeApple","p","reset","setDir","head","nx","ny","tick","SWIPE_MIN","touchStartX","touchStartY","touchStartId","onTouchEnd","end","adx","ady","createShelf","registry","rendered","activeModal","render","shelf"],"mappings":"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"}