@jgengine/core 0.11.0 → 0.12.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 +26 -0
- package/dist/ai/populationDirector.d.ts +103 -0
- package/dist/ai/populationDirector.js +190 -0
- package/dist/ai/pursuit.d.ts +56 -0
- package/dist/ai/pursuit.js +53 -0
- package/dist/authoring.d.ts +1 -1
- package/dist/authoring.js +1 -1
- package/dist/combat.d.ts +1 -0
- package/dist/combat.js +1 -0
- package/dist/devtools/controls.d.ts +38 -0
- package/dist/devtools/controls.js +181 -0
- package/dist/devtools/devtools.d.ts +5 -197
- package/dist/devtools/devtools.js +38 -774
- package/dist/devtools/discover.d.ts +32 -0
- package/dist/devtools/discover.js +240 -0
- package/dist/devtools/fallbackSeams.d.ts +50 -0
- package/dist/devtools/fallbackSeams.js +111 -0
- package/dist/devtools/frame.d.ts +15 -0
- package/dist/devtools/frame.js +247 -0
- package/dist/devtools/logs.d.ts +15 -0
- package/dist/devtools/logs.js +86 -0
- package/dist/devtools/overrides.d.ts +16 -0
- package/dist/devtools/overrides.js +66 -0
- package/dist/devtools/types.d.ts +212 -0
- package/dist/devtools/types.js +1 -0
- package/dist/economy/auctionBook.d.ts +122 -0
- package/dist/economy/auctionBook.js +213 -0
- package/dist/economy/priceHistory.d.ts +44 -0
- package/dist/economy/priceHistory.js +89 -0
- package/dist/economy/unlockPoints.d.ts +92 -0
- package/dist/economy/unlockPoints.js +103 -0
- package/dist/editor/commandApply.d.ts +5 -0
- package/dist/editor/commandApply.js +755 -0
- package/dist/editor/commands.d.ts +48 -3
- package/dist/editor/commands.js +40 -754
- package/dist/editor/directives.d.ts +94 -0
- package/dist/editor/directives.js +206 -0
- package/dist/editor/document.d.ts +37 -2
- package/dist/editor/document.js +422 -6
- package/dist/editor/entityCatalog.d.ts +42 -0
- package/dist/editor/entityCatalog.js +101 -0
- package/dist/editor/environment.d.ts +74 -0
- package/dist/editor/environment.js +169 -0
- package/dist/editor/index.d.ts +26 -1
- package/dist/editor/index.js +8 -1
- package/dist/editor/minimap.d.ts +31 -0
- package/dist/editor/minimap.js +73 -0
- package/dist/editor/streamer.d.ts +66 -0
- package/dist/editor/streamer.js +68 -0
- package/dist/editor/types.d.ts +143 -0
- package/dist/editor/world.d.ts +136 -0
- package/dist/editor/world.js +303 -0
- package/dist/game/breeding.d.ts +161 -0
- package/dist/game/breeding.js +181 -0
- package/dist/game/cameraConfig.d.ts +451 -0
- package/dist/game/cameraConfig.js +1 -0
- package/dist/game/defineGame.d.ts +16 -9
- package/dist/game/defineGame.js +14 -6
- package/dist/game/defineSystem.d.ts +2 -0
- package/dist/game/defineSystem.js +2 -0
- package/dist/game/events.d.ts +28 -0
- package/dist/game/playableGame.d.ts +34 -435
- package/dist/game/playableGame.js +1 -1
- package/dist/game/progression.d.ts +35 -0
- package/dist/game/progression.js +19 -0
- package/dist/game/quest.js +1 -3
- package/dist/game/tribe.d.ts +184 -0
- package/dist/game/tribe.js +432 -0
- package/dist/gameplay.d.ts +3 -1
- package/dist/gameplay.js +3 -1
- package/dist/inventory/encumbrance.d.ts +69 -0
- package/dist/inventory/encumbrance.js +68 -0
- package/dist/item/durability.js +1 -3
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +24 -1
- package/dist/movement/movementModel.d.ts +15 -1
- package/dist/movement/movementModel.js +33 -15
- package/dist/movement/playerMovement.js +102 -2
- package/dist/multiplayer/combatSnapshot.js +13 -8
- package/dist/multiplayer/presenceModel.d.ts +2 -0
- package/dist/multiplayer/presenceModel.js +8 -0
- package/dist/physics/drivableVehicle.d.ts +2 -0
- package/dist/physics/drivableVehicle.js +1 -1
- package/dist/physics/flightDynamics.d.ts +82 -0
- package/dist/physics/flightDynamics.js +165 -0
- package/dist/physics/gravityField.d.ts +25 -0
- package/dist/physics/gravityField.js +41 -0
- package/dist/physics/kinematicVehicle.d.ts +87 -0
- package/dist/physics/kinematicVehicle.js +193 -11
- package/dist/physics/physicsWorld.d.ts +26 -0
- package/dist/physics/physicsWorld.js +109 -117
- package/dist/physics/vehicleObstacles.d.ts +44 -0
- package/dist/physics/vehicleObstacles.js +115 -0
- package/dist/random/rng.d.ts +4 -1
- package/dist/random/rng.js +4 -1
- package/dist/runtime/adapter.d.ts +13 -0
- package/dist/runtime/adapter.js +13 -0
- package/dist/runtime/context/combat.d.ts +51 -0
- package/dist/runtime/context/combat.js +130 -0
- package/dist/runtime/context/deathLoot.d.ts +30 -0
- package/dist/runtime/context/deathLoot.js +39 -0
- package/dist/runtime/context/player.d.ts +48 -0
- package/dist/runtime/context/player.js +125 -0
- package/dist/runtime/context/scene.d.ts +59 -0
- package/dist/runtime/context/scene.js +291 -0
- package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
- package/dist/runtime/context/snapshotCodecs.js +26 -0
- package/dist/runtime/descriptors/baseline.js +26 -3
- package/dist/runtime/descriptors/features.d.ts +5 -0
- package/dist/runtime/descriptors/features.js +20 -2
- package/dist/runtime/gameContext.d.ts +2 -428
- package/dist/runtime/gameContext.js +88 -501
- package/dist/runtime/gameContextTypes.d.ts +467 -0
- package/dist/runtime/gameContextTypes.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +4 -2
- package/dist/runtime/headlessRunner.js +1 -0
- package/dist/runtime/hostPolicy.d.ts +51 -0
- package/dist/runtime/hostPolicy.js +68 -0
- package/dist/runtime/hostedGameRunner.d.ts +3 -1
- package/dist/runtime/hostedGameRunner.js +1 -0
- package/dist/runtime/hostedWorldSession.d.ts +3 -1
- package/dist/runtime/hostedWorldSession.js +1 -0
- package/dist/runtime/worldSnapshot.d.ts +13 -1
- package/dist/runtime/worldSnapshot.js +15 -3
- package/dist/scene/assetCatalog.d.ts +5 -0
- package/dist/scene/assetSpace.js +1 -3
- package/dist/scene/authoredTriggers.d.ts +50 -0
- package/dist/scene/authoredTriggers.js +114 -0
- package/dist/scene/builtinSceneKinds.js +8 -3
- package/dist/scene/colliders.d.ts +58 -0
- package/dist/scene/colliders.js +108 -0
- package/dist/scene/collisionMesh.d.ts +94 -0
- package/dist/scene/collisionMesh.js +699 -0
- package/dist/scene/companion.d.ts +147 -0
- package/dist/scene/companion.js +193 -0
- package/dist/scene/entityStats.d.ts +7 -9
- package/dist/scene/entityStats.js +10 -14
- package/dist/scene/sceneKinds.d.ts +16 -0
- package/dist/scene/sceneKinds.js +4 -0
- package/dist/scene/sceneRaycast.js +15 -0
- package/dist/stats/spawnLevelStats.d.ts +110 -0
- package/dist/stats/spawnLevelStats.js +140 -0
- package/dist/stats/statPool.d.ts +70 -0
- package/dist/stats/statPool.js +59 -0
- package/dist/store/changeSignal.d.ts +3 -0
- package/dist/store/changeSignal.js +2 -0
- package/dist/store/observableKeyedStore.d.ts +2 -0
- package/dist/store/observableKeyedStore.js +1 -0
- package/dist/survival/decayMeter.js +1 -3
- package/dist/survival/regionHealth.js +1 -3
- package/dist/ui/hudLayout.d.ts +5 -0
- package/dist/ui/hudLayout.js +17 -1
- package/dist/world/authoredEntities.d.ts +29 -0
- package/dist/world/authoredEntities.js +29 -0
- package/dist/world/authoredObjects.d.ts +15 -1
- package/dist/world/authoredObjects.js +13 -1
- package/dist/world/authoredSpawn.d.ts +39 -0
- package/dist/world/authoredSpawn.js +37 -0
- package/dist/world/buildSockets.d.ts +152 -0
- package/dist/world/buildSockets.js +188 -0
- package/dist/world/cityBlocks.d.ts +152 -0
- package/dist/world/cityBlocks.js +670 -0
- package/dist/world/cityContent.d.ts +77 -0
- package/dist/world/cityContent.js +261 -0
- package/dist/world/cityGeometry.d.ts +114 -0
- package/dist/world/cityGeometry.js +573 -0
- package/dist/world/cityKind.d.ts +314 -0
- package/dist/world/cityKind.js +1578 -0
- package/dist/world/features.d.ts +18 -3
- package/dist/world/features.js +10 -1
- package/dist/world/grassKind.js +2 -2
- package/dist/world/markers.d.ts +50 -4
- package/dist/world/markers.js +49 -0
- package/dist/world/massing.js +1 -1
- package/dist/world/minimapBake.d.ts +78 -0
- package/dist/world/minimapBake.js +208 -0
- package/dist/world/minimapTrack.d.ts +17 -0
- package/dist/world/minimapTrack.js +22 -0
- package/dist/world/pathNetwork.d.ts +159 -0
- package/dist/world/pathNetwork.js +684 -0
- package/dist/world/place.d.ts +166 -0
- package/dist/world/place.js +96 -0
- package/dist/world/placeAsset.js +3 -1
- package/dist/world/poleLineKind.d.ts +40 -0
- package/dist/world/poleLineKind.js +97 -0
- package/dist/world/polyline.js +9 -2
- package/dist/world/resourceNode.d.ts +109 -0
- package/dist/world/resourceNode.js +140 -0
- package/dist/world/scatter.js +2 -20
- package/dist/world/streets.d.ts +29 -0
- package/dist/world/streets.js +55 -0
- package/dist/world/terraform.js +58 -88
- package/dist/world/terrain.d.ts +45 -0
- package/dist/world/terrain.js +78 -0
- package/dist/world.d.ts +14 -5
- package/dist/world.js +12 -3
- package/package.json +1 -1
- package/skills/game-design/SKILL.md +28 -0
- package/skills/game-design/agents/openai.yaml +4 -0
- package/skills/game-design/references/application-playbook.md +170 -0
- package/skills/game-design/references/field-guide.md +288 -0
- package/skills/jgengine/SKILL.md +7 -4
- package/skills/jgengine/api.md +172 -79
- package/skills/jgengine/capabilities.md +104 -2
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-combat/SKILL.md +5 -1
- package/skills/jgengine-combat/api.md +36 -0
- package/skills/jgengine-combat/capabilities.md +44 -0
- package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
- package/skills/jgengine-combat/reference.md +12 -2
- package/skills/jgengine-gameplay/api.md +152 -26
- package/skills/jgengine-gameplay/capabilities.md +78 -2
- package/skills/jgengine-gameplay/reference-systems.md +1 -5
- package/skills/jgengine-world/SKILL.md +13 -0
- package/skills/jgengine-world/api.md +419 -15
- package/skills/jgengine-world/capabilities.md +108 -2
- package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
- package/skills/jgengine-world/reference.md +43 -4
- package/skills/jgengine/reference-cartridge.md +0 -72
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The proximity streamer for a sharded world (#985 stage 3): a stateful scheduler that decides,
|
|
3
|
+
* as the camera moves, which shards enter and leave residency. It is pure scheduling — actually
|
|
4
|
+
* reading/merging the shard documents stays the caller's job (compose with
|
|
5
|
+
* `@jgengine/core/editor/world`'s `loadWorldDocument` on each returned delta) — so the streamer has
|
|
6
|
+
* no I/O and stays deterministic and testable. Hysteresis (`loadRadius` < `keepRadius`) stops a
|
|
7
|
+
* shard on a boundary from thrashing load/unload every frame.
|
|
8
|
+
*/
|
|
9
|
+
function isAlwaysResident(shard) {
|
|
10
|
+
return shard.residency === "always" || shard.bounds === undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Distance from a point to a shard's XZ footprint (0 when inside), or 0 for an always-resident shard.
|
|
14
|
+
* @capability world-streaming distance from a camera to a shard footprint
|
|
15
|
+
*/
|
|
16
|
+
export function shardDistance(shard, center) {
|
|
17
|
+
if (shard.bounds === undefined)
|
|
18
|
+
return 0;
|
|
19
|
+
const { min, max } = shard.bounds;
|
|
20
|
+
const qx = Math.max(min[0], Math.min(center.x, max[0]));
|
|
21
|
+
const qz = Math.max(min[1], Math.min(center.z, max[1]));
|
|
22
|
+
return Math.hypot(center.x - qx, center.z - qz);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a proximity streamer over a world's shards. Always-resident shards are resident from the
|
|
26
|
+
* first update onward; each bounded shard loads when the camera comes within `loadRadius` of its
|
|
27
|
+
* footprint and unloads only once the camera passes `keepRadius` (≥ `loadRadius`, clamped up),
|
|
28
|
+
* giving a hysteresis band that prevents boundary thrash. Purely spatial and deterministic; the
|
|
29
|
+
* caller wires each delta to `loadWorldDocument`.
|
|
30
|
+
* @capability world-streaming schedule shard load/unload by camera proximity
|
|
31
|
+
*/
|
|
32
|
+
export function createWorldStreamer(config) {
|
|
33
|
+
const loadRadius = Math.max(0, config.loadRadius);
|
|
34
|
+
const keepRadius = Math.max(loadRadius, config.keepRadius);
|
|
35
|
+
const shards = [...config.shards];
|
|
36
|
+
const resident = new Set();
|
|
37
|
+
const residentSorted = () => [...resident].sort();
|
|
38
|
+
return {
|
|
39
|
+
update(center) {
|
|
40
|
+
const load = [];
|
|
41
|
+
const unload = [];
|
|
42
|
+
for (const shard of shards) {
|
|
43
|
+
if (isAlwaysResident(shard)) {
|
|
44
|
+
if (!resident.has(shard.id)) {
|
|
45
|
+
resident.add(shard.id);
|
|
46
|
+
load.push(shard.id);
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const distance = shardDistance(shard, center);
|
|
51
|
+
const isResident = resident.has(shard.id);
|
|
52
|
+
if (!isResident && distance <= loadRadius) {
|
|
53
|
+
resident.add(shard.id);
|
|
54
|
+
load.push(shard.id);
|
|
55
|
+
}
|
|
56
|
+
else if (isResident && distance > keepRadius) {
|
|
57
|
+
resident.delete(shard.id);
|
|
58
|
+
unload.push(shard.id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { load: load.sort(), unload: unload.sort(), resident: residentSorted() };
|
|
62
|
+
},
|
|
63
|
+
resident: residentSorted,
|
|
64
|
+
reset() {
|
|
65
|
+
resident.clear();
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
package/dist/editor/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ParamSchema } from "../scene/sceneKinds.js";
|
|
2
2
|
import type { EditorUiDocument } from "../ui/hudDocument.js";
|
|
3
|
+
import type { MinimapBakeBounds } from "../world/minimapBake.js";
|
|
3
4
|
import type { TerraformSnapshot } from "../world/terraform.js";
|
|
4
5
|
import type { EditorGridLayer } from "./grid.js";
|
|
5
6
|
export type { EditorUiDocument, EditorUiPanelLayout, HudResizeAxes, HudPanelTypeDef } from "../ui/hudDocument.js";
|
|
@@ -26,6 +27,16 @@ export interface EditorMarker {
|
|
|
26
27
|
catalogId?: string;
|
|
27
28
|
/** Id of the object this one is parented under; moving the parent moves this with it. */
|
|
28
29
|
parentId?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Per-object edit lock — blocks transform/remove the same way a locked collection does.
|
|
32
|
+
* Combined with collection locks in `isEditorObjectLocked`.
|
|
33
|
+
*/
|
|
34
|
+
locked?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Per-object viewport hide — object stays in the hierarchy/document but is omitted from
|
|
37
|
+
* editor overlays and picking when true. Independent of per-kind layer visibility.
|
|
38
|
+
*/
|
|
39
|
+
hidden?: boolean;
|
|
29
40
|
meta?: Record<string, unknown>;
|
|
30
41
|
}
|
|
31
42
|
/** A spatial region — zone, aggro range, capture area — placed in the scene. */
|
|
@@ -41,6 +52,10 @@ export interface EditorVolume {
|
|
|
41
52
|
label?: string;
|
|
42
53
|
/** Id of the object this one is parented under; moving the parent moves this with it. */
|
|
43
54
|
parentId?: string;
|
|
55
|
+
/** Per-object edit lock — see {@link EditorMarker.locked}. */
|
|
56
|
+
locked?: boolean;
|
|
57
|
+
/** Per-object viewport hide — see {@link EditorMarker.hidden}. */
|
|
58
|
+
hidden?: boolean;
|
|
44
59
|
meta?: Record<string, unknown>;
|
|
45
60
|
}
|
|
46
61
|
/** A polyline of points — road, corridor, patrol route — placed in the scene. */
|
|
@@ -53,6 +68,10 @@ export interface EditorPath {
|
|
|
53
68
|
label?: string;
|
|
54
69
|
/** Id of the object this one is parented under; moving the parent moves this with it. */
|
|
55
70
|
parentId?: string;
|
|
71
|
+
/** Per-object edit lock — see {@link EditorMarker.locked}. */
|
|
72
|
+
locked?: boolean;
|
|
73
|
+
/** Per-object viewport hide — see {@link EditorMarker.hidden}. */
|
|
74
|
+
hidden?: boolean;
|
|
56
75
|
meta?: Record<string, unknown>;
|
|
57
76
|
}
|
|
58
77
|
/** A free-text annotation pinned to a world position for designers. */
|
|
@@ -63,6 +82,10 @@ export interface EditorNote {
|
|
|
63
82
|
color?: string;
|
|
64
83
|
/** Id of the object this one is parented under; moving the parent moves this with it. */
|
|
65
84
|
parentId?: string;
|
|
85
|
+
/** Per-object edit lock — see {@link EditorMarker.locked}. */
|
|
86
|
+
locked?: boolean;
|
|
87
|
+
/** Per-object viewport hide — see {@link EditorMarker.hidden}. */
|
|
88
|
+
hidden?: boolean;
|
|
66
89
|
meta?: Record<string, unknown>;
|
|
67
90
|
}
|
|
68
91
|
/**
|
|
@@ -120,6 +143,14 @@ export interface EditorCatalogEntry {
|
|
|
120
143
|
export interface EditorCatalogData {
|
|
121
144
|
id: string;
|
|
122
145
|
entries: EditorCatalogEntry[];
|
|
146
|
+
/**
|
|
147
|
+
* Optional document-carried `ParamSchema`. Present only for editor-authored catalogs (created from
|
|
148
|
+
* the Data tab, no matching game export); game-exported catalogs keep their schema in code. Carrying
|
|
149
|
+
* it here is what lets an editor-only catalog round-trip through save/reload and drive the inspector.
|
|
150
|
+
*/
|
|
151
|
+
schema?: ParamSchema;
|
|
152
|
+
/** Optional display label for a document-authored catalog; falls back to the id when absent. */
|
|
153
|
+
label?: string;
|
|
123
154
|
}
|
|
124
155
|
/**
|
|
125
156
|
* Game-exported catalog definition: a `ParamSchema` plus default entries. Schemas stay in code;
|
|
@@ -134,6 +165,48 @@ export interface EditorCatalogDefinition {
|
|
|
134
165
|
}
|
|
135
166
|
/** Accepted shape for a game's `editorCatalogs` export: definitions, or a factory. */
|
|
136
167
|
export type EditorCatalogsInput = readonly EditorCatalogDefinition[] | (() => readonly EditorCatalogDefinition[]);
|
|
168
|
+
/**
|
|
169
|
+
* A baked top-down minimap stored on the scene document (#1036): the PNG the editor rasterized from
|
|
170
|
+
* the authored terrain (a `data:image/png;base64,…` URI) plus the world bounds it spans. Runtime
|
|
171
|
+
* feeds these straight into the `Minimap`/`WorldMap` `background`/`mapBounds` props — no re-raster.
|
|
172
|
+
* @capability minimap-bake persist a baked minimap PNG + bounds on the scene document
|
|
173
|
+
*/
|
|
174
|
+
export interface EditorMinimapBake {
|
|
175
|
+
/** `data:image/png;base64,…` background produced by `bakeMinimapFromDocument`. */
|
|
176
|
+
background: string;
|
|
177
|
+
/** World-space rectangle the baked image spans. */
|
|
178
|
+
bounds: MinimapBakeBounds;
|
|
179
|
+
}
|
|
180
|
+
/** Named sky look stored on the scene document; matches runtime `SkyEnvironmentConfig.preset`. */
|
|
181
|
+
export type EditorSkyPreset = "day" | "dusk" | "night";
|
|
182
|
+
/**
|
|
183
|
+
* Linear distance fog authored on the scene document — serializable subset of sky/backdrop fog.
|
|
184
|
+
* Absent fields keep engine defaults when the document is applied at runtime.
|
|
185
|
+
*/
|
|
186
|
+
export interface EditorFogConfig {
|
|
187
|
+
color?: string;
|
|
188
|
+
near?: number;
|
|
189
|
+
far?: number;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Scene-document environment/lighting authoring (#1110): sky preset, optional time-of-day drive,
|
|
193
|
+
* horizon/zenith tints, sun/ambient intensity, and fog. Serializable and genre-agnostic — games
|
|
194
|
+
* feed it into `environment({ sky: sky(skyFromDocument(doc)) })` (or leave world.ts sky as a
|
|
195
|
+
* fallback when the field is absent). Absent until the lighting workspace (or a seed layer) writes
|
|
196
|
+
* it, so existing documents load unchanged.
|
|
197
|
+
* @capability editor-environment persist sky/fog/lighting knobs on the scene document
|
|
198
|
+
*/
|
|
199
|
+
export interface EditorEnvironment {
|
|
200
|
+
/** Fixed sky look when `timeOfDay` is off (or no clock is available). */
|
|
201
|
+
preset?: EditorSkyPreset;
|
|
202
|
+
/** Drive sun/sky from the world clock's day fraction instead of the fixed `preset`. */
|
|
203
|
+
timeOfDay?: boolean;
|
|
204
|
+
horizonColor?: string;
|
|
205
|
+
zenithColor?: string;
|
|
206
|
+
sunIntensity?: number;
|
|
207
|
+
ambientIntensity?: number;
|
|
208
|
+
fog?: EditorFogConfig;
|
|
209
|
+
}
|
|
137
210
|
/** The full authored scene: every marker, volume, path, note, and sculpted terrain for a game. */
|
|
138
211
|
export interface EditorDocument {
|
|
139
212
|
version: 1;
|
|
@@ -160,7 +233,77 @@ export interface EditorDocument {
|
|
|
160
233
|
* Canvas mode (F2+C) and `canvas_move_panel` / `canvas_resize_panel` write here; HudPanel reads it.
|
|
161
234
|
*/
|
|
162
235
|
ui?: EditorUiDocument;
|
|
236
|
+
/**
|
|
237
|
+
* Procedural **directives** — the scene-authorable face of the runtime scatter/population
|
|
238
|
+
* primitives. One directive line materializes into many placements at load (via
|
|
239
|
+
* `@jgengine/core/editor/directives`) instead of hundreds of explicit entries, so bulk ambient
|
|
240
|
+
* content (rocks, trees, mob populations) stays one diffable row. Absent until a game authors one.
|
|
241
|
+
*/
|
|
242
|
+
directives?: EditorDirective[];
|
|
243
|
+
/**
|
|
244
|
+
* Baked top-down minimap (#1036) — the editor's `bake_minimap` action rasterizes the authored
|
|
245
|
+
* terrain into this PNG + bounds; runtime hands them to the `Minimap`/`WorldMap` props. Absent
|
|
246
|
+
* until baked, so old docs and unbaked games load unchanged.
|
|
247
|
+
*/
|
|
248
|
+
minimap?: EditorMinimapBake;
|
|
249
|
+
/**
|
|
250
|
+
* Scene-document sky/fog/lighting (#1110). Absent until authored in the lighting workspace or
|
|
251
|
+
* seeded via `editorLayers`, so old docs load unchanged and world.ts can keep a fallback sky.
|
|
252
|
+
*/
|
|
253
|
+
environment?: EditorEnvironment;
|
|
254
|
+
}
|
|
255
|
+
/** XZ world-space bounds, `[minX, minZ]`..`[maxX, maxZ]`, for a directive that names no region. */
|
|
256
|
+
export interface EditorDirectiveArea {
|
|
257
|
+
min: [number, number];
|
|
258
|
+
max: [number, number];
|
|
259
|
+
}
|
|
260
|
+
/** Fields shared by every directive: a stable id, the region/area it fills, and a deterministic seed. */
|
|
261
|
+
interface EditorDirectiveBase {
|
|
262
|
+
/** Stable directive id; also the prefix of every minted instance id (`<id>#<index>`). */
|
|
263
|
+
id: string;
|
|
264
|
+
/** Id of a document volume or scatter path whose footprint bounds the directive. */
|
|
265
|
+
region?: string;
|
|
266
|
+
/** Explicit XZ bounds used when no `region` is named. */
|
|
267
|
+
area?: EditorDirectiveArea;
|
|
268
|
+
/** Deterministic seed — the same directive + seed always materializes the same field. */
|
|
269
|
+
seed?: string | number;
|
|
270
|
+
/** Free-form authoring metadata. */
|
|
271
|
+
meta?: Record<string, unknown>;
|
|
272
|
+
}
|
|
273
|
+
/** Scatters catalog props (rocks/trees/foliage) across a region — feeds the existing scatter system. */
|
|
274
|
+
export interface EditorScatterDirective extends EditorDirectiveBase {
|
|
275
|
+
kind: "scatter";
|
|
276
|
+
/** Catalog/asset id every placement instantiates. */
|
|
277
|
+
asset: string;
|
|
278
|
+
/** Items per square meter across the footprint. */
|
|
279
|
+
density: number;
|
|
280
|
+
/** Minimum spacing between placements (m); 0 allows clumping. */
|
|
281
|
+
minSpacing?: number;
|
|
282
|
+
/** Grid jitter 0..1 — 0 is a rigid lattice, 1 fully scattered. */
|
|
283
|
+
jitter?: number;
|
|
284
|
+
minScale?: number;
|
|
285
|
+
maxScale?: number;
|
|
286
|
+
/** Yaw range (radians) applied per placement. */
|
|
287
|
+
minYaw?: number;
|
|
288
|
+
maxYaw?: number;
|
|
289
|
+
}
|
|
290
|
+
/** One weighted species in a population directive, with a hard instance cap. */
|
|
291
|
+
export interface EditorPopulationSpecies {
|
|
292
|
+
id: string;
|
|
293
|
+
/** Relative spawn weight; defaults to 1. */
|
|
294
|
+
weight?: number;
|
|
295
|
+
/** Maximum instances of this species the directive materializes. */
|
|
296
|
+
cap: number;
|
|
297
|
+
}
|
|
298
|
+
/** Populates a region with weighted, capped mob spawns — config for `ai/populationDirector`. */
|
|
299
|
+
export interface EditorPopulationDirective extends EditorDirectiveBase {
|
|
300
|
+
kind: "population";
|
|
301
|
+
species: EditorPopulationSpecies[];
|
|
163
302
|
}
|
|
303
|
+
/** A procedural directive on the scene document: scatter props or a mob population. */
|
|
304
|
+
export type EditorDirective = EditorScatterDirective | EditorPopulationDirective;
|
|
305
|
+
/** The distinct directive kinds a materializer expands. */
|
|
306
|
+
export type EditorDirectiveKind = EditorDirective["kind"];
|
|
164
307
|
/** Accepted shape for a game's `editorLayers` export: a document, partial data, or a factory. */
|
|
165
308
|
export type EditorLayersInput = EditorDocument | Partial<Omit<EditorDocument, "version">> | (() => EditorDocument | Partial<Omit<EditorDocument, "version">>);
|
|
166
309
|
/** Per-kind show/hide flags for the editor's layer panel. */
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { type EditorDocumentDiagnostic } from "./document.js";
|
|
2
|
+
import type { EditorDocument } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* A sharded **world**: a scene that is no longer one monolithic `editor.scene.json` but a manifest
|
|
5
|
+
* plus spatially-partitioned shard documents. A single-file game is the degenerate one-shard case,
|
|
6
|
+
* so nothing pays for scale it does not have. The shard/overlay documents are the exact
|
|
7
|
+
* {@link EditorDocument} format loaders already consume — this module is composition over
|
|
8
|
+
* `mergeEditorDocuments` / `extractEditorFragment` / `editorDocumentBounds`, not a new format.
|
|
9
|
+
*/
|
|
10
|
+
/** The manifest `kind` discriminator — a world folder's `world.json`. */
|
|
11
|
+
export declare const WORLD_MANIFEST_KIND = "world";
|
|
12
|
+
/** Whether a shard is always loaded (terrain, always-resident hero content) or streamed by proximity. */
|
|
13
|
+
export type WorldShardResidency = "always" | "streamed";
|
|
14
|
+
/** A shard's XZ world-space footprint, `[minX, minZ]`..`[maxX, maxZ]`, used to route/stream loads. */
|
|
15
|
+
export interface WorldShardBounds {
|
|
16
|
+
min: [number, number];
|
|
17
|
+
max: [number, number];
|
|
18
|
+
}
|
|
19
|
+
/** One entry in a world manifest: a shard document, its footprint, residency, and optional overlay. */
|
|
20
|
+
export interface WorldManifestShard {
|
|
21
|
+
/** Stable shard id (also the merge/stream unit). */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Path to the shard's `EditorDocument` JSON, relative to the world folder. */
|
|
24
|
+
file: string;
|
|
25
|
+
/** XZ footprint used to cull the shard against a streaming query; absent = always resident. */
|
|
26
|
+
bounds?: WorldShardBounds;
|
|
27
|
+
/** `"always"` keeps the shard resident regardless of the query; default `"streamed"` when bounded. */
|
|
28
|
+
residency?: WorldShardResidency;
|
|
29
|
+
/** Path to a sparse overlay document applied on top of this shard (hand-tweaks over materialized content). */
|
|
30
|
+
overlay?: string;
|
|
31
|
+
}
|
|
32
|
+
/** The world grid the shards partition space on. */
|
|
33
|
+
export interface WorldGrid {
|
|
34
|
+
/** Cell edge length in meters. */
|
|
35
|
+
cellSize: number;
|
|
36
|
+
}
|
|
37
|
+
/** Proximity streaming radii, in meters. */
|
|
38
|
+
export interface WorldStreamingConfig {
|
|
39
|
+
/** Load shards whose footprint is within this distance of the query center. */
|
|
40
|
+
loadRadius: number;
|
|
41
|
+
/** Keep already-loaded shards resident until they fall outside this (larger) distance — hysteresis. */
|
|
42
|
+
keepRadius: number;
|
|
43
|
+
}
|
|
44
|
+
/** A world manifest — the `world.json` at the root of a world folder. */
|
|
45
|
+
export interface WorldManifest {
|
|
46
|
+
kind: typeof WORLD_MANIFEST_KIND;
|
|
47
|
+
/** Manifest schema version; defaults to 1 when absent. */
|
|
48
|
+
version?: number;
|
|
49
|
+
grid?: WorldGrid;
|
|
50
|
+
shards: WorldManifestShard[];
|
|
51
|
+
streaming?: WorldStreamingConfig;
|
|
52
|
+
}
|
|
53
|
+
/** A spatial query used to select which shards a neighborhood needs. */
|
|
54
|
+
export interface WorldQuery {
|
|
55
|
+
/** Query center in world space (typically the camera/player position). */
|
|
56
|
+
center: {
|
|
57
|
+
x: number;
|
|
58
|
+
z: number;
|
|
59
|
+
};
|
|
60
|
+
/** Selection radius in meters; 0 (default) selects only shards whose footprint contains the center. */
|
|
61
|
+
radius?: number;
|
|
62
|
+
}
|
|
63
|
+
/** Resolves a shard/overlay file path to a decoded document, or null when it cannot be read. */
|
|
64
|
+
export type WorldShardResolver = (file: string) => EditorDocument | null;
|
|
65
|
+
/**
|
|
66
|
+
* True when a shard should be resident for a query: always-resident shards always, bounded shards
|
|
67
|
+
* only when the query disc (`center` ± `radius`) overlaps their footprint.
|
|
68
|
+
* @capability world-shards select shards for a neighborhood by spatial query
|
|
69
|
+
*/
|
|
70
|
+
export declare function shardMatchesQuery(shard: WorldManifestShard, query: WorldQuery): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The shards a query needs — always-resident shards plus every bounded shard whose footprint the
|
|
73
|
+
* query disc overlaps, in manifest order. With no query every shard is selected (load the planet),
|
|
74
|
+
* so a one-shard game and an unqueried load behave exactly as a monolithic document does today.
|
|
75
|
+
* @capability world-shards select shards for a neighborhood by spatial query
|
|
76
|
+
*/
|
|
77
|
+
export declare function selectWorldShards(manifest: WorldManifest, query?: WorldQuery): WorldManifestShard[];
|
|
78
|
+
/**
|
|
79
|
+
* Loads the live neighborhood document for a query: reads each selected shard through `resolve`,
|
|
80
|
+
* applies its overlay (if any) on top, then merges them into one {@link EditorDocument} downstream
|
|
81
|
+
* consumers (`placeAuthoredObjects`, `collectAuthoredTriggers`, scatter, …) read unchanged. The
|
|
82
|
+
* monolith becomes an internal detail of the loader; a one-shard world yields exactly that shard.
|
|
83
|
+
* @capability world-shards merge the shards for a neighborhood into one live document
|
|
84
|
+
*/
|
|
85
|
+
export declare function loadWorldDocument(manifest: WorldManifest, resolve: WorldShardResolver, query?: WorldQuery): EditorDocument;
|
|
86
|
+
/** The always-resident base shard id used by {@link splitEditorDocumentIntoShards}. */
|
|
87
|
+
export declare const WORLD_BASE_SHARD_ID = "base";
|
|
88
|
+
/** Options controlling how a monolithic document is partitioned into shards. */
|
|
89
|
+
export interface SplitWorldOptions {
|
|
90
|
+
/** Grid cell edge length in meters. Default 256. */
|
|
91
|
+
cellSize?: number;
|
|
92
|
+
/** Directory prefix for generated shard files. Default `"shards"`. */
|
|
93
|
+
shardDir?: string;
|
|
94
|
+
}
|
|
95
|
+
/** The result of splitting a document: a manifest plus the shard documents keyed by their file path. */
|
|
96
|
+
export interface SplitWorldResult {
|
|
97
|
+
manifest: WorldManifest;
|
|
98
|
+
/** Shard file path → document, for a caller to serialize into a world folder. */
|
|
99
|
+
shards: Record<string, EditorDocument>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Splits a monolithic document into a sharded world: placeable objects (markers, volumes, paths,
|
|
103
|
+
* notes) are bucketed into `cellSize`-meter grid cells by a representative point and extracted into
|
|
104
|
+
* per-cell shard documents; the non-placeable extras (terrain, catalogs, prefabs, collections,
|
|
105
|
+
* grids, HUD layout) go into one always-resident `base` shard. Round-trips through
|
|
106
|
+
* {@link loadWorldDocument} to the same object set — the reverse of monolith authoring, so a large
|
|
107
|
+
* scene can be sharded once and streamed thereafter. Cell shards carry their exact object footprint
|
|
108
|
+
* as bounds; empty cells are omitted; order is deterministic (row-major by grid coordinate).
|
|
109
|
+
* @capability world-shards split a monolithic scene document into spatial shards
|
|
110
|
+
*/
|
|
111
|
+
export declare function splitEditorDocumentIntoShards(doc: EditorDocument, options?: SplitWorldOptions): SplitWorldResult;
|
|
112
|
+
/**
|
|
113
|
+
* The backward-compatible degenerate manifest: one always-resident shard pointing at a single scene
|
|
114
|
+
* document file. `loadWorldDocument(singleShardWorldManifest(file), resolve)` returns exactly that
|
|
115
|
+
* document — the migration path for a game that has one `editor.scene.json` and wants the world API
|
|
116
|
+
* without sharding yet.
|
|
117
|
+
* @capability world-shards wrap a single scene document as a one-shard world
|
|
118
|
+
*/
|
|
119
|
+
export declare function singleShardWorldManifest(file: string, shardId?: string): WorldManifest;
|
|
120
|
+
/** Result of {@link decodeWorldManifest}: a typed manifest, or every diagnostic collected decoding it. */
|
|
121
|
+
export type DecodeWorldManifestResult = {
|
|
122
|
+
ok: true;
|
|
123
|
+
manifest: WorldManifest;
|
|
124
|
+
} | {
|
|
125
|
+
ok: false;
|
|
126
|
+
errors: EditorDocumentDiagnostic[];
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* The authoritative decoder for a `world.json` manifest arriving from disk or an agent: validates
|
|
130
|
+
* `kind`, the shard list, and each shard's fields with a path-specific diagnostic on failure, so a
|
|
131
|
+
* malformed manifest fails loudly at the boundary instead of streaming a broken world.
|
|
132
|
+
* @capability world-shards decode an untrusted world manifest with per-field diagnostics
|
|
133
|
+
*/
|
|
134
|
+
export declare function decodeWorldManifest(raw: unknown): DecodeWorldManifestResult;
|
|
135
|
+
/** Serializes a world manifest to pretty JSON for writing `world.json`. */
|
|
136
|
+
export declare function exportWorldManifestJson(manifest: WorldManifest, pretty?: boolean): string;
|