diff --git a/package-lock.json b/package-lock.json index 13309eb..988ea19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,14 @@ "name": "startup-claude-retro-console", "version": "0.1.0", "dependencies": { + "@react-three/drei": "^9.122.0", + "@react-three/fiber": "^8.17.10", "dotenv": "^16.4.7", "express": "^4.21.2", "node-pty": "^1.0.0", "socket.io": "^4.8.1", - "strip-ansi": "^7.1.0" + "strip-ansi": "^7.1.0", + "three": "^0.161.0" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.4", @@ -257,6 +260,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", @@ -305,6 +317,12 @@ "node": ">=6.9.0" } }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -797,6 +815,214 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mediapipe/tasks-vision": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", + "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", + "license": "Apache-2.0" + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz", + "integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==", + "license": "MIT", + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" + } + }, + "node_modules/@react-spring/animated": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", + "license": "MIT", + "dependencies": { + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==", + "license": "MIT" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", + "license": "MIT", + "dependencies": { + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/three": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.7.5.tgz", + "integrity": "sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==", + "license": "MIT", + "dependencies": { + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" + }, + "peerDependencies": { + "@react-three/fiber": ">=6.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "three": ">=0.126" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==", + "license": "MIT" + }, + "node_modules/@react-three/drei": { + "version": "9.122.0", + "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-9.122.0.tgz", + "integrity": "sha512-SEO/F/rBCTjlLez7WAlpys+iGe9hty4rNgjZvgkQeXFSiwqD4Hbk/wNHMAbdd8vprO2Aj81mihv4dF5bC7D0CA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mediapipe/tasks-vision": "0.10.17", + "@monogrid/gainmap-js": "^3.0.6", + "@react-spring/three": "~9.7.5", + "@use-gesture/react": "^10.3.1", + "camera-controls": "^2.9.0", + "cross-env": "^7.0.3", + "detect-gpu": "^5.0.56", + "glsl-noise": "^0.0.0", + "hls.js": "^1.5.17", + "maath": "^0.10.8", + "meshline": "^3.3.1", + "react-composer": "^5.0.3", + "stats-gl": "^2.2.8", + "stats.js": "^0.17.0", + "suspend-react": "^0.1.3", + "three-mesh-bvh": "^0.7.8", + "three-stdlib": "^2.35.6", + "troika-three-text": "^0.52.0", + "tunnel-rat": "^0.1.2", + "utility-types": "^3.11.0", + "zustand": "^5.0.1" + }, + "peerDependencies": { + "@react-three/fiber": "^8", + "react": "^18", + "react-dom": "^18", + "three": ">=0.137" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber": { + "version": "8.17.10", + "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.17.10.tgz", + "integrity": "sha512-S6bqa4DqUooEkInYv/W+Jklv2zjSYCXAhm6qKpAQyOXhTEt5gBXnA7W6aoJ0bjmp9pAeaSj/AZUoz1HCSof/uA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8", + "@types/debounce": "^1.2.1", + "@types/react-reconciler": "^0.26.7", + "@types/webxr": "*", + "base64-js": "^1.5.1", + "buffer": "^6.0.3", + "debounce": "^1.2.1", + "its-fine": "^1.0.6", + "react-reconciler": "^0.27.0", + "scheduler": "^0.21.0", + "suspend-react": "^0.1.3", + "zustand": "^3.7.1" + }, + "peerDependencies": { + "expo": ">=43.0", + "expo-asset": ">=8.4", + "expo-file-system": ">=11.0", + "expo-gl": ">=11.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "react-native": ">=0.64", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "expo-asset": { + "optional": true + }, + "expo-file-system": { + "optional": true + }, + "expo-gl": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@react-three/fiber/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@react-three/fiber/node_modules/zustand": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", + "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", + "license": "MIT", + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1160,6 +1386,12 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1214,6 +1446,18 @@ "@types/node": "*" } }, + "node_modules/@types/debounce": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.4.tgz", + "integrity": "sha512-jBqiORIzKDOToaF63Fm//haOCHuwQuLa2202RK4MozpA6lh93eCBc+/8+wZn5OzjJt3ySdc+74SXWXB55Ewtyw==", + "license": "MIT" + }, + "node_modules/@types/draco3d": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", + "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1230,6 +1474,57 @@ "undici-types": "~7.18.0" } }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.3", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", + "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", + "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.183.1", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz", + "integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~1.0.1" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -1239,6 +1534,24 @@ "@types/node": "*" } }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -1260,6 +1573,12 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/@webgpu/types": { + "version": "0.1.69", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", + "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", + "license": "BSD-3-Clause" + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1307,6 +1626,26 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -1329,6 +1668,15 @@ "node": ">=6.0.0" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/body-parser": { "version": "1.20.4", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", @@ -1402,6 +1750,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1440,6 +1812,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/camera-controls": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.10.1.tgz", + "integrity": "sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.126.1" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001779", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001779.tgz", @@ -1634,6 +2015,50 @@ "url": "https://opencollective.com/express" } }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1670,6 +2095,15 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-gpu": { + "version": "5.0.70", + "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz", + "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==", + "license": "MIT", + "dependencies": { + "webgl-constants": "^1.1.1" + } + }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -1682,6 +2116,12 @@ "url": "https://dotenvx.com" } }, + "node_modules/draco3d": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", + "license": "Apache-2.0" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1945,6 +2385,12 @@ } } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/finalhandler": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", @@ -2077,6 +2523,12 @@ "node": ">= 0.4" } }, + "node_modules/glsl-noise": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz", + "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==", + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2123,6 +2575,12 @@ "node": ">= 0.4" } }, + "node_modules/hls.js": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz", + "integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==", + "license": "Apache-2.0" + }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -2155,6 +2613,32 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2180,11 +2664,43 @@ "node": ">=8" } }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/its-fine": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", + "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", + "license": "MIT", + "dependencies": { + "@types/react-reconciler": "^0.28.0" + }, + "peerDependencies": { + "react": ">=18.0" + } + }, + "node_modules/its-fine/node_modules/@types/react-reconciler": { + "version": "0.28.9", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", + "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/jsesc": { @@ -2213,11 +2729,19 @@ "node": ">=6" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -2236,6 +2760,16 @@ "yallist": "^3.0.2" } }, + "node_modules/maath": { + "version": "0.10.8", + "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz", + "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==", + "license": "MIT", + "peerDependencies": { + "@types/three": ">=0.134.0", + "three": ">=0.134.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2263,6 +2797,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/meshline": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz", + "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.137" + } + }, + "node_modules/meshoptimizer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", + "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", + "license": "MIT" + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -2404,6 +2953,15 @@ "node": ">= 0.8" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", @@ -2459,6 +3017,33 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/potpack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", + "license": "ISC" + }, + "node_modules/promise-worker-transferable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz", + "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==", + "license": "Apache-2.0", + "dependencies": { + "is-promise": "^2.1.0", + "lie": "^3.0.2" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2515,7 +3100,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -2524,11 +3108,23 @@ "node": ">=0.10.0" } }, + "node_modules/react-composer": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-composer/-/react-composer-5.0.3.tgz", + "integrity": "sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -2538,6 +3134,37 @@ "react": "^18.3.1" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-reconciler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", + "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.21.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/react-reconciler/node_modules/scheduler": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", + "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -2558,6 +3185,15 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -2643,7 +3279,7 @@ "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -2719,6 +3355,27 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/shell-quote": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", @@ -2871,6 +3528,32 @@ "node": ">=0.10.0" } }, + "node_modules/stats-gl": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz", + "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==", + "license": "MIT", + "dependencies": { + "@types/three": "*", + "three": "^0.170.0" + }, + "peerDependencies": { + "@types/three": "*", + "three": "*" + } + }, + "node_modules/stats-gl/node_modules/three": { + "version": "0.170.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz", + "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==", + "license": "MIT" + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -2949,6 +3632,54 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/suspend-react": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", + "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=17.0" + } + }, + "node_modules/three": { + "version": "0.161.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.161.0.tgz", + "integrity": "sha512-LC28VFtjbOyEu5b93K0bNRLw1rQlMJ85lilKsYj6dgTu+7i17W+JCCEbvrpmNHF1F3NAUqDSWq50UD7w9H2xQw==", + "license": "MIT" + }, + "node_modules/three-mesh-bvh": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.8.tgz", + "integrity": "sha512-BGEZTOIC14U0XIRw3tO4jY7IjP7n7v24nv9JXS1CyeVRWOCkcOMhRnmENUjuV39gktAw4Ofhr0OvIAiTspQrrw==", + "deprecated": "Deprecated due to three.js version incompatibility. Please use v0.8.0, instead.", + "license": "MIT", + "peerDependencies": { + "three": ">= 0.151.0" + } + }, + "node_modules/three-stdlib": { + "version": "2.36.1", + "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.1.tgz", + "integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==", + "license": "MIT", + "dependencies": { + "@types/draco3d": "^1.4.0", + "@types/offscreencanvas": "^2019.6.4", + "@types/webxr": "^0.5.2", + "draco3d": "^1.4.1", + "fflate": "^0.6.9", + "potpack": "^1.0.1" + }, + "peerDependencies": { + "three": ">=0.128.0" + } + }, + "node_modules/three-stdlib/node_modules/fflate": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -2985,6 +3716,36 @@ "tree-kill": "cli.js" } }, + "node_modules/troika-three-text": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz", + "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", + "license": "MIT", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.52.4", + "troika-worker-utils": "^0.52.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-three-utils": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz", + "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", + "license": "MIT", + "peerDependencies": { + "three": ">=0.125.0" + } + }, + "node_modules/troika-worker-utils": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", + "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==", + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -2992,6 +3753,43 @@ "dev": true, "license": "0BSD" }, + "node_modules/tunnel-rat": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", + "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", + "license": "MIT", + "dependencies": { + "zustand": "^4.3.2" + } + }, + "node_modules/tunnel-rat/node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3051,6 +3849,24 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -3144,6 +3960,32 @@ } } }, + "node_modules/webgl-constants": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz", + "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==" + }, + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3260,6 +4102,35 @@ "engines": { "node": ">=12" } + }, + "node_modules/zustand": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz", + "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index db02bdc..659618e 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,14 @@ "start": "NODE_ENV=production node server/index.js" }, "dependencies": { + "@react-three/drei": "^9.122.0", + "@react-three/fiber": "^8.17.10", "dotenv": "^16.4.7", "express": "^4.21.2", "node-pty": "^1.0.0", "socket.io": "^4.8.1", - "strip-ansi": "^7.1.0" + "strip-ansi": "^7.1.0", + "three": "^0.161.0" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.4", diff --git a/web/public/apple-logo.png b/web/public/apple-logo.png new file mode 100644 index 0000000..e36b69c Binary files /dev/null and b/web/public/apple-logo.png differ diff --git a/web/public/mona.png b/web/public/mona.png new file mode 100644 index 0000000..8890a64 Binary files /dev/null and b/web/public/mona.png differ diff --git a/web/public/steve.png b/web/public/steve.png new file mode 100644 index 0000000..8038ca4 Binary files /dev/null and b/web/public/steve.png differ diff --git a/web/src/App.jsx b/web/src/App.jsx index af457fb..1a0fef9 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -7,11 +7,16 @@ import TeamBoard from "./components/TeamBoard.jsx"; import ToastStack from "./components/ToastStack.jsx"; import { useSocket } from "./hooks/useSocket.js"; import { useSession } from "./hooks/useSession.js"; +import { createInitialOfficeAgents } from "./office/officeAgents.js"; +import { parseOfficeCommand } from "./office/officeCommands.js"; +import { getZoneById } from "./office/officeZones.js"; export default function App() { const { socket, connected } = useSocket(); const { session, chat, startSession, clearProject, sendPrompt, selectProject, clearError, toasts, dismissToast } = useSession(socket); const [busy, setBusy] = useState(false); + const [teamView, setTeamView] = useState("board"); + const [officeAgents, setOfficeAgents] = useState(() => createInitialOfficeAgents()); const autoStartedRef = useRef(false); async function runAction(action) { @@ -38,6 +43,45 @@ export default function App() { } }, [connected, session.status]); + function handleOfficeCommand(prompt) { + const command = parseOfficeCommand(prompt); + if (!command) { + return false; + } + + const zone = getZoneById(command.zoneId); + const officeAgent = officeAgents[command.agentId]; + if (!zone || !officeAgent) { + return false; + } + + setOfficeAgents((current) => ({ + ...current, + [command.agentId]: { + ...current[command.agentId], + zoneId: command.zoneId, + targetPosition: zone.approachPosition + } + })); + + return true; + } + + function handleAgentArrive(agentId, position) { + setOfficeAgents((current) => ({ + ...current, + [agentId]: { + ...current[agentId], + currentPosition: position + } + })); + } + + async function handlePromptSubmit(prompt) { + handleOfficeCommand(prompt); + await runAction(() => sendPrompt(prompt)); + } + return (
@@ -60,7 +104,13 @@ export default function App() {
- +
runAction(() => sendPrompt(prompt))} + onSubmit={handlePromptSubmit} />
diff --git a/web/src/components/PixelButton.jsx b/web/src/components/PixelButton.jsx index 11a123d..8d86686 100644 --- a/web/src/components/PixelButton.jsx +++ b/web/src/components/PixelButton.jsx @@ -1,6 +1,6 @@ -export default function PixelButton({ tone = "green", disabled, children, ...props }) { +export default function PixelButton({ tone = "green", disabled, className = "", children, ...props }) { return ( - ); diff --git a/web/src/components/TeamBoard.jsx b/web/src/components/TeamBoard.jsx index 496146a..6e84601 100644 --- a/web/src/components/TeamBoard.jsx +++ b/web/src/components/TeamBoard.jsx @@ -1,6 +1,10 @@ +import { Suspense, lazy } from "react"; import PanelFrame from "./PanelFrame.jsx"; +import PixelButton from "./PixelButton.jsx"; import { parseTeamFeed } from "../lib/teamFeed.js"; +const OfficeCanvas = lazy(() => import("../office/OfficeCanvas.jsx")); + function TeamCard({ member }) { return (
@@ -33,16 +37,52 @@ function TeamCard({ member }) { ); } -export default function TeamBoard({ chat }) { +export default function TeamBoard({ chat, view = "board", onViewChange, officeAgents, onAgentArrive }) { const members = parseTeamFeed(chat); + const isOfficeView = view === "office"; return ( - -
- {members.map((member) => ( - - ))} -
+ + onViewChange?.("board")} + aria-pressed={view === "board"} + > + Board + + + onViewChange?.("office")} + aria-pressed={view === "office"} + > + Office + +
+ } + > + {isOfficeView ? ( +
+ }> + + +
+ ) : ( +
+ {members.map((member) => ( + + ))} +
+ )} ); } diff --git a/web/src/office/OfficeAgent.jsx b/web/src/office/OfficeAgent.jsx new file mode 100644 index 0000000..d1b58c1 --- /dev/null +++ b/web/src/office/OfficeAgent.jsx @@ -0,0 +1,241 @@ +import { useEffect, useRef } from "react"; +import { Html, RoundedBox } from "@react-three/drei"; +import { useFrame } from "@react-three/fiber"; +import { Vector3 } from "three"; + +function nearlyEqual(a, b, epsilon = 0.04) { + return Math.abs(a - b) < epsilon; +} + +function positionsMatch(current, target) { + return nearlyEqual(current[0], target[0]) && nearlyEqual(current[1], target[1]) && nearlyEqual(current[2], target[2]); +} + +function HairStyle({ style, color }) { + if (style === "bob") { + return ( + + + + + + + + + + + + + + + ); + } + + if (style === "swept") { + return ( + + + + + + + + + + + ); + } + + if (style === "sidePart") { + return ( + + + + + + + + + + + ); + } + + if (style === "crew") { + return ( + + + + + ); + } + + return ( + + + + + ); +} + +export default function OfficeAgent({ agent, onArrive }) { + const groupRef = useRef(null); + const lastArrivalKeyRef = useRef(""); + const targetRef = useRef(new Vector3(...agent.targetPosition)); + const appearance = { + skinColor: "#f0c6a9", + hairColor: "#171717", + hairStyle: "short", + shirtColor: "#fbfbf4", + tieColor: null, + lowerColor: "#6d7078", + shoeColor: "#111111", + lowerType: "pants", + ...agent.appearance + }; + + const isSkirt = appearance.lowerType === "skirt"; + const isShorts = appearance.lowerType === "shorts"; + + useEffect(() => { + if (!groupRef.current) { + return; + } + + groupRef.current.position.set(...agent.currentPosition); + }, [agent.currentPosition]); + + useEffect(() => { + targetRef.current.set(...agent.targetPosition); + }, [agent.targetPosition]); + + useFrame((_, delta) => { + if (!groupRef.current) { + return; + } + + const speed = Math.min(1, delta * 2.4); + groupRef.current.position.lerp(targetRef.current, speed); + + const current = [ + groupRef.current.position.x, + groupRef.current.position.y, + groupRef.current.position.z + ]; + + const arrivalKey = `${agent.id}:${agent.targetPosition.join(",")}`; + if (positionsMatch(current, agent.targetPosition) && lastArrivalKeyRef.current !== arrivalKey) { + lastArrivalKeyRef.current = arrivalKey; + onArrive?.(agent.id, agent.targetPosition); + } + }); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {appearance.tieColor ? ( + + + + + ) : null} + + + + + + + + + + + + + + + + + {isSkirt ? ( + + + + + ) : ( + + + + + )} + + + + + + + + + + + + + + + + + {isShorts ? ( + <> + + + + + + + + + + ) : null} + + + + + + + + + +
{agent.name}
+ +
+ ); +} diff --git a/web/src/office/OfficeCamera.jsx b/web/src/office/OfficeCamera.jsx new file mode 100644 index 0000000..45da287 --- /dev/null +++ b/web/src/office/OfficeCamera.jsx @@ -0,0 +1,18 @@ +import { OrbitControls } from "@react-three/drei"; + +export default function OfficeCamera() { + return ( + + ); +} diff --git a/web/src/office/OfficeCanvas.jsx b/web/src/office/OfficeCanvas.jsx new file mode 100644 index 0000000..c7bb34d --- /dev/null +++ b/web/src/office/OfficeCanvas.jsx @@ -0,0 +1,12 @@ +import { Canvas } from "@react-three/fiber"; +import OfficeScene from "./OfficeScene.jsx"; + +export default function OfficeCanvas({ debug = false, agents = {}, onAgentArrive }) { + return ( +
+ + + +
+ ); +} diff --git a/web/src/office/OfficeDebugLabels.jsx b/web/src/office/OfficeDebugLabels.jsx new file mode 100644 index 0000000..5233f7f --- /dev/null +++ b/web/src/office/OfficeDebugLabels.jsx @@ -0,0 +1,16 @@ +import { Html } from "@react-three/drei"; + +export default function OfficeDebugLabels({ zones = [] }) { + return ( + + {zones.map((zone) => ( + +
+ {zone.label} + {zone.id} +
+ + ))} +
+ ); +} diff --git a/web/src/office/OfficeFloor.jsx b/web/src/office/OfficeFloor.jsx new file mode 100644 index 0000000..24250cb --- /dev/null +++ b/web/src/office/OfficeFloor.jsx @@ -0,0 +1,8 @@ +export default function OfficeFloor() { + return ( + + + + + ); +} diff --git a/web/src/office/OfficeLayout.jsx b/web/src/office/OfficeLayout.jsx new file mode 100644 index 0000000..1da0726 --- /dev/null +++ b/web/src/office/OfficeLayout.jsx @@ -0,0 +1,76 @@ +import { useLoader } from "@react-three/fiber"; +import { TextureLoader } from "three"; +import Desk from "./primitives/Desk.jsx"; +import MeetingTable from "./primitives/MeetingTable.jsx"; +import CoffeeMachine from "./primitives/CoffeeMachine.jsx"; +import { OFFICE_ZONES } from "./officeZones.js"; + +function AccentWallPanels() { + const steveTexture = useLoader(TextureLoader, "/steve.png"); + const monaTexture = useLoader(TextureLoader, "/mona.png"); + const panels = [ + { position: [-8.2, 1.8, -8.78], color: "#495b8a" }, + { position: [0, 2.15, -8.76], color: "#6b4c78" }, + { position: [7.4, 1.8, -8.78], color: "#495b8a" } + ]; + + return ( + + + + + + + + + + {[panels[2]].map((panel, index) => ( + + + + + ))} + + ); +} + +function FloorDecals() { + return ( + + + + + + + + + + + ); +} + +export default function OfficeLayout() { + return ( + + + + + + + + + + + + ); +} diff --git a/web/src/office/OfficeLighting.jsx b/web/src/office/OfficeLighting.jsx new file mode 100644 index 0000000..2d8cbb5 --- /dev/null +++ b/web/src/office/OfficeLighting.jsx @@ -0,0 +1,21 @@ +export default function OfficeLighting() { + return ( + <> + + + + + ); +} diff --git a/web/src/office/OfficeScene.jsx b/web/src/office/OfficeScene.jsx new file mode 100644 index 0000000..d15316c --- /dev/null +++ b/web/src/office/OfficeScene.jsx @@ -0,0 +1,26 @@ +import OfficeCamera from "./OfficeCamera.jsx"; +import OfficeLighting from "./OfficeLighting.jsx"; +import OfficeFloor from "./OfficeFloor.jsx"; +import OfficeWalls from "./OfficeWalls.jsx"; +import OfficeLayout from "./OfficeLayout.jsx"; +import OfficeDebugLabels from "./OfficeDebugLabels.jsx"; +import OfficeAgent from "./OfficeAgent.jsx"; +import { OFFICE_ZONES } from "./officeZones.js"; + +export default function OfficeScene({ debug = false, agents = {}, onAgentArrive }) { + return ( + <> + + + + + + + {Object.values(agents).map((agent) => ( + + ))} + + {debug ? : null} + + ); +} diff --git a/web/src/office/OfficeWalls.jsx b/web/src/office/OfficeWalls.jsx new file mode 100644 index 0000000..f2a7100 --- /dev/null +++ b/web/src/office/OfficeWalls.jsx @@ -0,0 +1,19 @@ +function Wall({ position, args }) { + return ( + + + + + ); +} + +export default function OfficeWalls() { + return ( + + + + + + + ); +} diff --git a/web/src/office/officeAgents.js b/web/src/office/officeAgents.js new file mode 100644 index 0000000..f1b7975 --- /dev/null +++ b/web/src/office/officeAgents.js @@ -0,0 +1,113 @@ +import { getZoneById } from "./officeZones.js"; + +function createAgent({ + id, + name, + role, + zoneId, + color, + appearance +}) { + const zone = getZoneById(zoneId); + + return { + id, + name, + role, + color, + zoneId, + currentPosition: zone?.approachPosition ?? [0, 0, 0], + targetPosition: zone?.approachPosition ?? [0, 0, 0], + appearance + }; +} + +export function createInitialOfficeAgents() { + return { + teamLead: createAgent({ + id: "teamLead", + name: "Mazlum", + role: "Team Lead", + zoneId: "teamLeadDesk", + color: "#e0c15c", + appearance: { + skinColor: "#f0c6a9", + hairColor: "#171717", + hairStyle: "short", + shirtColor: "#fbfbf4", + tieColor: "#ba1d2f", + lowerColor: "#75777d", + shoeColor: "#111111", + lowerType: "shorts" + } + }), + frontend: createAgent({ + id: "frontend", + name: "Berkecan", + role: "Frontend Developer", + zoneId: "frontendDesk", + color: "#49c2f1", + appearance: { + skinColor: "#e8c09b", + hairColor: "#3e2415", + hairStyle: "swept", + shirtColor: "#3d79d8", + tieColor: null, + lowerColor: "#d7c8a4", + shoeColor: "#3b2d25", + lowerType: "pants" + } + }), + backend: createAgent({ + id: "backend", + name: "Simsar", + role: "Backend Developer", + zoneId: "backendDesk", + color: "#7bd87a", + appearance: { + skinColor: "#dcb28f", + hairColor: "#2a2a2a", + hairStyle: "crew", + shirtColor: "#2f6b48", + tieColor: null, + lowerColor: "#42464f", + shoeColor: "#141414", + lowerType: "pants" + } + }), + uiux: createAgent({ + id: "uiux", + name: "Aybuke", + role: "UI/UX Designer", + zoneId: "uiuxDesk", + color: "#f48cc7", + appearance: { + skinColor: "#efc4aa", + hairColor: "#6b3f30", + hairStyle: "bob", + shirtColor: "#d8a0cf", + tieColor: null, + lowerColor: "#564760", + shoeColor: "#2f2430", + lowerType: "skirt" + } + }), + ios: createAgent({ + id: "ios", + name: "Ive", + role: "iOS Developer", + zoneId: "iosDesk", + color: "#8aa4ff", + appearance: { + skinColor: "#e6bc97", + hairColor: "#7b4d22", + hairStyle: "sidePart", + shirtColor: "#d4b258", + tieColor: null, + lowerColor: "#5a77ae", + shoeColor: "#171717", + lowerType: "pants" + } + }) + }; +} diff --git a/web/src/office/officeCommands.js b/web/src/office/officeCommands.js new file mode 100644 index 0000000..091a55a --- /dev/null +++ b/web/src/office/officeCommands.js @@ -0,0 +1,50 @@ +const AGENT_ALIASES = { + teamLead: ["team lead", "lead", "mazlum", "mazlum bey"], + frontend: ["frontend", "frontend developer", "berkecan"], + backend: ["backend", "backend developer", "simsar"], + uiux: ["ui ux", "ui/ux", "designer", "ui ux designer", "aybuke", "aybuke hanim", "aybüke", "aybüke hanım"], + ios: ["ios", "ios developer", "ive", "i os"] +}; + +const ZONE_ALIASES = { + teamLeadDesk: ["team lead desk", "lead desk", "mazlum desk", "team lead masasi", "mazlum masasi"], + frontendDesk: ["frontend desk", "frontend masasi", "berkecan masasi"], + backendDesk: ["backend desk", "backend masasi", "simsar masasi"], + uiuxDesk: ["ui ux desk", "ui/ux desk", "designer desk", "aybuke masasi", "aybüke masası", "ui ux masasi"], + iosDesk: ["ios desk", "ios masasi", "ive masasi", "i os masasi"], + meetingTable: ["meeting table", "toplanti masasi", "toplanti masasi", "meeting room", "toplanti"], + coffeeMachine: ["coffee machine", "kahve makinesi", "kahve alani", "kahve makinasi"] +}; + +function normalizeText(value) { + return String(value ?? "") + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .toLowerCase() + .trim(); +} + +function findMatch(normalizedText, map) { + return Object.entries(map).find(([, aliases]) => aliases.some((alias) => normalizedText.includes(alias)))?.[0] ?? null; +} + +export function parseOfficeCommand(prompt) { + const normalized = normalizeText(prompt); + + if (!/\b(git|gidebilir|gitsin|gidin|toplan|yuru|yurusun|gitmesi)\b/.test(normalized)) { + return null; + } + + const agentId = findMatch(normalized, AGENT_ALIASES); + const zoneId = findMatch(normalized, ZONE_ALIASES); + + if (!agentId || !zoneId) { + return null; + } + + return { + type: "move", + agentId, + zoneId + }; +} diff --git a/web/src/office/officeSceneData.js b/web/src/office/officeSceneData.js new file mode 100644 index 0000000..0b18a61 --- /dev/null +++ b/web/src/office/officeSceneData.js @@ -0,0 +1,13 @@ +export const officeBadges = [ + { id: "lead", label: "Mazlum Bey", tone: "amber" }, + { id: "frontend", label: "Frontend Kanka", tone: "cyan" }, + { id: "backend", label: "Backend Kanka", tone: "green" }, + { id: "ios", label: "iOS Kanka", tone: "cyan" }, + { id: "ui", label: "UI Hanim", tone: "amber" } +]; + +export const officeNotes = [ + "Patron icin hizli briefing hazir.", + "3D sahne: masa, ekranlar, duvar notlari, neon akis.", + "Office modu sadece gorunum degistirir; veri akisi ayni kalir." +]; diff --git a/web/src/office/officeStations.js b/web/src/office/officeStations.js new file mode 100644 index 0000000..91c675d --- /dev/null +++ b/web/src/office/officeStations.js @@ -0,0 +1,8 @@ +export const OFFICE_STATIONS = [ + { id: "mazlum", name: "Mazlum Bey", role: "Team Lead", debug: "BRIEFING NODE", x: 548, y: 196, tone: "amber" }, + { id: "berkecan", name: "Berkecan", role: "Frontend", debug: "UI BENCH", x: 264, y: 392, tone: "cyan" }, + { id: "simsar", name: "Simsar", role: "Backend", debug: "API BENCH", x: 820, y: 388, tone: "green" }, + { id: "aybuke", name: "UI Hanim", role: "Design Wall", debug: "UX BOARD", x: 250, y: 190, tone: "amber" }, + { id: "ive", name: "Ive", role: "iOS Bay", debug: "MOBILE RACK", x: 842, y: 178, tone: "cyan" }, + { id: "irgatov", name: "Irgatov", role: "Coffee Station", debug: "SERVICE DESK", x: 548, y: 562, tone: "red" } +]; diff --git a/web/src/office/officeZones.js b/web/src/office/officeZones.js new file mode 100644 index 0000000..e70c170 --- /dev/null +++ b/web/src/office/officeZones.js @@ -0,0 +1,62 @@ +export const OFFICE_ZONES = [ + { + id: "teamLeadDesk", + label: "Team Lead Desk", + role: "Team Lead", + type: "desk", + position: [0, 0, -4.2], + approachPosition: [0, 0, -2.9] + }, + { + id: "frontendDesk", + label: "Frontend Desk", + role: "Frontend Dev", + type: "desk", + position: [-3.8, 0, -0.9], + approachPosition: [-2.7, 0, 0.3] + }, + { + id: "backendDesk", + label: "Backend Desk", + role: "Backend Dev", + type: "desk", + position: [3.8, 0, -0.9], + approachPosition: [2.7, 0, 0.3] + }, + { + id: "uiuxDesk", + label: "UI/UX Desk", + role: "UI/UX Designer", + type: "desk", + position: [-3.8, 0, 2.9], + approachPosition: [-2.7, 0, 1.8] + }, + { + id: "iosDesk", + label: "iOS Desk", + role: "iOS Dev", + type: "desk", + position: [3.8, 0, 2.9], + approachPosition: [2.7, 0, 1.8] + }, + { + id: "meetingTable", + label: "Meeting Table", + role: "Meeting", + type: "meeting", + position: [6.4, 0, -4], + approachPosition: [5, 0, -3.9] + }, + { + id: "coffeeMachine", + label: "Coffee Machine", + role: "Utility", + type: "utility", + position: [6.8, 0, 4], + approachPosition: [5.7, 0, 4] + } +]; + +export function getZoneById(id) { + return OFFICE_ZONES.find((zone) => zone.id === id) ?? null; +} diff --git a/web/src/office/primitives/Chair.jsx b/web/src/office/primitives/Chair.jsx new file mode 100644 index 0000000..c1865e8 --- /dev/null +++ b/web/src/office/primitives/Chair.jsx @@ -0,0 +1,22 @@ +export default function Chair({ position = [0, 0, 0], rotation = [0, 0, 0] }) { + return ( + + + + + + + + + + + + + + + + + + + ); +} diff --git a/web/src/office/primitives/CoffeeMachine.jsx b/web/src/office/primitives/CoffeeMachine.jsx new file mode 100644 index 0000000..fce5256 --- /dev/null +++ b/web/src/office/primitives/CoffeeMachine.jsx @@ -0,0 +1,143 @@ +function Cup({ position = [0, 0, 0], scale = 1, sleeve = false }) { + return ( + + + + + + + + + + {sleeve ? ( + + + + + ) : null} + + + + + + ); +} + +function TopCups() { + const topCupPositions = [ + [-0.38, 1.55, -0.14], + [-0.16, 1.55, -0.14], + [0.06, 1.55, -0.14], + [0.28, 1.55, -0.14], + [-0.27, 1.55, 0.06], + [-0.05, 1.55, 0.06], + [0.17, 1.55, 0.06] + ]; + + return topCupPositions.map((position, index) => ( + + )); +} + +function FrontCups() { + return ( + + + + + + + + + + + + + + ); +} + +export default function CoffeeMachine({ position = [0, 0, 0] }) { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/web/src/office/primitives/Desk.jsx b/web/src/office/primitives/Desk.jsx new file mode 100644 index 0000000..0798158 --- /dev/null +++ b/web/src/office/primitives/Desk.jsx @@ -0,0 +1,57 @@ +import { useLoader } from "@react-three/fiber"; +import { TextureLoader } from "three"; +import { DoubleSide } from "three"; +import Chair from "./Chair.jsx"; + +export default function Desk({ position = [0, 0, 0], nameplateColor = "#52b6ff" }) { + const appleLogoTexture = useLoader(TextureLoader, "/apple-logo.png"); + + return ( + + + + + + {[ + [-0.78, 0.38, -0.43], + [0.78, 0.38, -0.43], + [-0.78, 0.38, 0.43], + [0.78, 0.38, 0.43] + ].map((leg, index) => ( + + + + + ))} + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/web/src/office/primitives/MeetingTable.jsx b/web/src/office/primitives/MeetingTable.jsx new file mode 100644 index 0000000..e09b1ca --- /dev/null +++ b/web/src/office/primitives/MeetingTable.jsx @@ -0,0 +1,14 @@ +export default function MeetingTable({ position = [0, 0, 0] }) { + return ( + + + + + + + + + + + ); +} diff --git a/web/src/styles/app.css b/web/src/styles/app.css index 62eabaf..3f1ffd6 100644 --- a/web/src/styles/app.css +++ b/web/src/styles/app.css @@ -367,6 +367,602 @@ align-items: start; } +.team-board__tabs { + display: inline-flex; + gap: 6px; + align-items: center; +} + +.team-board__tab { + min-width: 84px; +} + +.team-board__tab span { + padding: 8px 10px; + font-size: 0.58rem; + letter-spacing: 0.12em; +} + +.team-board__tab.is-active span { + color: var(--text-main); +} + +.team-board__divider { + color: var(--accent-amber); + font-family: var(--font-display); + font-size: 0.7rem; + opacity: 0.7; +} + +.team-board__office { + min-height: 1006px; + border: 0; + background: #000; + box-shadow: none; + overflow: hidden; +} + +.team-board-panel--office .panel-frame__body { + padding: 0; +} + +.team-board-panel--office .team-board__office { + min-height: 1006px; + background: #000; +} + +.team-board__office-fallback, +.office-canvas { + width: 100%; + height: 1006px; +} + +.team-board__office-fallback { + background: #000; +} + +.office-debug-label { + display: grid; + gap: 4px; + min-width: 140px; + padding: 8px 10px; + border: 1px solid rgba(99, 245, 255, 0.55); + background: rgba(6, 11, 8, 0.9); + color: var(--text-main); + font-family: var(--font-display); + font-size: 0.5rem; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.office-debug-label code { + color: var(--accent-cyan); + font-family: var(--font-body); + font-size: 0.64rem; + letter-spacing: 0; + text-transform: none; +} + +.office-agent__label { + padding: 6px 10px; + border: 1px solid rgba(99, 245, 255, 0.45); + background: rgba(6, 11, 8, 0.92); + color: var(--text-main); + font-family: var(--font-display); + font-size: 0.58rem; + letter-spacing: 0.1em; + text-transform: uppercase; + white-space: nowrap; +} + +.office-scene__svg { + display: block; + width: 100%; + height: 1006px; + min-height: 1006px; +} + +.office-scene__station { + shape-rendering: geometricPrecision; +} + +.office-scene__station-shadow { + fill: rgba(0, 0, 0, 0.48); +} + +.office-scene__station-top, +.office-scene__station-left, +.office-scene__station-right, +.office-scene__station-monitor, +.office-scene__station-stand, +.office-scene__station-plaque { + stroke: rgba(70, 121, 84, 0.34); + stroke-width: 1.2; +} + +.office-scene__station--amber .office-scene__station-top, +.office-scene__station--amber .office-scene__station-left, +.office-scene__station--amber .office-scene__station-right, +.office-scene__station--amber .office-scene__station-monitor, +.office-scene__station--amber .office-scene__station-plaque { + fill: rgba(28, 19, 7, 0.96); +} + +.office-scene__station--cyan .office-scene__station-top, +.office-scene__station--cyan .office-scene__station-left, +.office-scene__station--cyan .office-scene__station-right, +.office-scene__station--cyan .office-scene__station-monitor, +.office-scene__station--cyan .office-scene__station-plaque { + fill: rgba(8, 19, 22, 0.96); +} + +.office-scene__station--green .office-scene__station-top, +.office-scene__station--green .office-scene__station-left, +.office-scene__station--green .office-scene__station-right, +.office-scene__station--green .office-scene__station-monitor, +.office-scene__station--green .office-scene__station-plaque { + fill: rgba(8, 20, 12, 0.96); +} + +.office-scene__station--red .office-scene__station-top, +.office-scene__station--red .office-scene__station-left, +.office-scene__station--red .office-scene__station-right, +.office-scene__station--red .office-scene__station-monitor, +.office-scene__station--red .office-scene__station-plaque { + fill: rgba(25, 10, 10, 0.96); +} + +.office-scene__station-stand { + fill: rgba(20, 28, 21, 0.98); +} + +.office-scene__station-debug, +.office-scene__station-name, +.office-scene__station-role, +.office-scene__hud-text { + font-family: var(--font-display); + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.office-scene__station-debug { + fill: var(--accent-amber); + font-size: 12px; + opacity: 0.88; +} + +.office-scene__station-name { + fill: var(--text-main); + font-size: 18px; +} + +.office-scene__station-role { + fill: var(--text-dim); + font-size: 11px; +} + +.office-scene__hud-text { + font-size: 13px; +} + +.office-scene__hud-text--amber { + fill: var(--accent-amber); +} + +.office-scene__hud-text--cyan { + fill: var(--accent-cyan); +} + +.office-scene__hud-text--green { + fill: var(--accent-green); +} + +.office-scene__desk-shadow { + fill: rgba(0, 0, 0, 0.42); +} + +.office-scene__desk-top { + fill: url(#desk-top); + stroke: rgba(99, 245, 255, 0.18); + stroke-width: 1.5; +} + +.office-scene__desk-left, +.office-scene__desk-right { + stroke: rgba(70, 121, 84, 0.22); + stroke-width: 1.1; +} + +.office-scene__monitor { + fill: rgba(5, 16, 12, 0.98); + stroke: rgba(99, 245, 255, 0.28); + stroke-width: 1.8; +} + +.office-scene__monitor-glare { + fill: rgba(99, 245, 255, 0.12); +} + +.office-scene__keyboard { + fill: rgba(18, 24, 19, 0.98); + stroke: rgba(99, 245, 255, 0.14); + stroke-width: 1; +} + +.office-scene__mug { + fill: rgba(132, 95, 37, 0.98); + stroke: rgba(255, 179, 71, 0.35); + stroke-width: 1.2; +} + +.office-scene { + position: relative; + min-height: 1006px; + height: 100%; + overflow: hidden; + background: + radial-gradient(circle at 50% 42%, rgba(31, 61, 39, 0.18), transparent 34%), + radial-gradient(circle at 50% 110%, rgba(0, 0, 0, 0.92), rgba(0, 0, 0, 1) 58%); +} + +.office-scene__ambient { + position: absolute; + inset: 0; + pointer-events: none; + filter: blur(12px); + opacity: 0.65; +} + +.office-scene__ambient--left { + background: radial-gradient(circle at 20% 35%, rgba(99, 245, 255, 0.18), transparent 28%); +} + +.office-scene__ambient--right { + background: radial-gradient(circle at 80% 30%, rgba(255, 179, 71, 0.16), transparent 30%); +} + +.office-scene__viewport { + position: absolute; + inset: 0; + display: grid; + place-items: center; + perspective: 1600px; +} + +.office-scene__room { + position: relative; + width: min(1020px, 100%); + height: 100%; + min-height: 1006px; + transform-style: preserve-3d; + transform: rotateX(66deg) rotateZ(-11deg) translate3d(0, 26px, 0); + animation: office-room-float 14s ease-in-out infinite alternate; +} + +.office-scene__wall, +.office-scene__floor, +.office-scene__ceiling, +.office-scene__window, +.office-scene__board, +.office-scene__plant, +.office-scene__desk, +.office-scene__monitor, +.office-scene__chair, +.office-scene__mug, +.office-scene__lamp { + position: absolute; + transform-style: preserve-3d; +} + +.office-scene__wall { + inset: 0; + border: 1px solid rgba(114, 255, 132, 0.08); + background: linear-gradient(180deg, rgba(4, 7, 5, 0.96), rgba(0, 0, 0, 0.98)); +} + +.office-scene__wall--back { + inset: 8% 9% 42% 9%; + transform: translateZ(-280px); + background: + linear-gradient(180deg, rgba(9, 19, 11, 0.96), rgba(4, 7, 5, 0.98)), + radial-gradient(circle at center, rgba(114, 255, 132, 0.16), transparent 62%); +} + +.office-scene__wall--left { + inset: 8% auto 14% 0; + width: 16%; + transform-origin: left center; + transform: rotateY(88deg) translateZ(-220px); + background: linear-gradient(180deg, rgba(7, 13, 9, 0.98), rgba(3, 5, 4, 0.98)); +} + +.office-scene__wall--right { + inset: 8% 0 14% auto; + width: 16%; + transform-origin: right center; + transform: rotateY(-88deg) translateZ(-220px); + background: linear-gradient(180deg, rgba(8, 15, 10, 0.98), rgba(2, 4, 3, 0.98)); +} + +.office-scene__ceiling { + inset: 8% 10% auto 10%; + height: 8%; + transform: translateZ(-260px); + background: linear-gradient(180deg, rgba(28, 44, 31, 0.3), rgba(5, 8, 6, 0)); +} + +.office-scene__floor { + inset: 48% 8% 6% 8%; + transform: translateZ(-120px); + background: + linear-gradient(180deg, rgba(8, 10, 9, 0.78), rgba(1, 2, 1, 0.98)), + repeating-linear-gradient(90deg, rgba(99, 245, 255, 0.05) 0 1px, transparent 1px 72px), + repeating-linear-gradient(0deg, rgba(70, 121, 84, 0.06) 0 1px, transparent 1px 72px); + box-shadow: inset 0 0 120px rgba(0, 0, 0, 0.82); +} + +.office-scene__window { + top: 18%; + width: 20%; + height: 18%; + border: 1px solid rgba(99, 245, 255, 0.16); + background: + linear-gradient(180deg, rgba(12, 34, 42, 0.45), rgba(2, 5, 8, 0.9)), + repeating-linear-gradient(90deg, rgba(99, 245, 255, 0.14) 0 2px, transparent 2px 18px); + box-shadow: inset 0 0 22px rgba(99, 245, 255, 0.12); +} + +.office-scene__window--left { + left: 8%; + transform: translateZ(-160px) rotateY(16deg); +} + +.office-scene__window--right { + right: 8%; + transform: translateZ(-160px) rotateY(-16deg); +} + +.office-scene__board { + left: 50%; + top: 15%; + width: 28%; + height: 13%; + transform: translateX(-50%) translateZ(-150px); + border: 2px solid rgba(255, 179, 71, 0.22); + background: + linear-gradient(180deg, rgba(19, 13, 6, 0.9), rgba(7, 5, 3, 0.96)), + repeating-linear-gradient(0deg, rgba(255, 179, 71, 0.08) 0 1px, transparent 1px 18px); + box-shadow: inset 0 0 30px rgba(255, 179, 71, 0.08); +} + +.office-scene__plant { + left: 12%; + bottom: 18%; + width: 8%; + height: 16%; + transform: translateZ(-40px); + background: + radial-gradient(circle at 50% 16%, rgba(70, 121, 84, 0.92), transparent 22%), + radial-gradient(circle at 30% 38%, rgba(70, 121, 84, 0.9), transparent 18%), + radial-gradient(circle at 70% 38%, rgba(70, 121, 84, 0.9), transparent 18%), + linear-gradient(180deg, rgba(28, 18, 12, 0.95), rgba(10, 8, 6, 0.98)); + clip-path: polygon(34% 0, 66% 0, 76% 22%, 58% 32%, 72% 48%, 52% 58%, 62% 80%, 44% 100%, 28% 80%, 38% 58%, 18% 48%, 32% 32%, 14% 22%); + filter: drop-shadow(0 0 12px rgba(70, 121, 84, 0.25)); +} + +.office-scene__desk { + left: 50%; + bottom: 13%; + width: 60%; + height: 28%; + transform: translateX(-50%) translateZ(120px); +} + +.office-scene__desk-top { + position: absolute; + inset: 0 0 38% 0; + border: 1px solid rgba(99, 245, 255, 0.18); + background: linear-gradient(180deg, rgba(34, 52, 39, 0.96), rgba(16, 24, 18, 0.98)); + transform: perspective(900px) rotateX(68deg); + transform-origin: center bottom; + box-shadow: + inset 0 0 24px rgba(0, 0, 0, 0.4), + 0 18px 42px rgba(0, 0, 0, 0.4); +} + +.office-scene__desk-front { + position: absolute; + left: 6%; + right: 6%; + bottom: 0; + height: 44%; + border: 1px solid rgba(70, 121, 84, 0.3); + background: linear-gradient(180deg, rgba(20, 31, 22, 0.98), rgba(7, 10, 8, 0.98)); + transform: perspective(900px) rotateX(18deg); + transform-origin: center top; +} + +.office-scene__monitor { + top: 14%; + width: 16%; + height: 24%; + border: 2px solid rgba(99, 245, 255, 0.22); + background: + radial-gradient(circle at 50% 30%, rgba(99, 245, 255, 0.18), transparent 56%), + linear-gradient(180deg, rgba(8, 21, 18, 0.98), rgba(4, 7, 6, 0.98)); + box-shadow: + inset 0 0 18px rgba(99, 245, 255, 0.08), + 0 16px 24px rgba(0, 0, 0, 0.45); + animation: office-glow 5s ease-in-out infinite alternate; +} + +.office-scene__monitor span { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + color: var(--text-main); + font-family: var(--font-display); + font-size: 0.48rem; + letter-spacing: 0.16em; + text-transform: uppercase; + white-space: nowrap; +} + +.office-scene__monitor--left { + left: 10%; + transform: perspective(900px) rotateY(24deg); +} + +.office-scene__monitor--center { + left: 50%; + width: 20%; + height: 28%; + transform: translateX(-50%); +} + +.office-scene__monitor--right { + right: 10%; + transform: perspective(900px) rotateY(-24deg); +} + +.office-scene__chair { + bottom: 10%; + width: 12%; + height: 18%; + border: 1px solid rgba(114, 255, 132, 0.18); + background: + linear-gradient(180deg, rgba(15, 25, 17, 0.94), rgba(6, 10, 7, 0.98)); + clip-path: polygon(36% 0, 64% 0, 72% 18%, 72% 46%, 88% 70%, 80% 100%, 20% 100%, 12% 70%, 28% 46%, 28% 18%); + opacity: 0.86; +} + +.office-scene__chair--left { + left: 18%; + transform: perspective(900px) rotateY(12deg) rotateZ(-8deg); +} + +.office-scene__chair--right { + right: 18%; + transform: perspective(900px) rotateY(-12deg) rotateZ(8deg); +} + +.office-scene__mug { + right: 18%; + bottom: 30%; + width: 4.5%; + height: 7%; + border: 1px solid rgba(255, 179, 71, 0.28); + border-radius: 0 0 10px 10px; + background: linear-gradient(180deg, rgba(56, 38, 14, 0.98), rgba(24, 16, 6, 0.98)); + transform: translateZ(20px); + box-shadow: 0 0 18px rgba(255, 179, 71, 0.12); +} + +.office-scene__lamp { + left: 50%; + bottom: 43%; + width: 11%; + height: 12%; + transform: translateX(-50%) translateZ(140px); + background: + radial-gradient(circle at 50% 0%, rgba(255, 179, 71, 0.46), transparent 42%), + linear-gradient(180deg, rgba(255, 179, 71, 0.28), rgba(0, 0, 0, 0)); + filter: blur(0.4px); +} + +.office-scene__hud { + position: absolute; + inset: 16px 18px auto 18px; + display: grid; + gap: 8px; + pointer-events: none; +} + +.office-scene__title { + display: inline-flex; + align-self: start; + width: fit-content; + padding: 6px 10px; + border: 1px solid rgba(99, 245, 255, 0.24); + background: rgba(5, 9, 7, 0.72); + color: var(--accent-cyan); + font-family: var(--font-display); + font-size: 0.58rem; + letter-spacing: 0.18em; + text-transform: uppercase; +} + +.office-scene__notes { + display: grid; + gap: 4px; + max-width: 34ch; + padding: 10px 12px; + border: 1px solid rgba(70, 121, 84, 0.24); + background: rgba(4, 8, 5, 0.7); + color: var(--text-dim); + font-size: 0.64rem; + line-height: 1.5; +} + +.office-scene__notes p { + margin: 0; +} + +.office-scene__badges { + position: absolute; + right: 0; + top: 0; + display: grid; + gap: 8px; +} + +.office-scene__label { + width: fit-content; + padding: 6px 10px; + border: 1px solid rgba(70, 121, 84, 0.3); + background: rgba(0, 0, 0, 0.5); + font-family: var(--font-display); + font-size: 0.54rem; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.office-scene__label--amber { + color: var(--accent-amber); + border-color: rgba(255, 179, 71, 0.28); +} + +.office-scene__label--cyan { + color: var(--accent-cyan); + border-color: rgba(99, 245, 255, 0.28); +} + +.office-scene__label--green { + color: var(--accent-green); + border-color: rgba(114, 255, 132, 0.28); +} + +@keyframes office-room-float { + 0% { + transform: rotateX(66deg) rotateZ(-11deg) translate3d(0, 22px, 0); + } + + 100% { + transform: rotateX(66deg) rotateZ(-11deg) translate3d(0, 34px, 0); + } +} + +@keyframes office-glow { + 0% { + filter: brightness(0.95); + } + + 100% { + filter: brightness(1.08); + } +} + .team-card { border: 2px solid var(--border-mid); background: linear-gradient(180deg, rgba(10, 16, 11, 0.92), rgba(8, 12, 9, 0.96));