incanto 0.70.0 → 0.71.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-verify.mjs +36 -98
- package/dist/2d.d.ts +18 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +3 -3
- package/dist/3d.js +6 -6
- package/dist/{agent8-CmNF01gA.js → agent8-Cfmd3ar_.js} +1 -1
- package/dist/{audio-player-DaMxqfNE.d.ts → audio-player-L8yccdMP.d.ts} +1 -1
- package/dist/{behavior-DZExDn9o.d.ts → behavior-Dcz0fr1S.d.ts} +11 -0
- package/dist/{create-game-Bwvh6q8A.js → create-game-CH4kt78v.js} +7 -7
- package/dist/{create-game-C7ffQWW7.js → create-game-LCHBLfA4.js} +7 -7
- package/dist/debug.d.ts +1 -1
- package/dist/editor.js +29 -25
- package/dist/{environment-presets-D6Q5BxeE.js → environment-presets-99BzP_L-.js} +3 -3
- package/dist/{frame-report-Dlq13Gyj.js → frame-report-D-_7YF2G.js} +1 -1
- package/dist/{gameplay-BfHkuzVb.js → gameplay-CNULJvwh.js} +108 -6
- package/dist/gameplay.d.ts +68 -4
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +27 -4
- package/dist/index.js +4 -4
- package/dist/{loader-Cff09LMm.d.ts → loader-8-IHvbKD.d.ts} +1 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +2 -2
- package/dist/{physics-2d-CE0Qvy3V.js → physics-2d-FhrXUc6B.js} +2 -2
- package/dist/{physics-3d-CpH-2gn5.js → physics-3d-CFEGxBXZ.js} +3 -3
- package/dist/{picking-CQJ_PJKh.js → picking-DVo7fI13.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-Bkk0wSDB.js → register-BYQCBySi.js} +100 -8
- package/dist/{register-6DYnKZcy.js → register-DuVdzxbq.js} +49 -15
- package/dist/{replay-DjAkAzMq.js → replay-DEvp3kyV.js} +2 -2
- package/dist/{replay-Dmw-PKQu.d.ts → replay-F7IZHdFR.d.ts} +1 -1
- package/dist/{save-slots-BXVg148r.js → save-slots-Bvuh2p_r.js} +56 -3
- package/dist/{split-screen--k-XpBjr.d.ts → split-screen-CIYf1zSf.d.ts} +2 -2
- package/dist/{split-screen-PL78oVXP.js → split-screen-eULetcg-.js} +3 -3
- package/dist/{src-Cxfiv1Hg.js → src-_jk0qLsS.js} +1 -1
- package/dist/{test-iHYVUcDK.js → test-CmN54kWv.js} +252 -24
- package/dist/test.d.ts +113 -5
- package/dist/test.js +3 -3
- package/dist/vite.js +3 -3
- package/editor/assets/{agent8-D0MS174y.js → agent8-yLIEYHbd.js} +1 -1
- package/editor/assets/{debug-BnXkKuYu.js → debug-u31w_yhq.js} +1 -1
- package/editor/assets/{index-CIu3uc3l.js → index-DK9xMGpW.js} +94 -94
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +4 -0
- package/skills/incanto-behaviors-and-scripts.md +30 -9
- package/skills/incanto-building-2d-games.md +20 -2
- package/skills/incanto-gameplay-behaviors.md +63 -1
- package/skills/incanto-hud.md +14 -0
- package/skills/incanto-node-reference.md +18 -2
- package/skills/incanto-playtesting.md +34 -0
- package/skills/incanto-save-slots.md +56 -1
- package/skills/incanto-verifying-your-game.md +11 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +44 -226
- package/templates-app/molehill-2d/package.json +1 -1
- package/templates-app/molehill-2d/src/game.scene.json +10 -60
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/game.scene.json +80 -416
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/star-survivor/src/game.scene.json +5 -24
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +13 -71
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/behaviors.ts +21 -4
- package/templates-app/village-quest-3d/src/grove.scene.json +16 -87
- package/templates-app/village-quest-3d/src/village.scene.json +5 -27
package/bin/incanto-verify.mjs
CHANGED
|
@@ -25,7 +25,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
25
25
|
import { readJson } from './_read-json.mjs';
|
|
26
26
|
|
|
27
27
|
const PKG = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
28
|
-
const { firstLine, ladderText, ladderVerdict, saysRung } = await import(
|
|
28
|
+
const { feelsRung, firstLine, ladderText, ladderVerdict, saysRung, unmeasuredPlays } = await import(
|
|
29
29
|
pathToFileURL(join(PKG, 'dist', 'test.js')).href
|
|
30
30
|
);
|
|
31
31
|
|
|
@@ -218,6 +218,9 @@ const rungs = [];
|
|
|
218
218
|
/** The playtest's JSON, shared by the `plays` and `feels` rungs. */
|
|
219
219
|
let playtestReport = null;
|
|
220
220
|
|
|
221
|
+
/** Did the bot get the game MOVING? Set by the `plays` rung, read by `feels`. */
|
|
222
|
+
let botPlayed = true;
|
|
223
|
+
|
|
221
224
|
// ---- plays ---------------------------------------------------------------
|
|
222
225
|
if (rungs[0].status === 'pass') {
|
|
223
226
|
const args = [scene, '--json', '--runs', '8'];
|
|
@@ -274,6 +277,8 @@ if (rungs[0].status === 'pass') {
|
|
|
274
277
|
const DEFECT = new Set(stuckCounts ? ['error', 'fell', 'stuck'] : ['error', 'fell']);
|
|
275
278
|
const defects = out?.runs?.filter((x) => DEFECT.has(x.outcome)) ?? [];
|
|
276
279
|
const undrivable = total > 0 && defects.length === 0 && tally('stuck') === total;
|
|
280
|
+
// …and the `feels` rung below asks the same question, so it is answered once.
|
|
281
|
+
botPlayed = !undrivable;
|
|
277
282
|
const count = (n, word) => n && `${n} ${word}`;
|
|
278
283
|
|
|
279
284
|
if (total === 0) {
|
|
@@ -343,23 +348,10 @@ if (rungs[0].status === 'pass') {
|
|
|
343
348
|
* match-3, tower defense, cards, point-and-click, RTS, board games — has no
|
|
344
349
|
* character to add, and the advice was to add one anyway.
|
|
345
350
|
*/
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
summary:
|
|
351
|
-
clicks > 0
|
|
352
|
-
? `played with the MOUSE — ${clicks} click(s) across ${total} runs, and no win to reach`
|
|
353
|
-
: out?.hasPlayer === false
|
|
354
|
-
? `nothing here is drivable — ${total} runs had nobody to move and nothing to click`
|
|
355
|
-
: `${total} runs went nowhere, and your behaviours were not loaded — that is most of what moves a character`,
|
|
356
|
-
fix:
|
|
357
|
-
clicks > 0
|
|
358
|
-
? 'a mouse game is played, not walked — emit `won`/`lost` and this rung can pass'
|
|
359
|
-
: out?.hasPlayer === false
|
|
360
|
-
? 'give the player a character controller, the `player` group, or the name Player — or `Clickable` on what the cursor drives'
|
|
361
|
-
: `name them: \`incanto-verify ${scene} --behaviors src/behaviors.ts\``,
|
|
362
|
-
});
|
|
351
|
+
// The wording lives in `verify-ladder.ts` (pure, and tested there) —
|
|
352
|
+
// this branch owns only the fact that the bot could not WALK.
|
|
353
|
+
const said = unmeasuredPlays({ ...(out ?? {}), scene });
|
|
354
|
+
rungs.push({ name: 'plays', status: 'unmeasured', summary: said.summary, fix: said.fix });
|
|
363
355
|
} else if (noGoal) {
|
|
364
356
|
rungs.push({
|
|
365
357
|
name: 'plays',
|
|
@@ -403,71 +395,10 @@ if (rungs[0].status === 'pass') {
|
|
|
403
395
|
// Sound and effects, from the same playtest that just ran. A game whose
|
|
404
396
|
// feedback is wired but never triggered plays perfectly and feels dead, and
|
|
405
397
|
// every other rung here calls it healthy.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (!fb) {
|
|
411
|
-
rungs.push({
|
|
412
|
-
name: 'feels',
|
|
413
|
-
status: 'skipped',
|
|
414
|
-
summary: 'not run — the playtest did not report',
|
|
415
|
-
});
|
|
416
|
-
} else if (declared === 0) {
|
|
417
|
-
rungs.push({
|
|
418
|
-
name: 'feels',
|
|
419
|
-
status: 'skipped',
|
|
420
|
-
summary: 'this game declares no sound and no effects',
|
|
421
|
-
});
|
|
422
|
-
} else if (fired.size === 0) {
|
|
423
|
-
rungs.push({
|
|
424
|
-
name: 'feels',
|
|
425
|
-
status: 'fail',
|
|
426
|
-
summary: `${declared} sound/effect node(s) declared, and not one fired in any run`,
|
|
427
|
-
fix: 'connect them — a signal to `play` on an AudioPlayer, or `replay()` on a one-shot; `engine.audio.recent()` and `engine.effects.recent()` say what did fire',
|
|
428
|
-
});
|
|
429
|
-
} else {
|
|
430
|
-
const declaredPaths = [...(fb.declaredAudio ?? []), ...(fb.declaredEffects ?? [])];
|
|
431
|
-
const silent = declaredPaths.filter((path) => !fired.has(path));
|
|
432
|
-
// Of the nodes this rung is ABOUT, how many fired. `fired` also holds paths
|
|
433
|
-
// nobody declared — a spawned clone sounds from its own path, a procedural
|
|
434
|
-
// preset from wherever a behaviour played it — so using its size printed
|
|
435
|
-
// arithmetic that cannot be true: `✓ feels — 12 of 9 fired`. The number has
|
|
436
|
-
// to add up with the `silent` list beside it.
|
|
437
|
-
const firedDeclared = declaredPaths.length - silent.length;
|
|
438
|
-
/*
|
|
439
|
-
* A rung that exists because "wired but never triggered plays perfectly and
|
|
440
|
-
* feels dead, and every other rung here calls it healthy" — and which then
|
|
441
|
-
* called it healthy itself. `fired.size === 0` failed and ANYTHING else
|
|
442
|
-
* passed, so the flagship starter reported
|
|
443
|
-
*
|
|
444
|
-
* ✓ feels — 13 of 26 fired — silent: /Game/Ward1/ChimeSfx …
|
|
445
|
-
*
|
|
446
|
-
* A tick next to thirteen emitters nobody heard is the same claim the rung
|
|
447
|
-
* was written to stop.
|
|
448
|
-
*
|
|
449
|
-
* It is not a FAILURE either: a random bot does not light three wards, so a
|
|
450
|
-
* win chime it never reached is not a broken wire. That is exactly what
|
|
451
|
-
* `unmeasured` means in this ladder — the tool did not get to look — and it
|
|
452
|
-
* is the one status that cannot be read as approval.
|
|
453
|
-
*/
|
|
454
|
-
rungs.push({
|
|
455
|
-
name: 'feels',
|
|
456
|
-
...(silent.length === 0
|
|
457
|
-
? { status: 'pass', summary: `every one of the ${declared} sound/effect nodes fired` }
|
|
458
|
-
: {
|
|
459
|
-
status: 'unmeasured',
|
|
460
|
-
summary:
|
|
461
|
-
`${firedDeclared} of ${declared} fired — silent: ${silent.slice(0, 3).join(', ')}` +
|
|
462
|
-
`${silent.length > 3 ? ` +${silent.length - 3}` : ''}`,
|
|
463
|
-
fix:
|
|
464
|
-
'a silent emitter is either a broken wire or a moment random play never ' +
|
|
465
|
-
'reached — the two look identical from here. Reach it in a scripted run ' +
|
|
466
|
-
'(`runScript` from `incanto/test`), and this rung can tell you which.',
|
|
467
|
-
}),
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
}
|
|
398
|
+
// The wording lives in `verify-ladder.ts` (pure, and tested there).
|
|
399
|
+
// `undrivable` is the plays rung's own "the bot never got it moving", so the
|
|
400
|
+
// two never disagree about whether anything was played.
|
|
401
|
+
rungs.push(feelsRung(playtestReport?.feedback, { played: botPlayed }));
|
|
471
402
|
|
|
472
403
|
// ---- agrees --------------------------------------------------------------
|
|
473
404
|
// A desync is the purest silent failure this engine has: both clients run,
|
|
@@ -544,28 +475,27 @@ if (rungs[0].status === 'pass') {
|
|
|
544
475
|
? 'bring the preview window to the front — a hidden tab does not render, and a frame is captured inside a render'
|
|
545
476
|
: 'start your dev server, open the page, and run this again — the pixels are in the browser',
|
|
546
477
|
});
|
|
547
|
-
} else if (report.hidden) {
|
|
478
|
+
} else if (report.hidden && report.droveFrames === 0) {
|
|
548
479
|
/*
|
|
549
|
-
* A hidden page
|
|
550
|
-
*
|
|
551
|
-
* A browser stops animating a page it considers hidden — a window merely
|
|
552
|
-
* covered by another counts — and the back buffer keeps whatever it last
|
|
553
|
-
* drew. Measured at one instant, same page:
|
|
480
|
+
* A hidden page cannot be DRIVEN, and that one is still unmeasured.
|
|
554
481
|
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
482
|
+
* The rung used to refuse any hidden page, on the belief that its pixels
|
|
483
|
+
* were "whatever it last drew". They are not: `captureFrame` in both
|
|
484
|
+
* renderers waits ~120 ms for a loop that a hidden tab never runs, and then
|
|
485
|
+
* draws a frame itself. Measured — hide every node from the console and
|
|
486
|
+
* capture again: 2D `luminance 0.09 → 0.00 BLACK SCREEN`, 3D `0.64 → 0.96,
|
|
487
|
+
* subject 44.3% → 22.0%`.
|
|
559
488
|
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
* the
|
|
489
|
+
* So a plain capture is current and measurable, and the ONLY thing a hidden
|
|
490
|
+
* page cannot do is advance — which is exactly what a drive needs, and what
|
|
491
|
+
* `droveFrames: 0` reports. Refusing both cost this rung every measurement
|
|
492
|
+
* it could have made in the setup the whole toolchain is built for: a
|
|
493
|
+
* terminal in front and a browser behind it.
|
|
564
494
|
*/
|
|
565
495
|
rungs.push({
|
|
566
496
|
name: 'draws',
|
|
567
497
|
status: 'unmeasured',
|
|
568
|
-
summary: 'the
|
|
498
|
+
summary: 'the drive ran on a HIDDEN page — 0 frames drawn, so nothing it did shows here',
|
|
569
499
|
fix: 'bring the window to the front (one covered by another counts as hidden) and run this again',
|
|
570
500
|
});
|
|
571
501
|
} else if (report.black) {
|
|
@@ -598,6 +528,14 @@ if (rungs[0].status === 'pass') {
|
|
|
598
528
|
if (report.uniform) {
|
|
599
529
|
notes.push('one flat colour — the camera may be inside geometry, or only the sky is drawn');
|
|
600
530
|
}
|
|
531
|
+
// Measured, not refused — but the reader still has to know the world was
|
|
532
|
+
// not moving while it was drawn.
|
|
533
|
+
if (report.hidden) {
|
|
534
|
+
notes.push(
|
|
535
|
+
'the page is hidden, so the game is PAUSED — this frame was rendered for the ' +
|
|
536
|
+
'capture, and shows the moment it froze',
|
|
537
|
+
);
|
|
538
|
+
}
|
|
601
539
|
rungs.push({
|
|
602
540
|
name: 'draws',
|
|
603
541
|
status: 'pass',
|
package/dist/2d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-
|
|
2
|
-
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-
|
|
1
|
+
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-L8yccdMP.js";
|
|
2
|
+
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-Dcz0fr1S.js";
|
|
3
3
|
import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
|
|
4
4
|
import { a as SceneJson, s as JsonObject } from "./rng-Bb-IutXB.js";
|
|
5
5
|
import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.js";
|
|
6
6
|
import { r as FrameStats } from "./frame-report-DNxDAb1w.js";
|
|
7
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
7
|
+
import { t as LoadSceneOptions } from "./loader-8-IHvbKD.js";
|
|
8
8
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
9
9
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
10
10
|
import * as RapierNs from "@dimforge/rapier2d-compat";
|
|
@@ -1151,6 +1151,21 @@ declare class TileMap2D extends Node2D {
|
|
|
1151
1151
|
set cells(value: (string | number[])[]);
|
|
1152
1152
|
get legend(): Record<string, number>;
|
|
1153
1153
|
set legend(value: Record<string, number>);
|
|
1154
|
+
private _colors;
|
|
1155
|
+
get colors(): Record<string, string>;
|
|
1156
|
+
set colors(value: Record<string, string>);
|
|
1157
|
+
/**
|
|
1158
|
+
* The colours, in declaration order — a cell's tile index is `COLOR_BASE + i`.
|
|
1159
|
+
*
|
|
1160
|
+
* A synthetic index rather than a second grid: everything downstream (the
|
|
1161
|
+
* collider merge, `tileAt`, `setTile`, the editor's paint tool) already
|
|
1162
|
+
* speaks in indices, and one number per cell keeps it that way.
|
|
1163
|
+
*/
|
|
1164
|
+
private palette;
|
|
1165
|
+
/** `legend` plus the colour chars, which is what every cell lookup wants. */
|
|
1166
|
+
private allChars;
|
|
1167
|
+
/** `solid` as INDICES: an entry may name the char that painted the cell. */
|
|
1168
|
+
private solidIndices;
|
|
1154
1169
|
get solid(): number[];
|
|
1155
1170
|
set solid(value: number[]);
|
|
1156
1171
|
opacity: number;
|
package/dist/2d.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
2
|
import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
|
|
3
3
|
import { t as isWebGLAvailable } from "./webgl-unavailable-C8aDbGmR.js";
|
|
4
|
-
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-
|
|
5
|
-
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-
|
|
6
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
4
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-CH4kt78v.js";
|
|
5
|
+
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-BYQCBySi.js";
|
|
6
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-FhrXUc6B.js";
|
|
7
7
|
//#region src/2d/library-sprite.ts
|
|
8
8
|
/**
|
|
9
9
|
* What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
|
package/dist/3d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-
|
|
2
|
-
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-
|
|
1
|
+
import { c as showBootFailure, i as ParticleSim, o as ParticleView, r as SpatialPose, s as isWebGLAvailable } from "./audio-player-L8yccdMP.js";
|
|
2
|
+
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats, x as EngineOptions } from "./behavior-Dcz0fr1S.js";
|
|
3
3
|
import { t as DiagnosticSink } from "./diagnostics-Cu85N3tL.js";
|
|
4
4
|
import { a as SceneJson$1, s as JsonObject } from "./rng-Bb-IutXB.js";
|
|
5
5
|
import { t as EditorSwitchOptions } from "./editor-switch-CFU9mCec.js";
|
|
6
6
|
import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DNxDAb1w.js";
|
|
7
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
7
|
+
import { t as LoadSceneOptions } from "./loader-8-IHvbKD.js";
|
|
8
8
|
import { n as PathGrid } from "./pathfinding-_fGrCFmH.js";
|
|
9
9
|
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
|
|
10
10
|
import { VRM } from "@pixiv/three-vrm";
|
package/dist/3d.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as sunDirectionFromSky, S as sunDirectionFromElevationAzimuth, b as horizonColorFromSky, x as parseEnvironment3D } from "./save-slots-Bvuh2p_r.js";
|
|
2
2
|
import { t as showBootFailure } from "./boot-failure-CKYrEcGF.js";
|
|
3
3
|
import { t as isWebGLAvailable } from "./webgl-unavailable-C8aDbGmR.js";
|
|
4
|
-
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-
|
|
5
|
-
import {
|
|
6
|
-
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-
|
|
7
|
-
import { a as Environment3D, c as AssetStore3D, i as syncTree, o as applyQualityTier3D, r as Renderer3D, s as setEnvironment3D, t as createGame3D } from "./create-game-
|
|
4
|
+
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-D-_7YF2G.js";
|
|
5
|
+
import { G as StaticBody3D, H as CharacterBody3D, K as Node3D, L as Water3D, R as WATER_CUTOUT_MAX, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, Y as WATER_MAX_RIPPLES, z as WaterCutout3D } from "./gameplay-CNULJvwh.js";
|
|
6
|
+
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-99BzP_L-.js";
|
|
7
|
+
import { a as Environment3D, c as AssetStore3D, i as syncTree, o as applyQualityTier3D, r as Renderer3D, s as setEnvironment3D, t as createGame3D } from "./create-game-LCHBLfA4.js";
|
|
8
8
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-BYgD5Edk.js";
|
|
9
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
9
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-CFEGxBXZ.js";
|
|
10
10
|
//#region src/3d/model-verdict.ts
|
|
11
11
|
/** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
|
|
12
12
|
const MIXAMO = /^mixamorig[:_]?/i;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as __exportAll } from "./json-CfTjpvW8.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Y as diagnose } from "./save-slots-Bvuh2p_r.js";
|
|
3
3
|
//#region src/net/agent8.ts
|
|
4
4
|
var agent8_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
Agent8TransportForTest: () => Agent8Transport,
|
|
@@ -414,6 +414,17 @@ declare class Node implements NodeLifecycle {
|
|
|
414
414
|
* SceneTree). Frees immediately when detached from any tree.
|
|
415
415
|
*/
|
|
416
416
|
queueFree(): void;
|
|
417
|
+
/**
|
|
418
|
+
* Has this node been torn down?
|
|
419
|
+
*
|
|
420
|
+
* A scene swap frees the tree it replaces, so the answer is `true` for every
|
|
421
|
+
* node of the scene you just left — which is exactly the state a behavior is
|
|
422
|
+
* in when it runs one more line after `goToScene`. Kept as a flag rather than
|
|
423
|
+
* inferred from `parent`/`tree`, because a DETACHED node (a prefab on a
|
|
424
|
+
* shelf, a clone waiting to be added) has neither and is perfectly alive.
|
|
425
|
+
*/
|
|
426
|
+
get freed(): boolean;
|
|
427
|
+
private _freed;
|
|
417
428
|
/** Immediately detach and tear down this node and its children. */
|
|
418
429
|
free(): void;
|
|
419
430
|
/**
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { o as __exportAll } from "./json-CfTjpvW8.js";
|
|
2
|
-
import {
|
|
3
|
-
import { C as qualityRendering, _ as AudioPlayer, v as Engine } from "./register-
|
|
2
|
+
import { D as computeViewport, O as resolveViewport, Y as diagnose, h as loadScene, ot as registerBehavior } from "./save-slots-Bvuh2p_r.js";
|
|
3
|
+
import { C as qualityRendering, _ as AudioPlayer, v as Engine } from "./register-DuVdzxbq.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { n as attachTouchControls } from "./touch-BnCyPA0G.js";
|
|
6
6
|
import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-C8aDbGmR.js";
|
|
7
|
-
import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, t as nodeFromHits, u as claimCanvasGestures } from "./picking-
|
|
8
|
-
import { o as frameStats } from "./frame-report-
|
|
9
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
10
|
-
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-
|
|
7
|
+
import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, t as nodeFromHits, u as claimCanvasGestures } from "./picking-DVo7fI13.js";
|
|
8
|
+
import { o as frameStats } from "./frame-report-D-_7YF2G.js";
|
|
9
|
+
import { n as registerGameplayBehaviors } from "./gameplay-CNULJvwh.js";
|
|
10
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-BYQCBySi.js";
|
|
11
11
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
12
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
12
|
+
import { n as enablePhysics2D } from "./physics-2d-FhrXUc6B.js";
|
|
13
13
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
14
14
|
//#region src/2d/assets.ts
|
|
15
15
|
/**
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { o as __exportAll } from "./json-CfTjpvW8.js";
|
|
2
|
-
import {
|
|
3
|
-
import { C as qualityRendering, S as qualityEnvironment, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-
|
|
2
|
+
import { C as sunDirectionFromSky, Y as diagnose, b as horizonColorFromSky, h as loadScene, ot as registerBehavior, x as parseEnvironment3D } from "./save-slots-Bvuh2p_r.js";
|
|
3
|
+
import { C as qualityRendering, S as qualityEnvironment, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-DuVdzxbq.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { n as attachTouchControls } from "./touch-BnCyPA0G.js";
|
|
6
6
|
import { n as withWebGLContext, r as resolveRendering } from "./webgl-unavailable-C8aDbGmR.js";
|
|
7
|
-
import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, s as poseFromRenderer, t as nodeFromHits, u as claimCanvasGestures } from "./picking-
|
|
8
|
-
import { o as frameStats } from "./frame-report-
|
|
9
|
-
import {
|
|
7
|
+
import { a as devServerLibrary, c as applyDriveStep, d as audioErrors, i as crossFade, l as wireDevChannel, n as teardown, o as openBundledEditor, r as pauseWhenHidden, s as poseFromRenderer, t as nodeFromHits, u as claimCanvasGestures } from "./picking-DVo7fI13.js";
|
|
8
|
+
import { o as frameStats } from "./frame-report-D-_7YF2G.js";
|
|
9
|
+
import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-CNULJvwh.js";
|
|
10
10
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
11
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
12
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
11
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-99BzP_L-.js";
|
|
12
|
+
import { n as enablePhysics3D } from "./physics-3d-CFEGxBXZ.js";
|
|
13
13
|
import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, LoadingManager, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
14
14
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
15
15
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-
|
|
1
|
+
import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-Dcz0fr1S.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|
package/dist/editor.js
CHANGED
|
@@ -5,18 +5,21 @@ import { registerGameplayBehaviors as A } from "incanto/gameplay";
|
|
|
5
5
|
import { registerNodesNet as ee } from "incanto/net";
|
|
6
6
|
import { GENERATORS as te, runGenerator as j } from "incanto/env";
|
|
7
7
|
//#region src/format-json.ts
|
|
8
|
-
var ne =
|
|
8
|
+
var ne = 100, re = " ";
|
|
9
9
|
function M(e) {
|
|
10
|
-
return `${ie(e, 0)}\n`;
|
|
10
|
+
return `${ie(e, 0, 0)}\n`;
|
|
11
11
|
}
|
|
12
|
-
function ie(e, t) {
|
|
12
|
+
function ie(e, t, n) {
|
|
13
13
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
14
|
-
let
|
|
15
|
-
if (
|
|
16
|
-
let
|
|
17
|
-
if (Array.isArray(e)) return e.length === 0 ? "[]" : `[\n${e.map((e) =>
|
|
18
|
-
let
|
|
19
|
-
return
|
|
14
|
+
let r = N(e);
|
|
15
|
+
if (n + r.length + 1 <= ne) return r;
|
|
16
|
+
let i = re.repeat(t + 1), a = re.repeat(t), o = (t + 1) * 2;
|
|
17
|
+
if (Array.isArray(e)) return e.length === 0 ? "[]" : `[\n${e.map((e) => i + ie(e, t + 1, o)).join(",\n")}\n${a}]`;
|
|
18
|
+
let s = Object.entries(e);
|
|
19
|
+
return s.length === 0 ? "{}" : `{\n${s.map(([e, n]) => {
|
|
20
|
+
let r = `${JSON.stringify(e)}: `;
|
|
21
|
+
return `${i}${r}${ie(n, t + 1, o + r.length)}`;
|
|
22
|
+
}).join(",\n")}\n${a}}`;
|
|
20
23
|
}
|
|
21
24
|
function N(e) {
|
|
22
25
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
@@ -1289,8 +1292,8 @@ var kt = {
|
|
|
1289
1292
|
en: "A whole tile level as ONE node — grid render + merged static colliders.",
|
|
1290
1293
|
ko: "타일 레벨 전체를 노드 하나로 — 그리드 렌더 + 병합된 정적 콜라이더."
|
|
1291
1294
|
}, {
|
|
1292
|
-
en: "Author cells as rows of characters: \".\" / space = empty, digits 0-9 = atlas tile index, other chars map through legend ({\"G\": 12}). texture is a \"$atlas\" asset read left-to-right top-to-bottom in tileSize squares (columns: 0 derives from the texture width).
|
|
1293
|
-
ko: "cells를 문자 행으로 작성합니다: \".\"/공백 = 빈 칸, 숫자 0-9 = 아틀라스 타일 번호, 그 외 문자는 legend({\"G\": 12})로
|
|
1295
|
+
en: "Author cells as rows of characters: \".\" / space = empty, digits 0-9 = atlas tile index, other chars map through legend ({\"G\": 12}) or colors ({\"#\": \"#3a4356\"}), which paints a flat colour and needs no atlas at all — use it to block out a level before the art arrives (exclusive with texture). texture is a \"$atlas\" asset read left-to-right top-to-bottom in tileSize squares (columns: 0 derives from the texture width). solid becomes static colliders, greedy-merged into a few rectangles, and takes the CHAR you painted as well as a tile index. Cell (0,0) hangs its top-left on the node origin.",
|
|
1296
|
+
ko: "cells를 문자 행으로 작성합니다: \".\"/공백 = 빈 칸, 숫자 0-9 = 아틀라스 타일 번호, 그 외 문자는 legend({\"G\": 12}) 또는 colors({\"#\": \"#3a4356\"})로 매핑합니다. colors는 아틀라스 없이 단색 칸을 그려서 아트가 오기 전에 레벨을 잡을 때 씁니다(texture와 동시 사용 불가). texture는 tileSize 정사각형을 좌→우, 상→하로 읽는 \"$아틀라스\" 에셋입니다(columns: 0이면 텍스처 폭에서 유도). solid는 정적 콜라이더가 되며(타일 번호뿐 아니라 칠한 문자도 받습니다) 소수의 직사각형으로 탐욕 병합됩니다. (0,0) 칸의 좌상단이 노드 원점에 걸립니다."
|
|
1294
1297
|
}),
|
|
1295
1298
|
L("AnimatedSprite2D", {
|
|
1296
1299
|
en: "Spritesheet animation player.",
|
|
@@ -2374,15 +2377,16 @@ function In(e, t, n, r) {
|
|
|
2374
2377
|
}
|
|
2375
2378
|
return s;
|
|
2376
2379
|
}
|
|
2377
|
-
function Ln(e, t) {
|
|
2378
|
-
let
|
|
2380
|
+
function Ln(e, t, n = {}) {
|
|
2381
|
+
let r = new Set([
|
|
2379
2382
|
".",
|
|
2380
2383
|
"0",
|
|
2381
2384
|
"1"
|
|
2382
2385
|
]);
|
|
2383
|
-
for (let t of e) if (typeof t == "string") for (let e of t) e !== " " &&
|
|
2384
|
-
for (let e of Object.keys(t))
|
|
2385
|
-
|
|
2386
|
+
for (let t of e) if (typeof t == "string") for (let e of t) e !== " " && r.add(e);
|
|
2387
|
+
for (let e of Object.keys(t)) r.add(e);
|
|
2388
|
+
for (let e of Object.keys(n)) r.add(e);
|
|
2389
|
+
return [...r];
|
|
2386
2390
|
}
|
|
2387
2391
|
//#endregion
|
|
2388
2392
|
//#region src/inspector.ts
|
|
@@ -3536,17 +3540,17 @@ function Ir(e, t) {
|
|
|
3536
3540
|
r.type = "button", r.className = t.active() ? "paint-toggle on" : "paint-toggle", r.textContent = t.active() ? "🖌 painting — click the canvas" : "🖌 paint tiles", r.addEventListener("click", () => t.toggle()), n.appendChild(r);
|
|
3537
3541
|
let i = document.createElement("div");
|
|
3538
3542
|
i.className = "paint-palette";
|
|
3539
|
-
let a = e.props?.cells ?? [], o = e.props?.legend ?? {};
|
|
3540
|
-
for (let e of Ln(a, o)) {
|
|
3543
|
+
let a = e.props?.cells ?? [], o = e.props?.legend ?? {}, s = e.props?.colors ?? {};
|
|
3544
|
+
for (let e of Ln(a, o, s)) {
|
|
3541
3545
|
let n = document.createElement("button");
|
|
3542
|
-
n.type = "button", n.className = t.brush() === e ? "paint-chip on" : "paint-chip", n.textContent = e === "." ? "␡" : e, n.title = e === "." ? "eraser (empty cell)" : `tile '${e}'`, n.addEventListener("click", () => t.setBrush(e)), i.appendChild(n);
|
|
3546
|
+
n.type = "button", n.className = t.brush() === e ? "paint-chip on" : "paint-chip", n.textContent = e === "." ? "␡" : e, n.title = e === "." ? "eraser (empty cell)" : s[e] ? `tile '${e}' — ${s[e]}` : `tile '${e}'`, s[e] && (n.style.borderColor = s[e]), n.addEventListener("click", () => t.setBrush(e)), i.appendChild(n);
|
|
3543
3547
|
}
|
|
3544
|
-
let
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
}), i.appendChild(
|
|
3548
|
-
let
|
|
3549
|
-
return
|
|
3548
|
+
let c = document.createElement("input");
|
|
3549
|
+
c.type = "text", c.maxLength = 1, c.className = "paint-brush-input", c.value = t.brush(), c.title = "brush char (a digit, or a char from legend/colors)", c.addEventListener("change", () => {
|
|
3550
|
+
c.value.length === 1 && t.setBrush(c.value);
|
|
3551
|
+
}), i.appendChild(c), n.appendChild(i);
|
|
3552
|
+
let l = document.createElement("div");
|
|
3553
|
+
return l.className = "paint-hint", l.textContent = "grid grows right/down; digits map to atlas tiles, others need legend or colors", n.appendChild(l), n;
|
|
3550
3554
|
}
|
|
3551
3555
|
function Lr(e, t, n, r = "", i) {
|
|
3552
3556
|
let a = document.createElement("textarea");
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { M as translateOn, t as registerCoreNodes } from "./register-
|
|
1
|
+
import { Y as diagnose } from "./save-slots-Bvuh2p_r.js";
|
|
2
|
+
import { M as translateOn, t as registerCoreNodes } from "./register-DuVdzxbq.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-CDOMybym.js";
|
|
5
5
|
import { c as getNodeSchema, h as didYouMean, p as registerNode } from "./touch-BnCyPA0G.js";
|
|
6
6
|
import { t as createNoise2D } from "./noise-D3nPpmFg.js";
|
|
7
7
|
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimations, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CqR2o3SA.js";
|
|
8
|
-
import { B as
|
|
8
|
+
import { B as rejectScale, D as effectRng, G as StaticBody3D, H as CharacterBody3D, K as Node3D, L as Water3D, Q as worldPosition, T as tolerateUnknownAction, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, X as colliderFootDrop, z as WaterCutout3D } from "./gameplay-CNULJvwh.js";
|
|
9
9
|
import { t as checkSheetGrid } from "./sheet-grid-Cea343VO.js";
|
|
10
10
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-BYgD5Edk.js";
|
|
11
11
|
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
@@ -177,7 +177,7 @@ const pct = (v) => `${(v * 100).toFixed(1)}%`;
|
|
|
177
177
|
/** The report a person or an agent reads. Verdict first, numbers after. */
|
|
178
178
|
function frameText(stats) {
|
|
179
179
|
const lines = [];
|
|
180
|
-
if (stats.hidden) lines.push("
|
|
180
|
+
if (stats.hidden) lines.push("the page is hidden, so the game is PAUSED — these pixels were rendered for this capture (current), but nothing is moving. A `--do` drive needs the window in front.");
|
|
181
181
|
if (stats.black) lines.push("BLACK SCREEN — nothing was drawn (no light, no camera, or nothing in view)");
|
|
182
182
|
else if (stats.uniform) lines.push("one flat colour — the camera may be inside geometry, or only the sky is drawn");
|
|
183
183
|
else if (!stats.subject) lines.push("nothing but background — the camera is pointed away from everything in the scene");
|