Compare commits

...

4 Commits

Author SHA1 Message Date
azykov@mail.ru f3033d1d0d
selected object is highlighted only in editor 2026-06-02 08:13:39 +03:00
azykov@mail.ru ca5dea5093
selected object highlight 2026-06-02 08:11:43 +03:00
azykov@mail.ru 745ffe4f31
added CharacterView 2026-06-01 23:13:59 +03:00
azykov@mail.ru d23300afc3
added editor camera controls 2026-06-01 23:13:19 +03:00
8 changed files with 384 additions and 4 deletions

View File

@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@react-three/drei": "^10.7.7",
"@react-three/fiber": "^9.6.1",
"@types/three": "^0.184.1",
"install": "^0.13.0",

View File

@ -8,6 +8,9 @@ importers:
.:
dependencies:
'@react-three/drei':
specifier: ^10.7.7
version: 10.7.7(@react-three/fiber@9.6.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0))(@types/react@19.2.15)(@types/three@0.184.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0)
'@react-three/fiber':
specifier: ^9.6.1
version: 9.6.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0)
@ -236,6 +239,14 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@mediapipe/tasks-vision@0.10.17':
resolution: {integrity: sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==}
'@monogrid/gainmap-js@3.4.0':
resolution: {integrity: sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==}
peerDependencies:
three: '>= 0.159.0'
'@napi-rs/wasm-runtime@1.1.4':
resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
peerDependencies:
@ -245,6 +256,17 @@ packages:
'@oxc-project/types@0.132.0':
resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==}
'@react-three/drei@10.7.7':
resolution: {integrity: sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==}
peerDependencies:
'@react-three/fiber': ^9.0.0
react: ^19
react-dom: ^19
three: '>=0.159'
peerDependenciesMeta:
react-dom:
optional: true
'@react-three/fiber@9.6.1':
resolution: {integrity: sha512-zF0rsKcVYpcJwbFEnv2HkHX9cvOEgsfQo/X8lwmR2dn13S4qEQJXir9fxf5js2LQFoXqxOY7MDkOkYx2uZ4gSg==}
peerDependencies:
@ -374,6 +396,9 @@ packages:
'@tybys/wasm-util@0.10.2':
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
'@types/draco3d@1.4.10':
resolution: {integrity: sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==}
'@types/esrecurse@4.3.1':
resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==}
@ -386,6 +411,9 @@ packages:
'@types/node@24.12.4':
resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==}
'@types/offscreencanvas@2019.7.3':
resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==}
'@types/react-dom@19.2.3':
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
peerDependencies:
@ -467,6 +495,14 @@ packages:
resolution: {integrity: sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@use-gesture/core@10.3.1':
resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==}
'@use-gesture/react@10.3.1':
resolution: {integrity: sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==}
peerDependencies:
react: '>= 16.8.0'
'@vitejs/plugin-react@6.0.2':
resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==}
engines: {node: ^20.19.0 || >=22.12.0}
@ -505,6 +541,9 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
brace-expansion@5.0.6:
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
engines: {node: 18 || 20 || >=22}
@ -517,12 +556,23 @@ packages:
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
camera-controls@3.1.2:
resolution: {integrity: sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==}
engines: {node: '>=22.0.0', npm: '>=10.5.1'}
peerDependencies:
three: '>=0.126.1'
caniuse-lite@1.0.30001793:
resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
cross-env@7.0.3:
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
hasBin: true
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@ -542,10 +592,16 @@ packages:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
detect-gpu@5.0.70:
resolution: {integrity: sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
draco3d@1.5.7:
resolution: {integrity: sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==}
electron-to-chromium@1.5.364:
resolution: {integrity: sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==}
@ -628,6 +684,9 @@ packages:
picomatch:
optional: true
fflate@0.6.10:
resolution: {integrity: sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==}
fflate@0.8.3:
resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==}
@ -663,12 +722,18 @@ packages:
resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==}
engines: {node: '>=18'}
glsl-noise@0.0.0:
resolution: {integrity: sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==}
hermes-estree@0.25.1:
resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
hls.js@1.6.16:
resolution: {integrity: sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@ -680,6 +745,9 @@ packages:
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
engines: {node: '>= 4'}
immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
@ -696,6 +764,9 @@ packages:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-promise@2.2.2:
resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@ -733,6 +804,9 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
lightningcss-android-arm64@1.32.0:
resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
engines: {node: '>= 12.0.0'}
@ -814,6 +888,17 @@ packages:
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
maath@0.10.8:
resolution: {integrity: sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==}
peerDependencies:
'@types/three': '>=0.134.0'
three: '>=0.134.0'
meshline@3.3.1:
resolution: {integrity: sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==}
peerDependencies:
three: '>=0.137'
meshoptimizer@1.1.1:
resolution: {integrity: sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==}
@ -954,10 +1039,16 @@ packages:
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14}
potpack@1.0.2:
resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
promise-worker-transferable@1.0.4:
resolution: {integrity: sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@ -980,6 +1071,10 @@ packages:
resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==}
engines: {node: '>=0.10.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
rolldown@1.0.2:
resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==}
engines: {node: ^20.19.0 || >=22.12.0}
@ -1009,11 +1104,30 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
stats-gl@2.4.2:
resolution: {integrity: sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==}
peerDependencies:
'@types/three': '*'
three: '*'
stats.js@0.17.0:
resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==}
suspend-react@0.1.3:
resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==}
peerDependencies:
react: '>=17.0'
three-mesh-bvh@0.8.3:
resolution: {integrity: sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==}
peerDependencies:
three: '>= 0.159.0'
three-stdlib@2.36.1:
resolution: {integrity: sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==}
peerDependencies:
three: '>=0.128.0'
three@0.184.0:
resolution: {integrity: sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg==}
@ -1021,6 +1135,19 @@ packages:
resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
engines: {node: '>=12.0.0'}
troika-three-text@0.52.4:
resolution: {integrity: sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==}
peerDependencies:
three: '>=0.125.0'
troika-three-utils@0.52.4:
resolution: {integrity: sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==}
peerDependencies:
three: '>=0.125.0'
troika-worker-utils@0.52.0:
resolution: {integrity: sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==}
ts-api-utils@2.5.0:
resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==}
engines: {node: '>=18.12'}
@ -1030,6 +1157,9 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tunnel-rat@0.1.2:
resolution: {integrity: sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==}
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@ -1063,6 +1193,10 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
utility-types@3.11.0:
resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
engines: {node: '>= 4'}
uuid@14.0.0:
resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==}
hasBin: true
@ -1110,6 +1244,12 @@ packages:
yaml:
optional: true
webgl-constants@1.1.1:
resolution: {integrity: sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==}
webgl-sdf-generator@1.1.1:
resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@ -1135,6 +1275,21 @@ packages:
zod@4.4.3:
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
zustand@4.5.7:
resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
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
zustand@5.0.14:
resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==}
engines: {node: '>=12.20.0'}
@ -1344,6 +1499,13 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@mediapipe/tasks-vision@0.10.17': {}
'@monogrid/gainmap-js@3.4.0(three@0.184.0)':
dependencies:
promise-worker-transferable: 1.0.4
three: 0.184.0
'@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
dependencies:
'@emnapi/core': 1.10.0
@ -1353,6 +1515,39 @@ snapshots:
'@oxc-project/types@0.132.0': {}
'@react-three/drei@10.7.7(@react-three/fiber@9.6.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0))(@types/react@19.2.15)(@types/three@0.184.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0)':
dependencies:
'@babel/runtime': 7.29.7
'@mediapipe/tasks-vision': 0.10.17
'@monogrid/gainmap-js': 3.4.0(three@0.184.0)
'@react-three/fiber': 9.6.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0)
'@use-gesture/react': 10.3.1(react@19.2.6)
camera-controls: 3.1.2(three@0.184.0)
cross-env: 7.0.3
detect-gpu: 5.0.70
glsl-noise: 0.0.0
hls.js: 1.6.16
maath: 0.10.8(@types/three@0.184.1)(three@0.184.0)
meshline: 3.3.1(three@0.184.0)
react: 19.2.6
stats-gl: 2.4.2(@types/three@0.184.1)(three@0.184.0)
stats.js: 0.17.0
suspend-react: 0.1.3(react@19.2.6)
three: 0.184.0
three-mesh-bvh: 0.8.3(three@0.184.0)
three-stdlib: 2.36.1(three@0.184.0)
troika-three-text: 0.52.4(three@0.184.0)
tunnel-rat: 0.1.2(@types/react@19.2.15)(react@19.2.6)
use-sync-external-store: 1.6.0(react@19.2.6)
utility-types: 3.11.0
zustand: 5.0.14(@types/react@19.2.15)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6))
optionalDependencies:
react-dom: 19.2.6(react@19.2.6)
transitivePeerDependencies:
- '@types/react'
- '@types/three'
- immer
'@react-three/fiber@9.6.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(three@0.184.0)':
dependencies:
'@babel/runtime': 7.29.7
@ -1431,6 +1626,8 @@ snapshots:
tslib: 2.8.1
optional: true
'@types/draco3d@1.4.10': {}
'@types/esrecurse@4.3.1': {}
'@types/estree@1.0.9': {}
@ -1441,6 +1638,8 @@ snapshots:
dependencies:
undici-types: 7.16.0
'@types/offscreencanvas@2019.7.3': {}
'@types/react-dom@19.2.3(@types/react@19.2.15)':
dependencies:
'@types/react': 19.2.15
@ -1557,6 +1756,13 @@ snapshots:
'@typescript-eslint/types': 8.60.0
eslint-visitor-keys: 5.0.1
'@use-gesture/core@10.3.1': {}
'@use-gesture/react@10.3.1(react@19.2.6)':
dependencies:
'@use-gesture/core': 10.3.1
react: 19.2.6
'@vitejs/plugin-react@6.0.2(vite@8.0.14(@types/node@24.12.4))':
dependencies:
'@rolldown/pluginutils': 1.0.1
@ -1581,6 +1787,10 @@ snapshots:
baseline-browser-mapping@2.10.33: {}
bidi-js@1.0.3:
dependencies:
require-from-string: 2.0.2
brace-expansion@5.0.6:
dependencies:
balanced-match: 4.0.4
@ -1598,10 +1808,18 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
camera-controls@3.1.2(three@0.184.0):
dependencies:
three: 0.184.0
caniuse-lite@1.0.30001793: {}
convert-source-map@2.0.0: {}
cross-env@7.0.3:
dependencies:
cross-spawn: 7.0.6
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@ -1616,8 +1834,14 @@ snapshots:
deep-is@0.1.4: {}
detect-gpu@5.0.70:
dependencies:
webgl-constants: 1.1.1
detect-libc@2.1.2: {}
draco3d@1.5.7: {}
electron-to-chromium@1.5.364: {}
escalade@3.2.0: {}
@ -1713,6 +1937,8 @@ snapshots:
optionalDependencies:
picomatch: 4.0.4
fflate@0.6.10: {}
fflate@0.8.3: {}
file-entry-cache@8.0.0:
@ -1742,18 +1968,24 @@ snapshots:
globals@17.6.0: {}
glsl-noise@0.0.0: {}
hermes-estree@0.25.1: {}
hermes-parser@0.25.1:
dependencies:
hermes-estree: 0.25.1
hls.js@1.6.16: {}
ieee754@1.2.1: {}
ignore@5.3.2: {}
ignore@7.0.5: {}
immediate@3.0.6: {}
imurmurhash@0.1.4: {}
install@0.13.0: {}
@ -1764,6 +1996,8 @@ snapshots:
dependencies:
is-extglob: 2.1.1
is-promise@2.2.2: {}
isexe@2.0.0: {}
its-fine@2.0.0(@types/react@19.2.15)(react@19.2.6):
@ -1794,6 +2028,10 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lie@3.3.0:
dependencies:
immediate: 3.0.6
lightningcss-android-arm64@1.32.0:
optional: true
@ -1851,6 +2089,15 @@ snapshots:
dependencies:
yallist: 3.1.1
maath@0.10.8(@types/three@0.184.1)(three@0.184.0):
dependencies:
'@types/three': 0.184.1
three: 0.184.0
meshline@3.3.1(three@0.184.0):
dependencies:
three: 0.184.0
meshoptimizer@1.1.1: {}
minimatch@10.2.5:
@ -1908,8 +2155,15 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
potpack@1.0.2: {}
prelude-ls@1.2.1: {}
promise-worker-transferable@1.0.4:
dependencies:
is-promise: 2.2.2
lie: 3.3.0
punycode@2.3.1: {}
react-dom@19.2.6(react@19.2.6):
@ -1925,6 +2179,8 @@ snapshots:
react@19.2.6: {}
require-from-string@2.0.2: {}
rolldown@1.0.2:
dependencies:
'@oxc-project/types': 0.132.0
@ -1960,10 +2216,31 @@ snapshots:
source-map-js@1.2.1: {}
stats-gl@2.4.2(@types/three@0.184.1)(three@0.184.0):
dependencies:
'@types/three': 0.184.1
three: 0.184.0
stats.js@0.17.0: {}
suspend-react@0.1.3(react@19.2.6):
dependencies:
react: 19.2.6
three-mesh-bvh@0.8.3(three@0.184.0):
dependencies:
three: 0.184.0
three-stdlib@2.36.1(three@0.184.0):
dependencies:
'@types/draco3d': 1.4.10
'@types/offscreencanvas': 2019.7.3
'@types/webxr': 0.5.24
draco3d: 1.5.7
fflate: 0.6.10
potpack: 1.0.2
three: 0.184.0
three@0.184.0: {}
tinyglobby@0.2.17:
@ -1971,6 +2248,20 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
troika-three-text@0.52.4(three@0.184.0):
dependencies:
bidi-js: 1.0.3
three: 0.184.0
troika-three-utils: 0.52.4(three@0.184.0)
troika-worker-utils: 0.52.0
webgl-sdf-generator: 1.1.1
troika-three-utils@0.52.4(three@0.184.0):
dependencies:
three: 0.184.0
troika-worker-utils@0.52.0: {}
ts-api-utils@2.5.0(typescript@6.0.3):
dependencies:
typescript: 6.0.3
@ -1978,6 +2269,14 @@ snapshots:
tslib@2.8.1:
optional: true
tunnel-rat@0.1.2(@types/react@19.2.15)(react@19.2.6):
dependencies:
zustand: 4.5.7(@types/react@19.2.15)(react@19.2.6)
transitivePeerDependencies:
- '@types/react'
- immer
- react
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
@ -2011,6 +2310,8 @@ snapshots:
dependencies:
react: 19.2.6
utility-types@3.11.0: {}
uuid@14.0.0: {}
vite@8.0.14(@types/node@24.12.4):
@ -2024,6 +2325,10 @@ snapshots:
'@types/node': 24.12.4
fsevents: 2.3.3
webgl-constants@1.1.1: {}
webgl-sdf-generator@1.1.1: {}
which@2.0.2:
dependencies:
isexe: 2.0.0
@ -2040,6 +2345,13 @@ snapshots:
zod@4.4.3: {}
zustand@4.5.7(@types/react@19.2.15)(react@19.2.6):
dependencies:
use-sync-external-store: 1.6.0(react@19.2.6)
optionalDependencies:
'@types/react': 19.2.15
react: 19.2.6
zustand@5.0.14(@types/react@19.2.15)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)):
optionalDependencies:
'@types/react': 19.2.15

