star-canvas 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,19 +1,32 @@
1
- "use strict";var _=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var $=(r,n)=>{for(var o in n)_(r,o,{get:n[o],enumerable:!0})},B=(r,n,o,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of F(n))!W.call(r,i)&&i!==o&&_(r,i,{get:()=>n[i],enumerable:!(e=Y(n,i))||e.enumerable});return r};var P=r=>B(_({},"__esModule",{value:!0}),r);var V={};$(V,{createDragState:()=>X,game:()=>U,version:()=>I});module.exports=P(V);var I="0.7.0",z={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function X(r){let n=null,o=0,e=0;return{point(i){return r(i)},grab(i,f){let{x,y:M}=r(i);n=f,o=x-f.x,e=M-f.y},move(i){if(n){let{x:f,y:x}=r(i);n.x=f-o,n.y=x-e}},release(){let i=n;return n=null,i},get dragging(){return n}}}function k(){return typeof window<"u"&&typeof document<"u"}function N(){if(!k()||document.getElementById("star-dom-base"))return;let r=document.createElement("style");r.id="star-dom-base",r.textContent=`
1
+ "use strict";var A=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var J=(a,o)=>{for(var l in o)A(a,l,{get:o[l],enumerable:!0})},K=(a,o,l,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of j(o))!V.call(a,s)&&s!==l&&A(a,s,{get:()=>o[s],enumerable:!(t=U(o,s))||t.enumerable});return a};var Q=a=>K(A({},"__esModule",{value:!0}),a);var ne={};J(ne,{createDragState:()=>W,game:()=>te,version:()=>Z});module.exports=Q(ne);var Z="0.8.0",X={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function W(a){let o=null,l=0,t=0;return{point(s){return a(s)},grab(s,d){let{x:y,y:T}=a(s);o=d,l=y-d.x,t=T-d.y},move(s){if(o){let{x:d,y}=a(s);o.x=d-l,o.y=y-t}},release(){let s=o;return o=null,s},get dragging(){return o}}}function Y(){return typeof window<"u"&&typeof document<"u"}function ee(){if(!Y()||document.getElementById("star-dom-base"))return;let a=document.createElement("style");a.id="star-dom-base",a.textContent=`
2
2
  html, body { height: 100%; }
3
3
  body {
4
4
  margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
5
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
6
6
  }
7
- /* Canvas is at z-index 0 */
8
- .star-canvas {
9
- position: absolute; inset: 0; width: 100%; height: 100%;
10
- overflow: hidden; touch-action: none;
7
+ /* Canvas is rendering only - no pointer events */
8
+ .star-canvas {
9
+ position: absolute; inset: 0; width: 100%; height: 100%;
10
+ overflow: hidden; touch-action: none;
11
11
  z-index: 0;
12
12
  display: block;
13
+ pointer-events: none;
14
+ }
15
+ /* Input layer captures all game input (including letterbox areas) */
16
+ .star-input {
17
+ position: absolute; inset: 0; width: 100%; height: 100%;
18
+ z-index: 5;
19
+ touch-action: none;
13
20
  }
14
- /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
21
+ /* UI overlay - container is non-interactive, children opt-in */
15
22
  .star-ui {
16
23
  position: absolute; inset: 0; width: 100%; height: 100%;
17
24
  overflow-y: auto; z-index: 10;
25
+ pointer-events: none;
26
+ }
27
+ /* Interactive UI elements opt-in to receive pointer events */
28
+ .star-ui button, .star-ui a, .star-ui input, .star-ui select,
29
+ .star-ui textarea, .star-ui [data-interactive] {
30
+ pointer-events: auto;
18
31
  }
19
- `,document.head.appendChild(r)}function U(r,n={}){k()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>H(r,n),{once:!0}):queueMicrotask(()=>H(r,n)))}function H(r,n){if(N(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas").forEach(t=>t.remove());let o=document.createElement("div");o.className="star-ui",document.body.appendChild(o);let e=document.createElement("canvas");e.className="star-canvas",document.body.appendChild(e);let i=e.getContext("2d",n.contextAttributes??{alpha:!0});if(!i)throw new Error("[star-dom] Failed to get 2D context");if(n.preventContextMenu!==!1){let t=a=>a.preventDefault();e.addEventListener("contextmenu",t)}let f=e.addEventListener.bind(e);e.addEventListener=function(t,a,s){return/^(pointer|mouse|touch)/.test(t)&&(o.style.pointerEvents="none"),f(t,a,s)};let x=n.preset??"landscape",M=z[x]??z.landscape,w=n.width??M.width,E=n.height??M.height,A=n.maxPixelRatio??2,D=n.pixelRatio??"device",C=n.fit??"contain",g=1,c=w??1,u=E??1,R=new Set,T=null,b=[];function q(){return Math.min(typeof D=="number"?Math.max(1,D):Math.max(1,window.devicePixelRatio||1),A)}function p(){g=q();let t=document.body.getBoundingClientRect(),a=Math.max(1,Math.floor(t.width||window.innerWidth||800)),s=Math.max(1,Math.floor(t.height||window.innerHeight||600));if(w&&E){c=w,u=E;let d=c/u,h=a/s,v=1;if(C==="contain"?v=h>d?s/u:a/c:C==="cover"&&(v=h>d?a/c:s/u),C==="stretch")e.style.width="100%",e.style.height="100%";else{let y=Math.floor(c*v),O=Math.floor(u*v);e.style.width=`${y}px`,e.style.height=`${O}px`,e.style.position="absolute",e.style.left=`${Math.floor((a-y)/2)}px`,e.style.top=`${Math.floor((s-O)/2)}px`}}else if(E){u=E;let d=a/s;c=Math.floor(u*d),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else if(w){c=w;let d=a/s;u=Math.floor(c/d),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else c=a,u=s,e.style.width=`${c}px`,e.style.height=`${u}px`,e.style.position="absolute",e.style.left="0",e.style.top="0";let l=Math.max(1,Math.floor(c*g)),m=Math.max(1,Math.floor(u*g));e.width!==l&&(e.width=l),e.height!==m&&(e.height=m),i.setTransform(g,0,0,g,0,0),R.forEach(d=>d())}let G=new ResizeObserver(p);G.observe(document.body),b.push(()=>G.disconnect()),window.addEventListener("resize",p),b.push(()=>window.removeEventListener("resize",p));let L=window.visualViewport;L&&(L.addEventListener("resize",p),b.push(()=>L.removeEventListener("resize",p)));let S={stage:document.body,canvas:e,ctx:i,get width(){return c},get height(){return u},get dpr(){return g},resize:p,toStagePoint:t=>{let a=e.getBoundingClientRect(),s=(t.clientX-a.left)*(c/a.width),l=(t.clientY-a.top)*(u/a.height);return{x:s,y:l}},createDrag:()=>X(S.toStagePoint),on:(t,a,s,l)=>{let m=h=>{let y=h.target?.closest?.(a);y&&s.call(y,h)};document.addEventListener(t,m,l);let d=()=>document.removeEventListener(t,m,l);return b.push(d),d},loop:t=>{let s=0,l=!1,m=0,d=h=>{if(!l)return;let v=m?Math.min((h-m)/1e3,.1):0;m=h;try{t(v,h)}catch(y){console.error("[star-dom] Game loop error:",y)}s=requestAnimationFrame(d)};return T={get running(){return l},start(){l||(l=!0,m=performance.now(),s=requestAnimationFrame(d))},stop(){l&&(l=!1,cancelAnimationFrame(s))}},T.start(),T},ui:{root:o,render:t=>{o.innerHTML!==t&&(o.innerHTML=t)},el:t=>o.querySelector(t),all:t=>o.querySelectorAll(t)},destroy:()=>{T?.stop(),b.forEach(t=>t()),b=[],R.clear(),e.parentElement&&e.parentElement.removeChild(e),o.parentElement&&o.parentElement.removeChild(o)},scoped:t=>{i.save();try{t()}finally{i.restore()}}};window.__STAR_DOM__={destroy:S.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{p();try{r(S)}catch(t){console.error("[star-dom] Game initialization failed:",t)}}))}0&&(module.exports={createDragState,game,version});
32
+ `,document.head.appendChild(a)}function te(a,o={}){Y()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>q(a,o),{once:!0}):queueMicrotask(()=>q(a,o)))}function q(a,o){if(ee(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas, .star-input").forEach(e=>e.remove());let l=document.createElement("div");l.className="star-ui",document.body.appendChild(l);let t=document.createElement("canvas");t.className="star-canvas",document.body.appendChild(t);let s=t.getContext("2d",o.contextAttributes??{alpha:!0});if(!s)throw new Error("[star-dom] Failed to get 2D context");if(o.preventContextMenu!==!1){let e=n=>n.preventDefault();t.addEventListener("contextmenu",e)}let d=document.createElement("div");d.className="star-input",document.body.appendChild(d);let y=[],T=[],O=[],R=null,w=null;Object.defineProperty(t,"onclick",{get:()=>R,set:e=>{w&&(d.removeEventListener("click",w),w=null),R=e,e&&(w=n=>e.call(t,n),d.addEventListener("click",w))}});let F=t.addEventListener.bind(t),$=t.removeEventListener.bind(t),H=new WeakMap;t.addEventListener=function(e,n,r){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let i=(p=>n.call(t,p));H.set(n,i),d.addEventListener(e,i,r)}else F(e,n,r)},t.removeEventListener=function(e,n,r){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let i=H.get(n);i&&(d.removeEventListener(e,i,r),H.delete(n))}else $(e,n,r)};let B=o.preset??"landscape",D=X[B]??X.landscape,L=o.width??D.width,M=o.height??D.height,I=o.maxPixelRatio??2,k=o.pixelRatio??"device",S=o.fit??"contain",b=1,c=L??1,u=M??1,G=new Set,C=null,x=[];function N(){return Math.min(typeof k=="number"?Math.max(1,k):Math.max(1,window.devicePixelRatio||1),I)}function h(){b=N();let e=document.body.getBoundingClientRect(),n=Math.max(1,Math.floor(e.width||window.innerWidth||800)),r=Math.max(1,Math.floor(e.height||window.innerHeight||600));if(L&&M){c=L,u=M;let m=c/u,v=n/r,f=1;if(S==="contain"?f=v>m?r/u:n/c:S==="cover"&&(f=v>m?n/c:r/u),S==="stretch")t.style.width="100%",t.style.height="100%";else{let g=Math.floor(c*f),z=Math.floor(u*f);t.style.width=`${g}px`,t.style.height=`${z}px`,t.style.position="absolute",t.style.left=`${Math.floor((n-g)/2)}px`,t.style.top=`${Math.floor((r-z)/2)}px`}}else if(M){u=M;let m=n/r;c=Math.floor(u*m),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else if(L){c=L;let m=n/r;u=Math.floor(c/m),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else c=n,u=r,t.style.width=`${c}px`,t.style.height=`${u}px`,t.style.position="absolute",t.style.left="0",t.style.top="0";let i=Math.max(1,Math.floor(c*b)),p=Math.max(1,Math.floor(u*b));t.width!==i&&(t.width=i),t.height!==p&&(t.height=p),s.setTransform(b,0,0,b,0,0),G.forEach(m=>m())}let P=new ResizeObserver(h);P.observe(document.body),x.push(()=>P.disconnect()),window.addEventListener("resize",h),x.push(()=>window.removeEventListener("resize",h));let _=window.visualViewport;_&&(_.addEventListener("resize",h),x.push(()=>_.removeEventListener("resize",h)));let E={stage:document.body,canvas:t,ctx:s,get width(){return c},get height(){return u},get dpr(){return b},resize:h,toStagePoint:e=>{let n=t.getBoundingClientRect(),r=(e.clientX-n.left)*(c/n.width),i=(e.clientY-n.top)*(u/n.height);return r=Math.max(0,Math.min(c,r)),i=Math.max(0,Math.min(u,i)),{x:r,y:i}},createDrag:()=>W(E.toStagePoint),onTap:e=>{y.push(e)},onMove:e=>{T.push(e)},onRelease:e=>{O.push(e)},on:(e,n,r,i)=>{let p=v=>{let g=v.target?.closest?.(n);g&&r.call(g,v)};document.addEventListener(e,p,i);let m=()=>document.removeEventListener(e,p,i);return x.push(m),m},loop:e=>{let r=0,i=!1,p=0,m=v=>{if(!i)return;let f=p?Math.min((v-p)/1e3,.1):0;p=v;try{e(f,v)}catch(g){console.error("[star-dom] Game loop error:",g)}r=requestAnimationFrame(m)};return C={get running(){return i},start(){i||(i=!0,p=performance.now(),r=requestAnimationFrame(m))},stop(){i&&(i=!1,cancelAnimationFrame(r))}},C.start(),C},ui:{root:l,render:e=>{l.innerHTML!==e&&(l.innerHTML=e)},el:e=>l.querySelector(e),all:e=>l.querySelectorAll(e)},destroy:()=>{C?.stop(),x.forEach(e=>e()),x=[],G.clear(),t.parentElement&&t.parentElement.removeChild(t),l.parentElement&&l.parentElement.removeChild(l),d.parentElement&&d.parentElement.removeChild(d)},scoped:e=>{s.save();try{e()}finally{s.restore()}}};d.addEventListener("pointerdown",e=>{let n={...E.toStagePoint(e),event:e};y.forEach(r=>r(n))}),d.addEventListener("pointermove",e=>{let n={...E.toStagePoint(e),event:e};T.forEach(r=>r(n))}),d.addEventListener("pointerup",e=>{let n={...E.toStagePoint(e),event:e};O.forEach(r=>r(n))}),window.__STAR_DOM__={destroy:E.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{h();try{a(E)}catch(e){console.error("[star-dom] Game initialization failed:",e)}}))}0&&(module.exports={createDragState,game,version});
package/dist/index.d.cts CHANGED
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * ~1.5KB min+gz, zero deps, SSR-safe, iframe-first.
15
15
  */
16
- declare const version = "0.7.0";
16
+ declare const version = "0.8.0";
17
17
  declare global {
18
18
  interface Window {
19
19
  __STAR_DOM__?: {
@@ -37,6 +37,14 @@ interface GameUI {
37
37
  /** Scoped querySelectorAll for the UI root. */
38
38
  all: <T extends Element = HTMLElement>(selector: string) => NodeListOf<T>;
39
39
  }
40
+ /** Point with coordinates and the original event */
41
+ interface InputPoint {
42
+ x: number;
43
+ y: number;
44
+ event: PointerEvent;
45
+ }
46
+ /** Input handler type */
47
+ type InputHandler = (point: InputPoint) => void;
40
48
  interface GameContext {
41
49
  /** The root <div> element for the canvas. */
42
50
  readonly stage: HTMLElement;
@@ -56,7 +64,7 @@ interface GameContext {
56
64
  loop: (tick: GameTick) => GameLoop;
57
65
  /** The dedicated UI overlay manager. */
58
66
  readonly ui: GameUI;
59
- /** Converts DOM event coords to logical stage coords (CSS px). */
67
+ /** Converts DOM event coords to logical stage coords (CSS px). Clamps to canvas bounds. */
60
68
  toStagePoint: (e: {
61
69
  clientX: number;
62
70
  clientY: number;
@@ -69,6 +77,12 @@ interface GameContext {
69
77
  x: number;
70
78
  y: number;
71
79
  }>() => DragState<T>;
80
+ /** Register handler for tap/click (fires on pointerdown). Works anywhere on screen including letterbox. */
81
+ onTap: (handler: InputHandler) => void;
82
+ /** Register handler for pointer move. Works anywhere on screen including letterbox. */
83
+ onMove: (handler: InputHandler) => void;
84
+ /** Register handler for pointer release (fires on pointerup). Works anywhere on screen including letterbox. */
85
+ onRelease: (handler: InputHandler) => void;
72
86
  /** Re-calculates stage size (rarely needed). */
73
87
  resize: () => void;
74
88
  /** Cleans up all listeners and observers. */
@@ -163,4 +177,4 @@ declare function createDragState<T extends {
163
177
  */
164
178
  declare function game(setup: (g: GameContext) => void, options?: GameOptions): void;
165
179
 
166
- export { type DragState, type GameContext, type GameLoop, type GameOptions, type GameTick, type GameUI, createDragState, game, version };
180
+ export { type DragState, type GameContext, type GameLoop, type GameOptions, type GameTick, type GameUI, type InputHandler, type InputPoint, createDragState, game, version };
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * ~1.5KB min+gz, zero deps, SSR-safe, iframe-first.
15
15
  */
16
- declare const version = "0.7.0";
16
+ declare const version = "0.8.0";
17
17
  declare global {
18
18
  interface Window {
19
19
  __STAR_DOM__?: {
@@ -37,6 +37,14 @@ interface GameUI {
37
37
  /** Scoped querySelectorAll for the UI root. */
38
38
  all: <T extends Element = HTMLElement>(selector: string) => NodeListOf<T>;
39
39
  }
40
+ /** Point with coordinates and the original event */
41
+ interface InputPoint {
42
+ x: number;
43
+ y: number;
44
+ event: PointerEvent;
45
+ }
46
+ /** Input handler type */
47
+ type InputHandler = (point: InputPoint) => void;
40
48
  interface GameContext {
41
49
  /** The root <div> element for the canvas. */
42
50
  readonly stage: HTMLElement;
@@ -56,7 +64,7 @@ interface GameContext {
56
64
  loop: (tick: GameTick) => GameLoop;
57
65
  /** The dedicated UI overlay manager. */
58
66
  readonly ui: GameUI;
59
- /** Converts DOM event coords to logical stage coords (CSS px). */
67
+ /** Converts DOM event coords to logical stage coords (CSS px). Clamps to canvas bounds. */
60
68
  toStagePoint: (e: {
61
69
  clientX: number;
62
70
  clientY: number;
@@ -69,6 +77,12 @@ interface GameContext {
69
77
  x: number;
70
78
  y: number;
71
79
  }>() => DragState<T>;
80
+ /** Register handler for tap/click (fires on pointerdown). Works anywhere on screen including letterbox. */
81
+ onTap: (handler: InputHandler) => void;
82
+ /** Register handler for pointer move. Works anywhere on screen including letterbox. */
83
+ onMove: (handler: InputHandler) => void;
84
+ /** Register handler for pointer release (fires on pointerup). Works anywhere on screen including letterbox. */
85
+ onRelease: (handler: InputHandler) => void;
72
86
  /** Re-calculates stage size (rarely needed). */
73
87
  resize: () => void;
74
88
  /** Cleans up all listeners and observers. */
@@ -163,4 +177,4 @@ declare function createDragState<T extends {
163
177
  */
164
178
  declare function game(setup: (g: GameContext) => void, options?: GameOptions): void;
165
179
 
166
- export { type DragState, type GameContext, type GameLoop, type GameOptions, type GameTick, type GameUI, createDragState, game, version };
180
+ export { type DragState, type GameContext, type GameLoop, type GameOptions, type GameTick, type GameUI, type InputHandler, type InputPoint, createDragState, game, version };
package/dist/index.mjs CHANGED
@@ -1,19 +1,32 @@
1
- var Y="0.7.0",O={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function k(u){let n=null,i=0,e=0;return{point(l){return u(l)},grab(l,f){let{x,y:M}=u(l);n=f,i=x-f.x,e=M-f.y},move(l){if(n){let{x:f,y:x}=u(l);n.x=f-i,n.y=x-e}},release(){let l=n;return n=null,l},get dragging(){return n}}}function H(){return typeof window<"u"&&typeof document<"u"}function q(){if(!H()||document.getElementById("star-dom-base"))return;let u=document.createElement("style");u.id="star-dom-base",u.textContent=`
1
+ var U="0.8.0",z={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function B(m){let i=null,c=0,t=0;return{point(u){return m(u)},grab(u,a){let{x:y,y:T}=m(u);i=a,c=y-a.x,t=T-a.y},move(u){if(i){let{x:a,y}=m(u);i.x=a-c,i.y=y-t}},release(){let u=i;return i=null,u},get dragging(){return i}}}function q(){return typeof window<"u"&&typeof document<"u"}function N(){if(!q()||document.getElementById("star-dom-base"))return;let m=document.createElement("style");m.id="star-dom-base",m.textContent=`
2
2
  html, body { height: 100%; }
3
3
  body {
4
4
  margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
5
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
6
6
  }
7
- /* Canvas is at z-index 0 */
8
- .star-canvas {
9
- position: absolute; inset: 0; width: 100%; height: 100%;
10
- overflow: hidden; touch-action: none;
7
+ /* Canvas is rendering only - no pointer events */
8
+ .star-canvas {
9
+ position: absolute; inset: 0; width: 100%; height: 100%;
10
+ overflow: hidden; touch-action: none;
11
11
  z-index: 0;
12
12
  display: block;
13
+ pointer-events: none;
14
+ }
15
+ /* Input layer captures all game input (including letterbox areas) */
16
+ .star-input {
17
+ position: absolute; inset: 0; width: 100%; height: 100%;
18
+ z-index: 5;
19
+ touch-action: none;
13
20
  }
14
- /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
21
+ /* UI overlay - container is non-interactive, children opt-in */
15
22
  .star-ui {
16
23
  position: absolute; inset: 0; width: 100%; height: 100%;
17
24
  overflow-y: auto; z-index: 10;
25
+ pointer-events: none;
26
+ }
27
+ /* Interactive UI elements opt-in to receive pointer events */
28
+ .star-ui button, .star-ui a, .star-ui input, .star-ui select,
29
+ .star-ui textarea, .star-ui [data-interactive] {
30
+ pointer-events: auto;
18
31
  }
19
- `,document.head.appendChild(u)}function F(u,n={}){H()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>z(u,n),{once:!0}):queueMicrotask(()=>z(u,n)))}function z(u,n){if(q(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas").forEach(t=>t.remove());let i=document.createElement("div");i.className="star-ui",document.body.appendChild(i);let e=document.createElement("canvas");e.className="star-canvas",document.body.appendChild(e);let l=e.getContext("2d",n.contextAttributes??{alpha:!0});if(!l)throw new Error("[star-dom] Failed to get 2D context");if(n.preventContextMenu!==!1){let t=r=>r.preventDefault();e.addEventListener("contextmenu",t)}let f=e.addEventListener.bind(e);e.addEventListener=function(t,r,o){return/^(pointer|mouse|touch)/.test(t)&&(i.style.pointerEvents="none"),f(t,r,o)};let x=n.preset??"landscape",M=O[x]??O.landscape,w=n.width??M.width,E=n.height??M.height,_=n.maxPixelRatio??2,A=n.pixelRatio??"device",C=n.fit??"contain",g=1,d=w??1,c=E??1,D=new Set,T=null,b=[];function X(){return Math.min(typeof A=="number"?Math.max(1,A):Math.max(1,window.devicePixelRatio||1),_)}function p(){g=X();let t=document.body.getBoundingClientRect(),r=Math.max(1,Math.floor(t.width||window.innerWidth||800)),o=Math.max(1,Math.floor(t.height||window.innerHeight||600));if(w&&E){d=w,c=E;let s=d/c,h=r/o,v=1;if(C==="contain"?v=h>s?o/c:r/d:C==="cover"&&(v=h>s?r/d:o/c),C==="stretch")e.style.width="100%",e.style.height="100%";else{let y=Math.floor(d*v),G=Math.floor(c*v);e.style.width=`${y}px`,e.style.height=`${G}px`,e.style.position="absolute",e.style.left=`${Math.floor((r-y)/2)}px`,e.style.top=`${Math.floor((o-G)/2)}px`}}else if(E){c=E;let s=r/o;d=Math.floor(c*s),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else if(w){d=w;let s=r/o;c=Math.floor(d/s),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else d=r,c=o,e.style.width=`${d}px`,e.style.height=`${c}px`,e.style.position="absolute",e.style.left="0",e.style.top="0";let a=Math.max(1,Math.floor(d*g)),m=Math.max(1,Math.floor(c*g));e.width!==a&&(e.width=a),e.height!==m&&(e.height=m),l.setTransform(g,0,0,g,0,0),D.forEach(s=>s())}let R=new ResizeObserver(p);R.observe(document.body),b.push(()=>R.disconnect()),window.addEventListener("resize",p),b.push(()=>window.removeEventListener("resize",p));let L=window.visualViewport;L&&(L.addEventListener("resize",p),b.push(()=>L.removeEventListener("resize",p)));let S={stage:document.body,canvas:e,ctx:l,get width(){return d},get height(){return c},get dpr(){return g},resize:p,toStagePoint:t=>{let r=e.getBoundingClientRect(),o=(t.clientX-r.left)*(d/r.width),a=(t.clientY-r.top)*(c/r.height);return{x:o,y:a}},createDrag:()=>k(S.toStagePoint),on:(t,r,o,a)=>{let m=h=>{let y=h.target?.closest?.(r);y&&o.call(y,h)};document.addEventListener(t,m,a);let s=()=>document.removeEventListener(t,m,a);return b.push(s),s},loop:t=>{let o=0,a=!1,m=0,s=h=>{if(!a)return;let v=m?Math.min((h-m)/1e3,.1):0;m=h;try{t(v,h)}catch(y){console.error("[star-dom] Game loop error:",y)}o=requestAnimationFrame(s)};return T={get running(){return a},start(){a||(a=!0,m=performance.now(),o=requestAnimationFrame(s))},stop(){a&&(a=!1,cancelAnimationFrame(o))}},T.start(),T},ui:{root:i,render:t=>{i.innerHTML!==t&&(i.innerHTML=t)},el:t=>i.querySelector(t),all:t=>i.querySelectorAll(t)},destroy:()=>{T?.stop(),b.forEach(t=>t()),b=[],D.clear(),e.parentElement&&e.parentElement.removeChild(e),i.parentElement&&i.parentElement.removeChild(i)},scoped:t=>{l.save();try{t()}finally{l.restore()}}};window.__STAR_DOM__={destroy:S.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{p();try{u(S)}catch(t){console.error("[star-dom] Game initialization failed:",t)}}))}export{k as createDragState,F as game,Y as version};
32
+ `,document.head.appendChild(m)}function j(m,i={}){q()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>X(m,i),{once:!0}):queueMicrotask(()=>X(m,i)))}function X(m,i){if(N(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas, .star-input").forEach(e=>e.remove());let c=document.createElement("div");c.className="star-ui",document.body.appendChild(c);let t=document.createElement("canvas");t.className="star-canvas",document.body.appendChild(t);let u=t.getContext("2d",i.contextAttributes??{alpha:!0});if(!u)throw new Error("[star-dom] Failed to get 2D context");if(i.preventContextMenu!==!1){let e=n=>n.preventDefault();t.addEventListener("contextmenu",e)}let a=document.createElement("div");a.className="star-input",document.body.appendChild(a);let y=[],T=[],A=[],O=null,w=null;Object.defineProperty(t,"onclick",{get:()=>O,set:e=>{w&&(a.removeEventListener("click",w),w=null),O=e,e&&(w=n=>e.call(t,n),a.addEventListener("click",w))}});let W=t.addEventListener.bind(t),Y=t.removeEventListener.bind(t),H=new WeakMap;t.addEventListener=function(e,n,o){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let r=(p=>n.call(t,p));H.set(n,r),a.addEventListener(e,r,o)}else W(e,n,o)},t.removeEventListener=function(e,n,o){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let r=H.get(n);r&&(a.removeEventListener(e,r,o),H.delete(n))}else Y(e,n,o)};let F=i.preset??"landscape",R=z[F]??z.landscape,L=i.width??R.width,M=i.height??R.height,D=i.maxPixelRatio??2,I=i.pixelRatio??"device",S=i.fit??"contain",b=1,s=L??1,l=M??1,k=new Set,C=null,x=[];function $(){return Math.min(typeof I=="number"?Math.max(1,I):Math.max(1,window.devicePixelRatio||1),D)}function h(){b=$();let e=document.body.getBoundingClientRect(),n=Math.max(1,Math.floor(e.width||window.innerWidth||800)),o=Math.max(1,Math.floor(e.height||window.innerHeight||600));if(L&&M){s=L,l=M;let d=s/l,v=n/o,f=1;if(S==="contain"?f=v>d?o/l:n/s:S==="cover"&&(f=v>d?n/s:o/l),S==="stretch")t.style.width="100%",t.style.height="100%";else{let g=Math.floor(s*f),P=Math.floor(l*f);t.style.width=`${g}px`,t.style.height=`${P}px`,t.style.position="absolute",t.style.left=`${Math.floor((n-g)/2)}px`,t.style.top=`${Math.floor((o-P)/2)}px`}}else if(M){l=M;let d=n/o;s=Math.floor(l*d),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else if(L){s=L;let d=n/o;l=Math.floor(s/d),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else s=n,l=o,t.style.width=`${s}px`,t.style.height=`${l}px`,t.style.position="absolute",t.style.left="0",t.style.top="0";let r=Math.max(1,Math.floor(s*b)),p=Math.max(1,Math.floor(l*b));t.width!==r&&(t.width=r),t.height!==p&&(t.height=p),u.setTransform(b,0,0,b,0,0),k.forEach(d=>d())}let G=new ResizeObserver(h);G.observe(document.body),x.push(()=>G.disconnect()),window.addEventListener("resize",h),x.push(()=>window.removeEventListener("resize",h));let _=window.visualViewport;_&&(_.addEventListener("resize",h),x.push(()=>_.removeEventListener("resize",h)));let E={stage:document.body,canvas:t,ctx:u,get width(){return s},get height(){return l},get dpr(){return b},resize:h,toStagePoint:e=>{let n=t.getBoundingClientRect(),o=(e.clientX-n.left)*(s/n.width),r=(e.clientY-n.top)*(l/n.height);return o=Math.max(0,Math.min(s,o)),r=Math.max(0,Math.min(l,r)),{x:o,y:r}},createDrag:()=>B(E.toStagePoint),onTap:e=>{y.push(e)},onMove:e=>{T.push(e)},onRelease:e=>{A.push(e)},on:(e,n,o,r)=>{let p=v=>{let g=v.target?.closest?.(n);g&&o.call(g,v)};document.addEventListener(e,p,r);let d=()=>document.removeEventListener(e,p,r);return x.push(d),d},loop:e=>{let o=0,r=!1,p=0,d=v=>{if(!r)return;let f=p?Math.min((v-p)/1e3,.1):0;p=v;try{e(f,v)}catch(g){console.error("[star-dom] Game loop error:",g)}o=requestAnimationFrame(d)};return C={get running(){return r},start(){r||(r=!0,p=performance.now(),o=requestAnimationFrame(d))},stop(){r&&(r=!1,cancelAnimationFrame(o))}},C.start(),C},ui:{root:c,render:e=>{c.innerHTML!==e&&(c.innerHTML=e)},el:e=>c.querySelector(e),all:e=>c.querySelectorAll(e)},destroy:()=>{C?.stop(),x.forEach(e=>e()),x=[],k.clear(),t.parentElement&&t.parentElement.removeChild(t),c.parentElement&&c.parentElement.removeChild(c),a.parentElement&&a.parentElement.removeChild(a)},scoped:e=>{u.save();try{e()}finally{u.restore()}}};a.addEventListener("pointerdown",e=>{let n={...E.toStagePoint(e),event:e};y.forEach(o=>o(n))}),a.addEventListener("pointermove",e=>{let n={...E.toStagePoint(e),event:e};T.forEach(o=>o(n))}),a.addEventListener("pointerup",e=>{let n={...E.toStagePoint(e),event:e};A.forEach(o=>o(n))}),window.__STAR_DOM__={destroy:E.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{h();try{m(E)}catch(e){console.error("[star-dom] Game initialization failed:",e)}}))}export{B as createDragState,j as game,U as version};
package/dist/legacy.cjs CHANGED
@@ -1,19 +1,32 @@
1
- "use strict";var S=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var I=(o,t)=>{for(var r in t)S(o,r,{get:t[r],enumerable:!0})},P=(o,t,r,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of $(t))!B.call(o,i)&&i!==r&&S(o,i,{get:()=>t[i],enumerable:!(e=W(t,i))||e.enumerable});return o};var U=o=>P(S({},"__esModule",{value:!0}),o);var j={};I(j,{createDragState:()=>_,game:()=>V,version:()=>X});module.exports=U(j);var X="0.7.0",H={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function _(o){let t=null,r=0,e=0;return{point(i){return o(i)},grab(i,p){let{x,y:M}=o(i);t=p,r=x-p.x,e=M-p.y},move(i){if(t){let{x:p,y:x}=o(i);t.x=p-r,t.y=x-e}},release(){let i=t;return t=null,i},get dragging(){return t}}}function q(){return typeof window<"u"&&typeof document<"u"}function N(){if(!q()||document.getElementById("star-dom-base"))return;let o=document.createElement("style");o.id="star-dom-base",o.textContent=`
1
+ "use strict";var H=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var K=Object.prototype.hasOwnProperty;var Q=(i,o)=>{for(var s in o)H(i,s,{get:o[s],enumerable:!0})},Z=(i,o,s,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let l of J(o))!K.call(i,l)&&l!==s&&H(i,l,{get:()=>o[l],enumerable:!(t=V(o,l))||t.enumerable});return i};var ee=i=>Z(H({},"__esModule",{value:!0}),i);var oe={};Q(oe,{createDragState:()=>_,game:()=>ne,version:()=>Y});module.exports=ee(oe);var Y="0.8.0",q={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function _(i){let o=null,s=0,t=0;return{point(l){return i(l)},grab(l,d){let{x:y,y:T}=i(l);o=d,s=y-d.x,t=T-d.y},move(l){if(o){let{x:d,y}=i(l);o.x=d-s,o.y=y-t}},release(){let l=o;return o=null,l},get dragging(){return o}}}function F(){return typeof window<"u"&&typeof document<"u"}function te(){if(!F()||document.getElementById("star-dom-base"))return;let i=document.createElement("style");i.id="star-dom-base",i.textContent=`
2
2
  html, body { height: 100%; }
3
3
  body {
4
4
  margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
5
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
6
6
  }
7
- /* Canvas is at z-index 0 */
8
- .star-canvas {
9
- position: absolute; inset: 0; width: 100%; height: 100%;
10
- overflow: hidden; touch-action: none;
7
+ /* Canvas is rendering only - no pointer events */
8
+ .star-canvas {
9
+ position: absolute; inset: 0; width: 100%; height: 100%;
10
+ overflow: hidden; touch-action: none;
11
11
  z-index: 0;
12
12
  display: block;
13
+ pointer-events: none;
14
+ }
15
+ /* Input layer captures all game input (including letterbox areas) */
16
+ .star-input {
17
+ position: absolute; inset: 0; width: 100%; height: 100%;
18
+ z-index: 5;
19
+ touch-action: none;
13
20
  }
14
- /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
21
+ /* UI overlay - container is non-interactive, children opt-in */
15
22
  .star-ui {
16
23
  position: absolute; inset: 0; width: 100%; height: 100%;
17
24
  overflow-y: auto; z-index: 10;
25
+ pointer-events: none;
26
+ }
27
+ /* Interactive UI elements opt-in to receive pointer events */
28
+ .star-ui button, .star-ui a, .star-ui input, .star-ui select,
29
+ .star-ui textarea, .star-ui [data-interactive] {
30
+ pointer-events: auto;
18
31
  }
19
- `,document.head.appendChild(o)}function Y(o,t={}){q()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>k(o,t),{once:!0}):queueMicrotask(()=>k(o,t)))}function k(o,t){if(N(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas").forEach(n=>n.remove());let r=document.createElement("div");r.className="star-ui",document.body.appendChild(r);let e=document.createElement("canvas");e.className="star-canvas",document.body.appendChild(e);let i=e.getContext("2d",t.contextAttributes??{alpha:!0});if(!i)throw new Error("[star-dom] Failed to get 2D context");if(t.preventContextMenu!==!1){let n=a=>a.preventDefault();e.addEventListener("contextmenu",n)}let p=e.addEventListener.bind(e);e.addEventListener=function(n,a,s){return/^(pointer|mouse|touch)/.test(n)&&(r.style.pointerEvents="none"),p(n,a,s)};let x=t.preset??"landscape",M=H[x]??H.landscape,w=t.width??M.width,E=t.height??M.height,A=t.maxPixelRatio??2,D=t.pixelRatio??"device",C=t.fit??"contain",g=1,c=w??1,u=E??1,O=new Set,T=null,b=[];function F(){return Math.min(typeof D=="number"?Math.max(1,D):Math.max(1,window.devicePixelRatio||1),A)}function f(){g=F();let n=document.body.getBoundingClientRect(),a=Math.max(1,Math.floor(n.width||window.innerWidth||800)),s=Math.max(1,Math.floor(n.height||window.innerHeight||600));if(w&&E){c=w,u=E;let d=c/u,h=a/s,v=1;if(C==="contain"?v=h>d?s/u:a/c:C==="cover"&&(v=h>d?a/c:s/u),C==="stretch")e.style.width="100%",e.style.height="100%";else{let y=Math.floor(c*v),z=Math.floor(u*v);e.style.width=`${y}px`,e.style.height=`${z}px`,e.style.position="absolute",e.style.left=`${Math.floor((a-y)/2)}px`,e.style.top=`${Math.floor((s-z)/2)}px`}}else if(E){u=E;let d=a/s;c=Math.floor(u*d),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else if(w){c=w;let d=a/s;u=Math.floor(c/d),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else c=a,u=s,e.style.width=`${c}px`,e.style.height=`${u}px`,e.style.position="absolute",e.style.left="0",e.style.top="0";let l=Math.max(1,Math.floor(c*g)),m=Math.max(1,Math.floor(u*g));e.width!==l&&(e.width=l),e.height!==m&&(e.height=m),i.setTransform(g,0,0,g,0,0),O.forEach(d=>d())}let R=new ResizeObserver(f);R.observe(document.body),b.push(()=>R.disconnect()),window.addEventListener("resize",f),b.push(()=>window.removeEventListener("resize",f));let L=window.visualViewport;L&&(L.addEventListener("resize",f),b.push(()=>L.removeEventListener("resize",f)));let G={stage:document.body,canvas:e,ctx:i,get width(){return c},get height(){return u},get dpr(){return g},resize:f,toStagePoint:n=>{let a=e.getBoundingClientRect(),s=(n.clientX-a.left)*(c/a.width),l=(n.clientY-a.top)*(u/a.height);return{x:s,y:l}},createDrag:()=>_(G.toStagePoint),on:(n,a,s,l)=>{let m=h=>{let y=h.target?.closest?.(a);y&&s.call(y,h)};document.addEventListener(n,m,l);let d=()=>document.removeEventListener(n,m,l);return b.push(d),d},loop:n=>{let s=0,l=!1,m=0,d=h=>{if(!l)return;let v=m?Math.min((h-m)/1e3,.1):0;m=h;try{n(v,h)}catch(y){console.error("[star-dom] Game loop error:",y)}s=requestAnimationFrame(d)};return T={get running(){return l},start(){l||(l=!0,m=performance.now(),s=requestAnimationFrame(d))},stop(){l&&(l=!1,cancelAnimationFrame(s))}},T.start(),T},ui:{root:r,render:n=>{r.innerHTML!==n&&(r.innerHTML=n)},el:n=>r.querySelector(n),all:n=>r.querySelectorAll(n)},destroy:()=>{T?.stop(),b.forEach(n=>n()),b=[],O.clear(),e.parentElement&&e.parentElement.removeChild(e),r.parentElement&&r.parentElement.removeChild(r)},scoped:n=>{i.save();try{n()}finally{i.restore()}}};window.__STAR_DOM__={destroy:G.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{f();try{o(G)}catch(n){console.error("[star-dom] Game initialization failed:",n)}}))}function V(o,t={}){let r={preset:"responsive",...t};return Y(o,r)}0&&(module.exports={createDragState,game,version});
32
+ `,document.head.appendChild(i)}function $(i,o={}){F()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>W(i,o),{once:!0}):queueMicrotask(()=>W(i,o)))}function W(i,o){if(te(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas, .star-input").forEach(e=>e.remove());let s=document.createElement("div");s.className="star-ui",document.body.appendChild(s);let t=document.createElement("canvas");t.className="star-canvas",document.body.appendChild(t);let l=t.getContext("2d",o.contextAttributes??{alpha:!0});if(!l)throw new Error("[star-dom] Failed to get 2D context");if(o.preventContextMenu!==!1){let e=n=>n.preventDefault();t.addEventListener("contextmenu",e)}let d=document.createElement("div");d.className="star-input",document.body.appendChild(d);let y=[],T=[],A=[],D=null,w=null;Object.defineProperty(t,"onclick",{get:()=>D,set:e=>{w&&(d.removeEventListener("click",w),w=null),D=e,e&&(w=n=>e.call(t,n),d.addEventListener("click",w))}});let B=t.addEventListener.bind(t),U=t.removeEventListener.bind(t),G=new WeakMap;t.addEventListener=function(e,n,r){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let a=(p=>n.call(t,p));G.set(n,a),d.addEventListener(e,a,r)}else B(e,n,r)},t.removeEventListener=function(e,n,r){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let a=G.get(n);a&&(d.removeEventListener(e,a,r),G.delete(n))}else U(e,n,r)};let N=o.preset??"landscape",I=q[N]??q.landscape,L=o.width??I.width,M=o.height??I.height,R=o.maxPixelRatio??2,k=o.pixelRatio??"device",O=o.fit??"contain",b=1,c=L??1,u=M??1,P=new Set,C=null,x=[];function j(){return Math.min(typeof k=="number"?Math.max(1,k):Math.max(1,window.devicePixelRatio||1),R)}function h(){b=j();let e=document.body.getBoundingClientRect(),n=Math.max(1,Math.floor(e.width||window.innerWidth||800)),r=Math.max(1,Math.floor(e.height||window.innerHeight||600));if(L&&M){c=L,u=M;let m=c/u,v=n/r,f=1;if(O==="contain"?f=v>m?r/u:n/c:O==="cover"&&(f=v>m?n/c:r/u),O==="stretch")t.style.width="100%",t.style.height="100%";else{let g=Math.floor(c*f),X=Math.floor(u*f);t.style.width=`${g}px`,t.style.height=`${X}px`,t.style.position="absolute",t.style.left=`${Math.floor((n-g)/2)}px`,t.style.top=`${Math.floor((r-X)/2)}px`}}else if(M){u=M;let m=n/r;c=Math.floor(u*m),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else if(L){c=L;let m=n/r;u=Math.floor(c/m),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else c=n,u=r,t.style.width=`${c}px`,t.style.height=`${u}px`,t.style.position="absolute",t.style.left="0",t.style.top="0";let a=Math.max(1,Math.floor(c*b)),p=Math.max(1,Math.floor(u*b));t.width!==a&&(t.width=a),t.height!==p&&(t.height=p),l.setTransform(b,0,0,b,0,0),P.forEach(m=>m())}let z=new ResizeObserver(h);z.observe(document.body),x.push(()=>z.disconnect()),window.addEventListener("resize",h),x.push(()=>window.removeEventListener("resize",h));let S=window.visualViewport;S&&(S.addEventListener("resize",h),x.push(()=>S.removeEventListener("resize",h)));let E={stage:document.body,canvas:t,ctx:l,get width(){return c},get height(){return u},get dpr(){return b},resize:h,toStagePoint:e=>{let n=t.getBoundingClientRect(),r=(e.clientX-n.left)*(c/n.width),a=(e.clientY-n.top)*(u/n.height);return r=Math.max(0,Math.min(c,r)),a=Math.max(0,Math.min(u,a)),{x:r,y:a}},createDrag:()=>_(E.toStagePoint),onTap:e=>{y.push(e)},onMove:e=>{T.push(e)},onRelease:e=>{A.push(e)},on:(e,n,r,a)=>{let p=v=>{let g=v.target?.closest?.(n);g&&r.call(g,v)};document.addEventListener(e,p,a);let m=()=>document.removeEventListener(e,p,a);return x.push(m),m},loop:e=>{let r=0,a=!1,p=0,m=v=>{if(!a)return;let f=p?Math.min((v-p)/1e3,.1):0;p=v;try{e(f,v)}catch(g){console.error("[star-dom] Game loop error:",g)}r=requestAnimationFrame(m)};return C={get running(){return a},start(){a||(a=!0,p=performance.now(),r=requestAnimationFrame(m))},stop(){a&&(a=!1,cancelAnimationFrame(r))}},C.start(),C},ui:{root:s,render:e=>{s.innerHTML!==e&&(s.innerHTML=e)},el:e=>s.querySelector(e),all:e=>s.querySelectorAll(e)},destroy:()=>{C?.stop(),x.forEach(e=>e()),x=[],P.clear(),t.parentElement&&t.parentElement.removeChild(t),s.parentElement&&s.parentElement.removeChild(s),d.parentElement&&d.parentElement.removeChild(d)},scoped:e=>{l.save();try{e()}finally{l.restore()}}};d.addEventListener("pointerdown",e=>{let n={...E.toStagePoint(e),event:e};y.forEach(r=>r(n))}),d.addEventListener("pointermove",e=>{let n={...E.toStagePoint(e),event:e};T.forEach(r=>r(n))}),d.addEventListener("pointerup",e=>{let n={...E.toStagePoint(e),event:e};A.forEach(r=>r(n))}),window.__STAR_DOM__={destroy:E.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{h();try{i(E)}catch(e){console.error("[star-dom] Game initialization failed:",e)}}))}function ne(i,o={}){let s={preset:"responsive",...o};return $(i,s)}0&&(module.exports={createDragState,game,version});
package/dist/legacy.mjs CHANGED
@@ -1,19 +1,32 @@
1
- var Y="0.7.0",R={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function H(a){let n=null,i=0,e=0;return{point(d){return a(d)},grab(d,p){let{x,y:M}=a(d);n=p,i=x-p.x,e=M-p.y},move(d){if(n){let{x:p,y:x}=a(d);n.x=p-i,n.y=x-e}},release(){let d=n;return n=null,d},get dragging(){return n}}}function k(){return typeof window<"u"&&typeof document<"u"}function F(){if(!k()||document.getElementById("star-dom-base"))return;let a=document.createElement("style");a.id="star-dom-base",a.textContent=`
1
+ var N="0.8.0",z={landscape:{width:640,height:360},portrait:{width:360,height:640},responsive:{}};function q(l){let i=null,s=0,t=0;return{point(m){return l(m)},grab(m,a){let{x:y,y:T}=l(m);i=a,s=y-a.x,t=T-a.y},move(m){if(i){let{x:a,y}=l(m);i.x=a-s,i.y=y-t}},release(){let m=i;return i=null,m},get dragging(){return i}}}function W(){return typeof window<"u"&&typeof document<"u"}function j(){if(!W()||document.getElementById("star-dom-base"))return;let l=document.createElement("style");l.id="star-dom-base",l.textContent=`
2
2
  html, body { height: 100%; }
3
3
  body {
4
4
  margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
5
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
6
6
  }
7
- /* Canvas is at z-index 0 */
8
- .star-canvas {
9
- position: absolute; inset: 0; width: 100%; height: 100%;
10
- overflow: hidden; touch-action: none;
7
+ /* Canvas is rendering only - no pointer events */
8
+ .star-canvas {
9
+ position: absolute; inset: 0; width: 100%; height: 100%;
10
+ overflow: hidden; touch-action: none;
11
11
  z-index: 0;
12
12
  display: block;
13
+ pointer-events: none;
14
+ }
15
+ /* Input layer captures all game input (including letterbox areas) */
16
+ .star-input {
17
+ position: absolute; inset: 0; width: 100%; height: 100%;
18
+ z-index: 5;
19
+ touch-action: none;
13
20
  }
14
- /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
21
+ /* UI overlay - container is non-interactive, children opt-in */
15
22
  .star-ui {
16
23
  position: absolute; inset: 0; width: 100%; height: 100%;
17
24
  overflow-y: auto; z-index: 10;
25
+ pointer-events: none;
26
+ }
27
+ /* Interactive UI elements opt-in to receive pointer events */
28
+ .star-ui button, .star-ui a, .star-ui input, .star-ui select,
29
+ .star-ui textarea, .star-ui [data-interactive] {
30
+ pointer-events: auto;
18
31
  }
19
- `,document.head.appendChild(a)}function X(a,n={}){k()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>z(a,n),{once:!0}):queueMicrotask(()=>z(a,n)))}function z(a,n){if(F(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas").forEach(t=>t.remove());let i=document.createElement("div");i.className="star-ui",document.body.appendChild(i);let e=document.createElement("canvas");e.className="star-canvas",document.body.appendChild(e);let d=e.getContext("2d",n.contextAttributes??{alpha:!0});if(!d)throw new Error("[star-dom] Failed to get 2D context");if(n.preventContextMenu!==!1){let t=o=>o.preventDefault();e.addEventListener("contextmenu",t)}let p=e.addEventListener.bind(e);e.addEventListener=function(t,o,r){return/^(pointer|mouse|touch)/.test(t)&&(i.style.pointerEvents="none"),p(t,o,r)};let x=n.preset??"landscape",M=R[x]??R.landscape,w=n.width??M.width,E=n.height??M.height,S=n.maxPixelRatio??2,_=n.pixelRatio??"device",C=n.fit??"contain",g=1,c=w??1,u=E??1,A=new Set,T=null,b=[];function q(){return Math.min(typeof _=="number"?Math.max(1,_):Math.max(1,window.devicePixelRatio||1),S)}function f(){g=q();let t=document.body.getBoundingClientRect(),o=Math.max(1,Math.floor(t.width||window.innerWidth||800)),r=Math.max(1,Math.floor(t.height||window.innerHeight||600));if(w&&E){c=w,u=E;let l=c/u,h=o/r,v=1;if(C==="contain"?v=h>l?r/u:o/c:C==="cover"&&(v=h>l?o/c:r/u),C==="stretch")e.style.width="100%",e.style.height="100%";else{let y=Math.floor(c*v),O=Math.floor(u*v);e.style.width=`${y}px`,e.style.height=`${O}px`,e.style.position="absolute",e.style.left=`${Math.floor((o-y)/2)}px`,e.style.top=`${Math.floor((r-O)/2)}px`}}else if(E){u=E;let l=o/r;c=Math.floor(u*l),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else if(w){c=w;let l=o/r;u=Math.floor(c/l),e.style.width="100%",e.style.height="100%",e.style.position="absolute",e.style.left="0",e.style.top="0"}else c=o,u=r,e.style.width=`${c}px`,e.style.height=`${u}px`,e.style.position="absolute",e.style.left="0",e.style.top="0";let s=Math.max(1,Math.floor(c*g)),m=Math.max(1,Math.floor(u*g));e.width!==s&&(e.width=s),e.height!==m&&(e.height=m),d.setTransform(g,0,0,g,0,0),A.forEach(l=>l())}let D=new ResizeObserver(f);D.observe(document.body),b.push(()=>D.disconnect()),window.addEventListener("resize",f),b.push(()=>window.removeEventListener("resize",f));let L=window.visualViewport;L&&(L.addEventListener("resize",f),b.push(()=>L.removeEventListener("resize",f)));let G={stage:document.body,canvas:e,ctx:d,get width(){return c},get height(){return u},get dpr(){return g},resize:f,toStagePoint:t=>{let o=e.getBoundingClientRect(),r=(t.clientX-o.left)*(c/o.width),s=(t.clientY-o.top)*(u/o.height);return{x:r,y:s}},createDrag:()=>H(G.toStagePoint),on:(t,o,r,s)=>{let m=h=>{let y=h.target?.closest?.(o);y&&r.call(y,h)};document.addEventListener(t,m,s);let l=()=>document.removeEventListener(t,m,s);return b.push(l),l},loop:t=>{let r=0,s=!1,m=0,l=h=>{if(!s)return;let v=m?Math.min((h-m)/1e3,.1):0;m=h;try{t(v,h)}catch(y){console.error("[star-dom] Game loop error:",y)}r=requestAnimationFrame(l)};return T={get running(){return s},start(){s||(s=!0,m=performance.now(),r=requestAnimationFrame(l))},stop(){s&&(s=!1,cancelAnimationFrame(r))}},T.start(),T},ui:{root:i,render:t=>{i.innerHTML!==t&&(i.innerHTML=t)},el:t=>i.querySelector(t),all:t=>i.querySelectorAll(t)},destroy:()=>{T?.stop(),b.forEach(t=>t()),b=[],A.clear(),e.parentElement&&e.parentElement.removeChild(e),i.parentElement&&i.parentElement.removeChild(i)},scoped:t=>{d.save();try{t()}finally{d.restore()}}};window.__STAR_DOM__={destroy:G.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{f();try{a(G)}catch(t){console.error("[star-dom] Game initialization failed:",t)}}))}function B(a,n={}){let i={preset:"responsive",...n};return X(a,i)}export{H as createDragState,B as game,Y as version};
32
+ `,document.head.appendChild(l)}function Y(l,i={}){W()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>X(l,i),{once:!0}):queueMicrotask(()=>X(l,i)))}function X(l,i){if(j(),window.__STAR_DOM__?.destroy)try{window.__STAR_DOM__.destroy()}catch{}document.querySelectorAll(".star-ui, .star-canvas, .star-input").forEach(e=>e.remove());let s=document.createElement("div");s.className="star-ui",document.body.appendChild(s);let t=document.createElement("canvas");t.className="star-canvas",document.body.appendChild(t);let m=t.getContext("2d",i.contextAttributes??{alpha:!0});if(!m)throw new Error("[star-dom] Failed to get 2D context");if(i.preventContextMenu!==!1){let e=n=>n.preventDefault();t.addEventListener("contextmenu",e)}let a=document.createElement("div");a.className="star-input",document.body.appendChild(a);let y=[],T=[],H=[],_=null,w=null;Object.defineProperty(t,"onclick",{get:()=>_,set:e=>{w&&(a.removeEventListener("click",w),w=null),_=e,e&&(w=n=>e.call(t,n),a.addEventListener("click",w))}});let F=t.addEventListener.bind(t),$=t.removeEventListener.bind(t),G=new WeakMap;t.addEventListener=function(e,n,o){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let r=(p=>n.call(t,p));G.set(n,r),a.addEventListener(e,r,o)}else F(e,n,o)},t.removeEventListener=function(e,n,o){if(/^(click|pointer|mouse|touch)/.test(e)&&typeof n=="function"){let r=G.get(n);r&&(a.removeEventListener(e,r,o),G.delete(n))}else $(e,n,o)};let B=i.preset??"landscape",A=z[B]??z.landscape,L=i.width??A.width,M=i.height??A.height,D=i.maxPixelRatio??2,I=i.pixelRatio??"device",O=i.fit??"contain",b=1,d=L??1,c=M??1,R=new Set,C=null,x=[];function U(){return Math.min(typeof I=="number"?Math.max(1,I):Math.max(1,window.devicePixelRatio||1),D)}function h(){b=U();let e=document.body.getBoundingClientRect(),n=Math.max(1,Math.floor(e.width||window.innerWidth||800)),o=Math.max(1,Math.floor(e.height||window.innerHeight||600));if(L&&M){d=L,c=M;let u=d/c,v=n/o,f=1;if(O==="contain"?f=v>u?o/c:n/d:O==="cover"&&(f=v>u?n/d:o/c),O==="stretch")t.style.width="100%",t.style.height="100%";else{let g=Math.floor(d*f),P=Math.floor(c*f);t.style.width=`${g}px`,t.style.height=`${P}px`,t.style.position="absolute",t.style.left=`${Math.floor((n-g)/2)}px`,t.style.top=`${Math.floor((o-P)/2)}px`}}else if(M){c=M;let u=n/o;d=Math.floor(c*u),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else if(L){d=L;let u=n/o;c=Math.floor(d/u),t.style.width="100%",t.style.height="100%",t.style.position="absolute",t.style.left="0",t.style.top="0"}else d=n,c=o,t.style.width=`${d}px`,t.style.height=`${c}px`,t.style.position="absolute",t.style.left="0",t.style.top="0";let r=Math.max(1,Math.floor(d*b)),p=Math.max(1,Math.floor(c*b));t.width!==r&&(t.width=r),t.height!==p&&(t.height=p),m.setTransform(b,0,0,b,0,0),R.forEach(u=>u())}let k=new ResizeObserver(h);k.observe(document.body),x.push(()=>k.disconnect()),window.addEventListener("resize",h),x.push(()=>window.removeEventListener("resize",h));let S=window.visualViewport;S&&(S.addEventListener("resize",h),x.push(()=>S.removeEventListener("resize",h)));let E={stage:document.body,canvas:t,ctx:m,get width(){return d},get height(){return c},get dpr(){return b},resize:h,toStagePoint:e=>{let n=t.getBoundingClientRect(),o=(e.clientX-n.left)*(d/n.width),r=(e.clientY-n.top)*(c/n.height);return o=Math.max(0,Math.min(d,o)),r=Math.max(0,Math.min(c,r)),{x:o,y:r}},createDrag:()=>q(E.toStagePoint),onTap:e=>{y.push(e)},onMove:e=>{T.push(e)},onRelease:e=>{H.push(e)},on:(e,n,o,r)=>{let p=v=>{let g=v.target?.closest?.(n);g&&o.call(g,v)};document.addEventListener(e,p,r);let u=()=>document.removeEventListener(e,p,r);return x.push(u),u},loop:e=>{let o=0,r=!1,p=0,u=v=>{if(!r)return;let f=p?Math.min((v-p)/1e3,.1):0;p=v;try{e(f,v)}catch(g){console.error("[star-dom] Game loop error:",g)}o=requestAnimationFrame(u)};return C={get running(){return r},start(){r||(r=!0,p=performance.now(),o=requestAnimationFrame(u))},stop(){r&&(r=!1,cancelAnimationFrame(o))}},C.start(),C},ui:{root:s,render:e=>{s.innerHTML!==e&&(s.innerHTML=e)},el:e=>s.querySelector(e),all:e=>s.querySelectorAll(e)},destroy:()=>{C?.stop(),x.forEach(e=>e()),x=[],R.clear(),t.parentElement&&t.parentElement.removeChild(t),s.parentElement&&s.parentElement.removeChild(s),a.parentElement&&a.parentElement.removeChild(a)},scoped:e=>{m.save();try{e()}finally{m.restore()}}};a.addEventListener("pointerdown",e=>{let n={...E.toStagePoint(e),event:e};y.forEach(o=>o(n))}),a.addEventListener("pointermove",e=>{let n={...E.toStagePoint(e),event:e};T.forEach(o=>o(n))}),a.addEventListener("pointerup",e=>{let n={...E.toStagePoint(e),event:e};H.forEach(o=>o(n))}),window.__STAR_DOM__={destroy:E.destroy},requestAnimationFrame(()=>requestAnimationFrame(()=>{h();try{l(E)}catch(e){console.error("[star-dom] Game initialization failed:",e)}}))}function K(l,i={}){let s={preset:"responsive",...i};return Y(l,s)}export{q as createDragState,K as game,N as version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "star-canvas",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "description": "Canvas game utilities for reliable game initialization - part of Star SDK.",
6
6
  "type": "module",
@@ -10,8 +10,14 @@
10
10
  "publicImport": "import { game } from 'star-canvas';",
11
11
  "publicPath": "dist/index.mjs",
12
12
  "outputs": [
13
- { "src": "dist/legacy.mjs", "dest": "dom.js" },
14
- { "src": "dist/index.mjs", "dest": "v1/dom.js" }
13
+ {
14
+ "src": "dist/legacy.mjs",
15
+ "dest": "dom.js"
16
+ },
17
+ {
18
+ "src": "dist/index.mjs",
19
+ "dest": "v1/dom.js"
20
+ }
15
21
  ],
16
22
  "skill": {
17
23
  "name": "star-dom-sdk",