├── .gitignore ├── LICENSE ├── README.md ├── cover.jpg ├── dist ├── assets │ ├── bead.glb │ └── normal.png ├── index-6ca6b2e6.css ├── index-be83070f.js └── index.html ├── package-lock.json ├── package.json ├── src ├── app │ ├── _sketch-template.js │ ├── app.js │ ├── audio-repeater.js │ ├── is-ios.js │ ├── shader │ │ ├── bead.frag.glsl │ │ ├── bead.vert.glsl │ │ ├── blur.frag.glsl │ │ ├── blur.vert.glsl │ │ ├── composite.frag.glsl │ │ ├── composite.vert.glsl │ │ ├── highpass.frag.glsl │ │ ├── highpass.vert.glsl │ │ ├── light-depth.frag.glsl │ │ ├── sph │ │ │ ├── draw.frag.glsl │ │ │ ├── draw.vert.glsl │ │ │ ├── force.frag.glsl │ │ │ ├── force.vert.glsl │ │ │ ├── indices.frag.glsl │ │ │ ├── indices.vert.glsl │ │ │ ├── integrate.frag.glsl │ │ │ ├── integrate.vert.glsl │ │ │ ├── offset.frag.glsl │ │ │ ├── offset.vert.glsl │ │ │ ├── pressure.frag.glsl │ │ │ ├── pressure.vert.glsl │ │ │ ├── sort.frag.glsl │ │ │ ├── sort.vert.glsl │ │ │ └── utils │ │ │ │ └── particle-utils.glsl │ │ ├── test.frag.glsl │ │ └── test.vert.glsl │ ├── sketch.js │ └── utils │ │ ├── glb-builder.js │ │ └── modernizr.js ├── assets │ ├── bead.glb │ ├── env-map-01.jpg │ ├── env-map-02.jpg │ └── normal.png ├── index.html └── styles.css └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | 84 | # Gatsby files 85 | .cache/ 86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # public 89 | 90 | # vuepress build output 91 | .vuepress/dist 92 | 93 | # Serverless directories 94 | .serverless/ 95 | 96 | # FuseBox cache 97 | .fusebox/ 98 | 99 | # DynamoDB Local files 100 | .dynamodb/ 101 | 102 | # TernJS port file 103 | .tern-port 104 | 105 | src/libs/** 106 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Robert Leitl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Liquid-Geo 2 | 3 | ![Liquid-Geo Screenshot](https://github.com/robert-leitl/liquid-geo/blob/main/cover.jpg?raw=true) 4 | 5 | This web experiment is inspired by the liquid-geo interface designs form the movie [Man of Steel](https://en.wikipedia.org/wiki/Man_of_Steel_(film)). It allows the user to record a short audio snippet. This snippet can then be played back in a distorted version and the sphere responds to the audio signal. In addition, the beads on the surface of the sphere can be manipulated by touch or mouse movement. 6 | 7 | [DEMO](https://robert-leitl.github.io/liquid-geo/dist/?debug=true) 8 | 9 | ### Features 10 | - SPH fluid simulation on sphere surface [Github Repo](https://robert-leitl.github.io/gpgpu-2d-sph-fluid-simulation) 11 | - Screen-space halo and bloom effect inspired by this [article](https://john-chapman.github.io/2017/11/05/pseudo-lens-flare.html) from John Chapman. 12 | - Audio recording and distorted playback using web audio API and tone.js. -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/liquid-geo/ec7c6907c7c14bf54a63eca593bf7716575866ba/cover.jpg -------------------------------------------------------------------------------- /dist/assets/bead.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/liquid-geo/ec7c6907c7c14bf54a63eca593bf7716575866ba/dist/assets/bead.glb -------------------------------------------------------------------------------- /dist/assets/normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/liquid-geo/ec7c6907c7c14bf54a63eca593bf7716575866ba/dist/assets/normal.png -------------------------------------------------------------------------------- /dist/index-6ca6b2e6.css: -------------------------------------------------------------------------------- 1 | *{box-sizing:border-box}html,body{padding:0;margin:0;width:100%;height:100%;width:100dvw;height:100dvh;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:18px;overflow:hidden;touch-action:none;background-color:#000}body{position:relative}@media screen and (max-width: 640px){body,html{font-size:14px}}canvas{width:100%;height:100%}.github-link{position:absolute;right:0;bottom:0;color:#aaa;mix-blend-mode:difference;text-transform:uppercase;text-decoration:none;padding:.7em 1em;font-size:.8em}.audio-controls{position:absolute;bottom:0;left:0;width:100%;display:flex;align-items:center;justify-content:center;padding:3em 0;pointer-events:none}.audio-controls button{pointer-events:all;cursor:pointer;background:none;border:2px solid #eee;border-radius:10rem;display:flex;align-items:center;min-height:4.25em;width:16em;justify-content:center}@media screen and (min-width: 641px){.audio-controls button{min-height:6em}}.audio-controls button:hover{background:#333}.audio-controls button:disabled{opacity:.4;pointer-events:none}.audio-controls button label{color:#eee;font-size:1.25rem;pointer-events:none}.audio-controls svg{height:2rem;width:2rem;margin-right:.5rem;pointer-events:none}@media (min-aspect-ratio: 7/5){.audio-controls{flex-direction:column;height:100%;padding:0 2em;align-items:flex-end}.audio-controls button+button{margin-top:1em}}@media (max-aspect-ratio: 5/8){.audio-controls{flex-direction:column}.audio-controls button+button{margin-top:1em;margin-left:0!important}}.audio-controls button+button{margin-left:1em}#playback-button svg{width:1.7rem;height:1.7rem}#record-button.is-recording:before{content:"";display:block;width:1.5rem;height:1.5rem;margin-right:.5rem;background:#f22;border-radius:100%}#record-button.is-recording svg{display:none} 2 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | liquid-geo 7 | 8 | 9 | 10 | 11 | 12 | 13 | github 14 | 15 |
16 | 22 | 27 |
28 | 29 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "liquid-geo", 3 | "version": "2.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "liquid-geo", 9 | "version": "2.0.0", 10 | "dependencies": { 11 | "@loaders.gl/core": "^3.2.3", 12 | "@loaders.gl/gltf": "^3.2.3", 13 | "gl-matrix": "^3.4.3", 14 | "rxjs": "^7.5.6", 15 | "tone": "^14.7.77", 16 | "tweakpane": "^3.1.0", 17 | "twgl.js": "^5.0.4" 18 | }, 19 | "devDependencies": { 20 | "terser": "^5.14.2", 21 | "vite": "^3.0.0", 22 | "vite-plugin-glsl": "^0.3.0" 23 | } 24 | }, 25 | "node_modules/@babel/runtime": { 26 | "version": "7.20.1", 27 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", 28 | "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", 29 | "dependencies": { 30 | "regenerator-runtime": "^0.13.10" 31 | }, 32 | "engines": { 33 | "node": ">=6.9.0" 34 | } 35 | }, 36 | "node_modules/@esbuild/android-arm": { 37 | "version": "0.15.13", 38 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", 39 | "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", 40 | "cpu": [ 41 | "arm" 42 | ], 43 | "dev": true, 44 | "optional": true, 45 | "os": [ 46 | "android" 47 | ], 48 | "engines": { 49 | "node": ">=12" 50 | } 51 | }, 52 | "node_modules/@esbuild/linux-loong64": { 53 | "version": "0.15.13", 54 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", 55 | "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", 56 | "cpu": [ 57 | "loong64" 58 | ], 59 | "dev": true, 60 | "optional": true, 61 | "os": [ 62 | "linux" 63 | ], 64 | "engines": { 65 | "node": ">=12" 66 | } 67 | }, 68 | "node_modules/@jridgewell/gen-mapping": { 69 | "version": "0.3.2", 70 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 71 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 72 | "dev": true, 73 | "dependencies": { 74 | "@jridgewell/set-array": "^1.0.1", 75 | "@jridgewell/sourcemap-codec": "^1.4.10", 76 | "@jridgewell/trace-mapping": "^0.3.9" 77 | }, 78 | "engines": { 79 | "node": ">=6.0.0" 80 | } 81 | }, 82 | "node_modules/@jridgewell/resolve-uri": { 83 | "version": "3.1.0", 84 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 85 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 86 | "dev": true, 87 | "engines": { 88 | "node": ">=6.0.0" 89 | } 90 | }, 91 | "node_modules/@jridgewell/set-array": { 92 | "version": "1.1.2", 93 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 94 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 95 | "dev": true, 96 | "engines": { 97 | "node": ">=6.0.0" 98 | } 99 | }, 100 | "node_modules/@jridgewell/source-map": { 101 | "version": "0.3.2", 102 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", 103 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", 104 | "dev": true, 105 | "dependencies": { 106 | "@jridgewell/gen-mapping": "^0.3.0", 107 | "@jridgewell/trace-mapping": "^0.3.9" 108 | } 109 | }, 110 | "node_modules/@jridgewell/sourcemap-codec": { 111 | "version": "1.4.14", 112 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 113 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 114 | "dev": true 115 | }, 116 | "node_modules/@jridgewell/trace-mapping": { 117 | "version": "0.3.17", 118 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", 119 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", 120 | "dev": true, 121 | "dependencies": { 122 | "@jridgewell/resolve-uri": "3.1.0", 123 | "@jridgewell/sourcemap-codec": "1.4.14" 124 | } 125 | }, 126 | "node_modules/@loaders.gl/core": { 127 | "version": "3.2.11", 128 | "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-3.2.11.tgz", 129 | "integrity": "sha512-uWQM1ZAuN0VYWEMMMwrlTKE1c4gor9SgCQXn8TlAW/4+9sL9KJ09T6AxgzYYAFdJmzTmT8BtC5aPUEYv031nRQ==", 130 | "dependencies": { 131 | "@babel/runtime": "^7.3.1", 132 | "@loaders.gl/loader-utils": "3.2.11", 133 | "@loaders.gl/worker-utils": "3.2.11", 134 | "@probe.gl/log": "^3.5.0", 135 | "probe.gl": "^3.4.0" 136 | } 137 | }, 138 | "node_modules/@loaders.gl/draco": { 139 | "version": "3.2.11", 140 | "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-3.2.11.tgz", 141 | "integrity": "sha512-cGLcMWFe/AP5ExVEPt23Q4uo8Ewbo6hCBvcFX+b9VDfz/mIbUNa0DLRRtSi7eKgCJBRCQ/MLLz3SCm5OL5CjEA==", 142 | "dependencies": { 143 | "@babel/runtime": "^7.3.1", 144 | "@loaders.gl/loader-utils": "3.2.11", 145 | "@loaders.gl/schema": "3.2.11", 146 | "@loaders.gl/worker-utils": "3.2.11", 147 | "draco3d": "1.4.1" 148 | } 149 | }, 150 | "node_modules/@loaders.gl/gltf": { 151 | "version": "3.2.11", 152 | "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-3.2.11.tgz", 153 | "integrity": "sha512-jhVFjNWMPydWB7MJVxSGGGdd3zhVgD94WsFKq9L/HcrdMY6s3nQtinALHXErh/G4XjH3efnjkZXfrE8KDzaJsw==", 154 | "dependencies": { 155 | "@loaders.gl/draco": "3.2.11", 156 | "@loaders.gl/images": "3.2.11", 157 | "@loaders.gl/loader-utils": "3.2.11", 158 | "@loaders.gl/textures": "3.2.11" 159 | } 160 | }, 161 | "node_modules/@loaders.gl/images": { 162 | "version": "3.2.11", 163 | "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-3.2.11.tgz", 164 | "integrity": "sha512-ch5JRXptb8JISYo2PQeASCvuiwdJjJx7ucejDT3EoeKfVHBL7vVjNkHY/UjOMQvljYoF2jD0NfmOJoll5DWjTQ==", 165 | "dependencies": { 166 | "@loaders.gl/loader-utils": "3.2.11" 167 | } 168 | }, 169 | "node_modules/@loaders.gl/loader-utils": { 170 | "version": "3.2.11", 171 | "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-3.2.11.tgz", 172 | "integrity": "sha512-/eQjBLQI1x+5MG3b235xrUcMdKl9ALtzOPMINYeA9TI1TJBULv1xNWBg6HqVdS2ZfaC+JFc9vMxrPI7YaklqNw==", 173 | "dependencies": { 174 | "@babel/runtime": "^7.3.1", 175 | "@loaders.gl/worker-utils": "3.2.11", 176 | "@probe.gl/stats": "^3.5.0" 177 | } 178 | }, 179 | "node_modules/@loaders.gl/schema": { 180 | "version": "3.2.11", 181 | "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-3.2.11.tgz", 182 | "integrity": "sha512-Fz0cWtHwE5Os0HxhEYxLCnJz5LD7djpZnNWk+lPVzIJ6HWPFlxI6lbD4zc1auN5omD2EXFkJigi8on8l3i63fQ==", 183 | "dependencies": { 184 | "@types/geojson": "^7946.0.7", 185 | "apache-arrow": "^4.0.0" 186 | } 187 | }, 188 | "node_modules/@loaders.gl/textures": { 189 | "version": "3.2.11", 190 | "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-3.2.11.tgz", 191 | "integrity": "sha512-GapLQ9XzCfVygVp2uFggk+Gr736hAkm0aZVRyGRi9hQjXffD7IvPOMh+cqNkHuxTcO5vHHR6jnQqYc5gtUODlg==", 192 | "dependencies": { 193 | "@loaders.gl/images": "3.2.11", 194 | "@loaders.gl/loader-utils": "3.2.11", 195 | "@loaders.gl/schema": "3.2.11", 196 | "@loaders.gl/worker-utils": "3.2.11", 197 | "ktx-parse": "^0.0.4", 198 | "texture-compressor": "^1.0.2" 199 | } 200 | }, 201 | "node_modules/@loaders.gl/worker-utils": { 202 | "version": "3.2.11", 203 | "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-3.2.11.tgz", 204 | "integrity": "sha512-2DyBkBJGDU66XbLz+eBByTlfbjUD3OarjzqAifenIrOaX1IuOcSqa8r6w2FOgsjlpT1ujcn0d4QO/o0zM8IWJA==", 205 | "dependencies": { 206 | "@babel/runtime": "^7.3.1" 207 | } 208 | }, 209 | "node_modules/@probe.gl/env": { 210 | "version": "3.5.2", 211 | "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-3.5.2.tgz", 212 | "integrity": "sha512-JlNvJ2p6+ObWX7es6n3TycGPTv5CfVrCS8vblI1eHhrFCcZ6RxIo727ffRVwldpp0YTzdgjx3/4fB/1dnVYElw==", 213 | "dependencies": { 214 | "@babel/runtime": "^7.0.0" 215 | } 216 | }, 217 | "node_modules/@probe.gl/log": { 218 | "version": "3.5.2", 219 | "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-3.5.2.tgz", 220 | "integrity": "sha512-5yo8Dg8LrSltuPBdGlLh/WOvt4LdU7DDHu75GMeiS0fKM+J4IACRpGV8SOrktCj1MWZ6JVHcNQkJnoyZ6G7p/w==", 221 | "dependencies": { 222 | "@babel/runtime": "^7.0.0", 223 | "@probe.gl/env": "3.5.2" 224 | } 225 | }, 226 | "node_modules/@probe.gl/stats": { 227 | "version": "3.5.2", 228 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-3.5.2.tgz", 229 | "integrity": "sha512-YKaYXiHF//fgy1OkX38JD70Lc8qxg2Viw8Q2CTNMwGPDJe12wda7kEmMKPJNw2oYLyFUfTzv00KJMA5h18z02w==", 230 | "dependencies": { 231 | "@babel/runtime": "^7.0.0" 232 | } 233 | }, 234 | "node_modules/@rollup/pluginutils": { 235 | "version": "4.2.1", 236 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 237 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 238 | "dev": true, 239 | "dependencies": { 240 | "estree-walker": "^2.0.1", 241 | "picomatch": "^2.2.2" 242 | }, 243 | "engines": { 244 | "node": ">= 8.0.0" 245 | } 246 | }, 247 | "node_modules/@types/flatbuffers": { 248 | "version": "1.10.0", 249 | "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", 250 | "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" 251 | }, 252 | "node_modules/@types/geojson": { 253 | "version": "7946.0.10", 254 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", 255 | "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" 256 | }, 257 | "node_modules/@types/node": { 258 | "version": "14.18.33", 259 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", 260 | "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==" 261 | }, 262 | "node_modules/@types/text-encoding-utf-8": { 263 | "version": "1.0.2", 264 | "resolved": "https://registry.npmjs.org/@types/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 265 | "integrity": "sha512-AQ6zewa0ucLJvtUi5HsErbOFKAcQfRLt9zFLlUOvcXBy2G36a+ZDpCHSGdzJVUD8aNURtIjh9aSjCStNMRCcRQ==" 266 | }, 267 | "node_modules/acorn": { 268 | "version": "8.8.1", 269 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 270 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 271 | "dev": true, 272 | "bin": { 273 | "acorn": "bin/acorn" 274 | }, 275 | "engines": { 276 | "node": ">=0.4.0" 277 | } 278 | }, 279 | "node_modules/ansi-styles": { 280 | "version": "3.2.1", 281 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 282 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 283 | "dependencies": { 284 | "color-convert": "^1.9.0" 285 | }, 286 | "engines": { 287 | "node": ">=4" 288 | } 289 | }, 290 | "node_modules/apache-arrow": { 291 | "version": "4.0.1", 292 | "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-4.0.1.tgz", 293 | "integrity": "sha512-DyF7GXCbSjsw4P5C8b+qW7OnJKa6w9mJI0mhV0+EfZbVZCmhfiF6ffqcnrI/kzBrRqn9hH/Ft9n5+m4DTbBJpg==", 294 | "dependencies": { 295 | "@types/flatbuffers": "^1.10.0", 296 | "@types/node": "^14.14.37", 297 | "@types/text-encoding-utf-8": "^1.0.1", 298 | "command-line-args": "5.1.1", 299 | "command-line-usage": "6.1.1", 300 | "flatbuffers": "1.12.0", 301 | "json-bignum": "^0.0.3", 302 | "pad-left": "^2.1.0", 303 | "text-encoding-utf-8": "^1.0.2", 304 | "tslib": "^2.2.0" 305 | }, 306 | "bin": { 307 | "arrow2csv": "bin/arrow2csv.js" 308 | } 309 | }, 310 | "node_modules/argparse": { 311 | "version": "1.0.10", 312 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 313 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 314 | "dependencies": { 315 | "sprintf-js": "~1.0.2" 316 | } 317 | }, 318 | "node_modules/array-back": { 319 | "version": "3.1.0", 320 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", 321 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", 322 | "engines": { 323 | "node": ">=6" 324 | } 325 | }, 326 | "node_modules/automation-events": { 327 | "version": "4.0.23", 328 | "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-4.0.23.tgz", 329 | "integrity": "sha512-3Q/moBk0NeWZb5jm5WtjmpAV5lxCoS00W+PQmQLp5mU0ra8AqU/lfjsIJly7Ze1drBE4aNfZIMGlbU+sTtJQJw==", 330 | "dependencies": { 331 | "@babel/runtime": "^7.20.1", 332 | "tslib": "^2.4.1" 333 | }, 334 | "engines": { 335 | "node": ">=12.20.1" 336 | } 337 | }, 338 | "node_modules/buffer-from": { 339 | "version": "1.1.2", 340 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 341 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 342 | "dev": true 343 | }, 344 | "node_modules/chalk": { 345 | "version": "2.4.2", 346 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 347 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 348 | "dependencies": { 349 | "ansi-styles": "^3.2.1", 350 | "escape-string-regexp": "^1.0.5", 351 | "supports-color": "^5.3.0" 352 | }, 353 | "engines": { 354 | "node": ">=4" 355 | } 356 | }, 357 | "node_modules/color-convert": { 358 | "version": "1.9.3", 359 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 360 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 361 | "dependencies": { 362 | "color-name": "1.1.3" 363 | } 364 | }, 365 | "node_modules/color-name": { 366 | "version": "1.1.3", 367 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 368 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 369 | }, 370 | "node_modules/command-line-args": { 371 | "version": "5.1.1", 372 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", 373 | "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", 374 | "dependencies": { 375 | "array-back": "^3.0.1", 376 | "find-replace": "^3.0.0", 377 | "lodash.camelcase": "^4.3.0", 378 | "typical": "^4.0.0" 379 | }, 380 | "engines": { 381 | "node": ">=4.0.0" 382 | } 383 | }, 384 | "node_modules/command-line-usage": { 385 | "version": "6.1.1", 386 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", 387 | "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", 388 | "dependencies": { 389 | "array-back": "^4.0.1", 390 | "chalk": "^2.4.2", 391 | "table-layout": "^1.0.1", 392 | "typical": "^5.2.0" 393 | }, 394 | "engines": { 395 | "node": ">=8.0.0" 396 | } 397 | }, 398 | "node_modules/command-line-usage/node_modules/array-back": { 399 | "version": "4.0.2", 400 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 401 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 402 | "engines": { 403 | "node": ">=8" 404 | } 405 | }, 406 | "node_modules/command-line-usage/node_modules/typical": { 407 | "version": "5.2.0", 408 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 409 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 410 | "engines": { 411 | "node": ">=8" 412 | } 413 | }, 414 | "node_modules/commander": { 415 | "version": "2.20.3", 416 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 417 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 418 | "dev": true 419 | }, 420 | "node_modules/deep-extend": { 421 | "version": "0.6.0", 422 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 423 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 424 | "engines": { 425 | "node": ">=4.0.0" 426 | } 427 | }, 428 | "node_modules/draco3d": { 429 | "version": "1.4.1", 430 | "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.4.1.tgz", 431 | "integrity": "sha512-9Rxonc70xiovBC+Bq1h57SNZIHzWTibU1VfIGp5z3Xx8dPtv4yT5uGhiH7P5uvJRR2jkrvHafRxR7bTANkvfpg==" 432 | }, 433 | "node_modules/esbuild": { 434 | "version": "0.15.13", 435 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", 436 | "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", 437 | "dev": true, 438 | "hasInstallScript": true, 439 | "bin": { 440 | "esbuild": "bin/esbuild" 441 | }, 442 | "engines": { 443 | "node": ">=12" 444 | }, 445 | "optionalDependencies": { 446 | "@esbuild/android-arm": "0.15.13", 447 | "@esbuild/linux-loong64": "0.15.13", 448 | "esbuild-android-64": "0.15.13", 449 | "esbuild-android-arm64": "0.15.13", 450 | "esbuild-darwin-64": "0.15.13", 451 | "esbuild-darwin-arm64": "0.15.13", 452 | "esbuild-freebsd-64": "0.15.13", 453 | "esbuild-freebsd-arm64": "0.15.13", 454 | "esbuild-linux-32": "0.15.13", 455 | "esbuild-linux-64": "0.15.13", 456 | "esbuild-linux-arm": "0.15.13", 457 | "esbuild-linux-arm64": "0.15.13", 458 | "esbuild-linux-mips64le": "0.15.13", 459 | "esbuild-linux-ppc64le": "0.15.13", 460 | "esbuild-linux-riscv64": "0.15.13", 461 | "esbuild-linux-s390x": "0.15.13", 462 | "esbuild-netbsd-64": "0.15.13", 463 | "esbuild-openbsd-64": "0.15.13", 464 | "esbuild-sunos-64": "0.15.13", 465 | "esbuild-windows-32": "0.15.13", 466 | "esbuild-windows-64": "0.15.13", 467 | "esbuild-windows-arm64": "0.15.13" 468 | } 469 | }, 470 | "node_modules/esbuild-android-64": { 471 | "version": "0.15.13", 472 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", 473 | "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", 474 | "cpu": [ 475 | "x64" 476 | ], 477 | "dev": true, 478 | "optional": true, 479 | "os": [ 480 | "android" 481 | ], 482 | "engines": { 483 | "node": ">=12" 484 | } 485 | }, 486 | "node_modules/esbuild-android-arm64": { 487 | "version": "0.15.13", 488 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", 489 | "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", 490 | "cpu": [ 491 | "arm64" 492 | ], 493 | "dev": true, 494 | "optional": true, 495 | "os": [ 496 | "android" 497 | ], 498 | "engines": { 499 | "node": ">=12" 500 | } 501 | }, 502 | "node_modules/esbuild-darwin-64": { 503 | "version": "0.15.13", 504 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", 505 | "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", 506 | "cpu": [ 507 | "x64" 508 | ], 509 | "dev": true, 510 | "optional": true, 511 | "os": [ 512 | "darwin" 513 | ], 514 | "engines": { 515 | "node": ">=12" 516 | } 517 | }, 518 | "node_modules/esbuild-darwin-arm64": { 519 | "version": "0.15.13", 520 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", 521 | "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", 522 | "cpu": [ 523 | "arm64" 524 | ], 525 | "dev": true, 526 | "optional": true, 527 | "os": [ 528 | "darwin" 529 | ], 530 | "engines": { 531 | "node": ">=12" 532 | } 533 | }, 534 | "node_modules/esbuild-freebsd-64": { 535 | "version": "0.15.13", 536 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", 537 | "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", 538 | "cpu": [ 539 | "x64" 540 | ], 541 | "dev": true, 542 | "optional": true, 543 | "os": [ 544 | "freebsd" 545 | ], 546 | "engines": { 547 | "node": ">=12" 548 | } 549 | }, 550 | "node_modules/esbuild-freebsd-arm64": { 551 | "version": "0.15.13", 552 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", 553 | "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", 554 | "cpu": [ 555 | "arm64" 556 | ], 557 | "dev": true, 558 | "optional": true, 559 | "os": [ 560 | "freebsd" 561 | ], 562 | "engines": { 563 | "node": ">=12" 564 | } 565 | }, 566 | "node_modules/esbuild-linux-32": { 567 | "version": "0.15.13", 568 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", 569 | "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", 570 | "cpu": [ 571 | "ia32" 572 | ], 573 | "dev": true, 574 | "optional": true, 575 | "os": [ 576 | "linux" 577 | ], 578 | "engines": { 579 | "node": ">=12" 580 | } 581 | }, 582 | "node_modules/esbuild-linux-64": { 583 | "version": "0.15.13", 584 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", 585 | "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", 586 | "cpu": [ 587 | "x64" 588 | ], 589 | "dev": true, 590 | "optional": true, 591 | "os": [ 592 | "linux" 593 | ], 594 | "engines": { 595 | "node": ">=12" 596 | } 597 | }, 598 | "node_modules/esbuild-linux-arm": { 599 | "version": "0.15.13", 600 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", 601 | "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", 602 | "cpu": [ 603 | "arm" 604 | ], 605 | "dev": true, 606 | "optional": true, 607 | "os": [ 608 | "linux" 609 | ], 610 | "engines": { 611 | "node": ">=12" 612 | } 613 | }, 614 | "node_modules/esbuild-linux-arm64": { 615 | "version": "0.15.13", 616 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", 617 | "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", 618 | "cpu": [ 619 | "arm64" 620 | ], 621 | "dev": true, 622 | "optional": true, 623 | "os": [ 624 | "linux" 625 | ], 626 | "engines": { 627 | "node": ">=12" 628 | } 629 | }, 630 | "node_modules/esbuild-linux-mips64le": { 631 | "version": "0.15.13", 632 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", 633 | "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", 634 | "cpu": [ 635 | "mips64el" 636 | ], 637 | "dev": true, 638 | "optional": true, 639 | "os": [ 640 | "linux" 641 | ], 642 | "engines": { 643 | "node": ">=12" 644 | } 645 | }, 646 | "node_modules/esbuild-linux-ppc64le": { 647 | "version": "0.15.13", 648 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", 649 | "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", 650 | "cpu": [ 651 | "ppc64" 652 | ], 653 | "dev": true, 654 | "optional": true, 655 | "os": [ 656 | "linux" 657 | ], 658 | "engines": { 659 | "node": ">=12" 660 | } 661 | }, 662 | "node_modules/esbuild-linux-riscv64": { 663 | "version": "0.15.13", 664 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", 665 | "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", 666 | "cpu": [ 667 | "riscv64" 668 | ], 669 | "dev": true, 670 | "optional": true, 671 | "os": [ 672 | "linux" 673 | ], 674 | "engines": { 675 | "node": ">=12" 676 | } 677 | }, 678 | "node_modules/esbuild-linux-s390x": { 679 | "version": "0.15.13", 680 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", 681 | "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", 682 | "cpu": [ 683 | "s390x" 684 | ], 685 | "dev": true, 686 | "optional": true, 687 | "os": [ 688 | "linux" 689 | ], 690 | "engines": { 691 | "node": ">=12" 692 | } 693 | }, 694 | "node_modules/esbuild-netbsd-64": { 695 | "version": "0.15.13", 696 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", 697 | "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", 698 | "cpu": [ 699 | "x64" 700 | ], 701 | "dev": true, 702 | "optional": true, 703 | "os": [ 704 | "netbsd" 705 | ], 706 | "engines": { 707 | "node": ">=12" 708 | } 709 | }, 710 | "node_modules/esbuild-openbsd-64": { 711 | "version": "0.15.13", 712 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", 713 | "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", 714 | "cpu": [ 715 | "x64" 716 | ], 717 | "dev": true, 718 | "optional": true, 719 | "os": [ 720 | "openbsd" 721 | ], 722 | "engines": { 723 | "node": ">=12" 724 | } 725 | }, 726 | "node_modules/esbuild-sunos-64": { 727 | "version": "0.15.13", 728 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", 729 | "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", 730 | "cpu": [ 731 | "x64" 732 | ], 733 | "dev": true, 734 | "optional": true, 735 | "os": [ 736 | "sunos" 737 | ], 738 | "engines": { 739 | "node": ">=12" 740 | } 741 | }, 742 | "node_modules/esbuild-windows-32": { 743 | "version": "0.15.13", 744 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", 745 | "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", 746 | "cpu": [ 747 | "ia32" 748 | ], 749 | "dev": true, 750 | "optional": true, 751 | "os": [ 752 | "win32" 753 | ], 754 | "engines": { 755 | "node": ">=12" 756 | } 757 | }, 758 | "node_modules/esbuild-windows-64": { 759 | "version": "0.15.13", 760 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", 761 | "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", 762 | "cpu": [ 763 | "x64" 764 | ], 765 | "dev": true, 766 | "optional": true, 767 | "os": [ 768 | "win32" 769 | ], 770 | "engines": { 771 | "node": ">=12" 772 | } 773 | }, 774 | "node_modules/esbuild-windows-arm64": { 775 | "version": "0.15.13", 776 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", 777 | "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", 778 | "cpu": [ 779 | "arm64" 780 | ], 781 | "dev": true, 782 | "optional": true, 783 | "os": [ 784 | "win32" 785 | ], 786 | "engines": { 787 | "node": ">=12" 788 | } 789 | }, 790 | "node_modules/escape-string-regexp": { 791 | "version": "1.0.5", 792 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 793 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 794 | "engines": { 795 | "node": ">=0.8.0" 796 | } 797 | }, 798 | "node_modules/estree-walker": { 799 | "version": "2.0.2", 800 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 801 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 802 | "dev": true 803 | }, 804 | "node_modules/find-replace": { 805 | "version": "3.0.0", 806 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", 807 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", 808 | "dependencies": { 809 | "array-back": "^3.0.1" 810 | }, 811 | "engines": { 812 | "node": ">=4.0.0" 813 | } 814 | }, 815 | "node_modules/flatbuffers": { 816 | "version": "1.12.0", 817 | "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", 818 | "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" 819 | }, 820 | "node_modules/fsevents": { 821 | "version": "2.3.2", 822 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 823 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 824 | "dev": true, 825 | "hasInstallScript": true, 826 | "optional": true, 827 | "os": [ 828 | "darwin" 829 | ], 830 | "engines": { 831 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 832 | } 833 | }, 834 | "node_modules/function-bind": { 835 | "version": "1.1.1", 836 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 837 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 838 | "dev": true 839 | }, 840 | "node_modules/gl-matrix": { 841 | "version": "3.4.3", 842 | "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", 843 | "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" 844 | }, 845 | "node_modules/has": { 846 | "version": "1.0.3", 847 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 848 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 849 | "dev": true, 850 | "dependencies": { 851 | "function-bind": "^1.1.1" 852 | }, 853 | "engines": { 854 | "node": ">= 0.4.0" 855 | } 856 | }, 857 | "node_modules/has-flag": { 858 | "version": "3.0.0", 859 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 860 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 861 | "engines": { 862 | "node": ">=4" 863 | } 864 | }, 865 | "node_modules/image-size": { 866 | "version": "0.7.5", 867 | "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", 868 | "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", 869 | "bin": { 870 | "image-size": "bin/image-size.js" 871 | }, 872 | "engines": { 873 | "node": ">=6.9.0" 874 | } 875 | }, 876 | "node_modules/is-core-module": { 877 | "version": "2.11.0", 878 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 879 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 880 | "dev": true, 881 | "dependencies": { 882 | "has": "^1.0.3" 883 | }, 884 | "funding": { 885 | "url": "https://github.com/sponsors/ljharb" 886 | } 887 | }, 888 | "node_modules/json-bignum": { 889 | "version": "0.0.3", 890 | "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", 891 | "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", 892 | "engines": { 893 | "node": ">=0.8" 894 | } 895 | }, 896 | "node_modules/ktx-parse": { 897 | "version": "0.0.4", 898 | "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.0.4.tgz", 899 | "integrity": "sha512-LY3nrmfXl+wZZdPxgJ3ZmLvG+wkOZZP3/dr4RbQj1Pk3Qwz44esOOSFFVQJcNWpXAtiNIC66WgXufX/SYgYz6A==" 900 | }, 901 | "node_modules/lodash.camelcase": { 902 | "version": "4.3.0", 903 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 904 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" 905 | }, 906 | "node_modules/nanoid": { 907 | "version": "3.3.4", 908 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 909 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 910 | "dev": true, 911 | "bin": { 912 | "nanoid": "bin/nanoid.cjs" 913 | }, 914 | "engines": { 915 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 916 | } 917 | }, 918 | "node_modules/pad-left": { 919 | "version": "2.1.0", 920 | "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", 921 | "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", 922 | "dependencies": { 923 | "repeat-string": "^1.5.4" 924 | }, 925 | "engines": { 926 | "node": ">=0.10.0" 927 | } 928 | }, 929 | "node_modules/path-parse": { 930 | "version": "1.0.7", 931 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 932 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 933 | "dev": true 934 | }, 935 | "node_modules/picocolors": { 936 | "version": "1.0.0", 937 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 938 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 939 | "dev": true 940 | }, 941 | "node_modules/picomatch": { 942 | "version": "2.3.1", 943 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 944 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 945 | "dev": true, 946 | "engines": { 947 | "node": ">=8.6" 948 | }, 949 | "funding": { 950 | "url": "https://github.com/sponsors/jonschlinkert" 951 | } 952 | }, 953 | "node_modules/postcss": { 954 | "version": "8.4.18", 955 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", 956 | "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", 957 | "dev": true, 958 | "funding": [ 959 | { 960 | "type": "opencollective", 961 | "url": "https://opencollective.com/postcss/" 962 | }, 963 | { 964 | "type": "tidelift", 965 | "url": "https://tidelift.com/funding/github/npm/postcss" 966 | } 967 | ], 968 | "dependencies": { 969 | "nanoid": "^3.3.4", 970 | "picocolors": "^1.0.0", 971 | "source-map-js": "^1.0.2" 972 | }, 973 | "engines": { 974 | "node": "^10 || ^12 || >=14" 975 | } 976 | }, 977 | "node_modules/probe.gl": { 978 | "version": "3.5.2", 979 | "resolved": "https://registry.npmjs.org/probe.gl/-/probe.gl-3.5.2.tgz", 980 | "integrity": "sha512-8lFQVmi7pMQZkqfj8+VjX4GU9HTkyxgRm5/h/xxA/4/IvZPv3qtP996L+awPwZsrPRKEw99t12SvqEHqSls/sA==", 981 | "dependencies": { 982 | "@babel/runtime": "^7.0.0", 983 | "@probe.gl/env": "3.5.2", 984 | "@probe.gl/log": "3.5.2", 985 | "@probe.gl/stats": "3.5.2" 986 | } 987 | }, 988 | "node_modules/reduce-flatten": { 989 | "version": "2.0.0", 990 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", 991 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", 992 | "engines": { 993 | "node": ">=6" 994 | } 995 | }, 996 | "node_modules/regenerator-runtime": { 997 | "version": "0.13.10", 998 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", 999 | "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" 1000 | }, 1001 | "node_modules/repeat-string": { 1002 | "version": "1.6.1", 1003 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1004 | "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", 1005 | "engines": { 1006 | "node": ">=0.10" 1007 | } 1008 | }, 1009 | "node_modules/resolve": { 1010 | "version": "1.22.1", 1011 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 1012 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 1013 | "dev": true, 1014 | "dependencies": { 1015 | "is-core-module": "^2.9.0", 1016 | "path-parse": "^1.0.7", 1017 | "supports-preserve-symlinks-flag": "^1.0.0" 1018 | }, 1019 | "bin": { 1020 | "resolve": "bin/resolve" 1021 | }, 1022 | "funding": { 1023 | "url": "https://github.com/sponsors/ljharb" 1024 | } 1025 | }, 1026 | "node_modules/rollup": { 1027 | "version": "2.79.1", 1028 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 1029 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 1030 | "dev": true, 1031 | "bin": { 1032 | "rollup": "dist/bin/rollup" 1033 | }, 1034 | "engines": { 1035 | "node": ">=10.0.0" 1036 | }, 1037 | "optionalDependencies": { 1038 | "fsevents": "~2.3.2" 1039 | } 1040 | }, 1041 | "node_modules/rxjs": { 1042 | "version": "7.5.7", 1043 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", 1044 | "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", 1045 | "dependencies": { 1046 | "tslib": "^2.1.0" 1047 | } 1048 | }, 1049 | "node_modules/source-map": { 1050 | "version": "0.6.1", 1051 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1052 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1053 | "dev": true, 1054 | "engines": { 1055 | "node": ">=0.10.0" 1056 | } 1057 | }, 1058 | "node_modules/source-map-js": { 1059 | "version": "1.0.2", 1060 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1061 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1062 | "dev": true, 1063 | "engines": { 1064 | "node": ">=0.10.0" 1065 | } 1066 | }, 1067 | "node_modules/source-map-support": { 1068 | "version": "0.5.21", 1069 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1070 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1071 | "dev": true, 1072 | "dependencies": { 1073 | "buffer-from": "^1.0.0", 1074 | "source-map": "^0.6.0" 1075 | } 1076 | }, 1077 | "node_modules/sprintf-js": { 1078 | "version": "1.0.3", 1079 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1080 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" 1081 | }, 1082 | "node_modules/standardized-audio-context": { 1083 | "version": "25.3.34", 1084 | "resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.34.tgz", 1085 | "integrity": "sha512-SL8FQYqpfOifYGhAVfnAgC9o86mFNhy+W3xp28lHI6HgOQMbLTMcBoSN3FT0SwE51br7I9tmgjwiLggg7WWD/Q==", 1086 | "dependencies": { 1087 | "@babel/runtime": "^7.20.1", 1088 | "automation-events": "^4.0.23", 1089 | "tslib": "^2.4.1" 1090 | } 1091 | }, 1092 | "node_modules/supports-color": { 1093 | "version": "5.5.0", 1094 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1095 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1096 | "dependencies": { 1097 | "has-flag": "^3.0.0" 1098 | }, 1099 | "engines": { 1100 | "node": ">=4" 1101 | } 1102 | }, 1103 | "node_modules/supports-preserve-symlinks-flag": { 1104 | "version": "1.0.0", 1105 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1106 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1107 | "dev": true, 1108 | "engines": { 1109 | "node": ">= 0.4" 1110 | }, 1111 | "funding": { 1112 | "url": "https://github.com/sponsors/ljharb" 1113 | } 1114 | }, 1115 | "node_modules/table-layout": { 1116 | "version": "1.0.2", 1117 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", 1118 | "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", 1119 | "dependencies": { 1120 | "array-back": "^4.0.1", 1121 | "deep-extend": "~0.6.0", 1122 | "typical": "^5.2.0", 1123 | "wordwrapjs": "^4.0.0" 1124 | }, 1125 | "engines": { 1126 | "node": ">=8.0.0" 1127 | } 1128 | }, 1129 | "node_modules/table-layout/node_modules/array-back": { 1130 | "version": "4.0.2", 1131 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 1132 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 1133 | "engines": { 1134 | "node": ">=8" 1135 | } 1136 | }, 1137 | "node_modules/table-layout/node_modules/typical": { 1138 | "version": "5.2.0", 1139 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1140 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1141 | "engines": { 1142 | "node": ">=8" 1143 | } 1144 | }, 1145 | "node_modules/terser": { 1146 | "version": "5.15.1", 1147 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", 1148 | "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", 1149 | "dev": true, 1150 | "dependencies": { 1151 | "@jridgewell/source-map": "^0.3.2", 1152 | "acorn": "^8.5.0", 1153 | "commander": "^2.20.0", 1154 | "source-map-support": "~0.5.20" 1155 | }, 1156 | "bin": { 1157 | "terser": "bin/terser" 1158 | }, 1159 | "engines": { 1160 | "node": ">=10" 1161 | } 1162 | }, 1163 | "node_modules/text-encoding-utf-8": { 1164 | "version": "1.0.2", 1165 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 1166 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 1167 | }, 1168 | "node_modules/texture-compressor": { 1169 | "version": "1.0.2", 1170 | "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", 1171 | "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", 1172 | "dependencies": { 1173 | "argparse": "^1.0.10", 1174 | "image-size": "^0.7.4" 1175 | }, 1176 | "bin": { 1177 | "texture-compressor": "bin/texture-compressor.js" 1178 | } 1179 | }, 1180 | "node_modules/tone": { 1181 | "version": "14.7.77", 1182 | "resolved": "https://registry.npmjs.org/tone/-/tone-14.7.77.tgz", 1183 | "integrity": "sha512-tCfK73IkLHyzoKUvGq47gyDyxiKLFvKiVCOobynGgBB9Dl0NkxTM2p+eRJXyCYrjJwy9Y0XCMqD3uOYsYt2Fdg==", 1184 | "dependencies": { 1185 | "standardized-audio-context": "^25.1.8", 1186 | "tslib": "^2.0.1" 1187 | } 1188 | }, 1189 | "node_modules/tslib": { 1190 | "version": "2.4.1", 1191 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", 1192 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" 1193 | }, 1194 | "node_modules/tweakpane": { 1195 | "version": "3.1.0", 1196 | "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.1.0.tgz", 1197 | "integrity": "sha512-PGAp/LPQdHwzL7/iAW4lV1p9iPQTti7YMjMWO48CoYjvZRS59RmgQnhEGzKzqST1JnmOYmQUjTe8bdhlZRJs5A==", 1198 | "funding": { 1199 | "url": "https://github.com/sponsors/cocopon" 1200 | } 1201 | }, 1202 | "node_modules/twgl.js": { 1203 | "version": "5.2.0", 1204 | "resolved": "https://registry.npmjs.org/twgl.js/-/twgl.js-5.2.0.tgz", 1205 | "integrity": "sha512-DuiCzdjO3PNOrxbxHMYuhvVPhBaH0f3WThJSixFU4eNnpe0NzECMeaEEe/aznt+EJ5JAU3pXyeXiYSgEJHJH4A==" 1206 | }, 1207 | "node_modules/typical": { 1208 | "version": "4.0.0", 1209 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", 1210 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", 1211 | "engines": { 1212 | "node": ">=8" 1213 | } 1214 | }, 1215 | "node_modules/vite": { 1216 | "version": "3.2.2", 1217 | "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.2.tgz", 1218 | "integrity": "sha512-pLrhatFFOWO9kS19bQ658CnRYzv0WLbsPih6R+iFeEEhDOuYgYCX2rztUViMz/uy/V8cLCJvLFeiOK7RJEzHcw==", 1219 | "dev": true, 1220 | "dependencies": { 1221 | "esbuild": "^0.15.9", 1222 | "postcss": "^8.4.18", 1223 | "resolve": "^1.22.1", 1224 | "rollup": "^2.79.1" 1225 | }, 1226 | "bin": { 1227 | "vite": "bin/vite.js" 1228 | }, 1229 | "engines": { 1230 | "node": "^14.18.0 || >=16.0.0" 1231 | }, 1232 | "optionalDependencies": { 1233 | "fsevents": "~2.3.2" 1234 | }, 1235 | "peerDependencies": { 1236 | "less": "*", 1237 | "sass": "*", 1238 | "stylus": "*", 1239 | "sugarss": "*", 1240 | "terser": "^5.4.0" 1241 | }, 1242 | "peerDependenciesMeta": { 1243 | "less": { 1244 | "optional": true 1245 | }, 1246 | "sass": { 1247 | "optional": true 1248 | }, 1249 | "stylus": { 1250 | "optional": true 1251 | }, 1252 | "sugarss": { 1253 | "optional": true 1254 | }, 1255 | "terser": { 1256 | "optional": true 1257 | } 1258 | } 1259 | }, 1260 | "node_modules/vite-plugin-glsl": { 1261 | "version": "0.3.0", 1262 | "resolved": "https://registry.npmjs.org/vite-plugin-glsl/-/vite-plugin-glsl-0.3.0.tgz", 1263 | "integrity": "sha512-cH7ni+Y3Vz1yOumvrP/71hXVdyTxZIaYYNDeK7KMvO5nzo0uGZZrrkwEVUaESS8/5dYemb/6G0YBj3jsP2sW1A==", 1264 | "dev": true, 1265 | "dependencies": { 1266 | "@rollup/pluginutils": "^4.2.1" 1267 | }, 1268 | "engines": { 1269 | "node": ">= 14.18.0", 1270 | "npm": ">= 6.14.17" 1271 | } 1272 | }, 1273 | "node_modules/wordwrapjs": { 1274 | "version": "4.0.1", 1275 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", 1276 | "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", 1277 | "dependencies": { 1278 | "reduce-flatten": "^2.0.0", 1279 | "typical": "^5.2.0" 1280 | }, 1281 | "engines": { 1282 | "node": ">=8.0.0" 1283 | } 1284 | }, 1285 | "node_modules/wordwrapjs/node_modules/typical": { 1286 | "version": "5.2.0", 1287 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1288 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1289 | "engines": { 1290 | "node": ">=8" 1291 | } 1292 | } 1293 | }, 1294 | "dependencies": { 1295 | "@babel/runtime": { 1296 | "version": "7.20.1", 1297 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", 1298 | "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", 1299 | "requires": { 1300 | "regenerator-runtime": "^0.13.10" 1301 | } 1302 | }, 1303 | "@esbuild/android-arm": { 1304 | "version": "0.15.13", 1305 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", 1306 | "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", 1307 | "dev": true, 1308 | "optional": true 1309 | }, 1310 | "@esbuild/linux-loong64": { 1311 | "version": "0.15.13", 1312 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", 1313 | "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", 1314 | "dev": true, 1315 | "optional": true 1316 | }, 1317 | "@jridgewell/gen-mapping": { 1318 | "version": "0.3.2", 1319 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 1320 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 1321 | "dev": true, 1322 | "requires": { 1323 | "@jridgewell/set-array": "^1.0.1", 1324 | "@jridgewell/sourcemap-codec": "^1.4.10", 1325 | "@jridgewell/trace-mapping": "^0.3.9" 1326 | } 1327 | }, 1328 | "@jridgewell/resolve-uri": { 1329 | "version": "3.1.0", 1330 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 1331 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 1332 | "dev": true 1333 | }, 1334 | "@jridgewell/set-array": { 1335 | "version": "1.1.2", 1336 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 1337 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 1338 | "dev": true 1339 | }, 1340 | "@jridgewell/source-map": { 1341 | "version": "0.3.2", 1342 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", 1343 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", 1344 | "dev": true, 1345 | "requires": { 1346 | "@jridgewell/gen-mapping": "^0.3.0", 1347 | "@jridgewell/trace-mapping": "^0.3.9" 1348 | } 1349 | }, 1350 | "@jridgewell/sourcemap-codec": { 1351 | "version": "1.4.14", 1352 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 1353 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 1354 | "dev": true 1355 | }, 1356 | "@jridgewell/trace-mapping": { 1357 | "version": "0.3.17", 1358 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", 1359 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", 1360 | "dev": true, 1361 | "requires": { 1362 | "@jridgewell/resolve-uri": "3.1.0", 1363 | "@jridgewell/sourcemap-codec": "1.4.14" 1364 | } 1365 | }, 1366 | "@loaders.gl/core": { 1367 | "version": "3.2.11", 1368 | "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-3.2.11.tgz", 1369 | "integrity": "sha512-uWQM1ZAuN0VYWEMMMwrlTKE1c4gor9SgCQXn8TlAW/4+9sL9KJ09T6AxgzYYAFdJmzTmT8BtC5aPUEYv031nRQ==", 1370 | "requires": { 1371 | "@babel/runtime": "^7.3.1", 1372 | "@loaders.gl/loader-utils": "3.2.11", 1373 | "@loaders.gl/worker-utils": "3.2.11", 1374 | "@probe.gl/log": "^3.5.0", 1375 | "probe.gl": "^3.4.0" 1376 | } 1377 | }, 1378 | "@loaders.gl/draco": { 1379 | "version": "3.2.11", 1380 | "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-3.2.11.tgz", 1381 | "integrity": "sha512-cGLcMWFe/AP5ExVEPt23Q4uo8Ewbo6hCBvcFX+b9VDfz/mIbUNa0DLRRtSi7eKgCJBRCQ/MLLz3SCm5OL5CjEA==", 1382 | "requires": { 1383 | "@babel/runtime": "^7.3.1", 1384 | "@loaders.gl/loader-utils": "3.2.11", 1385 | "@loaders.gl/schema": "3.2.11", 1386 | "@loaders.gl/worker-utils": "3.2.11", 1387 | "draco3d": "1.4.1" 1388 | } 1389 | }, 1390 | "@loaders.gl/gltf": { 1391 | "version": "3.2.11", 1392 | "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-3.2.11.tgz", 1393 | "integrity": "sha512-jhVFjNWMPydWB7MJVxSGGGdd3zhVgD94WsFKq9L/HcrdMY6s3nQtinALHXErh/G4XjH3efnjkZXfrE8KDzaJsw==", 1394 | "requires": { 1395 | "@loaders.gl/draco": "3.2.11", 1396 | "@loaders.gl/images": "3.2.11", 1397 | "@loaders.gl/loader-utils": "3.2.11", 1398 | "@loaders.gl/textures": "3.2.11" 1399 | } 1400 | }, 1401 | "@loaders.gl/images": { 1402 | "version": "3.2.11", 1403 | "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-3.2.11.tgz", 1404 | "integrity": "sha512-ch5JRXptb8JISYo2PQeASCvuiwdJjJx7ucejDT3EoeKfVHBL7vVjNkHY/UjOMQvljYoF2jD0NfmOJoll5DWjTQ==", 1405 | "requires": { 1406 | "@loaders.gl/loader-utils": "3.2.11" 1407 | } 1408 | }, 1409 | "@loaders.gl/loader-utils": { 1410 | "version": "3.2.11", 1411 | "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-3.2.11.tgz", 1412 | "integrity": "sha512-/eQjBLQI1x+5MG3b235xrUcMdKl9ALtzOPMINYeA9TI1TJBULv1xNWBg6HqVdS2ZfaC+JFc9vMxrPI7YaklqNw==", 1413 | "requires": { 1414 | "@babel/runtime": "^7.3.1", 1415 | "@loaders.gl/worker-utils": "3.2.11", 1416 | "@probe.gl/stats": "^3.5.0" 1417 | } 1418 | }, 1419 | "@loaders.gl/schema": { 1420 | "version": "3.2.11", 1421 | "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-3.2.11.tgz", 1422 | "integrity": "sha512-Fz0cWtHwE5Os0HxhEYxLCnJz5LD7djpZnNWk+lPVzIJ6HWPFlxI6lbD4zc1auN5omD2EXFkJigi8on8l3i63fQ==", 1423 | "requires": { 1424 | "@types/geojson": "^7946.0.7", 1425 | "apache-arrow": "^4.0.0" 1426 | } 1427 | }, 1428 | "@loaders.gl/textures": { 1429 | "version": "3.2.11", 1430 | "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-3.2.11.tgz", 1431 | "integrity": "sha512-GapLQ9XzCfVygVp2uFggk+Gr736hAkm0aZVRyGRi9hQjXffD7IvPOMh+cqNkHuxTcO5vHHR6jnQqYc5gtUODlg==", 1432 | "requires": { 1433 | "@loaders.gl/images": "3.2.11", 1434 | "@loaders.gl/loader-utils": "3.2.11", 1435 | "@loaders.gl/schema": "3.2.11", 1436 | "@loaders.gl/worker-utils": "3.2.11", 1437 | "ktx-parse": "^0.0.4", 1438 | "texture-compressor": "^1.0.2" 1439 | } 1440 | }, 1441 | "@loaders.gl/worker-utils": { 1442 | "version": "3.2.11", 1443 | "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-3.2.11.tgz", 1444 | "integrity": "sha512-2DyBkBJGDU66XbLz+eBByTlfbjUD3OarjzqAifenIrOaX1IuOcSqa8r6w2FOgsjlpT1ujcn0d4QO/o0zM8IWJA==", 1445 | "requires": { 1446 | "@babel/runtime": "^7.3.1" 1447 | } 1448 | }, 1449 | "@probe.gl/env": { 1450 | "version": "3.5.2", 1451 | "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-3.5.2.tgz", 1452 | "integrity": "sha512-JlNvJ2p6+ObWX7es6n3TycGPTv5CfVrCS8vblI1eHhrFCcZ6RxIo727ffRVwldpp0YTzdgjx3/4fB/1dnVYElw==", 1453 | "requires": { 1454 | "@babel/runtime": "^7.0.0" 1455 | } 1456 | }, 1457 | "@probe.gl/log": { 1458 | "version": "3.5.2", 1459 | "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-3.5.2.tgz", 1460 | "integrity": "sha512-5yo8Dg8LrSltuPBdGlLh/WOvt4LdU7DDHu75GMeiS0fKM+J4IACRpGV8SOrktCj1MWZ6JVHcNQkJnoyZ6G7p/w==", 1461 | "requires": { 1462 | "@babel/runtime": "^7.0.0", 1463 | "@probe.gl/env": "3.5.2" 1464 | } 1465 | }, 1466 | "@probe.gl/stats": { 1467 | "version": "3.5.2", 1468 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-3.5.2.tgz", 1469 | "integrity": "sha512-YKaYXiHF//fgy1OkX38JD70Lc8qxg2Viw8Q2CTNMwGPDJe12wda7kEmMKPJNw2oYLyFUfTzv00KJMA5h18z02w==", 1470 | "requires": { 1471 | "@babel/runtime": "^7.0.0" 1472 | } 1473 | }, 1474 | "@rollup/pluginutils": { 1475 | "version": "4.2.1", 1476 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 1477 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 1478 | "dev": true, 1479 | "requires": { 1480 | "estree-walker": "^2.0.1", 1481 | "picomatch": "^2.2.2" 1482 | } 1483 | }, 1484 | "@types/flatbuffers": { 1485 | "version": "1.10.0", 1486 | "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", 1487 | "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" 1488 | }, 1489 | "@types/geojson": { 1490 | "version": "7946.0.10", 1491 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", 1492 | "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" 1493 | }, 1494 | "@types/node": { 1495 | "version": "14.18.33", 1496 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz", 1497 | "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==" 1498 | }, 1499 | "@types/text-encoding-utf-8": { 1500 | "version": "1.0.2", 1501 | "resolved": "https://registry.npmjs.org/@types/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 1502 | "integrity": "sha512-AQ6zewa0ucLJvtUi5HsErbOFKAcQfRLt9zFLlUOvcXBy2G36a+ZDpCHSGdzJVUD8aNURtIjh9aSjCStNMRCcRQ==" 1503 | }, 1504 | "acorn": { 1505 | "version": "8.8.1", 1506 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 1507 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 1508 | "dev": true 1509 | }, 1510 | "ansi-styles": { 1511 | "version": "3.2.1", 1512 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1513 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1514 | "requires": { 1515 | "color-convert": "^1.9.0" 1516 | } 1517 | }, 1518 | "apache-arrow": { 1519 | "version": "4.0.1", 1520 | "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-4.0.1.tgz", 1521 | "integrity": "sha512-DyF7GXCbSjsw4P5C8b+qW7OnJKa6w9mJI0mhV0+EfZbVZCmhfiF6ffqcnrI/kzBrRqn9hH/Ft9n5+m4DTbBJpg==", 1522 | "requires": { 1523 | "@types/flatbuffers": "^1.10.0", 1524 | "@types/node": "^14.14.37", 1525 | "@types/text-encoding-utf-8": "^1.0.1", 1526 | "command-line-args": "5.1.1", 1527 | "command-line-usage": "6.1.1", 1528 | "flatbuffers": "1.12.0", 1529 | "json-bignum": "^0.0.3", 1530 | "pad-left": "^2.1.0", 1531 | "text-encoding-utf-8": "^1.0.2", 1532 | "tslib": "^2.2.0" 1533 | } 1534 | }, 1535 | "argparse": { 1536 | "version": "1.0.10", 1537 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 1538 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 1539 | "requires": { 1540 | "sprintf-js": "~1.0.2" 1541 | } 1542 | }, 1543 | "array-back": { 1544 | "version": "3.1.0", 1545 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", 1546 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" 1547 | }, 1548 | "automation-events": { 1549 | "version": "4.0.23", 1550 | "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-4.0.23.tgz", 1551 | "integrity": "sha512-3Q/moBk0NeWZb5jm5WtjmpAV5lxCoS00W+PQmQLp5mU0ra8AqU/lfjsIJly7Ze1drBE4aNfZIMGlbU+sTtJQJw==", 1552 | "requires": { 1553 | "@babel/runtime": "^7.20.1", 1554 | "tslib": "^2.4.1" 1555 | } 1556 | }, 1557 | "buffer-from": { 1558 | "version": "1.1.2", 1559 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1560 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1561 | "dev": true 1562 | }, 1563 | "chalk": { 1564 | "version": "2.4.2", 1565 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 1566 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 1567 | "requires": { 1568 | "ansi-styles": "^3.2.1", 1569 | "escape-string-regexp": "^1.0.5", 1570 | "supports-color": "^5.3.0" 1571 | } 1572 | }, 1573 | "color-convert": { 1574 | "version": "1.9.3", 1575 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 1576 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 1577 | "requires": { 1578 | "color-name": "1.1.3" 1579 | } 1580 | }, 1581 | "color-name": { 1582 | "version": "1.1.3", 1583 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1584 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 1585 | }, 1586 | "command-line-args": { 1587 | "version": "5.1.1", 1588 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", 1589 | "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", 1590 | "requires": { 1591 | "array-back": "^3.0.1", 1592 | "find-replace": "^3.0.0", 1593 | "lodash.camelcase": "^4.3.0", 1594 | "typical": "^4.0.0" 1595 | } 1596 | }, 1597 | "command-line-usage": { 1598 | "version": "6.1.1", 1599 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", 1600 | "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", 1601 | "requires": { 1602 | "array-back": "^4.0.1", 1603 | "chalk": "^2.4.2", 1604 | "table-layout": "^1.0.1", 1605 | "typical": "^5.2.0" 1606 | }, 1607 | "dependencies": { 1608 | "array-back": { 1609 | "version": "4.0.2", 1610 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 1611 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" 1612 | }, 1613 | "typical": { 1614 | "version": "5.2.0", 1615 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1616 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" 1617 | } 1618 | } 1619 | }, 1620 | "commander": { 1621 | "version": "2.20.3", 1622 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 1623 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 1624 | "dev": true 1625 | }, 1626 | "deep-extend": { 1627 | "version": "0.6.0", 1628 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 1629 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 1630 | }, 1631 | "draco3d": { 1632 | "version": "1.4.1", 1633 | "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.4.1.tgz", 1634 | "integrity": "sha512-9Rxonc70xiovBC+Bq1h57SNZIHzWTibU1VfIGp5z3Xx8dPtv4yT5uGhiH7P5uvJRR2jkrvHafRxR7bTANkvfpg==" 1635 | }, 1636 | "esbuild": { 1637 | "version": "0.15.13", 1638 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", 1639 | "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", 1640 | "dev": true, 1641 | "requires": { 1642 | "@esbuild/android-arm": "0.15.13", 1643 | "@esbuild/linux-loong64": "0.15.13", 1644 | "esbuild-android-64": "0.15.13", 1645 | "esbuild-android-arm64": "0.15.13", 1646 | "esbuild-darwin-64": "0.15.13", 1647 | "esbuild-darwin-arm64": "0.15.13", 1648 | "esbuild-freebsd-64": "0.15.13", 1649 | "esbuild-freebsd-arm64": "0.15.13", 1650 | "esbuild-linux-32": "0.15.13", 1651 | "esbuild-linux-64": "0.15.13", 1652 | "esbuild-linux-arm": "0.15.13", 1653 | "esbuild-linux-arm64": "0.15.13", 1654 | "esbuild-linux-mips64le": "0.15.13", 1655 | "esbuild-linux-ppc64le": "0.15.13", 1656 | "esbuild-linux-riscv64": "0.15.13", 1657 | "esbuild-linux-s390x": "0.15.13", 1658 | "esbuild-netbsd-64": "0.15.13", 1659 | "esbuild-openbsd-64": "0.15.13", 1660 | "esbuild-sunos-64": "0.15.13", 1661 | "esbuild-windows-32": "0.15.13", 1662 | "esbuild-windows-64": "0.15.13", 1663 | "esbuild-windows-arm64": "0.15.13" 1664 | } 1665 | }, 1666 | "esbuild-android-64": { 1667 | "version": "0.15.13", 1668 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", 1669 | "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", 1670 | "dev": true, 1671 | "optional": true 1672 | }, 1673 | "esbuild-android-arm64": { 1674 | "version": "0.15.13", 1675 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", 1676 | "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", 1677 | "dev": true, 1678 | "optional": true 1679 | }, 1680 | "esbuild-darwin-64": { 1681 | "version": "0.15.13", 1682 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", 1683 | "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", 1684 | "dev": true, 1685 | "optional": true 1686 | }, 1687 | "esbuild-darwin-arm64": { 1688 | "version": "0.15.13", 1689 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", 1690 | "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", 1691 | "dev": true, 1692 | "optional": true 1693 | }, 1694 | "esbuild-freebsd-64": { 1695 | "version": "0.15.13", 1696 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", 1697 | "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", 1698 | "dev": true, 1699 | "optional": true 1700 | }, 1701 | "esbuild-freebsd-arm64": { 1702 | "version": "0.15.13", 1703 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", 1704 | "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", 1705 | "dev": true, 1706 | "optional": true 1707 | }, 1708 | "esbuild-linux-32": { 1709 | "version": "0.15.13", 1710 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", 1711 | "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", 1712 | "dev": true, 1713 | "optional": true 1714 | }, 1715 | "esbuild-linux-64": { 1716 | "version": "0.15.13", 1717 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", 1718 | "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", 1719 | "dev": true, 1720 | "optional": true 1721 | }, 1722 | "esbuild-linux-arm": { 1723 | "version": "0.15.13", 1724 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", 1725 | "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", 1726 | "dev": true, 1727 | "optional": true 1728 | }, 1729 | "esbuild-linux-arm64": { 1730 | "version": "0.15.13", 1731 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", 1732 | "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", 1733 | "dev": true, 1734 | "optional": true 1735 | }, 1736 | "esbuild-linux-mips64le": { 1737 | "version": "0.15.13", 1738 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", 1739 | "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", 1740 | "dev": true, 1741 | "optional": true 1742 | }, 1743 | "esbuild-linux-ppc64le": { 1744 | "version": "0.15.13", 1745 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", 1746 | "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", 1747 | "dev": true, 1748 | "optional": true 1749 | }, 1750 | "esbuild-linux-riscv64": { 1751 | "version": "0.15.13", 1752 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", 1753 | "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", 1754 | "dev": true, 1755 | "optional": true 1756 | }, 1757 | "esbuild-linux-s390x": { 1758 | "version": "0.15.13", 1759 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", 1760 | "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", 1761 | "dev": true, 1762 | "optional": true 1763 | }, 1764 | "esbuild-netbsd-64": { 1765 | "version": "0.15.13", 1766 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", 1767 | "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", 1768 | "dev": true, 1769 | "optional": true 1770 | }, 1771 | "esbuild-openbsd-64": { 1772 | "version": "0.15.13", 1773 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", 1774 | "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", 1775 | "dev": true, 1776 | "optional": true 1777 | }, 1778 | "esbuild-sunos-64": { 1779 | "version": "0.15.13", 1780 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", 1781 | "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", 1782 | "dev": true, 1783 | "optional": true 1784 | }, 1785 | "esbuild-windows-32": { 1786 | "version": "0.15.13", 1787 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", 1788 | "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", 1789 | "dev": true, 1790 | "optional": true 1791 | }, 1792 | "esbuild-windows-64": { 1793 | "version": "0.15.13", 1794 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", 1795 | "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", 1796 | "dev": true, 1797 | "optional": true 1798 | }, 1799 | "esbuild-windows-arm64": { 1800 | "version": "0.15.13", 1801 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", 1802 | "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", 1803 | "dev": true, 1804 | "optional": true 1805 | }, 1806 | "escape-string-regexp": { 1807 | "version": "1.0.5", 1808 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1809 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" 1810 | }, 1811 | "estree-walker": { 1812 | "version": "2.0.2", 1813 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1814 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1815 | "dev": true 1816 | }, 1817 | "find-replace": { 1818 | "version": "3.0.0", 1819 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", 1820 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", 1821 | "requires": { 1822 | "array-back": "^3.0.1" 1823 | } 1824 | }, 1825 | "flatbuffers": { 1826 | "version": "1.12.0", 1827 | "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", 1828 | "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" 1829 | }, 1830 | "fsevents": { 1831 | "version": "2.3.2", 1832 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1833 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1834 | "dev": true, 1835 | "optional": true 1836 | }, 1837 | "function-bind": { 1838 | "version": "1.1.1", 1839 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1840 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1841 | "dev": true 1842 | }, 1843 | "gl-matrix": { 1844 | "version": "3.4.3", 1845 | "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", 1846 | "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" 1847 | }, 1848 | "has": { 1849 | "version": "1.0.3", 1850 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1851 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1852 | "dev": true, 1853 | "requires": { 1854 | "function-bind": "^1.1.1" 1855 | } 1856 | }, 1857 | "has-flag": { 1858 | "version": "3.0.0", 1859 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1860 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" 1861 | }, 1862 | "image-size": { 1863 | "version": "0.7.5", 1864 | "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", 1865 | "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==" 1866 | }, 1867 | "is-core-module": { 1868 | "version": "2.11.0", 1869 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 1870 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 1871 | "dev": true, 1872 | "requires": { 1873 | "has": "^1.0.3" 1874 | } 1875 | }, 1876 | "json-bignum": { 1877 | "version": "0.0.3", 1878 | "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", 1879 | "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==" 1880 | }, 1881 | "ktx-parse": { 1882 | "version": "0.0.4", 1883 | "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.0.4.tgz", 1884 | "integrity": "sha512-LY3nrmfXl+wZZdPxgJ3ZmLvG+wkOZZP3/dr4RbQj1Pk3Qwz44esOOSFFVQJcNWpXAtiNIC66WgXufX/SYgYz6A==" 1885 | }, 1886 | "lodash.camelcase": { 1887 | "version": "4.3.0", 1888 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1889 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" 1890 | }, 1891 | "nanoid": { 1892 | "version": "3.3.4", 1893 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 1894 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 1895 | "dev": true 1896 | }, 1897 | "pad-left": { 1898 | "version": "2.1.0", 1899 | "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", 1900 | "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", 1901 | "requires": { 1902 | "repeat-string": "^1.5.4" 1903 | } 1904 | }, 1905 | "path-parse": { 1906 | "version": "1.0.7", 1907 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1908 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1909 | "dev": true 1910 | }, 1911 | "picocolors": { 1912 | "version": "1.0.0", 1913 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1914 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 1915 | "dev": true 1916 | }, 1917 | "picomatch": { 1918 | "version": "2.3.1", 1919 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1920 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1921 | "dev": true 1922 | }, 1923 | "postcss": { 1924 | "version": "8.4.18", 1925 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", 1926 | "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", 1927 | "dev": true, 1928 | "requires": { 1929 | "nanoid": "^3.3.4", 1930 | "picocolors": "^1.0.0", 1931 | "source-map-js": "^1.0.2" 1932 | } 1933 | }, 1934 | "probe.gl": { 1935 | "version": "3.5.2", 1936 | "resolved": "https://registry.npmjs.org/probe.gl/-/probe.gl-3.5.2.tgz", 1937 | "integrity": "sha512-8lFQVmi7pMQZkqfj8+VjX4GU9HTkyxgRm5/h/xxA/4/IvZPv3qtP996L+awPwZsrPRKEw99t12SvqEHqSls/sA==", 1938 | "requires": { 1939 | "@babel/runtime": "^7.0.0", 1940 | "@probe.gl/env": "3.5.2", 1941 | "@probe.gl/log": "3.5.2", 1942 | "@probe.gl/stats": "3.5.2" 1943 | } 1944 | }, 1945 | "reduce-flatten": { 1946 | "version": "2.0.0", 1947 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", 1948 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" 1949 | }, 1950 | "regenerator-runtime": { 1951 | "version": "0.13.10", 1952 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", 1953 | "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" 1954 | }, 1955 | "repeat-string": { 1956 | "version": "1.6.1", 1957 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1958 | "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" 1959 | }, 1960 | "resolve": { 1961 | "version": "1.22.1", 1962 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 1963 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 1964 | "dev": true, 1965 | "requires": { 1966 | "is-core-module": "^2.9.0", 1967 | "path-parse": "^1.0.7", 1968 | "supports-preserve-symlinks-flag": "^1.0.0" 1969 | } 1970 | }, 1971 | "rollup": { 1972 | "version": "2.79.1", 1973 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 1974 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 1975 | "dev": true, 1976 | "requires": { 1977 | "fsevents": "~2.3.2" 1978 | } 1979 | }, 1980 | "rxjs": { 1981 | "version": "7.5.7", 1982 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", 1983 | "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", 1984 | "requires": { 1985 | "tslib": "^2.1.0" 1986 | } 1987 | }, 1988 | "source-map": { 1989 | "version": "0.6.1", 1990 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1991 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1992 | "dev": true 1993 | }, 1994 | "source-map-js": { 1995 | "version": "1.0.2", 1996 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1997 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1998 | "dev": true 1999 | }, 2000 | "source-map-support": { 2001 | "version": "0.5.21", 2002 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 2003 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 2004 | "dev": true, 2005 | "requires": { 2006 | "buffer-from": "^1.0.0", 2007 | "source-map": "^0.6.0" 2008 | } 2009 | }, 2010 | "sprintf-js": { 2011 | "version": "1.0.3", 2012 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 2013 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" 2014 | }, 2015 | "standardized-audio-context": { 2016 | "version": "25.3.34", 2017 | "resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.34.tgz", 2018 | "integrity": "sha512-SL8FQYqpfOifYGhAVfnAgC9o86mFNhy+W3xp28lHI6HgOQMbLTMcBoSN3FT0SwE51br7I9tmgjwiLggg7WWD/Q==", 2019 | "requires": { 2020 | "@babel/runtime": "^7.20.1", 2021 | "automation-events": "^4.0.23", 2022 | "tslib": "^2.4.1" 2023 | } 2024 | }, 2025 | "supports-color": { 2026 | "version": "5.5.0", 2027 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2028 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2029 | "requires": { 2030 | "has-flag": "^3.0.0" 2031 | } 2032 | }, 2033 | "supports-preserve-symlinks-flag": { 2034 | "version": "1.0.0", 2035 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 2036 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 2037 | "dev": true 2038 | }, 2039 | "table-layout": { 2040 | "version": "1.0.2", 2041 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", 2042 | "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", 2043 | "requires": { 2044 | "array-back": "^4.0.1", 2045 | "deep-extend": "~0.6.0", 2046 | "typical": "^5.2.0", 2047 | "wordwrapjs": "^4.0.0" 2048 | }, 2049 | "dependencies": { 2050 | "array-back": { 2051 | "version": "4.0.2", 2052 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 2053 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" 2054 | }, 2055 | "typical": { 2056 | "version": "5.2.0", 2057 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 2058 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" 2059 | } 2060 | } 2061 | }, 2062 | "terser": { 2063 | "version": "5.15.1", 2064 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", 2065 | "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", 2066 | "dev": true, 2067 | "requires": { 2068 | "@jridgewell/source-map": "^0.3.2", 2069 | "acorn": "^8.5.0", 2070 | "commander": "^2.20.0", 2071 | "source-map-support": "~0.5.20" 2072 | } 2073 | }, 2074 | "text-encoding-utf-8": { 2075 | "version": "1.0.2", 2076 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 2077 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 2078 | }, 2079 | "texture-compressor": { 2080 | "version": "1.0.2", 2081 | "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", 2082 | "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", 2083 | "requires": { 2084 | "argparse": "^1.0.10", 2085 | "image-size": "^0.7.4" 2086 | } 2087 | }, 2088 | "tone": { 2089 | "version": "14.7.77", 2090 | "resolved": "https://registry.npmjs.org/tone/-/tone-14.7.77.tgz", 2091 | "integrity": "sha512-tCfK73IkLHyzoKUvGq47gyDyxiKLFvKiVCOobynGgBB9Dl0NkxTM2p+eRJXyCYrjJwy9Y0XCMqD3uOYsYt2Fdg==", 2092 | "requires": { 2093 | "standardized-audio-context": "^25.1.8", 2094 | "tslib": "^2.0.1" 2095 | } 2096 | }, 2097 | "tslib": { 2098 | "version": "2.4.1", 2099 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", 2100 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" 2101 | }, 2102 | "tweakpane": { 2103 | "version": "3.1.0", 2104 | "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.1.0.tgz", 2105 | "integrity": "sha512-PGAp/LPQdHwzL7/iAW4lV1p9iPQTti7YMjMWO48CoYjvZRS59RmgQnhEGzKzqST1JnmOYmQUjTe8bdhlZRJs5A==" 2106 | }, 2107 | "twgl.js": { 2108 | "version": "5.2.0", 2109 | "resolved": "https://registry.npmjs.org/twgl.js/-/twgl.js-5.2.0.tgz", 2110 | "integrity": "sha512-DuiCzdjO3PNOrxbxHMYuhvVPhBaH0f3WThJSixFU4eNnpe0NzECMeaEEe/aznt+EJ5JAU3pXyeXiYSgEJHJH4A==" 2111 | }, 2112 | "typical": { 2113 | "version": "4.0.0", 2114 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", 2115 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" 2116 | }, 2117 | "vite": { 2118 | "version": "3.2.2", 2119 | "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.2.tgz", 2120 | "integrity": "sha512-pLrhatFFOWO9kS19bQ658CnRYzv0WLbsPih6R+iFeEEhDOuYgYCX2rztUViMz/uy/V8cLCJvLFeiOK7RJEzHcw==", 2121 | "dev": true, 2122 | "requires": { 2123 | "esbuild": "^0.15.9", 2124 | "fsevents": "~2.3.2", 2125 | "postcss": "^8.4.18", 2126 | "resolve": "^1.22.1", 2127 | "rollup": "^2.79.1" 2128 | } 2129 | }, 2130 | "vite-plugin-glsl": { 2131 | "version": "0.3.0", 2132 | "resolved": "https://registry.npmjs.org/vite-plugin-glsl/-/vite-plugin-glsl-0.3.0.tgz", 2133 | "integrity": "sha512-cH7ni+Y3Vz1yOumvrP/71hXVdyTxZIaYYNDeK7KMvO5nzo0uGZZrrkwEVUaESS8/5dYemb/6G0YBj3jsP2sW1A==", 2134 | "dev": true, 2135 | "requires": { 2136 | "@rollup/pluginutils": "^4.2.1" 2137 | } 2138 | }, 2139 | "wordwrapjs": { 2140 | "version": "4.0.1", 2141 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", 2142 | "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", 2143 | "requires": { 2144 | "reduce-flatten": "^2.0.0", 2145 | "typical": "^5.2.0" 2146 | }, 2147 | "dependencies": { 2148 | "typical": { 2149 | "version": "5.2.0", 2150 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 2151 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" 2152 | } 2153 | } 2154 | } 2155 | } 2156 | } 2157 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "liquid-geo", 3 | "private": true, 4 | "version": "2.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "start": "vite serve", 8 | "build": "vite build --emptyOutDir --base=/liquid-geo/dist/", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "terser": "^5.14.2", 13 | "vite": "^3.0.0", 14 | "vite-plugin-glsl": "^0.3.0" 15 | }, 16 | "dependencies": { 17 | "@loaders.gl/core": "^3.2.3", 18 | "@loaders.gl/gltf": "^3.2.3", 19 | "gl-matrix": "^3.4.3", 20 | "rxjs": "^7.5.6", 21 | "tone": "^14.7.77", 22 | "tweakpane": "^3.1.0", 23 | "twgl.js": "^5.0.4" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/_sketch-template.js: -------------------------------------------------------------------------------- 1 | import { vec2 } from "gl-matrix"; 2 | 3 | export class Sketch { 4 | 5 | TARGET_FRAME_DURATION = 16; 6 | #time = 0; // total time 7 | #deltaTime = 0; // duration betweent the previous and the current animation frame 8 | #frames = 0; // total framecount according to the target frame duration 9 | // relative frames according to the target frame duration (1 = 60 fps) 10 | // gets smaller with higher framerates --> use to adapt animation timing 11 | #deltaFrames = 0; 12 | 13 | constructor(canvasElm, onInit = null) { 14 | this.canvas = canvasElm; 15 | this.onInit = onInit; 16 | 17 | this.#init(); 18 | } 19 | 20 | run(time = 0) { 21 | this.#deltaTime = Math.min(32, time - this.#time); 22 | this.#time = time; 23 | this.#deltaFrames = this.#deltaTime / this.TARGET_FRAME_DURATION; 24 | this.#frames += this.#deltaFrames 25 | 26 | this.#animate(this.#deltaTime); 27 | this.#render(); 28 | 29 | requestAnimationFrame((t) => this.run(t)); 30 | } 31 | 32 | resize() { 33 | this.viewportSize = vec2.set( 34 | this.viewportSize, 35 | this.canvas.clientWidth, 36 | this.canvas.clientHeight 37 | ); 38 | } 39 | 40 | #init() { 41 | this.viewportSize = vec2.fromValues( 42 | this.canvas.clientWidth, 43 | this.canvas.clientHeight 44 | ); 45 | 46 | if (this.onInit) this.onInit(this); 47 | } 48 | 49 | #animate(deltaTime) { 50 | 51 | } 52 | 53 | #render() { 54 | 55 | } 56 | } -------------------------------------------------------------------------------- /src/app/app.js: -------------------------------------------------------------------------------- 1 | import { concatAll, take, count, debounceTime, delay, filter, forkJoin, from, fromEvent, map, scan, withLatestFrom, of, switchMap, tap, distinctUntilChanged } from 'rxjs'; 2 | import { Sketch } from './sketch'; 3 | import { Pane } from 'tweakpane'; 4 | import * as modernizr from './utils/modernizr'; 5 | import { AudioRepeater } from './audio-repeater'; 6 | 7 | const queryString = window.location.search; 8 | const urlParams = new URLSearchParams(queryString); 9 | const hasDebugParam = urlParams.get('debug'); 10 | const isDev = import.meta.env.MODE === 'development'; 11 | let sketch; 12 | let audioRepeater; 13 | let pane; 14 | 15 | if (isDev) { 16 | import('https://greggman.github.io/webgl-lint/webgl-lint.js'); 17 | } 18 | 19 | if (hasDebugParam || isDev) { 20 | pane = new Pane({ title: 'Settings', expanded: isDev }); 21 | } 22 | 23 | const resize = () => { 24 | // explicitly set the width and height to compensate for missing dvh and dvw support 25 | document.body.style.width = `${document.documentElement.clientWidth}px`; 26 | document.body.style.height = `${document.documentElement.clientHeight}px`; 27 | 28 | if (sketch) { 29 | sketch.resize(); 30 | } 31 | } 32 | 33 | // add a debounced resize listener 34 | fromEvent(window, 'resize').pipe(debounceTime(100)).subscribe(() => resize()); 35 | 36 | // resize initially on load 37 | fromEvent(window, 'load').pipe(take(1)).subscribe(() => resize()); 38 | 39 | // INIT APP 40 | const canvasElm = document.querySelector('canvas'); 41 | const recordBtnElm = document.querySelector('#record-button'); 42 | const playbackBtnElm = document.querySelector('#playback-button'); 43 | audioRepeater = new AudioRepeater(recordBtnElm, playbackBtnElm, isDev, pane); 44 | sketch = new Sketch(canvasElm, audioRepeater, (instance) => instance.run(), isDev, pane); 45 | resize(); 46 | -------------------------------------------------------------------------------- /src/app/audio-repeater.js: -------------------------------------------------------------------------------- 1 | import * as Tone from 'tone'; 2 | 3 | export class AudioRepeater { 4 | 5 | MAX_RECORD_LENGTH = 5; // seconds 6 | FFT_BUFFER_SIZE = 256; 7 | 8 | isRecording = false; 9 | isRecordingTimeoutId = null; 10 | 11 | MIN_DB = -100; 12 | 13 | constructor(recordBtnElm, playbackBtnElm, isDev = false, pane = null) { 14 | this.isDev = isDev; 15 | this.pane = pane; 16 | this.recordBtnElm = recordBtnElm; 17 | this.recordBtnLabelElm = recordBtnElm.querySelector('label'); 18 | this.playbackBtnElm = playbackBtnElm; 19 | this.playbackBtnLabelElm = playbackBtnElm.querySelector('label'); 20 | this.playbackBtnElm.setAttribute('disabled', true); 21 | 22 | this.init(); 23 | } 24 | 25 | init() { 26 | this.recordBtnLabelElm.innerHTML = 'RECORD'; 27 | this.playbackBtnLabelElm.innerHTML = 'PLAY'; 28 | this.playbackBtnElm.setAttribute('disabled', true); 29 | 30 | this.recordBtnElm.addEventListener('click', () => this.onRecordButtonClicked()); 31 | this.playbackBtnElm.addEventListener('click', () => this.onPlaybackButtonClicked()); 32 | } 33 | 34 | initAudio() { 35 | this.audioContext = new AudioContext(); 36 | Tone.setContext(this.audioContext); 37 | 38 | this.gain = this.audioContext.createGain(); 39 | 40 | this.analyser = this.audioContext.createAnalyser(); 41 | this.analyser.fftSize = this.FFT_BUFFER_SIZE; 42 | this.analyser.minDecibels = -90; 43 | this.bufferLength = this.analyser.frequencyBinCount; 44 | this.buffer = new Uint8Array(this.bufferLength); 45 | this.smoothedBuffer1 = new Float32Array(this.bufferLength); 46 | this.smoothedBuffer2 = new Float32Array(this.bufferLength); 47 | this.buffer.fill(0); 48 | this.smoothedBuffer1.fill(0); 49 | this.smoothedBuffer2.fill(0); 50 | // calculate the frequency bin bandwidth 51 | this.freqBandwidth = (this.audioContext.sampleRate / 2) / this.bufferLength; 52 | 53 | this.dist = new Tone.Distortion(0.3); 54 | this.pitchShift = new Tone.PitchShift(-2); 55 | this.reverb = new Tone.Reverb(3); 56 | 57 | Tone.connect(this.dist, this.pitchShift); 58 | Tone.connect(this.pitchShift, this.reverb); 59 | this.reverb.toDestination(); 60 | } 61 | 62 | startPlayback() { 63 | this.audio.currentTime = 0; 64 | this.audio.play(); 65 | } 66 | 67 | pausePlayback() { 68 | this.audio.pause(); 69 | } 70 | 71 | onPlaybackButtonClicked() { 72 | this.startPlayback(); 73 | } 74 | 75 | async onRecordButtonClicked() { 76 | if (!this.audioContext) this.initAudio(); 77 | 78 | if (this.isRecording) { 79 | this.stopRecording(); 80 | } else { 81 | await this.startRecording(); 82 | } 83 | } 84 | 85 | async startRecording() { 86 | if (this.audio) { 87 | this.audio.pause(); 88 | } 89 | 90 | this.recordBtnElm.classList.add('is-recording'); 91 | this.playbackBtnElm.setAttribute('disabled', true); 92 | this.recordBtnLabelElm.innerHTML = 'STOP'; 93 | this.isRecording = true; 94 | this.audioChunks = []; 95 | 96 | if (!this.mediaRecorder) { 97 | const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); 98 | this.mediaRecorder = new MediaRecorder(stream); 99 | 100 | this.mediaRecorder.addEventListener("dataavailable", event => { 101 | this.audioChunks.push(event.data); 102 | }); 103 | 104 | this.mediaRecorder.addEventListener("stop", () => { 105 | this.audioBlob = new Blob(this.audioChunks, { type: "audio/mpeg" }); 106 | this.audioUrl = URL.createObjectURL(this.audioBlob); 107 | this.audio = new Audio(this.audioUrl); 108 | 109 | this.source = this.audioContext.createMediaElementSource(this.audio); 110 | Tone.connect(this.source, this.dist); 111 | Tone.connect(this.source, this.analyser); 112 | }); 113 | } 114 | this.mediaRecorder.start(); 115 | 116 | this.isRecordingTimeoutId = setTimeout(() => this.stopRecording(), this.MAX_RECORD_LENGTH * 1000); 117 | } 118 | 119 | stopRecording() { 120 | this.recordBtnElm.classList.remove('is-recording'); 121 | this.playbackBtnElm.removeAttribute('disabled'); 122 | this.isRecording = false; 123 | this.recordBtnLabelElm.innerHTML = 'RECORD'; 124 | clearTimeout(this.isRecordingTimeoutId); 125 | this.mediaRecorder.stop(); 126 | } 127 | 128 | getSpectrum(){ 129 | if (this.audioContext) { 130 | if (this.audio && !this.audio.paused) { 131 | this.analyser.getByteFrequencyData( this.buffer ); 132 | } else { 133 | this.buffer.fill(0); 134 | } 135 | 136 | if (this.buffer) { 137 | for(let i=0; i u_twoStagePmS1) ) 33 | // must copy -> compare with self 34 | compare = 0.0; 35 | else 36 | // must sort 37 | if ( mod((j + u_passModStage) / u_ppass, 2.0) < 1.0) 38 | // we are on the left side -> compare with partner on the right 39 | compare = 1.0; 40 | else 41 | // we are on the right side -> compare with partner on the left 42 | compare = -1.0; 43 | 44 | // get the partner 45 | float adr = i + compare * u_ppass; 46 | uvec4 partner = texture(u_indicesTexture, vec2(floor(mod(adr, width)) / width, floor(adr / width) / height)); 47 | 48 | // on the left it's a < operation; on the right it's a >= operation 49 | outIndices = (float(self.x) * compare < float(partner.x) * compare) ? self : partner; 50 | } 51 | -------------------------------------------------------------------------------- /src/app/shader/sph/sort.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec2 a_position; 4 | 5 | void main() { 6 | gl_Position = vec4(a_position, 0., 1.); 7 | } -------------------------------------------------------------------------------- /src/app/shader/sph/utils/particle-utils.glsl: -------------------------------------------------------------------------------- 1 | 2 | ivec2 ndx2tex(ivec2 dimensions, int index) { 3 | int y = index / dimensions.x; 4 | int x = index % dimensions.x; 5 | return ivec2(x, y); 6 | } 7 | 8 | int tex2ndx(ivec2 dimensions, ivec2 tex) { 9 | return tex.x + tex.y * dimensions.x; 10 | } 11 | 12 | float sphericalDistance(vec3 pi, vec3 pj) { 13 | return (acos(dot(pj, pi))); 14 | } 15 | 16 | float sqrParticleDist(vec3 pi, vec3 pj) { 17 | vec3 pij = pj - pi; 18 | return dot(pij, pij); 19 | } 20 | 21 | ivec2 pos2CellIndex(vec2 p, ivec2 cellTexSize, vec2 domainScale, float cellSize) { 22 | vec2 pi = p * 0.5 + 0.5; 23 | pi = clamp(pi, vec2(0.001), vec2(.999)); 24 | pi *= domainScale; 25 | return ivec2(pi / cellSize); 26 | } 27 | 28 | int pos2CellId(vec2 p, ivec2 cellTexSize, vec2 domainScale, float cellSize) { 29 | ivec2 cellIndex = pos2CellIndex(p, cellTexSize, domainScale, cellSize); 30 | return tex2ndx(cellTexSize, cellIndex); 31 | } 32 | 33 | int getFlatCellIndex(ivec2 cellIndex, int numGridCells) { 34 | int p1 = 73856093; // some large primes 35 | int p2 = 19349663; 36 | int n = p1 * cellIndex.x ^ p2 * cellIndex.y; 37 | n %= numGridCells; 38 | return n; 39 | } 40 | 41 | float mod289(float x){return x - floor(x * (1.0 / 289.0)) * 289.0;} 42 | vec4 mod289(vec4 x){return x - floor(x * (1.0 / 289.0)) * 289.0;} 43 | vec4 perm(vec4 x){return mod289(((x * 34.0) + 1.0) * x);} 44 | 45 | float noise(vec3 p){ 46 | vec3 a = floor(p); 47 | vec3 d = p - a; 48 | d = d * d * (3.0 - 2.0 * d); 49 | 50 | vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0); 51 | vec4 k1 = perm(b.xyxy); 52 | vec4 k2 = perm(k1.xyxy + b.zzww); 53 | 54 | vec4 c = k2 + a.zzzz; 55 | vec4 k3 = perm(c); 56 | vec4 k4 = perm(c + 1.0); 57 | 58 | vec4 o1 = fract(k3 * (1.0 / 41.0)); 59 | vec4 o2 = fract(k4 * (1.0 / 41.0)); 60 | 61 | vec4 o3 = o2 * d.z + o1 * (1.0 - d.z); 62 | vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x); 63 | 64 | return o4.y * d.y + o4.x * (1.0 - d.y); 65 | } 66 | 67 | vec3 snoiseVec3( vec3 x ){ 68 | float s = noise(vec3( x )); 69 | float s1 = noise(vec3( x.y - 19.1 , x.z + 33.4 , x.x + 47.2 )); 70 | float s2 = noise(vec3( x.z + 74.2 , x.x - 124.5 , x.y + 99.4 )); 71 | vec3 c = vec3( s , s1 , s2 ); 72 | return c; 73 | } 74 | 75 | vec3 curlNoise( vec3 p ){ 76 | const float e = .1; 77 | vec3 dx = vec3( e , 0.0 , 0.0 ); 78 | vec3 dy = vec3( 0.0 , e , 0.0 ); 79 | vec3 dz = vec3( 0.0 , 0.0 , e ); 80 | 81 | vec3 p_x0 = snoiseVec3( p - dx ); 82 | vec3 p_x1 = snoiseVec3( p + dx ); 83 | vec3 p_y0 = snoiseVec3( p - dy ); 84 | vec3 p_y1 = snoiseVec3( p + dy ); 85 | vec3 p_z0 = snoiseVec3( p - dz ); 86 | vec3 p_z1 = snoiseVec3( p + dz ); 87 | 88 | float x = p_y1.z - p_y0.z - p_z1.y + p_z0.y; 89 | float y = p_z1.x - p_z0.x - p_x1.z + p_x0.z; 90 | float z = p_x1.y - p_x0.y - p_y1.x + p_y0.x; 91 | 92 | const float divisor = 1.0 / ( 2.0 * e ); 93 | return normalize( vec3( x , y , z ) * divisor ); 94 | } -------------------------------------------------------------------------------- /src/app/shader/test.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform sampler2D u_texture; 6 | 7 | out vec4 outColor; 8 | 9 | in vec2 v_uv; 10 | 11 | void main() { 12 | outColor = vec4(texture(u_texture, v_uv)); 13 | } -------------------------------------------------------------------------------- /src/app/shader/test.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec2 a_position; 4 | 5 | out vec2 v_uv; 6 | 7 | void main() { 8 | v_uv = 0.5 * a_position + 0.5; 9 | gl_Position = vec4(a_position, 0., 1.); 10 | } -------------------------------------------------------------------------------- /src/app/sketch.js: -------------------------------------------------------------------------------- 1 | import { mat4, vec2, vec3, vec4 } from "gl-matrix"; 2 | import { filter, fromEvent, merge, throwIfEmpty } from "rxjs"; 3 | import * as twgl from "twgl.js"; 4 | import { GLBBuilder } from "./utils/glb-builder"; 5 | 6 | import drawVert from './shader/sph/draw.vert.glsl'; 7 | import drawFrag from './shader/sph/draw.frag.glsl'; 8 | import integrateVert from './shader/sph/integrate.vert.glsl'; 9 | import integrateFrag from './shader/sph/integrate.frag.glsl'; 10 | import pressureVert from './shader/sph/pressure.vert.glsl'; 11 | import pressureFrag from './shader/sph/pressure.frag.glsl'; 12 | import forceVert from './shader/sph/force.vert.glsl'; 13 | import forceFrag from './shader/sph/force.frag.glsl'; 14 | import testVert from './shader/test.vert.glsl'; 15 | import testFrag from './shader/test.frag.glsl'; 16 | import beadVert from './shader/bead.vert.glsl'; 17 | import beadFrag from './shader/bead.frag.glsl'; 18 | import lightDepthFrag from './shader/light-depth.frag.glsl'; 19 | import highpassVert from './shader/highpass.vert.glsl'; 20 | import highpassFrag from './shader/highpass.frag.glsl'; 21 | import blurVert from './shader/blur.vert.glsl'; 22 | import blurFrag from './shader/blur.frag.glsl'; 23 | import compositeVert from './shader/composite.vert.glsl'; 24 | import compositeFrag from './shader/composite.frag.glsl'; 25 | import {isIOS} from './is-ios.js'; 26 | 27 | export class Sketch { 28 | 29 | TARGET_FRAME_DURATION = 16; 30 | #time = 0; // total time 31 | #deltaTime = 0; // duration betweent the previous and the current animation frame 32 | #frames = 0; // total framecount according to the target frame duration 33 | // relative frames according to the target frame duration (1 = 60 fps) 34 | // gets smaller with higher framerates --> use to adapt animation timing 35 | #deltaFrames = 0; 36 | 37 | // particle constants 38 | NUM_PARTICLES = 500; 39 | 40 | // the scale factor for the bloom and lensflare highpass texture 41 | SS_FX_SCALE = 0.2; 42 | 43 | simulationParams = { 44 | H: 1, // kernel radius 45 | MASS: 1, // particle mass 46 | REST_DENS: 1.5, // rest density 47 | GAS_CONST: 400, // gas constant 48 | VISC: 18.5, // viscosity constant 49 | 50 | // these are calculated from the above constants 51 | POLY6: 0, 52 | HSQ: 0, 53 | SPIKY_GRAD: 0, 54 | VISC_LAP: 0, 55 | 56 | PARTICLE_COUNT: 0, 57 | DOMAIN_SCALE: vec4.fromValues(1, 1, 1, 1), 58 | 59 | STEPS: 0 60 | }; 61 | 62 | pointerParams = { 63 | RADIUS: .5, 64 | STRENGTH: 20, 65 | } 66 | 67 | camera = { 68 | matrix: mat4.create(), 69 | near: 4, 70 | far: 6, 71 | fov: Math.PI / 3, 72 | aspect: 1, 73 | position: vec3.fromValues(0, 0, 6), 74 | up: vec3.fromValues(0, 1, 0), 75 | matrices: { 76 | view: mat4.create(), 77 | projection: mat4.create(), 78 | inversProjection: mat4.create(), 79 | inversViewProjection: mat4.create() 80 | } 81 | }; 82 | 83 | light = { 84 | matrix: mat4.create(), 85 | position: vec3.scale(vec3.create(), vec3.normalize(vec3.create(), vec3.fromValues(1, 1, 1)), 6), 86 | up: vec3.fromValues(0, 1, 0), 87 | size: 2.4, 88 | near: 4, 89 | far: 7, 90 | textureSize: 1024, 91 | matrices: { 92 | view: mat4.create(), 93 | projection: mat4.create(), 94 | viewProjection: mat4.create() 95 | } 96 | } 97 | 98 | constructor(canvasElm, audioRepeater, onInit = null, isDev = false, pane = null) { 99 | this.canvas = canvasElm; 100 | this.onInit = onInit; 101 | this.isDev = isDev; 102 | this.pane = pane; 103 | this.audioRepeater = audioRepeater; 104 | 105 | this.#init().then(() => { 106 | if (this.onInit) this.onInit(this) 107 | }); 108 | } 109 | 110 | run(time = 0) { 111 | this.#deltaTime = Math.min(16, time - this.#time); 112 | this.#time = time; 113 | this.#deltaFrames = this.#deltaTime / this.TARGET_FRAME_DURATION; 114 | this.#frames += this.#deltaFrames; 115 | 116 | this.#animate(this.#deltaTime); 117 | this.#render(); 118 | 119 | requestAnimationFrame((t) => this.run(t)); 120 | } 121 | 122 | resize() { 123 | /** @type {WebGLRenderingContext} */ 124 | const gl = this.gl; 125 | 126 | this.viewportSize = vec2.set( 127 | this.viewportSize, 128 | this.canvas.clientWidth, 129 | this.canvas.clientHeight 130 | ); 131 | 132 | const needsResize = twgl.resizeCanvasToDisplaySize(this.canvas); 133 | 134 | const maxViewportSide = Math.max(this.viewportSize[0], this.viewportSize[1]); 135 | this.SS_FX_SCALE = Math.min(1, 256 / maxViewportSide); 136 | 137 | if (needsResize) { 138 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 139 | 140 | if (this.highpassFBO) { 141 | twgl.resizeFramebufferInfo(gl, this.highpassFBO, [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 142 | this.viewportSize[0] * this.SS_FX_SCALE, this.viewportSize[1] * this.SS_FX_SCALE); 143 | } 144 | 145 | if (this.blurFBO) { 146 | twgl.resizeFramebufferInfo(gl, this.blurFBO, [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 147 | this.viewportSize[0] * this.SS_FX_SCALE, this.viewportSize[1] * this.SS_FX_SCALE); 148 | } 149 | 150 | if (this.drawFBO) { 151 | twgl.resizeFramebufferInfo(gl, this.drawFBO, this.drawFBOAttachements, this.viewportSize[0], this.viewportSize[1]); 152 | } 153 | } 154 | 155 | this.#updateProjectionMatrix(gl); 156 | } 157 | 158 | async #init() { 159 | this.gl = this.canvas.getContext('webgl2', { antialias: false, alpha: false }); 160 | 161 | this.touchevents = Modernizr.touchevents; 162 | 163 | /** @type {WebGLRenderingContext} */ 164 | const gl = this.gl; 165 | 166 | twgl.addExtensionsToContext(gl); 167 | 168 | this.viewportSize = vec2.fromValues( 169 | this.canvas.clientWidth, 170 | this.canvas.clientHeight 171 | ); 172 | 173 | this.#initTextures(); 174 | this.#initLight(); 175 | await this.#initEnvMap(); 176 | await this.#initNormalMap(); 177 | 178 | // Setup Programs 179 | this.drawPrg = twgl.createProgramInfo(gl, [drawVert, drawFrag]); 180 | this.integratePrg = twgl.createProgramInfo(gl, [integrateVert, integrateFrag]); 181 | this.pressurePrg = twgl.createProgramInfo(gl, [pressureVert, pressureFrag]); 182 | this.forcePrg = twgl.createProgramInfo(gl, [forceVert, forceFrag]); 183 | this.beadPrg = twgl.createProgramInfo(gl, [beadVert, beadFrag]); 184 | this.testPrg = twgl.createProgramInfo(gl, [testVert, testFrag]); 185 | this.lightDepthPrg = twgl.createProgramInfo(gl, [beadVert, lightDepthFrag]); 186 | this.highpassPrg = twgl.createProgramInfo(gl, [highpassVert, highpassFrag]); 187 | this.blurPrg = twgl.createProgramInfo(gl, [blurVert, blurFrag]); 188 | this.compositePrg = twgl.createProgramInfo(gl, [compositeVert, compositeFrag]); 189 | 190 | // Setup uinform blocks 191 | this.simulationParamsUBO = twgl.createUniformBlockInfo(gl, this.pressurePrg, 'u_SimulationParams'); 192 | this.pointerParamsUBO = twgl.createUniformBlockInfo(gl, this.integratePrg, 'u_PointerParams'); 193 | this.simulationParamsNeedUpdate = true; 194 | 195 | // Setup Meshes 196 | this.quadBufferInfo = twgl.createBufferInfoFromArrays(gl, { a_position: { numComponents: 2, data: [-1, -1, 3, -1, -1, 3] }}); 197 | this.quadVAO = twgl.createVAOAndSetAttributes(gl, this.pressurePrg.attribSetters, this.quadBufferInfo.attribs, this.quadBufferInfo.indices); 198 | 199 | // load the bead model 200 | this.glbBuilder = new GLBBuilder(gl); 201 | await this.glbBuilder.load(new URL('../assets/bead.glb', import.meta.url)); 202 | this.beadPrimitive = this.glbBuilder.getPrimitiveDataByMeshName('bead'); 203 | this.beadBuffers = this.beadPrimitive.buffers; 204 | this.beadBufferInfo = twgl.createBufferInfoFromArrays(gl, { 205 | a_position: {...this.beadBuffers.vertices, numComponents: this.beadBuffers.vertices.numberOfComponents}, 206 | a_normal: {...this.beadBuffers.normals, numComponents: this.beadBuffers.normals.numberOfComponents}, 207 | a_texcoord: {...this.beadBuffers.texcoords, numComponents: this.beadBuffers.texcoords.numberOfComponents}, 208 | a_tangent: {...this.beadBuffers.tangents, numComponents: this.beadBuffers.tangents.numberOfComponents}, 209 | indices: {...this.beadBuffers.indices, numComponents: this.beadBuffers.indices.numberOfComponents} 210 | }); 211 | this.beadVAO = twgl.createVAOAndSetAttributes(gl, this.beadPrg.attribSetters, this.beadBufferInfo.attribs, this.beadBufferInfo.indices); 212 | 213 | // Setup Framebuffers 214 | this.pressureFBO = twgl.createFramebufferInfo(gl, [{attachment: this.textures.densityPressure}], this.textureSize, this.textureSize); 215 | this.forceFBO = twgl.createFramebufferInfo(gl, [{attachment: this.textures.force}], this.textureSize, this.textureSize); 216 | this.inFBO = twgl.createFramebufferInfo(gl, [{attachment: this.textures.position1},{attachment: this.textures.velocity1}], this.textureSize, this.textureSize); 217 | this.outFBO = twgl.createFramebufferInfo(gl, [{attachment: this.textures.position2},{attachment: this.textures.velocity2}], this.textureSize, this.textureSize); 218 | this.lightDepthFBO = twgl.createFramebufferInfo(gl, [{ 219 | attachmentPoint: gl.DEPTH_ATTACHMENT, 220 | attachment: this.lightDepthTexture 221 | }], this.light.textureSize, this.light.textureSize); 222 | this.drawFBOAttachements = [ 223 | {format: gl.RGBA, internalFormat: gl.RGBA32F, min: isIOS ? gl.NEAREST : gl.LINEAR, mag: isIOS ? gl.NEAREST : gl.LINEAR}, 224 | {attachmentPoint: gl.DEPTH_ATTACHMENT, format: gl.DEPTH_COMPONENT, internalFormat: gl.DEPTH_COMPONENT32F} 225 | ]; 226 | this.drawFBO = twgl.createFramebufferInfo(gl, this.drawFBOAttachements, this.viewportSize[0], this.viewportSize[1]); 227 | this.colorTexture = this.drawFBO.attachments[0]; 228 | this.highpassFBO = twgl.createFramebufferInfo( 229 | gl, 230 | [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 231 | this.viewportSize[0] * this.SS_FX_SCALE, 232 | this.viewportSize[1] * this.SS_FX_SCALE 233 | ); 234 | this.highpassTexture = this.highpassFBO.attachments[0]; 235 | this.blurFBO = twgl.createFramebufferInfo( 236 | gl, 237 | [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 238 | this.viewportSize[0] * this.SS_FX_SCALE, 239 | this.viewportSize[1] * this.SS_FX_SCALE 240 | ); 241 | this.blurTexture = this.blurFBO.attachments[0]; 242 | 243 | this.worldMatrix = mat4.create(); 244 | 245 | this.#initEvents(); 246 | this.#updateSimulationParams(); 247 | this.#initTweakpane(); 248 | this.#updateCameraMatrix(); 249 | this.#updateProjectionMatrix(gl); 250 | 251 | this.resize(); 252 | } 253 | 254 | #initEvents() { 255 | this.isPointerDown = false; 256 | this.pointerLeft = true; 257 | this.pointer = vec2.create(); 258 | this.pointerLerp = vec2.create(); 259 | this.pointerLerpPrev = vec2.create(); 260 | this.pointerLerpDelta = vec2.create(); 261 | this.arcPointer = vec3.create(); 262 | this.arcPointerPrev = vec3.create(); 263 | this.arcPointerDelta = vec3.create(); 264 | 265 | fromEvent(this.canvas, 'pointerdown').subscribe((e) => { 266 | this.isPointerDown = true; 267 | this.pointerLeft = false; 268 | this.pointer = vec2.fromValues(e.clientX, e.clientY); 269 | vec2.copy(this.pointerLerp, this.pointer); 270 | vec2.copy(this.pointerLerpPrev, this.pointerLerp); 271 | }); 272 | merge( 273 | fromEvent(this.canvas, 'pointerup'), 274 | fromEvent(this.canvas, 'pointerleave') 275 | ).subscribe(() => { 276 | this.isPointerDown = false; 277 | this.leftSphere = true; 278 | this.pointerLeft = true; 279 | }); 280 | 281 | fromEvent(this.canvas, 'pointermove').subscribe((e) => { 282 | this.pointer = vec2.fromValues(e.clientX, e.clientY); 283 | if (this.pointerLeft) { 284 | this.pointerLerp = vec2.clone(this.pointer); 285 | this.pointerLerpPrev = vec2.clone(this.pointer); 286 | } 287 | this.pointerLeft = false; 288 | }); 289 | 290 | fromEvent(window.document, 'keyup').subscribe(() => this.debugKey = true); 291 | } 292 | 293 | #updateSimulationParams() { 294 | const sim = this.simulationParams 295 | sim.HSQ = sim.H * sim.H; 296 | sim.POLY6 = 315.0 / (64. * Math.PI * Math.pow(sim.H, 9.)); 297 | sim.SPIKY_GRAD = -45.0 / (Math.PI * Math.pow(sim.H, 6.)); 298 | sim.VISC_LAP = 45.0 / (Math.PI * Math.pow(sim.H, 5.)); 299 | 300 | this.simulationParamsNeedUpdate = true; 301 | } 302 | 303 | #initTextures() { 304 | /** @type {WebGLRenderingContext} */ 305 | const gl = this.gl; 306 | 307 | // get a power of two texture size 308 | this.textureSize = 2**Math.ceil(Math.log2(Math.sqrt(this.NUM_PARTICLES))); 309 | 310 | // update the particle size to fill the texture space 311 | this.NUM_PARTICLES = this.textureSize * this.textureSize; 312 | this.simulationParams.PARTICLE_COUNT = this.NUM_PARTICLES; 313 | this.simulationParamsNeedUpdate = true; 314 | 315 | console.log('number of particles:', this.NUM_PARTICLES); 316 | 317 | this.spectrumTextureSize = Math.sqrt(this.audioRepeater.bufferLength); 318 | 319 | const initVelocities = new Float32Array(this.NUM_PARTICLES * 4); 320 | const initForces = new Float32Array(this.NUM_PARTICLES * 4); 321 | const initPositions = new Float32Array(this.NUM_PARTICLES * 4); 322 | 323 | for(let i=0; i { 394 | this.envMapTexture = twgl.createTexture(gl, { 395 | src: new URL('../assets/env-map-02.jpg', import.meta.url).toString(), 396 | }, () => resolve()); 397 | }); 398 | } 399 | 400 | #initNormalMap() { 401 | /** @type {WebGLRenderingContext} */ 402 | const gl = this.gl; 403 | 404 | return new Promise((resolve) => { 405 | this.normalMapTexture = twgl.createTexture(gl, { 406 | src: new URL('../assets/normal.png', import.meta.url).toString(), 407 | }, () => resolve()); 408 | }); 409 | } 410 | 411 | #initTweakpane() { 412 | if (!this.pane) return; 413 | 414 | const sim = this.pane.addFolder({ title: 'Simulation' }); 415 | sim.addInput(this.simulationParams, 'MASS', { min: 0.01, max: 5, }); 416 | sim.addInput(this.simulationParams, 'REST_DENS', { min: 0.1, max: 5, }); 417 | sim.addInput(this.simulationParams, 'GAS_CONST', { min: 10, max: 500, }); 418 | sim.addInput(this.simulationParams, 'VISC', { min: 1, max: 20, }); 419 | sim.addInput(this.simulationParams, 'STEPS', { min: 0, max: 6, step: 1 }); 420 | 421 | const pointer = this.pane.addFolder({ title: 'Pointer' }); 422 | pointer.addInput(this.pointerParams, 'RADIUS', { min: 0.1, max: 5, }); 423 | pointer.addInput(this.pointerParams, 'STRENGTH', { min: 1, max: 35, }); 424 | 425 | sim.on('change', () => this.#updateSimulationParams()); 426 | pointer.on('change', () => this.pointerParamsNeedUpdate = true); 427 | } 428 | 429 | #initLight() { 430 | mat4.targetTo(this.light.matrix, this.light.position, [0, 0, 0], this.light.up); 431 | mat4.invert(this.light.matrices.view, this.light.matrix); 432 | mat4.ortho( 433 | this.light.matrices.projection, 434 | -this.light.size / 2, 435 | this.light.size / 2, 436 | -this.light.size / 2, 437 | this.light.size / 2, 438 | this.light.near, 439 | this.light.far 440 | ); 441 | mat4.multiply(this.light.matrices.viewProjection, this.light.matrices.projection, this.light.matrices.view); 442 | } 443 | 444 | #updatePointer() { 445 | this.pointerLerp[0] += (this.pointer[0] - this.pointerLerp[0]) / 5; 446 | this.pointerLerp[1] += (this.pointer[1] - this.pointerLerp[1]) / 5; 447 | 448 | let newArcPointer = null; 449 | if (!this.touchevents || this.isPointerDown) 450 | newArcPointer = this.#screenToSpherePos(this.pointerLerp); 451 | 452 | if (newArcPointer !== null) { 453 | this.arcPointer = newArcPointer; 454 | if (this.leftSphere) { 455 | vec3.copy(this.arcPointerPrev, this.arcPointer); 456 | this.leftSphere = false; 457 | } 458 | } else { 459 | this.leftSphere = true; 460 | } 461 | 462 | 463 | this.arcPointerDelta = vec3.subtract(this.arcPointerDelta, this.arcPointer, this.arcPointerPrev); 464 | vec3.copy(this.arcPointerPrev, this.arcPointer); 465 | 466 | vec2.subtract(this.pointerLerpDelta, this.pointerLerp, this.pointerLerpPrev); 467 | vec2.copy(this.pointerLerpPrev, this.pointerLerp); 468 | } 469 | 470 | #simulate(deltaTime) { 471 | /** @type {WebGLRenderingContext} */ 472 | const gl = this.gl; 473 | 474 | if (this.simulationParamsNeedUpdate) { 475 | twgl.setBlockUniforms( 476 | this.simulationParamsUBO, 477 | { 478 | ...this.simulationParams, 479 | } 480 | ); 481 | twgl.setUniformBlock(gl, this.pressurePrg, this.simulationParamsUBO); 482 | this.simulationParamsNeedUpdate = false; 483 | } else { 484 | twgl.bindUniformBlock(gl, this.pressurePrg, this.simulationParamsUBO); 485 | } 486 | 487 | 488 | // calculate density and pressure for every particle 489 | gl.useProgram(this.pressurePrg.program); 490 | twgl.bindFramebufferInfo(gl, this.pressureFBO); 491 | gl.bindVertexArray(this.quadVAO); 492 | twgl.setUniforms(this.pressurePrg, { 493 | u_positionTexture: this.inFBO.attachments[0] 494 | }); 495 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 496 | 497 | 498 | // calculate pressure-, viscosity- and boundary forces for every particle 499 | gl.useProgram(this.forcePrg.program); 500 | twgl.bindFramebufferInfo(gl, this.forceFBO); 501 | twgl.setUniforms(this.forcePrg, { 502 | u_densityPressureTexture: this.pressureFBO.attachments[0], 503 | u_positionTexture: this.inFBO.attachments[0], 504 | u_velocityTexture: this.inFBO.attachments[1] 505 | }); 506 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 507 | 508 | // perform the integration to update the particles position and velocity 509 | gl.useProgram(this.integratePrg.program); 510 | twgl.bindFramebufferInfo(gl, this.outFBO); 511 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 512 | twgl.setUniforms(this.integratePrg, { 513 | u_positionTexture: this.inFBO.attachments[0], 514 | u_velocityTexture: this.inFBO.attachments[1], 515 | u_forceTexture: this.forceFBO.attachments[0], 516 | u_densityPressureTexture: this.pressureFBO.attachments[0], 517 | u_dt: deltaTime, 518 | u_time: this.#time, 519 | u_domainScale: this.simulationParams.DOMAIN_SCALE 520 | }); 521 | twgl.setBlockUniforms( 522 | this.pointerParamsUBO, 523 | { 524 | pointerRadius: this.pointerParams.RADIUS, 525 | pointerStrength: this.pointerParams.STRENGTH, 526 | pointerPos: this.arcPointer, 527 | pointerVelocity: this.arcPointerDelta 528 | } 529 | ); 530 | twgl.setUniformBlock(gl, this.integratePrg, this.pointerParamsUBO); 531 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 532 | 533 | // update the current result textures 534 | this.currentPositionTexture = this.outFBO.attachments[0]; 535 | this.currentVelocityTexture = this.outFBO.attachments[1]; 536 | 537 | // swap the integrate FBOs 538 | const tmp = this.inFBO; 539 | this.inFBO = this.outFBO; 540 | this.outFBO = tmp; 541 | } 542 | 543 | #animate(deltaTime) { 544 | /** @type {WebGLRenderingContext} */ 545 | const gl = this.gl; 546 | 547 | this.#updatePointer(); 548 | 549 | // use a fixed deltaTime of 10 ms adapted to 550 | // device frame rate 551 | deltaTime = 16 * this.#deltaFrames; 552 | 553 | // simulate at least once 554 | this.#simulate(deltaTime); 555 | 556 | // clear the pointer force so that it wont add up during 557 | // subsequent simulation steps 558 | vec2.set(this.pointerLerpDelta, 0, 0); 559 | 560 | // additional simulation steps 561 | for(let i=0; i 1) { 692 | this.camera.fov = 2 * Math.atan( height / distance ); 693 | } else { 694 | this.camera.fov = 2 * Math.atan( (height / this.camera.aspect) / distance ); 695 | } 696 | 697 | mat4.perspective(this.camera.matrices.projection, this.camera.fov, this.camera.aspect, this.camera.near, this.camera.far); 698 | mat4.invert(this.camera.matrices.inversProjection, this.camera.matrices.projection); 699 | mat4.multiply(this.camera.matrices.inversViewProjection, this.camera.matrix, this.camera.matrices.inversProjection) 700 | } 701 | 702 | #screenToSpherePos(screenPos) { 703 | // map to -1 to 1 704 | const x = (screenPos[0] / this.viewportSize[0]) * 2. - 1; 705 | const y = (1 - (screenPos[1] / this.viewportSize[1])) * 2. - 1; 706 | 707 | // l(t) = p + t * u 708 | const p = this.#screenToWorldPosition(x, y, 0); 709 | const u = vec3.subtract(vec3.create(), p, this.camera.position); 710 | vec3.normalize(u, u); 711 | 712 | // sphere at origin intersection 713 | const radius = 1.05; 714 | const c = vec3.dot(p, p) - radius * radius; 715 | const b = vec3.dot(u, p) * 2; 716 | const a = 1; 717 | const d = b * b - 4 * a * c; 718 | 719 | if (d < 0) { 720 | // No solution 721 | return null; 722 | } else { 723 | const sd = Math.sqrt(d); 724 | const t1 = (-b + sd) / (2 * a); 725 | const t2 = (-b - sd) / (2 * a); 726 | const t = Math.min(t1, t2); 727 | 728 | vec3.scale(u, u, t); 729 | const i = vec3.add(vec3.create(), p, u); 730 | 731 | return i; 732 | } 733 | } 734 | 735 | #screenToWorldPosition(x, y, z) { 736 | const ndcPos = vec3.fromValues(x, y, z); 737 | const worldPos = vec4.transformMat4(vec4.create(), vec4.fromValues(ndcPos[0], ndcPos[1], ndcPos[2], 1), this.camera.matrices.inversViewProjection); 738 | if (worldPos[3] !== 0){ 739 | vec4.scale(worldPos, worldPos, 1 / worldPos[3]); 740 | } 741 | 742 | return worldPos; 743 | } 744 | } -------------------------------------------------------------------------------- /src/app/utils/glb-builder.js: -------------------------------------------------------------------------------- 1 | import {load} from '@loaders.gl/core'; 2 | import {GLBLoader} from '@loaders.gl/gltf'; 3 | 4 | /** 5 | * Based on https://github.com/visgl/loaders.gl/blob/master/examples/experimental/gltf-with-raw-webgl/GlbBuilder.js 6 | */ 7 | export class GLBBuilder { 8 | 9 | constructor(gl) { 10 | this.gl = gl; 11 | } 12 | 13 | async load(url) { 14 | this.glb = await load(fetch(url), GLBLoader); 15 | 16 | this.primitives = []; 17 | for (let mesh of this.glb.json.meshes) { 18 | for (let primitiveDef of mesh.primitives) { 19 | const primitive = await this.loadPrimitive(this.glb, mesh.name, primitiveDef); 20 | if (primitive) { 21 | this.primitives.push(primitive); 22 | } 23 | } 24 | } 25 | 26 | return this.primitives; 27 | } 28 | 29 | getPrimitiveDataByMeshName(meshName) { 30 | return this.primitives.find(item => item.meshName == meshName); 31 | } 32 | 33 | async loadPrimitive(glb, meshName, primitiveDef) { 34 | /** @type {WebGLRenderingContext} */ 35 | const gl = this.gl; 36 | 37 | const indices = GLBBuilder.getAccessorData(glb, primitiveDef.indices); 38 | const vertices = GLBBuilder.getAccessorData(glb, primitiveDef.attributes.POSITION); 39 | const normals = GLBBuilder.getAccessorData(glb, primitiveDef.attributes.NORMAL); 40 | const texcoords = GLBBuilder.getAccessorData(glb, primitiveDef.attributes.TEXCOORD_0); 41 | const tangents = GLBBuilder.getAccessorData(glb, primitiveDef.attributes.TANGENT); 42 | 43 | if (!indices || !vertices || !normals || !texcoords || !tangents) return null; 44 | 45 | // Create buffers: 46 | const indicesBuffer = gl.createBuffer(); 47 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer); 48 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); 49 | 50 | const verticesBuffer = gl.createBuffer(); 51 | gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer); 52 | gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); 53 | 54 | const normalsBuffer = gl.createBuffer(); 55 | gl.bindBuffer(gl.ARRAY_BUFFER, normalsBuffer); 56 | gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW); 57 | 58 | const texcoordsBuffer = gl.createBuffer(); 59 | gl.bindBuffer(gl.ARRAY_BUFFER, texcoordsBuffer); 60 | gl.bufferData(gl.ARRAY_BUFFER, texcoords, gl.STATIC_DRAW); 61 | 62 | const tangentsBuffer = gl.createBuffer(); 63 | gl.bindBuffer(gl.ARRAY_BUFFER, tangentsBuffer); 64 | gl.bufferData(gl.ARRAY_BUFFER, tangents, gl.STATIC_DRAW); 65 | 66 | const buffers = { 67 | 68 | indices: { 69 | data: indices, 70 | webglBuffer: indicesBuffer, 71 | length: indices.length, 72 | dataType: GLBBuilder.getAccessorDataType(gl, glb, primitiveDef.indices), 73 | numberOfComponents: GLBBuilder.getAccessorNumberOfComponents(glb, primitiveDef.indices) 74 | }, 75 | 76 | vertices: { 77 | data: vertices, 78 | webglBuffer: verticesBuffer, 79 | length: vertices.length, 80 | dataType: GLBBuilder.getAccessorDataType(gl, glb, primitiveDef.attributes.POSITION), 81 | numberOfComponents: GLBBuilder.getAccessorNumberOfComponents(glb, primitiveDef.attributes.POSITION), 82 | stride: glb.json.bufferViews[glb.json.accessors[primitiveDef.attributes.POSITION].bufferView].byteStride || 0 83 | }, 84 | 85 | normals: { 86 | data: normals, 87 | webglBuffer: normalsBuffer, 88 | length: normals.length, 89 | dataType: GLBBuilder.getAccessorDataType(gl, glb, primitiveDef.attributes.NORMAL), 90 | numberOfComponents: GLBBuilder.getAccessorNumberOfComponents(glb, primitiveDef.attributes.NORMAL), 91 | stride: glb.json.bufferViews[glb.json.accessors[primitiveDef.attributes.NORMAL].bufferView].byteStride || 0 92 | }, 93 | 94 | texcoords: { 95 | data: texcoords, 96 | webglBuffer: texcoordsBuffer, 97 | length: texcoords.length, 98 | dataType: GLBBuilder.getAccessorDataType(gl, glb, primitiveDef.attributes.TEXCOORD_0), 99 | numberOfComponents: GLBBuilder.getAccessorNumberOfComponents(glb, primitiveDef.attributes.TEXCOORD_0), 100 | stride: glb.json.bufferViews[glb.json.accessors[primitiveDef.attributes.TEXCOORD_0].bufferView].byteStride || 0 101 | }, 102 | 103 | tangents: { 104 | data: tangents, 105 | webglBuffer: tangentsBuffer, 106 | length: tangents.length, 107 | dataType: GLBBuilder.getAccessorDataType(gl, glb, primitiveDef.attributes.TANGENT), 108 | numberOfComponents: GLBBuilder.getAccessorNumberOfComponents(glb, primitiveDef.attributes.TANGENT), 109 | stride: glb.json.bufferViews[glb.json.accessors[primitiveDef.attributes.TANGENT].bufferView].byteStride || 0 110 | } 111 | }; 112 | 113 | return { 114 | meshName, 115 | buffers: buffers 116 | } 117 | } 118 | 119 | static getAccessorData(glb, accessorIndex) { 120 | 121 | const accessorDef = glb.json.accessors[accessorIndex]; 122 | 123 | if (accessorDef) { 124 | 125 | const binChunk = glb.binChunks[0]; 126 | 127 | const bufferViewDef = glb.json.bufferViews[accessorDef.bufferView]; 128 | const componentType = accessorDef.componentType; 129 | const count = accessorDef.count; 130 | 131 | const byteOffset = binChunk.byteOffset + (accessorDef.byteOffset || 0) + bufferViewDef.byteOffset; 132 | 133 | let numberOfComponents = GLBBuilder.getAccessorNumberOfComponents(glb, accessorIndex); 134 | 135 | switch (componentType) { 136 | case 5120: { return new Int8Array(binChunk.arrayBuffer, byteOffset, count * numberOfComponents); } 137 | case 5121: { return new Uint8Array(binChunk.arrayBuffer, byteOffset, count * numberOfComponents); } 138 | case 5122: { return new Int16Array(binChunk.arrayBuffer, byteOffset, count * numberOfComponents); } 139 | case 5123: { return new Uint16Array(binChunk.arrayBuffer, byteOffset, count * numberOfComponents); } 140 | case 5125: { return new Uint32Array(binChunk.arrayBuffer, byteOffset, count * numberOfComponents); } 141 | case 5126: { return new Float32Array(binChunk.arrayBuffer, byteOffset, count * numberOfComponents); } 142 | } 143 | } 144 | 145 | return null; 146 | } 147 | 148 | static getAccessorNumberOfComponents(glb, accessorIndex) { 149 | 150 | const accessorDef = glb.json.accessors[accessorIndex]; 151 | 152 | switch (accessorDef.type) { 153 | case "SCALAR": return 1; 154 | case "VEC2": return 2; 155 | case "VEC3": return 3; 156 | case "VEC4": return 4; 157 | case "MAT2": return 4; 158 | case "MAT3": return 9; 159 | case "MAT4": return 16; 160 | } 161 | 162 | return null; 163 | } 164 | 165 | static getAccessorDataType(gl, glb, accessorIndex) { 166 | 167 | const accessorDef = glb.json.accessors[accessorIndex]; 168 | const componentType = accessorDef.componentType; 169 | 170 | switch (componentType) { 171 | case 5120: { return gl.BYTE; } 172 | case 5121: { return gl.UNSIGNED_BYTE; } 173 | case 5122: { return gl.SHORT; } 174 | case 5123: { return gl.UNSIGNED_SHORT; } 175 | case 5125: { return gl.UNSIGNED_INT; } 176 | case 5126: { return gl.FLOAT; } 177 | } 178 | } 179 | } -------------------------------------------------------------------------------- /src/app/utils/modernizr.js: -------------------------------------------------------------------------------- 1 | /*! modernizr 3.6.0 (Custom Build) | MIT * 2 | * https://modernizr.com/download/?-touchevents-setclasses !*/ 3 | !function(e,n,t){function o(e){var n=c.className,t=Modernizr._config.classPrefix||"";if(d&&(n=n.baseVal),Modernizr._config.enableJSClass){var o=new RegExp("(^|\\s)"+t+"no-js(\\s|$)");n=n.replace(o,"$1"+t+"js$2")}Modernizr._config.enableClasses&&(n+=" "+t+e.join(" "+t),d?c.className.baseVal=n:c.className=n)}function s(e,n){return typeof e===n}function a(){var e,n,t,o,a,i,r;for(var l in u)if(u.hasOwnProperty(l)){if(e=[],n=u[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t 2 | 3 | 4 | 5 | 6 | liquid-geo 7 | 8 | 9 | 10 | 11 | github 12 | 13 |
14 | 20 | 25 |
26 | 27 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, body { 6 | padding: 0; 7 | margin: 0; 8 | width: 100%; 9 | height: 100%; 10 | width: 100dvw; 11 | height: 100dvh; 12 | font-family: Arial,"Helvetica Neue",Helvetica,sans-serif; 13 | font-size: 18px; 14 | overflow: hidden; 15 | touch-action: none; 16 | background-color: black; 17 | } 18 | 19 | body { 20 | position: relative; 21 | } 22 | 23 | @media screen and (max-width: 640px) { 24 | body, html { 25 | font-size: 14px; 26 | } 27 | } 28 | 29 | canvas { 30 | width: 100%; 31 | height: 100%; 32 | } 33 | 34 | .github-link { 35 | position: absolute; 36 | right: 0; 37 | bottom: 0; 38 | color: #aaa; 39 | mix-blend-mode: difference; 40 | text-transform: uppercase; 41 | text-decoration: none; 42 | padding: 0.7em 1em; 43 | font-size: 0.8em; 44 | } 45 | 46 | .audio-controls { 47 | position: absolute; 48 | bottom: 0; 49 | left: 0; 50 | width: 100%; 51 | display: flex; 52 | align-items: center; 53 | justify-content: center; 54 | padding: 3em 0; 55 | pointer-events: none; 56 | } 57 | 58 | .audio-controls button { 59 | pointer-events: all; 60 | cursor: pointer; 61 | background: none; 62 | border: 2px solid #eee; 63 | border-radius: 10rem; 64 | display: flex; 65 | align-items: center; 66 | min-height: 4.25em; 67 | width: 16em; 68 | justify-content: center; 69 | } 70 | 71 | @media screen and (min-width: 641px) { 72 | .audio-controls button { 73 | min-height: 6em; 74 | } 75 | } 76 | 77 | .audio-controls button:hover { 78 | background: #333; 79 | } 80 | 81 | .audio-controls button:disabled { 82 | opacity: 0.4; 83 | pointer-events: none; 84 | } 85 | 86 | .audio-controls button label { 87 | color: #eee; 88 | font-size: 1.25rem; 89 | pointer-events: none; 90 | } 91 | 92 | .audio-controls svg { 93 | height: 2rem; 94 | width: 2rem; 95 | margin-right: 0.5rem; 96 | pointer-events: none; 97 | } 98 | 99 | @media (min-aspect-ratio: 7/5) { 100 | .audio-controls { 101 | flex-direction: column; 102 | height: 100%; 103 | padding: 0 2em; 104 | align-items: flex-end; 105 | } 106 | 107 | .audio-controls button + button { 108 | margin-top: 1em; 109 | } 110 | } 111 | 112 | @media (max-aspect-ratio: 5/8) { 113 | .audio-controls { 114 | flex-direction: column; 115 | } 116 | 117 | .audio-controls button + button { 118 | margin-top: 1em; 119 | margin-left: 0 !important; 120 | } 121 | } 122 | 123 | .audio-controls button + button { 124 | margin-left: 1em; 125 | } 126 | 127 | #playback-button svg { 128 | width: 1.7rem; 129 | height: 1.7rem; 130 | } 131 | 132 | #record-button.is-recording::before { 133 | content: ''; 134 | display: block; 135 | width: 1.5rem; 136 | height: 1.5rem; 137 | margin-right: 0.5rem; 138 | background: #f22; 139 | border-radius: 100%; 140 | } 141 | 142 | #record-button.is-recording svg { 143 | display: none; 144 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import glsl from 'vite-plugin-glsl'; 2 | import { defineConfig } from 'vite'; 3 | import path from 'path' 4 | 5 | export default defineConfig({ 6 | root: './src', 7 | server: { 8 | open: true 9 | }, 10 | plugins: [glsl({ 11 | exclude: undefined, // File paths/extensions to ignore 12 | include: /\.(glsl|wgsl|vert|frag|vs|fs)$/i, // File paths/extensions to import 13 | defaultExtension: 'glsl', // Shader suffix when no extension is specified 14 | warnDuplicatedImports: true, // Warn if the same chunk was imported multiple times 15 | compress: false // Compress the resulting shader code 16 | })], 17 | build: { 18 | outDir: '../dist', 19 | minify: 'terser', 20 | assetsDir: 'assets', 21 | rollupOptions: { 22 | output: { 23 | entryFileNames: '[name]-[hash].js', 24 | chunkFileNames: '[name]-[hash].js', 25 | assetFileNames: (assetInfo) => { 26 | let extType = path.extname(assetInfo.name); 27 | if (!/js|css/i.test(extType)) { 28 | return `assets/[name][extname]`; 29 | } 30 | return '[name]-[hash][extname]'; 31 | } 32 | } 33 | } 34 | } 35 | }); --------------------------------------------------------------------------------