@hypertools/sdk 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -402,10 +402,185 @@ controls.refresh();
402
402
  controls.dispose();
403
403
  ```
404
404
 
405
+ ## Using Exported HyperTools Experiences
406
+
407
+ When you export a project from [HyperTools](https://hypertools.dev), you get a standalone web component that can be embedded anywhere. Use `ExperienceController` from this SDK to control it programmatically.
408
+
409
+ ### Setup
410
+
411
+ 1. **Get your exported experience** - Export from HyperTools to get a JS file (e.g., `my-experience.js`)
412
+
413
+ 2. **Load the experience** in your HTML:
414
+ ```html
415
+ <script src="./my-experience.js"></script>
416
+ <my-experience></my-experience>
417
+ ```
418
+
419
+ 3. **Install the SDK** to control it:
420
+ ```bash
421
+ npm install @hypertools/sdk
422
+ ```
423
+
424
+ ### Basic Control
425
+
426
+ ```typescript
427
+ import { ExperienceController } from '@hypertools/sdk';
428
+
429
+ // Get reference to the web component
430
+ const element = document.querySelector('my-experience');
431
+
432
+ // Connect the controller
433
+ const controller = new ExperienceController({
434
+ element,
435
+ initialParams: {
436
+ speed: 5,
437
+ color: '#ff0000',
438
+ },
439
+ });
440
+
441
+ // Control parameters
442
+ controller.setParam('speed', 10);
443
+ controller.setParams({ speed: 8, color: '#00ff00' });
444
+
445
+ // Get current values
446
+ const params = controller.getParams();
447
+ const paramDefs = controller.getParamDefs();
448
+
449
+ // Reset to defaults
450
+ controller.resetParams();
451
+
452
+ // Listen to changes
453
+ controller.on('paramChange', (event) => {
454
+ console.log(`${event.key} changed to ${event.value}`);
455
+ });
456
+
457
+ // Cleanup when done
458
+ controller.destroy();
459
+ ```
460
+
461
+ ### Dispatching Events
462
+
463
+ Trigger interactions programmatically by dispatching synthetic events:
464
+
465
+ ```typescript
466
+ // Simulate a click
467
+ controller.dispatchToCanvas('click', { clientX: 400, clientY: 300 });
468
+
469
+ // Simulate a long press (e.g., for formation triggers)
470
+ controller.dispatchToCanvas('mousedown', { clientX: 400, clientY: 300 });
471
+ setTimeout(() => {
472
+ controller.dispatchToCanvas('mouseup', { clientX: 400, clientY: 300 });
473
+ }, 600);
474
+
475
+ // Keyboard events
476
+ controller.dispatchToCanvas('keydown', { key: 'Space' });
477
+
478
+ // Custom events
479
+ controller.dispatchCustomEvent('myEvent', { data: 'hello' });
480
+ ```
481
+
482
+ ### React Integration
483
+
484
+ ```tsx
485
+ import { useEffect, useRef, useState } from 'react';
486
+ import { ExperienceController } from '@hypertools/sdk';
487
+ import type { ExportedExperienceElement } from '@hypertools/sdk';
488
+
489
+ function App() {
490
+ const experienceRef = useRef<ExportedExperienceElement>(null);
491
+ const controllerRef = useRef<ExperienceController | null>(null);
492
+ const [isReady, setIsReady] = useState(false);
493
+
494
+ useEffect(() => {
495
+ const element = experienceRef.current;
496
+ if (!element) return;
497
+
498
+ const onReady = () => {
499
+ controllerRef.current = new ExperienceController({ element });
500
+ setIsReady(true);
501
+ };
502
+
503
+ element.addEventListener('ready', onReady, { once: true });
504
+
505
+ return () => {
506
+ element.removeEventListener('ready', onReady);
507
+ controllerRef.current?.destroy();
508
+ };
509
+ }, []);
510
+
511
+ return (
512
+ <div>
513
+ {/* @ts-expect-error - Custom element */}
514
+ <my-experience ref={experienceRef} />
515
+
516
+ {isReady && (
517
+ <button onClick={() => controllerRef.current?.setParam('speed', 10)}>
518
+ Speed Up
519
+ </button>
520
+ )}
521
+ </div>
522
+ );
523
+ }
524
+ ```
525
+
526
+ ### ExperienceController API
527
+
528
+ ```typescript
529
+ // Constructor options
530
+ interface ExperienceControllerConfig {
531
+ element: ExportedExperienceElement; // The web component
532
+ initialParams?: Record<string, unknown>; // Override initial values
533
+ autoConnect?: boolean; // Connect immediately (default: true)
534
+ }
535
+
536
+ // Methods
537
+ controller.connect(); // Connect to element
538
+ controller.disconnect(); // Disconnect from element
539
+ controller.destroy(); // Full cleanup
540
+
541
+ controller.setParam(key, value);
542
+ controller.setParams(params);
543
+ controller.getParams();
544
+ controller.getParamDefs();
545
+ controller.resetParams();
546
+
547
+ controller.on(event, handler); // Subscribe
548
+ controller.once(event, handler); // Subscribe once
549
+ controller.off(event, handler); // Unsubscribe
550
+
551
+ controller.dispatchToCanvas(eventType, eventInit); // Dispatch to canvas
552
+ controller.dispatchToElement(eventType, eventInit); // Dispatch to element
553
+ controller.dispatchCustomEvent(type, detail); // Custom event
554
+
555
+ controller.getCanvas(); // Get canvas element
556
+ controller.getMount(); // Get mount element
557
+
558
+ // Properties
559
+ controller.element; // The web component
560
+ controller.isConnected; // Connection status
561
+ controller.isDestroyed; // Destroyed status
562
+
563
+ // Static factories
564
+ ExperienceController.fromSelector('my-experience');
565
+ await ExperienceController.whenDefined('my-experience');
566
+ ```
567
+
568
+ ### Building Custom Features
569
+
570
+ See [`examples/react-landing/`](./examples/react-landing/) for a complete example showing how to build custom features on top of exported experiences:
571
+
572
+ - **Preset System** - Pre-configured settings with visual selection
573
+ - **Click-to-Form Mode** - Click anywhere to trigger interactions at that position
574
+ - **Auto-pilot Mode** - Automatically cycle through presets
575
+ - **Idle Screensaver** - Start animations after inactivity
576
+ - **Share Configuration** - Generate shareable URLs with encoded settings
577
+ - **Keyboard Shortcuts** - Custom keyboard controls
578
+
405
579
  ## Examples
406
580
 
407
581
  See the `/examples` directory for complete working examples:
408
582
 
583
+ - `examples/react-landing/` - **React app with exported experience as background + custom features**
409
584
  - `examples/vanilla-canvas/` - Pure Canvas API
410
585
  - `examples/p5js/` - p5.js sketch
411
586
  - `examples/threejs/` - Three.js scene
@@ -100,12 +100,51 @@ export declare class ExperienceController {
100
100
  * Unsubscribe from an event
101
101
  */
102
102
  off<T extends ExperienceEvent>(type: T['type'], handler: EventHandler<T>): void;
103
+ /**
104
+ * Dispatch a synthetic event to the experience's canvas
105
+ * Useful for triggering interactions programmatically (mousedown, click, etc.)
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * // Simulate a click at center
110
+ * controller.dispatchToCanvas('click', { clientX: 500, clientY: 300 });
111
+ *
112
+ * // Simulate long press for formation
113
+ * controller.dispatchToCanvas('mousedown', { clientX: 400, clientY: 300 });
114
+ * setTimeout(() => controller.dispatchToCanvas('mouseup'), 600);
115
+ * ```
116
+ */
117
+ dispatchToCanvas(eventType: string, eventInit?: MouseEventInit | KeyboardEventInit | EventInit): boolean;
118
+ /**
119
+ * Dispatch a synthetic event to the experience element itself
120
+ */
121
+ dispatchToElement(eventType: string, eventInit?: CustomEventInit | EventInit): boolean;
122
+ /**
123
+ * Dispatch a custom event with data to the experience
124
+ */
125
+ dispatchCustomEvent(eventType: string, detail?: unknown): boolean;
126
+ /**
127
+ * Get the canvas element inside the experience (if any)
128
+ */
129
+ getCanvas(): HTMLCanvasElement | null;
130
+ /**
131
+ * Get the mount element inside the experience shadow DOM
132
+ */
133
+ getMount(): HTMLElement | null;
103
134
  /**
104
135
  * Destroy the controller and disconnect from the element
105
136
  */
106
137
  destroy(): void;
107
138
  private _handleReady;
108
139
  private _handleParamChange;
140
+ /**
141
+ * Find canvas element inside the experience's shadow DOM
142
+ */
143
+ private _findCanvas;
144
+ /**
145
+ * Create appropriate event based on type
146
+ */
147
+ private _createEvent;
109
148
  /**
110
149
  * Connect to an experience by CSS selector
111
150
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ExperienceController.d.ts","sourceRoot":"","sources":["../../src/core/ExperienceController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ExperienceController.d.ts","sourceRoot":"","sources":["../../src/core/ExperienceController.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,8 @@
8
8
  * @license MIT
9
9
  * @see https://github.com/hypertools/sdk
10
10
  */
