mbt-3d 0.3.1 → 0.3.3

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/dist/index.d.ts CHANGED
@@ -3,6 +3,22 @@ import { JSX as JSX_2 } from 'react/jsx-runtime';
3
3
  import { RefAttributes } from 'react';
4
4
  import * as THREE from 'three';
5
5
 
6
+ /**
7
+ * Ambient light configuration - uniform background lighting (no shadows)
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * { type: 'ambient', intensity: 0.3, color: '#ffffff' }
12
+ * ```
13
+ */
14
+ declare interface AmbientLightConfig {
15
+ type: 'ambient';
16
+ /** Light intensity. Default: 0.5 */
17
+ intensity?: number;
18
+ /** Light color. Default: '#ffffff' */
19
+ color?: string;
20
+ }
21
+
6
22
  /**
7
23
  * AnimatedModel - 3D model with animation support and bone attachment capability
8
24
  *
@@ -181,6 +197,18 @@ export declare interface AnimatedModelProps extends Omit<ModelProps, 'onLoad'> {
181
197
  onLoad?: (info: AnimatedModelInfo) => void;
182
198
  }
183
199
 
200
+ /**
201
+ * Base light configuration with common properties
202
+ */
203
+ declare interface BaseLightConfig {
204
+ /** Light type */
205
+ type: LightType;
206
+ /** Light color as hex string. Default: '#ffffff' */
207
+ color?: string;
208
+ /** Light intensity. Default varies by light type */
209
+ intensity?: number;
210
+ }
211
+
184
212
  /**
185
213
  * BoneAttachment - Attach models to bones of an AnimatedModel parent
186
214
  *
@@ -235,6 +263,52 @@ export declare interface BoneAttachmentProps {
235
263
  scale?: number | [number, number, number];
236
264
  }
237
265
 
266
+ /**
267
+ * Directional light configuration - parallel rays (like sunlight)
268
+ *
269
+ * @example
270
+ * ```tsx
271
+ * { type: 'directional', position: [10, 20, 10], intensity: 40, castShadow: true }
272
+ * ```
273
+ */
274
+ declare interface DirectionalLightConfig extends BaseLightConfig {
275
+ type: 'directional';
276
+ /** Light position [x, y, z]. Default: [10, 20, 10] */
277
+ position?: [number, number, number];
278
+ /** Enable shadow casting. Default: true */
279
+ castShadow?: boolean;
280
+ }
281
+
282
+ /**
283
+ * Hemisphere light configuration - soft sky/ground lighting (no shadows)
284
+ *
285
+ * @example
286
+ * ```tsx
287
+ * { type: 'hemisphere', skyColor: '#87CEEB', groundColor: '#362312', intensity: 0.5 }
288
+ * ```
289
+ */
290
+ declare interface HemisphereLightConfig {
291
+ type: 'hemisphere';
292
+ /** Sky color. Default: '#ffffff' */
293
+ skyColor?: string;
294
+ /** Ground color. Default: '#444444' */
295
+ groundColor?: string;
296
+ /** Light intensity. Default: 0.5 */
297
+ intensity?: number;
298
+ /** Light position [x, y, z]. Default: [0, 10, 0] */
299
+ position?: [number, number, number];
300
+ }
301
+
302
+ /**
303
+ * Union type for all light configurations
304
+ */
305
+ declare type LightConfigUnion = SpotLightConfig | PointLightConfig | DirectionalLightConfig | HemisphereLightConfig | AmbientLightConfig;
306
+
307
+ /**
308
+ * Light types supported by Scene3D component
309
+ */
310
+ declare type LightType = 'spot' | 'point' | 'directional' | 'hemisphere' | 'ambient';
311
+
238
312
  export declare type MaterialTextures = MaterialTextures_2;
239
313
 
240
314
  /**
@@ -472,6 +546,26 @@ export declare interface MorphableModelProps extends ModelProps {
472
546
  onMorphTargetsFound?: (names: string[]) => void;
473
547
  }
474
548
 
549
+ /**
550
+ * Point light configuration - omnidirectional light (like a light bulb)
551
+ *
552
+ * @example
553
+ * ```tsx
554
+ * { type: 'point', position: [0, 5, 0], intensity: 20, color: '#ffaa00' }
555
+ * ```
556
+ */
557
+ declare interface PointLightConfig extends BaseLightConfig {
558
+ type: 'point';
559
+ /** Light position [x, y, z]. Default: [0, 5, 0] */
560
+ position?: [number, number, number];
561
+ /** Light distance. Default: 0 (infinite) */
562
+ distance?: number;
563
+ /** Light decay. Default: 2 */
564
+ decay?: number;
565
+ /** Enable shadow casting. Default: false */
566
+ castShadow?: boolean;
567
+ }
568
+
475
569
  export declare function preloadModel(url: string): void;
476
570
 
477
571
  /**
@@ -480,7 +574,7 @@ export declare function preloadModel(url: string): void;
480
574
  * @remarks
481
575
  * This component wraps React Three Fiber's Canvas and provides:
482
576
  * - OrbitControls for camera rotation (preserves state between model changes)
483
- * - Configurable lighting (ambient + spot light)
577
+ * - Configurable multi-light system (spot, point, directional, hemisphere, ambient)
484
578
  * - Optional background (image URL or hex color like "#1a1a2e")
485
579
  * - Optional contact shadows under models
486
580
  * - Shadow support
@@ -502,11 +596,7 @@ export declare function preloadModel(url: string): void;
502
596
  * @param controls.autoRotateSpeed - Auto-rotation speed. Default: `2`
503
597
  * @param background - Background: image URL (e.g., `"/bg.jpg"`) or hex color (e.g., `"#1a1a2e"`)
504
598
  * @param shadows - Enable shadow rendering. Default: `true`
505
- * @param ambientIntensity - Ambient light intensity (0-1). Example: `0.5`. Default: `0.5`
506
- * @param spotLight - Spot light configuration object. Example: `{ position: [5, 10, 5], intensity: 50 }`
507
- * @param spotLight.position - Light position as [x, y, z]. Example: `[5, 10, 5]`. Default: `[5, 10, 5]`
508
- * @param spotLight.intensity - Light intensity. Example: `50`. Default: `50`
509
- * @param spotLight.castShadow - Enable shadow casting. Default: `true`
599
+ * @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 }]`
510
600
  * @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 }`
511
601
  * @param contactShadows.position - Shadow position as [x, y, z]. Example: `[0, -1, 0]`. Default: `[0, -1, 0]`
512
602
  * @param contactShadows.opacity - Shadow opacity (0-1). Example: `0.5`. Default: `0.5`
@@ -515,6 +605,7 @@ export declare function preloadModel(url: string): void;
515
605
  * @param className - Container CSS class name
516
606
  *
517
607
  * @example
608
+ * Basic setup with default lighting:
518
609
  * ```tsx
519
610
  * <Scene3D
520
611
  * camera={{ position: [0, 2, 5], fov: 45 }}
@@ -525,8 +616,38 @@ export declare function preloadModel(url: string): void;
525
616
  * <AnimatedModel url="/model.glb" position={[0, -1, 0]} />
526
617
  * </Scene3D>
527
618
  * ```
619
+ *
620
+ * @example
621
+ * Multi-light setup for better illumination:
622
+ * ```tsx
623
+ * <Scene3D
624
+ * camera={{ position: [0, 2, 5], fov: 45 }}
625
+ * lights={[
626
+ * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true },
627
+ * { type: 'spot', position: [-5, 10, -5], intensity: 30, castShadow: false },
628
+ * { type: 'point', position: [0, 5, 0], intensity: 20 },
629
+ * { type: 'ambient', intensity: 0.3 }
630
+ * ]}
631
+ * >
632
+ * <AnimatedModel url="/model.glb" position={[0, -1, 0]} />
633
+ * </Scene3D>
634
+ * ```
635
+ *
636
+ * @example
637
+ * Using different light types:
638
+ * ```tsx
639
+ * <Scene3D
640
+ * lights={[
641
+ * { type: 'directional', position: [10, 20, 10], intensity: 40, castShadow: true },
642
+ * { type: 'hemisphere', skyColor: '#87CEEB', groundColor: '#362312', intensity: 0.5 },
643
+ * { type: 'ambient', intensity: 0.2 }
644
+ * ]}
645
+ * >
646
+ * <Model url="/model.glb" />
647
+ * </Scene3D>
648
+ * ```
528
649
  */
