@combos-fun/plugin-development-tool 0.0.53 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- "use strict";var e=require("tslib"),t=require("@combos-fun/engine"),n=require("@combos-fun/inspector-decorator");const o="combos-development-tool:set-pick-mode",r="combos-development-tool:pick-mode-success",i="combos-development-tool:refresh",s="combos-development-tool:gameobject-selected",a="combos-development-tool:clear-selection",c="combos-development-tool:gameobject-deselected",l="combos-development-tool:apply-property",d="combos-development-tool:set-marker-overlay",h="combos-development-tool:marker-overlay-success";class u extends t.Component{constructor(){super(...arguments),this.payload={}}static{this.componentName="CombosDevelopmentToolTarget"}init(e){this.payload=e?.payload?{...e.payload}:{}}}function p(e,t=1){return`rgba(${e>>16&255}, ${e>>8&255}, ${255&e}, ${t})`}class m{constructor(e){this.ctx=e}clear(){this.ctx.beginPath()}roundRect(e,t,n,o,r=0){const i=this.ctx;if("function"==typeof i.roundRect)return void i.roundRect(e,t,n,o,r);const s=Math.max(0,Math.min(r,Math.min(n,o)/2));i.moveTo(e+s,t),i.lineTo(e+n-s,t),i.quadraticCurveTo(e+n,t,e+n,t+s),i.lineTo(e+n,t+o-s),i.quadraticCurveTo(e+n,t+o,e+n-s,t+o),i.lineTo(e+s,t+o),i.quadraticCurveTo(e,t+o,e,t+o-s),i.lineTo(e,t+s),i.quadraticCurveTo(e,t,e+s,t),i.closePath()}rect(e,t,n,o){this.ctx.rect(e,t,n,o)}circle(e,t,n){this.ctx.moveTo(e+n,t),this.ctx.arc(e,t,n,0,2*Math.PI)}poly(e,t=!0){if(!(e.length<4)){this.ctx.moveTo(e[0],e[1]);for(let t=2;t<e.length;t+=2)this.ctx.lineTo(e[t],e[t+1]);t&&this.ctx.closePath()}}fill(e){this.ctx.fillStyle=p(e.color,e.alpha??1),this.ctx.fill(),this.ctx.beginPath()}stroke(e){this.ctx.strokeStyle=p(e.color,e.alpha??1),this.ctx.lineWidth=e.width,this.ctx.stroke(),this.ctx.beginPath()}}const f=[{componentName:"Sound",badgeColor:9133302,glyph:"speaker"}],y=28;function g(e,t=f){for(const n of t)if(e.getComponent(n.componentName))return n;return null}const b=16777215;function v(e,t,n=28){if(function(e,t,n){e.clear(),e.roundRect(0,0,n,n,.22*n),e.fill({color:t.badgeColor,alpha:.92}),e.roundRect(0,0,n,n,.22*n),e.stroke({width:Math.max(1,.05*n),color:16777215,alpha:.6})}(e,t,n),"speaker"===t.glyph)!function(e,t){e.poly([.28*t,.4*t,.42*t,.4*t,.55*t,.26*t,.55*t,.74*t,.42*t,.6*t,.28*t,.6*t]),e.fill({color:b,alpha:.96}),e.rect(.62*t,.44*t,.045*t,.12*t),e.fill({color:b,alpha:.96}),e.rect(.71*t,.39*t,.045*t,.22*t),e.fill({color:b,alpha:.96})}(e,n);else!function(e,t){e.circle(.5*t,.5*t,.18*t),e.fill({color:b,alpha:.96})}(e,n)}const w=["knoffice.tech","converge.ai"];function O(e,t){if(t.includes("*"))return!0;if(0===t.length)return!1;let n;try{n=new URL(e)}catch{return!1}const o=e.toLowerCase(),r=n.hostname.toLowerCase();for(const e of t){const t=e.trim();if(!t)continue;if(t.includes("://")){if(o===t.toLowerCase())return!0;continue}const n=t.toLowerCase().replace(/^\./,"");if(r===n||r.endsWith(`.${n}`))return!0}return!1}function x(e){if(!e?.length)return[...w];if(e.includes("*"))return["*"];const t=new Set,n=[];for(const o of[...w,...e]){const e=o.trim();e&&!t.has(e)&&(t.add(e),n.push(e))}return n}function M(){if("undefined"==typeof document)return null;const e=document.createElement("canvas");e.setAttribute("data-combos-development-tool-overlay","true"),e.style.position="fixed",e.style.left="0",e.style.top="0",e.style.width="0",e.style.height="0",e.style.margin="0",e.style.padding="0",e.style.border="0",e.style.background="transparent",e.style.pointerEvents="none",e.style.touchAction="none",e.style.userSelect="none",e.style.zIndex="2147483000",e.style.display="none";const t=e.getContext("2d");if(!t)return null;let n=!1,o=!1;return{canvas:e,ctx:t,sync:n=>{!function(e,t){const n=e.parentElement??document.body;t.parentElement!==n&&n.appendChild(t)}(n,e);const r=n.getBoundingClientRect();if(r.width<=0||r.height<=0)return e.style.display="none",null;e.style.display=o?"block":"none",e.style.left=`${r.left}px`,e.style.top=`${r.top}px`,e.style.width=`${r.width}px`,e.style.height=`${r.height}px`;const i="undefined"!=typeof window&&window.devicePixelRatio||1,s=Math.max(1,Math.round(r.width*i)),a=Math.max(1,Math.round(r.height*i));return e.width===s&&e.height===a||(e.width=s,e.height=a),t.setTransform(i,0,0,i,0,0),{width:r.width,height:r.height}},setPickEnabled(t){n=t,e.style.pointerEvents=n?"auto":"none",e.style.cursor=n?"crosshair":"default"},setVisible(t){o=t,e.style.display=t?"block":"none"},destroy(){e.remove()}}}function E(e){return!!e&&"object"==typeof e&&"string"==typeof e.file}function S(e){return"string"==typeof e?"string":"number"==typeof e?"number":"boolean"==typeof e?"boolean":null!==e&&"object"==typeof e?"object":"unsupported"}function k(e,t=0){if(null==e)return e;if("number"==typeof e||"string"==typeof e||"boolean"==typeof e)return e;if(!(t>6)){if(Array.isArray(e))return e.map(e=>k(e,t+1));if("object"==typeof e){const n={};for(const[o,r]of Object.entries(e)){if("function"==typeof r)continue;const e=k(r,t+1);void 0!==e&&(n[o]=e)}return n}}}function T(e){const t=e.constructor,o=function(e){const t=Reflect.getMetadata(n.IDE_PROPERTY_METADATA,e)||{};return Object.keys(t).map(e=>({key:e,...t[e]}))}(t);return o.length>0?o:function(e){const t=e.IDEProps;return!t||Array.isArray(t)||"object"!=typeof t?[]:Object.keys(t).map(e=>{const n=t[e]||{};return{key:e,type:"string"==typeof n.type?n.type:void 0,step:"number"==typeof n.step?n.step:void 0,min:"number"==typeof n.min?n.min:void 0,max:"number"==typeof n.max?n.max:void 0,label:"string"==typeof n.label?n.label:void 0,description:"string"==typeof n.description?n.description:void 0,group:"string"==typeof n.group?n.group:void 0,editor:n.editor,enumOptions:Array.isArray(n.enumOptions)?n.enumOptions:void 0,unit:"string"==typeof n.unit?n.unit:void 0}})}(t)}function C(e,t){return e.editor?e.editor:"boolean"===t?"toggle":e.enumOptions?.length&&"string"===t?"enum":"number"===t?void 0!==e.min&&void 0!==e.max?"number-slider":"number-stepper":"string"===t?"text":void 0}function P(e){if(void 0!==e.min||void 0!==e.max||void 0!==e.step||void 0!==e.unit)return{min:e.min,max:e.max,step:e.step,unit:e.unit}}function _(e,t){if(e.label?.trim())return e.label.trim();const n=t[t.length-1];return n?function(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/_/g," ").replace(/^./,e=>e.toUpperCase())}(n):void 0}function R(e,t,n,o){const r=t.description?.trim();if(!r)return[];const i=S(o);if("unsupported"===i)return[];const s=t.type,a="size"===s||"object"===i&&null!==o&&"width"in o&&"height"in o;if("vector2"===s||"object"===i&&null!==o&&"x"in o&&"y"in o||a){const i=o,s=a?["width","height"]:["x","y"],c=_(t,n)??e,l=[];for(const o of s){const s=i[o],a=S(s);if("unsupported"===a||"object"===a)continue;const d=[...n,o];l.push({path:d,value:s,valueType:a,label:`${c} ${o.toUpperCase()}`,description:r,group:t.group??e,editorKind:C(t,a),numberMeta:P(t),persistTarget:"Transform"===e?"gameObjectConstructor":"component"})}return l}if("object"===i)return[];const c=_(t,n);return c?[{path:n,value:k(o),valueType:i,label:c,description:r,group:t.group??e,editorKind:C(t,i),enumOptions:t.enumOptions,numberMeta:P(t),persistTarget:"Transform"===e?"gameObjectConstructor":"component"}]:[]}function D(e){const t=e.name,n=T(e);if(0===n.length)return[];const o=[],r=e;for(const e of n){const n=r[e.key];"function"!=typeof n&&o.push(...R(t,e,[e.key],n))}return o}function j(e){const t=e.getComponent(u),n=t?.payload?.source;if(E(n))return{file:n.file,anchor:n.anchor??e.name}}function L(e){const t=e.components.filter(e=>"CombosDevelopmentToolTarget"!==e.name).map(e=>({componentName:e.name,fieldDescriptors:D(e)})).filter(e=>e.fieldDescriptors.length>0);return{id:e.id,name:e.name,components:t,source:j(e)}}function N(e,t,n,o){const r=e.getComponent(t);if(!r||!n.length)return!1;let i=r;for(let e=0;e<n.length-1;e++){const t=n[e];void 0!==i[t]&&null!==i[t]||(i[t]={}),i=i[t]}return i[n[n.length-1]]=o,!0}const A=new Set(["position","size","origin","anchor","scale","skew"]);function G(e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e&&""!==e.trim()){const t=Number(e);return Number.isFinite(t)?t:void 0}}const B={Transform:function(e,t,n,o){const r=e.transform,i=r;if(1===n.length&&"rotation"===n[0]){const e=G(o);return void 0!==e&&(r.rotation=e,!0)}if(2===n.length&&A.has(n[0])){const t=n[0],r=n[1],s=G(o);if(void 0===s)return!1;const a=i[t];return!(!a||"object"!=typeof a)&&(a[r]=s,"position"===t&&(function(e){const t=e.getComponent("Physics");if(!t?.body)return;const{x:n,y:o}=e.transform.position;t.Body?.setPosition?t.Body.setPosition(t.body,{x:n,y:o}):(t.body.position.x=n,t.body.position.y=o)}(e),function(e){const t=e.getComponent("PlatformerMover");t&&(t.originX=e.transform.position.x,t.originY=e.transform.position.y)}(e)),!0)}return!1},Text:function(e,t,n,o){const r=t;if(1===n.length&&"text"===n[0])return r.text=String(o??""),!0;if(2===n.length&&"style"===n[0]){const e=n[1],t={...r.style??{},[e]:o};return r.style=t,!0}return!1},Sound:function(e,t,n,o){const r=t;if(1===n.length&&"volume"===n[0]||2===n.length&&"config"===n[0]&&"volume"===n[1]){const e=G(o);return void 0!==e&&(r.volume=e,!0)}return!1}};function I(e,t,n,o){const r=e.getComponent(t);if(!r||!n.length)return!1;const i=B[t];return!!i?.(e,r,n,o)||N(e,t,n,o)}function W(e){return{type:c,reason:e}}function V(e){return e}function F(e){return!(!e||"object"!=typeof e)&&e.type===a}function U(e,t){return{a:e.a*t.a+e.c*t.b,b:e.b*t.a+e.d*t.b,c:e.a*t.c+e.c*t.d,d:e.b*t.c+e.d*t.d,tx:e.a*t.tx+e.c*t.ty+e.tx,ty:e.b*t.tx+e.d*t.ty+e.ty}}function Y(e){const t=e.position.x+(e.parent?e.parent.size.width*e.anchor.x:0),n=e.position.y+(e.parent?e.parent.size.height*e.anchor.y:0),o=e.size.width*e.origin.x,r=e.size.height*e.origin.y,i=Math.cos(e.rotation),s=Math.sin(e.rotation),a=i*e.scale.x,c=s*e.scale.x,l=-s*e.scale.y,d=i*e.scale.y;return{a:a,b:c,c:l,d:d,tx:t-(o*a+r*l),ty:n-(o*c+r*d)}}function $(e){if(0===e.length)return null;let t=1/0,n=1/0,o=-1/0,r=-1/0;for(const i of e)Number.isFinite(i.x)&&Number.isFinite(i.y)&&(t=Math.min(t,i.x),n=Math.min(n,i.y),o=Math.max(o,i.x),r=Math.max(r,i.y));return Number.isFinite(t)&&Number.isFinite(n)?{x:t,y:n,width:o-t,height:r-n}:null}function q(e){return"number"==typeof e&&Number.isFinite(e)&&e>0?e:null}function z(e){const t=e?.getSystem?.("Renderer"),n=t?.application?.screen,o=q(n?.width),r=q(n?.height);if(o&&r)return{width:o,height:r};const i=q(t?.params?.width),s=q(t?.params?.height);return i&&s?{width:i,height:s}:null}function K(e){const t=e?.getSystem?.("Renderer3DSystem");return t?.threeContext?.camera??null}function X(e,t){const n=e?.getSystem?.("Renderer3DSystem");return n?.threeContext?.nodes?.get?.(t)??null}function Z(e,t,n,o,r){return[e[0]*t+e[4]*n+e[8]*o+e[12]*r,e[1]*t+e[5]*n+e[9]*o+e[13]*r,e[2]*t+e[6]*n+e[10]*o+e[14]*r,e[3]*t+e[7]*n+e[11]*o+e[15]*r]}function H(e,t,n,o,r){const i=o.matrixWorldInverse?.elements,s=o.projectionMatrix?.elements;if(!i||i.length<16||!s||s.length<16)return null;if(r.width<=0||r.height<=0)return null;const a=Z(i,e,t,n,1),c=Z(s,a[0],a[1],a[2],a[3]);if(!Number.isFinite(c[3])||Math.abs(c[3])<1e-8)return null;if(c[3]<0)return null;const l=c[0]/c[3],d=c[1]/c[3],h=c[2]/c[3];return{x:.5*(l+1)*r.width,y:.5*(1-d)*r.height,depth:h}}function J(e,t,n,o){const r=e[3]*t+e[7]*n+e[11]*o+e[15],i=Math.abs(r)<1e-8?1:1/r;return[(e[0]*t+e[4]*n+e[8]*o+e[12])*i,(e[1]*t+e[5]*n+e[9]*o+e[13])*i,(e[2]*t+e[6]*n+e[10]*o+e[14])*i]}function Q(e,t){const n=Math.max(1,t);return{x:e.x-n/2,y:e.y-n/2,width:n,height:n}}function ee(e,t,n){const o=function(e){const t=[];let n=e;for(;n;)t.push(n),n=n.parent;t.reverse();let o={a:1,b:0,c:0,d:1,tx:0,ty:0};for(const e of t)o=U(o,Y(e));return o}(e),r=e.size.width,i=e.size.height,s=(r>0&&i>0?[{x:0,y:0},{x:r,y:0},{x:r,y:i},{x:0,y:i}]:[{x:0,y:0}]).map(e=>{return t=o,n=e.x,r=e.y,{x:t.a*n+t.c*r+t.tx,y:t.b*n+t.d*r+t.ty};var t,n,r}).map(e=>function(e,t,n){return!t||t.width<=0||t.height<=0?{x:e.x,y:e.y}:{x:e.x*(n.width/t.width),y:e.y*(n.height/t.height)}}(e,n,t)),a=$(s);if(a&&a.width>0&&a.height>0)return a;return Q(s[0]??{x:0,y:0},1)}function te(e,t,n,o){if(o){const e=function(e){const t=[],n=e=>{const n=e.geometry;if(!n)return;n.computeBoundingBox?.();const o=n.boundingBox,r=e.matrixWorld?.elements;if(!o||!r||r.length<16)return;const{min:i,max:s}=o;for(const e of[i.x,s.x])for(const n of[i.y,s.y])for(const o of[i.z,s.z])t.push(J(r,e,n,o))};return e.updateWorldMatrix?.(!0,!0),"function"==typeof e.traverse?e.traverse(n):n(e),t}(o),r=e.map(([e,o,r])=>H(e,o,r,t,n)).filter(e=>null!=e),i=$(r);if(i&&i.width>0&&i.height>0)return i}const r=H(e.worldPositionX??e.positionX??0,e.worldPositionY??e.positionY??0,e.worldPositionZ??e.positionZ??0,t,n);if(!r)return null;return Q(r,32*Math.max(Math.abs(e.scaleX??1),Math.abs(e.scaleY??1),Math.abs(e.scaleZ??1),1))}function ne(e,t){if(t.css.width<=0||t.css.height<=0)return null;const n=function(e){if(!e||"object"!=typeof e)return null;const t=e,n=[t.worldPositionX,t.worldPositionY,t.worldPositionZ].some(e=>"number"==typeof e&&Number.isFinite(e)),o=[t.positionX,t.positionY,t.positionZ].some(e=>"number"==typeof e&&Number.isFinite(e));return n||o?t:null}(e.getComponent("Transform3D"));return n&&t.camera?te(n,t.camera,t.css,t.object3D):ee(e.transform,t.css,t.design??null)}function oe(e,t,n){return t>=e.x&&n>=e.y&&t<=e.x+e.width&&n<=e.y+e.height}let re=class extends t.System{constructor(){super(...arguments),this.postMessageOrigin="*",this.allowedMessageOrigins=x(),this.enabled=!1,this.selected=null,this.overlay=null,this.overlayCss={width:0,height:0},this.pointerDownGoId=null,this.needsRescan=!1,this.mutedWithoutSoundSystem=!1,this.markerOverlayEnabled=!1,this.needsMarkerRescan=!1,this.markerOwners=new Set,this.onWindowSetPickMode=e=>{const t=e.detail;t&&"boolean"==typeof t.enabled&&this.setEnabled(t.enabled)},this.onWindowSetMarkerOverlay=e=>{const t=e.detail;t&&"boolean"==typeof t.enabled&&this.setMarkerOverlay(t.enabled)},this.onGameSetMarkerOverlay=e=>{e&&"boolean"==typeof e.enabled&&this.setMarkerOverlay(e.enabled)},this.onWindowMessage=e=>{if(!O(e.origin,this.allowedMessageOrigins))return;const t=e.data;t&&"object"==typeof t&&(t.type===o&&"boolean"==typeof t.enabled?this.setEnabled(t.enabled):t.type===d&&"boolean"==typeof t.enabled?this.setMarkerOverlay(t.enabled):t.type===i?this.requestSceneRescan():F(t)?this.clearSelectionAndNotify("parent-request"):t.type===l&&this.handleApplyProperty(t))},this.onGameSetPickMode=e=>{e&&"boolean"==typeof e.enabled&&this.setEnabled(e.enabled)},this.onGameRefresh=()=>{this.requestSceneRescan()},this.onWindowRefresh=()=>{this.requestSceneRescan()},this.onPointerDown=e=>{if(!this.enabled)return;e.preventDefault(),e.stopPropagation();try{this.overlay?.canvas.setPointerCapture(e.pointerId)}catch{}const t=this.hitTestPointer(e);this.pointerDownGoId=t?.id??null},this.onPointerUp=e=>{if(!this.enabled)return;e.preventDefault(),e.stopPropagation();const t=this.hitTestPointer(e);t&&t.id===this.pointerDownGoId&&this.onSelect(t,e),this.pointerDownGoId=null}}static{this.systemName="CombosDevelopmentToolSystem"}init(e){this.postMessageOrigin=e?.postMessageOrigin??"*",this.allowedMessageOrigins=x(e?.allowedMessageOrigins),this.overlay=M(),this.overlay&&(this.overlay.canvas.addEventListener("pointerdown",this.onPointerDown),this.overlay.canvas.addEventListener("pointerup",this.onPointerUp)),"undefined"!=typeof window&&(window.addEventListener(o,this.onWindowSetPickMode),window.addEventListener(d,this.onWindowSetMarkerOverlay),window.addEventListener(i,this.onWindowRefresh),window.addEventListener("message",this.onWindowMessage)),this.game.on(o,this.onGameSetPickMode),this.game.on(d,this.onGameSetMarkerOverlay),this.game.on(i,this.onGameRefresh),this.syncOverlayMode(),this.enabled&&(this.needsRescan=!0)}onDestroy(){this.overlay&&(this.overlay.canvas.removeEventListener("pointerdown",this.onPointerDown),this.overlay.canvas.removeEventListener("pointerup",this.onPointerUp),this.overlay.destroy(),this.overlay=null),"undefined"!=typeof window&&(window.removeEventListener(o,this.onWindowSetPickMode),window.removeEventListener(d,this.onWindowSetMarkerOverlay),window.removeEventListener(i,this.onWindowRefresh),window.removeEventListener("message",this.onWindowMessage)),this.game.off(o,this.onGameSetPickMode),this.game.off(d,this.onGameSetMarkerOverlay),this.game.off(i,this.onGameRefresh),this.markerOwners.clear(),this.clearSelectionAndNotify("pick-disabled")}setEnabled(e){this.enabled!==e&&(this.enabled=e,this.syncOverlayMode(),e?(this.needsRescan=!0,this.redrawOverlay()):(this.clearSelectionAndNotify("pick-disabled"),this.postSetSuccess(!1)))}get isEnabled(){return this.enabled}setMarkerOverlay(e){this.markerOverlayEnabled!==e&&(this.markerOverlayEnabled=e,this.syncOverlayMode(),e?this.needsMarkerRescan=!0:(this.markerOwners.clear(),this.postMarkerOverlaySuccess(!1,[]),this.redrawOverlay()))}get isMarkerOverlayEnabled(){return this.markerOverlayEnabled}get isMuted(){const e=this.getSoundSystem();return e?e.muted:this.mutedWithoutSoundSystem}setMuted(e){const t=this.getSoundSystem();t?t.muted=e:this.mutedWithoutSoundSystem=e}update(){this.enabled&&this.needsRescan&&(this.needsRescan=!1,this.postSetSuccess(!0)),this.markerOverlayEnabled&&this.needsMarkerRescan&&(this.needsMarkerRescan=!1,this.attachMarkers()),this.selected?.destroyed&&this.clearSelectionAndNotify("target-removed")}lateUpdate(e){this.redrawOverlay()}componentChanged(e){const{type:n,gameObject:o,componentName:r}=e;o&&"CombosDevelopmentToolTarget"===r&&(n===t.OBSERVER_TYPE.REMOVE&&this.selected===o&&this.clearSelectionAndNotify("target-removed"),this.markerOverlayEnabled&&(this.needsMarkerRescan=!0))}requestSceneRescan(){this.enabled&&(this.needsRescan=!0),this.markerOverlayEnabled&&(this.needsMarkerRescan=!0)}syncOverlayMode(){const e=this.enabled||this.markerOverlayEnabled;this.overlay?.setVisible(e),this.overlay?.setPickEnabled(this.enabled)}collectGameObjects(e,t){t.push(e);for(const n of e.transform.children)this.collectGameObjects(n.gameObject,t)}listSceneObjects(){const e=[],t=this.game.scene;if(!t?.transform?.children)return e;for(const n of t.transform.children)this.collectGameObjects(n.gameObject,e);return e}isIgnoredPickGo(e){return"__combosDevelopmentToolOutline"===e.name||this.isMarkerGo(e)}isMarkerGo(e){return"string"==typeof e.name&&e.name.startsWith("__combosDevelopmentToolMarker:")}projectGo(e){return ne(e,{css:this.overlayCss,design:z(this.game),camera:K(this.game),object3D:X(this.game,e.id)})}collectOverlayHits(){const e=[];for(const t of this.listSceneObjects()){if(t.destroyed||this.isIgnoredPickGo(t))continue;if(!t.getComponent(u))continue;const n=this.projectGo(t);if(n&&e.push({go:t,rect:n}),this.markerOverlayEnabled&&g(t)){const o=this.markerRectFor(t,n);o&&e.push({go:t,rect:o})}}return e}markerRectFor(e,t){const n=t??this.projectGo(e);return n?e.getComponent("Transform3D")?{x:n.x+n.width/2-14,y:n.y+n.height/2-14,width:y,height:y}:{x:n.x,y:n.y,width:y,height:y}:null}overlayPoint(e){const t=this.overlay?.canvas;if(!t)return{x:0,y:0};const n=t.getBoundingClientRect();return{x:e.clientX-n.left,y:e.clientY-n.top}}hitTestPointer(e){const t=this.overlayPoint(e),n=this.collectOverlayHits();return function(e,t,n){let o=null;for(let r=0;r<n.length;r++){const i=n[r];if(!oe(i.rect,e,t))continue;const s=Math.max(i.rect.width,0)*Math.max(i.rect.height,0);(!o||s<o.area||s===o.area&&r>o.index)&&(o={id:i.id,area:s,index:r})}return o?o.id:null}(t.x,t.y,n.map(e=>({id:e.go,rect:e.rect})))}redrawOverlay(){const e=this.overlay;if(!e)return;if(!(this.enabled||this.markerOverlayEnabled))return void e.setVisible(!1);const t=this.game.canvas??this.game.scene?.canvas;if(!t)return;const n=e.sync(t);n&&(this.overlayCss=n,e.ctx.clearRect(0,0,n.width,n.height),this.drawMarkers(e.ctx),this.drawSelectionOutline(e.ctx))}drawMarkers(e){if(!this.markerOverlayEnabled)return;const t=new m(e);for(const n of this.listSceneObjects()){if(n.destroyed||this.isIgnoredPickGo(n))continue;const o=g(n);if(!o)continue;const r=this.projectGo(n),i=this.markerRectFor(n,r);i&&(e.save(),e.translate(i.x,i.y),v(t,o,y),e.restore())}}drawSelectionOutline(e){if(!this.enabled||!this.selected||this.selected.destroyed)return;const t=this.projectGo(this.selected);if(!t)return;const n=z(this.game),o=n?this.overlayCss.width/n.width:1;e.save(),e.strokeStyle="#55ffaa",e.lineWidth=Math.max(2,4*(Number.isFinite(o)&&o>0?o:1)),e.strokeRect(t.x,t.y,t.width,t.height),e.restore()}postSetSuccess(e){const t={type:r,enabled:e};"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(t,this.postMessageOrigin),this.game.emit(r,{enabled:e})}attachMarkers(){this.markerOwners.clear();const e=new Map;for(const t of this.listSceneObjects()){if(this.isIgnoredPickGo(t))continue;const n=g(t);n&&(this.markerOwners.add(t.id),e.set(n.componentName,(e.get(n.componentName)??0)+1))}const t=[...e.entries()].map(([e,t])=>({componentName:e,count:t}));this.postMarkerOverlaySuccess(!0,t),this.redrawOverlay()}postMarkerOverlaySuccess(e,t){const n={enabled:e,total:t.reduce((e,t)=>e+t.count,0),markers:t},o={type:h,...n};"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(o,this.postMessageOrigin),this.game.emit(h,n)}getSoundSystem(){const e=this.game.getSystem("SoundSystem");return e&&"object"==typeof e&&"muted"in e&&"boolean"==typeof e.muted?e:null}onSelect(e,t){if(!this.enabled)return;this.selected=e,this.redrawOverlay();const n=this.overlayPoint(t),o=(r=n,i=z(this.game),a=this.overlayCss,!i||i.width<=0||i.height<=0||a.width<=0||a.height<=0?{x:r.x,y:r.y}:{x:r.x*(i.width/a.width),y:r.y*(i.height/a.height)});var r,i,a;const c=L(e),l={type:s,snapshot:c,pointer:o};"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(l,this.postMessageOrigin)}findGameObjectById(e){return this.listSceneObjects().find(t=>t.id===e)??null}findGameObjectBySource(e){const t=e.file.trim(),n=(e.anchor??"").trim();if(!n)return null;for(const e of this.listSceneObjects()){const o=j(e);if(!o||o.file!==t)continue;if((o.anchor??e.name)===n)return e}return null}resolveApplyTarget(e){if("number"==typeof e.gameObjectId){const t=this.findGameObjectById(e.gameObjectId);if(t)return t}const t=e.source?.file?.trim(),n=e.source?.anchor?.trim();return t&&n?this.findGameObjectBySource({file:t,anchor:n}):null}handleApplyProperty(e){const t=e.componentName,n=e.path,o="number"==typeof e.gameObjectId,r=Boolean(e.source?.file?.trim())&&Boolean(e.source?.anchor?.trim());if(!o&&!r||"string"!=typeof t||!Array.isArray(n)||0===n.length)return;const i=this.resolveApplyTarget(e);if(!i)return;I(i,t,n,e.value)&&this.selected?.id===i.id&&(this.redrawOverlay(),this.postSnapshotUpdate(i))}postSnapshotUpdate(e){const t=L(e);"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage({type:s,snapshot:t,pointer:null,source:"property-applied"},this.postMessageOrigin)}clearSelectionAndNotify(e){const t=null!=this.selected;this.selected=null,this.redrawOverlay(),t&&this.postGameObjectDeselected(e)}postGameObjectDeselected(e){const t=W(e);"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(t,this.postMessageOrigin),this.game.emit(t.type,{reason:e})}};re=e.__decorate([t.decorators.componentObserver({CombosDevelopmentToolTarget:[]})],re);var ie=re;Object.assign(ie,{packageName:"@combos-fun/plugin-development-tool",packageVersion:"0.0.53"}),exports.COMBOS_DEVELOPMENT_TOOL_APPLY_PROPERTY=l,exports.COMBOS_DEVELOPMENT_TOOL_CLEAR_SELECTION=a,exports.COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_DESELECTED=c,exports.COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED=s,exports.COMBOS_DEVELOPMENT_TOOL_MARKER_OVERLAY_SUCCESS=h,exports.COMBOS_DEVELOPMENT_TOOL_PICK_MODE_SUCCESS=r,exports.COMBOS_DEVELOPMENT_TOOL_READY="combos-development-tool:ready",exports.COMBOS_DEVELOPMENT_TOOL_REFRESH=i,exports.COMBOS_DEVELOPMENT_TOOL_SET_MARKER_OVERLAY=d,exports.COMBOS_DEVELOPMENT_TOOL_SET_MUTED="combos-development-tool:set-muted",exports.COMBOS_DEVELOPMENT_TOOL_SET_PICK_MODE=o,exports.COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED="combos-development-tool:state-changed",exports.CombosDevelopmentToolSystem=ie,exports.CombosDevelopmentToolTarget=u,exports.DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES=w,exports.MARKER_COMPONENTS=f,exports.MARKER_ICON_SIZE=y,exports.applyPropertyValue=N,exports.applyPropertyWithHooks=I,exports.attachDevelopmentTarget=function(e,t){if(!e||e.destroyed||function(e){return"string"==typeof e.name&&e.name.startsWith("__")}(e)||function(e){return Array.isArray(e.gameObjects)}(e))return e;const n=t.file.trim(),o=t.anchor.trim();if(!n||!o)return e;const r=e.getComponent(u);return r?(i=r.payload?.source,E(i)&&Boolean(i.file.trim())&&Boolean((i.anchor??"").trim())||(r.payload={...r.payload??{},source:{file:n,anchor:o}}),e):(e.addComponent(new u({payload:{source:{file:n,anchor:o}}})),e);var i},exports.buildGameObjectDeselectedPayload=W,exports.buildGameObjectSnapshot=L,exports.drawMarkerIcon=v,exports.isAllowedMessageOrigin=O,exports.isClearSelectionMessage=F,exports.mergeAllowedMessageOrigins=x,exports.readPropertyValue=function(e,t,n){const o=e.getComponent(t);if(!o||!n.length)return;let r=o;for(const e of n){if(null==r||"object"!=typeof r)return;r=r[e]}return r},exports.readSourceAnchor=j,exports.resolveMarkerDef=g,exports.shouldNotifyGameObjectDeselected=V;
1
+ "use strict";var e=require("tslib"),t=require("@combos-fun/engine"),n=require("@combos-fun/inspector-decorator");const o="combos-development-tool:set-pick-mode",i="combos-development-tool:pick-mode-success",r="combos-development-tool:refresh",s="combos-development-tool:gameobject-selected",a="combos-development-tool:clear-selection",c="combos-development-tool:gameobject-deselected",l="combos-development-tool:apply-property",h="combos-development-tool:set-marker-overlay",d="combos-development-tool:marker-overlay-success";class u extends t.Component{constructor(){super(...arguments),this.payload={}}static{this.componentName="CombosDevelopmentToolTarget"}init(e){this.payload=e?.payload?{...e.payload}:{}}}function p(e,t=1){return`rgba(${e>>16&255}, ${e>>8&255}, ${255&e}, ${t})`}class m{constructor(e){this.ctx=e}clear(){this.ctx.beginPath()}roundRect(e,t,n,o,i=0){const r=this.ctx;if("function"==typeof r.roundRect)return void r.roundRect(e,t,n,o,i);const s=Math.max(0,Math.min(i,Math.min(n,o)/2));r.moveTo(e+s,t),r.lineTo(e+n-s,t),r.quadraticCurveTo(e+n,t,e+n,t+s),r.lineTo(e+n,t+o-s),r.quadraticCurveTo(e+n,t+o,e+n-s,t+o),r.lineTo(e+s,t+o),r.quadraticCurveTo(e,t+o,e,t+o-s),r.lineTo(e,t+s),r.quadraticCurveTo(e,t,e+s,t),r.closePath()}rect(e,t,n,o){this.ctx.rect(e,t,n,o)}circle(e,t,n){this.ctx.moveTo(e+n,t),this.ctx.arc(e,t,n,0,2*Math.PI)}poly(e,t=!0){if(!(e.length<4)){this.ctx.moveTo(e[0],e[1]);for(let t=2;t<e.length;t+=2)this.ctx.lineTo(e[t],e[t+1]);t&&this.ctx.closePath()}}fill(e){this.ctx.fillStyle=p(e.color,e.alpha??1),this.ctx.fill(),this.ctx.beginPath()}stroke(e){this.ctx.strokeStyle=p(e.color,e.alpha??1),this.ctx.lineWidth=e.width,this.ctx.stroke(),this.ctx.beginPath()}}const f=[{componentName:"Sound",badgeColor:9133302,glyph:"speaker"}],y=28;function g(e,t=f){for(const n of t)if(e.getComponent(n.componentName))return n;return null}const b=16777215;function w(e,t,n=28){if(function(e,t,n){e.clear(),e.roundRect(0,0,n,n,.22*n),e.fill({color:t.badgeColor,alpha:.92}),e.roundRect(0,0,n,n,.22*n),e.stroke({width:Math.max(1,.05*n),color:16777215,alpha:.6})}(e,t,n),"speaker"===t.glyph)!function(e,t){e.poly([.28*t,.4*t,.42*t,.4*t,.55*t,.26*t,.55*t,.74*t,.42*t,.6*t,.28*t,.6*t]),e.fill({color:b,alpha:.96}),e.rect(.62*t,.44*t,.045*t,.12*t),e.fill({color:b,alpha:.96}),e.rect(.71*t,.39*t,.045*t,.22*t),e.fill({color:b,alpha:.96})}(e,n);else!function(e,t){e.circle(.5*t,.5*t,.18*t),e.fill({color:b,alpha:.96})}(e,n)}const v=["knoffice.tech","converge.ai"];function O(e,t){if(t.includes("*"))return!0;if(0===t.length)return!1;let n;try{n=new URL(e)}catch{return!1}const o=e.toLowerCase(),i=n.hostname.toLowerCase();for(const e of t){const t=e.trim();if(!t)continue;if(t.includes("://")){if(o===t.toLowerCase())return!0;continue}const n=t.toLowerCase().replace(/^\./,"");if(i===n||i.endsWith(`.${n}`))return!0}return!1}function x(e){if(!e?.length)return[...v];if(e.includes("*"))return["*"];const t=new Set,n=[];for(const o of[...v,...e]){const e=o.trim();e&&!t.has(e)&&(t.add(e),n.push(e))}return n}function M(){if("undefined"==typeof document)return null;const e=document.createElement("canvas");e.setAttribute("data-combos-development-tool-overlay","true"),e.style.position="fixed",e.style.left="0",e.style.top="0",e.style.width="0",e.style.height="0",e.style.margin="0",e.style.padding="0",e.style.border="0",e.style.background="transparent",e.style.pointerEvents="none",e.style.touchAction="none",e.style.userSelect="none",e.style.zIndex="2147483000",e.style.display="none";const t=e.getContext("2d");if(!t)return null;let n=!1,o=!1;return{canvas:e,ctx:t,sync:n=>{!function(e,t){const n=document.body;n&&t.parentElement!==n&&n.appendChild(t)}(0,e);const i=n.getBoundingClientRect();if(i.width<=0||i.height<=0)return e.style.display="none",null;e.style.display=o?"block":"none",e.style.left=`${i.left}px`,e.style.top=`${i.top}px`,e.style.width=`${i.width}px`,e.style.height=`${i.height}px`;const r="undefined"!=typeof window&&window.devicePixelRatio||1,s=Math.max(1,Math.round(i.width*r)),a=Math.max(1,Math.round(i.height*r));return e.width===s&&e.height===a||(e.width=s,e.height=a),t.setTransform(r,0,0,r,0,0),{width:i.width,height:i.height}},setPickEnabled(t){n=t,e.style.pointerEvents=n?"auto":"none",e.style.cursor=n?"crosshair":"default"},setVisible(t){o=t,e.style.display=t?"block":"none"},destroy(){e.remove()}}}function E(e){return!!e&&"object"==typeof e&&"string"==typeof e.file}function S(e){return"string"==typeof e?"string":"number"==typeof e?"number":"boolean"==typeof e?"boolean":null!==e&&"object"==typeof e?"object":"unsupported"}function k(e,t=0){if(null==e)return e;if("number"==typeof e||"string"==typeof e||"boolean"==typeof e)return e;if(!(t>6)){if(Array.isArray(e))return e.map(e=>k(e,t+1));if("object"==typeof e){const n={};for(const[o,i]of Object.entries(e)){if("function"==typeof i)continue;const e=k(i,t+1);void 0!==e&&(n[o]=e)}return n}}}function T(e){const t=e.constructor,o=function(e){const t=Reflect.getMetadata(n.IDE_PROPERTY_METADATA,e)||{};return Object.keys(t).map(e=>({key:e,...t[e]}))}(t);return o.length>0?o:function(e){const t=e.IDEProps;return!t||Array.isArray(t)||"object"!=typeof t?[]:Object.keys(t).map(e=>{const n=t[e]||{};return{key:e,type:"string"==typeof n.type?n.type:void 0,step:"number"==typeof n.step?n.step:void 0,min:"number"==typeof n.min?n.min:void 0,max:"number"==typeof n.max?n.max:void 0,label:"string"==typeof n.label?n.label:void 0,description:"string"==typeof n.description?n.description:void 0,group:"string"==typeof n.group?n.group:void 0,editor:n.editor,enumOptions:Array.isArray(n.enumOptions)?n.enumOptions:void 0,unit:"string"==typeof n.unit?n.unit:void 0}})}(t)}function P(e,t){return e.editor?e.editor:"boolean"===t?"toggle":e.enumOptions?.length&&"string"===t?"enum":"number"===t?void 0!==e.min&&void 0!==e.max?"number-slider":"number-stepper":"string"===t?"text":void 0}function C(e){if(void 0!==e.min||void 0!==e.max||void 0!==e.step||void 0!==e.unit)return{min:e.min,max:e.max,step:e.step,unit:e.unit}}function D(e,t){if(e.label?.trim())return e.label.trim();const n=t[t.length-1];return n?function(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/_/g," ").replace(/^./,e=>e.toUpperCase())}(n):void 0}function _(e,t,n,o){const i=t.description?.trim();if(!i)return[];const r=S(o);if("unsupported"===r)return[];const s=t.type,a="size"===s||"object"===r&&null!==o&&"width"in o&&"height"in o;if("vector2"===s||"object"===r&&null!==o&&"x"in o&&"y"in o||a){const r=o,s=a?["width","height"]:["x","y"],c=D(t,n)??e,l=[];for(const o of s){const s=r[o],a=S(s);if("unsupported"===a||"object"===a)continue;const h=[...n,o];l.push({path:h,value:s,valueType:a,label:`${c} ${o.toUpperCase()}`,description:i,group:t.group??e,editorKind:P(t,a),numberMeta:C(t),persistTarget:"component"})}return l}if("object"===r)return[];const c=D(t,n);return c?[{path:n,value:k(o),valueType:r,label:c,description:i,group:t.group??e,editorKind:P(t,r),enumOptions:t.enumOptions,numberMeta:C(t),persistTarget:"component"}]:[]}function R(e){const t=e.name,n=T(e);if(0===n.length)return[];const o=[],i=e;for(const e of n){const n=i[e.key];"function"!=typeof n&&o.push(..._(t,e,[e.key],n))}return o}function L(e){const t=e.getComponent(u),n=t?.payload?.source;if(E(n))return{file:n.file,anchor:n.anchor??e.name}}function j(e){const t=e.components.filter(e=>"CombosDevelopmentToolTarget"!==e.name).map(e=>({componentName:e.name,fieldDescriptors:R(e)})).filter(e=>e.fieldDescriptors.length>0);return{id:e.id,name:e.name,components:t,source:L(e)}}function N(e,t,n,o){const i=e.getComponent(t);if(!i||!n.length)return!1;let r=i;for(let e=0;e<n.length-1;e++){const t=n[e];void 0!==r[t]&&null!==r[t]||(r[t]={}),r=r[t]}return r[n[n.length-1]]=o,!0}const A=new Set(["position","size","origin","anchor","scale","skew"]);function G(e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e&&""!==e.trim()){const t=Number(e);return Number.isFinite(t)?t:void 0}}const I={Transform2D:function(e,t,n,o){const i=e.getComponent("Transform2D");if(!i)return!1;const r=i;if(1===n.length&&"rotation"===n[0]){const e=G(o);return void 0!==e&&(i.rotation=e,!0)}if(2===n.length&&A.has(n[0])){const t=n[0],i=n[1],s=G(o);if(void 0===s)return!1;const a=r[t];return!(!a||"object"!=typeof a)&&(a[i]=s,"position"===t&&(function(e){const t=e.getComponent("Physics");if(!t?.body)return;const n=e.getComponent("Transform2D");if(!n)return;const{x:o,y:i}=n.position;t.Body?.setPosition?t.Body.setPosition(t.body,{x:o,y:i}):(t.body.position.x=o,t.body.position.y=i)}(e),function(e){const t=e.getComponent("PlatformerMover");if(!t)return;const n=e.getComponent("Transform2D");n&&(t.originX=n.position.x,t.originY=n.position.y)}(e)),!0)}return!1},Text:function(e,t,n,o){const i=t;if(1===n.length&&"text"===n[0])return i.text=String(o??""),!0;if(2===n.length&&"style"===n[0]){const e=n[1],t={...i.style??{},[e]:o};return i.style=t,!0}return!1},Sound:function(e,t,n,o){const i=t;if(1===n.length&&"volume"===n[0]||2===n.length&&"config"===n[0]&&"volume"===n[1]){const e=G(o);return void 0!==e&&(i.volume=e,!0)}return!1}};function B(e,t,n,o){const i=e.getComponent(t);if(!i||!n.length)return!1;const r=I[t];return!!r?.(e,i,n,o)||N(e,t,n,o)}function W(e){return{type:c,reason:e}}function V(e){return e}function F(e){return!(!e||"object"!=typeof e)&&e.type===a}function Y(e,t){return{a:e.a*t.a+e.c*t.b,b:e.b*t.a+e.d*t.b,c:e.a*t.c+e.c*t.d,d:e.b*t.c+e.d*t.d,tx:e.a*t.tx+e.c*t.ty+e.tx,ty:e.b*t.tx+e.d*t.ty+e.ty}}function z(e){const t=e.position.x+(e.parent?e.parent.size.width*e.anchor.x:0),n=e.position.y+(e.parent?e.parent.size.height*e.anchor.y:0),o=e.size.width*e.origin.x,i=e.size.height*e.origin.y,r=Math.cos(e.rotation),s=Math.sin(e.rotation),a=r*e.scale.x,c=s*e.scale.x,l=-s*e.scale.y,h=r*e.scale.y;return{a:a,b:c,c:l,d:h,tx:t-(o*a+i*l),ty:n-(o*c+i*h)}}function U(e){if(0===e.length)return null;let t=1/0,n=1/0,o=-1/0,i=-1/0;for(const r of e)Number.isFinite(r.x)&&Number.isFinite(r.y)&&(t=Math.min(t,r.x),n=Math.min(n,r.y),o=Math.max(o,r.x),i=Math.max(i,r.y));return Number.isFinite(t)&&Number.isFinite(n)?{x:t,y:n,width:o-t,height:i-n}:null}function $(e){return"number"==typeof e&&Number.isFinite(e)&&e>0?e:null}function q(e){const t=e?.getSystem?.("Renderer"),n=t?.application?.screen,o=$(n?.width),i=$(n?.height);if(o&&i)return{width:o,height:i};const r=$(t?.params?.width),s=$(t?.params?.height);return r&&s?{width:r,height:s}:null}function X(e){const t=e?.getSystem?.("Renderer3DSystem");return t?.threeContext?.camera??null}function K(e,t){const n=e?.getSystem?.("Renderer3DSystem");return n?.threeContext?.nodes?.get?.(t)??null}function Z(e,t,n,o,i){return[e[0]*t+e[4]*n+e[8]*o+e[12]*i,e[1]*t+e[5]*n+e[9]*o+e[13]*i,e[2]*t+e[6]*n+e[10]*o+e[14]*i,e[3]*t+e[7]*n+e[11]*o+e[15]*i]}function H(e,t,n,o,i){const r=o.matrixWorldInverse?.elements,s=o.projectionMatrix?.elements;if(!r||r.length<16||!s||s.length<16)return null;if(i.width<=0||i.height<=0)return null;const a=Z(r,e,t,n,1),c=Z(s,a[0],a[1],a[2],a[3]);if(!Number.isFinite(c[3])||Math.abs(c[3])<1e-8)return null;if(c[3]<0)return null;const l=c[0]/c[3],h=c[1]/c[3],d=c[2]/c[3];return{x:.5*(l+1)*i.width,y:.5*(1-h)*i.height,depth:d}}function J(e,t,n,o){const i=e[3]*t+e[7]*n+e[11]*o+e[15],r=Math.abs(i)<1e-8?1:1/i;return[(e[0]*t+e[4]*n+e[8]*o+e[12])*r,(e[1]*t+e[5]*n+e[9]*o+e[13])*r,(e[2]*t+e[6]*n+e[10]*o+e[14])*r]}function Q(e,t){const n=Math.max(1,t);return{x:e.x-n/2,y:e.y-n/2,width:n,height:n}}function ee(e,t,n){const o=function(e){const t=[];let n=e;for(;n;)t.push(n),n=n.parent;t.reverse();let o={a:1,b:0,c:0,d:1,tx:0,ty:0};for(const e of t)o=Y(o,z(e));return o}(e),i=e.size.width,r=e.size.height,s=(i>0&&r>0?[{x:0,y:0},{x:i,y:0},{x:i,y:r},{x:0,y:r}]:[{x:0,y:0}]).map(e=>{return t=o,n=e.x,i=e.y,{x:t.a*n+t.c*i+t.tx,y:t.b*n+t.d*i+t.ty};var t,n,i}).map(e=>function(e,t,n){return!t||t.width<=0||t.height<=0?{x:e.x,y:e.y}:{x:e.x*(n.width/t.width),y:e.y*(n.height/t.height)}}(e,n,t)),a=U(s);if(a&&a.width>0&&a.height>0)return a;return Q(s[0]??{x:0,y:0},1)}function te(e,t,n,o){if(o){const e=function(e){const t=[],n=e=>{const n=e.geometry;if(!n)return;n.computeBoundingBox?.();const o=n.boundingBox,i=e.matrixWorld?.elements;if(!o||!i||i.length<16)return;const{min:r,max:s}=o;for(const e of[r.x,s.x])for(const n of[r.y,s.y])for(const o of[r.z,s.z])t.push(J(i,e,n,o))};return e.updateWorldMatrix?.(!0,!0),"function"==typeof e.traverse?e.traverse(n):n(e),t}(o),i=e.map(([e,o,i])=>H(e,o,i,t,n)).filter(e=>null!=e),r=U(i);if(r&&r.width>0&&r.height>0)return r}const i=H(e.worldPositionX??e.positionX??0,e.worldPositionY??e.positionY??0,e.worldPositionZ??e.positionZ??0,t,n);if(!i)return null;return Q(i,32*Math.max(Math.abs(e.scaleX??1),Math.abs(e.scaleY??1),Math.abs(e.scaleZ??1),1))}function ne(e){const t=function(e){if(!e||"object"!=typeof e)return null;const t=e;return t.position&&t.size?{position:t.position,size:t.size,origin:t.origin??{x:0,y:0},anchor:t.anchor??{x:0,y:0},scale:t.scale??{x:1,y:1},skew:t.skew??{x:0,y:0},rotation:t.rotation??0}:null}(e.getComponent("Transform2D"));if(!t)return null;const n=e.parent&&e.parent!==e.scene?e.parent:null;return{...t,parent:n?ne(n):null}}function oe(e,t){if(t.css.width<=0||t.css.height<=0)return null;const n=function(e){if(!e||"object"!=typeof e)return null;const t=e,n=[t.worldPositionX,t.worldPositionY,t.worldPositionZ].some(e=>"number"==typeof e&&Number.isFinite(e)),o=[t.positionX,t.positionY,t.positionZ].some(e=>"number"==typeof e&&Number.isFinite(e));return n||o?t:null}(e.getComponent("Transform3D"));if(n&&t.camera)return te(n,t.camera,t.css,t.object3D);const o=ne(e);return o?ee(o,t.css,t.design??null):null}function ie(e,t,n){return t>=e.x&&n>=e.y&&t<=e.x+e.width&&n<=e.y+e.height}const re=["Img","Sprite","TilingSprite","NinePatch","Text","Graphics","SpriteAnimation","Img3D","Sprite3D","TilingSprite3D","Text3D","Graphics3D","Model3D","SpriteAnimation3D"];function se(e,t,n=.75){if(!t||t.width<=0||t.height<=0)return!1;const o=t.width*t.height;return!(o<=0)&&function(e,t){const n=Math.min(e.x+e.width,t.x+t.width)-Math.max(e.x,t.x),o=Math.min(e.y+e.height,t.y+t.height)-Math.max(e.y,t.y);return n<=0||o<=0?0:n*o}(e,{x:0,y:0,width:t.width,height:t.height})/o>=n}function ae(e){const t=e.getComponent("Render"),n=e.getComponent("Render3D"),o=!1!==t?.visible&&!1!==n?.visible,i=Math.min("number"==typeof t?.alpha&&Number.isFinite(t.alpha)?t.alpha:1,"number"==typeof n?.opacity&&Number.isFinite(n.opacity)?n.opacity:1);let r=0;return!o||i<=0?r+=2:i<=.35&&(r+=1),function(e){return re.some(t=>Boolean(e.getComponent(t)))}(e)||(r+=1),r}function ce(e,t){return e.score!==t.score?e.score<t.score:e.covering!==t.covering?!e.covering:e.covering?e.index<t.index:e.area!==t.area?e.area<t.area:e.index>t.index}let le=class extends t.System{constructor(){super(...arguments),this.postMessageOrigin="*",this.allowedMessageOrigins=x(),this.enabled=!1,this.selected=null,this.overlay=null,this.overlayCss={width:0,height:0},this.pointerDownGoId=null,this.pickListening=!1,this.needsRescan=!1,this.mutedWithoutSoundSystem=!1,this.markerOverlayEnabled=!1,this.needsMarkerRescan=!1,this.markerOwners=new Set,this.onWindowSetPickMode=e=>{const t=e.detail;t&&"boolean"==typeof t.enabled&&this.setEnabled(t.enabled)},this.onWindowSetMarkerOverlay=e=>{const t=e.detail;t&&"boolean"==typeof t.enabled&&this.setMarkerOverlay(t.enabled)},this.onGameSetMarkerOverlay=e=>{e&&"boolean"==typeof e.enabled&&this.setMarkerOverlay(e.enabled)},this.onWindowMessage=e=>{if(!O(e.origin,this.allowedMessageOrigins))return;const t=e.data;t&&"object"==typeof t&&(t.type===o&&"boolean"==typeof t.enabled?this.setEnabled(t.enabled):t.type===h&&"boolean"==typeof t.enabled?this.setMarkerOverlay(t.enabled):t.type===r?this.requestSceneRescan():F(t)?this.clearSelectionAndNotify("parent-request"):t.type===l&&this.handleApplyProperty(t))},this.onGameSetPickMode=e=>{e&&"boolean"==typeof e.enabled&&this.setEnabled(e.enabled)},this.onGameRefresh=()=>{this.requestSceneRescan()},this.onWindowRefresh=()=>{this.requestSceneRescan()},this.onPointerDown=e=>{if(!this.enabled||!this.isPickPointInGame(e))return;e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();try{this.overlay?.canvas.setPointerCapture(e.pointerId)}catch{}const t=this.hitTestPointer(e);this.pointerDownGoId=t?.id??null},this.onPointerUp=e=>{if(!this.enabled)return;if(!this.isPickPointInGame(e))return void(this.pointerDownGoId=null);e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation();const t=this.hitTestPointer(e);t&&t.id===this.pointerDownGoId&&this.onSelect(t,e),this.pointerDownGoId=null}}static{this.systemName="CombosDevelopmentToolSystem"}init(e){this.postMessageOrigin=e?.postMessageOrigin??"*",this.allowedMessageOrigins=x(e?.allowedMessageOrigins),this.overlay=M(),"undefined"!=typeof window&&(window.addEventListener(o,this.onWindowSetPickMode),window.addEventListener(h,this.onWindowSetMarkerOverlay),window.addEventListener(r,this.onWindowRefresh),window.addEventListener("message",this.onWindowMessage)),this.game.on(o,this.onGameSetPickMode),this.game.on(h,this.onGameSetMarkerOverlay),this.game.on(r,this.onGameRefresh),this.syncOverlayMode(),this.enabled&&(this.needsRescan=!0)}onDestroy(){this.unbindPickListeners(),this.overlay&&(this.overlay.destroy(),this.overlay=null),"undefined"!=typeof window&&(window.removeEventListener(o,this.onWindowSetPickMode),window.removeEventListener(h,this.onWindowSetMarkerOverlay),window.removeEventListener(r,this.onWindowRefresh),window.removeEventListener("message",this.onWindowMessage)),this.game.off(o,this.onGameSetPickMode),this.game.off(h,this.onGameSetMarkerOverlay),this.game.off(r,this.onGameRefresh),this.markerOwners.clear(),this.clearSelectionAndNotify("pick-disabled")}setEnabled(e){this.enabled!==e&&(this.enabled=e,this.syncOverlayMode(),e?(this.needsRescan=!0,this.redrawOverlay()):(this.clearSelectionAndNotify("pick-disabled"),this.postSetSuccess(!1)))}get isEnabled(){return this.enabled}setMarkerOverlay(e){this.markerOverlayEnabled!==e&&(this.markerOverlayEnabled=e,this.syncOverlayMode(),e?this.needsMarkerRescan=!0:(this.markerOwners.clear(),this.postMarkerOverlaySuccess(!1,[]),this.redrawOverlay()))}get isMarkerOverlayEnabled(){return this.markerOverlayEnabled}get isMuted(){const e=this.getSoundSystem();return e?e.muted:this.mutedWithoutSoundSystem}setMuted(e){const t=this.getSoundSystem();t?t.muted=e:this.mutedWithoutSoundSystem=e}update(){this.enabled&&this.needsRescan&&(this.needsRescan=!1,this.postSetSuccess(!0)),this.markerOverlayEnabled&&this.needsMarkerRescan&&(this.needsMarkerRescan=!1,this.attachMarkers()),this.selected?.destroyed&&this.clearSelectionAndNotify("target-removed")}lateUpdate(e){this.redrawOverlay()}componentChanged(e){const{type:n,gameObject:o,componentName:i}=e;o&&"CombosDevelopmentToolTarget"===i&&(n===t.OBSERVER_TYPE.REMOVE&&this.selected===o&&this.clearSelectionAndNotify("target-removed"),this.markerOverlayEnabled&&(this.needsMarkerRescan=!0))}requestSceneRescan(){this.enabled&&(this.needsRescan=!0),this.markerOverlayEnabled&&(this.needsMarkerRescan=!0)}syncOverlayMode(){const e=this.enabled||this.markerOverlayEnabled;this.overlay?.setVisible(e),this.overlay?.setPickEnabled(this.enabled),this.enabled?this.bindPickListeners():this.unbindPickListeners()}bindPickListeners(){this.pickListening||"undefined"==typeof window||(window.addEventListener("pointerdown",this.onPointerDown,!0),window.addEventListener("pointerup",this.onPointerUp,!0),this.pickListening=!0)}unbindPickListeners(){this.pickListening&&"undefined"!=typeof window&&(window.removeEventListener("pointerdown",this.onPointerDown,!0),window.removeEventListener("pointerup",this.onPointerUp,!0),this.pickListening=!1)}isPickPointInGame(e){const t=this.game.canvas??this.game.scene?.canvas??this.overlay?.canvas;if(!t)return!1;const n=t.getBoundingClientRect();return n.width>0&&n.height>0&&e.clientX>=n.left&&e.clientX<=n.right&&e.clientY>=n.top&&e.clientY<=n.bottom}collectGameObjects(e,t){t.push(e);for(const n of e.children)this.collectGameObjects(n,t)}listSceneObjects(){const e=[],t=this.game.scene;if(!t?.children)return e;for(const n of t.children)this.collectGameObjects(n,e);return e}isIgnoredPickGo(e){return"__combosDevelopmentToolOutline"===e.name||this.isMarkerGo(e)}isMarkerGo(e){return"string"==typeof e.name&&e.name.startsWith("__combosDevelopmentToolMarker:")}projectGo(e){return oe(e,{css:this.overlayCss,design:q(this.game),camera:X(this.game),object3D:K(this.game,e.id)})}collectOverlayHits(){const e=[];for(const t of this.listSceneObjects()){if(t.destroyed||this.isIgnoredPickGo(t))continue;if(!t.getComponent(u))continue;const n=this.projectGo(t),o=ae(t);if(n&&e.push({go:t,rect:n,passThrough:o}),this.markerOverlayEnabled&&g(t)){const i=this.markerRectFor(t,n);i&&e.push({go:t,rect:i,passThrough:o})}}return e}markerRectFor(e,t){const n=t??this.projectGo(e);return n?e.getComponent("Transform3D")?{x:n.x+n.width/2-14,y:n.y+n.height/2-14,width:y,height:y}:{x:n.x,y:n.y,width:y,height:y}:null}overlayPoint(e){const t=this.overlay?.canvas;if(!t)return{x:0,y:0};const n=t.getBoundingClientRect();return{x:e.clientX-n.left,y:e.clientY-n.top}}hitTestPointer(e){const t=this.overlayPoint(e),n=this.collectOverlayHits();return function(e,t,n,o){let i=null;const r=o?.coveringRatio??.75;for(let s=0;s<n.length;s++){const a=n[s];if(!ie(a.rect,e,t))continue;const c=Math.max(a.rect.width,0)*Math.max(a.rect.height,0),l=se(a.rect,o?.viewport,r),h=(a.passThrough??0)+(l?1:0),d={id:a.id,score:h,covering:l,area:c,index:s};i&&!ce(d,i)||(i=d)}return i?i.id:null}(t.x,t.y,n.map(e=>({id:e.go,rect:e.rect,passThrough:e.passThrough})),{viewport:this.overlayCss})}redrawOverlay(){const e=this.overlay;if(!e)return;if(!(this.enabled||this.markerOverlayEnabled))return void e.setVisible(!1);const t=this.game.canvas??this.game.scene?.canvas;if(!t)return;const n=e.sync(t);n&&(this.overlayCss=n,e.ctx.clearRect(0,0,n.width,n.height),this.drawMarkers(e.ctx),this.drawSelectionOutline(e.ctx))}drawMarkers(e){if(!this.markerOverlayEnabled)return;const t=new m(e);for(const n of this.listSceneObjects()){if(n.destroyed||this.isIgnoredPickGo(n))continue;const o=g(n);if(!o)continue;const i=this.projectGo(n),r=this.markerRectFor(n,i);r&&(e.save(),e.translate(r.x,r.y),w(t,o,y),e.restore())}}drawSelectionOutline(e){if(!this.enabled||!this.selected||this.selected.destroyed)return;const t=this.projectGo(this.selected);if(!t)return;const n=q(this.game),o=n?this.overlayCss.width/n.width:1;e.save(),e.strokeStyle="#55ffaa",e.lineWidth=Math.max(2,4*(Number.isFinite(o)&&o>0?o:1)),e.strokeRect(t.x,t.y,t.width,t.height),e.restore()}postSetSuccess(e){const t={type:i,enabled:e};"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(t,this.postMessageOrigin),this.game.emit(i,{enabled:e})}attachMarkers(){this.markerOwners.clear();const e=new Map;for(const t of this.listSceneObjects()){if(this.isIgnoredPickGo(t))continue;const n=g(t);n&&(this.markerOwners.add(t.id),e.set(n.componentName,(e.get(n.componentName)??0)+1))}const t=[...e.entries()].map(([e,t])=>({componentName:e,count:t}));this.postMarkerOverlaySuccess(!0,t),this.redrawOverlay()}postMarkerOverlaySuccess(e,t){const n={enabled:e,total:t.reduce((e,t)=>e+t.count,0),markers:t},o={type:d,...n};"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(o,this.postMessageOrigin),this.game.emit(d,n)}getSoundSystem(){const e=this.game.getSystem("SoundSystem");return e&&"object"==typeof e&&"muted"in e&&"boolean"==typeof e.muted?e:null}onSelect(e,t){if(!this.enabled)return;this.selected=e,this.redrawOverlay();const n=this.overlayPoint(t),o=(i=n,r=q(this.game),a=this.overlayCss,!r||r.width<=0||r.height<=0||a.width<=0||a.height<=0?{x:i.x,y:i.y}:{x:i.x*(r.width/a.width),y:i.y*(r.height/a.height)});var i,r,a;const c=j(e),l={type:s,snapshot:c,pointer:o};"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(l,this.postMessageOrigin)}findGameObjectById(e){return this.listSceneObjects().find(t=>t.id===e)??null}findGameObjectBySource(e){const t=e.file.trim(),n=(e.anchor??"").trim();if(!n)return null;for(const e of this.listSceneObjects()){const o=L(e);if(!o||o.file!==t)continue;if((o.anchor??e.name)===n)return e}return null}resolveApplyTarget(e){if("number"==typeof e.gameObjectId){const t=this.findGameObjectById(e.gameObjectId);if(t)return t}const t=e.source?.file?.trim(),n=e.source?.anchor?.trim();return t&&n?this.findGameObjectBySource({file:t,anchor:n}):null}handleApplyProperty(e){const t=e.componentName,n=e.path,o="number"==typeof e.gameObjectId,i=Boolean(e.source?.file?.trim())&&Boolean(e.source?.anchor?.trim());if(!o&&!i||"string"!=typeof t||!Array.isArray(n)||0===n.length)return;const r=this.resolveApplyTarget(e);if(!r)return;B(r,t,n,e.value)&&this.selected?.id===r.id&&(this.redrawOverlay(),this.postSnapshotUpdate(r))}postSnapshotUpdate(e){const t=j(e);"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage({type:s,snapshot:t,pointer:null,source:"property-applied"},this.postMessageOrigin)}clearSelectionAndNotify(e){const t=null!=this.selected;this.selected=null,this.redrawOverlay(),t&&this.postGameObjectDeselected(e)}postGameObjectDeselected(e){const t=W(e);"undefined"!=typeof window&&window.parent&&window.parent!==window&&window.parent.postMessage(t,this.postMessageOrigin),this.game.emit(t.type,{reason:e})}};le=e.__decorate([t.decorators.componentObserver({CombosDevelopmentToolTarget:[]})],le);var he=le;Object.assign(he,{packageName:"@combos-fun/plugin-development-tool",packageVersion:"0.1.0"}),exports.COMBOS_DEVELOPMENT_TOOL_APPLY_PROPERTY=l,exports.COMBOS_DEVELOPMENT_TOOL_CLEAR_SELECTION=a,exports.COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_DESELECTED=c,exports.COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED=s,exports.COMBOS_DEVELOPMENT_TOOL_MARKER_OVERLAY_SUCCESS=d,exports.COMBOS_DEVELOPMENT_TOOL_PICK_MODE_SUCCESS=i,exports.COMBOS_DEVELOPMENT_TOOL_READY="combos-development-tool:ready",exports.COMBOS_DEVELOPMENT_TOOL_REFRESH=r,exports.COMBOS_DEVELOPMENT_TOOL_SET_MARKER_OVERLAY=h,exports.COMBOS_DEVELOPMENT_TOOL_SET_MUTED="combos-development-tool:set-muted",exports.COMBOS_DEVELOPMENT_TOOL_SET_PICK_MODE=o,exports.COMBOS_DEVELOPMENT_TOOL_STATE_CHANGED="combos-development-tool:state-changed",exports.CombosDevelopmentToolSystem=he,exports.CombosDevelopmentToolTarget=u,exports.DEFAULT_ALLOWED_MESSAGE_HOST_SUFFIXES=v,exports.MARKER_COMPONENTS=f,exports.MARKER_ICON_SIZE=y,exports.applyPropertyValue=N,exports.applyPropertyWithHooks=B,exports.attachDevelopmentTarget=function(e,t){if(!e||e.destroyed||function(e){return"string"==typeof e.name&&e.name.startsWith("__")}(e)||function(e){return Array.isArray(e.gameObjects)}(e))return e;const n=t.file.trim(),o=t.anchor.trim();if(!n||!o)return e;const i=e.getComponent(u);return i?(r=i.payload?.source,E(r)&&Boolean(r.file.trim())&&Boolean((r.anchor??"").trim())||(i.payload={...i.payload??{},source:{file:n,anchor:o}}),e):(e.addComponent(new u({payload:{source:{file:n,anchor:o}}})),e);var r},exports.buildGameObjectDeselectedPayload=W,exports.buildGameObjectSnapshot=j,exports.drawMarkerIcon=w,exports.isAllowedMessageOrigin=O,exports.isClearSelectionMessage=F,exports.mergeAllowedMessageOrigins=x,exports.readPropertyValue=function(e,t,n){const o=e.getComponent(t);if(!o||!n.length)return;let i=o;for(const e of n){if(null==i||"object"!=typeof i)return;i=i[e]}return i},exports.readSourceAnchor=L,exports.resolveMarkerDef=g,exports.shouldNotifyGameObjectDeselected=V;
@@ -130,8 +130,10 @@ interface CombosDevelopmentToolSystemParams {
130
130
  /**
131
131
  * **Off** at start. While enabled:
132
132
  * - a transparent HTML canvas overlay captures pointer events (game Event / Event3D
133
- * do not receive the tap);
133
+ * do not receive the tap); pick also listens on `window` capture so a mostly
134
+ * transparent DOM HUD above the canvas cannot swallow the tap;
134
135
  * - only nodes with {@link CombosDevelopmentToolTarget} are pickable;
136
+ * - fullscreen / hollow / low-alpha layers lose to content underneath;
135
137
  * - selection outline and markers are drawn with the Canvas 2D API (no renderer plugin).
136
138
  *
137
139
  * Turn on/off via:
@@ -158,6 +160,7 @@ declare class CombosDevelopmentToolSystem extends System<CombosDevelopmentToolSy
158
160
  private overlay;
159
161
  private overlayCss;
160
162
  private pointerDownGoId;
163
+ private pickListening;
161
164
  private needsRescan;
162
165
  /** Remembered mute when `SoundSystem` is not registered yet. */
163
166
  private mutedWithoutSoundSystem;
@@ -205,6 +208,9 @@ declare class CombosDevelopmentToolSystem extends System<CombosDevelopmentToolSy
205
208
  /** Re-bind pick targets / markers after dynamic scene changes while active. */
206
209
  requestSceneRescan(): void;
207
210
  private syncOverlayMode;
211
+ private bindPickListeners;
212
+ private unbindPickListeners;
213
+ private isPickPointInGame;
208
214
  private collectGameObjects;
209
215
  private listSceneObjects;
210
216
  private isIgnoredPickGo;
@@ -253,14 +253,17 @@ function mergeAllowedMessageOrigins(extra) {
253
253
 
254
254
  const OVERLAY_Z_INDEX = '2147483000';
255
255
  const OVERLAY_ATTR = 'data-combos-development-tool-overlay';
256
- function ensureParent(gameCanvas, overlay) {
257
- const parent = gameCanvas.parentElement ?? document.body;
256
+ function ensureParent(_gameCanvas, overlay) {
257
+ const parent = document.body;
258
+ if (!parent)
259
+ return;
258
260
  if (overlay.parentElement !== parent) {
259
261
  parent.appendChild(overlay);
260
262
  }
261
263
  }
262
264
  /**
263
- * Transparent HTML canvas stacked on the game canvas.
265
+ * Transparent HTML canvas stacked on the game canvas and mounted on `document.body`
266
+ * so a transformed canvas parent cannot trap `position: fixed` under a DOM HUD.
264
267
  * Pick mode sets `pointer-events: auto` so game Event / Event3D do not receive the tap.
265
268
  */
266
269
  function createOverlayCanvas() {
@@ -496,7 +499,7 @@ function leafDescriptorsFromValue(componentName, options, path, value) {
496
499
  group: options.group ?? componentName,
497
500
  editorKind: mapEditorKind(options, axisType),
498
501
  numberMeta: buildNumberMeta(options),
499
- persistTarget: componentName === 'Transform' ? 'gameObjectConstructor' : 'component',
502
+ persistTarget: 'component',
500
503
  });
501
504
  }
502
505
  return out;
@@ -519,7 +522,7 @@ function leafDescriptorsFromValue(componentName, options, path, value) {
519
522
  editorKind: mapEditorKind(options, valueType),
520
523
  enumOptions: options.enumOptions,
521
524
  numberMeta: buildNumberMeta(options),
522
- persistTarget: componentName === 'Transform' ? 'gameObjectConstructor' : 'component',
525
+ persistTarget: 'component',
523
526
  },
524
527
  ];
525
528
  }
