[feat] Initial commit
All checks were successful
continuous-integration/drone Build is passing

This commit is contained in:
supercodeur 2025-06-29 20:05:44 +02:00
commit 8a5ba1c541
12 changed files with 962 additions and 0 deletions

34
.drone.yml Normal file
View File

@ -0,0 +1,34 @@
kind: pipeline
type: docker
name: deploy-static-site
steps:
- name: deploy public_html
image: alpine:3.20
volumes:
- name: ididit
path: /var/www/ididit
commands:
- |
if [ -d public_html ] && [ "$(ls -A public_html)" ]; then
target="/var/www/ididit/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}"
echo "Déploiement vers $target"
rm -rf "$target"
mkdir -p "$target"
cp -r public_html/* "$target/"
echo "Déploiement terminé."
echo "https://ididit.bymycode.com/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}"
ls -alh "$target"
else
echo "Aucun dossier public_html à déployer."
fi
when:
branch:
- main
event:
- push
volumes:
- name: ididit
host:
path: /var/www/ididit

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/node_modules/
/.idea/

489
package-lock.json generated Normal file
View File

@ -0,0 +1,489 @@
{
"name": "tetris",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tetris",
"dependencies": {
"kaboom": "^3000.1.17"
},
"devDependencies": {
"esbuild": "^0.25.5"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/esbuild": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.5",
"@esbuild/android-arm": "0.25.5",
"@esbuild/android-arm64": "0.25.5",
"@esbuild/android-x64": "0.25.5",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@esbuild/freebsd-arm64": "0.25.5",
"@esbuild/freebsd-x64": "0.25.5",
"@esbuild/linux-arm": "0.25.5",
"@esbuild/linux-arm64": "0.25.5",
"@esbuild/linux-ia32": "0.25.5",
"@esbuild/linux-loong64": "0.25.5",
"@esbuild/linux-mips64el": "0.25.5",
"@esbuild/linux-ppc64": "0.25.5",
"@esbuild/linux-riscv64": "0.25.5",
"@esbuild/linux-s390x": "0.25.5",
"@esbuild/linux-x64": "0.25.5",
"@esbuild/netbsd-arm64": "0.25.5",
"@esbuild/netbsd-x64": "0.25.5",
"@esbuild/openbsd-arm64": "0.25.5",
"@esbuild/openbsd-x64": "0.25.5",
"@esbuild/sunos-x64": "0.25.5",
"@esbuild/win32-arm64": "0.25.5",
"@esbuild/win32-ia32": "0.25.5",
"@esbuild/win32-x64": "0.25.5"
}
},
"node_modules/kaboom": {
"version": "3000.1.17",
"resolved": "https://registry.npmjs.org/kaboom/-/kaboom-3000.1.17.tgz",
"integrity": "sha512-npAtjGxj9Oj9vLpXfURck9eUPHR2ac1Lhc1bNcZ0NWcs+Lgs40Ty+wjujv1C2DwjWvxaX+3r2G64M35BS/Ry2g==",
"deprecated": "Kaboom is no longer maintained. Please use KAPLAY, the new game library built as its successor, by its developers.",
"license": "MIT"
}
}
}

14
package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "tetris",
"scripts": {
"build": "esbuild --bundle src/main.js --outfile=www/main.js --minify",
"dev": "esbuild --bundle src/main.js --outfile=www/main.js --servedir=www",
"bundle": "npm run build && mkdir -p dist && zip -r dist/game.zip www -x \"**/.DS_Store\""
},
"dependencies": {
"kaboom": "^3000.1.17"
},
"devDependencies": {
"esbuild": "^0.25.5"
}
}

BIN
public_html/img/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

9
public_html/index.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>tetris</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>

56
public_html/main.js Normal file

File diff suppressed because one or more lines are too long

BIN
public_html/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

293
src/main.js Normal file
View File

