├── .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 | 
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 | });
--------------------------------------------------------------------------------