@@ -616,7 +619,10 @@ function syncPhysicsBodyFromTransform(go) {
616
619
  if (!physics?.body) {
617
620
  return;
618
621
  }
619
- const { x, y } = go.transform.position;
622
+ const pose = go.getComponent('Transform2D');
623
+ if (!pose)
624
+ return;
625
+ const { x, y } = pose.position;
620
626
  if (physics.Body?.setPosition) {
621
627
  physics.Body.setPosition(physics.body, { x, y });
622
628
  return;
@@ -629,11 +635,16 @@ function syncMoverOriginFromTransform(go) {
629
635
  if (!mover) {
630
636
  return;
631
637
  }
632
- mover.originX = go.transform.position.x;
633
- mover.originY = go.transform.position.y;
638
+ const pose = go.getComponent('Transform2D');
639
+ if (!pose)
640
+ return;
641
+ mover.originX = pose.position.x;
642
+ mover.originY = pose.position.y;
634
643
  }
635
644
  function applyTransformProperty(go, _comp, path, value) {
636
- const transform = go.transform;
645
+ const transform = go.getComponent('Transform2D');
646
+ if (!transform)
647
+ return false;
637
648
  const transformRecord = transform;
638
649
  if (path.length === 1 && path[0] === 'rotation') {
639
650
  const next = asNumber(value);
@@ -691,7 +702,7 @@ function applySoundProperty(_go, comp, path, value) {
691
702
  return false;
692
703
  }
693
704
  const APPLY_HOOKS = {
694
- Transform: applyTransformProperty,
705
+ Transform2D: applyTransformProperty,
695
706
  Text: applyTextProperty,
696
707
  Sound: applySoundProperty,
697
708
  };
@@ -975,6 +986,32 @@ function projectTransform3D(transform, camera, css, object3D) {
975
986
  const scale = Math.max(Math.abs(transform.scaleX ?? 1), Math.abs(transform.scaleY ?? 1), Math.abs(transform.scaleZ ?? 1), 1);
976
987
  return padAround(projected, DEFAULT_POINT_EXTENT * scale);
977
988
  }
989
+ function asTransform2DPose(value) {
990
+ if (!value || typeof value !== 'object')
991
+ return null;
992
+ const t = value;
993
+ if (!t.position || !t.size)
994
+ return null;
995
+ return {
996
+ position: t.position,
997
+ size: t.size,
998
+ origin: t.origin ?? { x: 0, y: 0 },
999
+ anchor: t.anchor ?? { x: 0, y: 0 },
1000
+ scale: t.scale ?? { x: 1, y: 1 },
1001
+ skew: t.skew ?? { x: 0, y: 0 },
1002
+ rotation: t.rotation ?? 0,
1003
+ };
1004
+ }
1005
+ function pose2DFromGameObject(go) {
1006
+ const pose = asTransform2DPose(go.getComponent('Transform2D'));
1007
+ if (!pose)
1008
+ return null;
1009
+ const parentGo = go.parent && go.parent !== go.scene ? go.parent : null;
1010
+ return {
1011
+ ...pose,
1012
+ parent: parentGo ? pose2DFromGameObject(parentGo) : null,
1013
+ };
1014
+ }
978
1015
  function projectGameObjectToScreen(go, opts) {
979
1016
  if (opts.css.width <= 0 || opts.css.height <= 0) {
980
1017
  return null;
@@ -983,21 +1020,108 @@ function projectGameObjectToScreen(go, opts) {
983
1020
  if (t3d && opts.camera) {
984
1021
  return projectTransform3D(t3d, opts.camera, opts.css, opts.object3D);
985
1022
  }
986
- return projectTransform2D(go.transform, opts.css, opts.design ?? null);
1023
+ const t2d = pose2DFromGameObject(go);
1024
+ if (!t2d)
1025
+ return null;
1026
+ return projectTransform2D(t2d, opts.css, opts.design ?? null);
987
1027
  }
988
1028
  function rectContains(rect, x, y) {
989
1029
  return x >= rect.x && y >= rect.y && x <= rect.x + rect.width && y <= rect.y + rect.height;
990
1030
  }
991
- /** Smallest containing rect wins; later items win ties (front-most in walk order). */
992
- function hitTestRects(x, y, items) {
1031
+ /** Fraction of the overlay a rect must cover to count as a fullscreen pass-through layer. */
1032
+ const COVERING_OVERLAY_RATIO = 0.75;
1033
+ /** `Render.alpha` / `Render3D.opacity` at or below this is treated as see-through. */
1034
+ const LOW_ALPHA_PASSTHROUGH = 0.35;
1035
+ /**
1036
+ * Known drawable component names. Duck-typed so this package does not import
1037
+ * renderer plugins. Unknown custom visuals are treated as non-drawable only for
1038
+ * pass-through ranking; they remain pickable when they are the only hit.
1039
+ */
1040
+ const KNOWN_VISUAL_COMPONENT_NAMES = [
1041
+ 'Img',
1042
+ 'Sprite',
1043
+ 'TilingSprite',
1044
+ 'NinePatch',
1045
+ 'Text',
1046
+ 'Graphics',
1047
+ 'SpriteAnimation',
1048
+ 'Img3D',
1049
+ 'Sprite3D',
1050
+ 'TilingSprite3D',
1051
+ 'Text3D',
1052
+ 'Graphics3D',
1053
+ 'Model3D',
1054
+ 'SpriteAnimation3D',
1055
+ ];
1056
+ function rectOverlapArea(a, b) {
1057
+ const width = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x);
1058
+ const height = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y);
1059
+ if (width <= 0 || height <= 0)
1060
+ return 0;
1061
+ return width * height;
1062
+ }
1063
+ function isCoveringOverlay(rect, viewport, ratio = COVERING_OVERLAY_RATIO) {
1064
+ if (!viewport || viewport.width <= 0 || viewport.height <= 0) {
1065
+ return false;
1066
+ }
1067
+ const viewportArea = viewport.width * viewport.height;
1068
+ if (viewportArea <= 0)
1069
+ return false;
1070
+ return rectOverlapArea(rect, { x: 0, y: 0, width: viewport.width, height: viewport.height }) / viewportArea >= ratio;
1071
+ }
1072
+ function hasKnownVisual(go) {
1073
+ return KNOWN_VISUAL_COMPONENT_NAMES.some(name => Boolean(go.getComponent(name)));
1074
+ }
1075
+ /**
1076
+ * Higher = more likely to click through to a target underneath.
1077
+ * Invisible / zero-alpha layers rank above hollow containers and low-alpha dimmers.
1078
+ */
1079
+ function pickPassThrough(go) {
1080
+ const render = go.getComponent('Render');
1081
+ const render3d = go.getComponent('Render3D');
1082
+ const visible = render?.visible !== false && render3d?.visible !== false;
1083
+ const alpha = Math.min(typeof render?.alpha === 'number' && Number.isFinite(render.alpha) ? render.alpha : 1, typeof render3d?.opacity === 'number' && Number.isFinite(render3d.opacity) ? render3d.opacity : 1);
1084
+ let score = 0;
1085
+ if (!visible || alpha <= 0)
1086
+ score += 2;
1087
+ else if (alpha <= LOW_ALPHA_PASSTHROUGH)
1088
+ score += 1;
1089
+ if (!hasKnownVisual(go))
1090
+ score += 1;
1091
+ return score;
1092
+ }
1093
+ function isBetterHit(next, best) {
1094
+ if (next.score !== best.score)
1095
+ return next.score < best.score;
1096
+ if (next.covering !== best.covering)
1097
+ return !next.covering;
1098
+ if (next.covering) {
1099
+ return next.index < best.index;
1100
+ }
1101
+ if (next.area !== best.area)
1102
+ return next.area < best.area;
1103
+ return next.index > best.index;
1104
+ }
1105
+ /**
1106
+ * Pick among overlapping targets:
1107
+ * - lower pass-through score wins (content over invisible / hollow / low-alpha);
1108
+ * - a covering fullscreen layer loses to any non-covering hit;
1109
+ * - among covering-only hits, the earlier scene-walk item wins (what's behind);
1110
+ * - among content hits, smallest rect wins, later items win ties (front-most).
1111
+ */
1112
+ function hitTestRects(x, y, items, opts) {
993
1113
  let best = null;
1114
+ const coveringRatio = opts?.coveringRatio ?? COVERING_OVERLAY_RATIO;
994
1115
  for (let i = 0; i < items.length; i++) {
995
1116
  const item = items[i];
996
1117
  if (!rectContains(item.rect, x, y))
997
1118
  continue;
998
1119
  const area = Math.max(item.rect.width, 0) * Math.max(item.rect.height, 0);
999
- if (!best || area < best.area || (area === best.area && i > best.index)) {
1000
- best = { id: item.id, area, index: i };
1120
+ const covering = isCoveringOverlay(item.rect, opts?.viewport, coveringRatio);
1121
+ const score = (item.passThrough ?? 0) + (covering ? 1 : 0);
1122
+ const next = { id: item.id, score, covering, area, index: i };
1123
+ if (!best || isBetterHit(next, best)) {
1124
+ best = next;
1001
1125
  }
1002
1126
  }
1003
1127
  return best ? best.id : null;
@@ -1009,8 +1133,10 @@ const OUTLINE_COLOR = '#55ffaa';
1009
1133
  /**
1010
1134
  * **Off** at start. While enabled:
1011
1135
  * - a transparent HTML canvas overlay captures pointer events (game Event / Event3D
1012
- * do not receive the tap);
1136
+ * do not receive the tap); pick also listens on `window` capture so a mostly
1137
+ * transparent DOM HUD above the canvas cannot swallow the tap;
1013
1138
  * - only nodes with {@link CombosDevelopmentToolTarget} are pickable;
1139
+ * - fullscreen / hollow / low-alpha layers lose to content underneath;
1014
1140
  * - selection outline and markers are drawn with the Canvas 2D API (no renderer plugin).
1015
1141
  *
1016
1142
  * Turn on/off via:
@@ -1038,6 +1164,7 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1038
1164
  this.overlay = null;
1039
1165
  this.overlayCss = { width: 0, height: 0 };
1040
1166
  this.pointerDownGoId = null;
1167
+ this.pickListening = false;
1041
1168
  this.needsRescan = false;
1042
1169
  /** Remembered mute when `SoundSystem` is not registered yet. */
1043
1170
  this.mutedWithoutSoundSystem = false;
@@ -1103,10 +1230,11 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1103
1230
  this.requestSceneRescan();
1104
1231
  };
1105
1232
  this.onPointerDown = (e) => {
1106
- if (!this.enabled)
1233
+ if (!this.enabled || !this.isPickPointInGame(e))
1107
1234
  return;
1108
1235
  e.preventDefault();
1109
1236
  e.stopPropagation();
1237
+ e.stopImmediatePropagation();
1110
1238
  try {
1111
1239
  this.overlay?.canvas.setPointerCapture(e.pointerId);
1112
1240
  }
@@ -1119,8 +1247,13 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1119
1247
  this.onPointerUp = (e) => {
1120
1248
  if (!this.enabled)
1121
1249
  return;
1250
+ if (!this.isPickPointInGame(e)) {
1251
+ this.pointerDownGoId = null;
1252
+ return;
1253
+ }
1122
1254
  e.preventDefault();
1123
1255
  e.stopPropagation();
1256
+ e.stopImmediatePropagation();
1124
1257
  const hit = this.hitTestPointer(e);
1125
1258
  if (hit && hit.id === this.pointerDownGoId) {
1126
1259
  this.onSelect(hit, e);
@@ -1133,10 +1266,6 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1133
1266
  this.postMessageOrigin = params?.postMessageOrigin ?? '*';
1134
1267
  this.allowedMessageOrigins = mergeAllowedMessageOrigins(params?.allowedMessageOrigins);
1135
1268
  this.overlay = createOverlayCanvas();
1136
- if (this.overlay) {
1137
- this.overlay.canvas.addEventListener('pointerdown', this.onPointerDown);
1138
- this.overlay.canvas.addEventListener('pointerup', this.onPointerUp);
1139
- }
1140
1269
  if (typeof window !== 'undefined') {
1141
1270
  window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_PICK_MODE, this.onWindowSetPickMode);
1142
1271
  window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MARKER_OVERLAY, this.onWindowSetMarkerOverlay);
@@ -1152,9 +1281,8 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1152
1281
  }
1153
1282
  }
1154
1283
  onDestroy() {
1284
+ this.unbindPickListeners();
1155
1285
  if (this.overlay) {
1156
- this.overlay.canvas.removeEventListener('pointerdown', this.onPointerDown);
1157
- this.overlay.canvas.removeEventListener('pointerup', this.onPointerUp);
1158
1286
  this.overlay.destroy();
1159
1287
  this.overlay = null;
1160
1288
  }
@@ -1271,20 +1399,52 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1271
1399
  const active = this.enabled || this.markerOverlayEnabled;
1272
1400
  this.overlay?.setVisible(active);
1273
1401
  this.overlay?.setPickEnabled(this.enabled);
1402
+ if (this.enabled) {
1403
+ this.bindPickListeners();
1404
+ }
1405
+ else {
1406
+ this.unbindPickListeners();
1407
+ }
1408
+ }
1409
+ bindPickListeners() {
1410
+ if (this.pickListening || typeof window === 'undefined')
1411
+ return;
1412
+ window.addEventListener('pointerdown', this.onPointerDown, true);
1413
+ window.addEventListener('pointerup', this.onPointerUp, true);
1414
+ this.pickListening = true;
1415
+ }
1416
+ unbindPickListeners() {
1417
+ if (!this.pickListening || typeof window === 'undefined')
1418
+ return;
1419
+ window.removeEventListener('pointerdown', this.onPointerDown, true);
1420
+ window.removeEventListener('pointerup', this.onPointerUp, true);
1421
+ this.pickListening = false;
1422
+ }
1423
+ isPickPointInGame(e) {
1424
+ const canvas = this.game.canvas ?? this.game.scene?.canvas ?? this.overlay?.canvas;
1425
+ if (!canvas)
1426
+ return false;
1427
+ const rect = canvas.getBoundingClientRect();
1428
+ return (rect.width > 0 &&
1429
+ rect.height > 0 &&
1430
+ e.clientX >= rect.left &&
1431
+ e.clientX <= rect.right &&
1432
+ e.clientY >= rect.top &&
1433
+ e.clientY <= rect.bottom);
1274
1434
  }
1275
1435
  collectGameObjects(go, out) {
1276
1436
  out.push(go);
1277
- for (const tr of go.transform.children) {
1278
- this.collectGameObjects(tr.gameObject, out);
1437
+ for (const child of go.children) {
1438
+ this.collectGameObjects(child, out);
1279
1439
  }
1280
1440
  }
1281
1441
  listSceneObjects() {
1282
1442
  const list = [];
1283
1443
  const scene = this.game.scene;
1284
- if (!scene?.transform?.children)
1444
+ if (!scene?.children)
1285
1445
  return list;
1286
- for (const tr of scene.transform.children) {
1287
- this.collectGameObjects(tr.gameObject, list);
1446
+ for (const child of scene.children) {
1447
+ this.collectGameObjects(child, list);
1288
1448
  }
1289
1449
  return list;
1290
1450
  }
@@ -1310,13 +1470,14 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1310
1470
  if (!go.getComponent(CombosDevelopmentToolTarget))
1311
1471
  continue;
1312
1472
  const rect = this.projectGo(go);
1473
+ const passThrough = pickPassThrough(go);
1313
1474
  if (rect) {
1314
- hits.push({ go, rect });
1475
+ hits.push({ go, rect, passThrough });
1315
1476
  }
1316
1477
  if (this.markerOverlayEnabled && resolveMarkerDef(go)) {
1317
1478
  const markerRect = this.markerRectFor(go, rect);
1318
1479
  if (markerRect) {
1319
- hits.push({ go, rect: markerRect });
1480
+ hits.push({ go, rect: markerRect, passThrough });
1320
1481
  }
1321
1482
  }
1322
1483
  }
@@ -1351,7 +1512,7 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1351
1512
  hitTestPointer(e) {
1352
1513
  const pt = this.overlayPoint(e);
1353
1514
  const hits = this.collectOverlayHits();
1354
- return hitTestRects(pt.x, pt.y, hits.map(h => ({ id: h.go, rect: h.rect })));
1515
+ return hitTestRects(pt.x, pt.y, hits.map(h => ({ id: h.go, rect: h.rect, passThrough: h.passThrough })), { viewport: this.overlayCss });
1355
1516
  }
1356
1517
  redrawOverlay() {
1357
1518
  const overlay = this.overlay;
@@ -1570,7 +1731,7 @@ var CombosDevelopmentToolSystem$1 = CombosDevelopmentToolSystem;
1570
1731
  /** Auto-generated by scripts/build-package.mjs — do not edit. */
1571
1732
  Object.assign(CombosDevelopmentToolSystem$1, {
1572
1733
  packageName: "@combos-fun/plugin-development-tool",
1573
- packageVersion: "0.0.53",
1734
+ packageVersion: "0.1.0",
1574
1735
  });
1575
1736
 
1576
1737
  function isInternalEditorGo(go) {