incanto 0.41.0 → 0.42.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/bin/incanto-frame.mjs +144 -0
- package/dist/2d.d.ts +2 -2
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +76 -4
- package/dist/3d.js +5 -5
- package/dist/{behavior-TA8nySqb.d.ts → behavior-62q0HWBO.d.ts} +3 -1
- package/dist/{create-game-CZpENyin.js → create-game-9KPppR0L.js} +4 -4
- package/dist/{create-game-u7TDbvln.js → create-game-DItIRyXH.js} +158 -5
- package/dist/debug.d.ts +1 -1
- package/dist/{environment-presets-pGTHb_V4.js → environment-presets-Vl5xBsXp.js} +2 -2
- package/dist/{gameplay-By8mslMc.js → gameplay-DRi9524r.js} +13 -0
- package/dist/gameplay.d.ts +13 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -167
- package/dist/{loader-CvSDKC3v.d.ts → loader-CeyU_bm1.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +2 -2
- package/dist/{pathfinding-_UlKUoox.d.ts → pathfinding-C49JSNNq.d.ts} +1 -1
- package/dist/{physics-2d-CEnZFcpM.js → physics-2d-BmgXBNDB.js} +1 -1
- package/dist/{physics-3d-CumBBvQo.js → physics-3d-C2G604O1.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-DuTlY56W.js → register-BSXV8T9F.js} +3 -1
- package/dist/{register-DnycZ91Q.js → register-D651it1J.js} +1 -1
- package/dist/{register-MSZvnHkp.js → register-R2JTnIMw.js} +1 -1
- package/dist/{replay-DN-kG4va.d.ts → replay-CAphXMyM.d.ts} +1 -1
- package/dist/{replay-DcWg4LT5.js → replay-DilbZgQI.js} +1 -1
- package/dist/src-cU57Uwdw.js +166 -0
- package/dist/{test-B4kSwQzq.js → test-DuOD1DO8.js} +22 -11
- package/dist/test.d.ts +3 -3
- package/dist/test.js +2 -2
- package/dist/vite.d.ts +61 -1
- package/dist/vite.js +149 -2
- package/editor/assets/{agent8-DCHkff44.js → agent8-Csw0T7jh.js} +1 -1
- package/editor/assets/{debug-uHHxqj0a.js → debug-C3qeBD4X.js} +1 -1
- package/editor/assets/{index-i1mIkyMA.js → index-B1rUkWxB.js} +49 -49
- package/editor/index.html +1 -1
- package/package.json +3 -2
- package/skills/incanto-audio.md +6 -2
- package/skills/incanto-verifying-your-game.md +41 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
package/dist/vite.js
CHANGED
|
@@ -1,6 +1,152 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as VERSION } from "./src-cU57Uwdw.js";
|
|
2
|
+
import { s as validateScene } from "./test-DuOD1DO8.js";
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { basename, dirname, join, normalize, relative, resolve, sep } from "node:path";
|
|
5
|
+
//#region src/vite/frame-endpoint.ts
|
|
6
|
+
/**
|
|
7
|
+
* The dev server's half of `incanto-frame`.
|
|
8
|
+
*
|
|
9
|
+
* The server does not have the pixels — the BROWSER does. Vite already keeps a
|
|
10
|
+
* websocket to every connected client (that is how HMR works), so the frame
|
|
11
|
+
* request rides that channel: ask the page, wait, answer the CLI. No new
|
|
12
|
+
* transport, no file, nothing written anywhere.
|
|
13
|
+
*
|
|
14
|
+
* Three outcomes, and they must be told apart, because the fix differs:
|
|
15
|
+
* no server → the preview was never started
|
|
16
|
+
* server, no client → started, but nobody opened the page
|
|
17
|
+
* server + client → the frame
|
|
18
|
+
*/
|
|
19
|
+
/** How long to wait for a page to answer before calling it absent. */
|
|
20
|
+
const CLIENT_TIMEOUT_MS = 2e3;
|
|
21
|
+
/**
|
|
22
|
+
* Wire `/__incanto/ping` and `/__incanto/frame` onto a dev server.
|
|
23
|
+
*
|
|
24
|
+
* `ping` is how the CLI tells our server apart from anything else listening in
|
|
25
|
+
* the container: it enumerates the ports that are actually open and asks each
|
|
26
|
+
* one. That answer has to be cheap and unmistakable.
|
|
27
|
+
*/
|
|
28
|
+
function serveFrameEndpoints(host, version, opts = {}) {
|
|
29
|
+
const channel = host.hot ?? host.ws;
|
|
30
|
+
const timeoutMs = opts.timeoutMs ?? CLIENT_TIMEOUT_MS;
|
|
31
|
+
let nextId = 1;
|
|
32
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
33
|
+
channel?.on("incanto:frame-report", (data) => {
|
|
34
|
+
const payload = data;
|
|
35
|
+
const id = payload?.id;
|
|
36
|
+
if (typeof id !== "number") return;
|
|
37
|
+
const resolve = waiting.get(id);
|
|
38
|
+
if (!resolve) return;
|
|
39
|
+
waiting.delete(id);
|
|
40
|
+
resolve({
|
|
41
|
+
ok: true,
|
|
42
|
+
report: payload?.report
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
host.middlewares.use("/__incanto/ping", (_req, res) => {
|
|
46
|
+
json$1(res, 200, {
|
|
47
|
+
incanto: version,
|
|
48
|
+
frame: Boolean(channel)
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
host.middlewares.use("/__incanto/frame", (_req, res) => {
|
|
52
|
+
if (!channel) {
|
|
53
|
+
json$1(res, 503, { error: "no-hmr-channel" });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const id = nextId++;
|
|
57
|
+
const timer = setTimeout(() => {
|
|
58
|
+
waiting.delete(id);
|
|
59
|
+
json$1(res, 504, { error: "no-page-connected" });
|
|
60
|
+
}, timeoutMs);
|
|
61
|
+
waiting.set(id, (value) => {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
if (value.ok) json$1(res, 200, { report: value.report });
|
|
64
|
+
else json$1(res, 500, { error: "capture-failed" });
|
|
65
|
+
});
|
|
66
|
+
channel.send({
|
|
67
|
+
type: "custom",
|
|
68
|
+
event: "incanto:frame-request",
|
|
69
|
+
data: { id }
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function json$1(res, status, body) {
|
|
74
|
+
res.statusCode = status;
|
|
75
|
+
res.setHeader("content-type", "application/json");
|
|
76
|
+
res.end(JSON.stringify(body));
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/vite/discover.ts
|
|
80
|
+
/**
|
|
81
|
+
* Finding the dev server — the generic half of the frame capture.
|
|
82
|
+
*
|
|
83
|
+
* Nothing here knows what incanto is. It answers one question: which local
|
|
84
|
+
* ports might be serving something, best candidates first. Deciding which of
|
|
85
|
+
* them is OURS is a ping, and that belongs to the caller.
|
|
86
|
+
*
|
|
87
|
+
* This is deliberately code and not documentation. An agent told "check the
|
|
88
|
+
* screen" runs one command; anything it has to work out for itself — which
|
|
89
|
+
* port, whether the preview is even up — is a coin flip that lands differently
|
|
90
|
+
* every session.
|
|
91
|
+
*/
|
|
92
|
+
/** Where a vite dev server usually is, tried after anything actually observed. */
|
|
93
|
+
const LIKELY = [
|
|
94
|
+
5173,
|
|
95
|
+
5174,
|
|
96
|
+
5175,
|
|
97
|
+
5176,
|
|
98
|
+
4173,
|
|
99
|
+
3e3,
|
|
100
|
+
8080
|
|
101
|
+
];
|
|
102
|
+
/** `/proc/net/tcp` state code for LISTEN. */
|
|
103
|
+
const TCP_LISTEN = "0A";
|
|
104
|
+
/**
|
|
105
|
+
* The listening TCP ports in `/proc/net/tcp` (and `tcp6`) format.
|
|
106
|
+
*
|
|
107
|
+
* Linux-only and dependency-free ON PURPOSE: `lsof` and `ss` are routinely
|
|
108
|
+
* absent from a slim container, and this has to work in the container a
|
|
109
|
+
* vibe-coding service actually ships, not in a developer's laptop.
|
|
110
|
+
*/
|
|
111
|
+
function parseProcNetTcp(text) {
|
|
112
|
+
const ports = /* @__PURE__ */ new Set();
|
|
113
|
+
for (const line of text.split("\n")) {
|
|
114
|
+
const cols = line.trim().split(/\s+/);
|
|
115
|
+
if (cols.length < 4) continue;
|
|
116
|
+
const local = cols[1];
|
|
117
|
+
if (cols[3] !== TCP_LISTEN || !local?.includes(":")) continue;
|
|
118
|
+
const hex = local.slice(local.lastIndexOf(":") + 1);
|
|
119
|
+
const port = Number.parseInt(hex, 16);
|
|
120
|
+
if (Number.isFinite(port) && port > 0 && port < 65536) ports.add(port);
|
|
121
|
+
}
|
|
122
|
+
return [...ports];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Ports worth asking, in the order worth asking them.
|
|
126
|
+
*
|
|
127
|
+
* Observed first — those are facts. The usual suspects after, because a
|
|
128
|
+
* container that hides `/proc` should still find a vite server on 5173.
|
|
129
|
+
*/
|
|
130
|
+
async function listeningPorts(deps) {
|
|
131
|
+
const read = deps?.read ?? ((path) => {
|
|
132
|
+
try {
|
|
133
|
+
const fs = globalThis["__incantoFs"];
|
|
134
|
+
return fs ? fs.readFileSync(path, "utf-8") : null;
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const observed = [...parseProcNetTcp(read("/proc/net/tcp") ?? ""), ...parseProcNetTcp(read("/proc/net/tcp6") ?? "")];
|
|
140
|
+
const seen = /* @__PURE__ */ new Set();
|
|
141
|
+
const out = [];
|
|
142
|
+
for (const port of [...observed, ...LIKELY]) {
|
|
143
|
+
if (seen.has(port)) continue;
|
|
144
|
+
seen.add(port);
|
|
145
|
+
out.push(port);
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
4
150
|
//#region src/vite/index.ts
|
|
5
151
|
/**
|
|
6
152
|
* incanto/vite — dev-server integration: validate every `*.scene.json` edit
|
|
@@ -30,6 +176,7 @@ function incantoScenes(opts = {}) {
|
|
|
30
176
|
* `incanto-editor` does. Dev-only by construction (`configureServer`).
|
|
31
177
|
*/
|
|
32
178
|
configureServer(server) {
|
|
179
|
+
serveFrameEndpoints(server, VERSION);
|
|
33
180
|
const root = opts.root ?? server.config?.root ?? process.cwd();
|
|
34
181
|
server.middlewares.use("/api/scenes", (req, res) => {
|
|
35
182
|
serveSceneList(req, res, root);
|
|
@@ -405,4 +552,4 @@ function libraryItem(row) {
|
|
|
405
552
|
};
|
|
406
553
|
}
|
|
407
554
|
//#endregion
|
|
408
|
-
export { discoverScenes, incantoLibrary, incantoScenes, resolveSceneFile, sceneFacts, serveLibrary, serveSceneFile, serveSceneList };
|
|
555
|
+
export { discoverScenes, incantoLibrary, incantoScenes, listeningPorts, parseProcNetTcp, resolveSceneFile, sceneFacts, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./index-
|
|
1
|
+
import{n as e}from"./index-B1rUkWxB.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{i as e,r as t,t as n}from"./index-
|
|
1
|
+
import{i as e,r as t,t as n}from"./index-B1rUkWxB.js";function r(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 i(e,t){for(let[n,r]of Object.entries(t))e.style[n]=r}var a=`rgba(18, 20, 26, 0.92)`,o=`1px solid rgba(255,255,255,0.14)`,s=`12px ui-monospace, SFMono-Regular, Menlo, monospace`,c=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`),i(this.el,{position:`absolute`,background:a,border:o,borderRadius:`8px`,color:`rgba(255,255,255,0.88)`,font:s,display:`flex`,flexDirection:`column`,overflow:`hidden`,zIndex:`40`,pointerEvents:`auto`,boxShadow:`0 8px 28px rgba(0,0,0,0.45)`});let c=e.createElement(`div`);c.textContent=n,i(c,{padding:`6px 28px 6px 10px`,background:`rgba(255,255,255,0.07)`,cursor:`move`,userSelect:`none`,touchAction:`none`,fontWeight:`700`}),this.el.appendChild(c);let l=e.createElement(`div`);l.textContent=`×`,l.title=`close`,i(l,{position:`absolute`,top:`2px`,right:`8px`,cursor:`pointer`,fontSize:`16px`,lineHeight:`20px`,opacity:`0.7`}),l.addEventListener(`click`,()=>this.onClose()),this.el.appendChild(l),this.body=e.createElement(`div`),i(this.body,{flex:`1`,overflow:`auto`,padding:`8px 10px`}),this.el.appendChild(this.body);let u=e.createElement(`div`);u.textContent=`◢`,i(u,{position:`absolute`,right:`2px`,bottom:`0`,cursor:`nwse-resize`,opacity:`0.5`,userSelect:`none`,touchAction:`none`}),this.el.appendChild(u),this.wireDrag(c,(e,t)=>{this.x+=e,this.y+=t,this.layout()}),this.wireDrag(u,(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=r(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,i(this.el,{left:`${t.x}px`,top:`${t.y}px`,width:`${t.w}px`,height:`${t.h}px`})}wireDrag(e,t){let n=null,r=0,i=0;e.addEventListener(`pointerdown`,t=>{n=t.pointerId,r=t.clientX,i=t.clientY,e.setPointerCapture?.(t.pointerId)}),e.addEventListener(`pointermove`,e=>{e.pointerId===n&&(t(e.clientX-r,e.clientY-i),r=e.clientX,i=e.clientY)});let a=e=>{e.pointerId===n&&(n=null)};e.addEventListener(`pointerup`,a),e.addEventListener(`pointercancel`,a)}},l=96,u=200,d=8192;function f(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,u).map(e=>JSON.stringify(e)),n=e.length-u;return t.join(`
|
|
2
2
|
`)+(n>0?`\n… ${n} more`:``)}return t.length>d?`${t.slice(0,d)} … (${t.length-d} more chars)`:t}function m(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var h=2;function g(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 y(e,r,n,t.statsSource,t.actions)}var _=300,v=[`log`,`info`,`warn`,`error`,`debug`],y=class{engine;container;doc;statsSource;actions;panels=new Map;cleanups=[];menuButton;dropdown=null;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,a=[]){this.engine=e,this.container=t,this.doc=n,this.statsSource=r,this.actions=a,this.menuButton=n.createElement(`div`),this.menuButton.textContent=`☰ debug`,i(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.menuButton.addEventListener(`click`,()=>this.toggleDropdown()),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(S).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===`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 n(`2d`).concat(n(`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 c(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===`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 v){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(S).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.dropdown?.remove(),this.dropdown=null,this.menuButton.remove()}menuLabel(e,t){let n=e===`colliders`&&this.colliderMode!==`off`?` · ${this.colliderMode}`:``;return`${this.isOpen(e)?`✓ `:``}${t}${n}`}toggleDropdown(){if(this.dropdown){this.dropdown.remove(),this.dropdown=null;return}let e=this.doc.createElement(`div`);i(e,{position:`absolute`,top:`34px`,left:`8px`,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`],[`stats`,`Stats`],[`colliders`,`Colliders`]]){let r=this.doc.createElement(`div`);r.textContent=this.menuLabel(t,n),i(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.dropdown?.remove(),this.dropdown=null}),e.appendChild(r)}for(let t of this.actions){let n=this.doc.createElement(`div`);n.textContent=t.label,i(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.dropdown?.remove(),this.dropdown=null,t.run()}),e.appendChild(n)}this.container.appendChild(e),this.dropdown=e}openStatsChip(){if(this.statsChip)return;let e=this.doc.createElement(`div`);i(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 ${x(n.triangles)}`],...n.drawCalls===void 0?[]:[`calls ${n.drawCalls}`]].join(` · `);e.textContent=`${Math.round(t.fps)} fps · ${t.frameMs.toFixed(1)} ms\n${r}`}renderExplorer(){let e=this.panels.get(`explorer`);if(!e)return;let t=e.body.scrollTop;b(e.body);let n=this.engine.scene?.root;if(!n){e.body.scrollTop=t;return}let r=(e,t)=>{let n=e.constructor,a=e.children.length>0,o=this.collapsedFlags.get(e)===!0,s=this.doc.createElement(`div`);i(s,{display:`flex`,alignItems:`center`,cursor:`pointer`,padding:`1px 2px`,borderRadius:`3px`,background:e===this.selected?`rgba(110,160,255,0.25)`:`transparent`});let c=this.doc.createElement(`span`);c.textContent=a?o?`▸`:`▾`:`·`,i(c,{width:`14px`,flex:`none`,textAlign:`center`,opacity:a?`0.85`:`0.25`,userSelect:`none`}),a&&c.addEventListener(`click`,t=>{t.stopPropagation?.(),this.collapsedFlags.set(e,!o),this.renderExplorer()}),s.appendChild(c);let l=this.doc.createElement(`span`);l.textContent=e.name,i(l,{whiteSpace:`nowrap`}),s.appendChild(l);let u=this.doc.createElement(`span`);if(u.textContent=` ${n.typeName}`,i(u,{opacity:`0.45`,whiteSpace:`nowrap`,fontSize:`10px`}),s.appendChild(u),a&&o){let t=this.doc.createElement(`span`);t.textContent=` (${e.children.length})`,i(t,{opacity:`0.35`,fontSize:`10px`}),s.appendChild(t)}if(s.addEventListener(`click`,()=>{this.selected=e,this.engine.debugSelection=e,this.applyColliderScope(),this.open(`inspector`),this.renderExplorer(),this.renderInspector()}),t.appendChild(s),a&&!o){let n=this.doc.createElement(`div`);i(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;b(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`,i(t,{opacity:`0.6`}),e.body.appendChild(t);return}let a=r.constructor,o=this.doc.createElement(`div`);if(o.textContent=`${r.getPath()} · ${a.typeName}${r.uid?` · ${r.uid}`:``}`,i(o,{fontWeight:`700`,marginBottom:`6px`,whiteSpace:`pre-wrap`}),e.body.appendChild(o),r.groups.size>0){let t=this.doc.createElement(`div`);t.textContent=`groups: ${[...r.groups].join(`, `)}`,i(t,{opacity:`0.7`,marginBottom:`6px`}),e.body.appendChild(t)}let s=t(a),c=r;for(let t of Object.keys(s)){let n=s[t];this.renderValueRow(e.body,r,t,{read:()=>c[t],write:e=>{c[t]=e},options:n?.options,variants:n?.variants})}e.body.scrollTop=n}renderValueRow(t,n,r,a){let o=a.read(),s=a.options,c={get[r](){return a.read()},set[r](e){a.write(e)}},u=this.doc.createElement(`div`);i(u,{display:`flex`,gap:`6px`,alignItems:`center`,margin:`2px 0`});let d=this.doc.createElement(`div`);d.textContent=r,i(d,{minWidth:`84px`,opacity:`0.75`}),u.appendChild(d);let h=(e,t)=>{let a=this.doc.createElement(`input`);return a.type=`number`,a.value=String(e),i(a,w(`70px`)),this.trackEditing(a),a.addEventListener(`change`,()=>{let e=Number(a.value);Number.isFinite(e)?t(e):a.value=String(n[r])}),a};if(typeof o==`number`)u.appendChild(h(o,e=>{c[r]=e}));else if(typeof o==`boolean`){let e=this.doc.createElement(`input`);e.type=`checkbox`,e.checked=o,this.trackEditing(e),e.addEventListener(`change`,()=>{c[r]=e.checked}),u.appendChild(e)}else if(typeof o==`string`&&s&&s.length>0){let e=this.doc.createElement(`select`);for(let t of s.includes(o)?s:[o,...s]){let n=this.doc.createElement(`option`);n.value=t,n.textContent=t,t===o&&(n.selected=!0),e.appendChild(n)}e.value=o,this.trackEditing(e),e.addEventListener(`change`,()=>{c[r]=e.value}),i(e,w(`110px`)),u.appendChild(e)}else if(typeof o==`string`){let e=this.doc.createElement(`input`);e.type=`text`,e.value=o,this.trackEditing(e),i(e,w(`140px`)),e.addEventListener(`change`,()=>{c[r]=e.value}),u.appendChild(e)}else if(Array.isArray(o)&&o.length<=8&&o.every(e=>typeof e==`number`))for(let e=0;e<o.length;e++)u.appendChild(h(o[e],t=>{let n=[...c[r]];n[e]=t,c[r]=n}));else if(m(o)){let s=this.doc.createElement(`div`);i(s,{marginLeft:`10px`,paddingLeft:`8px`,borderLeft:`1px solid rgba(255,255,255,0.14)`});let c=a.variants?.tag,l=Object.keys(o);c&&!l.includes(c)&&l.unshift(c);let d=a.path??r;for(let t of l){let r=t===c;this.renderValueRow(s,n,t,{path:`${d}.${t}`,read:()=>a.read()[t]??(r?``:null),write:n=>{if(r&&a.variants){let t=a.variants.byTag[String(n)];if(t!==void 0){a.write(e(t));return}}a.write({...a.read(),[t]:n})},options:r&&a.variants?Object.keys(a.variants.byTag):void 0})}t.appendChild(u),t.appendChild(s);return}else{let s=JSON.stringify(e(o));if(s.length<=l){let e=this.doc.createElement(`div`);e.textContent=s,i(e,{opacity:`0.65`,whiteSpace:`pre-wrap`,wordBreak:`break-all`}),u.appendChild(e)}else{let e=a.path??r,c=this.detailOpen.get(n)?.has(e)??!1,l=this.doc.createElement(`div`);if(l.textContent=`${c?`▾`:`▸`} ${f(o)}`,i(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)),c?t.delete(e):t.add(e),this.renderInspector()}),u.appendChild(l),t.appendChild(u),c){let e=this.doc.createElement(`div`);e.textContent=p(o,s),i(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(u)}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>_&&this.logRows.splice(0,this.logRows.length-_),this.renderLogs()}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(),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,h)),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;b(e.body),this.timeEls=null;let t=this.doc.createElement(`div`);i(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(h),n.step=`0.05`,n.value=String(Math.min(this.engine.timeScale,h)),i(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`);i(r,{display:`flex`,gap:`6px`,alignItems:`center`,marginBottom:`8px`});let a=this.doc.createElement(`input`);a.type=`number`,a.min=`0`,a.step=`0.05`,a.value=String(this.engine.timeScale),i(a,w(`72px`)),this.trackEditing(a),a.addEventListener(`change`,()=>{let e=Number(a.value);Number.isFinite(e)&&this.setTimeScale(e),this.syncTimeAfterEdit()}),r.appendChild(a);for(let e of[.25,.5,1,2]){let t=this.doc.createElement(`div`);t.textContent=`${e}×`,i(t,{cursor:`pointer`,opacity:`0.7`,padding:`2px 4px`}),t.addEventListener(`click`,()=>this.setTimeScale(e)),r.appendChild(t)}e.body.appendChild(r);let o=this.doc.createElement(`div`);i(o,{display:`flex`,gap:`8px`});let s=this.doc.createElement(`div`);i(s,C()),s.addEventListener(`click`,()=>this.setPaused(!this.paused)),o.appendChild(s);let c=this.doc.createElement(`div`);c.textContent=`⏭ Next frame`,c.title=`Pauses, then advances one fixed step`,i(c,C()),c.addEventListener(`click`,()=>this.nextFrame()),o.appendChild(c),e.body.appendChild(o),this.timeEls={slider:n,box:a,readout:t,pause:s},this.syncTime()}syncTimeAfterEdit(){let e=this.timeEls;if(!e)return;let t=this.engine.timeScale;e.slider.value=String(Math.min(t,h)),e.box.value=String(Math.round(t*1e3)/1e3)}renderLogs(){let e=this.panels.get(`logs`);if(!e)return;b(e.body);let t=this.doc.createElement(`div`);i(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}`,i(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`,i(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}`,i(n,{color:r[t.level],whiteSpace:`pre-wrap`}),e.body.appendChild(n)}}};function b(e){for(let t of[...e.children])t.remove()}function x(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function S(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 C(){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 w(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{g as attachDebugOverlay};
|