summaryrefslogtreecommitdiff
path: root/2026/games_submissions/gbjk/src
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2026-08-17 20:14:16 -0400
committerLLLL Colonq <llll@colonq>2026-08-17 20:14:16 -0400
commitde99c5f7636a952025ea13de02bafd25bcb6bdec (patch)
treebe359424af4f6717103e3b667b6529ae5a4b4e6a /2026/games_submissions/gbjk/src
parent4d4d1f24721f27fbf37e1070be6414de130ace61 (diff)
Fix broken
Diffstat (limited to '2026/games_submissions/gbjk/src')
-rw-r--r--2026/games_submissions/gbjk/src/.gitignore24
-rw-r--r--2026/games_submissions/gbjk/src/index.html12
-rw-r--r--2026/games_submissions/gbjk/src/package.json16
-rw-r--r--2026/games_submissions/gbjk/src/pnpm-lock.yaml568
-rw-r--r--2026/games_submissions/gbjk/src/src/main.ts33
-rw-r--r--2026/games_submissions/gbjk/src/src/setup.ts389
-rw-r--r--2026/games_submissions/gbjk/src/src/style.css103
-rw-r--r--2026/games_submissions/gbjk/src/tsconfig.json23
-rw-r--r--2026/games_submissions/gbjk/src/vite.config.ts9
9 files changed, 1177 insertions, 0 deletions
diff --git a/2026/games_submissions/gbjk/src/.gitignore b/2026/games_submissions/gbjk/src/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/.gitignore
@@ -0,0 +1,24 @@
+# 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_submissions/gbjk/src/index.html b/2026/games_submissions/gbjk/src/index.html
new file mode 100644
index 0000000..c68a552
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/index.html
@@ -0,0 +1,12 @@
+<!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_submissions/gbjk/src/package.json b/2026/games_submissions/gbjk/src/package.json
new file mode 100644
index 0000000..a5e9656
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/package.json
@@ -0,0 +1,16 @@
+{
+ "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_submissions/gbjk/src/pnpm-lock.yaml b/2026/games_submissions/gbjk/src/pnpm-lock.yaml
new file mode 100644
index 0000000..1087420
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/pnpm-lock.yaml
@@ -0,0 +1,568 @@
+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_submissions/gbjk/src/src/main.ts b/2026/games_submissions/gbjk/src/src/main.ts
new file mode 100644
index 0000000..8752b31
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/src/main.ts
@@ -0,0 +1,33 @@
+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_submissions/gbjk/src/src/setup.ts b/2026/games_submissions/gbjk/src/src/setup.ts
new file mode 100644
index 0000000..9d0614b
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/src/setup.ts
@@ -0,0 +1,389 @@
+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_submissions/gbjk/src/src/style.css b/2026/games_submissions/gbjk/src/src/style.css
new file mode 100644
index 0000000..56e07d1
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/src/style.css
@@ -0,0 +1,103 @@
+* {
+ 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_submissions/gbjk/src/tsconfig.json b/2026/games_submissions/gbjk/src/tsconfig.json
new file mode 100644
index 0000000..1ab38c8
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "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_submissions/gbjk/src/vite.config.ts b/2026/games_submissions/gbjk/src/vite.config.ts
new file mode 100644
index 0000000..c9036bd
--- /dev/null
+++ b/2026/games_submissions/gbjk/src/vite.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from "vite";
+import { viteSingleFile } from "vite-plugin-singlefile";
+
+export default defineConfig({
+ plugins: [viteSingleFile()],
+ build: {
+ minify: false,
+ },
+});