From 0de74e11a397d8d9d4d922262758ddfc07309fc9 Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:01:36 +0200 Subject: [PATCH] bubbles: added --- .github/workflows/build.yml | 6 + bubbles/package-lock.json | 872 ++++++++++++++++++++++++++++++++++++ bubbles/package.json | 19 + bubbles/src/index.html | 22 + bubbles/src/js/main.js | 137 ++++++ bubbles/src/js/plugins.js | 24 + bubbles/vite.config.js | 9 + canvas-common/common.js | 4 + img/bubbles.png | Bin 0 -> 24897 bytes index.html | 1 + 10 files changed, 1094 insertions(+) create mode 100644 bubbles/package-lock.json create mode 100644 bubbles/package.json create mode 100644 bubbles/src/index.html create mode 100644 bubbles/src/js/main.js create mode 100644 bubbles/src/js/plugins.js create mode 100644 bubbles/vite.config.js create mode 100644 img/bubbles.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22a143c..af1ff20 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,6 +52,12 @@ jobs: - name: fireWorks Build run: npx vite build working-directory: fireWorks + - name: bubbles Install dependencies + run: npm install + working-directory: bubbles + - name: bubbles Build + run: npx vite build + working-directory: bubbles - name: Move index run: cp index.html dist/ - name: Move overview images diff --git a/bubbles/package-lock.json b/bubbles/package-lock.json new file mode 100644 index 0000000..f5ecbe9 --- /dev/null +++ b/bubbles/package-lock.json @@ -0,0 +1,872 @@ +{ + "name": "bubbles", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bubbles", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "canvas-common": "file:../canvas-common" + }, + "devDependencies": { + "vite": "^5.1.5" + } + }, + "../canvas-common": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/canvas-common": { + "resolved": "../canvas-common", + "link": true + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "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", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "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" + } + ], + "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.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "dev": true, + "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.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vite": { + "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + } +} diff --git a/bubbles/package.json b/bubbles/package.json new file mode 100644 index 0000000..3f5dbf7 --- /dev/null +++ b/bubbles/package.json @@ -0,0 +1,19 @@ +{ + "name": "bubbles", + "version": "1.0.0", + "description": "", + "private": true, + "type": "module", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "dependencies": { + "canvas-common": "file:../canvas-common" + }, + "devDependencies": { + "vite": "^5.1.5" + } +} diff --git a/bubbles/src/index.html b/bubbles/src/index.html new file mode 100644 index 0000000..4b9b697 --- /dev/null +++ b/bubbles/src/index.html @@ -0,0 +1,22 @@ + + + + + + bubbles + + + + + + + + + diff --git a/bubbles/src/js/main.js b/bubbles/src/js/main.js new file mode 100644 index 0000000..2dde60f --- /dev/null +++ b/bubbles/src/js/main.js @@ -0,0 +1,137 @@ +import { + createRainbowColors, docReady, pointDistance, randomInteger +} from "canvas-common"; + +var imageData = {}; +var ctx = {}; +var canvas = {}; + + +var config = { + size: { + width: window.innerWidth, + height: window.innerHeight + }, + buBbles: { + tileSize: 100, + growFactorDivider: 5, + radiusFactor: 1, + bubbleChance: 0.5 + } +}; + +var rainbow = createRainbowColors(1/16); +// max distance from top left corner +var max = Math.sqrt(Math.pow(config.size.width + config.buBbles.tileSize, 2) + Math.pow(config.size.height + config.buBbles.tileSize, 2)); +var startOffset = (rainbow.length * Math.random()) << 0; + +function getRandomPoint(x, y) { + var distance = Math.sqrt(x * x + y * y); + var index = ((startOffset + distance / max * 100) << 0) % rainbow.length; + var color = rainbow[index]; + color.a = 255; + return { + x: x + Math.random() * config.buBbles.tileSize, + y: y + Math.random() * config.buBbles.tileSize, + factor: Math.random() / config.buBbles.growFactorDivider, + radius: Math.random() * config.buBbles.radiusFactor, + color: color + }; +} + +function getTilePoints(){ + var points = []; + for(var x = 0; x < config.size.width; x += config.buBbles.tileSize){ + for(var y = 0; y < config.size.height; y += config.buBbles.tileSize){ + points.push(getRandomPoint(x, y)); + } + } + return points; +} + +docReady(function () { + canvas = document.getElementById('canvas') + ctx = canvas.getContext("2d"); + canvas.width = config.size.width; + canvas.height = config.size.height; + + var pointsOfInterest = getTilePoints(); + removeIntersecting(pointsOfInterest); + updateCanvas(pointsOfInterest); +}); + +function grow(points){ + for(var i = 0; i < points.length; i++){ + var currentPoint = points[i]; + if(!intersectsAnotherPoint(currentPoint, points)){ + currentPoint.radius += currentPoint.factor; + } else if(!currentPoint.spawnedAnother){ + currentPoint.spawnedAnother = true; + currentPoint.radius += currentPoint.factor; + addAnotherRandomPoint(points); + } + } + + if(Math.random() < config.buBbles.bubbleChance){ + addAnotherRandomPoint(points); + } +} + +function addAnotherRandomPoint(points){ + var probablePoint = getRandomPoint(randomInteger(config.size.width), randomInteger(config.size.height)); + if(!intersectsAnotherPoint(probablePoint, points)){ + points.push(probablePoint); + } +} + +function intersectsAnotherPoint(point, points){ + var intersects = false; + points.forEach(function(pointToLookAt){ + if(intersects) return; + var pointDist = pointDistance(point, pointToLookAt); + if(pointDist > 0 && pointDist < (point.radius + pointToLookAt.radius)){ + intersects = true; + } + }); + + return intersects; +} + +function updateCanvas(points){ + ctx.clearRect(0, 0, config.size.width, config.size.height); + grow(points); + paintPoints(points, function(){ + requestAnimationFrame(function(){ + updateCanvas(points); + }); + }); + +} + + +function removeIntersecting(points){ + for(var i = 0; i < points.length; ){ + if(intersectsAnotherPoint(points[i], points)){ + points.splice(i, 1); + } else { + i++; + } + } +} + + +function paintPoints(points, cb){ + for(var i = 0; i < points.length; i++){ + var point = points[i]; + if(point.radius < 0) continue; + ctx.beginPath(); + ctx.fillStyle = point.color.styleRGB; + ctx.arc(point.x, point.y, point.radius, 0, 2 * Math.PI); + ctx.fill(); + } + cb(); +} + + + + diff --git a/bubbles/src/js/plugins.js b/bubbles/src/js/plugins.js new file mode 100644 index 0000000..f887480 --- /dev/null +++ b/bubbles/src/js/plugins.js @@ -0,0 +1,24 @@ +// Avoid `console` errors in browsers that lack a console. +(function() { + var method; + var noop = function () {}; + var methods = [ + 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', + 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', + 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', + 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn' + ]; + var length = methods.length; + var console = (window.console = window.console || {}); + + while (length--) { + method = methods[length]; + + // Only stub undefined methods. + if (!console[method]) { + console[method] = noop; + } + } +}()); + +// Place any jQuery/helper plugins in here. diff --git a/bubbles/vite.config.js b/bubbles/vite.config.js new file mode 100644 index 0000000..efa7e7c --- /dev/null +++ b/bubbles/vite.config.js @@ -0,0 +1,9 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + base: './', + root: 'src', + build: { + outDir: '../../dist/bubbles' + } +}) diff --git a/canvas-common/common.js b/canvas-common/common.js index e4ba660..624f9f1 100644 --- a/canvas-common/common.js +++ b/canvas-common/common.js @@ -142,3 +142,7 @@ export function angleBetweenTwoVectors(vectorA, vectorB){ export function dotProduct(vector1, vector2) { return vector1.x * vector2.x + vector1.y * vector2.y; } + +export function randomInteger(n){ + return (Math.random() * n) << 0 +} diff --git a/img/bubbles.png b/img/bubbles.png new file mode 100644 index 0000000000000000000000000000000000000000..39327262315f75f043f60aedf7b76d549a4fb66c GIT binary patch literal 24897 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 bubbles
Fireworks Balls + Bubbles \ No newline at end of file