From 9b5ab25c4dae039a18c2c143385149b078ab28d4 Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Thu, 21 Aug 2025 13:16:29 +0200 Subject: [PATCH] survivors: adding first version --- .github/workflows/build.yml | 24 +- absurd-survivors/.gitignore | 24 + absurd-survivors/index.html | 13 + absurd-survivors/package-lock.json | 1088 ++++++++++++++++++++++++++++ absurd-survivors/package.json | 16 + absurd-survivors/src/Enemies.ts | 144 ++++ absurd-survivors/src/Player.ts | 116 +++ absurd-survivors/src/World.ts | 70 ++ absurd-survivors/src/base.ts | 59 ++ absurd-survivors/src/instance.ts | 7 + absurd-survivors/src/interfaces.ts | 31 + absurd-survivors/src/main.ts | 133 ++++ absurd-survivors/src/projectile.ts | 100 +++ absurd-survivors/src/style.css | 4 + absurd-survivors/src/ui.ts | 72 ++ absurd-survivors/src/utils.ts | 18 + absurd-survivors/src/vite-env.d.ts | 1 + absurd-survivors/src/weapons.ts | 59 ++ absurd-survivors/tsconfig.json | 25 + absurd-survivors/vite.config.js | 7 + img/survivors.png | Bin 0 -> 40381 bytes index.html | 1 + 22 files changed, 2003 insertions(+), 9 deletions(-) create mode 100644 absurd-survivors/.gitignore create mode 100644 absurd-survivors/index.html create mode 100644 absurd-survivors/package-lock.json create mode 100644 absurd-survivors/package.json create mode 100644 absurd-survivors/src/Enemies.ts create mode 100644 absurd-survivors/src/Player.ts create mode 100644 absurd-survivors/src/World.ts create mode 100644 absurd-survivors/src/base.ts create mode 100644 absurd-survivors/src/instance.ts create mode 100644 absurd-survivors/src/interfaces.ts create mode 100644 absurd-survivors/src/main.ts create mode 100644 absurd-survivors/src/projectile.ts create mode 100644 absurd-survivors/src/style.css create mode 100644 absurd-survivors/src/ui.ts create mode 100644 absurd-survivors/src/utils.ts create mode 100644 absurd-survivors/src/vite-env.d.ts create mode 100644 absurd-survivors/src/weapons.ts create mode 100644 absurd-survivors/tsconfig.json create mode 100644 absurd-survivors/vite.config.js create mode 100644 img/survivors.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 406ced2..fbd031d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,59 +29,65 @@ jobs: with: node-version: 21 - name: Orbits Install dependencies - run: npm install + run: npm ci working-directory: orbits - name: Orbits Build run: npx vite build working-directory: orbits - name: recBubbles Install dependencies - run: npm install + run: npm ci working-directory: recBubbles - name: recBubbles Build run: npx vite build working-directory: recBubbles - name: balls Install dependencies - run: npm install + run: npm ci working-directory: balls - name: balls Build run: npx vite build working-directory: balls - name: fireWorks Install dependencies - run: npm install + run: npm ci working-directory: fireWorks - name: fireWorks Build run: npx vite build working-directory: fireWorks - name: bubbles Install dependencies - run: npm install + run: npm ci working-directory: bubbles - name: bubbles Build run: npx vite build working-directory: bubbles - name: circleBs Install dependencies - run: npm install + run: npm ci working-directory: circleBs - name: circleBs Build run: npx vite build working-directory: circleBs - name: clusterFilter Install dependencies - run: npm install + run: npm ci working-directory: clusterFilter - name: clusterFilter Build run: npx vite build working-directory: clusterFilter - name: collatzConjecture Install dependencies - run: npm install + run: npm ci working-directory: collatzConjecture - name: collatzConjecture Build run: npx vite build working-directory: collatzConjecture - name: dotLines Install dependencies - run: npm install + run: npm ci working-directory: dotLines - name: dotLines Build run: npx vite build working-directory: dotLines + - name: survivors install dependencies + run: npm ci + working-directory: absurd-survivors + - name: survivors build + run: npx vite build + working-directory: absurd-survivors - name: Move index run: cp index.html dist/ - name: Move overview images diff --git a/absurd-survivors/.gitignore b/absurd-survivors/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/absurd-survivors/.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/absurd-survivors/index.html b/absurd-survivors/index.html new file mode 100644 index 0000000..b00cce9 --- /dev/null +++ b/absurd-survivors/index.html @@ -0,0 +1,13 @@ + + + + + + overtuned survivors + + + + + + + diff --git a/absurd-survivors/package-lock.json b/absurd-survivors/package-lock.json new file mode 100644 index 0000000..3a0d662 --- /dev/null +++ b/absurd-survivors/package-lock.json @@ -0,0 +1,1088 @@ +{ + "name": "overtuned-survivors", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "overtuned-survivors", + "version": "0.0.1", + "devDependencies": { + "canvas-common": "file:../canvas-common", + "typescript": "~5.8.3", + "vite": "^7.1.2" + } + }, + "../canvas-common": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.3", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.3", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/canvas-common": { + "resolved": "../canvas-common", + "link": true + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.46.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.46.3", + "@rollup/rollup-android-arm64": "4.46.3", + "@rollup/rollup-darwin-arm64": "4.46.3", + "@rollup/rollup-darwin-x64": "4.46.3", + "@rollup/rollup-freebsd-arm64": "4.46.3", + "@rollup/rollup-freebsd-x64": "4.46.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.3", + "@rollup/rollup-linux-arm-musleabihf": "4.46.3", + "@rollup/rollup-linux-arm64-gnu": "4.46.3", + "@rollup/rollup-linux-arm64-musl": "4.46.3", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.3", + "@rollup/rollup-linux-ppc64-gnu": "4.46.3", + "@rollup/rollup-linux-riscv64-gnu": "4.46.3", + "@rollup/rollup-linux-riscv64-musl": "4.46.3", + "@rollup/rollup-linux-s390x-gnu": "4.46.3", + "@rollup/rollup-linux-x64-gnu": "4.46.3", + "@rollup/rollup-linux-x64-musl": "4.46.3", + "@rollup/rollup-win32-arm64-msvc": "4.46.3", + "@rollup/rollup-win32-ia32-msvc": "4.46.3", + "@rollup/rollup-win32-x64-msvc": "4.46.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", + "integrity": "sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==", + "dev": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.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 + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + }, + "dependencies": { + "@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "dev": true, + "optional": true + }, + "@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.46.3", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.46.3", + "dev": true, + "optional": true + }, + "@types/estree": { + "version": "1.0.8", + "dev": true + }, + "canvas-common": { + "version": "file:../canvas-common" + }, + "esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "requires": {} + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "nanoid": { + "version": "3.3.11", + "dev": true + }, + "picocolors": { + "version": "1.1.1", + "dev": true + }, + "picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true + }, + "postcss": { + "version": "8.5.6", + "dev": true, + "requires": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "rollup": { + "version": "4.46.3", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.46.3", + "@rollup/rollup-android-arm64": "4.46.3", + "@rollup/rollup-darwin-arm64": "4.46.3", + "@rollup/rollup-darwin-x64": "4.46.3", + "@rollup/rollup-freebsd-arm64": "4.46.3", + "@rollup/rollup-freebsd-x64": "4.46.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.3", + "@rollup/rollup-linux-arm-musleabihf": "4.46.3", + "@rollup/rollup-linux-arm64-gnu": "4.46.3", + "@rollup/rollup-linux-arm64-musl": "4.46.3", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.3", + "@rollup/rollup-linux-ppc64-gnu": "4.46.3", + "@rollup/rollup-linux-riscv64-gnu": "4.46.3", + "@rollup/rollup-linux-riscv64-musl": "4.46.3", + "@rollup/rollup-linux-s390x-gnu": "4.46.3", + "@rollup/rollup-linux-x64-gnu": "4.46.3", + "@rollup/rollup-linux-x64-musl": "4.46.3", + "@rollup/rollup-win32-arm64-msvc": "4.46.3", + "@rollup/rollup-win32-ia32-msvc": "4.46.3", + "@rollup/rollup-win32-x64-msvc": "4.46.3", + "@types/estree": "1.0.8", + "fsevents": "~2.3.2" + } + }, + "source-map-js": { + "version": "1.2.1", + "dev": true + }, + "tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "requires": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + } + }, + "typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true + }, + "vite": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", + "integrity": "sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==", + "dev": true, + "requires": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "fsevents": "~2.3.3", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + } + } + } +} diff --git a/absurd-survivors/package.json b/absurd-survivors/package.json new file mode 100644 index 0000000..f40bd76 --- /dev/null +++ b/absurd-survivors/package.json @@ -0,0 +1,16 @@ +{ + "name": "overtuned-survivors", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "devDependencies": { + "canvas-common": "file:../canvas-common", + "typescript": "~5.8.3", + "vite": "^7.1.2" + } +} diff --git a/absurd-survivors/src/Enemies.ts b/absurd-survivors/src/Enemies.ts new file mode 100644 index 0000000..6ed1b23 --- /dev/null +++ b/absurd-survivors/src/Enemies.ts @@ -0,0 +1,144 @@ +import type {Acting, Drawable, Healthy, Moving, Shooting} from "./interfaces.ts"; +import {drawDot, moveInDirectionOf} from "./utils.ts"; +import {Vector} from "./base.ts"; +import {World} from "./World.ts"; +import type {Projectile} from "./projectile.ts"; +import {HomingProjectile, StraightProjectile} from "./projectile.ts"; + +export abstract class Enemy implements Moving, Drawable, Acting, Healthy { + protected _position: Vector; + protected speed: number; + protected world: World; + protected status: EnemyStatus = new EnemyStatus(10); + + constructor(position: Vector) { + this._position = position; + } + + draw(ctx: CanvasRenderingContext2D) { + } + + act() { + this.move() + } + + move() { + } + + + getPosition(): Vector { + return this._position; + } + + takeDamage(damage: number) { + this.status.health -= damage; + if(this.status.dead) { + this.world.removeEnemy(this) + } + } +} + +export class BasicEnemy extends Enemy { + + constructor(position: Vector) { + super(position); + } + + protected size: number; + protected color: string; + protected impactDamage: number; + protected impactCooldown: number = 0; + protected impactInterval: number = 60; + + draw(ctx: CanvasRenderingContext2D) { + drawDot(this._position, this.size, this.color, ctx) + } + + + move() { + this._position = moveInDirectionOf(this._position, this.world.player.position, this.speed) + } + + act() { + super.act(); + if(this._position.distanceTo(this.world.player.position) < this.size && this.impactCooldown <= 0) { + this.world.player.takeDamage(this.impactDamage) + this.impactCooldown = this.impactInterval; + } + this.impactCooldown -= 1; + } + + static generateBasicEnemy(world: World, position?: Vector): BasicEnemy { + if(position === undefined) { + position = new Vector(250, 250) + } + let basicEnemy = new BasicEnemy(position); + basicEnemy.size = 5; + basicEnemy.world = world; + basicEnemy.speed = 0.5; + basicEnemy.color = 'orange' + basicEnemy.impactDamage = 2; + return basicEnemy; + } +} + +export class ShootingEnemy extends BasicEnemy implements Shooting { + private shootCooldown: number = 0; + private shootInterval: number; + private projectiles: Projectile[] = [] + + constructor(position: Vector) { + super(position); + } + + removeProjectile(projectile: Projectile) { + this.projectiles = this.projectiles.filter(item => item !== projectile) + } + + act() { + super.act(); + if(this.shootCooldown <= 0) { + this.createProjectile() + this.shootCooldown = this.shootInterval; + } + this.shootCooldown -= 1; + } + + createProjectile() { + let projectile = StraightProjectile.createStraightProjectile(this.world, this._position, this.world.player.position, this) + this.projectiles.push(projectile) + return projectile + } + + static generateShootingEnemy(world: World, position?: Vector) { + if(position === undefined) { + position = new Vector(250, 250) + } + let basicEnemy = new ShootingEnemy(position); + basicEnemy.size = 5; + basicEnemy.world = world; + basicEnemy.speed = 0.5; + basicEnemy.color = 'green' + basicEnemy.impactDamage = 2; + basicEnemy.shootInterval = 100 + return basicEnemy; + } +} + +export class EnemyStatus { + constructor(private _health: number) { + } + + + get health(): number { + return this._health; + } + + get dead(): boolean { + return this._health <= 0; + } + + set health(value: number) { + this._health = value; + } +} \ No newline at end of file diff --git a/absurd-survivors/src/Player.ts b/absurd-survivors/src/Player.ts new file mode 100644 index 0000000..5976383 --- /dev/null +++ b/absurd-survivors/src/Player.ts @@ -0,0 +1,116 @@ +import type {Acting, Drawable, Healthy, Weapon} from "./interfaces.ts"; +import {Vector} from "./base.ts"; +import {drawDot} from "./utils.ts"; + +export class Player implements Drawable, Acting, Healthy { + private _position: Vector; + private _stats: Stats; + private _color: string; + private _status: Status; + private _weapons: [Weapon] = [] + + // temp + private _speed: Vector; + + + constructor(position: Vector) { + this._position = position; + } + + draw(ctx: CanvasRenderingContext2D) { + drawDot(this.position, this._stats.size, this._color, ctx) + this._weapons.forEach(weapon => weapon.draw(ctx)) + } + + public static generatePlayer(): Player { + let player = new Player(new Vector(500, 500)); + player._color = 'blue'; + player._stats = Stats.defaultPlayerStats(); + player._speed = new Vector(0, 0) + player._status = new Status(10); + return player; + } + + addWeapon(weapon: Weapon) { + this._weapons.push(weapon) + } + + move(direction: Vector) { + this._position = this.position.add(direction) + } + + takeDamage(damage: number) { + this._status.health -= damage; + } + + get health(): number { + return this._status.health; + } + + get position(): Vector { + return this._position; + } + + get color(): string { + return this._color; + } + + get stats(): Stats { + return this._stats; + } + + get speed(): Vector { + return this._speed; + } + + act() { + this._weapons.forEach(weapon => weapon.act()) + } +} + +export class Status { + constructor(private _health: number) { + } + + + get health(): number { + return this._health; + } + + + set health(value: number) { + this._health = value; + } +} + +export class Stats { + constructor(private _speed: number, + private _size: number, + private _health: number) { + } + + get speed(): number { + return this._speed; + } + + set speed(value: number) { + this._speed = value; + } + + get size(): number { + return this._size; + } + + set size(value: number) { + this._size = value; + } + + + get health(): number { + return this._health; + } + + public static defaultPlayerStats(): Stats { + return new Stats(2, 5, 10); + } +} \ No newline at end of file diff --git a/absurd-survivors/src/World.ts b/absurd-survivors/src/World.ts new file mode 100644 index 0000000..209fb18 --- /dev/null +++ b/absurd-survivors/src/World.ts @@ -0,0 +1,70 @@ +import {Enemy} from "./Enemies.ts"; +import type {Player} from "./Player.ts"; +import {Player} from "./Player.ts"; +import {Projectile} from "./projectile.ts"; +import {Vector} from "./base.ts"; +import type {Moving} from "./interfaces.ts"; + +export class World { + private _enemies: [Enemy] = []; + private _projectiles: [Projectile] = []; + private _player: Player; + private _ctx: CanvasRenderingContext2D; + + + constructor(player: Player, ctx: CanvasRenderingContext2D) { + this._player = player; + this._ctx = ctx; + } + + enemiesAct() { + this._enemies.forEach(enemy => enemy.act()) + this._projectiles.forEach(projectile => projectile.act()) + } + + draw() { + this._enemies.forEach(enemy => enemy.draw(this._ctx)) + this._projectiles.forEach(projectile => projectile.draw(this._ctx)) + this._player.draw(this._ctx); + } + + addProjectile(projectile: Projectile) { + this._projectiles.push(projectile) + } + + removeProjectile(projectile: Projectile) { + this._projectiles = this._projectiles.filter(item => item !== projectile) + } + + removeEnemy(enemy: Enemy) { + this._enemies = this._enemies.filter(item => item !== enemy) + } + + + get enemies(): [Enemy] { + return this._enemies; + } + + addEnemy(enemy: Enemy) { + this._enemies.push(enemy) + } + + getClosestTargetTo(point: Vector): [number, Moving | undefined] | undefined { + let currentTarget; + let currentDistance = Number.MAX_SAFE_INTEGER; + this._enemies.forEach(enemy => { + let distance = point.distanceTo(enemy.getPosition()); + if(distance < currentDistance) { + currentDistance = distance; + currentTarget = enemy + } + }) + if(currentTarget) { + return [currentDistance, currentTarget]; + } + } + + get player(): Player { + return this._player; + } +} \ No newline at end of file diff --git a/absurd-survivors/src/base.ts b/absurd-survivors/src/base.ts new file mode 100644 index 0000000..0264ac7 --- /dev/null +++ b/absurd-survivors/src/base.ts @@ -0,0 +1,59 @@ +export class Vector { + + constructor(private _x: number, private _y: number) { + } + + static createVector(tip: Vector, shaft: Vector): Vector { + return new Vector(tip.x - shaft.x, tip.y - shaft.y); + } + + normalize(): Vector { + let length = this.vecLength(); + return new Vector(this.x / length, this.y / length) + } + + vecLength(): number { + return Math.sqrt(this.x * this.x + this.y * this.y); + } + + distanceTo(point: Vector): number { + return Math.sqrt(Math.pow(this.x - point.x, 2) + Math.pow(this.y - point.y, 2)); + } + + add(vec: Vector): Vector { + return new Vector(this._x + vec._x, this._y + vec._y) + } + + minus(vec: Vector): Vector { + return new Vector(this.x - vec._x, this.y - vec.y) + } + + multiply(number: number): Vector { + return new Vector(this.x * number, this.y * number) + } + + multiplyVec(vec: Vector): Vector { + return new Vector(this.x * vec._x, this.y * vec.y) + } + + negate(): Vector { + return this.multiply(-1) + } + + + get x(): number { + return this._x; + } + + set x(value: number) { + this._x = value; + } + + get y(): number { + return this._y; + } + + set y(value: number) { + this._y = value; + } +} \ No newline at end of file diff --git a/absurd-survivors/src/instance.ts b/absurd-survivors/src/instance.ts new file mode 100644 index 0000000..5c58000 --- /dev/null +++ b/absurd-survivors/src/instance.ts @@ -0,0 +1,7 @@ +import type {Healthy} from "./interfaces.ts"; + +export class InstanceOfUtils { + static instanceOfHealthy(object: any): object is Healthy { + return 'takeDamage' in object; + } +} \ No newline at end of file diff --git a/absurd-survivors/src/interfaces.ts b/absurd-survivors/src/interfaces.ts new file mode 100644 index 0000000..432f560 --- /dev/null +++ b/absurd-survivors/src/interfaces.ts @@ -0,0 +1,31 @@ +import {Vector} from "./base.ts"; + +export interface Acting { + act() +} + +export interface Healthy { + takeDamage(damage: number); +} + +export interface Moving { + move() + getPosition(): Vector; +} + +export interface Projectile extends Drawable { + +} + +export interface Weapon extends Drawable{ + act() +} + +export interface Shooting { + createProjectile(): Projectile; + removeProjectile(projectile: Projectile) +} + +export interface Drawable { + draw(ctx: CanvasRenderingContext2D); +} \ No newline at end of file diff --git a/absurd-survivors/src/main.ts b/absurd-survivors/src/main.ts new file mode 100644 index 0000000..57bd976 --- /dev/null +++ b/absurd-survivors/src/main.ts @@ -0,0 +1,133 @@ +import './style.css' + +import {docReady} from "canvas-common"; +import {World} from "./World.ts"; +import {Player} from "./Player.ts"; +import {Vector} from "./base.ts"; +import {BasicEnemy, Enemy, ShootingEnemy} from "./Enemies.ts"; +import {HUD} from "./ui.ts"; +import {Pistol} from "./weapons.ts"; + + +let hud: HUD; +let world: World; +let config: Config; +let state: WorldState; +let ctx: CanvasRenderingContext2D; +let canvas; + +export class Config { + private _size: Vector = new Vector(window.innerWidth, window.innerHeight) + private _fps: number = 60; + + + get size(): Vector { + return this._size; + } + + get fps(): number { + return this._fps; + } +} + +export class WorldState { + private _ended: boolean = false; + + + get ended(): boolean { + return this._ended; + } +} + + +function updateCanvas() { + ctx.clearRect(0, 0, config.size.x, config.size.y); + hud.draw(ctx) + if(!state.ended) { + world.enemiesAct() + world.player.act() + world.draw() + for(let key in keys) { + if(keys[key].state) { + keys[key].fun() + } + } + } else { + ctx.fillText('End', 15, 15) + } + + setTimeout(function () { + requestAnimationFrame(updateCanvas); + }, 1000 / config.fps) + +} + +function makeKey(char, fun) { + keys[char] = { + state: false, + fun: fun + } +} + +let keys = {}; +makeKey('w', function () { + world.player.position.y += -world.player.stats.speed +}) +makeKey('s', function () { + world.player.position.y += world.player.stats.speed +}) +makeKey('a', function () { + world.player.position.x += -world.player.stats.speed +}) +makeKey('d', function () { + world.player.position.x += world.player.stats.speed +}) + + +function keyUp(event) { + if(event.key in keys) { + keys[event.key].state = false; + } +} + +function keyDown(event) { + if(event.key in keys) { + keys[event.key].state = true; + } +} + +document.onkeyup = keyUp; +document.onkeydown = keyDown; +docReady(function () { + canvas = document.getElementById('canvas'); + + config = new Config(); + canvas.width = config.size.x; + + canvas.height = config.size.y; + + + ctx = canvas.getContext("2d"); + + let player = Player.generatePlayer(); + + world = new World(player, ctx); + state = new WorldState(); + + world.addEnemy(BasicEnemy.generateBasicEnemy(world)) + world.addEnemy(ShootingEnemy.generateShootingEnemy(world, new Vector(350, 350))) + setInterval(() => { + world.addEnemy(ShootingEnemy.generateShootingEnemy(world, new Vector(Math.random() * config.size.x, Math.random() * config.size.y))) + }, 1000) + player.addWeapon(Pistol.spawnPistol(world)) + let secondPistol = Pistol.spawnPistol(world, new Vector(-5, -5)); + player.addWeapon(secondPistol) + hud = new HUD(world); + + + requestAnimationFrame(updateCanvas); + + + +}) + diff --git a/absurd-survivors/src/projectile.ts b/absurd-survivors/src/projectile.ts new file mode 100644 index 0000000..30914bb --- /dev/null +++ b/absurd-survivors/src/projectile.ts @@ -0,0 +1,100 @@ +import type {Acting, Moving, Healthy} from "./interfaces.ts"; +import type {Vector} from "./base.ts"; +import {World} from "./World.ts"; +import {Vector} from "./base.ts"; +import {drawDot, moveInDirectionOf, straightMove} from "./utils.ts"; +import {InstanceOfUtils} from "./instance.ts"; + +export abstract class Projectile implements Acting, Moving { + + protected position: Vector; + protected speedVec: Vector; + protected impact: number; + protected world: World; + protected size: number; + protected parent: any; + protected color: string + + + constructor(position: Vector, speedVec: Vector, world: World, parent: any) { + this.position = position; + this.speedVec = speedVec; + this.world = world; + this.parent = parent; + } + + act() { + this.move() + if(this.parent != this.world.player) { + if(this.position.distanceTo(this.world.player.position) < (this.size + this.world.player.stats.size)) { + this.impactPlayer() + } + } + if(this.parent == this.world.player) { + let closestTargetTo = this.world.getClosestTargetTo(this.position); + if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined && closestTargetTo[1]?.getPosition().distanceTo(this.position) < (this.size + this.world.player.stats.size)) { + let target: Moving = closestTargetTo[1]!; + if(InstanceOfUtils.instanceOfHealthy(target)) { + let healthy = target as Healthy; + healthy.takeDamage(this.impact) + } + } + } + + } + + impactPlayer() { + this.world.player.takeDamage(this.impact) + this.world.removeProjectile(this) + }; + + draw(ctx: CanvasRenderingContext2D) { + drawDot(this.position, this.size, this.color, ctx) + } + + move() { + } + + getPosition(): Vector { + return this.position; + } + +} + +export class StraightProjectile extends Projectile { + + + constructor(position: Vector, dirVector: Vector, world: World, parent: any) { + super(position, dirVector, world, parent); + } + + move() { + this.position = straightMove(this.position, this.speedVec) + } + + static createStraightProjectile(world: World, start: Vector, targetPosition: Vector, parent: any) { + let projectile = new StraightProjectile(start, Vector.createVector(targetPosition, start).normalize().multiply(5), world, parent) + projectile.impact = 1; + projectile.size = 1 + projectile.color = 'red'; + world.addProjectile(projectile) + return projectile; + } +} + +export class HomingProjectile extends Projectile { + + move() { + this.position = moveInDirectionOf(this.position, this.world.player.position, this.speedVec.vecLength()) + } + + static createHomingProjectile(world: World, start: Vector, parent: any) { + let projectile = new HomingProjectile(start, new Vector(5, 1), world, parent) + projectile.impact = 1; + projectile.size = 1 + projectile.color = 'red'; + world.addProjectile(projectile) + return projectile; + } + +} \ No newline at end of file diff --git a/absurd-survivors/src/style.css b/absurd-survivors/src/style.css new file mode 100644 index 0000000..cfb0669 --- /dev/null +++ b/absurd-survivors/src/style.css @@ -0,0 +1,4 @@ +html, body, div, canvas { + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/absurd-survivors/src/ui.ts b/absurd-survivors/src/ui.ts new file mode 100644 index 0000000..510125f --- /dev/null +++ b/absurd-survivors/src/ui.ts @@ -0,0 +1,72 @@ +import type {World} from "./World.ts"; +import type {Drawable} from "./interfaces.ts"; +import {World} from "./World.ts"; +import type {Vector} from "./base.ts"; +import {Vector} from "./base.ts"; + +export class HUD implements Drawable{ + private health: HealthInfo; + private world: World; + + + constructor(world: World) { + this.world = world; + this.health = new HealthInfo(world); + } + + draw(ctx: CanvasRenderingContext2D) { + this.health.draw(ctx) + } + + +} + +export class HealthInfo implements Drawable{ + private bar: InfoBar; + private world: World; + + constructor(world: World) { + this.world = world; + this.bar = new InfoBar(new Vector(0, 50), 50, 150, () => 'Health', () => this.world.player.health, () => this.world.player.stats.health) + } + + draw(ctx: CanvasRenderingContext2D) { + this.bar.draw(ctx) + } +} + +export class InfoBar implements Drawable { + private position: Vector; + private height: number; + private width: number; + private fillColor: string = 'green'; + private borderColor: string = 'black'; + private textLambda: () => string; + private valueLambda: () => number; + private totalValueLambda: () => number; + + + constructor(position: Vector, height: number, width: number, textLambda: () => string, valueLambda: () => number, totalValueLambda: () => number) { + this.position = position; + this.height = height; + this.width = width; + this.textLambda = textLambda; + this.valueLambda = valueLambda; + this.totalValueLambda = totalValueLambda; + } + + draw(ctx: CanvasRenderingContext2D) { + ctx.beginPath(); + ctx.strokeStyle = this.borderColor + ctx.strokeRect(this.position.x, this.position.y, this.width, this.height) + ctx.fillStyle = this.fillColor; + let value = this.valueLambda(); + let totalValue = this.totalValueLambda(); + let usedWidth = (value / totalValue) * this.width; + ctx.fillRect(this.position.x, this.position.y, usedWidth, this.height) + ctx.fillStyle = this.borderColor + ctx.fillText(`${value}/${totalValue}`, this.position.x + this.width / 2, this.position.y + this.height / 2) + ctx.fill() + } + +} \ No newline at end of file diff --git a/absurd-survivors/src/utils.ts b/absurd-survivors/src/utils.ts new file mode 100644 index 0000000..aae3eb8 --- /dev/null +++ b/absurd-survivors/src/utils.ts @@ -0,0 +1,18 @@ +import {Vector} from "./base.ts"; + +export function drawDot(position: Vector, size: number, color: string, ctx: CanvasRenderingContext2D) { + ctx.beginPath(); + ctx.fillStyle = color; + ctx.arc(position.x, position.y, size, 0, 2 * Math.PI); + ctx.fill(); +} + +export function moveInDirectionOf(position: Vector, target: Vector, speedFactor): Vector { + let playerVector = Vector.createVector(target, position); + let direction = playerVector.normalize() + return position.add(direction.multiply(speedFactor)) +} + +export function straightMove(position: Vector, speed: Vector): Vector { + return position.add(speed) +} \ No newline at end of file diff --git a/absurd-survivors/src/vite-env.d.ts b/absurd-survivors/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/absurd-survivors/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/absurd-survivors/src/weapons.ts b/absurd-survivors/src/weapons.ts new file mode 100644 index 0000000..d814751 --- /dev/null +++ b/absurd-survivors/src/weapons.ts @@ -0,0 +1,59 @@ +import type {Weapon} from "./interfaces.ts"; +import {drawDot} from "./utils.ts"; +import {Player} from "./Player.ts"; +import {Projectile, StraightProjectile} from "./projectile.ts"; +import {World} from "./World.ts"; +import {Vector} from "./base.ts"; + +export class Pistol implements Weapon { + + private player: Player + private shootInterval: number; + private shootCooldown: number = 0; + private world: World; + private offset: Vector; + private projectiles: [Projectile] = [] + private color: string; + private size: number; + + constructor(world: World) { + this.player = world.player; + this.world = world; + } + + draw(ctx: CanvasRenderingContext2D) { + drawDot(this.player.position.add(this.offset), this.size, this.color, ctx) + } + + act() { + if(this.shootCooldown <= 0) { + if(this.createProjectile()) { + this.shootCooldown = this.shootInterval; + } + } + this.shootCooldown -= 1; + } + + private createProjectile(): boolean { + let closestTargetTo = this.world.getClosestTargetTo(this.world.player.position); + if(closestTargetTo !== undefined && closestTargetTo[1] !== undefined) { + let projectile = StraightProjectile.createStraightProjectile(this.world, this.player.position.add(this.offset), closestTargetTo[1]!.getPosition(), this.player) + this.projectiles.push(projectile) + return true + } else { + return false; + } + } + + static spawnPistol(world: World, offset?: Vector) { + if(!offset) { + offset = new Vector(5, 5) + } + let pistol = new Pistol(world) + pistol.offset = offset; + pistol.size = 1; + pistol.color = 'yellow'; + pistol.shootInterval = 10; + return pistol; + } +} \ No newline at end of file diff --git a/absurd-survivors/tsconfig.json b/absurd-survivors/tsconfig.json new file mode 100644 index 0000000..4f5edc2 --- /dev/null +++ b/absurd-survivors/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/absurd-survivors/vite.config.js b/absurd-survivors/vite.config.js new file mode 100644 index 0000000..991563c --- /dev/null +++ b/absurd-survivors/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + build: { + outDir: '../../dist/survivors' + }, +}) \ No newline at end of file diff --git a/img/survivors.png b/img/survivors.png new file mode 100644 index 0000000000000000000000000000000000000000..80d50f10042479f1a399d126324cfd6cffa1fd7a GIT binary patch literal 40381 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 E|N6d?0;K_a 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 Vbzd2WYcc=;002ovPDHLkV1kfXpv3?H literal 0 HcmV?d00001 diff --git a/index.html b/index.html index bc5ea38..9f1fbea 100644 --- a/index.html +++ b/index.html @@ -18,5 +18,6 @@ clusterFilter collatzConjecture dotLines + survivors \ No newline at end of file