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

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 _(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 D(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=_(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:"Transform"===e?"gameObjectConstructor":"component"})}return l}if("object"===r)return[];const c=_(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:"Transform"===e?"gameObjectConstructor":"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(...D(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={Transform:function(e,t,n,o){const i=e.transform,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{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 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 U(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 $(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 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),i=q(n?.height);if(o&&i)return{width:o,height:i};const r=q(t?.params?.width),s=q(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,U(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=$(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=$(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,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}const ie=["Img","Sprite","TilingSprite","NinePatch","Text","Graphics","SpriteAnimation","Img3D","Sprite3D","TilingSprite3D","Text3D","Graphics3D","Model3D","SpriteAnimation3D"];function re(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 se(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 ie.some(t=>Boolean(e.getComponent(t)))}(e)||(r+=1),r}function ae(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 ce=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.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: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=se(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(!oe(a.rect,e,t))continue;const c=Math.max(a.rect.width,0)*Math.max(a.rect.height,0),l=re(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&&!ae(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=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: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=z(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})}};ce=e.__decorate([t.decorators.componentObserver({CombosDevelopmentToolTarget:[]})],ce);var le=ce;Object.assign(le,{packageName:"@combos-fun/plugin-development-tool",packageVersion:"0.0.54"}),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=le,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() {
@@ -988,16 +991,100 @@ function projectGameObjectToScreen(go, opts) {
988
991
  function rectContains(rect, x, y) {
989
992
  return x >= rect.x && y >= rect.y && x <= rect.x + rect.width && y <= rect.y + rect.height;
990
993
  }
991
- /** Smallest containing rect wins; later items win ties (front-most in walk order). */
992
- function hitTestRects(x, y, items) {
994
+ /** Fraction of the overlay a rect must cover to count as a fullscreen pass-through layer. */
995
+ const COVERING_OVERLAY_RATIO = 0.75;
996
+ /** `Render.alpha` / `Render3D.opacity` at or below this is treated as see-through. */
997
+ const LOW_ALPHA_PASSTHROUGH = 0.35;
998
+ /**
999
+ * Known drawable component names. Duck-typed so this package does not import
1000
+ * renderer plugins. Unknown custom visuals are treated as non-drawable only for
1001
+ * pass-through ranking; they remain pickable when they are the only hit.
1002
+ */
1003
+ const KNOWN_VISUAL_COMPONENT_NAMES = [
1004
+ 'Img',
1005
+ 'Sprite',
1006
+ 'TilingSprite',
1007
+ 'NinePatch',
1008
+ 'Text',
1009
+ 'Graphics',
1010
+ 'SpriteAnimation',
1011
+ 'Img3D',
1012
+ 'Sprite3D',
1013
+ 'TilingSprite3D',
1014
+ 'Text3D',
1015
+ 'Graphics3D',
1016
+ 'Model3D',
1017
+ 'SpriteAnimation3D',
1018
+ ];
1019
+ function rectOverlapArea(a, b) {
1020
+ const width = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x);
1021
+ const height = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y);
1022
+ if (width <= 0 || height <= 0)
1023
+ return 0;
1024
+ return width * height;
1025
+ }
1026
+ function isCoveringOverlay(rect, viewport, ratio = COVERING_OVERLAY_RATIO) {
1027
+ if (!viewport || viewport.width <= 0 || viewport.height <= 0) {
1028
+ return false;
1029
+ }
1030
+ const viewportArea = viewport.width * viewport.height;
1031
+ if (viewportArea <= 0)
1032
+ return false;
1033
+ return rectOverlapArea(rect, { x: 0, y: 0, width: viewport.width, height: viewport.height }) / viewportArea >= ratio;
1034
+ }
1035
+ function hasKnownVisual(go) {
1036
+ return KNOWN_VISUAL_COMPONENT_NAMES.some(name => Boolean(go.getComponent(name)));
1037
+ }
1038
+ /**
1039
+ * Higher = more likely to click through to a target underneath.
1040
+ * Invisible / zero-alpha layers rank above hollow containers and low-alpha dimmers.
1041
+ */
1042
+ function pickPassThrough(go) {
1043
+ const render = go.getComponent('Render');
1044
+ const render3d = go.getComponent('Render3D');
1045
+ const visible = render?.visible !== false && render3d?.visible !== false;
1046
+ 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);
1047
+ let score = 0;
1048
+ if (!visible || alpha <= 0)
1049
+ score += 2;
1050
+ else if (alpha <= LOW_ALPHA_PASSTHROUGH)
1051
+ score += 1;
1052
+ if (!hasKnownVisual(go))
1053
+ score += 1;
1054
+ return score;
1055
+ }
1056
+ function isBetterHit(next, best) {
1057
+ if (next.score !== best.score)
1058
+ return next.score < best.score;
1059
+ if (next.covering !== best.covering)
1060
+ return !next.covering;
1061
+ if (next.covering) {
1062
+ return next.index < best.index;
1063
+ }
1064
+ if (next.area !== best.area)
1065
+ return next.area < best.area;
1066
+ return next.index > best.index;
1067
+ }
1068
+ /**
1069
+ * Pick among overlapping targets:
1070
+ * - lower pass-through score wins (content over invisible / hollow / low-alpha);
1071
+ * - a covering fullscreen layer loses to any non-covering hit;
1072
+ * - among covering-only hits, the earlier scene-walk item wins (what's behind);
1073
+ * - among content hits, smallest rect wins, later items win ties (front-most).
1074
+ */
1075
+ function hitTestRects(x, y, items, opts) {
993
1076
  let best = null;
1077
+ const coveringRatio = opts?.coveringRatio ?? COVERING_OVERLAY_RATIO;
994
1078
  for (let i = 0; i < items.length; i++) {
995
1079
  const item = items[i];
996
1080
  if (!rectContains(item.rect, x, y))
997
1081
  continue;
998
1082
  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 };
1083
+ const covering = isCoveringOverlay(item.rect, opts?.viewport, coveringRatio);
1084
+ const score = (item.passThrough ?? 0) + (covering ? 1 : 0);
1085
+ const next = { id: item.id, score, covering, area, index: i };
1086
+ if (!best || isBetterHit(next, best)) {
1087
+ best = next;
1001
1088
  }
1002
1089
  }
