incanto 0.68.0 → 0.69.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.
Files changed (75) hide show
  1. package/assets/catalog.json +9 -5
  2. package/bin/incanto-assets.mjs +14 -1
  3. package/bin/incanto-check.mjs +53 -3
  4. package/bin/incanto-new.mjs +29 -1
  5. package/bin/incanto-serve.mjs +160 -0
  6. package/bin/incanto-verify.mjs +40 -0
  7. package/bin/incanto.mjs +1 -0
  8. package/dist/2d.d.ts +7 -5
  9. package/dist/2d.js +4 -4
  10. package/dist/3d.d.ts +4 -4
  11. package/dist/3d.js +7 -7
  12. package/dist/{audio-player-DOrq7sP-.d.ts → audio-player-C0j2k-yB.d.ts} +32 -13
  13. package/dist/{behavior-DoFPYrgo.d.ts → behavior-rm8vVzu_.d.ts} +67 -0
  14. package/dist/{create-game-DbWtVTxD.js → create-game-CvJ1wSRP.js} +13 -9
  15. package/dist/{create-game-IZIydDwI.js → create-game-CwxEDlCm.js} +13 -9
  16. package/dist/debug.d.ts +1 -1
  17. package/dist/{duplicate-IWIqk0HJ.js → duplicate-Dj4L-5AA.js} +1 -1
  18. package/dist/editor.js +1 -1
  19. package/dist/{environment-presets-CybQXNqS.js → environment-presets-BO-7XoFV.js} +4 -4
  20. package/dist/{frame-report-DCnHFmto.d.ts → frame-report-DNxDAb1w.d.ts} +8 -0
  21. package/dist/{frame-report-BSMny7oe.js → frame-report-Dlq13Gyj.js} +1 -0
  22. package/dist/{gameplay-DM1eu_cV.js → gameplay-D1KixWK8.js} +157 -151
  23. package/dist/gameplay.d.ts +1 -1
  24. package/dist/gameplay.js +1 -1
  25. package/dist/index.d.ts +4 -4
  26. package/dist/index.js +6 -6
  27. package/dist/{loader-BC4PNtJX.js → loader-DZE7B07H.js} +22 -6
  28. package/dist/{loader-CcB533FR.d.ts → loader-DadV2QCT.d.ts} +1 -1
  29. package/dist/net.d.ts +2 -2
  30. package/dist/net.js +1 -1
  31. package/dist/{physics-2d-B7Y6dPZO.js → physics-2d-CF5yyjbj.js} +2 -2
  32. package/dist/{physics-3d-bG3n70Ky.js → physics-3d-DbYaEcZy.js} +3 -3
  33. package/dist/react.d.ts +1 -1
  34. package/dist/react.js +1 -1
  35. package/dist/{register-ibCjm-wH.js → register-DbVArsns.js} +19 -10
  36. package/dist/{register-3ta-2Xig.js → register-mmfugpaQ.js} +107 -15
  37. package/dist/{replay-CYvhVHHN.js → replay-BEHLDcQV.js} +2 -2
  38. package/dist/{replay-Dvn8aeBd.d.ts → replay-BQfkX4x7.d.ts} +1 -1
  39. package/dist/{sheet-grid-BT6N_Bjs.js → sheet-grid-Cea343VO.js} +6 -2
  40. package/dist/{split-screen-CYwDkbLF.js → split-screen-CauMwu6y.js} +2 -2
  41. package/dist/{split-screen-DhrSzZIB.d.ts → split-screen-Cg76MCV5.d.ts} +2 -2
  42. package/dist/{src-D7RIqXYF.js → src-CYEu-_S9.js} +1 -1
  43. package/dist/{teardown-D2NEmxPB.js → teardown-CMqFVxO9.js} +5 -4
  44. package/dist/{test-8hoHeRmo.js → test-D6ISmuFE.js} +60 -17
  45. package/dist/test.d.ts +15 -4
  46. package/dist/test.js +2 -2
  47. package/dist/vite.d.ts +70 -2
  48. package/dist/vite.js +176 -14
  49. package/dist/{webgl-unavailable-N9nQqesw.js → webgl-unavailable-Z5_g8x9H.js} +12 -1
  50. package/editor/assets/{agent8-BrrHOjMJ.js → agent8-BDvaZMQJ.js} +1 -1
  51. package/editor/assets/{debug-BBhKuBNV.js → debug-CMULinBW.js} +1 -1
  52. package/editor/assets/{index-eVd0BToA.js → index-CZIRr5EL.js} +91 -91
  53. package/editor/index.html +1 -1
  54. package/package.json +4 -3
  55. package/skills/incanto-assets.md +16 -2
  56. package/skills/incanto-audio.md +19 -3
  57. package/skills/incanto-building-2d-games.md +29 -0
  58. package/skills/incanto-building-3d-games.md +60 -2
  59. package/skills/incanto-gameplay-behaviors.md +18 -1
  60. package/skills/incanto-save-slots.md +27 -0
  61. package/skills/incanto-verifying-your-game.md +96 -2
  62. package/skills/incanto-your-first-game.md +2 -1
  63. package/templates-app/beacon-isle-3d/package.json +1 -1
  64. package/templates-app/beacon-isle-3d/src/main.ts +13 -3
  65. package/templates-app/platformer-2d/index.html +0 -23
  66. package/templates-app/platformer-2d/package.json +1 -1
  67. package/templates-app/platformer-2d/src/behaviors.ts +26 -16
  68. package/templates-app/platformer-2d/src/game.scene.json +17 -27
  69. package/templates-app/platformer-2d/src/main.ts +24 -12
  70. package/templates-app/star-survivor/package.json +1 -1
  71. package/templates-app/star-survivor/src/main.ts +17 -6
  72. package/templates-app/tps-3d/package.json +1 -1
  73. package/templates-app/tps-3d/src/main.ts +26 -15
  74. package/templates-app/village-quest-3d/package.json +1 -1
  75. package/templates-app/village-quest-3d/src/main.ts +13 -3
package/dist/vite.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as FrameSignature } from "./frame-report-DCnHFmto.js";
1
+ import { n as FrameSignature } from "./frame-report-DNxDAb1w.js";
2
2
 
3
3
  //#region src/vite/discover.d.ts
4
4
  /**
@@ -76,6 +76,74 @@ interface FrameEndpointOptions {
76
76
  }
77
77
  declare function serveFrameEndpoints(host: FrameHost, version: string, opts?: FrameEndpointOptions): void;
78
78
  //#endregion
79
+ //#region src/vite/static-inspect.d.ts
80
+ interface StaticInspectHost extends FrameHost {
81
+ /** Handle `/__incanto/pull` and `/__incanto/push`; returns false if not ours. */
82
+ handleInspect(req: FrameReq, res: FrameRes): boolean;
83
+ /** The `<script>` to inject ahead of the game, as page source. */
84
+ clientScript(): string;
85
+ }
86
+ /**
87
+ * Build a `FrameHost` whose channel is a long poll.
88
+ *
89
+ * `use(path, handler)` records middleware the caller dispatches; `hot` is a
90
+ * channel that queues outgoing requests and delivers the page's replies.
91
+ */
92
+ declare function createStaticInspectHost(root: string): StaticInspectHost;
93
+ //#endregion
94
+ //#region src/vite/trim.d.ts
95
+ /**
96
+ * Leave out of the BUILD what this game can never run.
97
+ *
98
+ * A 2D game's `dist/` contains the 3D adapter and rapier3d. Measured on the
99
+ * shipped `platformer-2d` flagship:
100
+ *
101
+ * ```
102
+ * 2236503 assets/rapier-*.js # rapier3d
103
+ * 1692150 assets/rapier-*.js # rapier2d — the one it uses
104
+ * 471186 assets/3d-*.js # the 3D adapter
105
+ * ─────────
106
+ * 5942650 total → 45.6% of it can never execute
107
+ * ```
108
+ *
109
+ * Nothing is wrong at RUNTIME: the chunks are lazy and never requested. This is
110
+ * deploy weight — a CDN, a jam upload, an agent8 zip — and the only path that
111
+ * drags them in is the live game⇄editor switch: `createGame*` imports
112
+ * `incanto/editor`, and the editor imports `incanto/3d` so it can offer 3D node
113
+ * types.
114
+ *
115
+ * `editor: false` on `createGame*` is a RUNTIME option and cannot remove bytes
116
+ * from a bundle; it changed the artifact by 10 bytes while the docs said it
117
+ * "opts out". A build-time decision needs a build-time lever, which is this.
118
+ *
119
+ * ```ts
120
+ * import { incantoScenes, incantoTrim } from 'incanto/vite';
121
+ * export default defineConfig({
122
+ * plugins: [incantoScenes(), incantoTrim({ editor: false })],
123
+ * });
124
+ * ```
125
+ *
126
+ * Build only — the dev server keeps the editor, so `☰ debug ▸ ✎ edit this
127
+ * scene` works while you are building the game and is simply absent from what
128
+ * you ship.
129
+ */
130
+ interface IncantoTrimOptions {
131
+ /**
132
+ * Keep the in-game scene editor in the build. Default `false` when this
133
+ * plugin is used at all — using it is the request.
134
+ */
135
+ editor?: boolean;
136
+ }
137
+ /** Minimal plugin shape, so this file needs no vite types. */
138
+ interface TrimPlugin {
139
+ name: string;
140
+ apply: "build";
141
+ enforce: "pre";
142
+ resolveId(id: string): string | null;
143
+ load(id: string): string | null;
144
+ }
145
+ declare function incantoTrim(opts?: IncantoTrimOptions): TrimPlugin;
146
+ //#endregion
79
147
  //#region src/vite/index.d.ts
