incanto 0.41.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/incanto-frame.mjs +144 -0
- package/dist/2d.d.ts +2 -2
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +76 -4
- package/dist/3d.js +5 -5
- package/dist/{behavior-TA8nySqb.d.ts → behavior-62q0HWBO.d.ts} +3 -1
- package/dist/{create-game-CZpENyin.js → create-game-9KPppR0L.js} +4 -4
- package/dist/{create-game-u7TDbvln.js → create-game-DItIRyXH.js} +158 -5
- package/dist/debug.d.ts +1 -1
- package/dist/{environment-presets-pGTHb_V4.js → environment-presets-Vl5xBsXp.js} +2 -2
- package/dist/{gameplay-By8mslMc.js → gameplay-DRi9524r.js} +13 -0
- package/dist/gameplay.d.ts +13 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -167
- package/dist/{loader-CvSDKC3v.d.ts → loader-CeyU_bm1.d.ts} +1 -1
- package/dist/net.d.ts +1 -1
- package/dist/net.js +2 -2
- package/dist/{pathfinding-_UlKUoox.d.ts → pathfinding-C49JSNNq.d.ts} +1 -1
- package/dist/{physics-2d-CEnZFcpM.js → physics-2d-BmgXBNDB.js} +1 -1
- package/dist/{physics-3d-CumBBvQo.js → physics-3d-C2G604O1.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-DuTlY56W.js → register-BSXV8T9F.js} +3 -1
- package/dist/{register-DnycZ91Q.js → register-D651it1J.js} +1 -1
- package/dist/{register-MSZvnHkp.js → register-R2JTnIMw.js} +1 -1
- package/dist/{replay-DN-kG4va.d.ts → replay-CAphXMyM.d.ts} +1 -1
- package/dist/{replay-DcWg4LT5.js → replay-DilbZgQI.js} +1 -1
- package/dist/src-cU57Uwdw.js +166 -0
- package/dist/{test-B4kSwQzq.js → test-DuOD1DO8.js} +22 -11
- package/dist/test.d.ts +3 -3
- package/dist/test.js +2 -2
- package/dist/vite.d.ts +61 -1
- package/dist/vite.js +149 -2
- package/editor/assets/{agent8-DCHkff44.js → agent8-Csw0T7jh.js} +1 -1
- package/editor/assets/{debug-uHHxqj0a.js → debug-C3qeBD4X.js} +1 -1
- package/editor/assets/{index-i1mIkyMA.js → index-B1rUkWxB.js} +49 -49
- package/editor/index.html +1 -1
- package/package.json +3 -2
- package/skills/incanto-audio.md +6 -2
- package/skills/incanto-verifying-your-game.md +41 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
/**
|
|
4
|
+
* incanto-frame — what is actually on screen, as numbers.
|
|
5
|
+
*
|
|
6
|
+
* bunx incanto-frame
|
|
7
|
+
*
|
|
8
|
+
* The rung above `incanto-check`. That one says the scene loads; `framing` says
|
|
9
|
+
* what the camera SHOULD see; this says what the GPU actually drew — the only
|
|
10
|
+
* one that can catch a black screen, a material that failed, or a shader
|
|
11
|
+
* drawing where it should not.
|
|
12
|
+
*
|
|
13
|
+
* It writes no files. An image is only worth producing when a human is going to
|
|
14
|
+
* look at one, and a report is what an agent can act on.
|
|
15
|
+
*
|
|
16
|
+
* Finding the dev server is this program's job, never the caller's: it reads
|
|
17
|
+
* the ports that are actually listening and asks each one whether it is an
|
|
18
|
+
* incanto dev server. You run one command; it works out the rest.
|
|
19
|
+
*/
|
|
20
|
+
import { createRequire } from 'node:module';
|
|
21
|
+
import { dirname, join } from 'node:path';
|
|
22
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const PKG = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
25
|
+
const { listeningPorts, parseProcNetTcp } = await import(
|
|
26
|
+
pathToFileURL(join(PKG, 'dist', 'vite.js')).href
|
|
27
|
+
);
|
|
28
|
+
const { frameText } = await import(pathToFileURL(join(PKG, 'dist', '3d.js')).href);
|
|
29
|
+
|
|
30
|
+
const args = process.argv.slice(2);
|
|
31
|
+
const asJson = args.includes('--json');
|
|
32
|
+
const gridArg = args[args.indexOf('--grid') + 1];
|
|
33
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
34
|
+
console.error(`Usage: incanto-frame [options]
|
|
35
|
+
|
|
36
|
+
--json the full report as JSON instead of prose
|
|
37
|
+
--grid WxH cells across and down (default 16x9)
|
|
38
|
+
--port N skip discovery and use this port
|
|
39
|
+
|
|
40
|
+
Run your game's dev server and open the preview page first: the pixels live in
|
|
41
|
+
the browser, not in the dev server.`);
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const read = (path) => {
|
|
46
|
+
try {
|
|
47
|
+
return readFileSync(path, 'utf-8');
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Ports that are listening, on a machine with no `/proc` (macOS, BSD).
|
|
55
|
+
* The container this is built for is Linux, but a developer's laptop is not,
|
|
56
|
+
* and a tool that only works in CI teaches nobody anything.
|
|
57
|
+
*/
|
|
58
|
+
function bsdListeningPorts() {
|
|
59
|
+
try {
|
|
60
|
+
const { execFileSync } = createRequire(import.meta.url)('node:child_process');
|
|
61
|
+
const out = execFileSync('lsof', ['-nP', '-iTCP', '-sTCP:LISTEN'], {
|
|
62
|
+
encoding: 'utf-8',
|
|
63
|
+
timeout: 1500,
|
|
64
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
65
|
+
});
|
|
66
|
+
const ports = new Set();
|
|
67
|
+
for (const line of out.split('\n')) {
|
|
68
|
+
const m = line.match(/:(\d+)\s*\(LISTEN\)/);
|
|
69
|
+
if (m) ports.add(Number(m[1]));
|
|
70
|
+
}
|
|
71
|
+
return [...ports];
|
|
72
|
+
} catch {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const explicit = args.includes('--port') ? Number(args[args.indexOf('--port') + 1]) : null;
|
|
78
|
+
const discovered = explicit ? [explicit] : await listeningPorts({ read });
|
|
79
|
+
const ports = explicit ? discovered : [...new Set([...bsdListeningPorts(), ...discovered])];
|
|
80
|
+
|
|
81
|
+
let found = null;
|
|
82
|
+
// BOTH hosts, deliberately: vite binds to ::1 on some machines and 127.0.0.1 on
|
|
83
|
+
// others, and a probe of the wrong one reports "no dev server" while the page
|
|
84
|
+
// is plainly on screen.
|
|
85
|
+
const HOSTS = ['localhost', '127.0.0.1'];
|
|
86
|
+
outer: for (const port of ports) {
|
|
87
|
+
for (const host of HOSTS) {
|
|
88
|
+
try {
|
|
89
|
+
const res = await fetch(`http://${host}:${port}/__incanto/ping`, {
|
|
90
|
+
signal: AbortSignal.timeout(300),
|
|
91
|
+
});
|
|
92
|
+
if (!res.ok) continue;
|
|
93
|
+
const body = await res.json();
|
|
94
|
+
if (body?.incanto) {
|
|
95
|
+
found = { host, port, ...body };
|
|
96
|
+
break outer;
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
// not listening, not ours, or not answering — either way, next
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!found) {
|
|
105
|
+
console.error(
|
|
106
|
+
'no incanto dev server found.\n' +
|
|
107
|
+
' Start your game (the dev server) and try again — this reads the frame\n' +
|
|
108
|
+
' from the running preview, so there has to be one.',
|
|
109
|
+
);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const res = await fetch(`http://${found.host}:${found.port}/__incanto/frame`, {
|
|
114
|
+
signal: AbortSignal.timeout(10_000),
|
|
115
|
+
});
|
|
116
|
+
const body = await res.json().catch(() => null);
|
|
117
|
+
|
|
118
|
+
if (res.status === 504 || body?.error === 'no-page-connected') {
|
|
119
|
+
console.error(
|
|
120
|
+
`the dev server is running on :${found.port}, but no page is connected.\n` +
|
|
121
|
+
' Open the preview in a browser — the pixels are there, not in the server.',
|
|
122
|
+
);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
if (!res.ok || !body?.report) {
|
|
126
|
+
console.error(`could not capture a frame: ${body?.error ?? res.status}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const report = body.report;
|
|
131
|
+
if (report.error) {
|
|
132
|
+
console.error(`the page could not capture a frame: ${report.error}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (asJson) {
|
|
137
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
138
|
+
} else {
|
|
139
|
+
process.stdout.write(`${frameText(report)}\n`);
|
|
140
|
+
}
|
|
141
|
+
process.exit(report.black ? 1 : 0);
|
|
142
|
+
|
|
143
|
+
void parseProcNetTcp; // re-exported for tests; referenced so bundlers keep it
|
|
144
|
+
void gridArg;
|
package/dist/2d.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Et as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { Et as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-62q0HWBO.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DVwIGZdK.js";
|
|
3
3
|
import { i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-CeyU_bm1.js";
|
|
5
5
|
import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
6
6
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
7
7
|
import * as RapierNs from "@dimforge/rapier2d-compat";
|
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-
|
|
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-
|
|
4
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
2
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-9KPppR0L.js";
|
|
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-R2JTnIMw.js";
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-BmgXBNDB.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
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { D as QualityCaps, Et as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { D as QualityCaps, Et as Node, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, n as BehaviorCtor, w as GameStats } from "./behavior-62q0HWBO.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DVwIGZdK.js";
|
|
3
3
|
import { i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
4
|
+
import { t as LoadSceneOptions } from "./loader-CeyU_bm1.js";
|
|
5
5
|
import { t as ParticleSim } from "./particle-sim-BzJ1yxoE.js";
|
|
6
|
-
import { n as PathGrid, s as SpatialPose } from "./pathfinding-
|
|
6
|
+
import { n as PathGrid, s as SpatialPose } from "./pathfinding-C49JSNNq.js";
|
|
7
7
|
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
|
|
8
8
|
import { VRM } from "@pixiv/three-vrm";
|
|
9
9
|
import { Sky } from "three/examples/jsm/objects/Sky.js";
|
|
@@ -190,6 +190,45 @@ declare function keyboardIntensity(moving: boolean, sprinting: boolean): number;
|
|
|
190
190
|
/** intensity → movement state (the animation driver). */
|
|
191
191
|
declare function movementState(grounded: boolean, intensity: number): "idle" | "walk" | "run" | "fastRun" | "airborne";
|
|
192
192
|
//#endregion
|
|
193
|
+
//#region src/3d/frame-report.d.ts
|
|
194
|
+
/**
|
|
195
|
+
* What the frame looks like, as something worth saying.
|
|
196
|
+
*
|
|
197
|
+
* The pixels are not the deliverable. A 1280x720 frame is 2.8 million numbers:
|
|
198
|
+
* unreadable by a person, unaffordable for a model (roughly a thousand tokens
|
|
199
|
+
* as an image, roughly a million as text). The deliverable is the JUDGEMENT —
|
|
200
|
+
* black screen, one flat colour, washed out — and the numbers behind it, small
|
|
201
|
+
* enough to print and compare.
|
|
202
|
+
*
|
|
203
|
+
* Same principle as `framing`'s "lit by: NOTHING": a report is a sentence
|
|
204
|
+
* before it is a number, because a number needs a reader who already knows what
|
|
205
|
+
* to compare it against.
|
|
206
|
+
*
|
|
207
|
+
* Pure arithmetic over an RGBA buffer — no three, no DOM, no GPU. Whoever has
|
|
208
|
+
* the pixels calls this; in practice that is the browser holding the canvas.
|
|
209
|
+
*/
|
|
210
|
+
/** Per-cell mean colour, `[r, g, b]` 0..255. */
|
|
211
|
+
type GridCell = [number, number, number];
|
|
212
|
+
interface FrameStats {
|
|
213
|
+
width: number;
|
|
214
|
+
height: number;
|
|
215
|
+
/** Every pixel below the black threshold — the render produced nothing. */
|
|
216
|
+
black: boolean;
|
|
217
|
+
/** One colour everywhere: a clear-colour fill, or a camera inside geometry. */
|
|
218
|
+
uniform: boolean;
|
|
219
|
+
/** 0..1 mean relative luminance. */
|
|
220
|
+
meanLuma: number;
|
|
221
|
+
/** Coarse mean colour per cell, rows top to bottom. */
|
|
222
|
+
grid: GridCell[][];
|
|
223
|
+
}
|
|
224
|
+
interface FrameStatsOptions {
|
|
225
|
+
/** Cells across and down. Default 16x9 — 144 cells, printable. */
|
|
226
|
+
grid?: [number, number];
|
|
227
|
+
}
|
|
228
|
+
declare function frameStats(pixels: Uint8Array | Uint8ClampedArray, width: number, height: number, opts?: FrameStatsOptions): FrameStats;
|
|
229
|
+
/** The report a person or an agent reads. Verdict first, numbers after. */
|
|
230
|
+
declare function frameText(stats: FrameStats): string;
|
|
231
|
+
//#endregion
|
|
193
232
|
//#region src/3d/nodes/node-3d.d.ts
|
|
194
233
|
/**
|
|
195
234
|
* Per-frame hand-off from `Renderer3D` to nodes that need the LIVE WebGL
|
|
@@ -643,6 +682,20 @@ interface Game3D {
|
|
|
643
682
|
/** Engine + renderer perf counters in one read (fps/nodes/triangles/…). */
|
|
644
683
|
stats(): GameStats;
|
|
645
684
|
/**
|
|
685
|
+
* What is actually on screen, as numbers.
|
|
686
|
+
*
|
|
687
|
+
* The rung above `framing()`: that one PREDICTS what the camera should see
|
|
688
|
+
* from the scene graph, this one measures what the GPU drew. The difference
|
|
689
|
+
* between the two is the whole class of bug a scene graph cannot express — a
|
|
690
|
+
* black screen, a material that failed, a shader drawing where it should not.
|
|
691
|
+
*
|
|
692
|
+
* Returns the report, never a file. An image is only worth writing when a
|
|
693
|
+
* human is going to look at it.
|
|
694
|
+
*/
|
|
695
|
+
frame(opts?: {
|
|
696
|
+
grid?: [number, number];
|
|
697
|
+
}): Promise<FrameStats>;
|
|
698
|
+
/**
|
|
646
699
|
* Assets that failed to load, with the reason.
|
|
647
700
|
*
|
|
648
701
|
* "The model just never appeared" used to be unanswerable from outside: the
|
|
@@ -3351,6 +3404,25 @@ declare class Renderer3D {
|
|
|
3351
3404
|
warmUp(onProgress?: (fraction: number) => void): Promise<void>;
|
|
3352
3405
|
private render;
|
|
3353
3406
|
/**
|
|
3407
|
+
* A frame's pixels, read on the NEXT frame that draws.
|
|
3408
|
+
*
|
|
3409
|
+
* `preserveDrawingBuffer` is false by default — with good reason, it costs
|
|
3410
|
+
* bandwidth on every frame — so `canvas.toDataURL()` comes back blank, which
|
|
3411
|
+
* is the trap this repo has fallen into before. Reading with `gl.readPixels`
|
|
3412
|
+
* at the END of a render, in the same frame, needs no such flag and no
|
|
3413
|
+
* per-frame cost: nothing happens at all until somebody asks.
|
|
3414
|
+
*
|
|
3415
|
+
* That is why this lives in the engine rather than in a generic screenshot
|
|
3416
|
+
* tool. An outside tool cannot get inside the frame.
|
|
3417
|
+
*/
|
|
3418
|
+
captureFrame(): Promise<{
|
|
3419
|
+
pixels: Uint8Array;
|
|
3420
|
+
width: number;
|
|
3421
|
+
height: number;
|
|
3422
|
+
}>;
|
|
3423
|
+
private pendingCaptures;
|
|
3424
|
+
private drainFrameCapture;
|
|
3425
|
+
/**
|
|
3354
3426
|
* Bloom post pass (only when `environment.bloom` is declared). LDR and safe:
|
|
3355
3427
|
* 1. scene → full-res offscreen (tone-mapped exactly like direct output)
|
|
3356
3428
|
* 2. bright-pass at HALF res (keep pixels above threshold)
|
|
@@ -3575,4 +3647,4 @@ declare function createNavDebugNode(nav: TerrainNav, opts?: {
|
|
|
3575
3647
|
name?: string;
|
|
3576
3648
|
}): InstancedMesh3D;
|
|
3577
3649
|
//#endregion
|
|
3578
|
-
export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type Game3D, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, findRiverCoverageGaps, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
|
3650
|
+
export { Area3D, AssetStore3D, type BedSampler, Billboard3D, type BillboardGroupMode, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, type CreateGame3DOptions, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, type DownhillTraceOptions, Environment3D, type Environment3DConfig, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, type FlowerVariety, Flowers3D, type FogEnvironment, Foliage3D, type FoliageKind, type FoliageStyle, type FrameStats, type FrameStatsOptions, type Game3D, type GridCell, type HeightSampler, type Heightmap, type HeightmapOptions, InstancedMesh3D, Joint3D, type JointType3D, LoftMesh3D, type LoftSection, MeshInstance3D, type MeshKind, type MeshMaterialProps, type ModelEntry, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, type Physics3DOptions, PhysicsBody3D, QUARTER_PITCH, type RenderContext3D, type RenderHook3D, Renderer3D, type Renderer3DOptions, type RigView, RigidBody3D, type Ripple, River3D, type RiverCarveOptions, type RiverCoverageGap, type RiverHit, type RiverRing, type RiverRingOptions, type ShadowsEnvironment, type SkyEnvironment, StaticBody3D, type SunConsumer3D, type SyncOptions, type SyncResult, TERRAIN_THEMES, Terrain3D, type TerrainLayer, type TerrainNav, type TerrainNavOptions, type TerrainTheme, TextureCache3D, type TextureSpec, Trail3D, Tree3D, type TreeTier, type TreeType, VOXEL_PALETTE, type VoxelBlock, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, findRiverCoverageGaps, frameStats, frameText, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
package/dist/3d.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
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-
|
|
2
|
-
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-
|
|
3
|
-
import { a as Environment3D, c as
|
|
1
|
+
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-DRi9524r.js";
|
|
2
|
+
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-Vl5xBsXp.js";
|
|
3
|
+
import { a as Environment3D, c as setEnvironment3D, d as sunDirectionFromElevationAzimuth, f as sunDirectionFromSky, i as syncTree, l as horizonColorFromSky, o as frameStats, p as AssetStore3D, r as Renderer3D, s as frameText, t as createGame3D, u as parseEnvironment3D } from "./create-game-DItIRyXH.js";
|
|
4
4
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
5
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
5
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-C2G604O1.js";
|
|
6
6
|
//#region src/3d/terrain-nav.ts
|
|
7
7
|
function buildTerrainNav(terrain, opts) {
|
|
8
8
|
const cellSize = opts?.cellSize ?? 2;
|
|
@@ -114,4 +114,4 @@ function createNavDebugNode(nav, opts) {
|
|
|
114
114
|
return node;
|
|
115
115
|
}
|
|
116
116
|
//#endregion
|
|
117
|
-
export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, TextureCache3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, findRiverCoverageGaps, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
|
117
|
+
export { Area3D, AssetStore3D, Billboard3D, BoneAttachment3D, BoneLookAt3D, Camera3D, CharacterBody3D, CharacterController3D, DEFAULT_TERRAIN_TEXTURE_BASE, DirectionalLight3D, Environment3D, DENSITY_PRESETS as FLOWER_DENSITY_PRESETS, FLOWER_VARIETIES, Flowers3D, Foliage3D, InstancedMesh3D, Joint3D, LoftMesh3D, MeshInstance3D, ModelInstance3D, Node3D, OmniLight3D, Particles3D, Physics3D, PhysicsBody3D, QUARTER_PITCH, Renderer3D, RigidBody3D, River3D, StaticBody3D, TERRAIN_THEMES, Terrain3D, TextureCache3D, Trail3D, Tree3D, VOXEL_PALETTE, VoxelGrid3D, WATER_CUTOUT_MAX, WATER_MAX_RIPPLES, Water3D, WaterCutout3D, acquireOwnTexture, acquireTexture, buildHeightmap, buildRiverRings, buildTerrainNav, cameraRelative, createGame3D, createNavDebugNode, enablePhysics3D, findRiverCoverageGaps, frameStats, frameText, horizonColorFromSky, keyboardIntensity, movementState, parseEnvironment3D, projectToRiver, registerNodes3D, resolveFlowerDensity, rigPose, riverCarveChannels, riverStepFor, setEnvironment3D, smoothCourse, splatWeights, sunDirectionFromElevationAzimuth, sunDirectionFromSky, syncTree, terrainThemeLayers, traceDownhillPath };
|
|
@@ -390,7 +390,9 @@ interface PlayMusicOptions {
|
|
|
390
390
|
* frame to advance fades (the engine wires this to `updated`).
|
|
391
391
|
*
|
|
392
392
|
* ```ts
|
|
393
|
-
*
|
|
393
|
+
* // NOTE: the bundle ships SFX only — no music track. A background track is
|
|
394
|
+
* // your game's own file under public/, or a URL.
|
|
395
|
+
* engine.music.play('/audio/theme.mp3'); // loop, full
|
|
394
396
|
* engine.music.crossfadeTo('boss.mp3', 3); // 3s equal-power swap
|
|
395
397
|
* engine.music.stop(2); // fade out over 2s
|
|
396
398
|
* engine.music.setVolume(0.5); // per-manager volume
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { n as loadScene, o as computeViewport, s as resolveViewport, v as diagnose, w as registerBehavior } from "./loader-r49nDwB4.js";
|
|
3
|
-
import { h as Engine, m as AudioPlayer } from "./register-
|
|
3
|
+
import { h as Engine, m as AudioPlayer } from "./register-BSXV8T9F.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_MnF.js";
|
|
6
6
|
import { i as openBundledEditor, n as crossFade, r as devServerLibrary, t as teardown } from "./teardown-CCtAMDLB.js";
|
|
7
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
8
|
-
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-
|
|
7
|
+
import { n as registerGameplayBehaviors } from "./gameplay-DRi9524r.js";
|
|
8
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-R2JTnIMw.js";
|
|
9
9
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
10
|
+
import { n as enablePhysics2D } from "./physics-2d-BmgXBNDB.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
|
/**
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { n as loadScene, v as diagnose, w as registerBehavior } from "./loader-r49nDwB4.js";
|
|
3
|
-
import { _ as qualityCaps, h as Engine, m as AudioPlayer, y as qualityRendering } from "./register-
|
|
3
|
+
import { _ as qualityCaps, h as Engine, m as AudioPlayer, y as qualityRendering } from "./register-BSXV8T9F.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { i as resolveRendering, n as attachTouchControls } from "./touch-BoNg_MnF.js";
|
|
6
6
|
import { a as poseFromRenderer, i as openBundledEditor, n as crossFade, r as devServerLibrary, t as teardown } from "./teardown-CCtAMDLB.js";
|
|
7
|
-
import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-
|
|
7
|
+
import { B as createCausticsQuad, F as PhysicsBody3D, R as Node3D, n as registerGameplayBehaviors } from "./gameplay-DRi9524r.js";
|
|
8
8
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
9
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
10
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
9
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-Vl5xBsXp.js";
|
|
10
|
+
import { n as enablePhysics3D } from "./physics-3d-C2G604O1.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";
|
|
@@ -486,6 +486,76 @@ function setEnvironment3D(engine, patch) {
|
|
|
486
486
|
scene.environment = merged;
|
|
487
487
|
}
|
|
488
488
|
//#endregion
|
|
489
|
+
//#region src/3d/frame-report.ts
|
|
490
|
+
/** Rec. 709 relative luminance of an 8-bit triple, 0..1. */
|
|
491
|
+
function luma(r, g, b) {
|
|
492
|
+
return (.2126 * r + .7152 * g + .0722 * b) / 255;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* A pixel this dark is indistinguishable from "nothing was drawn". Not zero:
|
|
496
|
+
* a real render of a night scene still lands a few levels above black, and
|
|
497
|
+
* calling that a failure would make the check useless where it matters most.
|
|
498
|
+
*/
|
|
499
|
+
const BLACK_LEVEL = .012;
|
|
500
|
+
/** Cell-to-cell luminance range below this: the frame is one flat colour. */
|
|
501
|
+
const UNIFORM_EPSILON = .004;
|
|
502
|
+
function frameStats(pixels, width, height, opts = {}) {
|
|
503
|
+
const [cols, rows] = opts.grid ?? [16, 9];
|
|
504
|
+
const grid = [];
|
|
505
|
+
let total = 0;
|
|
506
|
+
let maxLuma = 0;
|
|
507
|
+
let minLuma = 1;
|
|
508
|
+
for (let row = 0; row < rows; row++) {
|
|
509
|
+
const line = [];
|
|
510
|
+
for (let col = 0; col < cols; col++) {
|
|
511
|
+
const x0 = Math.floor(col * width / cols);
|
|
512
|
+
const x1 = Math.max(x0 + 1, Math.floor((col + 1) * width / cols));
|
|
513
|
+
const y0 = Math.floor(row * height / rows);
|
|
514
|
+
const y1 = Math.max(y0 + 1, Math.floor((row + 1) * height / rows));
|
|
515
|
+
let r = 0;
|
|
516
|
+
let g = 0;
|
|
517
|
+
let b = 0;
|
|
518
|
+
let n = 0;
|
|
519
|
+
for (let y = y0; y < y1; y++) for (let x = x0; x < x1; x++) {
|
|
520
|
+
const i = (y * width + x) * 4;
|
|
521
|
+
r += pixels[i] ?? 0;
|
|
522
|
+
g += pixels[i + 1] ?? 0;
|
|
523
|
+
b += pixels[i + 2] ?? 0;
|
|
524
|
+
n += 1;
|
|
525
|
+
}
|
|
526
|
+
const cell = [
|
|
527
|
+
Math.round(r / n),
|
|
528
|
+
Math.round(g / n),
|
|
529
|
+
Math.round(b / n)
|
|
530
|
+
];
|
|
531
|
+
const cellLuma = luma(cell[0], cell[1], cell[2]);
|
|
532
|
+
total += cellLuma;
|
|
533
|
+
maxLuma = Math.max(maxLuma, cellLuma);
|
|
534
|
+
minLuma = Math.min(minLuma, cellLuma);
|
|
535
|
+
line.push(cell);
|
|
536
|
+
}
|
|
537
|
+
grid.push(line);
|
|
538
|
+
}
|
|
539
|
+
const cells = cols * rows;
|
|
540
|
+
const meanLuma = total / cells;
|
|
541
|
+
return {
|
|
542
|
+
width,
|
|
543
|
+
height,
|
|
544
|
+
black: maxLuma <= BLACK_LEVEL,
|
|
545
|
+
uniform: maxLuma - minLuma < UNIFORM_EPSILON,
|
|
546
|
+
meanLuma: Math.round(meanLuma * 1e3) / 1e3,
|
|
547
|
+
grid
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/** The report a person or an agent reads. Verdict first, numbers after. */
|
|
551
|
+
function frameText(stats) {
|
|
552
|
+
const lines = [];
|
|
553
|
+
if (stats.black) lines.push("BLACK SCREEN — nothing was drawn (no light, no camera, or nothing in view)");
|
|
554
|
+
else if (stats.uniform) lines.push("one flat colour — the camera may be inside geometry, or only the sky is drawn");
|
|
555
|
+
lines.push(`frame ${stats.width}×${stats.height} · luminance ${stats.meanLuma.toFixed(2)}`);
|
|
556
|
+
return lines.join("\n");
|
|
557
|
+
}
|
|
558
|
+
//#endregion
|
|
489
559
|
//#region src/3d/adaptive-resolution.ts
|
|
490
560
|
const DEFAULTS = {
|
|
491
561
|
slowMs: 20,
|
|
@@ -1869,6 +1939,50 @@ var Renderer3D = class {
|
|
|
1869
1939
|
else if (clouds && !underwater) this.renderWithClouds(activeCamera, clouds, threeLight);
|
|
1870
1940
|
else if ((bloom || post) && !underwater) this.renderWithBloom(activeCamera, bloom, post);
|
|
1871
1941
|
else this.webgl.render(this.threeScene, activeCamera);
|
|
1942
|
+
this.drainFrameCapture();
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* A frame's pixels, read on the NEXT frame that draws.
|
|
1946
|
+
*
|
|
1947
|
+
* `preserveDrawingBuffer` is false by default — with good reason, it costs
|
|
1948
|
+
* bandwidth on every frame — so `canvas.toDataURL()` comes back blank, which
|
|
1949
|
+
* is the trap this repo has fallen into before. Reading with `gl.readPixels`
|
|
1950
|
+
* at the END of a render, in the same frame, needs no such flag and no
|
|
1951
|
+
* per-frame cost: nothing happens at all until somebody asks.
|
|
1952
|
+
*
|
|
1953
|
+
* That is why this lives in the engine rather than in a generic screenshot
|
|
1954
|
+
* tool. An outside tool cannot get inside the frame.
|
|
1955
|
+
*/
|
|
1956
|
+
captureFrame() {
|
|
1957
|
+
return new Promise((resolve, reject) => {
|
|
1958
|
+
this.pendingCaptures.push({
|
|
1959
|
+
resolve,
|
|
1960
|
+
reject
|
|
1961
|
+
});
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1964
|
+
pendingCaptures = [];
|
|
1965
|
+
drainFrameCapture() {
|
|
1966
|
+
if (this.pendingCaptures.length === 0) return;
|
|
1967
|
+
const waiting = this.pendingCaptures;
|
|
1968
|
+
this.pendingCaptures = [];
|
|
1969
|
+
try {
|
|
1970
|
+
const gl = this.webgl.getContext();
|
|
1971
|
+
const width = this.webgl.domElement.width;
|
|
1972
|
+
const height = this.webgl.domElement.height;
|
|
1973
|
+
const pixels = new Uint8Array(width * height * 4);
|
|
1974
|
+
this.webgl.setRenderTarget(null);
|
|
1975
|
+
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
1976
|
+
flipRows(pixels, width, height);
|
|
1977
|
+
for (const w of waiting) w.resolve({
|
|
1978
|
+
pixels,
|
|
1979
|
+
width,
|
|
1980
|
+
height
|
|
1981
|
+
});
|
|
1982
|
+
} catch (error) {
|
|
1983
|
+
const e = error instanceof Error ? error : new Error(String(error));
|
|
1984
|
+
for (const w of waiting) w.reject(e);
|
|
1985
|
+
}
|
|
1872
1986
|
}
|
|
1873
1987
|
/**
|
|
1874
1988
|
* Bloom post pass (only when `environment.bloom` is declared). LDR and safe:
|
|
@@ -2235,6 +2349,18 @@ const camPosScratch = new Vector3();
|
|
|
2235
2349
|
/** Reused click-pick scratches (no per-pick allocation). */
|
|
2236
2350
|
const pickRaycaster = new Raycaster();
|
|
2237
2351
|
const pickNdc = new Vector2();
|
|
2352
|
+
/** Turn a bottom-left GL buffer into top-left screen order, in place. */
|
|
2353
|
+
function flipRows(pixels, width, height) {
|
|
2354
|
+
const stride = width * 4;
|
|
2355
|
+
const row = new Uint8Array(stride);
|
|
2356
|
+
for (let y = 0; y < Math.floor(height / 2); y++) {
|
|
2357
|
+
const top = y * stride;
|
|
2358
|
+
const bottom = (height - 1 - y) * stride;
|
|
2359
|
+
row.set(pixels.subarray(top, top + stride));
|
|
2360
|
+
pixels.copyWithin(top, bottom, bottom + stride);
|
|
2361
|
+
pixels.set(row, bottom);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2238
2364
|
//#endregion
|
|
2239
2365
|
//#region src/3d/create-game.ts
|
|
2240
2366
|
var create_game_exports = /* @__PURE__ */ __exportAll({ createGame3D: () => createGame3D });
|
|
@@ -2378,6 +2504,27 @@ async function createGame3D(opts) {
|
|
|
2378
2504
|
cleanups.push(engine.settings.bindRenderScale((scale) => {
|
|
2379
2505
|
renderer.setRenderScale?.(scale);
|
|
2380
2506
|
}));
|
|
2507
|
+
const captureReport = async (frameOpts) => {
|
|
2508
|
+
const capture = renderer.captureFrame;
|
|
2509
|
+
if (!capture) throw new IncantoError("TREE_VIOLATION", "this renderer cannot capture frames");
|
|
2510
|
+
const shot = await capture.call(renderer);
|
|
2511
|
+
return frameStats(shot.pixels, shot.width, shot.height, frameOpts);
|
|
2512
|
+
};
|
|
2513
|
+
const hot = import.meta.hot;
|
|
2514
|
+
if (hot) {
|
|
2515
|
+
const onFrameRequest = (data) => {
|
|
2516
|
+
const id = data?.id;
|
|
2517
|
+
captureReport().then((frameReport) => hot.send("incanto:frame-report", {
|
|
2518
|
+
id,
|
|
2519
|
+
report: frameReport
|
|
2520
|
+
})).catch((error) => hot.send("incanto:frame-report", {
|
|
2521
|
+
id,
|
|
2522
|
+
report: { error: error instanceof Error ? error.message : String(error) }
|
|
2523
|
+
}));
|
|
2524
|
+
};
|
|
2525
|
+
hot.on("incanto:frame-request", onFrameRequest);
|
|
2526
|
+
cleanups.push(() => hot.off?.("incanto:frame-request", onFrameRequest));
|
|
2527
|
+
}
|
|
2381
2528
|
await report(1, "ready");
|
|
2382
2529
|
function disposeGame() {
|
|
2383
2530
|
teardown([
|
|
@@ -2398,6 +2545,12 @@ async function createGame3D(opts) {
|
|
|
2398
2545
|
assetErrors() {
|
|
2399
2546
|
return renderer.assets?.errors() ?? [];
|
|
2400
2547
|
},
|
|
2548
|
+
async frame(frameOpts) {
|
|
2549
|
+
const capture = renderer.captureFrame;
|
|
2550
|
+
if (!capture) throw new IncantoError("TREE_VIOLATION", "this renderer cannot capture frames");
|
|
2551
|
+
const shot = await capture.call(renderer);
|
|
2552
|
+
return frameStats(shot.pixels, shot.width, shot.height, frameOpts);
|
|
2553
|
+
},
|
|
2401
2554
|
pick(x, y) {
|
|
2402
2555
|
return engine.picker?.(x, y) ?? null;
|
|
2403
2556
|
},
|
|
@@ -2464,4 +2617,4 @@ function wireAudioUnlock(engine, root, canvas) {
|
|
|
2464
2617
|
return detachAll;
|
|
2465
2618
|
}
|
|
2466
2619
|
//#endregion
|
|
2467
|
-
export { Environment3D as a,
|
|
2620
|
+
export { Environment3D as a, setEnvironment3D as c, sunDirectionFromElevationAzimuth as d, sunDirectionFromSky as f, syncTree as i, horizonColorFromSky as l, create_game_exports as n, frameStats as o, AssetStore3D as p, Renderer3D as r, frameText as s, createGame3D as t, parseEnvironment3D as u };
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as LogLevel, T as RendererStats, b as Engine } from "./behavior-
|
|
1
|
+
import { At as LogLevel, T as RendererStats, b as Engine } from "./behavior-62q0HWBO.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { t as registerCoreNodes } from "./register-
|
|
1
|
+
import { t as registerCoreNodes } from "./register-BSXV8T9F.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
4
4
|
import { i as getNodeSchema, l as registerNode } from "./registry-IyWCGe4q.js";
|
|
5
5
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
6
6
|
import { i as applyParticlePreset, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-Bw7hB93B.js";
|
|
7
|
-
import { A as Water3D, F as PhysicsBody3D, H as colliderFootDrop, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D } from "./gameplay-
|
|
7
|
+
import { A as Water3D, F as PhysicsBody3D, H as colliderFootDrop, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D } from "./gameplay-DRi9524r.js";
|
|
8
8
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
9
9
|
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";
|
|
10
10
|
import { clone } from "three/addons/utils/SkeletonUtils.js";
|
|
@@ -5166,7 +5166,20 @@ var CameraShake = class extends Behavior {
|
|
|
5166
5166
|
magnitude = 0;
|
|
5167
5167
|
t = 0;
|
|
5168
5168
|
prev = [];
|
|
5169
|
+
/**
|
|
5170
|
+
* Start a shake — unless the player asked for no motion.
|
|
5171
|
+
*
|
|
5172
|
+
* `settings.reduceMotion` is an accessibility switch, and camera movement the
|
|
5173
|
+
* player did not cause is the vestibular trigger it exists for. Checked HERE
|
|
5174
|
+
* rather than in `update` so a shake requested while it is on leaves nothing
|
|
5175
|
+
* queued to play the moment it is turned off.
|
|
5176
|
+
*
|
|
5177
|
+
* It deliberately does NOT touch gameplay timing (`hitStop`): freezing time
|
|
5178
|
+
* for 80 ms is feedback, not motion, and removing it would change what the
|
|
5179
|
+
* game is rather than how it moves.
|
|
5180
|
+
*/
|
|
5169
5181
|
shake(magnitude, seconds) {
|
|
5182
|
+
if (this.engine?.settings.get("reduceMotion") === true) return;
|
|
5170
5183
|
this.magnitude = Math.max(this.magnitude, magnitude);
|
|
5171
5184
|
this.t = seconds ?? this.falloff;
|
|
5172
5185
|
}
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Et as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-
|
|
1
|
+
import { Et as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-62q0HWBO.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
|
@@ -685,6 +685,18 @@ declare class CameraShake extends Behavior {
|
|
|
685
685
|
private magnitude;
|
|
686
686
|
private t;
|
|
687
687
|
private prev;
|
|
688
|
+
/**
|
|
689
|
+
* Start a shake — unless the player asked for no motion.
|
|
690
|
+
*
|
|
691
|
+
* `settings.reduceMotion` is an accessibility switch, and camera movement the
|
|
692
|
+
* player did not cause is the vestibular trigger it exists for. Checked HERE
|
|
693
|
+
* rather than in `update` so a shake requested while it is on leaves nothing
|
|
694
|
+
* queued to play the moment it is turned off.
|
|
695
|
+
*
|
|
696
|
+
* It deliberately does NOT touch gameplay timing (`hitStop`): freezing time
|
|
697
|
+
* for 80 ms is feedback, not motion, and removing it would change what the
|
|
698
|
+
* game is rather than how it moves.
|
|
699
|
+
*/
|
|
688
700
|
shake(magnitude: number, seconds?: number): void;
|
|
689
701
|
override update(dt: number): void;
|
|
690
702
|
}
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as FollowCamera, D as Health, E as DamageOnContact, O as Collector, S as restartScene, T as phaseOf, _ as hitStop, a as Wander, b as GameFlow, c as Projectile, d as PathFollow, f as Oscillate, g as Cooldown, h as CameraShake, i as WaveSpawner, k as Chase, l as Pickup, m as Lifetime, n as registerGameplayBehaviors, o as Spawner, p as MoveTo, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as screenFlash, w as DayNight, x as goToScene, y as Interactable } from "./gameplay-
|
|
1
|
+
import { C as FollowCamera, D as Health, E as DamageOnContact, O as Collector, S as restartScene, T as phaseOf, _ as hitStop, a as Wander, b as GameFlow, c as Projectile, d as PathFollow, f as Oscillate, g as Cooldown, h as CameraShake, i as WaveSpawner, k as Chase, l as Pickup, m as Lifetime, n as registerGameplayBehaviors, o as Spawner, p as MoveTo, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as screenFlash, w as DayNight, x as goToScene, y as Interactable } from "./gameplay-DRi9524r.js";
|
|
2
2
|
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|