@ -0,0 +1,293 @@
import kaboom from "kaboom"
const GRID_WIDTH = 10
const GRID_HEIGHT = 20
const BLOCK_SIZE = 8
const GAME_WIDTH = GRID_WIDTH * BLOCK_SIZE
const GAME_HEIGHT = GRID_HEIGHT * BLOCK_SIZE
const k = kaboom({
width: GAME_WIDTH,
height: GAME_HEIGHT,
background: [0, 0, 0],
scale: 1,
})
k.loadSprite("white_block", "img/white.png")
const TETROMINOS = [
// I
[
[0, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 0],
[0, 0, 0, 0],
],
// O
[
[1, 1],
[1, 1],
],
// T
[
[0, 1, 0],
[1, 1, 1],
[0, 0, 0],
],
// S
[
[0, 1, 1],
[1, 1, 0],
[0, 0, 0],
],
// Z
[
[1, 1, 0],
[0, 1, 1],
[0, 0, 0],
],
// J
[
[1, 0, 0],
[1, 1, 1],
[0, 0, 0],
],
// L
[
[0, 0, 1],
[1, 1, 1],
[0, 0, 0],
],
]
function randomFlashyColor() {
let c = [0, 0, 0]
let maxIndex = Math.floor(Math.random() * 3)
c[maxIndex] = 255
let other = [0, 1, 2].filter(i => i !== maxIndex)
c[other[0]] = Math.floor(Math.random() * 256)
c[other[1]] = Math.floor(Math.random() * 256)
return c
}
let grid = Array.from({length: GRID_HEIGHT}, () => Array(GRID_WIDTH).fill(0))
let current, pos, rotation, currentColor
let score = 0
function randomTetromino() {
const shape = TETROMINOS[Math.floor(Math.random() * TETROMINOS.length)]
return JSON.parse(JSON.stringify(shape))
}
function spawnTetromino() {
current = randomTetromino()
currentColor = randomFlashyColor()
pos = {x: Math.floor((GRID_WIDTH - current[0].length) / 2), y: 0}
rotation = 0
if (!isValidMove(current, pos.x, pos.y)) {
k.go("gameover", {score})
}
}
function isValidMove(matrix, x, y) {
for (let row = 0; row < matrix.length; row++) {
for (let col = 0; col < matrix[row].length; col++) {
if (matrix[row][col]) {
let nx = x + col
let ny = y + row
if (
nx < 0 ||
nx >= GRID_WIDTH ||
ny >= GRID_HEIGHT ||
(ny >= 0 && grid[ny][nx])
) {
return false
}
}
}
}
return true
}
function mergeTetromino() {
for (let row = 0; row < current.length; row++) {
for (let col = 0; col < current[row].length; col++) {
if (current[row][col]) {
let nx = pos.x + col
let ny = pos.y + row
if (ny >= 0) grid[ny][nx] = 1
}
}
}
}
function rotate(matrix) {
return matrix[0].map((_, i) => matrix.map(row => row[i]).reverse())
}
function clearLines() {
for (let y = GRID_HEIGHT - 1; y >= 0; y--) {
if (grid[y].every(cell => cell)) {
grid.splice(y, 1)
grid.unshift(Array(GRID_WIDTH).fill(0))
score += GRID_WIDTH // Ajoute 10 blocs par ligne éliminée
y++
}
}
}
function drawGrid() {
k.destroyAll("block")
for (let y = 0; y < GRID_HEIGHT; y++) {
for (let x = 0; x < GRID_WIDTH; x++) {
if (grid[y][x]) {
k.add([
k.sprite("white_block"),
k.pos(x * BLOCK_SIZE, y * BLOCK_SIZE),
k.area(),
"block"
])
}
}
}
for (let row = 0; row < current.length; row++) {
for (let col = 0; col < current[row].length; col++) {
if (current[row][col]) {
let nx = pos.x + col
let ny = pos.y + row
if (ny >= 0 && ny < GRID_HEIGHT) {
k.add([
k.sprite("white_block"),
k.pos(nx * BLOCK_SIZE, ny * BLOCK_SIZE),
k.area(),
k.color(...currentColor),
"block"
])
}
}
}
}
}
let rotateCooldown = 0
let leftCooldown = 0
let rightCooldown = 0
const INPUT_DELAY = 0.2
k.scene("main", () => {
grid = Array.from({length: GRID_HEIGHT}, () => Array(GRID_WIDTH).fill(0))
score = 0
spawnTetromino()
drawGrid()
let dropTimer = 0
let dropInterval = 0.5
rotateCooldown = 0
leftCooldown = 0
rightCooldown = 0
k.onUpdate(() => {
dropTimer += k.dt()
if (rotateCooldown > 0) rotateCooldown -= k.dt()
if (leftCooldown > 0) leftCooldown -= k.dt()
if (rightCooldown > 0) rightCooldown -= k.dt()
if (dropTimer > dropInterval) {
dropTimer = 0
if (isValidMove(current, pos.x, pos.y + 1)) {
pos.y++
} else {
mergeTetromino()
clearLines()
spawnTetromino()
}
drawGrid()
}
})
k.onKeyDown("left", () => {
if (leftCooldown <= 0) {
if (isValidMove(current, pos.x - 1, pos.y)) {
pos.x--
drawGrid()
}
leftCooldown = INPUT_DELAY
}
})
k.onKeyDown("right", () => {
if (rightCooldown <= 0) {
if (isValidMove(current, pos.x + 1, pos.y)) {
pos.x++
drawGrid()
}
rightCooldown = INPUT_DELAY
}
})
k.onKeyDown("down", () => {
if (isValidMove(current, pos.x, pos.y + 1)) {
pos.y++
drawGrid()
}
})
k.onKeyDown("up", () => {
if (rotateCooldown <= 0) {
const rotated = rotate(current)
if (isValidMove(rotated, pos.x, pos.y)) {
current = rotated
drawGrid()
}
rotateCooldown = INPUT_DELAY
}
})
})
k.scene("gameover", ({score}) => {
k.add([
k.rect(GAME_WIDTH, GAME_HEIGHT),
k.color(0, 0, 0),
k.opacity(0.75),
k.pos(0, 0),
"overlay"
])
k.add([
k.text("GAME OVER", {size: 24, width: GAME_WIDTH, align: "center"}),
k.pos(GAME_WIDTH / 2, GAME_HEIGHT / 2),
k.anchor("center"),
"gameover-text"
])
k.add([
k.text(`Score\n${score}`, {size: 12, width: GAME_WIDTH, align: "center"}),
k.pos(GAME_WIDTH / 2, GAME_HEIGHT / 2 - 50),
k.anchor("center"),
"score-text"
])
function restart() {
k.go("main")
}
k.onKeyPress(restart)
k.onClick(restart)
})
k.go("main")
function resizeCanvas() {
const canvas = document.querySelector('canvas')
if (!canvas) return
const scale = window.innerHeight / GAME_HEIGHT
canvas.style.width = `${GAME_WIDTH * scale}px`
canvas.style.height = `${GAME_HEIGHT * scale}px`
canvas.style.display = "block"
canvas.style.margin = "0 auto"
}
window.addEventListener("resize", resizeCanvas)
window.addEventListener("DOMContentLoaded", resizeCanvas)
resizeCanvas()

BIN
www/img/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

9
www/index.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>tetris</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>

56
www/main.js Normal file

File diff suppressed because one or more lines are too long