@jgengine/shell 0.25.0 → 0.27.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/CHANGELOG.md +109 -0
- package/dist/GamePlayerShell.d.ts +8 -0
- package/dist/GamePlayerShell.js +15 -1
- package/dist/Shell3dPresentation.js +29 -11
- package/dist/devtools/FrameTelemetry.d.ts +12 -0
- package/dist/devtools/FrameTelemetry.js +68 -0
- package/dist/devtools/agentBridge.js +2 -0
- package/dist/devtools/devtoolsReports.d.ts +2 -0
- package/dist/devtools/devtoolsReports.js +3 -0
- package/dist/devtools/frameSampler.d.ts +127 -0
- package/dist/devtools/frameSampler.js +345 -0
- package/dist/environment/AuthoredDaylight.d.ts +28 -0
- package/dist/environment/AuthoredDaylight.js +42 -0
- package/dist/environment/Daylight.d.ts +55 -7
- package/dist/environment/Daylight.js +126 -29
- package/dist/environment/EnvironmentScene.js +51 -8
- package/dist/environment/daylightCycle.d.ts +26 -4
- package/dist/environment/daylightCycle.js +36 -5
- package/dist/postfx/PostProcessing.d.ts +7 -1
- package/dist/postfx/PostProcessing.js +28 -2
- package/dist/postfx/autoExposure.d.ts +49 -0
- package/dist/postfx/autoExposure.js +189 -0
- package/dist/postfx/gradeShader.js +43 -4
- package/dist/presentationRecovery3d.js +2 -1
- package/dist/render/CascadedShadows.d.ts +3 -1
- package/dist/render/CascadedShadows.js +9 -1
- package/dist/render/EnvironmentLighting.d.ts +10 -1
- package/dist/render/EnvironmentLighting.js +11 -3
- package/dist/render/IrradianceVolumeLighting.d.ts +18 -0
- package/dist/render/IrradianceVolumeLighting.js +35 -0
- package/dist/render/SceneLighting.d.ts +14 -1
- package/dist/render/SceneLighting.js +29 -8
- package/dist/render/authoredGrade.d.ts +11 -0
- package/dist/render/authoredGrade.js +26 -0
- package/dist/render/decalGeometry.d.ts +26 -0
- package/dist/render/decalGeometry.js +54 -0
- package/dist/render/decalTexture.d.ts +13 -0
- package/dist/render/decalTexture.js +114 -0
- package/dist/render/modelWind.d.ts +28 -0
- package/dist/render/modelWind.js +103 -0
- package/dist/render/presentationLook.d.ts +15 -0
- package/dist/render/presentationLook.js +18 -0
- package/dist/render/stableTextureSet.d.ts +9 -0
- package/dist/render/stableTextureSet.js +24 -0
- package/dist/render/triplanarMaterial.d.ts +52 -0
- package/dist/render/triplanarMaterial.js +169 -0
- package/dist/render/useModelInstance.d.ts +1 -1
- package/dist/render/useModelInstance.js +3 -1
- package/dist/scatter/scatterModels.js +2 -0
- package/dist/scene/DecalRenderer.d.ts +2 -0
- package/dist/scene/DecalRenderer.js +74 -0
- package/dist/scene/GrassFieldRenderer.js +3 -2
- package/dist/scene/builtinSceneKindRenderers.js +2 -0
- package/dist/settings/appliedSettings.js +16 -13
- package/dist/terrain/GrassCover.d.ts +21 -0
- package/dist/terrain/GrassCover.js +84 -0
- package/dist/terrain/grassCoverGeometry.d.ts +40 -0
- package/dist/terrain/grassCoverGeometry.js +112 -0
- package/dist/terrain/terrainDetailMaterial.d.ts +12 -0
- package/dist/terrain/terrainDetailMaterial.js +54 -1
- package/dist/terrain/terrainSurfaces.d.ts +6 -0
- package/dist/terrain/terrainSurfaces.js +10 -0
- package/dist/world/WorldScene.js +2 -1
- package/package.json +4 -4
- package/skills/jgengine/api.md +59 -6
- package/skills/jgengine/capabilities.md +4 -0
- package/skills/jgengine-ui/api.md +114 -23
- package/skills/jgengine-ui/capabilities.md +14 -0
- package/skills/jgengine-ui/reference-primitives.md +4 -2
- package/skills/jgengine-world/SKILL.md +7 -1
- package/skills/jgengine-world/api.md +222 -8
- package/skills/jgengine-world/capabilities.md +42 -2
- package/skills/jgengine-world/recipes/npc-senses.md +8 -2
- package/skills/jgengine-world/recipes/vehicle-feel.md +5 -0
|
@@ -34,9 +34,21 @@ export interface TerrainDetailMaterialOptions {
|
|
|
34
34
|
classMask?: number;
|
|
35
35
|
/** Initial editor relief-contour strength. Default 0. */
|
|
36
36
|
contour?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Per-painted-slot scanned color maps (slot 1 first), each with its own world tile metres. Layers
|
|
39
|
+
* without a map (or beyond {@link MAX_TERRAIN_LAYER_MAPS}) keep the procedural surface response.
|
|
40
|
+
*/
|
|
41
|
+
layerMaps?: readonly (TerrainLayerMap | undefined)[];
|
|
37
42
|
}
|
|
38
43
|
/** Compile every surface response, for an editor viewport whose paint can change to any surface. */
|
|
39
44
|
export declare const ALL_TERRAIN_SURFACE_CLASSES = 511;
|
|
45
|
+
/** One painted layer's scanned color map plus the world metres one tile covers. */
|
|
46
|
+
export interface TerrainLayerMap {
|
|
47
|
+
color: THREE.Texture;
|
|
48
|
+
tileMetres: number;
|
|
49
|
+
}
|
|
50
|
+
/** At most this many painted layers sample their own scanned map; extra layers keep procedural shading. */
|
|
51
|
+
export declare const MAX_TERRAIN_LAYER_MAPS = 4;
|
|
40
52
|
/**
|
|
41
53
|
* A `MeshStandardMaterial` that renders terrain as ground rather than flat colour. Each painted
|
|
42
54
|
* layer draws its surface type's procedural response (grass clumps and blades, dirt clods and
|
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { NOISE_GLSL, PAINT_PARS_GLSL, SURFACE_BUMP_NORMAL_GLSL, SURFACE_FUNCTIONS_GLSL } from "./terrainSurfaceShader.js";
|
|
3
|
+
let placeholder;
|
|
4
|
+
function placeholderTexture() {
|
|
5
|
+
if (placeholder !== undefined)
|
|
6
|
+
return placeholder;
|
|
7
|
+
placeholder = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, THREE.RGBAFormat);
|
|
8
|
+
placeholder.needsUpdate = true;
|
|
9
|
+
return placeholder;
|
|
10
|
+
}
|
|
3
11
|
const ROCK_CLASS_BIT = 1 << 4;
|
|
4
12
|
/** Compile every surface response, for an editor viewport whose paint can change to any surface. */
|
|
5
13
|
export const ALL_TERRAIN_SURFACE_CLASSES = 0x1ff;
|
|
14
|
+
/** At most this many painted layers sample their own scanned map; extra layers keep procedural shading. */
|
|
15
|
+
export const MAX_TERRAIN_LAYER_MAPS = 4;
|
|
6
16
|
// Slot 0 is the unpainted base, 1–8 the paint layers, 9 slope rock.
|
|
7
17
|
const SLOT_GLSL = /* glsl */ `
|
|
18
|
+
#ifdef JG_TERRAIN_LAYER_MAPS
|
|
19
|
+
uniform sampler2D uLayerMap1;
|
|
20
|
+
uniform sampler2D uLayerMap2;
|
|
21
|
+
uniform sampler2D uLayerMap3;
|
|
22
|
+
uniform sampler2D uLayerMap4;
|
|
23
|
+
uniform float uLayerTile1;
|
|
24
|
+
uniform float uLayerTile2;
|
|
25
|
+
uniform float uLayerTile3;
|
|
26
|
+
uniform float uLayerTile4;
|
|
27
|
+
vec3 jgLayerMap(int slot, vec3 wp, out bool has) {
|
|
28
|
+
has = false;
|
|
29
|
+
if (slot == 1) { if (uLayerTile1 > 0.0) { has = true; return texture2D(uLayerMap1, wp.xz / uLayerTile1).rgb; } }
|
|
30
|
+
else if (slot == 2) { if (uLayerTile2 > 0.0) { has = true; return texture2D(uLayerMap2, wp.xz / uLayerTile2).rgb; } }
|
|
31
|
+
else if (slot == 3) { if (uLayerTile3 > 0.0) { has = true; return texture2D(uLayerMap3, wp.xz / uLayerTile3).rgb; } }
|
|
32
|
+
else if (slot == 4) { if (uLayerTile4 > 0.0) { has = true; return texture2D(uLayerMap4, wp.xz / uLayerTile4).rgb; } }
|
|
33
|
+
return vec3(0.0);
|
|
34
|
+
}
|
|
35
|
+
#endif
|
|
8
36
|
JgSurf jgSlot(int slot, vec3 baseTone, vec3 wp){
|
|
9
37
|
vec3 jgFlatC = baseTone;
|
|
10
38
|
JgSurf s;
|
|
@@ -22,6 +50,15 @@ JgSurf jgSlot(int slot, vec3 baseTone, vec3 wp){
|
|
|
22
50
|
else {
|
|
23
51
|
s = jgSurface(0, baseTone, roughness, 1.0, wp);
|
|
24
52
|
}
|
|
53
|
+
#ifdef JG_TERRAIN_LAYER_MAPS
|
|
54
|
+
if (slot > 0 && slot <= 4) {
|
|
55
|
+
bool jgHasMap;
|
|
56
|
+
vec3 jgMapped = jgLayerMap(slot, wp, jgHasMap);
|
|
57
|
+
// The layer owns its own scan: grain, colour and all, tiled at its authored metres, and the
|
|
58
|
+
// mask weights decide how much of it shows against the neighbour layer.
|
|
59
|
+
if (jgHasMap) s.albedo = mix(s.albedo, jgMapped, 0.92);
|
|
60
|
+
}
|
|
61
|
+
#endif
|
|
25
62
|
s.albedo = mix(jgFlatC, s.albedo, uSurface);
|
|
26
63
|
s.height *= uSurface;
|
|
27
64
|
s.bump *= uSurface;
|
|
@@ -48,6 +85,20 @@ export function createTerrainDetailMaterial(detail, textures, options = {}) {
|
|
|
48
85
|
const strength = detail.material?.strength ?? 1;
|
|
49
86
|
const tint = detail.material?.tint ?? 1;
|
|
50
87
|
const paint = options.paint;
|
|
88
|
+
const layerMaps = (options.layerMaps ?? []).slice(0, MAX_TERRAIN_LAYER_MAPS);
|
|
89
|
+
const hasLayerMaps = layerMaps.some((entry) => entry !== undefined);
|
|
90
|
+
const layerMapUniforms = hasLayerMaps
|
|
91
|
+
? {
|
|
92
|
+
uLayerMap1: { value: layerMaps[0]?.color ?? placeholderTexture() },
|
|
93
|
+
uLayerMap2: { value: layerMaps[1]?.color ?? placeholderTexture() },
|
|
94
|
+
uLayerMap3: { value: layerMaps[2]?.color ?? placeholderTexture() },
|
|
95
|
+
uLayerMap4: { value: layerMaps[3]?.color ?? placeholderTexture() },
|
|
96
|
+
uLayerTile1: { value: layerMaps[0]?.tileMetres ?? 0 },
|
|
97
|
+
uLayerTile2: { value: layerMaps[1]?.tileMetres ?? 0 },
|
|
98
|
+
uLayerTile3: { value: layerMaps[2]?.tileMetres ?? 0 },
|
|
99
|
+
uLayerTile4: { value: layerMaps[3]?.tileMetres ?? 0 },
|
|
100
|
+
}
|
|
101
|
+
: {};
|
|
51
102
|
const low = options.quality === "low";
|
|
52
103
|
const contour = { value: options.contour ?? 0 };
|
|
53
104
|
// Rock is always compiled for slope rock; each extra class costs shader time even where unused on
|
|
@@ -68,6 +119,7 @@ export function createTerrainDetailMaterial(detail, textures, options = {}) {
|
|
|
68
119
|
uSurface: { value: detail.surfaceStrength },
|
|
69
120
|
uContour: contour,
|
|
70
121
|
...(paint === undefined ? {} : paint.uniforms),
|
|
122
|
+
...layerMapUniforms,
|
|
71
123
|
...(hasTexture
|
|
72
124
|
? {
|
|
73
125
|
uMatColor: { value: textures.color },
|
|
@@ -88,6 +140,7 @@ export function createTerrainDetailMaterial(detail, textures, options = {}) {
|
|
|
88
140
|
});
|
|
89
141
|
material.defines = {
|
|
90
142
|
...(paint === undefined ? {} : { JG_TERRAIN_PAINT: "" }),
|
|
143
|
+
...(hasLayerMaps ? { JG_TERRAIN_LAYER_MAPS: "" } : {}),
|
|
91
144
|
...(low ? { JG_SURFACE_LOW: "" } : {}),
|
|
92
145
|
JG_SURFACE_CLASSES: String(classMask),
|
|
93
146
|
};
|
|
@@ -264,6 +317,6 @@ ${materialNormalGlsl}`)
|
|
|
264
317
|
.replace("#include <aomap_fragment>", `#include <aomap_fragment>
|
|
265
318
|
${materialAoGlsl}`);
|
|
266
319
|
};
|
|
267
|
-
material.customProgramCacheKey = () => `jgengine-terrain-detail-${hasTexture ? "tex" : "flat"}-${hasTexture && textures.roughness !== undefined ? "rough" : "scalar"}-${hasTexture && textures.ao !== undefined ? "ao" : "unoccluded"}-${paint === undefined ? "bare" : "paint"}-${low ? "low" : "full"}-${classMask}`;
|
|
320
|
+
material.customProgramCacheKey = () => `jgengine-terrain-detail-${hasTexture ? "tex" : "flat"}-${hasTexture && textures.roughness !== undefined ? "rough" : "scalar"}-${hasTexture && textures.ao !== undefined ? "ao" : "unoccluded"}-${paint === undefined ? "bare" : "paint"}-${hasLayerMaps ? "layers" : "procedural"}-${low ? "low" : "full"}-${classMask}`;
|
|
268
321
|
return { material, contour };
|
|
269
322
|
}
|
|
@@ -21,6 +21,10 @@ export interface TerrainPaintSlot {
|
|
|
21
21
|
roughness: number;
|
|
22
22
|
/** Pattern frequency multiplier from the layer's authored `tiling`. */
|
|
23
23
|
scale: number;
|
|
24
|
+
/** World metres per texture repeat for this layer's scanned color map; 0 when the layer has no map. */
|
|
25
|
+
tileMetres: number;
|
|
26
|
+
/** Resolved color-map URL the slot's scanned texture comes from, if any. */
|
|
27
|
+
materialUrl?: string;
|
|
24
28
|
}
|
|
25
29
|
/** Per-cell paint coverage packed for the shader: two RGBA8 planes holding up to eight layer weights. */
|
|
26
30
|
export interface TerrainPaintWeights {
|
|
@@ -50,6 +54,8 @@ export interface TerrainPaintTextures {
|
|
|
50
54
|
readonly classMask: number;
|
|
51
55
|
/** Re-upload coverage and layer slots; reallocates only when the cell grid size changes. */
|
|
52
56
|
update(weights: TerrainPaintWeights): void;
|
|
57
|
+
/** The slot table the current coverage was packed from (layer materials, tile metres, classes). */
|
|
58
|
+
readonly slots: readonly TerrainPaintSlot[];
|
|
53
59
|
dispose(): void;
|
|
54
60
|
}
|
|
55
61
|
/**
|
|
@@ -53,6 +53,8 @@ function slotFor(surface, layer) {
|
|
|
53
53
|
classIndex: CLASS_INDEX[surfaceClass],
|
|
54
54
|
roughness: layer?.roughness ?? CLASS_ROUGHNESS[surfaceClass],
|
|
55
55
|
scale: tiling === undefined || tiling <= 0 ? 1 : Math.min(2, Math.max(0.5, CLASS_TILING[surfaceClass] / tiling)),
|
|
56
|
+
tileMetres: layer?.materialUrl === undefined ? 0 : tiling !== undefined && tiling > 0 ? tiling : 6,
|
|
57
|
+
...(layer?.materialUrl === undefined ? {} : { materialUrl: layer.materialUrl }),
|
|
56
58
|
};
|
|
57
59
|
}
|
|
58
60
|
/**
|
|
@@ -145,6 +147,7 @@ export function createTerrainPaintTextures(weights) {
|
|
|
145
147
|
const classes = new Float32Array(MAX_TERRAIN_PAINT_LAYERS);
|
|
146
148
|
const roughness = new Float32Array(MAX_TERRAIN_PAINT_LAYERS);
|
|
147
149
|
const scales = new Float32Array(MAX_TERRAIN_PAINT_LAYERS);
|
|
150
|
+
const tiles = new Float32Array(MAX_TERRAIN_PAINT_LAYERS);
|
|
148
151
|
const uniforms = {
|
|
149
152
|
uPaintA: { value: coverageTexture(weights.planes[0], weights.cols, weights.rows) },
|
|
150
153
|
uPaintB: { value: coverageTexture(weights.planes[1], weights.cols, weights.rows) },
|
|
@@ -156,9 +159,12 @@ export function createTerrainPaintTextures(weights) {
|
|
|
156
159
|
uLayerClass: { value: classes },
|
|
157
160
|
uLayerRough: { value: roughness },
|
|
158
161
|
uLayerScale: { value: scales },
|
|
162
|
+
uLayerTile: { value: tiles },
|
|
159
163
|
};
|
|
160
164
|
let classMask = 0;
|
|
165
|
+
let slots = weights.slots;
|
|
161
166
|
const update = (next) => {
|
|
167
|
+
slots = next.slots;
|
|
162
168
|
classMask = next.slots.reduce((mask, slot) => mask | (1 << slot.classIndex), 0);
|
|
163
169
|
for (const [key, plane] of [["uPaintA", next.planes[0]], ["uPaintB", next.planes[1]]]) {
|
|
164
170
|
const current = uniforms[key].value;
|
|
@@ -182,6 +188,7 @@ export function createTerrainPaintTextures(weights) {
|
|
|
182
188
|
classes[i] = slot?.classIndex ?? 0;
|
|
183
189
|
roughness[i] = slot?.roughness ?? 0.9;
|
|
184
190
|
scales[i] = slot?.scale ?? 1;
|
|
191
|
+
tiles[i] = slot?.tileMetres ?? 0;
|
|
185
192
|
}
|
|
186
193
|
};
|
|
187
194
|
update(weights);
|
|
@@ -190,6 +197,9 @@ export function createTerrainPaintTextures(weights) {
|
|
|
190
197
|
get classMask() {
|
|
191
198
|
return classMask;
|
|
192
199
|
},
|
|
200
|
+
get slots() {
|
|
201
|
+
return slots;
|
|
202
|
+
},
|
|
193
203
|
update,
|
|
194
204
|
dispose: () => {
|
|
195
205
|
uniforms.uPaintA.value.dispose();
|
package/dist/world/WorldScene.js
CHANGED
|
@@ -17,6 +17,7 @@ import { useSceneEntityIds, useSceneObjectIds, useGameStore, usePlayer, useTarge
|
|
|
17
17
|
import { colorFromId } from "../worldSky.js";
|
|
18
18
|
import { DefaultSurface, detailMaps } from "../render/defaultSurface.js";
|
|
19
19
|
import { useDisposable } from "../render/useDisposable.js";
|
|
20
|
+
import { WindClock } from "../render/modelWind.js";
|
|
20
21
|
import { MeasuredBoundsGroup } from "../render/measureBounds.js";
|
|
21
22
|
import { EntitySprite, IsolatedEntityModel } from "../render/SceneModels.js";
|
|
22
23
|
import { resolveEntityModel, resolveObjectModel } from "../render/resolveModel.js";
|
|
@@ -202,7 +203,7 @@ function WorldActors({ entitySprites, entityModels, objectModels, objectStyles,
|
|
|
202
203
|
}), grouped.singles.map((candidate) => renderSingle(candidate.object)), grouped.batches.map((batch) => _jsx(StaticObjectModels, { batch: batch, single: renderSingle }, batch.key))] }));
|
|
203
204
|
}
|
|
204
205
|
export function WorldView({ entitySprites, entityModels, objectModels, objectStyles, environment, assets, renderEntity, renderObject, selectedIds, hideLocalActor, editorLayers, }) {
|
|
205
|
-
return (_jsxs(_Fragment, { children: [_jsx(WorldEnvironment, { environment: environment }), _jsx(WorldActors, { entitySprites: entitySprites, entityModels: entityModels, objectModels: objectModels, objectStyles: objectStyles, assets: assets, renderEntity: renderEntity, renderObject: renderObject, selectedIds: selectedIds, hideLocalActor: hideLocalActor, editorLayers: editorLayers })] }));
|
|
206
|
+
return (_jsxs(_Fragment, { children: [_jsx(WindClock, {}), _jsx(WorldEnvironment, { environment: environment }), _jsx(WorldActors, { entitySprites: entitySprites, entityModels: entityModels, objectModels: objectModels, objectStyles: objectStyles, assets: assets, renderEntity: renderEntity, renderObject: renderObject, selectedIds: selectedIds, hideLocalActor: hideLocalActor, editorLayers: editorLayers })] }));
|
|
206
207
|
}
|
|
207
208
|
export function RemotePlayers({ rows, presenceInterpolationMs = 100 }) {
|
|
208
209
|
const groups = useRef(new Map());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jgengine/shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Game player shell for JGengine: React Three Fiber canvas, orbit camera, input tracking, HUD mounting, GameUiPreview, and a demo game. Consumers supply a GameRegistry.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"test": "bun test src"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@jgengine/core": "^0.
|
|
39
|
-
"@jgengine/react": "^0.
|
|
40
|
-
"@jgengine/ws": "^0.
|
|
38
|
+
"@jgengine/core": "^0.27.0",
|
|
39
|
+
"@jgengine/react": "^0.27.0",
|
|
40
|
+
"@jgengine/ws": "^0.27.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@react-three/drei": "^10.0.0",
|
package/skills/jgengine/api.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
8
8
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
9
|
-
- `VERSION` (const): const VERSION: "0.
|
|
9
|
+
- `VERSION` (const): const VERSION: "0.27.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
10
10
|
|
|
11
11
|
## @jgengine/core/authoring
|
|
12
12
|
|
|
@@ -82,25 +82,42 @@
|
|
|
82
82
|
- `Devtools` (interface): interface Devtools — Top-level devtools facade aggregating frame, profile, render, logs, latency, controls, discover, overrides, and probes.
|
|
83
83
|
- `DevtoolsControl` (interface): interface DevtoolsControl — Registered tunable control with its resolved schema metadata and read/write/reset accessors.
|
|
84
84
|
- `DevtoolsControlKind` (type): type DevtoolsControlKind = | "slider" | "toggle" | "color" | "select" | "text" | "vec2" | "vec3" | "vec4" | "interval" | "angle" | "enum" — ⚠ undocumented
|
|
85
|
-
- `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — A single captured log line with timestamp, level, and formatted message.
|
|
85
|
+
- `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — A single captured log line with timestamp, level, owning system tag, and formatted message.
|
|
86
86
|
- `DevtoolsLogLevel` (type): type DevtoolsLogLevel = "log" | "info" | "warn" | "error" — Severity level for a captured devtools log entry.
|
|
87
|
+
- `DevtoolsLogs` (interface): interface DevtoolsLogs — Bounded log ring with per-system tags, a warning/error ring, and lifetime counts.
|
|
87
88
|
- `DevtoolsOverrides` (interface): interface DevtoolsOverrides { version: number; enabled: string[]; values: Record<string, unknown>; schemas?: Record<string, {kind: DevtoolsControlKind; schemaVersion?: number}> } — ⚠ undocumented
|
|
88
89
|
- `DevtoolsSnapshot` (interface): interface DevtoolsSnapshot — Serializable point-in-time snapshot of devtools state: frame, render, latency, logs, controls, and discovered fields.
|
|
89
90
|
- `DiscoveredEntry` (interface): interface DiscoveredEntry — A control auto-discovered by scanning an object/table, with its binding metadata and current reader.
|
|
90
91
|
- `DiscoverySkip` (interface): interface DiscoverySkip { readonly path: string; readonly reason: string } — ⚠ undocumented
|
|
91
92
|
- `FrameRecordSample` (interface): interface FrameRecordSample — Per-frame timing input recorded by callers: total frame time, sim time, and optional named phase durations.
|
|
92
93
|
- `FrameStats` (interface): interface FrameStats — Aggregated frame-timing statistics over the recent sampling window, including per-phase breakdown.
|
|
93
|
-
- `
|
|
94
|
+
- `FrameWindow` (interface): interface FrameWindow — Frame timings over the measured window, as the player sees them.
|
|
95
|
+
- `GlReport` (interface): interface GlReport — GPU-object creation counts. `total` is since the page loaded, the named fields since warmup.
|
|
96
|
+
- `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — The one perf record shape. `bun run perf` (CDP, out of process) and the in-page telemetry report (`window.__JG.report()`, the dev-server route, `bun run debug`) both produce exactly this object, so a budget check and a diff read either one.
|
|
94
97
|
- `LatencyStats` (interface): interface LatencyStats — Aggregated latency statistics (last/avg/min/max) over recorded latency samples.
|
|
98
|
+
- `LogBusCounts` (interface): interface LogBusCounts — Lifetime totals per level, plus how many lines the ring dropped.
|
|
99
|
+
- `LogBusEntry` (interface): interface LogBusEntry — One captured line: when, how bad, which system said it, and what it said.
|
|
100
|
+
- `LogBusSnapshot` (interface): interface LogBusSnapshot — Read-out of the log bus: newest-window entries, the warning/error ring, totals, and evictions.
|
|
95
101
|
- `LongFrameEvent` (interface): interface LongFrameEvent — Recorded spike event for a frame that exceeded the long-frame threshold, with culprit attribution.
|
|
96
102
|
- `NormalizedColor` (interface): interface NormalizedColor { readonly hex: string; readonly rgb: string; readonly alpha: number; readonly hasAlpha: boolean } — ⚠ undocumented
|
|
97
103
|
- `OVERRIDES_FORMAT_VERSION` (const): const OVERRIDES_FORMAT_VERSION: 1 — ⚠ undocumented
|
|
98
104
|
- `OverrideApplyDiagnostic` (interface): interface OverrideApplyDiagnostic { readonly id: string; readonly reason: string } — ⚠ undocumented
|
|
99
105
|
- `OverrideApplyResult` (interface): interface OverrideApplyResult — Outcome of applying a devtools overrides payload: counts of applied and skipped entries plus diagnostics.
|
|
106
|
+
- `PerfQuality` (type): type PerfQuality = "full" | "draft" — Graphics tier the record was measured at.
|
|
107
|
+
- `PerfReport` (interface): interface PerfReport — One measured window of one game: the record `bun run perf`, `window.__JG.report()` and `bun run debug` print.
|
|
100
108
|
- `PhaseStats` (interface): interface PhaseStats — Timing summary for a single named profiling phase across the sampling window.
|
|
109
|
+
- `ProfileEntry` (interface): interface ProfileEntry — One sampled stack frame reduced to a readable key and its self time.
|
|
110
|
+
- `ProfileReport` (interface): interface ProfileReport — CPU profile summary; only the CDP harness can produce one.
|
|
111
|
+
- `RenderReport` (interface): interface RenderReport — Renderer-side counts for the measured window; `null` where the source could not read them.
|
|
101
112
|
- `RenderSample` (interface): interface RenderSample — Snapshot of renderer resource counts (draw calls, triangles, geometries, textures) for a frame.
|
|
113
|
+
- `ReportLogLine` (interface): interface ReportLogLine — One log line as it appears in the report.
|
|
114
|
+
- `ReportLogs` (interface): interface ReportLogs — Bounded log read-out carried by the report: warn/error lines survive even a flood of info logs.
|
|
115
|
+
- `ReportTelemetry` (interface): interface ReportTelemetry — Who produced the report, and how much producing it cost.
|
|
102
116
|
- `ScanFieldMeta` (interface): interface ScanFieldMeta extends TunableOptions { kind?: DevtoolsControlKind } — ⚠ undocumented
|
|
103
117
|
- `ScanMeta` (type): type ScanMeta = Readonly<Record<string, ScanFieldMeta>> — ⚠ undocumented
|
|
118
|
+
- `SceneNodeSource` (type): type SceneNodeSource = "scene-graph" | "heap-object3d" | "unavailable" — Where the scene-node count came from: the live scene graph, a heap walk, or nowhere.
|
|
119
|
+
- `SystemProbe` (interface): interface SystemProbe — What one system reports about itself: totals it keeps anyway, named timings, and one state line.
|
|
120
|
+
- `SystemProbeReading` (interface): interface SystemProbeReading — One system's probe read out on demand; missing sections stay empty rather than absent.
|
|
104
121
|
- `Tunable` (interface): interface Tunable<T> — Typed handle to a registered control, exposing its live value and subscribe/set/reset operations.
|
|
105
122
|
- `TunableAccessor` (interface): interface TunableAccessor — Get/set accessor pair plus initial value used to bind a discovered field to a control.
|
|
106
123
|
- `TunableChoice` (interface): interface TunableChoice<T = unknown> { readonly value: T; readonly label?: string } — ⚠ undocumented
|
|
@@ -139,9 +156,20 @@
|
|
|
139
156
|
## @jgengine/core/devtools/frame
|
|
140
157
|
|
|
141
158
|
- `FrameModule` (interface): interface FrameModule — Frame subsystem exposing the frame-timing, profiling, and render-sample facades.
|
|
142
|
-
- `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — Frame duration in milliseconds above which a frame is recorded as a long-frame spike (~30fps budget).
|
|
143
159
|
- `createFrameModule` (const): const createFrameModule: (deps: { readProbes: () => Record<string, unknown>; }) => FrameModule — Create the frame subsystem that records frame/sim/phase timings, computes stats, and captures long-frame events.
|
|
144
160
|
|
|
161
|
+
## @jgengine/core/devtools/logBus
|
|
162
|
+
|
|
163
|
+
- `LOG_BUS_CAPACITY` (const): const LOG_BUS_CAPACITY: 200 — Default measured window for the log ring; older lines are evicted, never grown.
|
|
164
|
+
- `LOG_BUS_MESSAGE_MAX` (const): const LOG_BUS_MESSAGE_MAX: 400 — Longest kept message; a longer one is cut once, at write time.
|
|
165
|
+
- `LOG_BUS_SEVERE_CAPACITY` (const): const LOG_BUS_SEVERE_CAPACITY: 64 — Warnings and errors also land in their own ring, so an error is never pushed out by info traffic.
|
|
166
|
+
- `LogBus` (interface): interface LogBus — A fixed-capacity ring of log lines tagged by owning system. `write` reuses a preallocated slot — no array growth, no splice, no per-write object — so a hot path can call it and only the message string (already built by the caller) costs an allocation.
|
|
167
|
+
- `LogBusCounts` (interface): interface LogBusCounts — Lifetime totals per level, plus how many lines the ring dropped.
|
|
168
|
+
- `LogBusEntry` (interface): interface LogBusEntry — One captured line: when, how bad, which system said it, and what it said.
|
|
169
|
+
- `LogBusOptions` (interface): interface LogBusOptions — Tunables for the log ring: capacity, the severity ring's capacity, and the clock.
|
|
170
|
+
- `LogBusSnapshot` (interface): interface LogBusSnapshot — Read-out of the log bus: newest-window entries, the warning/error ring, totals, and evictions.
|
|
171
|
+
- `createLogBus` (function): function createLogBus(options: LogBusOptions = {}): LogBus — Create the bounded log bus the devtools log facade writes through.
|
|
172
|
+
|
|
145
173
|
## @jgengine/core/devtools/logs
|
|
146
174
|
|
|
147
175
|
- `LogsModule` (interface): interface LogsModule — Logs subsystem exposing the log-capture and latency-tracking facades.
|
|
@@ -153,6 +181,27 @@
|
|
|
153
181
|
- `OverridesModule` (interface): interface OverridesModule — Overrides subsystem exposing the export/apply facade for persisting and restoring control values.
|
|
154
182
|
- `createOverridesModule` (const): const createOverridesModule: (deps: { signal: ChangeSignal; controlRecords: Map<string, ControlRecord>; writeControl: (record: ControlRecord, raw: unknown) => boolean; discoveredRecords: Map<string, DiscoveredRecord>; enableDiscovered: (id: string) => void; }) => OverridesModule — Create the overrides subsystem that serializes changed control values and re-applies a saved overrides payload.
|
|
155
183
|
|
|
184
|
+
## @jgengine/core/devtools/report
|
|
185
|
+
|
|
186
|
+
- `FrameWindow` (interface): interface FrameWindow — Frame timings over the measured window, as the player sees them.
|
|
187
|
+
- `GlReport` (interface): interface GlReport — GPU-object creation counts. `total` is since the page loaded, the named fields since warmup.
|
|
188
|
+
- `LONG_FRAME_MS` (const): const LONG_FRAME_MS: 33.4 — The one perf record shape. `bun run perf` (CDP, out of process) and the in-page telemetry report (`window.__JG.report()`, the dev-server route, `bun run debug`) both produce exactly this object, so a budget check and a diff read either one.
|
|
189
|
+
- `PerfQuality` (type): type PerfQuality = "full" | "draft" — Graphics tier the record was measured at.
|
|
190
|
+
- `PerfReport` (interface): interface PerfReport — One measured window of one game: the record `bun run perf`, `window.__JG.report()` and `bun run debug` print.
|
|
191
|
+
- `ProfileEntry` (interface): interface ProfileEntry — One sampled stack frame reduced to a readable key and its self time.
|
|
192
|
+
- `ProfileReport` (interface): interface ProfileReport — CPU profile summary; only the CDP harness can produce one.
|
|
193
|
+
- `RenderReport` (interface): interface RenderReport — Renderer-side counts for the measured window; `null` where the source could not read them.
|
|
194
|
+
- `ReportLogLine` (interface): interface ReportLogLine — One log line as it appears in the report.
|
|
195
|
+
- `ReportLogs` (interface): interface ReportLogs — Bounded log read-out carried by the report: warn/error lines survive even a flood of info logs.
|
|
196
|
+
- `ReportTelemetry` (interface): interface ReportTelemetry — Who produced the report, and how much producing it cost.
|
|
197
|
+
- `SceneNodeSource` (type): type SceneNodeSource = "scene-graph" | "heap-object3d" | "unavailable" — Where the scene-node count came from: the live scene graph, a heap walk, or nowhere.
|
|
198
|
+
|
|
199
|
+
## @jgengine/core/devtools/reportEndpoint
|
|
200
|
+
|
|
201
|
+
- `REPORT_ENDPOINT_PATH` (const): const REPORT_ENDPOINT_PATH: "/__jgengine/report" — The dev-only route a running game pushes its in-page report to, and that `bun run debug <game>` reads back. One process: the page gathers, the dev server holds the newest record per game, the CLI fetches it. Nothing here ships in a production build — the Vite plugin mounts it under `apply: "serve"`.
|
|
202
|
+
- `ReportPushBody` (interface): interface ReportPushBody — Body the page POSTs: the game it measured and the record itself.
|
|
203
|
+
- `ReportRouteError` (interface): interface ReportRouteError — Body sent when there is nothing to return yet.
|
|
204
|
+
|
|
156
205
|
## @jgengine/core/devtools/rewriteTunables
|
|
157
206
|
|
|
158
207
|
- `TunableDelta` (interface): interface TunableDelta — One changed tunable to write back into game source: which table, key path, and new value.
|
|
@@ -203,8 +252,10 @@
|
|
|
203
252
|
|
|
204
253
|
- `Devtools` (interface): interface Devtools — Top-level devtools facade aggregating frame, profile, render, logs, latency, controls, discover, overrides, and probes.
|
|
205
254
|
- `DevtoolsControl` (interface): interface DevtoolsControl — Registered tunable control with its resolved schema metadata and read/write/reset accessors.
|
|
206
|
-
- `
|
|
255
|
+
- `DevtoolsLatency` (interface): interface DevtoolsLatency — Latency samples recorded by instrumented transport methods.
|
|
256
|
+
- `DevtoolsLogEntry` (interface): interface DevtoolsLogEntry — A single captured log line with timestamp, level, owning system tag, and formatted message.
|
|
207
257
|
- `DevtoolsLogLevel` (type): type DevtoolsLogLevel = "log" | "info" | "warn" | "error" — Severity level for a captured devtools log entry.
|
|
258
|
+
- `DevtoolsLogs` (interface): interface DevtoolsLogs — Bounded log ring with per-system tags, a warning/error ring, and lifetime counts.
|
|
208
259
|
- `DevtoolsSnapshot` (interface): interface DevtoolsSnapshot — Serializable point-in-time snapshot of devtools state: frame, render, latency, logs, controls, and discovered fields.
|
|
209
260
|
- `DiscoveredEntry` (interface): interface DiscoveredEntry — A control auto-discovered by scanning an object/table, with its binding metadata and current reader.
|
|
210
261
|
- `FrameRecordSample` (interface): interface FrameRecordSample — Per-frame timing input recorded by callers: total frame time, sim time, and optional named phase durations.
|
|
@@ -214,6 +265,8 @@
|
|
|
214
265
|
- `OverrideApplyResult` (interface): interface OverrideApplyResult — Outcome of applying a devtools overrides payload: counts of applied and skipped entries plus diagnostics.
|
|
215
266
|
- `PhaseStats` (interface): interface PhaseStats — Timing summary for a single named profiling phase across the sampling window.
|
|
216
267
|
- `RenderSample` (interface): interface RenderSample — Snapshot of renderer resource counts (draw calls, triangles, geometries, textures) for a frame.
|
|
268
|
+
- `SystemProbe` (interface): interface SystemProbe — What one system reports about itself: totals it keeps anyway, named timings, and one state line.
|
|
269
|
+
- `SystemProbeReading` (interface): interface SystemProbeReading — One system's probe read out on demand; missing sections stay empty rather than absent.
|
|
217
270
|
- `Tunable` (interface): interface Tunable<T> — Typed handle to a registered control, exposing its live value and subscribe/set/reset operations.
|
|
218
271
|
- `TunableAccessor` (interface): interface TunableAccessor — Get/set accessor pair plus initial value used to bind a discovered field to a control.
|
|
219
272
|
|
|
@@ -232,7 +285,7 @@
|
|
|
232
285
|
|
|
233
286
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
234
287
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
235
|
-
- `VERSION` (const): const VERSION: "0.
|
|
288
|
+
- `VERSION` (const): const VERSION: "0.27.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
236
289
|
|
|
237
290
|
## @jgengine/core/runtime/adapter
|
|
238
291
|
|
|
@@ -48,6 +48,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
48
48
|
|
|
49
49
|
- `defineSystem` (function) · `import { defineSystem } from "@jgengine/shell/gameKit"`
|
|
50
50
|
|
|
51
|
+
## devtools-log-bus — a bounded, per-system-tagged log ring a system writes to and a report reads
|
|
52
|
+
|
|
53
|
+
- `LogBus` (interface) · `import { LogBus } from "@jgengine/core/devtools/logBus"`
|
|
54
|
+
|
|
51
55
|
## editor-catalogs — Export typed gameplay catalogs for in-editor tuning.
|
|
52
56
|
|
|
53
57
|
- `EditorCatalogDefinition` (interface) · `import { EditorCatalogDefinition } from "@jgengine/shell/gameKit"`
|