incanto 0.75.0 → 0.77.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/dist/2d.d.ts +1 -1
- package/dist/2d.js +4 -4
- package/dist/3d.d.ts +121 -3
- package/dist/3d.js +4 -4
- package/dist/{create-game-DnwhJ5nW.js → create-game-BMIPKrQW.js} +5 -5
- package/dist/{create-game-DVUhHs2B.js → create-game-Dai5vfVu.js} +5 -5
- package/dist/{editor-switch-O8mxpgRX.d.ts → editor-switch-Bzt0GzVp.d.ts} +12 -2
- package/dist/{environment-presets-BP77Dl0K.js → environment-presets-e_9YCnGu.js} +348 -36
- package/dist/{gameplay-D-JuGura.js → gameplay-Bfff_beb.js} +1468 -61
- package/dist/gameplay.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{physics-2d-x3bCrQf0.js → physics-2d-Tuf5LAyq.js} +2 -2
- package/dist/{physics-3d-Bz2VPQ6D.js → physics-3d-C5MOujfQ.js} +2 -2
- package/dist/{picking-Buita5T9.js → picking-DIwE48sU.js} +8 -5
- package/dist/react.js +1 -1
- package/dist/{register-DxAbTO2T.js → register-7E3P1gz6.js} +1 -1
- package/dist/{src-DLKVc6Hj.js → src-DygJfhOb.js} +1 -1
- package/dist/{test-HlVUeCSn.js → test-CVbxnXlv.js} +7 -7
- package/dist/test.js +1 -1
- package/dist/vite.d.ts +47 -3
- package/dist/vite.js +81 -20
- package/editor/assets/{agent8-BXlYM9rv.js → agent8-DA-I5qhv.js} +1 -1
- package/editor/assets/{debug-S42XGP4Y.js → debug-99tEPoGm.js} +1 -1
- package/editor/assets/index-Db74LZY-.js +11579 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +30 -2
- package/skills/incanto-3d-character.md +26 -1
- package/skills/incanto-editor.md +56 -2
- package/skills/incanto-environment.md +30 -12
- package/skills/incanto-node-reference.md +6 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +6 -1
- package/templates-app/molehill-2d/package.json +1 -1
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/editor/assets/index-DgrgUKno.js +0 -11046
package/dist/gameplay.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { i as worldPosition, n as localFromWorld, r as worldDirection } from "./pose-ByFB_J3O.js";
|
|
2
|
-
import { A as Lifetime, B as FollowCamera, C as Pickup, D as Oscillate, E as PathFollow, F as Interactable, G as phaseOf, H as FloatAway, I as GroupCamera, J as Collector, K as DamageOnContact, L as GameFlow, M as Cooldown, N as hitStop, O as MoveTo, P as screenFlash, R as goToScene, S as PrefabShelf, T as Patrol, U as FaceTarget, W as DayNight, X as ChaseCamera, Y as Checkpoint, Z as Chase, a as Wander, b as SavePoint, c as ballisticPath, d as Sight, i as WaveSpawner, j as CameraShake, k as Mount, l as maxRangeAim,
|
|
2
|
+
import { A as Lifetime, B as FollowCamera, C as Pickup, D as Oscillate, E as PathFollow, F as Interactable, G as phaseOf, H as FloatAway, I as GroupCamera, J as Collector, K as DamageOnContact, L as GameFlow, M as Cooldown, N as hitStop, O as MoveTo, P as screenFlash, R as goToScene, S as PrefabShelf, T as Patrol, U as FaceTarget, W as DayNight, X as ChaseCamera, Y as Checkpoint, Z as Chase, _t as Health, a as Wander, b as SavePoint, c as ballisticPath, d as Sight, gt as Blast, i as WaveSpawner, j as CameraShake, k as Mount, l as maxRangeAim, n as registerGameplayBehaviors, o as Turret, q as Currency, r as ZombieAI, s as ballisticAim, t as GAMEPLAY_BEHAVIORS, u as Spawner, w as Phases, x as Projectile, y as ScoreKeeper, z as restartScene } from "./gameplay-Bfff_beb.js";
|
|
3
3
|
export { Blast, CameraShake, Chase, ChaseCamera, Checkpoint, Collector, Cooldown, Currency, DamageOnContact, DayNight, FaceTarget, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, GroupCamera, Health, Interactable, Lifetime, Mount, MoveTo, Oscillate, PathFollow, Patrol, Phases, Pickup, PrefabShelf, Projectile, SavePoint, ScoreKeeper, Sight, Spawner, Turret, Wander, WaveSpawner, ZombieAI, ballisticAim, ballisticPath, goToScene, hitStop, localFromWorld, maxRangeAim, phaseOf, registerGameplayBehaviors, restartScene, screenFlash, worldDirection, worldPosition };
|
package/dist/index.js
CHANGED
|
@@ -9,5 +9,5 @@ import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
|
|
|
9
9
|
import { a as logText, i as logReport, o as parseDrive, r as resolveRendering, t as isWebGLAvailable } from "./webgl-unavailable-C8aDbGmR.js";
|
|
10
10
|
import { t as createNoise2D } from "./noise-D3nPpmFg.js";
|
|
11
11
|
import { a as PARTICLE_PRESETS, i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-SQa5gIu2.js";
|
|
12
|
-
import { a as findPath, i as preloadUrls, n as assetUrls, o as gridFromRows, r as preloadSceneAssets, t as VERSION } from "./src-
|
|
12
|
+
import { a as findPath, i as preloadUrls, n as assetUrls, o as gridFromRows, r as preloadSceneAssets, t as VERSION } from "./src-DygJfhOb.js";
|
|
13
13
|
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, EffectLog, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Respawn, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMinimap, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, UiWaypoint, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, isWebGLAvailable, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, showBootFailure, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { o as __exportAll } from "./json-CfTjpvW8.js";
|
|
2
2
|
import { et as diagnose } from "./pose-ByFB_J3O.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { _ as Node2D, f as Area2D, g as StaticBody2D, h as RigidBody2D, m as PhysicsBody2D, p as CharacterBody2D, v as validateCollider2D } from "./gameplay-
|
|
4
|
+
import { _ as Node2D, f as Area2D, g as StaticBody2D, h as RigidBody2D, m as PhysicsBody2D, p as CharacterBody2D, v as validateCollider2D } from "./gameplay-Bfff_beb.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { n as jointContacts, t as withoutRapierInitNoise } from "./quiet-rapier-C6fW4zcW.js";
|
|
7
|
-
import { p as Joint2D } from "./register-
|
|
7
|
+
import { p as Joint2D } from "./register-7E3P1gz6.js";
|
|
8
8
|
//#region src/2d/physics/physics-2d.ts
|
|
9
9
|
var physics_2d_exports = /* @__PURE__ */ __exportAll({
|
|
10
10
|
Physics2D: () => Physics2D,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { o as __exportAll } from "./json-CfTjpvW8.js";
|
|
2
2
|
import { et as diagnose } from "./pose-ByFB_J3O.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { $ as Water3D, at as PhysicsBody3D, ct as Node3D, it as CharacterBody3D, lt as validateCollider3D, ot as RigidBody3D, rt as Area3D, st as StaticBody3D } from "./gameplay-
|
|
4
|
+
import { $ as Water3D, at as PhysicsBody3D, ct as Node3D, it as CharacterBody3D, lt as validateCollider3D, ot as RigidBody3D, rt as Area3D, st as StaticBody3D } from "./gameplay-Bfff_beb.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { n as jointContacts, t as withoutRapierInitNoise } from "./quiet-rapier-C6fW4zcW.js";
|
|
7
|
-
import { B as InstancedMesh3D, F as Terrain3D, H as buildMeshGeometry, z as Joint3D } from "./environment-presets-
|
|
7
|
+
import { B as InstancedMesh3D, F as Terrain3D, H as buildMeshGeometry, z as Joint3D } from "./environment-presets-e_9YCnGu.js";
|
|
8
8
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
9
9
|
//#region src/3d/physics/collider-lines.ts
|
|
10
10
|
/**
|
|
@@ -359,11 +359,14 @@ async function openBundledEditor(opts) {
|
|
|
359
359
|
await opts.play(working, camera);
|
|
360
360
|
}, "starting the game…");
|
|
361
361
|
},
|
|
362
|
-
...opts.exit ? { onExit: () =>
|
|
363
|
-
handle?.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
362
|
+
...opts.exit ? { onExit: () => {
|
|
363
|
+
const working = handle?.working();
|
|
364
|
+
return crossFade(async () => {
|
|
365
|
+
handle?.dispose();
|
|
366
|
+
handle = null;
|
|
367
|
+
await opts.exit?.(working);
|
|
368
|
+
}, "back to the game…");
|
|
369
|
+
} } : {}
|
|
367
370
|
});
|
|
368
371
|
}
|
|
369
372
|
/**
|
package/dist/react.js
CHANGED
|
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
|
|
|
156
156
|
pointer: latest.pointer,
|
|
157
157
|
...keyboard !== void 0 ? { keyboard } : {}
|
|
158
158
|
};
|
|
159
|
-
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-
|
|
159
|
+
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-Dai5vfVu.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-BMIPKrQW.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|
|
@@ -3,7 +3,7 @@ import { P as translateOn, t as registerCoreNodes } from "./register-B768Qedj.js
|
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { c as getNodeSchema, p as registerNode } from "./touch-CioTZB-y.js";
|
|
5
5
|
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimations, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-SQa5gIu2.js";
|
|
6
|
-
import { Q as tolerateUnknownAction, V as effectRng, _ as Node2D, f as Area2D, g as StaticBody2D, h as RigidBody2D,
|
|
6
|
+
import { Q as tolerateUnknownAction, V as effectRng, _ as Node2D, f as Area2D, g as StaticBody2D, h as RigidBody2D, m as PhysicsBody2D, p as CharacterBody2D, vt as findHealth } from "./gameplay-Bfff_beb.js";
|
|
7
7
|
import { t as checkSheetGrid } from "./sheet-grid-Cea343VO.js";
|
|
8
8
|
import { AdditiveBlending, BufferAttribute, BufferGeometry, CanvasTexture, Color, DynamicDrawUsage, Group, InstancedMesh, Matrix4, Mesh, MeshBasicMaterial, NearestFilter, NormalBlending, PlaneGeometry, SRGBColorSpace } from "three";
|
|
9
9
|
//#region src/2d/nodes/joint-2d.ts
|
|
@@ -199,6 +199,6 @@ async function preloadSceneAssets(assets, title) {
|
|
|
199
199
|
//#endregion
|
|
200
200
|
//#region src/index.ts
|
|
201
201
|
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
202
|
-
const VERSION = "0.
|
|
202
|
+
const VERSION = "0.77.0";
|
|
203
203
|
//#endregion
|
|
204
204
|
export { findPath as a, preloadUrls as i, assetUrls as n, gridFromRows as o, preloadSceneAssets as r, VERSION as t };
|
|
@@ -5,9 +5,9 @@ import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
|
5
5
|
import { t as Rng } from "./rng-CDOMybym.js";
|
|
6
6
|
import { a as LIGHT_NODE_TYPES, n as startRecording } from "./replay-DrqQ6dZj.js";
|
|
7
7
|
import { c as getNodeSchema, d as mergeStaticProps, u as getNodeType } from "./touch-CioTZB-y.js";
|
|
8
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
9
|
-
import { t as registerNodes2D } from "./register-
|
|
10
|
-
import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-
|
|
8
|
+
import { n as registerGameplayBehaviors } from "./gameplay-Bfff_beb.js";
|
|
9
|
+
import { t as registerNodes2D } from "./register-7E3P1gz6.js";
|
|
10
|
+
import { n as registerNodes3D, t as resolveEnvironmentHdri } from "./environment-presets-e_9YCnGu.js";
|
|
11
11
|
import { a as NetworkManager, c as readSyncKey, i as sanitizeName, n as registerNodesNet, r as NetworkSpawner, s as findOwnerNode, t as createSplitScreen } from "./split-screen-B-dIcQsQ.js";
|
|
12
12
|
import { Box3, Euler, Frustum, Matrix4, PerspectiveCamera, Quaternion, Ray, Vector3 } from "three";
|
|
13
13
|
//#region src/core/asset-urls.ts
|
|
@@ -4467,10 +4467,10 @@ async function runScript(json, opts) {
|
|
|
4467
4467
|
if (opts.locale) engine.locale.locale = opts.locale;
|
|
4468
4468
|
const physics = opts.physics ?? "auto";
|
|
4469
4469
|
if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
|
|
4470
|
-
const { enablePhysics2D } = await import("./physics-2d-
|
|
4470
|
+
const { enablePhysics2D } = await import("./physics-2d-Tuf5LAyq.js").then((n) => n.r);
|
|
4471
4471
|
await enablePhysics2D(engine);
|
|
4472
4472
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
4473
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
4473
|
+
const { enablePhysics3D } = await import("./physics-3d-C5MOujfQ.js").then((n) => n.r);
|
|
4474
4474
|
await enablePhysics3D(engine);
|
|
4475
4475
|
}
|
|
4476
4476
|
const failures = [];
|
|
@@ -4755,10 +4755,10 @@ async function createPlaySession(json, opts = {}) {
|
|
|
4755
4755
|
engine.setScene(scene);
|
|
4756
4756
|
const physics = opts.physics ?? "auto";
|
|
4757
4757
|
if (physics === "2d" || physics === "auto" && scene.dimension === "2d") {
|
|
4758
|
-
const { enablePhysics2D } = await import("./physics-2d-
|
|
4758
|
+
const { enablePhysics2D } = await import("./physics-2d-Tuf5LAyq.js").then((n) => n.r);
|
|
4759
4759
|
await enablePhysics2D(engine);
|
|
4760
4760
|
} else if (physics === "3d" || physics === "auto" && scene.dimension === "3d") {
|
|
4761
|
-
const { enablePhysics3D } = await import("./physics-3d-
|
|
4761
|
+
const { enablePhysics3D } = await import("./physics-3d-C5MOujfQ.js").then((n) => n.r);
|
|
4762
4762
|
await enablePhysics3D(engine);
|
|
4763
4763
|
}
|
|
4764
4764
|
const stepMs = 1e3 / (opts.fixedHz ?? 60);
|
package/dist/test.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { i as instancedScenes, r as auditScene } from "./replay-DrqQ6dZj.js";
|
|
2
|
-
import { A as geometricPicker, C as facingReport, D as playtest, E as findPlayer, F as sceneAssetUrls, M as pointAtNode, N as describeFraming, O as playtestFailed, P as framingText, S as collectionProblems, T as failingReplays, _ as feelReport, a as registerAllNodes, b as takeCollectionSnapshots, c as feelsRung, d as ladderVerdict, f as saysRung, g as playMultiplayer, h as multiplayText, i as findFloatingProps, j as geometricView, k as playtestText, l as firstLine, m as multiplayProblems, n as createPlaySession, o as runScript, p as unmeasuredPlays, r as describeCapture, s as validateScene, t as captureScene, u as ladderText, v as feelText, w as facingText, x as agreementProblems, y as takeAgreementSnapshots } from "./test-
|
|
2
|
+
import { A as geometricPicker, C as facingReport, D as playtest, E as findPlayer, F as sceneAssetUrls, M as pointAtNode, N as describeFraming, O as playtestFailed, P as framingText, S as collectionProblems, T as failingReplays, _ as feelReport, a as registerAllNodes, b as takeCollectionSnapshots, c as feelsRung, d as ladderVerdict, f as saysRung, g as playMultiplayer, h as multiplayText, i as findFloatingProps, j as geometricView, k as playtestText, l as firstLine, m as multiplayProblems, n as createPlaySession, o as runScript, p as unmeasuredPlays, r as describeCapture, s as validateScene, t as captureScene, u as ladderText, v as feelText, w as facingText, x as agreementProblems, y as takeAgreementSnapshots } from "./test-CVbxnXlv.js";
|
|
3
3
|
export { agreementProblems, auditScene, captureScene, collectionProblems, createPlaySession, describeCapture, describeFraming, facingReport, facingText, failingReplays, feelReport, feelText, feelsRung, findFloatingProps, findPlayer, firstLine, framingText, geometricPicker, geometricView, instancedScenes, ladderText, ladderVerdict, multiplayProblems, multiplayText, playMultiplayer, playtest, playtestFailed, playtestText, pointAtNode, registerAllNodes, runScript, saysRung, sceneAssetUrls, takeAgreementSnapshots, takeCollectionSnapshots, unmeasuredPlays, validateScene };
|
package/dist/vite.d.ts
CHANGED
|
@@ -151,6 +151,50 @@ interface IncantoScenesOptions {
|
|
|
151
151
|
* Nothing outside it is readable or writable, whatever a request asks for.
|
|
152
152
|
*/
|
|
153
153
|
root?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Called after a scene is written through this server — the editor's save,
|
|
156
|
+
* and the editor's create. In-process, with the scene itself; the same
|
|
157
|
+
* event goes to stdout for anything watching the dev server from outside
|
|
158
|
+
* (see {@link SceneEvent}).
|
|
159
|
+
*/
|
|
160
|
+
onSave?(event: SceneEvent): void;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* What this server announces when a scene lands, on stdout AND to `onSave`.
|
|
164
|
+
*
|
|
165
|
+
* ONE line per event, `[incanto] ` and a JSON object — readable by a person in
|
|
166
|
+
* the terminal they are already watching, unambiguous to a machine, and
|
|
167
|
+
* extensible without breaking a parser that only reads the fields it knows:
|
|
168
|
+
*
|
|
169
|
+
* [incanto] {"event":"scene:saved","file":"src/game.scene.json","bytes":13284,"at":"2026-09-08T10:19:57.412Z"}
|
|
170
|
+
*
|
|
171
|
+
* It exists because a container had no way to hear a save that happened inside
|
|
172
|
+
* it. The editor a running game hosts writes through `PUT /api/scene`, and the
|
|
173
|
+
* only signals available to the process supervising that container were
|
|
174
|
+
* accidents: watching the filesystem, or scraping vite's `page reload` line —
|
|
175
|
+
* which existed only because saving used to reload the page, and went away
|
|
176
|
+
* when that was fixed.
|
|
177
|
+
*
|
|
178
|
+
* `abs` and `json` are for `onSave` only; the printed line carries neither (an
|
|
179
|
+
* absolute container path means nothing outside it, and a scene does not
|
|
180
|
+
* belong on one log line).
|
|
181
|
+
*/
|
|
182
|
+
interface SceneEvent {
|
|
183
|
+
event: "scene:saved" | "scene:created";
|
|
184
|
+
/** Project-relative, forward slashes on every OS. */
|
|
185
|
+
file: string;
|
|
186
|
+
/** Bytes written. */
|
|
187
|
+
bytes: number;
|
|
188
|
+
/** ISO-8601, when it landed. */
|
|
189
|
+
at: string;
|
|
190
|
+
/** Absolute path — `onSave` only, never printed. */
|
|
191
|
+
abs?: string;
|
|
192
|
+
/** The scene as written — `onSave` only, never printed. */
|
|
193
|
+
json?: unknown;
|
|
194
|
+
}
|
|
195
|
+
/** Hooks the middlewares carry (exported for tests, not for vite). */
|
|
196
|
+
interface SceneHooks {
|
|
197
|
+
onSave?(event: SceneEvent): void;
|
|
154
198
|
}
|
|
155
199
|
declare function incantoScenes(opts?: IncantoScenesOptions): {
|
|
156
200
|
name: string;
|
|
@@ -241,9 +285,9 @@ declare function discoverScenes(root: string): ProjectFileEntry[];
|
|
|
241
285
|
*/
|
|
242
286
|
declare function resolveSceneFile(root: string, rel: unknown): string | null;
|
|
243
287
|
/** @internal Exported for tests — `GET`/`POST /api/scenes`. */
|
|
244
|
-
declare function serveSceneList(req: ApiReq, res: LibraryRes, root: string): Promise<void>;
|
|
288
|
+
declare function serveSceneList(req: ApiReq, res: LibraryRes, root: string, hooks?: SceneHooks): Promise<void>;
|
|
245
289
|
/** @internal Exported for tests — `GET`/`PUT /api/scene?file=`. */
|
|
246
|
-
declare function serveSceneFile(req: ApiReq, res: LibraryRes, root: string): Promise<void>;
|
|
290
|
+
declare function serveSceneFile(req: ApiReq, res: LibraryRes, root: string, hooks?: SceneHooks): Promise<void>;
|
|
247
291
|
interface DevServer {
|
|
248
292
|
middlewares: {
|
|
249
293
|
use(path: string, handler: (req: LibraryReq, res: LibraryRes) => void): void;
|
|
@@ -317,4 +361,4 @@ declare function serveDeviceAuth(req: LibraryReq, res: LibraryRes, opts?: Incant
|
|
|
317
361
|
/** @internal Exported for tests — the whole request/response behaviour. */
|
|
318
362
|
declare function serveLibrary(req: LibraryReq, res: LibraryRes, opts?: IncantoLibraryOptions, doFetch?: typeof fetch): Promise<void>;
|
|
319
363
|
//#endregion
|
|
320
|
-
export { type FrameHost, type FrameReq, type FrameRes, IncantoLibraryOptions, IncantoScenesOptions, type IncantoTrimOptions, ProjectFileEntry, type StaticInspectHost, createStaticInspectHost, discoverScenes, incantoLibrary, incantoScenes, incantoTrim, listeningPorts, maskToken, onlyKnownOptions, parseProcNetTcp, projectDimension, resolveSceneFile, sceneFacts, serveDeviceAuth, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList, serveTokenStatus };
|
|
364
|
+
export { type FrameHost, type FrameReq, type FrameRes, IncantoLibraryOptions, IncantoScenesOptions, type IncantoTrimOptions, ProjectFileEntry, SceneEvent, SceneHooks, type StaticInspectHost, createStaticInspectHost, discoverScenes, incantoLibrary, incantoScenes, incantoTrim, listeningPorts, maskToken, onlyKnownOptions, parseProcNetTcp, projectDimension, resolveSceneFile, sceneFacts, serveDeviceAuth, serveFrameEndpoints, serveLibrary, serveSceneFile, serveSceneList, serveTokenStatus };
|
package/dist/vite.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as parseJsonText } from "./json-CfTjpvW8.js";
|
|
2
2
|
import { P as newUid } from "./pose-ByFB_J3O.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { t as VERSION } from "./src-
|
|
4
|
+
import { t as VERSION } from "./src-DygJfhOb.js";
|
|
5
5
|
import { n as diffSignatures } from "./frame-report-D-_7YF2G.js";
|
|
6
|
-
import { s as validateScene } from "./test-
|
|
6
|
+
import { s as validateScene } from "./test-CVbxnXlv.js";
|
|
7
7
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { basename, dirname, extname, join, normalize, relative, resolve, sep } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
@@ -525,6 +525,29 @@ function incantoTrim(opts = {}) {
|
|
|
525
525
|
* vite's Plugin interface.
|
|
526
526
|
*/
|
|
527
527
|
/**
|
|
528
|
+
* Announce a scene that LANDED. Never called for a refused write: the line
|
|
529
|
+
* means the bytes are on disk, which is the only reading that is any use to a
|
|
530
|
+
* process deciding whether to rebuild.
|
|
531
|
+
*/
|
|
532
|
+
function announce(kind, base, abs, raw, json, hooks) {
|
|
533
|
+
const event = {
|
|
534
|
+
event: kind,
|
|
535
|
+
file: relative(base, abs).split(sep).join("/"),
|
|
536
|
+
bytes: Buffer.byteLength(raw),
|
|
537
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
538
|
+
};
|
|
539
|
+
console.log(`[incanto] ${JSON.stringify(event)}`);
|
|
540
|
+
try {
|
|
541
|
+
hooks?.onSave?.({
|
|
542
|
+
...event,
|
|
543
|
+
abs,
|
|
544
|
+
json
|
|
545
|
+
});
|
|
546
|
+
} catch (error) {
|
|
547
|
+
console.error(`[incanto] onSave threw: ${message(error)}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
528
551
|
* The BUILT-IN art, at the path the scenes already name.
|
|
529
552
|
*
|
|
530
553
|
* `incanto-assets` prints `incanto/assets/items/coin.png` as an asset's url and
|
|
@@ -587,8 +610,28 @@ const ASSET_MIME = {
|
|
|
587
610
|
".glb": "model/gltf-binary",
|
|
588
611
|
".gltf": "model/gltf+json"
|
|
589
612
|
};
|
|
613
|
+
/**
|
|
614
|
+
* What this dev server has just written through `PUT /api/scene`, by absolute
|
|
615
|
+
* path, so its own hot update can be told apart from somebody else's edit.
|
|
616
|
+
*
|
|
617
|
+
* The editor a running game hosts saves through that endpoint — and the file
|
|
618
|
+
* it writes is the file vite is watching, so vite hot-updates it, and a JSON
|
|
619
|
+
* module imported by `main.ts` cannot be hot-swapped: vite full-page-RELOADS.
|
|
620
|
+
* The page comes back as the game and the editor is gone, mid-edit, on save.
|
|
621
|
+
* A write we just made is one the page already has; a hand edit in a text
|
|
622
|
+
* editor is news, and still reloads.
|
|
623
|
+
*
|
|
624
|
+
* Keyed by bytes as well as path so the pass cannot be spent by a different
|
|
625
|
+
* write that happens to arrive first, and it is one-shot: this is a receipt,
|
|
626
|
+
* never a mode.
|
|
627
|
+
*/
|
|
628
|
+
const OWN_WRITES = /* @__PURE__ */ new Map();
|
|
590
629
|
function incantoScenes(opts = {}) {
|
|
591
|
-
onlyKnownOptions("incantoScenes", opts, [
|
|
630
|
+
onlyKnownOptions("incantoScenes", opts, [
|
|
631
|
+
"strictBehaviors",
|
|
632
|
+
"root",
|
|
633
|
+
"onSave"
|
|
634
|
+
]);
|
|
592
635
|
return {
|
|
593
636
|
name: "incanto-scenes",
|
|
594
637
|
/**
|
|
@@ -599,19 +642,31 @@ function incantoScenes(opts = {}) {
|
|
|
599
642
|
configureServer(server) {
|
|
600
643
|
serveFrameEndpoints(server, VERSION);
|
|
601
644
|
const root = opts.root ?? server.config?.root ?? process.cwd();
|
|
645
|
+
const hooks = opts.onSave ? { onSave: opts.onSave } : {};
|
|
602
646
|
server.middlewares.use("/api/scenes", (req, res) => {
|
|
603
|
-
serveSceneList(req, res, root);
|
|
647
|
+
serveSceneList(req, res, root, hooks);
|
|
604
648
|
});
|
|
605
649
|
server.middlewares.use("/api/scene", (req, res) => {
|
|
606
|
-
serveSceneFile(req, res, root);
|
|
650
|
+
serveSceneFile(req, res, root, hooks);
|
|
607
651
|
});
|
|
608
652
|
serveBuiltInAssets(server);
|
|
609
653
|
},
|
|
610
654
|
async handleHotUpdate(ctx) {
|
|
611
655
|
if (!ctx.file.endsWith(".scene.json")) return void 0;
|
|
656
|
+
let text;
|
|
657
|
+
try {
|
|
658
|
+
text = await ctx.read();
|
|
659
|
+
} catch {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
const own = OWN_WRITES.get(normalize(ctx.file));
|
|
663
|
+
if (own !== void 0) {
|
|
664
|
+
OWN_WRITES.delete(normalize(ctx.file));
|
|
665
|
+
if (own === text) return [];
|
|
666
|
+
}
|
|
612
667
|
let json;
|
|
613
668
|
try {
|
|
614
|
-
json = parseJsonText(
|
|
669
|
+
json = parseJsonText(text);
|
|
615
670
|
} catch (e) {
|
|
616
671
|
report(ctx, `not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
617
672
|
return [];
|
|
@@ -811,7 +866,7 @@ function readBody(req) {
|
|
|
811
866
|
});
|
|
812
867
|
}
|
|
813
868
|
/** @internal Exported for tests — `GET`/`POST /api/scenes`. */
|
|
814
|
-
async function serveSceneList(req, res, root) {
|
|
869
|
+
async function serveSceneList(req, res, root, hooks) {
|
|
815
870
|
const base = normalize(resolve(root));
|
|
816
871
|
if (req.method === void 0 || req.method === "GET") return json(res, 200, discoverScenes(base));
|
|
817
872
|
if (req.method !== "POST") return json(res, 405, { error: "method not allowed" });
|
|
@@ -828,22 +883,25 @@ async function serveSceneList(req, res, root) {
|
|
|
828
883
|
if (existsSync(abs)) return json(res, 409, { error: `already exists: ${String(wanted)}` });
|
|
829
884
|
const name = basename(abs).replace(/\.scene\.json$|\.json$/, "") || "Scene";
|
|
830
885
|
const dimension = (body.dimension === "3d" || body.dimension === "2d" ? body.dimension : null) ?? projectDimension(base) ?? "2d";
|
|
886
|
+
const created = {
|
|
887
|
+
format: 1,
|
|
888
|
+
type: "scene",
|
|
889
|
+
dimension,
|
|
890
|
+
name,
|
|
891
|
+
root: {
|
|
892
|
+
name,
|
|
893
|
+
type: dimension === "3d" ? "Node3D" : "Node2D",
|
|
894
|
+
uid: newUid()
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
const raw = `${JSON.stringify(created, null, 2)}\n`;
|
|
831
898
|
try {
|
|
832
899
|
mkdirSync(dirname(abs), { recursive: true });
|
|
833
|
-
writeFileSync(abs,
|
|
834
|
-
format: 1,
|
|
835
|
-
type: "scene",
|
|
836
|
-
dimension,
|
|
837
|
-
name,
|
|
838
|
-
root: {
|
|
839
|
-
name,
|
|
840
|
-
type: dimension === "3d" ? "Node3D" : "Node2D",
|
|
841
|
-
uid: newUid()
|
|
842
|
-
}
|
|
843
|
-
}, null, 2)}\n`);
|
|
900
|
+
writeFileSync(abs, raw);
|
|
844
901
|
} catch (error) {
|
|
845
902
|
return json(res, 400, { error: message(error) });
|
|
846
903
|
}
|
|
904
|
+
announce("scene:created", base, abs, raw, created, hooks);
|
|
847
905
|
return json(res, 201, {
|
|
848
906
|
rel: relative(base, abs).split(sep).join("/"),
|
|
849
907
|
abs,
|
|
@@ -852,7 +910,7 @@ async function serveSceneList(req, res, root) {
|
|
|
852
910
|
});
|
|
853
911
|
}
|
|
854
912
|
/** @internal Exported for tests — `GET`/`PUT /api/scene?file=`. */
|
|
855
|
-
async function serveSceneFile(req, res, root) {
|
|
913
|
+
async function serveSceneFile(req, res, root, hooks) {
|
|
856
914
|
const base = normalize(resolve(root));
|
|
857
915
|
const file = new URL(req.url ?? "/", "http://localhost").searchParams.get("file");
|
|
858
916
|
const abs = resolveSceneFile(base, file);
|
|
@@ -903,11 +961,14 @@ async function serveSceneFile(req, res, root) {
|
|
|
903
961
|
};
|
|
904
962
|
if (!already.ok) return json(res, 409, { error: `refusing to overwrite ${file} — ${already.why}. The editor only replaces scenes, and only creates new files.` });
|
|
905
963
|
}
|
|
964
|
+
const written = raw.endsWith("\n") ? raw : `${raw}\n`;
|
|
906
965
|
try {
|
|
907
|
-
writeFileSync(abs,
|
|
966
|
+
writeFileSync(abs, written);
|
|
908
967
|
} catch (error) {
|
|
909
968
|
return json(res, 400, { error: message(error) });
|
|
910
969
|
}
|
|
970
|
+
OWN_WRITES.set(normalize(abs), written);
|
|
971
|
+
announce("scene:saved", base, abs, written, parsed, hooks);
|
|
911
972
|
return json(res, 200, {
|
|
912
973
|
ok: true,
|
|
913
974
|
output: abs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i as e,n as t}from"./index-
|
|
1
|
+
import{i as e,n as t}from"./index-Db74LZY-.js";async function n(e,n){return new a((await t(()=>import(`./GameServer-C56iOUgF.js`),[],import.meta.url)).GameServer,e,{diagnostics:n})}var r=[500,1e3,2e3,4e3,8e3],i=8,a=class{raw;active=new Map;reconnecting=!1;disposed=!1;diagnostics;wait;constructor(e,t,n){this.diagnostics=n?.diagnostics??null,this.wait=n?.wait??(e=>new Promise(t=>{setTimeout(t,e)})),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{for(let t=0;t<i;t++){let n=!1,i=null;try{n=await this.rawConnect()!==!1}catch(e){i=e}if(this.disposed)return;if(n){for(let e of this.active.values())e.off(),e.off=e.make();t>0&&e(this.diagnostics,`info`,`[incanto] multiplayer reconnected after ${t+1} attempts.`);return}t===0&&e(this.diagnostics,`warn`,`[incanto] the multiplayer connection dropped and the server would not take it back${i?` (${i instanceof Error?i.message:String(i)})`:``}. Retrying — other players cannot see this one until it comes back.`);let a=r[Math.min(t,r.length-1)]??8e3;if(await this.wait(a),this.disposed)return}e(this.diagnostics,`error`,`[incanto] multiplayer gave up after ${i} reconnect attempts — this client is offline and the others cannot see it. Call connect() again to retry.`)}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{n as createAgent8Server};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{a as e,o as t,r as n,t as r}from"./index-
|
|
1
|
+
import{a as e,o as t,r as n,t as r}from"./index-Db74LZY-.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 t=this.panels.get(`inspector`);if(!t)return;let n=t.body.scrollTop;H(t.body);let r=this.selected;if(r&&r.tree===null&&(this.selected=null,this.engine.debugSelection=null,this.applyColliderScope(),r=null),!r){let e=this.doc.createElement(`div`);e.textContent=`select a node in the Explorer`,b(e,{opacity:`0.6`}),t.body.appendChild(e);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`}),t.body.appendChild(a),r.groups.size>0){let e=this.doc.createElement(`div`);e.textContent=`groups: ${[...r.groups].join(`, `)}`,b(e,{opacity:`0.7`,marginBottom:`6px`}),t.body.appendChild(e)}let o=e(i),s=r;for(let e of Object.keys(o)){let n=o[e];this.renderValueRow(t.body,r,e,{read:()=>s[e],write:t=>{s[e]=t},options:n?.options,variants:n?.variants})}t.body.scrollTop=n}renderValueRow(e,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 e of l){let r=e===s;this.renderValueRow(o,n,e,{path:`${u}.${e}`,read:()=>i.read()[e]??(r?``:null),write:n=>{if(r&&i.variants){let e=i.variants.byTag[String(n)];if(e!==void 0){i.write(t(e));return}}i.write({...i.read(),[e]:n})},options:r&&i.variants?Object.keys(i.variants.byTag):void 0})}e.appendChild(c),e.appendChild(o);return}else{let o=JSON.stringify(t(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 t=i.path??r,s=this.detailOpen.get(n)?.has(t)??!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 e=this.detailOpen.get(n);e||(e=new Set,this.detailOpen.set(n,e)),s?e.delete(t):e.add(t),this.renderInspector()}),c.appendChild(l),e.appendChild(c),s){let t=this.doc.createElement(`div`);t.textContent=P(a,o),b(t,{opacity:`0.6`,whiteSpace:`pre-wrap`,wordBreak:`break-all`,marginLeft:`10px`,paddingLeft:`8px`,borderLeft:`1px solid rgba(255,255,255,0.14)`}),e.appendChild(t)}return}}e.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};
|