529
- export declare function Scene3D({ children, camera, controls, background, shadows, ambientIntensity, spotLight, contactShadows, style, className, }: Scene3DProps): JSX_2.Element;
650
+ export declare function Scene3D({ children, camera, controls, background, shadows, lights, contactShadows, style, className, }: Scene3DProps): JSX_2.Element;
530
651
 
531
652
  /**
532
653
  * Props for Scene3D component
@@ -538,6 +659,10 @@ export declare function Scene3D({ children, camera, controls, background, shadow
538
659
  * controls={{ enablePan: false, minDistance: 2 }}
539
660
  * background="#1a1a2e"
540
661
  * shadows
662
+ * lights={[
663
+ * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true },
664
+ * { type: 'ambient', intensity: 0.3 }
665
+ * ]}
541
666
  * >
542
667
  * {children}
543
668
  * </Scene3D>
@@ -580,17 +705,8 @@ export declare interface Scene3DProps {
580
705
  background?: string;
581
706
  /** Enable shadow rendering. Default: true */
582
707
  shadows?: boolean;
583
- /** Ambient light intensity. Default: 0.5 */
584
- ambientIntensity?: number;
585
- /** Spot light configuration */
586
- spotLight?: {
587
- /** Light position [x, y, z]. Default: [5, 10, 5] */
588
- position?: [number, number, number];
589
- /** Light intensity. Default: 50 */
590
- intensity?: number;
591
- /** Enable shadow casting. Default: true */
592
- castShadow?: boolean;
593
- };
708
+ /** Array of light configurations for multi-light setup */
709
+ lights?: LightConfigUnion[];
594
710
  /** Contact shadows configuration (ground shadows under models) */
