incanto 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/incanto-editor.mjs +101 -28
- package/dist/2d.d.ts +16 -1
- package/dist/2d.js +2 -2
- package/dist/3d.d.ts +34 -1
- package/dist/3d.js +4 -4
- package/dist/{create-game-CbuLWorm.js → create-game-5z_QVtLx.js} +13 -9
- package/dist/{create-game-CNKXGfpr.js → create-game-DuBTv2zI.js} +14 -10
- package/dist/debug-draw-BM3DsvtT.js +18 -0
- package/dist/debug.js +1 -1
- package/dist/editor.js +1346 -1231
- package/dist/{gameplay-L05WgWd1.js → gameplay-Cfr6aFZ1.js} +12 -3
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1 -1
- package/dist/{physics-2d-CCVTrKOd.js → physics-2d-3kOQCtgd.js} +26 -1
- package/dist/{physics-3d-BZZLtwJu.js → physics-3d-CeRH-Ff_.js} +38 -3
- package/dist/react.js +1 -1
- package/dist/{register-C44aSduO.js → register-DJ0SByQg.js} +1 -1
- package/dist/{editor-switch-CAKlJMIY.js → teardown-ByzfDPyu.js} +83 -4
- package/dist/test.js +6 -6
- package/dist/vite.d.ts +87 -1
- package/dist/vite.js +262 -3
- package/editor/assets/{agent8-DEVkEa3d.js → agent8-CAp0i5qn.js} +1 -1
- package/editor/assets/{debug-zGAtpDF0.js → debug-BoEYfbqK.js} +1 -1
- package/editor/assets/index-BO6WU8by.js +10696 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/skills/incanto-editor.md +61 -8
- package/skills/incanto-physics-and-input.md +15 -0
- package/skills/incanto-verifying-your-game.md +6 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/vite.config.ts +7 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/vite.config.ts +7 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/vite.config.ts +7 -0
- package/dist/debug-draw-CZmOYjL2.js +0 -13
- package/editor/assets/index-Bx4UtWYY.js +0 -10586
package/bin/incanto-editor.mjs
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* API (the page can only address *.scene.json files under the launch directory):
|
|
11
11
|
* GET /api/meta → { version, mode, root, input?, output? }
|
|
12
|
-
* GET /api/scenes → [{ rel, abs }]
|
|
12
|
+
* GET /api/scenes → [{ rel, abs, size, modified, scene?|notScene? }]
|
|
13
13
|
* POST /api/scenes → { path } creates a minimal scene (project mode)
|
|
14
14
|
* GET /api/scene[?file=] → scene JSON (single mode ignores ?file=)
|
|
15
15
|
* PUT /api/scene[?file=] → validates the scene shape, writes the file
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* request host. Bodies are capped at 8MB. Addressable paths are root-bounded
|
|
28
28
|
* and must end in .scene.json.
|
|
29
29
|
*/
|
|
30
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
30
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
31
31
|
import { createServer } from 'node:http';
|
|
32
32
|
import { basename, dirname, extname, join, normalize, relative, resolve, sep } from 'node:path';
|
|
33
33
|
import { fileURLToPath } from 'node:url';
|
|
@@ -213,9 +213,20 @@ function discoverScenes() {
|
|
|
213
213
|
for (const e of entries) {
|
|
214
214
|
if (e.isDirectory()) {
|
|
215
215
|
if (!SKIP_DIRS.has(e.name) && !e.name.startsWith('.')) walk(join(dir, e.name), depth + 1);
|
|
216
|
-
} else if (e.name.endsWith('.
|
|
216
|
+
} else if (e.name.endsWith('.json')) {
|
|
217
217
|
const abs = join(dir, e.name);
|
|
218
|
-
|
|
218
|
+
// size + mtime are what the browser prints beside each row; a folder
|
|
219
|
+
// whose files are all "just now" is the one you were working in
|
|
220
|
+
let size = 0;
|
|
221
|
+
let modified = 0;
|
|
222
|
+
try {
|
|
223
|
+
const stat = statSync(abs);
|
|
224
|
+
size = stat.size;
|
|
225
|
+
modified = stat.mtimeMs;
|
|
226
|
+
} catch {
|
|
227
|
+
// listed without facts beats not listed at all
|
|
228
|
+
}
|
|
229
|
+
found.push({ rel: relative(ROOT, abs), abs, size, modified, ...inspectJson(abs, size) });
|
|
219
230
|
}
|
|
220
231
|
}
|
|
221
232
|
};
|
|
@@ -223,9 +234,65 @@ function discoverScenes() {
|
|
|
223
234
|
return found.sort((a, b) => a.rel.localeCompare(b.rel));
|
|
224
235
|
}
|
|
225
236
|
|
|
226
|
-
/**
|
|
237
|
+
/**
|
|
238
|
+
* Is this JSON a scene? The file says so itself — `type: "scene"`, the same key
|
|
239
|
+
* the loader demands — so a row can be marked instead of guessed from its name.
|
|
240
|
+
*/
|
|
241
|
+
function sceneFacts(json) {
|
|
242
|
+
if (json === null || typeof json !== 'object' || Array.isArray(json)) {
|
|
243
|
+
return { ok: false, why: 'the file is JSON, but not a JSON object' };
|
|
244
|
+
}
|
|
245
|
+
if (json.type !== 'scene') {
|
|
246
|
+
return {
|
|
247
|
+
ok: false,
|
|
248
|
+
why:
|
|
249
|
+
json.type === undefined
|
|
250
|
+
? '"type" must be "scene", and this file has no "type"'
|
|
251
|
+
: `"type" must be "scene", not ${JSON.stringify(json.type)}`,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (json.format !== 1)
|
|
255
|
+
return { ok: false, why: `"format" must be 1, not ${JSON.stringify(json.format)}` };
|
|
256
|
+
if (typeof json.root !== 'object' || json.root === null) {
|
|
257
|
+
return { ok: false, why: '"root" must be a node object' };
|
|
258
|
+
}
|
|
259
|
+
const count = (n) =>
|
|
260
|
+
Array.isArray(n?.children) ? n.children.reduce((t, c) => t + count(c), 1) : 1;
|
|
261
|
+
return {
|
|
262
|
+
ok: true,
|
|
263
|
+
name: typeof json.name === 'string' ? json.name : '',
|
|
264
|
+
// only when the file SAYS so — `dimension` is optional and has no default
|
|
265
|
+
...(json.dimension === '2d' || json.dimension === '3d' ? { dimension: json.dimension } : {}),
|
|
266
|
+
nodes: count(json.root),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function inspectJson(abs, size) {
|
|
271
|
+
if (size > 16_000_000) return { notScene: 'too large to check without opening it' };
|
|
272
|
+
let parsed;
|
|
273
|
+
try {
|
|
274
|
+
parsed = JSON.parse(readFileSync(abs, 'utf-8'));
|
|
275
|
+
} catch (error) {
|
|
276
|
+
return { notScene: `not valid JSON: ${String(error.message ?? error)}` };
|
|
277
|
+
}
|
|
278
|
+
const facts = sceneFacts(parsed);
|
|
279
|
+
return facts.ok
|
|
280
|
+
? {
|
|
281
|
+
scene: {
|
|
282
|
+
name: facts.name,
|
|
283
|
+
...(facts.dimension ? { dimension: facts.dimension } : {}),
|
|
284
|
+
nodes: facts.nodes,
|
|
285
|
+
},
|
|
286
|
+
}
|
|
287
|
+
: { notScene: facts.why };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Root-bounded, .json-only — the browser offers every JSON and the LOAD decides,
|
|
292
|
+
* but this must never become a way to read .env or somebody's key file.
|
|
293
|
+
*/
|
|
227
294
|
function resolveSceneFile(rel) {
|
|
228
|
-
if (typeof rel !== 'string' || !rel.endsWith('.
|
|
295
|
+
if (typeof rel !== 'string' || !rel.endsWith('.json')) return null;
|
|
229
296
|
const abs = normalize(resolve(ROOT, rel));
|
|
230
297
|
if (abs !== ROOT && !abs.startsWith(ROOT + sep)) return null;
|
|
231
298
|
return abs;
|
|
@@ -276,18 +343,6 @@ function originAllowed(req) {
|
|
|
276
343
|
}
|
|
277
344
|
}
|
|
278
345
|
|
|
279
|
-
function isSceneShaped(json) {
|
|
280
|
-
return (
|
|
281
|
-
json !== null &&
|
|
282
|
-
typeof json === 'object' &&
|
|
283
|
-
json.format === 1 &&
|
|
284
|
-
json.type === 'scene' &&
|
|
285
|
-
typeof json.name === 'string' &&
|
|
286
|
-
json.root !== null &&
|
|
287
|
-
typeof json.root === 'object'
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
346
|
function readBody(req, res, onJson) {
|
|
292
347
|
const chunks = [];
|
|
293
348
|
let received = 0;
|
|
@@ -346,18 +401,23 @@ const server = createServer((req, res) => {
|
|
|
346
401
|
return send(res, 403, JSON.stringify({ error: 'cross-origin write rejected' }));
|
|
347
402
|
}
|
|
348
403
|
readBody(req, res, (body) => {
|
|
349
|
-
|
|
404
|
+
// a path with no extension means the usual thing, so `levels/arena` works
|
|
405
|
+
const wanted =
|
|
406
|
+
typeof body?.path === 'string' && body.path && !body.path.endsWith('.json')
|
|
407
|
+
? `${body.path}.scene.json`
|
|
408
|
+
: body?.path;
|
|
409
|
+
const abs = resolveSceneFile(wanted);
|
|
350
410
|
if (!abs) {
|
|
351
411
|
return send(
|
|
352
412
|
res,
|
|
353
413
|
400,
|
|
354
|
-
JSON.stringify({ error: 'path must be a
|
|
414
|
+
JSON.stringify({ error: 'path must be a .json file inside the project' }),
|
|
355
415
|
);
|
|
356
416
|
}
|
|
357
417
|
if (existsSync(abs)) {
|
|
358
|
-
return send(res, 409, JSON.stringify({ error: `already exists: ${
|
|
418
|
+
return send(res, 409, JSON.stringify({ error: `already exists: ${wanted}` }));
|
|
359
419
|
}
|
|
360
|
-
const name = basename(abs).replace(/\.scene\.json$/, '') || 'Scene';
|
|
420
|
+
const name = basename(abs).replace(/\.scene\.json$|\.json$/, '') || 'Scene';
|
|
361
421
|
const scene = {
|
|
362
422
|
format: 1,
|
|
363
423
|
type: 'scene',
|
|
@@ -388,26 +448,39 @@ const server = createServer((req, res) => {
|
|
|
388
448
|
);
|
|
389
449
|
}
|
|
390
450
|
if (req.method === 'GET') {
|
|
451
|
+
let text;
|
|
452
|
+
let parsed;
|
|
391
453
|
try {
|
|
392
|
-
|
|
393
|
-
JSON.parse(text); // must at least be JSON before the page gets it
|
|
394
|
-
return send(res, 200, text);
|
|
454
|
+
text = readFileSync(target.input, 'utf-8');
|
|
455
|
+
parsed = JSON.parse(text); // must at least be JSON before the page gets it
|
|
395
456
|
} catch (error) {
|
|
396
457
|
return send(res, 422, JSON.stringify({ error: String(error.message ?? error) }));
|
|
397
458
|
}
|
|
459
|
+
// A JSON that is not a scene is refused WITH THE REASON and its contents
|
|
460
|
+
// never leave: "offer everything, explain the no" must not also mean
|
|
461
|
+
// "this server will read you any JSON in the project".
|
|
462
|
+
const facts = sceneFacts(parsed);
|
|
463
|
+
if (!facts.ok) {
|
|
464
|
+
return send(
|
|
465
|
+
res,
|
|
466
|
+
422,
|
|
467
|
+
JSON.stringify({ error: `not an incanto scene — ${facts.why}.`, notScene: true }),
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
return send(res, 200, text);
|
|
398
471
|
}
|
|
399
472
|
if (req.method === 'PUT') {
|
|
400
473
|
if (!originAllowed(req)) {
|
|
401
474
|
return send(res, 403, JSON.stringify({ error: 'cross-origin write rejected' }));
|
|
402
475
|
}
|
|
403
476
|
readBody(req, res, (json, raw) => {
|
|
404
|
-
|
|
477
|
+
const shape = sceneFacts(json);
|
|
478
|
+
if (!shape.ok) {
|
|
405
479
|
return send(
|
|
406
480
|
res,
|
|
407
481
|
422,
|
|
408
482
|
JSON.stringify({
|
|
409
|
-
error:
|
|
410
|
-
'not an incanto scene — required: format: 1, type: "scene", name: string, root: object. The file was NOT written.',
|
|
483
|
+
error: `not an incanto scene — ${shape.why}. The file was NOT written.`,
|
|
411
484
|
}),
|
|
412
485
|
);
|
|
413
486
|
}
|
package/dist/2d.d.ts
CHANGED
|
@@ -146,6 +146,12 @@ type Rapier = typeof RapierNs;
|
|
|
146
146
|
interface Physics2DOptions {
|
|
147
147
|
/** px/s², y-down. Default: scene `physics.gravity`, else [0, 980]. */
|
|
148
148
|
gravity?: [number, number];
|
|
149
|
+
/**
|
|
150
|
+
* Build the colliders and keep them on the tree, but never advance the world
|
|
151
|
+
* (default: `true`, i.e. simulate). See {@link Physics3DOptions.simulate} —
|
|
152
|
+
* the scene editor uses it to draw the REAL colliders without running them.
|
|
153
|
+
*/
|
|
154
|
+
simulate?: boolean;
|
|
149
155
|
}
|
|
150
156
|
/**
|
|
151
157
|
* Enable 2D physics for an engine. Dynamically imports Rapier (compat build,
|
|
@@ -158,7 +164,7 @@ declare function enablePhysics2D(engine: Engine, opts?: Physics2DOptions): Promi
|
|
|
158
164
|
*/
|
|
159
165
|
declare class Physics2D {
|
|
160
166
|
private readonly R;
|
|
161
|
-
|
|
167
|
+
readonly engine: Engine;
|
|
162
168
|
/** Render collider outlines in the GAME view (renderers pick this up). */
|
|
163
169
|
debugDraw: boolean;
|
|
164
170
|
/** Narrow those outlines to one node's subtree (see DebugLineSource). */
|
|
@@ -177,6 +183,8 @@ declare class Physics2D {
|
|
|
177
183
|
private lastScene;
|
|
178
184
|
constructor(R: Rapier, engine: Engine, opts?: Physics2DOptions);
|
|
179
185
|
/** @internal Driven by engine.fixedUpdated. */
|
|
186
|
+
/** Whether the solver runs at all. False = collider outlines only. */
|
|
187
|
+
private readonly simulate;
|
|
180
188
|
step(dt: number): void;
|
|
181
189
|
/** @internal Called by CharacterBody2D.moveAndSlide (during tree fixedUpdate). */
|
|
182
190
|
moveAndSlide(node: CharacterBody2D): void;
|
|
@@ -210,6 +218,13 @@ declare class Physics2D {
|
|
|
210
218
|
private readonly jointSet;
|
|
211
219
|
private readonly joints;
|
|
212
220
|
private readonly bodySet;
|
|
221
|
+
/**
|
|
222
|
+
* Move every body to its node's current transform — outline mode only.
|
|
223
|
+
*
|
|
224
|
+
* Computed exactly as `ensureEntry` computes a body's first pose, so an
|
|
225
|
+
* outline drawn in the editor is the outline the running game draws.
|
|
226
|
+
*/
|
|
227
|
+
private poseFromTree;
|
|
213
228
|
private syncBodies;
|
|
214
229
|
private ensureEntry;
|
|
215
230
|
}
|
package/dist/2d.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-
|
|
2
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-5z_QVtLx.js";
|
|
3
3
|
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-DWcWq4QG.js";
|
|
4
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-3kOQCtgd.js";
|
|
5
5
|
//#region src/2d/library-sprite.ts
|
|
6
6
|
/**
|
|
7
7
|
* Turn a library sprite-animation JSON into a scene-ready spritesheet asset
|
package/dist/3d.d.ts
CHANGED
|
@@ -185,6 +185,13 @@ declare class Node3D extends Node {
|
|
|
185
185
|
* back to a local Y by subtracting the parents' offset.
|
|
186
186
|
*/
|
|
187
187
|
applyGroundSnap(): void;
|
|
188
|
+
/**
|
|
189
|
+
* @internal The backing object IF it has been built — never builds one.
|
|
190
|
+
*
|
|
191
|
+
* `_ensureObject3D()` is the wrong call during teardown: it allocates a mesh
|
|
192
|
+
* for a node that never rendered, purely so the next line can dispose it.
|
|
193
|
+
*/
|
|
194
|
+
protected get _builtObject3D(): Object3D | null;
|
|
188
195
|
/** @internal The backing three object (lazily created). */
|
|
189
196
|
_ensureObject3D(): Object3D;
|
|
190
197
|
/** @internal Override point for subclasses (mesh, camera, light…). */
|
|
@@ -269,6 +276,20 @@ type Rapier = typeof RapierNs;
|
|
|
269
276
|
interface Physics3DOptions {
|
|
270
277
|
/** m/s², y-up. Default: scene `physics.gravity`, else [0, -9.81, 0]. */
|
|
271
278
|
gravity?: [number, number, number];
|
|
279
|
+
/**
|
|
280
|
+
* Build the colliders and keep them on the tree, but never advance the world
|
|
281
|
+
* (default: `true`, i.e. simulate).
|
|
282
|
+
*
|
|
283
|
+
* This exists for the scene editor. "Show colliders" there used to hand-draw
|
|
284
|
+
* wireframes from the `collider` JSON — which cannot show what the engine
|
|
285
|
+
* actually creates, because the shape is not always in the JSON (a mesh-fitted
|
|
286
|
+
* body, a scatter's hulls, a character capsule) and the drawing ignored
|
|
287
|
+
* rotation and scale. With `simulate: false` the editor gets the SAME lines
|
|
288
|
+
* play mode gets, from the same Rapier world, without anything falling over
|
|
289
|
+
* the moment you look at it: bodies are posed FROM the tree each tick and the
|
|
290
|
+
* solver never runs.
|
|
291
|
+
*/
|
|
292
|
+
simulate?: boolean;
|
|
272
293
|
}
|
|
273
294
|
/**
|
|
274
295
|
* Enable 3D physics for an engine. Dynamically imports Rapier (compat build)
|
|
@@ -279,7 +300,7 @@ declare function enablePhysics3D(engine: Engine, opts?: Physics3DOptions): Promi
|
|
|
279
300
|
/** Per-engine 3D physics world. Same contract as Physics2D. */
|
|
280
301
|
declare class Physics3D {
|
|
281
302
|
private readonly R;
|
|
282
|
-
|
|
303
|
+
readonly engine: Engine;
|
|
283
304
|
/** Render collider outlines in the GAME view (renderers pick this up). */
|
|
284
305
|
debugDraw: boolean;
|
|
285
306
|
/** Narrow those outlines to one node's subtree (see DebugLineSource). */
|
|
@@ -297,8 +318,20 @@ declare class Physics3D {
|
|
|
297
318
|
private readonly optsGravity;
|
|
298
319
|
private lastScene;
|
|
299
320
|
constructor(R: Rapier, engine: Engine, opts?: Physics3DOptions);
|
|
321
|
+
/** Whether the solver runs at all. False = collider outlines only. */
|
|
322
|
+
private readonly simulate;
|
|
300
323
|
/** @internal Driven by engine.fixedUpdated. */
|
|
301
324
|
step(dt: number): void;
|
|
325
|
+
/**
|
|
326
|
+
* Move every body to its node's current transform.
|
|
327
|
+
*
|
|
328
|
+
* Only used in outline mode: normally physics owns the pose and writes it
|
|
329
|
+
* INTO the node, so nothing re-reads the tree. Deliberately computed the same
|
|
330
|
+
* way `ensureEntry` computes a body's initial pose — world position, node-local
|
|
331
|
+
* euler — so an outline in the editor is the outline the game will draw, right
|
|
332
|
+
* down to the places where that pair disagrees with a rotated parent.
|
|
333
|
+
*/
|
|
334
|
+
private poseFromTree;
|
|
302
335
|
/** @internal Called by CharacterBody3D.moveAndSlide (during tree fixedUpdate). */
|
|
303
336
|
moveAndSlide(node: CharacterBody3D): void;
|
|
304
337
|
/** Rapier debug segments (meters). Null while debugDraw is off. */
|
package/dist/3d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { A as Water3D, F as PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-
|
|
3
|
-
import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-
|
|
4
|
-
import { A as DEFAULT_TERRAIN_TEXTURE_BASE, B as movementState, C as FLOWER_VARIETIES, D as BoneAttachment3D, E as BoneLookAt3D, F as MeshInstance3D, L as QUARTER_PITCH, M as terrainThemeLayers, N as Joint3D, O as Billboard3D, P as InstancedMesh3D, R as cameraRelative, S as resolveFlowerDensity, T as Camera3D, V as rigPose, _ as DirectionalLight3D, a as Trail3D, b as DENSITY_PRESETS, c as findRiverCoverageGaps, d as riverStepFor, f as smoothCourse, g as LoftMesh3D, h as ModelInstance3D, i as Tree3D, j as TERRAIN_THEMES, k as Terrain3D, l as projectToRiver, m as Particles3D, n as VOXEL_PALETTE, o as River3D, p as traceDownhillPath, r as VoxelGrid3D, s as buildRiverRings, t as registerNodes3D, u as riverCarveChannels, v as OmniLight3D, w as CharacterController3D, x as Flowers3D, y as Foliage3D, z as keyboardIntensity } from "./register-
|
|
2
|
+
import { A as Water3D, F as PhysicsBody3D, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D, V as WATER_MAX_RIPPLES, j as WATER_CUTOUT_MAX } from "./gameplay-Cfr6aFZ1.js";
|
|
3
|
+
import { a as Environment3D, c as sunDirectionFromElevationAzimuth, i as syncTree, l as sunDirectionFromSky, o as horizonColorFromSky, r as Renderer3D, s as parseEnvironment3D, t as createGame3D, u as AssetStore3D } from "./create-game-DuBTv2zI.js";
|
|
4
|
+
import { A as DEFAULT_TERRAIN_TEXTURE_BASE, B as movementState, C as FLOWER_VARIETIES, D as BoneAttachment3D, E as BoneLookAt3D, F as MeshInstance3D, L as QUARTER_PITCH, M as terrainThemeLayers, N as Joint3D, O as Billboard3D, P as InstancedMesh3D, R as cameraRelative, S as resolveFlowerDensity, T as Camera3D, V as rigPose, _ as DirectionalLight3D, a as Trail3D, b as DENSITY_PRESETS, c as findRiverCoverageGaps, d as riverStepFor, f as smoothCourse, g as LoftMesh3D, h as ModelInstance3D, i as Tree3D, j as TERRAIN_THEMES, k as Terrain3D, l as projectToRiver, m as Particles3D, n as VOXEL_PALETTE, o as River3D, p as traceDownhillPath, r as VoxelGrid3D, s as buildRiverRings, t as registerNodes3D, u as riverCarveChannels, v as OmniLight3D, w as CharacterController3D, x as Flowers3D, y as Foliage3D, z as keyboardIntensity } from "./register-DJ0SByQg.js";
|
|
5
5
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
6
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
6
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CeRH-Ff_.js";
|
|
7
7
|
//#region src/3d/environment-runtime.ts
|
|
8
8
|
/**
|
|
9
9
|
* Live environment editing — the renderer re-applies `scene.environment`
|
|
@@ -3,11 +3,11 @@ import { _ as registerBehavior, n as loadScene, o as computeViewport, s as resol
|
|
|
3
3
|
import { l as AudioPlayer, u as Engine } from "./register-BTg0EM7s.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
|
|
6
|
-
import { n as
|
|
7
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
6
|
+
import { i as openBundledEditor, n as crossFade, r as devServerLibrary, t as teardown } from "./teardown-ByzfDPyu.js";
|
|
7
|
+
import { n as registerGameplayBehaviors } from "./gameplay-Cfr6aFZ1.js";
|
|
8
8
|
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-DWcWq4QG.js";
|
|
9
|
-
import { t as debugSources } from "./debug-draw-
|
|
10
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
9
|
+
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
+
import { n as enablePhysics2D } from "./physics-2d-3kOQCtgd.js";
|
|
11
11
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
12
12
|
//#region src/2d/assets.ts
|
|
13
13
|
/**
|
|
@@ -310,7 +310,7 @@ var Renderer2D = class {
|
|
|
310
310
|
}
|
|
311
311
|
syncDebugLines() {
|
|
312
312
|
let vertices = null;
|
|
313
|
-
for (const source of debugSources("2d")) {
|
|
313
|
+
for (const source of debugSources("2d", this.engine)) {
|
|
314
314
|
vertices = source.debugLines();
|
|
315
315
|
if (vertices) break;
|
|
316
316
|
}
|
|
@@ -603,10 +603,14 @@ async function createGame2D(opts) {
|
|
|
603
603
|
}
|
|
604
604
|
engine.start();
|
|
605
605
|
function disposeGame() {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
606
|
+
teardown([
|
|
607
|
+
physics ? ["physics", () => physics?.dispose()] : null,
|
|
608
|
+
["app cleanups", () => {
|
|
609
|
+
for (const cleanup of cleanups) cleanup();
|
|
610
|
+
}],
|
|
611
|
+
["engine", () => engine.dispose()],
|
|
612
|
+
["renderer", () => renderer.dispose()]
|
|
613
|
+
]);
|
|
610
614
|
}
|
|
611
615
|
return {
|
|
612
616
|
engine,
|
|
@@ -3,11 +3,11 @@ import { _ as registerBehavior, n as loadScene } from "./loader-BZqOKfI2.js";
|
|
|
3
3
|
import { l as AudioPlayer, u as Engine } from "./register-BTg0EM7s.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { i as resolveRendering, n as attachTouchControls } from "./touch-031PxtCR.js";
|
|
6
|
-
import {
|
|
7
|
-
import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-
|
|
8
|
-
import { t as debugSources } from "./debug-draw-
|
|
9
|
-
import { T as Camera3D, _ as DirectionalLight3D, h as ModelInstance3D, t as registerNodes3D } from "./register-
|
|
10
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
6
|
+
import { a as poseFromRenderer, i as openBundledEditor, n as crossFade, r as devServerLibrary, t as teardown } from "./teardown-ByzfDPyu.js";
|
|
7
|
+
import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-Cfr6aFZ1.js";
|
|
8
|
+
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
9
|
+
import { T as Camera3D, _ as DirectionalLight3D, h as ModelInstance3D, t as registerNodes3D } from "./register-DJ0SByQg.js";
|
|
10
|
+
import { n as enablePhysics3D } from "./physics-3d-CeRH-Ff_.js";
|
|
11
11
|
import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
12
12
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
13
13
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -1601,7 +1601,7 @@ var Renderer3D = class {
|
|
|
1601
1601
|
}
|
|
1602
1602
|
syncDebugLines() {
|
|
1603
1603
|
let vertices = null;
|
|
1604
|
-
for (const source of debugSources("3d")) {
|
|
1604
|
+
for (const source of debugSources("3d", this.engine)) {
|
|
1605
1605
|
vertices = source.debugLines();
|
|
1606
1606
|
if (vertices) break;
|
|
1607
1607
|
}
|
|
@@ -2250,10 +2250,14 @@ async function createGame3D(opts) {
|
|
|
2250
2250
|
} catch {}
|
|
2251
2251
|
await report(1, "ready");
|
|
2252
2252
|
function disposeGame() {
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2253
|
+
teardown([
|
|
2254
|
+
physics ? ["physics", () => physics?.dispose()] : null,
|
|
2255
|
+
["app cleanups", () => {
|
|
2256
|
+
for (const cleanup of cleanups) cleanup();
|
|
2257
|
+
}],
|
|
2258
|
+
["engine", () => engine.dispose()],
|
|
2259
|
+
["renderer", () => renderer.dispose()]
|
|
2260
|
+
]);
|
|
2257
2261
|
}
|
|
2258
2262
|
return {
|
|
2259
2263
|
engine,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/core/debug-draw.ts
|
|
2
|
+
const sources = /* @__PURE__ */ new Set();
|
|
3
|
+
/** @internal physics runtimes self-register on enable. */
|
|
4
|
+
function registerDebugSource(source) {
|
|
5
|
+
sources.add(source);
|
|
6
|
+
return () => sources.delete(source);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @internal renderers pull their OWN engine's sources for their dimension.
|
|
10
|
+
*
|
|
11
|
+
* `engine` is optional only so a caller with nothing to scope by still works;
|
|
12
|
+
* every renderer passes one, and should.
|
|
13
|
+
*/
|
|
14
|
+
function debugSources(dimension, engine) {
|
|
15
|
+
return [...sources].filter((s) => s.dimension === dimension && (engine === void 0 || s.engine === engine));
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { registerDebugSource as n, debugSources as t };
|
package/dist/debug.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
2
2
|
import { s as mergeStaticProps } from "./registry-BVJ2HbCn.js";
|
|
3
|
-
import { t as debugSources } from "./debug-draw-
|
|
3
|
+
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
4
4
|
//#region src/debug/panel.ts
|
|
5
5
|
/** Keep a panel rect on screen and above the minimum usable size. */
|
|
6
6
|
function clampPanelRect(x, y, w, h, viewW, viewH, minW = 180, minH = 120) {
|