├── .gitignore ├── LICENSE ├── README.md ├── cover.jpg ├── dist ├── assets │ ├── concrete.jpg │ ├── crack.mp3 │ ├── dirt.jpg │ ├── model.glb │ ├── negx.jpg │ ├── negy.jpg │ ├── negz.jpg │ ├── posx.jpg │ ├── posy.jpg │ └── posz.jpg ├── index-3e65a4b7.css ├── index-970496ac.js └── index.html ├── package-lock.json ├── package.json ├── src ├── app │ ├── app.js │ ├── shader │ │ ├── blur.frag.glsl │ │ ├── blur.vert.glsl │ │ ├── color.frag.glsl │ │ ├── color.vert.glsl │ │ ├── composite.frag.glsl │ │ ├── composite.vert.glsl │ │ ├── highpass.frag.glsl │ │ ├── highpass.vert.glsl │ │ ├── particle.frag.glsl │ │ ├── particle.vert.glsl │ │ ├── test.frag.glsl │ │ ├── test.vert.glsl │ │ ├── texture.frag.glsl │ │ └── texture.vert.glsl │ ├── sketch.js │ ├── utils.js │ └── utils │ │ ├── arcball-control.js │ │ ├── glb-builder.js │ │ ├── modernizr.js │ │ └── second-order-system.js ├── assets │ ├── concrete.jpg │ ├── crack.mp3 │ ├── dirt.jpg │ ├── env │ │ ├── negx.jpg │ │ ├── negy.jpg │ │ ├── negz.jpg │ │ ├── posx.jpg │ │ ├── posy.jpg │ │ └── posz.jpg │ └── model.glb ├── 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 | # parcel-bundler cache (https://parceljs.org/) 72 | .cache 73 | 74 | # Next.js build output 75 | .next 76 | 77 | # Nuxt.js build / generate output 78 | .nuxt 79 | 80 | # Gatsby files 81 | .cache/ 82 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 83 | # https://nextjs.org/blog/next-9-1#public-directory-support 84 | # public 85 | 86 | # vuepress build output 87 | .vuepress/dist 88 | 89 | # Serverless directories 90 | .serverless/ 91 | 92 | # FuseBox cache 93 | .fusebox/ 94 | 95 | # DynamoDB Local files 96 | .dynamodb/ 97 | 98 | # TernJS port file 99 | .tern-port 100 | 101 | 102 | src/libs/** 103 | .DS_Store 104 | /models/** -------------------------------------------------------------------------------- /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 | # Phase Transition 2 | 3 | ![phase-transition Screenshot](https://github.com/robert-leitl/phase-transition/blob/main/cover.jpg?raw=true) 4 | 5 | Ice shader on sphere with parallax mapping and vertex displacement from a procedurally generated equirectangular texture. 6 | 7 | [DEMO](https://robert-leitl.github.io/phase-transition/dist/?debug=true) 8 | 9 | ### Features 10 | - Interactive animation between texture states 11 | - Parallax mapping in equirectangular texture space 12 | - Simple bloom effect 13 | 14 | ### Credits 15 | - Ice crack sound is a snippet from [JustinBW](https://freesound.org/people/JustinBW/sounds/70110/) -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/cover.jpg -------------------------------------------------------------------------------- /dist/assets/concrete.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/concrete.jpg -------------------------------------------------------------------------------- /dist/assets/crack.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/crack.mp3 -------------------------------------------------------------------------------- /dist/assets/dirt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/dirt.jpg -------------------------------------------------------------------------------- /dist/assets/model.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/model.glb -------------------------------------------------------------------------------- /dist/assets/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/negx.jpg -------------------------------------------------------------------------------- /dist/assets/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/negy.jpg -------------------------------------------------------------------------------- /dist/assets/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/negz.jpg -------------------------------------------------------------------------------- /dist/assets/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/posx.jpg -------------------------------------------------------------------------------- /dist/assets/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/posy.jpg -------------------------------------------------------------------------------- /dist/assets/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/dist/assets/posz.jpg -------------------------------------------------------------------------------- /dist/index-3e65a4b7.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;--center-offset: 2em;color:#eee}body{position:relative}canvas{width:100%;height:100%;z-index:2}.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}#start-button,.loader,.loader:after{--track-color: rgba(134, 134, 134, .3);border-radius:50%;width:10em;height:10em;font-size:10px;margin:0;padding:0;border:2px solid var(--track-color)}#start-button,.loader{position:absolute;top:calc(50% - 5em - var(--center-offset));left:calc(50% - 5em)}.loader{border-left:2px solid #727272;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}#start-button{border-color:#aaa;background:black;color:#eee;background:#eee;color:#333;border:none;font-weight:700;text-transform:uppercase;text-align:center;opacity:0;transition:opacity .4s;cursor:pointer}#start-button label{pointer-events:none;font-size:1.5em;letter-spacing:.15em}#intro{font-family:Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace;width:100%;display:flex;flex-direction:column;align-items:center;text-align:center;position:absolute;top:calc(50% + 5em - var(--center-offset))}#intro p{font-size:.8em;max-width:24em;line-height:1.4em} 2 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Phase Transition 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |

Touch/Click and drag to transition between phases and rotate.

