{"id":2643,"date":"2025-07-03T13:16:31","date_gmt":"2025-07-03T11:16:31","guid":{"rendered":"https:\/\/read4more.com\/?page_id=2643"},"modified":"2025-07-12T15:56:15","modified_gmt":"2025-07-12T13:56:15","slug":"crosshair-game","status":"publish","type":"page","link":"https:\/\/read4more.com\/ar\/crosshair-game\/","title":{"rendered":"Crosshair Game"},"content":{"rendered":"\n<div class=\"wp-block-group is-layout-flow wp-block-group-is-layout-flow\">\n<!-- Recorder container + UI -->\n<div id=\"camera-container\">\n  <video id=\"videoElement\" autoplay playsinline muted><\/video>\n  <canvas id=\"outputCanvas\"><\/canvas>\n\n  <!-- hidden crosshair animation -->\n  <video\n    id=\"crosshairVid\"\n    src=\"https:\/\/read4more.com\/wp-content\/uploads\/2025\/07\/crosshair.webm\"\n    autoplay loop muted playsinline\n  ><\/video>\n\n  <!-- buttons -->\n  <div id=\"button-group\">\n    <button id=\"recordButton\">\ud83c\udfa5 Start Recording<\/button>\n    <button id=\"counterButton\">\u2705 Guess Words 0<\/button>\n  <\/div>\n\n  <!-- end-screen overlay -->\n  <div id=\"endScreen\">\n    <h1>\u23f1 Time\u2019s up!<\/h1>\n    <p>Your final score:<\/p>\n    <p><strong id=\"finalScore\">0<\/strong><\/p>\n    <button id=\"restartBtn\">\ud83d\udd04 Restart<\/button>\n  <\/div>\n<\/div>\n\n<!-- confetti lib -->\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/canvas-confetti@1.5.1\/dist\/confetti.browser.min.js\"><\/script>\n\n<!-- recorder + 10s timer + overlay + confetti logic -->\n<script>\ndocument.addEventListener('DOMContentLoaded', async () => {\n  let counter = 0,\n      mediaRecorder,\n      recordedChunks = [],\n      countdownInterval,\n      timer = 10;\n\n  const cameraVid    = document.getElementById(\"videoElement\");\n  const canvas       = document.getElementById(\"outputCanvas\");\n  const ctx          = canvas.getContext(\"2d\");\n  const crosshairVid = document.getElementById(\"crosshairVid\");\n  const recordBtn    = document.getElementById(\"recordButton\");\n  const counterBtn   = document.getElementById(\"counterButton\");\n  const endScreen    = document.getElementById(\"endScreen\");\n  const finalScoreEl = document.getElementById(\"finalScore\");\n  const restartBtn   = document.getElementById(\"restartBtn\");\n\n  \/\/ play crosshair\n  await crosshairVid.play().catch(() => {});\n\n  \/\/ open camera + mic\n  try {\n    const stream = await navigator.mediaDevices.getUserMedia({\n      video: { facingMode: \"environment\" },\n      audio: true\n    });\n    cameraVid.srcObject = stream;\n    await cameraVid.play().catch(() => {});\n  } catch (err) {\n    console.error(\"Camera error:\", err);\n    return alert(\"Could not access camera\u2014check HTTPS & permissions.\");\n  }\n\n  \/\/ size canvas to video\n  await new Promise(res => {\n    const iv = setInterval(() => {\n      if (cameraVid.videoWidth) {\n        clearInterval(iv);\n        canvas.width  = cameraVid.videoWidth;\n        canvas.height = cameraVid.videoHeight;\n        res();\n      }\n    }, 50);\n  });\n\n  \/\/ draw loop\n  (function drawFrame(){\n    ctx.drawImage(cameraVid, 0, 0, canvas.width, canvas.height);\n    const size = 100;\n    ctx.drawImage(\n      crosshairVid,\n      (canvas.width - size)\/2,\n      (canvas.height - size)\/2,\n      size, size\n    );\n    ctx.font      = \"bold 40px sans-serif\";\n    ctx.fillStyle = \"white\";\n    ctx.fillText(`Words: ${counter}`, 30, canvas.height - 40);\n    requestAnimationFrame(drawFrame);\n  })();\n\n  \/\/ counter button\n  counterBtn.addEventListener(\"click\", () => {\n    counter++;\n    counterBtn.textContent = `\u2705 Guess Words: ${counter}`;\n    confetti({ particleCount: 60, spread: 60, origin: { y: 0.6 } });\n  });\n\n  \/\/ record + 10s timer\n  recordBtn.addEventListener(\"click\", () => {\n    if (mediaRecorder && mediaRecorder.state === \"recording\") return;\n\n    recordedChunks = [];\n    counter = 0;\n    counterBtn.textContent = `\u2705 Guess Words: 0`;\n    timer = 10;\n    recordBtn.disabled = true;\n    recordBtn.textContent = `Recording: ${timer}s`;\n\n    const canvasStream = canvas.captureStream(30);\n    const micTracks    = cameraVid.srcObject.getAudioTracks();\n    mediaRecorder = new MediaRecorder(\n      new MediaStream([...canvasStream.getVideoTracks(), ...micTracks])\n    );\n    mediaRecorder.ondataavailable = e => e.data.size && recordedChunks.push(e.data);\n    mediaRecorder.start();\n\n    countdownInterval = setInterval(() => {\n      timer--;\n      if (timer > 0) {\n        recordBtn.textContent = `Recording: ${timer}s`;\n      } else {\n        clearInterval(countdownInterval);\n        mediaRecorder.stop();\n        recordBtn.textContent = `\ud83c\udfa5 Start Recording`;\n        recordBtn.disabled = false;\n\n        \/\/ show end screen\n        finalScoreEl.textContent = counter;\n        endScreen.style.display = 'flex';\n        confetti({ particleCount: 200, spread: 100, origin: { y: 0.4 } });\n\n        \/\/ auto-download\n        mediaRecorder.onstop = () => {\n          const blob = new Blob(recordedChunks, { type: \"video\/webm\" });\n          const url  = URL.createObjectURL(blob);\n          const a    = document.createElement(\"a\");\n          a.style.display = \"none\";\n          a.href     = url;\n          a.download = \"recording.webm\";\n          document.body.appendChild(a);\n          a.click();\n          URL.revokeObjectURL(url);\n        };\n      }\n    }, 1000);\n  });\n\n  \/\/ restart button\n  restartBtn.addEventListener(\"click\", () => {\n    endScreen.style.display = 'none';\n    counter = 0;\n    counterBtn.textContent = `\u2705 Guess Words: 0`;\n  });\n});\n<\/script>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>\ud83c\udfa5 Start Recording \u2705 Guess Words 0 \u23f1 Time\u2019s up! Your final score: 0 \ud83d\udd04 Restart<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-no-title","meta":{"footnotes":""},"class_list":["post-2643","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/pages\/2643","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/comments?post=2643"}],"version-history":[{"count":0,"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/pages\/2643\/revisions"}],"wp:attachment":[{"href":"https:\/\/read4more.com\/ar\/wp-json\/wp\/v2\/media?parent=2643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}