1003
1090
  return best ? best.id : null;
@@ -1009,8 +1096,10 @@ const OUTLINE_COLOR = '#55ffaa';
1009
1096
  /**
1010
1097
  * **Off** at start. While enabled:
1011
1098
  * - a transparent HTML canvas overlay captures pointer events (game Event / Event3D
1012
- * do not receive the tap);
1099
+ * do not receive the tap); pick also listens on `window` capture so a mostly
1100
+ * transparent DOM HUD above the canvas cannot swallow the tap;
1013
1101
  * - only nodes with {@link CombosDevelopmentToolTarget} are pickable;
1102
+ * - fullscreen / hollow / low-alpha layers lose to content underneath;
1014
1103
  * - selection outline and markers are drawn with the Canvas 2D API (no renderer plugin).
1015
1104
  *
1016
1105
  * Turn on/off via:
@@ -1038,6 +1127,7 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1038
1127
  this.overlay = null;
1039
1128
  this.overlayCss = { width: 0, height: 0 };
1040
1129
  this.pointerDownGoId = null;
1130
+ this.pickListening = false;
1041
1131
  this.needsRescan = false;
1042
1132
  /** Remembered mute when `SoundSystem` is not registered yet. */
1043
1133
  this.mutedWithoutSoundSystem = false;
@@ -1103,10 +1193,11 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1103
1193
  this.requestSceneRescan();
1104
1194
  };
