@jucie.io/engine-painter 1.0.22 → 1.0.23

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/main.js CHANGED
@@ -1,2 +1,2 @@
1
- var k={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};var L=class{#e=new Map;register(e,t){if(!e)throw new Error("Hit area must have an id");return this.#e.set(e,{id:e,...t}),()=>this.unregister(e)}unregister(e){this.#e.delete(e)}get(e){return this.#e.get(e)}has(e){return this.#e.has(e)}get areas(){return Array.from(this.#e.values())}clear(){this.#e.clear()}};import{ServiceProvider as ye}from"@jucie.io/engine";var D=class extends ye{#e=null;#r=null;#s=null;#a=null;#b=new Set;#v=new Set;#h=null;#u=null;#g=!1;static manifest={name:"CanvasEvents",namespace:"canvasEvents",version:"1.0.0"};actions(){return{setCanvas:e=>this.setCanvas(e),subscribe:e=>this.subscribe(e),onResize:e=>this.onResize(e),transferControlToOffscreen:()=>this.transferControlToOffscreen()}}setCanvas(e){this.#e&&this.#y(),this.#e=e,this.#t(),this.#l()}subscribe(e){return this.#b.add(e),()=>this.#b.delete(e)}onResize(e){return this.#v.add(e),()=>this.#v.delete(e)}transferControlToOffscreen(){if(!this.#e)throw new Error("Canvas must be set before transferring control to offscreen");if(this.#g)throw new Error("Control has already been transferred to offscreen");return this.#r=this.#e.transferControlToOffscreen(),this.#g=!0,this.#r.width=this.#e.width,this.#r.height=this.#e.height,this.#w({width:this.#e.width,height:this.#e.height}),this.#r}#t(){this.#e&&(this.#s=this.#e.getBoundingClientRect())}#l(){this.#e&&(this.#t(),this.#a=new ResizeObserver(e=>{for(let t of e){if(t.target!==this.#e)continue;let{width:s,height:n}=t.contentRect;this.#w({width:s,height:n})}this.#t()}),this.#a.observe(this.#e),document.addEventListener("wheel",this.#p,{passive:!1}),document.addEventListener("pointermove",this.#n),document.addEventListener("pointerdown",this.#d),document.addEventListener("pointerup",this.#c),document.addEventListener("pointercancel",this.#c),document.addEventListener("dblclick",this.#f))}#y(){this.#a&&(this.#a.disconnect(),this.#a=null),document.removeEventListener("wheel",this.#p),document.removeEventListener("pointermove",this.#n),document.removeEventListener("pointerdown",this.#d),document.removeEventListener("pointerup",this.#c),document.removeEventListener("pointercancel",this.#c),document.removeEventListener("dblclick",this.#f)}#p=e=>{if(e.target===this.#e)if(e.preventDefault(),e.stopPropagation(),e.ctrlKey){let t=this.#m(e,"zoom");this.#o(t)}else{let t=this.#m(e,"scroll");this.#o(t)}};#n=e=>{let t=this.#m(e,"move");this.#h=t,!this.#u&&(this.#u=requestAnimationFrame(()=>{this.#h&&(this.#o(this.#h),this.#h=null),this.#u=null}))};#d=e=>{if(e.target===this.#e){let t=this.#m(e,"down");this.#o(t)}};#c=e=>{let t=this.#m(e,"up");this.#o(t)};#f=e=>{let t=this.#m(e,"dblclick");this.#o(t)};#o(e){for(let t of this.#b)t(e)}#w(e){for(let t of this.#v)t(e)}#m(e,t){let s=e.target===this.#e,n,i;s?(n=e.offsetX,i=e.offsetY):this.#s?(n=e.clientX-this.#s.left,i=e.clientY-this.#s.top):(n=e.clientX,i=e.clientY);let a=s||this.#s&&n>=0&&n<=this.#s.width&&i>=0&&i<=this.#s.height,o={x:n,y:i,type:t,isOverCanvas:s,isWithinBounds:a,clientX:e.clientX,clientY:e.clientY,button:e.button??null,buttons:e.buttons??0,timestamp:Date.now()};return(t==="scroll"||t==="zoom")&&(o.deltaX=e.deltaX,o.deltaY=e.deltaY,o.deltaZ=e.deltaZ,o.deltaMode=e.deltaMode),o.shiftKey=e.shiftKey||!1,o.ctrlKey=e.ctrlKey||!1,o.altKey=e.altKey||!1,o.metaKey=e.metaKey||!1,o}destroy(){this.#u&&(cancelAnimationFrame(this.#u),this.#u=null),this.#y(),this.#e=null,this.#r=null,this.#s=null,this.#b.clear(),this.#v.clear(),this.#g=!1}};import{defineSurface as be}from"@jucie.io/reactive";var X=be(r=>{let e=r.value(0),t=r.value(0),s=r.value(0),n=r.value(0),i=r.value(0),a=r.value(0),o=r.value(!1),c=r.value(!1),h=r.value(!1),S=r.value(null),m=r.value(0),R=r.value(null),O=r.value(null),re=r.value(null),V=r.value(null),H=r.value(null),$=r.value(null),Y=r.value(null),y=r.value(!1),p=r.value(0),U=r.value(0),T=r.value(0),E=r.value(0),W=r.value(0),K=r.value(0),j=r.value(0),A=r.value(null),M=r.value(null),w=r.value({dragThreshold:5,doubleClickThreshold:300,holdThreshold:500,velocitySmoothing:.3,maxVelocity:1e4}),I=r.computed(()=>({x:e.value,y:t.value})),q=r.computed(()=>({x:i.value,y:a.value})),Z=r.computed(()=>({x:s.value,y:n.value})),G=r.computed(()=>{let u=typeof e.value=="number"?e.value:0,l=typeof s.value=="number"?s.value:0,d=typeof t.value=="number"?t.value:0,f=typeof n.value=="number"?n.value:0;return{x:u-l,y:d-f}}),N=r.computed(()=>({x:T.value,y:E.value})),J=r.computed(()=>{let u=T.value,l=E.value;return Math.sqrt(u*u+l*l)}),z=r.computed(()=>{let u=$.value,l=Y.value;if(u===null||l===null||typeof u!="number"||typeof l!="number")return 0;let d=typeof e.value=="number"?e.value:0,f=typeof t.value=="number"?t.value:0,x=d-u,v=f-l;return Math.sqrt(x*x+v*v)}),Q=r.computed(()=>{let u=$.value,l=Y.value;if(u===null||l===null||typeof u!="number"||typeof l!="number")return{x:0,y:0};let d=typeof e.value=="number"?e.value:0,f=typeof t.value=="number"?t.value:0;return{x:d-u,y:f-l}}),B=r.computed(()=>!h.value||!O.value?0:Date.now()-O.value),ee=r.computed(()=>B.value>w.value.holdThreshold&&!y.value),ae=r.computed(()=>{let u=H.value;return u?Date.now()-u:0}),oe=r.computed(()=>({position:I.value,clientPosition:q.value,previousPosition:Z.value,delta:G.value,velocity:N.value,speed:J.value,isPressed:h.value,button:S.value,buttons:m.value,isDragging:y.value,dragDistance:z.value,dragDelta:Q.value,isHolding:ee.value,holdDuration:B.value,isOverCanvas:o.value,isWithinBounds:c.value,hoveredArea:A.value,activeArea:M.value,clickCount:p.value,lastEventType:R.value})),C=(u,l,d,f)=>{s.value=e.value,n.value=t.value,e.value=u,t.value=l,i.value=d,a.value=f,V.value=Date.now()},le=()=>{let u=Date.now(),l=V.value;if(l){let d=(u-l)/1e3;if(d>0&&d<.1){let f=(e.value-s.value)/d,x=(t.value-n.value)/d,v=w.value.maxVelocity,b=Math.max(-v,Math.min(v,f)),F=Math.max(-v,Math.min(v,x)),g=w.value.velocitySmoothing;T.value=T.value*(1-g)+b*g,E.value=E.value*(1-g)+F*g}}},ce=r.action((u,l)=>{let{x:d,y:f,type:x,clientX:v,clientY:b,button:F,buttons:g,isOverCanvas:ve,isWithinBounds:me}=l,P=Date.now();switch(H.value=P,R.value=x,o.value=ve,c.value=me,x){case"down":C(d,f,v,b),h.value=!0,O.value=P,S.value=F,m.value=g,$.value=d,Y.value=f,y.value=!1,P-U.value<w.value.doubleClickThreshold?p.value=p.value+1:p.value=1;break;case"up":C(d,f,v,b),h.value=!1,re.value=P,U.value=P,y.value=!1,T.value=0,E.value=0,m.value=g;break;case"move":C(d,f,v,b),le(),m.value=g,h.value&&!y.value&&z.value>w.value.dragThreshold&&(y.value=!0);break;case"dblclick":C(d,f,v,b),p.value=2;break;case"scroll":C(d,f,v,b),l.deltaX!==void 0&&(W.value=l.deltaX),l.deltaY!==void 0&&(K.value=l.deltaY);break;case"zoom":C(d,f,v,b),l.deltaY!==void 0&&(j.value=l.deltaY);break}}),he=r.action((u,l)=>{A.value=l}),ue=r.action((u,l)=>{M.value=l}),de=r.action(()=>{h.value=!1,y.value=!1,M.value=null,A.value=null,T.value=0,E.value=0,p.value=0,W.value=0,K.value=0,j.value=0}),fe=r.action((u,l)=>{w.value={...w.value,...l}});return{state:oe,position:I,clientPosition:q,previousPosition:Z,delta:G,velocity:N,speed:J,isPressed:h,button:S,buttons:m,isDragging:y,dragDistance:z,dragDelta:Q,isHolding:ee,holdDuration:B,isOverCanvas:o,isWithinBounds:c,hoveredArea:A,activeArea:M,clickCount:p,lastEventType:R,timeSinceLastEvent:ae,handleEvent:ce,setHoveredArea:he,setActiveArea:ue,reset:de,updateConfig:fe}});import{ServiceProvider as ge}from"@jucie.io/engine";import{createComputed as te,destroyComputed as se,addEffect as pe}from"@jucie.io/reactive";import{createDefinition as ie,definitionType as ne}from"@jucie.io/engine";var we=ie("BRUSH",[Object]),xe=ie("LAYER",[Object]),_=class extends ge{#e=new Map;#r=null;#s=new Map;#a=new Map;#b=new Map;#v=!1;#h=null;#u=!1;#g=!1;#t={targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}};#l={lastFrameTime:0,deltaTime:0,elapsedTime:0,frameCount:0};#y={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#p=new L;#n=X();#d=null;#c=null;#f=null;#o=new Map;#w=!1;#m=!1;#T=!1;static manifest={name:"Painter",namespace:"painter",version:"1.0.0",defaults:{targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}}};getters(){return{pointer:()=>this.#n.state}}actions(){return this.config&&Object.assign(this.#t,this.config),{addLayer:e=>this.addLayer(e),addLayers:(...e)=>{for(let t of e)this.addLayer(t)},updateCanvas:e=>this.updateCanvas(e),setCanvas:e=>this.setCanvas(e),setOffscreenCanvas:e=>this.setOffscreenCanvas(e),setAssets:e=>this.setAssets(e),removeLayer:e=>this.removeLayer(e),start:()=>this.start(),stop:()=>this.stop(),render:()=>this.render(),setTargetFPS:e=>this.setTargetFPS(e),setTimeScale:e=>this.setTimeScale(e),setFixedTimeStep:e=>this.setFixedTimeStep(e),setDebug:e=>this.setDebug(e),getMetrics:()=>this.getMetrics(),handleResize:(e,t)=>this.handleResize(e,t),subscribe:(e,t)=>this.subscribe(e,t),handlePointerEvent:e=>this.handlePointerEvent(e),subscribeToPointer:e=>this.#n.$subscribe(e),bindPointer:e=>this.#n.$bind(e),_testEmitPointerEvent:e=>this._testEmitPointerEvent(e)}}setCanvas(e){let t=e,s=e.transferControlToOffscreen();s.width=t.width,s.height=t.height,this.#r=s,Object.values(k).forEach(n=>{try{let i=s.getContext(n);i&&this.#s.set(n,i)}catch{console.warn(`Context type ${n} not supported`)}}),this.#d||(this.#d=new D),this.#d.setCanvas(t),this.#f&&this.#f.disconnect(),this.#f=new ResizeObserver(n=>{let i=n[0];i&&i.target===t&&(s.width=t.width,s.height=t.height,this.handleResize(t.width,t.height))}),this.#f.observe(t),this.#c&&this.#c(),this.#c=this.#d.subscribe(n=>{this.handlePointerEvent(n)})}setOffscreenCanvas(e){this.#r=e,Object.values(k).forEach(t=>{try{let s=e.getContext(t);s&&this.#s.set(t,s)}catch{console.warn(`Context type ${t} not supported`)}})}updateCanvas(e){let t=e(this.#r);t&&(this.#r=t)}setAssets(e){this.#b=e}start(){this.#v||(this.#v=!0,this.#E())}stop(){this.#v&&(this.#v=!1,this.#h&&(cancelAnimationFrame(this.#h),this.#h=null))}addLayer(e){if(ne(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,s=e(this.useContext,this.#p);if(s.data){let a=this.#C(`layer_${t}`,s.data);a&&this.#a.set(`layer_${t}`,a)}let n=s.children.map(a=>{if(ne(a)==="BRUSH"){let o=a._name,c=a(this.useContext,this.#p),h=c.data?this.#C(`brush_${o}`,c.data):()=>{},S=c.when?te(c.when,{immediate:!0,context:()=>this.#n.state}):null,m={name:o,...c,dataReactor:h,whenReactor:S};if(m.lifecycle?.onMount)try{m.lifecycle.onMount(this.#s.get(m.context||s.context))}catch(R){console.error(`Error in brush "${m.name}" onMount:`,R)}return m}return this.addLayer(a)}),i={...s,name:t,brushes:n,context:this.#s.get(s.context)};if(this.#e.set(t,i),i.lifecycle?.onMount)try{i.lifecycle.onMount(i.context)}catch(a){console.error(`Error in layer "${t}" onMount:`,a)}return i}removeLayer(e){let t=this.#e.get(e);if(!t)return;if(t.lifecycle?.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(n){console.error(`Error in layer "${e}" onUnmount:`,n)}t.brushes.forEach(n=>{if(n.lifecycle?.onUnmount)try{n.lifecycle.onUnmount(this.#s.get(n.context||t.context))}catch(a){console.error(`Error in brush "${n.name}" onUnmount:`,a)}let i=this.#a.get(`painter_brush_${n.name}`);i&&(i.unsubscribe(),i.computed&&se(i.computed),this.#a.delete(`painter_brush_${n.name}`))});let s=this.#a.get(`painter_layer_${e}`);s&&(s.unsubscribe(),s.computed&&se(s.computed),this.#a.delete(`painter_layer_${e}`)),this.#e.delete(e)}#E(){this.#g||this.#u||(this.#g=!0,this.#h=requestAnimationFrame(()=>{this.#g=!1,this.#h=null,this.#P()}))}async#P(){if(this.#r){this.#u=!0;try{this.#p.clear();let e=this.#t.debug?.enabled?performance.now():0;this.#s.forEach(t=>{t.clearRect(0,0,this.#r.width,this.#r.height)});for(let t of this.#e.values()){let s=this.#t.debug?.enabled?performance.now():0;if(t.whenReactor){let i=this.#a.get(`painter_layer_${t.name}`)?.computed;if(!t.when(i()))continue}let n=t.context;if(n){if(t.lifecycle?.beforeRender)try{t.lifecycle.beforeRender(n,this.#l)}catch(i){console.error(`Error in layer "${t.name}" beforeRender:`,i),t.lifecycle?.onError&&t.lifecycle.onError(i)}n.save(),t.settings&&Object.entries(t.settings).forEach(([i,a])=>{typeof n[i]=="function"?n[i](...Array.isArray(a)?a:[a]):n[i]=a});for(let i of t.brushes){let a=this.#t.debug?.enabled?performance.now():0;if(i.whenReactor&&!i.whenReactor())continue;let o=i.context?this.#s.get(i.context):n;if(o){if(i.lifecycle?.beforeRender)try{i.lifecycle.beforeRender(o,this.#l)}catch(c){console.error(`Error in brush "${i.name}" beforeRender:`,c),i.lifecycle?.onError&&i.lifecycle.onError(c);continue}o.save(),i.settings&&Object.entries(i.settings).forEach(([c,h])=>{typeof o[c]=="function"?o[c](...Array.isArray(h)?h:[h]):o[c]=h});try{let c={};if(i.assets)for(let h of i.assets)c[h]=this.#b.get(h);if(i.render(o,i.dataReactor(),c,this.#l),i.lifecycle?.afterRender&&i.lifecycle.afterRender(o,this.#l),this.#t.debug?.enabled){let h=performance.now()-a;this.#y.brushTimes.set(i.name,h),this.#t.debug?.showBounds&&this.#k(o,i)}}catch(c){console.error(`Error in brush "${i.name}":`,c),i.lifecycle?.onError&&i.lifecycle.onError(c)}finally{o.restore()}}}if(n.restore(),t.lifecycle?.afterRender)try{t.lifecycle.afterRender(n,this.#l)}catch(i){console.error(`Error in layer "${t.name}" afterRender:`,i),t.lifecycle?.onError&&t.lifecycle.onError(i)}if(this.#t.debug?.enabled){let i=performance.now()-s;this.#y.layerTimes.set(t.name,i),this.#t.debug?.showBounds&&this.#L(n,t)}}}this.#t.debug?.enabled&&this.#D()}finally{this.#u=!1}}}#k(e,t){e.save(),e.strokeStyle="rgba(0, 255, 0, 0.5)",e.lineWidth=1,e.strokeRect(0,0,e.canvas.width,e.canvas.height),e.restore()}#L(e,t){e.save(),e.strokeStyle="rgba(255, 0, 0, 0.5)",e.lineWidth=2,e.strokeRect(0,0,e.canvas.width,e.canvas.height),e.restore()}#D(){let e=this.#s.get(k["2D"]);if(!e)return;e.save(),e.resetTransform(),e.font="12px monospace",e.fillStyle="white",e.strokeStyle="black",e.lineWidth=3;let t=20,s=15;if(this.#t.debug?.showFPS){let n=`FPS: ${Math.round(this.#y.fps)} (${this.#l.deltaTime.toFixed(2)}ms)`;e.strokeText(n,10,t),e.fillText(n,10,t),t+=s}if(this.#t.debug?.showLayerTiming){e.fillText("Layer Times:",10,t),t+=s;for(let[n,i]of this.#y.layerTimes){let a=` ${n}: ${i.toFixed(2)}ms`;e.strokeText(a,10,t),e.fillText(a,10,t),t+=s}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){for(let s of this.#e.values())if(s.lifecycle?.onResize)try{s.lifecycle.onResize(e,t,s.context)}catch(n){console.error(`Error in layer "${s.name}" onResize:`,n),s.lifecycle?.onError&&s.lifecycle.onError(n)}}#C(e,t){let s=te(t,{immediate:!0,context:()=>this.#n.state}),n=pe(s,()=>this.#E());return this.#a.set(`painter_${e}`,{computed:s,unsubscribe:n}),s}destroy(){this.stop(),this.#c&&(this.#c(),this.#c=null),this.#d&&(this.#d.destroy(),this.#d=null),this.#f&&(this.#f.disconnect(),this.#f=null),this.#n&&this.#n.$destroy();for(let e of this.#e.keys())this.removeLayer(e)}setTargetFPS(e){this.#t.targetFPS=e,this.#t.fixedTimeStep=1e3/e}setTimeScale(e){this.#t.timeScale=Math.max(0,e)}setFixedTimeStep(e){this.#t.fixedTimeStep=e}setDebug(e={}){this.#t.debug||(this.#t.debug={}),Object.assign(this.#t.debug,e)}getMetrics(){return{...this.#y,deltaTime:this.#l.deltaTime,elapsedTime:this.#l.elapsedTime,frameCount:this.#l.frameCount}}handlePointerEvent(e){this.#n.handleEvent(e),this.#S(e),this.#A(e)}#A(e){let{type:t}=e,s=this.#n;switch(t){case"down":this.#i("pointer:down",s.state);break;case"up":this.#i("pointer:up",s.state),s.isDragging||this.#i("pointer:click",s.state);break;case"move":if(this.#i("pointer:move",s.state),s.isDragging&&s.isPressed){let c=this.#w;this.#w=!0,c?this.#i("pointer:drag:move",s.state):this.#i("pointer:drag:start",s.state)}break;case"scroll":this.#i("pointer:scroll",s.state);break;case"zoom":this.#i("pointer:zoom",s.state);break;case"dblclick":this.#i("pointer:dblclick",s.state);break}t==="up"&&this.#w&&(this.#i("pointer:drag:end",s.state),this.#w=!1);let n=this.#m,i=s.isOverCanvas;i&&!n?this.#i("pointer:enter",s.state):!i&&n&&this.#i("pointer:leave",s.state),this.#m=i;let a=this.#T,o=s.isHolding;o&&!a?this.#i("pointer:hold:start",s.state):!o&&a&&this.#i("pointer:hold:end",s.state),this.#T=o}#S(e){let{type:t,x:s,y:n}=e,i=this.#n;switch(t){case"down":{let a=this.#R(s,n);if(i.setActiveArea(a),a?.onPointerDown?.handler){let o=this.#x(a);a.onPointerDown.handler({...i.state,ctx:o,emit:this.#i.bind(this)})}break}case"up":{let a=i.activeArea;if(a?.onPointerUp?.handler){let o=this.#x(a);a.onPointerUp.handler({...i.state,ctx:o,emit:this.#i.bind(this)})}break}case"move":{let a=this.#R(s,n),o=i.hoveredArea,c=i.activeArea;if(c?.onPointerMove?.handler&&i.isDragging){let h=this.#x(c);c.onPointerMove.handler({...i.state,ctx:h,emit:this.#i.bind(this)})}if(a?.id!==o?.id){if(o?.onPointerLeave?.handler){let h=this.#x(o);o.onPointerLeave.handler({...i.state,ctx:h,emit:this.#i.bind(this)})}if(a?.onPointerEnter?.handler){let h=this.#x(a);a.onPointerEnter.handler({...i.state,ctx:h,emit:this.#i.bind(this)})}i.setHoveredArea(a)}break}case"scroll":case"zoom":break;case"dblclick":break}}#x(e){return e?e.context?this.#s.get(e.context):this.#s.get(k["2D"]):null}subscribe(e,t){return this.#o.has(e)||this.#o.set(e,new Set),this.#o.get(e).add(t),()=>{let s=this.#o.get(e);s&&(s.delete(t),s.size===0&&this.#o.delete(e))}}#R(e,t){let s=this.#p.areas.sort((n,i)=>(i.priority||0)-(n.priority||0));for(let n of s)if(this.#M(e,t,n.bounds))return n;return null}#M(e,t,s){return e>=s.x&&e<=s.x+s.width&&t>=s.y&&t<=s.y+s.height}#i(e,t){let s=this.#o.get(e);if(s)for(let n of s)n(t)}_testEmitPointerEvent(e){this.#n.handleEvent(e),this.#S(e)}};export{D as CanvasEvents,L as HitRegistry,_ as Painter,we as defineBrush,xe as defineLayer,X as usePointerSurface};
1
+ var k={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};var L=class{#e=new Map;register(e,t){if(!e)throw new Error("Hit area must have an id");return this.#e.set(e,{id:e,...t}),()=>this.unregister(e)}unregister(e){this.#e.delete(e)}get(e){return this.#e.get(e)}has(e){return this.#e.has(e)}get areas(){return Array.from(this.#e.values())}clear(){this.#e.clear()}};import{ServiceProvider as ye}from"@jucie.io/engine";var D=class extends ye{#e=null;#r=null;#s=null;#a=null;#b=new Set;#v=new Set;#h=null;#u=null;#g=!1;static manifest={name:"CanvasEvents",namespace:"canvasEvents",version:"1.0.0"};actions(){return{setCanvas:e=>this.setCanvas(e),subscribe:e=>this.subscribe(e),onResize:e=>this.onResize(e),transferControlToOffscreen:()=>this.transferControlToOffscreen()}}setCanvas(e){this.#e&&this.#y(),this.#e=e,this.#t(),this.#l()}subscribe(e){return this.#b.add(e),()=>this.#b.delete(e)}onResize(e){return this.#v.add(e),()=>this.#v.delete(e)}transferControlToOffscreen(){if(!this.#e)throw new Error("Canvas must be set before transferring control to offscreen");if(this.#g)throw new Error("Control has already been transferred to offscreen");return this.#r=this.#e.transferControlToOffscreen(),this.#g=!0,this.#r.width=this.#e.width,this.#r.height=this.#e.height,this.#w({width:this.#e.width,height:this.#e.height}),this.#r}#t(){this.#e&&(this.#s=this.#e.getBoundingClientRect())}#l(){this.#e&&(this.#t(),this.#a=new ResizeObserver(e=>{for(let t of e){if(t.target!==this.#e)continue;let{width:s,height:n}=t.contentRect;this.#w({width:s,height:n})}this.#t()}),this.#a.observe(this.#e),document.addEventListener("wheel",this.#p,{passive:!1}),document.addEventListener("pointermove",this.#n),document.addEventListener("pointerdown",this.#d),document.addEventListener("pointerup",this.#c),document.addEventListener("pointercancel",this.#c),document.addEventListener("dblclick",this.#f))}#y(){this.#a&&(this.#a.disconnect(),this.#a=null),document.removeEventListener("wheel",this.#p),document.removeEventListener("pointermove",this.#n),document.removeEventListener("pointerdown",this.#d),document.removeEventListener("pointerup",this.#c),document.removeEventListener("pointercancel",this.#c),document.removeEventListener("dblclick",this.#f)}#p=e=>{if(e.target===this.#e)if(e.preventDefault(),e.stopPropagation(),e.ctrlKey){let t=this.#m(e,"zoom");this.#o(t)}else{let t=this.#m(e,"scroll");this.#o(t)}};#n=e=>{let t=this.#m(e,"move");this.#h=t,!this.#u&&(this.#u=requestAnimationFrame(()=>{this.#h&&(this.#o(this.#h),this.#h=null),this.#u=null}))};#d=e=>{if(e.target===this.#e){let t=this.#m(e,"down");this.#o(t)}};#c=e=>{let t=this.#m(e,"up");this.#o(t)};#f=e=>{let t=this.#m(e,"dblclick");this.#o(t)};#o(e){for(let t of this.#b)t(e)}#w(e){for(let t of this.#v)t(e)}#m(e,t){let s=e.target===this.#e,n,i;s?(n=e.offsetX,i=e.offsetY):this.#s?(n=e.clientX-this.#s.left,i=e.clientY-this.#s.top):(n=e.clientX,i=e.clientY);let a=s||this.#s&&n>=0&&n<=this.#s.width&&i>=0&&i<=this.#s.height,o={x:n,y:i,type:t,isOverCanvas:s,isWithinBounds:a,clientX:e.clientX,clientY:e.clientY,button:e.button??null,buttons:e.buttons??0,timestamp:Date.now()};return(t==="scroll"||t==="zoom")&&(o.deltaX=e.deltaX,o.deltaY=e.deltaY,o.deltaZ=e.deltaZ,o.deltaMode=e.deltaMode),o.shiftKey=e.shiftKey||!1,o.ctrlKey=e.ctrlKey||!1,o.altKey=e.altKey||!1,o.metaKey=e.metaKey||!1,o}destroy(){this.#u&&(cancelAnimationFrame(this.#u),this.#u=null),this.#y(),this.#e=null,this.#r=null,this.#s=null,this.#b.clear(),this.#v.clear(),this.#g=!1}};import{defineSurface as be}from"@jucie.io/reactive";var X=be(r=>{let e=r.value(0),t=r.value(0),s=r.value(0),n=r.value(0),i=r.value(0),a=r.value(0),o=r.value(!1),c=r.value(!1),h=r.value(!1),S=r.value(null),m=r.value(0),R=r.value(null),O=r.value(null),re=r.value(null),V=r.value(null),H=r.value(null),$=r.value(null),Y=r.value(null),y=r.value(!1),p=r.value(0),U=r.value(0),T=r.value(0),E=r.value(0),W=r.value(0),K=r.value(0),j=r.value(0),A=r.value(null),M=r.value(null),w=r.value({dragThreshold:5,doubleClickThreshold:300,holdThreshold:500,velocitySmoothing:.3,maxVelocity:1e4}),I=r.computed(()=>({x:e.value,y:t.value})),q=r.computed(()=>({x:i.value,y:a.value})),Z=r.computed(()=>({x:s.value,y:n.value})),G=r.computed(()=>{let u=typeof e.value=="number"?e.value:0,l=typeof s.value=="number"?s.value:0,d=typeof t.value=="number"?t.value:0,f=typeof n.value=="number"?n.value:0;return{x:u-l,y:d-f}}),N=r.computed(()=>({x:T.value,y:E.value})),J=r.computed(()=>{let u=T.value,l=E.value;return Math.sqrt(u*u+l*l)}),z=r.computed(()=>{let u=$.value,l=Y.value;if(u===null||l===null||typeof u!="number"||typeof l!="number")return 0;let d=typeof e.value=="number"?e.value:0,f=typeof t.value=="number"?t.value:0,x=d-u,v=f-l;return Math.sqrt(x*x+v*v)}),Q=r.computed(()=>{let u=$.value,l=Y.value;if(u===null||l===null||typeof u!="number"||typeof l!="number")return{x:0,y:0};let d=typeof e.value=="number"?e.value:0,f=typeof t.value=="number"?t.value:0;return{x:d-u,y:f-l}}),B=r.computed(()=>!h.value||!O.value?0:Date.now()-O.value),ee=r.computed(()=>B.value>w.value.holdThreshold&&!y.value),ae=r.computed(()=>{let u=H.value;return u?Date.now()-u:0}),oe=r.computed(()=>({position:I.value,clientPosition:q.value,previousPosition:Z.value,delta:G.value,velocity:N.value,speed:J.value,isPressed:h.value,button:S.value,buttons:m.value,isDragging:y.value,dragDistance:z.value,dragDelta:Q.value,isHolding:ee.value,holdDuration:B.value,isOverCanvas:o.value,isWithinBounds:c.value,hoveredArea:A.value,activeArea:M.value,clickCount:p.value,lastEventType:R.value})),C=(u,l,d,f)=>{s.value=e.value,n.value=t.value,e.value=u,t.value=l,i.value=d,a.value=f,V.value=Date.now()},le=()=>{let u=Date.now(),l=V.value;if(l){let d=(u-l)/1e3;if(d>0&&d<.1){let f=(e.value-s.value)/d,x=(t.value-n.value)/d,v=w.value.maxVelocity,b=Math.max(-v,Math.min(v,f)),F=Math.max(-v,Math.min(v,x)),g=w.value.velocitySmoothing;T.value=T.value*(1-g)+b*g,E.value=E.value*(1-g)+F*g}}},ce=r.action((u,l)=>{let{x:d,y:f,type:x,clientX:v,clientY:b,button:F,buttons:g,isOverCanvas:ve,isWithinBounds:me}=l,P=Date.now();switch(H.value=P,R.value=x,o.value=ve,c.value=me,x){case"down":C(d,f,v,b),h.value=!0,O.value=P,S.value=F,m.value=g,$.value=d,Y.value=f,y.value=!1,P-U.value<w.value.doubleClickThreshold?p.value=p.value+1:p.value=1;break;case"up":C(d,f,v,b),h.value=!1,re.value=P,U.value=P,y.value=!1,T.value=0,E.value=0,m.value=g;break;case"move":C(d,f,v,b),le(),m.value=g,h.value&&!y.value&&z.value>w.value.dragThreshold&&(y.value=!0);break;case"dblclick":C(d,f,v,b),p.value=2;break;case"scroll":C(d,f,v,b),l.deltaX!==void 0&&(W.value=l.deltaX),l.deltaY!==void 0&&(K.value=l.deltaY);break;case"zoom":C(d,f,v,b),l.deltaY!==void 0&&(j.value=l.deltaY);break}}),he=r.action((u,l)=>{A.value=l}),ue=r.action((u,l)=>{M.value=l}),de=r.action(()=>{h.value=!1,y.value=!1,M.value=null,A.value=null,T.value=0,E.value=0,p.value=0,W.value=0,K.value=0,j.value=0}),fe=r.action((u,l)=>{w.value={...w.value,...l}});return{state:oe,position:I,clientPosition:q,previousPosition:Z,delta:G,velocity:N,speed:J,isPressed:h,button:S,buttons:m,isDragging:y,dragDistance:z,dragDelta:Q,isHolding:ee,holdDuration:B,isOverCanvas:o,isWithinBounds:c,hoveredArea:A,activeArea:M,clickCount:p,lastEventType:R,timeSinceLastEvent:ae,handleEvent:ce,setHoveredArea:he,setActiveArea:ue,reset:de,updateConfig:fe}});import{ServiceProvider as ge}from"@jucie.io/engine";import{createComputed as te,destroyComputed as se,addEffect as pe}from"@jucie.io/reactive";import{createDefinition as ie,definitionType as ne}from"@jucie.io/engine";var we=ie("BRUSH",[Object]),xe=ie("LAYER",[Object]),_=class extends ge{#e=new Map;#r=null;#s=new Map;#a=new Map;#b=new Map;#v=!1;#h=null;#u=!1;#g=!1;#t={targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}};#l={lastFrameTime:0,deltaTime:0,elapsedTime:0,frameCount:0};#y={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#p=new L;#n=X();#d=null;#c=null;#f=null;#o=new Map;#w=!1;#m=!1;#T=!1;static manifest={name:"Painter",namespace:"painter",version:"1.0.0",defaults:{targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}}};getters(){return{pointer:()=>this.#n.state}}actions(){return this.config&&Object.assign(this.#t,this.config),{addLayer:e=>this.addLayer(e),addLayers:(...e)=>{for(let t of e)this.addLayer(t)},updateCanvas:e=>this.updateCanvas(e),setCanvas:e=>this.setCanvas(e),setOffscreenCanvas:e=>this.setOffscreenCanvas(e),setAssets:e=>this.setAssets(e),removeLayer:e=>this.removeLayer(e),start:()=>this.start(),stop:()=>this.stop(),render:()=>this.render(),setTargetFPS:e=>this.setTargetFPS(e),setTimeScale:e=>this.setTimeScale(e),setFixedTimeStep:e=>this.setFixedTimeStep(e),setDebug:e=>this.setDebug(e),getMetrics:()=>this.getMetrics(),handleResize:(e,t)=>this.handleResize(e,t),subscribe:(e,t)=>this.subscribe(e,t),handlePointerEvent:e=>this.handlePointerEvent(e),subscribeToPointer:e=>this.#n.$subscribe(e),bindPointer:e=>this.#n.$bind(e),_testEmitPointerEvent:e=>this._testEmitPointerEvent(e)}}setCanvas(e){let t=e,s=e.transferControlToOffscreen();s.width=t.width,s.height=t.height,this.#r=s,Object.values(k).forEach(n=>{try{let i=s.getContext(n);i&&this.#s.set(n,i)}catch{console.warn(`Context type ${n} not supported`)}}),this.#d||(this.#d=new D),this.#d.setCanvas(t),this.#f&&this.#f.disconnect(),this.#f=new ResizeObserver(n=>{let i=n[0];i&&i.target===t&&(s.width=t.width,s.height=t.height,this.handleResize(t.width,t.height))}),this.#f.observe(t),this.#c&&this.#c(),this.#c=this.#d.subscribe(n=>{this.handlePointerEvent(n)})}setOffscreenCanvas(e){this.#r=e,Object.values(k).forEach(t=>{try{let s=e.getContext(t);s&&this.#s.set(t,s)}catch{console.warn(`Context type ${t} not supported`)}})}updateCanvas(e){let t=e(this.#r);t&&(this.#r=t)}setAssets(e){this.#b=e}start(){this.#v||(this.#v=!0,this.#E())}stop(){this.#v&&(this.#v=!1,this.#h&&(cancelAnimationFrame(this.#h),this.#h=null))}addLayer(e){if(ne(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,s=e(this.useContext,this.#p);if(s.data){let a=this.#C(`layer_${t}`,s.data);a&&this.#a.set(`layer_${t}`,a)}let n=s.children.map(a=>{if(ne(a)==="BRUSH"){let o=a._name,c=a(this.useContext,this.#p),h=c.data?this.#C(`brush_${o}`,c.data):void 0,S=c.when?te(c.when,{immediate:!0,context:this.#n.state}):null,m={name:o,...c,dataReactor:h,whenReactor:S};if(m.lifecycle?.onMount)try{m.lifecycle.onMount(this.#s.get(m.context||s.context))}catch(R){console.error(`Error in brush "${m.name}" onMount:`,R)}return m}return this.addLayer(a)}),i={...s,name:t,brushes:n,context:this.#s.get(s.context)};if(this.#e.set(t,i),i.lifecycle?.onMount)try{i.lifecycle.onMount(i.context)}catch(a){console.error(`Error in layer "${t}" onMount:`,a)}return i}removeLayer(e){let t=this.#e.get(e);if(!t)return;if(t.lifecycle?.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(n){console.error(`Error in layer "${e}" onUnmount:`,n)}t.brushes.forEach(n=>{if(n.lifecycle?.onUnmount)try{n.lifecycle.onUnmount(this.#s.get(n.context||t.context))}catch(a){console.error(`Error in brush "${n.name}" onUnmount:`,a)}let i=this.#a.get(`painter_brush_${n.name}`);i&&(i.unsubscribe(),i.computed&&se(i.computed),this.#a.delete(`painter_brush_${n.name}`))});let s=this.#a.get(`painter_layer_${e}`);s&&(s.unsubscribe(),s.computed&&se(s.computed),this.#a.delete(`painter_layer_${e}`)),this.#e.delete(e)}#E(){this.#g||this.#u||(this.#g=!0,this.#h=requestAnimationFrame(()=>{this.#g=!1,this.#h=null,this.#P()}))}async#P(){if(this.#r){this.#u=!0;try{this.#p.clear();let e=this.#t.debug?.enabled?performance.now():0;this.#s.forEach(t=>{t.clearRect(0,0,this.#r.width,this.#r.height)});for(let t of this.#e.values()){let s=this.#t.debug?.enabled?performance.now():0;if(t.whenReactor){let i=this.#a.get(`painter_layer_${t.name}`)?.computed;if(!t.when(i()))continue}let n=t.context;if(n){if(t.lifecycle?.beforeRender)try{t.lifecycle.beforeRender(n,this.#l)}catch(i){console.error(`Error in layer "${t.name}" beforeRender:`,i),t.lifecycle?.onError&&t.lifecycle.onError(i)}n.save(),t.settings&&Object.entries(t.settings).forEach(([i,a])=>{typeof n[i]=="function"?n[i](...Array.isArray(a)?a:[a]):n[i]=a});for(let i of t.brushes){let a=this.#t.debug?.enabled?performance.now():0;if(i.whenReactor&&!i.whenReactor())continue;let o=i.context?this.#s.get(i.context):n;if(o){if(i.lifecycle?.beforeRender)try{i.lifecycle.beforeRender(o,this.#l)}catch(c){console.error(`Error in brush "${i.name}" beforeRender:`,c),i.lifecycle?.onError&&i.lifecycle.onError(c);continue}o.save(),i.settings&&Object.entries(i.settings).forEach(([c,h])=>{typeof o[c]=="function"?o[c](...Array.isArray(h)?h:[h]):o[c]=h});try{let c={};if(i.assets)for(let h of i.assets)c[h]=this.#b.get(h);if(i.render(o,i.dataReactor(),c,this.#l),i.lifecycle?.afterRender&&i.lifecycle.afterRender(o,this.#l),this.#t.debug?.enabled){let h=performance.now()-a;this.#y.brushTimes.set(i.name,h),this.#t.debug?.showBounds&&this.#k(o,i)}}catch(c){console.error(`Error in brush "${i.name}":`,c),i.lifecycle?.onError&&i.lifecycle.onError(c)}finally{o.restore()}}}if(n.restore(),t.lifecycle?.afterRender)try{t.lifecycle.afterRender(n,this.#l)}catch(i){console.error(`Error in layer "${t.name}" afterRender:`,i),t.lifecycle?.onError&&t.lifecycle.onError(i)}if(this.#t.debug?.enabled){let i=performance.now()-s;this.#y.layerTimes.set(t.name,i),this.#t.debug?.showBounds&&this.#L(n,t)}}}this.#t.debug?.enabled&&this.#D()}finally{this.#u=!1}}}#k(e,t){e.save(),e.strokeStyle="rgba(0, 255, 0, 0.5)",e.lineWidth=1,e.strokeRect(0,0,e.canvas.width,e.canvas.height),e.restore()}#L(e,t){e.save(),e.strokeStyle="rgba(255, 0, 0, 0.5)",e.lineWidth=2,e.strokeRect(0,0,e.canvas.width,e.canvas.height),e.restore()}#D(){let e=this.#s.get(k["2D"]);if(!e)return;e.save(),e.resetTransform(),e.font="12px monospace",e.fillStyle="white",e.strokeStyle="black",e.lineWidth=3;let t=20,s=15;if(this.#t.debug?.showFPS){let n=`FPS: ${Math.round(this.#y.fps)} (${this.#l.deltaTime.toFixed(2)}ms)`;e.strokeText(n,10,t),e.fillText(n,10,t),t+=s}if(this.#t.debug?.showLayerTiming){e.fillText("Layer Times:",10,t),t+=s;for(let[n,i]of this.#y.layerTimes){let a=` ${n}: ${i.toFixed(2)}ms`;e.strokeText(a,10,t),e.fillText(a,10,t),t+=s}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){for(let s of this.#e.values())if(s.lifecycle?.onResize)try{s.lifecycle.onResize(e,t,s.context)}catch(n){console.error(`Error in layer "${s.name}" onResize:`,n),s.lifecycle?.onError&&s.lifecycle.onError(n)}}#C(e,t){let s=te(t,{immediate:!0,context:this.#n.state}),n=pe(s,()=>this.#E());return this.#a.set(`painter_${e}`,{computed:s,unsubscribe:n}),s}destroy(){this.stop(),this.#c&&(this.#c(),this.#c=null),this.#d&&(this.#d.destroy(),this.#d=null),this.#f&&(this.#f.disconnect(),this.#f=null),this.#n&&this.#n.$destroy();for(let e of this.#e.keys())this.removeLayer(e)}setTargetFPS(e){this.#t.targetFPS=e,this.#t.fixedTimeStep=1e3/e}setTimeScale(e){this.#t.timeScale=Math.max(0,e)}setFixedTimeStep(e){this.#t.fixedTimeStep=e}setDebug(e={}){this.#t.debug||(this.#t.debug={}),Object.assign(this.#t.debug,e)}getMetrics(){return{...this.#y,deltaTime:this.#l.deltaTime,elapsedTime:this.#l.elapsedTime,frameCount:this.#l.frameCount}}handlePointerEvent(e){this.#n.handleEvent(e),this.#S(e),this.#A(e)}#A(e){let{type:t}=e,s=this.#n;switch(t){case"down":this.#i("pointer:down",s.state);break;case"up":this.#i("pointer:up",s.state),s.isDragging||this.#i("pointer:click",s.state);break;case"move":if(this.#i("pointer:move",s.state),s.isDragging&&s.isPressed){let c=this.#w;this.#w=!0,c?this.#i("pointer:drag:move",s.state):this.#i("pointer:drag:start",s.state)}break;case"scroll":this.#i("pointer:scroll",s.state);break;case"zoom":this.#i("pointer:zoom",s.state);break;case"dblclick":this.#i("pointer:dblclick",s.state);break}t==="up"&&this.#w&&(this.#i("pointer:drag:end",s.state),this.#w=!1);let n=this.#m,i=s.isOverCanvas;i&&!n?this.#i("pointer:enter",s.state):!i&&n&&this.#i("pointer:leave",s.state),this.#m=i;let a=this.#T,o=s.isHolding;o&&!a?this.#i("pointer:hold:start",s.state):!o&&a&&this.#i("pointer:hold:end",s.state),this.#T=o}#S(e){let{type:t,x:s,y:n}=e,i=this.#n;switch(t){case"down":{let a=this.#R(s,n);if(i.setActiveArea(a),a?.onPointerDown?.handler){let o=this.#x(a);a.onPointerDown.handler({...i.state,ctx:o,emit:this.#i.bind(this)})}break}case"up":{let a=i.activeArea;if(a?.onPointerUp?.handler){let o=this.#x(a);a.onPointerUp.handler({...i.state,ctx:o,emit:this.#i.bind(this)})}break}case"move":{let a=this.#R(s,n),o=i.hoveredArea,c=i.activeArea;if(c?.onPointerMove?.handler&&i.isDragging){let h=this.#x(c);c.onPointerMove.handler({...i.state,ctx:h,emit:this.#i.bind(this)})}if(a?.id!==o?.id){if(o?.onPointerLeave?.handler){let h=this.#x(o);o.onPointerLeave.handler({...i.state,ctx:h,emit:this.#i.bind(this)})}if(a?.onPointerEnter?.handler){let h=this.#x(a);a.onPointerEnter.handler({...i.state,ctx:h,emit:this.#i.bind(this)})}i.setHoveredArea(a)}break}case"scroll":case"zoom":break;case"dblclick":break}}#x(e){return e?e.context?this.#s.get(e.context):this.#s.get(k["2D"]):null}subscribe(e,t){return this.#o.has(e)||this.#o.set(e,new Set),this.#o.get(e).add(t),()=>{let s=this.#o.get(e);s&&(s.delete(t),s.size===0&&this.#o.delete(e))}}#R(e,t){let s=this.#p.areas.sort((n,i)=>(i.priority||0)-(n.priority||0));for(let n of s)if(this.#M(e,t,n.bounds))return n;return null}#M(e,t,s){return e>=s.x&&e<=s.x+s.width&&t>=s.y&&t<=s.y+s.height}#i(e,t){let s=this.#o.get(e);if(s)for(let n of s)n(t)}_testEmitPointerEvent(e){this.#n.handleEvent(e),this.#S(e)}};export{D as CanvasEvents,L as HitRegistry,_ as Painter,we as defineBrush,xe as defineLayer,X as usePointerSurface};
2
2
  //# sourceMappingURL=main.js.map
package/dist/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/ContextTypes.js", "../src/HitRegistry.js", "../src/CanvasEvents.js", "../src/usePointerSurface.js", "../src/Painter.js"],
4
- "sourcesContent": ["export const ContextTypes = {\n '2D': '2d',\n 'WEBGL': 'webgl',\n 'WEBGL2': 'webgl2',\n 'BITMAPRENDERER': 'bitmaprenderer'\n};", "export class HitRegistry {\n #areas = new Map();\n\n register(id, area) {\n if (!id) {\n throw new Error('Hit area must have an id');\n }\n this.#areas.set(id, { id, ...area });\n return () => this.unregister(id);\n }\n\n unregister(id) {\n this.#areas.delete(id);\n }\n\n get(id) {\n return this.#areas.get(id);\n }\n\n has(id) {\n return this.#areas.has(id);\n }\n\n get areas() {\n return Array.from(this.#areas.values());\n }\n\n clear() {\n this.#areas.clear();\n }\n}", "import { ServiceProvider } from '@jucie.io/engine';\n\nexport class CanvasEvents extends ServiceProvider {\n #canvas = null;\n #offscreenCanvas = null;\n #cachedRect = null;\n #resizeObserver = null;\n #subscribers = new Set();\n #resizeSubscribers = new Set();\n #pendingMove = null;\n #rafId = null;\n #hasTransferredControl = false;\n\n static manifest = {\n name: 'CanvasEvents',\n namespace: 'canvasEvents',\n version: '1.0.0'\n };\n\n actions() {\n return {\n setCanvas: (canvas) => this.setCanvas(canvas),\n subscribe: (listener) => this.subscribe(listener),\n onResize: (listener) => this.onResize(listener),\n transferControlToOffscreen: () => this.transferControlToOffscreen()\n };\n }\n\n setCanvas(canvas) {\n if (this.#canvas) {\n this.#removeListeners();\n }\n \n this.#canvas = canvas;\n this.#updateCachedRect();\n this.#initializeListeners();\n }\n\n subscribe(subscriber) {\n this.#subscribers.add(subscriber);\n return () => this.#subscribers.delete(subscriber);\n }\n\n onResize(subscriber) {\n this.#resizeSubscribers.add(subscriber);\n return () => this.#resizeSubscribers.delete(subscriber);\n }\n\n transferControlToOffscreen() {\n if (!this.#canvas) {\n throw new Error('Canvas must be set before transferring control to offscreen');\n }\n\n if (this.#hasTransferredControl) {\n throw new Error('Control has already been transferred to offscreen');\n }\n\n // Transfer control\n this.#offscreenCanvas = this.#canvas.transferControlToOffscreen();\n this.#hasTransferredControl = true;\n\n // Set initial dimensions on offscreen canvas\n this.#offscreenCanvas.width = this.#canvas.width;\n this.#offscreenCanvas.height = this.#canvas.height;\n\n // Emit initial resize event with actual canvas dimensions\n this.#emitResize({\n width: this.#canvas.width,\n height: this.#canvas.height\n });\n\n return this.#offscreenCanvas;\n }\n\n #updateCachedRect() {\n if (this.#canvas) {\n this.#cachedRect = this.#canvas.getBoundingClientRect();\n }\n }\n\n #initializeListeners() {\n if (!this.#canvas) return;\n\n this.#updateCachedRect();\n\n this.#resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target !== this.#canvas) {\n continue;\n }\n const { width, height } = entry.contentRect;\n this.#emitResize({\n width: width,\n height: height\n });\n }\n this.#updateCachedRect();\n });\n this.#resizeObserver.observe(this.#canvas);\n\n document.addEventListener('wheel', this.#handleScroll, { passive: false });\n document.addEventListener('pointermove', this.#handleMove);\n document.addEventListener('pointerdown', this.#handleDown);\n document.addEventListener('pointerup', this.#handleUp);\n document.addEventListener('pointercancel', this.#handleUp);\n document.addEventListener('dblclick', this.#handleDblClick);\n }\n\n #removeListeners() {\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n\n document.removeEventListener('wheel', this.#handleScroll);\n document.removeEventListener('pointermove', this.#handleMove);\n document.removeEventListener('pointerdown', this.#handleDown);\n document.removeEventListener('pointerup', this.#handleUp);\n document.removeEventListener('pointercancel', this.#handleUp);\n document.removeEventListener('dblclick', this.#handleDblClick);\n }\n\n #handleScroll = (event) => {\n if (event.target !== this.#canvas) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n \n if (event.ctrlKey) {\n const normalized = this.#normalizeEvent(event, 'zoom');\n this.#emit(normalized);\n } else {\n const normalized = this.#normalizeEvent(event, 'scroll');\n this.#emit(normalized);\n }\n }\n\n #handleMove = (event) => {\n const normalized = this.#normalizeEvent(event, 'move');\n \n // Store latest move and throttle with RAF\n this.#pendingMove = normalized;\n if (this.#rafId) return;\n \n this.#rafId = requestAnimationFrame(() => {\n if (this.#pendingMove) {\n this.#emit(this.#pendingMove);\n this.#pendingMove = null;\n }\n this.#rafId = null;\n });\n }\n\n #handleDown = (event) => {\n // Only capture if starting on canvas\n if (event.target === this.#canvas) {\n const normalized = this.#normalizeEvent(event, 'down');\n this.#emit(normalized); // Immediate\n }\n }\n\n #handleUp = (event) => {\n // Use the actual up event position, not pending move\n const normalized = this.#normalizeEvent(event, 'up');\n this.#emit(normalized); // Immediate\n }\n\n #handleDblClick = (event) => {\n const normalized = this.#normalizeEvent(event, 'dblclick');\n this.#emit(normalized);\n }\n\n #emit(event) {\n for (const subscriber of this.#subscribers) {\n subscriber(event);\n }\n }\n\n #emitResize(resizeData) {\n for (const subscriber of this.#resizeSubscribers) {\n subscriber(resizeData);\n }\n }\n\n #normalizeEvent(event, type) {\n const isOverCanvas = event.target === this.#canvas;\n \n let x, y;\n if (isOverCanvas) {\n x = event.offsetX;\n y = event.offsetY;\n } else if (this.#cachedRect) {\n x = event.clientX - this.#cachedRect.left;\n y = event.clientY - this.#cachedRect.top;\n } else {\n x = event.clientX;\n y = event.clientY;\n }\n\n const isWithinBounds = isOverCanvas || (\n this.#cachedRect &&\n x >= 0 && \n x <= this.#cachedRect.width && \n y >= 0 && \n y <= this.#cachedRect.height\n );\n\n const normalized = {\n x,\n y,\n type,\n isOverCanvas,\n isWithinBounds,\n clientX: event.clientX,\n clientY: event.clientY,\n button: event.button ?? null,\n buttons: event.buttons ?? 0,\n timestamp: Date.now()\n };\n\n // Add wheel-specific data for scroll/zoom\n if (type === 'scroll' || type === 'zoom') {\n normalized.deltaX = event.deltaX;\n normalized.deltaY = event.deltaY;\n normalized.deltaZ = event.deltaZ;\n normalized.deltaMode = event.deltaMode;\n }\n\n // Add modifier keys\n normalized.shiftKey = event.shiftKey || false;\n normalized.ctrlKey = event.ctrlKey || false;\n normalized.altKey = event.altKey || false;\n normalized.metaKey = event.metaKey || false;\n\n return normalized;\n }\n\n destroy() {\n if (this.#rafId) {\n cancelAnimationFrame(this.#rafId);\n this.#rafId = null;\n }\n this.#removeListeners();\n this.#canvas = null;\n this.#offscreenCanvas = null;\n this.#cachedRect = null;\n this.#subscribers.clear();\n this.#resizeSubscribers.clear();\n this.#hasTransferredControl = false;\n }\n}\n", "import { defineSurface } from '@jucie.io/reactive';\n\nexport const usePointerSurface = defineSurface((setup) => {\n // ============= Core State =============\n \n // Position (canvas coordinates)\n const x = setup.value(0);\n const y = setup.value(0);\n const prevX = setup.value(0);\n const prevY = setup.value(0);\n \n // Client position (screen coordinates)\n const clientX = setup.value(0);\n const clientY = setup.value(0);\n \n // Canvas boundary state\n const isOverCanvas = setup.value(false);\n const isWithinBounds = setup.value(false);\n \n // Button state\n const isPressed = setup.value(false);\n const button = setup.value(null); // 0=left, 1=middle, 2=right\n const buttons = setup.value(0); // Bitmask of pressed buttons\n \n // Event type tracking\n const lastEventType = setup.value(null);\n \n // Timing\n const downTime = setup.value(null);\n const upTime = setup.value(null);\n const lastMoveTime = setup.value(null);\n const lastEventTime = setup.value(null);\n \n // Drag state\n const dragStartX = setup.value(null);\n const dragStartY = setup.value(null);\n const isDragging = setup.value(false);\n \n // Click detection\n const clickCount = setup.value(0);\n const lastClickTime = setup.value(0);\n \n // Velocity tracking\n const velocityX = setup.value(0);\n const velocityY = setup.value(0);\n \n // Scroll/Zoom state\n const lastScrollDeltaX = setup.value(0);\n const lastScrollDeltaY = setup.value(0);\n const lastZoomDelta = setup.value(0);\n \n // Hit areas (from HitRegistry)\n const hoveredArea = setup.value(null);\n const activeArea = setup.value(null);\n \n // ============= Configuration =============\n const config = setup.value({\n dragThreshold: 5,\n doubleClickThreshold: 300,\n holdThreshold: 500,\n velocitySmoothing: 0.3,\n maxVelocity: 10000 // Clamp unrealistic velocities\n });\n \n // ============= Computed Values =============\n \n const position = setup.computed(() => ({\n x: x.value,\n y: y.value\n }));\n \n const clientPosition = setup.computed(() => ({\n x: clientX.value,\n y: clientY.value\n }));\n \n const previousPosition = setup.computed(() => ({\n x: prevX.value,\n y: prevY.value\n }));\n \n const delta = setup.computed(() => {\n const xVal = typeof x.value === 'number' ? x.value : 0;\n const prevXVal = typeof prevX.value === 'number' ? prevX.value : 0;\n const yVal = typeof y.value === 'number' ? y.value : 0;\n const prevYVal = typeof prevY.value === 'number' ? prevY.value : 0;\n return {\n x: xVal - prevXVal,\n y: yVal - prevYVal\n };\n });\n \n const velocity = setup.computed(() => ({\n x: velocityX.value,\n y: velocityY.value\n }));\n \n const speed = setup.computed(() => {\n const vx = velocityX.value;\n const vy = velocityY.value;\n return Math.sqrt(vx * vx + vy * vy);\n });\n \n const dragDistance = setup.computed(() => {\n const startX = dragStartX.value;\n const startY = dragStartY.value;\n if (startX === null || startY === null || typeof startX !== 'number' || typeof startY !== 'number') return 0;\n \n const xVal = typeof x.value === 'number' ? x.value : 0;\n const yVal = typeof y.value === 'number' ? y.value : 0;\n const dx = xVal - startX;\n const dy = yVal - startY;\n return Math.sqrt(dx * dx + dy * dy);\n });\n \n const dragDelta = setup.computed(() => {\n const startX = dragStartX.value;\n const startY = dragStartY.value;\n if (startX === null || startY === null || typeof startX !== 'number' || typeof startY !== 'number') {\n return { x: 0, y: 0 };\n }\n const xVal = typeof x.value === 'number' ? x.value : 0;\n const yVal = typeof y.value === 'number' ? y.value : 0;\n return {\n x: xVal - startX,\n y: yVal - startY\n };\n });\n \n const holdDuration = setup.computed(() => {\n if (!isPressed.value || !downTime.value) return 0;\n return Date.now() - downTime.value;\n });\n \n const isHolding = setup.computed(() => {\n return holdDuration.value > config.value.holdThreshold && !isDragging.value;\n });\n \n const timeSinceLastEvent = setup.computed(() => {\n const lastTime = lastEventTime.value;\n return lastTime ? Date.now() - lastTime : 0;\n });\n \n // Full state snapshot\n const state = setup.computed(() => ({\n position: position.value,\n clientPosition: clientPosition.value,\n previousPosition: previousPosition.value,\n delta: delta.value,\n velocity: velocity.value,\n speed: speed.value,\n isPressed: isPressed.value,\n button: button.value,\n buttons: buttons.value,\n isDragging: isDragging.value,\n dragDistance: dragDistance.value,\n dragDelta: dragDelta.value,\n isHolding: isHolding.value,\n holdDuration: holdDuration.value,\n isOverCanvas: isOverCanvas.value,\n isWithinBounds: isWithinBounds.value,\n hoveredArea: hoveredArea.value,\n activeArea: activeArea.value,\n clickCount: clickCount.value,\n lastEventType: lastEventType.value\n }));\n \n // ============= Actions =============\n \n const updatePosition = (newX, newY, newClientX, newClientY) => {\n prevX.value = x.value;\n prevY.value = y.value;\n x.value = newX;\n y.value = newY;\n clientX.value = newClientX;\n clientY.value = newClientY;\n lastMoveTime.value = Date.now();\n };\n\n const updateVelocity = () => {\n const now = Date.now();\n const lastMove = lastMoveTime.value;\n \n if (lastMove) {\n const dt = (now - lastMove) / 1000;\n if (dt > 0 && dt < 0.1) {\n const newVx = (x.value - prevX.value) / dt;\n const newVy = (y.value - prevY.value) / dt;\n \n // Clamp unrealistic velocities\n const maxVel = config.value.maxVelocity;\n const clampedVx = Math.max(-maxVel, Math.min(maxVel, newVx));\n const clampedVy = Math.max(-maxVel, Math.min(maxVel, newVy));\n \n // Apply smoothing\n const smoothing = config.value.velocitySmoothing;\n velocityX.value = velocityX.value * (1 - smoothing) + clampedVx * smoothing;\n velocityY.value = velocityY.value * (1 - smoothing) + clampedVy * smoothing;\n }\n }\n };\n \n // Main event handler - consumes normalized events from CanvasEvents\n const handleEvent = setup.action((ctx, normalizedEvent) => {\n const { x: newX, y: newY, type, clientX: newClientX, clientY: newClientY, button: eventButton, buttons: eventButtons, isOverCanvas: eventIsOverCanvas, isWithinBounds: eventIsWithinBounds } = normalizedEvent;\n const now = Date.now();\n \n lastEventTime.value = now;\n lastEventType.value = type;\n isOverCanvas.value = eventIsOverCanvas;\n isWithinBounds.value = eventIsWithinBounds;\n \n switch (type) {\n case 'down':\n updatePosition(newX, newY, newClientX, newClientY);\n isPressed.value = true;\n downTime.value = now;\n button.value = eventButton;\n buttons.value = eventButtons;\n dragStartX.value = newX;\n dragStartY.value = newY;\n isDragging.value = false;\n \n // Double-click detection\n const timeSinceLastClick = now - lastClickTime.value;\n if (timeSinceLastClick < config.value.doubleClickThreshold) {\n clickCount.value = clickCount.value + 1;\n } else {\n clickCount.value = 1;\n }\n break;\n \n case 'up':\n updatePosition(newX, newY, newClientX, newClientY);\n isPressed.value = false;\n upTime.value = now;\n lastClickTime.value = now;\n isDragging.value = false;\n velocityX.value = 0;\n velocityY.value = 0;\n buttons.value = eventButtons;\n break;\n \n case 'move':\n updatePosition(newX, newY, newClientX, newClientY);\n updateVelocity();\n buttons.value = eventButtons;\n \n // Check for drag start\n if (isPressed.value && !isDragging.value) {\n const distance = dragDistance.value;\n if (distance > config.value.dragThreshold) {\n isDragging.value = true;\n }\n }\n break;\n \n case 'dblclick':\n updatePosition(newX, newY, newClientX, newClientY);\n clickCount.value = 2;\n break;\n \n case 'scroll':\n updatePosition(newX, newY, newClientX, newClientY);\n // Extract wheel delta from event if available\n if (normalizedEvent.deltaX !== undefined) {\n lastScrollDeltaX.value = normalizedEvent.deltaX;\n }\n if (normalizedEvent.deltaY !== undefined) {\n lastScrollDeltaY.value = normalizedEvent.deltaY;\n }\n break;\n \n case 'zoom':\n updatePosition(newX, newY, newClientX, newClientY);\n if (normalizedEvent.deltaY !== undefined) {\n lastZoomDelta.value = normalizedEvent.deltaY;\n }\n break;\n }\n });\n \n const setHoveredArea = setup.action((ctx, area) => {\n hoveredArea.value = area;\n });\n \n const setActiveArea = setup.action((ctx, area) => {\n activeArea.value = area;\n });\n \n const reset = setup.action(() => {\n isPressed.value = false;\n isDragging.value = false;\n activeArea.value = null;\n hoveredArea.value = null;\n velocityX.value = 0;\n velocityY.value = 0;\n clickCount.value = 0;\n lastScrollDeltaX.value = 0;\n lastScrollDeltaY.value = 0;\n lastZoomDelta.value = 0;\n });\n \n const updateConfig = setup.action((ctx, updates) => {\n config.value = { ...config.value, ...updates };\n });\n \n // ============= Return Public API =============\n return {\n // State (read-only through computed)\n state,\n position,\n clientPosition,\n previousPosition,\n delta,\n velocity,\n speed,\n isPressed,\n button,\n buttons,\n isDragging,\n dragDistance,\n dragDelta,\n isHolding,\n holdDuration,\n isOverCanvas,\n isWithinBounds,\n hoveredArea,\n activeArea,\n clickCount,\n lastEventType,\n timeSinceLastEvent,\n \n // Actions\n handleEvent, // Main entry point for normalized events\n setHoveredArea,\n setActiveArea,\n reset,\n updateConfig\n };\n});\n", "import { ServiceProvider } from '@jucie.io/engine';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createComputed, destroyComputed, addEffect } from '@jucie.io/reactive';\nimport { createDefinition, definitionType } from '@jucie.io/engine';\nimport { HitRegistry } from './HitRegistry.js';\nimport { CanvasEvents } from './CanvasEvents.js';\nimport { usePointerSurface } from './usePointerSurface.js';\n\nexport const defineBrush = createDefinition('BRUSH', [Object]);\nexport const defineLayer = createDefinition('LAYER', [Object]);\n\nexport class Painter extends ServiceProvider {\n #layers = new Map();\n #canvas = null; // Always OffscreenCanvas\n #contexts = new Map();\n #reactors = new Map();\n #assets = new Map();\n #isRunning = false;\n #frameId = null;\n #isRendering = false;\n #renderScheduled = false;\n\n // Mutable runtime config (separate from frozen config)\n #runtimeConfig = {\n targetFPS: 60,\n fixedTimeStep: 1000 / 60,\n timeScale: 1.0,\n debug: {\n enabled: false,\n showFPS: true,\n showBounds: true,\n showLayerTiming: true\n }\n };\n\n // Timing state\n #timing = {\n lastFrameTime: 0,\n deltaTime: 0,\n elapsedTime: 0,\n frameCount: 0\n };\n\n // Debug metrics\n #metrics = {\n fps: 0,\n frameTime: 0,\n layerTimes: new Map(),\n brushTimes: new Map(),\n skippedFrames: 0\n };\n\n // Hit detection state\n #hitRegistry = new HitRegistry();\n #pointerSurface = usePointerSurface();\n #canvasEvents = null; // Only created in main thread mode\n #pointerUnsubscribe = null;\n #resizeObserver = null; // For main thread canvas resize watching\n #subscribers = new Map(); // Map<event, Set<callback>>\n \n // Track state for event emission\n #wasDragging = false;\n #wasOverCanvas = false;\n #wasHolding = false;\n\n static manifest = {\n name: 'Painter',\n namespace: 'painter',\n version: '1.0.0',\n defaults: {\n // Timing configuration\n targetFPS: 60,\n fixedTimeStep: 1000 / 60,\n timeScale: 1.0,\n // Debug configuration\n debug: {\n enabled: false,\n showFPS: true,\n showBounds: true,\n showLayerTiming: true\n }\n }\n };\n\n getters () {\n return {\n pointer: () => this.#pointerSurface.state,\n };\n }\n\n actions() {\n // Initialize runtime config from frozen config\n if (this.config) {\n Object.assign(this.#runtimeConfig, this.config);\n }\n \n return {\n addLayer: (layerDef) => this.addLayer(layerDef),\n addLayers: (...layers) => {\n for (const layer of layers) {\n this.addLayer(layer);\n }\n },\n updateCanvas: (fn) => this.updateCanvas(fn),\n setCanvas: (canvas) => this.setCanvas(canvas),\n setOffscreenCanvas: (offscreenCanvas) => this.setOffscreenCanvas(offscreenCanvas),\n setAssets: (assets) => this.setAssets(assets),\n removeLayer: (name) => this.removeLayer(name),\n start: () => this.start(),\n stop: () => this.stop(),\n render: () => this.render(),\n setTargetFPS: (fps) => this.setTargetFPS(fps),\n setTimeScale: (scale) => this.setTimeScale(scale),\n setFixedTimeStep: (step) => this.setFixedTimeStep(step),\n setDebug: (options) => this.setDebug(options),\n getMetrics: () => this.getMetrics(),\n handleResize: (width, height) => this.handleResize(width, height),\n subscribe: (event, callback) => this.subscribe(event, callback),\n // Pointer API - receives normalized events from main thread\n handlePointerEvent: (normalizedEvent) => this.handlePointerEvent(normalizedEvent),\n subscribeToPointer: (callback) => this.#pointerSurface.$subscribe(callback),\n bindPointer: (path) => this.#pointerSurface.$bind(path),\n // Test helper - only for testing\n _testEmitPointerEvent: (normalizedEvent) => this._testEmitPointerEvent(normalizedEvent)\n };\n }\n\n // Main thread mode: Pass regular canvas, we create OffscreenCanvas + CanvasEvents\n setCanvas(canvas) {\n // Store reference to DOM canvas for resize observation\n const domCanvas = canvas;\n \n // Transfer control to offscreen\n const offscreenCanvas = canvas.transferControlToOffscreen();\n \n // Set initial dimensions\n offscreenCanvas.width = domCanvas.width;\n offscreenCanvas.height = domCanvas.height;\n \n this.#canvas = offscreenCanvas;\n \n // Create contexts for each type\n Object.values(ContextTypes).forEach(type => {\n try {\n const ctx = offscreenCanvas.getContext(type);\n if (ctx) this.#contexts.set(type, ctx);\n } catch (e) {\n console.warn(`Context type ${type} not supported`);\n }\n });\n\n // Create and set up canvas events (main thread only)\n if (!this.#canvasEvents) {\n this.#canvasEvents = new CanvasEvents();\n }\n \n this.#canvasEvents.setCanvas(domCanvas);\n\n // Watch for canvas resizes and sync to offscreen canvas\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n }\n \n this.#resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry && entry.target === domCanvas) {\n // Sync dimensions to offscreen canvas\n offscreenCanvas.width = domCanvas.width;\n offscreenCanvas.height = domCanvas.height;\n \n // Notify layers of resize\n this.handleResize(domCanvas.width, domCanvas.height);\n }\n });\n \n this.#resizeObserver.observe(domCanvas);\n\n // Connect canvas events to surface\n if (this.#pointerUnsubscribe) {\n this.#pointerUnsubscribe();\n }\n\n this.#pointerUnsubscribe = this.#canvasEvents.subscribe((normalizedEvent) => {\n this.handlePointerEvent(normalizedEvent);\n });\n }\n\n // Worker thread mode: Accept pre-created OffscreenCanvas, expect external events\n setOffscreenCanvas(offscreenCanvas) {\n this.#canvas = offscreenCanvas;\n \n // Create contexts for each type\n Object.values(ContextTypes).forEach(type => {\n try {\n const ctx = offscreenCanvas.getContext(type);\n if (ctx) this.#contexts.set(type, ctx);\n } catch (e) {\n console.warn(`Context type ${type} not supported`);\n }\n });\n\n // Don't create CanvasEvents - events will come from external source\n // via handlePointerEvent()\n }\n\n updateCanvas(fn) {\n const result = fn(this.#canvas);\n if (result) {\n this.#canvas = result;\n }\n }\n\n setAssets(assets) {\n this.#assets = assets;\n }\n\n start() {\n if (!this.#isRunning) {\n this.#isRunning = true;\n this.#scheduleRender();\n }\n }\n\n stop() {\n if (this.#isRunning) {\n this.#isRunning = false;\n if (this.#frameId) {\n cancelAnimationFrame(this.#frameId);\n this.#frameId = null;\n }\n }\n }\n\n addLayer(layerDef) {\n if (definitionType(layerDef) !== 'LAYER') {\n throw new Error('Invalid layer definition');\n }\n\n const name = layerDef._name;\n const config = layerDef(this.useContext, this.#hitRegistry);\n \n // Set up layer computed if it has data paths\n if (config.data) {\n const dataReactor = this.#createDataReactor(`layer_${name}`, config.data);\n if (dataReactor) {\n this.#reactors.set(`layer_${name}`, dataReactor);\n }\n }\n\n // Set up brush reactors and structure\n const brushes = config.children.map(child => {\n if (definitionType(child) === 'BRUSH') {\n const name = child._name;\n const brushConfig = child(this.useContext, this.#hitRegistry);\n \n // Only create data computed if data exists\n const dataReactor = brushConfig.data \n ? this.#createDataReactor(`brush_${name}`, brushConfig.data)\n : () => undefined;\n \n const whenReactor = brushConfig.when \n ? createComputed(brushConfig.when, {\n immediate: true,\n context: () => this.#pointerSurface.state\n })\n : null;\n\n const brush = {\n name,\n ...brushConfig,\n dataReactor,\n whenReactor\n };\n\n // Call brush mount hook\n if (brush.lifecycle?.onMount) {\n try {\n brush.lifecycle.onMount(this.#contexts.get(brush.context || config.context));\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\" onMount:`, error);\n }\n }\n\n return brush;\n }\n // Handle nested layers recursively\n return this.addLayer(child);\n });\n\n const layer = {\n ...config,\n name,\n brushes,\n context: this.#contexts.get(config.context)\n };\n\n this.#layers.set(name, layer);\n\n // Call layer mount hook\n if (layer.lifecycle?.onMount) {\n try {\n layer.lifecycle.onMount(layer.context);\n } catch (error) {\n console.error(`Error in layer \"${name}\" onMount:`, error);\n }\n }\n\n return layer;\n }\n\n removeLayer(name) {\n const layer = this.#layers.get(name);\n if (!layer) return;\n\n // Call layer unmount hook\n if (layer.lifecycle?.onUnmount) {\n try {\n layer.lifecycle.onUnmount(layer.context);\n } catch (error) {\n console.error(`Error in layer \"${name}\" onUnmount:`, error);\n }\n }\n\n // Call brush unmount hooks and clean up reactors\n layer.brushes.forEach(brush => {\n if (brush.lifecycle?.onUnmount) {\n try {\n brush.lifecycle.onUnmount(\n this.#contexts.get(brush.context || layer.context)\n );\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\" onUnmount:`, error);\n }\n }\n // Clean up brush computed and subscription\n const reactorData = this.#reactors.get(`painter_brush_${brush.name}`);\n if (reactorData) {\n reactorData.unsubscribe();\n if (reactorData.computed) {\n destroyComputed(reactorData.computed);\n }\n this.#reactors.delete(`painter_brush_${brush.name}`);\n }\n });\n\n // Clean up layer computed and subscription\n const layerReactorData = this.#reactors.get(`painter_layer_${name}`);\n if (layerReactorData) {\n layerReactorData.unsubscribe();\n if (layerReactorData.computed) {\n destroyComputed(layerReactorData.computed);\n }\n this.#reactors.delete(`painter_layer_${name}`);\n }\n\n this.#layers.delete(name);\n }\n\n #scheduleRender() {\n if (this.#renderScheduled || this.#isRendering) return;\n \n this.#renderScheduled = true;\n \n this.#frameId = requestAnimationFrame(() => {\n this.#renderScheduled = false;\n this.#frameId = null;\n this.#render();\n });\n }\n\n async #render() {\n if (!this.#canvas) return;\n this.#isRendering = true;\n \n try {\n // Clear hit registry at start of render\n this.#hitRegistry.clear();\n \n const renderStart = this.#runtimeConfig.debug?.enabled ? performance.now() : 0;\n\n // Clear all contexts\n this.#contexts.forEach(ctx => {\n ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height);\n });\n\n // Render layers in order\n for (const layer of this.#layers.values()) {\n const layerStart = this.#runtimeConfig.debug?.enabled ? performance.now() : 0;\n\n // Check layer condition\n if (layer.whenReactor) {\n const layerReactor = this.#reactors.get(`painter_layer_${layer.name}`)?.computed;\n if (!layer.when(layerReactor())) continue;\n }\n\n const ctx = layer.context;\n\n if (!ctx) continue;\n\n // Layer beforeRender hook\n if (layer.lifecycle?.beforeRender) {\n try {\n layer.lifecycle.beforeRender(ctx, this.#timing);\n } catch (error) {\n console.error(`Error in layer \"${layer.name}\" beforeRender:`, error);\n if (layer.lifecycle?.onError) layer.lifecycle.onError(error);\n }\n }\n\n // Apply layer settings\n ctx.save();\n if (layer.settings) {\n Object.entries(layer.settings).forEach(([key, value]) => {\n if (typeof ctx[key] === 'function') {\n ctx[key](...(Array.isArray(value) ? value : [value]));\n } else {\n ctx[key] = value;\n }\n });\n }\n\n // Render brushes\n for (const brush of layer.brushes) {\n const brushStart = this.#runtimeConfig.debug?.enabled ? performance.now() : 0;\n\n if (brush.whenReactor && !brush.whenReactor()) continue;\n\n\n const brushCtx = brush.context ? \n this.#contexts.get(brush.context) : \n ctx;\n\n if (!brushCtx) continue;\n\n // Brush beforeRender hook\n if (brush.lifecycle?.beforeRender) {\n try {\n brush.lifecycle.beforeRender(brushCtx, this.#timing);\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\" beforeRender:`, error);\n if (brush.lifecycle?.onError) brush.lifecycle.onError(error);\n continue;\n }\n }\n\n brushCtx.save();\n \n if (brush.settings) {\n Object.entries(brush.settings).forEach(([key, value]) => {\n if (typeof brushCtx[key] === 'function') {\n brushCtx[key](...(Array.isArray(value) ? value : [value]));\n } else {\n brushCtx[key] = value;\n }\n });\n }\n \n try {\n const requiredAssets = {};\n if (brush.assets) {\n for (const key of brush.assets) {\n requiredAssets[key] = this.#assets.get(key);\n }\n }\n brush.render(brushCtx, brush.dataReactor(), requiredAssets, this.#timing);\n\n // Brush afterRender hook\n if (brush.lifecycle?.afterRender) {\n brush.lifecycle.afterRender(brushCtx, this.#timing);\n }\n\n if (this.#runtimeConfig.debug?.enabled) {\n const brushTime = performance.now() - brushStart;\n this.#metrics.brushTimes.set(brush.name, brushTime);\n\n if (this.#runtimeConfig.debug?.showBounds) {\n this.#renderBrushBounds(brushCtx, brush);\n }\n }\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\":`, error);\n if (brush.lifecycle?.onError) brush.lifecycle.onError(error);\n } finally {\n brushCtx.restore();\n }\n }\n\n ctx.restore();\n\n // Layer afterRender hook\n if (layer.lifecycle?.afterRender) {\n try {\n layer.lifecycle.afterRender(ctx, this.#timing);\n } catch (error) {\n console.error(`Error in layer \"${layer.name}\" afterRender:`, error);\n if (layer.lifecycle?.onError) layer.lifecycle.onError(error);\n }\n }\n\n if (this.#runtimeConfig.debug?.enabled) {\n const layerTime = performance.now() - layerStart;\n this.#metrics.layerTimes.set(layer.name, layerTime);\n\n if (this.#runtimeConfig.debug?.showBounds) {\n this.#renderLayerBounds(ctx, layer);\n }\n }\n }\n\n // Render debug overlay if enabled\n if (this.#runtimeConfig.debug?.enabled) {\n this.#renderDebugOverlay();\n }\n \n } finally {\n this.#isRendering = false;\n }\n }\n\n #renderBrushBounds(ctx, brush) {\n ctx.save();\n ctx.strokeStyle = 'rgba(0, 255, 0, 0.5)';\n ctx.lineWidth = 1;\n ctx.strokeRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n ctx.restore();\n }\n\n #renderLayerBounds(ctx, layer) {\n ctx.save();\n ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)';\n ctx.lineWidth = 2;\n ctx.strokeRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n ctx.restore();\n }\n\n #renderDebugOverlay() {\n const ctx = this.#contexts.get(ContextTypes['2D']);\n if (!ctx) return;\n\n ctx.save();\n ctx.resetTransform();\n ctx.font = '12px monospace';\n ctx.fillStyle = 'white';\n ctx.strokeStyle = 'black';\n ctx.lineWidth = 3;\n\n let y = 20;\n const lineHeight = 15;\n\n if (this.#runtimeConfig.debug?.showFPS) {\n const text = `FPS: ${Math.round(this.#metrics.fps)} (${this.#timing.deltaTime.toFixed(2)}ms)`;\n ctx.strokeText(text, 10, y);\n ctx.fillText(text, 10, y);\n y += lineHeight;\n }\n\n if (this.#runtimeConfig.debug?.showLayerTiming) {\n ctx.fillText('Layer Times:', 10, y);\n y += lineHeight;\n\n for (const [name, time] of this.#metrics.layerTimes) {\n const text = ` ${name}: ${time.toFixed(2)}ms`;\n ctx.strokeText(text, 10, y);\n ctx.fillText(text, 10, y);\n y += lineHeight;\n }\n\n ctx.fillText(this.state.get(['_transitions', 'pointer', 'currentState']), 10, y);\n }\n\n ctx.restore();\n }\n\n handleResize(width, height) {\n // Call onResize hooks for all layers\n for (const layer of this.#layers.values()) {\n if (layer.lifecycle?.onResize) {\n try {\n layer.lifecycle.onResize(width, height, layer.context);\n } catch (error) {\n console.error(`Error in layer \"${layer.name}\" onResize:`, error);\n if (layer.lifecycle?.onError) layer.lifecycle.onError(error);\n }\n }\n }\n }\n\n #createDataReactor(id, data) {\n const computed = createComputed(data, {\n immediate: true,\n context: () => this.#pointerSurface.state\n });\n\n const unsubscribe = addEffect(computed, () => this.#scheduleRender());\n\n this.#reactors.set(`painter_${id}`, {\n computed,\n unsubscribe\n });\n\n return computed;\n }\n\n destroy() {\n this.stop();\n\n // Clean up pointer system\n if (this.#pointerUnsubscribe) {\n this.#pointerUnsubscribe();\n this.#pointerUnsubscribe = null;\n }\n if (this.#canvasEvents) {\n this.#canvasEvents.destroy();\n this.#canvasEvents = null;\n }\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n if (this.#pointerSurface) {\n this.#pointerSurface.$destroy();\n }\n\n // Clean up all layers and reactors\n for (const name of this.#layers.keys()) {\n this.removeLayer(name);\n }\n }\n\n setTargetFPS(fps) {\n this.#runtimeConfig.targetFPS = fps;\n this.#runtimeConfig.fixedTimeStep = 1000 / fps;\n }\n\n setTimeScale(scale) {\n this.#runtimeConfig.timeScale = Math.max(0, scale);\n }\n\n setFixedTimeStep(step) {\n this.#runtimeConfig.fixedTimeStep = step;\n }\n\n setDebug(options = {}) {\n if (!this.#runtimeConfig.debug) {\n this.#runtimeConfig.debug = {};\n }\n Object.assign(this.#runtimeConfig.debug, options);\n }\n\n getMetrics() {\n return {\n ...this.#metrics,\n deltaTime: this.#timing.deltaTime,\n elapsedTime: this.#timing.elapsedTime,\n frameCount: this.#timing.frameCount\n };\n }\n\n // Public method to receive pointer events from main thread\n handlePointerEvent(normalizedEvent) {\n // Feed normalized events into surface\n this.#pointerSurface.handleEvent(normalizedEvent);\n\n // Handle hit testing and interactions\n this.#handlePointerInteraction(normalizedEvent);\n \n // Emit generic pointer events for external subscribers\n this.#emitPointerEvents(normalizedEvent);\n }\n\n #emitPointerEvents(normalizedEvent) {\n const { type } = normalizedEvent;\n const pointer = this.#pointerSurface;\n \n // Emit basic pointer events\n switch (type) {\n case 'down':\n this.#emit('pointer:down', pointer.state);\n break;\n \n case 'up':\n this.#emit('pointer:up', pointer.state);\n \n // Emit click if it wasn't a drag\n if (!pointer.isDragging) {\n this.#emit('pointer:click', pointer.state);\n }\n break;\n \n case 'move':\n this.#emit('pointer:move', pointer.state);\n \n // Check for drag start/move\n if (pointer.isDragging && pointer.isPressed) {\n const wasDragging = this.#wasDragging;\n this.#wasDragging = true;\n \n if (!wasDragging) {\n this.#emit('pointer:drag:start', pointer.state);\n } else {\n this.#emit('pointer:drag:move', pointer.state);\n }\n }\n break;\n \n case 'scroll':\n this.#emit('pointer:scroll', pointer.state);\n break;\n \n case 'zoom':\n this.#emit('pointer:zoom', pointer.state);\n break;\n \n case 'dblclick':\n this.#emit('pointer:dblclick', pointer.state);\n break;\n }\n \n // Check for drag end\n if (type === 'up' && this.#wasDragging) {\n this.#emit('pointer:drag:end', pointer.state);\n this.#wasDragging = false;\n }\n \n // Check for canvas enter/leave\n const wasOverCanvas = this.#wasOverCanvas;\n const isOverCanvas = pointer.isOverCanvas;\n \n if (isOverCanvas && !wasOverCanvas) {\n this.#emit('pointer:enter', pointer.state);\n } else if (!isOverCanvas && wasOverCanvas) {\n this.#emit('pointer:leave', pointer.state);\n }\n \n this.#wasOverCanvas = isOverCanvas;\n \n // Check for hold start/end\n const wasHolding = this.#wasHolding;\n const isHolding = pointer.isHolding;\n \n if (isHolding && !wasHolding) {\n this.#emit('pointer:hold:start', pointer.state);\n } else if (!isHolding && wasHolding) {\n this.#emit('pointer:hold:end', pointer.state);\n }\n \n this.#wasHolding = isHolding;\n }\n\n #handlePointerInteraction(normalizedEvent) {\n const { type, x, y } = normalizedEvent;\n const pointer = this.#pointerSurface;\n\n switch (type) {\n case 'down': {\n const hitArea = this.#hitTest(x, y);\n pointer.setActiveArea(hitArea);\n\n if (hitArea?.onPointerDown?.handler) {\n const ctx = this.#getContextForArea(hitArea);\n hitArea.onPointerDown.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n break;\n }\n\n case 'up': {\n const activeArea = pointer.activeArea;\n if (activeArea?.onPointerUp?.handler) {\n const ctx = this.#getContextForArea(activeArea);\n activeArea.onPointerUp.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n break;\n }\n\n case 'move': {\n const hitArea = this.#hitTest(x, y);\n const prevHovered = pointer.hoveredArea;\n\n // Handle drag on active area\n const activeArea = pointer.activeArea;\n if (activeArea?.onPointerMove?.handler && pointer.isDragging) {\n const ctx = this.#getContextForArea(activeArea);\n activeArea.onPointerMove.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n\n // Handle hover changes\n if (hitArea?.id !== prevHovered?.id) {\n if (prevHovered?.onPointerLeave?.handler) {\n const ctx = this.#getContextForArea(prevHovered);\n prevHovered.onPointerLeave.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n\n if (hitArea?.onPointerEnter?.handler) {\n const ctx = this.#getContextForArea(hitArea);\n hitArea.onPointerEnter.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n\n pointer.setHoveredArea(hitArea);\n }\n break;\n }\n\n case 'scroll':\n case 'zoom':\n // These are already emitted in #emitPointerEvents\n break;\n\n case 'dblclick':\n // This is already emitted in #emitPointerEvents\n break;\n }\n }\n\n #getContextForArea(area) {\n if (!area) return null;\n return area.context \n ? this.#contexts.get(area.context) \n : this.#contexts.get(ContextTypes['2D']);\n }\n\n subscribe(event, callback) {\n if (!this.#subscribers.has(event)) {\n this.#subscribers.set(event, new Set());\n }\n this.#subscribers.get(event).add(callback);\n \n return () => {\n const callbacks = this.#subscribers.get(event);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.#subscribers.delete(event);\n }\n }\n };\n }\n\n #hitTest(x, y) {\n // Sort by priority (highest first) and test\n const sorted = this.#hitRegistry.areas.sort((a, b) => \n (b.priority || 0) - (a.priority || 0)\n );\n \n for (const area of sorted) {\n if (this.#isPointInBounds(x, y, area.bounds)) {\n return area;\n }\n }\n return null;\n }\n\n #isPointInBounds(x, y, bounds) {\n return x >= bounds.x && \n x <= bounds.x + bounds.width &&\n y >= bounds.y && \n y <= bounds.y + bounds.height;\n }\n\n #emit(event, data) {\n const callbacks = this.#subscribers.get(event);\n if (callbacks) {\n for (const callback of callbacks) {\n callback(data);\n }\n }\n }\n\n // Test helper - only for testing, simulates normalized pointer events\n _testEmitPointerEvent(normalizedEvent) {\n this.#pointerSurface.handleEvent(normalizedEvent);\n this.#handlePointerInteraction(normalizedEvent);\n }\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export const ContextTypes = {\n '2D': '2d',\n 'WEBGL': 'webgl',\n 'WEBGL2': 'webgl2',\n 'BITMAPRENDERER': 'bitmaprenderer'\n};", "export class HitRegistry {\n #areas = new Map();\n\n register(id, area) {\n if (!id) {\n throw new Error('Hit area must have an id');\n }\n this.#areas.set(id, { id, ...area });\n return () => this.unregister(id);\n }\n\n unregister(id) {\n this.#areas.delete(id);\n }\n\n get(id) {\n return this.#areas.get(id);\n }\n\n has(id) {\n return this.#areas.has(id);\n }\n\n get areas() {\n return Array.from(this.#areas.values());\n }\n\n clear() {\n this.#areas.clear();\n }\n}", "import { ServiceProvider } from '@jucie.io/engine';\n\nexport class CanvasEvents extends ServiceProvider {\n #canvas = null;\n #offscreenCanvas = null;\n #cachedRect = null;\n #resizeObserver = null;\n #subscribers = new Set();\n #resizeSubscribers = new Set();\n #pendingMove = null;\n #rafId = null;\n #hasTransferredControl = false;\n\n static manifest = {\n name: 'CanvasEvents',\n namespace: 'canvasEvents',\n version: '1.0.0'\n };\n\n actions() {\n return {\n setCanvas: (canvas) => this.setCanvas(canvas),\n subscribe: (listener) => this.subscribe(listener),\n onResize: (listener) => this.onResize(listener),\n transferControlToOffscreen: () => this.transferControlToOffscreen()\n };\n }\n\n setCanvas(canvas) {\n if (this.#canvas) {\n this.#removeListeners();\n }\n \n this.#canvas = canvas;\n this.#updateCachedRect();\n this.#initializeListeners();\n }\n\n subscribe(subscriber) {\n this.#subscribers.add(subscriber);\n return () => this.#subscribers.delete(subscriber);\n }\n\n onResize(subscriber) {\n this.#resizeSubscribers.add(subscriber);\n return () => this.#resizeSubscribers.delete(subscriber);\n }\n\n transferControlToOffscreen() {\n if (!this.#canvas) {\n throw new Error('Canvas must be set before transferring control to offscreen');\n }\n\n if (this.#hasTransferredControl) {\n throw new Error('Control has already been transferred to offscreen');\n }\n\n // Transfer control\n this.#offscreenCanvas = this.#canvas.transferControlToOffscreen();\n this.#hasTransferredControl = true;\n\n // Set initial dimensions on offscreen canvas\n this.#offscreenCanvas.width = this.#canvas.width;\n this.#offscreenCanvas.height = this.#canvas.height;\n\n // Emit initial resize event with actual canvas dimensions\n this.#emitResize({\n width: this.#canvas.width,\n height: this.#canvas.height\n });\n\n return this.#offscreenCanvas;\n }\n\n #updateCachedRect() {\n if (this.#canvas) {\n this.#cachedRect = this.#canvas.getBoundingClientRect();\n }\n }\n\n #initializeListeners() {\n if (!this.#canvas) return;\n\n this.#updateCachedRect();\n\n this.#resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target !== this.#canvas) {\n continue;\n }\n const { width, height } = entry.contentRect;\n this.#emitResize({\n width: width,\n height: height\n });\n }\n this.#updateCachedRect();\n });\n this.#resizeObserver.observe(this.#canvas);\n\n document.addEventListener('wheel', this.#handleScroll, { passive: false });\n document.addEventListener('pointermove', this.#handleMove);\n document.addEventListener('pointerdown', this.#handleDown);\n document.addEventListener('pointerup', this.#handleUp);\n document.addEventListener('pointercancel', this.#handleUp);\n document.addEventListener('dblclick', this.#handleDblClick);\n }\n\n #removeListeners() {\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n\n document.removeEventListener('wheel', this.#handleScroll);\n document.removeEventListener('pointermove', this.#handleMove);\n document.removeEventListener('pointerdown', this.#handleDown);\n document.removeEventListener('pointerup', this.#handleUp);\n document.removeEventListener('pointercancel', this.#handleUp);\n document.removeEventListener('dblclick', this.#handleDblClick);\n }\n\n #handleScroll = (event) => {\n if (event.target !== this.#canvas) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n \n if (event.ctrlKey) {\n const normalized = this.#normalizeEvent(event, 'zoom');\n this.#emit(normalized);\n } else {\n const normalized = this.#normalizeEvent(event, 'scroll');\n this.#emit(normalized);\n }\n }\n\n #handleMove = (event) => {\n const normalized = this.#normalizeEvent(event, 'move');\n \n // Store latest move and throttle with RAF\n this.#pendingMove = normalized;\n if (this.#rafId) return;\n \n this.#rafId = requestAnimationFrame(() => {\n if (this.#pendingMove) {\n this.#emit(this.#pendingMove);\n this.#pendingMove = null;\n }\n this.#rafId = null;\n });\n }\n\n #handleDown = (event) => {\n // Only capture if starting on canvas\n if (event.target === this.#canvas) {\n const normalized = this.#normalizeEvent(event, 'down');\n this.#emit(normalized); // Immediate\n }\n }\n\n #handleUp = (event) => {\n // Use the actual up event position, not pending move\n const normalized = this.#normalizeEvent(event, 'up');\n this.#emit(normalized); // Immediate\n }\n\n #handleDblClick = (event) => {\n const normalized = this.#normalizeEvent(event, 'dblclick');\n this.#emit(normalized);\n }\n\n #emit(event) {\n for (const subscriber of this.#subscribers) {\n subscriber(event);\n }\n }\n\n #emitResize(resizeData) {\n for (const subscriber of this.#resizeSubscribers) {\n subscriber(resizeData);\n }\n }\n\n #normalizeEvent(event, type) {\n const isOverCanvas = event.target === this.#canvas;\n \n let x, y;\n if (isOverCanvas) {\n x = event.offsetX;\n y = event.offsetY;\n } else if (this.#cachedRect) {\n x = event.clientX - this.#cachedRect.left;\n y = event.clientY - this.#cachedRect.top;\n } else {\n x = event.clientX;\n y = event.clientY;\n }\n\n const isWithinBounds = isOverCanvas || (\n this.#cachedRect &&\n x >= 0 && \n x <= this.#cachedRect.width && \n y >= 0 && \n y <= this.#cachedRect.height\n );\n\n const normalized = {\n x,\n y,\n type,\n isOverCanvas,\n isWithinBounds,\n clientX: event.clientX,\n clientY: event.clientY,\n button: event.button ?? null,\n buttons: event.buttons ?? 0,\n timestamp: Date.now()\n };\n\n // Add wheel-specific data for scroll/zoom\n if (type === 'scroll' || type === 'zoom') {\n normalized.deltaX = event.deltaX;\n normalized.deltaY = event.deltaY;\n normalized.deltaZ = event.deltaZ;\n normalized.deltaMode = event.deltaMode;\n }\n\n // Add modifier keys\n normalized.shiftKey = event.shiftKey || false;\n normalized.ctrlKey = event.ctrlKey || false;\n normalized.altKey = event.altKey || false;\n normalized.metaKey = event.metaKey || false;\n\n return normalized;\n }\n\n destroy() {\n if (this.#rafId) {\n cancelAnimationFrame(this.#rafId);\n this.#rafId = null;\n }\n this.#removeListeners();\n this.#canvas = null;\n this.#offscreenCanvas = null;\n this.#cachedRect = null;\n this.#subscribers.clear();\n this.#resizeSubscribers.clear();\n this.#hasTransferredControl = false;\n }\n}\n", "import { defineSurface } from '@jucie.io/reactive';\n\nexport const usePointerSurface = defineSurface((setup) => {\n // ============= Core State =============\n \n // Position (canvas coordinates)\n const x = setup.value(0);\n const y = setup.value(0);\n const prevX = setup.value(0);\n const prevY = setup.value(0);\n \n // Client position (screen coordinates)\n const clientX = setup.value(0);\n const clientY = setup.value(0);\n \n // Canvas boundary state\n const isOverCanvas = setup.value(false);\n const isWithinBounds = setup.value(false);\n \n // Button state\n const isPressed = setup.value(false);\n const button = setup.value(null); // 0=left, 1=middle, 2=right\n const buttons = setup.value(0); // Bitmask of pressed buttons\n \n // Event type tracking\n const lastEventType = setup.value(null);\n \n // Timing\n const downTime = setup.value(null);\n const upTime = setup.value(null);\n const lastMoveTime = setup.value(null);\n const lastEventTime = setup.value(null);\n \n // Drag state\n const dragStartX = setup.value(null);\n const dragStartY = setup.value(null);\n const isDragging = setup.value(false);\n \n // Click detection\n const clickCount = setup.value(0);\n const lastClickTime = setup.value(0);\n \n // Velocity tracking\n const velocityX = setup.value(0);\n const velocityY = setup.value(0);\n \n // Scroll/Zoom state\n const lastScrollDeltaX = setup.value(0);\n const lastScrollDeltaY = setup.value(0);\n const lastZoomDelta = setup.value(0);\n \n // Hit areas (from HitRegistry)\n const hoveredArea = setup.value(null);\n const activeArea = setup.value(null);\n \n // ============= Configuration =============\n const config = setup.value({\n dragThreshold: 5,\n doubleClickThreshold: 300,\n holdThreshold: 500,\n velocitySmoothing: 0.3,\n maxVelocity: 10000 // Clamp unrealistic velocities\n });\n \n // ============= Computed Values =============\n \n const position = setup.computed(() => ({\n x: x.value,\n y: y.value\n }));\n \n const clientPosition = setup.computed(() => ({\n x: clientX.value,\n y: clientY.value\n }));\n \n const previousPosition = setup.computed(() => ({\n x: prevX.value,\n y: prevY.value\n }));\n \n const delta = setup.computed(() => {\n const xVal = typeof x.value === 'number' ? x.value : 0;\n const prevXVal = typeof prevX.value === 'number' ? prevX.value : 0;\n const yVal = typeof y.value === 'number' ? y.value : 0;\n const prevYVal = typeof prevY.value === 'number' ? prevY.value : 0;\n return {\n x: xVal - prevXVal,\n y: yVal - prevYVal\n };\n });\n \n const velocity = setup.computed(() => ({\n x: velocityX.value,\n y: velocityY.value\n }));\n \n const speed = setup.computed(() => {\n const vx = velocityX.value;\n const vy = velocityY.value;\n return Math.sqrt(vx * vx + vy * vy);\n });\n \n const dragDistance = setup.computed(() => {\n const startX = dragStartX.value;\n const startY = dragStartY.value;\n if (startX === null || startY === null || typeof startX !== 'number' || typeof startY !== 'number') return 0;\n \n const xVal = typeof x.value === 'number' ? x.value : 0;\n const yVal = typeof y.value === 'number' ? y.value : 0;\n const dx = xVal - startX;\n const dy = yVal - startY;\n return Math.sqrt(dx * dx + dy * dy);\n });\n \n const dragDelta = setup.computed(() => {\n const startX = dragStartX.value;\n const startY = dragStartY.value;\n if (startX === null || startY === null || typeof startX !== 'number' || typeof startY !== 'number') {\n return { x: 0, y: 0 };\n }\n const xVal = typeof x.value === 'number' ? x.value : 0;\n const yVal = typeof y.value === 'number' ? y.value : 0;\n return {\n x: xVal - startX,\n y: yVal - startY\n };\n });\n \n const holdDuration = setup.computed(() => {\n if (!isPressed.value || !downTime.value) return 0;\n return Date.now() - downTime.value;\n });\n \n const isHolding = setup.computed(() => {\n return holdDuration.value > config.value.holdThreshold && !isDragging.value;\n });\n \n const timeSinceLastEvent = setup.computed(() => {\n const lastTime = lastEventTime.value;\n return lastTime ? Date.now() - lastTime : 0;\n });\n \n // Full state snapshot\n const state = setup.computed(() => ({\n position: position.value,\n clientPosition: clientPosition.value,\n previousPosition: previousPosition.value,\n delta: delta.value,\n velocity: velocity.value,\n speed: speed.value,\n isPressed: isPressed.value,\n button: button.value,\n buttons: buttons.value,\n isDragging: isDragging.value,\n dragDistance: dragDistance.value,\n dragDelta: dragDelta.value,\n isHolding: isHolding.value,\n holdDuration: holdDuration.value,\n isOverCanvas: isOverCanvas.value,\n isWithinBounds: isWithinBounds.value,\n hoveredArea: hoveredArea.value,\n activeArea: activeArea.value,\n clickCount: clickCount.value,\n lastEventType: lastEventType.value\n }));\n \n // ============= Actions =============\n \n const updatePosition = (newX, newY, newClientX, newClientY) => {\n prevX.value = x.value;\n prevY.value = y.value;\n x.value = newX;\n y.value = newY;\n clientX.value = newClientX;\n clientY.value = newClientY;\n lastMoveTime.value = Date.now();\n };\n\n const updateVelocity = () => {\n const now = Date.now();\n const lastMove = lastMoveTime.value;\n \n if (lastMove) {\n const dt = (now - lastMove) / 1000;\n if (dt > 0 && dt < 0.1) {\n const newVx = (x.value - prevX.value) / dt;\n const newVy = (y.value - prevY.value) / dt;\n \n // Clamp unrealistic velocities\n const maxVel = config.value.maxVelocity;\n const clampedVx = Math.max(-maxVel, Math.min(maxVel, newVx));\n const clampedVy = Math.max(-maxVel, Math.min(maxVel, newVy));\n \n // Apply smoothing\n const smoothing = config.value.velocitySmoothing;\n velocityX.value = velocityX.value * (1 - smoothing) + clampedVx * smoothing;\n velocityY.value = velocityY.value * (1 - smoothing) + clampedVy * smoothing;\n }\n }\n };\n \n // Main event handler - consumes normalized events from CanvasEvents\n const handleEvent = setup.action((ctx, normalizedEvent) => {\n const { x: newX, y: newY, type, clientX: newClientX, clientY: newClientY, button: eventButton, buttons: eventButtons, isOverCanvas: eventIsOverCanvas, isWithinBounds: eventIsWithinBounds } = normalizedEvent;\n const now = Date.now();\n \n lastEventTime.value = now;\n lastEventType.value = type;\n isOverCanvas.value = eventIsOverCanvas;\n isWithinBounds.value = eventIsWithinBounds;\n \n switch (type) {\n case 'down':\n updatePosition(newX, newY, newClientX, newClientY);\n isPressed.value = true;\n downTime.value = now;\n button.value = eventButton;\n buttons.value = eventButtons;\n dragStartX.value = newX;\n dragStartY.value = newY;\n isDragging.value = false;\n \n // Double-click detection\n const timeSinceLastClick = now - lastClickTime.value;\n if (timeSinceLastClick < config.value.doubleClickThreshold) {\n clickCount.value = clickCount.value + 1;\n } else {\n clickCount.value = 1;\n }\n break;\n \n case 'up':\n updatePosition(newX, newY, newClientX, newClientY);\n isPressed.value = false;\n upTime.value = now;\n lastClickTime.value = now;\n isDragging.value = false;\n velocityX.value = 0;\n velocityY.value = 0;\n buttons.value = eventButtons;\n break;\n \n case 'move':\n updatePosition(newX, newY, newClientX, newClientY);\n updateVelocity();\n buttons.value = eventButtons;\n \n // Check for drag start\n if (isPressed.value && !isDragging.value) {\n const distance = dragDistance.value;\n if (distance > config.value.dragThreshold) {\n isDragging.value = true;\n }\n }\n break;\n \n case 'dblclick':\n updatePosition(newX, newY, newClientX, newClientY);\n clickCount.value = 2;\n break;\n \n case 'scroll':\n updatePosition(newX, newY, newClientX, newClientY);\n // Extract wheel delta from event if available\n if (normalizedEvent.deltaX !== undefined) {\n lastScrollDeltaX.value = normalizedEvent.deltaX;\n }\n if (normalizedEvent.deltaY !== undefined) {\n lastScrollDeltaY.value = normalizedEvent.deltaY;\n }\n break;\n \n case 'zoom':\n updatePosition(newX, newY, newClientX, newClientY);\n if (normalizedEvent.deltaY !== undefined) {\n lastZoomDelta.value = normalizedEvent.deltaY;\n }\n break;\n }\n });\n \n const setHoveredArea = setup.action((ctx, area) => {\n hoveredArea.value = area;\n });\n \n const setActiveArea = setup.action((ctx, area) => {\n activeArea.value = area;\n });\n \n const reset = setup.action(() => {\n isPressed.value = false;\n isDragging.value = false;\n activeArea.value = null;\n hoveredArea.value = null;\n velocityX.value = 0;\n velocityY.value = 0;\n clickCount.value = 0;\n lastScrollDeltaX.value = 0;\n lastScrollDeltaY.value = 0;\n lastZoomDelta.value = 0;\n });\n \n const updateConfig = setup.action((ctx, updates) => {\n config.value = { ...config.value, ...updates };\n });\n \n // ============= Return Public API =============\n return {\n // State (read-only through computed)\n state,\n position,\n clientPosition,\n previousPosition,\n delta,\n velocity,\n speed,\n isPressed,\n button,\n buttons,\n isDragging,\n dragDistance,\n dragDelta,\n isHolding,\n holdDuration,\n isOverCanvas,\n isWithinBounds,\n hoveredArea,\n activeArea,\n clickCount,\n lastEventType,\n timeSinceLastEvent,\n \n // Actions\n handleEvent, // Main entry point for normalized events\n setHoveredArea,\n setActiveArea,\n reset,\n updateConfig\n };\n});\n", "import { ServiceProvider } from '@jucie.io/engine';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createComputed, destroyComputed, addEffect } from '@jucie.io/reactive';\nimport { createDefinition, definitionType } from '@jucie.io/engine';\nimport { HitRegistry } from './HitRegistry.js';\nimport { CanvasEvents } from './CanvasEvents.js';\nimport { usePointerSurface } from './usePointerSurface.js';\n\nexport const defineBrush = createDefinition('BRUSH', [Object]);\nexport const defineLayer = createDefinition('LAYER', [Object]);\n\nexport class Painter extends ServiceProvider {\n #layers = new Map();\n #canvas = null; // Always OffscreenCanvas\n #contexts = new Map();\n #reactors = new Map();\n #assets = new Map();\n #isRunning = false;\n #frameId = null;\n #isRendering = false;\n #renderScheduled = false;\n\n // Mutable runtime config (separate from frozen config)\n #runtimeConfig = {\n targetFPS: 60,\n fixedTimeStep: 1000 / 60,\n timeScale: 1.0,\n debug: {\n enabled: false,\n showFPS: true,\n showBounds: true,\n showLayerTiming: true\n }\n };\n\n // Timing state\n #timing = {\n lastFrameTime: 0,\n deltaTime: 0,\n elapsedTime: 0,\n frameCount: 0\n };\n\n // Debug metrics\n #metrics = {\n fps: 0,\n frameTime: 0,\n layerTimes: new Map(),\n brushTimes: new Map(),\n skippedFrames: 0\n };\n\n // Hit detection state\n #hitRegistry = new HitRegistry();\n #pointerSurface = usePointerSurface();\n #canvasEvents = null; // Only created in main thread mode\n #pointerUnsubscribe = null;\n #resizeObserver = null; // For main thread canvas resize watching\n #subscribers = new Map(); // Map<event, Set<callback>>\n \n // Track state for event emission\n #wasDragging = false;\n #wasOverCanvas = false;\n #wasHolding = false;\n\n static manifest = {\n name: 'Painter',\n namespace: 'painter',\n version: '1.0.0',\n defaults: {\n // Timing configuration\n targetFPS: 60,\n fixedTimeStep: 1000 / 60,\n timeScale: 1.0,\n // Debug configuration\n debug: {\n enabled: false,\n showFPS: true,\n showBounds: true,\n showLayerTiming: true\n }\n }\n };\n\n getters () {\n return {\n pointer: () => this.#pointerSurface.state,\n };\n }\n\n actions() {\n // Initialize runtime config from frozen config\n if (this.config) {\n Object.assign(this.#runtimeConfig, this.config);\n }\n \n return {\n addLayer: (layerDef) => this.addLayer(layerDef),\n addLayers: (...layers) => {\n for (const layer of layers) {\n this.addLayer(layer);\n }\n },\n updateCanvas: (fn) => this.updateCanvas(fn),\n setCanvas: (canvas) => this.setCanvas(canvas),\n setOffscreenCanvas: (offscreenCanvas) => this.setOffscreenCanvas(offscreenCanvas),\n setAssets: (assets) => this.setAssets(assets),\n removeLayer: (name) => this.removeLayer(name),\n start: () => this.start(),\n stop: () => this.stop(),\n render: () => this.render(),\n setTargetFPS: (fps) => this.setTargetFPS(fps),\n setTimeScale: (scale) => this.setTimeScale(scale),\n setFixedTimeStep: (step) => this.setFixedTimeStep(step),\n setDebug: (options) => this.setDebug(options),\n getMetrics: () => this.getMetrics(),\n handleResize: (width, height) => this.handleResize(width, height),\n subscribe: (event, callback) => this.subscribe(event, callback),\n // Pointer API - receives normalized events from main thread\n handlePointerEvent: (normalizedEvent) => this.handlePointerEvent(normalizedEvent),\n subscribeToPointer: (callback) => this.#pointerSurface.$subscribe(callback),\n bindPointer: (path) => this.#pointerSurface.$bind(path),\n // Test helper - only for testing\n _testEmitPointerEvent: (normalizedEvent) => this._testEmitPointerEvent(normalizedEvent)\n };\n }\n\n // Main thread mode: Pass regular canvas, we create OffscreenCanvas + CanvasEvents\n setCanvas(canvas) {\n // Store reference to DOM canvas for resize observation\n const domCanvas = canvas;\n \n // Transfer control to offscreen\n const offscreenCanvas = canvas.transferControlToOffscreen();\n \n // Set initial dimensions\n offscreenCanvas.width = domCanvas.width;\n offscreenCanvas.height = domCanvas.height;\n \n this.#canvas = offscreenCanvas;\n \n // Create contexts for each type\n Object.values(ContextTypes).forEach(type => {\n try {\n const ctx = offscreenCanvas.getContext(type);\n if (ctx) this.#contexts.set(type, ctx);\n } catch (e) {\n console.warn(`Context type ${type} not supported`);\n }\n });\n\n // Create and set up canvas events (main thread only)\n if (!this.#canvasEvents) {\n this.#canvasEvents = new CanvasEvents();\n }\n \n this.#canvasEvents.setCanvas(domCanvas);\n\n // Watch for canvas resizes and sync to offscreen canvas\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n }\n \n this.#resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry && entry.target === domCanvas) {\n // Sync dimensions to offscreen canvas\n offscreenCanvas.width = domCanvas.width;\n offscreenCanvas.height = domCanvas.height;\n \n // Notify layers of resize\n this.handleResize(domCanvas.width, domCanvas.height);\n }\n });\n \n this.#resizeObserver.observe(domCanvas);\n\n // Connect canvas events to surface\n if (this.#pointerUnsubscribe) {\n this.#pointerUnsubscribe();\n }\n\n this.#pointerUnsubscribe = this.#canvasEvents.subscribe((normalizedEvent) => {\n this.handlePointerEvent(normalizedEvent);\n });\n }\n\n // Worker thread mode: Accept pre-created OffscreenCanvas, expect external events\n setOffscreenCanvas(offscreenCanvas) {\n this.#canvas = offscreenCanvas;\n \n // Create contexts for each type\n Object.values(ContextTypes).forEach(type => {\n try {\n const ctx = offscreenCanvas.getContext(type);\n if (ctx) this.#contexts.set(type, ctx);\n } catch (e) {\n console.warn(`Context type ${type} not supported`);\n }\n });\n\n // Don't create CanvasEvents - events will come from external source\n // via handlePointerEvent()\n }\n\n updateCanvas(fn) {\n const result = fn(this.#canvas);\n if (result) {\n this.#canvas = result;\n }\n }\n\n setAssets(assets) {\n this.#assets = assets;\n }\n\n start() {\n if (!this.#isRunning) {\n this.#isRunning = true;\n this.#scheduleRender();\n }\n }\n\n stop() {\n if (this.#isRunning) {\n this.#isRunning = false;\n if (this.#frameId) {\n cancelAnimationFrame(this.#frameId);\n this.#frameId = null;\n }\n }\n }\n\n addLayer(layerDef) {\n if (definitionType(layerDef) !== 'LAYER') {\n throw new Error('Invalid layer definition');\n }\n\n const name = layerDef._name;\n const config = layerDef(this.useContext, this.#hitRegistry);\n \n // Set up layer computed if it has data paths\n if (config.data) {\n const dataReactor = this.#createDataReactor(`layer_${name}`, config.data);\n if (dataReactor) {\n this.#reactors.set(`layer_${name}`, dataReactor);\n }\n }\n\n // Set up brush reactors and structure\n const brushes = config.children.map(child => {\n if (definitionType(child) === 'BRUSH') {\n const name = child._name;\n const brushConfig = child(this.useContext, this.#hitRegistry);\n \n // Only create data computed if data exists\n const dataReactor = brushConfig.data \n ? this.#createDataReactor(`brush_${name}`, brushConfig.data)\n : undefined;\n \n const whenReactor = brushConfig.when \n ? createComputed(brushConfig.when, {\n immediate: true,\n context: this.#pointerSurface.state\n })\n : null;\n\n const brush = {\n name,\n ...brushConfig,\n dataReactor,\n whenReactor\n };\n\n // Call brush mount hook\n if (brush.lifecycle?.onMount) {\n try {\n brush.lifecycle.onMount(this.#contexts.get(brush.context || config.context));\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\" onMount:`, error);\n }\n }\n\n return brush;\n }\n // Handle nested layers recursively\n return this.addLayer(child);\n });\n\n const layer = {\n ...config,\n name,\n brushes,\n context: this.#contexts.get(config.context)\n };\n\n this.#layers.set(name, layer);\n\n // Call layer mount hook\n if (layer.lifecycle?.onMount) {\n try {\n layer.lifecycle.onMount(layer.context);\n } catch (error) {\n console.error(`Error in layer \"${name}\" onMount:`, error);\n }\n }\n\n return layer;\n }\n\n removeLayer(name) {\n const layer = this.#layers.get(name);\n if (!layer) return;\n\n // Call layer unmount hook\n if (layer.lifecycle?.onUnmount) {\n try {\n layer.lifecycle.onUnmount(layer.context);\n } catch (error) {\n console.error(`Error in layer \"${name}\" onUnmount:`, error);\n }\n }\n\n // Call brush unmount hooks and clean up reactors\n layer.brushes.forEach(brush => {\n if (brush.lifecycle?.onUnmount) {\n try {\n brush.lifecycle.onUnmount(\n this.#contexts.get(brush.context || layer.context)\n );\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\" onUnmount:`, error);\n }\n }\n // Clean up brush computed and subscription\n const reactorData = this.#reactors.get(`painter_brush_${brush.name}`);\n if (reactorData) {\n reactorData.unsubscribe();\n if (reactorData.computed) {\n destroyComputed(reactorData.computed);\n }\n this.#reactors.delete(`painter_brush_${brush.name}`);\n }\n });\n\n // Clean up layer computed and subscription\n const layerReactorData = this.#reactors.get(`painter_layer_${name}`);\n if (layerReactorData) {\n layerReactorData.unsubscribe();\n if (layerReactorData.computed) {\n destroyComputed(layerReactorData.computed);\n }\n this.#reactors.delete(`painter_layer_${name}`);\n }\n\n this.#layers.delete(name);\n }\n\n #scheduleRender() {\n if (this.#renderScheduled || this.#isRendering) return;\n \n this.#renderScheduled = true;\n \n this.#frameId = requestAnimationFrame(() => {\n this.#renderScheduled = false;\n this.#frameId = null;\n this.#render();\n });\n }\n\n async #render() {\n if (!this.#canvas) return;\n this.#isRendering = true;\n \n try {\n // Clear hit registry at start of render\n this.#hitRegistry.clear();\n \n const renderStart = this.#runtimeConfig.debug?.enabled ? performance.now() : 0;\n\n // Clear all contexts\n this.#contexts.forEach(ctx => {\n ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height);\n });\n\n // Render layers in order\n for (const layer of this.#layers.values()) {\n const layerStart = this.#runtimeConfig.debug?.enabled ? performance.now() : 0;\n\n // Check layer condition\n if (layer.whenReactor) {\n const layerReactor = this.#reactors.get(`painter_layer_${layer.name}`)?.computed;\n if (!layer.when(layerReactor())) continue;\n }\n\n const ctx = layer.context;\n\n if (!ctx) continue;\n\n // Layer beforeRender hook\n if (layer.lifecycle?.beforeRender) {\n try {\n layer.lifecycle.beforeRender(ctx, this.#timing);\n } catch (error) {\n console.error(`Error in layer \"${layer.name}\" beforeRender:`, error);\n if (layer.lifecycle?.onError) layer.lifecycle.onError(error);\n }\n }\n\n // Apply layer settings\n ctx.save();\n if (layer.settings) {\n Object.entries(layer.settings).forEach(([key, value]) => {\n if (typeof ctx[key] === 'function') {\n ctx[key](...(Array.isArray(value) ? value : [value]));\n } else {\n ctx[key] = value;\n }\n });\n }\n\n // Render brushes\n for (const brush of layer.brushes) {\n const brushStart = this.#runtimeConfig.debug?.enabled ? performance.now() : 0;\n\n if (brush.whenReactor && !brush.whenReactor()) continue;\n\n\n const brushCtx = brush.context ? \n this.#contexts.get(brush.context) : \n ctx;\n\n if (!brushCtx) continue;\n\n // Brush beforeRender hook\n if (brush.lifecycle?.beforeRender) {\n try {\n brush.lifecycle.beforeRender(brushCtx, this.#timing);\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\" beforeRender:`, error);\n if (brush.lifecycle?.onError) brush.lifecycle.onError(error);\n continue;\n }\n }\n\n brushCtx.save();\n \n if (brush.settings) {\n Object.entries(brush.settings).forEach(([key, value]) => {\n if (typeof brushCtx[key] === 'function') {\n brushCtx[key](...(Array.isArray(value) ? value : [value]));\n } else {\n brushCtx[key] = value;\n }\n });\n }\n \n try {\n const requiredAssets = {};\n if (brush.assets) {\n for (const key of brush.assets) {\n requiredAssets[key] = this.#assets.get(key);\n }\n }\n brush.render(brushCtx, brush.dataReactor(), requiredAssets, this.#timing);\n\n // Brush afterRender hook\n if (brush.lifecycle?.afterRender) {\n brush.lifecycle.afterRender(brushCtx, this.#timing);\n }\n\n if (this.#runtimeConfig.debug?.enabled) {\n const brushTime = performance.now() - brushStart;\n this.#metrics.brushTimes.set(brush.name, brushTime);\n\n if (this.#runtimeConfig.debug?.showBounds) {\n this.#renderBrushBounds(brushCtx, brush);\n }\n }\n } catch (error) {\n console.error(`Error in brush \"${brush.name}\":`, error);\n if (brush.lifecycle?.onError) brush.lifecycle.onError(error);\n } finally {\n brushCtx.restore();\n }\n }\n\n ctx.restore();\n\n // Layer afterRender hook\n if (layer.lifecycle?.afterRender) {\n try {\n layer.lifecycle.afterRender(ctx, this.#timing);\n } catch (error) {\n console.error(`Error in layer \"${layer.name}\" afterRender:`, error);\n if (layer.lifecycle?.onError) layer.lifecycle.onError(error);\n }\n }\n\n if (this.#runtimeConfig.debug?.enabled) {\n const layerTime = performance.now() - layerStart;\n this.#metrics.layerTimes.set(layer.name, layerTime);\n\n if (this.#runtimeConfig.debug?.showBounds) {\n this.#renderLayerBounds(ctx, layer);\n }\n }\n }\n\n // Render debug overlay if enabled\n if (this.#runtimeConfig.debug?.enabled) {\n this.#renderDebugOverlay();\n }\n \n } finally {\n this.#isRendering = false;\n }\n }\n\n #renderBrushBounds(ctx, brush) {\n ctx.save();\n ctx.strokeStyle = 'rgba(0, 255, 0, 0.5)';\n ctx.lineWidth = 1;\n ctx.strokeRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n ctx.restore();\n }\n\n #renderLayerBounds(ctx, layer) {\n ctx.save();\n ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)';\n ctx.lineWidth = 2;\n ctx.strokeRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n ctx.restore();\n }\n\n #renderDebugOverlay() {\n const ctx = this.#contexts.get(ContextTypes['2D']);\n if (!ctx) return;\n\n ctx.save();\n ctx.resetTransform();\n ctx.font = '12px monospace';\n ctx.fillStyle = 'white';\n ctx.strokeStyle = 'black';\n ctx.lineWidth = 3;\n\n let y = 20;\n const lineHeight = 15;\n\n if (this.#runtimeConfig.debug?.showFPS) {\n const text = `FPS: ${Math.round(this.#metrics.fps)} (${this.#timing.deltaTime.toFixed(2)}ms)`;\n ctx.strokeText(text, 10, y);\n ctx.fillText(text, 10, y);\n y += lineHeight;\n }\n\n if (this.#runtimeConfig.debug?.showLayerTiming) {\n ctx.fillText('Layer Times:', 10, y);\n y += lineHeight;\n\n for (const [name, time] of this.#metrics.layerTimes) {\n const text = ` ${name}: ${time.toFixed(2)}ms`;\n ctx.strokeText(text, 10, y);\n ctx.fillText(text, 10, y);\n y += lineHeight;\n }\n\n ctx.fillText(this.state.get(['_transitions', 'pointer', 'currentState']), 10, y);\n }\n\n ctx.restore();\n }\n\n handleResize(width, height) {\n // Call onResize hooks for all layers\n for (const layer of this.#layers.values()) {\n if (layer.lifecycle?.onResize) {\n try {\n layer.lifecycle.onResize(width, height, layer.context);\n } catch (error) {\n console.error(`Error in layer \"${layer.name}\" onResize:`, error);\n if (layer.lifecycle?.onError) layer.lifecycle.onError(error);\n }\n }\n }\n }\n\n #createDataReactor(id, data) {\n const computed = createComputed(data, {\n immediate: true,\n context: this.#pointerSurface.state\n });\n\n const unsubscribe = addEffect(computed, () => this.#scheduleRender());\n\n this.#reactors.set(`painter_${id}`, {\n computed,\n unsubscribe\n });\n\n return computed;\n }\n\n destroy() {\n this.stop();\n\n // Clean up pointer system\n if (this.#pointerUnsubscribe) {\n this.#pointerUnsubscribe();\n this.#pointerUnsubscribe = null;\n }\n if (this.#canvasEvents) {\n this.#canvasEvents.destroy();\n this.#canvasEvents = null;\n }\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n if (this.#pointerSurface) {\n this.#pointerSurface.$destroy();\n }\n\n // Clean up all layers and reactors\n for (const name of this.#layers.keys()) {\n this.removeLayer(name);\n }\n }\n\n setTargetFPS(fps) {\n this.#runtimeConfig.targetFPS = fps;\n this.#runtimeConfig.fixedTimeStep = 1000 / fps;\n }\n\n setTimeScale(scale) {\n this.#runtimeConfig.timeScale = Math.max(0, scale);\n }\n\n setFixedTimeStep(step) {\n this.#runtimeConfig.fixedTimeStep = step;\n }\n\n setDebug(options = {}) {\n if (!this.#runtimeConfig.debug) {\n this.#runtimeConfig.debug = {};\n }\n Object.assign(this.#runtimeConfig.debug, options);\n }\n\n getMetrics() {\n return {\n ...this.#metrics,\n deltaTime: this.#timing.deltaTime,\n elapsedTime: this.#timing.elapsedTime,\n frameCount: this.#timing.frameCount\n };\n }\n\n // Public method to receive pointer events from main thread\n handlePointerEvent(normalizedEvent) {\n // Feed normalized events into surface\n this.#pointerSurface.handleEvent(normalizedEvent);\n\n // Handle hit testing and interactions\n this.#handlePointerInteraction(normalizedEvent);\n \n // Emit generic pointer events for external subscribers\n this.#emitPointerEvents(normalizedEvent);\n }\n\n #emitPointerEvents(normalizedEvent) {\n const { type } = normalizedEvent;\n const pointer = this.#pointerSurface;\n \n // Emit basic pointer events\n switch (type) {\n case 'down':\n this.#emit('pointer:down', pointer.state);\n break;\n \n case 'up':\n this.#emit('pointer:up', pointer.state);\n \n // Emit click if it wasn't a drag\n if (!pointer.isDragging) {\n this.#emit('pointer:click', pointer.state);\n }\n break;\n \n case 'move':\n this.#emit('pointer:move', pointer.state);\n \n // Check for drag start/move\n if (pointer.isDragging && pointer.isPressed) {\n const wasDragging = this.#wasDragging;\n this.#wasDragging = true;\n \n if (!wasDragging) {\n this.#emit('pointer:drag:start', pointer.state);\n } else {\n this.#emit('pointer:drag:move', pointer.state);\n }\n }\n break;\n \n case 'scroll':\n this.#emit('pointer:scroll', pointer.state);\n break;\n \n case 'zoom':\n this.#emit('pointer:zoom', pointer.state);\n break;\n \n case 'dblclick':\n this.#emit('pointer:dblclick', pointer.state);\n break;\n }\n \n // Check for drag end\n if (type === 'up' && this.#wasDragging) {\n this.#emit('pointer:drag:end', pointer.state);\n this.#wasDragging = false;\n }\n \n // Check for canvas enter/leave\n const wasOverCanvas = this.#wasOverCanvas;\n const isOverCanvas = pointer.isOverCanvas;\n \n if (isOverCanvas && !wasOverCanvas) {\n this.#emit('pointer:enter', pointer.state);\n } else if (!isOverCanvas && wasOverCanvas) {\n this.#emit('pointer:leave', pointer.state);\n }\n \n this.#wasOverCanvas = isOverCanvas;\n \n // Check for hold start/end\n const wasHolding = this.#wasHolding;\n const isHolding = pointer.isHolding;\n \n if (isHolding && !wasHolding) {\n this.#emit('pointer:hold:start', pointer.state);\n } else if (!isHolding && wasHolding) {\n this.#emit('pointer:hold:end', pointer.state);\n }\n \n this.#wasHolding = isHolding;\n }\n\n #handlePointerInteraction(normalizedEvent) {\n const { type, x, y } = normalizedEvent;\n const pointer = this.#pointerSurface;\n\n switch (type) {\n case 'down': {\n const hitArea = this.#hitTest(x, y);\n pointer.setActiveArea(hitArea);\n\n if (hitArea?.onPointerDown?.handler) {\n const ctx = this.#getContextForArea(hitArea);\n hitArea.onPointerDown.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n break;\n }\n\n case 'up': {\n const activeArea = pointer.activeArea;\n if (activeArea?.onPointerUp?.handler) {\n const ctx = this.#getContextForArea(activeArea);\n activeArea.onPointerUp.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n break;\n }\n\n case 'move': {\n const hitArea = this.#hitTest(x, y);\n const prevHovered = pointer.hoveredArea;\n\n // Handle drag on active area\n const activeArea = pointer.activeArea;\n if (activeArea?.onPointerMove?.handler && pointer.isDragging) {\n const ctx = this.#getContextForArea(activeArea);\n activeArea.onPointerMove.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n\n // Handle hover changes\n if (hitArea?.id !== prevHovered?.id) {\n if (prevHovered?.onPointerLeave?.handler) {\n const ctx = this.#getContextForArea(prevHovered);\n prevHovered.onPointerLeave.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n\n if (hitArea?.onPointerEnter?.handler) {\n const ctx = this.#getContextForArea(hitArea);\n hitArea.onPointerEnter.handler({\n ...pointer.state,\n ctx,\n emit: this.#emit.bind(this)\n });\n }\n\n pointer.setHoveredArea(hitArea);\n }\n break;\n }\n\n case 'scroll':\n case 'zoom':\n // These are already emitted in #emitPointerEvents\n break;\n\n case 'dblclick':\n // This is already emitted in #emitPointerEvents\n break;\n }\n }\n\n #getContextForArea(area) {\n if (!area) return null;\n return area.context \n ? this.#contexts.get(area.context) \n : this.#contexts.get(ContextTypes['2D']);\n }\n\n subscribe(event, callback) {\n if (!this.#subscribers.has(event)) {\n this.#subscribers.set(event, new Set());\n }\n this.#subscribers.get(event).add(callback);\n \n return () => {\n const callbacks = this.#subscribers.get(event);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n this.#subscribers.delete(event);\n }\n }\n };\n }\n\n #hitTest(x, y) {\n // Sort by priority (highest first) and test\n const sorted = this.#hitRegistry.areas.sort((a, b) => \n (b.priority || 0) - (a.priority || 0)\n );\n \n for (const area of sorted) {\n if (this.#isPointInBounds(x, y, area.bounds)) {\n return area;\n }\n }\n return null;\n }\n\n #isPointInBounds(x, y, bounds) {\n return x >= bounds.x && \n x <= bounds.x + bounds.width &&\n y >= bounds.y && \n y <= bounds.y + bounds.height;\n }\n\n #emit(event, data) {\n const callbacks = this.#subscribers.get(event);\n if (callbacks) {\n for (const callback of callbacks) {\n callback(data);\n }\n }\n }\n\n // Test helper - only for testing, simulates normalized pointer events\n _testEmitPointerEvent(normalizedEvent) {\n this.#pointerSurface.handleEvent(normalizedEvent);\n this.#handlePointerInteraction(normalizedEvent);\n }\n}"],
5
+ "mappings": "AAAO,IAAMA,EAAe,CAC1B,KAAM,KACN,MAAS,QACT,OAAU,SACV,eAAkB,gBACpB,ECLO,IAAMC,EAAN,KAAkB,CACvBC,GAAS,IAAI,IAEb,SAASC,EAAIC,EAAM,CACjB,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,0BAA0B,EAE5C,YAAKD,GAAO,IAAIC,EAAI,CAAE,GAAAA,EAAI,GAAGC,CAAK,CAAC,EAC5B,IAAM,KAAK,WAAWD,CAAE,CACjC,CAEA,WAAWA,EAAI,CACb,KAAKD,GAAO,OAAOC,CAAE,CACvB,CAEA,IAAIA,EAAI,CACN,OAAO,KAAKD,GAAO,IAAIC,CAAE,CAC3B,CAEA,IAAIA,EAAI,CACN,OAAO,KAAKD,GAAO,IAAIC,CAAE,CAC3B,CAEA,IAAI,OAAQ,CACV,OAAO,MAAM,KAAK,KAAKD,GAAO,OAAO,CAAC,CACxC,CAEA,OAAQ,CACN,KAAKA,GAAO,MAAM,CACpB,CACF,EC9BA,OAAS,mBAAAG,OAAuB,mBAEzB,IAAMC,EAAN,cAA2BD,EAAgB,CAChDE,GAAU,KACVC,GAAmB,KACnBC,GAAc,KACdC,GAAkB,KAClBC,GAAe,IAAI,IACnBC,GAAqB,IAAI,IACzBC,GAAe,KACfC,GAAS,KACTC,GAAyB,GAEzB,OAAO,SAAW,CAChB,KAAM,eACN,UAAW,eACX,QAAS,OACX,EAEA,SAAU,CACR,MAAO,CACL,UAAYC,GAAW,KAAK,UAAUA,CAAM,EAC5C,UAAYC,GAAa,KAAK,UAAUA,CAAQ,EAChD,SAAWA,GAAa,KAAK,SAASA,CAAQ,EAC9C,2BAA4B,IAAM,KAAK,2BAA2B,CACpE,CACF,CAEA,UAAUD,EAAQ,CACZ,KAAKT,IACP,KAAKW,GAAiB,EAGxB,KAAKX,GAAUS,EACf,KAAKG,GAAkB,EACvB,KAAKC,GAAqB,CAC5B,CAEA,UAAUC,EAAY,CACpB,YAAKV,GAAa,IAAIU,CAAU,EACzB,IAAM,KAAKV,GAAa,OAAOU,CAAU,CAClD,CAEA,SAASA,EAAY,CACnB,YAAKT,GAAmB,IAAIS,CAAU,EAC/B,IAAM,KAAKT,GAAmB,OAAOS,CAAU,CACxD,CAEA,4BAA6B,CAC3B,GAAI,CAAC,KAAKd,GACR,MAAM,IAAI,MAAM,6DAA6D,EAG/E,GAAI,KAAKQ,GACP,MAAM,IAAI,MAAM,mDAAmD,EAIrE,YAAKP,GAAmB,KAAKD,GAAQ,2BAA2B,EAChE,KAAKQ,GAAyB,GAG9B,KAAKP,GAAiB,MAAQ,KAAKD,GAAQ,MAC3C,KAAKC,GAAiB,OAAS,KAAKD,GAAQ,OAG5C,KAAKe,GAAY,CACf,MAAO,KAAKf,GAAQ,MACpB,OAAQ,KAAKA,GAAQ,MACvB,CAAC,EAEM,KAAKC,EACd,CAEAW,IAAoB,CACd,KAAKZ,KACP,KAAKE,GAAc,KAAKF,GAAQ,sBAAsB,EAE1D,CAEAa,IAAuB,CAChB,KAAKb,KAEV,KAAKY,GAAkB,EAEvB,KAAKT,GAAkB,IAAI,eAAgBa,GAAY,CACrD,QAAWC,KAASD,EAAS,CAC3B,GAAIC,EAAM,SAAW,KAAKjB,GACxB,SAEF,GAAM,CAAE,MAAAkB,EAAO,OAAAC,CAAO,EAAIF,EAAM,YAChC,KAAKF,GAAY,CACf,MAAOG,EACP,OAAQC,CACV,CAAC,CACH,CACA,KAAKP,GAAkB,CACzB,CAAC,EACD,KAAKT,GAAgB,QAAQ,KAAKH,EAAO,EAEzC,SAAS,iBAAiB,QAAS,KAAKoB,GAAe,CAAE,QAAS,EAAM,CAAC,EACzE,SAAS,iBAAiB,cAAe,KAAKC,EAAW,EACzD,SAAS,iBAAiB,cAAe,KAAKC,EAAW,EACzD,SAAS,iBAAiB,YAAa,KAAKC,EAAS,EACrD,SAAS,iBAAiB,gBAAiB,KAAKA,EAAS,EACzD,SAAS,iBAAiB,WAAY,KAAKC,EAAe,EAC5D,CAEAb,IAAmB,CACb,KAAKR,KACP,KAAKA,GAAgB,WAAW,EAChC,KAAKA,GAAkB,MAGzB,SAAS,oBAAoB,QAAS,KAAKiB,EAAa,EACxD,SAAS,oBAAoB,cAAe,KAAKC,EAAW,EAC5D,SAAS,oBAAoB,cAAe,KAAKC,EAAW,EAC5D,SAAS,oBAAoB,YAAa,KAAKC,EAAS,EACxD,SAAS,oBAAoB,gBAAiB,KAAKA,EAAS,EAC5D,SAAS,oBAAoB,WAAY,KAAKC,EAAe,CAC/D,CAEAJ,GAAiBK,GAAU,CACzB,GAAIA,EAAM,SAAW,KAAKzB,GAO1B,GAHAyB,EAAM,eAAe,EACrBA,EAAM,gBAAgB,EAElBA,EAAM,QAAS,CACjB,IAAMC,EAAa,KAAKC,GAAgBF,EAAO,MAAM,EACrD,KAAKG,GAAMF,CAAU,CACvB,KAAO,CACL,IAAMA,EAAa,KAAKC,GAAgBF,EAAO,QAAQ,EACvD,KAAKG,GAAMF,CAAU,CACvB,CACF,EAEAL,GAAeI,GAAU,CACvB,IAAMC,EAAa,KAAKC,GAAgBF,EAAO,MAAM,EAGrD,KAAKnB,GAAeoB,EAChB,MAAKnB,KAET,KAAKA,GAAS,sBAAsB,IAAM,CACpC,KAAKD,KACP,KAAKsB,GAAM,KAAKtB,EAAY,EAC5B,KAAKA,GAAe,MAEtB,KAAKC,GAAS,IAChB,CAAC,EACH,EAEAe,GAAeG,GAAU,CAEvB,GAAIA,EAAM,SAAW,KAAKzB,GAAS,CACjC,IAAM0B,EAAa,KAAKC,GAAgBF,EAAO,MAAM,EACrD,KAAKG,GAAMF,CAAU,CACvB,CACF,EAEAH,GAAaE,GAAU,CAErB,IAAMC,EAAa,KAAKC,GAAgBF,EAAO,IAAI,EACnD,KAAKG,GAAMF,CAAU,CACvB,EAEAF,GAAmBC,GAAU,CAC3B,IAAMC,EAAa,KAAKC,GAAgBF,EAAO,UAAU,EACzD,KAAKG,GAAMF,CAAU,CACvB,EAEAE,GAAMH,EAAO,CACX,QAAWX,KAAc,KAAKV,GAC5BU,EAAWW,CAAK,CAEpB,CAEAV,GAAYc,EAAY,CACtB,QAAWf,KAAc,KAAKT,GAC5BS,EAAWe,CAAU,CAEzB,CAEAF,GAAgBF,EAAOK,EAAM,CAC3B,IAAMC,EAAeN,EAAM,SAAW,KAAKzB,GAEvCgC,EAAGC,EACHF,GACFC,EAAIP,EAAM,QACVQ,EAAIR,EAAM,SACD,KAAKvB,IACd8B,EAAIP,EAAM,QAAU,KAAKvB,GAAY,KACrC+B,EAAIR,EAAM,QAAU,KAAKvB,GAAY,MAErC8B,EAAIP,EAAM,QACVQ,EAAIR,EAAM,SAGZ,IAAMS,EAAiBH,GACrB,KAAK7B,IACL8B,GAAK,GACLA,GAAK,KAAK9B,GAAY,OACtB+B,GAAK,GACLA,GAAK,KAAK/B,GAAY,OAGlBwB,EAAa,CACjB,EAAAM,EACA,EAAAC,EACA,KAAAH,EACA,aAAAC,EACA,eAAAG,EACA,QAAST,EAAM,QACf,QAASA,EAAM,QACf,OAAQA,EAAM,QAAU,KACxB,QAASA,EAAM,SAAW,EAC1B,UAAW,KAAK,IAAI,CACtB,EAGA,OAAIK,IAAS,UAAYA,IAAS,UAChCJ,EAAW,OAASD,EAAM,OAC1BC,EAAW,OAASD,EAAM,OAC1BC,EAAW,OAASD,EAAM,OAC1BC,EAAW,UAAYD,EAAM,WAI/BC,EAAW,SAAWD,EAAM,UAAY,GACxCC,EAAW,QAAUD,EAAM,SAAW,GACtCC,EAAW,OAASD,EAAM,QAAU,GACpCC,EAAW,QAAUD,EAAM,SAAW,GAE/BC,CACT,CAEA,SAAU,CACJ,KAAKnB,KACP,qBAAqB,KAAKA,EAAM,EAChC,KAAKA,GAAS,MAEhB,KAAKI,GAAiB,EACtB,KAAKX,GAAU,KACf,KAAKC,GAAmB,KACxB,KAAKC,GAAc,KACnB,KAAKE,GAAa,MAAM,EACxB,KAAKC,GAAmB,MAAM,EAC9B,KAAKG,GAAyB,EAChC,CACF,EC5PA,OAAS,iBAAA2B,OAAqB,qBAEvB,IAAMC,EAAoBD,GAAeE,GAAU,CAIxD,IAAMC,EAAID,EAAM,MAAM,CAAC,EACjBE,EAAIF,EAAM,MAAM,CAAC,EACjBG,EAAQH,EAAM,MAAM,CAAC,EACrBI,EAAQJ,EAAM,MAAM,CAAC,EAGrBK,EAAUL,EAAM,MAAM,CAAC,EACvBM,EAAUN,EAAM,MAAM,CAAC,EAGvBO,EAAeP,EAAM,MAAM,EAAK,EAChCQ,EAAiBR,EAAM,MAAM,EAAK,EAGlCS,EAAYT,EAAM,MAAM,EAAK,EAC7BU,EAASV,EAAM,MAAM,IAAI,EACzBW,EAAUX,EAAM,MAAM,CAAC,EAGvBY,EAAgBZ,EAAM,MAAM,IAAI,EAGhCa,EAAWb,EAAM,MAAM,IAAI,EAC3Bc,GAASd,EAAM,MAAM,IAAI,EACzBe,EAAef,EAAM,MAAM,IAAI,EAC/BgB,EAAgBhB,EAAM,MAAM,IAAI,EAGhCiB,EAAajB,EAAM,MAAM,IAAI,EAC7BkB,EAAalB,EAAM,MAAM,IAAI,EAC7BmB,EAAanB,EAAM,MAAM,EAAK,EAG9BoB,EAAapB,EAAM,MAAM,CAAC,EAC1BqB,EAAgBrB,EAAM,MAAM,CAAC,EAG7BsB,EAAYtB,EAAM,MAAM,CAAC,EACzBuB,EAAYvB,EAAM,MAAM,CAAC,EAGzBwB,EAAmBxB,EAAM,MAAM,CAAC,EAChCyB,EAAmBzB,EAAM,MAAM,CAAC,EAChC0B,EAAgB1B,EAAM,MAAM,CAAC,EAG7B2B,EAAc3B,EAAM,MAAM,IAAI,EAC9B4B,EAAa5B,EAAM,MAAM,IAAI,EAG7B6B,EAAS7B,EAAM,MAAM,CACzB,cAAe,EACf,qBAAsB,IACtB,cAAe,IACf,kBAAmB,GACnB,YAAa,GACf,CAAC,EAIK8B,EAAW9B,EAAM,SAAS,KAAO,CACrC,EAAGC,EAAE,MACL,EAAGC,EAAE,KACP,EAAE,EAEI6B,EAAiB/B,EAAM,SAAS,KAAO,CAC3C,EAAGK,EAAQ,MACX,EAAGC,EAAQ,KACb,EAAE,EAEI0B,EAAmBhC,EAAM,SAAS,KAAO,CAC7C,EAAGG,EAAM,MACT,EAAGC,EAAM,KACX,EAAE,EAEI6B,EAAQjC,EAAM,SAAS,IAAM,CACjC,IAAMkC,EAAO,OAAOjC,EAAE,OAAU,SAAWA,EAAE,MAAQ,EAC/CkC,EAAW,OAAOhC,EAAM,OAAU,SAAWA,EAAM,MAAQ,EAC3DiC,EAAO,OAAOlC,EAAE,OAAU,SAAWA,EAAE,MAAQ,EAC/CmC,EAAW,OAAOjC,EAAM,OAAU,SAAWA,EAAM,MAAQ,EACjE,MAAO,CACL,EAAG8B,EAAOC,EACV,EAAGC,EAAOC,CACZ,CACF,CAAC,EAEKC,EAAWtC,EAAM,SAAS,KAAO,CACrC,EAAGsB,EAAU,MACb,EAAGC,EAAU,KACf,EAAE,EAEIgB,EAAQvC,EAAM,SAAS,IAAM,CACjC,IAAMwC,EAAKlB,EAAU,MACfmB,EAAKlB,EAAU,MACrB,OAAO,KAAK,KAAKiB,EAAKA,EAAKC,EAAKA,CAAE,CACpC,CAAC,EAEKC,EAAe1C,EAAM,SAAS,IAAM,CACxC,IAAM2C,EAAS1B,EAAW,MACpB2B,EAAS1B,EAAW,MAC1B,GAAIyB,IAAW,MAAQC,IAAW,MAAQ,OAAOD,GAAW,UAAY,OAAOC,GAAW,SAAU,MAAO,GAE3G,IAAMV,EAAO,OAAOjC,EAAE,OAAU,SAAWA,EAAE,MAAQ,EAC/CmC,EAAO,OAAOlC,EAAE,OAAU,SAAWA,EAAE,MAAQ,EAC/C2C,EAAKX,EAAOS,EACZG,EAAKV,EAAOQ,EAClB,OAAO,KAAK,KAAKC,EAAKA,EAAKC,EAAKA,CAAE,CACpC,CAAC,EAEKC,EAAY/C,EAAM,SAAS,IAAM,CACrC,IAAM2C,EAAS1B,EAAW,MACpB2B,EAAS1B,EAAW,MAC1B,GAAIyB,IAAW,MAAQC,IAAW,MAAQ,OAAOD,GAAW,UAAY,OAAOC,GAAW,SACxF,MAAO,CAAE,EAAG,EAAG,EAAG,CAAE,EAEtB,IAAMV,EAAO,OAAOjC,EAAE,OAAU,SAAWA,EAAE,MAAQ,EAC/CmC,EAAO,OAAOlC,EAAE,OAAU,SAAWA,EAAE,MAAQ,EACrD,MAAO,CACL,EAAGgC,EAAOS,EACV,EAAGP,EAAOQ,CACZ,CACF,CAAC,EAEKI,EAAehD,EAAM,SAAS,IAC9B,CAACS,EAAU,OAAS,CAACI,EAAS,MAAc,EACzC,KAAK,IAAI,EAAIA,EAAS,KAC9B,EAEKoC,GAAYjD,EAAM,SAAS,IACxBgD,EAAa,MAAQnB,EAAO,MAAM,eAAiB,CAACV,EAAW,KACvE,EAEK+B,GAAqBlD,EAAM,SAAS,IAAM,CAC9C,IAAMmD,EAAWnC,EAAc,MAC/B,OAAOmC,EAAW,KAAK,IAAI,EAAIA,EAAW,CAC5C,CAAC,EAGKC,GAAQpD,EAAM,SAAS,KAAO,CAClC,SAAU8B,EAAS,MACnB,eAAgBC,EAAe,MAC/B,iBAAkBC,EAAiB,MACnC,MAAOC,EAAM,MACb,SAAUK,EAAS,MACnB,MAAOC,EAAM,MACb,UAAW9B,EAAU,MACrB,OAAQC,EAAO,MACf,QAASC,EAAQ,MACjB,WAAYQ,EAAW,MACvB,aAAcuB,EAAa,MAC3B,UAAWK,EAAU,MACrB,UAAWE,GAAU,MACrB,aAAcD,EAAa,MAC3B,aAAczC,EAAa,MAC3B,eAAgBC,EAAe,MAC/B,YAAamB,EAAY,MACzB,WAAYC,EAAW,MACvB,WAAYR,EAAW,MACvB,cAAeR,EAAc,KAC/B,EAAE,EAIIyC,EAAiB,CAACC,EAAMC,EAAMC,EAAYC,IAAe,CAC7DtD,EAAM,MAAQF,EAAE,MAChBG,EAAM,MAAQF,EAAE,MAChBD,EAAE,MAAQqD,EACVpD,EAAE,MAAQqD,EACVlD,EAAQ,MAAQmD,EAChBlD,EAAQ,MAAQmD,EAChB1C,EAAa,MAAQ,KAAK,IAAI,CAChC,EAEM2C,GAAiB,IAAM,CAC3B,IAAMC,EAAM,KAAK,IAAI,EACfC,EAAW7C,EAAa,MAE9B,GAAI6C,EAAU,CACZ,IAAMC,GAAMF,EAAMC,GAAY,IAC9B,GAAIC,EAAK,GAAKA,EAAK,GAAK,CACtB,IAAMC,GAAS7D,EAAE,MAAQE,EAAM,OAAS0D,EAClCE,GAAS7D,EAAE,MAAQE,EAAM,OAASyD,EAGlCG,EAASnC,EAAO,MAAM,YACtBoC,EAAY,KAAK,IAAI,CAACD,EAAQ,KAAK,IAAIA,EAAQF,CAAK,CAAC,EACrDI,EAAY,KAAK,IAAI,CAACF,EAAQ,KAAK,IAAIA,EAAQD,CAAK,CAAC,EAGrDI,EAAYtC,EAAO,MAAM,kBAC/BP,EAAU,MAAQA,EAAU,OAAS,EAAI6C,GAAaF,EAAYE,EAClE5C,EAAU,MAAQA,EAAU,OAAS,EAAI4C,GAAaD,EAAYC,CACpE,CACF,CACF,EAGMC,GAAcpE,EAAM,OAAO,CAACqE,EAAKC,IAAoB,CACzD,GAAM,CAAE,EAAGhB,EAAM,EAAGC,EAAM,KAAAgB,EAAM,QAASf,EAAY,QAASC,EAAY,OAAQe,EAAa,QAASC,EAAc,aAAcC,GAAmB,eAAgBC,EAAoB,EAAIL,EACzLX,EAAM,KAAK,IAAI,EAOrB,OALA3C,EAAc,MAAQ2C,EACtB/C,EAAc,MAAQ2D,EACtBhE,EAAa,MAAQmE,GACrBlE,EAAe,MAAQmE,GAEfJ,EAAM,CACZ,IAAK,OACHlB,EAAeC,EAAMC,EAAMC,EAAYC,CAAU,EACjDhD,EAAU,MAAQ,GAClBI,EAAS,MAAQ8C,EACjBjD,EAAO,MAAQ8D,EACf7D,EAAQ,MAAQ8D,EAChBxD,EAAW,MAAQqC,EACnBpC,EAAW,MAAQqC,EACnBpC,EAAW,MAAQ,GAGQwC,EAAMtC,EAAc,MACtBQ,EAAO,MAAM,qBACpCT,EAAW,MAAQA,EAAW,MAAQ,EAEtCA,EAAW,MAAQ,EAErB,MAEF,IAAK,KACHiC,EAAeC,EAAMC,EAAMC,EAAYC,CAAU,EACjDhD,EAAU,MAAQ,GAClBK,GAAO,MAAQ6C,EACftC,EAAc,MAAQsC,EACtBxC,EAAW,MAAQ,GACnBG,EAAU,MAAQ,EAClBC,EAAU,MAAQ,EAClBZ,EAAQ,MAAQ8D,EAChB,MAEF,IAAK,OACHpB,EAAeC,EAAMC,EAAMC,EAAYC,CAAU,EACjDC,GAAe,EACf/C,EAAQ,MAAQ8D,EAGZhE,EAAU,OAAS,CAACU,EAAW,OAChBuB,EAAa,MACfb,EAAO,MAAM,gBAC1BV,EAAW,MAAQ,IAGvB,MAEF,IAAK,WACHkC,EAAeC,EAAMC,EAAMC,EAAYC,CAAU,EACjDrC,EAAW,MAAQ,EACnB,MAEF,IAAK,SACHiC,EAAeC,EAAMC,EAAMC,EAAYC,CAAU,EAE7Ca,EAAgB,SAAW,SAC7B9C,EAAiB,MAAQ8C,EAAgB,QAEvCA,EAAgB,SAAW,SAC7B7C,EAAiB,MAAQ6C,EAAgB,QAE3C,MAEF,IAAK,OACHjB,EAAeC,EAAMC,EAAMC,EAAYC,CAAU,EAC7Ca,EAAgB,SAAW,SAC7B5C,EAAc,MAAQ4C,EAAgB,QAExC,KACJ,CACF,CAAC,EAEKM,GAAiB5E,EAAM,OAAO,CAACqE,EAAKQ,IAAS,CACjDlD,EAAY,MAAQkD,CACtB,CAAC,EAEKC,GAAgB9E,EAAM,OAAO,CAACqE,EAAKQ,IAAS,CAChDjD,EAAW,MAAQiD,CACrB,CAAC,EAEKE,GAAQ/E,EAAM,OAAO,IAAM,CAC/BS,EAAU,MAAQ,GAClBU,EAAW,MAAQ,GACnBS,EAAW,MAAQ,KACnBD,EAAY,MAAQ,KACpBL,EAAU,MAAQ,EAClBC,EAAU,MAAQ,EAClBH,EAAW,MAAQ,EACnBI,EAAiB,MAAQ,EACzBC,EAAiB,MAAQ,EACzBC,EAAc,MAAQ,CACxB,CAAC,EAEKsD,GAAehF,EAAM,OAAO,CAACqE,EAAKY,IAAY,CAClDpD,EAAO,MAAQ,CAAE,GAAGA,EAAO,MAAO,GAAGoD,CAAQ,CAC/C,CAAC,EAGD,MAAO,CAEL,MAAA7B,GACA,SAAAtB,EACA,eAAAC,EACA,iBAAAC,EACA,MAAAC,EACA,SAAAK,EACA,MAAAC,EACA,UAAA9B,EACA,OAAAC,EACA,QAAAC,EACA,WAAAQ,EACA,aAAAuB,EACA,UAAAK,EACA,UAAAE,GACA,aAAAD,EACA,aAAAzC,EACA,eAAAC,EACA,YAAAmB,EACA,WAAAC,EACA,WAAAR,EACA,cAAAR,EACA,mBAAAsC,GAGA,YAAAkB,GACA,eAAAQ,GACA,cAAAE,GACA,MAAAC,GACA,aAAAC,EACF,CACF,CAAC,ECpVD,OAAS,mBAAAE,OAAuB,mBAEhC,OAAS,kBAAAC,GAAgB,mBAAAC,GAAiB,aAAAC,OAAiB,qBAC3D,OAAS,oBAAAC,GAAkB,kBAAAC,OAAsB,mBAK1C,IAAMC,GAAcF,GAAiB,QAAS,CAAC,MAAM,CAAC,EAChDG,GAAcH,GAAiB,QAAS,CAAC,MAAM,CAAC,EAEhDI,EAAN,cAAsBR,EAAgB,CAC3CS,GAAU,IAAI,IACdC,GAAU,KACVC,GAAY,IAAI,IAChBC,GAAY,IAAI,IAChBC,GAAU,IAAI,IACdC,GAAa,GACbC,GAAW,KACXC,GAAe,GACfC,GAAmB,GAGnBC,GAAiB,CACf,UAAW,GACX,cAAe,IAAO,GACtB,UAAW,EACX,MAAO,CACL,QAAS,GACT,QAAS,GACT,WAAY,GACZ,gBAAiB,EACnB,CACF,EAGAC,GAAU,CACR,cAAe,EACf,UAAW,EACX,YAAa,EACb,WAAY,CACd,EAGAC,GAAW,CACT,IAAK,EACL,UAAW,EACX,WAAY,IAAI,IAChB,WAAY,IAAI,IAChB,cAAe,CACjB,EAGAC,GAAe,IAAIC,EACnBC,GAAkBC,EAAkB,EACpCC,GAAgB,KAChBC,GAAsB,KACtBC,GAAkB,KAClBC,GAAe,IAAI,IAGnBC,GAAe,GACfC,GAAiB,GACjBC,GAAc,GAEd,OAAO,SAAW,CAChB,KAAM,UACN,UAAW,UACX,QAAS,QACT,SAAU,CAER,UAAW,GACX,cAAe,IAAO,GACtB,UAAW,EAEX,MAAO,CACL,QAAS,GACT,QAAS,GACT,WAAY,GACZ,gBAAiB,EACnB,CACF,CACF,EAEA,SAAW,CACT,MAAO,CACL,QAAS,IAAM,KAAKR,GAAgB,KACtC,CACF,CAEA,SAAU,CAER,OAAI,KAAK,QACP,OAAO,OAAO,KAAKL,GAAgB,KAAK,MAAM,EAGzC,CACL,SAAWc,GAAa,KAAK,SAASA,CAAQ,EAC9C,UAAW,IAAIC,IAAW,CACxB,QAAWC,KAASD,EAClB,KAAK,SAASC,CAAK,CAEvB,EACA,aAAeC,GAAO,KAAK,aAAaA,CAAE,EAC1C,UAAYC,GAAW,KAAK,UAAUA,CAAM,EAC5C,mBAAqBC,GAAoB,KAAK,mBAAmBA,CAAe,EAChF,UAAYC,GAAW,KAAK,UAAUA,CAAM,EAC5C,YAAcC,GAAS,KAAK,YAAYA,CAAI,EAC5C,MAAO,IAAM,KAAK,MAAM,EACxB,KAAM,IAAM,KAAK,KAAK,EACtB,OAAQ,IAAM,KAAK,OAAO,EAC1B,aAAeC,GAAQ,KAAK,aAAaA,CAAG,EAC5C,aAAeC,GAAU,KAAK,aAAaA,CAAK,EAChD,iBAAmBC,GAAS,KAAK,iBAAiBA,CAAI,EACtD,SAAWC,GAAY,KAAK,SAASA,CAAO,EAC5C,WAAY,IAAM,KAAK,WAAW,EAClC,aAAc,CAACC,EAAOC,IAAW,KAAK,aAAaD,EAAOC,CAAM,EAChE,UAAW,CAACC,EAAOC,IAAa,KAAK,UAAUD,EAAOC,CAAQ,EAE9D,mBAAqBC,GAAoB,KAAK,mBAAmBA,CAAe,EAChF,mBAAqBD,GAAa,KAAKxB,GAAgB,WAAWwB,CAAQ,EAC1E,YAAcE,GAAS,KAAK1B,GAAgB,MAAM0B,CAAI,EAEtD,sBAAwBD,GAAoB,KAAK,sBAAsBA,CAAe,CACxF,CACF,CAGA,UAAUZ,EAAQ,CAEhB,IAAMc,EAAYd,EAGZC,EAAkBD,EAAO,2BAA2B,EAG1DC,EAAgB,MAAQa,EAAU,MAClCb,EAAgB,OAASa,EAAU,OAEnC,KAAKxC,GAAU2B,EAGf,OAAO,OAAOc,CAAY,EAAE,QAAQC,GAAQ,CAC1C,GAAI,CACF,IAAMC,EAAMhB,EAAgB,WAAWe,CAAI,EACvCC,GAAK,KAAK1C,GAAU,IAAIyC,EAAMC,CAAG,CACvC,MAAY,CACV,QAAQ,KAAK,gBAAgBD,CAAI,gBAAgB,CACnD,CACF,CAAC,EAGI,KAAK3B,KACR,KAAKA,GAAgB,IAAI6B,GAG3B,KAAK7B,GAAc,UAAUyB,CAAS,EAGlC,KAAKvB,IACP,KAAKA,GAAgB,WAAW,EAGlC,KAAKA,GAAkB,IAAI,eAAgB4B,GAAY,CACrD,IAAMC,EAAQD,EAAQ,CAAC,EACnBC,GAASA,EAAM,SAAWN,IAE5Bb,EAAgB,MAAQa,EAAU,MAClCb,EAAgB,OAASa,EAAU,OAGnC,KAAK,aAAaA,EAAU,MAAOA,EAAU,MAAM,EAEvD,CAAC,EAED,KAAKvB,GAAgB,QAAQuB,CAAS,EAGlC,KAAKxB,IACP,KAAKA,GAAoB,EAG3B,KAAKA,GAAsB,KAAKD,GAAc,UAAWuB,GAAoB,CAC3E,KAAK,mBAAmBA,CAAe,CACzC,CAAC,CACH,CAGA,mBAAmBX,EAAiB,CAClC,KAAK3B,GAAU2B,EAGf,OAAO,OAAOc,CAAY,EAAE,QAAQC,GAAQ,CAC1C,GAAI,CACF,IAAMC,EAAMhB,EAAgB,WAAWe,CAAI,EACvCC,GAAK,KAAK1C,GAAU,IAAIyC,EAAMC,CAAG,CACvC,MAAY,CACV,QAAQ,KAAK,gBAAgBD,CAAI,gBAAgB,CACnD,CACF,CAAC,CAIH,CAEA,aAAajB,EAAI,CACf,IAAMsB,EAAStB,EAAG,KAAKzB,EAAO,EAC1B+C,IACF,KAAK/C,GAAU+C,EAEnB,CAEA,UAAUnB,EAAQ,CAChB,KAAKzB,GAAUyB,CACjB,CAEA,OAAQ,CACD,KAAKxB,KACR,KAAKA,GAAa,GAClB,KAAK4C,GAAgB,EAEzB,CAEA,MAAO,CACD,KAAK5C,KACP,KAAKA,GAAa,GACd,KAAKC,KACP,qBAAqB,KAAKA,EAAQ,EAClC,KAAKA,GAAW,MAGtB,CAEA,SAASiB,EAAU,CACjB,GAAI3B,GAAe2B,CAAQ,IAAM,QAC/B,MAAM,IAAI,MAAM,0BAA0B,EAG5C,IAAMO,EAAOP,EAAS,MAChB2B,EAAS3B,EAAS,KAAK,WAAY,KAAKX,EAAY,EAG1D,GAAIsC,EAAO,KAAM,CACf,IAAMC,EAAc,KAAKC,GAAmB,SAAStB,CAAI,GAAIoB,EAAO,IAAI,EACpEC,GACF,KAAKhD,GAAU,IAAI,SAAS2B,CAAI,GAAIqB,CAAW,CAEnD,CAGA,IAAME,EAAUH,EAAO,SAAS,IAAII,GAAS,CAC3C,GAAI1D,GAAe0D,CAAK,IAAM,QAAS,CACrC,IAAMxB,EAAOwB,EAAM,MACbC,EAAcD,EAAM,KAAK,WAAY,KAAK1C,EAAY,EAGtDuC,EAAcI,EAAY,KAC5B,KAAKH,GAAmB,SAAStB,CAAI,GAAIyB,EAAY,IAAI,EACzD,OAEEC,EAAcD,EAAY,KAC5B/D,GAAe+D,EAAY,KAAM,CAC/B,UAAW,GACX,QAAS,KAAKzC,GAAgB,KAChC,CAAC,EACD,KAEE2C,EAAQ,CACZ,KAAA3B,EACA,GAAGyB,EACH,YAAAJ,EACA,YAAAK,CACF,EAGA,GAAIC,EAAM,WAAW,QACnB,GAAI,CACFA,EAAM,UAAU,QAAQ,KAAKvD,GAAU,IAAIuD,EAAM,SAAWP,EAAO,OAAO,CAAC,CAC7E,OAASQ,EAAO,CACd,QAAQ,MAAM,mBAAmBD,EAAM,IAAI,aAAcC,CAAK,CAChE,CAGF,OAAOD,CACT,CAEA,OAAO,KAAK,SAASH,CAAK,CAC5B,CAAC,EAEK7B,EAAQ,CACZ,GAAGyB,EACH,KAAApB,EACA,QAAAuB,EACA,QAAS,KAAKnD,GAAU,IAAIgD,EAAO,OAAO,CAC5C,EAKA,GAHA,KAAKlD,GAAQ,IAAI8B,EAAML,CAAK,EAGxBA,EAAM,WAAW,QACnB,GAAI,CACFA,EAAM,UAAU,QAAQA,EAAM,OAAO,CACvC,OAASiC,EAAO,CACd,QAAQ,MAAM,mBAAmB5B,CAAI,aAAc4B,CAAK,CAC1D,CAGF,OAAOjC,CACT,CAEA,YAAYK,EAAM,CAChB,IAAML,EAAQ,KAAKzB,GAAQ,IAAI8B,CAAI,EACnC,GAAI,CAACL,EAAO,OAGZ,GAAIA,EAAM,WAAW,UACnB,GAAI,CACFA,EAAM,UAAU,UAAUA,EAAM,OAAO,CACzC,OAASiC,EAAO,CACd,QAAQ,MAAM,mBAAmB5B,CAAI,eAAgB4B,CAAK,CAC5D,CAIFjC,EAAM,QAAQ,QAAQgC,GAAS,CAC7B,GAAIA,EAAM,WAAW,UACnB,GAAI,CACFA,EAAM,UAAU,UACd,KAAKvD,GAAU,IAAIuD,EAAM,SAAWhC,EAAM,OAAO,CACnD,CACF,OAASiC,EAAO,CACd,QAAQ,MAAM,mBAAmBD,EAAM,IAAI,eAAgBC,CAAK,CAClE,CAGF,IAAMC,EAAc,KAAKxD,GAAU,IAAI,iBAAiBsD,EAAM,IAAI,EAAE,EAChEE,IACFA,EAAY,YAAY,EACpBA,EAAY,UACdlE,GAAgBkE,EAAY,QAAQ,EAEtC,KAAKxD,GAAU,OAAO,iBAAiBsD,EAAM,IAAI,EAAE,EAEvD,CAAC,EAGD,IAAMG,EAAmB,KAAKzD,GAAU,IAAI,iBAAiB2B,CAAI,EAAE,EAC/D8B,IACFA,EAAiB,YAAY,EACzBA,EAAiB,UACnBnE,GAAgBmE,EAAiB,QAAQ,EAE3C,KAAKzD,GAAU,OAAO,iBAAiB2B,CAAI,EAAE,GAG/C,KAAK9B,GAAQ,OAAO8B,CAAI,CAC1B,CAEAmB,IAAkB,CACZ,KAAKzC,IAAoB,KAAKD,KAElC,KAAKC,GAAmB,GAExB,KAAKF,GAAW,sBAAsB,IAAM,CAC1C,KAAKE,GAAmB,GACxB,KAAKF,GAAW,KAChB,KAAKuD,GAAQ,CACf,CAAC,EACH,CAEA,KAAMA,IAAU,CACd,GAAK,KAAK5D,GACV,MAAKM,GAAe,GAEpB,GAAI,CAEF,KAAKK,GAAa,MAAM,EAExB,IAAMkD,EAAc,KAAKrD,GAAe,OAAO,QAAU,YAAY,IAAI,EAAI,EAG7E,KAAKP,GAAU,QAAQ0C,GAAO,CAC5BA,EAAI,UAAU,EAAG,EAAG,KAAK3C,GAAQ,MAAO,KAAKA,GAAQ,MAAM,CAC7D,CAAC,EAGD,QAAWwB,KAAS,KAAKzB,GAAQ,OAAO,EAAG,CACzC,IAAM+D,EAAa,KAAKtD,GAAe,OAAO,QAAU,YAAY,IAAI,EAAI,EAG5E,GAAIgB,EAAM,YAAa,CACrB,IAAMuC,EAAe,KAAK7D,GAAU,IAAI,iBAAiBsB,EAAM,IAAI,EAAE,GAAG,SACxE,GAAI,CAACA,EAAM,KAAKuC,EAAa,CAAC,EAAG,QACnC,CAEA,IAAMpB,EAAMnB,EAAM,QAElB,GAAKmB,EAGL,IAAInB,EAAM,WAAW,aACnB,GAAI,CACFA,EAAM,UAAU,aAAamB,EAAK,KAAKlC,EAAO,CAChD,OAASgD,EAAO,CACd,QAAQ,MAAM,mBAAmBjC,EAAM,IAAI,kBAAmBiC,CAAK,EAC/DjC,EAAM,WAAW,SAASA,EAAM,UAAU,QAAQiC,CAAK,CAC7D,CAIFd,EAAI,KAAK,EACLnB,EAAM,UACR,OAAO,QAAQA,EAAM,QAAQ,EAAE,QAAQ,CAAC,CAACwC,EAAKC,CAAK,IAAM,CACnD,OAAOtB,EAAIqB,CAAG,GAAM,WACtBrB,EAAIqB,CAAG,EAAE,GAAI,MAAM,QAAQC,CAAK,EAAIA,EAAQ,CAACA,CAAK,CAAE,EAEpDtB,EAAIqB,CAAG,EAAIC,CAEf,CAAC,EAIH,QAAWT,KAAShC,EAAM,QAAS,CACjC,IAAM0C,EAAa,KAAK1D,GAAe,OAAO,QAAU,YAAY,IAAI,EAAI,EAE5E,GAAIgD,EAAM,aAAe,CAACA,EAAM,YAAY,EAAG,SAG/C,IAAMW,EAAWX,EAAM,QACrB,KAAKvD,GAAU,IAAIuD,EAAM,OAAO,EAChCb,EAEF,GAAKwB,EAGL,IAAIX,EAAM,WAAW,aACnB,GAAI,CACFA,EAAM,UAAU,aAAaW,EAAU,KAAK1D,EAAO,CACrD,OAASgD,EAAO,CACd,QAAQ,MAAM,mBAAmBD,EAAM,IAAI,kBAAmBC,CAAK,EAC/DD,EAAM,WAAW,SAASA,EAAM,UAAU,QAAQC,CAAK,EAC3D,QACF,CAGFU,EAAS,KAAK,EAEVX,EAAM,UACR,OAAO,QAAQA,EAAM,QAAQ,EAAE,QAAQ,CAAC,CAACQ,EAAKC,CAAK,IAAM,CACnD,OAAOE,EAASH,CAAG,GAAM,WAC3BG,EAASH,CAAG,EAAE,GAAI,MAAM,QAAQC,CAAK,EAAIA,EAAQ,CAACA,CAAK,CAAE,EAEzDE,EAASH,CAAG,EAAIC,CAElB,CAAC,EAGL,GAAI,CACF,IAAMG,EAAiB,CAAC,EACxB,GAAIZ,EAAM,OACR,QAAWQ,KAAOR,EAAM,OACtBY,EAAeJ,CAAG,EAAI,KAAK7D,GAAQ,IAAI6D,CAAG,EAU9C,GAPAR,EAAM,OAAOW,EAAUX,EAAM,YAAY,EAAGY,EAAgB,KAAK3D,EAAO,EAGpE+C,EAAM,WAAW,aACnBA,EAAM,UAAU,YAAYW,EAAU,KAAK1D,EAAO,EAGhD,KAAKD,GAAe,OAAO,QAAS,CACtC,IAAM6D,EAAY,YAAY,IAAI,EAAIH,EACtC,KAAKxD,GAAS,WAAW,IAAI8C,EAAM,KAAMa,CAAS,EAE9C,KAAK7D,GAAe,OAAO,YAC7B,KAAK8D,GAAmBH,EAAUX,CAAK,CAE3C,CACF,OAASC,EAAO,CACd,QAAQ,MAAM,mBAAmBD,EAAM,IAAI,KAAMC,CAAK,EAClDD,EAAM,WAAW,SAASA,EAAM,UAAU,QAAQC,CAAK,CAC7D,QAAE,CACAU,EAAS,QAAQ,CACnB,EACF,CAKA,GAHAxB,EAAI,QAAQ,EAGRnB,EAAM,WAAW,YACnB,GAAI,CACFA,EAAM,UAAU,YAAYmB,EAAK,KAAKlC,EAAO,CAC/C,OAASgD,EAAO,CACd,QAAQ,MAAM,mBAAmBjC,EAAM,IAAI,iBAAkBiC,CAAK,EAC9DjC,EAAM,WAAW,SAASA,EAAM,UAAU,QAAQiC,CAAK,CAC7D,CAGF,GAAI,KAAKjD,GAAe,OAAO,QAAS,CACtC,IAAM+D,EAAY,YAAY,IAAI,EAAIT,EACtC,KAAKpD,GAAS,WAAW,IAAIc,EAAM,KAAM+C,CAAS,EAE9C,KAAK/D,GAAe,OAAO,YAC7B,KAAKgE,GAAmB7B,EAAKnB,CAAK,CAEtC,EACF,CAGI,KAAKhB,GAAe,OAAO,SAC7B,KAAKiE,GAAoB,CAG7B,QAAE,CACA,KAAKnE,GAAe,EACtB,EACF,CAEAgE,GAAmB3B,EAAKa,EAAO,CAC7Bb,EAAI,KAAK,EACTA,EAAI,YAAc,uBAClBA,EAAI,UAAY,EAChBA,EAAI,WAAW,EAAG,EAAGA,EAAI,OAAO,MAAOA,EAAI,OAAO,MAAM,EACxDA,EAAI,QAAQ,CACd,CAEA6B,GAAmB7B,EAAKnB,EAAO,CAC7BmB,EAAI,KAAK,EACTA,EAAI,YAAc,uBAClBA,EAAI,UAAY,EAChBA,EAAI,WAAW,EAAG,EAAGA,EAAI,OAAO,MAAOA,EAAI,OAAO,MAAM,EACxDA,EAAI,QAAQ,CACd,CAEA8B,IAAsB,CACpB,IAAM9B,EAAM,KAAK1C,GAAU,IAAIwC,EAAa,IAAI,CAAC,EACjD,GAAI,CAACE,EAAK,OAEVA,EAAI,KAAK,EACTA,EAAI,eAAe,EACnBA,EAAI,KAAO,iBACXA,EAAI,UAAY,QAChBA,EAAI,YAAc,QAClBA,EAAI,UAAY,EAEhB,IAAI+B,EAAI,GACFC,EAAa,GAEnB,GAAI,KAAKnE,GAAe,OAAO,QAAS,CACtC,IAAMoE,EAAO,QAAQ,KAAK,MAAM,KAAKlE,GAAS,GAAG,CAAC,KAAK,KAAKD,GAAQ,UAAU,QAAQ,CAAC,CAAC,MACxFkC,EAAI,WAAWiC,EAAM,GAAIF,CAAC,EAC1B/B,EAAI,SAASiC,EAAM,GAAIF,CAAC,EACxBA,GAAKC,CACP,CAEA,GAAI,KAAKnE,GAAe,OAAO,gBAAiB,CAC9CmC,EAAI,SAAS,eAAgB,GAAI+B,CAAC,EAClCA,GAAKC,EAEL,OAAW,CAAC9C,EAAMgD,CAAI,IAAK,KAAKnE,GAAS,WAAY,CACnD,IAAMkE,EAAO,KAAK/C,CAAI,KAAKgD,EAAK,QAAQ,CAAC,CAAC,KAC1ClC,EAAI,WAAWiC,EAAM,GAAIF,CAAC,EAC1B/B,EAAI,SAASiC,EAAM,GAAIF,CAAC,EACxBA,GAAKC,CACP,CAEAhC,EAAI,SAAS,KAAK,MAAM,IAAI,CAAC,eAAgB,UAAW,cAAc,CAAC,EAAG,GAAI+B,CAAC,CACjF,CAEA/B,EAAI,QAAQ,CACd,CAEA,aAAaT,EAAOC,EAAQ,CAE1B,QAAWX,KAAS,KAAKzB,GAAQ,OAAO,EACtC,GAAIyB,EAAM,WAAW,SACnB,GAAI,CACFA,EAAM,UAAU,SAASU,EAAOC,EAAQX,EAAM,OAAO,CACvD,OAASiC,EAAO,CACd,QAAQ,MAAM,mBAAmBjC,EAAM,IAAI,cAAeiC,CAAK,EAC3DjC,EAAM,WAAW,SAASA,EAAM,UAAU,QAAQiC,CAAK,CAC7D,CAGN,CAEAN,GAAmB2B,EAAIC,EAAM,CAC3B,IAAMC,EAAWzF,GAAewF,EAAM,CACpC,UAAW,GACX,QAAS,KAAKlE,GAAgB,KAChC,CAAC,EAEKoE,EAAcxF,GAAUuF,EAAU,IAAM,KAAKhC,GAAgB,CAAC,EAEpE,YAAK9C,GAAU,IAAI,WAAW4E,CAAE,GAAI,CAClC,SAAAE,EACA,YAAAC,CACF,CAAC,EAEMD,CACT,CAEA,SAAU,CACR,KAAK,KAAK,EAGN,KAAKhE,KACP,KAAKA,GAAoB,EACzB,KAAKA,GAAsB,MAEzB,KAAKD,KACP,KAAKA,GAAc,QAAQ,EAC3B,KAAKA,GAAgB,MAEnB,KAAKE,KACP,KAAKA,GAAgB,WAAW,EAChC,KAAKA,GAAkB,MAErB,KAAKJ,IACP,KAAKA,GAAgB,SAAS,EAIhC,QAAWgB,KAAQ,KAAK9B,GAAQ,KAAK,EACnC,KAAK,YAAY8B,CAAI,CAEzB,CAEA,aAAaC,EAAK,CAChB,KAAKtB,GAAe,UAAYsB,EAChC,KAAKtB,GAAe,cAAgB,IAAOsB,CAC7C,CAEA,aAAaC,EAAO,CAClB,KAAKvB,GAAe,UAAY,KAAK,IAAI,EAAGuB,CAAK,CACnD,CAEA,iBAAiBC,EAAM,CACrB,KAAKxB,GAAe,cAAgBwB,CACtC,CAEA,SAASC,EAAU,CAAC,EAAG,CAChB,KAAKzB,GAAe,QACvB,KAAKA,GAAe,MAAQ,CAAC,GAE/B,OAAO,OAAO,KAAKA,GAAe,MAAOyB,CAAO,CAClD,CAEA,YAAa,CACX,MAAO,CACL,GAAG,KAAKvB,GACR,UAAW,KAAKD,GAAQ,UACxB,YAAa,KAAKA,GAAQ,YAC1B,WAAY,KAAKA,GAAQ,UAC3B,CACF,CAGA,mBAAmB6B,EAAiB,CAElC,KAAKzB,GAAgB,YAAYyB,CAAe,EAGhD,KAAK4C,GAA0B5C,CAAe,EAG9C,KAAK6C,GAAmB7C,CAAe,CACzC,CAEA6C,GAAmB7C,EAAiB,CAClC,GAAM,CAAE,KAAAI,CAAK,EAAIJ,EACX8C,EAAU,KAAKvE,GAGrB,OAAQ6B,EAAM,CACZ,IAAK,OACH,KAAK2C,GAAM,eAAgBD,EAAQ,KAAK,EACxC,MAEF,IAAK,KACH,KAAKC,GAAM,aAAcD,EAAQ,KAAK,EAGjCA,EAAQ,YACX,KAAKC,GAAM,gBAAiBD,EAAQ,KAAK,EAE3C,MAEF,IAAK,OAIH,GAHA,KAAKC,GAAM,eAAgBD,EAAQ,KAAK,EAGpCA,EAAQ,YAAcA,EAAQ,UAAW,CAC3C,IAAME,EAAc,KAAKnE,GACzB,KAAKA,GAAe,GAEfmE,EAGH,KAAKD,GAAM,oBAAqBD,EAAQ,KAAK,EAF7C,KAAKC,GAAM,qBAAsBD,EAAQ,KAAK,CAIlD,CACA,MAEF,IAAK,SACH,KAAKC,GAAM,iBAAkBD,EAAQ,KAAK,EAC1C,MAEF,IAAK,OACH,KAAKC,GAAM,eAAgBD,EAAQ,KAAK,EACxC,MAEF,IAAK,WACH,KAAKC,GAAM,mBAAoBD,EAAQ,KAAK,EAC5C,KACJ,CAGI1C,IAAS,MAAQ,KAAKvB,KACxB,KAAKkE,GAAM,mBAAoBD,EAAQ,KAAK,EAC5C,KAAKjE,GAAe,IAItB,IAAMoE,EAAgB,KAAKnE,GACrBoE,EAAeJ,EAAQ,aAEzBI,GAAgB,CAACD,EACnB,KAAKF,GAAM,gBAAiBD,EAAQ,KAAK,EAChC,CAACI,GAAgBD,GAC1B,KAAKF,GAAM,gBAAiBD,EAAQ,KAAK,EAG3C,KAAKhE,GAAiBoE,EAGtB,IAAMC,EAAa,KAAKpE,GAClBqE,EAAYN,EAAQ,UAEtBM,GAAa,CAACD,EAChB,KAAKJ,GAAM,qBAAsBD,EAAQ,KAAK,EACrC,CAACM,GAAaD,GACvB,KAAKJ,GAAM,mBAAoBD,EAAQ,KAAK,EAG9C,KAAK/D,GAAcqE,CACrB,CAEAR,GAA0B5C,EAAiB,CACzC,GAAM,CAAE,KAAAI,EAAM,EAAAiD,EAAG,EAAAjB,CAAE,EAAIpC,EACjB8C,EAAU,KAAKvE,GAErB,OAAQ6B,EAAM,CACZ,IAAK,OAAQ,CACX,IAAMkD,EAAU,KAAKC,GAASF,EAAGjB,CAAC,EAGlC,GAFAU,EAAQ,cAAcQ,CAAO,EAEzBA,GAAS,eAAe,QAAS,CACnC,IAAMjD,EAAM,KAAKmD,GAAmBF,CAAO,EAC3CA,EAAQ,cAAc,QAAQ,CAC5B,GAAGR,EAAQ,MACX,IAAAzC,EACA,KAAM,KAAK0C,GAAM,KAAK,IAAI,CAC5B,CAAC,CACH,CACA,KACF,CAEA,IAAK,KAAM,CACT,IAAMU,EAAaX,EAAQ,WAC3B,GAAIW,GAAY,aAAa,QAAS,CACpC,IAAMpD,EAAM,KAAKmD,GAAmBC,CAAU,EAC9CA,EAAW,YAAY,QAAQ,CAC7B,GAAGX,EAAQ,MACX,IAAAzC,EACA,KAAM,KAAK0C,GAAM,KAAK,IAAI,CAC5B,CAAC,CACH,CACA,KACF,CAEA,IAAK,OAAQ,CACX,IAAMO,EAAU,KAAKC,GAASF,EAAGjB,CAAC,EAC5BsB,EAAcZ,EAAQ,YAGtBW,EAAaX,EAAQ,WAC3B,GAAIW,GAAY,eAAe,SAAWX,EAAQ,WAAY,CAC5D,IAAMzC,EAAM,KAAKmD,GAAmBC,CAAU,EAC9CA,EAAW,cAAc,QAAQ,CAC/B,GAAGX,EAAQ,MACX,IAAAzC,EACA,KAAM,KAAK0C,GAAM,KAAK,IAAI,CAC5B,CAAC,CACH,CAGA,GAAIO,GAAS,KAAOI,GAAa,GAAI,CACnC,GAAIA,GAAa,gBAAgB,QAAS,CACxC,IAAMrD,EAAM,KAAKmD,GAAmBE,CAAW,EAC/CA,EAAY,eAAe,QAAQ,CACjC,GAAGZ,EAAQ,MACX,IAAAzC,EACA,KAAM,KAAK0C,GAAM,KAAK,IAAI,CAC5B,CAAC,CACH,CAEA,GAAIO,GAAS,gBAAgB,QAAS,CACpC,IAAMjD,EAAM,KAAKmD,GAAmBF,CAAO,EAC3CA,EAAQ,eAAe,QAAQ,CAC7B,GAAGR,EAAQ,MACX,IAAAzC,EACA,KAAM,KAAK0C,GAAM,KAAK,IAAI,CAC5B,CAAC,CACH,CAEAD,EAAQ,eAAeQ,CAAO,CAChC,CACA,KACF,CAEA,IAAK,SACL,IAAK,OAEH,MAEF,IAAK,WAEH,KACJ,CACF,CAEAE,GAAmBG,EAAM,CACvB,OAAKA,EACEA,EAAK,QACR,KAAKhG,GAAU,IAAIgG,EAAK,OAAO,EAC/B,KAAKhG,GAAU,IAAIwC,EAAa,IAAI,CAAC,EAHvB,IAIpB,CAEA,UAAUL,EAAOC,EAAU,CACzB,OAAK,KAAKnB,GAAa,IAAIkB,CAAK,GAC9B,KAAKlB,GAAa,IAAIkB,EAAO,IAAI,GAAK,EAExC,KAAKlB,GAAa,IAAIkB,CAAK,EAAE,IAAIC,CAAQ,EAElC,IAAM,CACX,IAAM6D,EAAY,KAAKhF,GAAa,IAAIkB,CAAK,EACzC8D,IACFA,EAAU,OAAO7D,CAAQ,EACrB6D,EAAU,OAAS,GACrB,KAAKhF,GAAa,OAAOkB,CAAK,EAGpC,CACF,CAEAyD,GAASF,EAAGjB,EAAG,CAEb,IAAMyB,EAAS,KAAKxF,GAAa,MAAM,KAAK,CAACyF,EAAGC,KAC7CA,EAAE,UAAY,IAAMD,EAAE,UAAY,EACrC,EAEA,QAAWH,KAAQE,EACjB,GAAI,KAAKG,GAAiBX,EAAGjB,EAAGuB,EAAK,MAAM,EACzC,OAAOA,EAGX,OAAO,IACT,CAEAK,GAAiBX,EAAGjB,EAAG6B,EAAQ,CAC7B,OAAOZ,GAAKY,EAAO,GACZZ,GAAKY,EAAO,EAAIA,EAAO,OACvB7B,GAAK6B,EAAO,GACZ7B,GAAK6B,EAAO,EAAIA,EAAO,MAChC,CAEAlB,GAAMjD,EAAO2C,EAAM,CACjB,IAAMmB,EAAY,KAAKhF,GAAa,IAAIkB,CAAK,EAC7C,GAAI8D,EACF,QAAW7D,KAAY6D,EACrB7D,EAAS0C,CAAI,CAGnB,CAGA,sBAAsBzC,EAAiB,CACrC,KAAKzB,GAAgB,YAAYyB,CAAe,EAChD,KAAK4C,GAA0B5C,CAAe,CAChD,CACF",
6
6
  "names": ["ContextTypes", "HitRegistry", "#areas", "id", "area", "ServiceProvider", "CanvasEvents", "#canvas", "#offscreenCanvas", "#cachedRect", "#resizeObserver", "#subscribers", "#resizeSubscribers", "#pendingMove", "#rafId", "#hasTransferredControl", "canvas", "listener", "#removeListeners", "#updateCachedRect", "#initializeListeners", "subscriber", "#emitResize", "entries", "entry", "width", "height", "#handleScroll", "#handleMove", "#handleDown", "#handleUp", "#handleDblClick", "event", "normalized", "#normalizeEvent", "#emit", "resizeData", "type", "isOverCanvas", "x", "y", "isWithinBounds", "defineSurface", "usePointerSurface", "setup", "x", "y", "prevX", "prevY", "clientX", "clientY", "isOverCanvas", "isWithinBounds", "isPressed", "button", "buttons", "lastEventType", "downTime", "upTime", "lastMoveTime", "lastEventTime", "dragStartX", "dragStartY", "isDragging", "clickCount", "lastClickTime", "velocityX", "velocityY", "lastScrollDeltaX", "lastScrollDeltaY", "lastZoomDelta", "hoveredArea", "activeArea", "config", "position", "clientPosition", "previousPosition", "delta", "xVal", "prevXVal", "yVal", "prevYVal", "velocity", "speed", "vx", "vy", "dragDistance", "startX", "startY", "dx", "dy", "dragDelta", "holdDuration", "isHolding", "timeSinceLastEvent", "lastTime", "state", "updatePosition", "newX", "newY", "newClientX", "newClientY", "updateVelocity", "now", "lastMove", "dt", "newVx", "newVy", "maxVel", "clampedVx", "clampedVy", "smoothing", "handleEvent", "ctx", "normalizedEvent", "type", "eventButton", "eventButtons", "eventIsOverCanvas", "eventIsWithinBounds", "setHoveredArea", "area", "setActiveArea", "reset", "updateConfig", "updates", "ServiceProvider", "createComputed", "destroyComputed", "addEffect", "createDefinition", "definitionType", "defineBrush", "defineLayer", "Painter", "#layers", "#canvas", "#contexts", "#reactors", "#assets", "#isRunning", "#frameId", "#isRendering", "#renderScheduled", "#runtimeConfig", "#timing", "#metrics", "#hitRegistry", "HitRegistry", "#pointerSurface", "usePointerSurface", "#canvasEvents", "#pointerUnsubscribe", "#resizeObserver", "#subscribers", "#wasDragging", "#wasOverCanvas", "#wasHolding", "layerDef", "layers", "layer", "fn", "canvas", "offscreenCanvas", "assets", "name", "fps", "scale", "step", "options", "width", "height", "event", "callback", "normalizedEvent", "path", "domCanvas", "ContextTypes", "type", "ctx", "CanvasEvents", "entries", "entry", "result", "#scheduleRender", "config", "dataReactor", "#createDataReactor", "brushes", "child", "brushConfig", "whenReactor", "brush", "error", "reactorData", "layerReactorData", "#render", "renderStart", "layerStart", "layerReactor", "key", "value", "brushStart", "brushCtx", "requiredAssets", "brushTime", "#renderBrushBounds", "layerTime", "#renderLayerBounds", "#renderDebugOverlay", "y", "lineHeight", "text", "time", "id", "data", "computed", "unsubscribe", "#handlePointerInteraction", "#emitPointerEvents", "pointer", "#emit", "wasDragging", "wasOverCanvas", "isOverCanvas", "wasHolding", "isHolding", "x", "hitArea", "#hitTest", "#getContextForArea", "activeArea", "prevHovered", "area", "callbacks", "sorted", "a", "b", "#isPointInBounds", "bounds"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jucie.io/engine-painter",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "Canvas painting service for @jucie.io/engine with reactive rendering support",
5
5
  "type": "module",
6
6
  "main": "./dist/main.js",