diff options
| author | LLLL Colonq <llll@colonq> | 2026-07-17 03:10:43 -0400 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2026-07-17 03:10:43 -0400 |
| commit | 07a36f2b38a5cba402ebc5158710f5a85f443456 (patch) | |
| tree | f28855384eadc73f49cc1a707a73896f87bc5530 /2026/games/gbjk | |
| parent | 951b316773265052fbc5fa546bbcf31bef277062 (diff) | |
Post-stream update
Diffstat (limited to '2026/games/gbjk')
| -rw-r--r-- | 2026/games/gbjk/LICENSE | 21 | ||||
| -rw-r--r-- | 2026/games/gbjk/index.html | 456 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/.gitignore | 24 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/index.html | 12 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/package.json | 16 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/pnpm-lock.yaml | 568 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/src/main.ts | 33 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/src/setup.ts | 389 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/src/style.css | 103 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/tsconfig.json | 23 | ||||
| -rw-r--r-- | 2026/games/gbjk/src/vite.config.ts | 9 |
11 files changed, 0 insertions, 1654 deletions
diff --git a/2026/games/gbjk/LICENSE b/2026/games/gbjk/LICENSE deleted file mode 100644 index 14fac91..0000000 --- a/2026/games/gbjk/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/2026/games/gbjk/index.html b/2026/games/gbjk/index.html deleted file mode 100644 index 0e43bab..0000000 --- a/2026/games/gbjk/index.html +++ /dev/null @@ -1,456 +0,0 @@ -<!doctype html> -<html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>tortis</title> - <script type="module" crossorigin>//#region \0vite/modulepreload-polyfill.js -(function polyfill() { - const relList = document.createElement("link").relList; - if (relList && relList.supports && relList.supports("modulepreload")) return; - for (const link of document.querySelectorAll("link[rel=\"modulepreload\"]")) processPreload(link); - new MutationObserver((mutations) => { - for (const mutation of mutations) { - if (mutation.type !== "childList") continue; - for (const node of mutation.addedNodes) if (node.tagName === "LINK" && node.rel === "modulepreload") processPreload(node); - } - }).observe(document, { - childList: true, - subtree: true - }); - function getFetchOpts(link) { - const fetchOpts = {}; - if (link.integrity) fetchOpts.integrity = link.integrity; - if (link.referrerPolicy) fetchOpts.referrerPolicy = link.referrerPolicy; - if (link.crossOrigin === "use-credentials") fetchOpts.credentials = "include"; - else if (link.crossOrigin === "anonymous") fetchOpts.credentials = "omit"; - else fetchOpts.credentials = "same-origin"; - return fetchOpts; - } - function processPreload(link) { - if (link.ep) return; - link.ep = true; - const fetchOpts = getFetchOpts(link); - fetch(link.href, fetchOpts); - } -})(); -//#endregion -//#region src/setup.ts -var WIDTH = 160; -var HEIGHT = 240; -var GRID_HEIGHT = HEIGHT - 10; -var ROWS = 15; -var COLS = 10; -var GRID_WIDTH = GRID_HEIGHT / ROWS * 10; -var GRID_X = 5; -var GRID_Y = 5; -var MARGIN = 2; -var CELL_WIDTH = GRID_HEIGHT / ROWS - MARGIN; -var FALLTIME = 600; -var MIN_FALLTIME = 300; -var rotation = 0; -var board = []; -function resetBoard() { - board.length = 0; - for (let height = 0; height < ROWS; height++) { - const row = []; - for (let width = 0; width < COLS; width++) row.push("void"); - board.push(row); - } -} -resetBoard(); -function random(elements) { - return elements[Math.floor(Math.random() * elements.length)]; -} -var addedShapeNumber = 1; -function addSquares() { - const color = random([ - "fallingRed", - "fallingGreen", - "fallingBlue" - ]); - let w = COLS / 2; - let h = 1; - for (let i = 0; i < 4; i++) { - board[h][w] = color; - if (i === 3) break; - let move = null; - let j = 0; - for (; j < 20; j++) { - move = addedShapeNumber % 6 === 0 ? "down" : random([ - "up", - "down", - "left", - "right" - ]); - if (move === "up" && (h === 0 || board[h - 1][w] !== "void")) continue; - if (move === "down" && (h === ROWS - 1 || board[h + 1][w] !== "void")) continue; - if (move === "left" && (w === 0 || board[h][w - 1] !== "void")) continue; - if (move === "right" && (w === COLS - 1 || board[h][w + 1] !== "void")) continue; - break; - } - if (j === 20) return false; - switch (move) { - case "up": - h--; - break; - case "down": - h++; - break; - case "left": - w--; - break; - case "right": - w++; - break; - } - } - addedShapeNumber++; - return true; -} -function clearFilledRows() { - let lastClearedRow = ROWS; - let clearedRows = 0; - for (let row = ROWS - 1; row >= 0; row--) if (!board[row].some((cell) => cell === "void" || cell === "fallingBlue" || cell === "fallingGreen" || cell === "fallingRed")) { - for (let col = 0; col < COLS; col++) board[row][col] = "void"; - lastClearedRow = row; - clearedRows++; - } else if (lastClearedRow !== ROWS) for (let col = 0; col < COLS; col++) switch (board[row][col]) { - case "red": - board[row][col] = "fallingRed"; - break; - case "green": - board[row][col] = "fallingGreen"; - break; - case "blue": - board[row][col] = "fallingBlue"; - break; - } - return clearedRows; -} -function setup(elements) { - const ctx = elements.main.getContext("2d"); - let gameRunning = false; - let animationFrameId = null; - let lastFrame = 0; - let fallTime = FALLTIME; - let speedUpPressed = false; - elements.left.addEventListener("click", () => moveFalling("left")); - elements.right.addEventListener("click", () => moveFalling("right")); - elements.rotateLeft.addEventListener("click", () => { - if (!gameRunning) return; - rotation -= 30 * Math.random(); - elements.main.style.transform = `rotate(${rotation}deg)`; - }); - elements.rotateRight.addEventListener("click", () => { - if (!gameRunning) return; - rotation += 30 * Math.random(); - elements.main.style.transform = `rotate(${rotation}deg)`; - }); - elements.speedUp.addEventListener("mousedown", () => speedUpPressed = gameRunning); - elements.speedUp.addEventListener("mouseup", () => speedUpPressed = false); - window.addEventListener("message", (ev) => { - const message = ev.data; - if (!isStartMessage(message)) return; - startGame(message.difficulty); - }); - window.parent.postMessage({ op: "ready" }, "*"); - draw(); - function isStartMessage(message) { - if (typeof message !== "object" || message === null) return false; - const candidate = message; - return candidate.op === "start" && typeof candidate.difficulty === "number" && Number.isFinite(candidate.difficulty); - } - function resetGame(difficulty) { - resetBoard(); - addedShapeNumber = 1; - fallTime = Math.max(MIN_FALLTIME, FALLTIME - Math.max(0, difficulty) * 5); - rotation = 0; - elements.main.style.transform = ""; - speedUpPressed = false; - lastFrame = 0; - } - function startGame(difficulty) { - if (animationFrameId !== null) { - cancelAnimationFrame(animationFrameId); - animationFrameId = null; - } - resetGame(difficulty); - gameRunning = true; - window.parent.postMessage({ - op: "started", - verb: "catch!" - }, "*"); - animationFrameId = requestAnimationFrame(gameLoop); - } - function finishGame(win) { - if (!gameRunning) return; - gameRunning = false; - if (animationFrameId !== null) { - cancelAnimationFrame(animationFrameId); - animationFrameId = null; - } - window.parent.postMessage({ - op: "done", - win - }, "*"); - resetGame(0); - draw(); - } - function moveFalling(move) { - if (!gameRunning) return; - switch (move) { - case "left": - for (let row = 0; row < ROWS; row++) for (let col = 0; col < COLS - 1; col++) if (board[row][col] === "void") switch (board[row][col + 1]) { - case "fallingRed": - case "fallingGreen": - case "fallingBlue": - board[row][col] = board[row][col + 1]; - board[row][col + 1] = "void"; - } - break; - case "right": - for (let row = 0; row < ROWS; row++) for (let col = COLS - 1; col > 0; col--) if (board[row][col] === "void") switch (board[row][col - 1]) { - case "fallingRed": - case "fallingGreen": - case "fallingBlue": - board[row][col] = board[row][col - 1]; - board[row][col - 1] = "void"; - } - break; - } - } - function physics() { - let somethingFell = false; - for (let row = ROWS - 1; row >= 1; row--) for (let col = 0; col < COLS; col++) { - let space = board[row][col]; - let above = board[row - 1][col]; - switch (above) { - case "fallingRed": - case "fallingGreen": - case "fallingBlue": if (space === "void") { - somethingFell = true; - board[row][col] = board[row - 1][col]; - board[row - 1][col] = "void"; - } else switch (above) { - case "fallingRed": - board[row - 1][col] = "red"; - break; - case "fallingGreen": - board[row - 1][col] = "green"; - break; - case "fallingBlue": - board[row - 1][col] = "blue"; - break; - } - } - } - for (let col = 0; col < COLS; col++) switch (board[ROWS - 1][col]) { - case "fallingRed": - board[ROWS - 1][col] = "red"; - break; - case "fallingGreen": - board[ROWS - 1][col] = "green"; - break; - case "fallingBlue": - board[ROWS - 1][col] = "blue"; - break; - } - return somethingFell; - } - function draw() { - ctx.clearRect(0, 0, WIDTH, HEIGHT); - ctx.fillStyle = "black"; - ctx.fillRect(GRID_X, GRID_Y, GRID_WIDTH, GRID_HEIGHT); - for (let h = 0; h < ROWS; h++) for (let w = 0; w < COLS; w++) { - switch (board[h][w]) { - case "void": - ctx.fillStyle = "#2e2e2e"; - break; - case "red": - ctx.fillStyle = "#994444"; - break; - case "green": - ctx.fillStyle = "#449944"; - break; - case "blue": - ctx.fillStyle = "#444499"; - break; - case "fallingRed": - ctx.fillStyle = "#bb3333"; - break; - case "fallingGreen": - ctx.fillStyle = "#33bb33"; - break; - case "fallingBlue": - ctx.fillStyle = "#3333bb"; - break; - } - const x = 8 + w * CELL_WIDTH + (w - 1) * MARGIN; - const y = 8 + h * CELL_WIDTH + (h - 1) * MARGIN; - ctx.fillRect(x, y, CELL_WIDTH, CELL_WIDTH); - } - } - function gameLoop(time) { - animationFrameId = null; - if (!gameRunning) return; - if (time - lastFrame > (speedUpPressed ? fallTime / 10 : fallTime)) { - lastFrame = time; - if (!physics()) { - const clearedRows = clearFilledRows(); - if (clearedRows >= 4) { - finishGame(true); - return; - } else if (clearedRows === 0) { - if (!addSquares()) { - finishGame(false); - return; - } - } - } - } - draw(); - animationFrameId = requestAnimationFrame(gameLoop); - } -} -//#endregion -//#region src/main.ts -document.querySelector("#app").innerHTML = ` - <div class="layout"> - - <div class="game"> - <div class="title-bar"> - <h1>Tortis</h1> - <p>(4row clear to win)</p> - </div> - - <canvas height="240" width="160" id="main"></canvas> - </div> - - <ul> - <button id="move-left">move left</button> - <button id="rotate-left">rotate left</button> - <button id="move-right">move right</button> - <button id="rotate-right">rotate right</button> - <button id="speed-up">speed up</button> - </ul> - </div> -`; -setup({ - main: document.querySelector("#main"), - left: document.querySelector("#move-left"), - right: document.querySelector("#move-right"), - rotateLeft: document.querySelector("#rotate-left"), - rotateRight: document.querySelector("#rotate-right"), - speedUp: document.querySelector("#speed-up") -}); -//#endregion</script> - <style rel="stylesheet" crossorigin>* { - box-sizing: border-box; -} - -html, -body, -#app { - min-height: 100%; -} - -body { - margin: 0; - color: darksalmon; - background-color: #2e2e2e; - font-family: monospace; - overflow-x: hidden; -} - -button { - min-width: 0; - font: inherit; - font-size: .4rem; - line-height: 1.1; - padding: .15rem; - color: darksalmon; - background-color: #2e2e2e; - border-color: salmon; - cursor: pointer; - white-space: normal; - overflow-wrap: anywhere; - - z-index: 9999; -} - -button:hover { - background-color: darkslategray; -} - -button:active { - background-color: slategray; -} - -.layout { - margin: auto; - display: flex; - min-height: 100dvh; - width: 100%; - padding: .15rem; - gap: .2rem; - align-items: center; - justify-content: center; - overflow: hidden; -} - -.game { - min-width: 0; -} - -.title-bar { - display: flex; - align-items: baseline; - gap: .25rem; - margin-bottom: .2rem; -} - -h1, -p { - margin: 0; -} - -h1 { - font-size: .6rem; - line-height: 1; -} - -p { - font-size: .4rem; - line-height: 1.1; -} - -canvas { - display: block; - aspect-ratio: 2 / 3; - border-radius: 6px; - border: 1px solid darksalmon; - box-shadow: 0px 0px 4px darksalmon; - height: 80vmin; - width: auto; - - transition: transform 100ms; - margin: auto; -} - -ul { - display: flex; - justify-content: center; - flex-direction: column; - gap: .15rem; - width: min(6rem, 42vw); - margin: 0; - padding: 0; - list-style: none; -} -/*$vite$:1*/</style> - </head> - <body> - <div id="app"></div> - </body> -</html> diff --git a/2026/games/gbjk/src/.gitignore b/2026/games/gbjk/src/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/2026/games/gbjk/src/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/2026/games/gbjk/src/index.html b/2026/games/gbjk/src/index.html deleted file mode 100644 index c68a552..0000000 --- a/2026/games/gbjk/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ -<!doctype html> -<html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>tortis</title> - </head> - <body> - <div id="app"></div> - <script type="module" src="/src/main.ts"></script> - </body> -</html> diff --git a/2026/games/gbjk/src/package.json b/2026/games/gbjk/src/package.json deleted file mode 100644 index a5e9656..0000000 --- a/2026/games/gbjk/src/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "tortis", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "typescript": "6.0.2", - "vite": "8.0.12", - "vite-plugin-singlefile": "2.3.3" - } -} diff --git a/2026/games/gbjk/src/pnpm-lock.yaml b/2026/games/gbjk/src/pnpm-lock.yaml deleted file mode 100644 index 1087420..0000000 --- a/2026/games/gbjk/src/pnpm-lock.yaml +++ /dev/null @@ -1,568 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - typescript: - specifier: ~6.0.2 - version: 6.0.3 - vite: - specifier: ^8.0.12 - version: 8.0.16 - vite-plugin-singlefile: - specifier: ^2.3.3 - version: 2.3.3(vite@8.0.16) - -packages: - - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - - '@napi-rs/wasm-runtime@1.1.5': - resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} - - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - nanoid@3.3.13: - resolution: {integrity: sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} - engines: {node: ^10 || ^12 || >=14} - - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - tinyglobby@0.2.17: - resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} - engines: {node: '>=12.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} - hasBin: true - - vite-plugin-singlefile@2.3.3: - resolution: {integrity: sha512-XVnGH0QzbOa8fxRSsHdCarVN1BSBXNi7uLMQYlrGRN5apdHkk62XQWRJhVever0lnfuyBkwn+kvVChdm/OoOUg==} - engines: {node: '>18.0.0'} - peerDependencies: - rollup: ^4.59.0 - vite: ^5.4.21 || ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - rollup: - optional: true - - vite@8.0.16: - resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 - esbuild: ^0.27.0 || ^0.28.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - -snapshots: - - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - - '@oxc-project/types@0.133.0': {} - - '@rolldown/binding-android-arm64@1.0.3': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.3': - optional: true - - '@rolldown/binding-darwin-x64@1.0.3': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.3': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.3': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.3': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.3': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.3': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.3': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.3': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.0.3': - optional: true - - '@rolldown/pluginutils@1.0.1': {} - - '@tybys/wasm-util@0.10.2': - dependencies: - tslib: 2.8.1 - optional: true - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - detect-libc@2.1.2: {} - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - fsevents@2.3.3: - optional: true - - is-number@7.0.0: {} - - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - - nanoid@3.3.13: {} - - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - postcss@8.5.15: - dependencies: - nanoid: 3.3.13 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - rolldown@1.0.3: - dependencies: - '@oxc-project/types': 0.133.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 - - source-map-js@1.2.1: {} - - tinyglobby@0.2.17: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tslib@2.8.1: - optional: true - - typescript@6.0.3: {} - - vite-plugin-singlefile@2.3.3(vite@8.0.16): - dependencies: - micromatch: 4.0.8 - vite: 8.0.16 - - vite@8.0.16: - dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.15 - rolldown: 1.0.3 - tinyglobby: 0.2.17 - optionalDependencies: - fsevents: 2.3.3 diff --git a/2026/games/gbjk/src/src/main.ts b/2026/games/gbjk/src/src/main.ts deleted file mode 100644 index 8752b31..0000000 --- a/2026/games/gbjk/src/src/main.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { setup } from "./setup"; -import "./style.css"; - -document.querySelector<HTMLDivElement>("#app")!.innerHTML = ` - <div class="layout"> - - <div class="game"> - <div class="title-bar"> - <h1>Tortis</h1> - <p>(4row clear to win)</p> - </div> - - <canvas height="240" width="160" id="main"></canvas> - </div> - - <ul> - <button id="move-left">move left</button> - <button id="rotate-left">rotate left</button> - <button id="move-right">move right</button> - <button id="rotate-right">rotate right</button> - <button id="speed-up">speed up</button> - </ul> - </div> -`; - -setup({ - main: document.querySelector<HTMLCanvasElement>("#main")!, - left: document.querySelector<HTMLButtonElement>("#move-left")!, - right: document.querySelector<HTMLButtonElement>("#move-right")!, - rotateLeft: document.querySelector<HTMLButtonElement>("#rotate-left")!, - rotateRight: document.querySelector<HTMLButtonElement>("#rotate-right")!, - speedUp: document.querySelector<HTMLButtonElement>("#speed-up")!, -}); diff --git a/2026/games/gbjk/src/src/setup.ts b/2026/games/gbjk/src/src/setup.ts deleted file mode 100644 index 9d0614b..0000000 --- a/2026/games/gbjk/src/src/setup.ts +++ /dev/null @@ -1,389 +0,0 @@ -export type Elements = { - main: HTMLCanvasElement; - right: HTMLButtonElement; - left: HTMLButtonElement; - rotateRight: HTMLButtonElement; - rotateLeft: HTMLButtonElement; - speedUp: HTMLButtonElement; -}; - -const WIDTH = 160; -const HEIGHT = 240; - -const GRID_HEIGHT = HEIGHT - 10; -const ROWS = 15; -const COLS = 10; -const GRID_WIDTH = (GRID_HEIGHT / ROWS) * 10; -const GRID_X = 5; -const GRID_Y = 5; -const MARGIN = 2; -const CELL_WIDTH = GRID_HEIGHT / ROWS - MARGIN; -const FALLTIME = 600; -const MIN_FALLTIME = 300; - -let rotation = 0; - -type Block = - | "void" - | "red" - | "green" - | "blue" - | "fallingRed" - | "fallingGreen" - | "fallingBlue"; - -const board: Block[][] = []; - -function resetBoard() { - board.length = 0; - - for (let height = 0; height < ROWS; height++) { - const row: Block[] = []; - for (let width = 0; width < COLS; width++) { - row.push("void"); - } - board.push(row); - } -} - -resetBoard(); - -function random<T>(elements: T[]): T { - return elements[Math.floor(Math.random() * elements.length)]; -} - -let addedShapeNumber = 1; -function addSquares(): boolean { - const color = random(["fallingRed", "fallingGreen", "fallingBlue"] as const); - let w = COLS / 2; - let h = 1; - for (let i = 0; i < 4; i++) { - board[h][w] = color; - - if (i === 3) break; - - let move: "up" | "down" | "left" | "right" | null = null; - let j = 0; - for (; j < 20; j++) { - move = - addedShapeNumber % 6 === 0 - ? "down" - : random(["up", "down", "left", "right"] as const); - - if (move === "up" && (h === 0 || board[h - 1][w] !== "void")) continue; - if (move === "down" && (h === ROWS - 1 || board[h + 1][w] !== "void")) - continue; - - if (move === "left" && (w === 0 || board[h][w - 1] !== "void")) continue; - if (move === "right" && (w === COLS - 1 || board[h][w + 1] !== "void")) - continue; - - break; - } - if (j === 20) { - return false; - } - - switch (move) { - case "up": - h--; - break; - case "down": - h++; - break; - case "left": - w--; - break; - case "right": - w++; - break; - } - } - - addedShapeNumber++; - return true; -} - -function clearFilledRows(): number { - let lastClearedRow = ROWS; - let clearedRows = 0; - - for (let row = ROWS - 1; row >= 0; row--) { - if ( - !board[row].some( - (cell) => - cell === "void" || - cell === "fallingBlue" || - cell === "fallingGreen" || - cell === "fallingRed", - ) - ) { - for (let col = 0; col < COLS; col++) { - board[row][col] = "void"; - } - lastClearedRow = row; - clearedRows++; - } else if (lastClearedRow !== ROWS) { - for (let col = 0; col < COLS; col++) { - switch (board[row][col]) { - case "red": - board[row][col] = "fallingRed"; - break; - case "green": - board[row][col] = "fallingGreen"; - break; - case "blue": - board[row][col] = "fallingBlue"; - break; - } - } - } - } - - return clearedRows; -} - -export function setup(elements: Elements) { - const ctx = elements.main.getContext("2d")!; - - let gameRunning = false; - let animationFrameId: number | null = null; - let lastFrame = 0; - let fallTime = FALLTIME; - - let speedUpPressed = false; - - elements.left.addEventListener("click", () => moveFalling("left")); - elements.right.addEventListener("click", () => moveFalling("right")); - - elements.rotateLeft.addEventListener("click", () => { - if (!gameRunning) return; - - rotation -= 30 * Math.random(); - elements.main.style.transform = `rotate(${rotation}deg)`; - }); - elements.rotateRight.addEventListener("click", () => { - if (!gameRunning) return; - - rotation += 30 * Math.random(); - elements.main.style.transform = `rotate(${rotation}deg)`; - }); - - elements.speedUp.addEventListener( - "mousedown", - () => (speedUpPressed = gameRunning), - ); - elements.speedUp.addEventListener("mouseup", () => (speedUpPressed = false)); - - window.addEventListener("message", (ev: MessageEvent<unknown>) => { - const message = ev.data; - if (!isStartMessage(message)) return; - - startGame(message.difficulty); - }); - - window.parent.postMessage({ op: "ready" }, "*"); - - draw(); - - function isStartMessage( - message: unknown, - ): message is { op: "start"; difficulty: number } { - if (typeof message !== "object" || message === null) return false; - - const candidate = message as { op?: unknown; difficulty?: unknown }; - return ( - candidate.op === "start" && - typeof candidate.difficulty === "number" && - Number.isFinite(candidate.difficulty) - ); - } - - function resetGame(difficulty: number) { - resetBoard(); - addedShapeNumber = 1; - fallTime = Math.max(MIN_FALLTIME, FALLTIME - Math.max(0, difficulty) * 5); - rotation = 0; - elements.main.style.transform = ""; - speedUpPressed = false; - lastFrame = 0; - } - - function startGame(difficulty: number) { - if (animationFrameId !== null) { - cancelAnimationFrame(animationFrameId); - animationFrameId = null; - } - - resetGame(difficulty); - gameRunning = true; - window.parent.postMessage({ op: "started", verb: "catch!" }, "*"); - animationFrameId = requestAnimationFrame(gameLoop); - } - - function finishGame(win: boolean) { - if (!gameRunning) return; - - gameRunning = false; - if (animationFrameId !== null) { - cancelAnimationFrame(animationFrameId); - animationFrameId = null; - } - - window.parent.postMessage({ op: "done", win }, "*"); - resetGame(0); - draw(); - } - - function moveFalling(move: "left" | "right") { - if (!gameRunning) return; - - switch (move) { - case "left": - for (let row = 0; row < ROWS; row++) { - for (let col = 0; col < COLS - 1; col++) { - if (board[row][col] === "void") { - switch (board[row][col + 1]) { - case "fallingRed": - case "fallingGreen": - case "fallingBlue": - board[row][col] = board[row][col + 1]; - board[row][col + 1] = "void"; - } - } - } - } - break; - case "right": - for (let row = 0; row < ROWS; row++) { - for (let col = COLS - 1; col > 0; col--) { - if (board[row][col] === "void") { - switch (board[row][col - 1]) { - case "fallingRed": - case "fallingGreen": - case "fallingBlue": - board[row][col] = board[row][col - 1]; - board[row][col - 1] = "void"; - } - } - } - } - break; - } - } - - function physics(): boolean { - let somethingFell = false; - - for (let row = ROWS - 1; row >= 1; row--) { - for (let col = 0; col < COLS; col++) { - let space = board[row][col]; - let above = board[row - 1][col]; - switch (above) { - case "fallingRed": - case "fallingGreen": - case "fallingBlue": - if (space === "void") { - somethingFell = true; - board[row][col] = board[row - 1][col]; - board[row - 1][col] = "void"; - } else { - switch (above) { - case "fallingRed": - board[row - 1][col] = "red"; - break; - case "fallingGreen": - board[row - 1][col] = "green"; - break; - case "fallingBlue": - board[row - 1][col] = "blue"; - break; - } - } - } - } - } - - for (let col = 0; col < COLS; col++) { - switch (board[ROWS - 1][col]) { - case "fallingRed": - board[ROWS - 1][col] = "red"; - break; - case "fallingGreen": - board[ROWS - 1][col] = "green"; - break; - case "fallingBlue": - board[ROWS - 1][col] = "blue"; - break; - } - } - - return somethingFell; - } - - function draw() { - ctx.clearRect(0, 0, WIDTH, HEIGHT); - - ctx.fillStyle = "black"; - ctx.fillRect(GRID_X, GRID_Y, GRID_WIDTH, GRID_HEIGHT); - - for (let h = 0; h < ROWS; h++) { - for (let w = 0; w < COLS; w++) { - switch (board[h][w]) { - case "void": - ctx.fillStyle = "#2e2e2e"; - break; - case "red": - ctx.fillStyle = "#994444"; - break; - case "green": - ctx.fillStyle = "#449944"; - break; - case "blue": - ctx.fillStyle = "#444499"; - break; - case "fallingRed": - ctx.fillStyle = "#bb3333"; - break; - case "fallingGreen": - ctx.fillStyle = "#33bb33"; - break; - case "fallingBlue": - ctx.fillStyle = "#3333bb"; - break; - } - - const x = GRID_X + MARGIN * 1.5 + w * CELL_WIDTH + (w - 1) * MARGIN; - const y = GRID_Y + MARGIN * 1.5 + h * CELL_WIDTH + (h - 1) * MARGIN; - - ctx.fillRect(x, y, CELL_WIDTH, CELL_WIDTH); - } - } - } - - function gameLoop(time: number) { - animationFrameId = null; - - if (!gameRunning) return; - - if (time - lastFrame > (speedUpPressed ? fallTime / 10 : fallTime)) { - lastFrame = time; - const somethingFell = physics(); - if (!somethingFell) { - const clearedRows = clearFilledRows(); - if (clearedRows >= 4) { - finishGame(true); - return; - } else if (clearedRows === 0) { - if (!addSquares()) { - finishGame(false); - return; - } - } - } - } - - draw(); - animationFrameId = requestAnimationFrame(gameLoop); - } -} diff --git a/2026/games/gbjk/src/src/style.css b/2026/games/gbjk/src/src/style.css deleted file mode 100644 index 56e07d1..0000000 --- a/2026/games/gbjk/src/src/style.css +++ /dev/null @@ -1,103 +0,0 @@ -* { - box-sizing: border-box; -} - -html, -body, -#app { - min-height: 100%; -} - -body { - margin: 0; - color: darksalmon; - background-color: #2e2e2e; - font-family: monospace; - overflow-x: hidden; -} - -button { - min-width: 0; - font: inherit; - font-size: .4rem; - line-height: 1.1; - padding: .15rem; - color: darksalmon; - background-color: #2e2e2e; - border-color: salmon; - cursor: pointer; - white-space: normal; - overflow-wrap: anywhere; - - z-index: 9999; -} - -button:hover { - background-color: darkslategray; -} - -button:active { - background-color: slategray; -} - -.layout { - margin: auto; - display: flex; - min-height: 100dvh; - width: 100%; - padding: .15rem; - gap: .2rem; - align-items: center; - justify-content: center; - overflow: hidden; -} - -.game { - min-width: 0; -} - -.title-bar { - display: flex; - align-items: baseline; - gap: .25rem; - margin-bottom: .2rem; -} - -h1, -p { - margin: 0; -} - -h1 { - font-size: .6rem; - line-height: 1; -} - -p { - font-size: .4rem; - line-height: 1.1; -} - -canvas { - display: block; - aspect-ratio: 2 / 3; - border-radius: 6px; - border: 1px solid darksalmon; - box-shadow: 0px 0px 4px darksalmon; - height: 80vmin; - width: auto; - - transition: transform 100ms; - margin: auto; -} - -ul { - display: flex; - justify-content: center; - flex-direction: column; - gap: .15rem; - width: min(6rem, 42vw); - margin: 0; - padding: 0; - list-style: none; -} diff --git a/2026/games/gbjk/src/tsconfig.json b/2026/games/gbjk/src/tsconfig.json deleted file mode 100644 index 1ab38c8..0000000 --- a/2026/games/gbjk/src/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "module": "esnext", - "lib": ["ES2023", "DOM"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/2026/games/gbjk/src/vite.config.ts b/2026/games/gbjk/src/vite.config.ts deleted file mode 100644 index c9036bd..0000000 --- a/2026/games/gbjk/src/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "vite"; -import { viteSingleFile } from "vite-plugin-singlefile"; - -export default defineConfig({ - plugins: [viteSingleFile()], - build: { - minify: false, - }, -}); |
