{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Tetris</title>\n<style>\n  :root {\n    --bg: #16181d;\n    --panel: #1e2127;\n    --border: #33363d;\n    --text: #e8e8ea;\n    --dim: #9a9da3;\n    --accent: #7fd66c;\n  }\n  * { margin: 0; padding: 0; box-sizing: border-box; }\n  body {\n    background: var(--bg);\n    color: var(--text);\n    font-family: \"Segoe UI\", \"Helvetica Neue\", sans-serif;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    min-height: 100vh;\n  }\n  .shell {\n    display: flex;\n    gap: 28px;\n    align-items: flex-start;\n  }\n  h1 {\n    position: absolute;\n    top: -70px;\n    left: 0;\n    right: 0;\n    text-align: center;\n    font-size: 26px;\n    font-weight: 300;\n    letter-spacing: 14px;\n    color: var(--dim);\n  }\n  .shell { position: relative; margin-top: 90px; }\n  .board-wrap { position: relative; }\n  canvas {\n    background: #101216;\n    border: 2px solid var(--border);\n    display: block;\n  }\n  #overlay {\n    position: absolute;\n    inset: 0;\n    display: none;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    background: rgba(10, 11, 13, 0.82);\n    text-align: center;\n  }\n  #overlay h2 { font-size: 22px; letter-spacing: 6px; font-weight: 400; color: #ff6b6b; }\n  #overlay p { margin-top: 10px; font-size: 12px; color: var(--dim); letter-spacing: 2px; }\n  .side {\n    background: var(--panel);\n    border: 1px solid var(--border);\n    padding: 16px 20px;\n    min-width: 150px;\n  }\n  .side h3 {\n    font-size: 10px;\n    font-weight: 600;\n    letter-spacing: 3px;\n    color: var(--dim);\n    text-transform: uppercase;\n    margin-bottom: 8px;\n  }\n  .side .value { font-size: 20px; font-weight: 300; }\n  .stats .row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 14px; gap: 16px; }\n  .stats .row:last-child { margin-bottom: 0; }\n  .keys { font-size: 11px; color: var(--dim); line-height: 1.9; }\n  .keys b { color: var(--text); font-weight: 600; }\n</style>\n</head>\n<body>\n<div class=\"shell\">\n  <h1>T E T R I S</h1>\n  <div class=\"board-wrap\">\n    <canvas id=\"board\" width=\"300\" height=\"600\"></canvas>\n    <div id=\"overlay\"><h2>GAME OVER</h2><p>PRESS R TO RESTART</p></div>\n  </div>\n  <div class=\"side\">\n    <div class=\"stats\">\n      <div class=\"row\"><h3>Score</h3><span class=\"value\" id=\"score\">0</span></div>\n      <div class=\"row\"><h3>Lines</h3><span class=\"value\" id=\"lines\">0</span></div>\n      <div class=\"row\"><h3>Level</h3><span class=\"value\" id=\"level\">1</span></div>\n    </div>\n  </div>\n  <div class=\"side\">\n    <h3>Next</h3>\n    <canvas id=\"next\" width=\"90\" height=\"90\"></canvas>\n  </div>\n  <div class=\"side keys\">\n    <h3>Controls</h3>\n    <div><b>\u2190\u2192</b> move</div>\n    <div><b>\u2191</b> rotate</div>\n    <div><b>\u2193</b> soft drop</div>\n    <div><b>Space</b> hard drop</div>\n    <div><b>P</b> pause &nbsp; <b>R</b> restart</div>\n  </div>\n</div>\n\n<script>\nconst COLS = 10, ROWS = 20, CELL = 30;\nconst cv = document.getElementById('board'), ctx = cv.getContext('2d');\nconst nc = document.getElementById('next'), nctx = nc.getContext('2d');\nconst scoreEl = document.getElementById('score'), linesEl = document.getElementById('lines'),\n      levelEl = document.getElementById('level'), overlay = document.getElementById('overlay');\n\nconst COLORS = { I:'#4fc3f7', O:'#ffd54f', T:'#b39ddb', S:'#7fd66c', Z:'#ff6b6b', J:'#5c8bff', L:'#ffb36b' };\nconst SHAPES = {\n  I: [[1,0],[1,0],[1,0],[1,0]],\n  O: [[1,1],[1,1]],\n  T: [[0,1,0],[1,1,1]],\n  S: [[0,1,1],[1,1,0]],\n  Z: [[1,1,0],[0,1,1]],\n  J: [[1,0],[1,0],[1,1]],\n  L: [[0,1],[0,1],[1,1]],\n};\nconst ORDER = ['I','O','T','S','Z','J','L'];\n\nlet grid, piece, nextPiece, score, lines, level, dropTimer, dropInterval, lastTime, gameOver, paused;\n\nfunction makePiece(type) {\n  return { type, cells: SHAPES[type].map(r=>r.slice()), x: 0, y: 0 };\n}\nfunction spawn() {\n  piece = nextPiece || makePiece(ORDER[Math.floor(Math.random()*7)]);\n  nextPiece = makePiece(ORDER[Math.floor(Math.random()*7)]);\n  piece.x = Math.floor((COLS - piece.cells[0].length) / 2);\n  piece.y = piece.type === 'I' ? 0 : 1;\n  if (collide(piece.cells, piece.x, piece.y)) gameOver = true;\n  drawNext();\n}\n\nfunction collide(cells, x, y) {\n  for (let r=0; r<cells.length; r++)\n    for (let c=0; c<cells[r].length; c++) {\n      if (!cells[r][c]) continue;\n      const gx = x+c, gy = y+r;\n      if (gx < 0 || gx >= COLS || gy >= ROWS) return true;\n      if (gy >= 0 && grid[gy][gx]) return true;\n    }\n  return false;\n}\n\nfunction rotate() {\n  const rows = piece.cells.length, cols = piece.cells[0].length;\n  const rot = [];\n  for (let c=0; c<cols; c++) { rot.push([]); for (let r=rows-1; r>=0; r--) rot[c].push(piece.cells[r][c]); }\n  // try offsets 0, -1, +1, -2, +2 for wall/floor kicks\n  for (const dx of [0,-1,1,-2,2]) {\n    if (!collide(rot, piece.x+dx, piece.y)) {\n      piece.cells = rot; piece.x += dx;\n      return;\n    }\n  }\n}\n\nfunction hardDrop() {\n  while (!collide(piece.cells, piece.x, piece.y+1)) piece.y++;\n  lock();\n}\nfunction lock() {\n  for (let r=0; r<piece.cells.length; r++)\n    for (let c=0; c<piece.cells[r].length; c++)\n      if (piece.cells[r][c]) {\n        const gy = piece.y+r;\n        if (gy < 0) { gameOver = true; return; }\n        grid[gy][piece.x+c] = COLORS[piece.type];\n      }\n  // clear lines\n  let cleared = 0;\n  for (let r=ROWS-1; r>=0; r--) {\n    if (grid[r].every(v => v)) {\n      grid.splice(r,1); grid.unshift(Array(COLS).fill(0));\n      cleared++;\n    }\n  }\n  if (cleared) {\n    score += [0,100,300,600,1000][cleared] * level;\n    lines += cleared;\n    level = Math.floor(lines/10)+1;\n    dropInterval = Math.max(60, 600 - (level-1)*55);\n    updateUI();\n  }\n  spawn();\n}\n\nfunction updateUI() {\n  scoreEl.textContent = score; linesEl.textContent = lines; levelEl.textContent = level;\n}\n\nfunction draw() {\n  ctx.fillStyle = '#101216';\n  ctx.fillRect(0,0,cv.width,cv.height);\n  // grid lines\n  ctx.strokeStyle = '#1c1f24';\n  for (let i=0;i<=COLS;i++) { ctx.beginPath(); ctx.moveTo(i*CELL,0); ctx.lineTo(i*CELL,cv.height); ctx.stroke(); }\n  for (let i=0;i<=ROWS;i++) { ctx.beginPath(); ctx.moveTo(0,i*CELL); ctx.lineTo(cv.width,i*CELL); ctx.stroke(); }\n  // locked blocks\n  for (let r=0;r<ROWS;r++) for (let c=0;c<COLS;c++)\n    if (grid[r][c]) drawCell(c,r,grid[r][c]);\n  // ghost (hard-drop preview)\n  if (!gameOver) {\n    let gy = piece.y;\n    while (!collide(piece.cells, piece.x, gy+1)) gy++;\n    if (gy > piece.y) {\n      ctx.strokeStyle = piece.cells[0].some(()=>true) ? 'rgba(255,255,255,0.08)' : '';\n      for (let r=0;r<piece.cells.length;r++) for (let c=0;c<piece.cells[r].length;c++)\n        if (piece.cells[r][c]) strokeCell(piece.x+c, gy+r);\n    }\n    // active piece\n    for (let r=0;r<piece.cells.length;r++) for (let c=0;c<piece.cells[r].length;c++)\n      if (piece.cells[r][c] && piece.y+r >= 0) drawCell(piece.x+c, piece.y+r, COLORS[piece.type]);\n  }\n}\nfunction drawCell(x,y,color) {\n  ctx.fillStyle = color;\n  ctx.fillRect(x*CELL+2, y*CELL+2, CELL-4, CELL-4);\n  ctx.strokeStyle = 'rgba(0,0,0,0.35)';\n  ctx.strokeRect(x*CELL+2.5, y*CELL+2.5, CELL-5, CELL-5);\n}\nfunction strokeCell(x,y) {\n  ctx.strokeStyle = 'rgba(255,255,255,0.12)';\n  ctx.strokeRect(x*CELL+4, y*CELL+4, CELL-8, CELL-8);\n}\n\nfunction drawNext() {\n  nctx.clearRect(0,0,nc.width,nc.height);\n  const p = nextPiece, size = p.cells.length > 3 ? 18 : 24;\n  const w = p.cells[0].length, h = p.cells.length;\n  const ox = (nc.width - w*size)/2, oy = (nc.height - h*size)/2;\n  for (let r=0;r<h;r++) for (let c=0;c<w;c++)\n    if (p.cells[r][c]) {\n      nctx.fillStyle = COLORS[p.type];\n      nctx.fillRect(ox+c*size+1, oy+r*size+1, size-2, size-2);\n    }\n}\n\nfunction reset() {\n  grid = Array.from({length:ROWS},()=>Array(COLS).fill(0));\n  score = 0; lines = 0; level = 1; dropInterval = 600;\n  dropTimer = 0; lastTime = performance.now();\n  gameOver = false; paused = false;\n  overlay.style.display = 'none';\n  nextPiece = null; spawn();\n  updateUI();\n}\n\ndocument.addEventListener('keydown', e => {\n  if (e.key === 'r' || e.key === 'R') { reset(); return; }\n  if (gameOver) return;\n  if (e.key === 'p' || e.key === 'P') { paused = !paused; return; }\n  if (paused || gameOver) return;\n  switch (e.key) {\n    case 'ArrowLeft':\n      if (!collide(piece.cells, piece.x-1, piece.y)) piece.x--; e.preventDefault(); break;\n    case 'ArrowRight':\n      if (!collide(piece.cells, piece.x+1, piece.y)) piece.x++; e.preventDefault(); break;\n    case 'ArrowUp':\n      rotate(); e.preventDefault(); break;\n    case 'ArrowDown':\n      if (!collide(piece.cells, piece.x, piece.y+1)) piece.y++; e.preventDefault(); break;\n    case ' ':\n      hardDrop(); e.preventDefault(); break;\n  }\n});\n\nfunction loop(t) {\n  const dt = t - lastTime;\n  lastTime = t;\n  if (!gameOver && !paused) {\n    dropTimer += dt;\n    if (dropTimer > dropInterval) {\n      dropTimer = 0;\n      if (collide(piece.cells, piece.x, piece.y+1)) lock();\n      else piece.y++;\n    }\n  }\n  draw();\n  if (gameOver) {\n    overlay.style.display = 'flex';\n    overlay.querySelector('h2').textContent = 'GAME OVER';\n  }\n  requestAnimationFrame(loop);\n}\n\nreset();\nrequestAnimationFrame(loop);\n</script>\n</body>\n</html>\n```"
      }
    }
  ],
  "created": 1788534008,
  "model": "~/.cache/huggingface/hub/models--unsloth--GLM-5.3-Flash-GGUF/snapshots/ac47690c15c8703615ab7d9c1ef2293d45372757/UD-IQ1_S/GLM-5.3-Flash-UD-IQ1_S-00001-of-00003.gguf",
  "system_fingerprint": "b1-1f0a36a",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 3037,
    "prompt_tokens": 201,
    "total_tokens": 3238,
    "prompt_tokens_details": {
      "cached_tokens": 9
    }
  },
  "id": "chatcmpl-uEgC6ruimsoRzY3c7z7YzCdEEQBtS1JJ",
  "timings": {
    "cache_n": 9,
    "prompt_n": 192,
    "prompt_ms": 4255.645,
    "prompt_per_token_ms": 22.164817708333334,
    "prompt_per_second": 45.116545200551265,
    "predicted_n": 3037,
    "predicted_ms": 316706.983,
    "predicted_per_token_ms": 104.31718807641634,
    "predicted_per_second": 9.586147963147374
  }
}