mirror of
https://github.com/Sheldan/canvas.git
synced 2026-01-01 06:49:08 +00:00
sling: dumping current content
This commit is contained in:
24
sling/.gitignore
vendored
Normal file
24
sling/.gitignore
vendored
Normal file
@@ -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?
|
||||
12
sling/index.html
Normal file
12
sling/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>sling</title>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
971
sling/package-lock.json
generated
Normal file
971
sling/package-lock.json
generated
Normal file
@@ -0,0 +1,971 @@
|
||||
{
|
||||
"name": "sling",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sling",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^6.2.0"
|
||||
}
|
||||
},
|
||||
"../canvas-common": {
|
||||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
|
||||
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
|
||||
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
|
||||
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
|
||||
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
|
||||
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
|
||||
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
|
||||
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
|
||||
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
|
||||
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
|
||||
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz",
|
||||
"integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz",
|
||||
"integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz",
|
||||
"integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz",
|
||||
"integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz",
|
||||
"integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz",
|
||||
"integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz",
|
||||
"integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz",
|
||||
"integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz",
|
||||
"integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz",
|
||||
"integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz",
|
||||
"integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz",
|
||||
"integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz",
|
||||
"integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz",
|
||||
"integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz",
|
||||
"integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz",
|
||||
"integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz",
|
||||
"integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz",
|
||||
"integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz",
|
||||
"integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/canvas-common": {
|
||||
"resolved": "../canvas-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
|
||||
"integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.25.0",
|
||||
"@esbuild/android-arm": "0.25.0",
|
||||
"@esbuild/android-arm64": "0.25.0",
|
||||
"@esbuild/android-x64": "0.25.0",
|
||||
"@esbuild/darwin-arm64": "0.25.0",
|
||||
"@esbuild/darwin-x64": "0.25.0",
|
||||
"@esbuild/freebsd-arm64": "0.25.0",
|
||||
"@esbuild/freebsd-x64": "0.25.0",
|
||||
"@esbuild/linux-arm": "0.25.0",
|
||||
"@esbuild/linux-arm64": "0.25.0",
|
||||
"@esbuild/linux-ia32": "0.25.0",
|
||||
"@esbuild/linux-loong64": "0.25.0",
|
||||
"@esbuild/linux-mips64el": "0.25.0",
|
||||
"@esbuild/linux-ppc64": "0.25.0",
|
||||
"@esbuild/linux-riscv64": "0.25.0",
|
||||
"@esbuild/linux-s390x": "0.25.0",
|
||||
"@esbuild/linux-x64": "0.25.0",
|
||||
"@esbuild/netbsd-arm64": "0.25.0",
|
||||
"@esbuild/netbsd-x64": "0.25.0",
|
||||
"@esbuild/openbsd-arm64": "0.25.0",
|
||||
"@esbuild/openbsd-x64": "0.25.0",
|
||||
"@esbuild/sunos-x64": "0.25.0",
|
||||
"@esbuild/win32-arm64": "0.25.0",
|
||||
"@esbuild/win32-ia32": "0.25.0",
|
||||
"@esbuild/win32-x64": "0.25.0"
|
||||
}
|
||||
},
|
||||
"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,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.9",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz",
|
||||
"integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==",
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||
"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.8",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.35.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz",
|
||||
"integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.6"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.35.0",
|
||||
"@rollup/rollup-android-arm64": "4.35.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.35.0",
|
||||
"@rollup/rollup-darwin-x64": "4.35.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.35.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.35.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.35.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.35.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.35.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.35.0",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.35.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.35.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.35.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.35.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.35.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.35.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.35.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.35.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.35.0",
|
||||
"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,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
||||
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz",
|
||||
"integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.30.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.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 || >=22.0.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
sling/package.json
Normal file
18
sling/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "sling",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"canvas-common": "file:../canvas-common"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^6.2.0"
|
||||
}
|
||||
}
|
||||
97
sling/src/abstracts.ts
Normal file
97
sling/src/abstracts.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import {World} from "./data.ts";
|
||||
import {PointGravitySource} from "./objects.ts";
|
||||
import {BoundingBox, Circle, Line, Vector} from "./vector.ts";
|
||||
|
||||
export interface Drawable extends Item, Positionable {
|
||||
draw(ctx)
|
||||
}
|
||||
|
||||
export interface Actable extends Item {
|
||||
act(world: World)
|
||||
}
|
||||
|
||||
export enum CollisionBehaviour {
|
||||
CIRCLE,
|
||||
LINE
|
||||
}
|
||||
|
||||
export interface Collidable extends Item {
|
||||
collide(world: World, collidable: Collidable);
|
||||
boundingBox(): BoundingBox;
|
||||
geometricCollisionBehaviour(): CollisionBehaviour;
|
||||
}
|
||||
|
||||
export interface Gravitatable extends Item {
|
||||
affect(gravitySource: PointGravitySource)
|
||||
}
|
||||
|
||||
export interface Circable {
|
||||
getCircle(): Circle;
|
||||
}
|
||||
|
||||
export interface Lineable {
|
||||
getLine(): Line;
|
||||
}
|
||||
|
||||
export interface Positionable {
|
||||
get position(): Vector;
|
||||
set position(vector: Vector);
|
||||
}
|
||||
|
||||
export interface MassOwning {
|
||||
get mass(): number;
|
||||
set mass(mass: number);
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
id(): number;
|
||||
}
|
||||
|
||||
export abstract class AbstractItem implements Item {
|
||||
private _id: number;
|
||||
private _flag: boolean;
|
||||
|
||||
protected constructor() {
|
||||
this._id = ~~(Math.random() * 10000000)
|
||||
this._flag = false;
|
||||
}
|
||||
|
||||
id(): number {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export abstract class MovingItem extends AbstractItem implements Positionable, Actable {
|
||||
|
||||
private _speed: Vector;
|
||||
private _position: Vector;
|
||||
|
||||
constructor(_x?: number,
|
||||
_y?: number,
|
||||
_x_speed?: number,
|
||||
_y_speed?: number) {
|
||||
super();
|
||||
this._position = new Vector(_x?? 0, _y?? 0)
|
||||
this._speed = new Vector(_x_speed?? 0, _y_speed?? 0)
|
||||
}
|
||||
|
||||
act(world: World) {
|
||||
this._position = this.position.plus(this._speed)
|
||||
}
|
||||
|
||||
get speed(): Vector {
|
||||
return this._speed;
|
||||
}
|
||||
set speed(vector: Vector){
|
||||
this._speed = vector;
|
||||
}
|
||||
accelerate(vector: Vector) {
|
||||
this._speed = this.speed.plus(vector)
|
||||
}
|
||||
|
||||
get position(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
}
|
||||
246
sling/src/collision.ts
Normal file
246
sling/src/collision.ts
Normal file
@@ -0,0 +1,246 @@
|
||||
import {Circle, Line, Vector} from "./vector.ts";
|
||||
import {Circable, Collidable, CollisionBehaviour, Drawable, Lineable, MassOwning, MovingItem} from "./abstracts.ts";
|
||||
import {InstanceOfUtils} from "./instances.ts";
|
||||
|
||||
export enum CollisionType {
|
||||
MISS = 0,
|
||||
HIT = 1,
|
||||
}
|
||||
|
||||
export class CollisionResult {
|
||||
constructor(private _type: CollisionType, private _collisionLocation?: Vector) {
|
||||
|
||||
}
|
||||
|
||||
static miss(): CollisionResult {
|
||||
return new CollisionResult(CollisionType.MISS)
|
||||
}
|
||||
|
||||
static hit(point: Vector): CollisionResult {
|
||||
return new CollisionResult(CollisionType.HIT, point)
|
||||
}
|
||||
|
||||
get type(): CollisionType {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
get collision(): Vector | undefined {
|
||||
return this._collisionLocation;
|
||||
}
|
||||
}
|
||||
|
||||
class CollisionPair {
|
||||
constructor(private _first: CollisionBehaviour, private _second: CollisionBehaviour) {
|
||||
}
|
||||
|
||||
|
||||
get first(): CollisionBehaviour {
|
||||
return this._first;
|
||||
}
|
||||
|
||||
get second(): CollisionBehaviour {
|
||||
return this._second;
|
||||
}
|
||||
}
|
||||
|
||||
export class CollisionManager {
|
||||
|
||||
private collTypes = new Map<CollisionPair, (first: Collidable, second: Collidable) => CollisionResult>();
|
||||
private collReactions = new Map<CollisionPair, (first: Collidable, second: Collidable, point: Vector) => void>();
|
||||
|
||||
constructor() {
|
||||
this.addCollisionMapper(CollisionBehaviour.LINE, CollisionBehaviour.CIRCLE, this.circleLine)
|
||||
this.addCollisionMapper(CollisionBehaviour.CIRCLE, CollisionBehaviour.CIRCLE, this.circleCircle)
|
||||
this.addCollisionReactions(CollisionBehaviour.LINE, CollisionBehaviour.CIRCLE, this.circleLineAngleOut)
|
||||
this.addCollisionReactions(CollisionBehaviour.CIRCLE, CollisionBehaviour.CIRCLE, this.circleCircleAngleOut)
|
||||
}
|
||||
|
||||
private addCollisionMapper(first: CollisionBehaviour, second: CollisionBehaviour, method: (first: Collidable, second: Collidable) => CollisionResult) {
|
||||
this.collTypes.set(new CollisionPair(first, second), method)
|
||||
this.collTypes.set(new CollisionPair(second, first), method)
|
||||
}
|
||||
|
||||
private addCollisionReactions(first: CollisionBehaviour, second: CollisionBehaviour, method: (first: Collidable, second: Collidable, point: Vector) => void) {
|
||||
this.collReactions.set(new CollisionPair(first, second), method)
|
||||
this.collReactions.set(new CollisionPair(second, first), method)
|
||||
}
|
||||
|
||||
private getCollisionPair(first: CollisionBehaviour, second: CollisionBehaviour): CollisionPair | undefined {
|
||||
for (let [key, value] of this.collTypes.entries()) {
|
||||
if(key.first === first && key.second === second) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getCollisionReactionPair(first: CollisionBehaviour, second: CollisionBehaviour): CollisionPair | undefined {
|
||||
for (let [key, value] of this.collReactions.entries()) {
|
||||
if(key.first === first && key.second === second) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
collide(collidable: Collidable, secondCollidable: Collidable): CollisionResult {
|
||||
if(collidable.boundingBox().intersect(secondCollidable.boundingBox())) {
|
||||
let collisionPair = this.getCollisionPair(collidable.geometricCollisionBehaviour(), secondCollidable.geometricCollisionBehaviour());
|
||||
if(collisionPair) {
|
||||
let functionToExecute = this.collTypes.get(collisionPair);
|
||||
let collision = functionToExecute(collidable, secondCollidable);
|
||||
if(collision.type === CollisionType.HIT) {
|
||||
let reactionPair = this.getCollisionReactionPair(collidable.geometricCollisionBehaviour(), secondCollidable.geometricCollisionBehaviour());
|
||||
if(reactionPair) {
|
||||
let functionToExecute = this.collReactions.get(reactionPair);
|
||||
functionToExecute(collidable, secondCollidable, collision.collision!);
|
||||
return collision;
|
||||
} else {
|
||||
console.log(`Did not find a collision reaction pair between ${collidable.geometricCollisionBehaviour()} and ${secondCollidable.geometricCollisionBehaviour()}`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(`Did not find a collision pair between ${collidable.geometricCollisionBehaviour()} and ${secondCollidable.geometricCollisionBehaviour()}`)
|
||||
}
|
||||
}
|
||||
return CollisionResult.miss();
|
||||
}
|
||||
|
||||
circleLineAngleOut(first: Collidable, second: Collidable, collisionPoint: Vector): void {
|
||||
let firstCircle = first instanceof MovingItem;
|
||||
let secondCircle = first instanceof MovingItem;
|
||||
if(firstCircle || secondCircle) {
|
||||
let res = CollisionManager.getCircleLine(first, second);
|
||||
let circle = res.circle;
|
||||
let line= res.line;
|
||||
|
||||
let movingItem: MovingItem;
|
||||
if(firstCircle) {
|
||||
movingItem = first as MovingItem;
|
||||
} else {
|
||||
movingItem = second as MovingItem;
|
||||
}
|
||||
let vector = Vector.between(collisionPoint, circle.center).normalize()
|
||||
let lineNormal = line.toVector().normal();
|
||||
let secondLineNormal = line.toVector().otherNormal();
|
||||
let normalToUse = secondLineNormal;
|
||||
if(movingItem.speed.angleBetween(lineNormal) < movingItem.speed.angleBetween(secondLineNormal)) {
|
||||
normalToUse = lineNormal;
|
||||
}
|
||||
let normal = normalToUse.normalize()
|
||||
let distanceAlongNormal = vector.x * normal.x + vector.y * normal.y
|
||||
let x = - 2.0 * distanceAlongNormal * normal.x
|
||||
let y = - 2.0 * distanceAlongNormal * normal.y
|
||||
movingItem.speed = new Vector(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
circleCircleAngleOut(first: Collidable, second: Collidable, collisionPoint: Vector): void {
|
||||
if(first instanceof MovingItem && second instanceof MovingItem) {
|
||||
let firstMass = 1;
|
||||
let firstHasMass = false;
|
||||
if(InstanceOfUtils.instanceOfMassOwning(first)) {
|
||||
firstMass = (first as MassOwning).mass;
|
||||
firstHasMass = true;
|
||||
}
|
||||
|
||||
let secondMass = 1;
|
||||
let secondHasMass = false;
|
||||
if(InstanceOfUtils.instanceOfMassOwning(second)) {
|
||||
secondMass = (second as MassOwning).mass;
|
||||
secondHasMass = true;
|
||||
}
|
||||
let useMass = firstHasMass && secondHasMass;
|
||||
let firstMassFactor = useMass ? 2 * secondMass / (firstMass + secondMass) : 1;
|
||||
let secondMassFactor = useMass ? 2 * firstMass / (firstMass + secondMass) : 1;
|
||||
let v1MinV2 = first.speed.minus(second.speed)
|
||||
let x1MinX2 = first.position.minus(second.position)
|
||||
let v1 = x1MinX2.multNumber(v1MinV2.dot(x1MinX2) / (x1MinX2.secondNorm() ** 2) * firstMassFactor)
|
||||
first.speed = first.speed.minus(v1);
|
||||
|
||||
let v2MinV1 = second.speed.minus(first.speed)
|
||||
let x2Minx1 = second.position.minus(first.position)
|
||||
let v2 = x2Minx1.multNumber(v2MinV1.dot(x2Minx1) / (x2Minx1.secondNorm() ** 2) * secondMassFactor)
|
||||
second.speed = second.speed.minus(v2);
|
||||
} else {
|
||||
let movingItem;
|
||||
let notMovingItem;
|
||||
if(first instanceof MovingItem) {
|
||||
movingItem = first;
|
||||
notMovingItem = second;
|
||||
} else if(second instanceof MovingItem) {
|
||||
movingItem = second;
|
||||
notMovingItem = first;
|
||||
}
|
||||
let movingCircle = (movingItem as Circable).getCircle();
|
||||
let fixedCircle = (notMovingItem as Circable).getCircle();
|
||||
let directionVector = Vector.between(collisionPoint, fixedCircle.center).normalize();
|
||||
let vector = directionVector.normal();
|
||||
let circleNormal = vector.normal()
|
||||
let otherCircleNormal = vector.otherNormal()
|
||||
let normalToUse = circleNormal;
|
||||
if(movingItem.speed.angleBetween(otherCircleNormal) < movingItem.speed.angleBetween(circleNormal)) {
|
||||
normalToUse = otherCircleNormal;
|
||||
}
|
||||
let normal = normalToUse.normalize()
|
||||
let distanceAlongNormal = movingItem.speed.x * normal.x + movingItem.speed.y * normal.y
|
||||
let x = movingItem.speed.x - 2.0 * distanceAlongNormal * normal.x
|
||||
let y = movingItem.speed.y - 2.0 * distanceAlongNormal * normal.y
|
||||
movingItem.speed = new Vector(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
private circleCircle(first: Collidable, second: Collidable) {
|
||||
let firstCircle = (first as Circable).getCircle();
|
||||
let secondCircle = (second as Circable).getCircle();
|
||||
if(!firstCircle.circleCollision(secondCircle)) {
|
||||
return CollisionResult.miss();
|
||||
}
|
||||
|
||||
let vectorBetween = Vector.between(firstCircle.center, secondCircle.center);
|
||||
let collisionPoint = secondCircle.center.plus(vectorBetween.normalize().multNumber(secondCircle.radius));
|
||||
return CollisionResult.hit(collisionPoint)
|
||||
}
|
||||
|
||||
private circleLine(first: Collidable, second: Collidable): CollisionResult {
|
||||
let res = CollisionManager.getCircleLine(first, second);
|
||||
let circle = res.circle;
|
||||
let line= res.line;
|
||||
let collisionPoint = Vector.zero();
|
||||
let dot = ((circle.center.x - line.start.x) * (line.end.x - line.start.x) + (circle.center.y - line.start.y) * (line.end.y - line.start.y)) / Math.pow(line.len, 2)
|
||||
if (circle.pointInside(line.start) || circle.pointInside(line.end)) {
|
||||
collisionPoint = circle.center;
|
||||
} else {
|
||||
let closestX = line.start.x + dot * (line.end.x - line.start.x)
|
||||
let closestY = line.start.y + dot * (line.end.y - line.start.y)
|
||||
let closestPoint = new Vector(closestX, closestY);
|
||||
if (!line.pointCollision(closestPoint)) {
|
||||
return CollisionResult.miss();
|
||||
}
|
||||
let distance = closestPoint.distanceTo(circle.center)
|
||||
if (distance <= circle.radius) {
|
||||
collisionPoint = closestPoint;
|
||||
} else {
|
||||
return CollisionResult.miss();
|
||||
}
|
||||
}
|
||||
return CollisionResult.hit(collisionPoint)
|
||||
}
|
||||
|
||||
|
||||
private static getCircleLine(first: Collidable, second: Collidable): {circle: Circle, line: Line} {
|
||||
let circle;
|
||||
if (InstanceOfUtils.instanceOfCircable(first)) {
|
||||
circle = (first as Circable).getCircle();
|
||||
} else if (InstanceOfUtils.instanceOfCircable(second)) {
|
||||
circle = (second as Circable).getCircle();
|
||||
}
|
||||
let line;
|
||||
if (InstanceOfUtils.instanceOfLineable(first)) {
|
||||
line = (first as Lineable).getLine();
|
||||
} else if (InstanceOfUtils.instanceOfLineable(second)) {
|
||||
line = (second as Lineable).getLine();
|
||||
}
|
||||
return {circle, line};
|
||||
}
|
||||
}
|
||||
87
sling/src/data.ts
Normal file
87
sling/src/data.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import {Actable, Collidable, Drawable, Gravitatable, Item} from "./abstracts.ts";
|
||||
import {PointGravitySource} from "./objects.ts";
|
||||
import {InstanceOfUtils} from "./instances.ts";
|
||||
import {CollisionManager} from "./collision.ts";
|
||||
|
||||
export class World {
|
||||
private _items: Item[] = [];
|
||||
private _drawable: Drawable[] = [];
|
||||
private _actable: Actable[] = [];
|
||||
private _collidable: Collidable[] = [];
|
||||
private _gravitatable: Gravitatable[] = [];
|
||||
|
||||
private _collisionManager: CollisionManager = new CollisionManager();
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
addItem(item: Item) {
|
||||
this._items.push(item)
|
||||
if(InstanceOfUtils.instanceOfDrawable(item)) {
|
||||
this._drawable.push(item)
|
||||
}
|
||||
|
||||
if(InstanceOfUtils.instanceOfActable(item)) {
|
||||
this._actable.push(item)
|
||||
}
|
||||
|
||||
if(InstanceOfUtils.instanceOfGravitatable(item)) {
|
||||
this._gravitatable.push(item)
|
||||
}
|
||||
if(InstanceOfUtils.instanceOfCollidable(item)) {
|
||||
this._collidable.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
removeItem(itemToRemove: Item) {
|
||||
this._items = this._items.filter(item => item.id() !== itemToRemove.id())
|
||||
|
||||
if(InstanceOfUtils.instanceOfDrawable(itemToRemove)) {
|
||||
this._drawable = this._drawable.filter(item => item.id() !== itemToRemove.id())
|
||||
}
|
||||
|
||||
if(InstanceOfUtils.instanceOfActable(itemToRemove)) {
|
||||
this._actable = this._actable.filter(item => item.id() !== itemToRemove.id())
|
||||
}
|
||||
|
||||
if(InstanceOfUtils.instanceOfGravitatable(itemToRemove)) {
|
||||
this._gravitatable = this._gravitatable.filter(item => item.id() !== itemToRemove.id())
|
||||
}
|
||||
|
||||
if(InstanceOfUtils.instanceOfCollidable(itemToRemove)) {
|
||||
this._collidable = this._collidable.filter(item => item.id() !== itemToRemove.id())
|
||||
}
|
||||
}
|
||||
|
||||
act() {
|
||||
this.collide()
|
||||
this._actable.forEach(value => value.act(this))
|
||||
}
|
||||
|
||||
collide() {
|
||||
let collisionsDone = {}
|
||||
this._collidable.forEach(value => {
|
||||
this._collidable.forEach(innerCollidable => {
|
||||
let collidableKey = Math.min(value.id(), innerCollidable.id()) + '_' + Math.max(value.id(), innerCollidable.id());
|
||||
if(value.id() !== innerCollidable.id() && !(collidableKey in collisionsDone)) {
|
||||
value.collide(this, innerCollidable);
|
||||
collisionsDone[collidableKey] = 1;
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
this._drawable.forEach(value => value.draw(ctx))
|
||||
}
|
||||
|
||||
applyGravity(gravitySource: PointGravitySource) {
|
||||
this._gravitatable.forEach(value => value.affect(gravitySource))
|
||||
}
|
||||
|
||||
|
||||
get collisionManager(): CollisionManager {
|
||||
return this._collisionManager;
|
||||
}
|
||||
}
|
||||
|
||||
8
sling/src/generic.ts
Normal file
8
sling/src/generic.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export class Color {
|
||||
constructor(private _r: number, private _g: number, private _b: number, private _a?: number) {
|
||||
}
|
||||
|
||||
repr(): string {
|
||||
return `rgb(${this._r}, ${this._g}, ${this._b})`
|
||||
}
|
||||
}
|
||||
31
sling/src/instances.ts
Normal file
31
sling/src/instances.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {Actable, Circable, Collidable, Drawable, Gravitatable, Lineable, MassOwning} from "./abstracts.ts";
|
||||
|
||||
export class InstanceOfUtils {
|
||||
static instanceOfCircable(object: any): object is Circable{
|
||||
return 'getCircle' in object;
|
||||
}
|
||||
|
||||
static instanceOfLineable(object: any): object is Lineable {
|
||||
return 'getLine' in object;
|
||||
}
|
||||
|
||||
static instanceOfDrawable(object: any): object is Drawable {
|
||||
return 'draw' in object;
|
||||
}
|
||||
|
||||
static instanceOfGravitatable(object: any): object is Gravitatable {
|
||||
return 'affect' in object;
|
||||
}
|
||||
|
||||
static instanceOfCollidable(object: any): object is Collidable {
|
||||
return 'collide' in object;
|
||||
}
|
||||
|
||||
static instanceOfActable(object: any): object is Actable {
|
||||
return 'act' in object;
|
||||
}
|
||||
|
||||
static instanceOfMassOwning(object: any): object is MassOwning {
|
||||
return 'mass' in object;
|
||||
}
|
||||
}
|
||||
72
sling/src/main.ts
Normal file
72
sling/src/main.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {docReady} from "canvas-common";
|
||||
|
||||
import './style.css'
|
||||
import {World} from "./data.ts";
|
||||
import {Bubble, CircleBarrier, PointGravitySource, LineBarrier, DirectionalGravitySource} from "./objects.ts";
|
||||
import {Vector} from "./vector.ts";
|
||||
|
||||
let canvas;
|
||||
let ctx;
|
||||
let animationId;
|
||||
|
||||
let world = new World();
|
||||
|
||||
let config = {
|
||||
general: {
|
||||
size: {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth
|
||||
},
|
||||
fps: 60,
|
||||
debug: true
|
||||
}
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window { config: any; }
|
||||
}
|
||||
|
||||
window.config = config;
|
||||
|
||||
function loadWorld() {
|
||||
let borderSize = 0;
|
||||
world.addItem(new PointGravitySource(config.general.size.width / 2, config.general.size.height / 2, 10))
|
||||
for (let i = 0; i < 12; i++) {
|
||||
world.addItem(new Bubble(config.general.size.width * Math.random(), config.general.size.height * Math.random(), Math.random() * 25))
|
||||
}
|
||||
|
||||
// diamond shape
|
||||
//world.addItem(new LineBarrier(new Vector(config.general.size.width / 2, 0), new Vector(config.general.size.width, config.general.size.height / 2)))
|
||||
//world.addItem(new LineBarrier(new Vector(config.general.size.width, config.general.size.height / 2), new Vector(config.general.size.width / 2, config.general.size.height)))
|
||||
//world.addItem(new LineBarrier(new Vector(config.general.size.width / 2, config.general.size.height), new Vector(0, config.general.size.height / 2)))
|
||||
//world.addItem(new LineBarrier(new Vector(0, config.general.size.height / 2), new Vector(config.general.size.width / 2, 0)))
|
||||
|
||||
world.addItem(new CircleBarrier(new Vector(config.general.size.width / 2, config.general.size.height / 2), 150));
|
||||
// borders
|
||||
world.addItem(new LineBarrier(new Vector(borderSize, borderSize), new Vector(config.general.size.width - borderSize, borderSize)))
|
||||
world.addItem(new LineBarrier(new Vector(config.general.size.width - borderSize, borderSize), new Vector(config.general.size.width - borderSize, config.general.size.height - borderSize)))
|
||||
world.addItem(new LineBarrier(new Vector(borderSize, config.general.size.height - borderSize), new Vector(config.general.size.width - borderSize, config.general.size.height - borderSize)))
|
||||
world.addItem(new LineBarrier(new Vector(borderSize, config.general.size.height - borderSize), new Vector(borderSize, borderSize)))
|
||||
}
|
||||
|
||||
docReady(function() {
|
||||
canvas = document.getElementById('canvas')
|
||||
canvas.width = config.general.size.width;
|
||||
canvas.height = config.general.size.height;
|
||||
ctx = canvas.getContext("2d");
|
||||
ctx.translate(0.5, 0.5); // to make better anti-aliasing
|
||||
loadWorld();
|
||||
requestAnimationFrame(render);
|
||||
});
|
||||
|
||||
|
||||
function render() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
world.draw(ctx);
|
||||
world.act()
|
||||
setTimeout(function () {
|
||||
animationId = requestAnimationFrame(render);
|
||||
}, 1000 / config.general.fps)
|
||||
}
|
||||
|
||||
|
||||
331
sling/src/objects.ts
Normal file
331
sling/src/objects.ts
Normal file
@@ -0,0 +1,331 @@
|
||||
import {
|
||||
AbstractItem,
|
||||
Actable,
|
||||
Circable,
|
||||
Collidable,
|
||||
CollisionBehaviour,
|
||||
Drawable,
|
||||
Gravitatable,
|
||||
Lineable,
|
||||
MassOwning,
|
||||
MovingItem,
|
||||
Positionable
|
||||
} from "./abstracts.ts";
|
||||
import {Color} from "./generic.ts";
|
||||
import {World} from "./data.ts";
|
||||
import {BoundingBox, Circle, Line, Vector} from "./vector.ts";
|
||||
import {CollisionType} from "./collision.ts";
|
||||
|
||||
export class Bubble extends MovingItem implements Gravitatable, Drawable, Collidable, Circable, MassOwning {
|
||||
private _radius: number;
|
||||
private _color: Color;
|
||||
private _score: number;
|
||||
private _mass: number
|
||||
|
||||
constructor(_x: number,
|
||||
_y: number,
|
||||
radius?: number,
|
||||
color?: Color,
|
||||
_speed?: Vector,
|
||||
_score?: number) {
|
||||
super(_x, _y, _speed?.x ?? 0, _speed?.y ?? 0)
|
||||
this._radius = radius ?? 10;
|
||||
this._color = color ?? new Color(120, 120, 120);
|
||||
this._score = _score ?? 1;
|
||||
this._mass = 1;
|
||||
}
|
||||
|
||||
|
||||
act(world: World) {
|
||||
super.act(world);
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
ctx.beginPath();
|
||||
if (this.color) {
|
||||
ctx.fillStyle = this.color.repr();
|
||||
}
|
||||
ctx.arc(this.x, this.y, this._radius, 0, 2 * Math.PI);
|
||||
ctx.stroke()
|
||||
if(window.config.general.debug) {
|
||||
let box = this.boundingBox();
|
||||
ctx.beginPath();
|
||||
ctx.rect(box.topLeft.x, box.topLeft.y, box.len.x, box.len.y)
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = 'red'
|
||||
ctx.fillText(this._score, this.x, this.y)
|
||||
ctx.stroke()
|
||||
ctx.fillStyle = 'black'
|
||||
}
|
||||
|
||||
get x(): number {
|
||||
return this.position.x;
|
||||
}
|
||||
|
||||
get y(): number {
|
||||
return this.position.y;
|
||||
}
|
||||
|
||||
get radius(): number {
|
||||
return this._radius;
|
||||
}
|
||||
|
||||
get color(): Color {
|
||||
return this._color;
|
||||
}
|
||||
|
||||
affect(gravitySource: PointGravitySource) {
|
||||
let vector = Vector.between(gravitySource.position, this.position);
|
||||
let force = gravitySource.getForce(vector);
|
||||
this.accelerate(force)
|
||||
}
|
||||
|
||||
boundingBox(): BoundingBox {
|
||||
let topLeft = this.position.minus(new Vector(this._radius, this._radius))
|
||||
let len = new Vector(this._radius * 2, this._radius * 2)
|
||||
return new BoundingBox(topLeft, len);
|
||||
}
|
||||
|
||||
collide(world: World, collidable: Collidable) {
|
||||
let collisionResult = world.collisionManager.collide(this, collidable);
|
||||
if(collisionResult.type === CollisionType.HIT) {
|
||||
if(collidable instanceof Bubble) {
|
||||
let collidingBubble = (collidable as Bubble)
|
||||
if(this._score > collidingBubble._score && this.radius > collidingBubble.radius) {
|
||||
this._score += collidingBubble._score;
|
||||
this._radius += collidingBubble._radius;
|
||||
this._mass += collidingBubble._mass;
|
||||
world.removeItem(collidable)
|
||||
} else {
|
||||
collidingBubble._score += this._score;
|
||||
collidingBubble._radius += this._radius;
|
||||
collidingBubble._mass += this._mass;
|
||||
world.removeItem(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geometricCollisionBehaviour(): CollisionBehaviour {
|
||||
return CollisionBehaviour.CIRCLE;
|
||||
}
|
||||
|
||||
getCircle(): Circle {
|
||||
return new Circle(this.position, this._radius);
|
||||
}
|
||||
|
||||
|
||||
get score(): number {
|
||||
return this._score;
|
||||
}
|
||||
|
||||
|
||||
set score(value: number) {
|
||||
this._score = value;
|
||||
}
|
||||
|
||||
get mass(): number {
|
||||
return this._mass;
|
||||
}
|
||||
|
||||
set mass(mass: number) {
|
||||
this._mass = mass;
|
||||
}
|
||||
}
|
||||
|
||||
export class PointGravitySource extends AbstractItem implements Actable, Positionable, Drawable {
|
||||
|
||||
private _force: number;
|
||||
private _position: Vector;
|
||||
|
||||
constructor(_x: number,
|
||||
_y: number,
|
||||
force?: number) {
|
||||
super();
|
||||
this._position = new Vector(_x, _y)
|
||||
this._force = force ?? 10;
|
||||
}
|
||||
|
||||
act(world: World) {
|
||||
world.applyGravity(this)
|
||||
}
|
||||
|
||||
getForce(distanceVector: Vector): Vector {
|
||||
let distance = distanceVector.len();
|
||||
return new Vector(distanceVector.x * this._force / (distance * distance), distanceVector.y * this._force / (distance * distance))
|
||||
}
|
||||
|
||||
get x() {
|
||||
return this._position.x;
|
||||
}
|
||||
|
||||
get y() {
|
||||
return this._position.y;
|
||||
}
|
||||
|
||||
get position(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
if(window.config.general.debug) {
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = 'red'
|
||||
ctx.arc(this.x, this.y, 10, 0, 2 * Math.PI);
|
||||
ctx.stroke()
|
||||
ctx.strokeStyle= 'black'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DirectionalGravitySource extends AbstractItem implements Actable, Positionable, Drawable {
|
||||
private _force: number;
|
||||
private _position: Vector;
|
||||
private _direction: Vector;
|
||||
private _start: Vector;
|
||||
private _end: Vector;
|
||||
|
||||
|
||||
constructor(_x: number,
|
||||
_y: number,
|
||||
_direction?: Vector,
|
||||
force?: number) {
|
||||
super();
|
||||
this._position = new Vector(_x, _y)
|
||||
this._direction = _direction?? new Vector(1, 0);
|
||||
this._start = this._position.minus(this._direction.normal().multNumber(25))
|
||||
this._end = this._position.minus(this._direction.otherNormal().multNumber(25))
|
||||
this._force = force ?? 10;
|
||||
}
|
||||
|
||||
act(world: World) {
|
||||
world.applyGravity(this)
|
||||
}
|
||||
|
||||
getForce(distanceVector: Vector): Vector {
|
||||
let distance = distanceVector.len();
|
||||
return new Vector(distanceVector.x * this._force / (distance * distance) * this._direction.x, distanceVector.y * this._force / (distance * distance) * this._direction.y)
|
||||
}
|
||||
|
||||
get x() {
|
||||
return this._position.x;
|
||||
}
|
||||
|
||||
get y() {
|
||||
return this._position.y;
|
||||
}
|
||||
|
||||
get position(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
if(window.config.general.debug) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = 'red'
|
||||
ctx.moveTo(this._start.x, this._start.y);
|
||||
ctx.lineTo(this._end.x, this._end.y);
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = 'black'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Barrier extends AbstractItem implements Collidable, Positionable, Drawable {
|
||||
private _position: Vector;
|
||||
|
||||
constructor(position: Vector) {
|
||||
super();
|
||||
this._position = position;
|
||||
}
|
||||
|
||||
abstract collide(world: World, collidable: Collidable);
|
||||
abstract boundingBox(): BoundingBox;
|
||||
abstract geometricCollisionBehaviour(): CollisionBehaviour;
|
||||
|
||||
|
||||
get position(): Vector {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
set position(value: Vector) {
|
||||
this._position = value;
|
||||
}
|
||||
|
||||
abstract draw(ctx);
|
||||
}
|
||||
|
||||
export class CircleBarrier extends Barrier implements Circable {
|
||||
|
||||
private _radius: number;
|
||||
|
||||
constructor(position: Vector, radius: number) {
|
||||
super(position);
|
||||
this._radius = radius;
|
||||
}
|
||||
|
||||
boundingBox(): BoundingBox {
|
||||
let topLeft = this.position.minus(new Vector(this._radius, this._radius))
|
||||
let len = new Vector(this._radius * 2, this._radius * 2)
|
||||
return new BoundingBox(topLeft, len);
|
||||
}
|
||||
|
||||
collide(world: World, collidable: Collidable) {
|
||||
}
|
||||
|
||||
geometricCollisionBehaviour(): CollisionBehaviour {
|
||||
return CollisionBehaviour.CIRCLE;
|
||||
}
|
||||
|
||||
getCircle(): Circle {
|
||||
return new Circle(this.position, this._radius);
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.position.x, this.position.y, this._radius, 0, 2 * Math.PI);
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
export class LineBarrier extends Barrier implements Lineable {
|
||||
private _line: Line;
|
||||
|
||||
constructor(start: Vector, end: Vector) {
|
||||
super(start)
|
||||
this._line = new Line(start, end);
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this._line.start.x, this._line.start.y);
|
||||
ctx.lineTo(this._line.end.x, this._line.end.y);
|
||||
ctx.stroke();
|
||||
if(window.config.general.debug) {
|
||||
let box = this.boundingBox();
|
||||
ctx.beginPath();
|
||||
ctx.rect(box.topLeft.x, box.topLeft.y, box.len.x, box.len.y)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
|
||||
boundingBox(): BoundingBox {
|
||||
let topLeft = new Vector(Math.min(this._line.start.x, this._line.end.x), Math.min(this._line.start.y, this._line.end.y))
|
||||
let len = new Vector(this._line.start.x - this._line.end.x, this._line.start.y - this._line.end.y)
|
||||
return new BoundingBox(topLeft, len.abs());
|
||||
}
|
||||
|
||||
collide(world: World, collidable: Collidable) {
|
||||
}
|
||||
|
||||
geometricCollisionBehaviour(): CollisionBehaviour {
|
||||
return CollisionBehaviour.LINE;
|
||||
}
|
||||
|
||||
getLine(): Line {
|
||||
return this._line;
|
||||
}
|
||||
|
||||
}
|
||||
20
sling/src/style.css
Normal file
20
sling/src/style.css
Normal file
@@ -0,0 +1,20 @@
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
html, body { width:100%; height:100%; }
|
||||
|
||||
html, body, div, canvas {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
canvas { display:block; }
|
||||
171
sling/src/vector.ts
Normal file
171
sling/src/vector.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
export class Vector {
|
||||
constructor(private _x: number, private _y: number) {
|
||||
}
|
||||
|
||||
static zero(): Vector {
|
||||
return new Vector(0, 0)
|
||||
}
|
||||
|
||||
static between(pointy: Vector, shaft : Vector) {
|
||||
return new Vector(pointy.x - shaft.x, pointy.y - shaft.y)
|
||||
}
|
||||
|
||||
plus(vector: Vector) {
|
||||
return new Vector(this._x + vector.x, this._y + vector.y)
|
||||
}
|
||||
|
||||
minus(vector: Vector) {
|
||||
return new Vector(this._x - vector.x, this._y - vector.y)
|
||||
}
|
||||
|
||||
dot(vector: Vector): number {
|
||||
return this._x * vector._x + this._y * vector._y
|
||||
}
|
||||
|
||||
normal() {
|
||||
return new Vector(-this.y, this.x)
|
||||
}
|
||||
|
||||
otherNormal() {
|
||||
return new Vector(this.y, -this.x)
|
||||
}
|
||||
|
||||
normalize() {
|
||||
let length = this.len();
|
||||
return new Vector(this.x / length, this.y / length)
|
||||
}
|
||||
|
||||
secondNorm() {
|
||||
return Math.sqrt(this._x * this._x + this._y * this._y)
|
||||
}
|
||||
|
||||
divide(factor: number) {
|
||||
return new Vector(this._x / factor, this._y / factor)
|
||||
}
|
||||
|
||||
angleBetween(vector: Vector) {
|
||||
return Math.atan2(this._x * vector._y - this._y * vector._x, this._x * vector._x + this._y * vector._y) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
multNumber(factor: number) {
|
||||
return new Vector(this._x * factor, this._y * factor)
|
||||
}
|
||||
|
||||
mult(vector: Vector) {
|
||||
return new Vector(this._x * vector.x, this._y * vector.y)
|
||||
}
|
||||
|
||||
len() {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y)
|
||||
}
|
||||
|
||||
isZero() {
|
||||
return this.x === 0 && this.y === 0;
|
||||
}
|
||||
|
||||
distanceTo(vector: Vector): number {
|
||||
return Math.sqrt(Math.pow(vector.x - this.x, 2) + Math.pow(vector.y - this.y, 2))
|
||||
}
|
||||
|
||||
abs() {
|
||||
return new Vector(Math.abs(this.x), Math.abs(this.y))
|
||||
}
|
||||
|
||||
invert() {
|
||||
return new Vector(-this.x, -this.y)
|
||||
}
|
||||
|
||||
get x(): number {
|
||||
return this._x;
|
||||
}
|
||||
|
||||
get y(): number {
|
||||
return this._y;
|
||||
}
|
||||
}
|
||||
|
||||
export class Line {
|
||||
constructor(private _start: Vector, private _end: Vector) {
|
||||
}
|
||||
|
||||
get start(): Vector {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
get end(): Vector {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
toVector() {
|
||||
return Vector.between(this._end, this._start)
|
||||
}
|
||||
|
||||
get len(): number {
|
||||
let distX = this.end.x - this.start.x;
|
||||
let distY = this.end.y - this.start.y;
|
||||
return Math.sqrt(distX * distX + distY * distY)
|
||||
}
|
||||
|
||||
pointCollision(point: Vector) {
|
||||
// https://www.jeffreythompson.org/collision-detection/line-point.php
|
||||
let d1 = point.distanceTo(this.start)
|
||||
let d2 = point.distanceTo(this.end)
|
||||
let len = this.len;
|
||||
const buffer = 0.1
|
||||
if((d1 + d2) >= (len - buffer) && (d1 + d2) <= (len + buffer)) {
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Circle {
|
||||
constructor(private _center: Vector, private _radius: number) {
|
||||
}
|
||||
|
||||
pointInside(point: Vector) {
|
||||
return this._center.distanceTo(point) <= this._radius;
|
||||
}
|
||||
|
||||
circleCollision(circle: Circle) {
|
||||
return this._center.distanceTo(circle.center) <= this._radius + circle.radius;
|
||||
}
|
||||
|
||||
get center(): Vector {
|
||||
return this._center;
|
||||
}
|
||||
|
||||
|
||||
get radius(): number {
|
||||
return this._radius;
|
||||
}
|
||||
}
|
||||
|
||||
export class BoundingBox {
|
||||
constructor(private _topLeft: Vector, private _len: Vector) {
|
||||
}
|
||||
|
||||
// https://www.jeffreythompson.org/collision-detection/rect-rect.php
|
||||
intersect(box: BoundingBox): boolean {
|
||||
// r1 = this
|
||||
// r2 = box
|
||||
if (this._topLeft.x + this._len.x >= box._topLeft.x &&
|
||||
this._topLeft.x <= box._topLeft.x + box._len.x &&
|
||||
this._topLeft.y + this._len.y >= box._topLeft.y &&
|
||||
this._topLeft.y <= box._topLeft.y + box._len.y) {
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
get topLeft(): Vector {
|
||||
return this._topLeft;
|
||||
}
|
||||
|
||||
get len(): Vector {
|
||||
return this._len;
|
||||
}
|
||||
}
|
||||
1
sling/src/vite-env.d.ts
vendored
Normal file
1
sling/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
24
sling/tsconfig.json
Normal file
24
sling/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user