80
148
  interface HotUpdateContext {
81
149
  file: string;
@@ -259,4 +327,4 @@ declare function serveDeviceAuth(req: LibraryReq, res: LibraryRes, opts?: Incant
259
327
  /** @internal Exported for tests — the whole request/response behaviour. */
260
328
  declare function serveLibrary(req: LibraryReq, res: LibraryRes, opts?: IncantoLibraryOptions, doFetch?: typeof fetch): Promise<void>;
261
329
  //#endregion
262
- export { type FrameHost, IncantoLibraryOptions, IncantoScenesOptions, ProjectFileEntry, discoverScenes, incantoLibrary, incantoScenes, listeningPorts, maskToken, parseProcNetTcp, resolveSceneFile, sceneFacts, serveDeviceAuth, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList, serveTokenStatus };
330
+ export { type FrameHost, type FrameReq, type FrameRes, IncantoLibraryOptions, IncantoScenesOptions, type IncantoTrimOptions, ProjectFileEntry, type StaticInspectHost, createStaticInspectHost, discoverScenes, incantoLibrary, incantoScenes, incantoTrim, listeningPorts, maskToken, parseProcNetTcp, resolveSceneFile, sceneFacts, serveDeviceAuth, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList, serveTokenStatus };
package/dist/vite.js CHANGED
@@ -1,6 +1,6 @@
1
- import { t as VERSION } from "./src-D7RIqXYF.js";
2
- import { n as diffSignatures } from "./frame-report-BSMny7oe.js";
3
- import { s as validateScene } from "./test-8hoHeRmo.js";
1
+ import { t as VERSION } from "./src-CYEu-_S9.js";
2
+ import { n as diffSignatures } from "./frame-report-Dlq13Gyj.js";
3
+ import { s as validateScene } from "./test-D6ISmuFE.js";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
5
5
  import { basename, dirname, join, normalize, relative, resolve, sep } from "node:path";
6
6
  //#region src/vite/frame-endpoint.ts
@@ -71,7 +71,7 @@ function serveFrameEndpoints(host, version, opts = {}) {
71
71
  c.on("incanto:logs-report", onReport);
72
72
  }
73
73
  host.middlewares.use("/__incanto/ping", (_req, res) => {
74
- json$1(res, 200, {
74
+ json$2(res, 200, {
75
75
  incanto: version,
76
76
  frame: Boolean(channel),
77
77
  root: host.config?.root ?? process.cwd(),
@@ -81,7 +81,7 @@ function serveFrameEndpoints(host, version, opts = {}) {
81
81
  serveLogs(host, channels, waiting, () => nextId++, timeoutMs);
82
82
  host.middlewares.use("/__incanto/frame", (req, res) => {
83
83
  if (!channel) {
84
- json$1(res, 503, { error: "no-hmr-channel" });
84
+ json$2(res, 503, { error: "no-hmr-channel" });
85
85
  return;
86
86
  }
87
87
  const params = query(req);
@@ -95,13 +95,13 @@ function serveFrameEndpoints(host, version, opts = {}) {
95
95
  const id = nextId++;
96
96
  const timer = setTimeout(() => {
97
97
  waiting.delete(id);
98
- json$1(res, 504, { error: acked.delete(id) ? "page-not-drawing" : "no-page-connected" });
98
+ json$2(res, 504, { error: acked.delete(id) ? "page-not-drawing" : "no-page-connected" });
99
99
  }, timeoutMs + (driveMs > 0 ? driveMs * 2 + 2e3 : 0));
100
100
  waiting.set(id, (value) => {
101
101
  clearTimeout(timer);
102
102
  acked.delete(id);
103
103
  if (!value.ok) {
104
- json$1(res, 500, { error: "capture-failed" });
104
+ json$2(res, 500, { error: "capture-failed" });
105
105
  return;
106
106
  }
107
107
  const full = value.report;
@@ -119,7 +119,7 @@ function serveFrameEndpoints(host, version, opts = {}) {
119
119
  store.set(remember || DEFAULT_LABEL, signature);
120
120
  body.remembered = remember || DEFAULT_LABEL;
121
121
  }
122
- json$1(res, 200, body);
122
+ json$2(res, 200, body);
123
123
  });
124
124
  for (const c of channels) c.send({
125
125
  type: "custom",
@@ -142,21 +142,21 @@ function serveFrameEndpoints(host, version, opts = {}) {
142
142
  function serveLogs(host, channels, waiting, nextId, timeoutMs) {
143
143
  host.middlewares.use("/__incanto/logs", (_req, res) => {
144
144
  if (channels.length === 0) {
145
- json$1(res, 503, { error: "no-hmr-channel" });
145
+ json$2(res, 503, { error: "no-hmr-channel" });
146
146
  return;
147
147
  }
148
148
  const id = nextId();
149
149
  const timer = setTimeout(() => {
150
150
  waiting.delete(id);
151
- json$1(res, 504, { error: "no-page-connected" });
151
+ json$2(res, 504, { error: "no-page-connected" });
152
152
  }, timeoutMs);
153
153
  waiting.set(id, (value) => {
154
154
  clearTimeout(timer);
155
155
  if (!value.ok) {
156
- json$1(res, 500, { error: "report-failed" });
156
+ json$2(res, 500, { error: "report-failed" });
157
157
  return;
158
158
  }
159
- json$1(res, 200, { report: value.report });
159
+ json$2(res, 200, { report: value.report });
160
160
  });
161
161
  for (const c of channels) c.send({
162
162
  type: "custom",
@@ -178,7 +178,7 @@ function parseGrid(text) {
178
178
  const rows = Number(m[2]);
179
179
  return cols > 0 && rows > 0 ? [cols, rows] : void 0;
180
180
  }
181
- function json$1(res, status, body) {
181
+ function json$2(res, status, body) {
182
182
  res.statusCode = status;
183
183
  res.setHeader("content-type", "application/json");
184
184
  res.end(JSON.stringify(body));
@@ -255,6 +255,168 @@ async function listeningPorts(deps) {
255
255
  return out;
256
256
  }
257
257
  //#endregion
258
+ //#region src/vite/static-inspect.ts
259
+ /**
260
+ * Build a `FrameHost` whose channel is a long poll.
261
+ *
262
+ * `use(path, handler)` records middleware the caller dispatches; `hot` is a
263
+ * channel that queues outgoing requests and delivers the page's replies.
264
+ */
265
+ function createStaticInspectHost(root) {
266
+ const routes = [];
267
+ const listeners = /* @__PURE__ */ new Map();
268
+ const queue = [];
269
+ let waiter = null;
270
+ return {
271
+ config: { root },
272
+ middlewares: { use(path, handler) {
273
+ routes.push([path, handler]);
274
+ } },
275
+ hot: {
276
+ send(payload) {
277
+ const item = {
278
+ event: payload.event,
279
+ data: payload.data
280
+ };
281
+ if (waiter) {
282
+ const resolve = waiter;
283
+ waiter = null;
284
+ resolve(item);
285
+ return;
286
+ }
287
+ queue.push(item);
288
+ if (queue.length > 32) queue.shift();
289
+ },
290
+ on(event, cb) {
291
+ const list = listeners.get(event) ?? [];
292
+ list.push(cb);
293
+ listeners.set(event, list);
294
+ }
295
+ },
296
+ handleInspect(req, res) {
297
+ const url = (req.originalUrl ?? req.url ?? "").split("?")[0] ?? "";
298
+ if (url === "/__incanto/pull") {
299
+ const next = queue.shift();
300
+ if (next) {
301
+ json$1(res, next);
302
+ return true;
303
+ }
304
+ const timer = setTimeout(() => {
305
+ if (waiter) {
306
+ waiter = null;
307
+ json$1(res, null);
308
+ }
309
+ }, 25e3);
310
+ waiter = (value) => {
311
+ clearTimeout(timer);
312
+ json$1(res, value);
313
+ };
314
+ return true;
315
+ }
316
+ if (url === "/__incanto/push") {
317
+ readBody$1(req, (body) => {
318
+ const message = safeParse(body);
319
+ if (message?.event) for (const cb of listeners.get(message.event) ?? []) cb(message.data);
320
+ json$1(res, { ok: true });
321
+ });
322
+ return true;
323
+ }
324
+ for (const [path, handler] of routes) if (url === path || url.startsWith(`${path}/`)) {
325
+ handler(req, res);
326
+ return true;
327
+ }
328
+ return false;
329
+ },
330
+ clientScript: () => CLIENT
331
+ };
332
+ }
333
+ function json$1(res, body) {
334
+ res.statusCode = 200;
335
+ res.setHeader("content-type", "application/json");
336
+ res.end(JSON.stringify(body ?? {}));
337
+ }
338
+ function safeParse(text) {
339
+ try {
340
+ return JSON.parse(text);
341
+ } catch {
342
+ return null;
343
+ }
344
+ }
345
+ function readBody$1(req, done) {
346
+ const stream = req;
347
+ let body = "";
348
+ stream.on("data", (chunk) => {
349
+ body += String(chunk);
350
+ });
351
+ stream.on("end", () => done(body));
352
+ }
353
+ /**
354
+ * The page half: installs a channel shaped like vite's HMR, so `wireDevChannel`
355
+ * cannot tell the difference.
356
+ *
357
+ * Injected by `incanto-serve` into the served `index.html`, never bundled — a
358
+ * production build stays exactly what the author deployed, and this only exists
359
+ * while they are looking at it.
360
+ */
361
+ const CLIENT = `(() => {
362
+ const listeners = new Map();
363
+ const post = (event, data) =>
364
+ fetch('/__incanto/push', {
365
+ method: 'POST',
366
+ headers: { 'content-type': 'application/json' },
367
+ body: JSON.stringify({ event: event, data: data }),
368
+ }).catch(() => {});
369
+ globalThis.__incantoInspect = {
370
+ send: (event, data) => post(event, data),
371
+ on: (event, cb) => {
372
+ const list = listeners.get(event) || [];
373
+ list.push(cb);
374
+ listeners.set(event, list);
375
+ },
376
+ off: (event, cb) => {
377
+ const list = (listeners.get(event) || []).filter((f) => f !== cb);
378
+ listeners.set(event, list);
379
+ },
380
+ };
381
+ const pull = () => {
382
+ fetch('/__incanto/pull')
383
+ .then((r) => r.json())
384
+ .then((message) => {
385
+ if (message && message.event) {
386
+ for (const cb of listeners.get(message.event) || []) cb(message.data);
387
+ }
388
+ pull();
389
+ })
390
+ .catch(() => setTimeout(pull, 1000));
391
+ };
392
+ pull();
393
+ })();`;
394
+ //#endregion
395
+ //#region src/vite/trim.ts
396
+ const VIRTUAL = "\0incanto-trimmed-editor";
397
+ function incantoTrim(opts = {}) {
398
+ const keepEditor = opts.editor === true;
399
+ return {
400
+ name: "incanto:trim",
401
+ apply: "build",
402
+ enforce: "pre",
403
+ resolveId(id) {
404
+ if (!keepEditor && id === "incanto/editor") return VIRTUAL;
405
+ return null;
406
+ },
407
+ load(id) {
408
+ if (id !== VIRTUAL) return null;
409
+ return `export function mountEditor() {
410
+ throw new Error(
411
+ 'incanto: the scene editor was left out of this build by incantoTrim({ editor: false }). ' +
412
+ 'Run the dev server to edit scenes, or pass incantoTrim({ editor: true }) to include it.',
413
+ );
414
+ }
415
+ `;
416
+ }
417
+ };
418
+ }
419
+ //#endregion
258
420
  //#region src/vite/index.ts
259
421
  /**
260
422
  * incanto/vite — dev-server integration: validate every `*.scene.json` edit
@@ -734,4 +896,4 @@ function libraryItem(row) {
734
896
  };
735
897
  }
736
898
  //#endregion
737
- export { discoverScenes, incantoLibrary, incantoScenes, listeningPorts, maskToken, parseProcNetTcp, resolveSceneFile, sceneFacts, serveDeviceAuth, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList, serveTokenStatus };
899
+ export { createStaticInspectHost, discoverScenes, incantoLibrary, incantoScenes, incantoTrim, listeningPorts, maskToken, parseProcNetTcp, resolveSceneFile, sceneFacts, serveDeviceAuth, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList, serveTokenStatus };
@@ -103,6 +103,13 @@ const RANK = {
103
103
  error: 3
104
104
  };
105
105
  /** Under this, with the loop running, is a frame rate somebody can feel. */
106
+ /**
107
+ * How stale the newest frame may be before the rate stops describing NOW.
108
+ *
109
+ * A live game is always a frame or two behind; a third of a second is about
110
+ * twenty dropped frames, which is not a hiccup.
111
+ */
112
+ const STALE_FRAME_MS = 350;
106
113
  const SLOW_FPS = 50;
107
114
  /** How many distinct messages to carry. Beyond this it is a log file, not a report. */
108
115
  const MAX_GROUPS = 20;
@@ -167,7 +174,11 @@ function logText(r) {
167
174
  if (lines.length === 0) lines.push("nothing wrong — no warnings, no errors, no failed assets");
168
175
  if (!r.stats.running) lines.push(`not running — the loop is stopped (${r.stats.nodes} nodes in the scene)`);
169
176
  else if (r.hidden) lines.push(`${r.stats.nodes} nodes · frame rate not measurable — the page is hidden (a window covered by another counts), and the browser throttles it. Bring it to the front`);
170
- else lines.push(`${Math.round(r.stats.fps)} fps · ${r.stats.frameMs.toFixed(1)}ms per frame · ${r.stats.nodes} nodes${r.slow ? " — slow enough to feel" : ""}`);
177
+ else {
178
+ const age = r.stats.lastFrameAgeMs;
179
+ const stale = age !== null && age > STALE_FRAME_MS;
180
+ lines.push(`${Math.round(r.stats.fps)} fps · ${r.stats.frameMs.toFixed(1)}ms per frame · ${r.stats.nodes} nodes${r.slow ? " — slow enough to feel" : ""}` + (stale ? ` — measured ${(age / 1e3).toFixed(1)}s ago; nothing has drawn since, so this is the rate the game HAD, not the rate it has` : ""));
181
+ }
171
182
  return lines.join("\n");
172
183
  }
173
184
  //#endregion
@@ -1 +1 @@
1
- import{n as e}from"./index-eVd0BToA.js";async function t(t){return new n((await e(()=>import(`./GameServer-C56iOUgF.js`),[],import.meta.url)).GameServer,t)}var n=class{raw;active=new Map;reconnecting=!1;disposed=!1;constructor(e,t){this.raw=new e({...t})}get account(){return this.raw.account}get connected(){return this.raw.connected}connect(){return this.raw.connected?Promise.resolve(!0):(this.disposed=!1,this.rawConnect())}rawConnect(){return this.raw.connect({onDisconnect:()=>void this.reconnect()})}disconnect(){this.disposed=!0;for(let e of this.active.values())e.off();return this.active.clear(),this.raw.disconnect()}remoteFunction(e,t,n){return this.raw.remoteFunction(e,t,n)}track(e){let t=Symbol(`sub`),n={make:e,off:e()};return this.active.set(t,n),()=>{n.off(),this.active.delete(t)}}async reconnect(){if(!this.disposed&&!this.reconnecting){this.reconnecting=!0;try{await this.rawConnect();for(let e of this.active.values())e.off(),e.off=e.make()}finally{this.reconnecting=!1}}}subscribeRoomState(e,t){return this.track(()=>this.raw.subscribeRoomState(e,t))}subscribeRoomMyState(e,t){return this.track(()=>this.raw.subscribeRoomMyState(e,t))}subscribeRoomAllUserStates(e,t){return this.track(()=>this.raw.subscribeRoomAllUserStates(e,e=>{let n={};for(let t of e??[]){if(!t||typeof t.account!=`string`||t.__leaved)continue;let{account:e,__updated:r,__leaved:i,...a}=t;n[e]=a}t(n)}))}subscribeRoomCollection(e,t,n){return this.track(()=>this.raw.subscribeRoomCollection(e,t,({items:e})=>{let t={};for(let n of e??[])n&&typeof n.__id==`string`&&(t[n.__id]=n);n(t)}))}onRoomMessage(e,t,n){return this.track(()=>this.raw.onRoomMessage(e,t,n))}onRoomUserJoin(e,t){return this.track(()=>this.raw.onRoomUserJoin(e,t))}onRoomUserLeave(e,t){return this.track(()=>this.raw.onRoomUserLeave(e,t))}subscribeGlobalState(e){return this.track(()=>this.raw.subscribeGlobalState(e))}subscribeGlobalMyState(e){return this.track(()=>this.raw.subscribeGlobalMyState(e))}subscribeGlobalUserState(e,t){return this.track(()=>this.raw.subscribeGlobalUserState(e,t))}subscribeGlobalCollection(e,t){return this.track(()=>this.raw.subscribeGlobalCollection(e,({items:e})=>{let n={};for(let t of e??[])t&&typeof t.__id==`string`&&(n[t.__id]=t);t(n)}))}subscribeAsset(e,t){return this.track(()=>this.raw.subscribeAsset(e,t))}onGlobalMessage(e,t){return this.track(()=>this.raw.onGlobalMessage(e,t))}};export{t as createAgent8Server};
1
+ import{n as e}from"./index-CZIRr5EL.js";async function t(t){return new n((await e(()=>import(`./GameServer-C56iOUgF.js`),[],import.meta.url)).GameServer,t)}var n=class{raw;active=new Map;reconnecting=!1;disposed=!1;constructor(e,t){this.raw=new e({...t})}get account(){return this.raw.account}get connected(){return this.raw.connected}connect(){return this.raw.connected?Promise.resolve(!0):(this.disposed=!1,this.rawConnect())}rawConnect(){return this.raw.connect({onDisconnect:()=>void this.reconnect()})}disconnect(){this.disposed=!0;for(let e of this.active.values())e.off();return this.active.clear(),this.raw.disconnect()}remoteFunction(e,t,n){return this.raw.remoteFunction(e,t,n)}track(e){let t=Symbol(`sub`),n={make:e,off:e()};return this.active.set(t,n),()=>{n.off(),this.active.delete(t)}}async reconnect(){if(!this.disposed&&!this.reconnecting){this.reconnecting=!0;try{await this.rawConnect();for(let e of this.active.values())e.off(),e.off=e.make()}finally{this.reconnecting=!1}}}subscribeRoomState(e,t){return this.track(()=>this.raw.subscribeRoomState(e,t))}subscribeRoomMyState(e,t){return this.track(()=>this.raw.subscribeRoomMyState(e,t))}subscribeRoomAllUserStates(e,t){return this.track(()=>this.raw.subscribeRoomAllUserStates(e,e=>{let n={};for(let t of e??[]){if(!t||typeof t.account!=`string`||t.__leaved)continue;let{account:e,__updated:r,__leaved:i,...a}=t;n[e]=a}t(n)}))}subscribeRoomCollection(e,t,n){return this.track(()=>this.raw.subscribeRoomCollection(e,t,({items:e})=>{let t={};for(let n of e??[])n&&typeof n.__id==`string`&&(t[n.__id]=n);n(t)}))}onRoomMessage(e,t,n){return this.track(()=>this.raw.onRoomMessage(e,t,n))}onRoomUserJoin(e,t){return this.track(()=>this.raw.onRoomUserJoin(e,t))}onRoomUserLeave(e,t){return this.track(()=>this.raw.onRoomUserLeave(e,t))}subscribeGlobalState(e){return this.track(()=>this.raw.subscribeGlobalState(e))}subscribeGlobalMyState(e){return this.track(()=>this.raw.subscribeGlobalMyState(e))}subscribeGlobalUserState(e,t){return this.track(()=>this.raw.subscribeGlobalUserState(e,t))}subscribeGlobalCollection(e,t){return this.track(()=>this.raw.subscribeGlobalCollection(e,({items:e})=>{let n={};for(let t of e??[])t&&typeof t.__id==`string`&&(n[t.__id]=t);t(n)}))}subscribeAsset(e,t){return this.track(()=>this.raw.subscribeAsset(e,t))}onGlobalMessage(e,t){return this.track(()=>this.raw.onGlobalMessage(e,t))}};export{t as createAgent8Server};
@@ -1,3 +1,3 @@
1
- import{a as e,i as t,r as n,t as r}from"./index-eVd0BToA.js";function i(e,t,n,r=1){let i=Math.min(e.x0,e.x1)*r,a=Math.max(e.x0,e.x1)*r,o=Math.min(e.y0,e.y1)*r,s=Math.max(e.y0,e.y1)*r,c=Math.max(0,Math.min(Math.round(i),t-1)),l=Math.max(0,Math.min(Math.round(o),n-1));return{x:c,y:l,w:Math.max(1,Math.min(Math.round(a-i),t-c)),h:Math.max(1,Math.min(Math.round(s-o),n-l))}}function a(e,t,n,r){let{x:i,y:a,w:o,h:s}=r,c=new Uint8ClampedArray(o*s*4);for(let n=0;n<s;n++){let r=((a+n)*t+i)*4,s=n*o*4;c.set(e.subarray(r,r+o*4),s)}return{pixels:c,width:o,height:s}}function o(e){if(!e)return`// no scene loaded`;let t=e.source??e;return JSON.stringify(t,null,2)}async function s(e){let t=globalThis.navigator;if(!t?.clipboard?.writeText)return!1;try{return await t.clipboard.writeText(e),!0}catch{return!1}}async function c(e,t){let n=globalThis,r=n.navigator?.clipboard?.write;if(!r||!n.ImageData||!n.ClipboardItem)return!1;try{let i=e.createElement(`canvas`);i.width=t.width,i.height=t.height;let a=i.getContext(`2d`);if(!a)return!1;a.putImageData(new n.ImageData(t.pixels,t.width,t.height),0,0);let o=await new Promise(e=>i.toBlob(e,`image/png`));return o?(await r.call(n.navigator?.clipboard,[new n.ClipboardItem({"image/png":o})]),!0):!1}catch{return!1}}var l=[`nw`,`n`,`ne`,`e`,`se`,`s`,`sw`,`w`],u={nw:[0,0],n:[.5,0],ne:[1,0],e:[1,.5],se:[1,1],s:[.5,1],sw:[0,1],w:[0,.5]},d={nw:`nwse-resize`,se:`nwse-resize`,ne:`nesw-resize`,sw:`nesw-resize`,n:`ns-resize`,s:`ns-resize`,e:`ew-resize`,w:`ew-resize`},f=(e,t,n)=>Math.max(t,Math.min(n,e));function p(e){return{x:Math.min(e.x0,e.x1),y:Math.min(e.y0,e.y1),w:Math.abs(e.x1-e.x0),h:Math.abs(e.y1-e.y0)}}function m(e,t,n,r,i,a){let o=e.x,s=e.y,c=e.x+e.w,l=e.y+e.h;return t.includes(`w`)&&(o=f(o+n,0,i)),t.includes(`e`)&&(c=f(c+n,0,i)),t.includes(`n`)&&(s=f(s+r,0,a)),t.includes(`s`)&&(l=f(l+r,0,a)),{x:Math.min(o,c),y:Math.min(s,l),w:Math.max(1,Math.abs(c-o)),h:Math.max(1,Math.abs(l-s))}}function h(e,t,n,r,i){return{...e,x:f(e.x+t,0,Math.max(0,r-e.w)),y:f(e.y+n,0,Math.max(0,i-e.h))}}function g(e,t,n,r,i,a=8){let o=f(e.x+e.w/2-t/2,a,Math.max(a,r-t-a)),s=e.y+e.h+a,c=e.y-n-a;return{x:o,y:s+n<=i-a?s:c>=a?c:f(s,a,Math.max(a,i-n-a))}}function _(e,t,n,r,i,a,o=180,s=120){let c=Math.max(o,n),l=Math.max(s,r);return{x:Math.min(Math.max(0,e),Math.max(0,i-c)),y:Math.min(Math.max(0,t),Math.max(0,a-l)),w:c,h:l}}function v(e,t,n,r,i,a=4){let o=Math.min(Math.max(0,e.x),Math.max(0,r-t)),s=e.y+e.h+a,c=e.y-n-a;return s+n<=i?{x:o,y:s}:c>=0?{x:o,y:c}:{x:o,y:Math.min(Math.max(0,s),Math.max(0,i-n))}}function y(e,t,n){let r=e=>{e.key===`Escape`&&n()},i=e=>{let r=e.target;if(r){for(let e of t)if(e&&(e===r||e.contains?.(r)))return;n()}};return e.addEventListener?.(`keydown`,r),e.addEventListener?.(`pointerdown`,i),()=>{e.removeEventListener?.(`keydown`,r),e.removeEventListener?.(`pointerdown`,i)}}function b(e,t){for(let[n,r]of Object.entries(t))e.style[n]=r}var x=`rgba(18, 20, 26, 0.92)`,S=`1px solid rgba(255,255,255,0.14)`,C=`12px ui-monospace, SFMono-Regular, Menlo, monospace`,w=class{host;el;body;onClose=()=>{};x;y;w;h;constructor(e,t,n,r){this.host=t,this.x=r.x,this.y=r.y,this.w=r.w,this.h=r.h,this.el=e.createElement(`div`),b(this.el,{position:`absolute`,background:x,border:S,borderRadius:`8px`,color:`rgba(255,255,255,0.88)`,font:C,display:`flex`,flexDirection:`column`,overflow:`hidden`,zIndex:`40`,pointerEvents:`auto`,boxShadow:`0 8px 28px rgba(0,0,0,0.45)`});let i=e.createElement(`div`);i.textContent=n,b(i,{padding:`6px 28px 6px 10px`,background:`rgba(255,255,255,0.07)`,cursor:`move`,userSelect:`none`,touchAction:`none`,fontWeight:`700`}),this.el.appendChild(i);let a=e.createElement(`div`);a.textContent=`×`,a.title=`close`,b(a,{position:`absolute`,top:`2px`,right:`8px`,cursor:`pointer`,fontSize:`16px`,lineHeight:`20px`,opacity:`0.7`}),a.addEventListener(`click`,()=>this.onClose()),this.el.appendChild(a),this.body=e.createElement(`div`),b(this.body,{flex:`1`,overflow:`auto`,padding:`8px 10px`}),this.el.appendChild(this.body);let o=e.createElement(`div`);o.textContent=`◢`,b(o,{position:`absolute`,right:`2px`,bottom:`0`,cursor:`nwse-resize`,opacity:`0.5`,userSelect:`none`,touchAction:`none`}),this.el.appendChild(o),this.wireDrag(i,(e,t)=>{this.x+=e,this.y+=t,this.layout()}),this.wireDrag(o,(e,t)=>{this.w+=e,this.h+=t,this.layout()}),this.layout(),t.appendChild(this.el)}remove(){this.el.remove()}layout(){let e=this.host.getBoundingClientRect(),t=_(this.x,this.y,this.w,this.h,e.width,e.height);this.x=t.x,this.y=t.y,this.w=t.w,this.h=t.h,b(this.el,{left:`${t.x}px`,top:`${t.y}px`,width:`${t.w}px`,height:`${t.h}px`})}wireDrag(e,t){let r=null,i=0,a=0;e.addEventListener(`pointerdown`,t=>{r=t.pointerId,i=t.clientX,a=t.clientY,n(e,t.pointerId)}),e.addEventListener(`pointermove`,e=>{e.pointerId===r&&(t(e.clientX-i,e.clientY-a),i=e.clientX,a=e.clientY)});let o=e=>{e.pointerId===r&&(r=null)};e.addEventListener(`pointerup`,o),e.addEventListener(`pointercancel`,o)}},T=4,E=`#6ee7dc`,D=`rgba(18,20,26,0.94)`,O=`12px ui-monospace, Menlo, monospace`;function k(e){let{doc:t,container:r}=e,i=t.createElement(`div`);b(i,{position:`absolute`,inset:`0`,cursor:`crosshair`,zIndex:`80`,pointerEvents:`auto`,userSelect:`none`,touchAction:`none`});let a=t.createElement(`div`);b(a,{position:`absolute`,inset:`0`,background:`rgba(10,14,20,0.35)`,pointerEvents:`none`}),i.appendChild(a);let o=t.createElement(`div`);b(o,{position:`absolute`,outline:`1px solid ${E}`,boxShadow:`0 0 0 9999px rgba(10,14,20,0.35)`,cursor:`grab`,display:`none`,pointerEvents:`auto`}),i.appendChild(o);let s=t.createElement(`div`);b(s,{position:`absolute`,padding:`2px 6px`,borderRadius:`4px`,background:D,color:E,font:O,pointerEvents:`none`,display:`none`,whiteSpace:`nowrap`}),i.appendChild(s);let c=t.createElement(`div`);c.textContent=`drag to select · Esc to cancel`,b(c,{position:`absolute`,top:`10px`,left:`50%`,transform:`translateX(-50%)`,padding:`4px 10px`,borderRadius:`6px`,background:D,color:`rgba(255,255,255,0.85)`,font:O,pointerEvents:`none`,whiteSpace:`nowrap`}),i.appendChild(c);let f=null,_=`idle`,v={x:0,y:0},y={x:0,y:0,w:0,h:0},x=()=>({w:r.clientWidth||1,h:r.clientHeight||1});for(let e of l){let n=t.createElement(`div`),[r,i]=u[e];b(n,{position:`absolute`,left:`${r*100}%`,top:`${i*100}%`,width:`10px`,height:`10px`,marginLeft:`-5px`,marginTop:`-5px`,borderRadius:`2px`,background:E,border:`1px solid rgba(10,14,20,0.75)`,cursor:d[e],pointerEvents:`auto`}),n.addEventListener(`pointerdown`,t=>{A(t,e)}),o.appendChild(n)}let S=t.createElement(`div`);b(S,{position:`absolute`,display:`none`,gap:`6px`,padding:`6px`,borderRadius:`8px`,background:D,border:`1px solid rgba(255,255,255,0.18)`,font:O,pointerEvents:`auto`,whiteSpace:`nowrap`,boxShadow:`0 4px 16px rgba(0,0,0,0.45)`});let C=(e,n,r)=>{let i=t.createElement(`div`);return i.textContent=e,b(i,{padding:`5px 10px`,borderRadius:`5px`,cursor:`pointer`,color:n?`#08121a`:`rgba(255,255,255,0.85)`,background:n?E:`rgba(255,255,255,0.08)`,userSelect:`none`}),i.addEventListener(`pointerdown`,e=>{w(e),r()}),i};S.appendChild(C(`Copy to clipboard`,!0,()=>P())),S.appendChild(C(`Cancel`,!1,()=>L())),i.appendChild(S);function w(e){e.preventDefault?.(),e.stopPropagation?.()}function k(e){let t=e,n=r.getBoundingClientRect?.()??{left:0,top:0};return{x:(t.clientX??0)-n.left,y:(t.clientY??0)-n.top}}function A(e,t){w(e),v=k(e),_=t,t===`create`?f={x:v.x,y:v.y,w:0,h:0}:f&&(y=f),b(S,{display:`none`}),b(o,{cursor:t===`move`?`grabbing`:`crosshair`});let r=e.pointerId;r!==void 0&&n(i,r),j()}function j(){if(!f){b(o,{display:`none`}),b(s,{display:`none`}),b(a,{display:`block`});return}b(a,{display:`none`}),b(o,{display:`block`,left:`${f.x}px`,top:`${f.y}px`,width:`${f.w}px`,height:`${f.h}px`});let t=e.scale();s.textContent=`${Math.round(f.w*t)}×${Math.round(f.h*t)}`;let n=f.y-24;b(s,{display:`block`,left:`${Math.max(2,f.x)}px`,top:`${n>=2?n:f.y+4}px`})}function M(){if(!f||f.w<T||f.h<T)return;b(S,{display:`flex`});let e=x(),t=S.offsetWidth||200,n=S.offsetHeight||36,r=g(f,t,n,e.w,e.h);b(S,{left:`${r.x}px`,top:`${r.y}px`})}i.addEventListener(`pointerdown`,e=>{A(e,`create`)}),o.addEventListener(`pointerdown`,e=>{A(e,`move`)}),i.addEventListener(`pointermove`,e=>{if(_===`idle`||!f)return;let t=k(e),n=x();if(_===`create`){let e=p({x0:v.x,y0:v.y,x1:t.x,y1:t.y});f={x:Math.max(0,Math.min(e.x,n.w)),y:Math.max(0,Math.min(e.y,n.h)),w:Math.min(e.w,n.w-Math.max(0,Math.min(e.x,n.w))),h:Math.min(e.h,n.h-Math.max(0,Math.min(e.y,n.h)))}}else f=_===`move`?h(y,t.x-v.x,t.y-v.y,n.w,n.h):m(y,_,t.x-v.x,t.y-v.y,n.w,n.h);j()});let N=()=>{_!==`idle`&&(_===`create`&&f&&(f.w<T||f.h<T)&&(f=null),_=`idle`,b(o,{cursor:`grab`}),c.textContent=f?`drag the handles or the middle · Enter to copy · Esc to cancel`:`drag to select · Esc to cancel`,j(),M())};i.addEventListener(`pointerup`,N),i.addEventListener(`pointercancel`,N);function P(){let t=f;L(),t&&e.onCopy(t)}let F=e=>{let t=e.key;t===`Escape`?L():t===`Enter`&&f&&P()};t.addEventListener?.(`keydown`,F);let I=!1;function L(){I||(I=!0,t.removeEventListener?.(`keydown`,F),i.remove(),e.onClose())}return r.appendChild(i),{element:i,close:L}}var A=96,j=200,M=8192;function N(e){return Array.isArray(e)?`Array(${e.length})`:`Object(${Object.keys(e).length} keys)`}function P(e,t){if(Array.isArray(e)&&e.some(e=>typeof e==`object`&&!!e)){let t=e.slice(0,j).map(e=>JSON.stringify(e)),n=e.length-j;return t.join(`
1
+ import{a as e,i as t,r as n,t as r}from"./index-CZIRr5EL.js";function i(e,t,n,r=1){let i=Math.min(e.x0,e.x1)*r,a=Math.max(e.x0,e.x1)*r,o=Math.min(e.y0,e.y1)*r,s=Math.max(e.y0,e.y1)*r,c=Math.max(0,Math.min(Math.round(i),t-1)),l=Math.max(0,Math.min(Math.round(o),n-1));return{x:c,y:l,w:Math.max(1,Math.min(Math.round(a-i),t-c)),h:Math.max(1,Math.min(Math.round(s-o),n-l))}}function a(e,t,n,r){let{x:i,y:a,w:o,h:s}=r,c=new Uint8ClampedArray(o*s*4);for(let n=0;n<s;n++){let r=((a+n)*t+i)*4,s=n*o*4;c.set(e.subarray(r,r+o*4),s)}return{pixels:c,width:o,height:s}}function o(e){if(!e)return`// no scene loaded`;let t=e.source??e;return JSON.stringify(t,null,2)}async function s(e){let t=globalThis.navigator;if(!t?.clipboard?.writeText)return!1;try{return await t.clipboard.writeText(e),!0}catch{return!1}}async function c(e,t){let n=globalThis,r=n.navigator?.clipboard?.write;if(!r||!n.ImageData||!n.ClipboardItem)return!1;try{let i=e.createElement(`canvas`);i.width=t.width,i.height=t.height;let a=i.getContext(`2d`);if(!a)return!1;a.putImageData(new n.ImageData(t.pixels,t.width,t.height),0,0);let o=await new Promise(e=>i.toBlob(e,`image/png`));return o?(await r.call(n.navigator?.clipboard,[new n.ClipboardItem({"image/png":o})]),!0):!1}catch{return!1}}var l=[`nw`,`n`,`ne`,`e`,`se`,`s`,`sw`,`w`],u={nw:[0,0],n:[.5,0],ne:[1,0],e:[1,.5],se:[1,1],s:[.5,1],sw:[0,1],w:[0,.5]},d={nw:`nwse-resize`,se:`nwse-resize`,ne:`nesw-resize`,sw:`nesw-resize`,n:`ns-resize`,s:`ns-resize`,e:`ew-resize`,w:`ew-resize`},f=(e,t,n)=>Math.max(t,Math.min(n,e));function p(e){return{x:Math.min(e.x0,e.x1),y:Math.min(e.y0,e.y1),w:Math.abs(e.x1-e.x0),h:Math.abs(e.y1-e.y0)}}function m(e,t,n,r,i,a){let o=e.x,s=e.y,c=e.x+e.w,l=e.y+e.h;return t.includes(`w`)&&(o=f(o+n,0,i)),t.includes(`e`)&&(c=f(c+n,0,i)),t.includes(`n`)&&(s=f(s+r,0,a)),t.includes(`s`)&&(l=f(l+r,0,a)),{x:Math.min(o,c),y:Math.min(s,l),w:Math.max(1,Math.abs(c-o)),h:Math.max(1,Math.abs(l-s))}}function h(e,t,n,r,i){return{...e,x:f(e.x+t,0,Math.max(0,r-e.w)),y:f(e.y+n,0,Math.max(0,i-e.h))}}function g(e,t,n,r,i,a=8){let o=f(e.x+e.w/2-t/2,a,Math.max(a,r-t-a)),s=e.y+e.h+a,c=e.y-n-a;return{x:o,y:s+n<=i-a?s:c>=a?c:f(s,a,Math.max(a,i-n-a))}}function _(e,t,n,r,i,a,o=180,s=120){let c=Math.max(o,n),l=Math.max(s,r);return{x:Math.min(Math.max(0,e),Math.max(0,i-c)),y:Math.min(Math.max(0,t),Math.max(0,a-l)),w:c,h:l}}function v(e,t,n,r,i,a=4){let o=Math.min(Math.max(0,e.x),Math.max(0,r-t)),s=e.y+e.h+a,c=e.y-n-a;return s+n<=i?{x:o,y:s}:c>=0?{x:o,y:c}:{x:o,y:Math.min(Math.max(0,s),Math.max(0,i-n))}}function y(e,t,n){let r=e=>{e.key===`Escape`&&n()},i=e=>{let r=e.target;if(r){for(let e of t)if(e&&(e===r||e.contains?.(r)))return;n()}};return e.addEventListener?.(`keydown`,r),e.addEventListener?.(`pointerdown`,i),()=>{e.removeEventListener?.(`keydown`,r),e.removeEventListener?.(`pointerdown`,i)}}function b(e,t){for(let[n,r]of Object.entries(t))e.style[n]=r}var x=`rgba(18, 20, 26, 0.92)`,S=`1px solid rgba(255,255,255,0.14)`,C=`12px ui-monospace, SFMono-Regular, Menlo, monospace`,w=class{host;el;body;onClose=()=>{};x;y;w;h;constructor(e,t,n,r){this.host=t,this.x=r.x,this.y=r.y,this.w=r.w,this.h=r.h,this.el=e.createElement(`div`),b(this.el,{position:`absolute`,background:x,border:S,borderRadius:`8px`,color:`rgba(255,255,255,0.88)`,font:C,display:`flex`,flexDirection:`column`,overflow:`hidden`,zIndex:`40`,pointerEvents:`auto`,boxShadow:`0 8px 28px rgba(0,0,0,0.45)`});let i=e.createElement(`div`);i.textContent=n,b(i,{padding:`6px 28px 6px 10px`,background:`rgba(255,255,255,0.07)`,cursor:`move`,userSelect:`none`,touchAction:`none`,fontWeight:`700`}),this.el.appendChild(i);let a=e.createElement(`div`);a.textContent=`×`,a.title=`close`,b(a,{position:`absolute`,top:`2px`,right:`8px`,cursor:`pointer`,fontSize:`16px`,lineHeight:`20px`,opacity:`0.7`}),a.addEventListener(`click`,()=>this.onClose()),this.el.appendChild(a),this.body=e.createElement(`div`),b(this.body,{flex:`1`,overflow:`auto`,padding:`8px 10px`}),this.el.appendChild(this.body);let o=e.createElement(`div`);o.textContent=`◢`,b(o,{position:`absolute`,right:`2px`,bottom:`0`,cursor:`nwse-resize`,opacity:`0.5`,userSelect:`none`,touchAction:`none`}),this.el.appendChild(o),this.wireDrag(i,(e,t)=>{this.x+=e,this.y+=t,this.layout()}),this.wireDrag(o,(e,t)=>{this.w+=e,this.h+=t,this.layout()}),this.layout(),t.appendChild(this.el)}remove(){this.el.remove()}layout(){let e=this.host.getBoundingClientRect(),t=_(this.x,this.y,this.w,this.h,e.width,e.height);this.x=t.x,this.y=t.y,this.w=t.w,this.h=t.h,b(this.el,{left:`${t.x}px`,top:`${t.y}px`,width:`${t.w}px`,height:`${t.h}px`})}wireDrag(e,t){let r=null,i=0,a=0;e.addEventListener(`pointerdown`,t=>{r=t.pointerId,i=t.clientX,a=t.clientY,n(e,t.pointerId)}),e.addEventListener(`pointermove`,e=>{e.pointerId===r&&(t(e.clientX-i,e.clientY-a),i=e.clientX,a=e.clientY)});let o=e=>{e.pointerId===r&&(r=null)};e.addEventListener(`pointerup`,o),e.addEventListener(`pointercancel`,o)}},T=4,E=`#6ee7dc`,D=`rgba(18,20,26,0.94)`,O=`12px ui-monospace, Menlo, monospace`;function k(e){let{doc:t,container:r}=e,i=t.createElement(`div`);b(i,{position:`absolute`,inset:`0`,cursor:`crosshair`,zIndex:`80`,pointerEvents:`auto`,userSelect:`none`,touchAction:`none`});let a=t.createElement(`div`);b(a,{position:`absolute`,inset:`0`,background:`rgba(10,14,20,0.35)`,pointerEvents:`none`}),i.appendChild(a);let o=t.createElement(`div`);b(o,{position:`absolute`,outline:`1px solid ${E}`,boxShadow:`0 0 0 9999px rgba(10,14,20,0.35)`,cursor:`grab`,display:`none`,pointerEvents:`auto`}),i.appendChild(o);let s=t.createElement(`div`);b(s,{position:`absolute`,padding:`2px 6px`,borderRadius:`4px`,background:D,color:E,font:O,pointerEvents:`none`,display:`none`,whiteSpace:`nowrap`}),i.appendChild(s);let c=t.createElement(`div`);c.textContent=`drag to select · Esc to cancel`,b(c,{position:`absolute`,top:`10px`,left:`50%`,transform:`translateX(-50%)`,padding:`4px 10px`,borderRadius:`6px`,background:D,color:`rgba(255,255,255,0.85)`,font:O,pointerEvents:`none`,whiteSpace:`nowrap`}),i.appendChild(c);let f=null,_=`idle`,v={x:0,y:0},y={x:0,y:0,w:0,h:0},x=()=>({w:r.clientWidth||1,h:r.clientHeight||1});for(let e of l){let n=t.createElement(`div`),[r,i]=u[e];b(n,{position:`absolute`,left:`${r*100}%`,top:`${i*100}%`,width:`10px`,height:`10px`,marginLeft:`-5px`,marginTop:`-5px`,borderRadius:`2px`,background:E,border:`1px solid rgba(10,14,20,0.75)`,cursor:d[e],pointerEvents:`auto`}),n.addEventListener(`pointerdown`,t=>{A(t,e)}),o.appendChild(n)}let S=t.createElement(`div`);b(S,{position:`absolute`,display:`none`,gap:`6px`,padding:`6px`,borderRadius:`8px`,background:D,border:`1px solid rgba(255,255,255,0.18)`,font:O,pointerEvents:`auto`,whiteSpace:`nowrap`,boxShadow:`0 4px 16px rgba(0,0,0,0.45)`});let C=(e,n,r)=>{let i=t.createElement(`div`);return i.textContent=e,b(i,{padding:`5px 10px`,borderRadius:`5px`,cursor:`pointer`,color:n?`#08121a`:`rgba(255,255,255,0.85)`,background:n?E:`rgba(255,255,255,0.08)`,userSelect:`none`}),i.addEventListener(`pointerdown`,e=>{w(e),r()}),i};S.appendChild(C(`Copy to clipboard`,!0,()=>P())),S.appendChild(C(`Cancel`,!1,()=>L())),i.appendChild(S);function w(e){e.preventDefault?.(),e.stopPropagation?.()}function k(e){let t=e,n=r.getBoundingClientRect?.()??{left:0,top:0};return{x:(t.clientX??0)-n.left,y:(t.clientY??0)-n.top}}function A(e,t){w(e),v=k(e),_=t,t===`create`?f={x:v.x,y:v.y,w:0,h:0}:f&&(y=f),b(S,{display:`none`}),b(o,{cursor:t===`move`?`grabbing`:`crosshair`});let r=e.pointerId;r!==void 0&&n(i,r),j()}function j(){if(!f){b(o,{display:`none`}),b(s,{display:`none`}),b(a,{display:`block`});return}b(a,{display:`none`}),b(o,{display:`block`,left:`${f.x}px`,top:`${f.y}px`,width:`${f.w}px`,height:`${f.h}px`});let t=e.scale();s.textContent=`${Math.round(f.w*t)}×${Math.round(f.h*t)}`;let n=f.y-24;b(s,{display:`block`,left:`${Math.max(2,f.x)}px`,top:`${n>=2?n:f.y+4}px`})}function M(){if(!f||f.w<T||f.h<T)return;b(S,{display:`flex`});let e=x(),t=S.offsetWidth||200,n=S.offsetHeight||36,r=g(f,t,n,e.w,e.h);b(S,{left:`${r.x}px`,top:`${r.y}px`})}i.addEventListener(`pointerdown`,e=>{A(e,`create`)}),o.addEventListener(`pointerdown`,e=>{A(e,`move`)}),i.addEventListener(`pointermove`,e=>{if(_===`idle`||!f)return;let t=k(e),n=x();if(_===`create`){let e=p({x0:v.x,y0:v.y,x1:t.x,y1:t.y});f={x:Math.max(0,Math.min(e.x,n.w)),y:Math.max(0,Math.min(e.y,n.h)),w:Math.min(e.w,n.w-Math.max(0,Math.min(e.x,n.w))),h:Math.min(e.h,n.h-Math.max(0,Math.min(e.y,n.h)))}}else f=_===`move`?h(y,t.x-v.x,t.y-v.y,n.w,n.h):m(y,_,t.x-v.x,t.y-v.y,n.w,n.h);j()});let N=()=>{_!==`idle`&&(_===`create`&&f&&(f.w<T||f.h<T)&&(f=null),_=`idle`,b(o,{cursor:`grab`}),c.textContent=f?`drag the handles or the middle · Enter to copy · Esc to cancel`:`drag to select · Esc to cancel`,j(),M())};i.addEventListener(`pointerup`,N),i.addEventListener(`pointercancel`,N);function P(){let t=f;L(),t&&e.onCopy(t)}let F=e=>{let t=e.key;t===`Escape`?L():t===`Enter`&&f&&P()};t.addEventListener?.(`keydown`,F);let I=!1;function L(){I||(I=!0,t.removeEventListener?.(`keydown`,F),i.remove(),e.onClose())}return r.appendChild(i),{element:i,close:L}}var A=96,j=200,M=8192;function N(e){return Array.isArray(e)?`Array(${e.length})`:`Object(${Object.keys(e).length} keys)`}function P(e,t){if(Array.isArray(e)&&e.some(e=>typeof e==`object`&&!!e)){let t=e.slice(0,j).map(e=>JSON.stringify(e)),n=e.length-j;return t.join(`
2
2
  `)+(n>0?`\n… ${n} more`:``)}return t.length>M?`${t.slice(0,M)} … (${t.length-M} more chars)`:t}function F(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var I=2,L=4;function R(e,t={}){let n=t.doc??(typeof document<`u`?document:null);if(!n)return null;let r=t.container??(typeof document<`u`?document.body:null);return!r||typeof r.appendChild!=`function`?null:new V(e,r,n,t.statsSource,t.actions,t.frameSource)}var z=300,B=[`log`,`info`,`warn`,`error`,`debug`],V=class{engine;container;doc;statsSource;actions;frameSource;panels=new Map;cleanups=[];menuButton;dropdown=null;dismissDropdown=null;menuPos={x:8,y:8};selected=null;collapsedFlags=new Map;statsChip=null;logRows=[];levelEnabled={debug:!0,info:!0,warn:!0,error:!0};consoleCapture=!1;consolePatched=[];frame=0;editing=0;detailOpen=new WeakMap;resumeScale=1;timeEls=null;hovering=!1;constructor(e,t,n,r,i=[],a){this.engine=e,this.container=t,this.doc=n,this.statsSource=r,this.actions=i,this.frameSource=a,this.menuButton=n.createElement(`div`),this.menuButton.textContent=`☰ debug`,b(this.menuButton,{position:`absolute`,top:`8px`,left:`8px`,padding:`4px 10px`,background:`rgba(18,20,26,0.85)`,border:`1px solid rgba(255,255,255,0.18)`,borderRadius:`6px`,color:`rgba(255,255,255,0.85)`,font:`12px ui-monospace, Menlo, monospace`,cursor:`pointer`,userSelect:`none`,zIndex:`50`,pointerEvents:`auto`}),this.bindMenuDrag(),t.style.position||(t.style.position=`relative`),t.appendChild(this.menuButton),this.cleanups.push(e.log.added.connect(e=>{this.pushLog({level:e.level,source:`engine`,text:e.parts.map(W).join(` `)})})),this.cleanups.push(e.sceneChanged.connect(()=>{this.selected=null,this.applyColliderScope(),this.renderExplorer(),this.renderInspector()})),this.cleanups.push(e.updated.connect(()=>{this.frame+=1,this.frame%30==0&&(this.renderExplorer(),this.renderStats(),this.editing===0&&!this.hovering&&this.renderInspector(),this.syncTime())}))}isOpen(e){return e===`copyScene`||e===`captureRegion`?!1:e===`colliders`?this.colliderMode!==`off`:e===`stats`?this.statsChip!==null:this.panels.has(e)}colliderMode=`off`;setColliders(e){this.colliderMode=e,this.applyColliderScope()}applyColliderScope(){let e=this.colliderMode;for(let t of r(`2d`).concat(r(`3d`)))t.debugDraw=e!==`off`,t.debugScope=e===`selected`?this.selected:null}open(e){if(e===`stats`){this.openStatsChip();return}if(this.panels.has(e)){e===`explorer`&&this.renderExplorer(),e===`inspector`&&this.renderInspector(),e===`logs`&&this.renderLogs(),e===`time`&&this.renderTime();return}let t=new w(this.doc,this.container,{explorer:`Explorer`,inspector:`Inspector`,logs:`Logs`,time:`Time`}[e],{explorer:{x:12,y:44,w:240,h:320},inspector:{x:264,y:44,w:280,h:320},logs:{x:12,y:380,w:532,h:200},time:{x:556,y:44,w:260,h:150}}[e]);t.onClose=()=>this.close(e),e===`inspector`&&(t.body.addEventListener(`pointerenter`,()=>{this.hovering=!0}),t.body.addEventListener(`pointerleave`,()=>{this.hovering=!1})),this.panels.set(e,t),e===`explorer`&&this.renderExplorer(),e===`inspector`&&this.renderInspector(),e===`logs`&&this.renderLogs(),e===`time`&&this.renderTime()}close(e){if(e===`inspector`&&(this.hovering=!1),e===`stats`){this.statsChip?.remove(),this.statsChip=null;return}let t=this.panels.get(e);t&&(t.remove(),this.panels.delete(e))}toggle(e){if(e===`copyScene`){this.copyScene();return}if(e===`captureRegion`){this.captureRegion();return}if(e===`colliders`){this.setColliders({off:`all`,all:`selected`,selected:`off`}[this.colliderMode]);return}this.isOpen(e)?this.close(e):this.open(e)}setLevelEnabled(e,t){this.levelEnabled[e]=t,this.renderLogs()}setConsoleCapture(e){if(e!==this.consoleCapture)if(this.consoleCapture=e,e){this.renderLogs();let e=console;for(let t of B){let n=e[t];e[t]=(...e)=>{n.apply(console,e);let r=t===`log`?`info`:t;this.pushLog({level:r,source:`console`,text:e.map(W).join(` `)})},this.consolePatched.push(()=>{e[t]=n})}}else{for(let e of this.consolePatched)e();this.consolePatched=[],this.renderLogs()}}dispose(){this.engine.debugSelection=null,this.setColliders(`off`),this.setConsoleCapture(!1);for(let e of this.cleanups)e();for(let e of[...this.panels.keys()])this.close(e);this.close(`stats`),this.closeDropdown(),this.menuButton.remove()}menuLabel(e,t){let n=e===`colliders`&&this.colliderMode!==`off`?` · ${this.colliderMode}`:``;return`${this.isOpen(e)?`✓ `:``}${t}${n}`}bindMenuDrag(){let e=null,t=!1;this.menuButton.addEventListener(`pointerdown`,n=>{let r=n;e={x:r.clientX??0,y:r.clientY??0,bx:this.menuPos.x,by:this.menuPos.y},t=!1,r.pointerId!==void 0&&this.menuButton.setPointerCapture?.(r.pointerId)}),this.menuButton.addEventListener(`pointermove`,n=>{if(!e)return;let r=n,i=(r.clientX??0)-e.x,a=(r.clientY??0)-e.y;!t&&Math.hypot(i,a)<L||(t||(t=!0,this.closeDropdown(),b(this.menuButton,{cursor:`grabbing`})),this.moveMenuButton(e.bx+i,e.by+a))});let n=()=>{if(!e)return;let n=t;e=null,t=!1,b(this.menuButton,{cursor:`pointer`}),n||this.toggleDropdown()};this.menuButton.addEventListener(`pointerup`,n),this.menuButton.addEventListener(`pointercancel`,n)}moveMenuButton(e,t){let n=this.menuButton,r=_(e,t,n.offsetWidth??0,n.offsetHeight??0,this.container.clientWidth||0,this.container.clientHeight||0,0,0);this.menuPos={x:r.x,y:r.y},b(this.menuButton,{left:`${r.x}px`,top:`${r.y}px`})}closeDropdown(){this.dismissDropdown?.(),this.dismissDropdown=null,this.dropdown?.remove(),this.dropdown=null}toggleDropdown(){if(this.dropdown){this.closeDropdown();return}let e=this.doc.createElement(`div`);b(e,{position:`absolute`,background:`rgba(18,20,26,0.95)`,border:`1px solid rgba(255,255,255,0.18)`,borderRadius:`6px`,font:`12px ui-monospace, Menlo, monospace`,color:`rgba(255,255,255,0.85)`,zIndex:`60`,pointerEvents:`auto`,overflow:`hidden`});for(let[t,n]of[[`explorer`,`Explorer`],[`inspector`,`Inspector`],[`logs`,`Logs`],[`time`,`Time`],[`copyScene`,`Copy scene JSON`],[`captureRegion`,`Capture region`],[`stats`,`Stats`],[`colliders`,`Colliders`]]){let r=this.doc.createElement(`div`);r.textContent=this.menuLabel(t,n),b(r,{padding:`6px 14px`,cursor:`pointer`,userSelect:`none`}),r.addEventListener(`click`,()=>{if(this.toggle(t),t===`colliders`){r.textContent=this.menuLabel(t,n);return}this.closeDropdown()}),e.appendChild(r)}for(let t of this.actions){let n=this.doc.createElement(`div`);n.textContent=t.label,b(n,{padding:`6px 14px`,cursor:`pointer`,userSelect:`none`,borderTop:`1px solid rgba(255,255,255,0.14)`,color:`rgba(158,232,220,0.95)`}),n.addEventListener(`click`,()=>{this.closeDropdown(),t.run()}),e.appendChild(n)}this.container.appendChild(e),this.dropdown=e;let t=e,n=this.menuButton,r=v({x:this.menuPos.x,y:this.menuPos.y,w:n.offsetWidth??0,h:n.offsetHeight??26},t.offsetWidth??0,t.offsetHeight??0,this.container.clientWidth||0,this.container.clientHeight||0);b(e,{left:`${r.x}px`,top:`${r.y}px`}),this.dismissDropdown=y(this.doc,[e,this.menuButton],()=>this.closeDropdown())}openStatsChip(){if(this.statsChip)return;let e=this.doc.createElement(`div`);b(e,{position:`absolute`,top:`8px`,right:`8px`,padding:`4px 10px`,background:`rgba(18,20,26,0.85)`,border:`1px solid rgba(255,255,255,0.18)`,borderRadius:`6px`,color:`rgba(255,255,255,0.85)`,font:`12px ui-monospace, Menlo, monospace`,textAlign:`right`,whiteSpace:`pre`,userSelect:`none`,pointerEvents:`none`,zIndex:`70`}),this.container.appendChild(e),this.statsChip=e,this.renderStats()}renderStats(){let e=this.statsChip;if(!e)return;let t=this.engine.stats(),n=this.statsSource?.()??{},r=[`nodes ${t.nodes}`,...n.triangles===void 0?[]:[`tris ${U(n.triangles)}`],...n.drawCalls===void 0?[]:[`calls ${n.drawCalls}`]].join(` · `),i=t.phases,a=`\nphys ${i.fixedMs.toFixed(1)} · logic ${i.updateMs.toFixed(1)} · draw ${i.renderMs.toFixed(1)} · other ${i.otherMs.toFixed(1)}`;e.textContent=`${Math.round(t.fps)} fps · ${t.frameMs.toFixed(1)} ms\n${r}${a}`}renderExplorer(){let e=this.panels.get(`explorer`);if(!e)return;let t=e.body.scrollTop;H(e.body);let n=this.engine.scene?.root;if(!n){e.body.scrollTop=t;return}let r=(e,t)=>{let n=e.constructor,i=e.children.length>0,a=this.collapsedFlags.get(e)===!0,o=this.doc.createElement(`div`);b(o,{display:`flex`,alignItems:`center`,cursor:`pointer`,padding:`1px 2px`,borderRadius:`3px`,background:e===this.selected?`rgba(110,160,255,0.25)`:`transparent`});let s=this.doc.createElement(`span`);s.textContent=i?a?`▸`:`▾`:`·`,b(s,{width:`14px`,flex:`none`,textAlign:`center`,opacity:i?`0.85`:`0.25`,userSelect:`none`}),i&&s.addEventListener(`click`,t=>{t.stopPropagation?.(),this.collapsedFlags.set(e,!a),this.renderExplorer()}),o.appendChild(s);let c=this.doc.createElement(`span`);c.textContent=e.name,b(c,{whiteSpace:`nowrap`}),o.appendChild(c);let l=this.doc.createElement(`span`);if(l.textContent=` ${n.typeName}`,b(l,{opacity:`0.45`,whiteSpace:`nowrap`,fontSize:`10px`}),o.appendChild(l),i&&a){let t=this.doc.createElement(`span`);t.textContent=` (${e.children.length})`,b(t,{opacity:`0.35`,fontSize:`10px`}),o.appendChild(t)}if(o.addEventListener(`click`,()=>{this.selected=e,this.engine.debugSelection=e,this.applyColliderScope(),this.open(`inspector`),this.renderExplorer(),this.renderInspector()}),t.appendChild(o),i&&!a){let n=this.doc.createElement(`div`);b(n,{marginLeft:`8px`,paddingLeft:`8px`,borderLeft:`1px solid rgba(255,255,255,0.14)`});for(let t of e.children)r(t,n);t.appendChild(n)}};r(n,e.body),e.body.scrollTop=t}renderInspector(){let e=this.panels.get(`inspector`);if(!e)return;let n=e.body.scrollTop;H(e.body);let r=this.selected;if(r&&r.tree===null&&(this.selected=null,this.engine.debugSelection=null,this.applyColliderScope(),r=null),!r){let t=this.doc.createElement(`div`);t.textContent=`select a node in the Explorer`,b(t,{opacity:`0.6`}),e.body.appendChild(t);return}let i=r.constructor,a=this.doc.createElement(`div`);if(a.textContent=`${r.getPath()} · ${i.typeName}${r.uid?` · ${r.uid}`:``}`,b(a,{fontWeight:`700`,marginBottom:`6px`,whiteSpace:`pre-wrap`}),e.body.appendChild(a),r.groups.size>0){let t=this.doc.createElement(`div`);t.textContent=`groups: ${[...r.groups].join(`, `)}`,b(t,{opacity:`0.7`,marginBottom:`6px`}),e.body.appendChild(t)}let o=t(i),s=r;for(let t of Object.keys(o)){let n=o[t];this.renderValueRow(e.body,r,t,{read:()=>s[t],write:e=>{s[t]=e},options:n?.options,variants:n?.variants})}e.body.scrollTop=n}renderValueRow(t,n,r,i){let a=i.read(),o=i.options,s={get[r](){return i.read()},set[r](e){i.write(e)}},c=this.doc.createElement(`div`);b(c,{display:`flex`,gap:`6px`,alignItems:`center`,margin:`2px 0`});let l=this.doc.createElement(`div`);l.textContent=r,b(l,{minWidth:`84px`,opacity:`0.75`}),c.appendChild(l);let u=(e,t)=>{let i=this.doc.createElement(`input`);return i.type=`number`,i.value=String(e),b(i,K(`70px`)),this.trackEditing(i),i.addEventListener(`change`,()=>{let e=Number(i.value);Number.isFinite(e)?t(e):i.value=String(n[r])}),i};if(typeof a==`number`)c.appendChild(u(a,e=>{s[r]=e}));else if(typeof a==`boolean`){let e=this.doc.createElement(`input`);e.type=`checkbox`,e.checked=a,this.trackEditing(e),e.addEventListener(`change`,()=>{s[r]=e.checked}),c.appendChild(e)}else if(typeof a==`string`&&o&&o.length>0){let e=this.doc.createElement(`select`);for(let t of o.includes(a)?o:[a,...o]){let n=this.doc.createElement(`option`);n.value=t,n.textContent=t,t===a&&(n.selected=!0),e.appendChild(n)}e.value=a,this.trackEditing(e),e.addEventListener(`change`,()=>{s[r]=e.value}),b(e,K(`110px`)),c.appendChild(e)}else if(typeof a==`string`){let e=this.doc.createElement(`input`);e.type=`text`,e.value=a,this.trackEditing(e),b(e,K(`140px`)),e.addEventListener(`change`,()=>{s[r]=e.value}),c.appendChild(e)}else if(Array.isArray(a)&&a.length<=8&&a.every(e=>typeof e==`number`))for(let e=0;e<a.length;e++)c.appendChild(u(a[e],t=>{let n=[...s[r]];n[e]=t,s[r]=n}));else if(F(a)){let o=this.doc.createElement(`div`);b(o,{marginLeft:`10px`,paddingLeft:`8px`,borderLeft:`1px solid rgba(255,255,255,0.14)`});let s=i.variants?.tag,l=Object.keys(a);s&&!l.includes(s)&&l.unshift(s);let u=i.path??r;for(let t of l){let r=t===s;this.renderValueRow(o,n,t,{path:`${u}.${t}`,read:()=>i.read()[t]??(r?``:null),write:n=>{if(r&&i.variants){let t=i.variants.byTag[String(n)];if(t!==void 0){i.write(e(t));return}}i.write({...i.read(),[t]:n})},options:r&&i.variants?Object.keys(i.variants.byTag):void 0})}t.appendChild(c),t.appendChild(o);return}else{let o=JSON.stringify(e(a));if(o.length<=A){let e=this.doc.createElement(`div`);e.textContent=o,b(e,{opacity:`0.65`,whiteSpace:`pre-wrap`,wordBreak:`break-all`}),c.appendChild(e)}else{let e=i.path??r,s=this.detailOpen.get(n)?.has(e)??!1,l=this.doc.createElement(`div`);if(l.textContent=`${s?`▾`:`▸`} ${N(a)}`,b(l,{opacity:`0.75`,cursor:`pointer`,userSelect:`none`}),l.addEventListener(`click`,()=>{let t=this.detailOpen.get(n);t||(t=new Set,this.detailOpen.set(n,t)),s?t.delete(e):t.add(e),this.renderInspector()}),c.appendChild(l),t.appendChild(c),s){let e=this.doc.createElement(`div`);e.textContent=P(a,o),b(e,{opacity:`0.6`,whiteSpace:`pre-wrap`,wordBreak:`break-all`,marginLeft:`10px`,paddingLeft:`8px`,borderLeft:`1px solid rgba(255,255,255,0.14)`}),t.appendChild(e)}return}}t.appendChild(c)}trackEditing(e){e.addEventListener(`focus`,()=>{this.editing+=1}),e.addEventListener(`blur`,()=>{this.editing=Math.max(0,this.editing-1)})}pushLog(e){this.logRows.push(e),this.logRows.length>z&&this.logRows.splice(0,this.logRows.length-z),this.renderLogs()}async copyScene(){let e=await s(o(this.engine.scene??null));return this.toast(e?`scene JSON copied`:`could not reach the clipboard`),e}captureRegion(){this.capture||=(this.captureScale=globalThis.devicePixelRatio??1,this.frameSource?.().then(e=>{this.captureScale=e.width/Math.max(1,this.container.clientWidth||e.width)}).catch(()=>{}),k({doc:this.doc,container:this.container,scale:()=>this.captureScale,onCopy:e=>void this.copyRegion({x0:e.x,y0:e.y,x1:e.x+e.w,y1:e.y+e.h}),onClose:()=>{this.capture=null}}))}capture=null;captureScale=1;async copyRegion(e){let t=this.frameSource;if(!t)return this.toast(`no renderer to capture from`),!1;try{let n=await t(),r=n.width/Math.max(1,this.container.clientWidth||n.width),o=i(e,n.width,n.height,r),s=a(n.pixels,n.width,n.height,o),l=await c(this.doc,s);return this.toast(l?`copied ${s.width}×${s.height}`:`could not copy the image`),l}catch(e){return this.toast(`capture failed: ${e instanceof Error?e.message:String(e)}`),!1}}toast(e){let t=this.doc.createElement(`div`);t.textContent=e,b(t,{position:`absolute`,bottom:`16px`,left:`50%`,transform:`translateX(-50%)`,padding:`6px 12px`,borderRadius:`6px`,background:`rgba(18,20,26,0.92)`,color:`rgba(255,255,255,0.9)`,font:`12px ui-monospace, Menlo, monospace`,zIndex:`90`,pointerEvents:`none`}),this.container.appendChild(t),setTimeout(()=>t.remove(),1800)}setTimeScale(e){Number.isFinite(e)&&(this.engine.timeScale=Math.max(0,e),this.syncTime())}setPaused(e){e?(this.engine.timeScale>0&&(this.resumeScale=this.engine.timeScale),this.engine.timeScale=0):this.engine.timeScale=this.resumeScale>0?this.resumeScale:1,this.syncTime()}get paused(){return this.engine.timeScale===0}nextFrame(){this.paused||this.setPaused(!0),this.engine.step({ignorePause:!0}),this.syncTime()}syncTime(){let e=this.timeEls;if(!e)return;let t=this.engine.timeScale,n=String(Math.round(t*1e3)/1e3);this.editing===0&&(e.slider.value=String(Math.min(t,I)),e.box.value=n),e.readout.textContent=`timeScale ${n}${this.paused?` · paused`:``}`,e.pause.textContent=this.paused?`▶ Resume`:`⏸ Pause`}renderTime(){let e=this.panels.get(`time`);if(!e)return;H(e.body),this.timeEls=null;let t=this.doc.createElement(`div`);b(t,{marginBottom:`6px`,opacity:`0.85`}),e.body.appendChild(t);let n=this.doc.createElement(`input`);n.type=`range`,n.min=`0`,n.max=String(I),n.step=`0.05`,n.value=String(Math.min(this.engine.timeScale,I)),b(n,{width:`100%`,marginBottom:`6px`}),this.trackEditing(n),n.addEventListener(`input`,()=>this.setTimeScale(Number(n.value))),e.body.appendChild(n);let r=this.doc.createElement(`div`);b(r,{display:`flex`,gap:`6px`,alignItems:`center`,marginBottom:`8px`});let i=this.doc.createElement(`input`);i.type=`number`,i.min=`0`,i.step=`0.05`,i.value=String(this.engine.timeScale),b(i,K(`72px`)),this.trackEditing(i),i.addEventListener(`change`,()=>{let e=Number(i.value);Number.isFinite(e)&&this.setTimeScale(e),this.syncTimeAfterEdit()}),r.appendChild(i);for(let e of[.25,.5,1,2]){let t=this.doc.createElement(`div`);t.textContent=`${e}×`,b(t,{cursor:`pointer`,opacity:`0.7`,padding:`2px 4px`}),t.addEventListener(`click`,()=>this.setTimeScale(e)),r.appendChild(t)}e.body.appendChild(r);let a=this.doc.createElement(`div`);b(a,{display:`flex`,gap:`8px`});let o=this.doc.createElement(`div`);b(o,G()),o.addEventListener(`click`,()=>this.setPaused(!this.paused)),a.appendChild(o);let s=this.doc.createElement(`div`);s.textContent=`⏭ Next frame`,s.title=`Pauses, then advances one fixed step`,b(s,G()),s.addEventListener(`click`,()=>this.nextFrame()),a.appendChild(s),e.body.appendChild(a),this.timeEls={slider:n,box:i,readout:t,pause:o},this.syncTime()}syncTimeAfterEdit(){let e=this.timeEls;if(!e)return;let t=this.engine.timeScale;e.slider.value=String(Math.min(t,I)),e.box.value=String(Math.round(t*1e3)/1e3)}renderLogs(){let e=this.panels.get(`logs`);if(!e)return;H(e.body);let t=this.doc.createElement(`div`);b(t,{display:`flex`,gap:`8px`,marginBottom:`4px`,flexWrap:`wrap`});for(let e of[`debug`,`info`,`warn`,`error`]){let n=this.doc.createElement(`div`);n.textContent=`${this.levelEnabled[e]?`✓`:`·`}${e}`,b(n,{cursor:`pointer`,opacity:this.levelEnabled[e]?`1`:`0.45`}),n.addEventListener(`click`,()=>this.setLevelEnabled(e,!this.levelEnabled[e])),t.appendChild(n)}let n=this.doc.createElement(`div`);n.textContent=`${this.consoleCapture?`✓`:`·`}console`,b(n,{cursor:`pointer`,marginLeft:`auto`}),n.addEventListener(`click`,()=>this.setConsoleCapture(!this.consoleCapture)),t.appendChild(n),e.body.appendChild(t);let r={debug:`rgba(255,255,255,0.5)`,info:`rgba(255,255,255,0.85)`,warn:`#ffc861`,error:`#ff6b6b`};for(let t of this.logRows){if(!this.levelEnabled[t.level])continue;let n=this.doc.createElement(`div`);n.textContent=`[${t.source===`console`?`console`:t.level}] ${t.text}`,b(n,{color:r[t.level],whiteSpace:`pre-wrap`}),e.body.appendChild(n)}}};function H(e){for(let t of[...e.children])t.remove()}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function W(e){if(typeof e==`string`)return e;if(e instanceof Error){let t=e.stack?.split(`
3
3
  `)[1]?.trim();return`${e.name}: ${e.message}${t?` (${t})`:``}`}try{let t=JSON.stringify(e);return t===`{}`||t===void 0?String(e):t}catch{return String(e)}}function G(){return{background:`rgba(255,255,255,0.08)`,border:`1px solid rgba(255,255,255,0.2)`,borderRadius:`4px`,padding:`4px 8px`,cursor:`pointer`,userSelect:`none`}}function K(e){return{width:e,background:`rgba(255,255,255,0.08)`,border:`1px solid rgba(255,255,255,0.2)`,borderRadius:`4px`,color:`inherit`,font:`inherit`,padding:`2px 4px`}}export{R as attachDebugOverlay};