string-tune-3d 0.0.3 → 0.0.4
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 +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +48 -19
package/dist/index.d.ts
CHANGED
|
@@ -152,6 +152,9 @@ interface String3DOptions {
|
|
|
152
152
|
hideHTML?: boolean;
|
|
153
153
|
container?: string | HTMLElement;
|
|
154
154
|
zIndex?: number;
|
|
155
|
+
modelLoaderType?: string;
|
|
156
|
+
modelLoader?: I3DModelLoader;
|
|
157
|
+
modelLoaderFactory?: (engine: I3DEngine, type?: string) => I3DModelLoader;
|
|
155
158
|
}
|
|
156
159
|
declare class String3D extends StringModule {
|
|
157
160
|
private static provider;
|
|
@@ -164,11 +167,16 @@ declare class String3D extends StringModule {
|
|
|
164
167
|
private isLoading;
|
|
165
168
|
private options;
|
|
166
169
|
static setProvider(provider: I3DEngineProvider): void;
|
|
167
|
-
constructor(context: StringContext
|
|
170
|
+
constructor(context: StringContext);
|
|
168
171
|
canConnect(object: StringObject): boolean;
|
|
169
172
|
initializeObject(globalId: number, object: StringObject, element: HTMLElement, attributes: Record<string, any>): void;
|
|
170
173
|
onResize(): void;
|
|
171
174
|
onInit(): void;
|
|
175
|
+
onSettingsChange(): void;
|
|
176
|
+
private buildOptionsFromSettings;
|
|
177
|
+
private getSettingValue;
|
|
178
|
+
private resolveModelLoader;
|
|
179
|
+
private resolveModelLoaderFactory;
|
|
172
180
|
private createOrGetContainer;
|
|
173
181
|
private applyContainerStyles;
|
|
174
182
|
onObjectConnected(object: StringObject): void;
|
|
@@ -220,7 +228,11 @@ declare class String3DObject {
|
|
|
220
228
|
private _children;
|
|
221
229
|
private engine;
|
|
222
230
|
get children(): String3DObject[];
|
|
223
|
-
constructor(id: string, type: string, object: I3DObject, engine: I3DEngine
|
|
231
|
+
constructor(id: string, type: string, object: I3DObject, engine: I3DEngine, options?: {
|
|
232
|
+
material?: I3DMaterial;
|
|
233
|
+
geometry?: I3DGeometry;
|
|
234
|
+
texture?: any;
|
|
235
|
+
});
|
|
224
236
|
get object(): I3DObject;
|
|
225
237
|
get material(): I3DMaterial | undefined;
|
|
226
238
|
get originalSize(): I3DVector3;
|
|
@@ -239,19 +251,28 @@ declare class String3DObject {
|
|
|
239
251
|
set metalness(value: number);
|
|
240
252
|
set roughness(value: number);
|
|
241
253
|
set texture(texture: any);
|
|
254
|
+
set material(material: I3DMaterial | undefined);
|
|
255
|
+
set geometry(geometry: I3DGeometry | undefined);
|
|
242
256
|
updateBoundingBox(): void;
|
|
243
257
|
destroy(): void;
|
|
258
|
+
private disposeObjectResources;
|
|
244
259
|
}
|
|
245
260
|
|
|
261
|
+
interface String3DSceneOptions {
|
|
262
|
+
modelLoader?: I3DModelLoader;
|
|
263
|
+
modelLoaderFactory?: (engine: I3DEngine, type?: string) => I3DModelLoader;
|
|
264
|
+
}
|
|
246
265
|
declare class String3DScene {
|
|
247
266
|
private _scene;
|
|
248
267
|
private _objects;
|
|
249
268
|
private _rootObjects;
|
|
250
269
|
private _elementMap;
|
|
251
270
|
private engine;
|
|
252
|
-
private _modelLoader
|
|
271
|
+
private _modelLoader?;
|
|
272
|
+
private _modelLoaderFactory?;
|
|
273
|
+
private _modelLoaderCache;
|
|
253
274
|
get rootObjects(): String3DObject[];
|
|
254
|
-
constructor(engine: I3DEngine,
|
|
275
|
+
constructor(engine: I3DEngine, options?: String3DSceneOptions);
|
|
255
276
|
getScene(): I3DScene;
|
|
256
277
|
getObject(id: string): String3DObject | undefined;
|
|
257
278
|
hasObject(id: string): boolean;
|
|
@@ -264,8 +285,15 @@ declare class String3DScene {
|
|
|
264
285
|
private createPlane;
|
|
265
286
|
private createCylinder;
|
|
266
287
|
private createModel;
|
|
288
|
+
private resolveModelLoader;
|
|
289
|
+
private centerObject;
|
|
290
|
+
private getBoxCenter;
|
|
267
291
|
private createMaterialFromObject;
|
|
292
|
+
private createMaterialFromElement;
|
|
268
293
|
private loadTexture;
|
|
294
|
+
private parseFlipY;
|
|
295
|
+
private shouldOverrideModelMaterial;
|
|
296
|
+
private applyModelTextureRemap;
|
|
269
297
|
destroy(): void;
|
|
270
298
|
}
|
|
271
299
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var StringTune3D=(()=>{var V=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var X=(o,e)=>{for(var t in e)V(o,t,{get:e[t],enumerable:!0})},K=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Y(e))!G.call(o,i)&&i!==t&&V(o,i,{get:()=>e[i],enumerable:!(r=U(e,i))||r.enumerable});return o};var Q=o=>K(V({},"__esModule",{value:!0}),o);var ie={};X(ie,{String3D:()=>N,String3DCamera:()=>D,String3DObject:()=>S,String3DRenderer:()=>k,String3DScene:()=>L,String3DSynchronizer:()=>T,ThreeJSEngine:()=>O,ThreeJSProvider:()=>H});var Z=class{constructor(){this.desktop={rebuild:{width:!0,height:!0,scrollHeight:!0}},this.mobile={rebuild:{width:!0,height:!0,scrollHeight:!0}}}},F=class{constructor(o){this.objectMapOnPage=new Map,this.objectsOnPage=[],this.objectMap=new Map,this.objects=[],this.htmlKey="",this._type=1,this.permissions=new Z,this.tools=o.tools,this.data=o.data,this.settings=o.settings,this.events=o.events,this.centers=o.centers,this.hover=o.hover,this.attributesToMap=[{key:"active",type:"boolean",fallback:this.settings.active},{key:"fixed",type:"boolean",fallback:this.settings.fixed},{key:"outside-container",type:"boolean",fallback:this.settings["outside-container"]},{key:"repeat",type:"boolean",fallback:this.settings.repeat},{key:"self-disable",type:"boolean",fallback:this.settings["self-disable"]},{key:"abs",type:"boolean",fallback:this.settings.abs},{key:"key",type:"string",fallback:this.settings.key},{key:"offset-top",type:"dimension",fallback:this.settings["offset-top"]},{key:"offset-bottom",type:"dimension",fallback:this.settings["offset-bottom"]},{key:"inview-top",type:"dimension",fallback:this.settings["inview-top"]},{key:"inview-bottom",type:"dimension",fallback:this.settings["inview-bottom"]},{key:"start",type:"number",fallback:(e,t,r)=>{let i=r.top;return Math.floor(i)+this.data.scroll.container.scrollTop*this.data.viewport.transformScale}},{key:"end",type:"number",fallback:(e,t,r)=>{let i=r.top,s=r.height;return i+s-this.data.scroll.transformedCurrent}},{key:"size",type:"number",fallback:(e,t,r)=>r.height},{key:"half-width",type:"number",fallback:(e,t,r)=>r.width/2},{key:"half-height",type:"number",fallback:(e,t,r)=>r.height/2},{key:"enter-el",type:"string",fallback:this.settings["enter-el"]},{key:"enter-vp",type:"string",fallback:this.settings["enter-vp"]},{key:"exit-el",type:"string",fallback:this.settings["exit-el"]},{key:"exit-vp",type:"string",fallback:this.settings["exit-vp"]}]}get type(){return this._type}initializeObject(o,e,t,r){let i=this.tools.boundingClientRect.process({element:t});for(let{key:s,type:n,fallback:a,transform:l}of this.attributesToMap){let h=typeof a=="function"?a(t,e,i):a,d=this.tools.domAttribute.process({element:t,key:s,fallback:r[s]??this.settings[s]??h}),u=this.parseAttribute(d,n,{element:t,boundingRect:i,viewportHeight:this.data.viewport.windowHeight,baseRem:this.data.viewport.baseRem});l&&(u=l(u)),e.setProperty(s,u)}}calculatePositions(o,e){let t=o.getProperty("start"),r=o.getProperty("size"),i=o.getProperty("offset-bottom"),s=o.getProperty("offset-top"),n=o.getProperty("enter-el"),a=o.getProperty("enter-vp"),l=o.getProperty("exit-el"),h=o.getProperty("exit-vp"),d=0,u=0,v=0,g=0;n==="top"&&a==="top"||n==="left"&&a==="left"?(v=-e+1,d=t-i):n==="top"&&a==="bottom"||n==="left"&&a==="right"?d=t-e-i:n==="bottom"&&a==="top"||n==="right"&&a==="left"?(v=-e-r+1,d=t+r-i):(n==="bottom"&&a==="bottom"||n==="right"&&a==="right")&&(v=-r+1,d=t-e+r-i),l==="top"&&h==="top"||l==="left"&&h==="left"?(g=-r+1,u=t+s):l==="top"&&h==="bottom"||l==="left"&&h==="right"?(g=-e-r+1,u=t-e+s):l==="bottom"&&h==="top"||l==="right"&&h==="left"?u=t+r+s:(l==="bottom"&&h==="bottom"||l==="right"&&h==="right")&&(g=-e+1,u=t-e+r+s),o.setProperty("start-bias",v),o.setProperty("end-bias",g),o.setProperty("start-position",d-this.data.scroll.topPosition),o.setProperty("end-position",u-this.data.scroll.topPosition),o.setProperty("difference-position",u-d);let x=o.getProperty("inview-top")??0,y=o.getProperty("inview-bottom")??0;o.setProperty("inview-start-position",o.getProperty("start-position")+x),o.setProperty("inview-end-position",o.getProperty("end-position")+y)}parseAttribute(o,e,t={}){if(o==null)return null;if(typeof e=="object"&&e.type==="enum")return e.values.includes(o)?o:e.values[0];switch(e){case"number":return parseFloat(o);case"boolean":return o===""||o==="true";case"json":try{return JSON.parse(o)}catch{return null}case"tuple":return o.trim().split(/\s+/);case"easing":return this.tools.easingFunction.process({easing:o});case"color":return this.tools.colorParser.process({value:o});case"dimension":return o=="0"?0:t.element!=null&&t.viewportHeight!=null&&t.baseRem!=null&&t.boundingRect!=null?this.tools.unitParser.process({value:o,element:t.element,viewportHeight:t.viewportHeight,boundingRect:t.boundingRect,baseRem:t.baseRem}):0;case"breakpoint-dimension":if(t.element!=null&&t.viewportHeight!=null&&t.baseRem!=null&&t.boundingRect!=null){let r=o.trim().split("|"),i=[];for(let s of r)if(s.includes(":")){let[n,a]=s.split(":");i.push({breakpoint:parseInt(n),value:this.tools.unitParser.process({value:`${a}|`,element:t.element,viewportHeight:t.viewportHeight,boundingRect:t.boundingRect,baseRem:t.baseRem})})}else i.push({breakpoint:0,value:this.tools.unitParser.process({value:s,element:t.element,viewportHeight:t.viewportHeight,boundingRect:t.boundingRect,baseRem:t.baseRem})});return i}default:return o}}canConnect(o){return o.keys.includes(this.htmlKey)}connectObject(o){o.connect(this),this.onObjectConnected(o)}enterObject(o,e){this.objectMap.has(o)||(this.objectMap.set(o,e),this.objects.push(e))}exitObject(o){let e=this.objectMap.get(o);if(!e)return;this.objectMap.delete(o);let t=this.objects.indexOf(e);t!==-1&&this.objects.splice(t,1)}addObject(o,e){this.objectMapOnPage.has(o)||(this.objectMapOnPage.set(o,e),this.objectsOnPage.push(e))}removeObject(o){let e=this.objectMapOnPage.get(o);if(!e)return;this.objectMapOnPage.delete(o);let t=this.objectsOnPage.indexOf(e);t!==-1&&this.objectsOnPage.splice(t,1),this.onObjectDisconnected(e)}onObjectConnected(o){}onObjectDisconnected(o){}applyToElementAndConnects(o,e,t=e){o.getProperty("self-disable")!==!0&&e(o.htmlElement),o.mirrorObjects.forEach(r=>t(r.htmlElement,r))}destroy(){this.objects=[],this.objectMap=new Map}onInit(){}onFrame(o){}onMutate(o){}onScrollMeasure(o){}onMouseMoveMeasure(o){}onResize(){}onResizeWidth(){}onScroll(o){}onDirectionChange(){}onScrollStart(){}onScrollStop(){}onScrollDirectionChange(){}onAxisChange(){}onDeviceChange(){}onScrollConfigChange(){}onSettingsChange(){}onDOMRebuild(){}onMouseMove(o){}onWheel(o){}onDOMMutate(o,e){}};var J=class{constructor(){this.pendingVars=new Map,this.pendingProps=new Map,this.isOpen=!1}begin(){this.isOpen||(this.isOpen=!0)}setVars(o,e){if(!this.isOpen){console.warn("StyleTxn: call begin() first to set custom properties.");return}let t=this.pendingVars.get(o)??{};for(let[r,i]of Object.entries(e))t[r]!==i&&(t[r]=i);this.pendingVars.set(o,t)}setProps(o,e){if(!this.isOpen){console.warn("StyleTxn: call begin() first to set standard properties.");return}let t=this.pendingProps.get(o)??{};for(let[r,i]of Object.entries(e))t[r]!==i&&(t[r]=i);this.pendingProps.set(o,t)}run(o){let e=this.isOpen;e||this.begin();try{o(),e||this.commit()}catch(t){throw e||this.cancel(),t}}commit(){if(this.isOpen){this.isOpen=!1;for(let[o,e]of this.pendingVars){let t=o.style;for(let[r,i]of Object.entries(e))t.setProperty(r,String(i))}this.pendingVars.clear();for(let[o,e]of this.pendingProps){let t=o.style;for(let[r,i]of Object.entries(e))t[r]=String(i)}this.pendingProps.clear()}}cancel(){this.pendingVars.clear(),this.pendingProps.clear(),this.isOpen=!1}},$=new J;var ne=1/240;var ee=class{constructor(){this.measureQueue=[],this.mutateQueue=[],this.scheduled=!1}measure(o){this.measureQueue.push(o),this.schedule()}mutate(o){this.mutateQueue.push(o),this.schedule()}schedule(){this.scheduled||(this.scheduled=!0,requestAnimationFrame(()=>{let o=this.measureQueue;this.measureQueue=[];for(let t=0;t<o.length;t++)try{o[t]()}catch(r){console.error("Error in frameDOM measure task:",r)}let e=this.mutateQueue;this.mutateQueue=[];for(let t=0;t<e.length;t++)try{e[t]()}catch(r){console.error("Error in frameDOM mutate task:",r)}this.scheduled=!1}))}},B=new ee;var oe=Math.PI*2,ae=180/Math.PI;var W=(o=>(o.ACTIVE="-active",o.ENTERING="-entering",o.LEAVING="-leaving",o.DISABLED="-disabled",o))(W||{}),te={PROGRESS:"--sequence-progress",DIRECTION:"--sequence-direction"},re=class q extends F{constructor(e){super(e),this.activeStep=new Map,this.leavingStep=new Map,this.transitions=new Map,this.elementIndex=new Map,this.triggerElements=new Map,this.globalSettings=new Map,this.initialized=!1,this.onTriggerClick=t=>{let r=this.triggerElements.get(t.currentTarget);if(!r)return;let i=this.activeStep.get(r.slider)??0,s=this.getMaxStep(r.slider),n,a;if(r.step==="next"){if(n=i+1,a=1,!this.elementIndex.has(`${r.slider}[${n}]`))if(r.loop&&s>=0)n=0;else return}else if(r.step==="prev"){if(n=i-1,a=-1,n<0)if(r.loop&&s>=0)n=s;else return;if(!this.elementIndex.has(`${r.slider}[${n}]`))return}else{if(n=r.step,i===n)return;a=n>i?1:-1}this.startTransition(r.slider,n,a)},this.htmlKey="sequence",this.defaultDuration=this.settings["sequence-duration"]??600,this.attributesToMap=[...this.attributesToMap,{key:"sequence",type:"string",fallback:""},{key:"sequence-trigger",type:"string",fallback:""},{key:"entering-easing",type:"string",fallback:""},{key:"leaving-easing",type:"string",fallback:""},{key:"entering-duration",type:"string",fallback:""},{key:"leaving-duration",type:"string",fallback:""},{key:"sequence-duration",type:"string",fallback:""},{key:"active-step",type:"string",fallback:""}]}onInit(){super.onInit(),this.events.on("sequence",this.onSequenceEvent.bind(this)),this.scanStandaloneTriggers()}scanStandaloneTriggers(){let e=document.querySelectorAll("[string-sequence-trigger]:not([string-inited])");for(let t of e){let r=t.getAttribute("string-sequence-trigger"),i=r?this.parseTriggerKey(r):null;i&&(this.triggerElements.set(t,i),t.addEventListener("click",this.onTriggerClick))}}parseGlobalSettingsFromObject(e){let t=i=>e.getProperty(i),r=t("sequence-duration");this.tryParseGlobalSetting(r,"enteringDuration"),this.tryParseGlobalSetting(r,"leavingDuration"),this.tryParseGlobalSetting(t("entering-duration"),"enteringDuration"),this.tryParseGlobalSetting(t("leaving-duration"),"leavingDuration"),this.tryParseGlobalSetting(t("entering-easing"),"enteringEasing"),this.tryParseGlobalSetting(t("leaving-easing"),"leavingEasing"),this.tryParseGlobalSetting(t("active-step"),"activeStep")}tryParseGlobalSetting(e,t){if(!e)return;let r=e.match(/^(.+)\[(.+)\]$/);if(!r)return;let[,i,s]=r,n=this.globalSettings.get(i)??{};this.globalSettings.set(i,n),n[t]=t==="enteringEasing"||t==="leavingEasing"?s:parseFloat(s),this.applyGlobalSettingsToExistingObjects(i)}applyGlobalSettingsToExistingObjects(e){let t=this.globalSettings.get(e);if(t){for(let[r,i]of this.elementIndex)if(this.parseSequenceKey(r)?.slider===e){t.enteringDuration!==void 0&&(i.enteringDuration=t.enteringDuration),t.leavingDuration!==void 0&&(i.leavingDuration=t.leavingDuration);for(let s of i.objects)this.resolveEasings(s,r)}}}initializeSliders(){let e=new Set;for(let t of this.elementIndex.keys()){let r=this.parseSequenceKey(t);r&&e.add(r.slider)}for(let t of e){if(this.activeStep.has(t))continue;let r=this.globalSettings.get(t)?.activeStep??0;this.elementIndex.has(`${t}[${r}]`)||(r=0),this.switchInstant(t,r,1)}}tryApplyPendingActiveStep(e){if(this.activeStep.has(e))return;let t=this.globalSettings.get(e)?.activeStep;t!==void 0&&this.elementIndex.has(`${e}[${t}]`)&&this.switchInstant(e,t,1)}canConnect(e){return e.keys.includes("sequence")||e.keys.includes("sequence-trigger")}onObjectConnected(e){super.onObjectConnected(e),this.parseGlobalSettingsFromObject(e);let t=e.getProperty("sequence"),r=e.getProperty("sequence-trigger");if(!t&&r){let i=this.parseTriggerKey(r);i&&typeof i.step=="number"&&(t=`${i.slider}[${i.step}]`,e.setProperty("sequence",t))}if(t){let i=this.parseSequenceKey(t);if(i){let s=this.elementIndex.get(t);if(!s){let{enteringDuration:a,leavingDuration:l}=this.resolveDurations(e,t);s={objects:[],enteringDuration:a,leavingDuration:l},this.elementIndex.set(t,s)}s.objects.push(e),this.resolveEasings(e,t);let n=this.activeStep.get(i.slider);this.setState(e,n===i.step?"-active":"-disabled",n===i.step?1:0,1),this.tryApplyPendingActiveStep(i.slider)}}if(r){let i=this.parseTriggerKey(r);i&&(this.triggerElements.set(e.htmlElement,i),e.htmlElement.addEventListener("click",this.onTriggerClick))}}parseTriggerKey(e){let t=e.match(/^(.+)\[(next|prev|\d+)(\|loop)?\]$/);if(!t)return null;let r=t[2]==="next"||t[2]==="prev"?t[2]:parseInt(t[2],10);return{slider:t[1],step:r,loop:t[3]==="|loop"}}getMaxStep(e){let t=-1;for(let r of this.elementIndex.keys()){let i=this.parseSequenceKey(r);i?.slider===e&&i.step>t&&(t=i.step)}return t}resolveDuration(e,t,r,i){let s=e.getProperty(i),n=e.getProperty("sequence-duration"),a=this.globalSettings.get(t)?.[r];if(s&&!s.includes("[")){let l=parseFloat(s);if(!isNaN(l))return l}if(n&&!n.includes("[")){let l=parseFloat(n);if(!isNaN(l))return l}return a??this.defaultDuration}resolveDurations(e,t){let r=this.parseSequenceKey(t)?.slider??"";return{enteringDuration:this.resolveDuration(e,r,"enteringDuration","entering-duration"),leavingDuration:this.resolveDuration(e,r,"leavingDuration","leaving-duration")}}resolveEasing(e,t,r,i){let s=e.getProperty(i);(!s||typeof s=="string"&&s.includes("["))&&(s=this.globalSettings.get(t)?.[r]??this.settings.easing??"ease-out"),typeof s=="string"&&e.setProperty(i,this.tools.easingFunction.process({easing:s}))}resolveEasings(e,t){let r=this.parseSequenceKey(t)?.slider;r&&(this.resolveEasing(e,r,"enteringEasing","entering-easing"),this.resolveEasing(e,r,"leavingEasing","leaving-easing"))}onObjectDisconnected(e){super.onObjectDisconnected(e);let t=e.getProperty("sequence");if(t){let r=this.elementIndex.get(t);if(r){let i=r.objects.indexOf(e);i!==-1&&r.objects.splice(i,1),r.objects.length||this.elementIndex.delete(t)}}this.triggerElements.has(e.htmlElement)&&(e.htmlElement.removeEventListener("click",this.onTriggerClick),this.triggerElements.delete(e.htmlElement))}parseSequenceKey(e){let t=e.match(/^(.+)\[(\d+)\]$/);return t?{slider:t[1],step:parseInt(t[2],10)}:null}onSequenceEvent(e){let{slider:t,step:r,transitionProgress:i,direction:s=1,duration:n,instant:a}=e;this.activeStep.get(t)===r&&i===void 0||(i!==void 0?this.handleScrub(t,r,i,s):a?this.switchInstant(t,r,s):this.startTransition(t,r,s,n))}startTransition(e,t,r,i){let s=this.activeStep.get(e),n=this.leavingStep.get(e);n!==void 0&&n!==s&&this.setStepState(e,n,"-disabled",0,r);let a=this.elementIndex.get(`${e}[${t}]`),l=s!==void 0?this.elementIndex.get(`${e}[${s}]`):null;s!==void 0&&this.leavingStep.set(e,s),this.activeStep.set(e,t),this.transitions.set(e,{fromStep:s??t,toStep:t,direction:r,startTime:this.data.time.now,enteringDuration:i??a?.enteringDuration??this.defaultDuration,leavingDuration:i??l?.leavingDuration??this.defaultDuration})}handleScrub(e,t,r,i){this.transitions.delete(e);let s=this.activeStep.get(e);if(s!==t){let n=this.leavingStep.get(e);n!==void 0&&this.setStepState(e,n,"-disabled",0,i),s!==void 0&&this.leavingStep.set(e,s),this.activeStep.set(e,t)}this.applyProgress(e,r,r,i)}switchInstant(e,t,r){this.transitions.delete(e);let i=this.activeStep.get(e),s=this.leavingStep.get(e);s!==void 0&&this.setStepState(e,s,"-disabled",0,r),i!==void 0&&i!==t&&this.setStepState(e,i,"-disabled",0,r),this.activeStep.set(e,t),this.leavingStep.delete(e),this.setStepState(e,t,"-active",1,r)}applyProgress(e,t,r,i){let s=this.activeStep.get(e),n=this.leavingStep.get(e);this.setStepState(e,s,t>=1?"-active":"-entering",t,i),n!==void 0&&n!==s&&(r>=1?(this.setStepState(e,n,"-disabled",0,i),this.leavingStep.delete(e)):this.setStepState(e,n,"-leaving",r,i))}setStepState(e,t,r,i,s){let n=this.elementIndex.get(`${e}[${t}]`);if(n)for(let a of n.objects)this.setState(a,r,i,s)}setState(e,t,r,i){let s=e.htmlElement,n=e.getProperty("_state"),a=e.getProperty("_direction"),l=e.getProperty(t==="-leaving"?"leaving-easing":"entering-easing"),h=typeof l=="function"?l(r):r;n!==t&&(s.classList.remove(...q.ALL_STATES),s.classList.add(t),e.setProperty("_state",t)),a!==i&&(e.setProperty("_direction",i),$.run(()=>$.setVars(s,{[te.DIRECTION]:i.toString()})))}onFrame(e){super.onFrame(e),this.initialized||(this.initialized=!0,this.initializeSliders());for(let[t,r]of this.transitions){let i=e.time.now-r.startTime,s=Math.min(1,i/r.enteringDuration),n=Math.min(1,i/r.leavingDuration);this.applyProgress(t,s,n,r.direction),s>=1&&n>=1&&this.transitions.delete(t)}}};re.ALL_STATES=Object.values(W);var z=class R extends F{constructor(e){super(e),this.htmlKey="form"}initializeObject(e,t,r,i){super.initializeObject(e,t,r,i);let s=t.getProperty("form-events")??[];s.forEach(d=>{d.eventElement.removeEventListener(d.eventType,d.eventCallback)}),s.length=0,t.setProperty("form-events",s),super.onObjectConnected(t);let n=t.htmlElement,a=[],l={};this.getInteractiveFields(n).forEach((d,u)=>this.registerField(d,n,a,l,s,u));let h=d=>{d.preventDefault();let u=!0,v={},g=new Set;for(let x of a){let y=x.field;if(!y.isConnected||!this.shouldValidateField(y))continue;if(this.isRadioField(y)){if(g.has(x.key))continue;g.add(x.key)}let{key:m,rules:f,needsContext:c}=x,b=this.getFieldValue(y);v[m]=b,l[m]=b;let{valid:p,errors:w}=this.tools.validation.process({rules:f,value:b,context:this.buildContext(c,m,l)});this.applyValidationState(n,y,m,p,w,"submit"),p||(u=!1)}if(u)this.events.emit(`form:submit:${t.id}`,v);else{let x=new Set,y=a.find(m=>{let f=m.field;if(!f.isConnected||!this.shouldValidateField(f))return!1;if(this.isRadioField(f)){if(x.has(m.key))return!1;x.add(m.key)}let{key:c,rules:b,needsContext:p}=m,w=this.getFieldValue(f);l[c]=w;let{valid:E}=this.tools.validation.process({rules:b,value:w,context:this.buildContext(p,c,l)});return!E});y?.field&&typeof y.field.focus=="function"&&y.field.focus(),this.events.emit(`form:invalid:${t.id}`)}};n.addEventListener("submit",h),s.push({eventElement:n,eventType:"submit",eventCallback:h}),t.setProperty("form-field-entries",a),t.setProperty("form-field-values",l)}onObjectConnected(e){}onDOMMutate(e,t){this.objects.length!==0&&(e.length>0&&this.handleMutationAdditions(e),t.length>0&&this.handleMutationRemovals(t))}applyValidationState(e,t,r,i,s,n){let a=e.querySelector(`[string-input="error[${r}]"]`),l=e.querySelector(`[string-input="group[${r}]"]`);a&&(a.innerHTML="",s.forEach(d=>{let u=document.createElement("span");u.textContent=d,a.appendChild(u)})),n==="live"?(t.classList.toggle("-invalid",!i),t.classList.remove("-error")):(t.classList.remove("-invalid"),t.classList.toggle("-error",!i)),t.classList.toggle("-valid",i),l&&(n==="live"?(l.classList.toggle("-invalid",!i),l.classList.remove("-error")):(l.classList.remove("-invalid"),l.classList.toggle("-error",!i)),l.classList.toggle("-valid",i));let h=i?"valid":n==="live"?"invalid":"error";this.events.emit(`form:field:${h}:${r}`,{key:r,field:t,errors:s,phase:n,valid:i})}getInteractiveFields(e){return Array.from(e.querySelectorAll("[string-input]")).filter(t=>!this.isServiceFieldAttribute(t.getAttribute("string-input")||"")).filter(t=>this.isFormFieldElement(t)).map(t=>t)}getFieldRules(e){let t=this.tools.domAttribute.process({element:e,key:"input"})??"";return this.tools.ruleParser.process({value:t})}registerField(e,t,r,i,s,n){if(!this.isFormFieldElement(e)||e.closest("form")!==t||r.some(y=>y.field===e))return;let a=this.registerFieldIndex(e,n??r.length),l=this.getInputKey(e,a),h=this.getFieldRules(e),d=this.supportsBeforeInputValidation(h),u=this.requiresContext(h),v=this.getInputEventType(e),g={field:e,key:l,rules:h,supportsRealtime:d,needsContext:u,inputEventType:v,inputHandler:()=>{}},x=y=>{let m=y.currentTarget||y.target;if(!m||!m.isConnected||!this.shouldValidateField(m))return;let f=this.getFieldValue(m);i[g.key]=f;let c=this.buildContext(g.needsContext,g.key,i),{valid:b,errors:p}=this.tools.validation.process({rules:g.rules,value:f,context:c});this.applyValidationState(t,m,g.key,b,p,"live")};if(g.inputHandler=x,e.addEventListener(v,x),s.push({eventElement:e,eventType:v,eventCallback:x}),d&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)){let y=m=>{let f=m;if(f.isComposing||f.inputType?.startsWith("insertComposition"))return;let c=m.currentTarget||m.target;if(!c||!(c instanceof HTMLInputElement||c instanceof HTMLTextAreaElement)||!c.isConnected)return;let b=c.selectionStart??0,p=c.selectionEnd??0,w=c.value;switch(f.inputType){case"deleteContentBackward":w=b===p&&b>0?c.value.slice(0,b-1)+c.value.slice(p):c.value.slice(0,b)+c.value.slice(p);break;case"deleteContentForward":w=b===p&&b<c.value.length?c.value.slice(0,b)+c.value.slice(b+1):c.value.slice(0,b)+c.value.slice(p);break;case"insertFromPaste":case"insertFromDrop":case"insertReplacementText":w=c.value.slice(0,b)+(f.data||"")+c.value.slice(p);break;default:typeof f.data=="string"&&(w=c.value.slice(0,b)+f.data+c.value.slice(p))}let{errors:E}=this.tools.validation.process({rules:g.rules,value:w,type:"beforeinput",context:this.buildContext(g.needsContext,g.key,i,{applied:!0,value:w})});E.length>0&&m.cancelable&&m.preventDefault()};g.beforeInputHandler=y,e.addEventListener("beforeinput",y),s.push({eventElement:e,eventType:"beforeinput",eventCallback:y})}e.classList.add("-inited"),r.push(g),i[l]=this.getFieldValue(e)}unregisterField(e,t,r,i){let s=t.findIndex(a=>a.field===e);if(s===-1)return;let n=t[s];n.inputHandler&&e.removeEventListener(n.inputEventType,n.inputHandler),n.beforeInputHandler&&e.removeEventListener("beforeinput",n.beforeInputHandler),delete r[n.key],t.splice(s,1);for(let a=i.length-1;a>=0;a--){let l=i[a];l.eventElement===e&&(l.eventCallback===n.inputHandler||n.beforeInputHandler&&l.eventCallback===n.beforeInputHandler)&&i.splice(a,1)}e.classList.remove("-inited")}collectInteractiveFieldsFromNode(e){let t=[];return e instanceof Element?(e.hasAttribute("string-input")&&t.push(e),t.push(...Array.from(e.querySelectorAll("[string-input]")))):e instanceof DocumentFragment&&t.push(...Array.from(e.querySelectorAll("[string-input]"))),t.filter(r=>!this.isServiceFieldAttribute(r.getAttribute("string-input")||"")).filter(r=>this.isFormFieldElement(r))}isRadioField(e){return e instanceof HTMLInputElement&&e.type==="radio"}handleMutationAdditions(e){e.forEach(t=>{this.collectInteractiveFieldsFromNode(t).forEach(r=>{let i=this.getFormStateByContainment(r);i&&this.registerField(r,i.form,i.entries,i.values,i.events)})})}handleMutationRemovals(e){e.forEach(t=>{this.collectInteractiveFieldsFromNode(t).forEach(r=>{let i=this.getFormStateByReference(r);i&&this.unregisterField(r,i.entries,i.values,i.events)})})}getFormStateByContainment(e){let t=this.objects.find(r=>r.htmlElement instanceof HTMLFormElement&&r.htmlElement.contains(e));return t?this.buildFormState(t):null}getFormStateByReference(e){for(let t of this.objects){let r=t.getProperty("form-field-entries");if(r&&r.some(i=>i.field===e))return this.buildFormState(t,r)}return null}buildFormState(e,t){let r=e.htmlElement;if(!(r instanceof HTMLFormElement))return null;let i=t??e.getProperty("form-field-entries"),s=e.getProperty("form-field-values"),n=e.getProperty("form-events");return!i||!s||!n?null:{object:e,form:r,entries:i,values:s,events:n}}registerFieldIndex(e,t){let r=e.getAttribute("data-string-form-index");return r!==null?Number(r):(e.setAttribute("data-string-form-index",String(t)),t)}getFieldIndex(e,t){let r=e.getAttribute("data-string-form-index");if(r!==null){let i=Number(r);return Number.isNaN(i)?t:i}return this.registerFieldIndex(e,t)}shouldValidateField(e){return!(e.disabled||e instanceof HTMLInputElement&&e.type==="hidden")}supportsBeforeInputValidation(e){return e.some(t=>R.beforeInputRuleKeys.has(t.key))}requiresContext(e){return e.some(t=>R.crossFieldRuleKeys.has(t.key))}buildContext(e,t,r,i){if(!e)return{fieldKey:t};let s=!!i?.applied,n=s?{...r,[t]:i.value}:r;return{fieldKey:t,values:n,getValue:a=>s&&a===t?i.value:n[a]}}getInputKey(e,t){return this.tools.domAttribute.process({element:e,key:"id"})||e.getAttribute("name")||e.getAttribute("id")||`input-${t}`}getFieldValue(e){if(e instanceof HTMLInputElement){if(e.type==="checkbox"){if(e.name){let t=e.form||e.closest("form"),r=t?Array.from(t.querySelectorAll(`input[type="checkbox"][name="${e.name}"]:checked`)):[e];return r.length>1?r.map(i=>i.value):r.length===1?r[0].value:""}return e.checked}if(e.type==="radio"){if(e.name){let t=(e.form||e.closest("form"))?.querySelector(`input[type="radio"][name="${e.name}"]:checked`);return t?t.value:""}return e.checked?e.value:""}return e.type==="file"&&e.files&&e.files.length>0?e.multiple?Array.from(e.files):e.files[0]:e.value}return e instanceof HTMLSelectElement?e.multiple?Array.from(e.selectedOptions).map(t=>t.value):e.value:e instanceof HTMLTextAreaElement?e.value:""}isServiceFieldAttribute(e){return R.serviceAttributePrefixes.some(t=>e.startsWith(`${t}[`))}isFormFieldElement(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement}getInputEventType(e){return e instanceof HTMLSelectElement||e instanceof HTMLInputElement&&(e.type==="checkbox"||e.type==="radio")?"change":"input"}};z.beforeInputRuleKeys=new Set(["number","integer","email","phone","letters","lettersSpaces","lettersNumbers","alpha","alpha_num","alpha_dash","digits","url","pattern"]),z.crossFieldRuleKeys=new Set(["same","different","after","before"]),z.serviceAttributePrefixes=["error","group"];var D=class{constructor(e,t="orthographic",r=50,i=.1,s=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,s):this._camera=e.createPerspectiveCamera(r,1,i,s),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,s=-(t-this._height/2);return this.engine.createVector3(i,s,r)}else{let{width:i,height:s}=this.getFrustumSizeAt(r),n=e/this._width,a=t/this._height,l=(n-.5)*i,h=-(a-.5)*s;return this.engine.createVector3(l,h,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),s=i/t;return this.scaleCache.set(r,s),s}clearScaleCache(){this.scaleCache.clear()}getMode(){return this.mode}};var k=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 S=class{constructor(e,t,r,i){this._uniforms={};this._children=[];this.id=e,this.type=t,this._object=r,this.engine=i,this._quaternion=i.createQuaternion(),this._originalSize=i.createVector3(),this._bbox=i.createBox3(),this.updateBoundingBox()}get children(){return this._children}get object(){return this._object}get material(){return this._material}get originalSize(){return this._originalSize.clone()}get boundingBox(){return this._bbox.clone()}addChild(e){this._children.push(e),this.object.add(e.object)}getWorldMatrix(){return this._object.matrixWorld.clone()}getWorldPosition(){return this.engine.createVector3().setFromMatrixPosition(this._object.matrixWorld)}getOriginalBoundingBox(){if(!this._originalBoundingBox){let e=this.object.scale.clone();this.object.scale.set(1,1,1),this.object.updateMatrixWorld(!0),this._originalBoundingBox=this.engine.computeBoundingBoxRecursively(this.object),this.object.scale.copy(e),this.object.updateMatrixWorld(!0)}return this._originalBoundingBox.clone()}syncTransformFromMatrix(e){let t=this.engine.createVector3(),r=this.engine.createQuaternion(),i=this.engine.createVector3();e.decompose(t,r,i),this._object.position.copy(t),this._object.quaternion.copy(r),this._object.scale.copy(i),this._object.updateMatrix(),this._object.updateMatrixWorld()}applyWorldTransform(e,t,r){this._object.position.copy(e),this._object.quaternion.copy(t),this._object.scale.copy(r),this._object.updateMatrix(),this._object.updateMatrixWorld()}set quaternion(e){this._quaternion.copy(e),this._object.quaternion.copy(this._quaternion),this._object.updateMatrixWorld()}set position(e){this._object.position.copy(e)}set scale(e){this._object.scale.copy(e)}set rotation(e){this._object.rotation.copy(e)}set opacity(e){let t=this._object;t.material&&"opacity"in t.material&&(t.material.opacity=e)}set metalness(e){let t=this._object;t.material&&"metalness"in t.material&&(t.material.metalness=e)}set roughness(e){let t=this._object;t.material&&"roughness"in t.material&&(t.material.roughness=e)}set texture(e){this._texture=e,this._object.isMesh&&e?.applyTexture&&e.applyTexture(this._object)}updateBoundingBox(){this._bbox.setFromObject(this._object),this._bbox.getSize(this._originalSize)}destroy(){this._texture?.dispose?.(),this._material?.dispose(),this._geometry?.dispose()}};var L=class{constructor(e,t){this._objects=new Map;this._rootObjects=[];this._elementMap=new Map;this.engine=e,this._modelLoader=t,this._scene=e.createScene()}get rootObjects(){return this._rootObjects}getScene(){return this._scene}getObject(e){return this._objects.get(e)}hasObject(e){return this._objects.has(e)}deleteObject(e){let t=this._objects.get(e);return t?(this._scene.remove(t.object),this._objects.delete(e),t.destroy(),!0):!1}createFromElement(e){let t=e.getProperty("3d");if(!t)return;let r=e.htmlElement;if(!r)return;let i=s=>{if(s){let n=e.getProperty("parentId");n==null?(this._scene.add(s.object),this._rootObjects.push(s)):this._objects.get(n)?.addChild(s),this._objects.set(e.id,s),this._elementMap.set(e.id,r),s.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 S(e.id,"group",r,this.engine);return t(i),i}createLight(e,t,r){let i=e.getProperty("3d-color")||"#ffffff",s=e.getProperty("3d-intensity")??1,n;if(t==="point"){let l=e.getProperty("3d-distance")??1e3,h=e.getProperty("3d-decay")??0;n=this.engine.createPointLight(i,s,l,h)}else t==="directional"?n=this.engine.createDirectionalLight(i,s):n=this.engine.createAmbientLight(i,s);let a=new S(e.id,t+"Light",n,this.engine);return r(a),a}createBox(e,t){let r=this.engine.createBoxGeometry(1,1,1),i=this.createMaterialFromObject(e),s=this.engine.createMesh(r,i),n=new S(e.id,"box",s,this.engine);return t(n),n}createSphere(e,t){let r=e.getProperty("3d-segments-width")??32,i=e.getProperty("3d-segments-height")??32,s=this.engine.createSphereGeometry(.5,r,i),n=this.createMaterialFromObject(e),a=this.engine.createMesh(s,n),l=new S(e.id,"sphere",a,this.engine);return t(l),l}createPlane(e,t){let r=this.engine.createPlaneGeometry(1,1),i=this.createMaterialFromObject(e),s=this.engine.createMesh(r,i),n=new S(e.id,"plane",s,this.engine);return t(n),n}createCylinder(e,t){let r=e.getProperty("3d-segments")??32,i=this.engine.createCylinderGeometry(.5,.5,1,r),s=this.createMaterialFromObject(e),n=this.engine.createMesh(i,s),a=new S(e.id,"cylinder",n,this.engine);return t(a),a}createModel(e,t){if(!this._modelLoader){console.warn("[String3D] Model loader not configured");return}let r=e.getProperty("3d-model");if(!r)return;let i=this.createMaterialFromObject(e);this._modelLoader.load(r,n=>{let a=n.scene;a.traverse(h=>{h.isMesh&&(h.material=i)});let l=new S(e.id,"model",a,this.engine);t(l)},n=>{console.log(n.loaded/n.total*100+"% loaded")},n=>{console.error("[String3D] Model loading error:",n)})}createMaterialFromObject(e){let t=e.getProperty("3d-material")||"basic[#ffffff]",[r,i]=t.split(/\[|\]/),s=i||"#ffffff",n=e.getProperty("3d-opacity")??1,a={color:s,transparent:n<1,opacity:n},l=e.el,h=l?.getAttribute("string-3d-map"),d=l?.getAttribute("string-3d-normalMap"),u=l?.getAttribute("string-3d-roughnessMap"),v=l?.getAttribute("string-3d-aoMap");return r==="standard"?(h&&(a.map=this.loadTexture(h)),d&&(a.normalMap=this.loadTexture(d)),u&&(a.roughnessMap=this.loadTexture(u)),v&&(a.aoMap=this.loadTexture(v)),this.engine.createMeshStandardMaterial(a)):this.engine.createMeshBasicMaterial(a)}loadTexture(e){return this.engine.createTextureLoader().load(e)}destroy(){this._objects.forEach(e=>e.destroy()),this._objects.clear(),this._rootObjects=[]}};var _=class{sync(e,t,r,i){let s=e.getBoundingClientRect(),n=s.left+s.width/2,a=s.top+s.height/2,l=getComputedStyle(e),h=parseFloat(l.getPropertyValue("--translate-z")||"0"),d=r.camera.screenToWorld(n,a,h);t.position=d;let u=parseFloat(l.getPropertyValue("--scale"))||1;t.scale=r.engine.createVector3(u,u,u);let v=-r.engine.degToRad(parseFloat(l.getPropertyValue("--rotate-x")||"0")),g=r.engine.degToRad(parseFloat(l.getPropertyValue("--rotate-y")||"0")),x=-r.engine.degToRad(parseFloat(l.getPropertyValue("--rotate-z")||"0"));return t.rotation=r.engine.createEuler(v,g,x,"XYZ"),t.object.updateMatrixWorld(!0),{scale:u}}};var I=class{sync(e,t,r,i){let s=e.getBoundingClientRect(),n=s.left+s.width/2,a=s.top+s.height/2,l=parseFloat(getComputedStyle(e).getPropertyValue("--translate-z")||"0"),h=r.camera.screenToWorld(n,a,l);return t.position=h,null}};var M=class{sync(e,t,r,i){let s=getComputedStyle(e),n=e.offsetWidth,a=e.offsetHeight,l=e.getBoundingClientRect(),h=parseFloat(s.getPropertyValue("--translate-z")||"0"),d=parseFloat(s.getPropertyValue("--scale")||"1"),u=l.left+l.width/2,v=l.top+l.height/2,g=r.camera.screenToWorld(u,v,h);t.position=g;let x=-r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-x")||"0")),y=r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-y")||"0")),m=-r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-z")||"0"));t.rotation=r.engine.createEuler(x,y,m,"XYZ");let f=n*d,c=a*d,b=parseFloat(s.getPropertyValue("--scale-z")||"1"),p=i?.scale||1,w=t.type,E,A,j;switch(w){case"box":case"sphere":{let C=Math.min(f,c);E=C*p,A=C*p,j=C*b*p;break}case"cylinder":{let C=f;E=C*p,A=c*p,j=C*b*p;break}case"plane":default:E=f*p,A=c*p,j=Math.min(f,c)*.5*b*p;break}return t.scale=r.engine.createVector3(E,A,j),{scale:d*p}}};var T=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 M),this.strategies.set("sphere",new M),this.strategies.set("plane",new M),this.strategies.set("cylinder",new M),this.strategies.set("model",new M),this.strategies.set("group",new _),this.strategies.set("pointLight",new I),this.strategies.set("ambientLight",new I),this.strategies.set("directionalLight",new I)}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 P=class P extends F{constructor(t,r={}){super(t);this.renderer=null;this.camera=null;this.scene=null;this.synchronizer=null;this.engine=null;this.canvasContainer=null;this.isLoading=new Map;this.htmlKey="3d",this.options={hideHTML:r.hideHTML??!1,container:r.container,zIndex:r.zIndex??1},this.attributesToMap=[...this.attributesToMap,{key:"3d",type:"string",fallback:"box"},{key:"3d-material",type:"string",fallback:"basic[#ffffff]"},{key:"3d-color",type:"string",fallback:"#ffffff"},{key:"3d-opacity",type:"number",fallback:1},{key:"3d-intensity",type:"number",fallback:1},{key:"3d-distance",type:"number",fallback:1e3},{key:"3d-decay",type:"number",fallback:0},{key:"3d-model",type:"string",fallback:""},{key:"3d-segments",type:"number",fallback:32},{key:"3d-segments-width",type:"number",fallback:32},{key:"3d-segments-height",type:"number",fallback:32}]}static setProvider(t){P.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,s){super.initializeObject(t,r,i,s),r.setProperty("parentId",null);let n=i.parentElement?.closest('[string-3d="group"]');if(n){let a=n.getAttribute("string-id");a&&(r.setProperty("parentId",a),r.setProperty("parent",n))}}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(!P.provider){console.error("[String3D] No provider set. Call String3D.setProvider() before use.");return}this.engine=P.provider.getEngine(),this.canvasContainer=this.createOrGetContainer(),this.injectCSS(),this.renderer=new k(this.canvasContainer,this.engine),this.renderer.attach(),this.camera=new D(this.engine,"orthographic"),this.camera.setPosition(0,0,1e3),this.camera.resize(this.renderer.width,this.renderer.height),this.scene=new L(this.engine),this.scene.getScene().add(this.camera.camera),this.synchronizer=new T(this.camera,this.renderer.width,this.renderer.height,this.engine),console.info(`[String3D] Initialized with: ${P.provider.getName()}`)}createOrGetContainer(){if(this.options.container instanceof HTMLElement)return this.applyContainerStyles(this.options.container),this.options.container;if(typeof this.options.container=="string"){let r=document.getElementById(this.options.container);if(r)return this.applyContainerStyles(r),r}let t=document.createElement("div");return t.id="string-3d-canvas",this.applyContainerStyles(t),document.body.insertBefore(t,document.body.firstChild),t}applyContainerStyles(t){Object.assign(t.style,{position:"fixed",left:"0",top:"0",width:"100vw",height:"100lvh",zIndex:String(this.options.zIndex),pointerEvents:"none"})}onObjectConnected(t){this.isLoading.has(t.id)||!this.scene||(this.isLoading.set(t.id,!0),this.scene.createFromElement(t),this.options.hideHTML&&t.htmlElement&&(t.htmlElement.style.opacity="0",t.htmlElement.style.pointerEvents="none"))}onFrame(t){!this.renderer||!this.scene||!this.camera||!this.synchronizer||(B.measure(()=>{this.scene.rootObjects.forEach(r=>{this.syncRecursive(r.el,r,{scale:1})})}),B.mutate(()=>{this.renderer.render(this.scene,this.camera)}))}syncRecursive(t,r,i){if(!this.synchronizer||!t)return;let s=this.synchronizer.syncElement(t,r,i);r.children.forEach(n=>this.syncRecursive(n.el,n,s))}injectCSS(){if(document.getElementById("string-3d-styles"))return;let t=document.createElement("style");t.id="string-3d-styles",t.textContent=`
|
|
1
|
+
"use strict";var StringTune3D=(()=>{var W=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var te=Object.prototype.hasOwnProperty;var re=(o,e)=>{for(var t in e)W(o,t,{get:e[t],enumerable:!0})},ie=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ee(e))!te.call(o,i)&&i!==t&&W(o,i,{get:()=>e[i],enumerable:!(r=J(e,i))||r.enumerable});return o};var se=o=>ie(W({},"__esModule",{value:!0}),o);var he={};re(he,{String3D:()=>z,String3DCamera:()=>T,String3DObject:()=>M,String3DRenderer:()=>O,String3DScene:()=>A,String3DSynchronizer:()=>R,ThreeJSEngine:()=>F,ThreeJSProvider:()=>B});var ne=class{constructor(){this.desktop={rebuild:{width:!0,height:!0,scrollHeight:!0}},this.mobile={rebuild:{width:!0,height:!0,scrollHeight:!0}}}},V=class{constructor(o){this.objectMapOnPage=new Map,this.objectsOnPage=[],this.objectMap=new Map,this.objects=[],this.htmlKey="",this._type=1,this.permissions=new ne,this.tools=o.tools,this.data=o.data,this.settings=o.settings,this.events=o.events,this.centers=o.centers,this.hover=o.hover,this.attributesToMap=[{key:"active",type:"boolean",fallback:this.settings.active},{key:"fixed",type:"boolean",fallback:this.settings.fixed},{key:"outside-container",type:"boolean",fallback:this.settings["outside-container"]},{key:"repeat",type:"boolean",fallback:this.settings.repeat},{key:"self-disable",type:"boolean",fallback:this.settings["self-disable"]},{key:"abs",type:"boolean",fallback:this.settings.abs},{key:"key",type:"string",fallback:this.settings.key},{key:"offset-top",type:"dimension",fallback:this.settings["offset-top"]},{key:"offset-bottom",type:"dimension",fallback:this.settings["offset-bottom"]},{key:"inview-top",type:"dimension",fallback:this.settings["inview-top"]},{key:"inview-bottom",type:"dimension",fallback:this.settings["inview-bottom"]},{key:"start",type:"number",fallback:(e,t,r)=>{let i=r.top;return Math.floor(i)+this.data.scroll.container.scrollTop*this.data.viewport.transformScale}},{key:"end",type:"number",fallback:(e,t,r)=>{let i=r.top,s=r.height;return i+s-this.data.scroll.transformedCurrent}},{key:"size",type:"number",fallback:(e,t,r)=>r.height},{key:"half-width",type:"number",fallback:(e,t,r)=>r.width/2},{key:"half-height",type:"number",fallback:(e,t,r)=>r.height/2},{key:"enter-el",type:"string",fallback:this.settings["enter-el"]},{key:"enter-vp",type:"string",fallback:this.settings["enter-vp"]},{key:"exit-el",type:"string",fallback:this.settings["exit-el"]},{key:"exit-vp",type:"string",fallback:this.settings["exit-vp"]}]}get type(){return this._type}initializeObject(o,e,t,r){let i=this.tools.boundingClientRect.process({element:t});for(let{key:s,type:n,fallback:l,transform:a}of this.attributesToMap){let c=typeof l=="function"?l(t,e,i):l,h=this.tools.domAttribute.process({element:t,key:s,fallback:r[s]??this.settings[s]??c}),u=this.parseAttribute(h,n,{element:t,boundingRect:i,viewportHeight:this.data.viewport.windowHeight,baseRem:this.data.viewport.baseRem});a&&(u=a(u)),e.setProperty(s,u)}}calculatePositions(o,e){let t=o.getProperty("start"),r=o.getProperty("size"),i=o.getProperty("offset-bottom"),s=o.getProperty("offset-top"),n=o.getProperty("enter-el"),l=o.getProperty("enter-vp"),a=o.getProperty("exit-el"),c=o.getProperty("exit-vp"),h=0,u=0,v=0,m=0;n==="top"&&l==="top"||n==="left"&&l==="left"?(v=-e+1,h=t-i):n==="top"&&l==="bottom"||n==="left"&&l==="right"?h=t-e-i:n==="bottom"&&l==="top"||n==="right"&&l==="left"?(v=-e-r+1,h=t+r-i):(n==="bottom"&&l==="bottom"||n==="right"&&l==="right")&&(v=-r+1,h=t-e+r-i),a==="top"&&c==="top"||a==="left"&&c==="left"?(m=-r+1,u=t+s):a==="top"&&c==="bottom"||a==="left"&&c==="right"?(m=-e-r+1,u=t-e+s):a==="bottom"&&c==="top"||a==="right"&&c==="left"?u=t+r+s:(a==="bottom"&&c==="bottom"||a==="right"&&c==="right")&&(m=-e+1,u=t-e+r+s),o.setProperty("start-bias",v),o.setProperty("end-bias",m),o.setProperty("start-position",h-this.data.scroll.topPosition),o.setProperty("end-position",u-this.data.scroll.topPosition),o.setProperty("difference-position",u-h);let S=o.getProperty("inview-top")??0,y=o.getProperty("inview-bottom")??0;o.setProperty("inview-start-position",o.getProperty("start-position")+S),o.setProperty("inview-end-position",o.getProperty("end-position")+y)}parseAttribute(o,e,t={}){if(o==null)return null;if(typeof e=="object"&&e.type==="enum")return e.values.includes(o)?o:e.values[0];switch(e){case"number":return parseFloat(o);case"boolean":return o===""||o==="true";case"json":try{return JSON.parse(o)}catch{return null}case"tuple":return o.trim().split(/\s+/);case"easing":return this.tools.easingFunction.process({easing:o});case"color":return this.tools.colorParser.process({value:o});case"dimension":return o=="0"?0:t.element!=null&&t.viewportHeight!=null&&t.baseRem!=null&&t.boundingRect!=null?this.tools.unitParser.process({value:o,element:t.element,viewportHeight:t.viewportHeight,boundingRect:t.boundingRect,baseRem:t.baseRem}):0;case"breakpoint-dimension":if(t.element!=null&&t.viewportHeight!=null&&t.baseRem!=null&&t.boundingRect!=null){let r=o.trim().split("|"),i=[];for(let s of r)if(s.includes(":")){let[n,l]=s.split(":");i.push({breakpoint:parseInt(n),value:this.tools.unitParser.process({value:`${l}|`,element:t.element,viewportHeight:t.viewportHeight,boundingRect:t.boundingRect,baseRem:t.baseRem})})}else i.push({breakpoint:0,value:this.tools.unitParser.process({value:s,element:t.element,viewportHeight:t.viewportHeight,boundingRect:t.boundingRect,baseRem:t.baseRem})});return i}default:return o}}canConnect(o){return o.keys.includes(this.htmlKey)}connectObject(o){o.connect(this),this.onObjectConnected(o)}enterObject(o,e){this.objectMap.has(o)||(this.objectMap.set(o,e),this.objects.push(e))}exitObject(o){let e=this.objectMap.get(o);if(!e)return;this.objectMap.delete(o);let t=this.objects.indexOf(e);t!==-1&&this.objects.splice(t,1)}addObject(o,e){this.objectMapOnPage.has(o)||(this.objectMapOnPage.set(o,e),this.objectsOnPage.push(e))}removeObject(o){let e=this.objectMapOnPage.get(o);if(!e)return;this.objectMapOnPage.delete(o);let t=this.objectsOnPage.indexOf(e);t!==-1&&this.objectsOnPage.splice(t,1),this.onObjectDisconnected(e)}onObjectConnected(o){}onObjectDisconnected(o){}applyToElementAndConnects(o,e,t=e){o.getProperty("self-disable")!==!0&&e(o.htmlElement),o.mirrorObjects.forEach(r=>t(r.htmlElement,r))}destroy(){this.objects=[],this.objectMap=new Map}onInit(){}onFrame(o){}onMutate(o){}onScrollMeasure(o){}onMouseMoveMeasure(o){}onResize(){}onResizeWidth(){}onScroll(o){}onDirectionChange(){}onScrollStart(){}onScrollStop(){}onScrollDirectionChange(){}onAxisChange(){}onDeviceChange(){}onScrollConfigChange(){}onSettingsChange(){}onDOMRebuild(){}onMouseMove(o){}onWheel(o){}onDOMMutate(o,e){}};var oe=class{constructor(){this.pendingVars=new Map,this.pendingProps=new Map,this.isOpen=!1}begin(){this.isOpen||(this.isOpen=!0)}setVars(o,e){if(!this.isOpen){console.warn("StyleTxn: call begin() first to set custom properties.");return}let t=this.pendingVars.get(o)??{};for(let[r,i]of Object.entries(e))t[r]!==i&&(t[r]=i);this.pendingVars.set(o,t)}setProps(o,e){if(!this.isOpen){console.warn("StyleTxn: call begin() first to set standard properties.");return}let t=this.pendingProps.get(o)??{};for(let[r,i]of Object.entries(e))t[r]!==i&&(t[r]=i);this.pendingProps.set(o,t)}run(o){let e=this.isOpen;e||this.begin();try{o(),e||this.commit()}catch(t){throw e||this.cancel(),t}}commit(){if(this.isOpen){this.isOpen=!1;for(let[o,e]of this.pendingVars){let t=o.style;for(let[r,i]of Object.entries(e))t.setProperty(r,String(i))}this.pendingVars.clear();for(let[o,e]of this.pendingProps){let t=o.style;for(let[r,i]of Object.entries(e))t[r]=String(i)}this.pendingProps.clear()}}cancel(){this.pendingVars.clear(),this.pendingProps.clear(),this.isOpen=!1}},X=new oe;var ue=1/240;var ae=class{constructor(){this.measureQueue=[],this.mutateQueue=[],this.scheduled=!1}measure(o){this.measureQueue.push(o),this.schedule()}mutate(o){this.mutateQueue.push(o),this.schedule()}schedule(){this.scheduled||(this.scheduled=!0,requestAnimationFrame(()=>{let o=this.measureQueue;this.measureQueue=[];for(let t=0;t<o.length;t++)try{o[t]()}catch(r){console.error("Error in frameDOM measure task:",r)}let e=this.mutateQueue;this.mutateQueue=[];for(let t=0;t<e.length;t++)try{e[t]()}catch(r){console.error("Error in frameDOM mutate task:",r)}this.scheduled=!1}))}},U=new ae;var pe=Math.PI*2,ge=180/Math.PI;var K=(o=>(o.ACTIVE="-active",o.ENTERING="-entering",o.LEAVING="-leaving",o.DISABLED="-disabled",o))(K||{}),le={PROGRESS:"--sequence-progress",DIRECTION:"--sequence-direction"},ce=class Q extends V{constructor(e){super(e),this.activeStep=new Map,this.leavingStep=new Map,this.transitions=new Map,this.elementIndex=new Map,this.triggerElements=new Map,this.globalSettings=new Map,this.initialized=!1,this.onTriggerClick=t=>{let r=this.triggerElements.get(t.currentTarget);if(!r)return;let i=this.activeStep.get(r.slider)??0,s=this.getMaxStep(r.slider),n,l;if(r.step==="next"){if(n=i+1,l=1,!this.elementIndex.has(`${r.slider}[${n}]`))if(r.loop&&s>=0)n=0;else return}else if(r.step==="prev"){if(n=i-1,l=-1,n<0)if(r.loop&&s>=0)n=s;else return;if(!this.elementIndex.has(`${r.slider}[${n}]`))return}else{if(n=r.step,i===n)return;l=n>i?1:-1}this.startTransition(r.slider,n,l)},this.htmlKey="sequence",this.defaultDuration=this.settings["sequence-duration"]??600,this.attributesToMap=[...this.attributesToMap,{key:"sequence",type:"string",fallback:""},{key:"sequence-trigger",type:"string",fallback:""},{key:"entering-easing",type:"string",fallback:""},{key:"leaving-easing",type:"string",fallback:""},{key:"entering-duration",type:"string",fallback:""},{key:"leaving-duration",type:"string",fallback:""},{key:"sequence-duration",type:"string",fallback:""},{key:"active-step",type:"string",fallback:""}]}onInit(){super.onInit(),this.events.on("sequence",this.onSequenceEvent.bind(this)),this.scanStandaloneTriggers()}scanStandaloneTriggers(){let e=document.querySelectorAll("[string-sequence-trigger]:not([string-inited])");for(let t of e){let r=t.getAttribute("string-sequence-trigger"),i=r?this.parseTriggerKey(r):null;i&&(this.triggerElements.set(t,i),t.addEventListener("click",this.onTriggerClick))}}parseGlobalSettingsFromObject(e){let t=i=>e.getProperty(i),r=t("sequence-duration");this.tryParseGlobalSetting(r,"enteringDuration"),this.tryParseGlobalSetting(r,"leavingDuration"),this.tryParseGlobalSetting(t("entering-duration"),"enteringDuration"),this.tryParseGlobalSetting(t("leaving-duration"),"leavingDuration"),this.tryParseGlobalSetting(t("entering-easing"),"enteringEasing"),this.tryParseGlobalSetting(t("leaving-easing"),"leavingEasing"),this.tryParseGlobalSetting(t("active-step"),"activeStep")}tryParseGlobalSetting(e,t){if(!e)return;let r=e.match(/^(.+)\[(.+)\]$/);if(!r)return;let[,i,s]=r,n=this.globalSettings.get(i)??{};this.globalSettings.set(i,n),n[t]=t==="enteringEasing"||t==="leavingEasing"?s:parseFloat(s),this.applyGlobalSettingsToExistingObjects(i)}applyGlobalSettingsToExistingObjects(e){let t=this.globalSettings.get(e);if(t){for(let[r,i]of this.elementIndex)if(this.parseSequenceKey(r)?.slider===e){t.enteringDuration!==void 0&&(i.enteringDuration=t.enteringDuration),t.leavingDuration!==void 0&&(i.leavingDuration=t.leavingDuration);for(let s of i.objects)this.resolveEasings(s,r)}}}initializeSliders(){let e=new Set;for(let t of this.elementIndex.keys()){let r=this.parseSequenceKey(t);r&&e.add(r.slider)}for(let t of e){if(this.activeStep.has(t))continue;let r=this.globalSettings.get(t)?.activeStep??0;this.elementIndex.has(`${t}[${r}]`)||(r=0),this.switchInstant(t,r,1)}}tryApplyPendingActiveStep(e){if(this.activeStep.has(e))return;let t=this.globalSettings.get(e)?.activeStep;t!==void 0&&this.elementIndex.has(`${e}[${t}]`)&&this.switchInstant(e,t,1)}canConnect(e){return e.keys.includes("sequence")||e.keys.includes("sequence-trigger")}onObjectConnected(e){super.onObjectConnected(e),this.parseGlobalSettingsFromObject(e);let t=e.getProperty("sequence"),r=e.getProperty("sequence-trigger");if(!t&&r){let i=this.parseTriggerKey(r);i&&typeof i.step=="number"&&(t=`${i.slider}[${i.step}]`,e.setProperty("sequence",t))}if(t){let i=this.parseSequenceKey(t);if(i){let s=this.elementIndex.get(t);if(!s){let{enteringDuration:l,leavingDuration:a}=this.resolveDurations(e,t);s={objects:[],enteringDuration:l,leavingDuration:a},this.elementIndex.set(t,s)}s.objects.push(e),this.resolveEasings(e,t);let n=this.activeStep.get(i.slider);this.setState(e,n===i.step?"-active":"-disabled",n===i.step?1:0,1),this.tryApplyPendingActiveStep(i.slider)}}if(r){let i=this.parseTriggerKey(r);i&&(this.triggerElements.set(e.htmlElement,i),e.htmlElement.addEventListener("click",this.onTriggerClick))}}parseTriggerKey(e){let t=e.match(/^(.+)\[(next|prev|\d+)(\|loop)?\]$/);if(!t)return null;let r=t[2]==="next"||t[2]==="prev"?t[2]:parseInt(t[2],10);return{slider:t[1],step:r,loop:t[3]==="|loop"}}getMaxStep(e){let t=-1;for(let r of this.elementIndex.keys()){let i=this.parseSequenceKey(r);i?.slider===e&&i.step>t&&(t=i.step)}return t}resolveDuration(e,t,r,i){let s=e.getProperty(i),n=e.getProperty("sequence-duration"),l=this.globalSettings.get(t)?.[r];if(s&&!s.includes("[")){let a=parseFloat(s);if(!isNaN(a))return a}if(n&&!n.includes("[")){let a=parseFloat(n);if(!isNaN(a))return a}return l??this.defaultDuration}resolveDurations(e,t){let r=this.parseSequenceKey(t)?.slider??"";return{enteringDuration:this.resolveDuration(e,r,"enteringDuration","entering-duration"),leavingDuration:this.resolveDuration(e,r,"leavingDuration","leaving-duration")}}resolveEasing(e,t,r,i){let s=e.getProperty(i);(!s||typeof s=="string"&&s.includes("["))&&(s=this.globalSettings.get(t)?.[r]??this.settings.easing??"ease-out"),typeof s=="string"&&e.setProperty(i,this.tools.easingFunction.process({easing:s}))}resolveEasings(e,t){let r=this.parseSequenceKey(t)?.slider;r&&(this.resolveEasing(e,r,"enteringEasing","entering-easing"),this.resolveEasing(e,r,"leavingEasing","leaving-easing"))}onObjectDisconnected(e){super.onObjectDisconnected(e);let t=e.getProperty("sequence");if(t){let r=this.elementIndex.get(t);if(r){let i=r.objects.indexOf(e);i!==-1&&r.objects.splice(i,1),r.objects.length||this.elementIndex.delete(t)}}this.triggerElements.has(e.htmlElement)&&(e.htmlElement.removeEventListener("click",this.onTriggerClick),this.triggerElements.delete(e.htmlElement))}parseSequenceKey(e){let t=e.match(/^(.+)\[(\d+)\]$/);return t?{slider:t[1],step:parseInt(t[2],10)}:null}onSequenceEvent(e){let{slider:t,step:r,transitionProgress:i,direction:s=1,duration:n,instant:l}=e;this.activeStep.get(t)===r&&i===void 0||(i!==void 0?this.handleScrub(t,r,i,s):l?this.switchInstant(t,r,s):this.startTransition(t,r,s,n))}startTransition(e,t,r,i){let s=this.activeStep.get(e),n=this.leavingStep.get(e);n!==void 0&&n!==s&&this.setStepState(e,n,"-disabled",0,r);let l=this.elementIndex.get(`${e}[${t}]`),a=s!==void 0?this.elementIndex.get(`${e}[${s}]`):null;s!==void 0&&this.leavingStep.set(e,s),this.activeStep.set(e,t),this.transitions.set(e,{fromStep:s??t,toStep:t,direction:r,startTime:this.data.time.now,enteringDuration:i??l?.enteringDuration??this.defaultDuration,leavingDuration:i??a?.leavingDuration??this.defaultDuration})}handleScrub(e,t,r,i){this.transitions.delete(e);let s=this.activeStep.get(e);if(s!==t){let n=this.leavingStep.get(e);n!==void 0&&this.setStepState(e,n,"-disabled",0,i),s!==void 0&&this.leavingStep.set(e,s),this.activeStep.set(e,t)}this.applyProgress(e,r,r,i)}switchInstant(e,t,r){this.transitions.delete(e);let i=this.activeStep.get(e),s=this.leavingStep.get(e);s!==void 0&&this.setStepState(e,s,"-disabled",0,r),i!==void 0&&i!==t&&this.setStepState(e,i,"-disabled",0,r),this.activeStep.set(e,t),this.leavingStep.delete(e),this.setStepState(e,t,"-active",1,r)}applyProgress(e,t,r,i){let s=this.activeStep.get(e),n=this.leavingStep.get(e);this.setStepState(e,s,t>=1?"-active":"-entering",t,i),n!==void 0&&n!==s&&(r>=1?(this.setStepState(e,n,"-disabled",0,i),this.leavingStep.delete(e)):this.setStepState(e,n,"-leaving",r,i))}setStepState(e,t,r,i,s){let n=this.elementIndex.get(`${e}[${t}]`);if(n)for(let l of n.objects)this.setState(l,r,i,s)}setState(e,t,r,i){let s=e.htmlElement,n=e.getProperty("_state"),l=e.getProperty("_direction"),a=e.getProperty(t==="-leaving"?"leaving-easing":"entering-easing"),c=typeof a=="function"?a(r):r;n!==t&&(s.classList.remove(...Q.ALL_STATES),s.classList.add(t),e.setProperty("_state",t)),l!==i&&(e.setProperty("_direction",i),X.run(()=>X.setVars(s,{[le.DIRECTION]:i.toString()})))}onFrame(e){super.onFrame(e),this.initialized||(this.initialized=!0,this.initializeSliders());for(let[t,r]of this.transitions){let i=e.time.now-r.startTime,s=Math.min(1,i/r.enteringDuration),n=Math.min(1,i/r.leavingDuration);this.applyProgress(t,s,n,r.direction),s>=1&&n>=1&&this.transitions.delete(t)}}};ce.ALL_STATES=Object.values(K);var q=class N extends V{constructor(e){super(e),this.htmlKey="form"}initializeObject(e,t,r,i){super.initializeObject(e,t,r,i);let s=t.getProperty("form-events")??[];s.forEach(h=>{h.eventElement.removeEventListener(h.eventType,h.eventCallback)}),s.length=0,t.setProperty("form-events",s),super.onObjectConnected(t);let n=t.htmlElement,l=[],a={};this.getInteractiveFields(n).forEach((h,u)=>this.registerField(h,n,l,a,s,u));let c=h=>{h.preventDefault();let u=!0,v={},m=new Set;for(let S of l){let y=S.field;if(!y.isConnected||!this.shouldValidateField(y))continue;if(this.isRadioField(y)){if(m.has(S.key))continue;m.add(S.key)}let{key:g,rules:b,needsContext:d}=S,f=this.getFieldValue(y);v[g]=f,a[g]=f;let{valid:p,errors:x}=this.tools.validation.process({rules:b,value:f,context:this.buildContext(d,g,a)});this.applyValidationState(n,y,g,p,x,"submit"),p||(u=!1)}if(u)this.events.emit(`form:submit:${t.id}`,v);else{let S=new Set,y=l.find(g=>{let b=g.field;if(!b.isConnected||!this.shouldValidateField(b))return!1;if(this.isRadioField(b)){if(S.has(g.key))return!1;S.add(g.key)}let{key:d,rules:f,needsContext:p}=g,x=this.getFieldValue(b);a[d]=x;let{valid:w}=this.tools.validation.process({rules:f,value:x,context:this.buildContext(p,d,a)});return!w});y?.field&&typeof y.field.focus=="function"&&y.field.focus(),this.events.emit(`form:invalid:${t.id}`)}};n.addEventListener("submit",c),s.push({eventElement:n,eventType:"submit",eventCallback:c}),t.setProperty("form-field-entries",l),t.setProperty("form-field-values",a)}onObjectConnected(e){}onDOMMutate(e,t){this.objects.length!==0&&(e.length>0&&this.handleMutationAdditions(e),t.length>0&&this.handleMutationRemovals(t))}applyValidationState(e,t,r,i,s,n){let l=e.querySelector(`[string-input="error[${r}]"]`),a=e.querySelector(`[string-input="group[${r}]"]`);l&&(l.innerHTML="",s.forEach(h=>{let u=document.createElement("span");u.textContent=h,l.appendChild(u)})),n==="live"?(t.classList.toggle("-invalid",!i),t.classList.remove("-error")):(t.classList.remove("-invalid"),t.classList.toggle("-error",!i)),t.classList.toggle("-valid",i),a&&(n==="live"?(a.classList.toggle("-invalid",!i),a.classList.remove("-error")):(a.classList.remove("-invalid"),a.classList.toggle("-error",!i)),a.classList.toggle("-valid",i));let c=i?"valid":n==="live"?"invalid":"error";this.events.emit(`form:field:${c}:${r}`,{key:r,field:t,errors:s,phase:n,valid:i})}getInteractiveFields(e){return Array.from(e.querySelectorAll("[string-input]")).filter(t=>!this.isServiceFieldAttribute(t.getAttribute("string-input")||"")).filter(t=>this.isFormFieldElement(t)).map(t=>t)}getFieldRules(e){let t=this.tools.domAttribute.process({element:e,key:"input"})??"";return this.tools.ruleParser.process({value:t})}registerField(e,t,r,i,s,n){if(!this.isFormFieldElement(e)||e.closest("form")!==t||r.some(y=>y.field===e))return;let l=this.registerFieldIndex(e,n??r.length),a=this.getInputKey(e,l),c=this.getFieldRules(e),h=this.supportsBeforeInputValidation(c),u=this.requiresContext(c),v=this.getInputEventType(e),m={field:e,key:a,rules:c,supportsRealtime:h,needsContext:u,inputEventType:v,inputHandler:()=>{}},S=y=>{let g=y.currentTarget||y.target;if(!g||!g.isConnected||!this.shouldValidateField(g))return;let b=this.getFieldValue(g);i[m.key]=b;let d=this.buildContext(m.needsContext,m.key,i),{valid:f,errors:p}=this.tools.validation.process({rules:m.rules,value:b,context:d});this.applyValidationState(t,g,m.key,f,p,"live")};if(m.inputHandler=S,e.addEventListener(v,S),s.push({eventElement:e,eventType:v,eventCallback:S}),h&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)){let y=g=>{let b=g;if(b.isComposing||b.inputType?.startsWith("insertComposition"))return;let d=g.currentTarget||g.target;if(!d||!(d instanceof HTMLInputElement||d instanceof HTMLTextAreaElement)||!d.isConnected)return;let f=d.selectionStart??0,p=d.selectionEnd??0,x=d.value;switch(b.inputType){case"deleteContentBackward":x=f===p&&f>0?d.value.slice(0,f-1)+d.value.slice(p):d.value.slice(0,f)+d.value.slice(p);break;case"deleteContentForward":x=f===p&&f<d.value.length?d.value.slice(0,f)+d.value.slice(f+1):d.value.slice(0,f)+d.value.slice(p);break;case"insertFromPaste":case"insertFromDrop":case"insertReplacementText":x=d.value.slice(0,f)+(b.data||"")+d.value.slice(p);break;default:typeof b.data=="string"&&(x=d.value.slice(0,f)+b.data+d.value.slice(p))}let{errors:w}=this.tools.validation.process({rules:m.rules,value:x,type:"beforeinput",context:this.buildContext(m.needsContext,m.key,i,{applied:!0,value:x})});w.length>0&&g.cancelable&&g.preventDefault()};m.beforeInputHandler=y,e.addEventListener("beforeinput",y),s.push({eventElement:e,eventType:"beforeinput",eventCallback:y})}e.classList.add("-inited"),r.push(m),i[a]=this.getFieldValue(e)}unregisterField(e,t,r,i){let s=t.findIndex(l=>l.field===e);if(s===-1)return;let n=t[s];n.inputHandler&&e.removeEventListener(n.inputEventType,n.inputHandler),n.beforeInputHandler&&e.removeEventListener("beforeinput",n.beforeInputHandler),delete r[n.key],t.splice(s,1);for(let l=i.length-1;l>=0;l--){let a=i[l];a.eventElement===e&&(a.eventCallback===n.inputHandler||n.beforeInputHandler&&a.eventCallback===n.beforeInputHandler)&&i.splice(l,1)}e.classList.remove("-inited")}collectInteractiveFieldsFromNode(e){let t=[];return e instanceof Element?(e.hasAttribute("string-input")&&t.push(e),t.push(...Array.from(e.querySelectorAll("[string-input]")))):e instanceof DocumentFragment&&t.push(...Array.from(e.querySelectorAll("[string-input]"))),t.filter(r=>!this.isServiceFieldAttribute(r.getAttribute("string-input")||"")).filter(r=>this.isFormFieldElement(r))}isRadioField(e){return e instanceof HTMLInputElement&&e.type==="radio"}handleMutationAdditions(e){e.forEach(t=>{this.collectInteractiveFieldsFromNode(t).forEach(r=>{let i=this.getFormStateByContainment(r);i&&this.registerField(r,i.form,i.entries,i.values,i.events)})})}handleMutationRemovals(e){e.forEach(t=>{this.collectInteractiveFieldsFromNode(t).forEach(r=>{let i=this.getFormStateByReference(r);i&&this.unregisterField(r,i.entries,i.values,i.events)})})}getFormStateByContainment(e){let t=this.objects.find(r=>r.htmlElement instanceof HTMLFormElement&&r.htmlElement.contains(e));return t?this.buildFormState(t):null}getFormStateByReference(e){for(let t of this.objects){let r=t.getProperty("form-field-entries");if(r&&r.some(i=>i.field===e))return this.buildFormState(t,r)}return null}buildFormState(e,t){let r=e.htmlElement;if(!(r instanceof HTMLFormElement))return null;let i=t??e.getProperty("form-field-entries"),s=e.getProperty("form-field-values"),n=e.getProperty("form-events");return!i||!s||!n?null:{object:e,form:r,entries:i,values:s,events:n}}registerFieldIndex(e,t){let r=e.getAttribute("data-string-form-index");return r!==null?Number(r):(e.setAttribute("data-string-form-index",String(t)),t)}getFieldIndex(e,t){let r=e.getAttribute("data-string-form-index");if(r!==null){let i=Number(r);return Number.isNaN(i)?t:i}return this.registerFieldIndex(e,t)}shouldValidateField(e){return!(e.disabled||e instanceof HTMLInputElement&&e.type==="hidden")}supportsBeforeInputValidation(e){return e.some(t=>N.beforeInputRuleKeys.has(t.key))}requiresContext(e){return e.some(t=>N.crossFieldRuleKeys.has(t.key))}buildContext(e,t,r,i){if(!e)return{fieldKey:t};let s=!!i?.applied,n=s?{...r,[t]:i.value}:r;return{fieldKey:t,values:n,getValue:l=>s&&l===t?i.value:n[l]}}getInputKey(e,t){return this.tools.domAttribute.process({element:e,key:"id"})||e.getAttribute("name")||e.getAttribute("id")||`input-${t}`}getFieldValue(e){if(e instanceof HTMLInputElement){if(e.type==="checkbox"){if(e.name){let t=e.form||e.closest("form"),r=t?Array.from(t.querySelectorAll(`input[type="checkbox"][name="${e.name}"]:checked`)):[e];return r.length>1?r.map(i=>i.value):r.length===1?r[0].value:""}return e.checked}if(e.type==="radio"){if(e.name){let t=(e.form||e.closest("form"))?.querySelector(`input[type="radio"][name="${e.name}"]:checked`);return t?t.value:""}return e.checked?e.value:""}return e.type==="file"&&e.files&&e.files.length>0?e.multiple?Array.from(e.files):e.files[0]:e.value}return e instanceof HTMLSelectElement?e.multiple?Array.from(e.selectedOptions).map(t=>t.value):e.value:e instanceof HTMLTextAreaElement?e.value:""}isServiceFieldAttribute(e){return N.serviceAttributePrefixes.some(t=>e.startsWith(`${t}[`))}isFormFieldElement(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement}getInputEventType(e){return e instanceof HTMLSelectElement||e instanceof HTMLInputElement&&(e.type==="checkbox"||e.type==="radio")?"change":"input"}};q.beforeInputRuleKeys=new Set(["number","integer","email","phone","letters","lettersSpaces","lettersNumbers","alpha","alpha_num","alpha_dash","digits","url","pattern"]),q.crossFieldRuleKeys=new Set(["same","different","after","before"]),q.serviceAttributePrefixes=["error","group"];var T=class{constructor(e,t="orthographic",r=50,i=.1,s=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,s):this._camera=e.createPerspectiveCamera(r,1,i,s),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,s=-(t-this._height/2);return this.engine.createVector3(i,s,r)}else{let{width:i,height:s}=this.getFrustumSizeAt(r),n=e/this._width,l=t/this._height,a=(n-.5)*i,c=-(l-.5)*s;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),s=i/t;return this.scaleCache.set(r,s),s}clearScaleCache(){this.scaleCache.clear()}getMode(){return this.mode}};var O=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 M=class{constructor(e,t,r,i,s={}){this._uniforms={};this._children=[];this.id=e,this.type=t,this._object=r,this.engine=i,this._material=s.material,this._geometry=s.geometry,this._texture=s.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 s=i?.material;Array.isArray(s)?s.forEach(n=>n?.dispose?.()):s?.dispose&&s.dispose()})}};var A=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=s=>{if(s){let n=e.getProperty("parentId");n==null?(this._scene.add(s.object),this._rootObjects.push(s)):this._objects.get(n)?.addChild(s),this._objects.set(e.id,s),this._elementMap.set(e.id,r),s.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 M(e.id,"group",r,this.engine);return t(i),i}createLight(e,t,r){let i=e.getProperty("3d-color")||"#ffffff",s=e.getProperty("3d-intensity")??1,n;if(t==="point"){let a=e.getProperty("3d-distance")??1e3,c=e.getProperty("3d-decay")??0;n=this.engine.createPointLight(i,s,a,c)}else t==="directional"?n=this.engine.createDirectionalLight(i,s):n=this.engine.createAmbientLight(i,s);let l=new M(e.id,t+"Light",n,this.engine);return r(l),l}createBox(e,t){let r=this.engine.createBoxGeometry(1,1,1),i=this.createMaterialFromObject(e),s=this.engine.createMesh(r,i),n=new M(e.id,"box",s,this.engine,{geometry:r,material:i});return t(n),n}createSphere(e,t){let r=e.getProperty("3d-segments-width")??32,i=e.getProperty("3d-segments-height")??32,s=this.engine.createSphereGeometry(.5,r,i),n=this.createMaterialFromObject(e),l=this.engine.createMesh(s,n),a=new M(e.id,"sphere",l,this.engine,{geometry:s,material:n});return t(a),a}createPlane(e,t){let r=this.engine.createPlaneGeometry(1,1),i=this.createMaterialFromObject(e),s=this.engine.createMesh(r,i),n=new M(e.id,"plane",s,this.engine,{geometry:r,material:i});return t(n),n}createCylinder(e,t){let r=e.getProperty("3d-segments")??32,i=this.engine.createCylinderGeometry(.5,.5,1,r),s=this.createMaterialFromObject(e),n=this.engine.createMesh(i,s),l=new M(e.id,"cylinder",n,this.engine,{geometry:i,material:s});return t(l),l}createModel(e,t){let r=e.getProperty("3d-model");if(!r)return;let i=e.getProperty("3d-model-loader")||void 0,s=this.resolveModelLoader(i);if(!s){console.warn("[String3D] Model loader not configured");return}let n=e.htmlElement;n&&this.applyModelTextureRemap(s,n);let l=e.getProperty("3d-model-center")??!1;s.load(r,a=>{let c=a?.scene||a?.object||a;if(!c){console.warn("[String3D] Model loader returned empty result");return}if(n&&this.shouldOverrideModelMaterial(n)){let u=this.createMaterialFromElement(n,e);typeof c.traverse=="function"&&c.traverse(v=>{v.isMesh&&(v.material=u)})}l&&this.centerObject(c);let h=new M(e.id,"model",c,this.engine);t(h)},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,s]=r.split(/\[|\]/),n=s||"#ffffff",l=t?.getProperty("3d-opacity")??1,a=t?.getProperty("3d-metalness"),c=t?.getProperty("3d-roughness"),h={color:n,transparent:l<1,opacity:l},u=e?.getAttribute("string-3d-map"),v=e?.getAttribute("string-3d-normalMap"),m=e?.getAttribute("string-3d-roughnessMap"),S=e?.getAttribute("string-3d-metalnessMap"),y=e?.getAttribute("string-3d-aoMap"),g=this.parseFlipY(t,e),b=t?.getProperty("3d-colorSpace")||e?.getAttribute("string-3d-colorSpace")||"";return i!=="standard"&&!!(u||v||m||S||y)&&(i="standard"),i==="standard"?(u&&(h.map=this.loadTexture(u,{flipY:g,colorSpace:b})),v&&(h.normalMap=this.loadTexture(v,{flipY:g})),m&&(h.roughnessMap=this.loadTexture(m,{flipY:g})),S&&(h.metalnessMap=this.loadTexture(S,{flipY:g})),y&&(h.aoMap=this.loadTexture(y,{flipY:g})),typeof a=="number"&&(h.metalness=a),typeof c=="number"&&(h.roughness=c),this.engine.createMeshStandardMaterial(h)):this.engine.createMeshBasicMaterial(h)}loadTexture(e,t={}){let i=this.engine.createTextureLoader().load(e);typeof t.flipY=="boolean"&&(i.flipY=t.flipY);let s=(t.colorSpace||"").toLowerCase().trim();return s&&"colorSpace"in i&&(i.colorSpace=s==="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(/\/?$/,"/"):"",s=t.getAttribute("string-3d-model-textures"),n=null;if(s)try{n=JSON.parse(s)}catch(a){console.warn("[String3D] Invalid model texture mapping JSON:",a)}let l=e?.manager;if(!l||typeof l.setURLModifier!="function"){(n||i)&&console.warn("[String3D] Model loader does not support URL remap.");return}l.setURLModifier(a=>{let c=n&&a in n?n[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 s=e.getBoundingClientRect(),n=s.left+s.width/2,l=s.top+s.height/2,a=getComputedStyle(e),c=parseFloat(a.getPropertyValue("--translate-z")||"0"),h=r.camera.screenToWorld(n,l,c);t.position=h;let u=parseFloat(a.getPropertyValue("--scale"))||1;t.scale=r.engine.createVector3(u,u,u);let v=-r.engine.degToRad(parseFloat(a.getPropertyValue("--rotate-x")||"0")),m=r.engine.degToRad(parseFloat(a.getPropertyValue("--rotate-y")||"0")),S=-r.engine.degToRad(parseFloat(a.getPropertyValue("--rotate-z")||"0"));return t.rotation=r.engine.createEuler(v,m,S,"XYZ"),t.object.updateMatrixWorld(!0),{scale:u}}};var j=class{sync(e,t,r,i){let s=e.getBoundingClientRect(),n=s.left+s.width/2,l=s.top+s.height/2,a=parseFloat(getComputedStyle(e).getPropertyValue("--translate-z")||"0"),c=r.camera.screenToWorld(n,l,a);return t.position=c,null}};var E=class{sync(e,t,r,i){let s=getComputedStyle(e),n=e.offsetWidth,l=e.offsetHeight,a=e.getBoundingClientRect(),c=parseFloat(s.getPropertyValue("--translate-z")||"0"),h=parseFloat(s.getPropertyValue("--scale")||"1"),u=a.left+a.width/2,v=a.top+a.height/2,m=r.camera.screenToWorld(u,v,c);t.position=m;let S=-r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-x")||"0")),y=r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-y")||"0")),g=-r.engine.degToRad(parseFloat(s.getPropertyValue("--rotate-z")||"0"));t.rotation=r.engine.createEuler(S,y,g,"XYZ");let b=n*h,d=l*h,f=parseFloat(s.getPropertyValue("--scale-z")||"1"),p=i?.scale||1,x=t.type,w,C,L;switch(x){case"box":case"sphere":{let P=Math.min(b,d);w=P*p,C=P*p,L=P*f*p;break}case"model":{let _=t.getOriginalBoundingBox().getSize(r.engine.createVector3()),Z=(e.getAttribute("string-3d-model-fit")||"contain").toLowerCase().trim(),Y=parseFloat(e.getAttribute("string-3d-model-scale")||"1"),k=Number.isFinite(Y)?Y:1;if(_.x>0&&_.y>0){let I=b/_.x,G=d/_.y,$=Z==="cover"?Math.max(I,G):Math.min(I,G);w=$*k*p,C=$*k*p,L=$*k*f*p}else{let I=Math.min(b,d);w=I*k*p,C=I*k*p,L=I*k*f*p}break}case"cylinder":{let P=b;w=P*p,C=d*p,L=P*f*p;break}case"plane":default:w=b*p,C=d*p,L=Math.min(b,d)*.5*f*p;break}return t.scale=r.engine.createVector3(w,C,L),{scale:h*p}}};var R=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 E),this.strategies.set("sphere",new E),this.strategies.set("plane",new E),this.strategies.set("cylinder",new E),this.strategies.set("model",new E),this.strategies.set("group",new H),this.strategies.set("pointLight",new j),this.strategies.set("ambientLight",new j),this.strategies.set("directionalLight",new j)}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 D=class D extends V{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){D.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,s){super.initializeObject(t,r,i,s),r.setProperty("parentId",null);let n=i.parentElement?.closest('[string-3d="group"]');if(n){let l=n.getAttribute("string-id");l&&(r.setProperty("parentId",l),r.setProperty("parent",n))}}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(),!D.provider){console.error("[String3D] No provider set. Call String3D.setProvider() before use.");return}this.engine=D.provider.getEngine(),this.canvasContainer=this.createOrGetContainer(),this.injectCSS(),this.renderer=new O(this.canvasContainer,this.engine),this.renderer.attach(),this.camera=new T(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 A(this.engine,{modelLoader:t,modelLoaderFactory:r}),this.scene.getScene().add(this.camera.camera),this.synchronizer=new R(this.camera,this.renderer.width,this.renderer.height,this.engine),console.info(`[String3D] Initialized with: ${D.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||(U.measure(()=>{this.scene.rootObjects.forEach(r=>{this.syncRecursive(r.el,r,{scale:1})})}),U.mutate(()=>{this.renderer.render(this.scene,this.camera)}))}syncRecursive(t,r,i){if(!this.synchronizer||!t)return;let s=this.synchronizer.syncElement(t,r,i);r.children.forEach(n=>this.syncRecursive(n.el,n,s))}injectCSS(){if(document.getElementById("string-3d-styles"))return;let t=document.createElement("style");t.id="string-3d-styles",t.textContent=`
|
|
2
2
|
@property --translate-x { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
3
3
|
@property --translate-y { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
4
4
|
@property --translate-z { syntax: "<number>"; inherits: false; initial-value: 0; }
|
|
@@ -25,5 +25,5 @@
|
|
|
25
25
|
rotateZ(calc(var(--rotate-z) * 1deg))
|
|
26
26
|
scale3d(calc(var(--scale) * var(--scale-x)), calc(var(--scale) * var(--scale-y)), calc(var(--scale) * var(--scale-z)));
|
|
27
27
|
}
|
|
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()}};
|
|
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()}};D.provider=null;var z=D;var F=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,s=.1,n=1e4){return new this.THREE.OrthographicCamera(e,t,r,i,s,n)}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 s=i.geometry.boundingBox;if(s){let n=s.clone().applyMatrix4(i.matrixWorld);t.union(n),r=!0}}}),r?t:new this.THREE.Box3}},B=class{constructor(e,t={}){this.engine=new F(e,t)}getEngine(){return this.engine}getName(){return"Three.js"}};return se(he);})();
|
|
29
29
|
//# sourceMappingURL=index.js.map
|