incanto 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/bin/incanto-editor.mjs +118 -1
- package/dist/2d.d.ts +38 -5
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +496 -150
- package/dist/3d.js +5 -5
- package/dist/{behavior-CPibUfnH.d.ts → behavior-BAc0erXF.d.ts} +21 -0
- package/dist/{create-game-DUAtTqID.js → create-game-CNKXGfpr.js} +270 -47
- package/dist/{create-game-C0bPoURs.js → create-game-CbuLWorm.js} +53 -14
- package/dist/debug.d.ts +51 -6
- package/dist/debug.js +242 -19
- package/dist/editor-switch-B0wB_DSr.d.ts +59 -0
- package/dist/editor-switch-CAKlJMIY.js +161 -0
- package/dist/editor.d.ts +49 -0
- package/dist/editor.js +8439 -0
- package/dist/{gameplay-Ddk13pQ6.js → gameplay-L05WgWd1.js} +220 -37
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +22 -3
- package/dist/index.js +2 -2
- package/dist/{loader-DILt9PGC.d.ts → loader-B242FF6N.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +2 -2
- package/dist/{pathfinding-RWYkNKx9.d.ts → pathfinding-BwD974Ss.d.ts} +1 -1
- package/dist/{physics-2d-DiVFFlH3.js → physics-2d-CCVTrKOd.js} +62 -2
- package/dist/{physics-3d-4mGzOZ2J.js → physics-3d-BZZLtwJu.js} +439 -8
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-nObreUQR.js → register-BTg0EM7s.js} +35 -3
- package/dist/{register-DcHXS1MA.js → register-C44aSduO.js} +5694 -5108
- package/dist/{register-CvpSUU3O.js → register-DWcWq4QG.js} +22 -2
- package/dist/{register-BFFE1Mh1.js → register-MelqEdza.js} +1 -1
- package/dist/test.d.ts +35 -3
- package/dist/test.js +104 -10
- package/dist/vite.d.ts +53 -1
- package/dist/vite.js +94 -2
- package/editor/assets/{agent8-DElIPozC.js → agent8-DEVkEa3d.js} +1 -1
- package/editor/assets/debug-zGAtpDF0.js +2 -0
- package/editor/assets/index-Bx4UtWYY.js +10586 -0
- package/editor/index.html +3 -157
- package/package.json +3 -2
- package/schemas/scene.schema.json +110 -4
- package/skills/incanto-3d-models.md +38 -0
- package/skills/incanto-assets.md +13 -0
- package/skills/incanto-building-3d-games.md +83 -6
- package/skills/incanto-editor.md +151 -0
- package/skills/incanto-environment.md +88 -1
- package/skills/incanto-node-reference.md +35 -1
- package/skills/incanto-physics-and-input.md +45 -6
- package/skills/incanto-verifying-your-game.md +51 -2
- package/templates-app/beacon-isle-3d/docs/project-3d-rules.md +5 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/docs/project-3d-rules.md +5 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/docs/project-3d-rules.md +5 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/editor/assets/index-BrneVqN0.js +0 -8330
- package/editor/assets/index-D8QvwvOm.css +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { f as Node } from "./loader-BZqOKfI2.js";
|
|
2
|
-
import { t as registerCoreNodes } from "./register-
|
|
2
|
+
import { t as registerCoreNodes } from "./register-BTg0EM7s.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { i as getNodeSchema, l as registerNode } from "./registry-BVJ2HbCn.js";
|
|
@@ -115,7 +115,27 @@ var Node2D = class extends Node {
|
|
|
115
115
|
* `{shape:'capsule', radius, height}` — never child shape nodes.
|
|
116
116
|
*/
|
|
117
117
|
var PhysicsBody2D = class extends Node2D {
|
|
118
|
-
static props = { collider: {
|
|
118
|
+
static props = { collider: {
|
|
119
|
+
default: {},
|
|
120
|
+
variants: {
|
|
121
|
+
tag: "shape",
|
|
122
|
+
byTag: {
|
|
123
|
+
rect: {
|
|
124
|
+
shape: "rect",
|
|
125
|
+
size: [32, 32]
|
|
126
|
+
},
|
|
127
|
+
circle: {
|
|
128
|
+
shape: "circle",
|
|
129
|
+
radius: 16
|
|
130
|
+
},
|
|
131
|
+
capsule: {
|
|
132
|
+
shape: "capsule",
|
|
133
|
+
radius: 12,
|
|
134
|
+
height: 32
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} };
|
|
119
139
|
/** The unified collision model: every collider participant can emit these. */
|
|
120
140
|
static signals = ["triggerEnter", "triggerExit"];
|
|
121
141
|
_collider = {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { f as Node, t as buildNodeJson, y as Signal } from "./loader-BZqOKfI2.js";
|
|
2
|
-
import { t as registerCoreNodes } from "./register-
|
|
2
|
+
import { t as registerCoreNodes } from "./register-BTg0EM7s.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
5
5
|
import { l as registerNode } from "./registry-BVJ2HbCn.js";
|
package/dist/test.d.ts
CHANGED
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
import { c as JsonValue, i as SceneJson } from "./schema-CcoWb32N.js";
|
|
2
|
-
import { $ as Node, T as LogEntry, n as BehaviorCtor, v as Engine, w as Scene } from "./behavior-
|
|
3
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
2
|
+
import { $ as Node, T as LogEntry, n as BehaviorCtor, v as Engine, w as Scene } from "./behavior-BAc0erXF.js";
|
|
3
|
+
import { t as LoadSceneOptions } from "./loader-B242FF6N.js";
|
|
4
4
|
import { i as auditScene, t as IncantoError } from "./errors-1dXlIwoR.js";
|
|
5
5
|
|
|
6
6
|
//#region src/test/index.d.ts
|
|
7
|
+
/** One thing that is not standing where it should be. */
|
|
8
|
+
interface GroundingIssue {
|
|
9
|
+
/** Scene path, e.g. `/World/Footbridge/PostL0`. */
|
|
10
|
+
path: string;
|
|
11
|
+
/** Metres between the node's underside and the ground: + floats, − buried. */
|
|
12
|
+
gap: number;
|
|
13
|
+
}
|
|
14
|
+
interface GroundingOptions {
|
|
15
|
+
/** How far a foot may sit off the ground before it is a bug (default 0.1 m). */
|
|
16
|
+
tolerance?: number;
|
|
17
|
+
/** Node types to check (default: the ones that read as props on a map). */
|
|
18
|
+
types?: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Every prop that is floating or buried.
|
|
22
|
+
*
|
|
23
|
+
* THE most repeated mistake in scene authoring, by humans and agents alike, is
|
|
24
|
+
* a hand-computed Y: correct when it is written and wrong the moment anything
|
|
25
|
+
* reshapes the ground under it — a river carving its bed, a new seed, a
|
|
26
|
+
* generator that mirrors a carve slightly differently. This is the check that
|
|
27
|
+
* catches it, and `snapToGround` is the fix that stops it happening.
|
|
28
|
+
*
|
|
29
|
+
* Anything explicitly marked `snapToGround: false` is skipped: that is the
|
|
30
|
+
* author saying "yes, this hangs in the air", which a bridge deck, a lantern
|
|
31
|
+
* and a cloud all legitimately do.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const off = findFloatingProps(gameJson);
|
|
35
|
+
* ok(`nothing floats (${off.length})`, off.length === 0);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare function findFloatingProps(json: unknown, opts?: GroundingOptions): GroundingIssue[];
|
|
7
39
|
declare function registerAllNodes(): void;
|
|
8
40
|
interface NodeCapture {
|
|
9
41
|
/** Absolute path ('/Root/Player') — stable, grep-able. */
|
|
@@ -149,4 +181,4 @@ interface PlaySession {
|
|
|
149
181
|
*/
|
|
150
182
|
declare function createPlaySession(json: unknown, opts?: PlaySessionOptions): Promise<PlaySession>;
|
|
151
183
|
//#endregion
|
|
152
|
-
export { NodeCapture, PlaySession, PlaySessionOptions, RunContext, RunFailure, RunResult, RunScriptOptions, SceneCapture, ScriptStep, ValidateSceneOptions, ValidationResult, auditScene, captureScene, createPlaySession, describeCapture, registerAllNodes, runScript, validateScene };
|
|
184
|
+
export { GroundingIssue, GroundingOptions, NodeCapture, PlaySession, PlaySessionOptions, RunContext, RunFailure, RunResult, RunScriptOptions, SceneCapture, ScriptStep, ValidateSceneOptions, ValidationResult, auditScene, captureScene, createPlaySession, describeCapture, findFloatingProps, registerAllNodes, runScript, validateScene };
|
package/dist/test.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { _ as registerBehavior, n as loadScene } from "./loader-BZqOKfI2.js";
|
|
2
|
-
import { u as Engine } from "./register-
|
|
2
|
+
import { u as Engine } from "./register-BTg0EM7s.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as auditScene } from "./audit-C6rMyict.js";
|
|
5
5
|
import { n as jsonEquals, t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
6
6
|
import { i as getNodeSchema, s as mergeStaticProps } from "./registry-BVJ2HbCn.js";
|
|
7
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
8
|
-
import { t as registerNodes2D } from "./register-
|
|
9
|
-
import { t as registerNodes3D } from "./register-
|
|
10
|
-
import { t as registerNodesNet } from "./register-
|
|
7
|
+
import { n as registerGameplayBehaviors } from "./gameplay-L05WgWd1.js";
|
|
8
|
+
import { t as registerNodes2D } from "./register-DWcWq4QG.js";
|
|
9
|
+
import { t as registerNodes3D } from "./register-C44aSduO.js";
|
|
10
|
+
import { t as registerNodesNet } from "./register-MelqEdza.js";
|
|
11
11
|
//#region src/test/index.ts
|
|
12
12
|
/**
|
|
13
13
|
* incanto/test — the browserless verification harness.
|
|
@@ -25,6 +25,100 @@ import { t as registerNodesNet } from "./register-BFFE1Mh1.js";
|
|
|
25
25
|
* Deterministic by construction: fixed timestep, seeded `engine.rng`,
|
|
26
26
|
* no requestAnimationFrame.
|
|
27
27
|
*/
|
|
28
|
+
/** Node types whose whole job is to sit on the ground. Characters, water,
|
|
29
|
+
* clouds, birds and lights are all legitimately off it. */
|
|
30
|
+
const GROUNDED_TYPES = ["MeshInstance3D", "InstancedMesh3D"];
|
|
31
|
+
/** Under one of these, the BODY owns where the thing stands — a character's
|
|
32
|
+
* skin hangs at whatever offset its rig wants, and is not a floating prop. */
|
|
33
|
+
const BODY_OWNED = new Set([
|
|
34
|
+
"CharacterBody3D",
|
|
35
|
+
"RigidBody3D",
|
|
36
|
+
"StaticBody3D",
|
|
37
|
+
"AreaBody3D"
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Every prop that is floating or buried.
|
|
41
|
+
*
|
|
42
|
+
* THE most repeated mistake in scene authoring, by humans and agents alike, is
|
|
43
|
+
* a hand-computed Y: correct when it is written and wrong the moment anything
|
|
44
|
+
* reshapes the ground under it — a river carving its bed, a new seed, a
|
|
45
|
+
* generator that mirrors a carve slightly differently. This is the check that
|
|
46
|
+
* catches it, and `snapToGround` is the fix that stops it happening.
|
|
47
|
+
*
|
|
48
|
+
* Anything explicitly marked `snapToGround: false` is skipped: that is the
|
|
49
|
+
* author saying "yes, this hangs in the air", which a bridge deck, a lantern
|
|
50
|
+
* and a cloud all legitimately do.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* const off = findFloatingProps(gameJson);
|
|
54
|
+
* ok(`nothing floats (${off.length})`, off.length === 0);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
function findFloatingProps(json, opts = {}) {
|
|
58
|
+
registerAllNodes();
|
|
59
|
+
const tolerance = opts.tolerance ?? .1;
|
|
60
|
+
const types = new Set(opts.types ?? GROUNDED_TYPES);
|
|
61
|
+
let scene;
|
|
62
|
+
try {
|
|
63
|
+
scene = loadScene(json);
|
|
64
|
+
} catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
let ground = null;
|
|
68
|
+
const findGround = (node) => {
|
|
69
|
+
if (!ground && node.constructor.typeName === "Terrain3D" && typeof node.heightAt === "function") ground = node;
|
|
70
|
+
for (const child of node.children) findGround(child);
|
|
71
|
+
};
|
|
72
|
+
findGround(scene.root);
|
|
73
|
+
if (!ground) return [];
|
|
74
|
+
const out = [];
|
|
75
|
+
const walk = (node, path, ox, oy, oz, yaw, bodyOwned) => {
|
|
76
|
+
const n = node;
|
|
77
|
+
let wx = ox;
|
|
78
|
+
let wy = oy;
|
|
79
|
+
let wz = oz;
|
|
80
|
+
let ownYaw = yaw;
|
|
81
|
+
if (Array.isArray(n.position)) {
|
|
82
|
+
const c = Math.cos(yaw);
|
|
83
|
+
const s = Math.sin(yaw);
|
|
84
|
+
const lx = n.position[0] ?? 0;
|
|
85
|
+
const lz = n.position[2] ?? 0;
|
|
86
|
+
wx = ox + lx * c + lz * s;
|
|
87
|
+
wz = oz - lx * s + lz * c;
|
|
88
|
+
wy = oy + (n.position[1] ?? 0);
|
|
89
|
+
ownYaw = yaw + (n.rotation?.[1] ?? 0) * Math.PI / 180;
|
|
90
|
+
}
|
|
91
|
+
const type = node.constructor.typeName ?? "";
|
|
92
|
+
const soil = ground;
|
|
93
|
+
if (types.has(type) && n.visible !== false && n.snapToGround !== false && !bodyOwned) {
|
|
94
|
+
const rows = node.transforms;
|
|
95
|
+
if (Array.isArray(rows) && rows.length > 0) {
|
|
96
|
+
let worst = null;
|
|
97
|
+
for (const row of rows) {
|
|
98
|
+
const scale = row[4] ?? 1;
|
|
99
|
+
const half = (n.size?.[1] ?? 0) * scale / 2;
|
|
100
|
+
const gap = wy + (row[1] ?? 0) - half - soil.heightAt(wx + (row[0] ?? 0), wz + (row[2] ?? 0));
|
|
101
|
+
if (Math.abs(gap) > tolerance && (!worst || Math.abs(gap) > Math.abs(worst.gap))) worst = {
|
|
102
|
+
path,
|
|
103
|
+
gap: Math.round(gap * 100) / 100
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (worst) out.push(worst);
|
|
107
|
+
} else {
|
|
108
|
+
const half = (n.size?.[1] ?? 0) / 2;
|
|
109
|
+
const gap = wy - half - soil.heightAt(wx, wz);
|
|
110
|
+
if (Math.abs(gap) > tolerance) out.push({
|
|
111
|
+
path,
|
|
112
|
+
gap: Math.round(gap * 100) / 100
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const childBodyOwned = bodyOwned || BODY_OWNED.has(type);
|
|
117
|
+
for (const child of node.children) walk(child, `${path}/${child.name}`, wx, wy, wz, ownYaw, childBodyOwned);
|
|
118
|
+
};
|
|
119
|
+
walk(scene.root, `/${scene.root.name}`, 0, 0, 0, 0, false);
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
28
122
|
function registerAllNodes() {
|
|
29
123
|
registerNodes2D();
|
|
30
124
|
registerNodes3D();
|
|
@@ -124,10 +218,10 @@ async function runScript(json, opts) {
|
|
|
124
218
|
engine.setScene(scene);
|
|
125
219
|
const physics = opts.physics ?? "auto";
|
|
126
220
|
if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
|
|
127
|
-
const { enablePhysics2D } = await import("./physics-2d-
|
|
221
|
+
const { enablePhysics2D } = await import("./physics-2d-CCVTrKOd.js").then((n) => n.r);
|
|
128
222
|
await enablePhysics2D(engine);
|
|
129
223
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
130
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
224
|
+
const { enablePhysics3D } = await import("./physics-3d-BZZLtwJu.js").then((n) => n.r);
|
|
131
225
|
await enablePhysics3D(engine);
|
|
132
226
|
}
|
|
133
227
|
const failures = [];
|
|
@@ -229,10 +323,10 @@ async function createPlaySession(json, opts = {}) {
|
|
|
229
323
|
engine.setScene(scene);
|
|
230
324
|
const physics = opts.physics ?? "auto";
|
|
231
325
|
if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
|
|
232
|
-
const { enablePhysics2D } = await import("./physics-2d-
|
|
326
|
+
const { enablePhysics2D } = await import("./physics-2d-CCVTrKOd.js").then((n) => n.r);
|
|
233
327
|
await enablePhysics2D(engine);
|
|
234
328
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
235
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
329
|
+
const { enablePhysics3D } = await import("./physics-3d-BZZLtwJu.js").then((n) => n.r);
|
|
236
330
|
await enablePhysics3D(engine);
|
|
237
331
|
}
|
|
238
332
|
const stepMs = 1e3 / (opts.fixedHz ?? 60);
|
|
@@ -267,4 +361,4 @@ async function createPlaySession(json, opts = {}) {
|
|
|
267
361
|
};
|
|
268
362
|
}
|
|
269
363
|
//#endregion
|
|
270
|
-
export { auditScene, captureScene, createPlaySession, describeCapture, registerAllNodes, runScript, validateScene };
|
|
364
|
+
export { auditScene, captureScene, createPlaySession, describeCapture, findFloatingProps, registerAllNodes, runScript, validateScene };
|
package/dist/vite.d.ts
CHANGED
|
@@ -22,5 +22,57 @@ declare function incantoScenes(opts?: IncantoScenesOptions): {
|
|
|
22
22
|
name: string;
|
|
23
23
|
handleHotUpdate(ctx: HotUpdateContext): Promise<undefined | never[]>;
|
|
24
24
|
};
|
|
25
|
+
interface DevServer {
|
|
26
|
+
middlewares: {
|
|
27
|
+
use(path: string, handler: (req: LibraryReq, res: LibraryRes) => void): void;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
interface LibraryReq {
|
|
31
|
+
url?: string | undefined;
|
|
32
|
+
method?: string | undefined;
|
|
33
|
+
headers: Record<string, string | string[] | undefined>;
|
|
34
|
+
}
|
|
35
|
+
interface LibraryRes {
|
|
36
|
+
statusCode: number;
|
|
37
|
+
setHeader(name: string, value: string): void;
|
|
38
|
+
end(body?: string): void;
|
|
39
|
+
}
|
|
40
|
+
interface IncantoLibraryOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Verse8 access token. Defaults to INCANTO_V8_TOKEN / V8_ACCESS_TOKEN.
|
|
43
|
+
* Read at request time so a token exported after the server started works.
|
|
44
|
+
*/
|
|
45
|
+
token?: string;
|
|
46
|
+
/** Upstream catalog (default: the agent8 backend). */
|
|
47
|
+
url?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Serve the agent8 asset catalog at `/api/library` on the dev server.
|
|
51
|
+
*
|
|
52
|
+
* The catalog wants a bearer token and does not CORS-allow localhost, so a page
|
|
53
|
+
* cannot call it — but the dev server can, and it is already running. This is
|
|
54
|
+
* the same proxy `incanto-editor` ships, so the editor's 📚 works identically
|
|
55
|
+
* whether it opened as a page or over a running game.
|
|
56
|
+
*
|
|
57
|
+
* DEV ONLY (vite `configureServer`): nothing about it reaches a build, and the
|
|
58
|
+
* token stays in the terminal that started the server.
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* // vite.config.ts
|
|
62
|
+
* import { incantoLibrary, incantoScenes } from 'incanto/vite';
|
|
63
|
+
* export default defineConfig({ plugins: [incantoScenes(), incantoLibrary()] });
|
|
64
|
+
* ```
|
|
65
|
+
* ```ts
|
|
66
|
+
* // main.ts — the editor then offers the library
|
|
67
|
+
* createGame3D({ ..., debug: DEV, editor: { library: true } });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
declare function incantoLibrary(opts?: IncantoLibraryOptions): {
|
|
71
|
+
name: string;
|
|
72
|
+
apply: "serve";
|
|
73
|
+
configureServer(server: DevServer): void;
|
|
74
|
+
};
|
|
75
|
+
/** @internal Exported for tests — the whole request/response behaviour. */
|
|
76
|
+
declare function serveLibrary(req: LibraryReq, res: LibraryRes, opts?: IncantoLibraryOptions, doFetch?: typeof fetch): Promise<void>;
|
|
25
77
|
//#endregion
|
|
26
|
-
export { IncantoScenesOptions, incantoScenes };
|
|
78
|
+
export { IncantoLibraryOptions, IncantoScenesOptions, incantoLibrary, incantoScenes, serveLibrary };
|
package/dist/vite.js
CHANGED
|
@@ -13,7 +13,12 @@ import { dirname, resolve } from "node:path";
|
|
|
13
13
|
* export default defineConfig({ plugins: [incantoScenes()] });
|
|
14
14
|
* ```
|
|
15
15
|
*
|
|
16
|
-
*
|
|
16
|
+
* `incantoLibrary()` is the second half: it puts the agent8 asset catalog on
|
|
17
|
+
* your own dev server, so the editor opened from a running game
|
|
18
|
+
* (`createGame3D({ editor: { library: true } })`) has the same 📚 the
|
|
19
|
+
* standalone `incanto-editor` has.
|
|
20
|
+
*
|
|
21
|
+
* Typed structurally (no vite dependency) — the returned objects satisfy
|
|
17
22
|
* vite's Plugin interface.
|
|
18
23
|
*/
|
|
19
24
|
function incantoScenes(opts = {}) {
|
|
@@ -53,5 +58,92 @@ function report(ctx, message) {
|
|
|
53
58
|
}
|
|
54
59
|
});
|
|
55
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Serve the agent8 asset catalog at `/api/library` on the dev server.
|
|
63
|
+
*
|
|
64
|
+
* The catalog wants a bearer token and does not CORS-allow localhost, so a page
|
|
65
|
+
* cannot call it — but the dev server can, and it is already running. This is
|
|
66
|
+
* the same proxy `incanto-editor` ships, so the editor's 📚 works identically
|
|
67
|
+
* whether it opened as a page or over a running game.
|
|
68
|
+
*
|
|
69
|
+
* DEV ONLY (vite `configureServer`): nothing about it reaches a build, and the
|
|
70
|
+
* token stays in the terminal that started the server.
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* // vite.config.ts
|
|
74
|
+
* import { incantoLibrary, incantoScenes } from 'incanto/vite';
|
|
75
|
+
* export default defineConfig({ plugins: [incantoScenes(), incantoLibrary()] });
|
|
76
|
+
* ```
|
|
77
|
+
* ```ts
|
|
78
|
+
* // main.ts — the editor then offers the library
|
|
79
|
+
* createGame3D({ ..., debug: DEV, editor: { library: true } });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function incantoLibrary(opts = {}) {
|
|
83
|
+
return {
|
|
84
|
+
name: "incanto-library",
|
|
85
|
+
apply: "serve",
|
|
86
|
+
configureServer(server) {
|
|
87
|
+
server.middlewares.use("/api/library", (req, res) => {
|
|
88
|
+
serveLibrary(req, res, opts);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** @internal Exported for tests — the whole request/response behaviour. */
|
|
94
|
+
async function serveLibrary(req, res, opts = {}, doFetch = fetch) {
|
|
95
|
+
const send = (status, body) => {
|
|
96
|
+
res.statusCode = status;
|
|
97
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
98
|
+
res.end(JSON.stringify(body));
|
|
99
|
+
};
|
|
100
|
+
if (req.method && req.method !== "GET") return send(405, { error: "method not allowed" });
|
|
101
|
+
const env = globalThis.process?.env;
|
|
102
|
+
const header = req.headers["x-incanto-v8-token"];
|
|
103
|
+
const token = (Array.isArray(header) ? header[0] : header)?.trim() || opts.token || env?.INCANTO_V8_TOKEN || env?.V8_ACCESS_TOKEN || "";
|
|
104
|
+
if (!token) return send(401, {
|
|
105
|
+
error: "no Verse8 access token. Pass one to incantoLibrary({ token }) or set INCANTO_V8_TOKEN, or paste one into the library panel.",
|
|
106
|
+
needsToken: true
|
|
107
|
+
});
|
|
108
|
+
const query = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
109
|
+
const params = new URLSearchParams({
|
|
110
|
+
tags: query.get("tags") ?? "",
|
|
111
|
+
page: query.get("page") ?? "1",
|
|
112
|
+
limit: query.get("limit") ?? "24"
|
|
113
|
+
});
|
|
114
|
+
const keyword = query.get("keyword");
|
|
115
|
+
if (keyword) params.set("keyword", keyword);
|
|
116
|
+
const base = opts.url ?? env?.INCANTO_LIBRARY_URL ?? "https://agent8-backend.verse8.io/api/resources";
|
|
117
|
+
try {
|
|
118
|
+
const upstream = await doFetch(`${base}?${params}`, { headers: {
|
|
119
|
+
authorization: `Bearer ${token}`,
|
|
120
|
+
accept: "application/json"
|
|
121
|
+
} });
|
|
122
|
+
if (upstream.status === 401 || upstream.status === 403) return send(401, {
|
|
123
|
+
error: "the asset library rejected that token (expired or wrong account)",
|
|
124
|
+
needsToken: true
|
|
125
|
+
});
|
|
126
|
+
if (!upstream.ok) return send(502, { error: `asset library: HTTP ${upstream.status}` });
|
|
127
|
+
const body = await upstream.json();
|
|
128
|
+
if (body.success === false) return send(502, { error: String(body.error ?? "library error") });
|
|
129
|
+
send(200, {
|
|
130
|
+
items: (Array.isArray(body.data) ? body.data : []).map(libraryItem).filter((i) => i.url),
|
|
131
|
+
page: body.pagination?.page ?? Number(params.get("page")),
|
|
132
|
+
hasNext: body.pagination?.hasNext === true,
|
|
133
|
+
...typeof body.pagination?.total === "number" ? { total: body.pagination.total } : {}
|
|
134
|
+
});
|
|
135
|
+
} catch (error) {
|
|
136
|
+
send(502, { error: `asset library unreachable: ${error instanceof Error ? error.message : String(error)}` });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function libraryItem(row) {
|
|
140
|
+
const r = row ?? {};
|
|
141
|
+
return {
|
|
142
|
+
id: String(r.id ?? r.url ?? ""),
|
|
143
|
+
url: typeof r.url === "string" ? r.url : "",
|
|
144
|
+
description: typeof r.description === "string" ? r.description : "",
|
|
145
|
+
metadata: r.metadata && typeof r.metadata === "object" ? r.metadata : {}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
56
148
|
//#endregion
|
|
57
|
-
export { incantoScenes };
|
|
149
|
+
export { incantoLibrary, incantoScenes, serveLibrary };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{n as e}from"./index-Bx4UtWYY.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};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{i as e,r as t,t as n}from"./index-Bx4UtWYY.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
|
+
`)+(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)}function h(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)}var g=300,_=[`log`,`info`,`warn`,`error`,`debug`],v=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;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(x).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())}))}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))return;let t=new c(this.doc,this.container,{explorer:`Explorer`,inspector:`Inspector`,logs:`Logs`}[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}}[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()}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 _){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(x).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`],[`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 ${b(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;y(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;y(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,S(`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,S(`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,S(`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>g&&this.logRows.splice(0,this.logRows.length-g),this.renderLogs()}renderLogs(){let e=this.panels.get(`logs`);if(!e)return;y(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 y(e){for(let t of[...e.children])t.remove()}function b(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function x(e){if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function S(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{h as attachDebugOverlay};
|