├── .gitignore ├── .prettierc.json ├── index.html ├── main.js ├── package-lock.json ├── package.json ├── public ├── coral_fort_wall_02_2k.gltf │ ├── coral_fort_wall_02.bin │ ├── coral_fort_wall_02_2k.gltf │ └── textures │ │ ├── coral_fort_wall_02_diff_2k.jpg │ │ ├── coral_fort_wall_02_nor_gl_2k.jpg │ │ └── coral_fort_wall_02_rough_2k.jpg └── vite.svg ├── style.css └── window.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /.prettierc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth":4 3 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import "./style.css" 2 | 3 | import WindowManager from './window'; 4 | import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; 5 | import * as THREE from 'three'; 6 | 7 | let camera, scene, renderer, world; 8 | let near, far; 9 | let objs = []; 10 | let sceneOffsetTarget = {x: 0, y: 0}; 11 | let sceneOffset = {x: 0, y: 0}; 12 | 13 | let today = new Date(); 14 | today.setHours(0); 15 | today.setMinutes(0); 16 | today.setSeconds(0); 17 | today.setMilliseconds(0); 18 | today = today.getTime(); 19 | 20 | const getTime =() =>{ 21 | return (new Date().getTime() - today) / 1000.0; 22 | } 23 | 24 | let internalTime = getTime(); 25 | let windowManager; 26 | let initialized = false; 27 | 28 | 29 | if (new URLSearchParams(window.location.search).get("clear")){ 30 | localStorage.clear(); 31 | } 32 | else { 33 | document.addEventListener("visibilitychange", () => 34 | { 35 | if (document.visibilityState != 'hidden' && !initialized) 36 | { 37 | init(); 38 | } 39 | }); 40 | 41 | window.onload = () => { 42 | if (document.visibilityState != 'hidden') 43 | { 44 | initialized = true; 45 | init(); 46 | 47 | } 48 | }; 49 | 50 | const init = () => { 51 | setTimeout(() => { 52 | paintScene() 53 | setupWindowManager(); 54 | resize(); 55 | updateWindowShape(false); 56 | animate(); 57 | window.addEventListener('resize', resize); 58 | }, 300) 59 | } 60 | 61 | const paintScene = () => { 62 | camera = new THREE.OrthographicCamera( window.innerWidth/-2, window.innerWidth/2, window.innerHeight/-2, window.innerHeight/2, 1, 1000); 63 | camera.position.z = 2.5; 64 | near = camera.position.z - .5; 65 | far = camera.position.z + 0.5; 66 | 67 | scene = new THREE.Scene(); 68 | scene.add( camera ); 69 | 70 | renderer = new THREE.WebGLRenderer({antialias: true, depthBuffer: true}); 71 | renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1); 72 | renderer.setClearColor("lightblue"); 73 | 74 | const loader = new GLTFLoader(); 75 | loader.load('/coral_fort_wall_02_2k.gltf/coral_fort_wall_02_2k.gltf', (th) => { 76 | const text = th.scene.children[0].material.map; 77 | scene.background = text 78 | }); 79 | 80 | 81 | world = new THREE.Object3D(); 82 | scene.add(world); 83 | 84 | const ambientLight = new THREE.AmbientLight('white', 1); 85 | scene.add(ambientLight) 86 | 87 | const directionalLight = new THREE.DirectionalLight('white', 4); 88 | scene.add(directionalLight); 89 | 90 | renderer.domElement.setAttribute("id", "scene"); 91 | document.body.appendChild( renderer.domElement ); 92 | } 93 | 94 | const updateWindowShape = (easing = true)=> { 95 | sceneOffsetTarget = {x: -window.screenX, y: -window.screenY}; 96 | if (!easing) sceneOffset = sceneOffsetTarget; 97 | } 98 | 99 | const setupWindowManager = ()=> { 100 | windowManager = new WindowManager(); 101 | windowManager.setWinShapeChangeCallback(updateWindowShape); 102 | windowManager.setWinChangeCallback(updateWindow); 103 | 104 | let metaData = {foo: "bar"}; 105 | windowManager.init(metaData); 106 | updateWindow(); 107 | } 108 | 109 | const updateWindow =()=> { 110 | updateNumberOfobjs(); 111 | } 112 | 113 | const updateNumberOfobjs = ()=> { 114 | let wins = windowManager.getWindows(); 115 | objs.forEach((c) => { 116 | world.remove(c); 117 | }) 118 | objs = []; 119 | for (let i = 0; i < wins.length; i++) 120 | { 121 | let win = wins[i]; 122 | 123 | let color = new THREE.Color(); 124 | color.setHSL(i * .1, 1.0, .5); 125 | let shape = 100 + i * 2; 126 | let obj = new THREE.Mesh(new THREE.TorusGeometry(shape, 30, shape), new THREE.MeshPhongMaterial({color: color, wireframe:true })); 127 | obj.position.x = win.shape.x + (win.shape.w * .5); 128 | obj.position.y = win.shape.y + (win.shape.h * .5); 129 | world.add(obj); 130 | objs.push(obj); 131 | } 132 | } 133 | 134 | function animate () { 135 | let time = getTime(); 136 | windowManager.update(); 137 | let falloff = 0.5; 138 | sceneOffset.x = sceneOffset.x + ((sceneOffsetTarget.x - sceneOffset.x) * falloff); 139 | sceneOffset.y = sceneOffset.y + ((sceneOffsetTarget.y - sceneOffset.y) * falloff); 140 | 141 | world.position.x = sceneOffset.x; 142 | world.position.y = sceneOffset.y; 143 | 144 | let wins = windowManager.getWindows(); 145 | for (let i = 0; i < objs.length; i++) { 146 | let obj = objs[i]; 147 | let win = wins[i]; 148 | let posTarget = {x: win.shape.x + (win.shape.w * .5), y: win.shape.y + (win.shape.h * .5)} 149 | obj.position.x = obj.position.x + (posTarget.x - obj.position.x) * falloff; 150 | obj.position.y = obj.position.y + (posTarget.y - obj.position.y) * falloff; 151 | obj.rotation.y = time * 1; 152 | }; 153 | renderer.render(scene, camera); 154 | requestAnimationFrame(animate) 155 | } 156 | 157 | 158 | 159 | function resize () 160 | { 161 | let width = window.innerWidth; 162 | let height = window.innerHeight 163 | 164 | camera = new THREE.OrthographicCamera(0, width, 0, height, -10000, 10000); 165 | camera.updateProjectionMatrix(); 166 | renderer.setSize( width, height ); 167 | } 168 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multi-window", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "multi-window", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "three": "^0.158.0" 12 | }, 13 | "devDependencies": { 14 | "vite": "^5.0.0" 15 | } 16 | }, 17 | "node_modules/@esbuild/android-arm": { 18 | "version": "0.19.7", 19 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.7.tgz", 20 | "integrity": "sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww==", 21 | "cpu": [ 22 | "arm" 23 | ], 24 | "dev": true, 25 | "optional": true, 26 | "os": [ 27 | "android" 28 | ], 29 | "engines": { 30 | "node": ">=12" 31 | } 32 | }, 33 | "node_modules/@esbuild/android-arm64": { 34 | "version": "0.19.7", 35 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.7.tgz", 36 | "integrity": "sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==", 37 | "cpu": [ 38 | "arm64" 39 | ], 40 | "dev": true, 41 | "optional": true, 42 | "os": [ 43 | "android" 44 | ], 45 | "engines": { 46 | "node": ">=12" 47 | } 48 | }, 49 | "node_modules/@esbuild/android-x64": { 50 | "version": "0.19.7", 51 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.7.tgz", 52 | "integrity": "sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw==", 53 | "cpu": [ 54 | "x64" 55 | ], 56 | "dev": true, 57 | "optional": true, 58 | "os": [ 59 | "android" 60 | ], 61 | "engines": { 62 | "node": ">=12" 63 | } 64 | }, 65 | "node_modules/@esbuild/darwin-arm64": { 66 | "version": "0.19.7", 67 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.7.tgz", 68 | "integrity": "sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw==", 69 | "cpu": [ 70 | "arm64" 71 | ], 72 | "dev": true, 73 | "optional": true, 74 | "os": [ 75 | "darwin" 76 | ], 77 | "engines": { 78 | "node": ">=12" 79 | } 80 | }, 81 | "node_modules/@esbuild/darwin-x64": { 82 | "version": "0.19.7", 83 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.7.tgz", 84 | "integrity": "sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ==", 85 | "cpu": [ 86 | "x64" 87 | ], 88 | "dev": true, 89 | "optional": true, 90 | "os": [ 91 | "darwin" 92 | ], 93 | "engines": { 94 | "node": ">=12" 95 | } 96 | }, 97 | "node_modules/@esbuild/freebsd-arm64": { 98 | "version": "0.19.7", 99 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.7.tgz", 100 | "integrity": "sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ==", 101 | "cpu": [ 102 | "arm64" 103 | ], 104 | "dev": true, 105 | "optional": true, 106 | "os": [ 107 | "freebsd" 108 | ], 109 | "engines": { 110 | "node": ">=12" 111 | } 112 | }, 113 | "node_modules/@esbuild/freebsd-x64": { 114 | "version": "0.19.7", 115 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.7.tgz", 116 | "integrity": "sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA==", 117 | "cpu": [ 118 | "x64" 119 | ], 120 | "dev": true, 121 | "optional": true, 122 | "os": [ 123 | "freebsd" 124 | ], 125 | "engines": { 126 | "node": ">=12" 127 | } 128 | }, 129 | "node_modules/@esbuild/linux-arm": { 130 | "version": "0.19.7", 131 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.7.tgz", 132 | "integrity": "sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww==", 133 | "cpu": [ 134 | "arm" 135 | ], 136 | "dev": true, 137 | "optional": true, 138 | "os": [ 139 | "linux" 140 | ], 141 | "engines": { 142 | "node": ">=12" 143 | } 144 | }, 145 | "node_modules/@esbuild/linux-arm64": { 146 | "version": "0.19.7", 147 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.7.tgz", 148 | "integrity": "sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g==", 149 | "cpu": [ 150 | "arm64" 151 | ], 152 | "dev": true, 153 | "optional": true, 154 | "os": [ 155 | "linux" 156 | ], 157 | "engines": { 158 | "node": ">=12" 159 | } 160 | }, 161 | "node_modules/@esbuild/linux-ia32": { 162 | "version": "0.19.7", 163 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.7.tgz", 164 | "integrity": "sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g==", 165 | "cpu": [ 166 | "ia32" 167 | ], 168 | "dev": true, 169 | "optional": true, 170 | "os": [ 171 | "linux" 172 | ], 173 | "engines": { 174 | "node": ">=12" 175 | } 176 | }, 177 | "node_modules/@esbuild/linux-loong64": { 178 | "version": "0.19.7", 179 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.7.tgz", 180 | "integrity": "sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw==", 181 | "cpu": [ 182 | "loong64" 183 | ], 184 | "dev": true, 185 | "optional": true, 186 | "os": [ 187 | "linux" 188 | ], 189 | "engines": { 190 | "node": ">=12" 191 | } 192 | }, 193 | "node_modules/@esbuild/linux-mips64el": { 194 | "version": "0.19.7", 195 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.7.tgz", 196 | "integrity": "sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w==", 197 | "cpu": [ 198 | "mips64el" 199 | ], 200 | "dev": true, 201 | "optional": true, 202 | "os": [ 203 | "linux" 204 | ], 205 | "engines": { 206 | "node": ">=12" 207 | } 208 | }, 209 | "node_modules/@esbuild/linux-ppc64": { 210 | "version": "0.19.7", 211 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.7.tgz", 212 | "integrity": "sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ==", 213 | "cpu": [ 214 | "ppc64" 215 | ], 216 | "dev": true, 217 | "optional": true, 218 | "os": [ 219 | "linux" 220 | ], 221 | "engines": { 222 | "node": ">=12" 223 | } 224 | }, 225 | "node_modules/@esbuild/linux-riscv64": { 226 | "version": "0.19.7", 227 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.7.tgz", 228 | "integrity": "sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw==", 229 | "cpu": [ 230 | "riscv64" 231 | ], 232 | "dev": true, 233 | "optional": true, 234 | "os": [ 235 | "linux" 236 | ], 237 | "engines": { 238 | "node": ">=12" 239 | } 240 | }, 241 | "node_modules/@esbuild/linux-s390x": { 242 | "version": "0.19.7", 243 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.7.tgz", 244 | "integrity": "sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg==", 245 | "cpu": [ 246 | "s390x" 247 | ], 248 | "dev": true, 249 | "optional": true, 250 | "os": [ 251 | "linux" 252 | ], 253 | "engines": { 254 | "node": ">=12" 255 | } 256 | }, 257 | "node_modules/@esbuild/linux-x64": { 258 | "version": "0.19.7", 259 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.7.tgz", 260 | "integrity": "sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ==", 261 | "cpu": [ 262 | "x64" 263 | ], 264 | "dev": true, 265 | "optional": true, 266 | "os": [ 267 | "linux" 268 | ], 269 | "engines": { 270 | "node": ">=12" 271 | } 272 | }, 273 | "node_modules/@esbuild/netbsd-x64": { 274 | "version": "0.19.7", 275 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.7.tgz", 276 | "integrity": "sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ==", 277 | "cpu": [ 278 | "x64" 279 | ], 280 | "dev": true, 281 | "optional": true, 282 | "os": [ 283 | "netbsd" 284 | ], 285 | "engines": { 286 | "node": ">=12" 287 | } 288 | }, 289 | "node_modules/@esbuild/openbsd-x64": { 290 | "version": "0.19.7", 291 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.7.tgz", 292 | "integrity": "sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ==", 293 | "cpu": [ 294 | "x64" 295 | ], 296 | "dev": true, 297 | "optional": true, 298 | "os": [ 299 | "openbsd" 300 | ], 301 | "engines": { 302 | "node": ">=12" 303 | } 304 | }, 305 | "node_modules/@esbuild/sunos-x64": { 306 | "version": "0.19.7", 307 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.7.tgz", 308 | "integrity": "sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw==", 309 | "cpu": [ 310 | "x64" 311 | ], 312 | "dev": true, 313 | "optional": true, 314 | "os": [ 315 | "sunos" 316 | ], 317 | "engines": { 318 | "node": ">=12" 319 | } 320 | }, 321 | "node_modules/@esbuild/win32-arm64": { 322 | "version": "0.19.7", 323 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.7.tgz", 324 | "integrity": "sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw==", 325 | "cpu": [ 326 | "arm64" 327 | ], 328 | "dev": true, 329 | "optional": true, 330 | "os": [ 331 | "win32" 332 | ], 333 | "engines": { 334 | "node": ">=12" 335 | } 336 | }, 337 | "node_modules/@esbuild/win32-ia32": { 338 | "version": "0.19.7", 339 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.7.tgz", 340 | "integrity": "sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A==", 341 | "cpu": [ 342 | "ia32" 343 | ], 344 | "dev": true, 345 | "optional": true, 346 | "os": [ 347 | "win32" 348 | ], 349 | "engines": { 350 | "node": ">=12" 351 | } 352 | }, 353 | "node_modules/@esbuild/win32-x64": { 354 | "version": "0.19.7", 355 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.7.tgz", 356 | "integrity": "sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ==", 357 | "cpu": [ 358 | "x64" 359 | ], 360 | "dev": true, 361 | "optional": true, 362 | "os": [ 363 | "win32" 364 | ], 365 | "engines": { 366 | "node": ">=12" 367 | } 368 | }, 369 | "node_modules/@rollup/rollup-android-arm-eabi": { 370 | "version": "4.5.1", 371 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.5.1.tgz", 372 | "integrity": "sha512-YaN43wTyEBaMqLDYeze+gQ4ZrW5RbTEGtT5o1GVDkhpdNcsLTnLRcLccvwy3E9wiDKWg9RIhuoy3JQKDRBfaZA==", 373 | "cpu": [ 374 | "arm" 375 | ], 376 | "dev": true, 377 | "optional": true, 378 | "os": [ 379 | "android" 380 | ] 381 | }, 382 | "node_modules/@rollup/rollup-android-arm64": { 383 | "version": "4.5.1", 384 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.5.1.tgz", 385 | "integrity": "sha512-n1bX+LCGlQVuPlCofO0zOKe1b2XkFozAVRoczT+yxWZPGnkEAKTTYVOGZz8N4sKuBnKMxDbfhUsB1uwYdup/sw==", 386 | "cpu": [ 387 | "arm64" 388 | ], 389 | "dev": true, 390 | "optional": true, 391 | "os": [ 392 | "android" 393 | ] 394 | }, 395 | "node_modules/@rollup/rollup-darwin-arm64": { 396 | "version": "4.5.1", 397 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.5.1.tgz", 398 | "integrity": "sha512-QqJBumdvfBqBBmyGHlKxje+iowZwrHna7pokj/Go3dV1PJekSKfmjKrjKQ/e6ESTGhkfPNLq3VXdYLAc+UtAQw==", 399 | "cpu": [ 400 | "arm64" 401 | ], 402 | "dev": true, 403 | "optional": true, 404 | "os": [ 405 | "darwin" 406 | ] 407 | }, 408 | "node_modules/@rollup/rollup-darwin-x64": { 409 | "version": "4.5.1", 410 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.5.1.tgz", 411 | "integrity": "sha512-RrkDNkR/P5AEQSPkxQPmd2ri8WTjSl0RYmuFOiEABkEY/FSg0a4riihWQGKDJ4LnV9gigWZlTMx2DtFGzUrYQw==", 412 | "cpu": [ 413 | "x64" 414 | ], 415 | "dev": true, 416 | "optional": true, 417 | "os": [ 418 | "darwin" 419 | ] 420 | }, 421 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 422 | "version": "4.5.1", 423 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.5.1.tgz", 424 | "integrity": "sha512-ZFPxvUZmE+fkB/8D9y/SWl/XaDzNSaxd1TJUSE27XAKlRpQ2VNce/86bGd9mEUgL3qrvjJ9XTGwoX0BrJkYK/A==", 425 | "cpu": [ 426 | "arm" 427 | ], 428 | "dev": true, 429 | "optional": true, 430 | "os": [ 431 | "linux" 432 | ] 433 | }, 434 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 435 | "version": "4.5.1", 436 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.5.1.tgz", 437 | "integrity": "sha512-FEuAjzVIld5WVhu+M2OewLmjmbXWd3q7Zcx+Rwy4QObQCqfblriDMMS7p7+pwgjZoo9BLkP3wa9uglQXzsB9ww==", 438 | "cpu": [ 439 | "arm64" 440 | ], 441 | "dev": true, 442 | "optional": true, 443 | "os": [ 444 | "linux" 445 | ] 446 | }, 447 | "node_modules/@rollup/rollup-linux-arm64-musl": { 448 | "version": "4.5.1", 449 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.5.1.tgz", 450 | "integrity": "sha512-f5Gs8WQixqGRtI0Iq/cMqvFYmgFzMinuJO24KRfnv7Ohi/HQclwrBCYkzQu1XfLEEt3DZyvveq9HWo4bLJf1Lw==", 451 | "cpu": [ 452 | "arm64" 453 | ], 454 | "dev": true, 455 | "optional": true, 456 | "os": [ 457 | "linux" 458 | ] 459 | }, 460 | "node_modules/@rollup/rollup-linux-x64-gnu": { 461 | "version": "4.5.1", 462 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.5.1.tgz", 463 | "integrity": "sha512-CWPkPGrFfN2vj3mw+S7A/4ZaU3rTV7AkXUr08W9lNP+UzOvKLVf34tWCqrKrfwQ0NTk5GFqUr2XGpeR2p6R4gw==", 464 | "cpu": [ 465 | "x64" 466 | ], 467 | "dev": true, 468 | "optional": true, 469 | "os": [ 470 | "linux" 471 | ] 472 | }, 473 | "node_modules/@rollup/rollup-linux-x64-musl": { 474 | "version": "4.5.1", 475 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.5.1.tgz", 476 | "integrity": "sha512-ZRETMFA0uVukUC9u31Ed1nx++29073goCxZtmZARwk5aF/ltuENaeTtRVsSQzFlzdd4J6L3qUm+EW8cbGt0CKQ==", 477 | "cpu": [ 478 | "x64" 479 | ], 480 | "dev": true, 481 | "optional": true, 482 | "os": [ 483 | "linux" 484 | ] 485 | }, 486 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 487 | "version": "4.5.1", 488 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.5.1.tgz", 489 | "integrity": "sha512-ihqfNJNb2XtoZMSCPeoo0cYMgU04ksyFIoOw5S0JUVbOhafLot+KD82vpKXOurE2+9o/awrqIxku9MRR9hozHQ==", 490 | "cpu": [ 491 | "arm64" 492 | ], 493 | "dev": true, 494 | "optional": true, 495 | "os": [ 496 | "win32" 497 | ] 498 | }, 499 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 500 | "version": "4.5.1", 501 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.5.1.tgz", 502 | "integrity": "sha512-zK9MRpC8946lQ9ypFn4gLpdwr5a01aQ/odiIJeL9EbgZDMgbZjjT/XzTqJvDfTmnE1kHdbG20sAeNlpc91/wbg==", 503 | "cpu": [ 504 | "ia32" 505 | ], 506 | "dev": true, 507 | "optional": true, 508 | "os": [ 509 | "win32" 510 | ] 511 | }, 512 | "node_modules/@rollup/rollup-win32-x64-msvc": { 513 | "version": "4.5.1", 514 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.5.1.tgz", 515 | "integrity": "sha512-5I3Nz4Sb9TYOtkRwlH0ow+BhMH2vnh38tZ4J4mggE48M/YyJyp/0sPSxhw1UeS1+oBgQ8q7maFtSeKpeRJu41Q==", 516 | "cpu": [ 517 | "x64" 518 | ], 519 | "dev": true, 520 | "optional": true, 521 | "os": [ 522 | "win32" 523 | ] 524 | }, 525 | "node_modules/esbuild": { 526 | "version": "0.19.7", 527 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.7.tgz", 528 | "integrity": "sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ==", 529 | "dev": true, 530 | "hasInstallScript": true, 531 | "bin": { 532 | "esbuild": "bin/esbuild" 533 | }, 534 | "engines": { 535 | "node": ">=12" 536 | }, 537 | "optionalDependencies": { 538 | "@esbuild/android-arm": "0.19.7", 539 | "@esbuild/android-arm64": "0.19.7", 540 | "@esbuild/android-x64": "0.19.7", 541 | "@esbuild/darwin-arm64": "0.19.7", 542 | "@esbuild/darwin-x64": "0.19.7", 543 | "@esbuild/freebsd-arm64": "0.19.7", 544 | "@esbuild/freebsd-x64": "0.19.7", 545 | "@esbuild/linux-arm": "0.19.7", 546 | "@esbuild/linux-arm64": "0.19.7", 547 | "@esbuild/linux-ia32": "0.19.7", 548 | "@esbuild/linux-loong64": "0.19.7", 549 | "@esbuild/linux-mips64el": "0.19.7", 550 | "@esbuild/linux-ppc64": "0.19.7", 551 | "@esbuild/linux-riscv64": "0.19.7", 552 | "@esbuild/linux-s390x": "0.19.7", 553 | "@esbuild/linux-x64": "0.19.7", 554 | "@esbuild/netbsd-x64": "0.19.7", 555 | "@esbuild/openbsd-x64": "0.19.7", 556 | "@esbuild/sunos-x64": "0.19.7", 557 | "@esbuild/win32-arm64": "0.19.7", 558 | "@esbuild/win32-ia32": "0.19.7", 559 | "@esbuild/win32-x64": "0.19.7" 560 | } 561 | }, 562 | "node_modules/fsevents": { 563 | "version": "2.3.3", 564 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 565 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 566 | "dev": true, 567 | "hasInstallScript": true, 568 | "optional": true, 569 | "os": [ 570 | "darwin" 571 | ], 572 | "engines": { 573 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 574 | } 575 | }, 576 | "node_modules/nanoid": { 577 | "version": "3.3.7", 578 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 579 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 580 | "dev": true, 581 | "funding": [ 582 | { 583 | "type": "github", 584 | "url": "https://github.com/sponsors/ai" 585 | } 586 | ], 587 | "bin": { 588 | "nanoid": "bin/nanoid.cjs" 589 | }, 590 | "engines": { 591 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 592 | } 593 | }, 594 | "node_modules/picocolors": { 595 | "version": "1.0.0", 596 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 597 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 598 | "dev": true 599 | }, 600 | "node_modules/postcss": { 601 | "version": "8.4.31", 602 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", 603 | "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", 604 | "dev": true, 605 | "funding": [ 606 | { 607 | "type": "opencollective", 608 | "url": "https://opencollective.com/postcss/" 609 | }, 610 | { 611 | "type": "tidelift", 612 | "url": "https://tidelift.com/funding/github/npm/postcss" 613 | }, 614 | { 615 | "type": "github", 616 | "url": "https://github.com/sponsors/ai" 617 | } 618 | ], 619 | "dependencies": { 620 | "nanoid": "^3.3.6", 621 | "picocolors": "^1.0.0", 622 | "source-map-js": "^1.0.2" 623 | }, 624 | "engines": { 625 | "node": "^10 || ^12 || >=14" 626 | } 627 | }, 628 | "node_modules/rollup": { 629 | "version": "4.5.1", 630 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.5.1.tgz", 631 | "integrity": "sha512-0EQribZoPKpb5z1NW/QYm3XSR//Xr8BeEXU49Lc/mQmpmVVG5jPUVrpc2iptup/0WMrY9mzas0fxH+TjYvG2CA==", 632 | "dev": true, 633 | "bin": { 634 | "rollup": "dist/bin/rollup" 635 | }, 636 | "engines": { 637 | "node": ">=18.0.0", 638 | "npm": ">=8.0.0" 639 | }, 640 | "optionalDependencies": { 641 | "@rollup/rollup-android-arm-eabi": "4.5.1", 642 | "@rollup/rollup-android-arm64": "4.5.1", 643 | "@rollup/rollup-darwin-arm64": "4.5.1", 644 | "@rollup/rollup-darwin-x64": "4.5.1", 645 | "@rollup/rollup-linux-arm-gnueabihf": "4.5.1", 646 | "@rollup/rollup-linux-arm64-gnu": "4.5.1", 647 | "@rollup/rollup-linux-arm64-musl": "4.5.1", 648 | "@rollup/rollup-linux-x64-gnu": "4.5.1", 649 | "@rollup/rollup-linux-x64-musl": "4.5.1", 650 | "@rollup/rollup-win32-arm64-msvc": "4.5.1", 651 | "@rollup/rollup-win32-ia32-msvc": "4.5.1", 652 | "@rollup/rollup-win32-x64-msvc": "4.5.1", 653 | "fsevents": "~2.3.2" 654 | } 655 | }, 656 | "node_modules/source-map-js": { 657 | "version": "1.0.2", 658 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 659 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 660 | "dev": true, 661 | "engines": { 662 | "node": ">=0.10.0" 663 | } 664 | }, 665 | "node_modules/three": { 666 | "version": "0.158.0", 667 | "resolved": "https://registry.npmjs.org/three/-/three-0.158.0.tgz", 668 | "integrity": "sha512-TALj4EOpdDPF1henk2Q+s17K61uEAAWQ7TJB68nr7FKxqwyDr3msOt5IWdbGm4TaWKjrtWS8DJJWe9JnvsWOhQ==" 669 | }, 670 | "node_modules/vite": { 671 | "version": "5.0.2", 672 | "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.2.tgz", 673 | "integrity": "sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==", 674 | "dev": true, 675 | "dependencies": { 676 | "esbuild": "^0.19.3", 677 | "postcss": "^8.4.31", 678 | "rollup": "^4.2.0" 679 | }, 680 | "bin": { 681 | "vite": "bin/vite.js" 682 | }, 683 | "engines": { 684 | "node": "^18.0.0 || >=20.0.0" 685 | }, 686 | "funding": { 687 | "url": "https://github.com/vitejs/vite?sponsor=1" 688 | }, 689 | "optionalDependencies": { 690 | "fsevents": "~2.3.3" 691 | }, 692 | "peerDependencies": { 693 | "@types/node": "^18.0.0 || >=20.0.0", 694 | "less": "*", 695 | "lightningcss": "^1.21.0", 696 | "sass": "*", 697 | "stylus": "*", 698 | "sugarss": "*", 699 | "terser": "^5.4.0" 700 | }, 701 | "peerDependenciesMeta": { 702 | "@types/node": { 703 | "optional": true 704 | }, 705 | "less": { 706 | "optional": true 707 | }, 708 | "lightningcss": { 709 | "optional": true 710 | }, 711 | "sass": { 712 | "optional": true 713 | }, 714 | "stylus": { 715 | "optional": true 716 | }, 717 | "sugarss": { 718 | "optional": true 719 | }, 720 | "terser": { 721 | "optional": true 722 | } 723 | } 724 | } 725 | }, 726 | "dependencies": { 727 | "@esbuild/android-arm": { 728 | "version": "0.19.7", 729 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.7.tgz", 730 | "integrity": "sha512-YGSPnndkcLo4PmVl2tKatEn+0mlVMr3yEpOOT0BeMria87PhvoJb5dg5f5Ft9fbCVgtAz4pWMzZVgSEGpDAlww==", 731 | "dev": true, 732 | "optional": true 733 | }, 734 | "@esbuild/android-arm64": { 735 | "version": "0.19.7", 736 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.7.tgz", 737 | "integrity": "sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==", 738 | "dev": true, 739 | "optional": true 740 | }, 741 | "@esbuild/android-x64": { 742 | "version": "0.19.7", 743 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.7.tgz", 744 | "integrity": "sha512-jhINx8DEjz68cChFvM72YzrqfwJuFbfvSxZAk4bebpngGfNNRm+zRl4rtT9oAX6N9b6gBcFaJHFew5Blf6CvUw==", 745 | "dev": true, 746 | "optional": true 747 | }, 748 | "@esbuild/darwin-arm64": { 749 | "version": "0.19.7", 750 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.7.tgz", 751 | "integrity": "sha512-dr81gbmWN//3ZnBIm6YNCl4p3pjnabg1/ZVOgz2fJoUO1a3mq9WQ/1iuEluMs7mCL+Zwv7AY5e3g1hjXqQZ9Iw==", 752 | "dev": true, 753 | "optional": true 754 | }, 755 | "@esbuild/darwin-x64": { 756 | "version": "0.19.7", 757 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.7.tgz", 758 | "integrity": "sha512-Lc0q5HouGlzQEwLkgEKnWcSazqr9l9OdV2HhVasWJzLKeOt0PLhHaUHuzb8s/UIya38DJDoUm74GToZ6Wc7NGQ==", 759 | "dev": true, 760 | "optional": true 761 | }, 762 | "@esbuild/freebsd-arm64": { 763 | "version": "0.19.7", 764 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.7.tgz", 765 | "integrity": "sha512-+y2YsUr0CxDFF7GWiegWjGtTUF6gac2zFasfFkRJPkMAuMy9O7+2EH550VlqVdpEEchWMynkdhC9ZjtnMiHImQ==", 766 | "dev": true, 767 | "optional": true 768 | }, 769 | "@esbuild/freebsd-x64": { 770 | "version": "0.19.7", 771 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.7.tgz", 772 | "integrity": "sha512-CdXOxIbIzPJmJhrpmJTLx+o35NoiKBIgOvmvT+jeSadYiWJn0vFKsl+0bSG/5lwjNHoIDEyMYc/GAPR9jxusTA==", 773 | "dev": true, 774 | "optional": true 775 | }, 776 | "@esbuild/linux-arm": { 777 | "version": "0.19.7", 778 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.7.tgz", 779 | "integrity": "sha512-Y+SCmWxsJOdQtjcBxoacn/pGW9HDZpwsoof0ttL+2vGcHokFlfqV666JpfLCSP2xLxFpF1lj7T3Ox3sr95YXww==", 780 | "dev": true, 781 | "optional": true 782 | }, 783 | "@esbuild/linux-arm64": { 784 | "version": "0.19.7", 785 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.7.tgz", 786 | "integrity": "sha512-inHqdOVCkUhHNvuQPT1oCB7cWz9qQ/Cz46xmVe0b7UXcuIJU3166aqSunsqkgSGMtUCWOZw3+KMwI6otINuC9g==", 787 | "dev": true, 788 | "optional": true 789 | }, 790 | "@esbuild/linux-ia32": { 791 | "version": "0.19.7", 792 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.7.tgz", 793 | "integrity": "sha512-2BbiL7nLS5ZO96bxTQkdO0euGZIUQEUXMTrqLxKUmk/Y5pmrWU84f+CMJpM8+EHaBPfFSPnomEaQiG/+Gmh61g==", 794 | "dev": true, 795 | "optional": true 796 | }, 797 | "@esbuild/linux-loong64": { 798 | "version": "0.19.7", 799 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.7.tgz", 800 | "integrity": "sha512-BVFQla72KXv3yyTFCQXF7MORvpTo4uTA8FVFgmwVrqbB/4DsBFWilUm1i2Oq6zN36DOZKSVUTb16jbjedhfSHw==", 801 | "dev": true, 802 | "optional": true 803 | }, 804 | "@esbuild/linux-mips64el": { 805 | "version": "0.19.7", 806 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.7.tgz", 807 | "integrity": "sha512-DzAYckIaK+pS31Q/rGpvUKu7M+5/t+jI+cdleDgUwbU7KdG2eC3SUbZHlo6Q4P1CfVKZ1lUERRFP8+q0ob9i2w==", 808 | "dev": true, 809 | "optional": true 810 | }, 811 | "@esbuild/linux-ppc64": { 812 | "version": "0.19.7", 813 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.7.tgz", 814 | "integrity": "sha512-JQ1p0SmUteNdUaaiRtyS59GkkfTW0Edo+e0O2sihnY4FoZLz5glpWUQEKMSzMhA430ctkylkS7+vn8ziuhUugQ==", 815 | "dev": true, 816 | "optional": true 817 | }, 818 | "@esbuild/linux-riscv64": { 819 | "version": "0.19.7", 820 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.7.tgz", 821 | "integrity": "sha512-xGwVJ7eGhkprY/nB7L7MXysHduqjpzUl40+XoYDGC4UPLbnG+gsyS1wQPJ9lFPcxYAaDXbdRXd1ACs9AE9lxuw==", 822 | "dev": true, 823 | "optional": true 824 | }, 825 | "@esbuild/linux-s390x": { 826 | "version": "0.19.7", 827 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.7.tgz", 828 | "integrity": "sha512-U8Rhki5PVU0L0nvk+E8FjkV8r4Lh4hVEb9duR6Zl21eIEYEwXz8RScj4LZWA2i3V70V4UHVgiqMpszXvG0Yqhg==", 829 | "dev": true, 830 | "optional": true 831 | }, 832 | "@esbuild/linux-x64": { 833 | "version": "0.19.7", 834 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.7.tgz", 835 | "integrity": "sha512-ZYZopyLhm4mcoZXjFt25itRlocKlcazDVkB4AhioiL9hOWhDldU9n38g62fhOI4Pth6vp+Mrd5rFKxD0/S+7aQ==", 836 | "dev": true, 837 | "optional": true 838 | }, 839 | "@esbuild/netbsd-x64": { 840 | "version": "0.19.7", 841 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.7.tgz", 842 | "integrity": "sha512-/yfjlsYmT1O3cum3J6cmGG16Fd5tqKMcg5D+sBYLaOQExheAJhqr8xOAEIuLo8JYkevmjM5zFD9rVs3VBcsjtQ==", 843 | "dev": true, 844 | "optional": true 845 | }, 846 | "@esbuild/openbsd-x64": { 847 | "version": "0.19.7", 848 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.7.tgz", 849 | "integrity": "sha512-MYDFyV0EW1cTP46IgUJ38OnEY5TaXxjoDmwiTXPjezahQgZd+j3T55Ht8/Q9YXBM0+T9HJygrSRGV5QNF/YVDQ==", 850 | "dev": true, 851 | "optional": true 852 | }, 853 | "@esbuild/sunos-x64": { 854 | "version": "0.19.7", 855 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.7.tgz", 856 | "integrity": "sha512-JcPvgzf2NN/y6X3UUSqP6jSS06V0DZAV/8q0PjsZyGSXsIGcG110XsdmuWiHM+pno7/mJF6fjH5/vhUz/vA9fw==", 857 | "dev": true, 858 | "optional": true 859 | }, 860 | "@esbuild/win32-arm64": { 861 | "version": "0.19.7", 862 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.7.tgz", 863 | "integrity": "sha512-ZA0KSYti5w5toax5FpmfcAgu3ZNJxYSRm0AW/Dao5up0YV1hDVof1NvwLomjEN+3/GMtaWDI+CIyJOMTRSTdMw==", 864 | "dev": true, 865 | "optional": true 866 | }, 867 | "@esbuild/win32-ia32": { 868 | "version": "0.19.7", 869 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.7.tgz", 870 | "integrity": "sha512-CTOnijBKc5Jpk6/W9hQMMvJnsSYRYgveN6O75DTACCY18RA2nqka8dTZR+x/JqXCRiKk84+5+bRKXUSbbwsS0A==", 871 | "dev": true, 872 | "optional": true 873 | }, 874 | "@esbuild/win32-x64": { 875 | "version": "0.19.7", 876 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.7.tgz", 877 | "integrity": "sha512-gRaP2sk6hc98N734luX4VpF318l3w+ofrtTu9j5L8EQXF+FzQKV6alCOHMVoJJHvVK/mGbwBXfOL1HETQu9IGQ==", 878 | "dev": true, 879 | "optional": true 880 | }, 881 | "@rollup/rollup-android-arm-eabi": { 882 | "version": "4.5.1", 883 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.5.1.tgz", 884 | "integrity": "sha512-YaN43wTyEBaMqLDYeze+gQ4ZrW5RbTEGtT5o1GVDkhpdNcsLTnLRcLccvwy3E9wiDKWg9RIhuoy3JQKDRBfaZA==", 885 | "dev": true, 886 | "optional": true 887 | }, 888 | "@rollup/rollup-android-arm64": { 889 | "version": "4.5.1", 890 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.5.1.tgz", 891 | "integrity": "sha512-n1bX+LCGlQVuPlCofO0zOKe1b2XkFozAVRoczT+yxWZPGnkEAKTTYVOGZz8N4sKuBnKMxDbfhUsB1uwYdup/sw==", 892 | "dev": true, 893 | "optional": true 894 | }, 895 | "@rollup/rollup-darwin-arm64": { 896 | "version": "4.5.1", 897 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.5.1.tgz", 898 | "integrity": "sha512-QqJBumdvfBqBBmyGHlKxje+iowZwrHna7pokj/Go3dV1PJekSKfmjKrjKQ/e6ESTGhkfPNLq3VXdYLAc+UtAQw==", 899 | "dev": true, 900 | "optional": true 901 | }, 902 | "@rollup/rollup-darwin-x64": { 903 | "version": "4.5.1", 904 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.5.1.tgz", 905 | "integrity": "sha512-RrkDNkR/P5AEQSPkxQPmd2ri8WTjSl0RYmuFOiEABkEY/FSg0a4riihWQGKDJ4LnV9gigWZlTMx2DtFGzUrYQw==", 906 | "dev": true, 907 | "optional": true 908 | }, 909 | "@rollup/rollup-linux-arm-gnueabihf": { 910 | "version": "4.5.1", 911 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.5.1.tgz", 912 | "integrity": "sha512-ZFPxvUZmE+fkB/8D9y/SWl/XaDzNSaxd1TJUSE27XAKlRpQ2VNce/86bGd9mEUgL3qrvjJ9XTGwoX0BrJkYK/A==", 913 | "dev": true, 914 | "optional": true 915 | }, 916 | "@rollup/rollup-linux-arm64-gnu": { 917 | "version": "4.5.1", 918 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.5.1.tgz", 919 | "integrity": "sha512-FEuAjzVIld5WVhu+M2OewLmjmbXWd3q7Zcx+Rwy4QObQCqfblriDMMS7p7+pwgjZoo9BLkP3wa9uglQXzsB9ww==", 920 | "dev": true, 921 | "optional": true 922 | }, 923 | "@rollup/rollup-linux-arm64-musl": { 924 | "version": "4.5.1", 925 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.5.1.tgz", 926 | "integrity": "sha512-f5Gs8WQixqGRtI0Iq/cMqvFYmgFzMinuJO24KRfnv7Ohi/HQclwrBCYkzQu1XfLEEt3DZyvveq9HWo4bLJf1Lw==", 927 | "dev": true, 928 | "optional": true 929 | }, 930 | "@rollup/rollup-linux-x64-gnu": { 931 | "version": "4.5.1", 932 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.5.1.tgz", 933 | "integrity": "sha512-CWPkPGrFfN2vj3mw+S7A/4ZaU3rTV7AkXUr08W9lNP+UzOvKLVf34tWCqrKrfwQ0NTk5GFqUr2XGpeR2p6R4gw==", 934 | "dev": true, 935 | "optional": true 936 | }, 937 | "@rollup/rollup-linux-x64-musl": { 938 | "version": "4.5.1", 939 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.5.1.tgz", 940 | "integrity": "sha512-ZRETMFA0uVukUC9u31Ed1nx++29073goCxZtmZARwk5aF/ltuENaeTtRVsSQzFlzdd4J6L3qUm+EW8cbGt0CKQ==", 941 | "dev": true, 942 | "optional": true 943 | }, 944 | "@rollup/rollup-win32-arm64-msvc": { 945 | "version": "4.5.1", 946 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.5.1.tgz", 947 | "integrity": "sha512-ihqfNJNb2XtoZMSCPeoo0cYMgU04ksyFIoOw5S0JUVbOhafLot+KD82vpKXOurE2+9o/awrqIxku9MRR9hozHQ==", 948 | "dev": true, 949 | "optional": true 950 | }, 951 | "@rollup/rollup-win32-ia32-msvc": { 952 | "version": "4.5.1", 953 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.5.1.tgz", 954 | "integrity": "sha512-zK9MRpC8946lQ9ypFn4gLpdwr5a01aQ/odiIJeL9EbgZDMgbZjjT/XzTqJvDfTmnE1kHdbG20sAeNlpc91/wbg==", 955 | "dev": true, 956 | "optional": true 957 | }, 958 | "@rollup/rollup-win32-x64-msvc": { 959 | "version": "4.5.1", 960 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.5.1.tgz", 961 | "integrity": "sha512-5I3Nz4Sb9TYOtkRwlH0ow+BhMH2vnh38tZ4J4mggE48M/YyJyp/0sPSxhw1UeS1+oBgQ8q7maFtSeKpeRJu41Q==", 962 | "dev": true, 963 | "optional": true 964 | }, 965 | "esbuild": { 966 | "version": "0.19.7", 967 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.7.tgz", 968 | "integrity": "sha512-6brbTZVqxhqgbpqBR5MzErImcpA0SQdoKOkcWK/U30HtQxnokIpG3TX2r0IJqbFUzqLjhU/zC1S5ndgakObVCQ==", 969 | "dev": true, 970 | "requires": { 971 | "@esbuild/android-arm": "0.19.7", 972 | "@esbuild/android-arm64": "0.19.7", 973 | "@esbuild/android-x64": "0.19.7", 974 | "@esbuild/darwin-arm64": "0.19.7", 975 | "@esbuild/darwin-x64": "0.19.7", 976 | "@esbuild/freebsd-arm64": "0.19.7", 977 | "@esbuild/freebsd-x64": "0.19.7", 978 | "@esbuild/linux-arm": "0.19.7", 979 | "@esbuild/linux-arm64": "0.19.7", 980 | "@esbuild/linux-ia32": "0.19.7", 981 | "@esbuild/linux-loong64": "0.19.7", 982 | "@esbuild/linux-mips64el": "0.19.7", 983 | "@esbuild/linux-ppc64": "0.19.7", 984 | "@esbuild/linux-riscv64": "0.19.7", 985 | "@esbuild/linux-s390x": "0.19.7", 986 | "@esbuild/linux-x64": "0.19.7", 987 | "@esbuild/netbsd-x64": "0.19.7", 988 | "@esbuild/openbsd-x64": "0.19.7", 989 | "@esbuild/sunos-x64": "0.19.7", 990 | "@esbuild/win32-arm64": "0.19.7", 991 | "@esbuild/win32-ia32": "0.19.7", 992 | "@esbuild/win32-x64": "0.19.7" 993 | } 994 | }, 995 | "fsevents": { 996 | "version": "2.3.3", 997 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 998 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 999 | "dev": true, 1000 | "optional": true 1001 | }, 1002 | "nanoid": { 1003 | "version": "3.3.7", 1004 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 1005 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 1006 | "dev": true 1007 | }, 1008 | "picocolors": { 1009 | "version": "1.0.0", 1010 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1011 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 1012 | "dev": true 1013 | }, 1014 | "postcss": { 1015 | "version": "8.4.31", 1016 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", 1017 | "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", 1018 | "dev": true, 1019 | "requires": { 1020 | "nanoid": "^3.3.6", 1021 | "picocolors": "^1.0.0", 1022 | "source-map-js": "^1.0.2" 1023 | } 1024 | }, 1025 | "rollup": { 1026 | "version": "4.5.1", 1027 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.5.1.tgz", 1028 | "integrity": "sha512-0EQribZoPKpb5z1NW/QYm3XSR//Xr8BeEXU49Lc/mQmpmVVG5jPUVrpc2iptup/0WMrY9mzas0fxH+TjYvG2CA==", 1029 | "dev": true, 1030 | "requires": { 1031 | "@rollup/rollup-android-arm-eabi": "4.5.1", 1032 | "@rollup/rollup-android-arm64": "4.5.1", 1033 | "@rollup/rollup-darwin-arm64": "4.5.1", 1034 | "@rollup/rollup-darwin-x64": "4.5.1", 1035 | "@rollup/rollup-linux-arm-gnueabihf": "4.5.1", 1036 | "@rollup/rollup-linux-arm64-gnu": "4.5.1", 1037 | "@rollup/rollup-linux-arm64-musl": "4.5.1", 1038 | "@rollup/rollup-linux-x64-gnu": "4.5.1", 1039 | "@rollup/rollup-linux-x64-musl": "4.5.1", 1040 | "@rollup/rollup-win32-arm64-msvc": "4.5.1", 1041 | "@rollup/rollup-win32-ia32-msvc": "4.5.1", 1042 | "@rollup/rollup-win32-x64-msvc": "4.5.1", 1043 | "fsevents": "~2.3.2" 1044 | } 1045 | }, 1046 | "source-map-js": { 1047 | "version": "1.0.2", 1048 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1049 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1050 | "dev": true 1051 | }, 1052 | "three": { 1053 | "version": "0.158.0", 1054 | "resolved": "https://registry.npmjs.org/three/-/three-0.158.0.tgz", 1055 | "integrity": "sha512-TALj4EOpdDPF1henk2Q+s17K61uEAAWQ7TJB68nr7FKxqwyDr3msOt5IWdbGm4TaWKjrtWS8DJJWe9JnvsWOhQ==" 1056 | }, 1057 | "vite": { 1058 | "version": "5.0.2", 1059 | "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.2.tgz", 1060 | "integrity": "sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==", 1061 | "dev": true, 1062 | "requires": { 1063 | "esbuild": "^0.19.3", 1064 | "fsevents": "~2.3.3", 1065 | "postcss": "^8.4.31", 1066 | "rollup": "^4.2.0" 1067 | } 1068 | } 1069 | } 1070 | } 1071 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multi-window", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "vite": "^5.0.0" 13 | }, 14 | "dependencies": { 15 | "three": "^0.158.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /public/coral_fort_wall_02_2k.gltf/coral_fort_wall_02.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akohjesse/mutli-browser-window-threejs/c6f100688f922f4c778514fe0080a7c9a617c7ce/public/coral_fort_wall_02_2k.gltf/coral_fort_wall_02.bin -------------------------------------------------------------------------------- /public/coral_fort_wall_02_2k.gltf/coral_fort_wall_02_2k.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "generator": "Khronos glTF Blender I/O v3.2.43", 4 | "version": "2.0" 5 | }, 6 | "scene": 0, 7 | "scenes": [ 8 | { 9 | "name": "Scene", 10 | "nodes": [ 11 | 0 12 | ] 13 | } 14 | ], 15 | "nodes": [ 16 | { 17 | "mesh": 0, 18 | "name": "sphere_gltf" 19 | } 20 | ], 21 | "materials": [ 22 | { 23 | "doubleSided": true, 24 | "name": "coral_fort_wall_02", 25 | "normalTexture": { 26 | "index": 0 27 | }, 28 | "pbrMetallicRoughness": { 29 | "baseColorTexture": { 30 | "index": 1 31 | }, 32 | "metallicFactor": 0, 33 | "metallicRoughnessTexture": { 34 | "index": 2 35 | } 36 | } 37 | } 38 | ], 39 | "meshes": [ 40 | { 41 | "name": "Sphere.001", 42 | "primitives": [ 43 | { 44 | "attributes": { 45 | "POSITION": 0, 46 | "NORMAL": 1, 47 | "TEXCOORD_0": 2 48 | }, 49 | "indices": 3, 50 | "material": 0 51 | } 52 | ] 53 | } 54 | ], 55 | "textures": [ 56 | { 57 | "sampler": 0, 58 | "source": 0 59 | }, 60 | { 61 | "sampler": 0, 62 | "source": 1 63 | }, 64 | { 65 | "sampler": 0, 66 | "source": 2 67 | } 68 | ], 69 | "images": [ 70 | { 71 | "mimeType": "image/jpeg", 72 | "name": "coral_fort_wall_02_nor_gl_8k", 73 | "uri": "textures/coral_fort_wall_02_nor_gl_2k.jpg" 74 | }, 75 | { 76 | "mimeType": "image/jpeg", 77 | "name": "coral_fort_wall_02_diff_8k", 78 | "uri": "textures/coral_fort_wall_02_diff_2k.jpg" 79 | }, 80 | { 81 | "mimeType": "image/jpeg", 82 | "name": "coral_fort_wall_02_rough_8k", 83 | "uri": "textures/coral_fort_wall_02_rough_2k.jpg" 84 | } 85 | ], 86 | "accessors": [ 87 | { 88 | "bufferView": 0, 89 | "componentType": 5126, 90 | "count": 53886, 91 | "max": [ 92 | 0.5066426992416382, 93 | 0.5039550065994263, 94 | 0.5038047432899475 95 | ], 96 | "min": [ 97 | -0.5066428184509277, 98 | -0.5026815533638, 99 | -0.5038062930107117 100 | ], 101 | "type": "VEC3" 102 | }, 103 | { 104 | "bufferView": 1, 105 | "componentType": 5126, 106 | "count": 53886, 107 | "type": "VEC3" 108 | }, 109 | { 110 | "bufferView": 2, 111 | "componentType": 5126, 112 | "count": 53886, 113 | "type": "VEC2" 114 | }, 115 | { 116 | "bufferView": 3, 117 | "componentType": 5123, 118 | "count": 322170, 119 | "type": "SCALAR" 120 | } 121 | ], 122 | "bufferViews": [ 123 | { 124 | "buffer": 0, 125 | "byteLength": 646632, 126 | "byteOffset": 0 127 | }, 128 | { 129 | "buffer": 0, 130 | "byteLength": 646632, 131 | "byteOffset": 646632 132 | }, 133 | { 134 | "buffer": 0, 135 | "byteLength": 431088, 136 | "byteOffset": 1293264 137 | }, 138 | { 139 | "buffer": 0, 140 | "byteLength": 644340, 141 | "byteOffset": 1724352 142 | } 143 | ], 144 | "samplers": [ 145 | { 146 | "magFilter": 9729, 147 | "minFilter": 9987 148 | } 149 | ], 150 | "buffers": [ 151 | { 152 | "byteLength": 2368692, 153 | "uri": "coral_fort_wall_02.bin" 154 | } 155 | ] 156 | } -------------------------------------------------------------------------------- /public/coral_fort_wall_02_2k.gltf/textures/coral_fort_wall_02_diff_2k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akohjesse/mutli-browser-window-threejs/c6f100688f922f4c778514fe0080a7c9a617c7ce/public/coral_fort_wall_02_2k.gltf/textures/coral_fort_wall_02_diff_2k.jpg -------------------------------------------------------------------------------- /public/coral_fort_wall_02_2k.gltf/textures/coral_fort_wall_02_nor_gl_2k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akohjesse/mutli-browser-window-threejs/c6f100688f922f4c778514fe0080a7c9a617c7ce/public/coral_fort_wall_02_2k.gltf/textures/coral_fort_wall_02_nor_gl_2k.jpg -------------------------------------------------------------------------------- /public/coral_fort_wall_02_2k.gltf/textures/coral_fort_wall_02_rough_2k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akohjesse/mutli-browser-window-threejs/c6f100688f922f4c778514fe0080a7c9a617c7ce/public/coral_fort_wall_02_2k.gltf/textures/coral_fort_wall_02_rough_2k.jpg -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | body { 7 | overflow: hidden; 8 | } 9 | -------------------------------------------------------------------------------- /window.js: -------------------------------------------------------------------------------- 1 | class WindowManager { 2 | #windows; 3 | #count; 4 | #id; 5 | #winData; 6 | #winShapeChangeCallback; 7 | #winChangeCallback; 8 | 9 | constructor() { 10 | let that = this; 11 | addEventListener("storage", (event) => { 12 | if (event.key == "windows") { 13 | let newWindows = JSON.parse(event.newValue); 14 | let winChange = that.#didWindowsChange(that.#windows, newWindows); 15 | 16 | that.#windows = newWindows; 17 | 18 | if (winChange) { 19 | if (that.#winChangeCallback) that.#winChangeCallback(); 20 | } 21 | } 22 | }); 23 | 24 | window.addEventListener("beforeunload", function (e) { 25 | let index = that.getWindowIndexFromId(that.#id); 26 | 27 | that.#windows.splice(index, 1); 28 | that.updateWindowsLocalStorage(); 29 | }); 30 | } 31 | 32 | #didWindowsChange(pWins, nWins) { 33 | if (pWins.length != nWins.length) { 34 | return true; 35 | } else { 36 | let c = false; 37 | 38 | for (let i = 0; i < pWins.length; i++) { 39 | if (pWins[i].id != nWins[i].id) c = true; 40 | } 41 | 42 | return c; 43 | } 44 | } 45 | init(metaData) { 46 | this.#windows = JSON.parse(localStorage.getItem("windows")) || []; 47 | this.#count = localStorage.getItem("count") || 0; 48 | this.#count++; 49 | 50 | this.#id = this.#count; 51 | let shape = this.getWinShape(); 52 | this.#winData = { id: this.#id, shape: shape, metaData: metaData }; 53 | this.#windows.push(this.#winData); 54 | 55 | localStorage.setItem("count", this.#count); 56 | this.updateWindowsLocalStorage(); 57 | } 58 | 59 | getWinShape() { 60 | let shape = { 61 | x: window.screenLeft, 62 | y: window.screenTop, 63 | w: window.innerWidth, 64 | h: window.innerHeight, 65 | }; 66 | return shape; 67 | } 68 | 69 | getWindowIndexFromId(id) { 70 | let index = -1; 71 | 72 | for (let i = 0; i < this.#windows.length; i++) { 73 | if (this.#windows[i].id == id) index = i; 74 | } 75 | 76 | return index; 77 | } 78 | 79 | updateWindowsLocalStorage() { 80 | localStorage.setItem("windows", JSON.stringify(this.#windows)); 81 | } 82 | 83 | update() { 84 | let winShape = this.getWinShape(); 85 | 86 | if ( 87 | winShape.x != this.#winData.shape.x || 88 | winShape.y != this.#winData.shape.y || 89 | winShape.w != this.#winData.shape.w || 90 | winShape.h != this.#winData.shape.h 91 | ) { 92 | this.#winData.shape = winShape; 93 | 94 | let index = this.getWindowIndexFromId(this.#id); 95 | this.#windows[index].shape = winShape; 96 | 97 | if (this.#winShapeChangeCallback) this.#winShapeChangeCallback(); 98 | this.updateWindowsLocalStorage(); 99 | } 100 | } 101 | setWinShapeChangeCallback(callback) { 102 | this.#winShapeChangeCallback = callback; 103 | } 104 | setWinChangeCallback(callback) { 105 | this.#winChangeCallback = callback; 106 | } 107 | getWindows() { 108 | return this.#windows; 109 | } 110 | 111 | getThisWindowData() { 112 | return this.#winData; 113 | } 114 | getThisWindowID() { 115 | return this.#id; 116 | } 117 | } 118 | 119 | export default WindowManager; 120 | --------------------------------------------------------------------------------