1105
1195
  this.onPointerDown = (e) => {
1106
- if (!this.enabled)
1196
+ if (!this.enabled || !this.isPickPointInGame(e))
1107
1197
  return;
1108
1198
  e.preventDefault();
1109
1199
  e.stopPropagation();
1200
+ e.stopImmediatePropagation();
1110
1201
  try {
1111
1202
  this.overlay?.canvas.setPointerCapture(e.pointerId);
1112
1203
  }
@@ -1119,8 +1210,13 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1119
1210
  this.onPointerUp = (e) => {
1120
1211
  if (!this.enabled)
1121
1212
  return;
1213
+ if (!this.isPickPointInGame(e)) {
1214
+ this.pointerDownGoId = null;
1215
+ return;
1216
+ }
1122
1217
  e.preventDefault();
1123
1218
  e.stopPropagation();
1219
+ e.stopImmediatePropagation();
1124
1220
  const hit = this.hitTestPointer(e);
1125
1221
  if (hit && hit.id === this.pointerDownGoId) {
1126
1222
  this.onSelect(hit, e);
@@ -1133,10 +1229,6 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1133
1229
  this.postMessageOrigin = params?.postMessageOrigin ?? '*';
1134
1230
  this.allowedMessageOrigins = mergeAllowedMessageOrigins(params?.allowedMessageOrigins);
1135
1231
  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
1232
  if (typeof window !== 'undefined') {
1141
1233
  window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_PICK_MODE, this.onWindowSetPickMode);
1142
1234
  window.addEventListener(COMBOS_DEVELOPMENT_TOOL_SET_MARKER_OVERLAY, this.onWindowSetMarkerOverlay);
@@ -1152,9 +1244,8 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1152
1244
  }
1153
1245
  }
1154
1246
  onDestroy() {
1247
+ this.unbindPickListeners();
1155
1248
  if (this.overlay) {
1156
- this.overlay.canvas.removeEventListener('pointerdown', this.onPointerDown);
1157
- this.overlay.canvas.removeEventListener('pointerup', this.onPointerUp);
1158
1249
  this.overlay.destroy();
1159
1250
  this.overlay = null;
1160
1251
  }
@@ -1271,6 +1362,38 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1271
1362
  const active = this.enabled || this.markerOverlayEnabled;
1272
1363
  this.overlay?.setVisible(active);
1273
1364
  this.overlay?.setPickEnabled(this.enabled);
1365
+ if (this.enabled) {
1366
+ this.bindPickListeners();
1367
+ }
1368
+ else {
1369
+ this.unbindPickListeners();
1370
+ }
1371
+ }
1372
+ bindPickListeners() {
1373
+ if (this.pickListening || typeof window === 'undefined')
1374
+ return;
1375
+ window.addEventListener('pointerdown', this.onPointerDown, true);
1376
+ window.addEventListener('pointerup', this.onPointerUp, true);
1377
+ this.pickListening = true;
1378
+ }
1379
+ unbindPickListeners() {
1380
+ if (!this.pickListening || typeof window === 'undefined')
1381
+ return;
1382
+ window.removeEventListener('pointerdown', this.onPointerDown, true);
1383
+ window.removeEventListener('pointerup', this.onPointerUp, true);
1384
+ this.pickListening = false;
1385
+ }
1386
+ isPickPointInGame(e) {
1387
+ const canvas = this.game.canvas ?? this.game.scene?.canvas ?? this.overlay?.canvas;
1388
+ if (!canvas)
1389
+ return false;
1390
+ const rect = canvas.getBoundingClientRect();
1391
+ return (rect.width > 0 &&
1392
+ rect.height > 0 &&
1393
+ e.clientX >= rect.left &&
1394
+ e.clientX <= rect.right &&
1395
+ e.clientY >= rect.top &&
1396
+ e.clientY <= rect.bottom);
1274
1397
  }
1275
1398
  collectGameObjects(go, out) {
1276
1399
  out.push(go);
@@ -1310,13 +1433,14 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1310
1433
  if (!go.getComponent(CombosDevelopmentToolTarget))
1311
1434
  continue;
1312
1435
  const rect = this.projectGo(go);
1436
+ const passThrough = pickPassThrough(go);
1313
1437
  if (rect) {
1314
- hits.push({ go, rect });
1438
+ hits.push({ go, rect, passThrough });
1315
1439
  }
1316
1440
  if (this.markerOverlayEnabled && resolveMarkerDef(go)) {
1317
1441
  const markerRect = this.markerRectFor(go, rect);
1318
1442
  if (markerRect) {
1319
- hits.push({ go, rect: markerRect });
1443
+ hits.push({ go, rect: markerRect, passThrough });
1320
1444
  }
1321
1445
  }
1322
1446
  }
@@ -1351,7 +1475,7 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
1351
1475
  hitTestPointer(e) {
1352
1476
  const pt = this.overlayPoint(e);
1353
1477
  const hits = this.collectOverlayHits();
1354
- return hitTestRects(pt.x, pt.y, hits.map(h => ({ id: h.go, rect: h.rect })));
1478
+ return hitTestRects(pt.x, pt.y, hits.map(h => ({ id: h.go, rect: h.rect, passThrough: h.passThrough })), { viewport: this.overlayCss });
1355
1479
  }
1356
1480
  redrawOverlay() {
1357
1481
  const overlay = this.overlay;
@@ -1570,7 +1694,7 @@ var CombosDevelopmentToolSystem$1 = CombosDevelopmentToolSystem;
1570
1694
  /** Auto-generated by scripts/build-package.mjs — do not edit. */
1571
1695
  Object.assign(CombosDevelopmentToolSystem$1, {
1572
1696
  packageName: "@combos-fun/plugin-development-tool",
1573
- packageVersion: "0.0.53",
1697
+ packageVersion: "0.0.54",
1574
1698
  });
1575
1699
 
1576
1700
  function isInternalEditorGo(go) {