string-tune-3d 0.0.3 → 0.0.5

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.cjs CHANGED
@@ -1,4 +1,137 @@
1
- "use strict";var P=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var Z=(c,e)=>{for(var t in e)P(c,t,{get:e[t],enumerable:!0})},Q=(c,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of W(e))!A.call(c,i)&&i!==t&&P(c,i,{get:()=>e[i],enumerable:!(r=G(e,i))||r.enumerable});return c};var X=c=>Q(P({},"__esModule",{value:!0}),c);var Y={};Z(Y,{String3D:()=>C,String3DCamera:()=>D,String3DObject:()=>h,String3DRenderer:()=>S,String3DScene:()=>f,String3DSynchronizer:()=>I,ThreeJSEngine:()=>x,ThreeJSProvider:()=>T});module.exports=X(Y);var z=require("@fiddle-digital/string-tune");var D=class{constructor(e,t="orthographic",r=50,i=.1,n=1e4){this.scaleCache=new Map;this._width=1;this._height=1;this.engine=e,this.mode=t,this.perspectiveFov=r,t==="orthographic"?this._camera=e.createOrthographicCamera(-1,1,1,-1,i,n):this._camera=e.createPerspectiveCamera(r,1,i,n),this._position=e.createVector3(0,0,1e3),this.update()}get camera(){return this._camera}resize(e,t){if(this._width=e,this._height=t,this.mode==="orthographic"){let r=this._camera;r.left=-e/2,r.right=e/2,r.top=t/2,r.bottom=-t/2}else this._camera.aspect=e/t;this.update()}setPosition(e,t,r){this._position.set(e,t,r),this._camera.position.copy(this._position),this.update()}lookAt(e,t,r){this._camera.lookAt(e,t,r),this.update()}update(){this._camera.updateProjectionMatrix(),this._camera.updateMatrixWorld?.()}screenToWorld(e,t,r=0){if(this.mode==="orthographic"){let i=e-this._width/2,n=-(t-this._height/2);return this.engine.createVector3(i,n,r)}else{let{width:i,height:n}=this.getFrustumSizeAt(r),a=e/this._width,o=t/this._height,s=(a-.5)*i,l=-(o-.5)*n;return this.engine.createVector3(s,l,r)}}getFrustumSizeAt(e){if(this.mode==="orthographic")return{width:this._width,height:this._height};let t=this.engine.degToRad(this.perspectiveFov),r=Math.abs(e-this._camera.position.z),i=2*Math.tan(t/2)*r;return{width:i*this._camera.aspect,height:i}}getScaleAtZ(e,t){if(this.mode==="orthographic")return 1;let r=Math.round(e*1e3)/1e3;if(this.scaleCache.has(r))return this.scaleCache.get(r);let{height:i}=this.getFrustumSizeAt(e),n=i/t;return this.scaleCache.set(r,n),n}clearScaleCache(){this.scaleCache.clear()}getMode(){return this.mode}};var S=class{constructor(e,t){this.engine=t,this._container=e;let{width:r,height:i}=e.getBoundingClientRect();this._width=r,this._height=i,this._renderer=t.createRenderer({antialias:!0,alpha:!0,logarithmicDepthBuffer:!0}),this._renderer.setPixelRatio(window.devicePixelRatio),this._renderer.setSize(r,i)}attach(){this._container.appendChild(this._renderer.domElement)}render(e,t){this._renderer.render(e.getScene(),t.camera)}resize(e){let{width:t,height:r}=this._container.getBoundingClientRect();this._width=t,this._height=r,this._renderer.setSize(t,r),e.resize(t,r)}get width(){return this._width}get height(){return this._height}get renderer(){return this._renderer}destroy(){this._renderer.dispose()}};var h=class{constructor(e,t,r,i){this._uniforms={};this._children=[];this.id=e,this.type=t,this._object=r,this.engine=i,this._quaternion=i.createQuaternion(),this._originalSize=i.createVector3(),this._bbox=i.createBox3(),this.updateBoundingBox()}get children(){return this._children}get object(){return this._object}get material(){return this._material}get originalSize(){return this._originalSize.clone()}get boundingBox(){return this._bbox.clone()}addChild(e){this._children.push(e),this.object.add(e.object)}getWorldMatrix(){return this._object.matrixWorld.clone()}getWorldPosition(){return this.engine.createVector3().setFromMatrixPosition(this._object.matrixWorld)}getOriginalBoundingBox(){if(!this._originalBoundingBox){let e=this.object.scale.clone();this.object.scale.set(1,1,1),this.object.updateMatrixWorld(!0),this._originalBoundingBox=this.engine.computeBoundingBoxRecursively(this.object),this.object.scale.copy(e),this.object.updateMatrixWorld(!0)}return this._originalBoundingBox.clone()}syncTransformFromMatrix(e){let t=this.engine.createVector3(),r=this.engine.createQuaternion(),i=this.engine.createVector3();e.decompose(t,r,i),this._object.position.copy(t),this._object.quaternion.copy(r),this._object.scale.copy(i),this._object.updateMatrix(),this._object.updateMatrixWorld()}applyWorldTransform(e,t,r){this._object.position.copy(e),this._object.quaternion.copy(t),this._object.scale.copy(r),this._object.updateMatrix(),this._object.updateMatrixWorld()}set quaternion(e){this._quaternion.copy(e),this._object.quaternion.copy(this._quaternion),this._object.updateMatrixWorld()}set position(e){this._object.position.copy(e)}set scale(e){this._object.scale.copy(e)}set rotation(e){this._object.rotation.copy(e)}set opacity(e){let t=this._object;t.material&&"opacity"in t.material&&(t.material.opacity=e)}set metalness(e){let t=this._object;t.material&&"metalness"in t.material&&(t.material.metalness=e)}set roughness(e){let t=this._object;t.material&&"roughness"in t.material&&(t.material.roughness=e)}set texture(e){this._texture=e,this._object.isMesh&&e?.applyTexture&&e.applyTexture(this._object)}updateBoundingBox(){this._bbox.setFromObject(this._object),this._bbox.getSize(this._originalSize)}destroy(){this._texture?.dispose?.(),this._material?.dispose(),this._geometry?.dispose()}};var f=class{constructor(e,t){this._objects=new Map;this._rootObjects=[];this._elementMap=new Map;this.engine=e,this._modelLoader=t,this._scene=e.createScene()}get rootObjects(){return this._rootObjects}getScene(){return this._scene}getObject(e){return this._objects.get(e)}hasObject(e){return this._objects.has(e)}deleteObject(e){let t=this._objects.get(e);return t?(this._scene.remove(t.object),this._objects.delete(e),t.destroy(),!0):!1}createFromElement(e){let t=e.getProperty("3d");if(!t)return;let r=e.htmlElement;if(!r)return;let i=n=>{if(n){let a=e.getProperty("parentId");a==null?(this._scene.add(n.object),this._rootObjects.push(n)):this._objects.get(a)?.addChild(n),this._objects.set(e.id,n),this._elementMap.set(e.id,r),n.el=r}};switch(t){case"group":this.createGroup(e,i);break;case"pointLight":this.createLight(e,"point",i);break;case"ambientLight":this.createLight(e,"ambient",i);break;case"directionalLight":this.createLight(e,"directional",i);break;case"model":this.createModel(e,i);break;case"box":this.createBox(e,i);break;case"sphere":this.createSphere(e,i);break;case"plane":this.createPlane(e,i);break;case"cylinder":this.createCylinder(e,i);break}}createGroup(e,t){let r=this.engine.createGroup(),i=new h(e.id,"group",r,this.engine);return t(i),i}createLight(e,t,r){let i=e.getProperty("3d-color")||"#ffffff",n=e.getProperty("3d-intensity")??1,a;if(t==="point"){let s=e.getProperty("3d-distance")??1e3,l=e.getProperty("3d-decay")??0;a=this.engine.createPointLight(i,n,s,l)}else t==="directional"?a=this.engine.createDirectionalLight(i,n):a=this.engine.createAmbientLight(i,n);let o=new h(e.id,t+"Light",a,this.engine);return r(o),o}createBox(e,t){let r=this.engine.createBoxGeometry(1,1,1),i=this.createMaterialFromObject(e),n=this.engine.createMesh(r,i),a=new h(e.id,"box",n,this.engine);return t(a),a}createSphere(e,t){let r=e.getProperty("3d-segments-width")??32,i=e.getProperty("3d-segments-height")??32,n=this.engine.createSphereGeometry(.5,r,i),a=this.createMaterialFromObject(e),o=this.engine.createMesh(n,a),s=new h(e.id,"sphere",o,this.engine);return t(s),s}createPlane(e,t){let r=this.engine.createPlaneGeometry(1,1),i=this.createMaterialFromObject(e),n=this.engine.createMesh(r,i),a=new h(e.id,"plane",n,this.engine);return t(a),a}createCylinder(e,t){let r=e.getProperty("3d-segments")??32,i=this.engine.createCylinderGeometry(.5,.5,1,r),n=this.createMaterialFromObject(e),a=this.engine.createMesh(i,n),o=new h(e.id,"cylinder",a,this.engine);return t(o),o}createModel(e,t){if(!this._modelLoader){console.warn("[String3D] Model loader not configured");return}let r=e.getProperty("3d-model");if(!r)return;let i=this.createMaterialFromObject(e);this._modelLoader.load(r,a=>{let o=a.scene;o.traverse(l=>{l.isMesh&&(l.material=i)});let s=new h(e.id,"model",o,this.engine);t(s)},a=>{console.log(a.loaded/a.total*100+"% loaded")},a=>{console.error("[String3D] Model loading error:",a)})}createMaterialFromObject(e){let t=e.getProperty("3d-material")||"basic[#ffffff]",[r,i]=t.split(/\[|\]/),n=i||"#ffffff",a=e.getProperty("3d-opacity")??1,o={color:n,transparent:a<1,opacity:a},s=e.el,l=s?.getAttribute("string-3d-map"),d=s?.getAttribute("string-3d-normalMap"),g=s?.getAttribute("string-3d-roughnessMap"),y=s?.getAttribute("string-3d-aoMap");return r==="standard"?(l&&(o.map=this.loadTexture(l)),d&&(o.normalMap=this.loadTexture(d)),g&&(o.roughnessMap=this.loadTexture(g)),y&&(o.aoMap=this.loadTexture(y)),this.engine.createMeshStandardMaterial(o)):this.engine.createMeshBasicMaterial(o)}loadTexture(e){return this.engine.createTextureLoader().load(e)}destroy(){this._objects.forEach(e=>e.destroy()),this._objects.clear(),this._rootObjects=[]}};var O=class{sync(e,t,r,i){let n=e.getBoundingClientRect(),a=n.left+n.width/2,o=n.top+n.height/2,s=getComputedStyle(e),l=parseFloat(s.getPropertyValue("--translate-z")||"0"),d=r.camera.screenToWorld(a,o,l);t.position=d;let g=parseFloat(s.getPropertyValue("--scale"))||1;t.scale=r.engine.createVector3(g,g,g);let y=-r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-x")||"0")),R=r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-y")||"0")),L=-r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-z")||"0"));return t.rotation=r.engine.createEuler(y,R,L,"XYZ"),t.object.updateMatrixWorld(!0),{scale:g}}};var v=class{sync(e,t,r,i){let n=e.getBoundingClientRect(),a=n.left+n.width/2,o=n.top+n.height/2,s=parseFloat(getComputedStyle(e).getPropertyValue("--translate-z")||"0"),l=r.camera.screenToWorld(a,o,s);return t.position=l,null}};var u=class{sync(e,t,r,i){let n=getComputedStyle(e),a=e.offsetWidth,o=e.offsetHeight,s=e.getBoundingClientRect(),l=parseFloat(n.getPropertyValue("--translate-z")||"0"),d=parseFloat(n.getPropertyValue("--scale")||"1"),g=s.left+s.width/2,y=s.top+s.height/2,R=r.camera.screenToWorld(g,y,l);t.position=R;let L=-r.engine.degToRad(parseFloat(n.getPropertyValue("--rotate-x")||"0")),V=r.engine.degToRad(parseFloat(n.getPropertyValue("--rotate-y")||"0")),k=-r.engine.degToRad(parseFloat(n.getPropertyValue("--rotate-z")||"0"));t.rotation=r.engine.createEuler(L,V,k,"XYZ");let E=a*d,M=o*d,B=parseFloat(n.getPropertyValue("--scale-z")||"1"),p=i?.scale||1,F=t.type,_,j,w;switch(F){case"box":case"sphere":{let b=Math.min(E,M);_=b*p,j=b*p,w=b*B*p;break}case"cylinder":{let b=E;_=b*p,j=M*p,w=b*B*p;break}case"plane":default:_=E*p,j=M*p,w=Math.min(E,M)*.5*B*p;break}return t.scale=r.engine.createVector3(_,j,w),{scale:d*p}}};var I=class{constructor(e,t,r,i){this.camera=e;this.viewportWidth=t;this.viewportHeight=r;this.engine=i;this.strategies=new Map;this.strategies.set("box",new u),this.strategies.set("sphere",new u),this.strategies.set("plane",new u),this.strategies.set("cylinder",new u),this.strategies.set("model",new u),this.strategies.set("group",new O),this.strategies.set("pointLight",new v),this.strategies.set("ambientLight",new v),this.strategies.set("directionalLight",new v)}syncElement(e,t,r){let i=this.strategies.get(t.type);return i?i.sync(e,t,{camera:this.camera,viewportWidth:this.viewportWidth,viewportHeight:this.viewportHeight,engine:this.engine},r):(console.warn(`[String3D Sync] No strategy for type "${t.type}"`),null)}updateViewportSize(e,t){this.viewportWidth=e,this.viewportHeight=t}};var H=require("@fiddle-digital/string-tune"),m=class m extends z.StringModule{constructor(t,r={}){super(t);this.renderer=null;this.camera=null;this.scene=null;this.synchronizer=null;this.engine=null;this.canvasContainer=null;this.isLoading=new Map;this.htmlKey="3d",this.options={hideHTML:r.hideHTML??!1,container:r.container,zIndex:r.zIndex??1},this.attributesToMap=[...this.attributesToMap,{key:"3d",type:"string",fallback:"box"},{key:"3d-material",type:"string",fallback:"basic[#ffffff]"},{key:"3d-color",type:"string",fallback:"#ffffff"},{key:"3d-opacity",type:"number",fallback:1},{key:"3d-intensity",type:"number",fallback:1},{key:"3d-distance",type:"number",fallback:1e3},{key:"3d-decay",type:"number",fallback:0},{key:"3d-model",type:"string",fallback:""},{key:"3d-segments",type:"number",fallback:32},{key:"3d-segments-width",type:"number",fallback:32},{key:"3d-segments-height",type:"number",fallback:32}]}static setProvider(t){m.provider=t}canConnect(t){let r=super.canConnect(t);return console.log("[String3D] canConnect:",t.id,"keys:",t.keys,"htmlKey:",this.htmlKey,"result:",r),r}initializeObject(t,r,i,n){super.initializeObject(t,r,i,n),r.setProperty("parentId",null);let a=i.parentElement?.closest('[string-3d="group"]');if(a){let o=a.getAttribute("string-id");o&&(r.setProperty("parentId",o),r.setProperty("parent",a))}}onResize(){this.renderer&&this.camera&&this.synchronizer&&(this.renderer.resize(this.camera),this.synchronizer.updateViewportSize(this.renderer.width,this.renderer.height),this.camera.clearScaleCache())}onInit(){if(!m.provider){console.error("[String3D] No provider set. Call String3D.setProvider() before use.");return}this.engine=m.provider.getEngine(),this.canvasContainer=this.createOrGetContainer(),this.injectCSS(),this.renderer=new S(this.canvasContainer,this.engine),this.renderer.attach(),this.camera=new D(this.engine,"orthographic"),this.camera.setPosition(0,0,1e3),this.camera.resize(this.renderer.width,this.renderer.height),this.scene=new f(this.engine),this.scene.getScene().add(this.camera.camera),this.synchronizer=new I(this.camera,this.renderer.width,this.renderer.height,this.engine),console.info(`[String3D] Initialized with: ${m.provider.getName()}`)}createOrGetContainer(){if(this.options.container instanceof HTMLElement)return this.applyContainerStyles(this.options.container),this.options.container;if(typeof this.options.container=="string"){let r=document.getElementById(this.options.container);if(r)return this.applyContainerStyles(r),r}let t=document.createElement("div");return t.id="string-3d-canvas",this.applyContainerStyles(t),document.body.insertBefore(t,document.body.firstChild),t}applyContainerStyles(t){Object.assign(t.style,{position:"fixed",left:"0",top:"0",width:"100vw",height:"100lvh",zIndex:String(this.options.zIndex),pointerEvents:"none"})}onObjectConnected(t){this.isLoading.has(t.id)||!this.scene||(this.isLoading.set(t.id,!0),this.scene.createFromElement(t),this.options.hideHTML&&t.htmlElement&&(t.htmlElement.style.opacity="0",t.htmlElement.style.pointerEvents="none"))}onFrame(t){!this.renderer||!this.scene||!this.camera||!this.synchronizer||(H.frameDOM.measure(()=>{this.scene.rootObjects.forEach(r=>{this.syncRecursive(r.el,r,{scale:1})})}),H.frameDOM.mutate(()=>{this.renderer.render(this.scene,this.camera)}))}syncRecursive(t,r,i){if(!this.synchronizer||!t)return;let n=this.synchronizer.syncElement(t,r,i);r.children.forEach(a=>this.syncRecursive(a.el,a,n))}injectCSS(){if(document.getElementById("string-3d-styles"))return;let t=document.createElement("style");t.id="string-3d-styles",t.textContent=`
1
+ "use strict";var q=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var ee=Object.prototype.hasOwnProperty;var te=(m,t)=>{for(var e in t)q(m,e,{get:t[e],enumerable:!0})},re=(m,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of K(t))!ee.call(m,i)&&i!==e&&q(m,i,{get:()=>t[i],enumerable:!(r=$(t,i))||r.enumerable});return m};var ie=m=>re(q({},"__esModule",{value:!0}),m);var ae={};te(ae,{String3D:()=>G,String3DCamera:()=>P,String3DObject:()=>w,String3DRenderer:()=>V,String3DScene:()=>B,String3DSynchronizer:()=>j,ThreeJSEngine:()=>Y,ThreeJSProvider:()=>U});module.exports=ie(ae);var J=require("@fiddle-digital/string-tune");var P=class{constructor(t,e="orthographic",r=50,i=.1,n=1e4){this.scaleCache=new Map;this._width=1;this._height=1;this.engine=t,this.mode=e,this.perspectiveFov=r,e==="orthographic"?this._camera=t.createOrthographicCamera(-1,1,1,-1,i,n):this._camera=t.createPerspectiveCamera(r,1,i,n),this._position=t.createVector3(0,0,1e3),this.update()}get camera(){return this._camera}resize(t,e){if(this._width=t,this._height=e,this.mode==="orthographic"){let r=this._camera;r.left=-t/2,r.right=t/2,r.top=e/2,r.bottom=-e/2}else this._camera.aspect=t/e;this.update()}setPosition(t,e,r){this._position.set(t,e,r),this._camera.position.copy(this._position),this.update()}lookAt(t,e,r){this._camera.lookAt(t,e,r),this.update()}update(){this._camera.updateProjectionMatrix(),this._camera.updateMatrixWorld?.()}screenToWorld(t,e,r=0){if(this.mode==="orthographic"){let i=t-this._width/2,n=-(e-this._height/2);return this.engine.createVector3(i,n,r)}else{let{width:i,height:n}=this.getFrustumSizeAt(r),a=t/this._width,s=e/this._height,c=(a-.5)*i,l=-(s-.5)*n;return this.engine.createVector3(c,l,r)}}getFrustumSizeAt(t){if(this.mode==="orthographic")return{width:this._width,height:this._height};let e=this.engine.degToRad(this.perspectiveFov),r=Math.abs(t-this._camera.position.z),i=2*Math.tan(e/2)*r;return{width:i*this._camera.aspect,height:i}}getScaleAtZ(t,e){if(this.mode==="orthographic")return 1;let r=Math.round(t*1e3)/1e3;if(this.scaleCache.has(r))return this.scaleCache.get(r);let{height:i}=this.getFrustumSizeAt(t),n=i/e;return this.scaleCache.set(r,n),n}clearScaleCache(){this.scaleCache.clear()}getMode(){return this.mode}getPerspectiveFov(){return this.perspectiveFov}getPositionZ(){return this._position.z}};var V=class{constructor(t,e){this.engine=e,this._container=t;let{width:r,height:i}=t.getBoundingClientRect();this._width=r,this._height=i,this._renderer=e.createRenderer({antialias:!0,alpha:!0,logarithmicDepthBuffer:!0}),this._renderer.setPixelRatio(window.devicePixelRatio),this._renderer.setSize(r,i),this._renderer.shadowMap&&(this._renderer.shadowMap.enabled=!0)}attach(){this._container.appendChild(this._renderer.domElement)}render(t,e){this._renderer.render(t.getScene(),e.camera)}resize(t){let{width:e,height:r}=this._container.getBoundingClientRect();this._width=e,this._height=r,this._renderer.setSize(e,r),t.resize(e,r)}get width(){return this._width}get height(){return this._height}get renderer(){return this._renderer}destroy(){this._renderer.dispose()}};var w=class{constructor(t,e,r,i,n={}){this._uniforms={};this._children=[];this.id=t,this.type=e,this._object=r,this.engine=i,this._material=n.material,this._geometry=n.geometry,this._texture=n.texture,this._quaternion=i.createQuaternion(),this._originalSize=i.createVector3(),this._bbox=i.createBox3(),this.updateBoundingBox()}get children(){return this._children}get object(){return this._object}get material(){return this._material}get originalSize(){return this._originalSize.clone()}get boundingBox(){return this._bbox.clone()}addChild(t){this._children.push(t),this.object.add(t.object)}getWorldMatrix(){return this._object.matrixWorld.clone()}getWorldPosition(){return this.engine.createVector3().setFromMatrixPosition(this._object.matrixWorld)}getOriginalBoundingBox(){if(!this._originalBoundingBox){let t=this.object.scale.clone();this.object.scale.set(1,1,1),this.object.updateMatrixWorld(!0),this._originalBoundingBox=this.engine.computeBoundingBoxRecursively(this.object),this.object.scale.copy(t),this.object.updateMatrixWorld(!0)}return this._originalBoundingBox.clone()}syncTransformFromMatrix(t){let e=this.engine.createVector3(),r=this.engine.createQuaternion(),i=this.engine.createVector3();t.decompose(e,r,i),this._object.position.copy(e),this._object.quaternion.copy(r),this._object.scale.copy(i),this._object.updateMatrix(),this._object.updateMatrixWorld()}applyWorldTransform(t,e,r){this._object.position.copy(t),this._object.quaternion.copy(e),this._object.scale.copy(r),this._object.updateMatrix(),this._object.updateMatrixWorld()}set quaternion(t){this._quaternion.copy(t),this._object.quaternion.copy(this._quaternion),this._object.updateMatrixWorld()}set position(t){this._object.position.copy(t)}set scale(t){this._object.scale.copy(t)}set rotation(t){this._object.rotation.copy(t)}set opacity(t){let e=this._object;e.material&&"opacity"in e.material&&(e.material.opacity=t)}set metalness(t){let e=this._object;e.material&&"metalness"in e.material&&(e.material.metalness=t)}set roughness(t){let e=this._object;e.material&&"roughness"in e.material&&(e.material.roughness=t)}set texture(t){this._texture=t,this._object.isMesh&&t?.applyTexture&&t.applyTexture(this._object)}set material(t){this._material=t}set geometry(t){this._geometry=t}updateBoundingBox(){this._bbox.setFromObject(this._object),this._bbox.getSize(this._originalSize)}destroy(){this.disposeObjectResources(this._object),this._texture?.dispose?.(),this._material?.dispose(),this._geometry?.dispose()}disposeObjectResources(t){let e=t;e?.geometry?.dispose&&e.geometry.dispose();let r=e?.material;Array.isArray(r)?r.forEach(i=>i?.dispose?.()):r?.dispose&&r.dispose(),typeof e?.traverse=="function"&&e.traverse(i=>{i?.geometry?.dispose&&i.geometry.dispose();let n=i?.material;Array.isArray(n)?n.forEach(a=>a?.dispose?.()):n?.dispose&&n.dispose()})}};var B=class{constructor(t,e={}){this._objects=new Map;this._rootObjects=[];this._elementMap=new Map;this._modelLoaderCache=new Map;this.engine=t,this._modelLoader=e.modelLoader,this._modelLoaderFactory=e.modelLoaderFactory,this._scene=t.createScene()}get rootObjects(){return this._rootObjects}getScene(){return this._scene}getObject(t){return this._objects.get(t)}hasObject(t){return this._objects.has(t)}deleteObject(t){let e=this._objects.get(t);return e?(this._scene.remove(e.object),this._objects.delete(t),e.destroy(),!0):!1}createFromElement(t){let e=t.getProperty("3d");if(!e)return;let r=t.htmlElement;if(!r)return;let i=n=>{if(n){let a=t.getProperty("parentId");a==null?(this._scene.add(n.object),this._rootObjects.push(n)):this._objects.get(a)?.addChild(n),this._objects.set(t.id,n),this._elementMap.set(t.id,r),n.el=r}};switch(e){case"group":this.createGroup(t,i);break;case"pointLight":this.createLight(t,"point",i);break;case"ambientLight":this.createLight(t,"ambient",i);break;case"directionalLight":this.createLight(t,"directional",i);break;case"spotLight":this.createLight(t,"spot",i);break;case"hemisphereLight":this.createLight(t,"hemisphere",i);break;case"model":this.createModel(t,i);break;case"box":this.createBox(t,i);break;case"sphere":this.createSphere(t,i);break;case"plane":this.createPlane(t,i);break;case"cylinder":this.createCylinder(t,i);break}}createGroup(t,e){let r=this.engine.createGroup(),i=new w(t.id,"group",r,this.engine);return e(i),i}createLight(t,e,r){let i=t.getProperty("3d-color")||"#ffffff",n=t.getProperty("3d-intensity")??1,a;if(e==="point"){let l=t.getProperty("3d-distance")??1e3,o=t.getProperty("3d-decay")??0;a=this.engine.createPointLight(i,n,l,o)}else if(e==="directional")a=this.engine.createDirectionalLight(i,n);else if(e==="spot"){let l=t.getProperty("3d-distance")??0,o=t.getProperty("3d-angle")??Math.PI/3,d=t.getProperty("3d-penumbra")??0,g=t.getProperty("3d-decay")??1;a=this.engine.createSpotLight(i,n,l,o,d,g)}else if(e==="hemisphere"){let l=t.getProperty("3d-ground-color")||"#ffffff";a=this.engine.createHemisphereLight(i,l,n)}else a=this.engine.createAmbientLight(i,n);if((t.getProperty("3d-cast-shadow")??!1)&&a.shadow){a.castShadow=!0;let l=t.getProperty("3d-shadow-bias")??0,o=t.getProperty("3d-shadow-map-size")??512;a.shadow.bias=l,a.shadow.mapSize.width=o,a.shadow.mapSize.height=o}let c=new w(t.id,e+"Light",a,this.engine);return r(c),c}applyShadowProps(t,e){let r=t.getProperty("3d-cast-shadow")??!1,i=t.getProperty("3d-receive-shadow")??!1;e.castShadow=r,e.receiveShadow=i}createBox(t,e){let r=this.engine.createBoxGeometry(1,1,1),i=this.createMaterialFromObject(t),n=this.engine.createMesh(r,i);this.applyShadowProps(t,n);let a=new w(t.id,"box",n,this.engine,{geometry:r,material:i});return e(a),a}createSphere(t,e){let r=t.getProperty("3d-segments-width")??32,i=t.getProperty("3d-segments-height")??32,n=this.engine.createSphereGeometry(.5,r,i),a=this.createMaterialFromObject(t),s=this.engine.createMesh(n,a);this.applyShadowProps(t,s);let c=new w(t.id,"sphere",s,this.engine,{geometry:n,material:a});return e(c),c}createPlane(t,e){let r=this.engine.createPlaneGeometry(1,1),i=this.createMaterialFromObject(t),n=this.engine.createMesh(r,i);this.applyShadowProps(t,n);let a=new w(t.id,"plane",n,this.engine,{geometry:r,material:i});return e(a),a}createCylinder(t,e){let r=t.getProperty("3d-segments")??32,i=this.engine.createCylinderGeometry(.5,.5,1,r),n=this.createMaterialFromObject(t),a=this.engine.createMesh(i,n);this.applyShadowProps(t,a);let s=new w(t.id,"cylinder",a,this.engine,{geometry:i,material:n});return e(s),s}createModel(t,e){let r=t.getProperty("3d-model");if(!r)return;let i=t.getProperty("3d-model-loader")||void 0,n=this.resolveModelLoader(i);if(!n){console.warn("[String3D] Model loader not configured");return}let a=t.htmlElement;a&&this.applyModelTextureRemap(n,a);let s=t.getProperty("3d-model-center")??!1;n.load(r,c=>{let l=c?.scene||c?.object||c;if(!l){console.warn("[String3D] Model loader returned empty result");return}let o=a&&this.shouldOverrideModelMaterial(a)?this.createMaterialFromElement(a,t):null;typeof l.traverse=="function"&&l.traverse(g=>{g.isMesh&&(o&&(g.material=o),this.applyShadowProps(t,g))}),s&&this.centerObject(l);let d=new w(t.id,"model",l,this.engine);e(d)},c=>{console.log(c.loaded/c.total*100+"% loaded")},c=>{console.error("[String3D] Model loading error:",c)})}resolveModelLoader(t){if(t){if(this._modelLoaderCache.has(t))return this._modelLoaderCache.get(t);if(!this._modelLoaderFactory){console.warn(`[String3D] No model loader factory for type "${t}"`);return}let e=this._modelLoaderFactory(this.engine,t);return this._modelLoaderCache.set(t,e),e}if(this._modelLoader)return this._modelLoader;if(this._modelLoaderFactory)return this._modelLoaderFactory(this.engine)}centerObject(t){if(!t)return;let e=this.engine.computeBoundingBoxRecursively(t),r=this.getBoxCenter(e);t.position?.set&&t.position.set(-r.x,-r.y,-r.z),t.updateMatrixWorld(!0)}getBoxCenter(t){let e=this.engine.createVector3();return e.x=(t.min.x+t.max.x)/2,e.y=(t.min.y+t.max.y)/2,e.z=(t.min.z+t.max.z)/2,e}createMaterialFromObject(t){return this.createMaterialFromElement(t.htmlElement,t)}createMaterialFromElement(t,e){let r=e?.getProperty("3d-material")||"basic[#ffffff]",[i,n]=r.split(/\[|\]/),a=n||"#ffffff",s=e?.getProperty("3d-opacity")??1,c=e?.getProperty("3d-metalness"),l=e?.getProperty("3d-roughness"),o={color:a,transparent:s<1,opacity:s},d=t?.getAttribute("string-3d-map"),g=t?.getAttribute("string-3d-normalMap"),b=t?.getAttribute("string-3d-roughnessMap"),f=t?.getAttribute("string-3d-metalnessMap"),S=t?.getAttribute("string-3d-aoMap"),v=this.parseFlipY(e,t),I=e?.getProperty("3d-colorSpace")||t?.getAttribute("string-3d-colorSpace")||"";return i!=="standard"&&!!(d||g||b||f||S)&&(i="standard"),i==="standard"?(d&&(o.map=this.loadTexture(d,{flipY:v,colorSpace:I})),g&&(o.normalMap=this.loadTexture(g,{flipY:v})),b&&(o.roughnessMap=this.loadTexture(b,{flipY:v})),f&&(o.metalnessMap=this.loadTexture(f,{flipY:v})),S&&(o.aoMap=this.loadTexture(S,{flipY:v})),typeof c=="number"&&(o.metalness=c),typeof l=="number"&&(o.roughness=l),this.engine.createMeshStandardMaterial(o)):this.engine.createMeshBasicMaterial(o)}loadTexture(t,e={}){let i=this.engine.createTextureLoader().load(t);typeof e.flipY=="boolean"&&(i.flipY=e.flipY);let n=(e.colorSpace||"").toLowerCase().trim();return n&&"colorSpace"in i&&(i.colorSpace=n==="srgb"?"srgb":"linear"),i.needsUpdate=!0,i}parseFlipY(t,e){let r=t?.getProperty("3d-texture-flipY")??e?.getAttribute("string-3d-texture-flipY");if(r==null||r==="")return;if(typeof r=="boolean")return r;let i=String(r).toLowerCase().trim();if(i==="false"||i==="0"||i==="no")return!1;if(i==="true"||i==="1"||i==="yes")return!0}shouldOverrideModelMaterial(t){return["string-3d-material","string-3d-color","string-3d-opacity","string-3d-map","string-3d-normalMap","string-3d-roughnessMap","string-3d-metalnessMap","string-3d-aoMap","string-3d-metalness","string-3d-roughness"].some(r=>t.hasAttribute(r))}applyModelTextureRemap(t,e){let r=(e.getAttribute("string-3d-model-texture-base")||"").trim(),i=r?r.replace(/\/?$/,"/"):"",n=e.getAttribute("string-3d-model-textures"),a=null;if(n)try{a=JSON.parse(n)}catch(c){console.warn("[String3D] Invalid model texture mapping JSON:",c)}let s=t?.manager;if(!s||typeof s.setURLModifier!="function"){(a||i)&&console.warn("[String3D] Model loader does not support URL remap.");return}s.setURLModifier(c=>{let l=a&&c in a?a[c]:c;return!i||/^(blob:|data:|https?:|file:|\/)/i.test(l)?l:i+l.replace(/^\.?\//,"")})}destroy(){this._objects.forEach(t=>t.destroy()),this._objects.clear(),this._rootObjects=[]}};var X=class{sync(t,e,r,i){let n=t.getBoundingClientRect(),a=n.left+n.width/2,s=n.top+n.height/2,c=t.computedStyleMap?.(),l=null,o=()=>(l||(l=getComputedStyle(t)),l),d=(M,R)=>{let p=c?.get?.(M);if(p!==void 0){if(typeof p=="number")return p;if(typeof p=="string"){let h=Number.parseFloat(p);if(!Number.isNaN(h))return h}if(p&&typeof p=="object"){let h=p.value;if(typeof h=="number")return h;if(typeof h=="string"){let k=Number.parseFloat(h);if(!Number.isNaN(k))return k}}}let u=o().getPropertyValue(M),y=Number.parseFloat(u);return Number.isNaN(y)?R:y},g=d("--translate-z",0),b=r.camera.screenToWorld(a,s,g);e.position=b;let f=d("--scale",1);e.scale=r.engine.createVector3(f,f,f);let S=-r.engine.degToRad(d("--rotate-x",0)),v=r.engine.degToRad(d("--rotate-y",0)),I=-r.engine.degToRad(d("--rotate-z",0));return e.rotation=r.engine.createEuler(S,v,I,"XYZ"),e.object.updateMatrixWorld(!0),{scale:f}}};var C=class{sync(t,e,r,i){let n=t.getBoundingClientRect(),a=n.left+n.width/2,s=n.top+n.height/2,c=parseFloat(getComputedStyle(t).getPropertyValue("--translate-z")||"0"),l=r.camera.screenToWorld(a,s,c);e.position=l;let o=e.object,d=t.getAttribute("string-3d-color");d&&o.color&&typeof o.color.set=="function"&&o.color.set(d);let g=t.getAttribute("string-3d-intensity");g&&(o.intensity=parseFloat(g));let b=t.getAttribute("string-3d-distance");b&&typeof o.distance<"u"&&(o.distance=parseFloat(b));let f=t.getAttribute("string-3d-decay");f&&typeof o.decay<"u"&&(o.decay=parseFloat(f));let S=t.getAttribute("string-3d-angle");S&&typeof o.angle<"u"&&(o.angle=parseFloat(S));let v=t.getAttribute("string-3d-penumbra");v&&typeof o.penumbra<"u"&&(o.penumbra=parseFloat(v));let I=t.getAttribute("string-3d-ground-color");I&&o.groundColor&&typeof o.groundColor.set=="function"&&o.groundColor.set(I);let M=t.getAttribute("string-3d-cast-shadow")==="true";if(o.castShadow!==M&&(o.castShadow=M),M&&o.shadow){let p=t.getAttribute("string-3d-shadow-bias");p&&(o.shadow.bias=parseFloat(p));let u=t.getAttribute("string-3d-shadow-map-size");if(u){let y=parseFloat(u);o.shadow.mapSize.width!==y&&(o.shadow.mapSize.width=y,o.shadow.mapSize.height=y)}}let R=t.getAttribute("string-3d-target");if(R&&o.target){let p=document.querySelector(`[string-id="${R}"]`);if(p){let u=p.getBoundingClientRect(),y=u.left+u.width/2,h=u.top+u.height/2,k=parseFloat(getComputedStyle(p).getPropertyValue("--translate-z")||"0"),E=r.camera.screenToWorld(y,h,k);o.target.position.copy(E),o.target.updateMatrixWorld(!0)}}return null}};var T=class m{static applyVisualProps(t,e,r){let i=t.getAttribute("string-3d-cast-shadow")==="true",n=t.getAttribute("string-3d-receive-shadow")==="true",a=typeof r=="number"?r:NaN;if(e.object.traverse)e.object.traverse(s=>{s.isMesh&&(s.castShadow!==i&&(s.castShadow=i),s.receiveShadow!==n&&(s.receiveShadow=n),isNaN(a)||(Array.isArray(s.material)?s.material:[s.material]).forEach(l=>{l&&(l.opacity=a,l.transparent=a<1)}))});else if(e.object.isMesh){let s=e.object;s.castShadow!==i&&(s.castShadow=i),s.receiveShadow!==n&&(s.receiveShadow=n),isNaN(a)||(Array.isArray(s.material)?s.material:[s.material]).forEach(l=>{l&&(l.opacity=a,l.transparent=a<1)})}}sync(t,e,r,i){let n=t.computedStyleMap?.(),a=null,s=()=>(a||(a=getComputedStyle(t)),a),c=t.getBoundingClientRect(),l=t.offsetWidth||c.width,o=t.offsetHeight||c.height,d=(x,H)=>{let L=n?.get?.(x);if(L!==void 0){if(typeof L=="number")return L;if(typeof L=="string"){let D=Number.parseFloat(L);if(!Number.isNaN(D))return D}if(L&&typeof L=="object"){let D=L.value;if(typeof D=="number")return D;if(typeof D=="string"){let F=Number.parseFloat(D);if(!Number.isNaN(F))return F}}}let Z=s().getPropertyValue(x),_=Number.parseFloat(Z);return Number.isNaN(_)?H:_},g=d("--translate-z",0),b=d("--scale",1),f=c.left+c.width/2,S=c.top+c.height/2,v=r.camera.screenToWorld(f,S,g);e.position=v;let I=-r.engine.degToRad(d("--rotate-x",0)),M=r.engine.degToRad(d("--rotate-y",0)),R=-r.engine.degToRad(d("--rotate-z",0));e.rotation=r.engine.createEuler(I,M,R,"XYZ");let p=l*b,u=o*b,y=d("--scale-z",1),h=i?.scale||1,k=e.type,E,z,O;switch(k){case"box":case"sphere":{let x=Math.min(p,u);E=x*h,z=x*h,O=x*y*h;break}case"model":{let H=e.getOriginalBoundingBox().getSize(r.engine.createVector3()),L=(t.getAttribute("string-3d-model-fit")||"contain").toLowerCase().trim(),Z=parseFloat(t.getAttribute("string-3d-model-scale")||"1"),_=Number.isFinite(Z)?Z:1;if(H.x>0&&H.y>0){let D=p/H.x,F=u/H.y,Q=L==="cover"?Math.max(D,F):Math.min(D,F);E=Q*_*h,z=Q*_*h,O=Q*_*y*h}else{let D=Math.min(p,u);E=D*_*h,z=D*_*h,O=D*_*y*h}break}case"cylinder":{let x=p;E=x*h,z=u*h,O=x*y*h;break}case"plane":default:E=p*h,z=u*h,O=Math.min(p,u)*.5*y*h;break}e.scale=r.engine.createVector3(E,z,O);let A=d("--opacity",NaN);return m.applyVisualProps(t,e,A),{scale:b*h}}};var j=class{constructor(t,e,r,i){this.camera=t;this.viewportWidth=e;this.viewportHeight=r;this.engine=i;this.strategies=new Map;this.strategies.set("box",new T),this.strategies.set("sphere",new T),this.strategies.set("plane",new T),this.strategies.set("cylinder",new T),this.strategies.set("model",new T),this.strategies.set("group",new X),this.strategies.set("pointLight",new C),this.strategies.set("ambientLight",new C),this.strategies.set("directionalLight",new C),this.strategies.set("spotLight",new C),this.strategies.set("hemisphereLight",new C)}syncElement(t,e,r){let i=this.strategies.get(e.type);return i?i.sync(t,e,{camera:this.camera,viewportWidth:this.viewportWidth,viewportHeight:this.viewportHeight,engine:this.engine},r):(console.warn(`[String3D Sync] No strategy for type "${e.type}"`),null)}updateViewportSize(t,e){this.viewportWidth=t,this.viewportHeight=e}};var ne=`
2
+ let wasm = null;
3
+ let wasmReady = false;
4
+
5
+ function degToRad(deg) {
6
+ return (deg * Math.PI) / 180;
7
+ }
8
+
9
+ function computeTransform(item, camera) {
10
+ const centerX = item.rectLeft + item.rectWidth / 2;
11
+ const centerY = item.rectTop + item.rectHeight / 2;
12
+
13
+ let posX = 0;
14
+ let posY = 0;
15
+ let posZ = item.translateZ;
16
+
17
+ if (camera.mode === "orthographic") {
18
+ posX = centerX - camera.width / 2;
19
+ posY = -(centerY - camera.height / 2);
20
+ } else {
21
+ const fov = degToRad(camera.fov);
22
+ const distance = Math.abs(item.translateZ - camera.cameraZ);
23
+ const height = 2 * Math.tan(fov / 2) * distance;
24
+ const width = height * camera.aspect;
25
+ const normalizedX = centerX / camera.width;
26
+ const normalizedY = centerY / camera.height;
27
+ posX = (normalizedX - 0.5) * width;
28
+ posY = -(normalizedY - 0.5) * height;
29
+ }
30
+
31
+ const rotX = -degToRad(item.rotateX);
32
+ const rotY = degToRad(item.rotateY);
33
+ const rotZ = -degToRad(item.rotateZ);
34
+
35
+ let scaleX = 1;
36
+ let scaleY = 1;
37
+ let scaleZ = 1;
38
+
39
+ if (item.type === "group") {
40
+ scaleX = item.scale;
41
+ scaleY = item.scale;
42
+ scaleZ = item.scale;
43
+ } else {
44
+ const targetWidth = item.rectWidth * item.scale;
45
+ const targetHeight = item.rectHeight * item.scale;
46
+ const parentScale = item.parentScale || 1;
47
+ const cssScaleZ = item.scaleZ || 1;
48
+
49
+ if (item.type === "box" || item.type === "sphere") {
50
+ const uniformSize = Math.min(targetWidth, targetHeight);
51
+ scaleX = uniformSize * parentScale;
52
+ scaleY = uniformSize * parentScale;
53
+ scaleZ = uniformSize * cssScaleZ * parentScale;
54
+ } else if (item.type === "model") {
55
+ const sizeX = item.modelSizeX || 0;
56
+ const sizeY = item.modelSizeY || 0;
57
+ const fitMode = (item.fitMode || "contain").toLowerCase().trim();
58
+ const modelScale = Number.isFinite(item.modelScale) ? item.modelScale : 1;
59
+
60
+ if (sizeX > 0 && sizeY > 0) {
61
+ const scaleToWidth = targetWidth / sizeX;
62
+ const scaleToHeight = targetHeight / sizeY;
63
+ const uniformScale = fitMode === "cover"
64
+ ? Math.max(scaleToWidth, scaleToHeight)
65
+ : Math.min(scaleToWidth, scaleToHeight);
66
+ scaleX = uniformScale * modelScale * parentScale;
67
+ scaleY = uniformScale * modelScale * parentScale;
68
+ scaleZ = uniformScale * modelScale * cssScaleZ * parentScale;
69
+ } else {
70
+ const fallbackSize = Math.min(targetWidth, targetHeight);
71
+ scaleX = fallbackSize * modelScale * parentScale;
72
+ scaleY = fallbackSize * modelScale * parentScale;
73
+ scaleZ = fallbackSize * modelScale * cssScaleZ * parentScale;
74
+ }
75
+ } else if (item.type === "cylinder") {
76
+ const cylRadius = targetWidth;
77
+ scaleX = cylRadius * parentScale;
78
+ scaleY = targetHeight * parentScale;
79
+ scaleZ = cylRadius * cssScaleZ * parentScale;
80
+ } else {
81
+ scaleX = targetWidth * parentScale;
82
+ scaleY = targetHeight * parentScale;
83
+ scaleZ = Math.min(targetWidth, targetHeight) * 0.5 * cssScaleZ * parentScale;
84
+ }
85
+ }
86
+
87
+ return {
88
+ id: item.id,
89
+ posX,
90
+ posY,
91
+ posZ,
92
+ rotX,
93
+ rotY,
94
+ rotZ,
95
+ scaleX,
96
+ scaleY,
97
+ scaleZ,
98
+ };
99
+ }
100
+
101
+ async function initWasm(url) {
102
+ try {
103
+ const res = await fetch(url);
104
+ const bytes = await res.arrayBuffer();
105
+ const mod = await WebAssembly.instantiate(bytes, {});
106
+ wasm = mod.instance;
107
+ wasmReady = true;
108
+ } catch (error) {
109
+ wasm = null;
110
+ wasmReady = false;
111
+ }
112
+ }
113
+
114
+ self.onmessage = async (event) => {
115
+ const data = event.data || {};
116
+ if (data.type === "init") {
117
+ if (data.wasmUrl) {
118
+ await initWasm(data.wasmUrl);
119
+ }
120
+ self.postMessage({ type: "ready", wasmReady });
121
+ return;
122
+ }
123
+
124
+ if (data.type === "compute") {
125
+ const items = data.items || [];
126
+ const camera = data.camera || {};
127
+ const results = new Array(items.length);
128
+ for (let i = 0; i < items.length; i += 1) {
129
+ results[i] = computeTransform(items[i], camera);
130
+ }
131
+ self.postMessage({ type: "result", frameId: data.frameId, results });
132
+ }
133
+ };
134
+ `,N=class{constructor(t={}){this.worker=null;this.ready=!1;this.lastResult=null;this.pending=!1;if(typeof Worker>"u")return;let e=new Blob([ne],{type:"text/javascript"});this.worker=new Worker(URL.createObjectURL(e)),this.worker.onmessage=r=>{let i=r.data||{};if(i.type==="ready"){this.ready=!0;return}i.type==="result"&&(this.lastResult={frameId:typeof i.frameId=="number"?i.frameId:0,results:i.results||[]},this.pending=!1)},this.worker.postMessage({type:"init",wasmUrl:t.wasmUrl})}isReady(){return this.ready}isPending(){return this.pending}submit(t,e,r){!this.worker||!this.ready||this.pending||(this.pending=!0,this.worker.postMessage({type:"compute",frameId:r,items:t,camera:e}))}takeLastResult(){let t=this.lastResult;return this.lastResult=null,t}destroy(){this.worker?.terminate(),this.worker=null,this.ready=!1,this.pending=!1,this.lastResult=null}};var W=class W extends J.StringModule{constructor(e){super(e);this.renderer=null;this.camera=null;this.scene=null;this.synchronizer=null;this.engine=null;this.canvasContainer=null;this.isLoading=new Map;this.useDirtySync=!1;this.dirtyElements=new Set;this.observedElements=new Set;this.resizeObserver=null;this.mutationObserver=null;this.lastSyncData=new WeakMap;this.transformWorker=null;this.workerHasResult=!1;this.workerObjectMap=new Map;this.domVersion=0;this.lastSubmittedVersion=0;this.scrollTicking=!1;this.onScrollBound=()=>this.handleScroll();this.htmlKey="3d",this.options=this.buildOptionsFromSettings(),this.attributesToMap=[...this.attributesToMap,{key:"3d",type:"string",fallback:"box"},{key:"3d-material",type:"string",fallback:"basic[#ffffff]"},{key:"3d-color",type:"string",fallback:"#ffffff"},{key:"3d-opacity",type:"number",fallback:1},{key:"3d-intensity",type:"number",fallback:1},{key:"3d-distance",type:"number",fallback:1e3},{key:"3d-decay",type:"number",fallback:0},{key:"3d-model",type:"string",fallback:""},{key:"3d-segments",type:"number",fallback:32},{key:"3d-segments-width",type:"number",fallback:32},{key:"3d-segments-height",type:"number",fallback:32},{key:"3d-model-loader",type:"string",fallback:""},{key:"3d-model-scale",type:"number",fallback:1},{key:"3d-model-center",type:"boolean",fallback:!1},{key:"3d-model-fit",type:"string",fallback:"contain"},{key:"3d-metalness",type:"number",fallback:0},{key:"3d-roughness",type:"number",fallback:1},{key:"3d-texture-flipY",type:"boolean",fallback:!0},{key:"3d-colorSpace",type:"string",fallback:""},{key:"3d-cast-shadow",type:"boolean",fallback:!1},{key:"3d-receive-shadow",type:"boolean",fallback:!1},{key:"3d-shadow-bias",type:"number",fallback:0},{key:"3d-shadow-map-size",type:"number",fallback:512},{key:"3d-angle",type:"number",fallback:Math.PI/3},{key:"3d-penumbra",type:"number",fallback:0},{key:"3d-ground-color",type:"string",fallback:"#ffffff"},{key:"3d-target",type:"string",fallback:""}]}static setProvider(e){W.provider=e}canConnect(e){let r=super.canConnect(e);return console.log("[String3D] canConnect:",e.id,"keys:",e.keys,"htmlKey:",this.htmlKey,"result:",r),r}initializeObject(e,r,i,n){super.initializeObject(e,r,i,n),r.setProperty("parentId",null);let a=i.parentElement?.closest('[string-3d="group"]');if(a){let s=a.getAttribute("string-id");s&&(r.setProperty("parentId",s),r.setProperty("parent",a))}}onResize(){this.renderer&&this.camera&&this.synchronizer&&(this.renderer.resize(this.camera),this.synchronizer.updateViewportSize(this.renderer.width,this.renderer.height),this.camera.clearScaleCache(),this.useDirtySync&&this.markAllDirty())}onInit(){if(this.options=this.buildOptionsFromSettings(),!W.provider){console.error("[String3D] No provider set. Call String3D.setProvider() before use.");return}this.engine=W.provider.getEngine(),this.canvasContainer=this.createOrGetContainer(),this.registerTypedProperties(),this.injectCSS(),this.useDirtySync=!!this.options.useDirtySync,this.useDirtySync&&(this.setupObservers(),this.setupScrollListeners()),this.renderer=new V(this.canvasContainer,this.engine),this.renderer.attach(),this.camera=new P(this.engine,"orthographic"),this.camera.setPosition(0,0,1e3),this.camera.resize(this.renderer.width,this.renderer.height);let e=this.resolveModelLoader(),r=this.resolveModelLoaderFactory();this.scene=new B(this.engine,{modelLoader:e,modelLoaderFactory:r}),this.scene.getScene().add(this.camera.camera),this.synchronizer=new j(this.camera,this.renderer.width,this.renderer.height,this.engine),this.options.useTransformWorker&&(this.transformWorker=new N({wasmUrl:this.options.transformWorkerWasmUrl})),console.info(`[String3D] Initialized with: ${W.provider.getName()}`)}onSettingsChange(){this.options=this.buildOptionsFromSettings();let e=!!this.options.useDirtySync;e&&!this.useDirtySync?(this.useDirtySync=!0,this.setupObservers(),this.setupScrollListeners(),this.observeSceneElements(),this.markAllDirty()):!e&&this.useDirtySync&&(this.useDirtySync=!1,this.removeScrollListeners(),this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect(),this.dirtyElements.clear());let r=!!this.options.useTransformWorker;r&&!this.transformWorker?(this.transformWorker=new N({wasmUrl:this.options.transformWorkerWasmUrl}),this.workerHasResult=!1):!r&&this.transformWorker&&(this.transformWorker.destroy(),this.transformWorker=null,this.workerHasResult=!1)}buildOptionsFromSettings(){return{hideHTML:this.getSettingValue("hideHTML",!1),container:this.getSettingValue("container",void 0),zIndex:this.getSettingValue("zIndex",1),modelLoaderType:this.getSettingValue("modelLoaderType",void 0),modelLoader:this.getSettingValue("modelLoader",void 0),modelLoaderFactory:this.getSettingValue("modelLoaderFactory",void 0),useDirtySync:this.getSettingValue("useDirtySync",!1),useTransformWorker:this.getSettingValue("useTransformWorker",!1),transformWorkerWasmUrl:this.getSettingValue("transformWorkerWasmUrl",void 0)}}getSettingValue(e,r){return!this.settings||!(e in this.settings)?r:this.settings[e]}resolveModelLoader(){if(this.engine){if(this.options.modelLoader)return this.options.modelLoader;if(!this.options.modelLoaderFactory&&this.options.modelLoaderType)try{return this.engine.createModelLoader(this.options.modelLoaderType)}catch(e){console.warn("[String3D] Failed to create model loader:",e)}}}resolveModelLoaderFactory(){if(this.engine){if(this.options.modelLoaderFactory)return this.options.modelLoaderFactory;if(this.options.modelLoaderType)return(e,r)=>{let i=r||this.options.modelLoaderType;if(!i)throw new Error("[String3D] Model loader type not provided");return e.createModelLoader(i)}}}createOrGetContainer(){if(this.options.container instanceof HTMLElement)return this.applyContainerStyles(this.options.container),this.options.container;if(typeof this.options.container=="string"){let r=document.getElementById(this.options.container);if(r)return this.applyContainerStyles(r),r}let e=document.createElement("div");return e.id="string-3d-canvas",this.applyContainerStyles(e),document.body.insertBefore(e,document.body.firstChild),e}applyContainerStyles(e){Object.assign(e.style,{position:"fixed",left:"0",top:"0",width:"100vw",height:"100lvh",zIndex:String(this.options.zIndex),pointerEvents:"none"})}onObjectConnected(e){this.isLoading.has(e.id)||!this.scene||(this.isLoading.set(e.id,!0),this.scene.createFromElement(e),this.useDirtySync&&e.htmlElement&&(this.observeElement(e.htmlElement),this.markDirty(e.htmlElement)),this.options.hideHTML&&e.htmlElement&&(e.htmlElement.style.opacity="0",e.htmlElement.style.pointerEvents="none"))}onFrame(e){if(!this.renderer||!this.scene||!this.camera||!this.synchronizer)return;let r=this.transformWorker?.takeLastResult();r&&r.frameId===this.lastSubmittedVersion&&r.frameId>=this.domVersion&&(this.workerHasResult=!0,this.applyWorkerResults(r.results));let i=this.useDirtySync?this.dirtyElements:null,n=!i||i.size===0,a=this.transformWorker;if(a?.isReady()&&!a.isPending()){let s=[];if(this.workerObjectMap.clear(),this.scene.rootObjects.forEach(c=>{this.collectWorkerInputs(c,{scale:1},n,i,s)}),s.length>0){let c=this.domVersion;this.lastSubmittedVersion=c,a.submit(s,this.buildWorkerCameraData(),c)}}this.scene.rootObjects.forEach(s=>{this.syncRecursive(s.el,s,{scale:1},n,i)}),this.useDirtySync&&this.dirtyElements.clear(),this.renderer.render(this.scene,this.camera)}syncRecursive(e,r,i,n,a){if(!this.synchronizer||!e)return;let s=n||!a||a.has(e),c=i;if(s){let o=this.synchronizer.syncElement(e,r,i);o&&typeof o.scale=="number"&&(this.lastSyncData.set(r,o),c=o)}else{let o=this.lastSyncData.get(r);o&&(c=o)}let l=n||s;r.children.forEach(o=>this.syncRecursive(o.el,o,c,l,a))}injectCSS(){if(document.getElementById("string-3d-styles"))return;let e=document.createElement("style");e.id="string-3d-styles",e.textContent=`
2
135
  @property --translate-x { syntax: "<number>"; inherits: false; initial-value: 0; }
3
136
  @property --translate-y { syntax: "<number>"; inherits: false; initial-value: 0; }
4
137
  @property --translate-z { syntax: "<number>"; inherits: false; initial-value: 0; }
@@ -9,11 +142,12 @@
9
142
  @property --scale-x { syntax: "<number>"; inherits: false; initial-value: 1; }
10
143
  @property --scale-y { syntax: "<number>"; inherits: false; initial-value: 1; }
11
144
  @property --scale-z { syntax: "<number>"; inherits: false; initial-value: 1; }
145
+ @property --opacity { syntax: "<number>"; inherits: false; initial-value: 1; }
12
146
 
13
147
  [string-3d] {
14
148
  --translate-x: 0; --translate-y: 0; --translate-z: 0;
15
149
  --rotate-x: 0; --rotate-y: 0; --rotate-z: 0;
16
- --scale: 1; --scale-x: 1; --scale-y: 1; --scale-z: 1;
150
+ --scale: 1; --scale-x: 1; --scale-y: 1; --scale-z: 1;--opacity: 1;
17
151
  transform-style: preserve-3d;
18
152
  }
19
153
 
@@ -25,5 +159,5 @@
25
159
  rotateZ(calc(var(--rotate-z) * 1deg))
26
160
  scale3d(calc(var(--scale) * var(--scale-x)), calc(var(--scale) * var(--scale-y)), calc(var(--scale) * var(--scale-z)));
27
161
  }
28
- `,document.head.appendChild(t)}destroy(){this.renderer?.destroy(),this.scene?.destroy(),this.isLoading.clear(),document.getElementById("string-3d-styles")?.remove(),this.canvasContainer?.id==="string-3d-canvas"&&this.canvasContainer.remove(),super.destroy()}};m.provider=null;var C=m;var x=class{constructor(e,t={}){this.THREE=e,this.loaders=t}createVector3(e=0,t=0,r=0){return new this.THREE.Vector3(e,t,r)}createVector2(e=0,t=0){return new this.THREE.Vector2(e,t)}createQuaternion(e=0,t=0,r=0,i=1){return new this.THREE.Quaternion(e,t,r,i)}createEuler(e=0,t=0,r=0,i="XYZ"){return new this.THREE.Euler(e,t,r,i)}createMatrix4(){return new this.THREE.Matrix4}createBox3(e,t){return new this.THREE.Box3(e,t)}createScene(){return new this.THREE.Scene}createRenderer(e){let t=new this.THREE.WebGLRenderer(e);return t.outputEncoding=this.THREE.sRGBEncoding,t}createPerspectiveCamera(e=45,t=1,r=.1,i=2e3){return new this.THREE.PerspectiveCamera(e,t,r,i)}createOrthographicCamera(e,t,r,i,n=.1,a=1e4){return new this.THREE.OrthographicCamera(e,t,r,i,n,a)}createGroup(){return new this.THREE.Group}createMesh(e,t){return new this.THREE.Mesh(e,t)}createBoxGeometry(e,t,r){return new this.THREE.BoxGeometry(e,t,r)}createSphereGeometry(e,t=32,r=32){return new this.THREE.SphereGeometry(e,t,r)}createPlaneGeometry(e,t){return new this.THREE.PlaneGeometry(e,t)}createCylinderGeometry(e,t,r,i=32){return new this.THREE.CylinderGeometry(e,t,r,i)}createMeshBasicMaterial(e){return new this.THREE.MeshBasicMaterial(e)}createMeshStandardMaterial(e){return new this.THREE.MeshStandardMaterial(e)}createPointLight(e,t=1,r=0,i=2){return new this.THREE.PointLight(e,t,r,i)}createAmbientLight(e,t=1){return new this.THREE.AmbientLight(e,t)}createDirectionalLight(e,t=1){return new this.THREE.DirectionalLight(e,t)}createTextureLoader(){return new this.THREE.TextureLoader}createModelLoader(e){let t=this.loaders[e];if(!t)throw new Error(`[ThreeJSEngine] Model loader "${e}" not registered`);return new t}degToRad(e){return this.THREE.MathUtils.degToRad(e)}radToDeg(e){return this.THREE.MathUtils.radToDeg(e)}computeBoundingBoxRecursively(e){let t=new this.THREE.Box3,r=!1;return e.traverse&&e.traverse(i=>{if(i.visible&&i.geometry){typeof i.geometry.computeBoundingBox=="function"&&i.geometry.computeBoundingBox();let n=i.geometry.boundingBox;if(n){let a=n.clone().applyMatrix4(i.matrixWorld);t.union(a),r=!0}}}),r?t:new this.THREE.Box3}},T=class{constructor(e,t={}){this.engine=new x(e,t)}getEngine(){return this.engine}getName(){return"Three.js"}};0&&(module.exports={String3D,String3DCamera,String3DObject,String3DRenderer,String3DScene,String3DSynchronizer,ThreeJSEngine,ThreeJSProvider});
162
+ `,document.head.appendChild(e)}registerTypedProperties(){let e=globalThis.CSS;if(!e?.registerProperty)return;[{name:"--translate-x",initialValue:"0"},{name:"--translate-y",initialValue:"0"},{name:"--translate-z",initialValue:"0"},{name:"--rotate-x",initialValue:"0"},{name:"--rotate-y",initialValue:"0"},{name:"--rotate-z",initialValue:"0"},{name:"--scale",initialValue:"1"},{name:"--scale-x",initialValue:"1"},{name:"--scale-y",initialValue:"1"},{name:"--scale-z",initialValue:"1"},{name:"--opacity",initialValue:"1"}].forEach(({name:i,initialValue:n})=>{try{e.registerProperty({name:i,syntax:"<number>",inherits:!1,initialValue:n})}catch{}})}setupObservers(){typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(e=>{e.forEach(r=>{r.target instanceof HTMLElement&&this.markDirty(r.target)})})),typeof MutationObserver<"u"&&(this.mutationObserver=new MutationObserver(e=>{e.forEach(r=>{r.target instanceof HTMLElement&&this.markDirty(r.target)})}))}setupScrollListeners(){window.addEventListener("scroll",this.onScrollBound,{passive:!0}),window.addEventListener("resize",this.onScrollBound,{passive:!0}),window.visualViewport&&(window.visualViewport.addEventListener("scroll",this.onScrollBound,{passive:!0}),window.visualViewport.addEventListener("resize",this.onScrollBound,{passive:!0}))}removeScrollListeners(){window.removeEventListener("scroll",this.onScrollBound),window.removeEventListener("resize",this.onScrollBound),window.visualViewport&&(window.visualViewport.removeEventListener("scroll",this.onScrollBound),window.visualViewport.removeEventListener("resize",this.onScrollBound))}handleScroll(){this.useDirtySync&&this.markAllDirty()}observeElement(e){this.observedElements.has(e)||(this.observedElements.add(e),this.resizeObserver?.observe(e),this.mutationObserver?.observe(e,{attributes:!0,attributeFilter:["style","class","string-3d","string-3d-model-fit","string-3d-model-scale","string-3d-cast-shadow","string-3d-receive-shadow","string-3d-opacity","string-3d-target"]}))}observeSceneElements(){this.scene&&this.scene.rootObjects.forEach(e=>{this.observeRecursive(e)})}observeRecursive(e){e.el instanceof HTMLElement&&this.observeElement(e.el),e.children.forEach(r=>this.observeRecursive(r))}markDirty(e){this.dirtyElements.add(e),this.domVersion+=1}markAllDirty(){this.observedElements.forEach(e=>this.dirtyElements.add(e)),this.domVersion+=1}readNumberStyle(e,r,i){let a=e.computedStyleMap?.()?.get?.(r);if(a!==void 0){if(typeof a=="number")return a;if(typeof a=="string"){let o=Number.parseFloat(a);if(!Number.isNaN(o))return o}if(a&&typeof a=="object"){let o=a.value;if(typeof o=="number")return o;if(typeof o=="string"){let d=Number.parseFloat(o);if(!Number.isNaN(d))return d}}}let c=getComputedStyle(e).getPropertyValue(r),l=Number.parseFloat(c);return Number.isNaN(l)?i:l}buildWorkerCameraData(){return{mode:this.camera.getMode(),width:this.renderer.width,height:this.renderer.height,cameraZ:this.camera.getPositionZ(),fov:this.camera.getPerspectiveFov(),aspect:this.renderer.width/this.renderer.height}}collectWorkerInputs(e,r,i,n,a){if(!this.synchronizer||!e.el)return;let s=e.el,c=i||!n||n.has(s),l=r;if(e.type.endsWith("Light")){c&&this.synchronizer.syncElement(s,e,r);return}if(c){let d=s.getBoundingClientRect(),g=s.offsetWidth||d.width,b=s.offsetHeight||d.height,f=this.readNumberStyle(s,"--translate-z",0),S=this.readNumberStyle(s,"--scale",1),v=this.readNumberStyle(s,"--scale-z",1),I=this.readNumberStyle(s,"--rotate-x",0),M=this.readNumberStyle(s,"--rotate-y",0),R=this.readNumberStyle(s,"--rotate-z",0),p=this.readNumberStyle(s,"--opacity",NaN);e.type!=="group"&&T.applyVisualProps(s,e,p);let u,y,h,k;if(e.type==="model"){let O=e.getOriginalBoundingBox().getSize(this.engine.createVector3());u=O.x,y=O.y;let A=parseFloat(s.getAttribute("string-3d-model-scale")||"1");h=Number.isFinite(A)?A:1,k=(s.getAttribute("string-3d-model-fit")||"contain").toLowerCase().trim()}let E=e.type==="group"?S:S*r.scale;this.lastSyncData.set(e,{scale:E}),l={scale:E},this.workerObjectMap.set(e.id,{object:e,el:s}),a.push({id:e.id,type:e.type,rectLeft:d.left,rectTop:d.top,rectWidth:g,rectHeight:b,translateZ:f,scale:S,scaleZ:v,rotateX:I,rotateY:M,rotateZ:R,parentScale:r.scale,modelSizeX:u,modelSizeY:y,modelScale:h,fitMode:k})}else{let d=this.lastSyncData.get(e);d&&(l=d)}let o=i||c;e.children.forEach(d=>{this.collectWorkerInputs(d,l,o,n,a)})}applyWorkerResults(e){this.engine&&e.forEach(r=>{let i=this.workerObjectMap.get(r.id);if(!i)return;let n=i.object;n.position=this.engine.createVector3(r.posX,r.posY,r.posZ),n.rotation=this.engine.createEuler(r.rotX,r.rotY,r.rotZ,"XYZ"),n.scale=this.engine.createVector3(r.scaleX,r.scaleY,r.scaleZ),n.type==="group"&&n.object.updateMatrixWorld(!0)})}destroy(){this.renderer?.destroy(),this.scene?.destroy(),this.isLoading.clear(),this.transformWorker?.destroy(),this.transformWorker=null,this.removeScrollListeners(),this.resizeObserver?.disconnect(),this.mutationObserver?.disconnect(),this.observedElements.clear(),this.dirtyElements.clear(),this.workerObjectMap.clear(),this.lastSyncData=new WeakMap,document.getElementById("string-3d-styles")?.remove(),this.canvasContainer?.id==="string-3d-canvas"&&this.canvasContainer.remove(),super.destroy()}};W.provider=null;var G=W;var Y=class{constructor(t,e={}){this.THREE=t,this.loaders=e}createVector3(t=0,e=0,r=0){return new this.THREE.Vector3(t,e,r)}createVector2(t=0,e=0){return new this.THREE.Vector2(t,e)}createQuaternion(t=0,e=0,r=0,i=1){return new this.THREE.Quaternion(t,e,r,i)}createEuler(t=0,e=0,r=0,i="XYZ"){return new this.THREE.Euler(t,e,r,i)}createMatrix4(){return new this.THREE.Matrix4}createBox3(t,e){return new this.THREE.Box3(t,e)}createScene(){return new this.THREE.Scene}createRenderer(t){let e=new this.THREE.WebGLRenderer(t);return e.outputEncoding=this.THREE.sRGBEncoding,e}createPerspectiveCamera(t=45,e=1,r=.1,i=2e3){return new this.THREE.PerspectiveCamera(t,e,r,i)}createOrthographicCamera(t,e,r,i,n=.1,a=1e4){return new this.THREE.OrthographicCamera(t,e,r,i,n,a)}createGroup(){return new this.THREE.Group}createMesh(t,e){return new this.THREE.Mesh(t,e)}createBoxGeometry(t,e,r){return new this.THREE.BoxGeometry(t,e,r)}createSphereGeometry(t,e=32,r=32){return new this.THREE.SphereGeometry(t,e,r)}createPlaneGeometry(t,e){return new this.THREE.PlaneGeometry(t,e)}createCylinderGeometry(t,e,r,i=32){return new this.THREE.CylinderGeometry(t,e,r,i)}createMeshBasicMaterial(t){return new this.THREE.MeshBasicMaterial(t)}createMeshStandardMaterial(t){return new this.THREE.MeshStandardMaterial(t)}createPointLight(t,e=1,r=0,i=2){return new this.THREE.PointLight(t,e,r,i)}createSpotLight(t,e=1,r=0,i=Math.PI/3,n=0,a=1){return new this.THREE.SpotLight(t,e,r,i,n,a)}createHemisphereLight(t,e,r=1){return new this.THREE.HemisphereLight(t,e,r)}createAmbientLight(t,e=1){return new this.THREE.AmbientLight(t,e)}createDirectionalLight(t,e=1){return new this.THREE.DirectionalLight(t,e)}createTextureLoader(){return new this.THREE.TextureLoader}createModelLoader(t){let e=this.loaders[t];if(!e)throw new Error(`[ThreeJSEngine] Model loader "${t}" not registered`);return new e}degToRad(t){return this.THREE.MathUtils.degToRad(t)}radToDeg(t){return this.THREE.MathUtils.radToDeg(t)}computeBoundingBoxRecursively(t){let e=new this.THREE.Box3,r=!1;return t.traverse&&t.traverse(i=>{if(i.visible&&i.geometry){typeof i.geometry.computeBoundingBox=="function"&&i.geometry.computeBoundingBox();let n=i.geometry.boundingBox;if(n){let a=n.clone().applyMatrix4(i.matrixWorld);e.union(a),r=!0}}}),r?e:new this.THREE.Box3}},U=class{constructor(t,e={}){this.engine=new Y(t,e)}getEngine(){return this.engine}getName(){return"Three.js"}};0&&(module.exports={String3D,String3DCamera,String3DObject,String3DRenderer,String3DScene,String3DSynchronizer,ThreeJSEngine,ThreeJSProvider});
29
163
  //# sourceMappingURL=index.cjs.map