@jucie-engine/painter 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var G=Object.defineProperty;var xe=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var Te=Object.prototype.hasOwnProperty;var Ee=(s,e)=>{for(var t in e)G(s,t,{get:e[t],enumerable:!0})},Se=(s,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of we(e))!Te.call(s,r)&&r!==t&&G(s,r,{get:()=>e[r],enumerable:!(i=xe(e,r))||i.enumerable});return s};var Ce=s=>Se(G({},"__esModule",{value:!0}),s);var Re={};Ee(Re,{CanvasPointer:()=>B,HitRegistry:()=>Y,Painter:()=>j,defineBrush:()=>le,defineLayer:()=>ce,usePointerSurface:()=>I});module.exports=Ce(Re);var oe=require("@jucie-engine/core");var K={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};var V=require("@jucie-state/reactive"),F=require("@jucie-engine/core");var Y=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()}};var re=require("@jucie-engine/core"),B=class extends re.ServiceProvider{#e=null;#s=null;#i=null;#a=new Set;#f=null;#l=null;static manifest={name:"CanvasPointer",namespace:"canvasPointer",version:"1.0.0"};actions(){return{setCanvas:e=>this.setCanvas(e),subscribe:e=>this.subscribe(e),getOffscreenCanvas:()=>this.getOffscreenCanvas()}}getOffscreenCanvas(){return this.#e?this.#e.transferControlToOffscreen():null}setCanvas(e){this.#e&&this.#m(),this.#e=e,this.#u(),this.#b()}subscribe(e){return this.#a.add(e),()=>this.#a.delete(e)}#u(){this.#e&&(this.#s=this.#e.getBoundingClientRect())}#b(){this.#e&&(this.#u(),this.#i=new ResizeObserver(()=>{this.#u()}),this.#i.observe(this.#e),document.addEventListener("wheel",this.#t,{passive:!1}),document.addEventListener("pointermove",this.#o),document.addEventListener("pointerdown",this.#d),document.addEventListener("pointerup",this.#h),document.addEventListener("pointercancel",this.#h),document.addEventListener("dblclick",this.#c))}#m(){this.#i&&(this.#i.disconnect(),this.#i=null),document.removeEventListener("wheel",this.#t),document.removeEventListener("pointermove",this.#o),document.removeEventListener("pointerdown",this.#d),document.removeEventListener("pointerup",this.#h),document.removeEventListener("pointercancel",this.#h),document.removeEventListener("dblclick",this.#c)}#t=e=>{if(e.target===this.#e)if(e.preventDefault(),e.stopPropagation(),e.ctrlKey){let t=this.#r(e,"zoom");this.#n(t)}else{let t=this.#r(e,"scroll");this.#n(t)}};#o=e=>{let t=this.#r(e,"move");this.#f=t,!this.#l&&(this.#l=requestAnimationFrame(()=>{this.#f&&(this.#n(this.#f),this.#f=null),this.#l=null}))};#d=e=>{if(e.target===this.#e){let t=this.#r(e,"down");this.#n(t)}};#h=e=>{let t=this.#r(e,"up");this.#n(t)};#c=e=>{let t=this.#r(e,"dblclick");this.#n(t)};#n(e){for(let t of this.#a)t(e)}#r(e,t){let i=e.target===this.#e,r,n;i?(r=e.offsetX,n=e.offsetY):this.#s?(r=e.clientX-this.#s.left,n=e.clientY-this.#s.top):(r=e.clientX,n=e.clientY);let d=i||this.#s&&r>=0&&r<=this.#s.width&&n>=0&&n<=this.#s.height,o={x:r,y:n,type:t,isOverCanvas:i,isWithinBounds:d,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.#l&&(cancelAnimationFrame(this.#l),this.#l=null),this.#m(),this.#e=null,this.#s=null,this.#a.clear()}};var ae=require("@jucie-state/reactive"),I=(0,ae.defineSurface)(s=>{let e=s.value(0),t=s.value(0),i=s.value(0),r=s.value(0),n=s.value(0),d=s.value(0),o=s.value(!1),y=s.value(!1),g=s.value(!1),p=s.value(null),l=s.value(0),f=s.value(null),m=s.value(null),C=s.value(null),X=s.value(null),_=s.value(null),$=s.value(null),z=s.value(null),u=s.value(!1),P=s.value(0),T=s.value(0),a=s.value(0),E=s.value(0),S=s.value(0),x=s.value(0),R=s.value(0),U=s.value(null),W=s.value(null),D=s.value({dragThreshold:5,doubleClickThreshold:300,holdThreshold:500,velocitySmoothing:.3,maxVelocity:1e4}),N=s.computed(()=>({x:e.value,y:t.value})),J=s.computed(()=>({x:n.value,y:d.value})),Q=s.computed(()=>({x:i.value,y:r.value})),ee=s.computed(()=>{let h=typeof e.value=="number"?e.value:0,c=typeof i.value=="number"?i.value:0,v=typeof t.value=="number"?t.value:0,b=typeof r.value=="number"?r.value:0;return{x:h-c,y:v-b}}),te=s.computed(()=>({x:a.value,y:E.value})),se=s.computed(()=>{let h=a.value,c=E.value;return Math.sqrt(h*h+c*c)}),H=s.computed(()=>{let h=$.value,c=z.value;if(h===null||c===null||typeof h!="number"||typeof c!="number")return 0;let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0,L=v-h,w=b-c;return Math.sqrt(L*L+w*w)}),ie=s.computed(()=>{let h=$.value,c=z.value;if(h===null||c===null||typeof h!="number"||typeof c!="number")return{x:0,y:0};let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0;return{x:v-h,y:b-c}}),q=s.computed(()=>!g.value||!m.value?0:Date.now()-m.value),ne=s.computed(()=>q.value>D.value.holdThreshold&&!u.value),ue=s.computed(()=>{let h=_.value;return h?Date.now()-h:0}),he=s.computed(()=>({position:N.value,clientPosition:J.value,previousPosition:Q.value,delta:ee.value,velocity:te.value,speed:se.value,isPressed:g.value,button:p.value,buttons:l.value,isDragging:u.value,dragDistance:H.value,dragDelta:ie.value,isHolding:ne.value,holdDuration:q.value,isOverCanvas:o.value,isWithinBounds:y.value,hoveredArea:U.value,activeArea:W.value,clickCount:P.value,lastEventType:f.value})),A=s.action((h,c,v,b,L)=>{i.value=e.value,r.value=t.value,e.value=c,t.value=v,n.value=b,d.value=L,X.value=Date.now()}),de=s.action(()=>{let h=Date.now(),c=X.value;if(c){let v=(h-c)/1e3;if(v>0&&v<.1){let b=(e.value-i.value)/v,L=(t.value-r.value)/v,w=D.value.maxVelocity,k=Math.max(-w,Math.min(w,b)),Z=Math.max(-w,Math.min(w,L)),M=D.value.velocitySmoothing;a.value=a.value*(1-M)+k*M,E.value=E.value*(1-M)+Z*M}}}),fe=s.action((h,c)=>{let{x:v,y:b,type:L,clientX:w,clientY:k,button:Z,buttons:M,isOverCanvas:ge,isWithinBounds:pe}=c,O=Date.now();switch(_.value=O,f.value=L,o.value=ge,y.value=pe,L){case"down":A(h,v,b,w,k),g.value=!0,m.value=O,p.value=Z,l.value=M,$.value=v,z.value=b,u.value=!1,O-T.value<D.value.doubleClickThreshold?P.value=P.value+1:P.value=1;break;case"up":A(h,v,b,w,k),g.value=!1,C.value=O,T.value=O,u.value=!1,a.value=0,E.value=0,l.value=M;break;case"move":A(h,v,b,w,k),de(),l.value=M,g.value&&!u.value&&H.value>D.value.dragThreshold&&(u.value=!0);break;case"dblclick":A(h,v,b,w,k),P.value=2;break;case"scroll":A(h,v,b,w,k),c.deltaX!==void 0&&(S.value=c.deltaX),c.deltaY!==void 0&&(x.value=c.deltaY);break;case"zoom":A(h,v,b,w,k),c.deltaY!==void 0&&(R.value=c.deltaY);break}}),ve=s.action((h,c)=>{U.value=c}),me=s.action((h,c)=>{W.value=c}),ye=s.action(()=>{g.value=!1,u.value=!1,W.value=null,U.value=null,a.value=0,E.value=0,P.value=0,S.value=0,x.value=0,R.value=0}),be=s.action((h,c)=>{D.value={...D.value,...c}});return{state:he,position:N,clientPosition:J,previousPosition:Q,delta:ee,velocity:te,speed:se,isPressed:g,button:p,buttons:l,isDragging:u,dragDistance:H,dragDelta:ie,isHolding:ne,holdDuration:q,isOverCanvas:o,isWithinBounds:y,hoveredArea:U,activeArea:W,clickCount:P,lastEventType:f,timeSinceLastEvent:ue,handleEvent:fe,setHoveredArea:ve,setActiveArea:me,reset:ye,updateConfig:be}});var le=(0,F.createDefinition)("BRUSH",[Object]),ce=(0,F.createDefinition)("LAYER",[Object]),j=class extends oe.ServiceProvider{#e=new Map;#s=null;#i=new Map;#a=new Map;#f=new Map;#l=!1;#u=null;#b=!1;#m=!1;#t={targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}};#o={lastFrameTime:0,deltaTime:0,elapsedTime:0,frameCount:0};#d={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#h=new Y;#c=null;#n=I();#r=null;#y=new Map;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),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),subscribeToPointer:e=>this.#n.$subscribe(e),bindPointer:e=>this.#n.$bind(e),_testEmitPointerEvent:e=>this._testEmitPointerEvent(e)}}setCanvas(e){this.#s=e,Object.values(K).forEach(t=>{try{let i=e.getContext(t);i&&this.#i.set(t,i)}catch{console.warn(`Context type ${t} not supported`)}}),this.#c||(this.#c=new B),this.#c.setCanvas(e),this.#r&&this.#r(),this.#r=this.#c.subscribe(t=>{this.#n.handleEvent(t),this.#w(t)})}updateCanvas(e){let t=e(this.#s);t&&(this.#s=t)}setAssets(e){this.#f=e}start(){this.#l||(this.#l=!0,this.#p())}stop(){this.#l&&(this.#l=!1,this.#u&&(cancelAnimationFrame(this.#u),this.#u=null))}addLayer(e){var d;if((0,F.definitionType)(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,i=e(this.useContext,this.#h);if(i.data){let o=this.#x(`layer_${t}`,i.data);o&&this.#a.set(`layer_${t}`,o)}let r=i.children.map(o=>{var y;if((0,F.definitionType)(o)==="BRUSH"){let g=o._name,p=o(this.useContext,this.#h),l=p.data?this.#x(`brush_${g}`,p.data):()=>{},f=p.when?(0,V.createReactor)(p.when,{immediate:!0,context:this.useContext("state")}):null,m={name:g,...p,dataReactor:l,whenReactor:f};if((y=m.lifecycle)!=null&&y.onMount)try{m.lifecycle.onMount(this.#i.get(m.context||i.context))}catch(C){console.error(`Error in brush "${m.name}" onMount:`,C)}return m}return this.addLayer(o)}),n={...i,name:t,brushes:r,context:this.#i.get(i.context)};if(this.#e.set(t,n),(d=n.lifecycle)!=null&&d.onMount)try{n.lifecycle.onMount(n.context)}catch(o){console.error(`Error in layer "${t}" onMount:`,o)}return n}removeLayer(e){var r;let t=this.#e.get(e);if(!t)return;if((r=t.lifecycle)!=null&&r.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(n){console.error(`Error in layer "${e}" onUnmount:`,n)}t.brushes.forEach(n=>{var o;if((o=n.lifecycle)!=null&&o.onUnmount)try{n.lifecycle.onUnmount(this.#i.get(n.context||t.context))}catch(y){console.error(`Error in brush "${n.name}" onUnmount:`,y)}let d=this.#a.get(`painter_brush_${n.name}`);d&&(d.unsubscribe(),d.reactor.destroy(),this.#a.delete(`painter_brush_${n.name}`))});let i=this.#a.get(`painter_layer_${e}`);i&&(i.unsubscribe(),i.reactor.destroy(),this.#a.delete(`painter_layer_${e}`)),this.#e.delete(e)}#p(){this.#m||this.#b||(this.#m=!0,this.#u=requestAnimationFrame(()=>{this.#m=!1,this.#u=null,this.#E()}))}async#E(){var e,t,i,r,n,d,o,y,g,p,l,f,m,C,X,_,$;if(this.#s){this.#b=!0;try{this.#h.clear();let z=(e=this.#t.debug)!=null&&e.enabled?performance.now():0;this.#i.forEach(u=>{u.clearRect(0,0,this.#s.width,this.#s.height)});for(let u of this.#e.values()){let P=(t=this.#t.debug)!=null&&t.enabled?performance.now():0;if(u.whenReactor){let a=(i=this.#a.get(`painter_layer_${u.name}`))==null?void 0:i.reactor;if(!u.when(a()))continue}let T=u.context;if(T){if((r=u.lifecycle)!=null&&r.beforeRender)try{u.lifecycle.beforeRender(T,this.#o)}catch(a){console.error(`Error in layer "${u.name}" beforeRender:`,a),(n=u.lifecycle)!=null&&n.onError&&u.lifecycle.onError(a)}T.save(),u.settings&&Object.entries(u.settings).forEach(([a,E])=>{typeof T[a]=="function"?T[a](...Array.isArray(E)?E:[E]):T[a]=E});for(let a of u.brushes){let E=(d=this.#t.debug)!=null&&d.enabled?performance.now():0;if(a.whenReactor&&!a.whenReactor())continue;let S=a.context?this.#i.get(a.context):T;if(S){if((o=a.lifecycle)!=null&&o.beforeRender)try{a.lifecycle.beforeRender(S,this.#o)}catch(x){console.error(`Error in brush "${a.name}" beforeRender:`,x),(y=a.lifecycle)!=null&&y.onError&&a.lifecycle.onError(x);continue}S.save(),a.settings&&Object.entries(a.settings).forEach(([x,R])=>{typeof S[x]=="function"?S[x](...Array.isArray(R)?R:[R]):S[x]=R});try{let x={};if(a.assets)for(let R of a.assets)x[R]=this.#f.get(R);if(a.render(S,a.dataReactor(),x,this.#o),(g=a.lifecycle)!=null&&g.afterRender&&a.lifecycle.afterRender(S,this.#o),(p=this.#t.debug)!=null&&p.enabled){let R=performance.now()-E;this.#d.brushTimes.set(a.name,R),(l=this.#t.debug)!=null&&l.showBounds&&this.#S(S,a)}}catch(x){console.error(`Error in brush "${a.name}":`,x),(f=a.lifecycle)!=null&&f.onError&&a.lifecycle.onError(x)}finally{S.restore()}}}if(T.restore(),(m=u.lifecycle)!=null&&m.afterRender)try{u.lifecycle.afterRender(T,this.#o)}catch(a){console.error(`Error in layer "${u.name}" afterRender:`,a),(C=u.lifecycle)!=null&&C.onError&&u.lifecycle.onError(a)}if((X=this.#t.debug)!=null&&X.enabled){let a=performance.now()-P;this.#d.layerTimes.set(u.name,a),(_=this.#t.debug)!=null&&_.showBounds&&this.#C(T,u)}}}($=this.#t.debug)!=null&&$.enabled&&this.#R()}finally{this.#b=!1}}}#S(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()}#C(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()}#R(){var r,n;let e=this.#i.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,i=15;if((r=this.#t.debug)!=null&&r.showFPS){let d=`FPS: ${Math.round(this.#d.fps)} (${this.#o.deltaTime.toFixed(2)}ms)`;e.strokeText(d,10,t),e.fillText(d,10,t),t+=i}if((n=this.#t.debug)!=null&&n.showLayerTiming){e.fillText("Layer Times:",10,t),t+=i;for(let[d,o]of this.#d.layerTimes){let y=` ${d}: ${o.toFixed(2)}ms`;e.strokeText(y,10,t),e.fillText(y,10,t),t+=i}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){var i,r;for(let n of this.#e.values())if((i=n.lifecycle)!=null&&i.onResize)try{n.lifecycle.onResize(e,t,n.context)}catch(d){console.error(`Error in layer "${n.name}" onResize:`,d),(r=n.lifecycle)!=null&&r.onError&&n.lifecycle.onError(d)}}#x(e,t){let i=this.useContext("state"),r=(0,V.createReactor)(t,{immediate:!0,context:i}),n=(0,V.addEffect)(r,()=>this.#p());return this.#a.set(`painter_${e}`,{reactor:r,unsubscribe:n}),r}destroy(){this.stop(),this.#r&&(this.#r(),this.#r=null),this.#c&&(this.#c.destroy(),this.#c=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.#d,deltaTime:this.#o.deltaTime,elapsedTime:this.#o.elapsedTime,frameCount:this.#o.frameCount}}#w(e){var d,o,y,g,p;let{type:t,x:i,y:r}=e,n=this.#n;switch(t){case"down":{let l=this.#T(i,r);if(n.setActiveArea(l),(d=l==null?void 0:l.onPointerDown)!=null&&d.handler){let f=this.#g(l);l.onPointerDown.handler({...n.state,ctx:f,emit:this.#v.bind(this)})}break}case"up":{let l=n.activeArea;if((o=l==null?void 0:l.onPointerUp)!=null&&o.handler){let f=this.#g(l);l.onPointerUp.handler({...n.state,ctx:f,emit:this.#v.bind(this)})}break}case"move":{let l=this.#T(i,r),f=n.hoveredArea,m=n.activeArea;if((y=m==null?void 0:m.onPointerMove)!=null&&y.handler&&n.isDragging){let C=this.#g(m);m.onPointerMove.handler({...n.state,ctx:C,emit:this.#v.bind(this)})}if((l==null?void 0:l.id)!==(f==null?void 0:f.id)){if((g=f==null?void 0:f.onPointerLeave)!=null&&g.handler){let C=this.#g(f);f.onPointerLeave.handler({...n.state,ctx:C,emit:this.#v.bind(this)})}if((p=l==null?void 0:l.onPointerEnter)!=null&&p.handler){let C=this.#g(l);l.onPointerEnter.handler({...n.state,ctx:C,emit:this.#v.bind(this)})}n.setHoveredArea(l)}break}case"scroll":case"zoom":this.#v(`pointer:${t}`,n.state);break;case"dblclick":this.#v("pointer:dblclick",n.state);break}}#g(e){return e?e.context?this.#i.get(e.context):this.#i.get(K["2D"]):null}subscribe(e,t){return this.#y.has(e)||this.#y.set(e,new Set),this.#y.get(e).add(t),()=>{let i=this.#y.get(e);i&&(i.delete(t),i.size===0&&this.#y.delete(e))}}#T(e,t){let i=this.#h.areas.sort((r,n)=>(n.priority||0)-(r.priority||0));for(let r of i)if(this.#P(e,t,r.bounds))return r;return null}#P(e,t,i){return e>=i.x&&e<=i.x+i.width&&t>=i.y&&t<=i.y+i.height}#v(e,t){let i=this.#y.get(e);if(i)for(let r of i)r(t)}_testEmitPointerEvent(e){this.#n.handleEvent(e),this.#w(e)}};0&&(module.exports={CanvasPointer,HitRegistry,Painter,defineBrush,defineLayer,usePointerSurface});
1
+ var G=Object.defineProperty;var we=Object.getOwnPropertyDescriptor;var xe=Object.getOwnPropertyNames;var Te=Object.prototype.hasOwnProperty;var Ee=(n,e)=>{for(var t in e)G(n,t,{get:e[t],enumerable:!0})},Ce=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of xe(e))!Te.call(n,r)&&r!==t&&G(n,r,{get:()=>e[r],enumerable:!(s=we(e,r))||s.enumerable});return n};var Se=n=>Ce(G({},"__esModule",{value:!0}),n);var Re={};Ee(Re,{CanvasEvents:()=>Y,HitRegistry:()=>A,Painter:()=>j,defineBrush:()=>le,defineLayer:()=>ce,usePointerSurface:()=>K});module.exports=Se(Re);var oe=require("@jucie-engine/core");var _={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};var V=require("@jucie-state/reactive"),z=require("@jucie-engine/core");var A=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()}};var re=require("@jucie-engine/core"),Y=class extends re.ServiceProvider{#e=null;#r=null;#s=null;#a=null;#g=new Set;#v=new Set;#h=null;#u=null;#y=!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.#b(),this.#e=e,this.#t(),this.#l()}subscribe(e){return this.#g.add(e),()=>this.#g.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.#y)throw new Error("Control has already been transferred to offscreen");return this.#r=this.#e.transferControlToOffscreen(),this.#y=!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(()=>{this.#t(),this.#y&&this.#w({width:this.#e.width,height:this.#e.height})}),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))}#b(){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.#g)t(e)}#w(e){for(let t of this.#v)t(e)}#m(e,t){let s=e.target===this.#e,r,i;s?(r=e.offsetX,i=e.offsetY):this.#s?(r=e.clientX-this.#s.left,i=e.clientY-this.#s.top):(r=e.clientX,i=e.clientY);let u=s||this.#s&&r>=0&&r<=this.#s.width&&i>=0&&i<=this.#s.height,o={x:r,y:i,type:t,isOverCanvas:s,isWithinBounds:u,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.#b(),this.#e=null,this.#r=null,this.#s=null,this.#g.clear(),this.#v.clear(),this.#y=!1}};var ae=require("@jucie-state/reactive"),K=(0,ae.defineSurface)(n=>{let e=n.value(0),t=n.value(0),s=n.value(0),r=n.value(0),i=n.value(0),u=n.value(0),o=n.value(!1),m=n.value(!1),g=n.value(!1),p=n.value(null),l=n.value(0),f=n.value(null),y=n.value(null),S=n.value(null),B=n.value(null),F=n.value(null),O=n.value(null),U=n.value(null),h=n.value(!1),P=n.value(0),T=n.value(0),a=n.value(0),E=n.value(0),C=n.value(0),w=n.value(0),R=n.value(0),H=n.value(null),W=n.value(null),M=n.value({dragThreshold:5,doubleClickThreshold:300,holdThreshold:500,velocitySmoothing:.3,maxVelocity:1e4}),N=n.computed(()=>({x:e.value,y:t.value})),J=n.computed(()=>({x:i.value,y:u.value})),Q=n.computed(()=>({x:s.value,y:r.value})),ee=n.computed(()=>{let d=typeof e.value=="number"?e.value:0,c=typeof s.value=="number"?s.value:0,v=typeof t.value=="number"?t.value:0,b=typeof r.value=="number"?r.value:0;return{x:d-c,y:v-b}}),te=n.computed(()=>({x:a.value,y:E.value})),se=n.computed(()=>{let d=a.value,c=E.value;return Math.sqrt(d*d+c*c)}),I=n.computed(()=>{let d=O.value,c=U.value;if(d===null||c===null||typeof d!="number"||typeof c!="number")return 0;let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0,k=v-d,x=b-c;return Math.sqrt(k*k+x*x)}),ie=n.computed(()=>{let d=O.value,c=U.value;if(d===null||c===null||typeof d!="number"||typeof c!="number")return{x:0,y:0};let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0;return{x:v-d,y:b-c}}),q=n.computed(()=>!g.value||!y.value?0:Date.now()-y.value),ne=n.computed(()=>q.value>M.value.holdThreshold&&!h.value),he=n.computed(()=>{let d=F.value;return d?Date.now()-d:0}),ue=n.computed(()=>({position:N.value,clientPosition:J.value,previousPosition:Q.value,delta:ee.value,velocity:te.value,speed:se.value,isPressed:g.value,button:p.value,buttons:l.value,isDragging:h.value,dragDistance:I.value,dragDelta:ie.value,isHolding:ne.value,holdDuration:q.value,isOverCanvas:o.value,isWithinBounds:m.value,hoveredArea:H.value,activeArea:W.value,clickCount:P.value,lastEventType:f.value})),$=n.action((d,c,v,b,k)=>{s.value=e.value,r.value=t.value,e.value=c,t.value=v,i.value=b,u.value=k,B.value=Date.now()}),de=n.action(()=>{let d=Date.now(),c=B.value;if(c){let v=(d-c)/1e3;if(v>0&&v<.1){let b=(e.value-s.value)/v,k=(t.value-r.value)/v,x=M.value.maxVelocity,L=Math.max(-x,Math.min(x,b)),Z=Math.max(-x,Math.min(x,k)),D=M.value.velocitySmoothing;a.value=a.value*(1-D)+L*D,E.value=E.value*(1-D)+Z*D}}}),fe=n.action((d,c)=>{let{x:v,y:b,type:k,clientX:x,clientY:L,button:Z,buttons:D,isOverCanvas:ge,isWithinBounds:pe}=c,X=Date.now();switch(F.value=X,f.value=k,o.value=ge,m.value=pe,k){case"down":$(d,v,b,x,L),g.value=!0,y.value=X,p.value=Z,l.value=D,O.value=v,U.value=b,h.value=!1,X-T.value<M.value.doubleClickThreshold?P.value=P.value+1:P.value=1;break;case"up":$(d,v,b,x,L),g.value=!1,S.value=X,T.value=X,h.value=!1,a.value=0,E.value=0,l.value=D;break;case"move":$(d,v,b,x,L),de(),l.value=D,g.value&&!h.value&&I.value>M.value.dragThreshold&&(h.value=!0);break;case"dblclick":$(d,v,b,x,L),P.value=2;break;case"scroll":$(d,v,b,x,L),c.deltaX!==void 0&&(C.value=c.deltaX),c.deltaY!==void 0&&(w.value=c.deltaY);break;case"zoom":$(d,v,b,x,L),c.deltaY!==void 0&&(R.value=c.deltaY);break}}),ve=n.action((d,c)=>{H.value=c}),me=n.action((d,c)=>{W.value=c}),ye=n.action(()=>{g.value=!1,h.value=!1,W.value=null,H.value=null,a.value=0,E.value=0,P.value=0,C.value=0,w.value=0,R.value=0}),be=n.action((d,c)=>{M.value={...M.value,...c}});return{state:ue,position:N,clientPosition:J,previousPosition:Q,delta:ee,velocity:te,speed:se,isPressed:g,button:p,buttons:l,isDragging:h,dragDistance:I,dragDelta:ie,isHolding:ne,holdDuration:q,isOverCanvas:o,isWithinBounds:m,hoveredArea:H,activeArea:W,clickCount:P,lastEventType:f,timeSinceLastEvent:he,handleEvent:fe,setHoveredArea:ve,setActiveArea:me,reset:ye,updateConfig:be}});var le=(0,z.createDefinition)("BRUSH",[Object]),ce=(0,z.createDefinition)("LAYER",[Object]),j=class extends oe.ServiceProvider{#e=new Map;#r=null;#s=new Map;#a=new Map;#g=new Map;#v=!1;#h=null;#u=!1;#y=!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};#b={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#p=new A;#n=K();#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(_).forEach(r=>{try{let i=s.getContext(r);i&&this.#s.set(r,i)}catch{console.warn(`Context type ${r} not supported`)}}),this.#d||(this.#d=new Y),this.#d.setCanvas(t),this.#f&&this.#f.disconnect(),this.#f=new ResizeObserver(r=>{let i=r[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(r=>{this.handlePointerEvent(r)})}setOffscreenCanvas(e){this.#r=e,Object.values(_).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.#g=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){var u;if((0,z.definitionType)(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,s=e(this.useContext,this.#p);if(s.data){let o=this.#C(`layer_${t}`,s.data);o&&this.#a.set(`layer_${t}`,o)}let r=s.children.map(o=>{var m;if((0,z.definitionType)(o)==="BRUSH"){let g=o._name,p=o(this.useContext,this.#p),l=p.data?this.#C(`brush_${g}`,p.data):()=>{},f=p.when?(0,V.createReactor)(p.when,{immediate:!0,context:this.#n.state}):null,y={name:g,...p,dataReactor:l,whenReactor:f};if((m=y.lifecycle)!=null&&m.onMount)try{y.lifecycle.onMount(this.#s.get(y.context||s.context))}catch(S){console.error(`Error in brush "${y.name}" onMount:`,S)}return y}return this.addLayer(o)}),i={...s,name:t,brushes:r,context:this.#s.get(s.context)};if(this.#e.set(t,i),(u=i.lifecycle)!=null&&u.onMount)try{i.lifecycle.onMount(i.context)}catch(o){console.error(`Error in layer "${t}" onMount:`,o)}return i}removeLayer(e){var r;let t=this.#e.get(e);if(!t)return;if((r=t.lifecycle)!=null&&r.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(i){console.error(`Error in layer "${e}" onUnmount:`,i)}t.brushes.forEach(i=>{var o;if((o=i.lifecycle)!=null&&o.onUnmount)try{i.lifecycle.onUnmount(this.#s.get(i.context||t.context))}catch(m){console.error(`Error in brush "${i.name}" onUnmount:`,m)}let u=this.#a.get(`painter_brush_${i.name}`);u&&(u.unsubscribe(),u.reactor.destroy(),this.#a.delete(`painter_brush_${i.name}`))});let s=this.#a.get(`painter_layer_${e}`);s&&(s.unsubscribe(),s.reactor.destroy(),this.#a.delete(`painter_layer_${e}`)),this.#e.delete(e)}#E(){this.#y||this.#u||(this.#y=!0,this.#h=requestAnimationFrame(()=>{this.#y=!1,this.#h=null,this.#P()}))}async#P(){var e,t,s,r,i,u,o,m,g,p,l,f,y,S,B,F,O;if(this.#r){this.#u=!0;try{this.#p.clear();let U=(e=this.#t.debug)!=null&&e.enabled?performance.now():0;this.#s.forEach(h=>{h.clearRect(0,0,this.#r.width,this.#r.height)});for(let h of this.#e.values()){let P=(t=this.#t.debug)!=null&&t.enabled?performance.now():0;if(h.whenReactor){let a=(s=this.#a.get(`painter_layer_${h.name}`))==null?void 0:s.reactor;if(!h.when(a()))continue}let T=h.context;if(T){if((r=h.lifecycle)!=null&&r.beforeRender)try{h.lifecycle.beforeRender(T,this.#l)}catch(a){console.error(`Error in layer "${h.name}" beforeRender:`,a),(i=h.lifecycle)!=null&&i.onError&&h.lifecycle.onError(a)}T.save(),h.settings&&Object.entries(h.settings).forEach(([a,E])=>{typeof T[a]=="function"?T[a](...Array.isArray(E)?E:[E]):T[a]=E});for(let a of h.brushes){let E=(u=this.#t.debug)!=null&&u.enabled?performance.now():0;if(a.whenReactor&&!a.whenReactor())continue;let C=a.context?this.#s.get(a.context):T;if(C){if((o=a.lifecycle)!=null&&o.beforeRender)try{a.lifecycle.beforeRender(C,this.#l)}catch(w){console.error(`Error in brush "${a.name}" beforeRender:`,w),(m=a.lifecycle)!=null&&m.onError&&a.lifecycle.onError(w);continue}C.save(),a.settings&&Object.entries(a.settings).forEach(([w,R])=>{typeof C[w]=="function"?C[w](...Array.isArray(R)?R:[R]):C[w]=R});try{let w={};if(a.assets)for(let R of a.assets)w[R]=this.#g.get(R);if(a.render(C,a.dataReactor(),w,this.#l),(g=a.lifecycle)!=null&&g.afterRender&&a.lifecycle.afterRender(C,this.#l),(p=this.#t.debug)!=null&&p.enabled){let R=performance.now()-E;this.#b.brushTimes.set(a.name,R),(l=this.#t.debug)!=null&&l.showBounds&&this.#k(C,a)}}catch(w){console.error(`Error in brush "${a.name}":`,w),(f=a.lifecycle)!=null&&f.onError&&a.lifecycle.onError(w)}finally{C.restore()}}}if(T.restore(),(y=h.lifecycle)!=null&&y.afterRender)try{h.lifecycle.afterRender(T,this.#l)}catch(a){console.error(`Error in layer "${h.name}" afterRender:`,a),(S=h.lifecycle)!=null&&S.onError&&h.lifecycle.onError(a)}if((B=this.#t.debug)!=null&&B.enabled){let a=performance.now()-P;this.#b.layerTimes.set(h.name,a),(F=this.#t.debug)!=null&&F.showBounds&&this.#L(T,h)}}}(O=this.#t.debug)!=null&&O.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(){var r,i;let e=this.#s.get(_["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((r=this.#t.debug)!=null&&r.showFPS){let u=`FPS: ${Math.round(this.#b.fps)} (${this.#l.deltaTime.toFixed(2)}ms)`;e.strokeText(u,10,t),e.fillText(u,10,t),t+=s}if((i=this.#t.debug)!=null&&i.showLayerTiming){e.fillText("Layer Times:",10,t),t+=s;for(let[u,o]of this.#b.layerTimes){let m=` ${u}: ${o.toFixed(2)}ms`;e.strokeText(m,10,t),e.fillText(m,10,t),t+=s}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){var s,r;for(let i of this.#e.values())if((s=i.lifecycle)!=null&&s.onResize)try{i.lifecycle.onResize(e,t,i.context)}catch(u){console.error(`Error in layer "${i.name}" onResize:`,u),(r=i.lifecycle)!=null&&r.onError&&i.lifecycle.onError(u)}}#C(e,t){let s=(0,V.createReactor)(t,{immediate:!0,context:this.#n.state}),r=(0,V.addEffect)(s,()=>this.#E());return this.#a.set(`painter_${e}`,{reactor:s,unsubscribe:r}),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.#b,deltaTime:this.#l.deltaTime,elapsedTime:this.#l.elapsedTime,frameCount:this.#l.frameCount}}handlePointerEvent(e){this.#n.handleEvent(e),this.#S(e),this.#M(e)}#M(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 m=this.#w;this.#w=!0,m?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 r=this.#m,i=s.isOverCanvas;i&&!r?this.#i("pointer:enter",s.state):!i&&r&&this.#i("pointer:leave",s.state),this.#m=i;let u=this.#T,o=s.isHolding;o&&!u?this.#i("pointer:hold:start",s.state):!o&&u&&this.#i("pointer:hold:end",s.state),this.#T=o}#S(e){var u,o,m,g,p;let{type:t,x:s,y:r}=e,i=this.#n;switch(t){case"down":{let l=this.#R(s,r);if(i.setActiveArea(l),(u=l==null?void 0:l.onPointerDown)!=null&&u.handler){let f=this.#x(l);l.onPointerDown.handler({...i.state,ctx:f,emit:this.#i.bind(this)})}break}case"up":{let l=i.activeArea;if((o=l==null?void 0:l.onPointerUp)!=null&&o.handler){let f=this.#x(l);l.onPointerUp.handler({...i.state,ctx:f,emit:this.#i.bind(this)})}break}case"move":{let l=this.#R(s,r),f=i.hoveredArea,y=i.activeArea;if((m=y==null?void 0:y.onPointerMove)!=null&&m.handler&&i.isDragging){let S=this.#x(y);y.onPointerMove.handler({...i.state,ctx:S,emit:this.#i.bind(this)})}if((l==null?void 0:l.id)!==(f==null?void 0:f.id)){if((g=f==null?void 0:f.onPointerLeave)!=null&&g.handler){let S=this.#x(f);f.onPointerLeave.handler({...i.state,ctx:S,emit:this.#i.bind(this)})}if((p=l==null?void 0:l.onPointerEnter)!=null&&p.handler){let S=this.#x(l);l.onPointerEnter.handler({...i.state,ctx:S,emit:this.#i.bind(this)})}i.setHoveredArea(l)}break}case"scroll":case"zoom":break;case"dblclick":break}}#x(e){return e?e.context?this.#s.get(e.context):this.#s.get(_["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((r,i)=>(i.priority||0)-(r.priority||0));for(let r of s)if(this.#O(e,t,r.bounds))return r;return null}#O(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 r of s)r(t)}_testEmitPointerEvent(e){this.#n.handleEvent(e),this.#S(e)}};0&&(module.exports={CanvasEvents,HitRegistry,Painter,defineBrush,defineLayer,usePointerSurface});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/main.js", "../src/Painter.js", "../src/ContextTypes.js", "../src/HitRegistry.js", "../src/CanvasPointer.js", "../src/usePointerSurface.js"],
4
- "sourcesContent": ["export { Painter, defineLayer, defineBrush } from './Painter';\nexport { HitRegistry } from './HitRegistry';\nexport { CanvasPointer } from './CanvasPointer';\nexport { usePointerSurface } from './usePointerSurface';", "import { ServiceProvider } from '@jucie-engine/core';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createReactor, addEffect } from '@jucie-state/reactive';\nimport { createDefinition, definitionType } from '@jucie-engine/core';\nimport { HitRegistry } from './HitRegistry.js';\nimport { CanvasPointer } from './CanvasPointer.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;\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 #canvasPointer = null;\n #pointerSurface = usePointerSurface();\n #pointerUnsubscribe = null;\n #subscribers = new Map(); // Map<event, Set<callback>>\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 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\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 setCanvas(canvas) {\n this.#canvas = canvas;\n \n // Create contexts for each type\n Object.values(ContextTypes).forEach(type => {\n try {\n const ctx = canvas.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 // Set up canvas pointer if not already\n if (!this.#canvasPointer) {\n this.#canvasPointer = new CanvasPointer();\n }\n\n this.#canvasPointer.setCanvas(canvas);\n\n // Connect canvas pointer to surface\n if (this.#pointerUnsubscribe) {\n this.#pointerUnsubscribe();\n }\n\n this.#pointerUnsubscribe = this.#canvasPointer.subscribe((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 }\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 reactor 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 reactor if data exists\n const dataReactor = brushConfig.data \n ? this.#createDataReactor(`brush_${name}`, brushConfig.data)\n : () => undefined;\n \n const whenReactor = brushConfig.when \n ? createReactor(brushConfig.when, {\n immediate: true,\n context: this.useContext('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 reactor and subscription\n const reactorData = this.#reactors.get(`painter_brush_${brush.name}`);\n if (reactorData) {\n reactorData.unsubscribe();\n reactorData.reactor.destroy();\n this.#reactors.delete(`painter_brush_${brush.name}`);\n }\n });\n\n // Clean up layer reactor and subscription\n const layerReactorData = this.#reactors.get(`painter_layer_${name}`);\n if (layerReactorData) {\n layerReactorData.unsubscribe();\n layerReactorData.reactor.destroy();\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}`)?.reactor;\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 state = this.useContext('state');\n\n const reactor = createReactor(data, {\n immediate: true,\n context: state\n });\n\n const unsubscribe = addEffect(reactor, () => this.#scheduleRender());\n\n this.#reactors.set(`painter_${id}`, {\n reactor,\n unsubscribe\n });\n\n return reactor;\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.#canvasPointer) {\n this.#canvasPointer.destroy();\n this.#canvasPointer = 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 #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 // Emit custom events for scroll/zoom\n this.#emit(`pointer:${type}`, pointer.state);\n break;\n\n case 'dblclick':\n // Emit double-click event\n this.#emit('pointer:dblclick', pointer.state);\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}", "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-engine/core';\n\nexport class CanvasPointer extends ServiceProvider {\n #canvas = null;\n #cachedRect = null;\n #resizeObserver = null;\n #subscribers = new Set();\n #pendingMove = null;\n #rafId = null;\n\n static manifest = {\n name: 'CanvasPointer',\n namespace: 'canvasPointer',\n version: '1.0.0'\n };\n\n actions() {\n return {\n setCanvas: (canvas) => this.setCanvas(canvas),\n subscribe: (listener) => this.subscribe(listener),\n getOffscreenCanvas: () => this.getOffscreenCanvas(),\n };\n }\n\n getOffscreenCanvas() {\n if (!this.#canvas) return null;\n return this.#canvas.transferControlToOffscreen();\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 #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(() => {\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 #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.#cachedRect = null;\n this.#subscribers.clear();\n }\n}\n", "import { defineSurface } from '@jucie-state/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 = setup.action((ctx, 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 = setup.action(() => {\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 CanvasPointer\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(ctx, 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(ctx, 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(ctx, 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(ctx, newX, newY, newClientX, newClientY);\n clickCount.value = 2;\n break;\n \n case 'scroll':\n updatePosition(ctx, 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(ctx, 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"],
5
- "mappings": "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",
6
- "names": ["main_exports", "__export", "CanvasPointer", "HitRegistry", "Painter", "defineBrush", "defineLayer", "usePointerSurface", "__toCommonJS", "import_core", "ContextTypes", "import_reactive", "import_core", "HitRegistry", "#areas", "id", "area", "import_core", "CanvasPointer", "#canvas", "#cachedRect", "#resizeObserver", "#subscribers", "#pendingMove", "#rafId", "canvas", "listener", "#removeListeners", "#updateCachedRect", "#initializeListeners", "subscriber", "#handleScroll", "#handleMove", "#handleDown", "#handleUp", "#handleDblClick", "event", "normalized", "#normalizeEvent", "#emit", "type", "isOverCanvas", "x", "y", "isWithinBounds", "import_reactive", "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", "ctx", "newX", "newY", "newClientX", "newClientY", "updateVelocity", "now", "lastMove", "dt", "newVx", "newVy", "maxVel", "clampedVx", "clampedVy", "smoothing", "handleEvent", "normalizedEvent", "type", "eventButton", "eventButtons", "eventIsOverCanvas", "eventIsWithinBounds", "setHoveredArea", "area", "setActiveArea", "reset", "updateConfig", "updates", "defineBrush", "defineLayer", "Painter", "#layers", "#canvas", "#contexts", "#reactors", "#assets", "#isRunning", "#frameId", "#isRendering", "#renderScheduled", "#runtimeConfig", "#timing", "#metrics", "#hitRegistry", "HitRegistry", "#canvasPointer", "#pointerSurface", "usePointerSurface", "#pointerUnsubscribe", "#subscribers", "layerDef", "layers", "layer", "fn", "canvas", "assets", "name", "fps", "scale", "step", "options", "width", "height", "event", "callback", "path", "normalizedEvent", "ContextTypes", "type", "ctx", "CanvasPointer", "#handlePointerInteraction", "result", "#scheduleRender", "_a", "config", "dataReactor", "#createDataReactor", "brushes", "child", "brushConfig", "whenReactor", "brush", "error", "reactorData", "layerReactorData", "#render", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k", "_l", "_m", "_n", "_o", "_p", "_q", "renderStart", "layerStart", "layerReactor", "key", "value", "brushStart", "brushCtx", "requiredAssets", "brushTime", "#renderBrushBounds", "layerTime", "#renderLayerBounds", "#renderDebugOverlay", "y", "lineHeight", "text", "time", "id", "data", "state", "reactor", "unsubscribe", "x", "pointer", "hitArea", "#hitTest", "#getContextForArea", "#emit", "activeArea", "prevHovered", "area", "callbacks", "sorted", "a", "b", "#isPointInBounds", "bounds"]
3
+ "sources": ["../src/main.js", "../src/Painter.js", "../src/ContextTypes.js", "../src/HitRegistry.js", "../src/CanvasEvents.js", "../src/usePointerSurface.js"],
4
+ "sourcesContent": ["export { Painter, defineLayer, defineBrush } from './Painter';\nexport { HitRegistry } from './HitRegistry';\nexport { CanvasEvents } from './CanvasEvents';\nexport { usePointerSurface } from './usePointerSurface';", "import { ServiceProvider } from '@jucie-engine/core';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createReactor, addEffect } from '@jucie-state/reactive';\nimport { createDefinition, definitionType } from '@jucie-engine/core';\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 reactor 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 reactor if data exists\n const dataReactor = brushConfig.data \n ? this.#createDataReactor(`brush_${name}`, brushConfig.data)\n : () => undefined;\n \n const whenReactor = brushConfig.when \n ? createReactor(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 reactor and subscription\n const reactorData = this.#reactors.get(`painter_brush_${brush.name}`);\n if (reactorData) {\n reactorData.unsubscribe();\n reactorData.reactor.destroy();\n this.#reactors.delete(`painter_brush_${brush.name}`);\n }\n });\n\n // Clean up layer reactor and subscription\n const layerReactorData = this.#reactors.get(`painter_layer_${name}`);\n if (layerReactorData) {\n layerReactorData.unsubscribe();\n layerReactorData.reactor.destroy();\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}`)?.reactor;\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 reactor = createReactor(data, {\n immediate: true,\n context: this.#pointerSurface.state\n });\n\n const unsubscribe = addEffect(reactor, () => this.#scheduleRender());\n\n this.#reactors.set(`painter_${id}`, {\n reactor,\n unsubscribe\n });\n\n return reactor;\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}", "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-engine/core';\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(() => {\n this.#updateCachedRect();\n \n // Emit resize event if control was transferred\n // Pass actual canvas pixel dimensions (not CSS layout dimensions)\n if (this.#hasTransferredControl) {\n this.#emitResize({\n width: this.#canvas.width,\n height: this.#canvas.height\n });\n }\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-state/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 = setup.action((ctx, 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 = setup.action(() => {\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(ctx, 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(ctx, 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(ctx, 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(ctx, newX, newY, newClientX, newClientY);\n clickCount.value = 2;\n break;\n \n case 'scroll':\n updatePosition(ctx, 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(ctx, 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"],
5
+ "mappings": "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",
6
+ "names": ["main_exports", "__export", "CanvasEvents", "HitRegistry", "Painter", "defineBrush", "defineLayer", "usePointerSurface", "__toCommonJS", "import_core", "ContextTypes", "import_reactive", "import_core", "HitRegistry", "#areas", "id", "area", "import_core", "CanvasEvents", "#canvas", "#offscreenCanvas", "#cachedRect", "#resizeObserver", "#subscribers", "#resizeSubscribers", "#pendingMove", "#rafId", "#hasTransferredControl", "canvas", "listener", "#removeListeners", "#updateCachedRect", "#initializeListeners", "subscriber", "#emitResize", "#handleScroll", "#handleMove", "#handleDown", "#handleUp", "#handleDblClick", "event", "normalized", "#normalizeEvent", "#emit", "resizeData", "type", "isOverCanvas", "x", "y", "isWithinBounds", "import_reactive", "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", "ctx", "newX", "newY", "newClientX", "newClientY", "updateVelocity", "now", "lastMove", "dt", "newVx", "newVy", "maxVel", "clampedVx", "clampedVy", "smoothing", "handleEvent", "normalizedEvent", "type", "eventButton", "eventButtons", "eventIsOverCanvas", "eventIsWithinBounds", "setHoveredArea", "area", "setActiveArea", "reset", "updateConfig", "updates", "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", "_a", "config", "dataReactor", "#createDataReactor", "brushes", "child", "brushConfig", "whenReactor", "brush", "error", "reactorData", "layerReactorData", "#render", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k", "_l", "_m", "_n", "_o", "_p", "_q", "renderStart", "layerStart", "layerReactor", "key", "value", "brushStart", "brushCtx", "requiredAssets", "brushTime", "#renderBrushBounds", "layerTime", "#renderLayerBounds", "#renderDebugOverlay", "y", "lineHeight", "text", "time", "id", "data", "reactor", "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/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{ServiceProvider as be}from"@jucie-engine/core";var U={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};import{createReactor as se,addEffect as ge}from"@jucie-state/reactive";import{createDefinition as ne,definitionType as ie}from"@jucie-engine/core";var X=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 me}from"@jucie-engine/core";var _=class extends me{#e=null;#s=null;#i=null;#a=new Set;#f=null;#l=null;static manifest={name:"CanvasPointer",namespace:"canvasPointer",version:"1.0.0"};actions(){return{setCanvas:e=>this.setCanvas(e),subscribe:e=>this.subscribe(e),getOffscreenCanvas:()=>this.getOffscreenCanvas()}}getOffscreenCanvas(){return this.#e?this.#e.transferControlToOffscreen():null}setCanvas(e){this.#e&&this.#m(),this.#e=e,this.#u(),this.#b()}subscribe(e){return this.#a.add(e),()=>this.#a.delete(e)}#u(){this.#e&&(this.#s=this.#e.getBoundingClientRect())}#b(){this.#e&&(this.#u(),this.#i=new ResizeObserver(()=>{this.#u()}),this.#i.observe(this.#e),document.addEventListener("wheel",this.#t,{passive:!1}),document.addEventListener("pointermove",this.#o),document.addEventListener("pointerdown",this.#d),document.addEventListener("pointerup",this.#h),document.addEventListener("pointercancel",this.#h),document.addEventListener("dblclick",this.#c))}#m(){this.#i&&(this.#i.disconnect(),this.#i=null),document.removeEventListener("wheel",this.#t),document.removeEventListener("pointermove",this.#o),document.removeEventListener("pointerdown",this.#d),document.removeEventListener("pointerup",this.#h),document.removeEventListener("pointercancel",this.#h),document.removeEventListener("dblclick",this.#c)}#t=e=>{if(e.target===this.#e)if(e.preventDefault(),e.stopPropagation(),e.ctrlKey){let t=this.#r(e,"zoom");this.#n(t)}else{let t=this.#r(e,"scroll");this.#n(t)}};#o=e=>{let t=this.#r(e,"move");this.#f=t,!this.#l&&(this.#l=requestAnimationFrame(()=>{this.#f&&(this.#n(this.#f),this.#f=null),this.#l=null}))};#d=e=>{if(e.target===this.#e){let t=this.#r(e,"down");this.#n(t)}};#h=e=>{let t=this.#r(e,"up");this.#n(t)};#c=e=>{let t=this.#r(e,"dblclick");this.#n(t)};#n(e){for(let t of this.#a)t(e)}#r(e,t){let s=e.target===this.#e,a,i;s?(a=e.offsetX,i=e.offsetY):this.#s?(a=e.clientX-this.#s.left,i=e.clientY-this.#s.top):(a=e.clientX,i=e.clientY);let d=s||this.#s&&a>=0&&a<=this.#s.width&&i>=0&&i<=this.#s.height,o={x:a,y:i,type:t,isOverCanvas:s,isWithinBounds:d,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.#l&&(cancelAnimationFrame(this.#l),this.#l=null),this.#m(),this.#e=null,this.#s=null,this.#a.clear()}};import{defineSurface as ye}from"@jucie-state/reactive";var j=ye(n=>{let e=n.value(0),t=n.value(0),s=n.value(0),a=n.value(0),i=n.value(0),d=n.value(0),o=n.value(!1),y=n.value(!1),g=n.value(!1),p=n.value(null),l=n.value(0),f=n.value(null),m=n.value(null),C=n.value(null),Y=n.value(null),B=n.value(null),$=n.value(null),O=n.value(null),u=n.value(!1),P=n.value(0),T=n.value(0),r=n.value(0),E=n.value(0),S=n.value(0),x=n.value(0),R=n.value(0),V=n.value(null),z=n.value(null),D=n.value({dragThreshold:5,doubleClickThreshold:300,holdThreshold:500,velocitySmoothing:.3,maxVelocity:1e4}),q=n.computed(()=>({x:e.value,y:t.value})),Z=n.computed(()=>({x:i.value,y:d.value})),G=n.computed(()=>({x:s.value,y:a.value})),N=n.computed(()=>{let h=typeof e.value=="number"?e.value:0,c=typeof s.value=="number"?s.value:0,v=typeof t.value=="number"?t.value:0,b=typeof a.value=="number"?a.value:0;return{x:h-c,y:v-b}}),J=n.computed(()=>({x:r.value,y:E.value})),Q=n.computed(()=>{let h=r.value,c=E.value;return Math.sqrt(h*h+c*c)}),W=n.computed(()=>{let h=$.value,c=O.value;if(h===null||c===null||typeof h!="number"||typeof c!="number")return 0;let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0,L=v-h,w=b-c;return Math.sqrt(L*L+w*w)}),ee=n.computed(()=>{let h=$.value,c=O.value;if(h===null||c===null||typeof h!="number"||typeof c!="number")return{x:0,y:0};let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0;return{x:v-h,y:b-c}}),K=n.computed(()=>!g.value||!m.value?0:Date.now()-m.value),te=n.computed(()=>K.value>D.value.holdThreshold&&!u.value),re=n.computed(()=>{let h=B.value;return h?Date.now()-h:0}),ae=n.computed(()=>({position:q.value,clientPosition:Z.value,previousPosition:G.value,delta:N.value,velocity:J.value,speed:Q.value,isPressed:g.value,button:p.value,buttons:l.value,isDragging:u.value,dragDistance:W.value,dragDelta:ee.value,isHolding:te.value,holdDuration:K.value,isOverCanvas:o.value,isWithinBounds:y.value,hoveredArea:V.value,activeArea:z.value,clickCount:P.value,lastEventType:f.value})),A=n.action((h,c,v,b,L)=>{s.value=e.value,a.value=t.value,e.value=c,t.value=v,i.value=b,d.value=L,Y.value=Date.now()}),oe=n.action(()=>{let h=Date.now(),c=Y.value;if(c){let v=(h-c)/1e3;if(v>0&&v<.1){let b=(e.value-s.value)/v,L=(t.value-a.value)/v,w=D.value.maxVelocity,k=Math.max(-w,Math.min(w,b)),I=Math.max(-w,Math.min(w,L)),M=D.value.velocitySmoothing;r.value=r.value*(1-M)+k*M,E.value=E.value*(1-M)+I*M}}}),le=n.action((h,c)=>{let{x:v,y:b,type:L,clientX:w,clientY:k,button:I,buttons:M,isOverCanvas:fe,isWithinBounds:ve}=c,F=Date.now();switch(B.value=F,f.value=L,o.value=fe,y.value=ve,L){case"down":A(h,v,b,w,k),g.value=!0,m.value=F,p.value=I,l.value=M,$.value=v,O.value=b,u.value=!1,F-T.value<D.value.doubleClickThreshold?P.value=P.value+1:P.value=1;break;case"up":A(h,v,b,w,k),g.value=!1,C.value=F,T.value=F,u.value=!1,r.value=0,E.value=0,l.value=M;break;case"move":A(h,v,b,w,k),oe(),l.value=M,g.value&&!u.value&&W.value>D.value.dragThreshold&&(u.value=!0);break;case"dblclick":A(h,v,b,w,k),P.value=2;break;case"scroll":A(h,v,b,w,k),c.deltaX!==void 0&&(S.value=c.deltaX),c.deltaY!==void 0&&(x.value=c.deltaY);break;case"zoom":A(h,v,b,w,k),c.deltaY!==void 0&&(R.value=c.deltaY);break}}),ce=n.action((h,c)=>{V.value=c}),ue=n.action((h,c)=>{z.value=c}),he=n.action(()=>{g.value=!1,u.value=!1,z.value=null,V.value=null,r.value=0,E.value=0,P.value=0,S.value=0,x.value=0,R.value=0}),de=n.action((h,c)=>{D.value={...D.value,...c}});return{state:ae,position:q,clientPosition:Z,previousPosition:G,delta:N,velocity:J,speed:Q,isPressed:g,button:p,buttons:l,isDragging:u,dragDistance:W,dragDelta:ee,isHolding:te,holdDuration:K,isOverCanvas:o,isWithinBounds:y,hoveredArea:V,activeArea:z,clickCount:P,lastEventType:f,timeSinceLastEvent:re,handleEvent:le,setHoveredArea:ce,setActiveArea:ue,reset:he,updateConfig:de}});var pe=ne("BRUSH",[Object]),xe=ne("LAYER",[Object]),H=class extends be{#e=new Map;#s=null;#i=new Map;#a=new Map;#f=new Map;#l=!1;#u=null;#b=!1;#m=!1;#t={targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}};#o={lastFrameTime:0,deltaTime:0,elapsedTime:0,frameCount:0};#d={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#h=new X;#c=null;#n=j();#r=null;#y=new Map;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),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),subscribeToPointer:e=>this.#n.$subscribe(e),bindPointer:e=>this.#n.$bind(e),_testEmitPointerEvent:e=>this._testEmitPointerEvent(e)}}setCanvas(e){this.#s=e,Object.values(U).forEach(t=>{try{let s=e.getContext(t);s&&this.#i.set(t,s)}catch{console.warn(`Context type ${t} not supported`)}}),this.#c||(this.#c=new _),this.#c.setCanvas(e),this.#r&&this.#r(),this.#r=this.#c.subscribe(t=>{this.#n.handleEvent(t),this.#w(t)})}updateCanvas(e){let t=e(this.#s);t&&(this.#s=t)}setAssets(e){this.#f=e}start(){this.#l||(this.#l=!0,this.#p())}stop(){this.#l&&(this.#l=!1,this.#u&&(cancelAnimationFrame(this.#u),this.#u=null))}addLayer(e){var d;if(ie(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,s=e(this.useContext,this.#h);if(s.data){let o=this.#x(`layer_${t}`,s.data);o&&this.#a.set(`layer_${t}`,o)}let a=s.children.map(o=>{var y;if(ie(o)==="BRUSH"){let g=o._name,p=o(this.useContext,this.#h),l=p.data?this.#x(`brush_${g}`,p.data):()=>{},f=p.when?se(p.when,{immediate:!0,context:this.useContext("state")}):null,m={name:g,...p,dataReactor:l,whenReactor:f};if((y=m.lifecycle)!=null&&y.onMount)try{m.lifecycle.onMount(this.#i.get(m.context||s.context))}catch(C){console.error(`Error in brush "${m.name}" onMount:`,C)}return m}return this.addLayer(o)}),i={...s,name:t,brushes:a,context:this.#i.get(s.context)};if(this.#e.set(t,i),(d=i.lifecycle)!=null&&d.onMount)try{i.lifecycle.onMount(i.context)}catch(o){console.error(`Error in layer "${t}" onMount:`,o)}return i}removeLayer(e){var a;let t=this.#e.get(e);if(!t)return;if((a=t.lifecycle)!=null&&a.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(i){console.error(`Error in layer "${e}" onUnmount:`,i)}t.brushes.forEach(i=>{var o;if((o=i.lifecycle)!=null&&o.onUnmount)try{i.lifecycle.onUnmount(this.#i.get(i.context||t.context))}catch(y){console.error(`Error in brush "${i.name}" onUnmount:`,y)}let d=this.#a.get(`painter_brush_${i.name}`);d&&(d.unsubscribe(),d.reactor.destroy(),this.#a.delete(`painter_brush_${i.name}`))});let s=this.#a.get(`painter_layer_${e}`);s&&(s.unsubscribe(),s.reactor.destroy(),this.#a.delete(`painter_layer_${e}`)),this.#e.delete(e)}#p(){this.#m||this.#b||(this.#m=!0,this.#u=requestAnimationFrame(()=>{this.#m=!1,this.#u=null,this.#E()}))}async#E(){var e,t,s,a,i,d,o,y,g,p,l,f,m,C,Y,B,$;if(this.#s){this.#b=!0;try{this.#h.clear();let O=(e=this.#t.debug)!=null&&e.enabled?performance.now():0;this.#i.forEach(u=>{u.clearRect(0,0,this.#s.width,this.#s.height)});for(let u of this.#e.values()){let P=(t=this.#t.debug)!=null&&t.enabled?performance.now():0;if(u.whenReactor){let r=(s=this.#a.get(`painter_layer_${u.name}`))==null?void 0:s.reactor;if(!u.when(r()))continue}let T=u.context;if(T){if((a=u.lifecycle)!=null&&a.beforeRender)try{u.lifecycle.beforeRender(T,this.#o)}catch(r){console.error(`Error in layer "${u.name}" beforeRender:`,r),(i=u.lifecycle)!=null&&i.onError&&u.lifecycle.onError(r)}T.save(),u.settings&&Object.entries(u.settings).forEach(([r,E])=>{typeof T[r]=="function"?T[r](...Array.isArray(E)?E:[E]):T[r]=E});for(let r of u.brushes){let E=(d=this.#t.debug)!=null&&d.enabled?performance.now():0;if(r.whenReactor&&!r.whenReactor())continue;let S=r.context?this.#i.get(r.context):T;if(S){if((o=r.lifecycle)!=null&&o.beforeRender)try{r.lifecycle.beforeRender(S,this.#o)}catch(x){console.error(`Error in brush "${r.name}" beforeRender:`,x),(y=r.lifecycle)!=null&&y.onError&&r.lifecycle.onError(x);continue}S.save(),r.settings&&Object.entries(r.settings).forEach(([x,R])=>{typeof S[x]=="function"?S[x](...Array.isArray(R)?R:[R]):S[x]=R});try{let x={};if(r.assets)for(let R of r.assets)x[R]=this.#f.get(R);if(r.render(S,r.dataReactor(),x,this.#o),(g=r.lifecycle)!=null&&g.afterRender&&r.lifecycle.afterRender(S,this.#o),(p=this.#t.debug)!=null&&p.enabled){let R=performance.now()-E;this.#d.brushTimes.set(r.name,R),(l=this.#t.debug)!=null&&l.showBounds&&this.#S(S,r)}}catch(x){console.error(`Error in brush "${r.name}":`,x),(f=r.lifecycle)!=null&&f.onError&&r.lifecycle.onError(x)}finally{S.restore()}}}if(T.restore(),(m=u.lifecycle)!=null&&m.afterRender)try{u.lifecycle.afterRender(T,this.#o)}catch(r){console.error(`Error in layer "${u.name}" afterRender:`,r),(C=u.lifecycle)!=null&&C.onError&&u.lifecycle.onError(r)}if((Y=this.#t.debug)!=null&&Y.enabled){let r=performance.now()-P;this.#d.layerTimes.set(u.name,r),(B=this.#t.debug)!=null&&B.showBounds&&this.#C(T,u)}}}($=this.#t.debug)!=null&&$.enabled&&this.#R()}finally{this.#b=!1}}}#S(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()}#C(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()}#R(){var a,i;let e=this.#i.get(U["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((a=this.#t.debug)!=null&&a.showFPS){let d=`FPS: ${Math.round(this.#d.fps)} (${this.#o.deltaTime.toFixed(2)}ms)`;e.strokeText(d,10,t),e.fillText(d,10,t),t+=s}if((i=this.#t.debug)!=null&&i.showLayerTiming){e.fillText("Layer Times:",10,t),t+=s;for(let[d,o]of this.#d.layerTimes){let y=` ${d}: ${o.toFixed(2)}ms`;e.strokeText(y,10,t),e.fillText(y,10,t),t+=s}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){var s,a;for(let i of this.#e.values())if((s=i.lifecycle)!=null&&s.onResize)try{i.lifecycle.onResize(e,t,i.context)}catch(d){console.error(`Error in layer "${i.name}" onResize:`,d),(a=i.lifecycle)!=null&&a.onError&&i.lifecycle.onError(d)}}#x(e,t){let s=this.useContext("state"),a=se(t,{immediate:!0,context:s}),i=ge(a,()=>this.#p());return this.#a.set(`painter_${e}`,{reactor:a,unsubscribe:i}),a}destroy(){this.stop(),this.#r&&(this.#r(),this.#r=null),this.#c&&(this.#c.destroy(),this.#c=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.#d,deltaTime:this.#o.deltaTime,elapsedTime:this.#o.elapsedTime,frameCount:this.#o.frameCount}}#w(e){var d,o,y,g,p;let{type:t,x:s,y:a}=e,i=this.#n;switch(t){case"down":{let l=this.#T(s,a);if(i.setActiveArea(l),(d=l==null?void 0:l.onPointerDown)!=null&&d.handler){let f=this.#g(l);l.onPointerDown.handler({...i.state,ctx:f,emit:this.#v.bind(this)})}break}case"up":{let l=i.activeArea;if((o=l==null?void 0:l.onPointerUp)!=null&&o.handler){let f=this.#g(l);l.onPointerUp.handler({...i.state,ctx:f,emit:this.#v.bind(this)})}break}case"move":{let l=this.#T(s,a),f=i.hoveredArea,m=i.activeArea;if((y=m==null?void 0:m.onPointerMove)!=null&&y.handler&&i.isDragging){let C=this.#g(m);m.onPointerMove.handler({...i.state,ctx:C,emit:this.#v.bind(this)})}if((l==null?void 0:l.id)!==(f==null?void 0:f.id)){if((g=f==null?void 0:f.onPointerLeave)!=null&&g.handler){let C=this.#g(f);f.onPointerLeave.handler({...i.state,ctx:C,emit:this.#v.bind(this)})}if((p=l==null?void 0:l.onPointerEnter)!=null&&p.handler){let C=this.#g(l);l.onPointerEnter.handler({...i.state,ctx:C,emit:this.#v.bind(this)})}i.setHoveredArea(l)}break}case"scroll":case"zoom":this.#v(`pointer:${t}`,i.state);break;case"dblclick":this.#v("pointer:dblclick",i.state);break}}#g(e){return e?e.context?this.#i.get(e.context):this.#i.get(U["2D"]):null}subscribe(e,t){return this.#y.has(e)||this.#y.set(e,new Set),this.#y.get(e).add(t),()=>{let s=this.#y.get(e);s&&(s.delete(t),s.size===0&&this.#y.delete(e))}}#T(e,t){let s=this.#h.areas.sort((a,i)=>(i.priority||0)-(a.priority||0));for(let a of s)if(this.#P(e,t,a.bounds))return a;return null}#P(e,t,s){return e>=s.x&&e<=s.x+s.width&&t>=s.y&&t<=s.y+s.height}#v(e,t){let s=this.#y.get(e);if(s)for(let a of s)a(t)}_testEmitPointerEvent(e){this.#n.handleEvent(e),this.#w(e)}};export{_ as CanvasPointer,X as HitRegistry,H as Painter,pe as defineBrush,xe as defineLayer,j as usePointerSurface};
1
+ import{ServiceProvider as be}from"@jucie-engine/core";var B={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};import{createReactor as se,addEffect as ge}from"@jucie-state/reactive";import{createDefinition as ne,definitionType as ie}from"@jucie-engine/core";var F=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 me}from"@jucie-engine/core";var X=class extends me{#e=null;#r=null;#s=null;#a=null;#g=new Set;#v=new Set;#h=null;#u=null;#y=!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.#b(),this.#e=e,this.#t(),this.#l()}subscribe(e){return this.#g.add(e),()=>this.#g.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.#y)throw new Error("Control has already been transferred to offscreen");return this.#r=this.#e.transferControlToOffscreen(),this.#y=!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(()=>{this.#t(),this.#y&&this.#w({width:this.#e.width,height:this.#e.height})}),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))}#b(){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.#g)t(e)}#w(e){for(let t of this.#v)t(e)}#m(e,t){let s=e.target===this.#e,r,i;s?(r=e.offsetX,i=e.offsetY):this.#s?(r=e.clientX-this.#s.left,i=e.clientY-this.#s.top):(r=e.clientX,i=e.clientY);let u=s||this.#s&&r>=0&&r<=this.#s.width&&i>=0&&i<=this.#s.height,o={x:r,y:i,type:t,isOverCanvas:s,isWithinBounds:u,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.#b(),this.#e=null,this.#r=null,this.#s=null,this.#g.clear(),this.#v.clear(),this.#y=!1}};import{defineSurface as ye}from"@jucie-state/reactive";var j=ye(n=>{let e=n.value(0),t=n.value(0),s=n.value(0),r=n.value(0),i=n.value(0),u=n.value(0),o=n.value(!1),m=n.value(!1),g=n.value(!1),p=n.value(null),l=n.value(0),f=n.value(null),y=n.value(null),S=n.value(null),A=n.value(null),Y=n.value(null),O=n.value(null),_=n.value(null),h=n.value(!1),P=n.value(0),T=n.value(0),a=n.value(0),E=n.value(0),C=n.value(0),w=n.value(0),R=n.value(0),V=n.value(null),U=n.value(null),M=n.value({dragThreshold:5,doubleClickThreshold:300,holdThreshold:500,velocitySmoothing:.3,maxVelocity:1e4}),q=n.computed(()=>({x:e.value,y:t.value})),Z=n.computed(()=>({x:i.value,y:u.value})),G=n.computed(()=>({x:s.value,y:r.value})),N=n.computed(()=>{let d=typeof e.value=="number"?e.value:0,c=typeof s.value=="number"?s.value:0,v=typeof t.value=="number"?t.value:0,b=typeof r.value=="number"?r.value:0;return{x:d-c,y:v-b}}),J=n.computed(()=>({x:a.value,y:E.value})),Q=n.computed(()=>{let d=a.value,c=E.value;return Math.sqrt(d*d+c*c)}),H=n.computed(()=>{let d=O.value,c=_.value;if(d===null||c===null||typeof d!="number"||typeof c!="number")return 0;let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0,k=v-d,x=b-c;return Math.sqrt(k*k+x*x)}),ee=n.computed(()=>{let d=O.value,c=_.value;if(d===null||c===null||typeof d!="number"||typeof c!="number")return{x:0,y:0};let v=typeof e.value=="number"?e.value:0,b=typeof t.value=="number"?t.value:0;return{x:v-d,y:b-c}}),W=n.computed(()=>!g.value||!y.value?0:Date.now()-y.value),te=n.computed(()=>W.value>M.value.holdThreshold&&!h.value),re=n.computed(()=>{let d=Y.value;return d?Date.now()-d:0}),ae=n.computed(()=>({position:q.value,clientPosition:Z.value,previousPosition:G.value,delta:N.value,velocity:J.value,speed:Q.value,isPressed:g.value,button:p.value,buttons:l.value,isDragging:h.value,dragDistance:H.value,dragDelta:ee.value,isHolding:te.value,holdDuration:W.value,isOverCanvas:o.value,isWithinBounds:m.value,hoveredArea:V.value,activeArea:U.value,clickCount:P.value,lastEventType:f.value})),$=n.action((d,c,v,b,k)=>{s.value=e.value,r.value=t.value,e.value=c,t.value=v,i.value=b,u.value=k,A.value=Date.now()}),oe=n.action(()=>{let d=Date.now(),c=A.value;if(c){let v=(d-c)/1e3;if(v>0&&v<.1){let b=(e.value-s.value)/v,k=(t.value-r.value)/v,x=M.value.maxVelocity,L=Math.max(-x,Math.min(x,b)),K=Math.max(-x,Math.min(x,k)),D=M.value.velocitySmoothing;a.value=a.value*(1-D)+L*D,E.value=E.value*(1-D)+K*D}}}),le=n.action((d,c)=>{let{x:v,y:b,type:k,clientX:x,clientY:L,button:K,buttons:D,isOverCanvas:fe,isWithinBounds:ve}=c,z=Date.now();switch(Y.value=z,f.value=k,o.value=fe,m.value=ve,k){case"down":$(d,v,b,x,L),g.value=!0,y.value=z,p.value=K,l.value=D,O.value=v,_.value=b,h.value=!1,z-T.value<M.value.doubleClickThreshold?P.value=P.value+1:P.value=1;break;case"up":$(d,v,b,x,L),g.value=!1,S.value=z,T.value=z,h.value=!1,a.value=0,E.value=0,l.value=D;break;case"move":$(d,v,b,x,L),oe(),l.value=D,g.value&&!h.value&&H.value>M.value.dragThreshold&&(h.value=!0);break;case"dblclick":$(d,v,b,x,L),P.value=2;break;case"scroll":$(d,v,b,x,L),c.deltaX!==void 0&&(C.value=c.deltaX),c.deltaY!==void 0&&(w.value=c.deltaY);break;case"zoom":$(d,v,b,x,L),c.deltaY!==void 0&&(R.value=c.deltaY);break}}),ce=n.action((d,c)=>{V.value=c}),he=n.action((d,c)=>{U.value=c}),ue=n.action(()=>{g.value=!1,h.value=!1,U.value=null,V.value=null,a.value=0,E.value=0,P.value=0,C.value=0,w.value=0,R.value=0}),de=n.action((d,c)=>{M.value={...M.value,...c}});return{state:ae,position:q,clientPosition:Z,previousPosition:G,delta:N,velocity:J,speed:Q,isPressed:g,button:p,buttons:l,isDragging:h,dragDistance:H,dragDelta:ee,isHolding:te,holdDuration:W,isOverCanvas:o,isWithinBounds:m,hoveredArea:V,activeArea:U,clickCount:P,lastEventType:f,timeSinceLastEvent:re,handleEvent:le,setHoveredArea:ce,setActiveArea:he,reset:ue,updateConfig:de}});var pe=ne("BRUSH",[Object]),we=ne("LAYER",[Object]),I=class extends be{#e=new Map;#r=null;#s=new Map;#a=new Map;#g=new Map;#v=!1;#h=null;#u=!1;#y=!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};#b={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#p=new F;#n=j();#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(B).forEach(r=>{try{let i=s.getContext(r);i&&this.#s.set(r,i)}catch{console.warn(`Context type ${r} not supported`)}}),this.#d||(this.#d=new X),this.#d.setCanvas(t),this.#f&&this.#f.disconnect(),this.#f=new ResizeObserver(r=>{let i=r[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(r=>{this.handlePointerEvent(r)})}setOffscreenCanvas(e){this.#r=e,Object.values(B).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.#g=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){var u;if(ie(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,s=e(this.useContext,this.#p);if(s.data){let o=this.#C(`layer_${t}`,s.data);o&&this.#a.set(`layer_${t}`,o)}let r=s.children.map(o=>{var m;if(ie(o)==="BRUSH"){let g=o._name,p=o(this.useContext,this.#p),l=p.data?this.#C(`brush_${g}`,p.data):()=>{},f=p.when?se(p.when,{immediate:!0,context:this.#n.state}):null,y={name:g,...p,dataReactor:l,whenReactor:f};if((m=y.lifecycle)!=null&&m.onMount)try{y.lifecycle.onMount(this.#s.get(y.context||s.context))}catch(S){console.error(`Error in brush "${y.name}" onMount:`,S)}return y}return this.addLayer(o)}),i={...s,name:t,brushes:r,context:this.#s.get(s.context)};if(this.#e.set(t,i),(u=i.lifecycle)!=null&&u.onMount)try{i.lifecycle.onMount(i.context)}catch(o){console.error(`Error in layer "${t}" onMount:`,o)}return i}removeLayer(e){var r;let t=this.#e.get(e);if(!t)return;if((r=t.lifecycle)!=null&&r.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(i){console.error(`Error in layer "${e}" onUnmount:`,i)}t.brushes.forEach(i=>{var o;if((o=i.lifecycle)!=null&&o.onUnmount)try{i.lifecycle.onUnmount(this.#s.get(i.context||t.context))}catch(m){console.error(`Error in brush "${i.name}" onUnmount:`,m)}let u=this.#a.get(`painter_brush_${i.name}`);u&&(u.unsubscribe(),u.reactor.destroy(),this.#a.delete(`painter_brush_${i.name}`))});let s=this.#a.get(`painter_layer_${e}`);s&&(s.unsubscribe(),s.reactor.destroy(),this.#a.delete(`painter_layer_${e}`)),this.#e.delete(e)}#E(){this.#y||this.#u||(this.#y=!0,this.#h=requestAnimationFrame(()=>{this.#y=!1,this.#h=null,this.#P()}))}async#P(){var e,t,s,r,i,u,o,m,g,p,l,f,y,S,A,Y,O;if(this.#r){this.#u=!0;try{this.#p.clear();let _=(e=this.#t.debug)!=null&&e.enabled?performance.now():0;this.#s.forEach(h=>{h.clearRect(0,0,this.#r.width,this.#r.height)});for(let h of this.#e.values()){let P=(t=this.#t.debug)!=null&&t.enabled?performance.now():0;if(h.whenReactor){let a=(s=this.#a.get(`painter_layer_${h.name}`))==null?void 0:s.reactor;if(!h.when(a()))continue}let T=h.context;if(T){if((r=h.lifecycle)!=null&&r.beforeRender)try{h.lifecycle.beforeRender(T,this.#l)}catch(a){console.error(`Error in layer "${h.name}" beforeRender:`,a),(i=h.lifecycle)!=null&&i.onError&&h.lifecycle.onError(a)}T.save(),h.settings&&Object.entries(h.settings).forEach(([a,E])=>{typeof T[a]=="function"?T[a](...Array.isArray(E)?E:[E]):T[a]=E});for(let a of h.brushes){let E=(u=this.#t.debug)!=null&&u.enabled?performance.now():0;if(a.whenReactor&&!a.whenReactor())continue;let C=a.context?this.#s.get(a.context):T;if(C){if((o=a.lifecycle)!=null&&o.beforeRender)try{a.lifecycle.beforeRender(C,this.#l)}catch(w){console.error(`Error in brush "${a.name}" beforeRender:`,w),(m=a.lifecycle)!=null&&m.onError&&a.lifecycle.onError(w);continue}C.save(),a.settings&&Object.entries(a.settings).forEach(([w,R])=>{typeof C[w]=="function"?C[w](...Array.isArray(R)?R:[R]):C[w]=R});try{let w={};if(a.assets)for(let R of a.assets)w[R]=this.#g.get(R);if(a.render(C,a.dataReactor(),w,this.#l),(g=a.lifecycle)!=null&&g.afterRender&&a.lifecycle.afterRender(C,this.#l),(p=this.#t.debug)!=null&&p.enabled){let R=performance.now()-E;this.#b.brushTimes.set(a.name,R),(l=this.#t.debug)!=null&&l.showBounds&&this.#k(C,a)}}catch(w){console.error(`Error in brush "${a.name}":`,w),(f=a.lifecycle)!=null&&f.onError&&a.lifecycle.onError(w)}finally{C.restore()}}}if(T.restore(),(y=h.lifecycle)!=null&&y.afterRender)try{h.lifecycle.afterRender(T,this.#l)}catch(a){console.error(`Error in layer "${h.name}" afterRender:`,a),(S=h.lifecycle)!=null&&S.onError&&h.lifecycle.onError(a)}if((A=this.#t.debug)!=null&&A.enabled){let a=performance.now()-P;this.#b.layerTimes.set(h.name,a),(Y=this.#t.debug)!=null&&Y.showBounds&&this.#L(T,h)}}}(O=this.#t.debug)!=null&&O.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(){var r,i;let e=this.#s.get(B["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((r=this.#t.debug)!=null&&r.showFPS){let u=`FPS: ${Math.round(this.#b.fps)} (${this.#l.deltaTime.toFixed(2)}ms)`;e.strokeText(u,10,t),e.fillText(u,10,t),t+=s}if((i=this.#t.debug)!=null&&i.showLayerTiming){e.fillText("Layer Times:",10,t),t+=s;for(let[u,o]of this.#b.layerTimes){let m=` ${u}: ${o.toFixed(2)}ms`;e.strokeText(m,10,t),e.fillText(m,10,t),t+=s}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){var s,r;for(let i of this.#e.values())if((s=i.lifecycle)!=null&&s.onResize)try{i.lifecycle.onResize(e,t,i.context)}catch(u){console.error(`Error in layer "${i.name}" onResize:`,u),(r=i.lifecycle)!=null&&r.onError&&i.lifecycle.onError(u)}}#C(e,t){let s=se(t,{immediate:!0,context:this.#n.state}),r=ge(s,()=>this.#E());return this.#a.set(`painter_${e}`,{reactor:s,unsubscribe:r}),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.#b,deltaTime:this.#l.deltaTime,elapsedTime:this.#l.elapsedTime,frameCount:this.#l.frameCount}}handlePointerEvent(e){this.#n.handleEvent(e),this.#S(e),this.#M(e)}#M(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 m=this.#w;this.#w=!0,m?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 r=this.#m,i=s.isOverCanvas;i&&!r?this.#i("pointer:enter",s.state):!i&&r&&this.#i("pointer:leave",s.state),this.#m=i;let u=this.#T,o=s.isHolding;o&&!u?this.#i("pointer:hold:start",s.state):!o&&u&&this.#i("pointer:hold:end",s.state),this.#T=o}#S(e){var u,o,m,g,p;let{type:t,x:s,y:r}=e,i=this.#n;switch(t){case"down":{let l=this.#R(s,r);if(i.setActiveArea(l),(u=l==null?void 0:l.onPointerDown)!=null&&u.handler){let f=this.#x(l);l.onPointerDown.handler({...i.state,ctx:f,emit:this.#i.bind(this)})}break}case"up":{let l=i.activeArea;if((o=l==null?void 0:l.onPointerUp)!=null&&o.handler){let f=this.#x(l);l.onPointerUp.handler({...i.state,ctx:f,emit:this.#i.bind(this)})}break}case"move":{let l=this.#R(s,r),f=i.hoveredArea,y=i.activeArea;if((m=y==null?void 0:y.onPointerMove)!=null&&m.handler&&i.isDragging){let S=this.#x(y);y.onPointerMove.handler({...i.state,ctx:S,emit:this.#i.bind(this)})}if((l==null?void 0:l.id)!==(f==null?void 0:f.id)){if((g=f==null?void 0:f.onPointerLeave)!=null&&g.handler){let S=this.#x(f);f.onPointerLeave.handler({...i.state,ctx:S,emit:this.#i.bind(this)})}if((p=l==null?void 0:l.onPointerEnter)!=null&&p.handler){let S=this.#x(l);l.onPointerEnter.handler({...i.state,ctx:S,emit:this.#i.bind(this)})}i.setHoveredArea(l)}break}case"scroll":case"zoom":break;case"dblclick":break}}#x(e){return e?e.context?this.#s.get(e.context):this.#s.get(B["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((r,i)=>(i.priority||0)-(r.priority||0));for(let r of s)if(this.#O(e,t,r.bounds))return r;return null}#O(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 r of s)r(t)}_testEmitPointerEvent(e){this.#n.handleEvent(e),this.#S(e)}};export{X as CanvasEvents,F as HitRegistry,I as Painter,pe as defineBrush,we as defineLayer,j as usePointerSurface};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/Painter.js", "../src/ContextTypes.js", "../src/HitRegistry.js", "../src/CanvasPointer.js", "../src/usePointerSurface.js"],
4
- "sourcesContent": ["import { ServiceProvider } from '@jucie-engine/core';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createReactor, addEffect } from '@jucie-state/reactive';\nimport { createDefinition, definitionType } from '@jucie-engine/core';\nimport { HitRegistry } from './HitRegistry.js';\nimport { CanvasPointer } from './CanvasPointer.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;\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 #canvasPointer = null;\n #pointerSurface = usePointerSurface();\n #pointerUnsubscribe = null;\n #subscribers = new Map(); // Map<event, Set<callback>>\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 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\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 setCanvas(canvas) {\n this.#canvas = canvas;\n \n // Create contexts for each type\n Object.values(ContextTypes).forEach(type => {\n try {\n const ctx = canvas.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 // Set up canvas pointer if not already\n if (!this.#canvasPointer) {\n this.#canvasPointer = new CanvasPointer();\n }\n\n this.#canvasPointer.setCanvas(canvas);\n\n // Connect canvas pointer to surface\n if (this.#pointerUnsubscribe) {\n this.#pointerUnsubscribe();\n }\n\n this.#pointerUnsubscribe = this.#canvasPointer.subscribe((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 }\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 reactor 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 reactor if data exists\n const dataReactor = brushConfig.data \n ? this.#createDataReactor(`brush_${name}`, brushConfig.data)\n : () => undefined;\n \n const whenReactor = brushConfig.when \n ? createReactor(brushConfig.when, {\n immediate: true,\n context: this.useContext('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 reactor and subscription\n const reactorData = this.#reactors.get(`painter_brush_${brush.name}`);\n if (reactorData) {\n reactorData.unsubscribe();\n reactorData.reactor.destroy();\n this.#reactors.delete(`painter_brush_${brush.name}`);\n }\n });\n\n // Clean up layer reactor and subscription\n const layerReactorData = this.#reactors.get(`painter_layer_${name}`);\n if (layerReactorData) {\n layerReactorData.unsubscribe();\n layerReactorData.reactor.destroy();\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}`)?.reactor;\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 state = this.useContext('state');\n\n const reactor = createReactor(data, {\n immediate: true,\n context: state\n });\n\n const unsubscribe = addEffect(reactor, () => this.#scheduleRender());\n\n this.#reactors.set(`painter_${id}`, {\n reactor,\n unsubscribe\n });\n\n return reactor;\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.#canvasPointer) {\n this.#canvasPointer.destroy();\n this.#canvasPointer = 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 #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 // Emit custom events for scroll/zoom\n this.#emit(`pointer:${type}`, pointer.state);\n break;\n\n case 'dblclick':\n // Emit double-click event\n this.#emit('pointer:dblclick', pointer.state);\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}", "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-engine/core';\n\nexport class CanvasPointer extends ServiceProvider {\n #canvas = null;\n #cachedRect = null;\n #resizeObserver = null;\n #subscribers = new Set();\n #pendingMove = null;\n #rafId = null;\n\n static manifest = {\n name: 'CanvasPointer',\n namespace: 'canvasPointer',\n version: '1.0.0'\n };\n\n actions() {\n return {\n setCanvas: (canvas) => this.setCanvas(canvas),\n subscribe: (listener) => this.subscribe(listener),\n getOffscreenCanvas: () => this.getOffscreenCanvas(),\n };\n }\n\n getOffscreenCanvas() {\n if (!this.#canvas) return null;\n return this.#canvas.transferControlToOffscreen();\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 #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(() => {\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 #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.#cachedRect = null;\n this.#subscribers.clear();\n }\n}\n", "import { defineSurface } from '@jucie-state/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 = setup.action((ctx, 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 = setup.action(() => {\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 CanvasPointer\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(ctx, 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(ctx, 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(ctx, 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(ctx, newX, newY, newClientX, newClientY);\n clickCount.value = 2;\n break;\n \n case 'scroll':\n updatePosition(ctx, 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(ctx, 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"],
5
- "mappings": "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",
6
- "names": ["ServiceProvider", "ContextTypes", "createReactor", "addEffect", "createDefinition", "definitionType", "HitRegistry", "#areas", "id", "area", "ServiceProvider", "CanvasPointer", "#canvas", "#cachedRect", "#resizeObserver", "#subscribers", "#pendingMove", "#rafId", "canvas", "listener", "#removeListeners", "#updateCachedRect", "#initializeListeners", "subscriber", "#handleScroll", "#handleMove", "#handleDown", "#handleUp", "#handleDblClick", "event", "normalized", "#normalizeEvent", "#emit", "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", "ctx", "newX", "newY", "newClientX", "newClientY", "updateVelocity", "now", "lastMove", "dt", "newVx", "newVy", "maxVel", "clampedVx", "clampedVy", "smoothing", "handleEvent", "normalizedEvent", "type", "eventButton", "eventButtons", "eventIsOverCanvas", "eventIsWithinBounds", "setHoveredArea", "area", "setActiveArea", "reset", "updateConfig", "updates", "defineBrush", "createDefinition", "defineLayer", "Painter", "ServiceProvider", "#layers", "#canvas", "#contexts", "#reactors", "#assets", "#isRunning", "#frameId", "#isRendering", "#renderScheduled", "#runtimeConfig", "#timing", "#metrics", "#hitRegistry", "HitRegistry", "#canvasPointer", "#pointerSurface", "usePointerSurface", "#pointerUnsubscribe", "#subscribers", "layerDef", "layers", "layer", "fn", "canvas", "assets", "name", "fps", "scale", "step", "options", "width", "height", "event", "callback", "path", "normalizedEvent", "ContextTypes", "type", "ctx", "CanvasPointer", "#handlePointerInteraction", "result", "#scheduleRender", "_a", "definitionType", "config", "dataReactor", "#createDataReactor", "brushes", "child", "brushConfig", "whenReactor", "createReactor", "brush", "error", "reactorData", "layerReactorData", "#render", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k", "_l", "_m", "_n", "_o", "_p", "_q", "renderStart", "layerStart", "layerReactor", "key", "value", "brushStart", "brushCtx", "requiredAssets", "brushTime", "#renderBrushBounds", "layerTime", "#renderLayerBounds", "#renderDebugOverlay", "y", "lineHeight", "text", "time", "id", "data", "state", "reactor", "unsubscribe", "addEffect", "x", "pointer", "hitArea", "#hitTest", "#getContextForArea", "#emit", "activeArea", "prevHovered", "area", "callbacks", "sorted", "b", "#isPointInBounds", "bounds"]
3
+ "sources": ["../src/Painter.js", "../src/ContextTypes.js", "../src/HitRegistry.js", "../src/CanvasEvents.js", "../src/usePointerSurface.js"],
4
+ "sourcesContent": ["import { ServiceProvider } from '@jucie-engine/core';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createReactor, addEffect } from '@jucie-state/reactive';\nimport { createDefinition, definitionType } from '@jucie-engine/core';\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 reactor 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 reactor if data exists\n const dataReactor = brushConfig.data \n ? this.#createDataReactor(`brush_${name}`, brushConfig.data)\n : () => undefined;\n \n const whenReactor = brushConfig.when \n ? createReactor(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 reactor and subscription\n const reactorData = this.#reactors.get(`painter_brush_${brush.name}`);\n if (reactorData) {\n reactorData.unsubscribe();\n reactorData.reactor.destroy();\n this.#reactors.delete(`painter_brush_${brush.name}`);\n }\n });\n\n // Clean up layer reactor and subscription\n const layerReactorData = this.#reactors.get(`painter_layer_${name}`);\n if (layerReactorData) {\n layerReactorData.unsubscribe();\n layerReactorData.reactor.destroy();\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}`)?.reactor;\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 reactor = createReactor(data, {\n immediate: true,\n context: this.#pointerSurface.state\n });\n\n const unsubscribe = addEffect(reactor, () => this.#scheduleRender());\n\n this.#reactors.set(`painter_${id}`, {\n reactor,\n unsubscribe\n });\n\n return reactor;\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}", "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-engine/core';\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(() => {\n this.#updateCachedRect();\n \n // Emit resize event if control was transferred\n // Pass actual canvas pixel dimensions (not CSS layout dimensions)\n if (this.#hasTransferredControl) {\n this.#emitResize({\n width: this.#canvas.width,\n height: this.#canvas.height\n });\n }\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-state/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 = setup.action((ctx, 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 = setup.action(() => {\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(ctx, 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(ctx, 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(ctx, 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(ctx, newX, newY, newClientX, newClientY);\n clickCount.value = 2;\n break;\n \n case 'scroll':\n updatePosition(ctx, 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(ctx, 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"],
5
+ "mappings": "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",
6
+ "names": ["ServiceProvider", "ContextTypes", "createReactor", "addEffect", "createDefinition", "definitionType", "HitRegistry", "#areas", "id", "area", "ServiceProvider", "CanvasEvents", "#canvas", "#offscreenCanvas", "#cachedRect", "#resizeObserver", "#subscribers", "#resizeSubscribers", "#pendingMove", "#rafId", "#hasTransferredControl", "canvas", "listener", "#removeListeners", "#updateCachedRect", "#initializeListeners", "subscriber", "#emitResize", "#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", "ctx", "newX", "newY", "newClientX", "newClientY", "updateVelocity", "now", "lastMove", "dt", "newVx", "newVy", "maxVel", "clampedVx", "clampedVy", "smoothing", "handleEvent", "normalizedEvent", "type", "eventButton", "eventButtons", "eventIsOverCanvas", "eventIsWithinBounds", "setHoveredArea", "area", "setActiveArea", "reset", "updateConfig", "updates", "defineBrush", "createDefinition", "defineLayer", "Painter", "ServiceProvider", "#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", "_a", "definitionType", "config", "dataReactor", "#createDataReactor", "brushes", "child", "brushConfig", "whenReactor", "createReactor", "brush", "error", "reactorData", "layerReactorData", "#render", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j", "_k", "_l", "_m", "_n", "_o", "_p", "_q", "renderStart", "layerStart", "layerReactor", "key", "value", "brushStart", "brushCtx", "requiredAssets", "brushTime", "#renderBrushBounds", "layerTime", "#renderLayerBounds", "#renderDebugOverlay", "y", "lineHeight", "text", "time", "id", "data", "reactor", "unsubscribe", "addEffect", "#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-engine/painter",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Canvas painting service for @jucie-engine/core with reactive rendering support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",