11
- class F{_handlers=new Map;on(x,E){if(!this._handlers.has(x))this._handlers.set(x,new Set);return this._handlers.get(x).add(E),()=>this.off(x,E)}once(x,E){let R=(P)=>{this.off(x,R),E(P)};return this.on(x,R)}off(x,E){let R=this._handlers.get(x);if(R)R.delete(E)}emit(x){let E=this._handlers.get(x.type);if(!E)return;for(let R of E)try{R(x)}catch(P){console.error(`[EventEmitter] Handler error for ${x.type}:`,P)}}removeAllListeners(x){if(x)this._handlers.delete(x);else this._handlers.clear()}listenerCount(x){return this._handlers.get(x)?.size??0}}class S{_definitions;_values;_listeners;_proxy;constructor(x,E){this._definitions=x,this._listeners=new Set,this._values={};for(let[R,P]of Object.entries(x))this._values[R]=P.value;if(E){for(let[R,P]of Object.entries(E))if(R in this._definitions)this._values[R]=this._validate(R,P)}this._proxy=this._createProxy()}_createProxy(){let x=this;return new Proxy(this._values,{get(E,R){return E[R]},set(E,R,P){if(!(R in x._definitions))return console.warn(`[ParamStore] Unknown parameter: ${R}`),!1;let C=x._validate(R,P),D=E[R];if(C!==D)E[R]=C,x._notify(R,C,D);return!0},has(E,R){return R in E},ownKeys(E){return Object.keys(E)},getOwnPropertyDescriptor(E,R){if(R in E)return{enumerable:!0,configurable:!0,value:E[R]};return}})}_validate(x,E){let R=this._definitions[x];if(!R)return E;switch(R.type){case"number":{let P=typeof E==="number"?E:parseFloat(String(E));if(isNaN(P))P=R.value;if(R.min!==void 0)P=Math.max(R.min,P);if(R.max!==void 0)P=Math.min(R.max,P);if(R.step!==void 0)P=Math.round(P/R.step)*R.step;return P}case"color":{let P=String(E);if(/^#[0-9A-Fa-f]{6}$/.test(P))return P;if(/^#[0-9A-Fa-f]{3}$/.test(P))return P;if(/^#[0-9A-Fa-f]{8}$/.test(P))return P;if(/^rgb\(/.test(P))return P;if(/^rgba\(/.test(P))return P;if(/^hsl\(/.test(P))return P;if(/^hsla\(/.test(P))return P;return R.value}case"boolean":if(typeof E==="boolean")return E;if(E==="true"||E==="1")return!0;if(E==="false"||E==="0")return!1;return Boolean(E);case"string":return String(E);case"select":{let P=String(E);return(R.options||[]).some((H)=>typeof H==="object"?H.value===P:H===P)?P:R.value}case"point2d":{if(typeof E==="object"&&E!==null&&"x"in E&&"y"in E)return{x:Number(E.x),y:Number(E.y)};return R.value}case"point3d":{if(typeof E==="object"&&E!==null&&"x"in E&&"y"in E&&"z"in E)return{x:Number(E.x),y:Number(E.y),z:Number(E.z)};return R.value}default:return E}}_notify(x,E,R){for(let P of this._listeners)try{P(x,E,R)}catch(C){console.error("[ParamStore] Listener error:",C)}}getProxy(){return this._proxy}getSnapshot(){return{...this._values}}getDefinitions(){return{...this._definitions}}set(x,E){this._proxy[x]=E}setMultiple(x){for(let[E,R]of Object.entries(x))this._proxy[E]=R}reset(){for(let[x,E]of Object.entries(this._definitions))this._proxy[x]=E.value}subscribe(x){return this._listeners.add(x),()=>this._listeners.delete(x)}addDefinition(x,E){this._definitions[x]=E,this._values[x]=E.value}}class U{_byName=new Map;_byId=new Map;_onRegister=new Set;_onUnregister=new Set;register(x,E,R){if(this._byName.has(x))this.unregister(x);let P=this._generateId(),C={name:x,id:P,object:E,metadata:R};this._byName.set(x,C),this._byId.set(P,C);for(let D of this._onRegister)try{D(x,P,E)}catch(H){console.error("[ObjectRegistry] onRegister callback error:",H)}return P}unregister(x){let E=this._byName.get(x);if(!E)return!1;this._byName.delete(x),this._byId.delete(E.id);for(let R of this._onUnregister)try{R(x)}catch(P){console.error("[ObjectRegistry] onUnregister callback error:",P)}return!0}findByName(x){return this._byName.get(x)?.object}findById(x){return this._byId.get(x)?.object}getInfo(x){return this._byName.get(x)}has(x){return this._byName.has(x)}getNames(){return Array.from(this._byName.keys())}getAll(){let x=new Map;for(let[E,R]of this._byName)x.set(E,R.object);return x}query(x){let E=[];for(let R of this._byName.values())if(x(R))E.push(R);return E}findByType(x){return this.query((E)=>E.metadata?.type===x).map((E)=>E.object)}clear(){let x=Array.from(this._byName.keys());for(let E of x)this.unregister(E)}onRegister(x){return this._onRegister.add(x),()=>this._onRegister.delete(x)}onUnregister(x){return this._onUnregister.add(x),()=>this._onUnregister.delete(x)}get size(){return this._byName.size}_generateId(){return`obj_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}}class K{_isReady=!1;_isPlaying=!1;_isDestroyed=!1;_currentFrame=0;_paramStore;_events;_objects;_mount;_frameRate;_filename="capture";_cleanups=[];_userCleanup;_animationFrameId;_lastFrameTime=0;_resizeObserver;_captureHandler;constructor(x){if(this._mount=x.mount,this._frameRate=x.frameRate??60,x.background)this._mount.style.background=x.background;this._paramStore=new S(x.paramDefs??{},x.initialParams),this._events=new F,this._objects=new U,this._paramStore.subscribe((E,R,P)=>{this._events.emit({type:"paramChange",timestamp:Date.now(),key:E,value:R,previousValue:P})}),this._setupResizeObserver(),this._runSetup(x.setup,x.autoplay??!0)}get isReady(){return this._isReady}get isPlaying(){return this._isPlaying}get isDestroyed(){return this._isDestroyed}get currentFrame(){return this._currentFrame}get mount(){return this._mount}get params(){return this._paramStore.getProxy()}get events(){return this._events}get objects(){return this._objects}setParam(x,E){this._paramStore.set(x,E)}setParams(x){this._paramStore.setMultiple(x)}getParams(){return this._paramStore.getSnapshot()}getParamDefs(){return this._paramStore.getDefinitions()}resetParams(){this._paramStore.reset()}registerObject(x,E,R){return this._objects.register(x,E,R)}findObjectByName(x){return this._objects.findByName(x)}findObjectById(x){return this._objects.findById(x)}getAllObjects(){return this._objects.getAll()}play(){if(this._isPlaying||this._isDestroyed)return;this._isPlaying=!0,this._lastFrameTime=performance.now(),this._tick(),this._events.emit({type:"play",timestamp:Date.now()})}pause(){if(!this._isPlaying)return;if(this._isPlaying=!1,this._animationFrameId)cancelAnimationFrame(this._animationFrameId),this._animationFrameId=void 0;this._events.emit({type:"pause",timestamp:Date.now()})}toggle(){if(this._isPlaying)this.pause();else this.play()}on(x,E){return this._events.on(x,E)}once(x,E){return this._events.once(x,E)}off(x,E){this._events.off(x,E)}async captureImage(x="png"){if(this._captureHandler)return this._captureHandler(x);let E=this._mount.querySelector("canvas");if(!E)return console.warn("[Experience] No canvas found for capture"),null;return new Promise((R)=>{let P=`image/${x}`,C=x==="jpeg"?0.92:void 0;E.toBlob((D)=>R(D),P,C)})}getFilename(){return this._filename}addCleanup(x){if(typeof x==="function")this._cleanups.push(x)}destroy(){if(this._isDestroyed)return;if(this._isDestroyed=!0,this.pause(),this._userCleanup)try{this._userCleanup()}catch(x){console.error("[Experience] User cleanup error:",x)}while(this._cleanups.length>0){let x=this._cleanups.pop();if(x)try{x()}catch(E){console.error("[Experience] Cleanup error:",E)}}this._resizeObserver?.disconnect(),this._objects.clear(),this._events.removeAllListeners(),this._events.emit({type:"destroyed",timestamp:Date.now()})}async _runSetup(x,E){try{let R=this._createContext(),P=await x(R);if(typeof P==="function")this._userCleanup=P;if(this._isReady=!0,this._events.emit({type:"ready",timestamp:Date.now()}),E)this.play()}catch(R){console.error("[Experience] Setup error:",R),this._events.emit({type:"error",timestamp:Date.now(),error:R instanceof Error?R:Error(String(R))})}}_createContext(){return{mount:this._mount,params:this._paramStore.getProxy(),exports:this._createExportsApi(),environment:this._createEnvironmentApi(),registerObject:(x,E,R)=>this._objects.register(x,E,R),findObjectByName:(x)=>this._objects.findByName(x),experience:this}}_createExportsApi(){return{captureImage:(x)=>this.captureImage(x),setFilename:(x)=>{this._filename=x},registerCaptureHandler:(x)=>{this._captureHandler=x}}}_createEnvironmentApi(){return{window,document,onResize:(x)=>{let E=()=>{x(this._mount.clientWidth,this._mount.clientHeight)};E();let R=new ResizeObserver(E);R.observe(this._mount);let P=()=>R.disconnect();return this._cleanups.push(P),P},addCleanup:(x)=>this.addCleanup(x)}}_setupResizeObserver(){this._resizeObserver=new ResizeObserver((x)=>{for(let E of x){let{width:R,height:P}=E.contentRect;this._events.emit({type:"resize",timestamp:Date.now(),width:R,height:P})}}),this._resizeObserver.observe(this._mount)}_tick(){if(!this._isPlaying)return;let x=performance.now(),E=x-this._lastFrameTime,R=1000/this._frameRate;if(E>=R)this._currentFrame++,this._lastFrameTime=x-E%R,this._events.emit({type:"frame",timestamp:Date.now(),frame:this._currentFrame,deltaTime:E});this._animationFrameId=requestAnimationFrame(()=>this._tick())}}class A{_element;_events;_isConnected=!1;_isDestroyed=!1;_boundReadyHandler;_boundParamChangeHandler;constructor(x){let E=x instanceof HTMLElement?{element:x}:x;if(this._element=E.element,this._events=new F,this._boundReadyHandler=this._handleReady.bind(this),this._boundParamChangeHandler=this._handleParamChange.bind(this),E.autoConnect!==!1){if(this.connect(),E.initialParams)this.setParams(E.initialParams)}}connect(){if(this._isConnected||this._isDestroyed)return;this._element.addEventListener("ready",this._boundReadyHandler),this._element.addEventListener("paramchange",this._boundParamChangeHandler),this._isConnected=!0,this._events.emit({type:"connected",timestamp:Date.now()})}disconnect(){if(!this._isConnected)return;this._element.removeEventListener("ready",this._boundReadyHandler),this._element.removeEventListener("paramchange",this._boundParamChangeHandler),this._isConnected=!1,this._events.emit({type:"disconnected",timestamp:Date.now()})}get element(){return this._element}get isConnected(){return this._isConnected}get isDestroyed(){return this._isDestroyed}setParam(x,E){this._element.setParam(x,E)}setParams(x){this._element.setParams(x)}getParams(){return this._element.getParams()}getParamDefs(){return this._element.getParamDefs()}resetParams(){let x=this.getParamDefs(),E={};for(let[R,P]of Object.entries(x))E[R]=P.value;this.setParams(E)}on(x,E){return this._events.on(x,E)}once(x,E){return this._events.once(x,E)}off(x,E){this._events.off(x,E)}destroy(){if(this._isDestroyed)return;this.disconnect(),this._events.removeAllListeners(),this._isDestroyed=!0,this._events.emit({type:"destroyed",timestamp:Date.now()})}_handleReady(x){this._events.emit({type:"ready",timestamp:Date.now()})}_handleParamChange(x){let E=x;this._events.emit({type:"paramChange",timestamp:Date.now(),key:E.detail.key,value:E.detail.value,previousValue:E.detail.previousValue})}static fromSelector(x,E){let R=document.querySelector(x);if(!R)throw Error(`[ExperienceController] Element not found: ${x}`);return new A({element:R,initialParams:E})}static async whenDefined(x,E){await customElements.whenDefined(x);let R=document.querySelector(x);if(!R)R=document.createElement(x);return new A({element:R,initialParams:E})}}export{S as ParamStore,U as ObjectRegistry,A as ExperienceController,K as Experience,F as EventEmitter};
11
+ class F{_handlers=new Map;on(x,E){if(!this._handlers.has(x))this._handlers.set(x,new Set);return this._handlers.get(x).add(E),()=>this.off(x,E)}once(x,E){let P=(C)=>{this.off(x,P),E(C)};return this.on(x,P)}off(x,E){let P=this._handlers.get(x);if(P)P.delete(E)}emit(x){let E=this._handlers.get(x.type);if(!E)return;for(let P of E)try{P(x)}catch(C){console.error(`[EventEmitter] Handler error for ${x.type}:`,C)}}removeAllListeners(x){if(x)this._handlers.delete(x);else this._handlers.clear()}listenerCount(x){return this._handlers.get(x)?.size??0}}class S{_definitions;_values;_listeners;_proxy;constructor(x,E){this._definitions=x,this._listeners=new Set,this._values={};for(let[P,C]of Object.entries(x))this._values[P]=C.value;if(E){for(let[P,C]of Object.entries(E))if(P in this._definitions)this._values[P]=this._validate(P,C)}this._proxy=this._createProxy()}_createProxy(){let x=this;return new Proxy(this._values,{get(E,P){return E[P]},set(E,P,C){if(!(P in x._definitions))return console.warn(`[ParamStore] Unknown parameter: ${P}`),!1;let D=x._validate(P,C),R=E[P];if(D!==R)E[P]=D,x._notify(P,D,R);return!0},has(E,P){return P in E},ownKeys(E){return Object.keys(E)},getOwnPropertyDescriptor(E,P){if(P in E)return{enumerable:!0,configurable:!0,value:E[P]};return}})}_validate(x,E){let P=this._definitions[x];if(!P)return E;switch(P.type){case"number":{let C=typeof E==="number"?E:parseFloat(String(E));if(isNaN(C))C=P.value;if(P.min!==void 0)C=Math.max(P.min,C);if(P.max!==void 0)C=Math.min(P.max,C);if(P.step!==void 0)C=Math.round(C/P.step)*P.step;return C}case"color":{let C=String(E);if(/^#[0-9A-Fa-f]{6}$/.test(C))return C;if(/^#[0-9A-Fa-f]{3}$/.test(C))return C;if(/^#[0-9A-Fa-f]{8}$/.test(C))return C;if(/^rgb\(/.test(C))return C;if(/^rgba\(/.test(C))return C;if(/^hsl\(/.test(C))return C;if(/^hsla\(/.test(C))return C;return P.value}case"boolean":if(typeof E==="boolean")return E;if(E==="true"||E==="1")return!0;if(E==="false"||E==="0")return!1;return Boolean(E);case"string":return String(E);case"select":{let C=String(E);return(P.options||[]).some((H)=>typeof H==="object"?H.value===C:H===C)?C:P.value}case"point2d":{if(typeof E==="object"&&E!==null&&"x"in E&&"y"in E)return{x:Number(E.x),y:Number(E.y)};return P.value}case"point3d":{if(typeof E==="object"&&E!==null&&"x"in E&&"y"in E&&"z"in E)return{x:Number(E.x),y:Number(E.y),z:Number(E.z)};return P.value}default:return E}}_notify(x,E,P){for(let C of this._listeners)try{C(x,E,P)}catch(D){console.error("[ParamStore] Listener error:",D)}}getProxy(){return this._proxy}getSnapshot(){return{...this._values}}getDefinitions(){return{...this._definitions}}set(x,E){this._proxy[x]=E}setMultiple(x){for(let[E,P]of Object.entries(x))this._proxy[E]=P}reset(){for(let[x,E]of Object.entries(this._definitions))this._proxy[x]=E.value}subscribe(x){return this._listeners.add(x),()=>this._listeners.delete(x)}addDefinition(x,E){this._definitions[x]=E,this._values[x]=E.value}}class U{_byName=new Map;_byId=new Map;_onRegister=new Set;_onUnregister=new Set;register(x,E,P){if(this._byName.has(x))this.unregister(x);let C=this._generateId(),D={name:x,id:C,object:E,metadata:P};this._byName.set(x,D),this._byId.set(C,D);for(let R of this._onRegister)try{R(x,C,E)}catch(H){console.error("[ObjectRegistry] onRegister callback error:",H)}return C}unregister(x){let E=this._byName.get(x);if(!E)return!1;this._byName.delete(x),this._byId.delete(E.id);for(let P of this._onUnregister)try{P(x)}catch(C){console.error("[ObjectRegistry] onUnregister callback error:",C)}return!0}findByName(x){return this._byName.get(x)?.object}findById(x){return this._byId.get(x)?.object}getInfo(x){return this._byName.get(x)}has(x){return this._byName.has(x)}getNames(){return Array.from(this._byName.keys())}getAll(){let x=new Map;for(let[E,P]of this._byName)x.set(E,P.object);return x}query(x){let E=[];for(let P of this._byName.values())if(x(P))E.push(P);return E}findByType(x){return this.query((E)=>E.metadata?.type===x).map((E)=>E.object)}clear(){let x=Array.from(this._byName.keys());for(let E of x)this.unregister(E)}onRegister(x){return this._onRegister.add(x),()=>this._onRegister.delete(x)}onUnregister(x){return this._onUnregister.add(x),()=>this._onUnregister.delete(x)}get size(){return this._byName.size}_generateId(){return`obj_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}}class K{_isReady=!1;_isPlaying=!1;_isDestroyed=!1;_currentFrame=0;_paramStore;_events;_objects;_mount;_frameRate;_filename="capture";_cleanups=[];_userCleanup;_animationFrameId;_lastFrameTime=0;_resizeObserver;_captureHandler;constructor(x){if(this._mount=x.mount,this._frameRate=x.frameRate??60,x.background)this._mount.style.background=x.background;this._paramStore=new S(x.paramDefs??{},x.initialParams),this._events=new F,this._objects=new U,this._paramStore.subscribe((E,P,C)=>{this._events.emit({type:"paramChange",timestamp:Date.now(),key:E,value:P,previousValue:C})}),this._setupResizeObserver(),this._runSetup(x.setup,x.autoplay??!0)}get isReady(){return this._isReady}get isPlaying(){return this._isPlaying}get isDestroyed(){return this._isDestroyed}get currentFrame(){return this._currentFrame}get mount(){return this._mount}get params(){return this._paramStore.getProxy()}get events(){return this._events}get objects(){return this._objects}setParam(x,E){this._paramStore.set(x,E)}setParams(x){this._paramStore.setMultiple(x)}getParams(){return this._paramStore.getSnapshot()}getParamDefs(){return this._paramStore.getDefinitions()}resetParams(){this._paramStore.reset()}registerObject(x,E,P){return this._objects.register(x,E,P)}findObjectByName(x){return this._objects.findByName(x)}findObjectById(x){return this._objects.findById(x)}getAllObjects(){return this._objects.getAll()}play(){if(this._isPlaying||this._isDestroyed)return;this._isPlaying=!0,this._lastFrameTime=performance.now(),this._tick(),this._events.emit({type:"play",timestamp:Date.now()})}pause(){if(!this._isPlaying)return;if(this._isPlaying=!1,this._animationFrameId)cancelAnimationFrame(this._animationFrameId),this._animationFrameId=void 0;this._events.emit({type:"pause",timestamp:Date.now()})}toggle(){if(this._isPlaying)this.pause();else this.play()}on(x,E){return this._events.on(x,E)}once(x,E){return this._events.once(x,E)}off(x,E){this._events.off(x,E)}async captureImage(x="png"){if(this._captureHandler)return this._captureHandler(x);let E=this._mount.querySelector("canvas");if(!E)return console.warn("[Experience] No canvas found for capture"),null;return new Promise((P)=>{let C=`image/${x}`,D=x==="jpeg"?0.92:void 0;E.toBlob((R)=>P(R),C,D)})}getFilename(){return this._filename}addCleanup(x){if(typeof x==="function")this._cleanups.push(x)}destroy(){if(this._isDestroyed)return;if(this._isDestroyed=!0,this.pause(),this._userCleanup)try{this._userCleanup()}catch(x){console.error("[Experience] User cleanup error:",x)}while(this._cleanups.length>0){let x=this._cleanups.pop();if(x)try{x()}catch(E){console.error("[Experience] Cleanup error:",E)}}this._resizeObserver?.disconnect(),this._objects.clear(),this._events.removeAllListeners(),this._events.emit({type:"destroyed",timestamp:Date.now()})}async _runSetup(x,E){try{let P=this._createContext(),C=await x(P);if(typeof C==="function")this._userCleanup=C;if(this._isReady=!0,this._events.emit({type:"ready",timestamp:Date.now()}),E)this.play()}catch(P){console.error("[Experience] Setup error:",P),this._events.emit({type:"error",timestamp:Date.now(),error:P instanceof Error?P:Error(String(P))})}}_createContext(){return{mount:this._mount,params:this._paramStore.getProxy(),exports:this._createExportsApi(),environment:this._createEnvironmentApi(),registerObject:(x,E,P)=>this._objects.register(x,E,P),findObjectByName:(x)=>this._objects.findByName(x),experience:this}}_createExportsApi(){return{captureImage:(x)=>this.captureImage(x),setFilename:(x)=>{this._filename=x},registerCaptureHandler:(x)=>{this._captureHandler=x}}}_createEnvironmentApi(){return{window,document,onResize:(x)=>{let E=()=>{x(this._mount.clientWidth,this._mount.clientHeight)};E();let P=new ResizeObserver(E);P.observe(this._mount);let C=()=>P.disconnect();return this._cleanups.push(C),C},addCleanup:(x)=>this.addCleanup(x)}}_setupResizeObserver(){this._resizeObserver=new ResizeObserver((x)=>{for(let E of x){let{width:P,height:C}=E.contentRect;this._events.emit({type:"resize",timestamp:Date.now(),width:P,height:C})}}),this._resizeObserver.observe(this._mount)}_tick(){if(!this._isPlaying)return;let x=performance.now(),E=x-this._lastFrameTime,P=1000/this._frameRate;if(E>=P)this._currentFrame++,this._lastFrameTime=x-E%P,this._events.emit({type:"frame",timestamp:Date.now(),frame:this._currentFrame,deltaTime:E});this._animationFrameId=requestAnimationFrame(()=>this._tick())}}class A{_element;_events;_isConnected=!1;_isDestroyed=!1;_boundReadyHandler;_boundParamChangeHandler;constructor(x){let E=x instanceof HTMLElement?{element:x}:x;if(this._element=E.element,this._events=new F,this._boundReadyHandler=this._handleReady.bind(this),this._boundParamChangeHandler=this._handleParamChange.bind(this),E.autoConnect!==!1){if(this.connect(),E.initialParams)this.setParams(E.initialParams)}}connect(){if(this._isConnected||this._isDestroyed)return;this._element.addEventListener("ready",this._boundReadyHandler),this._element.addEventListener("paramchange",this._boundParamChangeHandler),this._isConnected=!0,this._events.emit({type:"connected",timestamp:Date.now()})}disconnect(){if(!this._isConnected)return;this._element.removeEventListener("ready",this._boundReadyHandler),this._element.removeEventListener("paramchange",this._boundParamChangeHandler),this._isConnected=!1,this._events.emit({type:"disconnected",timestamp:Date.now()})}get element(){return this._element}get isConnected(){return this._isConnected}get isDestroyed(){return this._isDestroyed}setParam(x,E){this._element.setParam(x,E)}setParams(x){this._element.setParams(x)}getParams(){return this._element.getParams()}getParamDefs(){return this._element.getParamDefs()}resetParams(){let x=this.getParamDefs(),E={};for(let[P,C]of Object.entries(x))E[P]=C.value;this.setParams(E)}on(x,E){return this._events.on(x,E)}once(x,E){return this._events.once(x,E)}off(x,E){this._events.off(x,E)}dispatchToCanvas(x,E){let P=this._findCanvas();if(!P)return console.warn("[ExperienceController] No canvas found in experience"),!1;let C=this._createEvent(x,E);return P.dispatchEvent(C)}dispatchToElement(x,E){let P=this._createEvent(x,E);return this._element.dispatchEvent(P)}dispatchCustomEvent(x,E){let P=new CustomEvent(x,{detail:E,bubbles:!0,cancelable:!0});return this._element.dispatchEvent(P)}getCanvas(){return this._findCanvas()}getMount(){return this._element.shadowRoot?.querySelector(".mount")}destroy(){if(this._isDestroyed)return;this.disconnect(),this._events.removeAllListeners(),this._isDestroyed=!0,this._events.emit({type:"destroyed",timestamp:Date.now()})}_handleReady(x){this._events.emit({type:"ready",timestamp:Date.now()})}_handleParamChange(x){let E=x;this._events.emit({type:"paramChange",timestamp:Date.now(),key:E.detail.key,value:E.detail.value,previousValue:E.detail.previousValue})}_findCanvas(){let x=this._element.shadowRoot;if(x){let E=x.querySelector("canvas");if(E)return E}return this._element.querySelector("canvas")}_createEvent(x,E){let P={bubbles:!0,cancelable:!0,...E};if(x.startsWith("mouse")||x==="click"||x==="dblclick")return new MouseEvent(x,P);if(x.startsWith("key"))return new KeyboardEvent(x,P);if(x.startsWith("pointer"))return new PointerEvent(x,P);if(x.startsWith("touch"))return new TouchEvent(x,P);if(x==="wheel")return new WheelEvent(x,P);if("detail"in(E||{}))return new CustomEvent(x,P);return new Event(x,P)}static fromSelector(x,E){let P=document.querySelector(x);if(!P)throw Error(`[ExperienceController] Element not found: ${x}`);return new A({element:P,initialParams:E})}static async whenDefined(x,E){await customElements.whenDefined(x);let P=document.querySelector(x);if(!P)P=document.createElement(x);return new A({element:P,initialParams:E})}}export{S as ParamStore,U as ObjectRegistry,A as ExperienceController,K as Experience,F as EventEmitter};
12
12
 
13
13
  /* @hypertools/sdk - MIT License - https://hypertools.dev */
14
14
 
15
- //# debugId=9F2CC592AD55E80264756E2164756E21
15
+ //# debugId=AF04FBCAE7C8AF9064756E2164756E21
@@ -6,9 +6,9 @@
6
6
  "/**\n * Reactive parameter store with Proxy-based reactivity\n */\n\nexport type ParamType =\n | 'number'\n | 'color'\n | 'boolean'\n | 'string'\n | 'select'\n | 'file'\n | 'point2d'\n | 'point3d';\n\nexport interface SelectOption {\n label: string;\n value: string;\n}\n\nexport interface ParamDefinition {\n type: ParamType;\n value: unknown;\n label?: string;\n\n // Number constraints\n min?: number;\n max?: number;\n step?: number;\n\n // Select options\n options?: (string | SelectOption)[];\n\n // File constraints\n accept?: string;\n maxSize?: number;\n}\n\nexport type ParamDefinitions = Record<string, ParamDefinition>;\nexport type ParamValues = Record<string, unknown>;\n\nexport type ParamChangeCallback = (\n key: string,\n value: unknown,\n previousValue: unknown\n) => void;\n\nexport class ParamStore {\n private _definitions: ParamDefinitions;\n private _values: ParamValues;\n private _listeners: Set<ParamChangeCallback>;\n private _proxy: ParamValues;\n\n constructor(definitions: ParamDefinitions, initialOverrides?: ParamValues) {\n this._definitions = definitions;\n this._listeners = new Set();\n\n // Initialize from definitions\n this._values = {};\n for (const [key, def] of Object.entries(definitions)) {\n this._values[key] = def.value;\n }\n\n // Apply overrides\n if (initialOverrides) {\n for (const [key, value] of Object.entries(initialOverrides)) {\n if (key in this._definitions) {\n this._values[key] = this._validate(key, value);\n }\n }\n }\n\n // Create reactive proxy\n this._proxy = this._createProxy();\n }\n\n private _createProxy(): ParamValues {\n const self = this;\n return new Proxy(this._values, {\n get(target, prop: string) {\n return target[prop];\n },\n set(target, prop: string, value: unknown) {\n if (!(prop in self._definitions)) {\n console.warn(`[ParamStore] Unknown parameter: ${prop}`);\n return false;\n }\n\n const validated = self._validate(prop, value);\n const previous = target[prop];\n\n if (validated !== previous) {\n target[prop] = validated;\n self._notify(prop, validated, previous);\n }\n\n return true;\n },\n has(target, prop: string) {\n return prop in target;\n },\n ownKeys(target) {\n return Object.keys(target);\n },\n getOwnPropertyDescriptor(target, prop: string) {\n if (prop in target) {\n return {\n enumerable: true,\n configurable: true,\n value: target[prop],\n };\n }\n return undefined;\n },\n });\n }\n\n private _validate(key: string, value: unknown): unknown {\n const def = this._definitions[key];\n if (!def) return value;\n\n switch (def.type) {\n case 'number': {\n let num = typeof value === 'number' ? value : parseFloat(String(value));\n if (isNaN(num)) num = def.value as number;\n if (def.min !== undefined) num = Math.max(def.min, num);\n if (def.max !== undefined) num = Math.min(def.max, num);\n if (def.step !== undefined) {\n num = Math.round(num / def.step) * def.step;\n }\n return num;\n }\n\n case 'color': {\n const str = String(value);\n // Accept various color formats\n if (/^#[0-9A-Fa-f]{6}$/.test(str)) return str;\n if (/^#[0-9A-Fa-f]{3}$/.test(str)) return str;\n if (/^#[0-9A-Fa-f]{8}$/.test(str)) return str; // RGBA\n if (/^rgb\\(/.test(str)) return str;\n if (/^rgba\\(/.test(str)) return str;\n if (/^hsl\\(/.test(str)) return str;\n if (/^hsla\\(/.test(str)) return str;\n return def.value;\n }\n\n case 'boolean':\n if (typeof value === 'boolean') return value;\n if (value === 'true' || value === '1') return true;\n if (value === 'false' || value === '0') return false;\n return Boolean(value);\n\n case 'string':\n return String(value);\n\n case 'select': {\n const str = String(value);\n const options = def.options || [];\n const valid = options.some((opt) =>\n typeof opt === 'object' ? opt.value === str : opt === str\n );\n return valid ? str : def.value;\n }\n\n case 'point2d': {\n if (\n typeof value === 'object' &&\n value !== null &&\n 'x' in value &&\n 'y' in value\n ) {\n return { x: Number((value as any).x), y: Number((value as any).y) };\n }\n return def.value;\n }\n\n case 'point3d': {\n if (\n typeof value === 'object' &&\n value !== null &&\n 'x' in value &&\n 'y' in value &&\n 'z' in value\n ) {\n return {\n x: Number((value as any).x),\n y: Number((value as any).y),\n z: Number((value as any).z),\n };\n }\n return def.value;\n }\n\n default:\n return value;\n }\n }\n\n private _notify(key: string, value: unknown, previous: unknown): void {\n for (const listener of this._listeners) {\n try {\n listener(key, value, previous);\n } catch (error) {\n console.error('[ParamStore] Listener error:', error);\n }\n }\n }\n\n /**\n * Get reactive params proxy\n */\n getProxy(): ParamValues {\n return this._proxy;\n }\n\n /**\n * Get snapshot of current values (non-reactive copy)\n */\n getSnapshot(): ParamValues {\n return { ...this._values };\n }\n\n /**\n * Get definitions\n */\n getDefinitions(): ParamDefinitions {\n return { ...this._definitions };\n }\n\n /**\n * Set single value\n */\n set(key: string, value: unknown): void {\n this._proxy[key] = value;\n }\n\n /**\n * Set multiple values\n */\n setMultiple(params: ParamValues): void {\n for (const [key, value] of Object.entries(params)) {\n this._proxy[key] = value;\n }\n }\n\n /**\n * Reset to defaults\n */\n reset(): void {\n for (const [key, def] of Object.entries(this._definitions)) {\n this._proxy[key] = def.value;\n }\n }\n\n /**\n * Subscribe to changes\n * @returns Unsubscribe function\n */\n subscribe(callback: ParamChangeCallback): () => void {\n this._listeners.add(callback);\n return () => this._listeners.delete(callback);\n }\n\n /**\n * Add a new param definition dynamically\n */\n addDefinition(key: string, definition: ParamDefinition): void {\n this._definitions[key] = definition;\n this._values[key] = definition.value;\n }\n}\n",
7
7
  "/**\n * Spline-like object registry for querying objects by name/id\n */\n\nexport interface RegisteredObject<T = unknown> {\n name: string;\n id: string;\n object: T;\n metadata?: Record<string, unknown>;\n}\n\nexport type ObjectRegisteredCallback = (name: string, id: string, object: unknown) => void;\nexport type ObjectUnregisteredCallback = (name: string) => void;\n\nexport class ObjectRegistry {\n private _byName = new Map<string, RegisteredObject>();\n private _byId = new Map<string, RegisteredObject>();\n private _onRegister: Set<ObjectRegisteredCallback> = new Set();\n private _onUnregister: Set<ObjectUnregisteredCallback> = new Set();\n\n /**\n * Register an object for external access\n * @returns Generated ID for the object\n */\n register<T>(\n name: string,\n object: T,\n metadata?: Record<string, unknown>\n ): string {\n // If name already exists, unregister first\n if (this._byName.has(name)) {\n this.unregister(name);\n }\n\n const id = this._generateId();\n\n const registered: RegisteredObject<T> = {\n name,\n id,\n object,\n metadata,\n };\n\n this._byName.set(name, registered);\n this._byId.set(id, registered);\n\n // Notify listeners\n for (const callback of this._onRegister) {\n try {\n callback(name, id, object);\n } catch (e) {\n console.error('[ObjectRegistry] onRegister callback error:', e);\n }\n }\n\n return id;\n }\n\n /**\n * Unregister an object by name\n */\n unregister(name: string): boolean {\n const obj = this._byName.get(name);\n if (!obj) return false;\n\n this._byName.delete(name);\n this._byId.delete(obj.id);\n\n // Notify listeners\n for (const callback of this._onUnregister) {\n try {\n callback(name);\n } catch (e) {\n console.error('[ObjectRegistry] onUnregister callback error:', e);\n }\n }\n\n return true;\n }\n\n /**\n * Find object by name (Spline-like API)\n */\n findByName<T = unknown>(name: string): T | undefined {\n return this._byName.get(name)?.object as T | undefined;\n }\n\n /**\n * Find object by ID\n */\n findById<T = unknown>(id: string): T | undefined {\n return this._byId.get(id)?.object as T | undefined;\n }\n\n /**\n * Get registered object info by name\n */\n getInfo(name: string): RegisteredObject | undefined {\n return this._byName.get(name);\n }\n\n /**\n * Check if an object exists\n */\n has(name: string): boolean {\n return this._byName.has(name);\n }\n\n /**\n * Get all registered object names\n */\n getNames(): string[] {\n return Array.from(this._byName.keys());\n }\n\n /**\n * Get all registered objects as a Map\n */\n getAll(): Map<string, unknown> {\n const result = new Map<string, unknown>();\n for (const [name, registered] of this._byName) {\n result.set(name, registered.object);\n }\n return result;\n }\n\n /**\n * Query objects by metadata\n */\n query(predicate: (obj: RegisteredObject) => boolean): RegisteredObject[] {\n const results: RegisteredObject[] = [];\n for (const obj of this._byName.values()) {\n if (predicate(obj)) {\n results.push(obj);\n }\n }\n return results;\n }\n\n /**\n * Query objects by type (requires metadata.type to be set)\n */\n findByType<T = unknown>(type: string): T[] {\n return this.query((obj) => obj.metadata?.type === type).map(\n (obj) => obj.object as T\n );\n }\n\n /**\n * Clear all registered objects\n */\n clear(): void {\n const names = Array.from(this._byName.keys());\n for (const name of names) {\n this.unregister(name);\n }\n }\n\n /**\n * Subscribe to object registration events\n */\n onRegister(callback: ObjectRegisteredCallback): () => void {\n this._onRegister.add(callback);\n return () => this._onRegister.delete(callback);\n }\n\n /**\n * Subscribe to object unregistration events\n */\n onUnregister(callback: ObjectUnregisteredCallback): () => void {\n this._onUnregister.add(callback);\n return () => this._onUnregister.delete(callback);\n }\n\n /**\n * Get the number of registered objects\n */\n get size(): number {\n return this._byName.size;\n }\n\n private _generateId(): string {\n return `obj_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n }\n}\n",
8
8
  "/**\n * Core Experience class - THE shared logic for all runtimes\n *\n * This is the brain. All adapters (Frame, Export, HostedPreview) use this.\n * Adapters are thin wiring layers - Experience contains ALL the logic.\n */\n\nimport {\n EventEmitter,\n type ExperienceEvent,\n type EventHandler,\n type ParamChangeEvent,\n type FrameEvent,\n type ResizeEvent,\n type ErrorEvent,\n} from './EventEmitter';\nimport { ParamStore, type ParamDefinitions, type ParamValues } from './ParamStore';\nimport { ObjectRegistry } from './ObjectRegistry';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ExperienceConfig {\n /** Mount element where content is rendered */\n mount: HTMLElement;\n\n /** Parameter definitions schema */\n paramDefs?: ParamDefinitions;\n\n /** Initial parameter values (overrides defaults from paramDefs) */\n initialParams?: Record<string, unknown>;\n\n /** User's setup function */\n setup: SetupFunction;\n\n /** Auto-start on init (default: true) */\n autoplay?: boolean;\n\n /** Target frame rate for frame events (default: 60) */\n frameRate?: number;\n\n /** Background color/style */\n background?: string;\n}\n\n/**\n * Context passed to user's setup function\n * This is the API users interact with in their code\n */\nexport interface ExperienceContext {\n /** DOM element to render into */\n mount: HTMLElement;\n\n /** Reactive params object (Proxy) - changes trigger events */\n params: ParamValues;\n\n /** Export/capture utilities */\n exports: ExportsApi;\n\n /** Environment utilities (window, document, resize) */\n environment: EnvironmentApi;\n\n /** Register an object for Spline-like queries */\n registerObject: <T = unknown>(\n name: string,\n object: T,\n metadata?: Record<string, unknown>\n ) => string;\n\n /** Find registered object by name */\n findObjectByName: <T = unknown>(name: string) => T | undefined;\n\n /** Experience instance (for advanced use) */\n experience: Experience;\n}\n\nexport interface ExportsApi {\n /** Capture canvas as image */\n captureImage: (format?: 'png' | 'jpeg' | 'webp') => Promise<Blob | null>;\n\n /** Set filename for exports */\n setFilename: (filename: string) => void;\n\n /** Register custom capture handler */\n registerCaptureHandler: (handler: CaptureHandler) => void;\n}\n\nexport type CaptureHandler = (format: string) => Promise<Blob | null>;\n\nexport interface EnvironmentApi {\n /** Window reference */\n window: Window;\n\n /** Document reference */\n document: Document;\n\n /** Subscribe to resize events, returns cleanup */\n onResize: (callback: (width: number, height: number) => void) => () => void;\n\n /** Add cleanup function to be called on destroy */\n addCleanup: (cleanup: () => void) => void;\n}\n\nexport type SetupFunction = (\n context: ExperienceContext\n) => CleanupFunction | void | Promise<CleanupFunction | void>;\n\nexport type CleanupFunction = () => void;\n\n// ============================================================================\n// Experience Class\n// ============================================================================\n\nexport class Experience {\n // State\n private _isReady = false;\n private _isPlaying = false;\n private _isDestroyed = false;\n private _currentFrame = 0;\n\n // Core systems\n private _paramStore: ParamStore;\n private _events: EventEmitter;\n private _objects: ObjectRegistry;\n\n // Config\n private _mount: HTMLElement;\n private _frameRate: number;\n private _filename = 'capture';\n\n // Lifecycle\n private _cleanups: CleanupFunction[] = [];\n private _userCleanup?: CleanupFunction;\n private _animationFrameId?: number;\n private _lastFrameTime = 0;\n private _resizeObserver?: ResizeObserver;\n private _captureHandler?: CaptureHandler;\n\n constructor(config: ExperienceConfig) {\n this._mount = config.mount;\n this._frameRate = config.frameRate ?? 60;\n\n // Apply background if provided\n if (config.background) {\n this._mount.style.background = config.background;\n }\n\n // Initialize core systems\n this._paramStore = new ParamStore(\n config.paramDefs ?? {},\n config.initialParams\n );\n this._events = new EventEmitter();\n this._objects = new ObjectRegistry();\n\n // Subscribe to param changes -> emit events\n this._paramStore.subscribe((key, value, previousValue) => {\n this._events.emit<ParamChangeEvent>({\n type: 'paramChange',\n timestamp: Date.now(),\n key,\n value,\n previousValue,\n });\n });\n\n // Setup resize observer\n this._setupResizeObserver();\n\n // Run user setup\n this._runSetup(config.setup, config.autoplay ?? true);\n }\n\n // ===== Public Getters =====\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isPlaying(): boolean {\n return this._isPlaying;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n get currentFrame(): number {\n return this._currentFrame;\n }\n\n get mount(): HTMLElement {\n return this._mount;\n }\n\n /** Reactive params proxy */\n get params(): ParamValues {\n return this._paramStore.getProxy();\n }\n\n /** EventEmitter for external subscriptions */\n get events(): EventEmitter {\n return this._events;\n }\n\n /** ObjectRegistry for external access */\n get objects(): ObjectRegistry {\n return this._objects;\n }\n\n // ===== Parameter Methods =====\n\n setParam(key: string, value: unknown): void {\n this._paramStore.set(key, value);\n }\n\n setParams(params: Record<string, unknown>): void {\n this._paramStore.setMultiple(params);\n }\n\n getParams(): Record<string, unknown> {\n return this._paramStore.getSnapshot();\n }\n\n getParamDefs(): ParamDefinitions {\n return this._paramStore.getDefinitions();\n }\n\n resetParams(): void {\n this._paramStore.reset();\n }\n\n // ===== Object Registry (Spline-like) =====\n\n registerObject<T = unknown>(\n name: string,\n object: T,\n metadata?: Record<string, unknown>\n ): string {\n return this._objects.register(name, object, metadata);\n }\n\n findObjectByName<T = unknown>(name: string): T | undefined {\n return this._objects.findByName<T>(name);\n }\n\n findObjectById<T = unknown>(id: string): T | undefined {\n return this._objects.findById<T>(id);\n }\n\n getAllObjects(): Map<string, unknown> {\n return this._objects.getAll();\n }\n\n // ===== Playback =====\n\n play(): void {\n if (this._isPlaying || this._isDestroyed) return;\n this._isPlaying = true;\n this._lastFrameTime = performance.now();\n this._tick();\n this._events.emit({ type: 'play', timestamp: Date.now() });\n }\n\n pause(): void {\n if (!this._isPlaying) return;\n this._isPlaying = false;\n if (this._animationFrameId) {\n cancelAnimationFrame(this._animationFrameId);\n this._animationFrameId = undefined;\n }\n this._events.emit({ type: 'pause', timestamp: Date.now() });\n }\n\n toggle(): void {\n if (this._isPlaying) {\n this.pause();\n } else {\n this.play();\n }\n }\n\n // ===== Events =====\n\n on<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.on(type, handler);\n }\n\n once<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.once(type, handler);\n }\n\n off<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): void {\n this._events.off(type, handler);\n }\n\n // ===== Capture =====\n\n async captureImage(format: 'png' | 'jpeg' | 'webp' = 'png'): Promise<Blob | null> {\n // Use custom handler if registered\n if (this._captureHandler) {\n return this._captureHandler(format);\n }\n\n // Default: find canvas and capture\n const canvas = this._mount.querySelector('canvas');\n if (!canvas) {\n console.warn('[Experience] No canvas found for capture');\n return null;\n }\n\n return new Promise((resolve) => {\n const mimeType = `image/${format}`;\n const quality = format === 'jpeg' ? 0.92 : undefined;\n canvas.toBlob((blob) => resolve(blob), mimeType, quality);\n });\n }\n\n getFilename(): string {\n return this._filename;\n }\n\n // ===== Lifecycle =====\n\n /**\n * Add a cleanup function to be called on destroy\n */\n addCleanup(cleanup: CleanupFunction): void {\n if (typeof cleanup === 'function') {\n this._cleanups.push(cleanup);\n }\n }\n\n /**\n * Destroy the experience and run all cleanups\n */\n destroy(): void {\n if (this._isDestroyed) return;\n this._isDestroyed = true;\n\n // Stop animation\n this.pause();\n\n // Run user cleanup first\n if (this._userCleanup) {\n try {\n this._userCleanup();\n } catch (e) {\n console.error('[Experience] User cleanup error:', e);\n }\n }\n\n // Run registered cleanups (reverse order)\n while (this._cleanups.length > 0) {\n const cleanup = this._cleanups.pop();\n if (cleanup) {\n try {\n cleanup();\n } catch (e) {\n console.error('[Experience] Cleanup error:', e);\n }\n }\n }\n\n // Disconnect observers\n this._resizeObserver?.disconnect();\n\n // Clear registry\n this._objects.clear();\n\n // Remove all event listeners\n this._events.removeAllListeners();\n\n // Emit destroyed event before clearing\n this._events.emit({ type: 'destroyed', timestamp: Date.now() });\n }\n\n // ===== Private Methods =====\n\n private async _runSetup(setup: SetupFunction, autoplay: boolean): Promise<void> {\n try {\n // Create context for user's setup\n const context = this._createContext();\n\n // Run user's setup\n const cleanup = await setup(context);\n if (typeof cleanup === 'function') {\n this._userCleanup = cleanup;\n }\n\n this._isReady = true;\n this._events.emit({ type: 'ready', timestamp: Date.now() });\n\n // Autoplay if enabled\n if (autoplay) {\n this.play();\n }\n } catch (error) {\n console.error('[Experience] Setup error:', error);\n this._events.emit<ErrorEvent>({\n type: 'error',\n timestamp: Date.now(),\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n private _createContext(): ExperienceContext {\n return {\n mount: this._mount,\n params: this._paramStore.getProxy(),\n exports: this._createExportsApi(),\n environment: this._createEnvironmentApi(),\n registerObject: (name, object, metadata) =>\n this._objects.register(name, object, metadata),\n findObjectByName: (name) => this._objects.findByName(name),\n experience: this,\n };\n }\n\n private _createExportsApi(): ExportsApi {\n return {\n captureImage: (format) => this.captureImage(format),\n setFilename: (filename) => {\n this._filename = filename;\n },\n registerCaptureHandler: (handler) => {\n this._captureHandler = handler;\n },\n };\n }\n\n private _createEnvironmentApi(): EnvironmentApi {\n return {\n window,\n document,\n onResize: (callback) => {\n const handler = () => {\n callback(this._mount.clientWidth, this._mount.clientHeight);\n };\n\n // Call immediately with current size\n handler();\n\n // Setup observer\n const ro = new ResizeObserver(handler);\n ro.observe(this._mount);\n\n const cleanup = () => ro.disconnect();\n this._cleanups.push(cleanup);\n return cleanup;\n },\n addCleanup: (cleanup) => this.addCleanup(cleanup),\n };\n }\n\n private _setupResizeObserver(): void {\n this._resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n this._events.emit<ResizeEvent>({\n type: 'resize',\n timestamp: Date.now(),\n width,\n height,\n });\n }\n });\n this._resizeObserver.observe(this._mount);\n }\n\n private _tick(): void {\n if (!this._isPlaying) return;\n\n const now = performance.now();\n const deltaTime = now - this._lastFrameTime;\n const targetInterval = 1000 / this._frameRate;\n\n if (deltaTime >= targetInterval) {\n this._currentFrame++;\n this._lastFrameTime = now - (deltaTime % targetInterval);\n\n this._events.emit<FrameEvent>({\n type: 'frame',\n timestamp: Date.now(),\n frame: this._currentFrame,\n deltaTime,\n });\n }\n\n this._animationFrameId = requestAnimationFrame(() => this._tick());\n }\n}\n",
9
- "/**\n * ExperienceController - Control exported HyperTools experiences programmatically\n *\n * Use this to connect to and control exported web components from the SDK.\n * The exported experience has its initial state packaged, but you can\n * override params, listen to events, and control it via this API.\n *\n * @example\n * ```typescript\n * import { ExperienceController } from '@hypertools/sdk';\n *\n * // Get the exported web component\n * const element = document.querySelector('my-experience');\n *\n * // Connect SDK controller\n * const controller = new ExperienceController(element);\n *\n * // Control programmatically\n * controller.setParam('speed', 5);\n * controller.on('paramchange', (e) => console.log(e.detail));\n *\n * // Later, disconnect\n * controller.destroy();\n * ```\n */\n\nimport { EventEmitter, type ExperienceEvent, type EventHandler, type ParamChangeEvent } from './EventEmitter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Interface for exported HyperTools web components\n */\nexport interface ExportedExperienceElement extends HTMLElement {\n setParam(key: string, value: unknown): void;\n setParams(params: Record<string, unknown>): void;\n getParams(): Record<string, unknown>;\n getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }>;\n}\n\nexport interface ExperienceControllerConfig {\n /** The exported web component element */\n element: ExportedExperienceElement;\n\n /** Initial param overrides (applied on connect) */\n initialParams?: Record<string, unknown>;\n\n /** Auto-connect on creation (default: true) */\n autoConnect?: boolean;\n}\n\n// ============================================================================\n// ExperienceController Class\n// ============================================================================\n\nexport class ExperienceController {\n private _element: ExportedExperienceElement;\n private _events: EventEmitter;\n private _isConnected = false;\n private _isDestroyed = false;\n\n // Event listeners we attach to the element\n private _boundReadyHandler: (e: Event) => void;\n private _boundParamChangeHandler: (e: Event) => void;\n\n constructor(elementOrConfig: ExportedExperienceElement | ExperienceControllerConfig) {\n // Handle both direct element and config object\n const config: ExperienceControllerConfig =\n elementOrConfig instanceof HTMLElement\n ? { element: elementOrConfig }\n : elementOrConfig;\n\n this._element = config.element;\n this._events = new EventEmitter();\n\n // Bind event handlers\n this._boundReadyHandler = this._handleReady.bind(this);\n this._boundParamChangeHandler = this._handleParamChange.bind(this);\n\n // Auto-connect unless disabled\n if (config.autoConnect !== false) {\n this.connect();\n\n // Apply initial params if provided\n if (config.initialParams) {\n this.setParams(config.initialParams);\n }\n }\n }\n\n // ===== Connection =====\n\n /**\n * Connect to the web component and start listening to events\n */\n connect(): void {\n if (this._isConnected || this._isDestroyed) return;\n\n this._element.addEventListener('ready', this._boundReadyHandler);\n this._element.addEventListener('paramchange', this._boundParamChangeHandler);\n\n this._isConnected = true;\n\n // Emit connected event\n this._events.emit({ type: 'connected', timestamp: Date.now() });\n }\n\n /**\n * Disconnect from the web component\n */\n disconnect(): void {\n if (!this._isConnected) return;\n\n this._element.removeEventListener('ready', this._boundReadyHandler);\n this._element.removeEventListener('paramchange', this._boundParamChangeHandler);\n\n this._isConnected = false;\n\n this._events.emit({ type: 'disconnected', timestamp: Date.now() });\n }\n\n // ===== Getters =====\n\n get element(): ExportedExperienceElement {\n return this._element;\n }\n\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ===== Parameter Methods =====\n\n /**\n * Set a single parameter\n */\n setParam(key: string, value: unknown): void {\n this._element.setParam(key, value);\n }\n\n /**\n * Set multiple parameters at once\n */\n setParams(params: Record<string, unknown>): void {\n this._element.setParams(params);\n }\n\n /**\n * Get current parameter values\n */\n getParams(): Record<string, unknown> {\n return this._element.getParams();\n }\n\n /**\n * Get parameter definitions (types, ranges, etc.)\n */\n getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }> {\n return this._element.getParamDefs();\n }\n\n /**\n * Reset parameters to their default values\n */\n resetParams(): void {\n const defs = this.getParamDefs();\n const defaults: Record<string, unknown> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n defaults[key] = def.value;\n }\n\n this.setParams(defaults);\n }\n\n // ===== Events =====\n\n /**\n * Subscribe to an event\n */\n on<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.on(type, handler);\n }\n\n /**\n * Subscribe to an event once\n */\n once<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.once(type, handler);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): void {\n this._events.off(type, handler);\n }\n\n // ===== Lifecycle =====\n\n /**\n * Destroy the controller and disconnect from the element\n */\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.disconnect();\n this._events.removeAllListeners();\n this._isDestroyed = true;\n\n this._events.emit({ type: 'destroyed', timestamp: Date.now() });\n }\n\n // ===== Private Event Handlers =====\n\n private _handleReady(_e: Event): void {\n this._events.emit({ type: 'ready', timestamp: Date.now() });\n }\n\n private _handleParamChange(e: Event): void {\n const customEvent = e as CustomEvent<{\n key: string;\n value: unknown;\n previousValue: unknown;\n }>;\n\n this._events.emit<ParamChangeEvent>({\n type: 'paramChange',\n timestamp: Date.now(),\n key: customEvent.detail.key,\n value: customEvent.detail.value,\n previousValue: customEvent.detail.previousValue,\n });\n }\n\n // ===== Static Factory Methods =====\n\n /**\n * Connect to an experience by CSS selector\n */\n static fromSelector(selector: string, initialParams?: Record<string, unknown>): ExperienceController {\n const element = document.querySelector(selector) as ExportedExperienceElement;\n if (!element) {\n throw new Error(`[ExperienceController] Element not found: ${selector}`);\n }\n return new ExperienceController({ element, initialParams });\n }\n\n /**\n * Wait for element to be defined, then connect\n */\n static async whenDefined(\n tagName: string,\n initialParams?: Record<string, unknown>\n ): Promise<ExperienceController> {\n // Wait for custom element to be defined\n await customElements.whenDefined(tagName);\n\n // Find or create the element\n let element = document.querySelector(tagName) as ExportedExperienceElement;\n if (!element) {\n element = document.createElement(tagName) as ExportedExperienceElement;\n }\n\n return new ExperienceController({ element, initialParams });\n }\n}\n"
9
+ "/**\n * ExperienceController - Control exported HyperTools experiences programmatically\n *\n * Use this to connect to and control exported web components from the SDK.\n * The exported experience has its initial state packaged, but you can\n * override params, listen to events, and control it via this API.\n *\n * @example\n * ```typescript\n * import { ExperienceController } from '@hypertools/sdk';\n *\n * // Get the exported web component\n * const element = document.querySelector('my-experience');\n *\n * // Connect SDK controller\n * const controller = new ExperienceController(element);\n *\n * // Control programmatically\n * controller.setParam('speed', 5);\n * controller.on('paramchange', (e) => console.log(e.detail));\n *\n * // Later, disconnect\n * controller.destroy();\n * ```\n */\n\nimport { EventEmitter, type ExperienceEvent, type EventHandler, type ParamChangeEvent } from './EventEmitter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Interface for exported HyperTools web components\n */\nexport interface ExportedExperienceElement extends HTMLElement {\n setParam(key: string, value: unknown): void;\n setParams(params: Record<string, unknown>): void;\n getParams(): Record<string, unknown>;\n getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }>;\n}\n\nexport interface ExperienceControllerConfig {\n /** The exported web component element */\n element: ExportedExperienceElement;\n\n /** Initial param overrides (applied on connect) */\n initialParams?: Record<string, unknown>;\n\n /** Auto-connect on creation (default: true) */\n autoConnect?: boolean;\n}\n\n// ============================================================================\n// ExperienceController Class\n// ============================================================================\n\nexport class ExperienceController {\n private _element: ExportedExperienceElement;\n private _events: EventEmitter;\n private _isConnected = false;\n private _isDestroyed = false;\n\n // Event listeners we attach to the element\n private _boundReadyHandler: (e: Event) => void;\n private _boundParamChangeHandler: (e: Event) => void;\n\n constructor(elementOrConfig: ExportedExperienceElement | ExperienceControllerConfig) {\n // Handle both direct element and config object\n const config: ExperienceControllerConfig =\n elementOrConfig instanceof HTMLElement\n ? { element: elementOrConfig }\n : elementOrConfig;\n\n this._element = config.element;\n this._events = new EventEmitter();\n\n // Bind event handlers\n this._boundReadyHandler = this._handleReady.bind(this);\n this._boundParamChangeHandler = this._handleParamChange.bind(this);\n\n // Auto-connect unless disabled\n if (config.autoConnect !== false) {\n this.connect();\n\n // Apply initial params if provided\n if (config.initialParams) {\n this.setParams(config.initialParams);\n }\n }\n }\n\n // ===== Connection =====\n\n /**\n * Connect to the web component and start listening to events\n */\n connect(): void {\n if (this._isConnected || this._isDestroyed) return;\n\n this._element.addEventListener('ready', this._boundReadyHandler);\n this._element.addEventListener('paramchange', this._boundParamChangeHandler);\n\n this._isConnected = true;\n\n // Emit connected event\n this._events.emit({ type: 'connected', timestamp: Date.now() });\n }\n\n /**\n * Disconnect from the web component\n */\n disconnect(): void {\n if (!this._isConnected) return;\n\n this._element.removeEventListener('ready', this._boundReadyHandler);\n this._element.removeEventListener('paramchange', this._boundParamChangeHandler);\n\n this._isConnected = false;\n\n this._events.emit({ type: 'disconnected', timestamp: Date.now() });\n }\n\n // ===== Getters =====\n\n get element(): ExportedExperienceElement {\n return this._element;\n }\n\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ===== Parameter Methods =====\n\n /**\n * Set a single parameter\n */\n setParam(key: string, value: unknown): void {\n this._element.setParam(key, value);\n }\n\n /**\n * Set multiple parameters at once\n */\n setParams(params: Record<string, unknown>): void {\n this._element.setParams(params);\n }\n\n /**\n * Get current parameter values\n */\n getParams(): Record<string, unknown> {\n return this._element.getParams();\n }\n\n /**\n * Get parameter definitions (types, ranges, etc.)\n */\n getParamDefs(): Record<string, { type: string; value: unknown; [key: string]: unknown }> {\n return this._element.getParamDefs();\n }\n\n /**\n * Reset parameters to their default values\n */\n resetParams(): void {\n const defs = this.getParamDefs();\n const defaults: Record<string, unknown> = {};\n\n for (const [key, def] of Object.entries(defs)) {\n defaults[key] = def.value;\n }\n\n this.setParams(defaults);\n }\n\n // ===== Events =====\n\n /**\n * Subscribe to an event\n */\n on<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.on(type, handler);\n }\n\n /**\n * Subscribe to an event once\n */\n once<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): () => void {\n return this._events.once(type, handler);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<T extends ExperienceEvent>(\n type: T['type'],\n handler: EventHandler<T>\n ): void {\n this._events.off(type, handler);\n }\n\n // ===== Event Dispatching =====\n\n /**\n * Dispatch a synthetic event to the experience's canvas\n * Useful for triggering interactions programmatically (mousedown, click, etc.)\n *\n * @example\n * ```typescript\n * // Simulate a click at center\n * controller.dispatchToCanvas('click', { clientX: 500, clientY: 300 });\n *\n * // Simulate long press for formation\n * controller.dispatchToCanvas('mousedown', { clientX: 400, clientY: 300 });\n * setTimeout(() => controller.dispatchToCanvas('mouseup'), 600);\n * ```\n */\n dispatchToCanvas(\n eventType: string,\n eventInit?: MouseEventInit | KeyboardEventInit | EventInit\n ): boolean {\n const canvas = this._findCanvas();\n if (!canvas) {\n console.warn('[ExperienceController] No canvas found in experience');\n return false;\n }\n\n const event = this._createEvent(eventType, eventInit);\n return canvas.dispatchEvent(event);\n }\n\n /**\n * Dispatch a synthetic event to the experience element itself\n */\n dispatchToElement(\n eventType: string,\n eventInit?: CustomEventInit | EventInit\n ): boolean {\n const event = this._createEvent(eventType, eventInit);\n return this._element.dispatchEvent(event);\n }\n\n /**\n * Dispatch a custom event with data to the experience\n */\n dispatchCustomEvent(eventType: string, detail?: unknown): boolean {\n const event = new CustomEvent(eventType, {\n detail,\n bubbles: true,\n cancelable: true,\n });\n return this._element.dispatchEvent(event);\n }\n\n /**\n * Get the canvas element inside the experience (if any)\n */\n getCanvas(): HTMLCanvasElement | null {\n return this._findCanvas();\n }\n\n /**\n * Get the mount element inside the experience shadow DOM\n */\n getMount(): HTMLElement | null {\n return this._element.shadowRoot?.querySelector('.mount') as HTMLElement | null;\n }\n\n // ===== Lifecycle =====\n\n /**\n * Destroy the controller and disconnect from the element\n */\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.disconnect();\n this._events.removeAllListeners();\n this._isDestroyed = true;\n\n this._events.emit({ type: 'destroyed', timestamp: Date.now() });\n }\n\n // ===== Private Event Handlers =====\n\n private _handleReady(_e: Event): void {\n this._events.emit({ type: 'ready', timestamp: Date.now() });\n }\n\n private _handleParamChange(e: Event): void {\n const customEvent = e as CustomEvent<{\n key: string;\n value: unknown;\n previousValue: unknown;\n }>;\n\n this._events.emit<ParamChangeEvent>({\n type: 'paramChange',\n timestamp: Date.now(),\n key: customEvent.detail.key,\n value: customEvent.detail.value,\n previousValue: customEvent.detail.previousValue,\n });\n }\n\n /**\n * Find canvas element inside the experience's shadow DOM\n */\n private _findCanvas(): HTMLCanvasElement | null {\n // Try shadow DOM first\n const shadowRoot = this._element.shadowRoot;\n if (shadowRoot) {\n const canvas = shadowRoot.querySelector('canvas');\n if (canvas) return canvas;\n }\n // Fallback to direct child\n return this._element.querySelector('canvas');\n }\n\n /**\n * Create appropriate event based on type\n */\n private _createEvent(\n eventType: string,\n eventInit?: MouseEventInit | KeyboardEventInit | CustomEventInit | EventInit\n ): Event {\n const baseInit = { bubbles: true, cancelable: true, ...eventInit };\n\n // Mouse events\n if (eventType.startsWith('mouse') || eventType === 'click' || eventType === 'dblclick') {\n return new MouseEvent(eventType, baseInit as MouseEventInit);\n }\n\n // Keyboard events\n if (eventType.startsWith('key')) {\n return new KeyboardEvent(eventType, baseInit as KeyboardEventInit);\n }\n\n // Pointer events\n if (eventType.startsWith('pointer')) {\n return new PointerEvent(eventType, baseInit as PointerEventInit);\n }\n\n // Touch events (basic support)\n if (eventType.startsWith('touch')) {\n return new TouchEvent(eventType, baseInit as TouchEventInit);\n }\n\n // Wheel events\n if (eventType === 'wheel') {\n return new WheelEvent(eventType, baseInit as WheelEventInit);\n }\n\n // Custom events (if detail is provided)\n if ('detail' in (eventInit || {})) {\n return new CustomEvent(eventType, baseInit as CustomEventInit);\n }\n\n // Generic event\n return new Event(eventType, baseInit);\n }\n\n // ===== Static Factory Methods =====\n\n /**\n * Connect to an experience by CSS selector\n */\n static fromSelector(selector: string, initialParams?: Record<string, unknown>): ExperienceController {\n const element = document.querySelector(selector) as ExportedExperienceElement;\n if (!element) {\n throw new Error(`[ExperienceController] Element not found: ${selector}`);\n }\n return new ExperienceController({ element, initialParams });\n }\n\n /**\n * Wait for element to be defined, then connect\n */\n static async whenDefined(\n tagName: string,\n initialParams?: Record<string, unknown>\n ): Promise<ExperienceController> {\n // Wait for custom element to be defined\n await customElements.whenDefined(tagName);\n\n // Find or create the element\n let element = document.querySelector(tagName) as ExportedExperienceElement;\n if (!element) {\n element = document.createElement(tagName) as ExportedExperienceElement;\n }\n\n return new ExperienceController({ element, initialParams });\n }\n}\n"
10
10
  ],
11
- "mappings": "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",
12
- "debugId": "9F2CC592AD55E80264756E2164756E21",
11
+ "mappings": ";;;;;;;;;;AAwEO,MAAM,CAAa,CAChB,UAAY,IAAI,IAMxB,EAA6B,CAC3B,EACA,EACY,CACZ,GAAI,CAAC,KAAK,UAAU,IAAI,CAAI,EAC1B,KAAK,UAAU,IAAI,EAAM,IAAI,GAAK,EAKpC,OAHA,KAAK,UAAU,IAAI,CAAI,EAAG,IAAI,CAAuB,EAG9C,IAAM,KAAK,IAAI,EAAM,CAAO,EAMrC,IAA+B,CAC7B,EACA,EACY,CACZ,IAAM,EAA2B,CAAC,IAAU,CAC1C,KAAK,IAAI,EAAM,CAAO,EACtB,EAAQ,CAAK,GAEf,OAAO,KAAK,GAAG,EAAM,CAAO,EAM9B,GAA8B,CAC5B,EACA,EACM,CACN,IAAM,EAAW,KAAK,UAAU,IAAI,CAAI,EACxC,GAAI,EACF,EAAS,OAAO,CAAuB,EAO3C,IAA+B,CAAC,EAAgB,CAC9C,IAAM,EAAW,KAAK,UAAU,IAAI,EAAM,IAAI,EAC9C,GAAI,CAAC,EAAU,OAEf,QAAW,KAAW,EACpB,GAAI,CACF,EAAQ,CAAK,EACb,MAAO,EAAO,CACd,QAAQ,MAAM,oCAAoC,EAAM,QAAS,CAAK,GAQ5E,kBAAkB,CAAC,EAAkC,CACnD,GAAI,EACF,KAAK,UAAU,OAAO,CAAI,EAE1B,UAAK,UAAU,MAAM,EAOzB,aAAa,CAAC,EAAmC,CAC/C,OAAO,KAAK,UAAU,IAAI,CAAI,GAAG,MAAQ,EAE7C,CC1GO,MAAM,CAAW,CACd,aACA,QACA,WACA,OAER,WAAW,CAAC,EAA+B,EAAgC,CACzE,KAAK,aAAe,EACpB,KAAK,WAAa,IAAI,IAGtB,KAAK,QAAU,CAAC,EAChB,QAAY,EAAK,KAAQ,OAAO,QAAQ,CAAW,EACjD,KAAK,QAAQ,GAAO,EAAI,MAI1B,GAAI,GACF,QAAY,EAAK,KAAU,OAAO,QAAQ,CAAgB,EACxD,GAAI,KAAO,KAAK,aACd,KAAK,QAAQ,GAAO,KAAK,UAAU,EAAK,CAAK,EAMnD,KAAK,OAAS,KAAK,aAAa,EAG1B,YAAY,EAAgB,CAClC,IAAM,EAAO,KACb,OAAO,IAAI,MAAM,KAAK,QAAS,CAC7B,GAAG,CAAC,EAAQ,EAAc,CACxB,OAAO,EAAO,IAEhB,GAAG,CAAC,EAAQ,EAAc,EAAgB,CACxC,GAAI,EAAE,KAAQ,EAAK,cAEjB,OADA,QAAQ,KAAK,mCAAmC,GAAM,EAC/C,GAGT,IAAM,EAAY,EAAK,UAAU,EAAM,CAAK,EACtC,EAAW,EAAO,GAExB,GAAI,IAAc,EAChB,EAAO,GAAQ,EACf,EAAK,QAAQ,EAAM,EAAW,CAAQ,EAGxC,MAAO,IAET,GAAG,CAAC,EAAQ,EAAc,CACxB,OAAO,KAAQ,GAEjB,OAAO,CAAC,EAAQ,CACd,OAAO,OAAO,KAAK,CAAM,GAE3B,wBAAwB,CAAC,EAAQ,EAAc,CAC7C,GAAI,KAAQ,EACV,MAAO,CACL,WAAY,GACZ,aAAc,GACd,MAAO,EAAO,EAChB,EAEF,OAEJ,CAAC,EAGK,SAAS,CAAC,EAAa,EAAyB,CACtD,IAAM,EAAM,KAAK,aAAa,GAC9B,GAAI,CAAC,EAAK,OAAO,EAEjB,OAAQ,EAAI,UACL,SAAU,CACb,IAAI,EAAM,OAAO,IAAU,SAAW,EAAQ,WAAW,OAAO,CAAK,CAAC,EACtE,GAAI,MAAM,CAAG,EAAG,EAAM,EAAI,MAC1B,GAAI,EAAI,MAAQ,OAAW,EAAM,KAAK,IAAI,EAAI,IAAK,CAAG,EACtD,GAAI,EAAI,MAAQ,OAAW,EAAM,KAAK,IAAI,EAAI,IAAK,CAAG,EACtD,GAAI,EAAI,OAAS,OACf,EAAM,KAAK,MAAM,EAAM,EAAI,IAAI,EAAI,EAAI,KAEzC,OAAO,CACT,KAEK,QAAS,CACZ,IAAM,EAAM,OAAO,CAAK,EAExB,GAAI,oBAAoB,KAAK,CAAG,EAAG,OAAO,EAC1C,GAAI,oBAAoB,KAAK,CAAG,EAAG,OAAO,EAC1C,GAAI,oBAAoB,KAAK,CAAG,EAAG,OAAO,EAC1C,GAAI,SAAS,KAAK,CAAG,EAAG,OAAO,EAC/B,GAAI,UAAU,KAAK,CAAG,EAAG,OAAO,EAChC,GAAI,SAAS,KAAK,CAAG,EAAG,OAAO,EAC/B,GAAI,UAAU,KAAK,CAAG,EAAG,OAAO,EAChC,OAAO,EAAI,KACb,KAEK,UACH,GAAI,OAAO,IAAU,UAAW,OAAO,EACvC,GAAI,IAAU,QAAU,IAAU,IAAK,MAAO,GAC9C,GAAI,IAAU,SAAW,IAAU,IAAK,MAAO,GAC/C,OAAO,QAAQ,CAAK,MAEjB,SACH,OAAO,OAAO,CAAK,MAEhB,SAAU,CACb,IAAM,EAAM,OAAO,CAAK,EAKxB,OAJgB,EAAI,SAAW,CAAC,GACV,KAAK,CAAC,IAC1B,OAAO,IAAQ,SAAW,EAAI,QAAU,EAAM,IAAQ,CACxD,EACe,EAAM,EAAI,KAC3B,KAEK,UAAW,CACd,GACE,OAAO,IAAU,UACjB,IAAU,MACV,MAAO,GACP,MAAO,EAEP,MAAO,CAAE,EAAG,OAAQ,EAAc,CAAC,EAAG,EAAG,OAAQ,EAAc,CAAC,CAAE,EAEpE,OAAO,EAAI,KACb,KAEK,UAAW,CACd,GACE,OAAO,IAAU,UACjB,IAAU,MACV,MAAO,GACP,MAAO,GACP,MAAO,EAEP,MAAO,CACL,EAAG,OAAQ,EAAc,CAAC,EAC1B,EAAG,OAAQ,EAAc,CAAC,EAC1B,EAAG,OAAQ,EAAc,CAAC,CAC5B,EAEF,OAAO,EAAI,KACb,SAGE,OAAO,GAIL,OAAO,CAAC,EAAa,EAAgB,EAAyB,CACpE,QAAW,KAAY,KAAK,WAC1B,GAAI,CACF,EAAS,EAAK,EAAO,CAAQ,EAC7B,MAAO,EAAO,CACd,QAAQ,MAAM,+BAAgC,CAAK,GAQzD,QAAQ,EAAgB,CACtB,OAAO,KAAK,OAMd,WAAW,EAAgB,CACzB,MAAO,IAAK,KAAK,OAAQ,EAM3B,cAAc,EAAqB,CACjC,MAAO,IAAK,KAAK,YAAa,EAMhC,GAAG,CAAC,EAAa,EAAsB,CACrC,KAAK,OAAO,GAAO,EAMrB,WAAW,CAAC,EAA2B,CACrC,QAAY,EAAK,KAAU,OAAO,QAAQ,CAAM,EAC9C,KAAK,OAAO,GAAO,EAOvB,KAAK,EAAS,CACZ,QAAY,EAAK,KAAQ,OAAO,QAAQ,KAAK,YAAY,EACvD,KAAK,OAAO,GAAO,EAAI,MAQ3B,SAAS,CAAC,EAA2C,CAEnD,OADA,KAAK,WAAW,IAAI,CAAQ,EACrB,IAAM,KAAK,WAAW,OAAO,CAAQ,EAM9C,aAAa,CAAC,EAAa,EAAmC,CAC5D,KAAK,aAAa,GAAO,EACzB,KAAK,QAAQ,GAAO,EAAW,MAEnC,CC/PO,MAAM,CAAe,CAClB,QAAU,IAAI,IACd,MAAQ,IAAI,IACZ,YAA6C,IAAI,IACjD,cAAiD,IAAI,IAM7D,QAAW,CACT,EACA,EACA,EACQ,CAER,GAAI,KAAK,QAAQ,IAAI,CAAI,EACvB,KAAK,WAAW,CAAI,EAGtB,IAAM,EAAK,KAAK,YAAY,EAEtB,EAAkC,CACtC,OACA,KACA,SACA,UACF,EAEA,KAAK,QAAQ,IAAI,EAAM,CAAU,EACjC,KAAK,MAAM,IAAI,EAAI,CAAU,EAG7B,QAAW,KAAY,KAAK,YAC1B,GAAI,CACF,EAAS,EAAM,EAAI,CAAM,EACzB,MAAO,EAAG,CACV,QAAQ,MAAM,8CAA+C,CAAC,EAIlE,OAAO,EAMT,UAAU,CAAC,EAAuB,CAChC,IAAM,EAAM,KAAK,QAAQ,IAAI,CAAI,EACjC,GAAI,CAAC,EAAK,MAAO,GAEjB,KAAK,QAAQ,OAAO,CAAI,EACxB,KAAK,MAAM,OAAO,EAAI,EAAE,EAGxB,QAAW,KAAY,KAAK,cAC1B,GAAI,CACF,EAAS,CAAI,EACb,MAAO,EAAG,CACV,QAAQ,MAAM,gDAAiD,CAAC,EAIpE,MAAO,GAMT,UAAuB,CAAC,EAA6B,CACnD,OAAO,KAAK,QAAQ,IAAI,CAAI,GAAG,OAMjC,QAAqB,CAAC,EAA2B,CAC/C,OAAO,KAAK,MAAM,IAAI,CAAE,GAAG,OAM7B,OAAO,CAAC,EAA4C,CAClD,OAAO,KAAK,QAAQ,IAAI,CAAI,EAM9B,GAAG,CAAC,EAAuB,CACzB,OAAO,KAAK,QAAQ,IAAI,CAAI,EAM9B,QAAQ,EAAa,CACnB,OAAO,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC,EAMvC,MAAM,EAAyB,CAC7B,IAAM,EAAS,IAAI,IACnB,QAAY,EAAM,KAAe,KAAK,QACpC,EAAO,IAAI,EAAM,EAAW,MAAM,EAEpC,OAAO,EAMT,KAAK,CAAC,EAAmE,CACvE,IAAM,EAA8B,CAAC,EACrC,QAAW,KAAO,KAAK,QAAQ,OAAO,EACpC,GAAI,EAAU,CAAG,EACf,EAAQ,KAAK,CAAG,EAGpB,OAAO,EAMT,UAAuB,CAAC,EAAmB,CACzC,OAAO,KAAK,MAAM,CAAC,IAAQ,EAAI,UAAU,OAAS,CAAI,EAAE,IACtD,CAAC,IAAQ,EAAI,MACf,EAMF,KAAK,EAAS,CACZ,IAAM,EAAQ,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC,EAC5C,QAAW,KAAQ,EACjB,KAAK,WAAW,CAAI,EAOxB,UAAU,CAAC,EAAgD,CAEzD,OADA,KAAK,YAAY,IAAI,CAAQ,EACtB,IAAM,KAAK,YAAY,OAAO,CAAQ,EAM/C,YAAY,CAAC,EAAkD,CAE7D,OADA,KAAK,cAAc,IAAI,CAAQ,EACxB,IAAM,KAAK,cAAc,OAAO,CAAQ,KAM7C,KAAI,EAAW,CACjB,OAAO,KAAK,QAAQ,KAGd,WAAW,EAAW,CAC5B,MAAO,OAAO,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,IAErE,CCtEO,MAAM,CAAW,CAEd,SAAW,GACX,WAAa,GACb,aAAe,GACf,cAAgB,EAGhB,YACA,QACA,SAGA,OACA,WACA,UAAY,UAGZ,UAA+B,CAAC,EAChC,aACA,kBACA,eAAiB,EACjB,gBACA,gBAER,WAAW,CAAC,EAA0B,CAKpC,GAJA,KAAK,OAAS,EAAO,MACrB,KAAK,WAAa,EAAO,WAAa,GAGlC,EAAO,WACT,KAAK,OAAO,MAAM,WAAa,EAAO,WAIxC,KAAK,YAAc,IAAI,EACrB,EAAO,WAAa,CAAC,EACrB,EAAO,aACT,EACA,KAAK,QAAU,IAAI,EACnB,KAAK,SAAW,IAAI,EAGpB,KAAK,YAAY,UAAU,CAAC,EAAK,EAAO,IAAkB,CACxD,KAAK,QAAQ,KAAuB,CAClC,KAAM,cACN,UAAW,KAAK,IAAI,EACpB,MACA,QACA,eACF,CAAC,EACF,EAGD,KAAK,qBAAqB,EAG1B,KAAK,UAAU,EAAO,MAAO,EAAO,UAAY,EAAI,KAKlD,QAAO,EAAY,CACrB,OAAO,KAAK,YAGV,UAAS,EAAY,CACvB,OAAO,KAAK,cAGV,YAAW,EAAY,CACzB,OAAO,KAAK,gBAGV,aAAY,EAAW,CACzB,OAAO,KAAK,iBAGV,MAAK,EAAgB,CACvB,OAAO,KAAK,UAIV,OAAM,EAAgB,CACxB,OAAO,KAAK,YAAY,SAAS,KAI/B,OAAM,EAAiB,CACzB,OAAO,KAAK,WAIV,QAAO,EAAmB,CAC5B,OAAO,KAAK,SAKd,QAAQ,CAAC,EAAa,EAAsB,CAC1C,KAAK,YAAY,IAAI,EAAK,CAAK,EAGjC,SAAS,CAAC,EAAuC,CAC/C,KAAK,YAAY,YAAY,CAAM,EAGrC,SAAS,EAA4B,CACnC,OAAO,KAAK,YAAY,YAAY,EAGtC,YAAY,EAAqB,CAC/B,OAAO,KAAK,YAAY,eAAe,EAGzC,WAAW,EAAS,CAClB,KAAK,YAAY,MAAM,EAKzB,cAA2B,CACzB,EACA,EACA,EACQ,CACR,OAAO,KAAK,SAAS,SAAS,EAAM,EAAQ,CAAQ,EAGtD,gBAA6B,CAAC,EAA6B,CACzD,OAAO,KAAK,SAAS,WAAc,CAAI,EAGzC,cAA2B,CAAC,EAA2B,CACrD,OAAO,KAAK,SAAS,SAAY,CAAE,EAGrC,aAAa,EAAyB,CACpC,OAAO,KAAK,SAAS,OAAO,EAK9B,IAAI,EAAS,CACX,GAAI,KAAK,YAAc,KAAK,aAAc,OAC1C,KAAK,WAAa,GAClB,KAAK,eAAiB,YAAY,IAAI,EACtC,KAAK,MAAM,EACX,KAAK,QAAQ,KAAK,CAAE,KAAM,OAAQ,UAAW,KAAK,IAAI,CAAE,CAAC,EAG3D,KAAK,EAAS,CACZ,GAAI,CAAC,KAAK,WAAY,OAEtB,GADA,KAAK,WAAa,GACd,KAAK,kBACP,qBAAqB,KAAK,iBAAiB,EAC3C,KAAK,kBAAoB,OAE3B,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,UAAW,KAAK,IAAI,CAAE,CAAC,EAG5D,MAAM,EAAS,CACb,GAAI,KAAK,WACP,KAAK,MAAM,EAEX,UAAK,KAAK,EAMd,EAA6B,CAC3B,EACA,EACY,CACZ,OAAO,KAAK,QAAQ,GAAG,EAAM,CAAO,EAGtC,IAA+B,CAC7B,EACA,EACY,CACZ,OAAO,KAAK,QAAQ,KAAK,EAAM,CAAO,EAGxC,GAA8B,CAC5B,EACA,EACM,CACN,KAAK,QAAQ,IAAI,EAAM,CAAO,OAK1B,aAAY,CAAC,EAAkC,MAA6B,CAEhF,GAAI,KAAK,gBACP,OAAO,KAAK,gBAAgB,CAAM,EAIpC,IAAM,EAAS,KAAK,OAAO,cAAc,QAAQ,EACjD,GAAI,CAAC,EAEH,OADA,QAAQ,KAAK,0CAA0C,EAChD,KAGT,OAAO,IAAI,QAAQ,CAAC,IAAY,CAC9B,IAAM,EAAW,SAAS,IACpB,EAAU,IAAW,OAAS,KAAO,OAC3C,EAAO,OAAO,CAAC,IAAS,EAAQ,CAAI,EAAG,EAAU,CAAO,EACzD,EAGH,WAAW,EAAW,CACpB,OAAO,KAAK,UAQd,UAAU,CAAC,EAAgC,CACzC,GAAI,OAAO,IAAY,WACrB,KAAK,UAAU,KAAK,CAAO,EAO/B,OAAO,EAAS,CACd,GAAI,KAAK,aAAc,OAOvB,GANA,KAAK,aAAe,GAGpB,KAAK,MAAM,EAGP,KAAK,aACP,GAAI,CACF,KAAK,aAAa,EAClB,MAAO,EAAG,CACV,QAAQ,MAAM,mCAAoC,CAAC,EAKvD,MAAO,KAAK,UAAU,OAAS,EAAG,CAChC,IAAM,EAAU,KAAK,UAAU,IAAI,EACnC,GAAI,EACF,GAAI,CACF,EAAQ,EACR,MAAO,EAAG,CACV,QAAQ,MAAM,8BAA+B,CAAC,GAMpD,KAAK,iBAAiB,WAAW,EAGjC,KAAK,SAAS,MAAM,EAGpB,KAAK,QAAQ,mBAAmB,EAGhC,KAAK,QAAQ,KAAK,CAAE,KAAM,YAAa,UAAW,KAAK,IAAI,CAAE,CAAC,OAKlD,UAAS,CAAC,EAAsB,EAAkC,CAC9E,GAAI,CAEF,IAAM,EAAU,KAAK,eAAe,EAG9B,EAAU,MAAM,EAAM,CAAO,EACnC,GAAI,OAAO,IAAY,WACrB,KAAK,aAAe,EAOtB,GAJA,KAAK,SAAW,GAChB,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,UAAW,KAAK,IAAI,CAAE,CAAC,EAGtD,EACF,KAAK,KAAK,EAEZ,MAAO,EAAO,CACd,QAAQ,MAAM,4BAA6B,CAAK,EAChD,KAAK,QAAQ,KAAiB,CAC5B,KAAM,QACN,UAAW,KAAK,IAAI,EACpB,MAAO,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CACjE,CAAC,GAIG,cAAc,EAAsB,CAC1C,MAAO,CACL,MAAO,KAAK,OACZ,OAAQ,KAAK,YAAY,SAAS,EAClC,QAAS,KAAK,kBAAkB,EAChC,YAAa,KAAK,sBAAsB,EACxC,eAAgB,CAAC,EAAM,EAAQ,IAC7B,KAAK,SAAS,SAAS,EAAM,EAAQ,CAAQ,EAC/C,iBAAkB,CAAC,IAAS,KAAK,SAAS,WAAW,CAAI,EACzD,WAAY,IACd,EAGM,iBAAiB,EAAe,CACtC,MAAO,CACL,aAAc,CAAC,IAAW,KAAK,aAAa,CAAM,EAClD,YAAa,CAAC,IAAa,CACzB,KAAK,UAAY,GAEnB,uBAAwB,CAAC,IAAY,CACnC,KAAK,gBAAkB,EAE3B,EAGM,qBAAqB,EAAmB,CAC9C,MAAO,CACL,OACA,SACA,SAAU,CAAC,IAAa,CACtB,IAAM,EAAU,IAAM,CACpB,EAAS,KAAK,OAAO,YAAa,KAAK,OAAO,YAAY,GAI5D,EAAQ,EAGR,IAAM,EAAK,IAAI,eAAe,CAAO,EACrC,EAAG,QAAQ,KAAK,MAAM,EAEtB,IAAM,EAAU,IAAM,EAAG,WAAW,EAEpC,OADA,KAAK,UAAU,KAAK,CAAO,EACpB,GAET,WAAY,CAAC,IAAY,KAAK,WAAW,CAAO,CAClD,EAGM,oBAAoB,EAAS,CACnC,KAAK,gBAAkB,IAAI,eAAe,CAAC,IAAY,CACrD,QAAW,KAAS,EAAS,CAC3B,IAAQ,QAAO,UAAW,EAAM,YAChC,KAAK,QAAQ,KAAkB,CAC7B,KAAM,SACN,UAAW,KAAK,IAAI,EACpB,QACA,QACF,CAAC,GAEJ,EACD,KAAK,gBAAgB,QAAQ,KAAK,MAAM,EAGlC,KAAK,EAAS,CACpB,GAAI,CAAC,KAAK,WAAY,OAEtB,IAAM,EAAM,YAAY,IAAI,EACtB,EAAY,EAAM,KAAK,eACvB,EAAiB,KAAO,KAAK,WAEnC,GAAI,GAAa,EACf,KAAK,gBACL,KAAK,eAAiB,EAAO,EAAY,EAEzC,KAAK,QAAQ,KAAiB,CAC5B,KAAM,QACN,UAAW,KAAK,IAAI,EACpB,MAAO,KAAK,cACZ,WACF,CAAC,EAGH,KAAK,kBAAoB,sBAAsB,IAAM,KAAK,MAAM,CAAC,EAErE,CC7bO,MAAM,CAAqB,CACxB,SACA,QACA,aAAe,GACf,aAAe,GAGf,mBACA,yBAER,WAAW,CAAC,EAAyE,CAEnF,IAAM,EACJ,aAA2B,YACvB,CAAE,QAAS,CAAgB,EAC3B,EAUN,GARA,KAAK,SAAW,EAAO,QACvB,KAAK,QAAU,IAAI,EAGnB,KAAK,mBAAqB,KAAK,aAAa,KAAK,IAAI,EACrD,KAAK,yBAA2B,KAAK,mBAAmB,KAAK,IAAI,EAG7D,EAAO,cAAgB,IAIzB,GAHA,KAAK,QAAQ,EAGT,EAAO,cACT,KAAK,UAAU,EAAO,aAAa,GAUzC,OAAO,EAAS,CACd,GAAI,KAAK,cAAgB,KAAK,aAAc,OAE5C,KAAK,SAAS,iBAAiB,QAAS,KAAK,kBAAkB,EAC/D,KAAK,SAAS,iBAAiB,cAAe,KAAK,wBAAwB,EAE3E,KAAK,aAAe,GAGpB,KAAK,QAAQ,KAAK,CAAE,KAAM,YAAa,UAAW,KAAK,IAAI,CAAE,CAAC,EAMhE,UAAU,EAAS,CACjB,GAAI,CAAC,KAAK,aAAc,OAExB,KAAK,SAAS,oBAAoB,QAAS,KAAK,kBAAkB,EAClE,KAAK,SAAS,oBAAoB,cAAe,KAAK,wBAAwB,EAE9E,KAAK,aAAe,GAEpB,KAAK,QAAQ,KAAK,CAAE,KAAM,eAAgB,UAAW,KAAK,IAAI,CAAE,CAAC,KAK/D,QAAO,EAA8B,CACvC,OAAO,KAAK,YAGV,YAAW,EAAY,CACzB,OAAO,KAAK,gBAGV,YAAW,EAAY,CACzB,OAAO,KAAK,aAQd,QAAQ,CAAC,EAAa,EAAsB,CAC1C,KAAK,SAAS,SAAS,EAAK,CAAK,EAMnC,SAAS,CAAC,EAAuC,CAC/C,KAAK,SAAS,UAAU,CAAM,EAMhC,SAAS,EAA4B,CACnC,OAAO,KAAK,SAAS,UAAU,EAMjC,YAAY,EAA6E,CACvF,OAAO,KAAK,SAAS,aAAa,EAMpC,WAAW,EAAS,CAClB,IAAM,EAAO,KAAK,aAAa,EACzB,EAAoC,CAAC,EAE3C,QAAY,EAAK,KAAQ,OAAO,QAAQ,CAAI,EAC1C,EAAS,GAAO,EAAI,MAGtB,KAAK,UAAU,CAAQ,EAQzB,EAA6B,CAC3B,EACA,EACY,CACZ,OAAO,KAAK,QAAQ,GAAG,EAAM,CAAO,EAMtC,IAA+B,CAC7B,EACA,EACY,CACZ,OAAO,KAAK,QAAQ,KAAK,EAAM,CAAO,EAMxC,GAA8B,CAC5B,EACA,EACM,CACN,KAAK,QAAQ,IAAI,EAAM,CAAO,EAmBhC,gBAAgB,CACd,EACA,EACS,CACT,IAAM,EAAS,KAAK,YAAY,EAChC,GAAI,CAAC,EAEH,OADA,QAAQ,KAAK,sDAAsD,EAC5D,GAGT,IAAM,EAAQ,KAAK,aAAa,EAAW,CAAS,EACpD,OAAO,EAAO,cAAc,CAAK,EAMnC,iBAAiB,CACf,EACA,EACS,CACT,IAAM,EAAQ,KAAK,aAAa,EAAW,CAAS,EACpD,OAAO,KAAK,SAAS,cAAc,CAAK,EAM1C,mBAAmB,CAAC,EAAmB,EAA2B,CAChE,IAAM,EAAQ,IAAI,YAAY,EAAW,CACvC,SACA,QAAS,GACT,WAAY,EACd,CAAC,EACD,OAAO,KAAK,SAAS,cAAc,CAAK,EAM1C,SAAS,EAA6B,CACpC,OAAO,KAAK,YAAY,EAM1B,QAAQ,EAAuB,CAC7B,OAAO,KAAK,SAAS,YAAY,cAAc,QAAQ,EAQzD,OAAO,EAAS,CACd,GAAI,KAAK,aAAc,OAEvB,KAAK,WAAW,EAChB,KAAK,QAAQ,mBAAmB,EAChC,KAAK,aAAe,GAEpB,KAAK,QAAQ,KAAK,CAAE,KAAM,YAAa,UAAW,KAAK,IAAI,CAAE,CAAC,EAKxD,YAAY,CAAC,EAAiB,CACpC,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,UAAW,KAAK,IAAI,CAAE,CAAC,EAGpD,kBAAkB,CAAC,EAAgB,CACzC,IAAM,EAAc,EAMpB,KAAK,QAAQ,KAAuB,CAClC,KAAM,cACN,UAAW,KAAK,IAAI,EACpB,IAAK,EAAY,OAAO,IACxB,MAAO,EAAY,OAAO,MAC1B,cAAe,EAAY,OAAO,aACpC,CAAC,EAMK,WAAW,EAA6B,CAE9C,IAAM,EAAa,KAAK,SAAS,WACjC,GAAI,EAAY,CACd,IAAM,EAAS,EAAW,cAAc,QAAQ,EAChD,GAAI,EAAQ,OAAO,EAGrB,OAAO,KAAK,SAAS,cAAc,QAAQ,EAMrC,YAAY,CAClB,EACA,EACO,CACP,IAAM,EAAW,CAAE,QAAS,GAAM,WAAY,MAAS,CAAU,EAGjE,GAAI,EAAU,WAAW,OAAO,GAAK,IAAc,SAAW,IAAc,WAC1E,OAAO,IAAI,WAAW,EAAW,CAA0B,EAI7D,GAAI,EAAU,WAAW,KAAK,EAC5B,OAAO,IAAI,cAAc,EAAW,CAA6B,EAInE,GAAI,EAAU,WAAW,SAAS,EAChC,OAAO,IAAI,aAAa,EAAW,CAA4B,EAIjE,GAAI,EAAU,WAAW,OAAO,EAC9B,OAAO,IAAI,WAAW,EAAW,CAA0B,EAI7D,GAAI,IAAc,QAChB,OAAO,IAAI,WAAW,EAAW,CAA0B,EAI7D,GAAI,WAAa,GAAa,CAAC,GAC7B,OAAO,IAAI,YAAY,EAAW,CAA2B,EAI/D,OAAO,IAAI,MAAM,EAAW,CAAQ,QAQ/B,aAAY,CAAC,EAAkB,EAA+D,CACnG,IAAM,EAAU,SAAS,cAAc,CAAQ,EAC/C,GAAI,CAAC,EACH,MAAU,MAAM,6CAA6C,GAAU,EAEzE,OAAO,IAAI,EAAqB,CAAE,UAAS,eAAc,CAAC,cAM/C,YAAW,CACtB,EACA,EAC+B,CAE/B,MAAM,eAAe,YAAY,CAAO,EAGxC,IAAI,EAAU,SAAS,cAAc,CAAO,EAC5C,GAAI,CAAC,EACH,EAAU,SAAS,cAAc,CAAO,EAG1C,OAAO,IAAI,EAAqB,CAAE,UAAS,eAAc,CAAC,EAE9D",
12
+ "debugId": "AF04FBCAE7C8AF9064756E2164756E21",
13
13
  "names": []
14
14
  }