@jucie-engine/painter 1.0.5 → 1.0.7

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 M=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var O=(g,e)=>{for(var t in e)M(g,t,{get:e[t],enumerable:!0})},j=(g,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of U(e))!k.call(g,n)&&n!==t&&M(g,n,{get:()=>e[n],enumerable:!(r=A(e,n))||r.enumerable});return g};var z=g=>j(M({},"__esModule",{value:!0}),g);var H={};O(H,{HitRegistry:()=>S,Painter:()=>$,defineBrush:()=>_,defineLayer:()=>B});module.exports=z(H);var F=require("@jucie-engine/core");var L={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};var v=require("@jucie-state/reactive"),E=require("@jucie-engine/core");var S=class{#t=new Map;register(e,t){if(!e)throw new Error("Hit area must have an id");return this.#t.set(e,{id:e,...t}),()=>this.unregister(e)}unregister(e){this.#t.delete(e)}get(e){return this.#t.get(e)}has(e){return this.#t.has(e)}get areas(){return Array.from(this.#t.values())}clear(){this.#t.clear()}};var _=(0,E.createDefinition)("BRUSH",[Object]),B=(0,E.createDefinition)("LAYER",[Object]),$=class extends F.ServiceProvider{#t=new Map;#o=null;#r=new Map;#n=new Map;#g=new Map;#d=!1;#c=null;#v=!1;#m=!1;#y=!1;#e={targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}};#s={lastFrameTime:0,deltaTime:0,elapsedTime:0,frameCount:0};#h={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#u=new S;#b={x:0,y:0,state:"up"};#l=null;#i=null;#a=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}}};actions(e){return this.config&&Object.assign(this.#e,this.config),{addLayer:t=>this.addLayer(t),addLayers:(...t)=>{for(let r of t)this.addLayer(r)},updateCanvas:t=>this.updateCanvas(t),setCanvas:t=>this.setCanvas(t),setAssets:t=>this.setAssets(t),removeLayer:t=>this.removeLayer(t),start:()=>this.start(),stop:()=>this.stop(),render:()=>this.render(),setTargetFPS:t=>this.setTargetFPS(t),setTimeScale:t=>this.setTimeScale(t),setFixedTimeStep:t=>this.setFixedTimeStep(t),setDebug:t=>this.setDebug(t),getMetrics:()=>this.getMetrics(),handleResize:(t,r)=>this.handleResize(t,r),updatePointer:(t,r,n)=>this.updatePointer(t,r,n),subscribe:(t,r)=>this.subscribe(t,r)}}setCanvas(e){this.#o=e,Object.values(L).forEach(t=>{try{let r=e.getContext(t);r&&this.#r.set(t,r)}catch{console.warn(`Context type ${t} not supported`)}})}updateCanvas(e){let t=e(this.#o);t&&(this.#o=t)}setAssets(e){this.#g=e}start(){this.#d||(this.#d=!0,this.#p())}stop(){this.#d&&(this.#d=!1,this.#c&&(cancelAnimationFrame(this.#c),this.#c=null))}addLayer(e){var o;if((0,E.definitionType)(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,r=e(this.useContext,this.#u);if(r.data){let c=this.#x(`layer_${t}`,r.data);c&&this.#n.set(`layer_${t}`,c)}let n=r.children.map(c=>{var l;if((0,E.definitionType)(c)==="BRUSH"){let p=c._name,d=c(this.useContext,this.#u),x=d.data?this.#x(`brush_${p}`,d.data):()=>{},w=d.when?(0,v.createReactor)(d.when,{immediate:!0,context:this.useContext("state")}):null,u={name:p,...d,dataReactor:x,whenReactor:w};if((l=u.lifecycle)!=null&&l.onMount)try{u.lifecycle.onMount(this.#r.get(u.context||r.context))}catch(T){console.error(`Error in brush "${u.name}" onMount:`,T)}return u}return this.addLayer(c)}),s={...r,name:t,brushes:n,context:this.#r.get(r.context)};if(this.#t.set(t,s),(o=s.lifecycle)!=null&&o.onMount)try{s.lifecycle.onMount(s.context)}catch(c){console.error(`Error in layer "${t}" onMount:`,c)}return s}removeLayer(e){var n;let t=this.#t.get(e);if(!t)return;if((n=t.lifecycle)!=null&&n.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(s){console.error(`Error in layer "${e}" onUnmount:`,s)}t.brushes.forEach(s=>{var c;if((c=s.lifecycle)!=null&&c.onUnmount)try{s.lifecycle.onUnmount(this.#r.get(s.context||t.context))}catch(l){console.error(`Error in brush "${s.name}" onUnmount:`,l)}let o=this.#n.get(`painter_brush_${s.name}`);o&&(o.unsubscribe(),o.reactor.destroy(),this.#n.delete(`painter_brush_${s.name}`))});let r=this.#n.get(`painter_layer_${e}`);r&&(r.unsubscribe(),r.reactor.destroy(),this.#n.delete(`painter_layer_${e}`)),this.#t.delete(e)}#p(){this.#y||this.#m||(this.#y=!0,this.#c=requestAnimationFrame(()=>{this.#y=!1,this.#c=null,this.#w()}))}async#w(){var e,t,r,n,s,o,c,l,p,d,x,w,u,T,P,h,C;if(this.#o){this.#m=!0;try{this.#u.clear();let W=(e=this.#e.debug)!=null&&e.enabled?performance.now():0;this.#r.forEach(a=>{a.clearRect(0,0,this.#o.width,this.#o.height)});for(let a of this.#t.values()){let D=(t=this.#e.debug)!=null&&t.enabled?performance.now():0;if(a.whenReactor){let i=(r=this.#n.get(`painter_layer_${a.name}`))==null?void 0:r.reactor;if(!a.when(i()))continue}let m=a.context;if(m){if((n=a.lifecycle)!=null&&n.beforeRender)try{a.lifecycle.beforeRender(m,this.#s)}catch(i){console.error(`Error in layer "${a.name}" beforeRender:`,i),(s=a.lifecycle)!=null&&s.onError&&a.lifecycle.onError(i)}m.save(),a.settings&&Object.entries(a.settings).forEach(([i,R])=>{typeof m[i]=="function"?m[i](...Array.isArray(R)?R:[R]):m[i]=R});for(let i of a.brushes){let R=(o=this.#e.debug)!=null&&o.enabled?performance.now():0;if(i.whenReactor&&!i.whenReactor())continue;let y=i.context?this.#r.get(i.context):m;if(y){if((c=i.lifecycle)!=null&&c.beforeRender)try{i.lifecycle.beforeRender(y,this.#s)}catch(f){console.error(`Error in brush "${i.name}" beforeRender:`,f),(l=i.lifecycle)!=null&&l.onError&&i.lifecycle.onError(f);continue}y.save(),i.settings&&Object.entries(i.settings).forEach(([f,b])=>{typeof y[f]=="function"?y[f](...Array.isArray(b)?b:[b]):y[f]=b});try{let f={};if(i.assets)for(let b of i.assets)f[b]=this.#g.get(b);if(i.render(y,i.dataReactor(),f,this.#s),(p=i.lifecycle)!=null&&p.afterRender&&i.lifecycle.afterRender(y,this.#s),(d=this.#e.debug)!=null&&d.enabled){let b=performance.now()-R;this.#h.brushTimes.set(i.name,b),(x=this.#e.debug)!=null&&x.showBounds&&this.#T(y,i)}}catch(f){console.error(`Error in brush "${i.name}":`,f),(w=i.lifecycle)!=null&&w.onError&&i.lifecycle.onError(f)}finally{y.restore()}}}if(m.restore(),(u=a.lifecycle)!=null&&u.afterRender)try{a.lifecycle.afterRender(m,this.#s)}catch(i){console.error(`Error in layer "${a.name}" afterRender:`,i),(T=a.lifecycle)!=null&&T.onError&&a.lifecycle.onError(i)}if((P=this.#e.debug)!=null&&P.enabled){let i=performance.now()-D;this.#h.layerTimes.set(a.name,i),(h=this.#e.debug)!=null&&h.showBounds&&this.#R(m,a)}}}(C=this.#e.debug)!=null&&C.enabled&&this.#S()}finally{this.#m=!1}}}#T(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()}#R(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()}#S(){var n,s;let e=this.#r.get(L["2D"]);if(!e)return;e.save(),e.resetTransform(),e.font="12px monospace",e.fillStyle="white",e.strokeStyle="black",e.lineWidth=3;let t=20,r=15;if((n=this.#e.debug)!=null&&n.showFPS){let o=`FPS: ${Math.round(this.#h.fps)} (${this.#s.deltaTime.toFixed(2)}ms)`;e.strokeText(o,10,t),e.fillText(o,10,t),t+=r}if((s=this.#e.debug)!=null&&s.showLayerTiming){e.fillText("Layer Times:",10,t),t+=r;for(let[o,c]of this.#h.layerTimes){let l=` ${o}: ${c.toFixed(2)}ms`;e.strokeText(l,10,t),e.fillText(l,10,t),t+=r}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){var r,n;for(let s of this.#t.values())if((r=s.lifecycle)!=null&&r.onResize)try{s.lifecycle.onResize(e,t,s.context)}catch(o){console.error(`Error in layer "${s.name}" onResize:`,o),(n=s.lifecycle)!=null&&n.onError&&s.lifecycle.onError(o)}}#x(e,t){let r=this.useContext("state"),n=(0,v.createReactor)(t,{immediate:!0,context:r}),s=(0,v.addEffect)(n,()=>this.#p());return this.#n.set(`painter_${e}`,{reactor:n,unsubscribe:s}),n}destroy(){this.stop();for(let e of this.#t.keys())this.removeLayer(e)}setTargetFPS(e){this.#e.targetFPS=e,this.#e.fixedTimeStep=1e3/e}setTimeScale(e){this.#e.timeScale=Math.max(0,e)}setFixedTimeStep(e){this.#e.fixedTimeStep=e}setDebug(e={}){this.#e.debug||(this.#e.debug={}),Object.assign(this.#e.debug,e)}getMetrics(){return{...this.#h,deltaTime:this.#s.deltaTime,elapsedTime:this.#s.elapsedTime,frameCount:this.#s.frameCount}}updatePointer(e,t,r){var c,l,p,d,x,w,u,T,P;let n={...this.#b};this.#b={x:e,y:t,state:r};let s=this.#E(e,t),o=h=>h?h.context?this.#r.get(h.context):this.#r.get(L["2D"]):null;if(r==="down"&&(this.#i=s,(c=s==null?void 0:s.onPointerDown)!=null&&c.handler)){let h=o(s);s.onPointerDown.handler(this.#f.bind(this),h)}if(r==="up"){if((p=(l=this.#i)==null?void 0:l.onPointerUp)!=null&&p.handler){let h=o(this.#i);this.#i.onPointerUp.handler(this.#f.bind(this),h)}this.#i=null}if(r==="move"){if((x=(d=this.#i)==null?void 0:d.onPointerMove)!=null&&x.handler){let h=o(this.#i);this.#i.onPointerMove.handler(this.#f.bind(this),h,{x:e,y:t})}if((s==null?void 0:s.id)!==((w=this.#l)==null?void 0:w.id)){if((T=(u=this.#l)==null?void 0:u.onPointerLeave)!=null&&T.handler){let h=o(this.#l);this.#l.onPointerLeave.handler(this.#f.bind(this),h)}if((P=s==null?void 0:s.onPointerEnter)!=null&&P.handler){let h=o(s);s.onPointerEnter.handler(this.#f.bind(this),h)}this.#l=s}}}subscribe(e,t){return this.#a.has(e)||this.#a.set(e,new Set),this.#a.get(e).add(t),()=>{let r=this.#a.get(e);r&&(r.delete(t),r.size===0&&this.#a.delete(e))}}#E(e,t){let r=this.#u.areas.sort((n,s)=>(s.priority||0)-(n.priority||0));for(let n of r)if(this.#P(e,t,n.bounds))return n;return null}#P(e,t,r){return e>=r.x&&e<=r.x+r.width&&t>=r.y&&t<=r.y+r.height}#f(e,t){let r=this.#a.get(e);if(r)for(let n of r)n(t)}};0&&(module.exports={HitRegistry,Painter,defineBrush,defineLayer});
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});
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"],
4
- "sourcesContent": ["export { Painter, defineLayer, defineBrush } from './Painter';\nexport { HitRegistry } from './HitRegistry';", "import { ServiceProvider } from '@jucie-engine/core';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createReactor, isReactor, addEffect } from '@jucie-state/reactive';\nimport { createDefinition, definitionType } from '@jucie-engine/core';\nimport { HitRegistry } from './HitRegistry.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 #renderNeeded = false;\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 #pointerState = { x: 0, y: 0, state: 'up' };\n #hoveredArea = null;\n #activeArea = 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 actions(context) {\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 updatePointer: (x, y, state) => this.updatePointer(x, y, state),\n subscribe: (event, callback) => this.subscribe(event, callback)\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\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 // 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 // Hit Registry Methods\n updatePointer(x, y, state) {\n const prevPointer = { ...this.#pointerState };\n this.#pointerState = { x, y, state };\n\n // Hit test current position\n const hitArea = this.#hitTest(x, y);\n\n // Get the canvas context for this area\n const getContext = (area) => {\n if (!area) return null;\n // Get the context from the area's specified context type or default\n return area.context ? this.#contexts.get(area.context) : this.#contexts.get(ContextTypes['2D']);\n };\n\n // Handle state transitions\n if (state === 'down') {\n this.#activeArea = hitArea;\n if (hitArea?.onPointerDown?.handler) {\n const ctx = getContext(hitArea);\n hitArea.onPointerDown.handler(this.#emit.bind(this), ctx);\n }\n }\n \n if (state === 'up') {\n if (this.#activeArea?.onPointerUp?.handler) {\n const ctx = getContext(this.#activeArea);\n this.#activeArea.onPointerUp.handler(this.#emit.bind(this), ctx);\n }\n this.#activeArea = null;\n }\n \n if (state === 'move') {\n // Handle drag on active area\n if (this.#activeArea?.onPointerMove?.handler) {\n const ctx = getContext(this.#activeArea);\n this.#activeArea.onPointerMove.handler(this.#emit.bind(this), ctx, { x, y });\n }\n \n // Handle hover enter/leave (compare by id, not object reference)\n if (hitArea?.id !== this.#hoveredArea?.id) {\n if (this.#hoveredArea?.onPointerLeave?.handler) {\n const ctx = getContext(this.#hoveredArea);\n this.#hoveredArea.onPointerLeave.handler(this.#emit.bind(this), ctx);\n }\n \n if (hitArea?.onPointerEnter?.handler) {\n const ctx = getContext(hitArea);\n hitArea.onPointerEnter.handler(this.#emit.bind(this), ctx);\n }\n \n this.#hoveredArea = hitArea;\n }\n }\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}", "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}"],
5
- "mappings": "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",
6
- "names": ["main_exports", "__export", "HitRegistry", "Painter", "defineBrush", "defineLayer", "__toCommonJS", "import_core", "ContextTypes", "import_reactive", "import_core", "HitRegistry", "#areas", "id", "area", "defineBrush", "defineLayer", "Painter", "#layers", "#canvas", "#contexts", "#reactors", "#assets", "#isRunning", "#frameId", "#renderNeeded", "#isRendering", "#renderScheduled", "#runtimeConfig", "#timing", "#metrics", "#hitRegistry", "HitRegistry", "#pointerState", "#hoveredArea", "#activeArea", "#subscribers", "context", "layerDef", "layers", "layer", "fn", "canvas", "assets", "name", "fps", "scale", "step", "options", "width", "height", "x", "y", "state", "event", "callback", "ContextTypes", "type", "ctx", "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", "lineHeight", "text", "time", "id", "data", "reactor", "unsubscribe", "prevPointer", "hitArea", "#hitTest", "getContext", "area", "#emit", "callbacks", "sorted", "a", "b", "#isPointInBounds", "bounds"]
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"]
7
7
  }
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{ServiceProvider as _}from"@jucie-engine/core";var E={"2D":"2d",WEBGL:"webgl",WEBGL2:"webgl2",BITMAPRENDERER:"bitmaprenderer"};import{createReactor as L,addEffect as B}from"@jucie-state/reactive";import{createDefinition as M,definitionType as $}from"@jucie-engine/core";var S=class{#t=new Map;register(e,t){if(!e)throw new Error("Hit area must have an id");return this.#t.set(e,{id:e,...t}),()=>this.unregister(e)}unregister(e){this.#t.delete(e)}get(e){return this.#t.get(e)}has(e){return this.#t.has(e)}get areas(){return Array.from(this.#t.values())}clear(){this.#t.clear()}};var D=M("BRUSH",[Object]),A=M("LAYER",[Object]),P=class extends _{#t=new Map;#o=null;#r=new Map;#n=new Map;#g=new Map;#d=!1;#c=null;#v=!1;#m=!1;#y=!1;#e={targetFPS:60,fixedTimeStep:1e3/60,timeScale:1,debug:{enabled:!1,showFPS:!0,showBounds:!0,showLayerTiming:!0}};#s={lastFrameTime:0,deltaTime:0,elapsedTime:0,frameCount:0};#h={fps:0,frameTime:0,layerTimes:new Map,brushTimes:new Map,skippedFrames:0};#u=new S;#b={x:0,y:0,state:"up"};#l=null;#i=null;#a=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}}};actions(e){return this.config&&Object.assign(this.#e,this.config),{addLayer:t=>this.addLayer(t),addLayers:(...t)=>{for(let r of t)this.addLayer(r)},updateCanvas:t=>this.updateCanvas(t),setCanvas:t=>this.setCanvas(t),setAssets:t=>this.setAssets(t),removeLayer:t=>this.removeLayer(t),start:()=>this.start(),stop:()=>this.stop(),render:()=>this.render(),setTargetFPS:t=>this.setTargetFPS(t),setTimeScale:t=>this.setTimeScale(t),setFixedTimeStep:t=>this.setFixedTimeStep(t),setDebug:t=>this.setDebug(t),getMetrics:()=>this.getMetrics(),handleResize:(t,r)=>this.handleResize(t,r),updatePointer:(t,r,n)=>this.updatePointer(t,r,n),subscribe:(t,r)=>this.subscribe(t,r)}}setCanvas(e){this.#o=e,Object.values(E).forEach(t=>{try{let r=e.getContext(t);r&&this.#r.set(t,r)}catch{console.warn(`Context type ${t} not supported`)}})}updateCanvas(e){let t=e(this.#o);t&&(this.#o=t)}setAssets(e){this.#g=e}start(){this.#d||(this.#d=!0,this.#p())}stop(){this.#d&&(this.#d=!1,this.#c&&(cancelAnimationFrame(this.#c),this.#c=null))}addLayer(e){var o;if($(e)!=="LAYER")throw new Error("Invalid layer definition");let t=e._name,r=e(this.useContext,this.#u);if(r.data){let c=this.#x(`layer_${t}`,r.data);c&&this.#n.set(`layer_${t}`,c)}let n=r.children.map(c=>{var l;if($(c)==="BRUSH"){let b=c._name,d=c(this.useContext,this.#u),p=d.data?this.#x(`brush_${b}`,d.data):()=>{},x=d.when?L(d.when,{immediate:!0,context:this.useContext("state")}):null,u={name:b,...d,dataReactor:p,whenReactor:x};if((l=u.lifecycle)!=null&&l.onMount)try{u.lifecycle.onMount(this.#r.get(u.context||r.context))}catch(w){console.error(`Error in brush "${u.name}" onMount:`,w)}return u}return this.addLayer(c)}),s={...r,name:t,brushes:n,context:this.#r.get(r.context)};if(this.#t.set(t,s),(o=s.lifecycle)!=null&&o.onMount)try{s.lifecycle.onMount(s.context)}catch(c){console.error(`Error in layer "${t}" onMount:`,c)}return s}removeLayer(e){var n;let t=this.#t.get(e);if(!t)return;if((n=t.lifecycle)!=null&&n.onUnmount)try{t.lifecycle.onUnmount(t.context)}catch(s){console.error(`Error in layer "${e}" onUnmount:`,s)}t.brushes.forEach(s=>{var c;if((c=s.lifecycle)!=null&&c.onUnmount)try{s.lifecycle.onUnmount(this.#r.get(s.context||t.context))}catch(l){console.error(`Error in brush "${s.name}" onUnmount:`,l)}let o=this.#n.get(`painter_brush_${s.name}`);o&&(o.unsubscribe(),o.reactor.destroy(),this.#n.delete(`painter_brush_${s.name}`))});let r=this.#n.get(`painter_layer_${e}`);r&&(r.unsubscribe(),r.reactor.destroy(),this.#n.delete(`painter_layer_${e}`)),this.#t.delete(e)}#p(){this.#y||this.#m||(this.#y=!0,this.#c=requestAnimationFrame(()=>{this.#y=!1,this.#c=null,this.#w()}))}async#w(){var e,t,r,n,s,o,c,l,b,d,p,x,u,w,R,h,v;if(this.#o){this.#m=!0;try{this.#u.clear();let U=(e=this.#e.debug)!=null&&e.enabled?performance.now():0;this.#r.forEach(a=>{a.clearRect(0,0,this.#o.width,this.#o.height)});for(let a of this.#t.values()){let F=(t=this.#e.debug)!=null&&t.enabled?performance.now():0;if(a.whenReactor){let i=(r=this.#n.get(`painter_layer_${a.name}`))==null?void 0:r.reactor;if(!a.when(i()))continue}let m=a.context;if(m){if((n=a.lifecycle)!=null&&n.beforeRender)try{a.lifecycle.beforeRender(m,this.#s)}catch(i){console.error(`Error in layer "${a.name}" beforeRender:`,i),(s=a.lifecycle)!=null&&s.onError&&a.lifecycle.onError(i)}m.save(),a.settings&&Object.entries(a.settings).forEach(([i,T])=>{typeof m[i]=="function"?m[i](...Array.isArray(T)?T:[T]):m[i]=T});for(let i of a.brushes){let T=(o=this.#e.debug)!=null&&o.enabled?performance.now():0;if(i.whenReactor&&!i.whenReactor())continue;let y=i.context?this.#r.get(i.context):m;if(y){if((c=i.lifecycle)!=null&&c.beforeRender)try{i.lifecycle.beforeRender(y,this.#s)}catch(f){console.error(`Error in brush "${i.name}" beforeRender:`,f),(l=i.lifecycle)!=null&&l.onError&&i.lifecycle.onError(f);continue}y.save(),i.settings&&Object.entries(i.settings).forEach(([f,g])=>{typeof y[f]=="function"?y[f](...Array.isArray(g)?g:[g]):y[f]=g});try{let f={};if(i.assets)for(let g of i.assets)f[g]=this.#g.get(g);if(i.render(y,i.dataReactor(),f,this.#s),(b=i.lifecycle)!=null&&b.afterRender&&i.lifecycle.afterRender(y,this.#s),(d=this.#e.debug)!=null&&d.enabled){let g=performance.now()-T;this.#h.brushTimes.set(i.name,g),(p=this.#e.debug)!=null&&p.showBounds&&this.#T(y,i)}}catch(f){console.error(`Error in brush "${i.name}":`,f),(x=i.lifecycle)!=null&&x.onError&&i.lifecycle.onError(f)}finally{y.restore()}}}if(m.restore(),(u=a.lifecycle)!=null&&u.afterRender)try{a.lifecycle.afterRender(m,this.#s)}catch(i){console.error(`Error in layer "${a.name}" afterRender:`,i),(w=a.lifecycle)!=null&&w.onError&&a.lifecycle.onError(i)}if((R=this.#e.debug)!=null&&R.enabled){let i=performance.now()-F;this.#h.layerTimes.set(a.name,i),(h=this.#e.debug)!=null&&h.showBounds&&this.#R(m,a)}}}(v=this.#e.debug)!=null&&v.enabled&&this.#S()}finally{this.#m=!1}}}#T(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()}#R(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()}#S(){var n,s;let e=this.#r.get(E["2D"]);if(!e)return;e.save(),e.resetTransform(),e.font="12px monospace",e.fillStyle="white",e.strokeStyle="black",e.lineWidth=3;let t=20,r=15;if((n=this.#e.debug)!=null&&n.showFPS){let o=`FPS: ${Math.round(this.#h.fps)} (${this.#s.deltaTime.toFixed(2)}ms)`;e.strokeText(o,10,t),e.fillText(o,10,t),t+=r}if((s=this.#e.debug)!=null&&s.showLayerTiming){e.fillText("Layer Times:",10,t),t+=r;for(let[o,c]of this.#h.layerTimes){let l=` ${o}: ${c.toFixed(2)}ms`;e.strokeText(l,10,t),e.fillText(l,10,t),t+=r}e.fillText(this.state.get(["_transitions","pointer","currentState"]),10,t)}e.restore()}handleResize(e,t){var r,n;for(let s of this.#t.values())if((r=s.lifecycle)!=null&&r.onResize)try{s.lifecycle.onResize(e,t,s.context)}catch(o){console.error(`Error in layer "${s.name}" onResize:`,o),(n=s.lifecycle)!=null&&n.onError&&s.lifecycle.onError(o)}}#x(e,t){let r=this.useContext("state"),n=L(t,{immediate:!0,context:r}),s=B(n,()=>this.#p());return this.#n.set(`painter_${e}`,{reactor:n,unsubscribe:s}),n}destroy(){this.stop();for(let e of this.#t.keys())this.removeLayer(e)}setTargetFPS(e){this.#e.targetFPS=e,this.#e.fixedTimeStep=1e3/e}setTimeScale(e){this.#e.timeScale=Math.max(0,e)}setFixedTimeStep(e){this.#e.fixedTimeStep=e}setDebug(e={}){this.#e.debug||(this.#e.debug={}),Object.assign(this.#e.debug,e)}getMetrics(){return{...this.#h,deltaTime:this.#s.deltaTime,elapsedTime:this.#s.elapsedTime,frameCount:this.#s.frameCount}}updatePointer(e,t,r){var c,l,b,d,p,x,u,w,R;let n={...this.#b};this.#b={x:e,y:t,state:r};let s=this.#E(e,t),o=h=>h?h.context?this.#r.get(h.context):this.#r.get(E["2D"]):null;if(r==="down"&&(this.#i=s,(c=s==null?void 0:s.onPointerDown)!=null&&c.handler)){let h=o(s);s.onPointerDown.handler(this.#f.bind(this),h)}if(r==="up"){if((b=(l=this.#i)==null?void 0:l.onPointerUp)!=null&&b.handler){let h=o(this.#i);this.#i.onPointerUp.handler(this.#f.bind(this),h)}this.#i=null}if(r==="move"){if((p=(d=this.#i)==null?void 0:d.onPointerMove)!=null&&p.handler){let h=o(this.#i);this.#i.onPointerMove.handler(this.#f.bind(this),h,{x:e,y:t})}if((s==null?void 0:s.id)!==((x=this.#l)==null?void 0:x.id)){if((w=(u=this.#l)==null?void 0:u.onPointerLeave)!=null&&w.handler){let h=o(this.#l);this.#l.onPointerLeave.handler(this.#f.bind(this),h)}if((R=s==null?void 0:s.onPointerEnter)!=null&&R.handler){let h=o(s);s.onPointerEnter.handler(this.#f.bind(this),h)}this.#l=s}}}subscribe(e,t){return this.#a.has(e)||this.#a.set(e,new Set),this.#a.get(e).add(t),()=>{let r=this.#a.get(e);r&&(r.delete(t),r.size===0&&this.#a.delete(e))}}#E(e,t){let r=this.#u.areas.sort((n,s)=>(s.priority||0)-(n.priority||0));for(let n of r)if(this.#P(e,t,n.bounds))return n;return null}#P(e,t,r){return e>=r.x&&e<=r.x+r.width&&t>=r.y&&t<=r.y+r.height}#f(e,t){let r=this.#a.get(e);if(r)for(let n of r)n(t)}};export{S as HitRegistry,P as Painter,D as defineBrush,A as defineLayer};
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};
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"],
4
- "sourcesContent": ["import { ServiceProvider } from '@jucie-engine/core';\nimport { ContextTypes } from './ContextTypes.js';\nimport { createReactor, isReactor, addEffect } from '@jucie-state/reactive';\nimport { createDefinition, definitionType } from '@jucie-engine/core';\nimport { HitRegistry } from './HitRegistry.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 #renderNeeded = false;\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 #pointerState = { x: 0, y: 0, state: 'up' };\n #hoveredArea = null;\n #activeArea = 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 actions(context) {\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 updatePointer: (x, y, state) => this.updatePointer(x, y, state),\n subscribe: (event, callback) => this.subscribe(event, callback)\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\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 // 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 // Hit Registry Methods\n updatePointer(x, y, state) {\n const prevPointer = { ...this.#pointerState };\n this.#pointerState = { x, y, state };\n\n // Hit test current position\n const hitArea = this.#hitTest(x, y);\n\n // Get the canvas context for this area\n const getContext = (area) => {\n if (!area) return null;\n // Get the context from the area's specified context type or default\n return area.context ? this.#contexts.get(area.context) : this.#contexts.get(ContextTypes['2D']);\n };\n\n // Handle state transitions\n if (state === 'down') {\n this.#activeArea = hitArea;\n if (hitArea?.onPointerDown?.handler) {\n const ctx = getContext(hitArea);\n hitArea.onPointerDown.handler(this.#emit.bind(this), ctx);\n }\n }\n \n if (state === 'up') {\n if (this.#activeArea?.onPointerUp?.handler) {\n const ctx = getContext(this.#activeArea);\n this.#activeArea.onPointerUp.handler(this.#emit.bind(this), ctx);\n }\n this.#activeArea = null;\n }\n \n if (state === 'move') {\n // Handle drag on active area\n if (this.#activeArea?.onPointerMove?.handler) {\n const ctx = getContext(this.#activeArea);\n this.#activeArea.onPointerMove.handler(this.#emit.bind(this), ctx, { x, y });\n }\n \n // Handle hover enter/leave (compare by id, not object reference)\n if (hitArea?.id !== this.#hoveredArea?.id) {\n if (this.#hoveredArea?.onPointerLeave?.handler) {\n const ctx = getContext(this.#hoveredArea);\n this.#hoveredArea.onPointerLeave.handler(this.#emit.bind(this), ctx);\n }\n \n if (hitArea?.onPointerEnter?.handler) {\n const ctx = getContext(hitArea);\n hitArea.onPointerEnter.handler(this.#emit.bind(this), ctx);\n }\n \n this.#hoveredArea = hitArea;\n }\n }\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}", "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}"],
5
- "mappings": "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",
6
- "names": ["ServiceProvider", "ContextTypes", "createReactor", "addEffect", "createDefinition", "definitionType", "HitRegistry", "#areas", "id", "area", "defineBrush", "createDefinition", "defineLayer", "Painter", "ServiceProvider", "#layers", "#canvas", "#contexts", "#reactors", "#assets", "#isRunning", "#frameId", "#renderNeeded", "#isRendering", "#renderScheduled", "#runtimeConfig", "#timing", "#metrics", "#hitRegistry", "HitRegistry", "#pointerState", "#hoveredArea", "#activeArea", "#subscribers", "context", "layerDef", "layers", "layer", "fn", "canvas", "assets", "name", "fps", "scale", "step", "options", "width", "height", "x", "y", "state", "event", "callback", "ContextTypes", "type", "ctx", "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", "lineHeight", "text", "time", "id", "data", "reactor", "unsubscribe", "addEffect", "prevPointer", "hitArea", "#hitTest", "getContext", "area", "#emit", "callbacks", "sorted", "a", "b", "#isPointInBounds", "bounds"]
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"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jucie-engine/painter",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Canvas painting service for @jucie-engine/core with reactive rendering support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@jucie-engine/core": "^1.0.0",
38
- "@jucie-state/reactive": "^1.0.0"
38
+ "@jucie-state/reactive": "^1.0.9"
39
39
  },
40
40
  "dependencies": {
41
41
  "@jucie-state/core": "^1.0.39"