star-canvas 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # Star Canvas
2
+
3
+ Essential DOM utilities for reliable game initialization.
4
+
5
+ `star-canvas` solves common bugs in web games: event listeners on null elements, canvas sizing issues, and frame-rate dependent speed. It provides a tiny (~1KB), zero-dependency toolkit with a mobile-first design.
6
+
7
+ This package is part of the **Star SDK**.
8
+
9
+ ## Features
10
+
11
+ - **Safe Initialization:** Never crash from timing issues with `onReady()`
12
+ - **Delegated Events:** Survive `innerHTML` re-renders with `on()`
13
+ - **Responsive Canvas:** Auto-sizing with DPR handling via `canvas()`
14
+ - **Frame-Rate Independence:** Delta time for consistent speed via `loop()`
15
+ - **Zero Dependencies:** Pure vanilla JavaScript, SSR-safe
16
+ - **Tiny:** <1KB gzipped
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ yarn add star-canvas
22
+ # or
23
+ npm install star-canvas
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### UI Click Game
29
+
30
+ ```javascript
31
+ import { onReady, mount, on } from 'star-canvas';
32
+
33
+ onReady(() => {
34
+ const root = mount('#game-root');
35
+ let score = 0;
36
+
37
+ function render() {
38
+ root.innerHTML = `
39
+ <div class="h-screen grid place-items-center bg-purple-900 text-white">
40
+ <div class="text-center space-y-4">
41
+ <h1 class="text-4xl font-bold">Score: ${score}</h1>
42
+ <button id="clickBtn" class="px-8 py-4 rounded-xl bg-cyan-400 text-slate-900 font-bold">
43
+ Click Me!
44
+ </button>
45
+ </div>
46
+ </div>`;
47
+ }
48
+
49
+ // Delegated event - survives re-renders
50
+ on(root, 'click', '#clickBtn', () => {
51
+ score++;
52
+ render();
53
+ });
54
+
55
+ render();
56
+ });
57
+ ```
58
+
59
+ ### Canvas Game
60
+
61
+ ```javascript
62
+ import { onReady, mount, canvas, loop } from 'star-canvas';
63
+
64
+ onReady(() => {
65
+ const root = mount('#game-root');
66
+
67
+ root.innerHTML = `
68
+ <div class="h-screen w-screen bg-slate-900">
69
+ <!-- canvas auto-created here -->
70
+ </div>`;
71
+
72
+ const container = root.firstElementChild;
73
+ const { ctx, canvas: c } = canvas(container, { pixelRatio: 'device' });
74
+
75
+ const player = { x: 50, y: 50, vx: 200 }; // 200 px/sec
76
+
77
+ loop((dt) => {
78
+ // Delta time → same speed on all devices
79
+ player.x += player.vx * dt;
80
+
81
+ // Wrap around
82
+ if (player.x > c.width) player.x = 0;
83
+
84
+ // Render
85
+ ctx.fillStyle = '#1e293b';
86
+ ctx.fillRect(0, 0, c.width, c.height);
87
+
88
+ ctx.fillStyle = '#22d3ee';
89
+ ctx.fillRect(player.x, player.y, 32, 32);
90
+ });
91
+ });
92
+ ```
93
+
94
+ ## API
95
+
96
+ ### `onReady(fn: () => void)`
97
+
98
+ Run callback when DOM is ready. Works with all script loading patterns.
99
+
100
+ ```javascript
101
+ onReady(() => {
102
+ // Safe to access DOM here
103
+ });
104
+ ```
105
+
106
+ ### `mount(selector?: string | Element): HTMLElement`
107
+
108
+ Ensure a root element exists. Creates `#game-root` if missing.
109
+
110
+ ```javascript
111
+ const root = mount('#game-root'); // guaranteed non-null
112
+ ```
113
+
114
+ ### `on(root, type, selector, handler, options?)`
115
+
116
+ Delegated event listener that survives re-renders.
117
+
118
+ ```javascript
119
+ on(root, 'click', '#button', () => {
120
+ console.log('Clicked!');
121
+ });
122
+
123
+ // Later, safe to do:
124
+ root.innerHTML = '<button id="button">Click</button>';
125
+ // Event still works!
126
+ ```
127
+
128
+ ### `canvas(root, opts?): { canvas, ctx, resize }`
129
+
130
+ Auto-sizing canvas with DPR handling.
131
+
132
+ ```javascript
133
+ const { canvas: c, ctx } = canvas(container, { pixelRatio: 'device' });
134
+ // Auto-resizes when container changes
135
+ // Handles retina displays automatically
136
+ ```
137
+
138
+ ### `loop(tick): { start, stop }`
139
+
140
+ RAF loop with delta time for frame-rate independence.
141
+
142
+ ```javascript
143
+ const { stop } = loop((dt) => {
144
+ player.x += speed * dt; // Same speed on 60Hz and 120Hz
145
+ });
146
+
147
+ // Later:
148
+ stop();
149
+ ```
150
+
151
+ ## Why Star DOM?
152
+
153
+ ### Problem: Event Listeners on Null
154
+
155
+ ```javascript
156
+ // ❌ Breaks if script runs before DOM ready
157
+ const btn = document.getElementById('start');
158
+ btn.addEventListener('click', () => { /* ... */ }); // TypeError!
159
+ ```
160
+
161
+ ```javascript
162
+ // ✅ Always works
163
+ import { onReady, mount, on } from 'star-canvas';
164
+
165
+ onReady(() => {
166
+ const root = mount();
167
+ on(root, 'click', '#start', () => { /* ... */ });
168
+ });
169
+ ```
170
+
171
+ ### Problem: Canvas Doesn't Resize
172
+
173
+ ```javascript
174
+ // ❌ Fixed size, doesn't adapt
175
+ const canvas = document.createElement('canvas');
176
+ canvas.width = 800;
177
+ canvas.height = 600;
178
+ ```
179
+
180
+ ```javascript
181
+ // ✅ Auto-sizes to container
182
+ const { canvas: c } = canvas(container);
183
+ // Resizes when sidebar appears/disappears
184
+ // Handles DPR for crisp rendering
185
+ ```
186
+
187
+ ### Problem: Game Speed Varies by Device
188
+
189
+ ```javascript
190
+ // ❌ 2x faster on 120Hz displays
191
+ function gameLoop() {
192
+ player.x += 5; // 300px/sec on 60Hz, 600px/sec on 120Hz
193
+ requestAnimationFrame(gameLoop);
194
+ }
195
+ ```
196
+
197
+ ```javascript
198
+ // ✅ Same speed everywhere
199
+ loop((dt) => {
200
+ player.x += 300 * dt; // 300px/sec on ALL devices
201
+ });
202
+ ```
203
+
204
+ ## License
205
+
206
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,19 @@
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=`
2
+ html, body { height: 100%; }
3
+ body {
4
+ margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
+ -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
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;
11
+ z-index: 0;
12
+ display: block;
13
+ }
14
+ /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
15
+ .star-ui {
16
+ position: absolute; inset: 0; width: 100%; height: 100%;
17
+ overflow-y: auto; z-index: 10;
18
+ }
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});
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Star DOM SDK v0.6.7
3
+ * MIT License
4
+ * https://buildwithstar.com
5
+ *
6
+ * A tiny, reliable DOM & Canvas SDK for browser games.
7
+ * Solves common LLM bugs: DOM timing, null listeners,
8
+ * canvas sizing/DPR, and canvas-vs-UI conflicts.
9
+ *
10
+ * Designed for LLMs and humans: owns the iframe <body>,
11
+ * provides a scrollable UI overlay, stable loop with dt,
12
+ * DPR-correct canvas sizing, and safe delegated events.
13
+ *
14
+ * ~1.5KB min+gz, zero deps, SSR-safe, iframe-first.
15
+ */
16
+ declare const version = "0.7.0";
17
+ declare global {
18
+ interface Window {
19
+ __STAR_DOM__?: {
20
+ destroy: () => void;
21
+ };
22
+ }
23
+ }
24
+ type GameTick = (dt: number, now: number) => void;
25
+ interface GameLoop {
26
+ start: () => void;
27
+ stop: () => void;
28
+ readonly running: boolean;
29
+ }
30
+ interface GameUI {
31
+ /** The root <div> element for UI, stacked on top of the canvas. */
32
+ readonly root: HTMLElement;
33
+ /** Safely replaces the content of the UI overlay. */
34
+ render: (html: string) => void;
35
+ /** Scoped querySelector for the UI root. */
36
+ el: <T extends Element = HTMLElement>(selector: string) => T | null;
37
+ /** Scoped querySelectorAll for the UI root. */
38
+ all: <T extends Element = HTMLElement>(selector: string) => NodeListOf<T>;
39
+ }
40
+ interface GameContext {
41
+ /** The root <div> element for the canvas. */
42
+ readonly stage: HTMLElement;
43
+ /** The canvas element. */
44
+ readonly canvas: HTMLCanvasElement;
45
+ /** The 2D rendering context. */
46
+ readonly ctx: CanvasRenderingContext2D;
47
+ /** Logical width (CSS px). Use this for game logic. Default: 640 (landscape) or 360 (portrait). */
48
+ readonly width: number;
49
+ /** Logical height (CSS px). Use this for game logic. Default: 360 (landscape) or 640 (portrait). */
50
+ readonly height: number;
51
+ /** Effective device pixel ratio. */
52
+ readonly dpr: number;
53
+ /** Safely attaches delegated event listeners to the document. */
54
+ on: (type: string, selector: string, handler: (this: Element, ev: Event) => void, options?: AddEventListenerOptions) => () => void;
55
+ /** Starts a stable, auto-starting game loop. */
56
+ loop: (tick: GameTick) => GameLoop;
57
+ /** The dedicated UI overlay manager. */
58
+ readonly ui: GameUI;
59
+ /** Converts DOM event coords to logical stage coords (CSS px). */
60
+ toStagePoint: (e: {
61
+ clientX: number;
62
+ clientY: number;
63
+ }) => {
64
+ x: number;
65
+ y: number;
66
+ };
67
+ /** Creates a drag state helper for pointer-based dragging. Handles coordinate conversion and offset. */
68
+ createDrag: <T extends {
69
+ x: number;
70
+ y: number;
71
+ }>() => DragState<T>;
72
+ /** Re-calculates stage size (rarely needed). */
73
+ resize: () => void;
74
+ /** Cleans up all listeners and observers. */
75
+ destroy: () => void;
76
+ /** Runs a function with ctx.save/restore automatically managed. */
77
+ scoped: (fn: () => void) => void;
78
+ }
79
+ interface GameOptions {
80
+ /**
81
+ * Preset for common game orientations (all use 16:9 aspect ratio with letterboxing).
82
+ * - 'landscape' (default): 640x360, works identically on all devices
83
+ * - 'portrait': 360x640, for mobile-style games
84
+ * - 'responsive': No fixed dimensions, fills container (legacy behavior, gameplay varies by device)
85
+ */
86
+ preset?: 'landscape' | 'portrait' | 'responsive';
87
+ /**
88
+ * Logical width for fixed-size stages (e.g., 800).
89
+ * Default: 640 (landscape preset).
90
+ */
91
+ width?: number;
92
+ /**
93
+ * Logical height for fixed-size stages (e.g., 600).
94
+ * Default: 360 (landscape preset).
95
+ */
96
+ height?: number;
97
+ /**
98
+ * How a fixed-size stage fits its container.
99
+ * - 'contain' (default): Letterbox/pillarbox to fit.
100
+ * - 'cover': Fill container and crop.
101
+ * - 'stretch': Distort to fill container.
102
+ */
103
+ fit?: 'contain' | 'cover' | 'stretch';
104
+ /**
105
+ * Backing store DPR. 'device' (default) or a number.
106
+ */
107
+ pixelRatio?: 'device' | number;
108
+ /**
109
+ * Max cap for 'device' DPR. Default: 2.
110
+ */
111
+ maxPixelRatio?: number;
112
+ /**
113
+ * 2D context attributes (e.g., { alpha: false }).
114
+ */
115
+ contextAttributes?: CanvasRenderingContext2DSettings;
116
+ /**
117
+ * Prevent context menu on canvas. Default: true.
118
+ */
119
+ preventContextMenu?: boolean;
120
+ }
121
+ /** Drag state helper - handles coordinate conversion and offset tracking */
122
+ interface DragState<T extends {
123
+ x: number;
124
+ y: number;
125
+ }> {
126
+ /** Convert event to stage coordinates (pure function, no side effects) */
127
+ point: (e: {
128
+ clientX: number;
129
+ clientY: number;
130
+ }) => {
131
+ x: number;
132
+ y: number;
133
+ };
134
+ /** Start dragging an object - computes offset from cursor to object origin */
135
+ grab: (e: {
136
+ clientX: number;
137
+ clientY: number;
138
+ }, obj: T) => void;
139
+ /** Update the grabbed object's position based on pointer movement */
140
+ move: (e: {
141
+ clientX: number;
142
+ clientY: number;
143
+ }) => void;
144
+ /** Release the grabbed object and return it (or null if nothing was grabbed) */
145
+ release: () => T | null;
146
+ /** The currently grabbed object (or null) */
147
+ readonly dragging: T | null;
148
+ }
149
+ /** Creates a drag state helper that handles coordinate conversion and offset tracking */
150
+ declare function createDragState<T extends {
151
+ x: number;
152
+ y: number;
153
+ }>(toStagePoint: (e: {
154
+ clientX: number;
155
+ clientY: number;
156
+ }) => {
157
+ x: number;
158
+ y: number;
159
+ }): DragState<T>;
160
+ /**
161
+ * The main entry point. Runs setup when the DOM is ready,
162
+ * providing a safe context for building a game.
163
+ */
164
+ declare function game(setup: (g: GameContext) => void, options?: GameOptions): void;
165
+
166
+ export { type DragState, type GameContext, type GameLoop, type GameOptions, type GameTick, type GameUI, createDragState, game, version };
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Star DOM SDK v0.6.7
3
+ * MIT License
4
+ * https://buildwithstar.com
5
+ *
6
+ * A tiny, reliable DOM & Canvas SDK for browser games.
7
+ * Solves common LLM bugs: DOM timing, null listeners,
8
+ * canvas sizing/DPR, and canvas-vs-UI conflicts.
9
+ *
10
+ * Designed for LLMs and humans: owns the iframe <body>,
11
+ * provides a scrollable UI overlay, stable loop with dt,
12
+ * DPR-correct canvas sizing, and safe delegated events.
13
+ *
14
+ * ~1.5KB min+gz, zero deps, SSR-safe, iframe-first.
15
+ */
16
+ declare const version = "0.7.0";
17
+ declare global {
18
+ interface Window {
19
+ __STAR_DOM__?: {
20
+ destroy: () => void;
21
+ };
22
+ }
23
+ }
24
+ type GameTick = (dt: number, now: number) => void;
25
+ interface GameLoop {
26
+ start: () => void;
27
+ stop: () => void;
28
+ readonly running: boolean;
29
+ }
30
+ interface GameUI {
31
+ /** The root <div> element for UI, stacked on top of the canvas. */
32
+ readonly root: HTMLElement;
33
+ /** Safely replaces the content of the UI overlay. */
34
+ render: (html: string) => void;
35
+ /** Scoped querySelector for the UI root. */
36
+ el: <T extends Element = HTMLElement>(selector: string) => T | null;
37
+ /** Scoped querySelectorAll for the UI root. */
38
+ all: <T extends Element = HTMLElement>(selector: string) => NodeListOf<T>;
39
+ }
40
+ interface GameContext {
41
+ /** The root <div> element for the canvas. */
42
+ readonly stage: HTMLElement;
43
+ /** The canvas element. */
44
+ readonly canvas: HTMLCanvasElement;
45
+ /** The 2D rendering context. */
46
+ readonly ctx: CanvasRenderingContext2D;
47
+ /** Logical width (CSS px). Use this for game logic. Default: 640 (landscape) or 360 (portrait). */
48
+ readonly width: number;
49
+ /** Logical height (CSS px). Use this for game logic. Default: 360 (landscape) or 640 (portrait). */
50
+ readonly height: number;
51
+ /** Effective device pixel ratio. */
52
+ readonly dpr: number;
53
+ /** Safely attaches delegated event listeners to the document. */
54
+ on: (type: string, selector: string, handler: (this: Element, ev: Event) => void, options?: AddEventListenerOptions) => () => void;
55
+ /** Starts a stable, auto-starting game loop. */
56
+ loop: (tick: GameTick) => GameLoop;
57
+ /** The dedicated UI overlay manager. */
58
+ readonly ui: GameUI;
59
+ /** Converts DOM event coords to logical stage coords (CSS px). */
60
+ toStagePoint: (e: {
61
+ clientX: number;
62
+ clientY: number;
63
+ }) => {
64
+ x: number;
65
+ y: number;
66
+ };
67
+ /** Creates a drag state helper for pointer-based dragging. Handles coordinate conversion and offset. */
68
+ createDrag: <T extends {
69
+ x: number;
70
+ y: number;
71
+ }>() => DragState<T>;
72
+ /** Re-calculates stage size (rarely needed). */
73
+ resize: () => void;
74
+ /** Cleans up all listeners and observers. */
75
+ destroy: () => void;
76
+ /** Runs a function with ctx.save/restore automatically managed. */
77
+ scoped: (fn: () => void) => void;
78
+ }
79
+ interface GameOptions {
80
+ /**
81
+ * Preset for common game orientations (all use 16:9 aspect ratio with letterboxing).
82
+ * - 'landscape' (default): 640x360, works identically on all devices
83
+ * - 'portrait': 360x640, for mobile-style games
84
+ * - 'responsive': No fixed dimensions, fills container (legacy behavior, gameplay varies by device)
85
+ */
86
+ preset?: 'landscape' | 'portrait' | 'responsive';
87
+ /**
88
+ * Logical width for fixed-size stages (e.g., 800).
89
+ * Default: 640 (landscape preset).
90
+ */
91
+ width?: number;
92
+ /**
93
+ * Logical height for fixed-size stages (e.g., 600).
94
+ * Default: 360 (landscape preset).
95
+ */
96
+ height?: number;
97
+ /**
98
+ * How a fixed-size stage fits its container.
99
+ * - 'contain' (default): Letterbox/pillarbox to fit.
100
+ * - 'cover': Fill container and crop.
101
+ * - 'stretch': Distort to fill container.
102
+ */
103
+ fit?: 'contain' | 'cover' | 'stretch';
104
+ /**
105
+ * Backing store DPR. 'device' (default) or a number.
106
+ */
107
+ pixelRatio?: 'device' | number;
108
+ /**
109
+ * Max cap for 'device' DPR. Default: 2.
110
+ */
111
+ maxPixelRatio?: number;
112
+ /**
113
+ * 2D context attributes (e.g., { alpha: false }).
114
+ */
115
+ contextAttributes?: CanvasRenderingContext2DSettings;
116
+ /**
117
+ * Prevent context menu on canvas. Default: true.
118
+ */
119
+ preventContextMenu?: boolean;
120
+ }
121
+ /** Drag state helper - handles coordinate conversion and offset tracking */
122
+ interface DragState<T extends {
123
+ x: number;
124
+ y: number;
125
+ }> {
126
+ /** Convert event to stage coordinates (pure function, no side effects) */
127
+ point: (e: {
128
+ clientX: number;
129
+ clientY: number;
130
+ }) => {
131
+ x: number;
132
+ y: number;
133
+ };
134
+ /** Start dragging an object - computes offset from cursor to object origin */
135
+ grab: (e: {
136
+ clientX: number;
137
+ clientY: number;
138
+ }, obj: T) => void;
139
+ /** Update the grabbed object's position based on pointer movement */
140
+ move: (e: {
141
+ clientX: number;
142
+ clientY: number;
143
+ }) => void;
144
+ /** Release the grabbed object and return it (or null if nothing was grabbed) */
145
+ release: () => T | null;
146
+ /** The currently grabbed object (or null) */
147
+ readonly dragging: T | null;
148
+ }
149
+ /** Creates a drag state helper that handles coordinate conversion and offset tracking */
150
+ declare function createDragState<T extends {
151
+ x: number;
152
+ y: number;
153
+ }>(toStagePoint: (e: {
154
+ clientX: number;
155
+ clientY: number;
156
+ }) => {
157
+ x: number;
158
+ y: number;
159
+ }): DragState<T>;
160
+ /**
161
+ * The main entry point. Runs setup when the DOM is ready,
162
+ * providing a safe context for building a game.
163
+ */
164
+ declare function game(setup: (g: GameContext) => void, options?: GameOptions): void;
165
+
166
+ export { type DragState, type GameContext, type GameLoop, type GameOptions, type GameTick, type GameUI, createDragState, game, version };
package/dist/index.mjs ADDED
@@ -0,0 +1,19 @@
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=`
2
+ html, body { height: 100%; }
3
+ body {
4
+ margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
+ -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
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;
11
+ z-index: 0;
12
+ display: block;
13
+ }
14
+ /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
15
+ .star-ui {
16
+ position: absolute; inset: 0; width: 100%; height: 100%;
17
+ overflow-y: auto; z-index: 10;
18
+ }
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};
@@ -0,0 +1,19 @@
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=`
2
+ html, body { height: 100%; }
3
+ body {
4
+ margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
+ -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
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;
11
+ z-index: 0;
12
+ display: block;
13
+ }
14
+ /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
15
+ .star-ui {
16
+ position: absolute; inset: 0; width: 100%; height: 100%;
17
+ overflow-y: auto; z-index: 10;
18
+ }
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});
@@ -0,0 +1,19 @@
1
+ import { GameContext, GameOptions } from './index.cjs';
2
+ export { DragState, GameLoop, GameTick, GameUI, createDragState, version } from './index.cjs';
3
+
4
+ /**
5
+ * Star DOM SDK - Legacy Entry Point
6
+ *
7
+ * This entry point preserves backward compatibility with games created before v0.7.
8
+ * It defaults to 'responsive' mode (no fixed dimensions).
9
+ *
10
+ * New games should use the main entry point which defaults to 'landscape' preset.
11
+ */
12
+
13
+ /**
14
+ * Legacy game entry point - defaults to responsive mode for backward compatibility.
15
+ * New games should use '/star-sdk/dom-v1.js' which defaults to fixed-height mode.
16
+ */
17
+ declare function game(setup: (g: GameContext) => void, options?: GameOptions): void;
18
+
19
+ export { GameContext, GameOptions, game };
@@ -0,0 +1,19 @@
1
+ import { GameContext, GameOptions } from './index.js';
2
+ export { DragState, GameLoop, GameTick, GameUI, createDragState, version } from './index.js';
3
+
4
+ /**
5
+ * Star DOM SDK - Legacy Entry Point
6
+ *
7
+ * This entry point preserves backward compatibility with games created before v0.7.
8
+ * It defaults to 'responsive' mode (no fixed dimensions).
9
+ *
10
+ * New games should use the main entry point which defaults to 'landscape' preset.
11
+ */
12
+
13
+ /**
14
+ * Legacy game entry point - defaults to responsive mode for backward compatibility.
15
+ * New games should use '/star-sdk/dom-v1.js' which defaults to fixed-height mode.
16
+ */
17
+ declare function game(setup: (g: GameContext) => void, options?: GameOptions): void;
18
+
19
+ export { GameContext, GameOptions, game };
@@ -0,0 +1,19 @@
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=`
2
+ html, body { height: 100%; }
3
+ body {
4
+ margin: 0; min-height: 100dvh; overflow: hidden; background: #000;
5
+ -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
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;
11
+ z-index: 0;
12
+ display: block;
13
+ }
14
+ /* UI overlay - interactive and scrollable by default (standard CSS behavior) */
15
+ .star-ui {
16
+ position: absolute; inset: 0; width: 100%; height: 100%;
17
+ overflow-y: auto; z-index: 10;
18
+ }
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};
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "star-canvas",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "Canvas game utilities for reliable game initialization - part of Star SDK.",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "starSdk": {
9
+ "internalImport": "import { game } from '/star-sdk/v1/dom.js';",
10
+ "publicImport": "import { game } from 'star-canvas';",
11
+ "publicPath": "dist/index.mjs",
12
+ "outputs": [
13
+ { "src": "dist/legacy.mjs", "dest": "dom.js" },
14
+ { "src": "dist/index.mjs", "dest": "v1/dom.js" }
15
+ ],
16
+ "skill": {
17
+ "name": "star-dom-sdk",
18
+ "description": "Star DOM SDK for canvas games and UI. Use when working with canvas rendering, game loops, sprites, input handling, UI overlays, or the game() initialization function."
19
+ }
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.mjs",
25
+ "require": "./dist/index.cjs"
26
+ },
27
+ "./*": {
28
+ "types": "./dist/*.d.ts",
29
+ "import": "./dist/*.mjs",
30
+ "require": "./dist/*.cjs"
31
+ }
32
+ },
33
+ "module": "./dist/index.mjs",
34
+ "main": "./dist/index.cjs",
35
+ "types": "./dist/index.d.ts",
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "clean": "rm -rf dist",
42
+ "prepublishOnly": "node ../../apps/web/scripts/process-sdks.js --package star-canvas --public-only && yarn build"
43
+ },
44
+ "keywords": [
45
+ "dom",
46
+ "canvas",
47
+ "game-loop",
48
+ "mobile",
49
+ "responsive",
50
+ "dpr",
51
+ "retina",
52
+ "games",
53
+ "web",
54
+ "nextjs",
55
+ "vite",
56
+ "typescript"
57
+ ],
58
+ "dependencies": {},
59
+ "devDependencies": {
60
+ "tsup": "^8.0.2",
61
+ "typescript": "^5.4.5"
62
+ }
63
+ }