View File

@ -0,0 +1,12 @@
import { observer } from "mobx-react-lite";
import { state } from "../state";
export const CharacterView = observer(function () {
const character = state.world.currentScene.character;
return <mesh position={character.position} rotation={character.look}>
<boxGeometry args={[0.8, 0.8, 0.8]} />
<meshStandardMaterial color="yellow" />
</mesh>
});

View File

@ -2,6 +2,7 @@ import { observer } from "mobx-react-lite";
import type { ObjectInstance } from "../types";
import { useRef } from "react";
import type { Mesh } from "three";
import { Edges } from "@react-three/drei";
import { state } from "../state";
type ObjectViewProps = {
@ -15,14 +16,29 @@ export const ObjectView = observer(function ({ object }: ObjectViewProps) {
if (!objectType)
return null;
const isSelected = state.worldEditor.isEnabled &&
state.worldEditor.selectedObjectId === object.id;
const handleClick = (e: { stopPropagation: () => void }) => {
if (!state.worldEditor.isEnabled)
return;
e.stopPropagation();
state.worldEditor.setSelectedObjectId(object.id);
};
return (<>
<group position={object.position} rotation={object.rotation}>
<group
position={object.position}
rotation={object.rotation}
onClick={handleClick}
>
{
objectType.voxels.map((v, idx) => {
const vt = state.world.getVoxelTypeById(v.typeId);
return <mesh key={idx} ref={meshRef} position={v.position}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={(v.color ?? vt?.color) ?? 'white'} opacity={(v.opacity ?? vt?.opacity) ?? 1} />
{isSelected && <Edges color="white" lineWidth={3} stencilWrite={false} />}
</mesh>
})
}

View File

@ -1,20 +1,43 @@
import { useRef } from 'react';
import type React from 'react';
import { useFrame } from '@react-three/fiber';
import { OrbitControls } from '@react-three/drei';
import { observer } from 'mobx-react-lite';
import { state } from '../state';
import { ObjectView } from './ObjectView';
import { CharacterView } from './CharacterView';
export const WorldView = observer(function () {
const world = state.world;
const controlsRef = useRef<React.ComponentRef<typeof OrbitControls>>(null);
console.log(world.currentScene.objects);
useFrame((_, delta) => {
world.tick(delta);
})
});
const handleEnd = () => {
const controls = controlsRef.current;
if (!controls || world.isPlaying)
return;
const [x, y, z] = controls.object.rotation.toArray();
state.worldEditor.setCamera({
position: controls.object.position.toArray(),
look: [x, y, z],
});
};
return (<>
<OrbitControls
ref={controlsRef}
enabled={!world.isPlaying}
onEnd={handleEnd}
enableDamping={false}
/>
<ambientLight intensity={0.5} />
<directionalLight position={[5, 5, 5]} intensity={1} />
{world.currentScene.objects.map((obj) => <ObjectView key={obj.id} object={obj} />)}
<CharacterView />
</>)
});

View File

@ -7,7 +7,6 @@ export class RootState {
public readonly worldEditor: WorldEditorState;
constructor() {
this.world.loadMock();
this.worldEditor = new WorldEditorState(this.world);
makeAutoObservable(

View File

@ -2,9 +2,10 @@ import { makeAutoObservable } from "mobx";
import { WorldFactory } from "../model/worldFactory";
import type { ObjectType, RunningGameState, Scene, World } from "../types";
import { CharacterState } from "./character";
import type { Pos3 } from "../types/3d";
import type { Pos3, V3 } from "../types/3d";
import { clone, randomId } from "../utils";
import type { VoxelType } from "../types/voxel";
import { state } from "./root";
export class WorldState {
public data: World = WorldFactory.create();
@ -12,6 +13,7 @@ export class WorldState {
public character = new CharacterState(this);
constructor() {
this.load();
makeAutoObservable(this);
}
@ -116,6 +118,8 @@ export class WorldState {
scene: clone(this.data.intialScene),
}
}
state.worldEditor.setSelectedObjectId(undefined);
}
public pause(): void {

View File

@ -3,10 +3,13 @@ import type { WorldState } from "./world";
import type { ObjectInstance } from "../types";
import { createObjectInstance } from "../utils/object";
import { randomId } from "../utils";
import type { Pos3 } from "../types/3d";
export class WorldEditorState {
private readonly world: WorldState;
public selectedObjectId: string | undefined;
constructor(world: WorldState) {
this.world = world;
makeAutoObservable(this);
@ -16,6 +19,16 @@ export class WorldEditorState {
return !this.world.isPlaying;
}
public setCamera(value: Pos3): void {
this.world.data.editorCamera = value;
console.log(JSON.stringify(this.world.data.editorCamera));
this.world.save();
}
public setSelectedObjectId(value: string | undefined): void {
this.selectedObjectId = value;
}
public addObjectCloneAtRandomPosition(typeId: string): ObjectInstance {
return this.addObjectClone(
typeId,