string-tune-3d 0.0.4 → 0.0.6
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 +251 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +178 -2
- package/dist/index.d.ts +178 -2
- package/dist/index.js +251 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +251 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +50 -50
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,250 @@
|
|
|
1
|
-
"use strict";var G=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var $=(l,e)=>{for(var t in e)G(l,t,{get:e[t],enumerable:!0})},J=(l,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of N(e))!U.call(l,i)&&i!==t&&G(l,i,{get:()=>e[i],enumerable:!(r=q(e,i))||r.enumerable});return l};var K=l=>J(G({},"__esModule",{value:!0}),l);var ee={};$(ee,{String3D:()=>F,String3DCamera:()=>O,String3DObject:()=>g,String3DRenderer:()=>w,String3DScene:()=>T,String3DSynchronizer:()=>j,ThreeJSEngine:()=>P,ThreeJSProvider:()=>V});module.exports=K(ee);var Z=require("@fiddle-digital/string-tune");var O=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),o=e/this._width,s=t/this._height,a=(o-.5)*i,c=-(s-.5)*n;return this.engine.createVector3(a,c,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 w=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 g=class{constructor(e,t,r,i,n={}){this._uniforms={};this._children=[];this.id=e,this.type=t,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(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)}set material(e){this._material=e}set geometry(e){this._geometry=e}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(e){let t=e;t?.geometry?.dispose&&t.geometry.dispose();let r=t?.material;Array.isArray(r)?r.forEach(i=>i?.dispose?.()):r?.dispose&&r.dispose(),typeof t?.traverse=="function"&&t.traverse(i=>{i?.geometry?.dispose&&i.geometry.dispose();let n=i?.material;Array.isArray(n)?n.forEach(o=>o?.dispose?.()):n?.dispose&&n.dispose()})}};var T=class{constructor(e,t={}){this._objects=new Map;this._rootObjects=[];this._elementMap=new Map;this._modelLoaderCache=new Map;this.engine=e,this._modelLoader=t.modelLoader,this._modelLoaderFactory=t.modelLoaderFactory,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 o=e.getProperty("parentId");o==null?(this._scene.add(n.object),this._rootObjects.push(n)):this._objects.get(o)?.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 g(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,o;if(t==="point"){let a=e.getProperty("3d-distance")??1e3,c=e.getProperty("3d-decay")??0;o=this.engine.createPointLight(i,n,a,c)}else t==="directional"?o=this.engine.createDirectionalLight(i,n):o=this.engine.createAmbientLight(i,n);let s=new g(e.id,t+"Light",o,this.engine);return r(s),s}createBox(e,t){let r=this.engine.createBoxGeometry(1,1,1),i=this.createMaterialFromObject(e),n=this.engine.createMesh(r,i),o=new g(e.id,"box",n,this.engine,{geometry:r,material:i});return t(o),o}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),o=this.createMaterialFromObject(e),s=this.engine.createMesh(n,o),a=new g(e.id,"sphere",s,this.engine,{geometry:n,material:o});return t(a),a}createPlane(e,t){let r=this.engine.createPlaneGeometry(1,1),i=this.createMaterialFromObject(e),n=this.engine.createMesh(r,i),o=new g(e.id,"plane",n,this.engine,{geometry:r,material:i});return t(o),o}createCylinder(e,t){let r=e.getProperty("3d-segments")??32,i=this.engine.createCylinderGeometry(.5,.5,1,r),n=this.createMaterialFromObject(e),o=this.engine.createMesh(i,n),s=new g(e.id,"cylinder",o,this.engine,{geometry:i,material:n});return t(s),s}createModel(e,t){let r=e.getProperty("3d-model");if(!r)return;let i=e.getProperty("3d-model-loader")||void 0,n=this.resolveModelLoader(i);if(!n){console.warn("[String3D] Model loader not configured");return}let o=e.htmlElement;o&&this.applyModelTextureRemap(n,o);let s=e.getProperty("3d-model-center")??!1;n.load(r,a=>{let c=a?.scene||a?.object||a;if(!c){console.warn("[String3D] Model loader returned empty result");return}if(o&&this.shouldOverrideModelMaterial(o)){let h=this.createMaterialFromElement(o,e);typeof c.traverse=="function"&&c.traverse(u=>{u.isMesh&&(u.material=h)})}s&&this.centerObject(c);let d=new g(e.id,"model",c,this.engine);t(d)},a=>{console.log(a.loaded/a.total*100+"% loaded")},a=>{console.error("[String3D] Model loading error:",a)})}resolveModelLoader(e){if(e){if(this._modelLoaderCache.has(e))return this._modelLoaderCache.get(e);if(!this._modelLoaderFactory){console.warn(`[String3D] No model loader factory for type "${e}"`);return}let t=this._modelLoaderFactory(this.engine,e);return this._modelLoaderCache.set(e,t),t}if(this._modelLoader)return this._modelLoader;if(this._modelLoaderFactory)return this._modelLoaderFactory(this.engine)}centerObject(e){if(!e)return;let t=this.engine.computeBoundingBoxRecursively(e),r=this.getBoxCenter(t);e.position?.set&&e.position.set(-r.x,-r.y,-r.z),e.updateMatrixWorld(!0)}getBoxCenter(e){let t=this.engine.createVector3();return t.x=(e.min.x+e.max.x)/2,t.y=(e.min.y+e.max.y)/2,t.z=(e.min.z+e.max.z)/2,t}createMaterialFromObject(e){return this.createMaterialFromElement(e.htmlElement,e)}createMaterialFromElement(e,t){let r=t?.getProperty("3d-material")||"basic[#ffffff]",[i,n]=r.split(/\[|\]/),o=n||"#ffffff",s=t?.getProperty("3d-opacity")??1,a=t?.getProperty("3d-metalness"),c=t?.getProperty("3d-roughness"),d={color:o,transparent:s<1,opacity:s},h=e?.getAttribute("string-3d-map"),u=e?.getAttribute("string-3d-normalMap"),b=e?.getAttribute("string-3d-roughnessMap"),f=e?.getAttribute("string-3d-metalnessMap"),R=e?.getAttribute("string-3d-aoMap"),D=this.parseFlipY(t,e),m=t?.getProperty("3d-colorSpace")||e?.getAttribute("string-3d-colorSpace")||"";return i!=="standard"&&!!(h||u||b||f||R)&&(i="standard"),i==="standard"?(h&&(d.map=this.loadTexture(h,{flipY:D,colorSpace:m})),u&&(d.normalMap=this.loadTexture(u,{flipY:D})),b&&(d.roughnessMap=this.loadTexture(b,{flipY:D})),f&&(d.metalnessMap=this.loadTexture(f,{flipY:D})),R&&(d.aoMap=this.loadTexture(R,{flipY:D})),typeof a=="number"&&(d.metalness=a),typeof c=="number"&&(d.roughness=c),this.engine.createMeshStandardMaterial(d)):this.engine.createMeshBasicMaterial(d)}loadTexture(e,t={}){let i=this.engine.createTextureLoader().load(e);typeof t.flipY=="boolean"&&(i.flipY=t.flipY);let n=(t.colorSpace||"").toLowerCase().trim();return n&&"colorSpace"in i&&(i.colorSpace=n==="srgb"?"srgb":"linear"),i.needsUpdate=!0,i}parseFlipY(e,t){let r=e?.getProperty("3d-texture-flipY")??t?.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(e){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=>e.hasAttribute(r))}applyModelTextureRemap(e,t){let r=(t.getAttribute("string-3d-model-texture-base")||"").trim(),i=r?r.replace(/\/?$/,"/"):"",n=t.getAttribute("string-3d-model-textures"),o=null;if(n)try{o=JSON.parse(n)}catch(a){console.warn("[String3D] Invalid model texture mapping JSON:",a)}let s=e?.manager;if(!s||typeof s.setURLModifier!="function"){(o||i)&&console.warn("[String3D] Model loader does not support URL remap.");return}s.setURLModifier(a=>{let c=o&&a in o?o[a]:a;return!i||/^(blob:|data:|https?:|file:|\/)/i.test(c)?c:i+c.replace(/^\.?\//,"")})}destroy(){this._objects.forEach(e=>e.destroy()),this._objects.clear(),this._rootObjects=[]}};var H=class{sync(e,t,r,i){let n=e.getBoundingClientRect(),o=n.left+n.width/2,s=n.top+n.height/2,a=getComputedStyle(e),c=parseFloat(a.getPropertyValue("--translate-z")||"0"),d=r.camera.screenToWorld(o,s,c);t.position=d;let h=parseFloat(a.getPropertyValue("--scale"))||1;t.scale=r.engine.createVector3(h,h,h);let u=-r.engine.degToRad(parseFloat(a.getPropertyValue("--rotate-x")||"0")),b=r.engine.degToRad(parseFloat(a.getPropertyValue("--rotate-y")||"0")),f=-r.engine.degToRad(parseFloat(a.getPropertyValue("--rotate-z")||"0"));return t.rotation=r.engine.createEuler(u,b,f,"XYZ"),t.object.updateMatrixWorld(!0),{scale:h}}};var C=class{sync(e,t,r,i){let n=e.getBoundingClientRect(),o=n.left+n.width/2,s=n.top+n.height/2,a=parseFloat(getComputedStyle(e).getPropertyValue("--translate-z")||"0"),c=r.camera.screenToWorld(o,s,a);return t.position=c,null}};var y=class{sync(e,t,r,i){let n=getComputedStyle(e),o=e.offsetWidth,s=e.offsetHeight,a=e.getBoundingClientRect(),c=parseFloat(n.getPropertyValue("--translate-z")||"0"),d=parseFloat(n.getPropertyValue("--scale")||"1"),h=a.left+a.width/2,u=a.top+a.height/2,b=r.camera.screenToWorld(h,u,c);t.position=b;let f=-r.engine.degToRad(parseFloat(n.getPropertyValue("--rotate-x")||"0")),R=r.engine.degToRad(parseFloat(n.getPropertyValue("--rotate-y")||"0")),D=-r.engine.degToRad(parseFloat(n.getPropertyValue("--rotate-z")||"0"));t.rotation=r.engine.createEuler(f,R,D,"XYZ");let m=o*d,S=s*d,B=parseFloat(n.getPropertyValue("--scale-z")||"1"),p=i?.scale||1,Q=t.type,I,x,E;switch(Q){case"box":case"sphere":{let v=Math.min(m,S);I=v*p,x=v*p,E=v*B*p;break}case"model":{let z=t.getOriginalBoundingBox().getSize(r.engine.createVector3()),X=(e.getAttribute("string-3d-model-fit")||"contain").toLowerCase().trim(),W=parseFloat(e.getAttribute("string-3d-model-scale")||"1"),_=Number.isFinite(W)?W:1;if(z.x>0&&z.y>0){let L=m/z.x,Y=S/z.y,k=X==="cover"?Math.max(L,Y):Math.min(L,Y);I=k*_*p,x=k*_*p,E=k*_*B*p}else{let L=Math.min(m,S);I=L*_*p,x=L*_*p,E=L*_*B*p}break}case"cylinder":{let v=m;I=v*p,x=S*p,E=v*B*p;break}case"plane":default:I=m*p,x=S*p,E=Math.min(m,S)*.5*B*p;break}return t.scale=r.engine.createVector3(I,x,E),{scale:d*p}}};var j=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 y),this.strategies.set("sphere",new y),this.strategies.set("plane",new y),this.strategies.set("cylinder",new y),this.strategies.set("model",new y),this.strategies.set("group",new H),this.strategies.set("pointLight",new C),this.strategies.set("ambientLight",new C),this.strategies.set("directionalLight",new C)}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 A=require("@fiddle-digital/string-tune"),M=class M extends Z.StringModule{constructor(t){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=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:""}]}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 o=i.parentElement?.closest('[string-3d="group"]');if(o){let s=o.getAttribute("string-id");s&&(r.setProperty("parentId",s),r.setProperty("parent",o))}}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(this.options=this.buildOptionsFromSettings(),!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 w(this.canvasContainer,this.engine),this.renderer.attach(),this.camera=new O(this.engine,"orthographic"),this.camera.setPosition(0,0,1e3),this.camera.resize(this.renderer.width,this.renderer.height);let t=this.resolveModelLoader(),r=this.resolveModelLoaderFactory();this.scene=new T(this.engine,{modelLoader:t,modelLoaderFactory:r}),this.scene.getScene().add(this.camera.camera),this.synchronizer=new j(this.camera,this.renderer.width,this.renderer.height,this.engine),console.info(`[String3D] Initialized with: ${M.provider.getName()}`)}onSettingsChange(){this.options=this.buildOptionsFromSettings()}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)}}getSettingValue(t,r){return!this.settings||!(t in this.settings)?r:this.settings[t]}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(t){console.warn("[String3D] Failed to create model loader:",t)}}}resolveModelLoaderFactory(){if(this.engine){if(this.options.modelLoaderFactory)return this.options.modelLoaderFactory;if(this.options.modelLoaderType)return(t,r)=>{let i=r||this.options.modelLoaderType;if(!i)throw new Error("[String3D] Model loader type not provided");return t.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 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||(A.frameDOM.measure(()=>{this.scene.rootObjects.forEach(r=>{this.syncRecursive(r.el,r,{scale:1})})}),A.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(o=>this.syncRecursive(o.el,o,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 te=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var ie=Object.prototype.hasOwnProperty;var ne=(b,t)=>{for(var e in t)Q(b,e,{get:t[e],enumerable:!0})},ae=(b,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of re(t))!ie.call(b,i)&&i!==e&&Q(b,i,{get:()=>t[i],enumerable:!(r=te(t,i))||r.enumerable});return b};var se=b=>ae(Q({},"__esModule",{value:!0}),b);var le={};ne(le,{String3D:()=>$,String3DCamera:()=>W,String3DCustomFilterRegistry:()=>k,String3DObject:()=>E,String3DRenderer:()=>H,String3DScene:()=>A,String3DSynchronizer:()=>V,ThreeJSEngine:()=>U,ThreeJSProvider:()=>q});module.exports=se(le);var ee=require("@fiddle-digital/string-tune");var W=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,o=e/this._height,l=(a-.5)*i,s=-(o-.5)*n;return this.engine.createVector3(l,s,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 k=class{static register(t){let e=t.name.trim().toLowerCase();if(!e)throw new Error("[String3D] Custom filter name is required.");this.filters.set(e,{...t,name:e})}static get(t){return this.filters.get(t.trim().toLowerCase())}static has(t){return this.filters.has(t.trim().toLowerCase())}static list(){return Array.from(this.filters.values())}};k.filters=new Map;var J=class{constructor(t){this.pool=[];this.create=t}acquire(t,e){let r=this.pool.pop()||this.create(t,e);return(r.width!==t||r.height!==e)&&r.setSize(t,e),r}release(t){this.pool.push(t)}dispose(){this.pool.forEach(t=>t.dispose()),this.pool=[]}},X=class{constructor(t,e,r,i){this.scale=1;this.customMaterials=new Map;this.engine=t,this.renderer=e,this.width=r,this.height=i,this.scene=t.createScene(),this.camera=t.createOrthographicCamera(-1,1,1,-1,0,1);let n=t.createPlaneGeometry(2,2);this.copyMaterial=this.createCopyMaterial(),this.blurMaterial=this.createBlurMaterial(),this.pixelMaterial=this.createPixelMaterial(),this.bloomExtractMaterial=this.createBloomExtractMaterial(),this.bloomAddMaterial=this.createBloomAddMaterial(),this.colorMaterial=this.createColorMaterial(),this.quad=t.createMesh(n,this.copyMaterial),this.scene.add(this.quad);let a=(o,l)=>{if(!this.engine.createRenderTarget)throw new Error("[String3DFilterPipeline] Render target support missing.");return this.engine.createRenderTarget(o,l)};this.pool=new J(a)}isSupported(){return!!this.engine.createRenderTarget&&!!this.engine.createShaderMaterial&&!!this.renderer.setRenderTarget}resize(t,e){this.width=t,this.height=e}setScale(t){let e=Math.max(.75,Math.min(1,t));this.scale=e}applyFilters(t,e,r=1){let i=t,n=[],a=l=>{let s=n.indexOf(l);s>=0&&(n.splice(s,1),this.pool.release(l))},o=()=>{let{width:l,height:s}=this.getScaledSize(),c=this.pool.acquire(l,s);return n.push(c),c};return e.forEach(l=>{if(l.type==="blur"){let s=l.amount*r;if(s<=1e-4)return;let c=o();this.renderPass(this.blurMaterial,i,c,{uDirection:[1,0],uRadius:s});let m=o();this.renderPass(this.blurMaterial,c,m,{uDirection:[0,1],uRadius:s}),a(c),i!==t&&a(i),i=m}else if(l.type==="pixel"){if(l.size<=.5)return;let s=o();this.renderPass(this.pixelMaterial,i,s,{uPixelSize:l.size}),i!==t&&a(i),i=s}else if(l.type==="bloom"){let s=l.intensity;if(s<=1e-4||l.threshold>=.99)return;let c=Math.max(1,4*r),m=o();this.renderPass(this.bloomExtractMaterial,i,m,{uThreshold:l.threshold});let h=o();this.renderPass(this.blurMaterial,m,h,{uDirection:[1,0],uRadius:c});let u=o();this.renderPass(this.blurMaterial,h,u,{uDirection:[0,1],uRadius:c}),a(m),a(h);let p=o();this.renderAddPass(i,u,p,s),a(u),i!==t&&a(i),i=p}else if(l.type==="brightness"||l.type==="contrast"||l.type==="saturate"||l.type==="grayscale"||l.type==="sepia"||l.type==="invert"||l.type==="hue-rotate"){let s=o(),c=this.getColorMode(l.type),m=l.type==="hue-rotate"?l.angle:l.amount;this.renderPass(this.colorMaterial,i,s,{uMode:c,uAmount:m}),i!==t&&a(i),i=s}else if(l.type==="custom"){let s=o(),c=this.getCustomMaterial(l.name);c?(this.renderPass(c,i,s,l.uniforms),i!==t&&a(i),i=s):a(s)}}),n.forEach(l=>{l!==i&&this.pool.release(l)}),i}acquireTarget(){let{width:t,height:e}=this.getScaledSize();return this.pool.acquire(t,e)}releaseTarget(t){this.pool.release(t)}renderToScreen(t){this.renderPass(this.copyMaterial,t,null,{},!1)}dispose(){this.pool.dispose(),this.customMaterials.forEach(t=>t.dispose()),this.customMaterials.clear()}renderPass(t,e,r,i={},n=!0){let a=this.renderer;a.setRenderTarget&&a.setRenderTarget(r),this.setMaterial(this.quad,t),this.setUniform(t,"tDiffuse",e.texture);let{width:o,height:l}=this.getScaledSize();this.setUniform(t,"uResolution",[o,l]),this.setUniform(t,"uTexel",[1/o,1/l]),Object.entries(i).forEach(([s,c])=>this.setUniform(t,s,c)),n&&a.clear&&a.clear(!0,!0,!0),this.renderer.render(this.scene,this.camera)}renderAddPass(t,e,r,i){let n=this.renderer;n.setRenderTarget&&n.setRenderTarget(r),this.setMaterial(this.quad,this.bloomAddMaterial),this.setUniform(this.bloomAddMaterial,"tBase",t.texture),this.setUniform(this.bloomAddMaterial,"tBloom",e.texture),this.setUniform(this.bloomAddMaterial,"uIntensity",i);let{width:a,height:o}=this.getScaledSize();this.setUniform(this.bloomAddMaterial,"uResolution",[a,o]),n.clear&&n.clear(!0,!0,!0),this.renderer.render(this.scene,this.camera)}setMaterial(t,e){let r=t;r.material!==e&&(r.material=e)}setUniform(t,e,r){let i=t.uniforms;i&&(i[e]?i[e].value=r:i[e]={value:r})}createCopyMaterial(){return this.createShaderMaterial({uniforms:{tDiffuse:{value:null}},vertexShader:this.getVertexShader(),fragmentShader:`
|
|
2
|
+
varying vec2 vUv;
|
|
3
|
+
uniform sampler2D tDiffuse;
|
|
4
|
+
void main() {
|
|
5
|
+
gl_FragColor = texture2D(tDiffuse, vUv);
|
|
6
|
+
}
|
|
7
|
+
`,transparent:!0,depthTest:!1,depthWrite:!1})}createPixelMaterial(){return this.createShaderMaterial({uniforms:{tDiffuse:{value:null},uResolution:{value:[this.width,this.height]},uPixelSize:{value:1}},vertexShader:this.getVertexShader(),fragmentShader:`
|
|
8
|
+
varying vec2 vUv;
|
|
9
|
+
uniform sampler2D tDiffuse;
|
|
10
|
+
uniform vec2 uResolution;
|
|
11
|
+
uniform float uPixelSize;
|
|
12
|
+
void main() {
|
|
13
|
+
vec2 pixel = uPixelSize / uResolution;
|
|
14
|
+
vec2 coord = floor(vUv / pixel) * pixel + pixel * 0.5;
|
|
15
|
+
gl_FragColor = texture2D(tDiffuse, coord);
|
|
16
|
+
}
|
|
17
|
+
`,transparent:!0,depthTest:!1,depthWrite:!1})}createBlurMaterial(){return this.createShaderMaterial({uniforms:{tDiffuse:{value:null},uTexel:{value:[1/this.width,1/this.height]},uDirection:{value:[1,0]},uRadius:{value:2}},vertexShader:this.getVertexShader(),fragmentShader:`
|
|
18
|
+
varying vec2 vUv;
|
|
19
|
+
uniform sampler2D tDiffuse;
|
|
20
|
+
uniform vec2 uTexel;
|
|
21
|
+
uniform vec2 uDirection;
|
|
22
|
+
uniform float uRadius;
|
|
23
|
+
void main() {
|
|
24
|
+
vec2 off1 = uDirection * uTexel * uRadius;
|
|
25
|
+
vec2 off2 = uDirection * uTexel * uRadius * 2.0;
|
|
26
|
+
vec2 off3 = uDirection * uTexel * uRadius * 3.0;
|
|
27
|
+
vec2 off4 = uDirection * uTexel * uRadius * 4.0;
|
|
28
|
+
vec4 color = texture2D(tDiffuse, vUv) * 0.227027;
|
|
29
|
+
color += texture2D(tDiffuse, vUv + off1) * 0.1945946;
|
|
30
|
+
color += texture2D(tDiffuse, vUv - off1) * 0.1945946;
|
|
31
|
+
color += texture2D(tDiffuse, vUv + off2) * 0.1216216;
|
|
32
|
+
color += texture2D(tDiffuse, vUv - off2) * 0.1216216;
|
|
33
|
+
color += texture2D(tDiffuse, vUv + off3) * 0.054054;
|
|
34
|
+
color += texture2D(tDiffuse, vUv - off3) * 0.054054;
|
|
35
|
+
color += texture2D(tDiffuse, vUv + off4) * 0.016216;
|
|
36
|
+
color += texture2D(tDiffuse, vUv - off4) * 0.016216;
|
|
37
|
+
gl_FragColor = color;
|
|
38
|
+
}
|
|
39
|
+
`,transparent:!0,depthTest:!1,depthWrite:!1})}createBloomExtractMaterial(){return this.createShaderMaterial({uniforms:{tDiffuse:{value:null},uThreshold:{value:.8}},vertexShader:this.getVertexShader(),fragmentShader:`
|
|
40
|
+
varying vec2 vUv;
|
|
41
|
+
uniform sampler2D tDiffuse;
|
|
42
|
+
uniform float uThreshold;
|
|
43
|
+
void main() {
|
|
44
|
+
vec4 color = texture2D(tDiffuse, vUv);
|
|
45
|
+
float brightness = max(max(color.r, color.g), color.b);
|
|
46
|
+
gl_FragColor = brightness > uThreshold ? color : vec4(0.0);
|
|
47
|
+
}
|
|
48
|
+
`,transparent:!0,depthTest:!1,depthWrite:!1})}createBloomAddMaterial(){return this.createShaderMaterial({uniforms:{tBase:{value:null},tBloom:{value:null},uIntensity:{value:1},uResolution:{value:[this.width,this.height]}},vertexShader:this.getVertexShader(),fragmentShader:`
|
|
49
|
+
varying vec2 vUv;
|
|
50
|
+
uniform sampler2D tBase;
|
|
51
|
+
uniform sampler2D tBloom;
|
|
52
|
+
uniform float uIntensity;
|
|
53
|
+
void main() {
|
|
54
|
+
vec4 base = texture2D(tBase, vUv);
|
|
55
|
+
vec4 bloom = texture2D(tBloom, vUv);
|
|
56
|
+
gl_FragColor = vec4(base.rgb + bloom.rgb * uIntensity, base.a);
|
|
57
|
+
}
|
|
58
|
+
`,transparent:!0,depthTest:!1,depthWrite:!1})}createColorMaterial(){return this.createShaderMaterial({uniforms:{tDiffuse:{value:null},uMode:{value:0},uAmount:{value:1}},vertexShader:this.getVertexShader(),fragmentShader:`
|
|
59
|
+
varying vec2 vUv;
|
|
60
|
+
uniform sampler2D tDiffuse;
|
|
61
|
+
uniform int uMode;
|
|
62
|
+
uniform float uAmount;
|
|
63
|
+
|
|
64
|
+
vec3 applyHueRotate(vec3 color, float angle) {
|
|
65
|
+
float cosA = cos(angle);
|
|
66
|
+
float sinA = sin(angle);
|
|
67
|
+
mat3 m = mat3(
|
|
68
|
+
0.213 + cosA * 0.787 - sinA * 0.213,
|
|
69
|
+
0.715 - cosA * 0.715 - sinA * 0.715,
|
|
70
|
+
0.072 - cosA * 0.072 + sinA * 0.928,
|
|
71
|
+
0.213 - cosA * 0.213 + sinA * 0.143,
|
|
72
|
+
0.715 + cosA * 0.285 + sinA * 0.140,
|
|
73
|
+
0.072 - cosA * 0.072 - sinA * 0.283,
|
|
74
|
+
0.213 - cosA * 0.213 - sinA * 0.787,
|
|
75
|
+
0.715 - cosA * 0.715 + sinA * 0.715,
|
|
76
|
+
0.072 + cosA * 0.928 + sinA * 0.072
|
|
77
|
+
);
|
|
78
|
+
return clamp(m * color, 0.0, 1.0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void main() {
|
|
82
|
+
vec4 color = texture2D(tDiffuse, vUv);
|
|
83
|
+
float luma = dot(color.rgb, vec3(0.299, 0.587, 0.114));
|
|
84
|
+
|
|
85
|
+
if (uMode == 1) {
|
|
86
|
+
color.rgb *= uAmount;
|
|
87
|
+
} else if (uMode == 2) {
|
|
88
|
+
color.rgb = (color.rgb - 0.5) * uAmount + 0.5;
|
|
89
|
+
} else if (uMode == 3) {
|
|
90
|
+
color.rgb = mix(vec3(luma), color.rgb, uAmount);
|
|
91
|
+
} else if (uMode == 4) {
|
|
92
|
+
color.rgb = mix(color.rgb, vec3(luma), uAmount);
|
|
93
|
+
} else if (uMode == 5) {
|
|
94
|
+
vec3 sepia = vec3(
|
|
95
|
+
dot(color.rgb, vec3(0.393, 0.769, 0.189)),
|
|
96
|
+
dot(color.rgb, vec3(0.349, 0.686, 0.168)),
|
|
97
|
+
dot(color.rgb, vec3(0.272, 0.534, 0.131))
|
|
98
|
+
);
|
|
99
|
+
color.rgb = mix(color.rgb, sepia, uAmount);
|
|
100
|
+
} else if (uMode == 6) {
|
|
101
|
+
color.rgb = mix(color.rgb, vec3(1.0) - color.rgb, uAmount);
|
|
102
|
+
} else if (uMode == 7) {
|
|
103
|
+
color.rgb = applyHueRotate(color.rgb, uAmount);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
gl_FragColor = color;
|
|
107
|
+
}
|
|
108
|
+
`,transparent:!0,depthTest:!1,depthWrite:!1})}getColorMode(t){switch(t){case"brightness":return 1;case"contrast":return 2;case"saturate":return 3;case"grayscale":return 4;case"sepia":return 5;case"invert":return 6;case"hue-rotate":return 7;default:return 0}}createShaderMaterial(t){if(!this.engine.createShaderMaterial)throw new Error("[String3DFilterPipeline] Shader material support missing.");return this.engine.createShaderMaterial(t)}getCustomMaterial(t){let e=t.trim().toLowerCase();if(!e)return null;if(this.customMaterials.has(e))return this.customMaterials.get(e);let r=k.get(e);if(!r)return null;let i={tDiffuse:{value:null}},{width:n,height:a}=this.getScaledSize();i.uResolution={value:[n,a]},i.uTexel={value:[1/n,1/a]},Object.entries(r.uniforms||{}).forEach(([l,s])=>{i[l]={value:s}});let o=this.createShaderMaterial({uniforms:i,vertexShader:this.getVertexShader(),fragmentShader:r.fragmentShader,transparent:!0,depthTest:!1,depthWrite:!1});return this.customMaterials.set(e,o),o}getScaledSize(){let t=Math.max(1,Math.round(this.width*this.scale)),e=Math.max(1,Math.round(this.height*this.scale));return{width:t,height:e}}getVertexShader(){return`
|
|
109
|
+
varying vec2 vUv;
|
|
110
|
+
void main() {
|
|
111
|
+
vUv = uv;
|
|
112
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
113
|
+
}
|
|
114
|
+
`}};var H=class{constructor(t,e){this.filterPipeline=null;this.filterCache=new Map;this.frameId=0;this.lastFrameTime=performance.now();this.avgFrameMs=16.7;this.qualityScale=1;this.lastQualityChange=0;this.filterLayer=1;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,r=[]){if(r.length===0){this._renderer.render(t.getScene(),e.camera);return}let i=this.ensureFilterPipeline();if(!i?.isSupported()){this._renderer.render(t.getScene(),e.camera);return}this.frameId+=1,this.updateQuality(r.length,i);let n=t.getAllObjects(),a=new Map;n.forEach(h=>{let u=h.object;"visible"in u&&a.set(h.object,u.visible)});let o=new Set;r.forEach(h=>{this.collectSubtreeObjects(h.object,o)}),n.forEach(h=>{o.has(h.object)&&this.setVisible(h.object,!1)});let l=this._renderer,s=l.autoClear;l.autoClear=!0,l.setRenderTarget&&l.setRenderTarget(null),l.clear&&l.clear(!0,!0,!0),this._renderer.render(t.getScene(),e.camera),l.autoClear=!1,n.forEach(h=>{let u=a.get(h.object);typeof u<"u"&&this.setVisible(h.object,u)});let c=n.filter(h=>h.type.endsWith("Light")),m=this.supportsLayers(e.camera,n);r.forEach(h=>{let u=this.filterCache.get(h.object.id);if(!h.dirty&&u&&u.effectsKey===h.effectsKey&&u.qualityScale===this.qualityScale){u.lastUsedFrame=this.frameId,i.renderToScreen(u.target);return}let d=this.injectEffectContext(h.object.el,h.effects),g=new Set;this.collectSubtreeObjects(h.object,g);let v=[],M=null;if(m){let f=h.object.getSubtreeObjects();v=this.applyLayerMask(f,c,this.filterLayer),M=this.setCameraLayer(e.camera,this.filterLayer)}else n.forEach(f=>{if(a.get(f.object)===!1){this.setVisible(f.object,!1);return}if(f.type.endsWith("Light")){this.setVisible(f.object,!0);return}this.setVisible(f.object,g.has(f.object))});let x=i.acquireTarget();l.setRenderTarget&&l.setRenderTarget(x),l.clear&&l.clear(!0,!0,!0),this._renderer.render(t.getScene(),e.camera);let y=i.applyFilters(x,d,this.qualityScale);l.setRenderTarget&&l.setRenderTarget(null),i.renderToScreen(y),m&&(this.restoreLayerMask(v),M!==null&&this.restoreCameraLayer(e.camera,M)),y!==x&&i.releaseTarget(x);let S={target:y,effectsKey:h.effectsKey,lastUsedFrame:this.frameId,qualityScale:this.qualityScale},D=this.filterCache.get(h.object.id);D&&D.target!==y&&i.releaseTarget(D.target),this.filterCache.set(h.object.id,S)}),m||n.forEach(h=>{let u=a.get(h.object);typeof u<"u"&&this.setVisible(h.object,u)}),l.autoClear=s,this.evictCache()}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),this.filterPipeline?.resize(e,r),this.invalidateFilterCache()}get width(){return this._width}get height(){return this._height}get renderer(){return this._renderer}destroy(){this._renderer.dispose(),this.filterPipeline?.dispose(),this.filterCache.clear()}ensureFilterPipeline(){return this.canCreateFilterPipeline()?(this.filterPipeline||(this.filterPipeline=new X(this.engine,this._renderer,this._width,this._height),this.filterPipeline.setScale(this.qualityScale)),this.filterPipeline):null}canCreateFilterPipeline(){return typeof this.engine.createRenderTarget=="function"&&typeof this.engine.createShaderMaterial=="function"&&typeof this._renderer.setRenderTarget=="function"}collectSubtreeObjects(t,e){e.add(t.object),t.children.forEach(r=>this.collectSubtreeObjects(r,e))}setVisible(t,e){let r=t;"visible"in r&&(r.visible=e)}getFilterCenter(t){if(!t||!this._width||!this._height)return[.5,.5];let e=t.getBoundingClientRect(),r=(e.left+e.width/2)/this._width,i=1-(e.top+e.height/2)/this._height,n=a=>Math.max(0,Math.min(1,a));return[n(r),n(i)]}injectEffectContext(t,e){if(!e.some(a=>a.type==="custom"))return e;let r=this.getFilterCenter(t),i=!1,n=e.map(a=>{if(a.type!=="custom"||a.uniforms&&"uCenter"in a.uniforms)return a;let o={...a.uniforms||{},uCenter:r};return i=!0,{...a,uniforms:o}});return i?n:e}updateQuality(t,e){let r=performance.now(),i=Math.max(.1,r-this.lastFrameTime);this.lastFrameTime=r,this.avgFrameMs=this.avgFrameMs*.9+i*.1;let n=1e3/this.avgFrameMs,a=Math.max(.75,1-Math.min(.4,t*.03)),o=a;n<48&&(o=Math.max(.75,a-.1)),n<40&&(o=Math.max(.75,a-.2)),n>58&&(o=Math.min(1,a+.05)),Math.abs(o-this.qualityScale)>=.05&&r-this.lastQualityChange>300&&(this.qualityScale=o,this.lastQualityChange=r,e.setScale(this.qualityScale),this.invalidateFilterCache())}invalidateFilterCache(){this.filterPipeline&&(this.filterCache.forEach(t=>{this.filterPipeline?.releaseTarget(t.target)}),this.filterCache.clear())}evictCache(){if(!this.filterPipeline)return;let t=120;this.filterCache.forEach((e,r)=>{this.frameId-e.lastUsedFrame>t&&(this.filterPipeline?.releaseTarget(e.target),this.filterCache.delete(r))})}supportsLayers(t,e){return!t?.layers||typeof t.layers.set!="function"?!1:e.some(r=>this.hasLayers(r.object))}hasLayers(t){return t?.layers&&typeof t.layers.set=="function"}applyLayerMask(t,e,r){let i=new Map,n=(a,o)=>{let l=a;this.hasLayers(l)&&(i.has(a)||i.set(a,l.layers.mask),o==="set"?l.layers.set(r):l.layers.enable(r))};return t.forEach(a=>n(a,"set")),e.forEach(a=>n(a.object,"enable")),Array.from(i.entries()).map(([a,o])=>({object:a,mask:o}))}restoreLayerMask(t){t.forEach(e=>{let r=e.object;this.hasLayers(r)&&(r.layers.mask=e.mask)})}setCameraLayer(t,e){if(!t?.layers||typeof t.layers.set!="function")return null;let r=t.layers.mask;return t.layers.set(e),r}restoreCameraLayer(t,e){t?.layers&&(t.layers.mask=e)}};var E=class{constructor(t,e,r,i,n={}){this._uniforms={};this._children=[];this._flatObjectsCache=null;this._subtreeCache=null;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),this.invalidateFlatCache(),this.invalidateSubtreeCache()}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(),this._subtreeCache=null}getFlatObjects(){if(this._flatObjectsCache)return this._flatObjectsCache;let t=[],e=r=>{t.push(r.object),r.children.forEach(i=>e(i))};return e(this),this._flatObjectsCache=t,t}getSubtreeObjects(){if(this._subtreeCache)return this._subtreeCache;let t=[],e=this._object;return t.push(this._object),typeof e.traverse=="function"&&e.traverse(r=>{r&&r!==this._object&&t.push(r)}),this._subtreeCache=t,t}invalidateFlatCache(){this._flatObjectsCache=null}invalidateSubtreeCache(){this._subtreeCache=null}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 A=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)}getAllObjects(){let t=[],e=r=>{t.push(r),r.children.forEach(i=>e(i))};return this._rootObjects.forEach(r=>e(r)),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 E(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 s=t.getProperty("3d-distance")??1e3,c=t.getProperty("3d-decay")??0;a=this.engine.createPointLight(i,n,s,c)}else if(e==="directional")a=this.engine.createDirectionalLight(i,n);else if(e==="spot"){let s=t.getProperty("3d-distance")??0,c=t.getProperty("3d-angle")??Math.PI/3,m=t.getProperty("3d-penumbra")??0,h=t.getProperty("3d-decay")??1;a=this.engine.createSpotLight(i,n,s,c,m,h)}else if(e==="hemisphere"){let s=t.getProperty("3d-ground-color")||"#ffffff";a=this.engine.createHemisphereLight(i,s,n)}else a=this.engine.createAmbientLight(i,n);if((t.getProperty("3d-cast-shadow")??!1)&&a.shadow){a.castShadow=!0;let s=t.getProperty("3d-shadow-bias")??0,c=t.getProperty("3d-shadow-map-size")??512;a.shadow.bias=s,a.shadow.mapSize.width=c,a.shadow.mapSize.height=c}let l=new E(t.id,e+"Light",a,this.engine);return r(l),l}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 E(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),o=this.engine.createMesh(n,a);this.applyShadowProps(t,o);let l=new E(t.id,"sphere",o,this.engine,{geometry:n,material:a});return e(l),l}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 E(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 o=new E(t.id,"cylinder",a,this.engine,{geometry:i,material:n});return e(o),o}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 o=t.getProperty("3d-model-center")??!1;n.load(r,l=>{let s=l?.scene||l?.object||l;if(!s){console.warn("[String3D] Model loader returned empty result");return}let c=a&&this.shouldOverrideModelMaterial(a)?this.createMaterialFromElement(a,t):null;typeof s.traverse=="function"&&s.traverse(h=>{h.isMesh&&(c&&(h.material=c),this.applyShadowProps(t,h))}),o&&this.centerObject(s);let m=new E(t.id,"model",s,this.engine);e(m)},l=>{console.log(l.loaded/l.total*100+"% loaded")},l=>{console.error("[String3D] Model loading error:",l)})}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",o=e?.getProperty("3d-opacity")??1,l=e?.getProperty("3d-metalness"),s=e?.getProperty("3d-roughness"),c={color:a,transparent:o<1,opacity:o},m=t?.getAttribute("string-3d-map"),h=t?.getAttribute("string-3d-normalMap"),u=t?.getAttribute("string-3d-roughnessMap"),p=t?.getAttribute("string-3d-metalnessMap"),d=t?.getAttribute("string-3d-aoMap"),g=this.parseFlipY(e,t),v=e?.getProperty("3d-colorSpace")||t?.getAttribute("string-3d-colorSpace")||"";return i!=="standard"&&!!(m||h||u||p||d)&&(i="standard"),i==="standard"?(m&&(c.map=this.loadTexture(m,{flipY:g,colorSpace:v})),h&&(c.normalMap=this.loadTexture(h,{flipY:g})),u&&(c.roughnessMap=this.loadTexture(u,{flipY:g})),p&&(c.metalnessMap=this.loadTexture(p,{flipY:g})),d&&(c.aoMap=this.loadTexture(d,{flipY:g})),typeof l=="number"&&(c.metalness=l),typeof s=="number"&&(c.roughness=s),this.engine.createMeshStandardMaterial(c)):this.engine.createMeshBasicMaterial(c)}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(l){console.warn("[String3D] Invalid model texture mapping JSON:",l)}let o=t?.manager;if(!o||typeof o.setURLModifier!="function"){(a||i)&&console.warn("[String3D] Model loader does not support URL remap.");return}o.setURLModifier(l=>{let s=a&&l in a?a[l]:l;return!i||/^(blob:|data:|https?:|file:|\/)/i.test(s)?s:i+s.replace(/^\.?\//,"")})}destroy(){this._objects.forEach(t=>t.destroy()),this._objects.clear(),this._rootObjects=[]}};var G=class{sync(t,e,r,i){let n=t.getBoundingClientRect(),a=n.left+n.width/2,o=n.top+n.height/2,l=t.computedStyleMap?.(),s=null,c=()=>(s||(s=getComputedStyle(t)),s),m=(M,x)=>{let y=l?.get?.(M);if(y!==void 0){if(typeof y=="number")return y;if(typeof y=="string"){let f=Number.parseFloat(y);if(!Number.isNaN(f))return f}if(y&&typeof y=="object"){let f=y.value;if(typeof f=="number")return f;if(typeof f=="string"){let I=Number.parseFloat(f);if(!Number.isNaN(I))return I}}}let S=c().getPropertyValue(M),D=Number.parseFloat(S);return Number.isNaN(D)?x:D},h=m("--translate-z",0),u=r.camera.screenToWorld(a,o,h);e.position=u;let p=m("--scale",1);e.scale=r.engine.createVector3(p,p,p);let d=-r.engine.degToRad(m("--rotate-x",0)),g=r.engine.degToRad(m("--rotate-y",0)),v=-r.engine.degToRad(m("--rotate-z",0));return e.rotation=r.engine.createEuler(d,g,v,"XYZ"),e.object.updateMatrixWorld(!0),{scale:p}}};var _=class{sync(t,e,r,i){let n=t.getBoundingClientRect(),a=n.left+n.width/2,o=n.top+n.height/2,l=parseFloat(getComputedStyle(t).getPropertyValue("--translate-z")||"0"),s=r.camera.screenToWorld(a,o,l);e.position=s;let c=e.object,m=t.getAttribute("string-3d-color");m&&c.color&&typeof c.color.set=="function"&&c.color.set(m);let h=t.getAttribute("string-3d-intensity");h&&(c.intensity=parseFloat(h));let u=t.getAttribute("string-3d-distance");u&&typeof c.distance<"u"&&(c.distance=parseFloat(u));let p=t.getAttribute("string-3d-decay");p&&typeof c.decay<"u"&&(c.decay=parseFloat(p));let d=t.getAttribute("string-3d-angle");d&&typeof c.angle<"u"&&(c.angle=parseFloat(d));let g=t.getAttribute("string-3d-penumbra");g&&typeof c.penumbra<"u"&&(c.penumbra=parseFloat(g));let v=t.getAttribute("string-3d-ground-color");v&&c.groundColor&&typeof c.groundColor.set=="function"&&c.groundColor.set(v);let M=t.getAttribute("string-3d-cast-shadow")==="true";if(c.castShadow!==M&&(c.castShadow=M),M&&c.shadow){let y=t.getAttribute("string-3d-shadow-bias");y&&(c.shadow.bias=parseFloat(y));let S=t.getAttribute("string-3d-shadow-map-size");if(S){let D=parseFloat(S);c.shadow.mapSize.width!==D&&(c.shadow.mapSize.width=D,c.shadow.mapSize.height=D)}}let x=t.getAttribute("string-3d-target");if(x&&c.target){let y=document.querySelector(`[string-id="${x}"]`);if(y){let S=y.getBoundingClientRect(),D=S.left+S.width/2,f=S.top+S.height/2,I=parseFloat(getComputedStyle(y).getPropertyValue("--translate-z")||"0"),T=r.camera.screenToWorld(D,f,I);c.target.position.copy(T),c.target.updateMatrixWorld(!0)}}return null}};var R=class b{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(o=>{o.isMesh&&(o.castShadow!==i&&(o.castShadow=i),o.receiveShadow!==n&&(o.receiveShadow=n),isNaN(a)||(Array.isArray(o.material)?o.material:[o.material]).forEach(s=>{s&&(s.opacity=a,s.transparent=a<1)}))});else if(e.object.isMesh){let o=e.object;o.castShadow!==i&&(o.castShadow=i),o.receiveShadow!==n&&(o.receiveShadow=n),isNaN(a)||(Array.isArray(o.material)?o.material:[o.material]).forEach(s=>{s&&(s.opacity=a,s.transparent=a<1)})}}sync(t,e,r,i){let n=t.computedStyleMap?.(),a=null,o=()=>(a||(a=getComputedStyle(t)),a),l=t.getBoundingClientRect(),s=t.offsetWidth||l.width,c=t.offsetHeight||l.height,m=(C,P)=>{let L=n?.get?.(C);if(L!==void 0){if(typeof L=="number")return L;if(typeof L=="string"){let w=Number.parseFloat(L);if(!Number.isNaN(w))return w}if(L&&typeof L=="object"){let w=L.value;if(typeof w=="number")return w;if(typeof w=="string"){let B=Number.parseFloat(w);if(!Number.isNaN(B))return B}}}let Y=o().getPropertyValue(C),F=Number.parseFloat(Y);return Number.isNaN(F)?P:F},h=m("--translate-z",0),u=m("--scale",1),p=l.left+l.width/2,d=l.top+l.height/2,g=r.camera.screenToWorld(p,d,h);e.position=g;let v=-r.engine.degToRad(m("--rotate-x",0)),M=r.engine.degToRad(m("--rotate-y",0)),x=-r.engine.degToRad(m("--rotate-z",0));e.rotation=r.engine.createEuler(v,M,x,"XYZ");let y=s*u,S=c*u,D=m("--scale-z",1),f=i?.scale||1,I=e.type,T,j,O;switch(I){case"box":case"sphere":{let C=Math.min(y,S);T=C*f,j=C*f,O=C*D*f;break}case"model":{let P=e.getOriginalBoundingBox().getSize(r.engine.createVector3()),L=(t.getAttribute("string-3d-model-fit")||"contain").toLowerCase().trim(),Y=parseFloat(t.getAttribute("string-3d-model-scale")||"1"),F=Number.isFinite(Y)?Y:1;if(P.x>0&&P.y>0){let w=y/P.x,B=S/P.y,K=L==="cover"?Math.max(w,B):Math.min(w,B);T=K*F*f,j=K*F*f,O=K*F*D*f}else{let w=Math.min(y,S);T=w*F*f,j=w*F*f,O=w*F*D*f}break}case"cylinder":{let C=y;T=C*f,j=S*f,O=C*D*f;break}case"plane":default:T=y*f,j=S*f,O=Math.min(y,S)*.5*D*f;break}e.scale=r.engine.createVector3(T,j,O);let Z=m("--opacity",NaN);return b.applyVisualProps(t,e,Z),{scale:u*f}}};var V=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 R),this.strategies.set("sphere",new R),this.strategies.set("plane",new R),this.strategies.set("cylinder",new R),this.strategies.set("model",new R),this.strategies.set("group",new G),this.strategies.set("pointLight",new _),this.strategies.set("ambientLight",new _),this.strategies.set("directionalLight",new _),this.strategies.set("spotLight",new _),this.strategies.set("hemisphereLight",new _)}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 oe=`
|
|
115
|
+
let wasm = null;
|
|
116
|
+
let wasmReady = false;
|
|
117
|
+
|
|
118
|
+
function degToRad(deg) {
|
|
119
|
+
return (deg * Math.PI) / 180;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function computeTransform(item, camera) {
|
|
123
|
+
const centerX = item.rectLeft + item.rectWidth / 2;
|
|
124
|
+
const centerY = item.rectTop + item.rectHeight / 2;
|
|
125
|
+
|
|
126
|
+
let posX = 0;
|
|
127
|
+
let posY = 0;
|
|
128
|
+
let posZ = item.translateZ;
|
|
129
|
+
|
|
130
|
+
if (camera.mode === "orthographic") {
|
|
131
|
+
posX = centerX - camera.width / 2;
|
|
132
|
+
posY = -(centerY - camera.height / 2);
|
|
133
|
+
} else {
|
|
134
|
+
const fov = degToRad(camera.fov);
|
|
135
|
+
const distance = Math.abs(item.translateZ - camera.cameraZ);
|
|
136
|
+
const height = 2 * Math.tan(fov / 2) * distance;
|
|
137
|
+
const width = height * camera.aspect;
|
|
138
|
+
const normalizedX = centerX / camera.width;
|
|
139
|
+
const normalizedY = centerY / camera.height;
|
|
140
|
+
posX = (normalizedX - 0.5) * width;
|
|
141
|
+
posY = -(normalizedY - 0.5) * height;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const rotX = -degToRad(item.rotateX);
|
|
145
|
+
const rotY = degToRad(item.rotateY);
|
|
146
|
+
const rotZ = -degToRad(item.rotateZ);
|
|
147
|
+
|
|
148
|
+
let scaleX = 1;
|
|
149
|
+
let scaleY = 1;
|
|
150
|
+
let scaleZ = 1;
|
|
151
|
+
|
|
152
|
+
if (item.type === "group") {
|
|
153
|
+
scaleX = item.scale;
|
|
154
|
+
scaleY = item.scale;
|
|
155
|
+
scaleZ = item.scale;
|
|
156
|
+
} else {
|
|
157
|
+
const targetWidth = item.rectWidth * item.scale;
|
|
158
|
+
const targetHeight = item.rectHeight * item.scale;
|
|
159
|
+
const parentScale = item.parentScale || 1;
|
|
160
|
+
const cssScaleZ = item.scaleZ || 1;
|
|
161
|
+
|
|
162
|
+
if (item.type === "box" || item.type === "sphere") {
|
|
163
|
+
const uniformSize = Math.min(targetWidth, targetHeight);
|
|
164
|
+
scaleX = uniformSize * parentScale;
|
|
165
|
+
scaleY = uniformSize * parentScale;
|
|
166
|
+
scaleZ = uniformSize * cssScaleZ * parentScale;
|
|
167
|
+
} else if (item.type === "model") {
|
|
168
|
+
const sizeX = item.modelSizeX || 0;
|
|
169
|
+
const sizeY = item.modelSizeY || 0;
|
|
170
|
+
const fitMode = (item.fitMode || "contain").toLowerCase().trim();
|
|
171
|
+
const modelScale = Number.isFinite(item.modelScale) ? item.modelScale : 1;
|
|
172
|
+
|
|
173
|
+
if (sizeX > 0 && sizeY > 0) {
|
|
174
|
+
const scaleToWidth = targetWidth / sizeX;
|
|
175
|
+
const scaleToHeight = targetHeight / sizeY;
|
|
176
|
+
const uniformScale = fitMode === "cover"
|
|
177
|
+
? Math.max(scaleToWidth, scaleToHeight)
|
|
178
|
+
: Math.min(scaleToWidth, scaleToHeight);
|
|
179
|
+
scaleX = uniformScale * modelScale * parentScale;
|
|
180
|
+
scaleY = uniformScale * modelScale * parentScale;
|
|
181
|
+
scaleZ = uniformScale * modelScale * cssScaleZ * parentScale;
|
|
182
|
+
} else {
|
|
183
|
+
const fallbackSize = Math.min(targetWidth, targetHeight);
|
|
184
|
+
scaleX = fallbackSize * modelScale * parentScale;
|
|
185
|
+
scaleY = fallbackSize * modelScale * parentScale;
|
|
186
|
+
scaleZ = fallbackSize * modelScale * cssScaleZ * parentScale;
|
|
187
|
+
}
|
|
188
|
+
} else if (item.type === "cylinder") {
|
|
189
|
+
const cylRadius = targetWidth;
|
|
190
|
+
scaleX = cylRadius * parentScale;
|
|
191
|
+
scaleY = targetHeight * parentScale;
|
|
192
|
+
scaleZ = cylRadius * cssScaleZ * parentScale;
|
|
193
|
+
} else {
|
|
194
|
+
scaleX = targetWidth * parentScale;
|
|
195
|
+
scaleY = targetHeight * parentScale;
|
|
196
|
+
scaleZ = Math.min(targetWidth, targetHeight) * 0.5 * cssScaleZ * parentScale;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
id: item.id,
|
|
202
|
+
posX,
|
|
203
|
+
posY,
|
|
204
|
+
posZ,
|
|
205
|
+
rotX,
|
|
206
|
+
rotY,
|
|
207
|
+
rotZ,
|
|
208
|
+
scaleX,
|
|
209
|
+
scaleY,
|
|
210
|
+
scaleZ,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function initWasm(url) {
|
|
215
|
+
try {
|
|
216
|
+
const res = await fetch(url);
|
|
217
|
+
const bytes = await res.arrayBuffer();
|
|
218
|
+
const mod = await WebAssembly.instantiate(bytes, {});
|
|
219
|
+
wasm = mod.instance;
|
|
220
|
+
wasmReady = true;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
wasm = null;
|
|
223
|
+
wasmReady = false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
self.onmessage = async (event) => {
|
|
228
|
+
const data = event.data || {};
|
|
229
|
+
if (data.type === "init") {
|
|
230
|
+
if (data.wasmUrl) {
|
|
231
|
+
await initWasm(data.wasmUrl);
|
|
232
|
+
}
|
|
233
|
+
self.postMessage({ type: "ready", wasmReady });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (data.type === "compute") {
|
|
238
|
+
const items = data.items || [];
|
|
239
|
+
const camera = data.camera || {};
|
|
240
|
+
const results = new Array(items.length);
|
|
241
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
242
|
+
results[i] = computeTransform(items[i], camera);
|
|
243
|
+
}
|
|
244
|
+
self.postMessage({ type: "result", frameId: data.frameId, results });
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
`,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([oe],{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 z=class z extends ee.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.filterStates=new WeakMap;this.filterWarnings=new WeakMap;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){z.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 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(),this.useDirtySync&&this.markAllDirty())}onInit(){if(this.options=this.buildOptionsFromSettings(),!z.provider){console.error("[String3D] No provider set. Call String3D.setProvider() before use.");return}this.engine=z.provider.getEngine(),this.canvasContainer=this.createOrGetContainer(),this.registerTypedProperties(),this.injectCSS(),this.useDirtySync=!!this.options.useDirtySync,this.useDirtySync&&(this.setupObservers(),this.setupScrollListeners()),this.renderer=new H(this.canvasContainer,this.engine),this.renderer.attach(),this.camera=new W(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 A(this.engine,{modelLoader:e,modelLoaderFactory:r}),this.scene.getScene().add(this.camera.camera),this.synchronizer=new V(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: ${z.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 l=[];if(this.workerObjectMap.clear(),this.scene.rootObjects.forEach(s=>{this.collectWorkerInputs(s,{scale:1},n,i,l)}),l.length>0){let s=this.domVersion;this.lastSubmittedVersion=s,a.submit(l,this.buildWorkerCameraData(),s)}}this.scene.rootObjects.forEach(l=>{this.syncRecursive(l.el,l,{scale:1},n,i)});let o=this.collectFilterTargets(performance.now(),n,i);this.renderer.render(this.scene,this.camera,o),this.useDirtySync&&this.dirtyElements.clear()}syncRecursive(e,r,i,n,a){if(!this.synchronizer||!e)return;let o=n||!a||a.has(e),l=i;if(o){let c=this.synchronizer.syncElement(e,r,i);c&&typeof c.scale=="number"&&(this.lastSyncData.set(r,c),l=c)}else{let c=this.lastSyncData.get(r);c&&(l=c)}let s=n||o;r.children.forEach(c=>this.syncRecursive(c.el,c,l,s,a))}injectCSS(){if(document.getElementById("string-3d-styles"))return;let e=document.createElement("style");e.id="string-3d-styles",e.textContent=`
|
|
2
248
|
@property --translate-x { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
3
249
|
@property --translate-y { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
4
250
|
@property --translate-z { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
@@ -9,11 +255,13 @@
|
|
|
9
255
|
@property --scale-x { syntax: "<number>"; inherits: false; initial-value: 1; }
|
|
10
256
|
@property --scale-y { syntax: "<number>"; inherits: false; initial-value: 1; }
|
|
11
257
|
@property --scale-z { syntax: "<number>"; inherits: false; initial-value: 1; }
|
|
258
|
+
@property --opacity { syntax: "<number>"; inherits: false; initial-value: 1; }
|
|
259
|
+
@property --filter { syntax: "*"; inherits: false; initial-value: none; }
|
|
12
260
|
|
|
13
261
|
[string-3d] {
|
|
14
262
|
--translate-x: 0; --translate-y: 0; --translate-z: 0;
|
|
15
263
|
--rotate-x: 0; --rotate-y: 0; --rotate-z: 0;
|
|
16
|
-
--scale: 1; --scale-x: 1; --scale-y: 1; --scale-z: 1;
|
|
264
|
+
--scale: 1; --scale-x: 1; --scale-y: 1; --scale-z: 1;--opacity: 1; --filter: none;
|
|
17
265
|
transform-style: preserve-3d;
|
|
18
266
|
}
|
|
19
267
|
|
|
@@ -25,5 +273,5 @@
|
|
|
25
273
|
rotateZ(calc(var(--rotate-z) * 1deg))
|
|
26
274
|
scale3d(calc(var(--scale) * var(--scale-x)), calc(var(--scale) * var(--scale-y)), calc(var(--scale) * var(--scale-z)));
|
|
27
275
|
}
|
|
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 F=M;var P=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,o=1e4){return new this.THREE.OrthographicCamera(e,t,r,i,n,o)}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 o=n.clone().applyMatrix4(i.matrixWorld);t.union(o),r=!0}}}),r?t:new this.THREE.Box3}},V=class{constructor(e,t={}){this.engine=new P(e,t)}getEngine(){return this.engine}getName(){return"Three.js"}};0&&(module.exports={String3D,String3DCamera,String3DObject,String3DRenderer,String3DScene,String3DSynchronizer,ThreeJSEngine,ThreeJSProvider});
|
|
276
|
+
`,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"},{name:"--filter",initialValue:"none"}].forEach(({name:i,initialValue:n})=>{try{e.registerProperty({name:i,syntax:i==="--filter"?"*":"<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 c=Number.parseFloat(a);if(!Number.isNaN(c))return c}if(a&&typeof a=="object"){let c=a.value;if(typeof c=="number")return c;if(typeof c=="string"){let m=Number.parseFloat(c);if(!Number.isNaN(m))return m}}}let l=getComputedStyle(e).getPropertyValue(r),s=Number.parseFloat(l);return Number.isNaN(s)?i:s}readFilterRaw(e){let r=e.computedStyleMap?.(),i="",n=r?.get?.("--filter");if(n!==void 0){if(typeof n=="string")i=n;else if(n&&typeof n=="object"){let a=n.value;typeof a=="string"&&(i=a)}}return i||(i=getComputedStyle(e).getPropertyValue("--filter")||""),i=i.trim(),i}parseFilterChain(e){let r=[],i=[],n=u=>{let d=u.trim().toLowerCase().match(/^(-?\d*\.?\d+)(px)?$/);if(!d)return null;let g=Number.parseFloat(d[1]);return Number.isFinite(g)?g:null},a=u=>{let p=u.trim().toLowerCase();if(!p)return null;if(p.endsWith("%")){let g=Number.parseFloat(p.slice(0,-1));return Number.isFinite(g)?g/100:null}let d=Number.parseFloat(p);return Number.isFinite(d)?d:null},o=u=>{let p=u.trim().toLowerCase();if(!p)return null;if(p.endsWith("rad")){let v=Number.parseFloat(p.slice(0,-3));return Number.isFinite(v)?v:null}let d=p.endsWith("deg")?p.slice(0,-3):p,g=Number.parseFloat(d);return Number.isFinite(g)?g*Math.PI/180:null},l=u=>{let p=u.split(",").map(v=>v.trim()),d=n(p[0]||"");if(d===null)return null;let g=p[1]?a(p[1]):null;return{intensity:Math.max(0,d),threshold:g===null?.8:Math.max(0,Math.min(1,g))}},s=(u,p,d=!1)=>{let g=n(u);return g===null?(r.push(`[String3D] Invalid ${p} value "${u}".`),null):!d&&g<=0?(r.push(`[String3D] ${p} must be > 0.`),null):g},c=(u,p)=>{let d=a(u);return d===null?(r.push(`[String3D] Invalid ${p} value "${u}".`),null):d},m=/([a-zA-Z-]+)\(([^)]*)\)/g,h;for(;h=m.exec(e);){let u=h[1].toLowerCase(),p=(h[2]||"").trim();if(u==="blur"){let d=s(p,"blur",!0);d!==null&&i.push({type:"blur",amount:d})}else if(u==="pixel"||u==="pixelate"){let d=s(p,"pixel",!0);d!==null&&i.push({type:"pixel",size:d})}else if(u==="bloom"){let d=l(p);d?i.push({type:"bloom",...d}):r.push(`[String3D] Invalid bloom value "${p}".`)}else if(u==="brightness"){let d=c(p,"brightness");d!==null&&i.push({type:"brightness",amount:Math.max(0,d)})}else if(u==="contrast"){let d=c(p,"contrast");d!==null&&i.push({type:"contrast",amount:Math.max(0,d)})}else if(u==="saturate"){let d=c(p,"saturate");d!==null&&i.push({type:"saturate",amount:Math.max(0,d)})}else if(u==="grayscale"){let d=c(p,"grayscale");d!==null&&i.push({type:"grayscale",amount:Math.max(0,Math.min(1,d))})}else if(u==="sepia"){let d=c(p,"sepia");d!==null&&i.push({type:"sepia",amount:Math.max(0,Math.min(1,d))})}else if(u==="invert"){let d=c(p,"invert");d!==null&&i.push({type:"invert",amount:Math.max(0,Math.min(1,d))})}else if(u==="hue-rotate"){let d=o(p);d!==null?i.push({type:"hue-rotate",angle:d}):r.push(`[String3D] Invalid hue-rotate value "${p}".`)}else if(u){let d=k.get(u);if(d){let g=d.parse?d.parse(p):{};g===null?r.push(`[String3D] Invalid custom filter "${u}" args "${p}".`):i.push({type:"custom",name:u,uniforms:g})}else r.push(`[String3D] Unknown filter "${u}".`)}}return i.length===0&&r.push("[String3D] No valid filters parsed from --filter."),{effects:i,warnings:r}}warnFilterIssues(e,r,i){i.length===0||this.filterWarnings.get(e)===r||(i.forEach(a=>console.warn(a,e)),this.filterWarnings.set(e,r))}readFilterChain(e,r,i){let n=this.filterStates.get(e);if(!i&&n)return n.animating?this.sampleTransition(n,r):n.effects;let a=this.readFilterRaw(e);if(!a||a==="none"){if(n){if(n.animating&&n.clearOnComplete){let g=this.sampleTransition(n,r);return n.animating?g:(this.filterStates.delete(e),null)}let{duration:u,delay:p,easing:d}=this.getFilterTransition(e);if(u<=0&&n.lastDuration>0&&(u=n.lastDuration,p=n.lastDelay,d=n.lastEasing),u>0){let g=this.makeZeroChain(n.effects);return n.from=n.effects,n.to=g,n.startTime=r+p,n.duration=u,n.easing=d,n.animating=!0,n.clearOnComplete=!0,n.lastDuration=u,n.lastDelay=p,n.lastEasing=d,this.sampleTransition(n,r)}}return this.filterStates.delete(e),null}let{effects:o,warnings:l}=this.parseFilterChain(a);if(this.warnFilterIssues(e,a,l),o.length===0)return null;let s=this.filterStates.get(e);if(!s){let{duration:u,delay:p,easing:d}=this.getFilterTransition(e);if(u>0){let g=this.makeZeroChain(o),v={raw:a,effects:o,animating:!0,from:g,to:o,startTime:r+p,duration:u,easing:d,clearOnComplete:!1,lastDuration:u,lastDelay:p,lastEasing:d};return v.effectsKey=this.stringifyFilterChain(o),this.filterStates.set(e,v),this.sampleTransition(v,r)}return this.filterStates.set(e,{raw:a,effects:o,animating:!1,from:o,to:o,startTime:0,duration:0,easing:g=>g,clearOnComplete:!1,lastDuration:0,lastDelay:0,lastEasing:g=>g,effectsKey:this.stringifyFilterChain(o)}),o}if(s.raw===a){if(s.animating){let u=this.sampleTransition(s,r);return!s.animating&&s.clearOnComplete?(this.filterStates.delete(e),null):u}return s.effects}s.pendingEffects=void 0,s.pendingRaw=void 0;let{duration:c,delay:m,easing:h}=this.getFilterTransition(e);if(c<=0&&s.lastDuration>0&&(c=s.lastDuration,m=s.lastDelay,h=s.lastEasing),c>0){let u=this.canInterpolate(s.effects,o),p=s.animating?this.getCurrentChain(s,r):s.effects;if(!u&&this.isZeroChain(o))return s.pendingRaw=a,s.pendingEffects=o,s.raw=a,s.effects=p,s.from=p,s.to=this.makeZeroChain(p),s.startTime=r+m,s.duration=c,s.easing=h,s.animating=!0,s.clearOnComplete=!1,s.lastDuration=c,s.lastDelay=m,s.lastEasing=h,s.effectsKey=this.stringifyFilterChain(o),this.sampleTransition(s,r);let d=u?p:this.makeZeroChain(o);return s.raw=a,s.effects=o,s.from=d,s.to=o,s.startTime=r+m,s.duration=c,s.easing=h,s.animating=!0,s.clearOnComplete=!1,s.lastDuration=c,s.lastDelay=m,s.lastEasing=h,s.effectsKey=this.stringifyFilterChain(o),this.sampleTransition(s,r)}return s.raw=a,s.effects=o,s.animating=!1,s.clearOnComplete=!1,s.effectsKey=this.stringifyFilterChain(o),o}collectFilterTargets(e,r,i){if(!this.scene)return[];let n=[],a=o=>{let l=o.el;if(l){let s=!this.useDirtySync||!i||i.has(l)||this.filterStates.get(l)?.animating===!0,c=this.readFilterChain(l,e,s);if(c&&c.length>0){let m=!this.useDirtySync||!i||i.has(l)||this.filterStates.get(l)?.animating===!0,h=this.filterStates.get(l)?.effectsKey||this.stringifyFilterChain(c);n.push({object:o,effects:c,effectsKey:h,dirty:m});return}}o.children.forEach(s=>a(s))};return this.scene.rootObjects.forEach(o=>a(o)),n}stringifyFilterChain(e){return e.map(i=>{if(i.type==="blur")return`blur:${i.amount}`;if(i.type==="pixel")return`pixel:${i.size}`;if(i.type==="bloom")return`bloom:${i.intensity},${i.threshold}`;if(i.type==="brightness")return`brightness:${i.amount}`;if(i.type==="contrast")return`contrast:${i.amount}`;if(i.type==="saturate")return`saturate:${i.amount}`;if(i.type==="grayscale")return`grayscale:${i.amount}`;if(i.type==="sepia")return`sepia:${i.amount}`;if(i.type==="invert")return`invert:${i.amount}`;if(i.type==="hue-rotate")return`hue-rotate:${i.angle}`;if(i.type==="custom"){let n=Object.keys(i.uniforms||{}).sort().map(a=>`${a}=${i.uniforms[a]}`).join(",");return`custom:${i.name}:${n}`}return"unknown"}).join("|")}getFilterTransition(e){let r=getComputedStyle(e),i=this.splitTransitionList(r.transitionProperty),n=this.splitTransitionList(r.transitionDuration),a=this.splitTransitionList(r.transitionDelay),o=this.splitTransitionList(r.transitionTimingFunction),l=this.findTransitionIndex(i,"--filter");if(l===-1){let h=this.parseTransitionShorthand(r.transition),u=h.get("--filter")||h.get("all");return u||{duration:0,delay:0,easing:p=>p}}let s=this.parseTime(n[l]||n[n.length-1]||"0s"),c=this.parseTime(a[l]||a[a.length-1]||"0s"),m=o[l]||o[o.length-1]||"linear";return{duration:s,delay:c,easing:this.parseEasing(m)}}splitTransitionList(e){let r=[],i="",n=0;for(let a=0;a<e.length;a+=1){let o=e[a];o==="("&&(n+=1),o===")"&&(n=Math.max(0,n-1)),o===","&&n===0?(r.push(i.trim()),i=""):i+=o}return i.trim()&&r.push(i.trim()),r.length>0?r:["all"]}findTransitionIndex(e,r){let i=e.map(a=>a.trim().toLowerCase()),n=i.indexOf(r);return n===-1&&(n=i.indexOf("all")),n}parseTime(e){let r=e.trim().toLowerCase();if(r.endsWith("ms")){let n=Number.parseFloat(r.slice(0,-2));return Number.isFinite(n)?n:0}if(r.endsWith("s")){let n=Number.parseFloat(r.slice(0,-1));return Number.isFinite(n)?n*1e3:0}let i=Number.parseFloat(r);return Number.isFinite(i)?i:0}parseTransitionShorthand(e){let r=new Map;return this.splitTransitionList(e).forEach(n=>{if(!n)return;let a=n.trim().split(/\s+(?![^()]*\))/g),o="",l="",s="",c="";a.forEach(m=>{let h=m.toLowerCase();h.endsWith("ms")||h.endsWith("s")||/^[0-9.]+$/.test(h)?l?s||(s=h):l=h:h.startsWith("cubic-bezier")||h.startsWith("steps")||h==="linear"||h==="ease"||h==="ease-in"||h==="ease-out"||h==="ease-in-out"?c=m:o||(o=m)}),o&&r.set(o.trim().toLowerCase(),{duration:this.parseTime(l||"0s"),delay:this.parseTime(s||"0s"),easing:this.parseEasing(c||"linear")})}),r}parseEasing(e){let r=e.trim().toLowerCase();if(r==="linear")return i=>i;if(r==="ease")return this.cubicBezier(.25,.1,.25,1);if(r==="ease-in")return this.cubicBezier(.42,0,1,1);if(r==="ease-out")return this.cubicBezier(0,0,.58,1);if(r==="ease-in-out")return this.cubicBezier(.42,0,.58,1);if(r.startsWith("cubic-bezier")){let i=r.match(/cubic-bezier\(([^)]+)\)/);if(i){let n=i[1].split(",").map(a=>Number.parseFloat(a.trim()));if(n.length===4&&n.every(a=>Number.isFinite(a)))return this.cubicBezier(n[0],n[1],n[2],n[3])}}return i=>i}cubicBezier(e,r,i,n){let a=s=>{let c=1-s;return 3*c*c*s*e+3*c*s*s*i+s*s*s},o=s=>{let c=1-s;return 3*c*c*s*r+3*c*s*s*n+s*s*s},l=s=>{let c=s;for(let m=0;m<5;m+=1){let h=a(c)-s,u=3*(1-c)*(1-c)*e+6*(1-c)*c*(i-e)+3*c*c*(1-i);if(Math.abs(h)<1e-5||u===0)break;c-=h/u}return c};return s=>{let c=Math.min(1,Math.max(0,s)),m=l(c);return Math.min(1,Math.max(0,o(m)))}}canInterpolate(e,r){return e.length!==r.length?!1:e.every((i,n)=>{let a=r[n];if(i.type!==a.type)return!1;if(i.type==="custom"&&a.type==="custom"){if(i.name!==a.name)return!1;let o=Object.keys(i.uniforms||{}),l=Object.keys(a.uniforms||{});return o.length!==l.length?!1:o.every(s=>s in a.uniforms&&this.isNumeric(i.uniforms[s]))}return!0})}makeZeroChain(e){return e.map(r=>{switch(r.type){case"blur":return{type:"blur",amount:0};case"pixel":return{type:"pixel",size:0};case"bloom":return{type:"bloom",intensity:0,threshold:r.threshold};case"brightness":return{type:"brightness",amount:1};case"contrast":return{type:"contrast",amount:1};case"saturate":return{type:"saturate",amount:1};case"grayscale":return{type:"grayscale",amount:0};case"sepia":return{type:"sepia",amount:0};case"invert":return{type:"invert",amount:0};case"hue-rotate":return{type:"hue-rotate",angle:0};case"custom":{let i={};return Object.entries(r.uniforms||{}).forEach(([n,a])=>{i[n]=this.isNumeric(a)?0:a}),{type:"custom",name:r.name,uniforms:i}}default:return r}})}sampleTransition(e,r){if(!e.animating)return e.effects;if(r<e.startTime)return e.from;let i=r-e.startTime,n=Math.max(1,e.duration),a=Math.min(1,Math.max(0,i/n)),o=e.easing(a),l=this.interpolateChain(e.from,e.to,o);return a>=1&&(e.animating=!1,e.from=e.to,e.pendingEffects&&e.pendingRaw===e.raw?(e.effects=e.pendingEffects,e.raw=e.pendingRaw||e.raw,e.pendingEffects=void 0,e.pendingRaw=void 0):e.pendingEffects&&(e.pendingEffects=void 0,e.pendingRaw=void 0)),l}getCurrentChain(e,r){if(!e.animating)return e.effects;if(r<e.startTime)return e.from;let i=r-e.startTime,n=Math.max(1,e.duration),a=Math.min(1,Math.max(0,i/n)),o=e.easing(a);return this.interpolateChain(e.from,e.to,o)}interpolateChain(e,r,i){return this.canInterpolate(e,r)?e.map((n,a)=>this.interpolateEffect(n,r[a],i)):r}interpolateEffect(e,r,i){let n=(a,o)=>a+(o-a)*i;if(e.type==="blur"&&r.type==="blur")return{type:"blur",amount:n(e.amount,r.amount)};if(e.type==="pixel"&&r.type==="pixel")return{type:"pixel",size:n(e.size,r.size)};if(e.type==="bloom"&&r.type==="bloom")return{type:"bloom",intensity:n(e.intensity,r.intensity),threshold:n(e.threshold,r.threshold)};if(e.type==="brightness"&&r.type==="brightness")return{type:"brightness",amount:n(e.amount,r.amount)};if(e.type==="contrast"&&r.type==="contrast")return{type:"contrast",amount:n(e.amount,r.amount)};if(e.type==="saturate"&&r.type==="saturate")return{type:"saturate",amount:n(e.amount,r.amount)};if(e.type==="grayscale"&&r.type==="grayscale")return{type:"grayscale",amount:n(e.amount,r.amount)};if(e.type==="sepia"&&r.type==="sepia")return{type:"sepia",amount:n(e.amount,r.amount)};if(e.type==="invert"&&r.type==="invert")return{type:"invert",amount:n(e.amount,r.amount)};if(e.type==="hue-rotate"&&r.type==="hue-rotate")return{type:"hue-rotate",angle:n(e.angle,r.angle)};if(e.type==="custom"&&r.type==="custom"&&e.name===r.name){let a={};return Object.entries(r.uniforms||{}).forEach(([o,l])=>{let s=e.uniforms?.[o];this.isNumeric(s)&&this.isNumeric(l)?a[o]=n(s,l):a[o]=l}),{type:"custom",name:r.name,uniforms:a}}return r}isNumeric(e){return typeof e=="number"&&Number.isFinite(e)}isZeroChain(e){return e.every(r=>{switch(r.type){case"blur":return r.amount<=0;case"pixel":return r.size<=0;case"bloom":return r.intensity<=0;case"brightness":return r.amount===1;case"contrast":return r.amount===1;case"saturate":return r.amount===1;case"grayscale":return r.amount===0;case"sepia":return r.amount===0;case"invert":return r.amount===0;case"hue-rotate":return r.angle===0;case"custom":return!1;default:return!1}})}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 o=e.el,l=i||!n||n.has(o),s=r;if(e.type.endsWith("Light")){l&&this.synchronizer.syncElement(o,e,r);return}if(l){let m=o.getBoundingClientRect(),h=o.offsetWidth||m.width,u=o.offsetHeight||m.height,p=this.readNumberStyle(o,"--translate-z",0),d=this.readNumberStyle(o,"--scale",1),g=this.readNumberStyle(o,"--scale-z",1),v=this.readNumberStyle(o,"--rotate-x",0),M=this.readNumberStyle(o,"--rotate-y",0),x=this.readNumberStyle(o,"--rotate-z",0),y=this.readNumberStyle(o,"--opacity",NaN);e.type!=="group"&&R.applyVisualProps(o,e,y);let S,D,f,I;if(e.type==="model"){let O=e.getOriginalBoundingBox().getSize(this.engine.createVector3());S=O.x,D=O.y;let Z=parseFloat(o.getAttribute("string-3d-model-scale")||"1");f=Number.isFinite(Z)?Z:1,I=(o.getAttribute("string-3d-model-fit")||"contain").toLowerCase().trim()}let T=e.type==="group"?d:d*r.scale;this.lastSyncData.set(e,{scale:T}),s={scale:T},this.workerObjectMap.set(e.id,{object:e,el:o}),a.push({id:e.id,type:e.type,rectLeft:m.left,rectTop:m.top,rectWidth:h,rectHeight:u,translateZ:p,scale:d,scaleZ:g,rotateX:v,rotateY:M,rotateZ:x,parentScale:r.scale,modelSizeX:S,modelSizeY:D,modelScale:f,fitMode:I})}else{let m=this.lastSyncData.get(e);m&&(s=m)}let c=i||l;e.children.forEach(m=>{this.collectWorkerInputs(m,s,c,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()}};z.provider=null;var $=z;var U=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)}createShaderMaterial(t){return new this.THREE.ShaderMaterial(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}createRenderTarget(t,e,r={}){let i={minFilter:this.THREE.LinearFilter,magFilter:this.THREE.LinearFilter,format:this.THREE.RGBAFormat,depthBuffer:!0,stencilBuffer:!1};return new this.THREE.WebGLRenderTarget(t,e,{...i,...r})}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}},q=class{constructor(t,e={}){this.engine=new U(t,e)}getEngine(){return this.engine}getName(){return"Three.js"}};0&&(module.exports={String3D,String3DCamera,String3DCustomFilterRegistry,String3DObject,String3DRenderer,String3DScene,String3DSynchronizer,ThreeJSEngine,ThreeJSProvider});
|
|
29
277
|
//# sourceMappingURL=index.cjs.map
|