18 |
19 | github 20 | 21 | -------------------------------------------------------------------------------- /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 | "tweakpane": "^3.1.0", 16 | "twgl.js": "^5.0.4" 17 | }, 18 | "devDependencies": { 19 | "terser": "^5.14.2", 20 | "vite": "^3.0.0", 21 | "vite-plugin-glsl": "^0.3.0" 22 | } 23 | }, 24 | "node_modules/@babel/runtime": { 25 | "version": "7.20.6", 26 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", 27 | "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", 28 | "dependencies": { 29 | "regenerator-runtime": "^0.13.11" 30 | }, 31 | "engines": { 32 | "node": ">=6.9.0" 33 | } 34 | }, 35 | "node_modules/@esbuild/android-arm": { 36 | "version": "0.15.18", 37 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", 38 | "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", 39 | "cpu": [ 40 | "arm" 41 | ], 42 | "dev": true, 43 | "optional": true, 44 | "os": [ 45 | "android" 46 | ], 47 | "engines": { 48 | "node": ">=12" 49 | } 50 | }, 51 | "node_modules/@esbuild/linux-loong64": { 52 | "version": "0.15.18", 53 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", 54 | "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", 55 | "cpu": [ 56 | "loong64" 57 | ], 58 | "dev": true, 59 | "optional": true, 60 | "os": [ 61 | "linux" 62 | ], 63 | "engines": { 64 | "node": ">=12" 65 | } 66 | }, 67 | "node_modules/@jridgewell/gen-mapping": { 68 | "version": "0.3.2", 69 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 70 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 71 | "dev": true, 72 | "dependencies": { 73 | "@jridgewell/set-array": "^1.0.1", 74 | "@jridgewell/sourcemap-codec": "^1.4.10", 75 | "@jridgewell/trace-mapping": "^0.3.9" 76 | }, 77 | "engines": { 78 | "node": ">=6.0.0" 79 | } 80 | }, 81 | "node_modules/@jridgewell/resolve-uri": { 82 | "version": "3.1.0", 83 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 84 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 85 | "dev": true, 86 | "engines": { 87 | "node": ">=6.0.0" 88 | } 89 | }, 90 | "node_modules/@jridgewell/set-array": { 91 | "version": "1.1.2", 92 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 93 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 94 | "dev": true, 95 | "engines": { 96 | "node": ">=6.0.0" 97 | } 98 | }, 99 | "node_modules/@jridgewell/source-map": { 100 | "version": "0.3.2", 101 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", 102 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", 103 | "dev": true, 104 | "dependencies": { 105 | "@jridgewell/gen-mapping": "^0.3.0", 106 | "@jridgewell/trace-mapping": "^0.3.9" 107 | } 108 | }, 109 | "node_modules/@jridgewell/sourcemap-codec": { 110 | "version": "1.4.14", 111 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 112 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 113 | "dev": true 114 | }, 115 | "node_modules/@jridgewell/trace-mapping": { 116 | "version": "0.3.17", 117 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", 118 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", 119 | "dev": true, 120 | "dependencies": { 121 | "@jridgewell/resolve-uri": "3.1.0", 122 | "@jridgewell/sourcemap-codec": "1.4.14" 123 | } 124 | }, 125 | "node_modules/@loaders.gl/core": { 126 | "version": "3.2.12", 127 | "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-3.2.12.tgz", 128 | "integrity": "sha512-kRQZGZ2+bvd++spjfp00aq2e3RrawAlaCwFxVyyQT6kYyQIzexr/obKd3X+yxYcrr4kUsav2iGqhLVObINlStQ==", 129 | "dependencies": { 130 | "@babel/runtime": "^7.3.1", 131 | "@loaders.gl/loader-utils": "3.2.12", 132 | "@loaders.gl/worker-utils": "3.2.12", 133 | "@probe.gl/log": "^3.5.0", 134 | "probe.gl": "^3.4.0" 135 | } 136 | }, 137 | "node_modules/@loaders.gl/draco": { 138 | "version": "3.2.12", 139 | "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-3.2.12.tgz", 140 | "integrity": "sha512-QoDlnL3ouwW3OSMRbyE4DyY41oxqadtaQ7wU3K6us4CF0XgvOToZZTG6QnCfF8FauFZ8JMebn6NT1LtobTNVYQ==", 141 | "dependencies": { 142 | "@babel/runtime": "^7.3.1", 143 | "@loaders.gl/loader-utils": "3.2.12", 144 | "@loaders.gl/schema": "3.2.12", 145 | "@loaders.gl/worker-utils": "3.2.12", 146 | "draco3d": "1.4.1" 147 | } 148 | }, 149 | "node_modules/@loaders.gl/gltf": { 150 | "version": "3.2.12", 151 | "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-3.2.12.tgz", 152 | "integrity": "sha512-vdLdWruh4nqmDm/9T0HWX30fJ+UVtB35uQk9dhN/couvrXXtdpkvtb7aFdX0nlCLcrbRlcCYbuCfKctt1CF2mg==", 153 | "dependencies": { 154 | "@loaders.gl/draco": "3.2.12", 155 | "@loaders.gl/images": "3.2.12", 156 | "@loaders.gl/loader-utils": "3.2.12", 157 | "@loaders.gl/textures": "3.2.12" 158 | } 159 | }, 160 | "node_modules/@loaders.gl/images": { 161 | "version": "3.2.12", 162 | "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-3.2.12.tgz", 163 | "integrity": "sha512-acPKRg9EwgrPyItF97x8LM9p4b8GR03JY+wFJwzBlVdOZXx1dmz1t4rVynRDwgAUgybGKLoPfJtwTIKARnICYQ==", 164 | "dependencies": { 165 | "@loaders.gl/loader-utils": "3.2.12" 166 | } 167 | }, 168 | "node_modules/@loaders.gl/loader-utils": { 169 | "version": "3.2.12", 170 | "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-3.2.12.tgz", 171 | "integrity": "sha512-OXu7vqBvYj2HD0Tcle8RwRAktJ5BsBTZc6ADPNia7FOGI9sA2ZDECPa0g8gBtKpbhzluLZzPj5N4OPdL6hNiQg==", 172 | "dependencies": { 173 | "@babel/runtime": "^7.3.1", 174 | "@loaders.gl/worker-utils": "3.2.12", 175 | "@probe.gl/stats": "^3.5.0" 176 | } 177 | }, 178 | "node_modules/@loaders.gl/schema": { 179 | "version": "3.2.12", 180 | "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-3.2.12.tgz", 181 | "integrity": "sha512-IP/fniG3PsMvhU+kkryULAoszgNEUSmfCvKZujDtU65xgIHScNQP87+wgqfZFScftEX0iBSahr7QYdQCEsv83w==", 182 | "dependencies": { 183 | "@types/geojson": "^7946.0.7", 184 | "apache-arrow": "^4.0.0" 185 | } 186 | }, 187 | "node_modules/@loaders.gl/textures": { 188 | "version": "3.2.12", 189 | "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-3.2.12.tgz", 190 | "integrity": "sha512-xludkKPnzdQAHC19J0depqEvUH8x61cjsMId9Q1Et/emwI5TyEiDK78vl7tsIzuOh/IvrPHykRxfXp4uayW+Nw==", 191 | "dependencies": { 192 | "@loaders.gl/images": "3.2.12", 193 | "@loaders.gl/loader-utils": "3.2.12", 194 | "@loaders.gl/schema": "3.2.12", 195 | "@loaders.gl/worker-utils": "3.2.12", 196 | "ktx-parse": "^0.0.4", 197 | "texture-compressor": "^1.0.2" 198 | } 199 | }, 200 | "node_modules/@loaders.gl/worker-utils": { 201 | "version": "3.2.12", 202 | "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-3.2.12.tgz", 203 | "integrity": "sha512-MRgk8ln4Ur2RAnalD6OWstSuIAlf0l/26KTHtJiVD+HtmLJDoxSoQOHsnrEsdE18m+8NpAQgTD+rDzZtEpsnlw==", 204 | "dependencies": { 205 | "@babel/runtime": "^7.3.1" 206 | } 207 | }, 208 | "node_modules/@probe.gl/env": { 209 | "version": "3.5.2", 210 | "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-3.5.2.tgz", 211 | "integrity": "sha512-JlNvJ2p6+ObWX7es6n3TycGPTv5CfVrCS8vblI1eHhrFCcZ6RxIo727ffRVwldpp0YTzdgjx3/4fB/1dnVYElw==", 212 | "dependencies": { 213 | "@babel/runtime": "^7.0.0" 214 | } 215 | }, 216 | "node_modules/@probe.gl/log": { 217 | "version": "3.5.2", 218 | "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-3.5.2.tgz", 219 | "integrity": "sha512-5yo8Dg8LrSltuPBdGlLh/WOvt4LdU7DDHu75GMeiS0fKM+J4IACRpGV8SOrktCj1MWZ6JVHcNQkJnoyZ6G7p/w==", 220 | "dependencies": { 221 | "@babel/runtime": "^7.0.0", 222 | "@probe.gl/env": "3.5.2" 223 | } 224 | }, 225 | "node_modules/@probe.gl/stats": { 226 | "version": "3.5.2", 227 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-3.5.2.tgz", 228 | "integrity": "sha512-YKaYXiHF//fgy1OkX38JD70Lc8qxg2Viw8Q2CTNMwGPDJe12wda7kEmMKPJNw2oYLyFUfTzv00KJMA5h18z02w==", 229 | "dependencies": { 230 | "@babel/runtime": "^7.0.0" 231 | } 232 | }, 233 | "node_modules/@rollup/pluginutils": { 234 | "version": "4.2.1", 235 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 236 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 237 | "dev": true, 238 | "dependencies": { 239 | "estree-walker": "^2.0.1", 240 | "picomatch": "^2.2.2" 241 | }, 242 | "engines": { 243 | "node": ">= 8.0.0" 244 | } 245 | }, 246 | "node_modules/@types/flatbuffers": { 247 | "version": "1.10.0", 248 | "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", 249 | "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" 250 | }, 251 | "node_modules/@types/geojson": { 252 | "version": "7946.0.10", 253 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", 254 | "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" 255 | }, 256 | "node_modules/@types/node": { 257 | "version": "14.18.34", 258 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz", 259 | "integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==" 260 | }, 261 | "node_modules/@types/text-encoding-utf-8": { 262 | "version": "1.0.2", 263 | "resolved": "https://registry.npmjs.org/@types/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 264 | "integrity": "sha512-AQ6zewa0ucLJvtUi5HsErbOFKAcQfRLt9zFLlUOvcXBy2G36a+ZDpCHSGdzJVUD8aNURtIjh9aSjCStNMRCcRQ==" 265 | }, 266 | "node_modules/acorn": { 267 | "version": "8.8.1", 268 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 269 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 270 | "dev": true, 271 | "bin": { 272 | "acorn": "bin/acorn" 273 | }, 274 | "engines": { 275 | "node": ">=0.4.0" 276 | } 277 | }, 278 | "node_modules/ansi-styles": { 279 | "version": "3.2.1", 280 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 281 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 282 | "dependencies": { 283 | "color-convert": "^1.9.0" 284 | }, 285 | "engines": { 286 | "node": ">=4" 287 | } 288 | }, 289 | "node_modules/apache-arrow": { 290 | "version": "4.0.1", 291 | "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-4.0.1.tgz", 292 | "integrity": "sha512-DyF7GXCbSjsw4P5C8b+qW7OnJKa6w9mJI0mhV0+EfZbVZCmhfiF6ffqcnrI/kzBrRqn9hH/Ft9n5+m4DTbBJpg==", 293 | "dependencies": { 294 | "@types/flatbuffers": "^1.10.0", 295 | "@types/node": "^14.14.37", 296 | "@types/text-encoding-utf-8": "^1.0.1", 297 | "command-line-args": "5.1.1", 298 | "command-line-usage": "6.1.1", 299 | "flatbuffers": "1.12.0", 300 | "json-bignum": "^0.0.3", 301 | "pad-left": "^2.1.0", 302 | "text-encoding-utf-8": "^1.0.2", 303 | "tslib": "^2.2.0" 304 | }, 305 | "bin": { 306 | "arrow2csv": "bin/arrow2csv.js" 307 | } 308 | }, 309 | "node_modules/argparse": { 310 | "version": "1.0.10", 311 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 312 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 313 | "dependencies": { 314 | "sprintf-js": "~1.0.2" 315 | } 316 | }, 317 | "node_modules/array-back": { 318 | "version": "3.1.0", 319 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", 320 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", 321 | "engines": { 322 | "node": ">=6" 323 | } 324 | }, 325 | "node_modules/buffer-from": { 326 | "version": "1.1.2", 327 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 328 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 329 | "dev": true 330 | }, 331 | "node_modules/chalk": { 332 | "version": "2.4.2", 333 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 334 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 335 | "dependencies": { 336 | "ansi-styles": "^3.2.1", 337 | "escape-string-regexp": "^1.0.5", 338 | "supports-color": "^5.3.0" 339 | }, 340 | "engines": { 341 | "node": ">=4" 342 | } 343 | }, 344 | "node_modules/color-convert": { 345 | "version": "1.9.3", 346 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 347 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 348 | "dependencies": { 349 | "color-name": "1.1.3" 350 | } 351 | }, 352 | "node_modules/color-name": { 353 | "version": "1.1.3", 354 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 355 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 356 | }, 357 | "node_modules/command-line-args": { 358 | "version": "5.1.1", 359 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", 360 | "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", 361 | "dependencies": { 362 | "array-back": "^3.0.1", 363 | "find-replace": "^3.0.0", 364 | "lodash.camelcase": "^4.3.0", 365 | "typical": "^4.0.0" 366 | }, 367 | "engines": { 368 | "node": ">=4.0.0" 369 | } 370 | }, 371 | "node_modules/command-line-usage": { 372 | "version": "6.1.1", 373 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", 374 | "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", 375 | "dependencies": { 376 | "array-back": "^4.0.1", 377 | "chalk": "^2.4.2", 378 | "table-layout": "^1.0.1", 379 | "typical": "^5.2.0" 380 | }, 381 | "engines": { 382 | "node": ">=8.0.0" 383 | } 384 | }, 385 | "node_modules/command-line-usage/node_modules/array-back": { 386 | "version": "4.0.2", 387 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 388 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 389 | "engines": { 390 | "node": ">=8" 391 | } 392 | }, 393 | "node_modules/command-line-usage/node_modules/typical": { 394 | "version": "5.2.0", 395 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 396 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 397 | "engines": { 398 | "node": ">=8" 399 | } 400 | }, 401 | "node_modules/commander": { 402 | "version": "2.20.3", 403 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 404 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 405 | "dev": true 406 | }, 407 | "node_modules/deep-extend": { 408 | "version": "0.6.0", 409 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 410 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 411 | "engines": { 412 | "node": ">=4.0.0" 413 | } 414 | }, 415 | "node_modules/draco3d": { 416 | "version": "1.4.1", 417 | "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.4.1.tgz", 418 | "integrity": "sha512-9Rxonc70xiovBC+Bq1h57SNZIHzWTibU1VfIGp5z3Xx8dPtv4yT5uGhiH7P5uvJRR2jkrvHafRxR7bTANkvfpg==" 419 | }, 420 | "node_modules/esbuild": { 421 | "version": "0.15.18", 422 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", 423 | "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", 424 | "dev": true, 425 | "hasInstallScript": true, 426 | "bin": { 427 | "esbuild": "bin/esbuild" 428 | }, 429 | "engines": { 430 | "node": ">=12" 431 | }, 432 | "optionalDependencies": { 433 | "@esbuild/android-arm": "0.15.18", 434 | "@esbuild/linux-loong64": "0.15.18", 435 | "esbuild-android-64": "0.15.18", 436 | "esbuild-android-arm64": "0.15.18", 437 | "esbuild-darwin-64": "0.15.18", 438 | "esbuild-darwin-arm64": "0.15.18", 439 | "esbuild-freebsd-64": "0.15.18", 440 | "esbuild-freebsd-arm64": "0.15.18", 441 | "esbuild-linux-32": "0.15.18", 442 | "esbuild-linux-64": "0.15.18", 443 | "esbuild-linux-arm": "0.15.18", 444 | "esbuild-linux-arm64": "0.15.18", 445 | "esbuild-linux-mips64le": "0.15.18", 446 | "esbuild-linux-ppc64le": "0.15.18", 447 | "esbuild-linux-riscv64": "0.15.18", 448 | "esbuild-linux-s390x": "0.15.18", 449 | "esbuild-netbsd-64": "0.15.18", 450 | "esbuild-openbsd-64": "0.15.18", 451 | "esbuild-sunos-64": "0.15.18", 452 | "esbuild-windows-32": "0.15.18", 453 | "esbuild-windows-64": "0.15.18", 454 | "esbuild-windows-arm64": "0.15.18" 455 | } 456 | }, 457 | "node_modules/esbuild-android-64": { 458 | "version": "0.15.18", 459 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", 460 | "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", 461 | "cpu": [ 462 | "x64" 463 | ], 464 | "dev": true, 465 | "optional": true, 466 | "os": [ 467 | "android" 468 | ], 469 | "engines": { 470 | "node": ">=12" 471 | } 472 | }, 473 | "node_modules/esbuild-android-arm64": { 474 | "version": "0.15.18", 475 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", 476 | "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", 477 | "cpu": [ 478 | "arm64" 479 | ], 480 | "dev": true, 481 | "optional": true, 482 | "os": [ 483 | "android" 484 | ], 485 | "engines": { 486 | "node": ">=12" 487 | } 488 | }, 489 | "node_modules/esbuild-darwin-64": { 490 | "version": "0.15.18", 491 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", 492 | "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", 493 | "cpu": [ 494 | "x64" 495 | ], 496 | "dev": true, 497 | "optional": true, 498 | "os": [ 499 | "darwin" 500 | ], 501 | "engines": { 502 | "node": ">=12" 503 | } 504 | }, 505 | "node_modules/esbuild-darwin-arm64": { 506 | "version": "0.15.18", 507 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", 508 | "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", 509 | "cpu": [ 510 | "arm64" 511 | ], 512 | "dev": true, 513 | "optional": true, 514 | "os": [ 515 | "darwin" 516 | ], 517 | "engines": { 518 | "node": ">=12" 519 | } 520 | }, 521 | "node_modules/esbuild-freebsd-64": { 522 | "version": "0.15.18", 523 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", 524 | "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", 525 | "cpu": [ 526 | "x64" 527 | ], 528 | "dev": true, 529 | "optional": true, 530 | "os": [ 531 | "freebsd" 532 | ], 533 | "engines": { 534 | "node": ">=12" 535 | } 536 | }, 537 | "node_modules/esbuild-freebsd-arm64": { 538 | "version": "0.15.18", 539 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", 540 | "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", 541 | "cpu": [ 542 | "arm64" 543 | ], 544 | "dev": true, 545 | "optional": true, 546 | "os": [ 547 | "freebsd" 548 | ], 549 | "engines": { 550 | "node": ">=12" 551 | } 552 | }, 553 | "node_modules/esbuild-linux-32": { 554 | "version": "0.15.18", 555 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", 556 | "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", 557 | "cpu": [ 558 | "ia32" 559 | ], 560 | "dev": true, 561 | "optional": true, 562 | "os": [ 563 | "linux" 564 | ], 565 | "engines": { 566 | "node": ">=12" 567 | } 568 | }, 569 | "node_modules/esbuild-linux-64": { 570 | "version": "0.15.18", 571 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", 572 | "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", 573 | "cpu": [ 574 | "x64" 575 | ], 576 | "dev": true, 577 | "optional": true, 578 | "os": [ 579 | "linux" 580 | ], 581 | "engines": { 582 | "node": ">=12" 583 | } 584 | }, 585 | "node_modules/esbuild-linux-arm": { 586 | "version": "0.15.18", 587 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", 588 | "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", 589 | "cpu": [ 590 | "arm" 591 | ], 592 | "dev": true, 593 | "optional": true, 594 | "os": [ 595 | "linux" 596 | ], 597 | "engines": { 598 | "node": ">=12" 599 | } 600 | }, 601 | "node_modules/esbuild-linux-arm64": { 602 | "version": "0.15.18", 603 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", 604 | "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", 605 | "cpu": [ 606 | "arm64" 607 | ], 608 | "dev": true, 609 | "optional": true, 610 | "os": [ 611 | "linux" 612 | ], 613 | "engines": { 614 | "node": ">=12" 615 | } 616 | }, 617 | "node_modules/esbuild-linux-mips64le": { 618 | "version": "0.15.18", 619 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", 620 | "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", 621 | "cpu": [ 622 | "mips64el" 623 | ], 624 | "dev": true, 625 | "optional": true, 626 | "os": [ 627 | "linux" 628 | ], 629 | "engines": { 630 | "node": ">=12" 631 | } 632 | }, 633 | "node_modules/esbuild-linux-ppc64le": { 634 | "version": "0.15.18", 635 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", 636 | "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", 637 | "cpu": [ 638 | "ppc64" 639 | ], 640 | "dev": true, 641 | "optional": true, 642 | "os": [ 643 | "linux" 644 | ], 645 | "engines": { 646 | "node": ">=12" 647 | } 648 | }, 649 | "node_modules/esbuild-linux-riscv64": { 650 | "version": "0.15.18", 651 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", 652 | "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", 653 | "cpu": [ 654 | "riscv64" 655 | ], 656 | "dev": true, 657 | "optional": true, 658 | "os": [ 659 | "linux" 660 | ], 661 | "engines": { 662 | "node": ">=12" 663 | } 664 | }, 665 | "node_modules/esbuild-linux-s390x": { 666 | "version": "0.15.18", 667 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", 668 | "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", 669 | "cpu": [ 670 | "s390x" 671 | ], 672 | "dev": true, 673 | "optional": true, 674 | "os": [ 675 | "linux" 676 | ], 677 | "engines": { 678 | "node": ">=12" 679 | } 680 | }, 681 | "node_modules/esbuild-netbsd-64": { 682 | "version": "0.15.18", 683 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", 684 | "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", 685 | "cpu": [ 686 | "x64" 687 | ], 688 | "dev": true, 689 | "optional": true, 690 | "os": [ 691 | "netbsd" 692 | ], 693 | "engines": { 694 | "node": ">=12" 695 | } 696 | }, 697 | "node_modules/esbuild-openbsd-64": { 698 | "version": "0.15.18", 699 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", 700 | "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", 701 | "cpu": [ 702 | "x64" 703 | ], 704 | "dev": true, 705 | "optional": true, 706 | "os": [ 707 | "openbsd" 708 | ], 709 | "engines": { 710 | "node": ">=12" 711 | } 712 | }, 713 | "node_modules/esbuild-sunos-64": { 714 | "version": "0.15.18", 715 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", 716 | "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", 717 | "cpu": [ 718 | "x64" 719 | ], 720 | "dev": true, 721 | "optional": true, 722 | "os": [ 723 | "sunos" 724 | ], 725 | "engines": { 726 | "node": ">=12" 727 | } 728 | }, 729 | "node_modules/esbuild-windows-32": { 730 | "version": "0.15.18", 731 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", 732 | "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", 733 | "cpu": [ 734 | "ia32" 735 | ], 736 | "dev": true, 737 | "optional": true, 738 | "os": [ 739 | "win32" 740 | ], 741 | "engines": { 742 | "node": ">=12" 743 | } 744 | }, 745 | "node_modules/esbuild-windows-64": { 746 | "version": "0.15.18", 747 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", 748 | "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", 749 | "cpu": [ 750 | "x64" 751 | ], 752 | "dev": true, 753 | "optional": true, 754 | "os": [ 755 | "win32" 756 | ], 757 | "engines": { 758 | "node": ">=12" 759 | } 760 | }, 761 | "node_modules/esbuild-windows-arm64": { 762 | "version": "0.15.18", 763 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", 764 | "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", 765 | "cpu": [ 766 | "arm64" 767 | ], 768 | "dev": true, 769 | "optional": true, 770 | "os": [ 771 | "win32" 772 | ], 773 | "engines": { 774 | "node": ">=12" 775 | } 776 | }, 777 | "node_modules/escape-string-regexp": { 778 | "version": "1.0.5", 779 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 780 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 781 | "engines": { 782 | "node": ">=0.8.0" 783 | } 784 | }, 785 | "node_modules/estree-walker": { 786 | "version": "2.0.2", 787 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 788 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 789 | "dev": true 790 | }, 791 | "node_modules/find-replace": { 792 | "version": "3.0.0", 793 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", 794 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", 795 | "dependencies": { 796 | "array-back": "^3.0.1" 797 | }, 798 | "engines": { 799 | "node": ">=4.0.0" 800 | } 801 | }, 802 | "node_modules/flatbuffers": { 803 | "version": "1.12.0", 804 | "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", 805 | "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" 806 | }, 807 | "node_modules/fsevents": { 808 | "version": "2.3.2", 809 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 810 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 811 | "dev": true, 812 | "hasInstallScript": true, 813 | "optional": true, 814 | "os": [ 815 | "darwin" 816 | ], 817 | "engines": { 818 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 819 | } 820 | }, 821 | "node_modules/function-bind": { 822 | "version": "1.1.1", 823 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 824 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 825 | "dev": true 826 | }, 827 | "node_modules/gl-matrix": { 828 | "version": "3.4.3", 829 | "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", 830 | "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" 831 | }, 832 | "node_modules/has": { 833 | "version": "1.0.3", 834 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 835 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 836 | "dev": true, 837 | "dependencies": { 838 | "function-bind": "^1.1.1" 839 | }, 840 | "engines": { 841 | "node": ">= 0.4.0" 842 | } 843 | }, 844 | "node_modules/has-flag": { 845 | "version": "3.0.0", 846 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 847 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 848 | "engines": { 849 | "node": ">=4" 850 | } 851 | }, 852 | "node_modules/image-size": { 853 | "version": "0.7.5", 854 | "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", 855 | "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", 856 | "bin": { 857 | "image-size": "bin/image-size.js" 858 | }, 859 | "engines": { 860 | "node": ">=6.9.0" 861 | } 862 | }, 863 | "node_modules/is-core-module": { 864 | "version": "2.11.0", 865 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 866 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 867 | "dev": true, 868 | "dependencies": { 869 | "has": "^1.0.3" 870 | }, 871 | "funding": { 872 | "url": "https://github.com/sponsors/ljharb" 873 | } 874 | }, 875 | "node_modules/json-bignum": { 876 | "version": "0.0.3", 877 | "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", 878 | "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", 879 | "engines": { 880 | "node": ">=0.8" 881 | } 882 | }, 883 | "node_modules/ktx-parse": { 884 | "version": "0.0.4", 885 | "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.0.4.tgz", 886 | "integrity": "sha512-LY3nrmfXl+wZZdPxgJ3ZmLvG+wkOZZP3/dr4RbQj1Pk3Qwz44esOOSFFVQJcNWpXAtiNIC66WgXufX/SYgYz6A==" 887 | }, 888 | "node_modules/lodash.camelcase": { 889 | "version": "4.3.0", 890 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 891 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" 892 | }, 893 | "node_modules/nanoid": { 894 | "version": "3.3.4", 895 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 896 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 897 | "dev": true, 898 | "bin": { 899 | "nanoid": "bin/nanoid.cjs" 900 | }, 901 | "engines": { 902 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 903 | } 904 | }, 905 | "node_modules/pad-left": { 906 | "version": "2.1.0", 907 | "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", 908 | "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", 909 | "dependencies": { 910 | "repeat-string": "^1.5.4" 911 | }, 912 | "engines": { 913 | "node": ">=0.10.0" 914 | } 915 | }, 916 | "node_modules/path-parse": { 917 | "version": "1.0.7", 918 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 919 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 920 | "dev": true 921 | }, 922 | "node_modules/picocolors": { 923 | "version": "1.0.0", 924 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 925 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 926 | "dev": true 927 | }, 928 | "node_modules/picomatch": { 929 | "version": "2.3.1", 930 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 931 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 932 | "dev": true, 933 | "engines": { 934 | "node": ">=8.6" 935 | }, 936 | "funding": { 937 | "url": "https://github.com/sponsors/jonschlinkert" 938 | } 939 | }, 940 | "node_modules/postcss": { 941 | "version": "8.4.20", 942 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", 943 | "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", 944 | "dev": true, 945 | "funding": [ 946 | { 947 | "type": "opencollective", 948 | "url": "https://opencollective.com/postcss/" 949 | }, 950 | { 951 | "type": "tidelift", 952 | "url": "https://tidelift.com/funding/github/npm/postcss" 953 | } 954 | ], 955 | "dependencies": { 956 | "nanoid": "^3.3.4", 957 | "picocolors": "^1.0.0", 958 | "source-map-js": "^1.0.2" 959 | }, 960 | "engines": { 961 | "node": "^10 || ^12 || >=14" 962 | } 963 | }, 964 | "node_modules/probe.gl": { 965 | "version": "3.5.2", 966 | "resolved": "https://registry.npmjs.org/probe.gl/-/probe.gl-3.5.2.tgz", 967 | "integrity": "sha512-8lFQVmi7pMQZkqfj8+VjX4GU9HTkyxgRm5/h/xxA/4/IvZPv3qtP996L+awPwZsrPRKEw99t12SvqEHqSls/sA==", 968 | "dependencies": { 969 | "@babel/runtime": "^7.0.0", 970 | "@probe.gl/env": "3.5.2", 971 | "@probe.gl/log": "3.5.2", 972 | "@probe.gl/stats": "3.5.2" 973 | } 974 | }, 975 | "node_modules/reduce-flatten": { 976 | "version": "2.0.0", 977 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", 978 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", 979 | "engines": { 980 | "node": ">=6" 981 | } 982 | }, 983 | "node_modules/regenerator-runtime": { 984 | "version": "0.13.11", 985 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 986 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" 987 | }, 988 | "node_modules/repeat-string": { 989 | "version": "1.6.1", 990 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 991 | "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", 992 | "engines": { 993 | "node": ">=0.10" 994 | } 995 | }, 996 | "node_modules/resolve": { 997 | "version": "1.22.1", 998 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 999 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 1000 | "dev": true, 1001 | "dependencies": { 1002 | "is-core-module": "^2.9.0", 1003 | "path-parse": "^1.0.7", 1004 | "supports-preserve-symlinks-flag": "^1.0.0" 1005 | }, 1006 | "bin": { 1007 | "resolve": "bin/resolve" 1008 | }, 1009 | "funding": { 1010 | "url": "https://github.com/sponsors/ljharb" 1011 | } 1012 | }, 1013 | "node_modules/rollup": { 1014 | "version": "2.79.1", 1015 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 1016 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 1017 | "dev": true, 1018 | "bin": { 1019 | "rollup": "dist/bin/rollup" 1020 | }, 1021 | "engines": { 1022 | "node": ">=10.0.0" 1023 | }, 1024 | "optionalDependencies": { 1025 | "fsevents": "~2.3.2" 1026 | } 1027 | }, 1028 | "node_modules/rxjs": { 1029 | "version": "7.6.0", 1030 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.6.0.tgz", 1031 | "integrity": "sha512-DDa7d8TFNUalGC9VqXvQ1euWNN7sc63TrUCuM9J998+ViviahMIjKSOU7rfcgFOF+FCD71BhDRv4hrFz+ImDLQ==", 1032 | "dependencies": { 1033 | "tslib": "^2.1.0" 1034 | } 1035 | }, 1036 | "node_modules/source-map": { 1037 | "version": "0.6.1", 1038 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1039 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1040 | "dev": true, 1041 | "engines": { 1042 | "node": ">=0.10.0" 1043 | } 1044 | }, 1045 | "node_modules/source-map-js": { 1046 | "version": "1.0.2", 1047 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1048 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1049 | "dev": true, 1050 | "engines": { 1051 | "node": ">=0.10.0" 1052 | } 1053 | }, 1054 | "node_modules/source-map-support": { 1055 | "version": "0.5.21", 1056 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1057 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1058 | "dev": true, 1059 | "dependencies": { 1060 | "buffer-from": "^1.0.0", 1061 | "source-map": "^0.6.0" 1062 | } 1063 | }, 1064 | "node_modules/sprintf-js": { 1065 | "version": "1.0.3", 1066 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1067 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" 1068 | }, 1069 | "node_modules/supports-color": { 1070 | "version": "5.5.0", 1071 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1072 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1073 | "dependencies": { 1074 | "has-flag": "^3.0.0" 1075 | }, 1076 | "engines": { 1077 | "node": ">=4" 1078 | } 1079 | }, 1080 | "node_modules/supports-preserve-symlinks-flag": { 1081 | "version": "1.0.0", 1082 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1083 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1084 | "dev": true, 1085 | "engines": { 1086 | "node": ">= 0.4" 1087 | }, 1088 | "funding": { 1089 | "url": "https://github.com/sponsors/ljharb" 1090 | } 1091 | }, 1092 | "node_modules/table-layout": { 1093 | "version": "1.0.2", 1094 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", 1095 | "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", 1096 | "dependencies": { 1097 | "array-back": "^4.0.1", 1098 | "deep-extend": "~0.6.0", 1099 | "typical": "^5.2.0", 1100 | "wordwrapjs": "^4.0.0" 1101 | }, 1102 | "engines": { 1103 | "node": ">=8.0.0" 1104 | } 1105 | }, 1106 | "node_modules/table-layout/node_modules/array-back": { 1107 | "version": "4.0.2", 1108 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 1109 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", 1110 | "engines": { 1111 | "node": ">=8" 1112 | } 1113 | }, 1114 | "node_modules/table-layout/node_modules/typical": { 1115 | "version": "5.2.0", 1116 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1117 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1118 | "engines": { 1119 | "node": ">=8" 1120 | } 1121 | }, 1122 | "node_modules/terser": { 1123 | "version": "5.16.1", 1124 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", 1125 | "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", 1126 | "dev": true, 1127 | "dependencies": { 1128 | "@jridgewell/source-map": "^0.3.2", 1129 | "acorn": "^8.5.0", 1130 | "commander": "^2.20.0", 1131 | "source-map-support": "~0.5.20" 1132 | }, 1133 | "bin": { 1134 | "terser": "bin/terser" 1135 | }, 1136 | "engines": { 1137 | "node": ">=10" 1138 | } 1139 | }, 1140 | "node_modules/text-encoding-utf-8": { 1141 | "version": "1.0.2", 1142 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 1143 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 1144 | }, 1145 | "node_modules/texture-compressor": { 1146 | "version": "1.0.2", 1147 | "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", 1148 | "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", 1149 | "dependencies": { 1150 | "argparse": "^1.0.10", 1151 | "image-size": "^0.7.4" 1152 | }, 1153 | "bin": { 1154 | "texture-compressor": "bin/texture-compressor.js" 1155 | } 1156 | }, 1157 | "node_modules/tslib": { 1158 | "version": "2.4.1", 1159 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", 1160 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" 1161 | }, 1162 | "node_modules/tweakpane": { 1163 | "version": "3.1.1", 1164 | "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.1.1.tgz", 1165 | "integrity": "sha512-b9bpZSvG4KLtvSuyP3r20XWztdbzXleXO1RZN5pS4gcVAVesq0+mYz/bylYIckwh/VZjp3f3zUFJSeV2M3eRCw==", 1166 | "funding": { 1167 | "url": "https://github.com/sponsors/cocopon" 1168 | } 1169 | }, 1170 | "node_modules/twgl.js": { 1171 | "version": "5.3.0", 1172 | "resolved": "https://registry.npmjs.org/twgl.js/-/twgl.js-5.3.0.tgz", 1173 | "integrity": "sha512-0L2YOZBe9fyNZ3NtvHS5uqJxPfSXxFJtz2RTryY1TMWy8asg6K52naHNVdYTMPH9IteYYwNiwq/nBHC5iEIBXw==" 1174 | }, 1175 | "node_modules/typical": { 1176 | "version": "4.0.0", 1177 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", 1178 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", 1179 | "engines": { 1180 | "node": ">=8" 1181 | } 1182 | }, 1183 | "node_modules/vite": { 1184 | "version": "3.2.5", 1185 | "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", 1186 | "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", 1187 | "dev": true, 1188 | "dependencies": { 1189 | "esbuild": "^0.15.9", 1190 | "postcss": "^8.4.18", 1191 | "resolve": "^1.22.1", 1192 | "rollup": "^2.79.1" 1193 | }, 1194 | "bin": { 1195 | "vite": "bin/vite.js" 1196 | }, 1197 | "engines": { 1198 | "node": "^14.18.0 || >=16.0.0" 1199 | }, 1200 | "optionalDependencies": { 1201 | "fsevents": "~2.3.2" 1202 | }, 1203 | "peerDependencies": { 1204 | "@types/node": ">= 14", 1205 | "less": "*", 1206 | "sass": "*", 1207 | "stylus": "*", 1208 | "sugarss": "*", 1209 | "terser": "^5.4.0" 1210 | }, 1211 | "peerDependenciesMeta": { 1212 | "@types/node": { 1213 | "optional": true 1214 | }, 1215 | "less": { 1216 | "optional": true 1217 | }, 1218 | "sass": { 1219 | "optional": true 1220 | }, 1221 | "stylus": { 1222 | "optional": true 1223 | }, 1224 | "sugarss": { 1225 | "optional": true 1226 | }, 1227 | "terser": { 1228 | "optional": true 1229 | } 1230 | } 1231 | }, 1232 | "node_modules/vite-plugin-glsl": { 1233 | "version": "0.3.0", 1234 | "resolved": "https://registry.npmjs.org/vite-plugin-glsl/-/vite-plugin-glsl-0.3.0.tgz", 1235 | "integrity": "sha512-cH7ni+Y3Vz1yOumvrP/71hXVdyTxZIaYYNDeK7KMvO5nzo0uGZZrrkwEVUaESS8/5dYemb/6G0YBj3jsP2sW1A==", 1236 | "dev": true, 1237 | "dependencies": { 1238 | "@rollup/pluginutils": "^4.2.1" 1239 | }, 1240 | "engines": { 1241 | "node": ">= 14.18.0", 1242 | "npm": ">= 6.14.17" 1243 | } 1244 | }, 1245 | "node_modules/wordwrapjs": { 1246 | "version": "4.0.1", 1247 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", 1248 | "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", 1249 | "dependencies": { 1250 | "reduce-flatten": "^2.0.0", 1251 | "typical": "^5.2.0" 1252 | }, 1253 | "engines": { 1254 | "node": ">=8.0.0" 1255 | } 1256 | }, 1257 | "node_modules/wordwrapjs/node_modules/typical": { 1258 | "version": "5.2.0", 1259 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1260 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", 1261 | "engines": { 1262 | "node": ">=8" 1263 | } 1264 | } 1265 | }, 1266 | "dependencies": { 1267 | "@babel/runtime": { 1268 | "version": "7.20.6", 1269 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", 1270 | "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", 1271 | "requires": { 1272 | "regenerator-runtime": "^0.13.11" 1273 | } 1274 | }, 1275 | "@esbuild/android-arm": { 1276 | "version": "0.15.18", 1277 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", 1278 | "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", 1279 | "dev": true, 1280 | "optional": true 1281 | }, 1282 | "@esbuild/linux-loong64": { 1283 | "version": "0.15.18", 1284 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", 1285 | "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", 1286 | "dev": true, 1287 | "optional": true 1288 | }, 1289 | "@jridgewell/gen-mapping": { 1290 | "version": "0.3.2", 1291 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 1292 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 1293 | "dev": true, 1294 | "requires": { 1295 | "@jridgewell/set-array": "^1.0.1", 1296 | "@jridgewell/sourcemap-codec": "^1.4.10", 1297 | "@jridgewell/trace-mapping": "^0.3.9" 1298 | } 1299 | }, 1300 | "@jridgewell/resolve-uri": { 1301 | "version": "3.1.0", 1302 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 1303 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 1304 | "dev": true 1305 | }, 1306 | "@jridgewell/set-array": { 1307 | "version": "1.1.2", 1308 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 1309 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 1310 | "dev": true 1311 | }, 1312 | "@jridgewell/source-map": { 1313 | "version": "0.3.2", 1314 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", 1315 | "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", 1316 | "dev": true, 1317 | "requires": { 1318 | "@jridgewell/gen-mapping": "^0.3.0", 1319 | "@jridgewell/trace-mapping": "^0.3.9" 1320 | } 1321 | }, 1322 | "@jridgewell/sourcemap-codec": { 1323 | "version": "1.4.14", 1324 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 1325 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 1326 | "dev": true 1327 | }, 1328 | "@jridgewell/trace-mapping": { 1329 | "version": "0.3.17", 1330 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", 1331 | "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", 1332 | "dev": true, 1333 | "requires": { 1334 | "@jridgewell/resolve-uri": "3.1.0", 1335 | "@jridgewell/sourcemap-codec": "1.4.14" 1336 | } 1337 | }, 1338 | "@loaders.gl/core": { 1339 | "version": "3.2.12", 1340 | "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-3.2.12.tgz", 1341 | "integrity": "sha512-kRQZGZ2+bvd++spjfp00aq2e3RrawAlaCwFxVyyQT6kYyQIzexr/obKd3X+yxYcrr4kUsav2iGqhLVObINlStQ==", 1342 | "requires": { 1343 | "@babel/runtime": "^7.3.1", 1344 | "@loaders.gl/loader-utils": "3.2.12", 1345 | "@loaders.gl/worker-utils": "3.2.12", 1346 | "@probe.gl/log": "^3.5.0", 1347 | "probe.gl": "^3.4.0" 1348 | } 1349 | }, 1350 | "@loaders.gl/draco": { 1351 | "version": "3.2.12", 1352 | "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-3.2.12.tgz", 1353 | "integrity": "sha512-QoDlnL3ouwW3OSMRbyE4DyY41oxqadtaQ7wU3K6us4CF0XgvOToZZTG6QnCfF8FauFZ8JMebn6NT1LtobTNVYQ==", 1354 | "requires": { 1355 | "@babel/runtime": "^7.3.1", 1356 | "@loaders.gl/loader-utils": "3.2.12", 1357 | "@loaders.gl/schema": "3.2.12", 1358 | "@loaders.gl/worker-utils": "3.2.12", 1359 | "draco3d": "1.4.1" 1360 | } 1361 | }, 1362 | "@loaders.gl/gltf": { 1363 | "version": "3.2.12", 1364 | "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-3.2.12.tgz", 1365 | "integrity": "sha512-vdLdWruh4nqmDm/9T0HWX30fJ+UVtB35uQk9dhN/couvrXXtdpkvtb7aFdX0nlCLcrbRlcCYbuCfKctt1CF2mg==", 1366 | "requires": { 1367 | "@loaders.gl/draco": "3.2.12", 1368 | "@loaders.gl/images": "3.2.12", 1369 | "@loaders.gl/loader-utils": "3.2.12", 1370 | "@loaders.gl/textures": "3.2.12" 1371 | } 1372 | }, 1373 | "@loaders.gl/images": { 1374 | "version": "3.2.12", 1375 | "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-3.2.12.tgz", 1376 | "integrity": "sha512-acPKRg9EwgrPyItF97x8LM9p4b8GR03JY+wFJwzBlVdOZXx1dmz1t4rVynRDwgAUgybGKLoPfJtwTIKARnICYQ==", 1377 | "requires": { 1378 | "@loaders.gl/loader-utils": "3.2.12" 1379 | } 1380 | }, 1381 | "@loaders.gl/loader-utils": { 1382 | "version": "3.2.12", 1383 | "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-3.2.12.tgz", 1384 | "integrity": "sha512-OXu7vqBvYj2HD0Tcle8RwRAktJ5BsBTZc6ADPNia7FOGI9sA2ZDECPa0g8gBtKpbhzluLZzPj5N4OPdL6hNiQg==", 1385 | "requires": { 1386 | "@babel/runtime": "^7.3.1", 1387 | "@loaders.gl/worker-utils": "3.2.12", 1388 | "@probe.gl/stats": "^3.5.0" 1389 | } 1390 | }, 1391 | "@loaders.gl/schema": { 1392 | "version": "3.2.12", 1393 | "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-3.2.12.tgz", 1394 | "integrity": "sha512-IP/fniG3PsMvhU+kkryULAoszgNEUSmfCvKZujDtU65xgIHScNQP87+wgqfZFScftEX0iBSahr7QYdQCEsv83w==", 1395 | "requires": { 1396 | "@types/geojson": "^7946.0.7", 1397 | "apache-arrow": "^4.0.0" 1398 | } 1399 | }, 1400 | "@loaders.gl/textures": { 1401 | "version": "3.2.12", 1402 | "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-3.2.12.tgz", 1403 | "integrity": "sha512-xludkKPnzdQAHC19J0depqEvUH8x61cjsMId9Q1Et/emwI5TyEiDK78vl7tsIzuOh/IvrPHykRxfXp4uayW+Nw==", 1404 | "requires": { 1405 | "@loaders.gl/images": "3.2.12", 1406 | "@loaders.gl/loader-utils": "3.2.12", 1407 | "@loaders.gl/schema": "3.2.12", 1408 | "@loaders.gl/worker-utils": "3.2.12", 1409 | "ktx-parse": "^0.0.4", 1410 | "texture-compressor": "^1.0.2" 1411 | } 1412 | }, 1413 | "@loaders.gl/worker-utils": { 1414 | "version": "3.2.12", 1415 | "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-3.2.12.tgz", 1416 | "integrity": "sha512-MRgk8ln4Ur2RAnalD6OWstSuIAlf0l/26KTHtJiVD+HtmLJDoxSoQOHsnrEsdE18m+8NpAQgTD+rDzZtEpsnlw==", 1417 | "requires": { 1418 | "@babel/runtime": "^7.3.1" 1419 | } 1420 | }, 1421 | "@probe.gl/env": { 1422 | "version": "3.5.2", 1423 | "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-3.5.2.tgz", 1424 | "integrity": "sha512-JlNvJ2p6+ObWX7es6n3TycGPTv5CfVrCS8vblI1eHhrFCcZ6RxIo727ffRVwldpp0YTzdgjx3/4fB/1dnVYElw==", 1425 | "requires": { 1426 | "@babel/runtime": "^7.0.0" 1427 | } 1428 | }, 1429 | "@probe.gl/log": { 1430 | "version": "3.5.2", 1431 | "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-3.5.2.tgz", 1432 | "integrity": "sha512-5yo8Dg8LrSltuPBdGlLh/WOvt4LdU7DDHu75GMeiS0fKM+J4IACRpGV8SOrktCj1MWZ6JVHcNQkJnoyZ6G7p/w==", 1433 | "requires": { 1434 | "@babel/runtime": "^7.0.0", 1435 | "@probe.gl/env": "3.5.2" 1436 | } 1437 | }, 1438 | "@probe.gl/stats": { 1439 | "version": "3.5.2", 1440 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-3.5.2.tgz", 1441 | "integrity": "sha512-YKaYXiHF//fgy1OkX38JD70Lc8qxg2Viw8Q2CTNMwGPDJe12wda7kEmMKPJNw2oYLyFUfTzv00KJMA5h18z02w==", 1442 | "requires": { 1443 | "@babel/runtime": "^7.0.0" 1444 | } 1445 | }, 1446 | "@rollup/pluginutils": { 1447 | "version": "4.2.1", 1448 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 1449 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 1450 | "dev": true, 1451 | "requires": { 1452 | "estree-walker": "^2.0.1", 1453 | "picomatch": "^2.2.2" 1454 | } 1455 | }, 1456 | "@types/flatbuffers": { 1457 | "version": "1.10.0", 1458 | "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", 1459 | "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" 1460 | }, 1461 | "@types/geojson": { 1462 | "version": "7946.0.10", 1463 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", 1464 | "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" 1465 | }, 1466 | "@types/node": { 1467 | "version": "14.18.34", 1468 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz", 1469 | "integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==" 1470 | }, 1471 | "@types/text-encoding-utf-8": { 1472 | "version": "1.0.2", 1473 | "resolved": "https://registry.npmjs.org/@types/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 1474 | "integrity": "sha512-AQ6zewa0ucLJvtUi5HsErbOFKAcQfRLt9zFLlUOvcXBy2G36a+ZDpCHSGdzJVUD8aNURtIjh9aSjCStNMRCcRQ==" 1475 | }, 1476 | "acorn": { 1477 | "version": "8.8.1", 1478 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 1479 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 1480 | "dev": true 1481 | }, 1482 | "ansi-styles": { 1483 | "version": "3.2.1", 1484 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1485 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1486 | "requires": { 1487 | "color-convert": "^1.9.0" 1488 | } 1489 | }, 1490 | "apache-arrow": { 1491 | "version": "4.0.1", 1492 | "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-4.0.1.tgz", 1493 | "integrity": "sha512-DyF7GXCbSjsw4P5C8b+qW7OnJKa6w9mJI0mhV0+EfZbVZCmhfiF6ffqcnrI/kzBrRqn9hH/Ft9n5+m4DTbBJpg==", 1494 | "requires": { 1495 | "@types/flatbuffers": "^1.10.0", 1496 | "@types/node": "^14.14.37", 1497 | "@types/text-encoding-utf-8": "^1.0.1", 1498 | "command-line-args": "5.1.1", 1499 | "command-line-usage": "6.1.1", 1500 | "flatbuffers": "1.12.0", 1501 | "json-bignum": "^0.0.3", 1502 | "pad-left": "^2.1.0", 1503 | "text-encoding-utf-8": "^1.0.2", 1504 | "tslib": "^2.2.0" 1505 | } 1506 | }, 1507 | "argparse": { 1508 | "version": "1.0.10", 1509 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 1510 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 1511 | "requires": { 1512 | "sprintf-js": "~1.0.2" 1513 | } 1514 | }, 1515 | "array-back": { 1516 | "version": "3.1.0", 1517 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", 1518 | "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" 1519 | }, 1520 | "buffer-from": { 1521 | "version": "1.1.2", 1522 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1523 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 1524 | "dev": true 1525 | }, 1526 | "chalk": { 1527 | "version": "2.4.2", 1528 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 1529 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 1530 | "requires": { 1531 | "ansi-styles": "^3.2.1", 1532 | "escape-string-regexp": "^1.0.5", 1533 | "supports-color": "^5.3.0" 1534 | } 1535 | }, 1536 | "color-convert": { 1537 | "version": "1.9.3", 1538 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 1539 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 1540 | "requires": { 1541 | "color-name": "1.1.3" 1542 | } 1543 | }, 1544 | "color-name": { 1545 | "version": "1.1.3", 1546 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1547 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 1548 | }, 1549 | "command-line-args": { 1550 | "version": "5.1.1", 1551 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", 1552 | "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", 1553 | "requires": { 1554 | "array-back": "^3.0.1", 1555 | "find-replace": "^3.0.0", 1556 | "lodash.camelcase": "^4.3.0", 1557 | "typical": "^4.0.0" 1558 | } 1559 | }, 1560 | "command-line-usage": { 1561 | "version": "6.1.1", 1562 | "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", 1563 | "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", 1564 | "requires": { 1565 | "array-back": "^4.0.1", 1566 | "chalk": "^2.4.2", 1567 | "table-layout": "^1.0.1", 1568 | "typical": "^5.2.0" 1569 | }, 1570 | "dependencies": { 1571 | "array-back": { 1572 | "version": "4.0.2", 1573 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 1574 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" 1575 | }, 1576 | "typical": { 1577 | "version": "5.2.0", 1578 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 1579 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" 1580 | } 1581 | } 1582 | }, 1583 | "commander": { 1584 | "version": "2.20.3", 1585 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 1586 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 1587 | "dev": true 1588 | }, 1589 | "deep-extend": { 1590 | "version": "0.6.0", 1591 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 1592 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 1593 | }, 1594 | "draco3d": { 1595 | "version": "1.4.1", 1596 | "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.4.1.tgz", 1597 | "integrity": "sha512-9Rxonc70xiovBC+Bq1h57SNZIHzWTibU1VfIGp5z3Xx8dPtv4yT5uGhiH7P5uvJRR2jkrvHafRxR7bTANkvfpg==" 1598 | }, 1599 | "esbuild": { 1600 | "version": "0.15.18", 1601 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", 1602 | "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", 1603 | "dev": true, 1604 | "requires": { 1605 | "@esbuild/android-arm": "0.15.18", 1606 | "@esbuild/linux-loong64": "0.15.18", 1607 | "esbuild-android-64": "0.15.18", 1608 | "esbuild-android-arm64": "0.15.18", 1609 | "esbuild-darwin-64": "0.15.18", 1610 | "esbuild-darwin-arm64": "0.15.18", 1611 | "esbuild-freebsd-64": "0.15.18", 1612 | "esbuild-freebsd-arm64": "0.15.18", 1613 | "esbuild-linux-32": "0.15.18", 1614 | "esbuild-linux-64": "0.15.18", 1615 | "esbuild-linux-arm": "0.15.18", 1616 | "esbuild-linux-arm64": "0.15.18", 1617 | "esbuild-linux-mips64le": "0.15.18", 1618 | "esbuild-linux-ppc64le": "0.15.18", 1619 | "esbuild-linux-riscv64": "0.15.18", 1620 | "esbuild-linux-s390x": "0.15.18", 1621 | "esbuild-netbsd-64": "0.15.18", 1622 | "esbuild-openbsd-64": "0.15.18", 1623 | "esbuild-sunos-64": "0.15.18", 1624 | "esbuild-windows-32": "0.15.18", 1625 | "esbuild-windows-64": "0.15.18", 1626 | "esbuild-windows-arm64": "0.15.18" 1627 | } 1628 | }, 1629 | "esbuild-android-64": { 1630 | "version": "0.15.18", 1631 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", 1632 | "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", 1633 | "dev": true, 1634 | "optional": true 1635 | }, 1636 | "esbuild-android-arm64": { 1637 | "version": "0.15.18", 1638 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", 1639 | "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", 1640 | "dev": true, 1641 | "optional": true 1642 | }, 1643 | "esbuild-darwin-64": { 1644 | "version": "0.15.18", 1645 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", 1646 | "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", 1647 | "dev": true, 1648 | "optional": true 1649 | }, 1650 | "esbuild-darwin-arm64": { 1651 | "version": "0.15.18", 1652 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", 1653 | "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", 1654 | "dev": true, 1655 | "optional": true 1656 | }, 1657 | "esbuild-freebsd-64": { 1658 | "version": "0.15.18", 1659 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", 1660 | "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", 1661 | "dev": true, 1662 | "optional": true 1663 | }, 1664 | "esbuild-freebsd-arm64": { 1665 | "version": "0.15.18", 1666 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", 1667 | "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", 1668 | "dev": true, 1669 | "optional": true 1670 | }, 1671 | "esbuild-linux-32": { 1672 | "version": "0.15.18", 1673 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", 1674 | "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", 1675 | "dev": true, 1676 | "optional": true 1677 | }, 1678 | "esbuild-linux-64": { 1679 | "version": "0.15.18", 1680 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", 1681 | "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", 1682 | "dev": true, 1683 | "optional": true 1684 | }, 1685 | "esbuild-linux-arm": { 1686 | "version": "0.15.18", 1687 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", 1688 | "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", 1689 | "dev": true, 1690 | "optional": true 1691 | }, 1692 | "esbuild-linux-arm64": { 1693 | "version": "0.15.18", 1694 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", 1695 | "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", 1696 | "dev": true, 1697 | "optional": true 1698 | }, 1699 | "esbuild-linux-mips64le": { 1700 | "version": "0.15.18", 1701 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", 1702 | "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", 1703 | "dev": true, 1704 | "optional": true 1705 | }, 1706 | "esbuild-linux-ppc64le": { 1707 | "version": "0.15.18", 1708 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", 1709 | "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", 1710 | "dev": true, 1711 | "optional": true 1712 | }, 1713 | "esbuild-linux-riscv64": { 1714 | "version": "0.15.18", 1715 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", 1716 | "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", 1717 | "dev": true, 1718 | "optional": true 1719 | }, 1720 | "esbuild-linux-s390x": { 1721 | "version": "0.15.18", 1722 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", 1723 | "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", 1724 | "dev": true, 1725 | "optional": true 1726 | }, 1727 | "esbuild-netbsd-64": { 1728 | "version": "0.15.18", 1729 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", 1730 | "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", 1731 | "dev": true, 1732 | "optional": true 1733 | }, 1734 | "esbuild-openbsd-64": { 1735 | "version": "0.15.18", 1736 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", 1737 | "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", 1738 | "dev": true, 1739 | "optional": true 1740 | }, 1741 | "esbuild-sunos-64": { 1742 | "version": "0.15.18", 1743 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", 1744 | "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", 1745 | "dev": true, 1746 | "optional": true 1747 | }, 1748 | "esbuild-windows-32": { 1749 | "version": "0.15.18", 1750 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", 1751 | "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", 1752 | "dev": true, 1753 | "optional": true 1754 | }, 1755 | "esbuild-windows-64": { 1756 | "version": "0.15.18", 1757 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", 1758 | "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", 1759 | "dev": true, 1760 | "optional": true 1761 | }, 1762 | "esbuild-windows-arm64": { 1763 | "version": "0.15.18", 1764 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", 1765 | "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", 1766 | "dev": true, 1767 | "optional": true 1768 | }, 1769 | "escape-string-regexp": { 1770 | "version": "1.0.5", 1771 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1772 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" 1773 | }, 1774 | "estree-walker": { 1775 | "version": "2.0.2", 1776 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1777 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1778 | "dev": true 1779 | }, 1780 | "find-replace": { 1781 | "version": "3.0.0", 1782 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", 1783 | "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", 1784 | "requires": { 1785 | "array-back": "^3.0.1" 1786 | } 1787 | }, 1788 | "flatbuffers": { 1789 | "version": "1.12.0", 1790 | "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", 1791 | "integrity": "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==" 1792 | }, 1793 | "fsevents": { 1794 | "version": "2.3.2", 1795 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1796 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1797 | "dev": true, 1798 | "optional": true 1799 | }, 1800 | "function-bind": { 1801 | "version": "1.1.1", 1802 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1803 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1804 | "dev": true 1805 | }, 1806 | "gl-matrix": { 1807 | "version": "3.4.3", 1808 | "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", 1809 | "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" 1810 | }, 1811 | "has": { 1812 | "version": "1.0.3", 1813 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1814 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1815 | "dev": true, 1816 | "requires": { 1817 | "function-bind": "^1.1.1" 1818 | } 1819 | }, 1820 | "has-flag": { 1821 | "version": "3.0.0", 1822 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1823 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" 1824 | }, 1825 | "image-size": { 1826 | "version": "0.7.5", 1827 | "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", 1828 | "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==" 1829 | }, 1830 | "is-core-module": { 1831 | "version": "2.11.0", 1832 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 1833 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 1834 | "dev": true, 1835 | "requires": { 1836 | "has": "^1.0.3" 1837 | } 1838 | }, 1839 | "json-bignum": { 1840 | "version": "0.0.3", 1841 | "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", 1842 | "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==" 1843 | }, 1844 | "ktx-parse": { 1845 | "version": "0.0.4", 1846 | "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.0.4.tgz", 1847 | "integrity": "sha512-LY3nrmfXl+wZZdPxgJ3ZmLvG+wkOZZP3/dr4RbQj1Pk3Qwz44esOOSFFVQJcNWpXAtiNIC66WgXufX/SYgYz6A==" 1848 | }, 1849 | "lodash.camelcase": { 1850 | "version": "4.3.0", 1851 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1852 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" 1853 | }, 1854 | "nanoid": { 1855 | "version": "3.3.4", 1856 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 1857 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 1858 | "dev": true 1859 | }, 1860 | "pad-left": { 1861 | "version": "2.1.0", 1862 | "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", 1863 | "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", 1864 | "requires": { 1865 | "repeat-string": "^1.5.4" 1866 | } 1867 | }, 1868 | "path-parse": { 1869 | "version": "1.0.7", 1870 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1871 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1872 | "dev": true 1873 | }, 1874 | "picocolors": { 1875 | "version": "1.0.0", 1876 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1877 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 1878 | "dev": true 1879 | }, 1880 | "picomatch": { 1881 | "version": "2.3.1", 1882 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1883 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1884 | "dev": true 1885 | }, 1886 | "postcss": { 1887 | "version": "8.4.20", 1888 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", 1889 | "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", 1890 | "dev": true, 1891 | "requires": { 1892 | "nanoid": "^3.3.4", 1893 | "picocolors": "^1.0.0", 1894 | "source-map-js": "^1.0.2" 1895 | } 1896 | }, 1897 | "probe.gl": { 1898 | "version": "3.5.2", 1899 | "resolved": "https://registry.npmjs.org/probe.gl/-/probe.gl-3.5.2.tgz", 1900 | "integrity": "sha512-8lFQVmi7pMQZkqfj8+VjX4GU9HTkyxgRm5/h/xxA/4/IvZPv3qtP996L+awPwZsrPRKEw99t12SvqEHqSls/sA==", 1901 | "requires": { 1902 | "@babel/runtime": "^7.0.0", 1903 | "@probe.gl/env": "3.5.2", 1904 | "@probe.gl/log": "3.5.2", 1905 | "@probe.gl/stats": "3.5.2" 1906 | } 1907 | }, 1908 | "reduce-flatten": { 1909 | "version": "2.0.0", 1910 | "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", 1911 | "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" 1912 | }, 1913 | "regenerator-runtime": { 1914 | "version": "0.13.11", 1915 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 1916 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" 1917 | }, 1918 | "repeat-string": { 1919 | "version": "1.6.1", 1920 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1921 | "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" 1922 | }, 1923 | "resolve": { 1924 | "version": "1.22.1", 1925 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 1926 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 1927 | "dev": true, 1928 | "requires": { 1929 | "is-core-module": "^2.9.0", 1930 | "path-parse": "^1.0.7", 1931 | "supports-preserve-symlinks-flag": "^1.0.0" 1932 | } 1933 | }, 1934 | "rollup": { 1935 | "version": "2.79.1", 1936 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 1937 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 1938 | "dev": true, 1939 | "requires": { 1940 | "fsevents": "~2.3.2" 1941 | } 1942 | }, 1943 | "rxjs": { 1944 | "version": "7.6.0", 1945 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.6.0.tgz", 1946 | "integrity": "sha512-DDa7d8TFNUalGC9VqXvQ1euWNN7sc63TrUCuM9J998+ViviahMIjKSOU7rfcgFOF+FCD71BhDRv4hrFz+ImDLQ==", 1947 | "requires": { 1948 | "tslib": "^2.1.0" 1949 | } 1950 | }, 1951 | "source-map": { 1952 | "version": "0.6.1", 1953 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1954 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1955 | "dev": true 1956 | }, 1957 | "source-map-js": { 1958 | "version": "1.0.2", 1959 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1960 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1961 | "dev": true 1962 | }, 1963 | "source-map-support": { 1964 | "version": "0.5.21", 1965 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 1966 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 1967 | "dev": true, 1968 | "requires": { 1969 | "buffer-from": "^1.0.0", 1970 | "source-map": "^0.6.0" 1971 | } 1972 | }, 1973 | "sprintf-js": { 1974 | "version": "1.0.3", 1975 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1976 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" 1977 | }, 1978 | "supports-color": { 1979 | "version": "5.5.0", 1980 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1981 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1982 | "requires": { 1983 | "has-flag": "^3.0.0" 1984 | } 1985 | }, 1986 | "supports-preserve-symlinks-flag": { 1987 | "version": "1.0.0", 1988 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1989 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1990 | "dev": true 1991 | }, 1992 | "table-layout": { 1993 | "version": "1.0.2", 1994 | "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", 1995 | "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", 1996 | "requires": { 1997 | "array-back": "^4.0.1", 1998 | "deep-extend": "~0.6.0", 1999 | "typical": "^5.2.0", 2000 | "wordwrapjs": "^4.0.0" 2001 | }, 2002 | "dependencies": { 2003 | "array-back": { 2004 | "version": "4.0.2", 2005 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", 2006 | "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" 2007 | }, 2008 | "typical": { 2009 | "version": "5.2.0", 2010 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 2011 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" 2012 | } 2013 | } 2014 | }, 2015 | "terser": { 2016 | "version": "5.16.1", 2017 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", 2018 | "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", 2019 | "dev": true, 2020 | "requires": { 2021 | "@jridgewell/source-map": "^0.3.2", 2022 | "acorn": "^8.5.0", 2023 | "commander": "^2.20.0", 2024 | "source-map-support": "~0.5.20" 2025 | } 2026 | }, 2027 | "text-encoding-utf-8": { 2028 | "version": "1.0.2", 2029 | "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", 2030 | "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" 2031 | }, 2032 | "texture-compressor": { 2033 | "version": "1.0.2", 2034 | "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", 2035 | "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", 2036 | "requires": { 2037 | "argparse": "^1.0.10", 2038 | "image-size": "^0.7.4" 2039 | } 2040 | }, 2041 | "tslib": { 2042 | "version": "2.4.1", 2043 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", 2044 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" 2045 | }, 2046 | "tweakpane": { 2047 | "version": "3.1.1", 2048 | "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.1.1.tgz", 2049 | "integrity": "sha512-b9bpZSvG4KLtvSuyP3r20XWztdbzXleXO1RZN5pS4gcVAVesq0+mYz/bylYIckwh/VZjp3f3zUFJSeV2M3eRCw==" 2050 | }, 2051 | "twgl.js": { 2052 | "version": "5.3.0", 2053 | "resolved": "https://registry.npmjs.org/twgl.js/-/twgl.js-5.3.0.tgz", 2054 | "integrity": "sha512-0L2YOZBe9fyNZ3NtvHS5uqJxPfSXxFJtz2RTryY1TMWy8asg6K52naHNVdYTMPH9IteYYwNiwq/nBHC5iEIBXw==" 2055 | }, 2056 | "typical": { 2057 | "version": "4.0.0", 2058 | "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", 2059 | "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" 2060 | }, 2061 | "vite": { 2062 | "version": "3.2.5", 2063 | "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", 2064 | "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", 2065 | "dev": true, 2066 | "requires": { 2067 | "esbuild": "^0.15.9", 2068 | "fsevents": "~2.3.2", 2069 | "postcss": "^8.4.18", 2070 | "resolve": "^1.22.1", 2071 | "rollup": "^2.79.1" 2072 | } 2073 | }, 2074 | "vite-plugin-glsl": { 2075 | "version": "0.3.0", 2076 | "resolved": "https://registry.npmjs.org/vite-plugin-glsl/-/vite-plugin-glsl-0.3.0.tgz", 2077 | "integrity": "sha512-cH7ni+Y3Vz1yOumvrP/71hXVdyTxZIaYYNDeK7KMvO5nzo0uGZZrrkwEVUaESS8/5dYemb/6G0YBj3jsP2sW1A==", 2078 | "dev": true, 2079 | "requires": { 2080 | "@rollup/pluginutils": "^4.2.1" 2081 | } 2082 | }, 2083 | "wordwrapjs": { 2084 | "version": "4.0.1", 2085 | "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", 2086 | "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", 2087 | "requires": { 2088 | "reduce-flatten": "^2.0.0", 2089 | "typical": "^5.2.0" 2090 | }, 2091 | "dependencies": { 2092 | "typical": { 2093 | "version": "5.2.0", 2094 | "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", 2095 | "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" 2096 | } 2097 | } 2098 | } 2099 | } 2100 | } 2101 | -------------------------------------------------------------------------------- /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=/phase-transition/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 | "tweakpane": "^3.1.0", 22 | "twgl.js": "^5.0.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/app/app.js: -------------------------------------------------------------------------------- 1 | import { take, debounceTime, fromEvent } from 'rxjs'; 2 | import { Sketch } from './sketch'; 3 | import { Pane } from 'tweakpane'; 4 | import * as modernizr from './utils/modernizr'; 5 | 6 | const queryString = window.location.search; 7 | const urlParams = new URLSearchParams(queryString); 8 | const hasDebugParam = urlParams.get('debug'); 9 | const isDev = import.meta.env.MODE === 'development'; 10 | let sketch; 11 | let pane; 12 | 13 | if (isDev) { 14 | import('https://greggman.github.io/webgl-lint/webgl-lint.js'); 15 | } 16 | 17 | if (hasDebugParam || isDev) { 18 | //pane = new Pane({ title: 'Settings', expanded: isDev }); 19 | } 20 | 21 | const resize = () => { 22 | // explicitly set the width and height to compensate for missing dvh and dvw support 23 | document.body.style.width = `${document.documentElement.clientWidth}px`; 24 | document.body.style.height = `${document.documentElement.clientHeight}px`; 25 | 26 | if (sketch) { 27 | sketch.resize(); 28 | } 29 | } 30 | 31 | // add a debounced resize listener 32 | fromEvent(window, 'resize').pipe(debounceTime(100)).subscribe(() => resize()); 33 | 34 | // resize initially on load 35 | fromEvent(window, 'load').pipe(take(1)).subscribe(() => resize()); 36 | 37 | // INIT APP 38 | const canvasElm = document.querySelector('canvas'); 39 | const startButton = document.querySelector('#start-button'); 40 | const intro = document.querySelector('#intro'); 41 | 42 | sketch = new Sketch(canvasElm, (instance) => { 43 | startButton.style.opacity = 1; 44 | document.body.removeChild(document.body.querySelector('#loader')); 45 | fromEvent(startButton, 'click').pipe(take(1)).subscribe(() => { 46 | intro.style.display = 'none'; 47 | startButton.style.display = 'none'; 48 | instance.run(); 49 | }); 50 | }, isDev, pane); 51 | -------------------------------------------------------------------------------- /src/app/shader/blur.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform sampler2D u_colorTexture; 6 | 7 | out vec4 outColor; 8 | 9 | in vec2 v_uv; 10 | 11 | vec4 gaussianBlur2D(in sampler2D tex, in vec2 st, in vec2 offset, const int kernelSize) { 12 | vec4 accumColor = vec4(0.); 13 | #define GAUSSIANBLUR2D_KERNELSIZE kernelSize 14 | 15 | float accumWeight = 0.; 16 | const float k = .15915494; // 1 / (2*PI) 17 | float kernelSize2 = float(GAUSSIANBLUR2D_KERNELSIZE) * float(GAUSSIANBLUR2D_KERNELSIZE); 18 | 19 | for (int j = 0; j < GAUSSIANBLUR2D_KERNELSIZE; j++) { 20 | float y = -.5 * (float(GAUSSIANBLUR2D_KERNELSIZE) - 1.) + float(j); 21 | for (int i = 0; i < GAUSSIANBLUR2D_KERNELSIZE; i++) { 22 | float x = -.5 * (float(GAUSSIANBLUR2D_KERNELSIZE) - 1.) + float(i); 23 | float weight = (k / float(GAUSSIANBLUR2D_KERNELSIZE)) * exp(-(x * x + y * y) / (2. * kernelSize2)); 24 | accumColor += weight * texture(tex, (st + vec2(x, y) * offset)); 25 | accumWeight += weight; 26 | } 27 | } 28 | return accumColor / accumWeight; 29 | } 30 | 31 | void main() { 32 | vec2 texSize = vec2(textureSize(u_colorTexture, 0)); 33 | outColor = gaussianBlur2D(u_colorTexture, v_uv, (1. / texSize) * 2., 20) * 1.6; 34 | } -------------------------------------------------------------------------------- /src/app/shader/blur.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/shader/color.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform mat4 u_worldInverseTransposeMatrix; 6 | uniform mat4 u_worldInverseMatrix; 7 | uniform sampler2D u_iceTexture; 8 | uniform sampler2D u_iceNormal; 9 | uniform sampler2D u_dirtTexture; 10 | uniform samplerCube u_envMapTexture; 11 | uniform vec3 u_cameraPos; 12 | uniform float u_time; 13 | uniform float u_progress1; 14 | uniform float u_progress2; 15 | uniform float u_progress3; 16 | 17 | out vec4 outColor; 18 | 19 | in vec3 v_position; 20 | in vec3 v_worldPosition; 21 | in vec2 v_texcoord; 22 | in vec3 v_normal; 23 | in vec3 v_tangent; 24 | in vec3 v_surfaceToView; 25 | 26 | #define TWO_PI 6.2831853071795864769252867665590 27 | #define PI 3.1415926535 28 | 29 | const vec2 inv_atan = vec2(0.1591, 0.3183); 30 | 31 | vec2 dir2equirect(highp vec3 dir) { 32 | highp vec2 uv = vec2(atan(dir.z, dir.x), asin(dir.y)); 33 | uv *= inv_atan; 34 | uv += 0.5; 35 | return uv; 36 | } 37 | 38 | vec3 cart2equirect(vec2 uv) { 39 | float Phi = PI - uv.y * PI; 40 | float Theta = uv.x * TWO_PI; 41 | vec3 dir = vec3(cos(Theta), 0.0, sin(Theta)); 42 | dir.y = cos(Phi);//clamp(cos(Phi), MinCos, 1.0); 43 | dir.xz *= sqrt(1.0 - dir.y * dir.y); 44 | return dir; 45 | } 46 | 47 | float powFast(float a, float b) { 48 | return a / ((1. - b) * a + b); 49 | } 50 | 51 | float blendMultiply(float src, float dest, float opacity) { 52 | float blend = src * dest; 53 | float ret = mix(src, blend, opacity); 54 | return ret; 55 | } 56 | 57 | float blendScreen(in float base, in float blend) { 58 | return 1. - ((1. - base) * (1. - blend)); 59 | } 60 | 61 | float blendOverlay(in float base, in float blend) { 62 | return (base < .5)? (2.*base*blend): (1. - 2. * (1. - base) * (1. - blend)); 63 | } 64 | 65 | float blendLighten(in float base, in float blend) { 66 | return max(blend, base); 67 | } 68 | 69 | float saturate( float x){ return clamp(x, 0.0, 1.0); } 70 | 71 | vec3 water(float x) { 72 | return pow(vec3(.1, .7, .8), vec3(4.* saturate(1.0-x) )); 73 | } 74 | 75 | float brightnessContrast( float value, float brightness, float contrast ) { 76 | return ( value - 0.5 ) * contrast + 0.5 + brightness; 77 | } 78 | 79 | vec3 brightnessContrast( vec3 color, float brightness, float contrast ) { 80 | return ( color - 0.5 ) * contrast + 0.5 + brightness; 81 | } 82 | 83 | vec4 brightnessContrast( vec4 color, float brightness, float contrast ) { 84 | return vec4(brightnessContrast(color.rgb, brightness, contrast), color.a); 85 | } 86 | 87 | vec2 parallaxOffset(float ratio, vec3 V) { 88 | vec3 pOff = V * ratio; 89 | vec3 pDir = (u_worldInverseMatrix * vec4(normalize(v_worldPosition + pOff), 0.)).xyz; 90 | return fract(dir2equirect(pDir)); 91 | } 92 | 93 | // https://github.com/glslify/glsl-specular-blinn-phong 94 | float specularBlinnPhong(vec3 L, vec3 N, vec3 V, float shininess) { 95 | // halfVector 96 | vec3 H = normalize(L + V); 97 | return powFast(max(0.0, dot(N, H)), shininess); 98 | } 99 | 100 | void main() { 101 | vec3 P = normalize(v_position); 102 | vec3 V = normalize(v_surfaceToView); 103 | 104 | // get equirect coords 105 | vec2 equirect = dir2equirect(P); 106 | 107 | // create the parallax texture 108 | vec4 iceLayer1 = texture(u_iceTexture, equirect); 109 | vec4 iceLayer2 = texture(u_iceTexture, parallaxOffset(-0.2, V)); 110 | float parallax = 0.; 111 | for (int j = 0; j <15; j ++) { 112 | float ratio = float(j) / 15.; 113 | float value = texture(u_iceTexture, parallaxOffset(ratio * -0.2, V)).r * (1. - smoothstep(0.5, 1.0, ratio)); 114 | parallax = blendScreen(parallax, value / 10.); 115 | } 116 | float iceValue = parallax * 2. + iceLayer1.r + iceLayer2.b * 0.5; 117 | vec3 gradColor1 = vec3(1.); 118 | vec3 gradColor2 = vec3(0.4, 0.8, 1.); 119 | vec3 gradColor3 = vec3(0.0, 0.05, .1); 120 | vec3 iceColor = mix(gradColor2, gradColor1, iceValue); 121 | iceColor = mix(gradColor3, iceColor, iceValue * 0.3 + 0.1); 122 | iceColor = mix(iceColor, water(iceValue), min(iceValue, 0.3)); 123 | iceColor += vec3(smoothstep(0.1, 1., iceLayer1.r) * 0.9); 124 | iceColor = mix(water(length(vec3(0., 0., 1.) - v_normal) * 0.01) * 0.4, iceColor, u_progress3); 125 | iceColor += vec3(smoothstep(0.1, 1., iceLayer1.g) * 0.3) * u_progress2; 126 | 127 | // get the normal offsets 128 | vec3 normalOffset = texture(u_iceNormal, equirect).xyz * 2. - 1.; 129 | vec3 dirt = texture(u_dirtTexture, equirect).xyz; 130 | vec3 dirt2 = texture(u_dirtTexture, vec2(equirect.x, 1. - equirect.y)).xyz; 131 | 132 | vec3 N = normalize(v_normal); 133 | vec3 T = normalize(v_tangent); 134 | vec3 L = normalize(vec3(1., 2., 2.)); 135 | vec3 B = normalize(cross(N, T)); 136 | vec3 R = reflect(N, -L); 137 | mat3 tangentSpace = mat3(T, B, N); 138 | N = normalize(mix(N, tangentSpace * normalOffset, .8 * u_progress3)); 139 | 140 | // basic lighting 141 | float specularValue = specularBlinnPhong(L, N, V, mix(400., 300., u_progress2)); 142 | vec3 specular = specularValue * vec3(1., .9, .8) * (.7 - u_progress2 * 0.2); 143 | float diffuse = max(0., dot(N, L)) * 0.1; 144 | float fresnelValue = 1. - dot(N, V); 145 | fresnelValue = fresnelValue * fresnelValue * fresnelValue; 146 | float fresnel = fresnelValue * .2; 147 | 148 | // env reflection 149 | vec4 env = texture(u_envMapTexture, N) * fresnelValue * ((1. - u_progress2) * 0.8 + 0.2); 150 | 151 | 152 | outColor = vec4(iceColor + specular + diffuse + fresnel + env.rgb, 0.); 153 | outColor = brightnessContrast(outColor, .1, 2.); 154 | 155 | } -------------------------------------------------------------------------------- /src/app/shader/color.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform mat4 u_worldMatrix; 4 | uniform mat4 u_worldInverseTransposeMatrix; 5 | uniform mat4 u_viewMatrix; 6 | uniform mat4 u_projectionMatrix; 7 | uniform float u_time; 8 | uniform sampler2D u_iceTexture; 9 | uniform sampler2D u_iceNormal; 10 | uniform vec3 u_cameraPos; 11 | uniform float u_wobbleStrength; 12 | uniform float u_scale; 13 | uniform float u_progress1; 14 | uniform float u_progress2; 15 | uniform float u_progress3; 16 | 17 | in vec3 a_position; 18 | in vec3 a_normal; 19 | in vec2 a_texcoord; 20 | in vec3 a_tangent; 21 | 22 | out vec3 v_position; 23 | out vec3 v_worldPosition; 24 | out vec2 v_texcoord; 25 | out vec3 v_normal; 26 | out vec3 v_tangent; 27 | out vec3 v_surfaceToView; 28 | 29 | const vec2 inv_atan = vec2(0.1591, 0.3183); 30 | 31 | vec2 dir2equirect(highp vec3 dir) { 32 | highp vec2 uv = vec2(atan(dir.z, dir.x), asin(dir.y)); 33 | uv *= inv_atan; 34 | uv += 0.5; 35 | return uv; 36 | } 37 | 38 | void main() { 39 | vec3 pos = a_position; 40 | vec2 st = dir2equirect(pos); 41 | vec4 map = texture(u_iceTexture, st); 42 | float h = (map.a - 0.2) * .1; 43 | float displacement = u_scale + h * u_progress3; 44 | float wobble = cos(u_time * 0.0015 + pos.y * 4.) * 0.04 + sin(u_time * 0.0025 + pos.x * 4.) * 0.04 + 1.; 45 | float dX = cos(4. * pos.x + u_time * 0.0025) * 0.08; 46 | float dY = -sin(4. * pos.y + u_time * 0.0015) * 0.08; 47 | float dZ = 0.; 48 | vec3 wN = normalize(vec3(dX, dY, dZ) + normalize(pos)); 49 | 50 | pos *= mix(displacement, wobble, u_wobbleStrength); 51 | vec3 N = mix(a_normal, wN, u_wobbleStrength); 52 | 53 | vec4 worldPosition = u_worldMatrix * vec4(pos, 1.); 54 | gl_Position = u_projectionMatrix * u_viewMatrix * worldPosition; 55 | 56 | v_position = a_position; 57 | v_texcoord = a_texcoord; 58 | v_worldPosition = worldPosition.xyz; 59 | v_surfaceToView = u_cameraPos - worldPosition.xyz; 60 | v_tangent = (u_worldInverseTransposeMatrix * vec4(a_tangent, 0.)).xyz; 61 | v_normal = (u_worldInverseTransposeMatrix * vec4(N, 0.)).xyz; 62 | } -------------------------------------------------------------------------------- /src/app/shader/composite.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform sampler2D u_colorTexture; 6 | uniform sampler2D u_bloomTexture; 7 | uniform sampler2D u_stainTexture; 8 | 9 | out vec4 outColor; 10 | 11 | in vec2 v_uv; 12 | 13 | float blendScreen(float base, float blend) { 14 | return 1.0-((1.0-base)*(1.0-blend)); 15 | } 16 | 17 | vec3 blendScreen(vec3 base, vec3 blend) { 18 | return vec3(blendScreen(base.r,blend.r),blendScreen(base.g,blend.g),blendScreen(base.b,blend.b)); 19 | } 20 | 21 | vec3 blendScreen(vec3 base, vec3 blend, float opacity) { 22 | return (blendScreen(base, blend) * opacity + base * (1.0 - opacity)); 23 | } 24 | 25 | void main() { 26 | vec4 color = texture(u_colorTexture, v_uv); 27 | vec4 bloom = texture(u_bloomTexture, v_uv); 28 | vec4 stain = texture(u_stainTexture, v_uv); 29 | 30 | vec3 comp = blendScreen(color.rgb, bloom.rgb, 0.4); 31 | 32 | outColor = vec4(comp, 0.); 33 | } -------------------------------------------------------------------------------- /src/app/shader/composite.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/shader/highpass.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform sampler2D u_colorTexture; 6 | 7 | out vec4 outColor; 8 | 9 | in vec2 v_uv; 10 | 11 | // credits: https://john-chapman.github.io/2017/11/05/pseudo-lens-flare.html 12 | 13 | vec4 applyThreshold(in vec4 rgb, in float threshold) { 14 | return max(rgb - vec4(threshold), vec4(0.0)); 15 | } 16 | 17 | // Cubic window; map [0, _radius] in [1, 0] as a cubic falloff from _center. 18 | float windowCubic(float x, float center, float radius) { 19 | x = min(abs(x - center) / radius, 1.0); 20 | return 1.0 - x * x * (3.0 - 2.0 * x); 21 | } 22 | 23 | vec4 sampleHalo(in vec2 uv, in float radius, in vec2 aspect, in float threshold) { 24 | vec2 off = .5 - uv; 25 | off *= aspect; 26 | off = normalize(off * .5); 27 | off /= aspect; 28 | off *= radius; 29 | vec2 st = uv + off; 30 | float mask = windowCubic(length((2. * uv - 1.) * aspect), radius * 2., 0.1); 31 | return applyThreshold(texture(u_colorTexture, st), threshold) * mask; 32 | } 33 | 34 | void main() { 35 | vec2 texSize = vec2(textureSize(u_colorTexture, 0)); 36 | vec2 texel = 1. / texSize; 37 | 38 | float haloThreshold = 0.3; 39 | float haloRadius = .7; 40 | vec2 aspect = texSize / min(texSize.y, texSize.x); 41 | float shift = min(texel.x, texel.y) * 30.; 42 | float haloR = sampleHalo(v_uv, haloRadius - shift * 3., aspect, haloThreshold).r; 43 | float haloG = sampleHalo(v_uv, haloRadius - shift * 2., aspect, haloThreshold).g; 44 | float haloB = sampleHalo(v_uv, haloRadius - shift, aspect, haloThreshold).b; 45 | vec4 halo = vec4(haloR, haloG, haloB, 0.); 46 | 47 | outColor = applyThreshold(texture(u_colorTexture, v_uv), 0.5) * 200.; 48 | } -------------------------------------------------------------------------------- /src/app/shader/highpass.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/shader/particle.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform float u_time; 6 | 7 | out vec4 outColor; 8 | 9 | in vec3 v_position; 10 | in vec3 v_normal; 11 | 12 | float powFast(float a, float b) { 13 | return a / ((1. - b) * a + b); 14 | } 15 | 16 | void main() { 17 | vec3 L = vec3(0., 0., 1.); 18 | vec3 N = normalize(v_normal); 19 | float diffuse = max(0., dot(L, N)); 20 | outColor = vec4(powFast(diffuse, 90.)); 21 | outColor.a *= max(0., v_position.z) * (1. - u_time) * 0.5; 22 | } -------------------------------------------------------------------------------- /src/app/shader/particle.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | uniform mat4 u_worldMatrix; 4 | uniform mat4 u_viewMatrix; 5 | uniform mat4 u_projectionMatrix; 6 | uniform float u_time; 7 | 8 | in vec3 a_position; 9 | in mat4 a_instanceMatrix; 10 | 11 | out vec3 v_position; 12 | out vec3 v_normal; 13 | 14 | float rand(vec2 n) { 15 | return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); 16 | } 17 | 18 | void main() { 19 | float t = u_time * rand(vec2(float(gl_VertexID)) * 100.); 20 | vec3 pos = a_position * (1. + t * 0.2); 21 | vec4 worldPosition = a_instanceMatrix * vec4(pos, 1.); 22 | gl_Position = u_projectionMatrix * u_viewMatrix * worldPosition; 23 | v_position = worldPosition.xyz; 24 | v_normal = (a_instanceMatrix * vec4(0., 0., 1., 0.)).xyz; 25 | } -------------------------------------------------------------------------------- /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/shader/texture.frag.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | uniform sampler2D u_concreteTexture; 6 | 7 | layout(location = 0) out vec4 outTexture; 8 | layout(location = 1) out vec4 outNormal; 9 | 10 | in vec2 v_texcoord; 11 | 12 | #define PI 3.1415926535897932384626433832795 13 | #define TWO_PI 6.2831853071795864769252867665590 14 | 15 | float random(in vec3 pos) { 16 | return fract(sin(dot(pos.xyz, vec3(70.9898, 78.233, 32.4355))) * 43758.5453123); 17 | } 18 | 19 | vec3 random3(vec3 p) { 20 | p = fract(p * vec3(.1031, .1030, .0973)); 21 | p += dot(p, p.yxz+19.19); 22 | return fract((p.xxy + p.yzz)*p.zyx); 23 | } 24 | 25 | vec4[2] voronoi( in vec3 x ) { 26 | vec3 n = floor(x); 27 | vec3 f = fract(x); 28 | vec3 mg, mr; 29 | 30 | vec3 c; 31 | float md = 8.0; 32 | float id; 33 | for( int j=-1; j<=1; j++ ) 34 | for( int i=-1; i<=1; i++ ) 35 | for( int k=-1; k<=1; k++ ) 36 | { 37 | vec3 g = vec3(float(i),float(j),float(k)); 38 | vec3 o = random3( n + g ); 39 | vec3 r = g + o - f; 40 | float d = dot(r,r); 41 | 42 | if( d < md ) 43 | { 44 | md = d; 45 | mr = r; 46 | mg = g; 47 | c = r; 48 | id = smoothstep(0., 1., length(o) * 0.15); 49 | } 50 | } 51 | 52 | md = 8.0; 53 | for( int j=-2; j<=2; j++ ) 54 | for( int i=-2; i<=2; i++ ) 55 | for( int k=-1; k<=1; k++ ) 56 | { 57 | vec3 g = mg + vec3(float(i),float(j),float(k)); 58 | vec3 o = random3( n + g ); 59 | vec3 r = g + o - f; 60 | 61 | if( dot(mr-r,mr-r)>0.00001 ) 62 | md = min( md, dot( 0.5*(mr+r), normalize(r-mr) ) ); 63 | } 64 | 65 | return vec4[2]( vec4(md, mr), vec4(c, float(id)) ); 66 | } 67 | 68 | vec3 cart2equirect(vec2 uv) { 69 | float Phi = PI - uv.y * PI; 70 | float Theta = uv.x * TWO_PI; 71 | vec3 dir = vec3(cos(Theta), 0.0, sin(Theta)); 72 | dir.y = cos(Phi);//clamp(cos(Phi), MinCos, 1.0); 73 | dir.xz *= sqrt(1.0 - dir.y * dir.y); 74 | return dir; 75 | } 76 | 77 | const vec2 inv_atan = vec2(0.1591, 0.3183); 78 | 79 | vec2 dir2equirect(highp vec3 dir) { 80 | highp vec2 uv = vec2(atan(dir.z, dir.x), asin(dir.y)); 81 | uv *= inv_atan; 82 | uv += 0.5; 83 | return uv; 84 | } 85 | 86 | float random(in float x) { 87 | return fract(sin(x) * 43758.5453); 88 | } 89 | 90 | mat2 rotate2d(in float radians){ 91 | float c = cos(radians); 92 | float s = sin(radians); 93 | return mat2(c, -s, s, c); 94 | } 95 | 96 | vec2 rotate(in vec2 st, in float radians, in vec2 center) { 97 | return rotate2d(radians) * (st - center) + center; 98 | } 99 | 100 | float sphericalDistance(vec3 pi, vec3 pj) { 101 | return (acos(dot(pj, pi))); 102 | } 103 | 104 | vec4 mod289(in vec4 x) { 105 | return x - floor(x * (1. / 289.)) * 289.; 106 | } 107 | 108 | vec3 mod289(in vec3 x) { 109 | return x - floor(x * (1. / 289.)) * 289.; 110 | } 111 | 112 | vec4 permute(in vec4 x) { 113 | return mod289(((x * 34.) + 1.)*x); 114 | } 115 | 116 | vec4 taylorInvSqrt(in vec4 r) { 117 | return 1.79284291400159 - 0.85373472095314 * r; 118 | } 119 | 120 | float snoise(in vec3 v) { 121 | const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; 122 | const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); 123 | 124 | // First corner 125 | vec3 i = floor(v + dot(v, C.yyy) ); 126 | vec3 x0 = v - i + dot(i, C.xxx) ; 127 | 128 | // Other corners 129 | vec3 g = step(x0.yzx, x0.xyz); 130 | vec3 l = 1.0 - g; 131 | vec3 i1 = min( g.xyz, l.zxy ); 132 | vec3 i2 = max( g.xyz, l.zxy ); 133 | 134 | // x0 = x0 - 0.0 + 0.0 * C.xxx; 135 | // x1 = x0 - i1 + 1.0 * C.xxx; 136 | // x2 = x0 - i2 + 2.0 * C.xxx; 137 | // x3 = x0 - 1.0 + 3.0 * C.xxx; 138 | vec3 x1 = x0 - i1 + C.xxx; 139 | vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y 140 | vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y 141 | 142 | // Permutations 143 | i = mod289(i); 144 | vec4 p = permute( permute( permute( 145 | i.z + vec4(0.0, i1.z, i2.z, 1.0 )) 146 | + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) 147 | + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); 148 | 149 | // Gradients: 7x7 points over a square, mapped onto an octahedron. 150 | // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 151 | float n_ = 0.142857142857; // 1.0/7.0 152 | vec3 ns = n_ * D.wyz - D.xzx; 153 | 154 | vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) 155 | 156 | vec4 x_ = floor(j * ns.z); 157 | vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) 158 | 159 | vec4 x = x_ *ns.x + ns.yyyy; 160 | vec4 y = y_ *ns.x + ns.yyyy; 161 | vec4 h = 1.0 - abs(x) - abs(y); 162 | 163 | vec4 b0 = vec4( x.xy, y.xy ); 164 | vec4 b1 = vec4( x.zw, y.zw ); 165 | 166 | //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; 167 | //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; 168 | vec4 s0 = floor(b0)*2.0 + 1.0; 169 | vec4 s1 = floor(b1)*2.0 + 1.0; 170 | vec4 sh = -step(h, vec4(0.0)); 171 | 172 | vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; 173 | vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; 174 | 175 | vec3 p0 = vec3(a0.xy,h.x); 176 | vec3 p1 = vec3(a0.zw,h.y); 177 | vec3 p2 = vec3(a1.xy,h.z); 178 | vec3 p3 = vec3(a1.zw,h.w); 179 | 180 | //Normalise gradients 181 | vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); 182 | p0 *= norm.x; 183 | p1 *= norm.y; 184 | p2 *= norm.z; 185 | p3 *= norm.w; 186 | 187 | // Mix final noise value 188 | vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); 189 | m = m * m; 190 | return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), 191 | dot(p2,x2), dot(p3,x3) ) ); 192 | } 193 | 194 | float fbm(in vec3 pos, in float ampScale) { 195 | // Initial values 196 | float value = 0.0; 197 | float amplitud = 0.3; 198 | 199 | // Loop of octaves 200 | for (int i = 0; i < 25; i++) { 201 | value += amplitud * snoise(pos); 202 | pos *= 2.; 203 | amplitud *= ampScale; 204 | } 205 | return value; 206 | } 207 | 208 | // creates a vector which is orthogonal to the given vector 209 | vec3 orthogonal(vec3 v) { 210 | return normalize(abs(v.x) > abs(v.z) ? 211 | vec3(-v.y, v.x, 0.0) : 212 | vec3(0.0, -v.z, v.y)); 213 | } 214 | 215 | void main() { 216 | vec2 st = v_texcoord; 217 | vec3 dir = normalize(cart2equirect(st)); 218 | 219 | float n0 = fbm(dir, 0.7); 220 | float n1 = fbm(dir, 0.6); 221 | 222 | vec4[2] voronoi0 = voronoi(dir * 2.1 * (1. - n0 * 0.12)); 223 | vec4[2] voronoi1 = voronoi(dir * 2.1 * (1. - n1 * 0.2)); 224 | vec4[2] voronoi2 = voronoi(dir * 1.5 * (1. - n1 * 0.3)); 225 | vec4[2] voronoi3 = voronoi(dir * 3.0 * (1. - n1 * 0.4)); 226 | vec4 v0 = voronoi0[0]; 227 | vec4 v1 = voronoi1[0]; 228 | vec4 v2 = voronoi2[0]; 229 | vec4 v3 = voronoi3[0]; 230 | vec3 c = normalize(voronoi1[1].xyz); 231 | float id = voronoi1[1].w; 232 | 233 | // generate the displacement value 234 | float sp = sphericalDistance(dir, c); 235 | float disp = length(v1.yzw) * 0.3 + id * 2.; 236 | 237 | // generate the ice textures 238 | float dirt1 = fbm(dir * 1000., 0.7); 239 | float dirt2 = 0.8 * fbm(dir * 10., 0.7) + 0.2; 240 | float dirt3 = 0.8 * fbm(dir * 3., 0.7) + 0.2; 241 | float ice1 = 0.; 242 | float ice2 = 0.; 243 | ice2 += smoothstep(0.3, 1., length(v1.yzw)) * 0.4; 244 | ice2 += smoothstep(0.1, 1., length(v1.yzw)) * 0.3 * dirt3; 245 | ice2 += smoothstep(0.5, 1., length(v3.yzw)) * .2; 246 | ice2 += (1. - smoothstep(0.00, 0.1, v2.r)) * 0.1; 247 | ice2 += (1. - smoothstep(0.00, 0.8, v2.r)) * 0.5 * dirt1; 248 | ice1 += abs((1. - smoothstep(0.00, 0.004, v0.r)) * 1. * dirt3); 249 | ice1 += abs((1. - smoothstep(0.00, 0.03, v1.r)) * .8 * dirt3); 250 | ice1 += abs((1. - smoothstep(0.00, 0.004, v0.r)) * 0.4 * dirt2); 251 | ice1 += abs((1. - smoothstep(0.00, 0.09, v0.r)) * 0.1); 252 | float ice3 = pow(length(v3.yzw), 5.); 253 | ice1 -= dirt1 * 0.05; 254 | ice3 -= dirt1 * 0.1; 255 | 256 | // generate normal map from the center point normal 257 | vec3 N = dir; 258 | vec3 T = normalize(cart2equirect(st + vec2(0.01, 0.)) - N); 259 | vec3 B = (cross(T, N)); 260 | T = normalize(cross(N, B)); 261 | mat3 inversTangentSpace = inverse(mat3(T, B, N)); 262 | vec3 normal = normalize(c * 0.4 + dir * dirt2 * 0.3 * ice1 * 100.); 263 | vec3 o = dir - c; 264 | float w1 = (1. - smoothstep(0.00, 0.3, length(v0.r))) * 0.3 + dirt2 * 0.1 + ice1 * 2.5; 265 | float w2 = (1. - smoothstep(0.00, 0.03, length(v0.r))) * 0.7; 266 | normal = normalize(dir + o * w1 + o * w2); 267 | vec3 normalOffset = inversTangentSpace * normal; 268 | 269 | outTexture = vec4(ice1, ice2, ice3, disp); 270 | outNormal = vec4(normalOffset * 0.5 + 0.5, 0); 271 | } -------------------------------------------------------------------------------- /src/app/shader/texture.vert.glsl: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | in vec2 a_position; 4 | 5 | out vec2 v_texcoord; 6 | 7 | void main() { 8 | gl_Position = vec4(a_position, 0., 1.); 9 | v_texcoord = a_position * 0.5 + 0.5; 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 | import { ArcballControl } from "./utils/arcball-control"; 6 | 7 | import colorVert from './shader/color.vert.glsl'; 8 | import colorFrag from './shader/color.frag.glsl'; 9 | import textureVert from './shader/texture.vert.glsl'; 10 | import textureFrag from './shader/texture.frag.glsl'; 11 | import testVert from './shader/test.vert.glsl'; 12 | import testFrag from './shader/test.frag.glsl'; 13 | import highpassVert from './shader/highpass.vert.glsl'; 14 | import highpassFrag from './shader/highpass.frag.glsl'; 15 | import blurVert from './shader/blur.vert.glsl'; 16 | import blurFrag from './shader/blur.frag.glsl'; 17 | import compositeVert from './shader/composite.vert.glsl'; 18 | import compositeFrag from './shader/composite.frag.glsl'; 19 | import particleVert from './shader/particle.vert.glsl'; 20 | import particleFrag from './shader/particle.frag.glsl'; 21 | import { easeInOutCubic, easeInOutExpo, easeOutExpo } from "./utils"; 22 | 23 | export class Sketch { 24 | 25 | TARGET_FRAME_DURATION = 16; 26 | #time = 0; // total time 27 | #deltaTime = 0; // duration betweent the previous and the current animation frame 28 | #frames = 0; // total framecount according to the target frame duration 29 | // relative frames according to the target frame duration (1 = 60 fps) 30 | // gets smaller with higher framerates --> use to adapt animation timing 31 | #deltaFrames = 0; 32 | 33 | // the scale factor for the bloom and lensflare highpass texture 34 | SS_FX_SCALE = 0.2; 35 | 36 | // animation properties 37 | TRANSITION_DURATION = 60; 38 | 39 | camera = { 40 | matrix: mat4.create(), 41 | near: 0.1, 42 | far: 5, 43 | fov: Math.PI / 3, 44 | aspect: 1, 45 | position: vec3.fromValues(0, 0, 3), 46 | up: vec3.fromValues(0, 1, 0), 47 | matrices: { 48 | view: mat4.create(), 49 | projection: mat4.create(), 50 | inversProjection: mat4.create(), 51 | inversViewProjection: mat4.create() 52 | } 53 | }; 54 | 55 | animationProps = { 56 | p: 0, // progress 57 | w: 0, // wobble strength 58 | p0: 0, // prev progress 59 | w: 0, // prev wobble strength 60 | wm: 0, 61 | s: 1, // scale 62 | sa: 0, // additional scale (for freezing) 63 | sm: 0, // scale momentum 64 | cracked: false, 65 | particleTime: 0, 66 | particleEaseTime: 0, 67 | particleStart: false, 68 | }; 69 | 70 | settings = { 71 | } 72 | 73 | PARTICLE_COUNT = 1000; 74 | 75 | constructor(canvasElm, onInit = null, isDev = false, pane = null) { 76 | this.canvas = canvasElm; 77 | this.onInit = onInit; 78 | this.isDev = isDev; 79 | this.pane = pane; 80 | 81 | this.#init().then(() => { 82 | if (this.onInit) this.onInit(this) 83 | }); 84 | } 85 | 86 | run(time = 0) { 87 | this.#deltaTime = Math.min(16, time - this.#time); 88 | this.#time = time; 89 | this.#deltaFrames = this.#deltaTime / this.TARGET_FRAME_DURATION; 90 | this.#frames += this.#deltaFrames; 91 | 92 | this.control.update(this.#deltaTime); 93 | mat4.fromQuat(this.worldMatrix, this.control.rotationQuat); 94 | 95 | // update the world inverse transpose 96 | mat4.invert(this.worldInverseMatrix, this.worldMatrix); 97 | mat4.transpose(this.worldInverseTransposeMatrix, this.worldInverseMatrix); 98 | 99 | this.#animate(this.#deltaTime); 100 | this.#render(); 101 | 102 | requestAnimationFrame((t) => this.run(t)); 103 | } 104 | 105 | resize() { 106 | /** @type {WebGLRenderingContext} */ 107 | const gl = this.gl; 108 | 109 | this.viewportSize = vec2.set( 110 | this.viewportSize, 111 | this.canvas.clientWidth, 112 | this.canvas.clientHeight 113 | ); 114 | 115 | const needsResize = twgl.resizeCanvasToDisplaySize(this.canvas); 116 | 117 | if (needsResize) { 118 | gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 119 | 120 | if (this.highpassFBO) { 121 | twgl.resizeFramebufferInfo(gl, this.highpassFBO, [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 122 | this.viewportSize[0] * this.SS_FX_SCALE, this.viewportSize[1] * this.SS_FX_SCALE); 123 | } 124 | 125 | if (this.blurFBO) { 126 | twgl.resizeFramebufferInfo(gl, this.blurFBO, [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 127 | this.viewportSize[0] * this.SS_FX_SCALE, this.viewportSize[1] * this.SS_FX_SCALE); 128 | } 129 | 130 | if (this.drawFBO) { 131 | twgl.resizeFramebufferInfo(gl, this.drawFBO, [ 132 | {attachmentPoint: gl.COLOR_ATTACHMENT0}, 133 | {attachmentPoint: gl.DEPTH_ATTACHMENT, format: gl.DEPTH_COMPONENT, internalFormat: gl.DEPTH_COMPONENT32F} 134 | ], this.viewportSize[0], this.viewportSize[1]); 135 | } 136 | } 137 | 138 | this.#updateProjectionMatrix(gl); 139 | } 140 | 141 | async #init() { 142 | this.gl = this.canvas.getContext('webgl2', { antialias: false, alpha: false }); 143 | 144 | this.touchevents = Modernizr.touchevents; 145 | 146 | /** @type {WebGLRenderingContext} */ 147 | const gl = this.gl; 148 | 149 | twgl.addExtensionsToContext(gl); 150 | 151 | this.viewportSize = vec2.fromValues( 152 | this.canvas.clientWidth, 153 | this.canvas.clientHeight 154 | ); 155 | 156 | await this.#initImageTextures(); 157 | this.#initParticles(); 158 | 159 | // Setup Programs 160 | this.colorPrg = twgl.createProgramInfo(gl, [colorVert, colorFrag]); 161 | this.texturePrg = twgl.createProgramInfo(gl, [textureVert, textureFrag]); 162 | this.testPrg = twgl.createProgramInfo(gl, [testVert, testFrag]); 163 | this.highpassPrg = twgl.createProgramInfo(gl, [highpassVert, highpassFrag]); 164 | this.blurPrg = twgl.createProgramInfo(gl, [blurVert, blurFrag]); 165 | this.compositePrg = twgl.createProgramInfo(gl, [compositeVert, compositeFrag]); 166 | this.particlePrg = twgl.createProgramInfo(gl, [particleVert, particleFrag]); 167 | 168 | // Setup Meshes 169 | this.quadBufferInfo = twgl.createBufferInfoFromArrays(gl, { a_position: { numComponents: 2, data: [-1, -1, 3, -1, -1, 3] }}); 170 | this.quadVAO = twgl.createVAOAndSetAttributes(gl, this.texturePrg.attribSetters, this.quadBufferInfo.attribs, this.quadBufferInfo.indices); 171 | this.particleBufferInfo = twgl.createBufferInfoFromArrays(gl, { 172 | a_position: { 173 | numComponents: 2, 174 | data: [0, 0, 0.1, -0.1, 0, 0.05], 175 | }, 176 | a_instanceMatrix: { 177 | numComponents: 16, 178 | data: this.particleInstanceMatricesData, 179 | divisor: 1, 180 | } 181 | }); 182 | this.particleVAO = twgl.createVAOAndSetAttributes(gl, this.particlePrg.attribSetters, this.particleBufferInfo.attribs, this.particleBufferInfo.indices); 183 | 184 | // load the bead model 185 | this.glbBuilder = new GLBBuilder(gl); 186 | await this.glbBuilder.load(new URL('../assets/model.glb', import.meta.url)); 187 | this.modelPrimitive = this.glbBuilder.getPrimitiveDataByMeshName('Icosphere'); 188 | this.modelBuffers = this.modelPrimitive.buffers; 189 | this.modelBufferInfo = twgl.createBufferInfoFromArrays(gl, { 190 | a_position: {...this.modelBuffers.vertices, numComponents: this.modelBuffers.vertices.numberOfComponents}, 191 | a_normal: {...this.modelBuffers.normals, numComponents: this.modelBuffers.normals.numberOfComponents}, 192 | a_texcoord: {...this.modelBuffers.texcoords, numComponents: this.modelBuffers.texcoords.numberOfComponents}, 193 | a_tangent: {...this.modelBuffers.tangents, numComponents: this.modelBuffers.tangents.numberOfComponents}, 194 | indices: {...this.modelBuffers.indices, numComponents: this.modelBuffers.indices.numberOfComponents} 195 | }); 196 | this.modelVAO = twgl.createVAOAndSetAttributes(gl, this.colorPrg.attribSetters, this.modelBufferInfo.attribs, this.modelBufferInfo.indices); 197 | 198 | // Setup Framebuffers 199 | const resScale = Math.max(this.viewportSize[0], this.viewportSize[1]) > 800 ? 1 : 0.5; 200 | this.textureFBO = twgl.createFramebufferInfo( 201 | gl, 202 | [{attachmentPoint: gl.COLOR_ATTACHMENT0}, {attachmentPoint: gl.COLOR_ATTACHMENT1}], 203 | 2048 * resScale, 1024 * resScale 204 | ); 205 | this.iceTexture = this.textureFBO.attachments[0]; 206 | this.iceNormalTexture = this.textureFBO.attachments[1]; 207 | this.drawFBO = twgl.createFramebufferInfo(gl, [ 208 | {attachmentPoint: gl.COLOR_ATTACHMENT0}, 209 | {attachmentPoint: gl.DEPTH_ATTACHMENT, format: gl.DEPTH_COMPONENT, internalFormat: gl.DEPTH_COMPONENT32F} 210 | ], this.viewportSize[0], this.viewportSize[1]); 211 | this.colorTexture = this.drawFBO.attachments[0]; 212 | this.highpassFBO = twgl.createFramebufferInfo( 213 | gl, 214 | [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 215 | this.viewportSize[0] * this.SS_FX_SCALE, 216 | this.viewportSize[1] * this.SS_FX_SCALE 217 | ); 218 | this.highpassTexture = this.highpassFBO.attachments[0]; 219 | this.blurFBO = twgl.createFramebufferInfo( 220 | gl, 221 | [{attachmentPoint: gl.COLOR_ATTACHMENT0}], 222 | this.viewportSize[0] * this.SS_FX_SCALE, 223 | this.viewportSize[1] * this.SS_FX_SCALE 224 | ); 225 | this.blurTexture = this.blurFBO.attachments[0]; 226 | 227 | 228 | ///// INIT AUDIO FX 229 | this.crackSound = new Audio(new URL('../assets/crack.mp3', import.meta.url)); 230 | 231 | this.worldMatrix = mat4.create(); 232 | this.worldInverseMatrix = mat4.create(); 233 | this.worldInverseTransposeMatrix = mat4.create(); 234 | 235 | this.progress = 0; 236 | this.control = new ArcballControl(this.canvas); 237 | this.#initTweakpane(); 238 | this.#updateCameraMatrix(); 239 | this.#updateProjectionMatrix(gl); 240 | this.#initEvents(); 241 | 242 | this.resize(); 243 | } 244 | 245 | #initEvents() { 246 | this.isPointerDown = false; 247 | 248 | fromEvent(this.canvas, 'pointerdown').subscribe((e) => { 249 | this.isPointerDown = true; 250 | }); 251 | merge( 252 | fromEvent(this.canvas, 'pointerup'), 253 | fromEvent(this.canvas, 'pointerleave') 254 | ).subscribe(() => this.isPointerDown = false); 255 | } 256 | 257 | #initImageTextures() { 258 | /** @type {WebGLRenderingContext} */ 259 | const gl = this.gl; 260 | 261 | const dirtTexturePromise = new Promise((resolve) => { 262 | this.dirtTexture = twgl.createTexture(gl, { 263 | src: new URL('../assets/dirt.jpg', import.meta.url).toString(), 264 | }, () => resolve()); 265 | }); 266 | 267 | const concreteTexturePromise = new Promise((resolve) => { 268 | this.concreteTexture = twgl.createTexture(gl, { 269 | src: new URL('../assets/concrete.jpg', import.meta.url).toString(), 270 | }, () => resolve()); 271 | }); 272 | 273 | const envMapPromise = new Promise(resolve => { 274 | this.envMapTexture = twgl.createTexture(gl, { 275 | target: gl.TEXTURE_CUBE_MAP, 276 | src: [ 277 | new URL('../assets/env/posx.jpg', import.meta.url).toString(), 278 | new URL('../assets/env/negx.jpg', import.meta.url).toString(), 279 | new URL('../assets/env/posy.jpg', import.meta.url).toString(), 280 | new URL('../assets/env/negy.jpg', import.meta.url).toString(), 281 | new URL('../assets/env/posz.jpg', import.meta.url).toString(), 282 | new URL('../assets/env/negz.jpg', import.meta.url).toString(), 283 | ], 284 | }, () => resolve()) 285 | }) 286 | 287 | return Promise.all([dirtTexturePromise]); 288 | } 289 | 290 | #initTweakpane() { 291 | if (!this.pane) return; 292 | 293 | /*this.animationFolder = this.pane.addFolder({ title: 'Animation', expanded: true }); 294 | this.animationFolder.addInput( 295 | this.settings, 296 | 'progress', 297 | { label: 'progress', min: 0, max: 1 } 298 | );*/ 299 | } 300 | 301 | #initParticles() { 302 | this.particleInstanceMatricesData = new Float32Array(this.PARTICLE_COUNT * 16); 303 | this.initParticlePositions = []; 304 | this.initParticleScales = []; 305 | this.initParticleRotations = []; 306 | this.particleInstanceMatrices = []; 307 | for (let i = 0; i < this.PARTICLE_COUNT; ++i) { 308 | const r = 1.0 + Math.random() * 0.2 309 | const polar = Math.random() * Math.PI * 2; 310 | const alpha = Math.random() * Math.PI * 2; 311 | const x = r * Math.sin(polar) * Math.cos(alpha); 312 | const y = r * Math.sin(polar) * Math.sin(alpha); 313 | const z = r * Math.cos(polar); 314 | 315 | const mat = new Float32Array(this.particleInstanceMatricesData.buffer, i * 16 * 4, 16); 316 | mat4.identity(mat); 317 | 318 | this.particleInstanceMatrices.push(mat); 319 | this.initParticlePositions.push([x, y, z]); 320 | this.initParticleScales.push([Math.random() * 0.2 + 0.1, Math.random() * 0.2 + 0.1, Math.random() * 0.2 + 0.1]); 321 | this.initParticleRotations.push([Math.PI * 2 * Math.random(), Math.PI * 2 * Math.random(), 0]); 322 | } 323 | } 324 | 325 | #animate(deltaTime) { 326 | /** @type {WebGLRenderingContext} */ 327 | const gl = this.gl; 328 | 329 | // use a fixed deltaTime of 16 ms adapted to 330 | // device frame rate 331 | deltaTime = 16 * this.#deltaFrames; 332 | 333 | this.animationProps.p0 = this.animationProps.p; 334 | let st = 1; 335 | let d1 = 50; 336 | let d2 = 0.92; 337 | let dw = 1; 338 | if (this.isPointerDown) { 339 | this.animationProps.p -= 1 * deltaTime * 0.00025; 340 | st = .9; 341 | d1 = 30; 342 | d2 = 0.92 343 | } else { 344 | this.animationProps.p += 2 * deltaTime * 0.00025; 345 | st = 1.05; 346 | d1 = 10; 347 | d2 = 0.5 348 | dw = 1; 349 | } 350 | 351 | // wobble scale 352 | const ds = (this.animationProps.s - st); 353 | this.animationProps.sm -= ds / d1; 354 | this.animationProps.sm *= d2; 355 | this.animationProps.s += this.animationProps.sm; 356 | this.animationProps.w = 0; 357 | 358 | if (this.animationProps.p0 < this.animationProps.p) { 359 | this.dir = 1; 360 | } else { 361 | this.dir = -1; 362 | } 363 | 364 | if (this.dir === 1 && this.animationProps.p > 0.7 && this.animationProps.p < 0.9) { 365 | this.animationProps.sa = Math.random() * 0.03; 366 | } else { 367 | this.animationProps.sa = 0; 368 | } 369 | 370 | this.animationProps.p = Math.min(14.5, this.animationProps.p); 371 | this.animationProps.p = Math.min(1, Math.max(0, this.animationProps.p)); 372 | this.animationProps.w = 1 - this.animationProps.p; 373 | this.animationProps.particleTime -= 0.0007; 374 | this.animationProps.particleTime = Math.max(0, this.animationProps.particleTime); 375 | 376 | if (this.dir === 1 && !this.animationProps.cracked && this.animationProps.p >= 0.77) { 377 | this.crackSound.play(); 378 | this.animationProps.cracked = true; 379 | } 380 | 381 | if (this.dir === 1 && !this.animationProps.particleStart && this.animationProps.p >= 0.9) { 382 | this.animationProps.particleStart = true; 383 | this.animationProps.particleTime = 1.; 384 | } 385 | 386 | if (this.dir === -1 && this.animationProps.p < 0.85) { 387 | this.animationProps.cracked = false; 388 | this.animationProps.particleStart = false; 389 | } 390 | 391 | //this.animationProps.particleTime = 1.; 392 | this.animationProps.particleEaseTime = easeOutExpo(1 - this.animationProps.particleTime); 393 | 394 | let offsetScale = this.animationProps.particleEaseTime * 0.5; 395 | let scale = 1 - this.animationProps.particleEaseTime; 396 | scale *= .7 397 | offsetScale -= 0.05; 398 | const offset = vec3.create(); 399 | for (let i = 0; i < this.PARTICLE_COUNT; ++i) { 400 | const mat = this.particleInstanceMatrices[i]; 401 | const pos = this.initParticlePositions[i]; 402 | const initScale = this.initParticleScales[i]; 403 | const initRot = this.initParticleRotations[i]; 404 | initRot[0] = initRot[0] + 0.01; 405 | initRot[1] = initRot[1] + 0.005; 406 | vec3.copy(offset, pos); 407 | vec3.scale(offset, offset, offsetScale); 408 | 409 | mat4.identity(mat); 410 | mat4.translate(mat, mat, pos); 411 | mat4.translate(mat, mat, offset); 412 | mat4.rotateY(mat, mat, initRot[0]); 413 | mat4.rotateZ(mat, mat, initRot[1]); 414 | mat4.scale(mat, mat, initScale); 415 | mat4.scale(mat, mat, [scale, scale, scale]); 416 | 417 | this.particleInstanceMatrices.push(mat); 418 | } 419 | // upload the instance matrix buffer 420 | gl.bindBuffer(gl.ARRAY_BUFFER, this.particleBufferInfo.attribs.a_instanceMatrix.buffer); 421 | gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.particleInstanceMatricesData); 422 | gl.bindBuffer(gl.ARRAY_BUFFER, null); 423 | } 424 | 425 | #render() { 426 | /** @type {WebGLRenderingContext} */ 427 | const gl = this.gl; 428 | 429 | // render the texture 430 | if (!this.prerender) { 431 | this.prerender = true; 432 | twgl.bindFramebufferInfo(gl, this.textureFBO); 433 | gl.bindVertexArray(this.quadVAO); 434 | gl.disable(gl.CULL_FACE); 435 | gl.disable(gl.DEPTH_TEST); 436 | this.gl.clearColor(0, 0, 0, 1); 437 | this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); 438 | this.gl.useProgram(this.texturePrg.program); 439 | twgl.setUniforms(this.texturePrg, { 440 | u_concreteTexture: this.concreteTexture 441 | }); 442 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 443 | } 444 | 445 | const p = this.animationProps.p; 446 | twgl.bindFramebufferInfo(gl, this.drawFBO ); 447 | this.gl.clearColor(0, 0, 0, 1); 448 | this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); 449 | this.gl.useProgram(this.colorPrg.program); 450 | twgl.setUniforms(this.colorPrg, { 451 | u_worldMatrix: this.worldMatrix, 452 | u_viewMatrix: this.camera.matrices.view, 453 | u_projectionMatrix: this.camera.matrices.projection, 454 | u_worldInverseTransposeMatrix: this.worldInverseTransposeMatrix, 455 | u_worldInverseMatrix: this.worldInverseMatrix, 456 | u_cameraPos: this.camera.position, 457 | u_time: this.#time, 458 | u_iceTexture: this.iceTexture, 459 | u_iceNormal: this.iceNormalTexture, 460 | u_dirtTexture: this.dirtTexture, 461 | u_envMapTexture: this.envMapTexture, 462 | u_wobbleStrength: this.animationProps.w, 463 | u_scale: this.animationProps.s + this.animationProps.sa, 464 | u_progress1: 1 - Math.pow((1-p), 5), 465 | u_progress2: easeInOutCubic(p), 466 | u_progress3: easeInOutExpo(Math.max(0, (p - 0.8) * (1 / (1 - 0.8)))) 467 | }); 468 | gl.bindVertexArray(this.modelVAO); 469 | gl.enable(gl.CULL_FACE); 470 | gl.enable(gl.DEPTH_TEST); 471 | gl.drawElements( 472 | gl.TRIANGLES, 473 | this.modelBufferInfo.numElements, 474 | gl.UNSIGNED_SHORT, 475 | 0 476 | ); 477 | // draw particles 478 | this.gl.useProgram(this.particlePrg.program); 479 | twgl.setUniforms(this.particlePrg, { 480 | u_worldMatrix: this.worldMatrix, 481 | u_viewMatrix: this.camera.matrices.view, 482 | u_projectionMatrix: this.camera.matrices.projection, 483 | u_time: this.animationProps.particleEaseTime 484 | }); 485 | gl.bindVertexArray(this.particleVAO); 486 | gl.enable(gl.BLEND); 487 | gl.blendFunc(gl.SRC_COLOR, gl.ONE_MINUS_DST_ALPHA); 488 | gl.drawArraysInstanced(gl.TRIANGLES, 0, this.particleBufferInfo.numElements, this.PARTICLE_COUNT); 489 | 490 | gl.disable(gl.BLEND); 491 | 492 | // get highpass 493 | twgl.bindFramebufferInfo(gl, this.highpassFBO); 494 | gl.bindVertexArray(this.quadVAO); 495 | gl.useProgram(this.highpassPrg.program); 496 | twgl.setUniforms(this.highpassPrg, { 497 | u_colorTexture: this.colorTexture 498 | }); 499 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 500 | 501 | // blur pass 502 | twgl.bindFramebufferInfo(gl, this.blurFBO); 503 | gl.bindVertexArray(this.quadVAO); 504 | gl.useProgram(this.blurPrg.program); 505 | twgl.setUniforms(this.blurPrg, { 506 | u_colorTexture: this.highpassTexture 507 | }); 508 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 509 | 510 | // composite the final image 511 | twgl.bindFramebufferInfo(gl, null); 512 | gl.viewport(0, 0, this.viewportSize[0], this.viewportSize[1]); 513 | gl.bindVertexArray(this.quadVAO); 514 | gl.useProgram(this.compositePrg.program); 515 | twgl.setUniforms(this.compositePrg, { 516 | u_bloomTexture: this.blurTexture, 517 | u_colorTexture: this.colorTexture, 518 | u_stainTexture: this.concreteTexture 519 | }); 520 | twgl.drawBufferInfo(gl, this.quadBufferInfo); 521 | 522 | 523 | if (this.isDev) { 524 | // draw helper view of particle texture 525 | /*twgl.bindFramebufferInfo(gl, null); 526 | gl.viewport(0, 0, this.viewportSize[0] / 4, this.viewportSize[1] / 4); 527 | gl.bindVertexArray(this.quadVAO); 528 | gl.disable(gl.DEPTH_TEST); 529 | gl.useProgram(this.testPrg.program); 530 | twgl.setUniforms(this.testPrg, { 531 | u_texture: this.blurTexture 532 | }); 533 | twgl.drawBufferInfo(gl, this.quadBufferInfo);*/ 534 | } 535 | } 536 | 537 | #updateCameraMatrix() { 538 | mat4.targetTo(this.camera.matrix, this.camera.position, [0, 0, 0], this.camera.up); 539 | mat4.invert(this.camera.matrices.view, this.camera.matrix); 540 | } 541 | 542 | #updateProjectionMatrix(gl) { 543 | this.camera.aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; 544 | 545 | const height = 1.45; 546 | const distance = this.camera.position[2]; 547 | if (this.camera.aspect > 1) { 548 | this.camera.fov = 2 * Math.atan( height / distance ); 549 | } else { 550 | this.camera.fov = 2 * Math.atan( (height / this.camera.aspect) / distance ); 551 | } 552 | 553 | mat4.perspective(this.camera.matrices.projection, this.camera.fov, this.camera.aspect, this.camera.near, this.camera.far); 554 | mat4.invert(this.camera.matrices.inversProjection, this.camera.matrices.projection); 555 | mat4.multiply(this.camera.matrices.inversViewProjection, this.camera.matrix, this.camera.matrices.inversProjection) 556 | } 557 | } -------------------------------------------------------------------------------- /src/app/utils.js: -------------------------------------------------------------------------------- 1 | export const mapRange = (value, min1, max1, min2, max2) => { 2 | return min2 + (max2 - min2) * (value - min1) / (max1 - min1); 3 | } 4 | 5 | export const clamp = (num, min, max) => Math.min(Math.max(num, min), max); 6 | 7 | export const easeInOutExpo = (x) => { 8 | return x === 0 9 | ? 0 10 | : x === 1 11 | ? 1 12 | : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 13 | : (2 - Math.pow(2, -20 * x + 10)) / 2; 14 | } 15 | 16 | export const easeInOutCubic = (x) => { 17 | return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2; 18 | } 19 | 20 | export const easeInExpo = (x) => { 21 | return x === 0 ? 0 : Math.pow(2, 10 * x - 10); 22 | } 23 | 24 | export const easeOutQuint = (x) => { 25 | return 1 - Math.pow(1 - x, 5); 26 | } 27 | 28 | export const easeOutExpo = (x) => { 29 | return x === 1 ? 1 : 1 - Math.pow(2, -10 * x); 30 | } -------------------------------------------------------------------------------- /src/app/utils/arcball-control.js: -------------------------------------------------------------------------------- 1 | import { quat, vec3, vec2, mat3 } from 'gl-matrix'; 2 | 3 | export class ArcballControl { 4 | 5 | // the current rotation quaternion 6 | rotationQuat = quat.create(); 7 | 8 | constructor(canvas, updateCallback) { 9 | this.canvas = canvas; 10 | this.updateCallback = updateCallback ? updateCallback : () => null; 11 | 12 | this.pointerDown = false; 13 | this.pointerDownPos = vec2.create(); 14 | this.pointerPos = vec2.create(); 15 | this.followPos = vec3.create(); 16 | this.prevFollowPos = vec3.create(); 17 | this.autoRotationSpeed = 0; 18 | this.velocity = 0.002; 19 | this.rotationAxis = vec3.fromValues(0, 1, 0); 20 | 21 | canvas.style.touchAction = 'none'; 22 | 23 | canvas.addEventListener('pointerdown', e => { 24 | this.pointerDownPos = vec2.fromValues(e.clientX, e.clientY); 25 | this.followPos = vec3.fromValues(e.clientX, e.clientY, 0); 26 | this.pointerPos = vec2.fromValues(e.clientX, e.clientY); 27 | this.prevFollowPos = vec3.fromValues(e.clientX, e.clientY, 0); 28 | this.pointerDown = true; 29 | this.autoRotationSpeed = 0; 30 | }); 31 | canvas.addEventListener('pointerup', e => { 32 | this.pointerDown = false; 33 | }); 34 | canvas.addEventListener('pointerleave', e => { 35 | this.pointerDown = false; 36 | }); 37 | canvas.addEventListener('pointermove', e => { 38 | if (this.pointerDown) { 39 | this.pointerPos[0] = e.clientX; 40 | this.pointerPos[1] = e.clientY; 41 | } 42 | }); 43 | } 44 | 45 | update(deltaTime) { 46 | const timeScale = 16 / (deltaTime + 0.01); 47 | 48 | // the mouse follower 49 | const damping = 10 * timeScale; 50 | this.followPos[0] += (this.pointerPos[0] - this.followPos[0]) / damping; 51 | this.followPos[1] += (this.pointerPos[1] - this.followPos[1]) / damping; 52 | 53 | let r; 54 | if (this.pointerDown) { 55 | // get points on the arcball and corresponding normals 56 | const p = this.#project(this.followPos); 57 | const q = this.#project(this.prevFollowPos); 58 | const np = vec3.normalize(vec3.create(), p); 59 | const nq = vec3.normalize(vec3.create(), q); 60 | 61 | // get the normalized axis of rotation 62 | const axis = vec3.cross(vec3.create(), p, q); 63 | vec3.normalize(axis, axis); 64 | 65 | // get the amount of rotation 66 | const d = Math.max(-1, Math.min(1, vec3.dot(np, nq))); 67 | const angle = Math.acos(d) * timeScale * 3; 68 | 69 | this.velocity = angle; 70 | this.rotationAxis = vec3.clone(axis); 71 | 72 | // get the new rotation quat 73 | r = quat.setAxisAngle(quat.create(), axis, angle); 74 | } else { 75 | this.velocity *= this.velocity > 0.002 ? .97 : 1; 76 | //r = quat.setAxisAngle(quat.create(), vec3.fromValues(0, 1, 0), this.autoRotationSpeed); 77 | r = quat.setAxisAngle(quat.create(), this.rotationAxis, this.velocity); 78 | } 79 | 80 | // apply the new rotation to the current rotation and normalize 81 | quat.multiply(this.rotationQuat, r, this.rotationQuat); 82 | quat.normalize(this.rotationQuat, this.rotationQuat); 83 | 84 | // update for the next iteration 85 | this.prevFollowPos = vec3.clone(this.followPos); 86 | this.updateCallback(); 87 | } 88 | 89 | /** 90 | * Maps pointer coordinates to canonical coordinates [-1, 1] 91 | * and projects them onto the arcball surface or onto a 92 | * hyperbolical function outside the arcball. 93 | * 94 | * @return vec3 The arcball coords 95 | * 96 | * @see https://www.xarg.org/2021/07/trackball-rotation-using-quaternions/ 97 | */ 98 | #project(pos) { 99 | const r = 1; // arcball radius 100 | const w = this.canvas.clientWidth; 101 | const h = this.canvas.clientHeight; 102 | const s = Math.max(w, h) - 1; 103 | 104 | // map to -1 to 1 105 | const x = (2 * pos[0] - w - 1) / s; 106 | const y = (2 * pos[1] - h - 1) / s; 107 | let z = 0; 108 | const xySq = x * x + y * y; 109 | const rSq = r * r; 110 | 111 | if (xySq <= rSq / 2) 112 | z = Math.sqrt(rSq - xySq); 113 | else 114 | z = (rSq / 2) / Math.sqrt(xySq); // hyperbolical function 115 | 116 | return vec3.fromValues(-x, y, z); 117 | } 118 | } -------------------------------------------------------------------------------- /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 0) 22 | * @param z The damping factor (0 = no damping, 0 < damping < 1 = underdamped -> vibration, > 1 = no vibration) 23 | * @param r The response factor (0 = slow acceleration, 0 < response < 1 = immediate response, r > 1 = overshoot, r < 0 = anticipate motion / wind up) 24 | * @param x0 The initial target value 25 | */ 26 | constructor(f, z, r, x0) { 27 | this.#y = x0; 28 | this.#xp = x0; 29 | this.#yd = 0; 30 | 31 | this.#k1 = z / (Math.PI * f); 32 | this.#k2 = 1 / ((2 * Math.PI * f) * (2 * Math.PI * f)); 33 | this.#k3 = (r * z) / (2 * Math.PI * f); 34 | } 35 | 36 | update(dt, x, xd) { 37 | // estimate the target velocity 38 | if (xd == null) { 39 | xd = (x - this.#xp) / dt; 40 | this.#xp = x; 41 | } 42 | 43 | // integrate position by velocity 44 | this.#y += this.#yd * dt; 45 | 46 | // clamp k2 for stability 47 | const k2 = Math.max(this.#k2, 1.1 * ((dt * dt) / 4 + (dt * this.#k1) / 2)); 48 | 49 | // update the acceleration 50 | const ydd = (x + this.#k3 * xd - this.#y - this.#k1 * this.#yd) / k2; 51 | 52 | // integrate velocity by acceleration 53 | this.#yd += ydd * dt; 54 | 55 | return this.#y; 56 | } 57 | 58 | get value() { 59 | return this.#y; 60 | } 61 | } -------------------------------------------------------------------------------- /src/assets/concrete.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/concrete.jpg -------------------------------------------------------------------------------- /src/assets/crack.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/crack.mp3 -------------------------------------------------------------------------------- /src/assets/dirt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/dirt.jpg -------------------------------------------------------------------------------- /src/assets/env/negx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/env/negx.jpg -------------------------------------------------------------------------------- /src/assets/env/negy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/env/negy.jpg -------------------------------------------------------------------------------- /src/assets/env/negz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/env/negz.jpg -------------------------------------------------------------------------------- /src/assets/env/posx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/env/posx.jpg -------------------------------------------------------------------------------- /src/assets/env/posy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/env/posy.jpg -------------------------------------------------------------------------------- /src/assets/env/posz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/env/posz.jpg -------------------------------------------------------------------------------- /src/assets/model.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert-leitl/phase-transition/78a9c7d1dbd1fe0962b2c1b5d2075f0da7ee13ba/src/assets/model.glb -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Phase Transition 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 |

Touch/Click and drag to transition between phases and rotate.

16 |
17 | github 18 | 19 | -------------------------------------------------------------------------------- /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 | --center-offset: 2em; 18 | color: #eee; 19 | } 20 | 21 | body { 22 | position: relative; 23 | position: relative; 24 | } 25 | 26 | canvas { 27 | width: 100%; 28 | height: 100%; 29 | z-index: 2; 30 | } 31 | 32 | .github-link { 33 | position: absolute; 34 | right: 0; 35 | bottom: 0; 36 | color: #aaa; 37 | mix-blend-mode: difference; 38 | text-transform: uppercase; 39 | text-decoration: none; 40 | padding: 0.7em 1em; 41 | font-size: 0.8em; 42 | } 43 | 44 | #start-button, 45 | .loader, 46 | .loader:after { 47 | --track-color: rgba(134, 134, 134, 0.3); 48 | border-radius: 50%; 49 | width: 10em; 50 | height: 10em; 51 | font-size: 10px; 52 | margin: 0; 53 | padding: 0; 54 | border: 2px solid var(--track-color); 55 | } 56 | 57 | #start-button, 58 | .loader { 59 | position: absolute; 60 | top: calc(50% - 5em - var(--center-offset)); 61 | left: calc(50% - 5em); 62 | } 63 | 64 | .loader { 65 | border-left: 2px solid #727272; 66 | -webkit-transform: translateZ(0); 67 | -ms-transform: translateZ(0); 68 | transform: translateZ(0); 69 | -webkit-animation: load8 1.1s infinite linear; 70 | animation: load8 1.1s infinite linear; 71 | } 72 | @-webkit-keyframes load8 { 73 | 0% { 74 | -webkit-transform: rotate(0deg); 75 | transform: rotate(0deg); 76 | } 77 | 100% { 78 | -webkit-transform: rotate(360deg); 79 | transform: rotate(360deg); 80 | } 81 | } 82 | @keyframes load8 { 83 | 0% { 84 | -webkit-transform: rotate(0deg); 85 | transform: rotate(0deg); 86 | } 87 | 100% { 88 | -webkit-transform: rotate(360deg); 89 | transform: rotate(360deg); 90 | } 91 | } 92 | 93 | #start-button { 94 | border-color: #aaa; 95 | background: black; 96 | color: #eee; 97 | background: #eee; 98 | color: #333; 99 | border: none; 100 | font-weight: bold; 101 | text-transform: uppercase; 102 | text-align: center; 103 | opacity: 0; 104 | transition: opacity 400ms; 105 | cursor: pointer; 106 | } 107 | 108 | #start-button label { 109 | pointer-events: none; 110 | font-size: 1.5em; 111 | letter-spacing: 0.15em; 112 | } 113 | 114 | #intro { 115 | font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace; 116 | width: 100%; 117 | display: flex; 118 | flex-direction: column; 119 | align-items: center; 120 | text-align: center; 121 | position: absolute; 122 | top: calc(50% + 5em - var(--center-offset)); 123 | } 124 | 125 | #intro p { 126 | font-size: .8em; 127 | max-width: 24em; 128 | line-height: 1.4em; 129 | } -------------------------------------------------------------------------------- /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 | }); --------------------------------------------------------------------------------