595
711
  contactShadows?: boolean | {
596
712
  /** Shadow position [x, y, z]. Default: [0, -1, 0] */
@@ -606,6 +722,30 @@ export declare interface Scene3DProps {
606
722
  className?: string;
607
723
  }
608
724
 
725
+ /**
726
+ * Spot light configuration - focused light in a cone (like a flashlight)
727
+ *
728
+ * @example
729
+ * ```tsx
730
+ * { type: 'spot', position: [5, 10, 5], intensity: 50, castShadow: true }
731
+ * ```
732
+ */
733
+ declare interface SpotLightConfig extends BaseLightConfig {
734
+ type: 'spot';
735
+ /** Light position [x, y, z]. Default: [5, 10, 5] */
736
+ position?: [number, number, number];
737
+ /** Enable shadow casting. Default: true */
738
+ castShadow?: boolean;
739
+ /** Cone angle in radians. Default: Math.PI / 6 */
740
+ angle?: number;
741
+ /** Penumbra (soft edges) 0-1. Default: 0.5 */
742
+ penumbra?: number;
743
+ /** Light decay. Default: 2 */
744
+ decay?: number;
745
+ /** Light distance. Default: 0 (infinite) */
746
+ distance?: number;
747
+ }
748
+
609
749
  export declare function useAnimationController(animations: THREE.AnimationClip[], scene: THREE.Object3D, options?: UseAnimationControllerOptions): {
610
750
  playAnimation: (name: string, opts?: {
611
751
  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"),D=require("@react-three/drei"),se=require("three"),ne=require("three/examples/jsm/utils/SkeletonUtils.js"),_=require("@react-three/fiber"),oe=require("three/examples/jsm/loaders/KTX2Loader.js"),R=require("react/jsx-runtime");function Q(a){const s=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const n in a)if(n!=="default"){const o=Object.getOwnPropertyDescriptor(a,n);Object.defineProperty(s,n,o.get?o:{enumerable:!0,get:()=>a[n]})}}return s.default=a,Object.freeze(s)}const C=Q(se),Y=Q(ne);function ie({position:a,controlsConfig:s}){const{camera:n}=_.useThree(),o=e.useRef(null);return e.useEffect(()=>{a&&n&&(n.position.set(a[0],a[1],a[2]),n.updateProjectionMatrix(),o.current&&(o.current.target.set(0,0,0),o.current.update()))},[a,n]),R.jsx(D.OrbitControls,{ref:o,makeDefault:!0,enabled:s.enabled,enablePan:s.enablePan,enableZoom:s.enableZoom,enableRotate:s.enableRotate,minDistance:s.minDistance,maxDistance:s.maxDistance,minPolarAngle:s.minPolarAngle,maxPolarAngle:s.maxPolarAngle,autoRotate:s.autoRotate,autoRotateSpeed:s.autoRotateSpeed})}function ce({background:a}){const s=a==null?void 0:a.startsWith("#");return a?s?R.jsx("color",{attach:"background",args:[a]}):R.jsx(ue,{url:a}):null}function ue({url:a}){const s=D.useTexture(a);return e.useMemo(()=>{s.colorSpace=C.SRGBColorSpace},[s]),R.jsx("primitive",{attach:"background",object:s})}function le({children:a,camera:s={},controls:n={},background:o,shadows:d=!0,ambientIntensity:g=.5,spotLight:b={},contactShadows:y=!0,style:h,className:r}){const t={position:s.position||[0,2,5],fov:s.fov||45},c={enabled:n.enabled??!0,enablePan:n.enablePan??!0,enableZoom:n.enableZoom??!0,enableRotate:n.enableRotate??!0,minDistance:n.minDistance,maxDistance:n.maxDistance,minPolarAngle:n.minPolarAngle,maxPolarAngle:n.maxPolarAngle,autoRotate:n.autoRotate??!1,autoRotateSpeed:n.autoRotateSpeed??2},u={position:b.position||[5,10,5],intensity:b.intensity??50,castShadow:b.castShadow??!0},p=typeof y=="object"?{position:y.position||[0,-1,0],opacity:y.opacity??.5,blur:y.blur??2}:y?{position:[0,-1,0],opacity:.5,blur:2}:null;return R.jsx("div",{style:h,className:r,children:R.jsxs(_.Canvas,{shadows:d,camera:{position:t.position,fov:t.fov},style:{width:"100%",height:"100%"},children:[R.jsx(e.Suspense,{fallback:null,children:R.jsx(ce,{background:o})}),R.jsx("ambientLight",{intensity:g}),R.jsx("spotLight",{position:u.position,intensity:u.intensity,castShadow:u.castShadow}),R.jsx(e.Suspense,{fallback:null,children:a}),R.jsx(ie,{position:t.position,controlsConfig:c}),p&&R.jsx(D.ContactShadows,{position:p.position,opacity:p.opacity,blur:p.blur})]})})}function U(a,s){const n=e.useRef(new Map),o=e.useRef({}),d=e.useRef({});e.useEffect(()=>{s&&(o.current={...s})},[s]),e.useEffect(()=>{if(!a)return;const h=new Map;a.traverse(r=>{if(r.isMesh){const t=r;t.name&&h.set(t.name,t)}}),n.current=h},[a]),_.useFrame(()=>{const h=n.current;if(h.size===0)return;const r={...o.current,...d.current};for(const[t,c]of Object.entries(r)){const u=h.get(t);u&&u.visible!==c&&(u.visible=c)}});const g=e.useCallback((h,r)=>{d.current[h]=r;const t=n.current.get(h);t&&(t.visible=r)},[]),b=e.useCallback(()=>Array.from(n.current.keys()).sort(),[]),y=e.useCallback(()=>{const h={};return n.current.forEach((r,t)=>{h[t]=r.visible}),h},[]);return{setMeshVisibility:g,getMeshNames:b,getMeshVisibility:y}}function z(a,s){const n=e.useRef(new Map),o=e.useRef(new Map);e.useEffect(()=>{if(!a)return;const r=new Map;a.traverse(t=>{if(t.isMesh){const c=t;(Array.isArray(c.material)?c.material:[c.material]).forEach(p=>{p.name&&!r.has(p.name)&&r.set(p.name,p)})}}),n.current=r,s&&Object.entries(s).forEach(([t,c])=>{const u=r.get(t);if(u&&!Array.isArray(u)){const p=d(c);u.color&&u.color.copy(p),o.current.set(t,p)}})},[a,s]),_.useFrame(()=>{o.current.forEach((r,t)=>{const c=n.current.get(t);if(c&&!Array.isArray(c)){const u=c;u.color&&!u.color.equals(r)&&(u.color.copy(r),u.needsUpdate=!0)}})});const d=r=>typeof r=="string"?new C.Color(r):new C.Color(r[0],r[1],r[2]),g=e.useCallback((r,t)=>{const c=d(t);o.current.set(r,c);const u=n.current.get(r);if(u&&!Array.isArray(u)){const p=u;p.color&&(p.color.copy(c),p.needsUpdate=!0)}},[]),b=e.useCallback(()=>Array.from(n.current.keys()).sort(),[]),y=e.useCallback(r=>{const t=n.current.get(r);if(t&&!Array.isArray(t)){const c=t;if(c.color)return"#"+c.color.getHexString()}return null},[]),h=e.useCallback(()=>{const r={};return n.current.forEach((t,c)=>{if(!Array.isArray(t)){const u=t;u.color&&(r[c]="#"+u.color.getHexString())}}),r},[]);return{setMaterialColor:g,getMaterialNames:b,getMaterialColor:y,getAllMaterialColors:h}}function X(a,s){const{gl:n}=_.useThree(),o=e.useRef(new Map),d=e.useRef(new C.TextureLoader),g=e.useRef(null),b=e.useRef(new Map),y=e.useRef(new Set),h=e.useRef("");e.useEffect(()=>{if(!g.current)try{const l=typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function";console.log("[useMaterialTexture] Browser features:"),console.log(` WebAssembly supported: ${l}`),console.log(` WebGL2: ${n.capabilities.isWebGL2}`);const i=new oe.KTX2Loader;i.setTranscoderPath("/basis/"),i.detectSupport(n),g.current=i,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)}),l||(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(l){console.error("[useMaterialTexture] ❌ Failed to initialize KTX2Loader:",l)}return()=>{g.current&&(g.current.dispose(),g.current=null)}},[n]),e.useEffect(()=>{if(!a)return;const l=new Map;a.traverse(i=>{if(i.isMesh){const f=i;(Array.isArray(f.material)?f.material:[f.material]).forEach(m=>{m.name&&!l.has(m.name)&&l.set(m.name,m)})}}),o.current=l},[a]);const r=e.useCallback(l=>l.toLowerCase().endsWith(".ktx2")?g.current?g.current:(console.warn("[useMaterialTexture] KTX2Loader not initialized, falling back to TextureLoader"),d.current):d.current,[]);e.useEffect(()=>{if(!s||!a)return;const l=o.current;if(l.size===0)return;const i=JSON.stringify(s);if(h.current===i){console.log("[useMaterialTexture] Textures unchanged, skipping reload");return}h.current=i;let f=!1;const A=new Map;Object.entries(s).forEach(([M,S])=>{A.set(M,typeof S=="string"?{map:S}:S)}),console.log("[useMaterialTexture] Starting texture load for",A.size,"materials");const m=[];A.forEach((M,S)=>{const O=l.get(S);if(!O||!O.isMeshStandardMaterial){console.warn(`[useMaterialTexture] Material "${S}" not found or not MeshStandardMaterial`);return}const x=O;x.map=null,x.normalMap=null,x.roughnessMap=null,x.metalnessMap=null,x.emissiveMap=null,x.emissive=new C.Color(0),x.emissiveIntensity=0,x.aoMap=null,x.needsUpdate=!0,Object.entries(M).forEach(([T,j])=>{if(!j)return;const E=`${S}_${T}_${j}`,v=b.current.get(E);if(v){console.log(`[useMaterialTexture] Using cached texture: ${S}.${T}`),f||t(x,T,v);return}if(y.current.has(E)){console.log(`[useMaterialTexture] Skipping already loading: ${S}.${T}`);return}m.push({materialName:S,textureType:T,url:j,material:x})})}),console.log(`[useMaterialTexture] Queued ${m.length} textures to load`);let w=0;const k=()=>{if(f||w>=m.length){console.log("[useMaterialTexture] All textures loaded");return}const M=m[w++],S=`${M.materialName}_${M.textureType}_${M.url}`;console.log(`[useMaterialTexture] Loading (${w}/${m.length}): ${M.materialName}.${M.textureType} from ${M.url}`),y.current.add(S);const O=r(M.url),x=M.url.toLowerCase().endsWith(".ktx2")?"KTX2Loader":"TextureLoader";console.log(`[useMaterialTexture] Using ${x} for ${M.url}`),O.load(M.url,T=>{var N,W,B,L,$,F;if(y.current.delete(S),f){console.log(`[useMaterialTexture] Disposed, cleaning up texture: ${M.materialName}.${M.textureType}`),T.dispose();return}const j=((N=T.image)==null?void 0:N.width)||((B=(W=T.source)==null?void 0:W.data)==null?void 0:B.width)||"unknown",E=((L=T.image)==null?void 0:L.height)||((F=($=T.source)==null?void 0:$.data)==null?void 0:F.height)||"unknown";console.log(`[useMaterialTexture] ✅ Loaded: ${M.materialName}.${M.textureType} (${j}x${E})`),T.colorSpace=M.textureType==="map"||M.textureType==="emissiveMap"?C.SRGBColorSpace:C.NoColorSpace,T.wrapS=C.RepeatWrapping,T.wrapT=C.RepeatWrapping,T.flipY=!1,b.current.set(S,T),t(M.material,M.textureType,T);const v=M.url.endsWith(".ktx2")?500:150;console.log(`[useMaterialTexture] Waiting ${v}ms before next texture...`),setTimeout(k,v)},T=>{if(T.lengthComputable){const j=Math.round(T.loaded/T.total*100);j%25===0&&console.log(`[useMaterialTexture] Progress ${M.materialName}.${M.textureType}: ${j}%`)}},T=>{y.current.delete(S),f||(console.error(`[useMaterialTexture] ❌ Failed to load ${M.materialName}.${M.textureType} from ${M.url}`),console.error("[useMaterialTexture] Error details:",T),console.error("[useMaterialTexture] Loader type:",x),M.url.endsWith(".ktx2")&&(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(k,100)})};return k(),()=>{console.log("[useMaterialTexture] Cleanup: disposed"),f=!0}},[a,s,r]);const t=(l,i,f)=>{switch(i){case"map":l.map=f;break;case"normalMap":l.normalMap=f;break;case"roughnessMap":l.roughnessMap=f;break;case"metalnessMap":l.metalnessMap=f;break;case"emissiveMap":l.emissiveMap=f,l.emissive=new C.Color(16777215),l.emissiveIntensity=1;break;case"alphaMap":console.log(`[useMaterialTexture] Skipping alphaMap for "${l.name}" to prevent disappearing`);break;case"aoMap":l.aoMap=f;break}l.needsUpdate=!0},c=e.useCallback((l,i)=>{const f=typeof i=="string"?{map:i}:i,A=o.current.get(l);if(!A||!A.isMeshStandardMaterial){console.warn(`Material "${l}" not found or not MeshStandardMaterial`);return}const m=A;Object.entries(f).forEach(([w,k])=>{if(!k)return;const M=`${l}_${w}_${k}`,S=b.current.get(M);if(S){t(m,w,S);return}r(k).load(k,x=>{x.colorSpace=w==="map"||w==="emissiveMap"?C.SRGBColorSpace:C.NoColorSpace,x.wrapS=C.RepeatWrapping,x.wrapT=C.RepeatWrapping,b.current.set(M,x),t(m,w,x)},void 0,x=>{console.error(`Failed to load texture ${k}:`,x)})})},[r]),u=e.useCallback(()=>Array.from(o.current.keys()).sort(),[]),p=e.useCallback(l=>{const i=o.current.get(l);if(!i||!i.isMeshStandardMaterial)return;const f=i;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:c,getMaterialNames:u,clearMaterialTextures:p}}function ee({url:a,position:s=[0,0,0],rotation:n=[0,0,0],scale:o=1,meshVisibility:d,materialColors:g,materialTextures:b,onLoad:y,onError:h}){const{scene:r}=D.useGLTF(a),t=e.useRef(y);t.current=y;const c=e.useMemo(()=>{const p=r.clone(),l=[],i=new Set,f=[];let A=0;return p.traverse(m=>{if(A++,m.type==="Bone"&&f.push(m.name),m.isMesh){const w=m;l.push(w.name),w.castShadow=!0,w.receiveShadow=!0,(Array.isArray(w.material)?w.material:[w.material]).forEach(M=>i.add(M.name))}}),setTimeout(()=>{var m;(m=t.current)==null||m.call(t,{meshes:l.sort(),materials:Array.from(i).sort(),bones:f.sort(),nodeCount:A})},0),p},[r]);U(c,d),z(c,g),X(c,b);const u=typeof o=="number"?[o,o,o]:o;return R.jsx("group",{position:s,rotation:n,scale:u,children:R.jsx("primitive",{object:c})})}ee.preload=a=>{D.useGLTF.preload(a)};function te(a,s,n){const{actions:o,names:d}=D.useAnimations(a,s),g=e.useRef(null),b=e.useRef(n==null?void 0:n.defaultAnimation);e.useEffect(()=>{if(d.length===0)return;const t=b.current;let c=d[0];if(t){const p=d.find(l=>l===t||l.includes(t));p&&(c=p)}const u=o[c];u&&(u.reset().fadeIn(.5).play(),g.current=u)},[o,d]);const y=e.useCallback((t,c)=>{const{loop:u=!1,crossFadeDuration:p=.2,restoreDefault:l=!0}=c||{};let i=o[t];if(!i){const A=Object.keys(o).find(m=>m.toLowerCase().includes(t.toLowerCase())||t.toLowerCase().includes(m.toLowerCase()));A&&(i=o[A])}if(!i){console.warn(`Animation "${t}" not found. Available: ${d.join(", ")}`);return}const f=g.current;if(!(f===i&&i.isRunning())&&(f&&f!==i&&f.fadeOut(p),i.reset(),i.fadeIn(p),i.setLoop(u?C.LoopRepeat:C.LoopOnce,u?1/0:1),i.clampWhenFinished=!u,i.play(),u||i.getMixer().update(0),g.current=i,l&&!u&&b.current)){const A=i.getMixer(),m=w=>{if(w.action===i){A.removeEventListener("finished",m);const k=o[b.current];k&&(i.fadeOut(p),k.reset().fadeIn(p).play(),g.current=k)}};A.addEventListener("finished",m)}},[o,d]),h=e.useCallback(()=>{var t;(t=g.current)==null||t.fadeOut(.2),g.current=null},[]),r=e.useCallback(()=>d,[d]);return{playAnimation:y,stopAnimation:h,getAnimationNames:r,actions:o}}function q(a,s){const n=e.useRef(s||{}),o=e.useRef([]),d=e.useRef([]);e.useEffect(()=>{const h=new Set,r=[];a.traverse(t=>{t instanceof C.Mesh&&t.morphTargetDictionary&&t.morphTargetInfluences&&(r.push(t),Object.keys(t.morphTargetDictionary).forEach(c=>{h.add(c)}))}),o.current=Array.from(h).sort(),d.current=r},[a]),_.useFrame(()=>{const h=n.current;d.current.forEach(r=>{!r.morphTargetDictionary||!r.morphTargetInfluences||Object.entries(h).forEach(([t,c])=>{const u=r.morphTargetDictionary[t];u!==void 0&&(r.morphTargetInfluences[u]=c)})})}),e.useEffect(()=>{s&&(n.current={...s})},[s]);const g=e.useCallback((h,r)=>{n.current[h]=Math.max(0,Math.min(1,r))},[]),b=e.useCallback(()=>o.current,[]),y=e.useCallback(()=>({...n.current}),[]);return{setMorphTarget:g,getMorphTargetNames:b,getMorphTargetValues:y}}const re=e.createContext(null);function fe(){const a=e.useContext(re);if(!a)throw new Error("BoneAttachment must be used within an AnimatedModel");return a}const V=e.forwardRef(({url:a,position:s=[0,0,0],rotation:n=[0,0,0],scale:o=1,defaultAnimation:d,morphTargets:g,meshVisibility:b,materialColors:y,materialTextures:h,onLoad:r,onError:t,children:c},u)=>{const p=e.useRef(null),l=e.useRef([]),i=e.useRef(r);i.current=r;const{scene:f,animations:A}=D.useGLTF(a),m=e.useMemo(()=>Y.clone(f),[f]),{playAnimation:w,stopAnimation:k,getAnimationNames:M}=te(A,m,{defaultAnimation:d}),{setMorphTarget:S}=q(m,g),{setMeshVisibility:O,getMeshNames:x}=U(m,b),{setMaterialColor:T,getMaterialNames:j,getMaterialColor:E}=z(m,y),{setMaterialTextures:v,clearMaterialTextures:N}=X(m,h);e.useEffect(()=>{if(!m)return;const L=setTimeout(()=>{var J;const $=[],F=[],I=new Set,H=new Set;let Z=0;m.traverse(G=>{if(Z++,G.type==="Bone"&&$.push(G.name),G.isMesh){const P=G;F.push(P.name),P.castShadow=!0,P.receiveShadow=!0,(Array.isArray(P.material)?P.material:[P.material]).forEach(K=>{I.add(K.name),K.shadowSide=C.DoubleSide}),P.morphTargetDictionary&&Object.keys(P.morphTargetDictionary).forEach(K=>{H.add(K)})}}),l.current=Array.from(H).sort(),(J=i.current)==null||J.call(i,{meshes:F.sort(),materials:Array.from(I).sort(),bones:$.sort(),nodeCount:Z,animations:A.map(G=>G.name),morphTargetNames:l.current})},0);return()=>clearTimeout(L)},[m,A]),e.useImperativeHandle(u,()=>({playAnimation:w,stopAnimation:k,getAnimationNames:M,getGroup:()=>p.current,setMorphTarget:S,getMorphTargetNames:()=>l.current,setMeshVisibility:O,getMeshNames:x,setMaterialColor:T,getMaterialNames:j,getMaterialColor:E,setMaterialTextures:v,clearMaterialTextures:N}));const W=e.useMemo(()=>({scene:m,getBone:L=>m.getObjectByName(L)||null}),[m]),B=typeof o=="number"?[o,o,o]:o;return R.jsx(re.Provider,{value:W,children:R.jsxs("group",{ref:p,position:s,rotation:n,scale:B,children:[R.jsx("primitive",{object:m}),c]})})});V.displayName="AnimatedModel";V.preload=a=>{D.useGLTF.preload(a)};const ae=e.forwardRef(({url:a,position:s=[0,0,0],rotation:n=[0,0,0],scale:o=1,morphTargets:d,meshVisibility:g,materialColors:b,materialTextures:y,onMorphTargetsFound:h,onLoad:r,onError:t},c)=>{const{scene:u}=D.useGLTF(a),p=e.useRef(r);p.current=r;const l=e.useRef(h);l.current=h;const i=e.useMemo(()=>u.clone(),[u]),{setMorphTarget:f,getMorphTargetNames:A,getMorphTargetValues:m}=q(i,d),{setMeshVisibility:w,getMeshNames:k}=U(i,g),{setMaterialColor:M,getMaterialNames:S,getMaterialColor:O}=z(i,b),{setMaterialTextures:x,clearMaterialTextures:T}=X(i,y);e.useEffect(()=>{var v;const E=A();E.length>0&&((v=l.current)==null||v.call(l,E))},[i,A]),e.useEffect(()=>{var B;if(!i)return;const E=[],v=new Set,N=[];let W=0;i.traverse(L=>{if(W++,L.type==="Bone"&&N.push(L.name),L.isMesh){const $=L;E.push($.name),$.castShadow=!0,$.receiveShadow=!0,(Array.isArray($.material)?$.material:[$.material]).forEach(I=>v.add(I.name))}}),(B=p.current)==null||B.call(p,{meshes:E.sort(),materials:Array.from(v).sort(),bones:N.sort(),nodeCount:W})},[i]),e.useImperativeHandle(c,()=>({setMorphTarget:f,getMorphTargetNames:A,getMorphTargetValues:m,setMeshVisibility:w,getMeshNames:k,setMaterialColor:M,getMaterialNames:S,getMaterialColor:O,setMaterialTextures:x,clearMaterialTextures:T}));const j=typeof o=="number"?[o,o,o]:o;return R.jsx("group",{position:s,rotation:n,scale:j,children:R.jsx("primitive",{object:i})})});ae.displayName="MorphableModel";function me({children:a,bone:s,position:n=[0,0,0],rotation:o=[0,0,0],scale:d=1}){const{getBone:g}=fe(),[b,y]=e.useState(null);if(e.useEffect(()=>{const r=g(s);r?y(r):console.warn(`Bone "${s}" not found in model`)},[s,g]),!b)return null;const h=typeof d=="number"?[d,d,d]:d;return _.createPortal(R.jsx("group",{position:n,rotation:o,scale:h,children:a}),b)}function pe(a,s){const{scene:n,animations:o}=D.useGLTF(a),d=e.useMemo(()=>Y.clone(n),[n]);return e.useEffect(()=>{var r;if(!d)return;const g=[],b=[],y=new Set;let h=0;d.traverse(t=>{if(h++,t.type==="Bone"&&g.push(t.name),t.isMesh){const c=t;b.push(c.name),c.castShadow=!0,c.receiveShadow=!0,(Array.isArray(c.material)?c.material:[c.material]).forEach(p=>{y.add(p.name),p.shadowSide=C.DoubleSide})}}),(r=s==null?void 0:s.onLoad)==null||r.call(s,{meshes:b.sort(),materials:Array.from(y).sort(),bones:g.sort(),nodeCount:h})},[d,s]),{scene:d,animations:o}}function de(a){D.useGLTF.preload(a)}exports.AnimatedModel=V;exports.BoneAttachment=me;exports.Model=ee;exports.MorphableModel=ae;exports.Scene3D=le;exports.preloadModel=de;exports.useAnimationController=te;exports.useClonedModel=pe;exports.useMaterialColor=z;exports.useMaterialTexture=X;exports.useMeshVisibility=U;exports.useMorphTargets=q;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react"),O=require("@react-three/drei"),oe=require("three"),ae=require("three/examples/jsm/utils/SkeletonUtils.js"),B=require("@react-three/fiber"),ne=require("three/examples/jsm/loaders/KTX2Loader.js"),w=require("react/jsx-runtime");function J(s){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const r in s)if(r!=="default"){const l=Object.getOwnPropertyDescriptor(s,r);Object.defineProperty(t,r,l.get?l:{enumerable:!0,get:()=>s[r]})}}return t.default=s,Object.freeze(t)}const E=J(oe),Q=J(ae);function le({position:s,controlsConfig:t}){const{camera:r}=B.useThree(),l=e.useRef(null);return e.useEffect(()=>{s&&r&&(r.position.set(s[0],s[1],s[2]),r.updateProjectionMatrix(),l.current&&(l.current.target.set(0,0,0),l.current.update()))},[s,r]),w.jsx(O.OrbitControls,{ref:l,makeDefault:!0,enabled:t.enabled,enablePan:t.enablePan,enableZoom:t.enableZoom,enableRotate:t.enableRotate,minDistance:t.minDistance,maxDistance:t.maxDistance,minPolarAngle:t.minPolarAngle,maxPolarAngle:t.maxPolarAngle,autoRotate:t.autoRotate,autoRotateSpeed:t.autoRotateSpeed})}function ie({background:s}){const t=s==null?void 0:s.startsWith("#");return s?t?w.jsx("color",{attach:"background",args:[s]}):w.jsx(ce,{url:s}):null}function ce({url:s}){const t=O.useTexture(s);return e.useMemo(()=>{t.colorSpace=E.SRGBColorSpace},[t]),w.jsx("primitive",{attach:"background",object:t})}function ue({config:s}){switch(s.type){case"spot":{const{position:t=[5,10,5],intensity:r=50,castShadow:l=!0,angle:p=Math.PI/6,penumbra:g=.5,decay:T=2,distance:S=0,color:h="#ffffff"}=s;return w.jsx("spotLight",{position:t,intensity:r,castShadow:l,angle:p,penumbra:g,decay:T,distance:S,color:h})}case"point":{const{position:t=[0,5,0],intensity:r=20,color:l="#ffffff",distance:p=0,decay:g=2,castShadow:T=!1}=s;return w.jsx("pointLight",{position:t,intensity:r,color:l,distance:p,decay:g,castShadow:T})}case"directional":{const{position:t=[10,20,10],intensity:r=40,color:l="#ffffff",castShadow:p=!0}=s;return w.jsx("directionalLight",{position:t,intensity:r,color:l,castShadow:p})}case"hemisphere":{const{skyColor:t="#ffffff",groundColor:r="#444444",intensity:l=.5,position:p=[0,10,0]}=s,g=e.useMemo(()=>new E.Color(t),[t]),T=e.useMemo(()=>new E.Color(r),[r]);return w.jsx("hemisphereLight",{args:[g,T,l],position:p})}case"ambient":{const{intensity:t=.5,color:r="#ffffff"}=s;return w.jsx("ambientLight",{intensity:t,color:r})}default:return null}}function pe({children:s,camera:t={},controls:r={},background:l,shadows:p=!0,lights:g=[{type:"ambient",intensity:.5},{type:"spot",position:[5,10,5],intensity:50,castShadow:!0}],contactShadows:T=!0,style:S,className:h}){const o={position:t.position||[0,2,5],fov:t.fov||45},a={enabled:r.enabled??!0,enablePan:r.enablePan??!0,enableZoom:r.enableZoom??!0,enableRotate:r.enableRotate??!0,minDistance:r.minDistance,maxDistance:r.maxDistance,minPolarAngle:r.minPolarAngle,maxPolarAngle:r.maxPolarAngle,autoRotate:r.autoRotate??!1,autoRotateSpeed:r.autoRotateSpeed??2},c=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 w.jsx("div",{style:S,className:h,children:w.jsxs(B.Canvas,{shadows:p,camera:{position:o.position,fov:o.fov},style:{width:"100%",height:"100%"},children:[w.jsx(e.Suspense,{fallback:null,children:w.jsx(ie,{background:l})}),g.map((m,b)=>w.jsx(ue,{config:m},`${m.type}-${b}`)),w.jsx(e.Suspense,{fallback:null,children:s}),w.jsx(le,{position:o.position,controlsConfig:a}),c&&w.jsx(O.ContactShadows,{position:c.position,opacity:c.opacity,blur:c.blur})]})})}function G(s,t){const r=e.useRef(new Map),l=e.useRef({}),p=e.useRef({});e.useEffect(()=>{t&&(l.current={...t})},[t]),e.useEffect(()=>{if(!s)return;const h=new Map;s.traverse(o=>{if(o.isMesh){const a=o;a.name&&h.set(a.name,a)}}),r.current=h},[s]),B.useFrame(()=>{const h=r.current;if(h.size===0)return;const o={...l.current,...p.current};for(const[a,c]of Object.entries(o)){const m=h.get(a);m&&m.visible!==c&&(m.visible=c)}});const g=e.useCallback((h,o)=>{p.current[h]=o;const a=r.current.get(h);a&&(a.visible=o)},[]),T=e.useCallback(()=>Array.from(r.current.keys()).sort(),[]),S=e.useCallback(()=>{const h={};return r.current.forEach((o,a)=>{h[a]=o.visible}),h},[]);return{setMeshVisibility:g,getMeshNames:T,getMeshVisibility:S}}function K(s,t){const r=e.useRef(new Map),l=e.useRef(new Map);e.useEffect(()=>{if(!s)return;const o=new Map;s.traverse(a=>{if(a.isMesh){const c=a;(Array.isArray(c.material)?c.material:[c.material]).forEach(b=>{b.name&&!o.has(b.name)&&o.set(b.name,b)})}}),r.current=o,t&&Object.entries(t).forEach(([a,c])=>{const m=o.get(a);if(m&&!Array.isArray(m)){const b=p(c);m.color&&m.color.copy(b),l.current.set(a,b)}})},[s,t]),B.useFrame(()=>{l.current.forEach((o,a)=>{const c=r.current.get(a);if(c&&!Array.isArray(c)){const m=c;m.color&&!m.color.equals(o)&&(m.color.copy(o),m.needsUpdate=!0)}})});const p=o=>typeof o=="string"?new E.Color(o):new E.Color(o[0],o[1],o[2]),g=e.useCallback((o,a)=>{const c=p(a);l.current.set(o,c);const m=r.current.get(o);if(m&&!Array.isArray(m)){const b=m;b.color&&(b.color.copy(c),b.needsUpdate=!0)}},[]),T=e.useCallback(()=>Array.from(r.current.keys()).sort(),[]),S=e.useCallback(o=>{const a=r.current.get(o);if(a&&!Array.isArray(a)){const c=a;if(c.color)return"#"+c.color.getHexString()}return null},[]),h=e.useCallback(()=>{const o={};return r.current.forEach((a,c)=>{if(!Array.isArray(a)){const m=a;m.color&&(o[c]="#"+m.color.getHexString())}}),o},[]);return{setMaterialColor:g,getMaterialNames:T,getMaterialColor:S,getAllMaterialColors:h}}function U(s,t){const{gl:r}=B.useThree(),l=e.useRef(new Map),p=e.useRef(new E.TextureLoader),g=e.useRef(null),T=e.useRef(new Map),S=e.useRef(new Set),h=e.useRef("");e.useEffect(()=>{if(!g.current)try{const n=typeof WebAssembly=="object"&&typeof WebAssembly.validate=="function";console.log("[useMaterialTexture] Browser features:"),console.log(` WebAssembly supported: ${n}`),console.log(` WebGL2: ${r.capabilities.isWebGL2}`);const i=new ne.KTX2Loader;i.setTranscoderPath("/basis/"),i.detectSupport(r),g.current=i,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)}),n||(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(n){console.error("[useMaterialTexture] ❌ Failed to initialize KTX2Loader:",n)}return()=>{g.current&&(g.current.dispose(),g.current=null)}},[r]),e.useEffect(()=>{if(!s)return;const n=new Map;s.traverse(i=>{if(i.isMesh){const f=i;(Array.isArray(f.material)?f.material:[f.material]).forEach(d=>{d.name&&!n.has(d.name)&&n.set(d.name,d)})}}),l.current=n},[s]);const o=e.useCallback(n=>n.toLowerCase().endsWith(".ktx2")?g.current?g.current:(console.warn("[useMaterialTexture] KTX2Loader not initialized, falling back to TextureLoader"),p.current):p.current,[]);e.useEffect(()=>{if(!t||!s)return;const n=l.current;if(n.size===0)return;const i=JSON.stringify(t);if(h.current===i){console.log("[useMaterialTexture] Textures unchanged, skipping reload");return}h.current=i;let f=!1;const x=new Map;Object.entries(t).forEach(([M,y])=>{x.set(M,typeof y=="string"?{map:y}:y)}),console.log("[useMaterialTexture] Starting texture load for",x.size,"materials");const d=[];x.forEach((M,y)=>{var A,k;const D=n.get(y);if(!D||!D.isMeshStandardMaterial){console.warn(`[useMaterialTexture] Material "${y}" not found or not MeshStandardMaterial`);return}const u=D;console.log(`[useMaterialTexture] 📋 Material "${y}" BEFORE reset:`),console.log(` - map: ${u.map?"EXISTS":"null"} ${u.map?`(uuid: ${u.map.uuid})`:""}`),console.log(` - normalMap: ${u.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${u.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${u.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${u.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${u.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(A=u.color)==null?void 0:A.getHexString()}`),console.log(` - emissive: ${(k=u.emissive)==null?void 0:k.getHexString()}`),console.log(` - material uuid: ${u.uuid}`),u.map&&(console.log(`[useMaterialTexture] 🗑️ Disposing old map (uuid: ${u.map.uuid})`),u.map.dispose()),u.normalMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old normalMap"),u.normalMap.dispose()),u.roughnessMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old roughnessMap"),u.roughnessMap.dispose()),u.metalnessMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old metalnessMap"),u.metalnessMap.dispose()),u.emissiveMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old emissiveMap"),u.emissiveMap.dispose()),u.aoMap&&(console.log("[useMaterialTexture] 🗑️ Disposing old aoMap"),u.aoMap.dispose()),u.map=null,u.normalMap=null,u.roughnessMap=null,u.metalnessMap=null,u.emissiveMap=null,u.emissive=new E.Color(0),u.emissiveIntensity=0,u.aoMap=null,u.needsUpdate=!0,console.log(`[useMaterialTexture] ✅ Material "${y}" AFTER reset: all maps cleared and disposed`),Object.entries(M).forEach(([$,C])=>{if(!C)return;const j=`${y}_${$}_${C}`,X=T.current.get(j);if(X){console.log(`[useMaterialTexture] Using cached texture: ${y}.${$}`),f||a(u,$,X);return}if(S.current.has(j)){console.log(`[useMaterialTexture] Skipping already loading: ${y}.${$}`);return}d.push({materialName:y,textureType:$,url:C,material:u})})}),console.log(`[useMaterialTexture] Queued ${d.length} textures to load`);let v=0;const R=()=>{if(f||v>=d.length){console.log("[useMaterialTexture] ✅ All textures loaded"),console.log("[useMaterialTexture] 📊 FINAL material states:"),n.forEach((A,k)=>{var C,j;const $=A;console.log(` Material "${k}":`),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: ${(C=$.color)==null?void 0:C.getHexString()}`),console.log(` - emissive: ${(j=$.emissive)==null?void 0:j.getHexString()}`),console.log(` - emissiveIntensity: ${$.emissiveIntensity}`),console.log(` - roughness: ${$.roughness}`),console.log(` - metalness: ${$.metalness}`)});return}const M=d[v++],y=`${M.materialName}_${M.textureType}_${M.url}`;console.log(`[useMaterialTexture] Loading (${v}/${d.length}): ${M.materialName}.${M.textureType} from ${M.url}`),S.current.add(y);const D=o(M.url),u=M.url.toLowerCase().endsWith(".ktx2")?"KTX2Loader":"TextureLoader";console.log(`[useMaterialTexture] Using ${u} for ${M.url}`),D.load(M.url,A=>{var j,X,P,I,L,W;if(S.current.delete(y),f){console.log(`[useMaterialTexture] Disposed, cleaning up texture: ${M.materialName}.${M.textureType}`),A.dispose();return}const k=((j=A.image)==null?void 0:j.width)||((P=(X=A.source)==null?void 0:X.data)==null?void 0:P.width)||"unknown",$=((I=A.image)==null?void 0:I.height)||((W=(L=A.source)==null?void 0:L.data)==null?void 0:W.height)||"unknown";console.log(`[useMaterialTexture] ✅ Loaded: ${M.materialName}.${M.textureType} (${k}x${$})`),A.colorSpace=M.textureType==="map"||M.textureType==="emissiveMap"?E.SRGBColorSpace:E.NoColorSpace,A.wrapS=E.RepeatWrapping,A.wrapT=E.RepeatWrapping,A.flipY=!1,T.current.set(y,A),a(M.material,M.textureType,A);const C=M.url.endsWith(".ktx2")?500:15056;console.log(`[useMaterialTexture] Waiting111111 ${C}ms before next texture...`),setTimeout(R,0)},A=>{if(A.lengthComputable){const k=Math.round(A.loaded/A.total*100);k%25===0&&console.log(`[useMaterialTexture] Progress ${M.materialName}.${M.textureType}: ${k}%`)}},A=>{S.current.delete(y),f||(console.error(`[useMaterialTexture] ❌ Failed to load ${M.materialName}.${M.textureType} from ${M.url}`),console.error("[useMaterialTexture] Error details:",A),console.error("[useMaterialTexture] Loader type:",u),M.url.endsWith(".ktx2")&&(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(R,100)})};return R(),()=>{console.log("[useMaterialTexture] Cleanup: disposed"),f=!0}},[s,t,o]);const a=(n,i,f)=>{var x,d;switch(console.log(`[useMaterialTexture] 🎨 Applying texture: ${n.name}.${i} (texture uuid: ${f.uuid})`),i){case"map":n.map=f;break;case"normalMap":n.normalMap=f;break;case"roughnessMap":n.roughnessMap=f;break;case"metalnessMap":n.metalnessMap=f;break;case"emissiveMap":n.emissiveMap=f,n.emissive=new E.Color(16777215),n.emissiveIntensity=1;break;case"alphaMap":console.log(`[useMaterialTexture] Skipping alphaMap for "${n.name}" to prevent disappearing`);break;case"aoMap":n.aoMap=f;break}n.needsUpdate=!0,console.log(`[useMaterialTexture] ✅ Applied ${i} to ${n.name}, needsUpdate=true`),console.log(`[useMaterialTexture] 📊 Material "${n.name}" FINAL state:`),console.log(` - map: ${n.map?"EXISTS":"null"} ${n.map?`(uuid: ${n.map.uuid}, colorSpace: ${n.map.colorSpace})`:""}`),console.log(` - normalMap: ${n.normalMap?"EXISTS":"null"}`),console.log(` - roughnessMap: ${n.roughnessMap?"EXISTS":"null"}`),console.log(` - metalnessMap: ${n.metalnessMap?"EXISTS":"null"}`),console.log(` - emissiveMap: ${n.emissiveMap?"EXISTS":"null"}`),console.log(` - aoMap: ${n.aoMap?"EXISTS":"null"}`),console.log(` - color: ${(x=n.color)==null?void 0:x.getHexString()}`),console.log(` - emissive: ${(d=n.emissive)==null?void 0:d.getHexString()}`),console.log(` - emissiveIntensity: ${n.emissiveIntensity}`),console.log(` - roughness: ${n.roughness}`),console.log(` - metalness: ${n.metalness}`)},c=e.useCallback((n,i)=>{const f=typeof i=="string"?{map:i}:i,x=l.current.get(n);if(!x||!x.isMeshStandardMaterial){console.warn(`Material "${n}" not found or not MeshStandardMaterial`);return}const d=x;Object.entries(f).forEach(([v,R])=>{if(!R)return;const M=`${n}_${v}_${R}`,y=T.current.get(M);if(y){a(d,v,y);return}o(R).load(R,u=>{u.colorSpace=v==="map"||v==="emissiveMap"?E.SRGBColorSpace:E.NoColorSpace,u.wrapS=E.RepeatWrapping,u.wrapT=E.RepeatWrapping,T.current.set(M,u),a(d,v,u)},void 0,u=>{console.error(`Failed to load texture ${R}:`,u)})})},[o]),m=e.useCallback(()=>Array.from(l.current.keys()).sort(),[]),b=e.useCallback(n=>{const i=l.current.get(n);if(!i||!i.isMeshStandardMaterial)return;const f=i;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:c,getMaterialNames:m,clearMaterialTextures:b}}function ee({url:s,position:t=[0,0,0],rotation:r=[0,0,0],scale:l=1,meshVisibility:p,materialColors:g,materialTextures:T,onLoad:S,onError:h}){const{scene:o}=O.useGLTF(s),a=e.useRef(S);a.current=S;const c=e.useMemo(()=>{const b=o.clone();console.log("[Model] 🔍 Scene clone created, checking materials...");const n=[],i=new Set,f=[];let x=0;return b.traverse(d=>{if(x++,d.type==="Bone"&&f.push(d.name),d.isMesh){const v=d;n.push(v.name),v.castShadow=!0,v.receiveShadow=!0,(Array.isArray(v.material)?v.material:[v.material]).forEach(M=>{i.add(M.name),console.log(`[Model] 📦 Material found: "${M.name}" (uuid: ${M.uuid})`);const y=M;console.log(` - Has map: ${y.map?"YES":"NO"}`),console.log(` - Has normalMap: ${y.normalMap?"YES":"NO"}`),console.log(` - Has roughnessMap: ${y.roughnessMap?"YES":"NO"}`),console.log(` - Has metalnessMap: ${y.metalnessMap?"YES":"NO"}`)})}}),console.log(`[Model] 📊 Clone summary: ${n.length} meshes, ${i.size} materials`),setTimeout(()=>{var d;(d=a.current)==null||d.call(a,{meshes:n.sort(),materials:Array.from(i).sort(),bones:f.sort(),nodeCount:x})},0),b},[o]);G(c,p),K(c,g),U(c,T);const m=typeof l=="number"?[l,l,l]:l;return w.jsx("group",{position:t,rotation:r,scale:m,children:w.jsx("primitive",{object:c})})}ee.preload=s=>{O.useGLTF.preload(s)};function te(s,t,r){const{actions:l,names:p}=O.useAnimations(s,t),g=e.useRef(null),T=e.useRef(r==null?void 0:r.defaultAnimation);e.useEffect(()=>{if(p.length===0)return;const a=T.current;let c=p[0];if(a){const b=p.find(n=>n===a||n.includes(a));b&&(c=b)}const m=l[c];m&&(m.reset().fadeIn(.5).play(),g.current=m)},[l,p]);const S=e.useCallback((a,c)=>{const{loop:m=!1,crossFadeDuration:b=.2,restoreDefault:n=!0}=c||{};let i=l[a];if(!i){const x=Object.keys(l).find(d=>d.toLowerCase().includes(a.toLowerCase())||a.toLowerCase().includes(d.toLowerCase()));x&&(i=l[x])}if(!i){console.warn(`Animation "${a}" not found. Available: ${p.join(", ")}`);return}const f=g.current;if(!(f===i&&i.isRunning())&&(f&&f!==i&&f.fadeOut(b),i.reset(),i.fadeIn(b),i.setLoop(m?E.LoopRepeat:E.LoopOnce,m?1/0:1),i.clampWhenFinished=!m,i.play(),m||i.getMixer().update(0),g.current=i,n&&!m&&T.current)){const x=i.getMixer(),d=v=>{if(v.action===i){x.removeEventListener("finished",d);const R=l[T.current];R&&(i.fadeOut(b),R.reset().fadeIn(b).play(),g.current=R)}};x.addEventListener("finished",d)}},[l,p]),h=e.useCallback(()=>{var a;(a=g.current)==null||a.fadeOut(.2),g.current=null},[]),o=e.useCallback(()=>p,[p]);return{playAnimation:S,stopAnimation:h,getAnimationNames:o,actions:l}}function z(s,t){const r=e.useRef(t||{}),l=e.useRef([]),p=e.useRef([]);e.useEffect(()=>{const h=new Set,o=[];s.traverse(a=>{a instanceof E.Mesh&&a.morphTargetDictionary&&a.morphTargetInfluences&&(o.push(a),Object.keys(a.morphTargetDictionary).forEach(c=>{h.add(c)}))}),l.current=Array.from(h).sort(),p.current=o},[s]),B.useFrame(()=>{const h=r.current;p.current.forEach(o=>{!o.morphTargetDictionary||!o.morphTargetInfluences||Object.entries(h).forEach(([a,c])=>{const m=o.morphTargetDictionary[a];m!==void 0&&(o.morphTargetInfluences[m]=c)})})}),e.useEffect(()=>{t&&(r.current={...t})},[t]);const g=e.useCallback((h,o)=>{r.current[h]=Math.max(0,Math.min(1,o))},[]),T=e.useCallback(()=>l.current,[]),S=e.useCallback(()=>({...r.current}),[]);return{setMorphTarget:g,getMorphTargetNames:T,getMorphTargetValues:S}}const re=e.createContext(null);function me(){const s=e.useContext(re);if(!s)throw new Error("BoneAttachment must be used within an AnimatedModel");return s}const q=e.forwardRef(({url:s,position:t=[0,0,0],rotation:r=[0,0,0],scale:l=1,defaultAnimation:p,morphTargets:g,meshVisibility:T,materialColors:S,materialTextures:h,onLoad:o,onError:a,children:c},m)=>{const b=e.useRef(null),n=e.useRef([]),i=e.useRef(o);i.current=o;const{scene:f,animations:x}=O.useGLTF(s),d=e.useMemo(()=>Q.clone(f),[f]),{playAnimation:v,stopAnimation:R,getAnimationNames:M}=te(x,d,{defaultAnimation:p}),{setMorphTarget:y}=z(d,g),{setMeshVisibility:D,getMeshNames:u}=G(d,T),{setMaterialColor:A,getMaterialNames:k,getMaterialColor:$}=K(d,S),{setMaterialTextures:C,clearMaterialTextures:j}=U(d,h);e.useEffect(()=>{if(!d)return;const I=setTimeout(()=>{var Z;const L=[],W=[],_=new Set,V=new Set;let Y=0;d.traverse(F=>{if(Y++,F.type==="Bone"&&L.push(F.name),F.isMesh){const N=F;W.push(N.name),N.castShadow=!0,N.receiveShadow=!0,(Array.isArray(N.material)?N.material:[N.material]).forEach(H=>{_.add(H.name),H.shadowSide=E.DoubleSide}),N.morphTargetDictionary&&Object.keys(N.morphTargetDictionary).forEach(H=>{V.add(H)})}}),n.current=Array.from(V).sort(),(Z=i.current)==null||Z.call(i,{meshes:W.sort(),materials:Array.from(_).sort(),bones:L.sort(),nodeCount:Y,animations:x.map(F=>F.name),morphTargetNames:n.current})},0);return()=>clearTimeout(I)},[d,x]),e.useImperativeHandle(m,()=>({playAnimation:v,stopAnimation:R,getAnimationNames:M,getGroup:()=>b.current,setMorphTarget:y,getMorphTargetNames:()=>n.current,setMeshVisibility:D,getMeshNames:u,setMaterialColor:A,getMaterialNames:k,getMaterialColor:$,setMaterialTextures:C,clearMaterialTextures:j}));const X=e.useMemo(()=>({scene:d,getBone:I=>d.getObjectByName(I)||null}),[d]),P=typeof l=="number"?[l,l,l]:l;return w.jsx(re.Provider,{value:X,children:w.jsxs("group",{ref:b,position:t,rotation:r,scale:P,children:[w.jsx("primitive",{object:d}),c]})})});q.displayName="AnimatedModel";q.preload=s=>{O.useGLTF.preload(s)};const se=e.forwardRef(({url:s,position:t=[0,0,0],rotation:r=[0,0,0],scale:l=1,morphTargets:p,meshVisibility:g,materialColors:T,materialTextures:S,onMorphTargetsFound:h,onLoad:o,onError:a},c)=>{const{scene:m}=O.useGLTF(s),b=e.useRef(o);b.current=o;const n=e.useRef(h);n.current=h;const i=e.useMemo(()=>m.clone(),[m]),{setMorphTarget:f,getMorphTargetNames:x,getMorphTargetValues:d}=z(i,p),{setMeshVisibility:v,getMeshNames:R}=G(i,g),{setMaterialColor:M,getMaterialNames:y,getMaterialColor:D}=K(i,T),{setMaterialTextures:u,clearMaterialTextures:A}=U(i,S);e.useEffect(()=>{var C;const $=x();$.length>0&&((C=n.current)==null||C.call(n,$))},[i,x]),e.useEffect(()=>{var P;if(!i)return;const $=[],C=new Set,j=[];let X=0;i.traverse(I=>{if(X++,I.type==="Bone"&&j.push(I.name),I.isMesh){const L=I;$.push(L.name),L.castShadow=!0,L.receiveShadow=!0,(Array.isArray(L.material)?L.material:[L.material]).forEach(_=>C.add(_.name))}}),(P=b.current)==null||P.call(b,{meshes:$.sort(),materials:Array.from(C).sort(),bones:j.sort(),nodeCount:X})},[i]),e.useImperativeHandle(c,()=>({setMorphTarget:f,getMorphTargetNames:x,getMorphTargetValues:d,setMeshVisibility:v,getMeshNames:R,setMaterialColor:M,getMaterialNames:y,getMaterialColor:D,setMaterialTextures:u,clearMaterialTextures:A}));const k=typeof l=="number"?[l,l,l]:l;return w.jsx("group",{position:t,rotation:r,scale:k,children:w.jsx("primitive",{object:i})})});se.displayName="MorphableModel";function fe({children:s,bone:t,position:r=[0,0,0],rotation:l=[0,0,0],scale:p=1}){const{getBone:g}=me(),[T,S]=e.useState(null);if(e.useEffect(()=>{const o=g(t);o?S(o):console.warn(`Bone "${t}" not found in model`)},[t,g]),!T)return null;const h=typeof p=="number"?[p,p,p]:p;return B.createPortal(w.jsx("group",{position:r,rotation:l,scale:h,children:s}),T)}function de(s,t){const{scene:r,animations:l}=O.useGLTF(s),p=e.useMemo(()=>Q.clone(r),[r]);return e.useEffect(()=>{var o;if(!p)return;const g=[],T=[],S=new Set;let h=0;p.traverse(a=>{if(h++,a.type==="Bone"&&g.push(a.name),a.isMesh){const c=a;T.push(c.name),c.castShadow=!0,c.receiveShadow=!0,(Array.isArray(c.material)?c.material:[c.material]).forEach(b=>{S.add(b.name),b.shadowSide=E.DoubleSide})}}),(o=t==null?void 0:t.onLoad)==null||o.call(t,{meshes:T.sort(),materials:Array.from(S).sort(),bones:g.sort(),nodeCount:h})},[p,t]),{scene:p,animations:l}}function Me(s){O.useGLTF.preload(s)}exports.AnimatedModel=q;exports.BoneAttachment=fe;exports.Model=ee;exports.MorphableModel=se;exports.Scene3D=pe;exports.preloadModel=Me;exports.useAnimationController=te;exports.useClonedModel=de;exports.useMaterialColor=K;exports.useMaterialTexture=U;exports.useMeshVisibility=G;exports.useMorphTargets=z;
2
2
  //# sourceMappingURL=mbt-3d.cjs.map