mbt-3d 0.3.8 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ npm install react react-dom three @react-three/fiber @react-three/drei
21
21
  - @react-three/fiber >= 8.0.0
22
22
  - @react-three/drei >= 9.0.0
23
23
 
24
- ## Local Development
24
+ ## Local Development
25
25
 
26
26
  For local development and testing with another project:
27
27
 
@@ -51,13 +51,50 @@ npm unlink
51
51
 
52
52
  **Alternative: Use file: protocol**
53
53
  ```json
54
- {
55
- "dependencies": {
56
- "mbt-3d": "file:../path/to/mbt-3d"
57
- }
58
- }
59
- ```
60
-
61
- ## License
62
-
63
- MIT
54
+ {
55
+ "dependencies": {
56
+ "mbt-3d": "file:../path/to/mbt-3d"
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Lighting and HDRI
62
+
63
+ `Scene3D` supports mixed lighting:
64
+
65
+ - `lights` and `environment` (HDRI) can be used together.
66
+ - `environment.intensity` controls scene environment intensity.
67
+ - `environment.blur` controls HDRI background blur when HDRI background is enabled.
68
+ - `renderer` accepts multiple parameters at once (`physicallyCorrectLights`, `outputColorSpace`, `toneMapping`, `toneMappingExposure`).
69
+ - Shadow-casting lights use `shadowMapSize: 2048` by default (override per light if needed).
70
+
71
+ ```tsx
72
+ <Scene3D
73
+ lights={[
74
+ { type: 'ambient', intensity: 0.4 },
75
+ { type: 'spot', position: [5, 8, 5], intensity: 120, castShadow: true, shadowMapSize: 2048 }
76
+ ]}
77
+ environment={{
78
+ files: '/hdri/studio.hdr',
79
+ intensity: 1.2,
80
+ blur: 0.15,
81
+ background: false
82
+ }}
83
+ renderer={{
84
+ physicallyCorrectLights: true,
85
+ outputColorSpace: 'srgb',
86
+ toneMapping: 'ACESFilmicToneMapping',
87
+ toneMappingExposure: 1
88
+ }}
89
+ >
90
+ {children}
91
+ </Scene3D>
92
+ ```
93
+
94
+ ### Demo workflow
95
+
96
+ In `TextureUploadDemo`, designers can configure model/textures + HDRI + dynamic lights + renderer settings, then use `Copy Scene Settings` to export JSON preset for integration into the main app scene props.
97
+
98
+ ## License
99
+
100
+ MIT
package/dist/index.d.ts CHANGED
@@ -185,6 +185,8 @@ export declare interface AnimatedModelProps extends Omit<ModelProps, 'onLoad'> {
185
185
  children?: React.ReactNode;
186
186
  /** Name of animation to play on load (auto-plays first if not specified) */
187
187
  defaultAnimation?: string;
188
+ /** Controlled animation name. When changed, AnimatedModel switches to this animation */
189
+ animation?: string;
188
190
  /** Morph target values as key-value pairs { targetName: value } where value is 0-1 */
189
191
  morphTargets?: Record<string, number>;
190
192
  /** Mesh visibility as key-value pairs { meshName: visible }. Example: { "Hairgirl1": true, "Hairgirl2": false } */
@@ -268,7 +270,7 @@ export declare interface BoneAttachmentProps {
268
270
  *
269
271
  * @example
270
272
  * ```tsx
271
- * { type: 'directional', position: [10, 20, 10], intensity: 40, castShadow: true }
273
+ * { type: 'directional', position: [10, 20, 10], intensity: 40, castShadow: true, shadowMapSize: 2048 }
272
274
  * ```
273
275
  */
274
276
  declare interface DirectionalLightConfig extends BaseLightConfig {
@@ -277,11 +279,17 @@ declare interface DirectionalLightConfig extends BaseLightConfig {
277
279
  position?: [number, number, number];
278
280
  /** Enable shadow casting. Default: true */
279
281
  castShadow?: boolean;
282
+ /** Shadow map size in px (square). Default: 2048 */
283
+ shadowMapSize?: number;
280
284
  }
281
285
 
282
286
  /**
283
287
  * Environment (HDRI) configuration for realistic lighting and reflections
284
288
  *
289
+ * @remarks
290
+ * Works together with `lights` (they are not mutually exclusive).
291
+ * `intensity` and `blur` are applied to the active scene environment/background.
292
+ *
285
293
  * @example
286
294
  * ```tsx
287
295
  * { files: '/scenes/studio.hdr', intensity: 1, background: false }
@@ -290,11 +298,11 @@ declare interface DirectionalLightConfig extends BaseLightConfig {
290
298
  declare interface EnvironmentConfig {
291
299
  /** URL to HDRI file (.hdr or .exr) */
292
300
  files: string;
293
- /** Environment intensity multiplier. Default: 1 */
301
+ /** Environment intensity multiplier for scene environment. Default: 1 */
294
302
  intensity?: number;
295
303
  /** Use HDRI as scene background. Default: false */
296
304
  background?: boolean;
297
- /** Blur amount for background (0-1). Default: 0 */
305
+ /** Background blur amount (0-1). Default: 0 */
298
306
  blur?: number;
299
307
  }
300
308
 
@@ -570,7 +578,7 @@ export declare interface MorphableModelProps extends ModelProps {
570
578
  *
571
579
  * @example
572
580
  * ```tsx
573
- * { type: 'point', position: [0, 5, 0], intensity: 20, color: '#ffaa00' }
581
+ * { type: 'point', position: [0, 5, 0], intensity: 20, color: '#ffaa00', castShadow: true, shadowMapSize: 2048 }
574
582
  * ```
575
583
  */
576
584
  declare interface PointLightConfig extends BaseLightConfig {
@@ -583,10 +591,30 @@ declare interface PointLightConfig extends BaseLightConfig {
583
591
  decay?: number;
584
592
  /** Enable shadow casting. Default: false */
585
593
  castShadow?: boolean;
594
+ /** Shadow map size in px (square). Default: 2048 */
595
+ shadowMapSize?: number;
586
596
  }
587
597
 
588
598
  export declare function preloadModel(url: string): void;
589
599
 
600
+ /**
601
+ * WebGL renderer settings for light response and color mapping.
602
+ * Useful for physically based lighting tests.
603
+ *
604
+ * @remarks
605
+ * All fields can be provided together in one `renderer` object.
606
+ */
607
+ export declare interface RendererConfig {
608
+ /** Toggle physically-correct light attenuation model */
609
+ physicallyCorrectLights?: boolean;
610
+ /** Output color space. Default: 'srgb' */
611
+ outputColorSpace?: 'srgb' | 'linear';
612
+ /** Tone mapping operator. Default: 'ACESFilmicToneMapping' */
613
+ toneMapping?: ToneMappingMode;
614
+ /** Tone mapping exposure. Default: 1 */
615
+ toneMappingExposure?: number;
616
+ }
617
+
590
618
  /**
591
619
  * Scene3D - Main 3D scene container with built-in canvas, lighting, and controls
592
620
  *
@@ -607,6 +635,7 @@ export declare function preloadModel(url: string): void;
607
635
  * @param controls.enablePan - Enable camera panning with middle mouse. Default: `true`
608
636
  * @param controls.enableZoom - Enable camera zoom with scroll wheel. Default: `true`
609
637
  * @param controls.enableRotate - Enable camera rotation with left mouse. Default: `true`
638
+ * @param controls.target - Orbit target point [x, y, z]. Camera looks at this point. Default: `[0, 0, 0]`
610
639
  * @param controls.minDistance - Minimum zoom distance. Example: `2`
611
640
  * @param controls.maxDistance - Maximum zoom distance. Example: `10`
612
641
  * @param controls.minPolarAngle - Minimum vertical rotation angle in radians. Example: `Math.PI / 4`
@@ -615,7 +644,9 @@ export declare function preloadModel(url: string): void;
615
644
  * @param controls.autoRotateSpeed - Auto-rotation speed. Default: `2`
616
645
  * @param background - Background: image URL (e.g., `"/bg.jpg"`) or hex color (e.g., `"#1a1a2e"`)
617
646
  * @param shadows - Enable shadow rendering. Default: `true`
618
- * @param lights - Array of light configurations. Supports spot, point, directional, hemisphere, and ambient lights. Default: `[{ type: 'ambient', intensity: 0.5 }, { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true }]`
647
+ * @param lights - Array of light configurations. Supports spot, point, directional, hemisphere, and ambient lights. Shadow-casting lights support `shadowMapSize` (default: `2048`). Default: `[{ type: 'ambient', intensity: 0.5 }, { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true }]`
648
+ * @param environment - Optional HDRI environment config. Works together with `lights` (combined lighting), not as a replacement.
649
+ * @param renderer - Optional renderer tuning for tone mapping, exposure, output color space and physically-correct lights. All options can be set together in one object.
619
650
  * @param contactShadows - Contact shadows configuration. Can be `true` for default settings or object with custom settings. Example: `{ position: [0, -1, 0], opacity: 0.5, blur: 2 }`
620
651
  * @param contactShadows.position - Shadow position as [x, y, z]. Example: `[0, -1, 0]`. Default: `[0, -1, 0]`
621
652
  * @param contactShadows.opacity - Shadow opacity (0-1). Example: `0.5`. Default: `0.5`
@@ -642,7 +673,7 @@ export declare function preloadModel(url: string): void;
642
673
  * <Scene3D
643
674
  * camera={{ position: [0, 2, 5], fov: 45 }}
644
675
  * lights={[
645
- * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true },
676
+ * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true, shadowMapSize: 2048 },
646
677
  * { type: 'spot', position: [-5, 10, -5], intensity: 30, castShadow: false },
647
678
  * { type: 'point', position: [0, 5, 0], intensity: 20 },
648
679
  * { type: 'ambient', intensity: 0.3 }
@@ -666,7 +697,7 @@ export declare function preloadModel(url: string): void;
666
697
  * </Scene3D>
667
698
  * ```
668
699
  */
669
- export declare function Scene3D({ children, camera, controls, background, shadows, lights, environment, contactShadows, showLoadingOverlay, style, className, }: Scene3DProps): JSX_2.Element;
700
+ export declare function Scene3D({ children, camera, controls, background, shadows, lights, environment, renderer, contactShadows, showLoadingOverlay, style, className, }: Scene3DProps): JSX_2.Element;
670
701
 
671
702
  /**
672
703
  * Props for Scene3D component
@@ -699,6 +730,8 @@ export declare interface Scene3DProps {
699
730
  };
700
731
  /** OrbitControls configuration for camera rotation */
701
732
  controls?: {
733
+ /** Orbit target point [x, y, z]. Camera will look at this point. Default: [0, 0, 0] */
734
+ target?: [number, number, number];
702
735
  /** Enable/disable all controls. Default: true */
703
736
  enabled?: boolean;
704
737
  /** Enable camera panning (middle mouse). Default: true */
@@ -726,8 +759,13 @@ export declare interface Scene3DProps {
726
759
  shadows?: boolean;
727
760
  /** Array of light configurations for multi-light setup */
728
761
  lights?: LightConfigUnion[];
729
- /** Environment (HDRI) configuration for realistic lighting and reflections */
762
+ /**
763
+ * Environment (HDRI) configuration for realistic lighting and reflections.
764
+ * Can be combined with `lights` for mixed lighting setups.
765
+ */
730
766
  environment?: EnvironmentConfig;
767
+ /** Optional renderer tuning (physically-correct lights, tone mapping, exposure, output color space). */
768
+ renderer?: RendererConfig;
731
769
  /** Contact shadows configuration (ground shadows under models) */
732
770
  contactShadows?: boolean | {
733
771
  /** Shadow position [x, y, z]. Default: [0, -1, 0] */
@@ -750,7 +788,7 @@ export declare interface Scene3DProps {
750
788
  *
751
789
  * @example
752
790
  * ```tsx
753
- * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true }
791
+ * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true, shadowMapSize: 2048 }
754
792
  * ```
755
793
  */
756
794
  declare interface SpotLightConfig extends BaseLightConfig {
@@ -759,6 +797,8 @@ declare interface SpotLightConfig extends BaseLightConfig {
759
797
  position?: [number, number, number];
760
798
  /** Enable shadow casting. Default: true */
761
799
  castShadow?: boolean;
800
+ /** Shadow map size in px (square). Default: 2048 */
801
+ shadowMapSize?: number;
762
802
  /** Cone angle in radians. Default: Math.PI / 6 */
763
803
  angle?: number;
764
804
  /** Penumbra (soft edges) 0-1. Default: 0.5 */
@@ -769,6 +809,8 @@ declare interface SpotLightConfig extends BaseLightConfig {
769
809
  distance?: number;
770
810
  }
771
811
 
812
+ export declare type ToneMappingMode = 'NoToneMapping' | 'LinearToneMapping' | 'ReinhardToneMapping' | 'CineonToneMapping' | 'ACESFilmicToneMapping';
813
+
772
814
  export declare function useAnimationController(animations: THREE.AnimationClip[], scene: THREE.Object3D, options?: UseAnimationControllerOptions): {
773
815
  playAnimation: (name: string, opts?: {
774
816
  loop?: boolean;
package/dist/mbt-3d.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react"),I=require("@react-three/drei"),ne=require("three"),ae=require("three/examples/jsm/utils/SkeletonUtils.js"),B=require("@react-three/fiber"),ie=require("three/examples/jsm/loaders/KTX2Loader.js"),M=require("react/jsx-runtime");function Q(t){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const o in t)if(o!=="default"){const a=Object.getOwnPropertyDescriptor(t,o);Object.defineProperty(r,o,a.get?a:{enumerable:!0,get:()=>t[o]})}}return r.default=t,Object.freeze(r)}const R=Q(ne),ee=Q(ae);function le({position:t,controlsConfig:r}){const{camera:o}=B.useThree(),a=e.useRef(null);return e.useEffect(()=>{t&&o&&(o.position.set(t[0],t[1],t[2]),o.updateProjectionMatrix(),a.current&&(a.current.target.set(0,0,0),a.current.update()))},[t,o]),M.jsx(I.OrbitControls,{ref:a,makeDefault:!0,enabled:r.enabled,enablePan:r.enablePan,enableZoom:r.enableZoom,enableRotate:r.enableRotate,minDistance:r.minDistance,maxDistance:r.maxDistance,minPolarAngle:r.minPolarAngle,maxPolarAngle:r.maxPolarAngle,autoRotate:r.autoRotate,autoRotateSpeed:r.autoRotateSpeed})}function ce({background:t}){const r=t==null?void 0:t.startsWith("#");return t?r?M.jsx("color",{attach:"background",args:[t]}):M.jsx(ue,{url:t}):null}function ue({url:t}){const r=I.useTexture(t);return e.useMemo(()=>{r.colorSpace=R.SRGBColorSpace},[r]),M.jsx("primitive",{attach:"background",object:r})}function fe({config:t}){return M.jsx(I.Environment,{files:t.files,background:t.background??!1,blur:t.blur??0,children:M.jsx("group",{scale:t.intensity??1,children:M.jsx("ambientLight",{intensity:0})})})}function me({config:t}){switch(t.type){case"spot":{const{position:r=[5,10,5],intensity:o=50,castShadow:a=!0,angle:c=Math.PI/6,penumbra:g=.5,decay:y=2,distance:T=0,color:h="#ffffff"}=t;return M.jsx("spotLight",{position:r,intensity:o,castShadow:a,angle:c,penumbra:g,decay:y,distance:T,color:h})}case"point":{const{position:r=[0,5,0],intensity:o=20,color:a="#ffffff",distance:c=0,decay:g=2,castShadow:y=!1}=t;return M.jsx("pointLight",{position:r,intensity:o,color:a,distance:c,decay:g,castShadow:y})}case"directional":{const{position:r=[10,20,10],intensity:o=40,color:a="#ffffff",castShadow:c=!0}=t;return M.jsx("directionalLight",{position:r,intensity:o,color:a,castShadow:c})}case"hemisphere":{const{skyColor:r="#ffffff",groundColor:o="#444444",intensity:a=.5,position:c=[0,10,0]}=t,g=e.useMemo(()=>new R.Color(r),[r]),y=e.useMemo(()=>new R.Color(o),[o]);return M.jsx("hemisphereLight",{args:[g,y,a],position:c})}case"ambient":{const{intensity:r=.5,color:o="#ffffff"}=t;return M.jsx("ambientLight",{intensity:r,color:o})}default:return null}}function pe({onChange:t}){const{active:r,progress:o}=I.useProgress();return e.useEffect(()=>{t(r,o)},[r,o,t]),null}function de({children:t,camera:r={},controls:o={},background:a,shadows:c=!0,lights:g=[{type:"ambient",intensity:.5},{type:"spot",position:[5,10,5],intensity:50,castShadow:!0}],environment:y,contactShadows:T=!0,showLoadingOverlay:h=!0,style:n,className:i}){const[u,m]=e.useState(!1),[b,s]=e.useState(0),l=e.useRef(null),f=e.useCallback((E,d)=>{if(E){l.current!==null&&(window.clearTimeout(l.current),l.current=null),m(!0),s(Math.max(0,Math.min(100,Math.round(d))));return}s(100),l.current=window.setTimeout(()=>{m(!1),s(0),l.current=null},200)},[]);e.useEffect(()=>()=>{l.current!==null&&window.clearTimeout(l.current)},[]);const S={position:r.position||[0,2,5],fov:r.fov||45},p={enabled:o.enabled??!0,enablePan:o.enablePan??!0,enableZoom:o.enableZoom??!0,enableRotate:o.enableRotate??!0,minDistance:o.minDistance,maxDistance:o.maxDistance,minPolarAngle:o.minPolarAngle,maxPolarAngle:o.maxPolarAngle,autoRotate:o.autoRotate??!1,autoRotateSpeed:o.autoRotateSpeed??2},A=typeof T=="object"?{position:T.position||[0,-1,0],opacity:T.opacity??.5,blur:T.blur??2}:T?{position:[0,-1,0],opacity:.5,blur:2}:null;return M.jsxs("div",{style:{...n||{},position:(n==null?void 0:n.position)??"relative"},className:i,children:[M.jsxs(B.Canvas,{shadows:c,camera:{position:S.position,fov:S.fov},style:{width:"100%",height:"100%"},children:[M.jsx(e.Suspense,{fallback:null,children:M.jsx(ce,{background:a})}),y&&M.jsx(e.Suspense,{fallback:null,children:M.jsx(fe,{config:y})}),g.map((E,d)=>M.jsx(me,{config:E},`${E.type}-${d}`)),M.jsx(e.Suspense,{fallback:null,children:t}),M.jsx(le,{position:S.position,controlsConfig:p}),A&&M.jsx(I.ContactShadows,{position:A.position,opacity:A.opacity,blur:A.blur}),M.jsx(pe,{onChange:f})]}),h&&u&&M.jsx("div",{style:{position:"absolute",inset:0,background:"rgba(8, 10, 16, 0.46)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none",zIndex:10},children:M.jsxs("div",{style:{minWidth:220,padding:"16px 18px",borderRadius:14,border:"1px solid rgba(255,255,255,0.2)",background:"linear-gradient(180deg, rgba(18,24,36,0.9), rgba(13,17,27,0.9))",color:"#eef3ff",boxShadow:"0 10px 30px rgba(0,0,0,0.35)",fontFamily:"system-ui, -apple-system, Segoe UI, sans-serif",textAlign:"center"},children:[M.jsx("div",{style:{display:"flex",justifyContent:"center",marginBottom:10},children:M.jsxs("svg",{width:"34",height:"34",viewBox:"0 0 34 34","aria-hidden":"true",children:[M.jsx("circle",{cx:"17",cy:"17",r:"14",fill:"none",stroke:"rgba(255,255,255,0.2)",strokeWidth:"4"}),M.jsx("path",{d:"M31 17a14 14 0 0 1-14 14",fill:"none",stroke:"#67b4ff",strokeWidth:"4",strokeLinecap:"round",children:M.jsx("animateTransform",{attributeName:"transform",type:"rotate",from:"0 17 17",to:"360 17 17",dur:"0.9s",repeatCount:"indefinite"})})]})}),M.jsxs("div",{style:{fontSize:12,opacity:.82,marginTop:4},children:[b,"%"]})]})})]})}function K(t,r){const o=e.useRef(new Map),a=e.useRef({}),c=e.useRef({});e.useEffect(()=>{r&&(a.current={...r})},[r]),e.useEffect(()=>{if(!t)return;const h=new Map;t.traverse(n=>{if(n.isMesh){const i=n;i.name&&h.set(i.name,i)}}),o.current=h},[t]),B.useFrame(()=>{const h=o.current;if(h.size===0)return;const n={...a.current,...c.current};for(const[i,u]of Object.entries(n)){const m=h.get(i);m&&m.visible!==u&&(m.visible=u)}});const g=e.useCallback((h,n)=>{c.current[h]=n;const i=o.current.get(h);i&&(i.visible=n)},[]),y=e.useCallback(()=>Array.from(o.current.keys()).sort(),[]),T=e.useCallback(()=>{const h={};return o.current.forEach((n,i)=>{h[i]=n.visible}),h},[]);return{setMeshVisibility:g,getMeshNames:y,getMeshVisibility:T}}function G(t,r){const o=e.useRef(new Map),a=e.useRef(new Map);e.useEffect(()=>{if(!t)return;const n=new Map;t.traverse(i=>{if(i.isMesh){const u=i;(Array.isArray(u.material)?u.material:[u.material]).forEach(b=>{b.name&&!n.has(b.name)&&n.set(b.name,b)})}}),o.current=n,r&&Object.entries(r).forEach(([i,u])=>{const m=n.get(i);if(m&&!Array.isArray(m)){const b=c(u);m.color&&m.color.copy(b),a.current.set(i,b)}})},[t,r]),B.useFrame(()=>{a.current.forEach((n,i)=>{const u=o.current.get(i);if(u&&!Array.isArray(u)){const m=u;m.color&&!m.color.equals(n)&&(m.color.copy(n),m.needsUpdate=!0)}})});const c=n=>typeof n=="string"?new R.Color(n):new R.Color(n[0],n[1],n[2]),g=e.useCallback((n,i)=>{const u=c(i);a.current.set(n,u);const m=o.current.get(n);if(m&&!Array.isArray(m)){const b=m;b.color&&(b.color.copy(u),b.needsUpdate=!0)}},[]),y=e.useCallback(()=>Array.from(o.current.keys()).sort(),[]),T=e.useCallback(n=>{const i=o.current.get(n);if(i&&!Array.isArray(i)){const u=i;if(u.color)return"#"+u.color.getHexString()}return null},[]),h=e.useCallback(()=>{const n={};return o.current.forEach((i,u)=>{if(!Array.isArray(i)){const m=i;m.color&&(n[u]="#"+m.color.getHexString())}}),n},[]);return{setMaterialColor:g,getMaterialNames:y,getMaterialColor:T,getAllMaterialColors:h}}function H(t){const r=t.toLowerCase();if(r.endsWith(".ktx2"))return!0;try{const o=new URL(t,window.location.origin),a=decodeURIComponent(o.hash.replace(/^#/,"")).toLowerCase(),c=decodeURIComponent(o.search).toLowerCase(),g=decodeURIComponent(o.pathname).toLowerCase();return a.endsWith(".ktx2")||c.includes(".ktx2")||g.endsWith(".ktx2")}catch{return r.includes(".ktx2")}}function z(t,r){const{gl:o}=B.useThree(),a=e.useRef(new Map),c=e.useRef(new R.TextureLoader),g=e.useRef(null),y=e.useRef(new Map),T=e.useRef(new Set),h=e.useRef("");e.useEffect(()=>{if(!g.current)try{const s=typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function";console.log("[useMaterialTexture] Browser features:"),console.log(` WebAssembly supported: ${s}`),console.log(` WebGL2: ${o.capabilities.isWebGL2}`);const l=new ie.KTX2Loader;l.setTranscoderPath("/basis/"),l.detectSupport(o),g.current=l,console.log("[useMaterialTexture] ✅ KTX2Loader initialized"),console.log("[useMaterialTexture] Transcoder path: /basis/"),fetch("/basis/basis_transcoder.wasm").then(f=>{f.ok?console.log("[useMaterialTexture] ✅ basis_transcoder.wasm is accessible"):console.error("[useMaterialTexture] ❌ basis_transcoder.wasm returned",f.status)}).catch(f=>{console.error("[useMaterialTexture] ❌ Failed to check basis_transcoder.wasm:",f)}),s||(console.warn("[useMaterialTexture] ⚠️ WebAssembly not supported! KTX2 will fallback to CPU decoding (slow)"),console.warn("[useMaterialTexture] ⚠️ Recommend using WebP instead of KTX2 for this browser"))}catch(s){console.error("[useMaterialTexture] ❌ Failed to initialize KTX2Loader:",s)}return()=>{g.current&&(g.current.dispose(),g.current=null)}},[o]),e.useEffect(()=>{if(!t)return;const s=new Map;t.traverse(l=>{if(l.isMesh){const f=l;(Array.isArray(f.material)?f.material:[f.material]).forEach(p=>{p.name&&!s.has(p.name)&&s.set(p.name,p)})}}),a.current=s},[t]);const n=e.useCallback(s=>H(s)?g.current?g.current:(console.warn("[useMaterialTexture] KTX2Loader not initialized, falling back to TextureLoader"),c.current):c.current,[]);e.useEffect(()=>{if(!r||!t)return;const s=a.current;if(s.size===0)return;const l=JSON.stringify(r);if(h.current===l){console.log("[useMaterialTexture] Textures unchanged, skipping reload");return}h.current=l;let f=!1;const S=new Map;Object.entries(r).forEach(([d,w])=>{S.set(d,typeof w=="string"?{map:w}:w)}),console.log("[useMaterialTexture] Starting texture load for",S.size,"materials");const p=[];S.forEach((d,w)=>{var v,L;const N=s.get(w);if(!N||!N.isMeshStandardMaterial){console.warn(`[useMaterialTexture] Material "${w}" not found or not MeshStandardMaterial`);return}const x=N;console.log(`[useMaterialTexture] 📋 Material "${w}" BEFORE reset:`),console.log(` - map: ${x.map?"EXISTS":"null"} ${x.map?`(uuid: ${x.map.uuid})`:""}`),console.log(` - normalMap: ${x.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${x.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${x.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${x.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${x.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(v=x.color)==null?void 0:v.getHexString()}`),console.log(` - emissive: ${(L=x.emissive)==null?void 0:L.getHexString()}`),console.log(` - material uuid: ${x.uuid}`),Object.entries(d).forEach(([$,j])=>{if(!j)return;const C=$,k=x[C];k&&(console.log(`[useMaterialTexture] 🗑️ Disposing old ${C} (uuid: ${k.uuid})`),k.dispose(),x[C]=null)}),d.emissiveMap&&(x.emissive=new R.Color(0),x.emissiveIntensity=0),x.needsUpdate=!0,x.color=new R.Color(16777215),console.log(`[useMaterialTexture] ✅ Material "${w}" AFTER reset: only specified maps cleared`),Object.entries(d).forEach(([$,j])=>{if(!j)return;const C=`${w}_${$}_${j}`,k=y.current.get(C);if(k){console.log(`[useMaterialTexture] Using cached texture: ${w}.${$}`),f||i(x,$,k);return}if(T.current.has(C)){console.log(`[useMaterialTexture] Skipping already loading: ${w}.${$}`);return}p.push({materialName:w,textureType:$,url:j,material:x})})}),console.log(`[useMaterialTexture] Queued ${p.length} textures to load`);let A=0;const E=()=>{if(f||A>=p.length){console.log("[useMaterialTexture] ✅ All textures loaded"),console.log("[useMaterialTexture] 📊 FINAL material states:"),s.forEach((v,L)=>{var j,C;const $=v;console.log(` Material "${L}":`),console.log(` - map: ${$.map?"EXISTS":"null"} ${$.map?`(colorSpace: ${$.map.colorSpace})`:""}`),console.log(` - normalMap: ${$.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${$.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${$.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${$.emissiveMap?"EXISTS":"null"}`),console.log(` - color: ${(j=$.color)==null?void 0:j.getHexString()}`),console.log(` - emissive: ${(C=$.emissive)==null?void 0:C.getHexString()}`),console.log(` - emissiveIntensity: ${$.emissiveIntensity}`),console.log(` - roughness: ${$.roughness}`),console.log(` - metalness: ${$.metalness}`)});return}const d=p[A++],w=`${d.materialName}_${d.textureType}_${d.url}`;console.log(`[useMaterialTexture] Loading (${A}/${p.length}): ${d.materialName}.${d.textureType} from ${d.url}`),T.current.add(w);const N=n(d.url),x=H(d.url)?"KTX2Loader":"TextureLoader";console.log(`[useMaterialTexture] Using ${x} for ${d.url}`),N.load(d.url,v=>{var C,k,D,P,O,W;if(T.current.delete(w),f){console.log(`[useMaterialTexture] Disposed, cleaning up texture: ${d.materialName}.${d.textureType}`),v.dispose();return}const L=((C=v.image)==null?void 0:C.width)||((D=(k=v.source)==null?void 0:k.data)==null?void 0:D.width)||"unknown",$=((P=v.image)==null?void 0:P.height)||((W=(O=v.source)==null?void 0:O.data)==null?void 0:W.height)||"unknown";console.log(`[useMaterialTexture] ✅ Loaded: ${d.materialName}.${d.textureType} (${L}x${$})`),v.colorSpace=d.textureType==="map"||d.textureType==="emissiveMap"?R.SRGBColorSpace:R.NoColorSpace,v.wrapS=R.RepeatWrapping,v.wrapT=R.RepeatWrapping,v.flipY=!1,y.current.set(w,v),i(d.material,d.textureType,v);const j=H(d.url)?500:150;console.log(`[useMaterialTexture] Waiting111111 ${j}ms before next texture...`),setTimeout(E,0)},v=>{if(v.lengthComputable){const L=Math.round(v.loaded/v.total*100);L%25===0&&console.log(`[useMaterialTexture] Progress ${d.materialName}.${d.textureType}: ${L}%`)}},v=>{T.current.delete(w),f||(console.error(`[useMaterialTexture] ❌ Failed to load ${d.materialName}.${d.textureType} from ${d.url}`),console.error("[useMaterialTexture] Error details:",v),console.error("[useMaterialTexture] Loader type:",x),H(d.url)&&(console.error("[useMaterialTexture] KTX2 error - file may not be in Basis Universal format!"),console.error("[useMaterialTexture] Make sure files are created with: gltf-transform etc1s input.png output.ktx2"))),setTimeout(E,100)})};return E(),()=>{console.log("[useMaterialTexture] Cleanup: disposed"),f=!0}},[t,r,n]);const i=(s,l,f)=>{var S,p;switch(console.log(`[useMaterialTexture] 🎨 Applying texture: ${s.name}.${l} (texture uuid: ${f.uuid})`),l){case"map":s.map=f;break;case"normalMap":s.normalMap=f;break;case"roughnessMap":s.roughnessMap=f;break;case"metalnessMap":s.metalnessMap=f;break;case"emissiveMap":s.emissiveMap=f,s.emissive=new R.Color(16777215),s.emissiveIntensity=1;break;case"alphaMap":console.log(`[useMaterialTexture] Skipping alphaMap for "${s.name}" to prevent disappearing`);break;case"aoMap":s.aoMap=f;break}s.needsUpdate=!0,console.log(`[useMaterialTexture] ✅ Applied ${l} to ${s.name}, needsUpdate=true`),console.log(`[useMaterialTexture] 📊 Material "${s.name}" FINAL state:`),console.log(` - map: ${s.map?"EXISTS":"null"} ${s.map?`(uuid: ${s.map.uuid}, colorSpace: ${s.map.colorSpace})`:""}`),console.log(` - normalMap: ${s.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${s.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${s.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${s.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${s.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(S=s.color)==null?void 0:S.getHexString()}`),console.log(` - emissive: ${(p=s.emissive)==null?void 0:p.getHexString()}`),console.log(` - emissiveIntensity: ${s.emissiveIntensity}`),console.log(` - roughness: ${s.roughness}`),console.log(` - metalness: ${s.metalness}`)},u=e.useCallback((s,l)=>{const f=typeof l=="string"?{map:l}:l,S=a.current.get(s);if(!S||!S.isMeshStandardMaterial){console.warn(`Material "${s}" not found or not MeshStandardMaterial`);return}const p=S;Object.entries(f).forEach(([A,E])=>{if(!E)return;const d=`${s}_${A}_${E}`,w=y.current.get(d);if(w){i(p,A,w);return}n(E).load(E,x=>{x.colorSpace=A==="map"||A==="emissiveMap"?R.SRGBColorSpace:R.NoColorSpace,x.wrapS=R.RepeatWrapping,x.wrapT=R.RepeatWrapping,y.current.set(d,x),i(p,A,x)},void 0,x=>{console.error(`Failed to load texture ${E}:`,x)})})},[n]),m=e.useCallback(()=>Array.from(a.current.keys()).sort(),[]),b=e.useCallback(s=>{const l=a.current.get(s);if(!l||!l.isMeshStandardMaterial)return;const f=l;f.map=null,f.normalMap=null,f.roughnessMap=null,f.metalnessMap=null,f.emissiveMap=null,f.alphaMap=null,f.aoMap=null,f.needsUpdate=!0},[]);return{setMaterialTextures:u,getMaterialNames:m,clearMaterialTextures:b}}function te({url:t,position:r=[0,0,0],rotation:o=[0,0,0],scale:a=1,meshVisibility:c,materialColors:g,materialTextures:y,onLoad:T,onError:h}){const{scene:n}=I.useGLTF(t),i=e.useRef(T);i.current=T;const u=e.useMemo(()=>{const b=n.clone();console.log("[Model] 🔍 Scene clone created, checking materials...");const s=[],l=new Set,f=[];let S=0;return b.traverse(p=>{if(S++,p.type==="Bone"&&f.push(p.name),p.isMesh){const A=p;s.push(A.name),A.castShadow=!0,A.receiveShadow=!0,(Array.isArray(A.material)?A.material:[A.material]).forEach(d=>{l.add(d.name),console.log(`[Model] 📦 Material found: "${d.name}" (uuid: ${d.uuid})`);const w=d;console.log(` - Has map: ${w.map?"YES":"NO"}`),console.log(` - Has normalMap: ${w.normalMap?"YES":"NO"}`),console.log(` - Has roughnessMap: ${w.roughnessMap?"YES":"NO"}`),console.log(` - Has metalnessMap: ${w.metalnessMap?"YES":"NO"}`)})}}),console.log(`[Model] 📊 Clone summary: ${s.length} meshes, ${l.size} materials`),setTimeout(()=>{var p;(p=i.current)==null||p.call(i,{meshes:s.sort(),materials:Array.from(l).sort(),bones:f.sort(),nodeCount:S})},0),b},[n]);K(u,c),G(u,g),z(u,y);const m=typeof a=="number"?[a,a,a]:a;return M.jsx("group",{position:r,rotation:o,scale:m,children:M.jsx("primitive",{object:u})})}te.preload=t=>{I.useGLTF.preload(t)};function re(t,r,o){const{actions:a,names:c}=I.useAnimations(t,r),g=e.useRef(null),y=e.useRef(o==null?void 0:o.defaultAnimation);e.useEffect(()=>{if(c.length===0)return;const i=y.current;let u=c[0];if(i){const b=c.find(s=>s===i||s.includes(i));b&&(u=b)}const m=a[u];m&&(m.reset().fadeIn(.5).play(),g.current=m)},[a,c]);const T=e.useCallback((i,u)=>{const{loop:m=!1,crossFadeDuration:b=.2,restoreDefault:s=!0}=u||{};let l=a[i];if(!l){const S=Object.keys(a).find(p=>p.toLowerCase().includes(i.toLowerCase())||i.toLowerCase().includes(p.toLowerCase()));S&&(l=a[S])}if(!l){console.warn(`Animation "${i}" not found. Available: ${c.join(", ")}`);return}const f=g.current;if(!(f===l&&l.isRunning())&&(f&&f!==l&&f.fadeOut(b),l.reset(),l.fadeIn(b),l.setLoop(m?R.LoopRepeat:R.LoopOnce,m?1/0:1),l.clampWhenFinished=!m,l.play(),m||l.getMixer().update(0),g.current=l,s&&!m&&y.current)){const S=l.getMixer(),p=A=>{if(A.action===l){S.removeEventListener("finished",p);const E=a[y.current];E&&(l.fadeOut(b),E.reset().fadeIn(b).play(),g.current=E)}};S.addEventListener("finished",p)}},[a,c]),h=e.useCallback(()=>{var i;(i=g.current)==null||i.fadeOut(.2),g.current=null},[]),n=e.useCallback(()=>c,[c]);return{playAnimation:T,stopAnimation:h,getAnimationNames:n,actions:a}}function q(t,r){const o=e.useRef(r||{}),a=e.useRef([]),c=e.useRef([]);e.useEffect(()=>{const h=new Set,n=[];t.traverse(i=>{i instanceof R.Mesh&&i.morphTargetDictionary&&i.morphTargetInfluences&&(n.push(i),Object.keys(i.morphTargetDictionary).forEach(u=>{h.add(u)}))}),a.current=Array.from(h).sort(),c.current=n},[t]),B.useFrame(()=>{const h=o.current;c.current.forEach(n=>{!n.morphTargetDictionary||!n.morphTargetInfluences||Object.entries(h).forEach(([i,u])=>{const m=n.morphTargetDictionary[i];m!==void 0&&(n.morphTargetInfluences[m]=u)})})}),e.useEffect(()=>{r&&(o.current={...r})},[r]);const g=e.useCallback((h,n)=>{o.current[h]=Math.max(0,Math.min(1,n))},[]),y=e.useCallback(()=>a.current,[]),T=e.useCallback(()=>({...o.current}),[]);return{setMorphTarget:g,getMorphTargetNames:y,getMorphTargetValues:T}}const oe=e.createContext(null);function ge(){const t=e.useContext(oe);if(!t)throw new Error("BoneAttachment must be used within an AnimatedModel");return t}const V=e.forwardRef(({url:t,position:r=[0,0,0],rotation:o=[0,0,0],scale:a=1,defaultAnimation:c,morphTargets:g,meshVisibility:y,materialColors:T,materialTextures:h,onLoad:n,onError:i,children:u},m)=>{const b=e.useRef(null),s=e.useRef([]),l=e.useRef(n);l.current=n;const{scene:f,animations:S}=I.useGLTF(t),p=e.useMemo(()=>ee.clone(f),[f]),{playAnimation:A,stopAnimation:E,getAnimationNames:d}=re(S,p,{defaultAnimation:c}),{setMorphTarget:w}=q(p,g),{setMeshVisibility:N,getMeshNames:x}=K(p,y),{setMaterialColor:v,getMaterialNames:L,getMaterialColor:$}=G(p,T),{setMaterialTextures:j,clearMaterialTextures:C}=z(p,h);e.useEffect(()=>{if(!p)return;const P=setTimeout(()=>{var J;const O=[],W=[],_=new Set,Y=new Set;let Z=0;p.traverse(F=>{if(Z++,F.type==="Bone"&&O.push(F.name),F.isMesh){const X=F;W.push(X.name),X.castShadow=!0,X.receiveShadow=!0,(Array.isArray(X.material)?X.material:[X.material]).forEach(U=>{_.add(U.name),U.shadowSide=R.DoubleSide}),X.morphTargetDictionary&&Object.keys(X.morphTargetDictionary).forEach(U=>{Y.add(U)})}}),s.current=Array.from(Y).sort(),(J=l.current)==null||J.call(l,{meshes:W.sort(),materials:Array.from(_).sort(),bones:O.sort(),nodeCount:Z,animations:S.map(F=>F.name),morphTargetNames:s.current})},0);return()=>clearTimeout(P)},[p,S]),e.useImperativeHandle(m,()=>({playAnimation:A,stopAnimation:E,getAnimationNames:d,getGroup:()=>b.current,setMorphTarget:w,getMorphTargetNames:()=>s.current,setMeshVisibility:N,getMeshNames:x,setMaterialColor:v,getMaterialNames:L,getMaterialColor:$,setMaterialTextures:j,clearMaterialTextures:C}));const k=e.useMemo(()=>({scene:p,getBone:P=>p.getObjectByName(P)||null}),[p]),D=typeof a=="number"?[a,a,a]:a;return M.jsx(oe.Provider,{value:k,children:M.jsxs("group",{ref:b,position:r,rotation:o,scale:D,children:[M.jsx("primitive",{object:p}),u]})})});V.displayName="AnimatedModel";V.preload=t=>{I.useGLTF.preload(t)};const se=e.forwardRef(({url:t,position:r=[0,0,0],rotation:o=[0,0,0],scale:a=1,morphTargets:c,meshVisibility:g,materialColors:y,materialTextures:T,onMorphTargetsFound:h,onLoad:n,onError:i},u)=>{const{scene:m}=I.useGLTF(t),b=e.useRef(n);b.current=n;const s=e.useRef(h);s.current=h;const l=e.useMemo(()=>m.clone(),[m]),{setMorphTarget:f,getMorphTargetNames:S,getMorphTargetValues:p}=q(l,c),{setMeshVisibility:A,getMeshNames:E}=K(l,g),{setMaterialColor:d,getMaterialNames:w,getMaterialColor:N}=G(l,y),{setMaterialTextures:x,clearMaterialTextures:v}=z(l,T);e.useEffect(()=>{var j;const $=S();$.length>0&&((j=s.current)==null||j.call(s,$))},[l,S]),e.useEffect(()=>{var D;if(!l)return;const $=[],j=new Set,C=[];let k=0;l.traverse(P=>{if(k++,P.type==="Bone"&&C.push(P.name),P.isMesh){const O=P;$.push(O.name),O.castShadow=!0,O.receiveShadow=!0,(Array.isArray(O.material)?O.material:[O.material]).forEach(_=>j.add(_.name))}}),(D=b.current)==null||D.call(b,{meshes:$.sort(),materials:Array.from(j).sort(),bones:C.sort(),nodeCount:k})},[l]),e.useImperativeHandle(u,()=>({setMorphTarget:f,getMorphTargetNames:S,getMorphTargetValues:p,setMeshVisibility:A,getMeshNames:E,setMaterialColor:d,getMaterialNames:w,getMaterialColor:N,setMaterialTextures:x,clearMaterialTextures:v}));const L=typeof a=="number"?[a,a,a]:a;return M.jsx("group",{position:r,rotation:o,scale:L,children:M.jsx("primitive",{object:l})})});se.displayName="MorphableModel";function he({children:t,bone:r,position:o=[0,0,0],rotation:a=[0,0,0],scale:c=1}){const{getBone:g}=ge(),[y,T]=e.useState(null);if(e.useEffect(()=>{const n=g(r);n?T(n):console.warn(`Bone "${r}" not found in model`)},[r,g]),!y)return null;const h=typeof c=="number"?[c,c,c]:c;return B.createPortal(M.jsx("group",{position:o,rotation:a,scale:h,children:t}),y)}function Me(t,r){const{scene:o,animations:a}=I.useGLTF(t),c=e.useMemo(()=>ee.clone(o),[o]);return e.useEffect(()=>{var n;if(!c)return;const g=[],y=[],T=new Set;let h=0;c.traverse(i=>{if(h++,i.type==="Bone"&&g.push(i.name),i.isMesh){const u=i;y.push(u.name),u.castShadow=!0,u.receiveShadow=!0,(Array.isArray(u.material)?u.material:[u.material]).forEach(b=>{T.add(b.name),b.shadowSide=R.DoubleSide})}}),(n=r==null?void 0:r.onLoad)==null||n.call(r,{meshes:y.sort(),materials:Array.from(T).sort(),bones:g.sort(),nodeCount:h})},[c,r]),{scene:c,animations:a}}function be(t){I.useGLTF.preload(t)}exports.AnimatedModel=V;exports.BoneAttachment=he;exports.Model=te;exports.MorphableModel=se;exports.Scene3D=de;exports.preloadModel=be;exports.useAnimationController=re;exports.useClonedModel=Me;exports.useMaterialColor=G;exports.useMaterialTexture=z;exports.useMeshVisibility=K;exports.useMorphTargets=q;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react"),B=require("@react-three/drei"),ae=require("three"),ie=require("three/examples/jsm/utils/SkeletonUtils.js"),P=require("@react-three/fiber"),le=require("three/examples/jsm/loaders/KTX2Loader.js"),b=require("react/jsx-runtime");function ee(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const e in r)if(e!=="default"){const a=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(t,e,a.get?a:{enumerable:!0,get:()=>r[e]})}}return t.default=r,Object.freeze(t)}const v=ee(ae),te=ee(ie);function ce({position:r,target:t,controlsConfig:e}){const{camera:a}=P.useThree(),u=n.useRef(null);return n.useEffect(()=>{a&&(a.position.set(r[0],r[1],r[2]),a.updateProjectionMatrix(),u.current&&(u.current.target.set(t[0],t[1],t[2]),u.current.update()))},[r,t,a]),b.jsx(B.OrbitControls,{ref:u,makeDefault:!0,enabled:e.enabled,enablePan:e.enablePan,enableZoom:e.enableZoom,enableRotate:e.enableRotate,minDistance:e.minDistance,maxDistance:e.maxDistance,minPolarAngle:e.minPolarAngle,maxPolarAngle:e.maxPolarAngle,autoRotate:e.autoRotate,autoRotateSpeed:e.autoRotateSpeed})}function ue({background:r}){const t=r==null?void 0:r.startsWith("#");return r?t?b.jsx("color",{attach:"background",args:[r]}):b.jsx(pe,{url:r}):null}function pe({url:r}){const t=B.useTexture(r);return n.useMemo(()=>{t.colorSpace=v.SRGBColorSpace},[t]),b.jsx("primitive",{attach:"background",object:t})}function fe({config:r}){return b.jsx(B.Environment,{files:r.files,background:r.background??!1,blur:r.blur??0})}function de({config:r}){const{scene:t}=P.useThree();return n.useEffect(()=>{const e=r.intensity??1,a=r.blur??0,u="environmentIntensity"in t,p="backgroundBlurriness"in t,h="backgroundIntensity"in t,S=u?t.environmentIntensity:void 0,m=p?t.backgroundBlurriness:void 0,i=h?t.backgroundIntensity:void 0;return u&&(t.environmentIntensity=e),p&&(t.backgroundBlurriness=a),r.background&&h&&(t.backgroundIntensity=e),()=>{u&&(t.environmentIntensity=S??1),p&&(t.backgroundBlurriness=m??0),h&&(t.backgroundIntensity=i??1)}},[t,r]),null}const me={NoToneMapping:v.NoToneMapping,LinearToneMapping:v.LinearToneMapping,ReinhardToneMapping:v.ReinhardToneMapping,CineonToneMapping:v.CineonToneMapping,ACESFilmicToneMapping:v.ACESFilmicToneMapping};function ge({config:r}){const{gl:t}=P.useThree();return n.useEffect(()=>{const e=r.outputColorSpace==="linear"?v.LinearSRGBColorSpace:v.SRGBColorSpace,a=me[r.toneMapping??"ACESFilmicToneMapping"];t.physicallyCorrectLights=r.physicallyCorrectLights??!0,t.outputColorSpace=e,t.toneMapping=a,t.toneMappingExposure=r.toneMappingExposure??1},[t,r]),null}function he({config:r}){switch(r.type){case"spot":{const{position:t=[5,10,5],intensity:e=50,castShadow:a=!0,shadowMapSize:u=2048,angle:p=Math.PI/6,penumbra:h=.5,decay:S=2,distance:m=0,color:i="#ffffff"}=r;return b.jsx("spotLight",{position:t,intensity:e,castShadow:a,angle:p,penumbra:h,decay:S,distance:m,color:i,"shadow-mapSize-width":u,"shadow-mapSize-height":u})}case"point":{const{position:t=[0,5,0],intensity:e=20,color:a="#ffffff",distance:u=0,decay:p=2,castShadow:h=!1,shadowMapSize:S=2048}=r;return b.jsx("pointLight",{position:t,intensity:e,color:a,distance:u,decay:p,castShadow:h,"shadow-mapSize-width":S,"shadow-mapSize-height":S})}case"directional":{const{position:t=[10,20,10],intensity:e=40,color:a="#ffffff",castShadow:u=!0,shadowMapSize:p=2048}=r;return b.jsx("directionalLight",{position:t,intensity:e,color:a,castShadow:u,"shadow-mapSize-width":p,"shadow-mapSize-height":p})}case"hemisphere":{const{skyColor:t="#ffffff",groundColor:e="#444444",intensity:a=.5,position:u=[0,10,0]}=r,p=n.useMemo(()=>new v.Color(t),[t]),h=n.useMemo(()=>new v.Color(e),[e]);return b.jsx("hemisphereLight",{args:[p,h,a],position:u})}case"ambient":{const{intensity:t=.5,color:e="#ffffff"}=r;return b.jsx("ambientLight",{intensity:t,color:e})}default:return null}}function Me({onChange:r}){const{active:t,progress:e}=B.useProgress();return n.useEffect(()=>{r(t,e)},[t,e,r]),null}function be({children:r,camera:t={},controls:e={},background:a,shadows:u=!0,lights:p=[{type:"ambient",intensity:.5},{type:"spot",position:[5,10,5],intensity:50,castShadow:!0}],environment:h,renderer:S={physicallyCorrectLights:!0,outputColorSpace:"srgb",toneMapping:"ACESFilmicToneMapping",toneMappingExposure:1},contactShadows:m=!0,showLoadingOverlay:i=!0,style:s,className:f}){const[g,y]=n.useState(!1),[o,l]=n.useState(0),c=n.useRef(null),E=n.useCallback((d,w)=>{if(d){c.current!==null&&(window.clearTimeout(c.current),c.current=null),y(!0),l(Math.max(0,Math.min(100,Math.round(w))));return}l(100),c.current=window.setTimeout(()=>{y(!1),l(0),c.current=null},200)},[]);n.useEffect(()=>()=>{c.current!==null&&window.clearTimeout(c.current)},[]);const M={position:t.position||[0,2,5],fov:t.fov||45},T={target:e.target||[0,0,0],enabled:e.enabled??!0,enablePan:e.enablePan??!0,enableZoom:e.enableZoom??!0,enableRotate:e.enableRotate??!0,minDistance:e.minDistance,maxDistance:e.maxDistance,minPolarAngle:e.minPolarAngle,maxPolarAngle:e.maxPolarAngle,autoRotate:e.autoRotate??!1,autoRotateSpeed:e.autoRotateSpeed??2},C=typeof m=="object"?{position:m.position||[0,-1,0],opacity:m.opacity??.5,blur:m.blur??2}:m?{position:[0,-1,0],opacity:.5,blur:2}:null;return b.jsxs("div",{style:{...s||{},position:(s==null?void 0:s.position)??"relative"},className:f,children:[b.jsxs(P.Canvas,{shadows:u,camera:{position:M.position,fov:M.fov},style:{width:"100%",height:"100%"},children:[b.jsx(n.Suspense,{fallback:null,children:b.jsx(ue,{background:a})}),h&&b.jsxs(n.Suspense,{fallback:null,children:[b.jsx(fe,{config:h}),b.jsx(de,{config:h})]}),b.jsx(ge,{config:S}),p.map((d,w)=>b.jsx(he,{config:d},`${d.type}-${w}`)),b.jsx(n.Suspense,{fallback:null,children:r}),b.jsx(ce,{position:M.position,target:T.target,controlsConfig:T}),C&&b.jsx(B.ContactShadows,{position:C.position,opacity:C.opacity,blur:C.blur}),b.jsx(Me,{onChange:E})]}),i&&g&&b.jsx("div",{style:{position:"absolute",inset:0,background:"rgba(8, 10, 16, 0.56)",backdropFilter:"blur(18px)",WebkitBackdropFilter:"blur(18px)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none",zIndex:10},children:b.jsxs("div",{style:{minWidth:220,padding:"16px 18px",borderRadius:14,border:"1px solid rgba(255,255,255,0.2)",background:"linear-gradient(180deg, rgba(18,24,36,0.9), rgba(13,17,27,0.9))",color:"#eef3ff",boxShadow:"0 10px 30px rgba(0,0,0,0.35)",fontFamily:"system-ui, -apple-system, Segoe UI, sans-serif",textAlign:"center"},children:[b.jsx("div",{style:{display:"flex",justifyContent:"center",marginBottom:10},children:b.jsxs("svg",{width:"34",height:"34",viewBox:"0 0 34 34","aria-hidden":"true",children:[b.jsx("circle",{cx:"17",cy:"17",r:"14",fill:"none",stroke:"rgba(255,255,255,0.2)",strokeWidth:"4"}),b.jsx("path",{d:"M31 17a14 14 0 0 1-14 14",fill:"none",stroke:"#67b4ff",strokeWidth:"4",strokeLinecap:"round",children:b.jsx("animateTransform",{attributeName:"transform",type:"rotate",from:"0 17 17",to:"360 17 17",dur:"0.9s",repeatCount:"indefinite"})})]})}),b.jsxs("div",{style:{fontSize:12,opacity:.82,marginTop:4},children:[o,"%"]})]})})]})}function H(r,t){const e=n.useRef(new Map),a=n.useRef({}),u=n.useRef({});n.useEffect(()=>{t&&(a.current={...t})},[t]),n.useEffect(()=>{if(!r)return;const m=new Map;r.traverse(i=>{if(i.isMesh){const s=i;s.name&&m.set(s.name,s)}}),e.current=m},[r]),P.useFrame(()=>{const m=e.current;if(m.size===0)return;const i={...a.current,...u.current};for(const[s,f]of Object.entries(i)){const g=m.get(s);g&&g.visible!==f&&(g.visible=f)}});const p=n.useCallback((m,i)=>{u.current[m]=i;const s=e.current.get(m);s&&(s.visible=i)},[]),h=n.useCallback(()=>Array.from(e.current.keys()).sort(),[]),S=n.useCallback(()=>{const m={};return e.current.forEach((i,s)=>{m[s]=i.visible}),m},[]);return{setMeshVisibility:p,getMeshNames:h,getMeshVisibility:S}}function G(r,t){const e=n.useRef(new Map),a=n.useRef(new Map);n.useEffect(()=>{if(!r)return;const i=new Map;r.traverse(s=>{if(s.isMesh){const f=s;(Array.isArray(f.material)?f.material:[f.material]).forEach(y=>{y.name&&!i.has(y.name)&&i.set(y.name,y)})}}),e.current=i,t&&Object.entries(t).forEach(([s,f])=>{const g=i.get(s);if(g&&!Array.isArray(g)){const y=u(f);g.color&&g.color.copy(y),a.current.set(s,y)}})},[r,t]),P.useFrame(()=>{a.current.forEach((i,s)=>{const f=e.current.get(s);if(f&&!Array.isArray(f)){const g=f;g.color&&!g.color.equals(i)&&(g.color.copy(i),g.needsUpdate=!0)}})});const u=i=>typeof i=="string"?new v.Color(i):new v.Color(i[0],i[1],i[2]),p=n.useCallback((i,s)=>{const f=u(s);a.current.set(i,f);const g=e.current.get(i);if(g&&!Array.isArray(g)){const y=g;y.color&&(y.color.copy(f),y.needsUpdate=!0)}},[]),h=n.useCallback(()=>Array.from(e.current.keys()).sort(),[]),S=n.useCallback(i=>{const s=e.current.get(i);if(s&&!Array.isArray(s)){const f=s;if(f.color)return"#"+f.color.getHexString()}return null},[]),m=n.useCallback(()=>{const i={};return e.current.forEach((s,f)=>{if(!Array.isArray(s)){const g=s;g.color&&(i[f]="#"+g.color.getHexString())}}),i},[]);return{setMaterialColor:p,getMaterialNames:h,getMaterialColor:S,getAllMaterialColors:m}}function U(r){const t=r.toLowerCase();if(t.endsWith(".ktx2"))return!0;try{const e=new URL(r,window.location.origin),a=decodeURIComponent(e.hash.replace(/^#/,"")).toLowerCase(),u=decodeURIComponent(e.search).toLowerCase(),p=decodeURIComponent(e.pathname).toLowerCase();return a.endsWith(".ktx2")||u.includes(".ktx2")||p.endsWith(".ktx2")}catch{return t.includes(".ktx2")}}function K(r,t){const{gl:e}=P.useThree(),a=n.useRef(new Map),u=n.useRef(new v.TextureLoader),p=n.useRef(null),h=n.useRef(new Map),S=n.useRef(new Set),m=n.useRef("");n.useEffect(()=>{if(!p.current)try{const o=typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function";console.log("[useMaterialTexture] Browser features:"),console.log(` WebAssembly supported: ${o}`),console.log(` WebGL2: ${e.capabilities.isWebGL2}`);const l=new le.KTX2Loader;l.setTranscoderPath("/basis/"),l.detectSupport(e),p.current=l,console.log("[useMaterialTexture] ✅ KTX2Loader initialized"),console.log("[useMaterialTexture] Transcoder path: /basis/"),fetch("/basis/basis_transcoder.wasm").then(c=>{c.ok?console.log("[useMaterialTexture] ✅ basis_transcoder.wasm is accessible"):console.error("[useMaterialTexture] ❌ basis_transcoder.wasm returned",c.status)}).catch(c=>{console.error("[useMaterialTexture] ❌ Failed to check basis_transcoder.wasm:",c)}),o||(console.warn("[useMaterialTexture] ⚠️ WebAssembly not supported! KTX2 will fallback to CPU decoding (slow)"),console.warn("[useMaterialTexture] ⚠️ Recommend using WebP instead of KTX2 for this browser"))}catch(o){console.error("[useMaterialTexture] ❌ Failed to initialize KTX2Loader:",o)}return()=>{p.current&&(p.current.dispose(),p.current=null)}},[e]),n.useEffect(()=>{if(!r)return;const o=new Map;r.traverse(l=>{if(l.isMesh){const c=l;(Array.isArray(c.material)?c.material:[c.material]).forEach(M=>{M.name&&!o.has(M.name)&&o.set(M.name,M)})}}),a.current=o},[r]);const i=n.useCallback(o=>U(o)?p.current?p.current:(console.warn("[useMaterialTexture] KTX2Loader not initialized, falling back to TextureLoader"),u.current):u.current,[]);n.useEffect(()=>{if(!t||!r)return;const o=a.current;if(o.size===0)return;const l=JSON.stringify(t);if(m.current===l){console.log("[useMaterialTexture] Textures unchanged, skipping reload");return}m.current=l;let c=!1;const E=new Map;Object.entries(t).forEach(([d,w])=>{E.set(d,typeof w=="string"?{map:w}:w)}),console.log("[useMaterialTexture] Starting texture load for",E.size,"materials");const M=[];E.forEach((d,w)=>{var A,I;const O=o.get(w);if(!O||!O.isMeshStandardMaterial){console.warn(`[useMaterialTexture] Material "${w}" not found or not MeshStandardMaterial`);return}const x=O;console.log(`[useMaterialTexture] 📋 Material "${w}" BEFORE reset:`),console.log(` - map: ${x.map?"EXISTS":"null"} ${x.map?`(uuid: ${x.map.uuid})`:""}`),console.log(` - normalMap: ${x.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${x.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${x.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${x.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${x.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(A=x.color)==null?void 0:A.getHexString()}`),console.log(` - emissive: ${(I=x.emissive)==null?void 0:I.getHexString()}`),console.log(` - material uuid: ${x.uuid}`),Object.entries(d).forEach(([$,k])=>{if(!k)return;const R=$,j=x[R];j&&(console.log(`[useMaterialTexture] 🗑️ Disposing old ${R} (uuid: ${j.uuid})`),j.dispose(),x[R]=null)}),d.emissiveMap&&(x.emissive=new v.Color(0),x.emissiveIntensity=0),x.needsUpdate=!0,x.color=new v.Color(16777215),console.log(`[useMaterialTexture] ✅ Material "${w}" AFTER reset: only specified maps cleared`),Object.entries(d).forEach(([$,k])=>{if(!k)return;const R=`${w}_${$}_${k}`,j=h.current.get(R);if(j){console.log(`[useMaterialTexture] Using cached texture: ${w}.${$}`),c||s(x,$,j);return}if(S.current.has(R)){console.log(`[useMaterialTexture] Skipping already loading: ${w}.${$}`);return}M.push({materialName:w,textureType:$,url:k,material:x})})}),console.log(`[useMaterialTexture] Queued ${M.length} textures to load`);let T=0;const C=()=>{if(c||T>=M.length){console.log("[useMaterialTexture] ✅ All textures loaded"),console.log("[useMaterialTexture] 📊 FINAL material states:"),o.forEach((A,I)=>{var k,R;const $=A;console.log(` Material "${I}":`),console.log(` - map: ${$.map?"EXISTS":"null"} ${$.map?`(colorSpace: ${$.map.colorSpace})`:""}`),console.log(` - normalMap: ${$.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${$.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${$.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${$.emissiveMap?"EXISTS":"null"}`),console.log(` - color: ${(k=$.color)==null?void 0:k.getHexString()}`),console.log(` - emissive: ${(R=$.emissive)==null?void 0:R.getHexString()}`),console.log(` - emissiveIntensity: ${$.emissiveIntensity}`),console.log(` - roughness: ${$.roughness}`),console.log(` - metalness: ${$.metalness}`)});return}const d=M[T++],w=`${d.materialName}_${d.textureType}_${d.url}`;console.log(`[useMaterialTexture] Loading (${T}/${M.length}): ${d.materialName}.${d.textureType} from ${d.url}`),S.current.add(w);const O=i(d.url),x=U(d.url)?"KTX2Loader":"TextureLoader";console.log(`[useMaterialTexture] Using ${x} for ${d.url}`),O.load(d.url,A=>{var R,j,X,N,L,D;if(S.current.delete(w),c){console.log(`[useMaterialTexture] Disposed, cleaning up texture: ${d.materialName}.${d.textureType}`),A.dispose();return}const I=((R=A.image)==null?void 0:R.width)||((X=(j=A.source)==null?void 0:j.data)==null?void 0:X.width)||"unknown",$=((N=A.image)==null?void 0:N.height)||((D=(L=A.source)==null?void 0:L.data)==null?void 0:D.height)||"unknown";console.log(`[useMaterialTexture] ✅ Loaded: ${d.materialName}.${d.textureType} (${I}x${$})`),A.colorSpace=d.textureType==="map"||d.textureType==="emissiveMap"?v.SRGBColorSpace:v.NoColorSpace,A.wrapS=v.RepeatWrapping,A.wrapT=v.RepeatWrapping,A.flipY=!1,h.current.set(w,A),s(d.material,d.textureType,A);const k=U(d.url)?500:150;console.log(`[useMaterialTexture] Waiting111111 ${k}ms before next texture...`),setTimeout(C,0)},A=>{if(A.lengthComputable){const I=Math.round(A.loaded/A.total*100);I%25===0&&console.log(`[useMaterialTexture] Progress ${d.materialName}.${d.textureType}: ${I}%`)}},A=>{S.current.delete(w),c||(console.error(`[useMaterialTexture] ❌ Failed to load ${d.materialName}.${d.textureType} from ${d.url}`),console.error("[useMaterialTexture] Error details:",A),console.error("[useMaterialTexture] Loader type:",x),U(d.url)&&(console.error("[useMaterialTexture] KTX2 error - file may not be in Basis Universal format!"),console.error("[useMaterialTexture] Make sure files are created with: gltf-transform etc1s input.png output.ktx2"))),setTimeout(C,100)})};return C(),()=>{console.log("[useMaterialTexture] Cleanup: disposed"),c=!0}},[r,t,i]);const s=(o,l,c)=>{var E,M;switch(console.log(`[useMaterialTexture] 🎨 Applying texture: ${o.name}.${l} (texture uuid: ${c.uuid})`),l){case"map":o.map=c;break;case"normalMap":o.normalMap=c;break;case"roughnessMap":o.roughnessMap=c;break;case"metalnessMap":o.metalnessMap=c;break;case"emissiveMap":o.emissiveMap=c,o.emissive=new v.Color(16777215),o.emissiveIntensity=1;break;case"alphaMap":o.alphaMap=c,o.transparent=!0,o.alphaTest=Math.max(o.alphaTest??0,.001),o.depthWrite=!1;break;case"aoMap":o.aoMap=c;break}o.needsUpdate=!0,console.log(`[useMaterialTexture] ✅ Applied ${l} to ${o.name}, needsUpdate=true`),console.log(`[useMaterialTexture] 📊 Material "${o.name}" FINAL state:`),console.log(` - map: ${o.map?"EXISTS":"null"} ${o.map?`(uuid: ${o.map.uuid}, colorSpace: ${o.map.colorSpace})`:""}`),console.log(` - normalMap: ${o.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${o.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${o.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${o.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${o.aoMap?"EXISTS":"null"}`),console.log(` - alphaMap: ${o.alphaMap?"EXISTS":"null"}`),console.log(` - transparent: ${o.transparent}`),console.log(` - alphaTest: ${o.alphaTest}`),console.log(` - depthWrite: ${o.depthWrite}`),console.log(` - color: ${(E=o.color)==null?void 0:E.getHexString()}`),console.log(` - emissive: ${(M=o.emissive)==null?void 0:M.getHexString()}`),console.log(` - emissiveIntensity: ${o.emissiveIntensity}`),console.log(` - roughness: ${o.roughness}`),console.log(` - metalness: ${o.metalness}`)},f=n.useCallback((o,l)=>{const c=typeof l=="string"?{map:l}:l,E=a.current.get(o);if(!E||!E.isMeshStandardMaterial){console.warn(`Material "${o}" not found or not MeshStandardMaterial`);return}const M=E;Object.entries(c).forEach(([T,C])=>{if(!C)return;const d=`${o}_${T}_${C}`,w=h.current.get(d);if(w){s(M,T,w);return}i(C).load(C,x=>{x.colorSpace=T==="map"||T==="emissiveMap"?v.SRGBColorSpace:v.NoColorSpace,x.wrapS=v.RepeatWrapping,x.wrapT=v.RepeatWrapping,h.current.set(d,x),s(M,T,x)},void 0,x=>{console.error(`Failed to load texture ${C}:`,x)})})},[i]),g=n.useCallback(()=>Array.from(a.current.keys()).sort(),[]),y=n.useCallback(o=>{const l=a.current.get(o);if(!l||!l.isMeshStandardMaterial)return;const c=l;c.map=null,c.normalMap=null,c.roughnessMap=null,c.metalnessMap=null,c.emissiveMap=null,c.alphaMap=null,c.aoMap=null,c.transparent=!1,c.alphaTest=0,c.depthWrite=!0,c.needsUpdate=!0},[]);return{setMaterialTextures:f,getMaterialNames:g,clearMaterialTextures:y}}function re({url:r,position:t=[0,0,0],rotation:e=[0,0,0],scale:a=1,meshVisibility:u,materialColors:p,materialTextures:h,onLoad:S,onError:m}){const{scene:i}=B.useGLTF(r),s=n.useRef(S);s.current=S;const f=n.useMemo(()=>{const y=i.clone();console.log("[Model] 🔍 Scene clone created, checking materials...");const o=[],l=new Set,c=[];let E=0;return y.traverse(M=>{if(E++,M.type==="Bone"&&c.push(M.name),M.isMesh){const T=M;o.push(T.name),T.castShadow=!0,T.receiveShadow=!0,(Array.isArray(T.material)?T.material:[T.material]).forEach(d=>{l.add(d.name),console.log(`[Model] 📦 Material found: "${d.name}" (uuid: ${d.uuid})`);const w=d;console.log(` - Has map: ${w.map?"YES":"NO"}`),console.log(` - Has normalMap: ${w.normalMap?"YES":"NO"}`),console.log(` - Has roughnessMap: ${w.roughnessMap?"YES":"NO"}`),console.log(` - Has metalnessMap: ${w.metalnessMap?"YES":"NO"}`)})}}),console.log(`[Model] 📊 Clone summary: ${o.length} meshes, ${l.size} materials`),setTimeout(()=>{var M;(M=s.current)==null||M.call(s,{meshes:o.sort(),materials:Array.from(l).sort(),bones:c.sort(),nodeCount:E})},0),y},[i]);H(f,u),G(f,p),K(f,h);const g=typeof a=="number"?[a,a,a]:a;return b.jsx("group",{position:t,rotation:e,scale:g,children:b.jsx("primitive",{object:f})})}re.preload=r=>{B.useGLTF.preload(r)};function ne(r,t,e){const{actions:a,names:u}=B.useAnimations(r,t),p=n.useRef(null),h=n.useRef(e==null?void 0:e.defaultAnimation);n.useEffect(()=>{h.current=e==null?void 0:e.defaultAnimation},[e==null?void 0:e.defaultAnimation]),n.useEffect(()=>{if(u.length===0)return;const s=h.current;let f=u[0];if(s){const y=u.find(o=>o===s||o.includes(s));y&&(f=y)}const g=a[f];g&&(g.reset().fadeIn(.5).play(),p.current=g)},[a,u]);const S=n.useCallback((s,f)=>{const{loop:g=!1,crossFadeDuration:y=.2,restoreDefault:o=!0}=f||{};let l=a[s];if(!l){const E=Object.keys(a).find(M=>M.toLowerCase().includes(s.toLowerCase())||s.toLowerCase().includes(M.toLowerCase()));E&&(l=a[E])}if(!l){console.warn(`Animation "${s}" not found. Available: ${u.join(", ")}`);return}const c=p.current;if(!(c===l&&l.isRunning())&&(c&&c!==l&&c.fadeOut(y),l.reset(),l.fadeIn(y),l.setLoop(g?v.LoopRepeat:v.LoopOnce,g?1/0:1),l.clampWhenFinished=!g,l.play(),g||l.getMixer().update(0),p.current=l,o&&!g&&h.current)){const E=l.getMixer(),M=T=>{if(T.action===l){E.removeEventListener("finished",M);const C=a[h.current];C&&(l.fadeOut(y),C.reset().fadeIn(y).play(),p.current=C)}};E.addEventListener("finished",M)}},[a,u]),m=n.useCallback(()=>{var s;(s=p.current)==null||s.fadeOut(.2),p.current=null},[]),i=n.useCallback(()=>u,[u]);return{playAnimation:S,stopAnimation:m,getAnimationNames:i,actions:a}}function q(r,t){const e=n.useRef(t||{}),a=n.useRef([]),u=n.useRef([]);n.useEffect(()=>{const m=new Set,i=[];r.traverse(s=>{s instanceof v.Mesh&&s.morphTargetDictionary&&s.morphTargetInfluences&&(i.push(s),Object.keys(s.morphTargetDictionary).forEach(f=>{m.add(f)}))}),a.current=Array.from(m).sort(),u.current=i},[r]),P.useFrame(()=>{const m=e.current;u.current.forEach(i=>{!i.morphTargetDictionary||!i.morphTargetInfluences||Object.entries(m).forEach(([s,f])=>{const g=i.morphTargetDictionary[s];g!==void 0&&(i.morphTargetInfluences[g]=f)})})}),n.useEffect(()=>{t&&(e.current={...t})},[t]);const p=n.useCallback((m,i)=>{e.current[m]=Math.max(0,Math.min(1,i))},[]),h=n.useCallback(()=>a.current,[]),S=n.useCallback(()=>({...e.current}),[]);return{setMorphTarget:p,getMorphTargetNames:h,getMorphTargetValues:S}}const oe=n.createContext(null);function ye(){const r=n.useContext(oe);if(!r)throw new Error("BoneAttachment must be used within an AnimatedModel");return r}const V=n.forwardRef(({url:r,position:t=[0,0,0],rotation:e=[0,0,0],scale:a=1,defaultAnimation:u,animation:p,morphTargets:h,meshVisibility:S,materialColors:m,materialTextures:i,onLoad:s,onError:f,children:g},y)=>{const o=n.useRef(null),l=n.useRef([]),c=n.useRef(s);c.current=s;const{scene:E,animations:M}=B.useGLTF(r),T=n.useMemo(()=>te.clone(E),[E]),{playAnimation:C,stopAnimation:d,getAnimationNames:w}=ne(M,T,{defaultAnimation:u});n.useEffect(()=>{p&&C(p,{loop:!0,restoreDefault:!1})},[p,C]);const{setMorphTarget:O}=q(T,h),{setMeshVisibility:x,getMeshNames:A}=H(T,S),{setMaterialColor:I,getMaterialNames:$,getMaterialColor:k}=G(T,m),{setMaterialTextures:R,clearMaterialTextures:j}=K(T,i);n.useEffect(()=>{if(!T)return;const L=setTimeout(()=>{var Q;const D=[],z=[],Y=new Set,Z=new Set;let J=0;T.traverse(F=>{if(J++,F.type==="Bone"&&D.push(F.name),F.isMesh){const W=F;z.push(W.name),W.castShadow=!0,W.receiveShadow=!0,(Array.isArray(W.material)?W.material:[W.material]).forEach(_=>{Y.add(_.name),_.shadowSide=v.DoubleSide}),W.morphTargetDictionary&&Object.keys(W.morphTargetDictionary).forEach(_=>{Z.add(_)})}}),l.current=Array.from(Z).sort(),(Q=c.current)==null||Q.call(c,{meshes:z.sort(),materials:Array.from(Y).sort(),bones:D.sort(),nodeCount:J,animations:M.map(F=>F.name),morphTargetNames:l.current})},0);return()=>clearTimeout(L)},[T,M]),n.useImperativeHandle(y,()=>({playAnimation:C,stopAnimation:d,getAnimationNames:w,getGroup:()=>o.current,setMorphTarget:O,getMorphTargetNames:()=>l.current,setMeshVisibility:x,getMeshNames:A,setMaterialColor:I,getMaterialNames:$,getMaterialColor:k,setMaterialTextures:R,clearMaterialTextures:j}));const X=n.useMemo(()=>({scene:T,getBone:L=>T.getObjectByName(L)||null}),[T]),N=typeof a=="number"?[a,a,a]:a;return b.jsx(oe.Provider,{value:X,children:b.jsxs("group",{ref:o,position:t,rotation:e,scale:N,children:[b.jsx("primitive",{object:T}),g]})})});V.displayName="AnimatedModel";V.preload=r=>{B.useGLTF.preload(r)};const se=n.forwardRef(({url:r,position:t=[0,0,0],rotation:e=[0,0,0],scale:a=1,morphTargets:u,meshVisibility:p,materialColors:h,materialTextures:S,onMorphTargetsFound:m,onLoad:i,onError:s},f)=>{const{scene:g}=B.useGLTF(r),y=n.useRef(i);y.current=i;const o=n.useRef(m);o.current=m;const l=n.useMemo(()=>g.clone(),[g]),{setMorphTarget:c,getMorphTargetNames:E,getMorphTargetValues:M}=q(l,u),{setMeshVisibility:T,getMeshNames:C}=H(l,p),{setMaterialColor:d,getMaterialNames:w,getMaterialColor:O}=G(l,h),{setMaterialTextures:x,clearMaterialTextures:A}=K(l,S);n.useEffect(()=>{var k;const $=E();$.length>0&&((k=o.current)==null||k.call(o,$))},[l,E]),n.useEffect(()=>{var X;if(!l)return;const $=[],k=new Set,R=[];let j=0;l.traverse(N=>{if(j++,N.type==="Bone"&&R.push(N.name),N.isMesh){const L=N;$.push(L.name),L.castShadow=!0,L.receiveShadow=!0,(Array.isArray(L.material)?L.material:[L.material]).forEach(z=>k.add(z.name))}}),(X=y.current)==null||X.call(y,{meshes:$.sort(),materials:Array.from(k).sort(),bones:R.sort(),nodeCount:j})},[l]),n.useImperativeHandle(f,()=>({setMorphTarget:c,getMorphTargetNames:E,getMorphTargetValues:M,setMeshVisibility:T,getMeshNames:C,setMaterialColor:d,getMaterialNames:w,getMaterialColor:O,setMaterialTextures:x,clearMaterialTextures:A}));const I=typeof a=="number"?[a,a,a]:a;return b.jsx("group",{position:t,rotation:e,scale:I,children:b.jsx("primitive",{object:l})})});se.displayName="MorphableModel";function Te({children:r,bone:t,position:e=[0,0,0],rotation:a=[0,0,0],scale:u=1}){const{getBone:p}=ye(),[h,S]=n.useState(null);if(n.useEffect(()=>{const i=p(t);i?S(i):console.warn(`Bone "${t}" not found in model`)},[t,p]),!h)return null;const m=typeof u=="number"?[u,u,u]:u;return P.createPortal(b.jsx("group",{position:e,rotation:a,scale:m,children:r}),h)}function xe(r,t){const{scene:e,animations:a}=B.useGLTF(r),u=n.useMemo(()=>te.clone(e),[e]);return n.useEffect(()=>{var i;if(!u)return;const p=[],h=[],S=new Set;let m=0;u.traverse(s=>{if(m++,s.type==="Bone"&&p.push(s.name),s.isMesh){const f=s;h.push(f.name),f.castShadow=!0,f.receiveShadow=!0,(Array.isArray(f.material)?f.material:[f.material]).forEach(y=>{S.add(y.name),y.shadowSide=v.DoubleSide})}}),(i=t==null?void 0:t.onLoad)==null||i.call(t,{meshes:h.sort(),materials:Array.from(S).sort(),bones:p.sort(),nodeCount:m})},[u,t]),{scene:u,animations:a}}function Se(r){B.useGLTF.preload(r)}exports.AnimatedModel=V;exports.BoneAttachment=Te;exports.Model=re;exports.MorphableModel=se;exports.Scene3D=be;exports.preloadModel=Se;exports.useAnimationController=ne;exports.useClonedModel=xe;exports.useMaterialColor=G;exports.useMaterialTexture=K;exports.useMeshVisibility=H;exports.useMorphTargets=q;
2
2
  //# sourceMappingURL=mbt-3d.cjs.map