{"version":3,"file":"bundle.js","sources":["range.js","video.js","index.js"],"sourcesContent":["export const GRID_LEN = 13;\nconst NUM_GRID_BYTES = 22; // ceil((13 * 13) / 8)\n\nfunction isSet(grid, row, col) {\n const bitIdx = row * GRID_LEN + col;\n return (grid[bitIdx >> 3] >> (7 - (bitIdx & 7))) & 1;\n}\n\nfunction set(grid, row, col) {\n const bitIdx = row * GRID_LEN + col;\n grid[bitIdx >> 3] |= 1 << (7 - (bitIdx & 7));\n}\n\nfunction unset(grid, row, col) {\n const bitIdx = row * GRID_LEN + col;\n grid[bitIdx >> 3] &= ~(1 << (7 - (bitIdx & 7)));\n}\n\nexport function newRangeState() {\n return {\n isMouseDown: false,\n clickBtnIsActive: false,\n handsSelected: 0,\n grid: new Uint8Array(NUM_GRID_BYTES),\n style: null,\n frozen: false,\n };\n}\n\nexport function decodeRangeState(encodedStr) {\n const binaryStr = atob(encodedStr);\n let arr = new Uint8Array(NUM_GRID_BYTES);\n for (let i = 0; i < NUM_GRID_BYTES; i++) {\n arr[i] = binaryStr.charCodeAt(i);\n }\n return arr;\n}\n\nexport function mouseOver(state, e, submitBtn) {\n if (!state.frozen && state.isMouseDown && e.target.tagName === \"BUTTON\") {\n actuateRangeBtn(state, e.target, submitBtn);\n }\n}\n\nexport function mouseDown(state, e, submitBtn) {\n if (!state.frozen && e.target.tagName === \"BUTTON\") {\n state.isMouseDown = true;\n\n let row = Number(e.target.dataset.row);\n let col = Number(e.target.dataset.col);\n state.clickBtnIsActive = isSet(state.grid, row, col);\n actuateRangeBtn(state, e.target, submitBtn);\n }\n}\n\nexport function actuateRangeBtn(state, b, submitBtn) {\n let row = Number(b.dataset.row);\n let col = Number(b.dataset.col);\n\n if (isSet(state.grid, row, col) !== state.clickBtnIsActive) {\n return;\n }\n\n let hand = b.dataset.hand;\n state.style[hand].forEach((c) => {\n b.classList.toggle(c);\n });\n\n if (state.clickBtnIsActive) {\n unset(state.grid, row, col);\n state.handsSelected--;\n } else {\n set(state.grid, row, col);\n state.handsSelected++;\n }\n\n submitBtn.disabled = state.handsSelected === 0;\n}\n\nfunction toggleStyles(state, btn) {\n state.style[btn.dataset.hand].forEach((c) => {\n btn.classList.toggle(c);\n });\n}\n\nexport function resetRange(state, rangeBtns, submitBtn) {\n for (let i = 0; i < GRID_LEN; i++) {\n for (let j = 0; j < GRID_LEN; j++) {\n if (isSet(state.grid, i, j)) {\n toggleStyles(state, rangeBtns[i][j]);\n }\n }\n }\n state.grid.fill(0);\n state.handsSelected = 0;\n submitBtn.disabled = true;\n}\n\nexport function fillRange(state, rangeBtns, submitBtn, newGrid) {\n let numSelected = 0;\n for (let i = 0; i < GRID_LEN; i++) {\n for (let j = 0; j < GRID_LEN; j++) {\n if (isSet(newGrid, i, j)) {\n numSelected++;\n if (!isSet(state.grid, i, j)) {\n toggleStyles(state, rangeBtns[i][j]);\n }\n } else {\n if (isSet(state.grid, i, j)) {\n toggleStyles(state, rangeBtns[i][j]);\n }\n }\n }\n }\n state.grid = newGrid;\n state.handsSelected = numSelected;\n submitBtn.disabled = false;\n}\n","const TWO_PI = 2 * Math.PI;\nconst FPS = 30;\nconst ASPECT_VIDEO = 16 / 9;\n\nconst TEXT_COLOR = \"#000000\";\n\nconst BOX_W_HALF = 0.095;\nconst BOX_H_HALF = 0.052;\nconst BOX_W_SIXTH = 0.014;\n// const AVG_BOX_W = 0.2\n// const AVG_BOX_H = 0.1\n// const BOX_W_HALF = 0.2 / 2;\n// const BOX_H_HALF = 0.1 / 2;\n// const BOX_W_SIXTH = 0.1 / 6;\n\nexport function newVideoMask(data) {\n let mask = new Map();\n for (let frame in data) {\n mask.set(Number(frame), data[frame]);\n }\n return mask;\n}\n\nexport function calcVideoArea(width, height) {\n const videoWidth = height * ASPECT_VIDEO;\n return {\n width: videoWidth,\n height: height,\n xOffset: (width - videoWidth) / 2,\n };\n}\n\nexport function isNear(f1, f2, epsilon = 0.001) {\n return Math.abs(f2 - f1) < epsilon;\n}\n\nexport function drawBoxesAfterSeek(ctx, player, time, handCtx) {\n setTimeout(() => {\n if (isNear(time, player.getCurrentTime())) {\n drawBoxes(ctx, time, handCtx);\n }\n }, 250);\n}\n\nfunction drawPlayerIndicator(ctx, x, y, size, color, letter) {\n x = x - size / 2;\n y = y + size;\n const radius = size / 3;\n\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.arc(x, y, radius, 0, TWO_PI);\n ctx.fill();\n\n ctx.strokeStyle = TEXT_COLOR;\n ctx.lineWidth = radius / 8;\n ctx.beginPath();\n ctx.arc(x, y, radius, 0, TWO_PI);\n ctx.stroke();\n\n const fontSize = Math.round(radius * 1.2);\n ctx.font = `bold ${fontSize}px Arial`;\n ctx.fillStyle = TEXT_COLOR;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(letter, x, y + 1);\n}\n\nexport function drawBoxesForFrame(ctx, frameNum, handCtx) {\n if (!handCtx.mask.has(frameNum)) return;\n\n for (const box of handCtx.mask.get(frameNum)) {\n // Initial box.pos values are screen percentages\n let [x1, y1, x2, y2] = box.pos;\n const w = x2 - x1;\n const h = y2 - y1;\n\n let blockHeight = Math.max(BOX_H_HALF, h / 2) * handCtx.videoArea.height;\n let blockWidth;\n if (box.id === handCtx.hero.id) {\n blockWidth = Math.max(BOX_W_SIXTH, w / 6) * handCtx.videoArea.width;\n } else {\n blockWidth = Math.max(BOX_W_HALF, w / 2) * handCtx.videoArea.width;\n }\n\n // x2, y1 // top right corner\n x2 = x2 * handCtx.videoArea.width + handCtx.videoArea.xOffset;\n y1 *= handCtx.videoArea.height;\n\n if (box.id === handCtx.hero.id) {\n x1 = x1 * handCtx.videoArea.width + handCtx.videoArea.xOffset;\n drawPlayerIndicator(ctx, x1, y1, blockHeight, handCtx.hero.color, \"H\");\n } else if (box.id === handCtx.villian.id) {\n x1 = x1 * handCtx.videoArea.width + handCtx.videoArea.xOffset;\n drawPlayerIndicator(ctx, x1, y1, blockHeight, handCtx.villian.color, \"V\");\n }\n\n ctx.fillStyle = handCtx.clip.color;\n ctx.beginPath();\n ctx.roundRect(x2 - blockWidth, y1, blockWidth, blockHeight, [3]);\n ctx.fill();\n }\n}\n\nexport function drawDoubleBoxes(ctx, t0, t1, handCtx) {\n const frame0 = Math.floor(t0 * FPS);\n const frame1 = Math.floor(t1 * FPS);\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n\n drawBoxesForFrame(ctx, frame0 - 1, handCtx);\n drawBoxesForFrame(ctx, frame0, handCtx);\n drawBoxesForFrame(ctx, frame0 + 1, handCtx);\n\n drawBoxesForFrame(ctx, frame1 - 1, handCtx);\n drawBoxesForFrame(ctx, frame1, handCtx);\n drawBoxesForFrame(ctx, frame1 + 1, handCtx);\n}\n\nexport function drawBoxes(ctx, time, handCtx) {\n const frameNum = Math.floor(time * FPS);\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n ctx.fillStyle = handCtx.clip.color;\n\n drawBoxesForFrame(ctx, frameNum - 1, handCtx);\n drawBoxesForFrame(ctx, frameNum, handCtx);\n drawBoxesForFrame(ctx, frameNum + 1, handCtx);\n}\n\nexport function togglePlayback(video, handCtx) {\n console.debug(\"togglePlayback\");\n if (video.playing) {\n video.player.pauseVideo();\n } else {\n if (video.player.getCurrentTime() < handCtx.quizTime) {\n video.player.playVideo();\n }\n }\n}\n\nfunction constrain(value, min, max) {\n return Math.min(Math.max(value, min), max);\n}\n\nexport function skipTime(ctx, player, handCtx, skipSeconds) {\n let currentTime = player.getCurrentTime();\n let seekTime = constrain(\n currentTime + skipSeconds,\n handCtx.clip.start,\n handCtx.quizTime,\n );\n if (isNear(seekTime, currentTime)) return;\n\n drawDoubleBoxes(ctx, currentTime, seekTime, handCtx);\n player.seekTo(seekTime, true);\n drawBoxesAfterSeek(ctx, player, seekTime, handCtx);\n}\n","import {\n GRID_LEN,\n decodeRangeState,\n newRangeState,\n mouseDown,\n mouseOver,\n resetRange,\n fillRange,\n} from \"./range.js\";\n\nimport {\n newVideoMask,\n isNear,\n drawBoxes,\n drawDoubleBoxes,\n drawBoxesAfterSeek,\n togglePlayback,\n skipTime,\n calcVideoArea,\n} from \"./video.js\";\n\nfunction onDOMLoad() {\n resetRange(rangeState, rangeBtns, submitBtn);\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key === \"t\") {\n toggleVisible(\"transcript-body\");\n } else if (event.key === \"r\") {\n toggleRange();\n } else if (event.key === \"h\") {\n toggleHidden(modals.howTo);\n } else if (event.key === \"Escape\") {\n hideTarget(modals.howTo);\n hideTarget(modals.about);\n hideTarget(modals.guessRange);\n }\n });\n}\n\nfunction hideTarget(targetId) {\n document.getElementById(targetId).classList.add(\"hidden\");\n}\n\nfunction showTarget(targetId) {\n document.getElementById(targetId).classList.remove(\"hidden\");\n}\n\nfunction toggleHidden(targetId) {\n document.getElementById(targetId).classList.toggle(\"hidden\");\n}\n\nfunction toggleVisible(targetId) {\n document.getElementById(targetId).classList.toggle(\"invisible\");\n}\n\nwindow.hideTarget = hideTarget;\nwindow.showTarget = showTarget;\nwindow.toggleHidden = toggleHidden;\nwindow.toggleVisible = toggleVisible;\n\nconst modals = {\n howTo: \"how-to-modal\",\n about: \"about-modal\",\n guessRange: \"guess-range-modal\",\n};\n\n//\n// range.js\n//\n\nconst correctHandCss = [\n \"border-2\",\n \"md:border-3\",\n \"lg:border-4\",\n \"border-green-600\",\n];\n\n// Handle mouse events for drag behavior\nconst rangeGridEl = document.getElementById(\"range-grid\");\n\nlet rangeState = newRangeState();\nrangeState.style = JSON.parse(rangeGridEl.dataset.style);\nwindow.rangeState = rangeState;\n\nrangeGridEl.addEventListener(\"mousedown\", (event) => {\n mouseDown(rangeState, event, submitBtn);\n});\n\nrangeGridEl.addEventListener(\"mouseover\", (event) => {\n mouseOver(rangeState, event, submitBtn);\n});\n\nrangeGridEl.addEventListener(\"mouseup\", () => {\n rangeState.isMouseDown = false;\n});\n\nrangeGridEl.addEventListener(\"mouseleave\", () => {\n rangeState.isMouseDown = false;\n});\n\nfunction initRangeBtns() {\n let btns = [];\n for (let row = 0; row < GRID_LEN; row++) {\n btns[row] = [];\n for (let col = 0; col < GRID_LEN; col++) {\n btns[row][col] = document.getElementById(\"pair-\" + row + \"-\" + col);\n }\n }\n return btns;\n}\nconst rangeBtns = initRangeBtns();\n\nconst toggleRangeBtn = document.getElementById(\"range-toggle\");\nconst rangeToolsEl = document.getElementById(\"range-tools\");\nconst resetRangeBtn = document.getElementById(\"range-reset\");\nconst fillRangeBtn = document.getElementById(\"range-fill\");\n\nfunction toggleRange() {\n rangeGridEl.classList.toggle(\"invisible\");\n if (!rangeState.frozen) {\n rangeToolsEl.classList.toggle(\"hidden\");\n }\n}\n\nfunction freezeRange() {\n rangeToolsEl.classList.add(\"hidden\");\n rangeState.frozen = true;\n}\n\nwindow.toggleRange = toggleRange;\nwindow.resetRange = () => {\n resetRange(rangeState, rangeBtns, submitBtn);\n};\nwindow.fillRange = () => {\n const newGrid = decodeRangeState(rangeGridEl.dataset.fill20);\n fillRange(rangeState, rangeBtns, submitBtn, newGrid);\n};\n\nconst submitBtn = document.getElementById(\"range-submit\");\n\nfunction uint8ArrayToBitString(uint8Array) {\n let bitString = \"\";\n for (let i = 0; i < uint8Array.length; i++) {\n const byte = uint8Array[i];\n for (let bit = 7; bit >= 0; bit--) {\n const bitValue = (byte >> bit) & 1;\n bitString += bitValue;\n }\n }\n return bitString;\n}\n\nfunction getSubmissionData() {\n return {\n clip: handCtx.clip.id,\n cards: handCtx.villian.cards,\n answer: btoa(String.fromCharCode.apply(null, rangeState.grid)),\n };\n}\n\nfunction onSubmission() {\n freezeRange();\n}\n\nfunction onSubmissionResult() {\n // Hide submit button and range tools\n submitBtn.classList.add(\"hidden\");\n rangeToolsEl.classList.add(\"hidden\");\n\n // Show result\n document.getElementById(\"villian-cards\").classList.remove(\"hidden\");\n\n // NEXT STEPS:\n // Remove correctHandCss classes when \"next\" button is clicked\n const { row, col } = handCtx.villian.cardCoords;\n rangeBtns[row][col].classList.add(...correctHandCss);\n}\n\nwindow.getSubmissionData = getSubmissionData;\nwindow.onSubmission = onSubmission;\nwindow.onSubmissionResult = onSubmissionResult;\n\n//\n// video.js\n//\n\nlet playerAreaEl = document.getElementById(\"player-area\");\nlet playerClickHandler = document.getElementById(\"player-click-handler\");\n\nlet canvas = document.getElementById(\"hand-block\");\nlet ctx = canvas.getContext(\"2d\");\n\nlet handCtx = (function () {\n let tmp = document.getElementById(\"hand-data\");\n let data = JSON.parse(tmp.textContent);\n tmp.remove();\n\n const rect = playerAreaEl.getBoundingClientRect();\n\n return {\n clip: data.clip,\n mask: newVideoMask(data.mask),\n videoArea: calcVideoArea(rect.width, rect.height),\n hero: data.hero,\n villian: data.villian,\n quizTime: data.quizTime,\n };\n})();\n\nconsole.assert(handCtx.mask.size > 0, \"%o\", {\n clip: handCtx.clip,\n msg: \"hand mask is empty\",\n});\n\nlet video = {\n player: null,\n autoplaying: true,\n playing: false,\n};\n\nfunction onYouTubeIframeAPIReady() {\n video.player = new YT.Player(\"yt-player\", {\n events: {\n onReady: onPlayerReady,\n onStateChange: onPlayerStateChange,\n },\n });\n}\n// The YouTube Iframe embed API (\"https://www.youtube.com/iframe_api\") calls\n// the global function `onYouTubeIframeAPIReady` when it downloads.\nwindow.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;\n\nfunction videoControlsKeydown(event) {\n if (event.key === \"ArrowLeft\") {\n hideTarget(modals.guessRange);\n skipTime(ctx, video.player, handCtx, -5);\n } else if (event.key === \"ArrowRight\") {\n skipTime(ctx, video.player, handCtx, 5);\n } else if (event.key === \" \") {\n const activeEl = document.activeElement;\n if (\n activeEl.tagName === \"TEXTAREA\" ||\n (activeEl.tagName === \"INPUT\" && activeEl.type === \"text\")\n ) {\n return; // Allow space to function normally inside text boxes\n }\n event.preventDefault(); // Stop space from toggling buttons or scrolling the page\n togglePlayback(video, handCtx);\n }\n}\n\nfunction onPlayerReady(event) {\n video.player.mute();\n const playerState = video.player.getPlayerState();\n console.debug(`onPlayerReady: state=${playerState}`);\n if (playerState === YT.PlayerState.PLAYING) {\n console.debug(\n `onPlayerReady: Video player already playing (state=${playerState}). Pausing...`,\n );\n video.player.pauseVideo();\n video.autoplaying = false;\n }\n\n const resizeObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n const { width, height } = entry.contentRect;\n canvas.width = width;\n canvas.height = height;\n\n handCtx.videoArea = calcVideoArea(width, height);\n\n drawBoxes(ctx, video.player.getCurrentTime(), handCtx);\n }\n });\n resizeObserver.observe(playerAreaEl);\n\n playerClickHandler.addEventListener(\"click\", () => {\n togglePlayback(video, handCtx);\n });\n document.addEventListener(\"keydown\", videoControlsKeydown);\n}\n\nfunction trackPlayback() {\n let currentTime = video.player.getCurrentTime();\n drawBoxes(ctx, currentTime, handCtx);\n\n if (currentTime > handCtx.quizTime) {\n video.player.pauseVideo();\n showTarget(modals.guessRange);\n }\n\n if (video.playing) {\n requestAnimationFrame(trackPlayback);\n }\n}\n\n// NOTE: player.removeEventListener() is known to not work\nfunction onPlayerStateChange(event) {\n console.debug(`onPlayerStateChange: state=${event.data}`);\n if (video.autoplaying) {\n if (event.data == YT.PlayerState.PLAYING) {\n video.player.pauseVideo();\n video.autoplaying = false;\n }\n } else {\n if (event.data == YT.PlayerState.PLAYING) {\n video.playing = true;\n trackPlayback();\n } else {\n video.playing = false;\n }\n }\n}\n\nfunction seekToTranscriptAction(time) {\n let currentTime = video.player.getCurrentTime();\n if (!isNear(time, currentTime)) {\n drawDoubleBoxes(ctx, currentTime, time, handCtx);\n video.player.seekTo(time, true);\n drawBoxesAfterSeek(ctx, video.player, time, handCtx);\n }\n}\nwindow.seekToTranscriptAction = seekToTranscriptAction;\n\nfunction loadNextHand() {\n // Hide and reset the range\n rangeToolsEl.classList.add(\"hidden\");\n rangeGridEl.classList.add(\"invisible\");\n resetRange(rangeState, rangeBtns, submitBtn);\n\n // Remove correct hand outline from range grid\n const { row, col } = handCtx.villian.cardCoords;\n rangeBtns[row][col].classList.remove(...correctHandCss);\n\n // Unfreeze range\n rangeState.frozen = false;\n\n // Show the submit button\n submitBtn.classList.remove(\"hidden\");\n\n let tmp = document.getElementById(\"hand-data\");\n let data = JSON.parse(tmp.textContent);\n tmp.remove();\n\n video.player.loadVideoById({\n videoId: data.clip.streamHash,\n startSeconds: data.clip.start,\n endSeconds: data.clip.stop,\n });\n video.autoplaying = true;\n\n const rect = playerAreaEl.getBoundingClientRect();\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n\n handCtx = {\n clip: data.clip,\n mask: newVideoMask(data.mask),\n videoArea: calcVideoArea(rect.width, rect.height),\n hero: data.hero,\n villian: data.villian,\n quizTime: data.quizTime,\n };\n}\n\nwindow.loadNextHand = loadNextHand;\nwindow.hideVillianCards = () => {\n // NOTE: For some reason, despite having the class \"hidden\" already, the\n // \"hidden\" class is not present for a flash while the content settles.\n // Adding \"hidden\" before-on-load resolves this issue.\n document.getElementById(\"villian-cards\").classList.add(\"hidden\");\n};\n\n// TODO: Should I use window.onload or document.addEventListener(\"DOMContentLoaded\", ...)?\ndocument.addEventListener(\"DOMContentLoaded\", onDOMLoad);\n"],"names":["GRID_LEN","isSet","grid","row","col","bitIdx","actuateRangeBtn","state","b","submitBtn","Number","dataset","clickBtnIsActive","hand","style","forEach","c","classList","toggle","unset","handsSelected","set","disabled","toggleStyles","btn","resetRange","rangeBtns","i","j","fill","TWO_PI","Math","PI","ASPECT_VIDEO","TEXT_COLOR","newVideoMask","data","mask","Map","frame","calcVideoArea","width","height","videoWidth","xOffset","isNear","f1","f2","epsilon","abs","drawBoxesAfterSeek","ctx","player","time","handCtx","setTimeout","getCurrentTime","drawBoxes","drawPlayerIndicator","x","y","size","color","letter","radius","fillStyle","beginPath","arc","strokeStyle","lineWidth","stroke","fontSize","round","font","textAlign","textBaseline","fillText","drawBoxesForFrame","frameNum","has","box","get","x1","y1","x2","y2","pos","w","h","blockWidth","blockHeight","max","videoArea","id","hero","villian","clip","roundRect","drawDoubleBoxes","t0","t1","frame0","floor","frame1","clearRect","canvas","togglePlayback","video","console","debug","playing","pauseVideo","quizTime","playVideo","skipTime","skipSeconds","currentTime","seekTime","value","min","start","seekTo","hideTarget","targetId","document","getElementById","add","showTarget","remove","toggleHidden","toggleVisible","window","modals","howTo","about","guessRange","correctHandCss","rangeGridEl","rangeState","isMouseDown","Uint8Array","frozen","JSON","parse","addEventListener","event","e","target","tagName","mouseDown","mouseOver","btns","initRangeBtns","rangeToolsEl","toggleRange","fillRange","newGrid","encodedStr","binaryStr","atob","arr","charCodeAt","decodeRangeState","fill20","numSelected","getSubmissionData","cards","answer","btoa","String","fromCharCode","apply","onSubmission","onSubmissionResult","cardCoords","playerAreaEl","playerClickHandler","getContext","tmp","textContent","rect","getBoundingClientRect","assert","msg","autoplaying","videoControlsKeydown","key","activeEl","activeElement","type","preventDefault","onPlayerReady","mute","playerState","getPlayerState","YT","PlayerState","PLAYING","ResizeObserver","entries","entry","contentRect","observe","trackPlayback","requestAnimationFrame","onPlayerStateChange","onYouTubeIframeAPIReady","Player","events","onReady","onStateChange","seekToTranscriptAction","loadNextHand","loadVideoById","videoId","streamHash","startSeconds","endSeconds","stop","hideVillianCards"],"mappings":"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"}