@jgengine/core 0.18.0 → 0.19.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 +265 -2
- package/dist/ai/decisionGraph.d.ts +96 -0
- package/dist/ai/decisionGraph.js +212 -0
- package/dist/ai/groupAssist.d.ts +10 -0
- package/dist/ai/groupAssist.js +11 -0
- package/dist/ai/mobBrainGraph.d.ts +3 -0
- package/dist/ai/mobBrainGraph.js +25 -0
- package/dist/ai/pursuit.d.ts +1 -1
- package/dist/ai/pursuit.js +1 -1
- package/dist/ai/tacticalQueries.d.ts +30 -0
- package/dist/ai/tacticalQueries.js +45 -0
- package/dist/ai/threat.d.ts +8 -0
- package/dist/ai/threat.js +10 -0
- package/dist/anim/animGraph.d.ts +155 -0
- package/dist/anim/animGraph.js +414 -0
- package/dist/anim/boneTexture.d.ts +55 -0
- package/dist/anim/boneTexture.js +43 -0
- package/dist/anim/footPlacement.d.ts +57 -0
- package/dist/anim/footPlacement.js +67 -0
- package/dist/anim/ikSolver.d.ts +51 -0
- package/dist/anim/ikSolver.js +124 -0
- package/dist/anim/locomotionGraph.d.ts +35 -0
- package/dist/anim/locomotionGraph.js +62 -0
- package/dist/assets/spriteAtlas.d.ts +21 -0
- package/dist/assets/spriteAtlas.js +103 -0
- package/dist/audio/audioFalloff.d.ts +12 -0
- package/dist/audio/doppler.d.ts +21 -0
- package/dist/audio/doppler.js +32 -0
- package/dist/audio/engineLayers.d.ts +83 -0
- package/dist/audio/engineLayers.js +115 -0
- package/dist/combat/abilityKit.d.ts +1 -0
- package/dist/combat/abilityKit.js +1 -0
- package/dist/combat/death.d.ts +7 -0
- package/dist/combat/shotOrigin.d.ts +6 -0
- package/dist/combat/shotOrigin.js +6 -0
- package/dist/combat/weaponFeedback.d.ts +36 -0
- package/dist/combat/weaponFeedback.js +42 -0
- package/dist/combat/weaponHandling.d.ts +161 -0
- package/dist/combat/weaponHandling.js +202 -0
- package/dist/combat/weaponPresentation.d.ts +115 -0
- package/dist/combat/weaponPresentation.js +96 -0
- package/dist/devtools/warnOnce.d.ts +8 -0
- package/dist/devtools/warnOnce.js +18 -0
- package/dist/economy/currency.d.ts +16 -2
- package/dist/economy/currency.js +55 -14
- package/dist/economy/wallet.d.ts +5 -4
- package/dist/economy/wallet.js +8 -4
- package/dist/editor/commandApply.js +1 -0
- package/dist/editor/commands.d.ts +4 -1
- package/dist/editor/document.d.ts +2 -1
- package/dist/editor/document.js +92 -1
- package/dist/editor/environment.d.ts +3 -0
- package/dist/editor/environment.js +24 -0
- package/dist/editor/index.d.ts +4 -2
- package/dist/editor/index.js +1 -1
- package/dist/editor/types.d.ts +20 -0
- package/dist/faction/reputation.d.ts +6 -0
- package/dist/faction/reputation.js +11 -0
- package/dist/game/cameraConfig.d.ts +59 -1
- package/dist/game/chat.d.ts +22 -1
- package/dist/game/chat.js +48 -19
- package/dist/game/controlGate.d.ts +6 -0
- package/dist/game/controlGate.js +30 -1
- package/dist/game/defineGame.d.ts +10 -1
- package/dist/game/events.d.ts +14 -1
- package/dist/game/lootTable.d.ts +4 -0
- package/dist/game/lootTable.js +16 -0
- package/dist/game/pixelPerfect.d.ts +25 -0
- package/dist/game/pixelPerfect.js +29 -0
- package/dist/game/playableGame.d.ts +167 -6
- package/dist/game/systemRuntime.js +6 -1
- package/dist/game/toasts.d.ts +8 -0
- package/dist/game/toasts.js +7 -0
- package/dist/game/vfxInstance.d.ts +9 -0
- package/dist/game/vfxInstance.js +12 -1
- package/dist/game/viewports.d.ts +43 -0
- package/dist/game/viewports.js +46 -0
- package/dist/game/worldItem.d.ts +5 -1
- package/dist/game/worldItem.js +0 -1
- package/dist/input/actionBindings.d.ts +17 -2
- package/dist/input/actionBindings.js +24 -11
- package/dist/input/actionContexts.d.ts +45 -0
- package/dist/input/actionContexts.js +113 -0
- package/dist/input/axisInput.d.ts +4 -0
- package/dist/input/axisInput.js +4 -0
- package/dist/input/axisShaper.d.ts +73 -0
- package/dist/input/axisShaper.js +105 -0
- package/dist/input/gamepadModel.d.ts +79 -0
- package/dist/input/gamepadModel.js +108 -0
- package/dist/input/haptics.d.ts +50 -0
- package/dist/input/haptics.js +74 -0
- package/dist/input/inputBuffer.d.ts +40 -0
- package/dist/input/inputBuffer.js +59 -0
- package/dist/input/lookChannel.d.ts +10 -0
- package/dist/input/lookChannel.js +6 -0
- package/dist/input/pointer.d.ts +2 -0
- package/dist/input/pointer.js +4 -0
- package/dist/item/affix.d.ts +6 -0
- package/dist/item/affix.js +6 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +196 -1
- package/dist/movement/characterController.d.ts +76 -0
- package/dist/movement/characterController.js +216 -0
- package/dist/movement/freeFlight.d.ts +119 -0
- package/dist/movement/freeFlight.js +294 -0
- package/dist/movement/glideModel.d.ts +3 -0
- package/dist/movement/glideModel.js +6 -0
- package/dist/movement/grappleSwing.d.ts +2 -0
- package/dist/movement/grappleSwing.js +5 -1
- package/dist/movement/movementModel.d.ts +39 -0
- package/dist/movement/movementModel.js +62 -19
- package/dist/movement/movementProbe.d.ts +51 -0
- package/dist/movement/movementProbe.js +119 -0
- package/dist/movement/playerMovement.d.ts +30 -3
- package/dist/movement/playerMovement.js +304 -7
- package/dist/movement/serverStep.d.ts +5 -0
- package/dist/movement/serverStep.js +6 -0
- package/dist/movement/solidObstacles.d.ts +39 -8
- package/dist/movement/solidObstacles.js +71 -6
- package/dist/movement/voxelController.js +7 -7
- package/dist/multiplayer/poseSyncGate.d.ts +3 -1
- package/dist/multiplayer/poseSyncGate.js +9 -1
- package/dist/multiplayer/presenceContract.d.ts +6 -0
- package/dist/multiplayer/presenceModel.d.ts +2 -0
- package/dist/multiplayer/presenceModel.js +11 -0
- package/dist/nav/navFromEnvironment.d.ts +9 -3
- package/dist/nav/navFromEnvironment.js +18 -12
- package/dist/nav/navMesh.d.ts +74 -0
- package/dist/nav/navMesh.js +570 -0
- package/dist/physics/aircraftDynamics.d.ts +390 -0
- package/dist/physics/aircraftDynamics.js +704 -0
- package/dist/physics/boatDynamics.d.ts +116 -0
- package/dist/physics/boatDynamics.js +160 -0
- package/dist/physics/drivableVehicle.d.ts +22 -8
- package/dist/physics/drivableVehicle.js +4 -2
- package/dist/physics/flightDynamics.d.ts +29 -4
- package/dist/physics/flightDynamics.js +28 -5
- package/dist/physics/handlingProbe.d.ts +249 -0
- package/dist/physics/handlingProbe.js +606 -0
- package/dist/physics/kinematicVehicle.d.ts +37 -2
- package/dist/physics/kinematicVehicle.js +15 -0
- package/dist/physics/physicsBackend.d.ts +203 -0
- package/dist/physics/physicsBackend.js +49 -0
- package/dist/physics/physicsBackendConformance.d.ts +27 -0
- package/dist/physics/physicsBackendConformance.js +151 -0
- package/dist/physics/physicsWorldBackend.d.ts +45 -0
- package/dist/physics/physicsWorldBackend.js +518 -0
- package/dist/physics/vehicleBackendLink.d.ts +49 -0
- package/dist/physics/vehicleBackendLink.js +102 -0
- package/dist/physics/vehicleDynamics.d.ts +374 -0
- package/dist/physics/vehicleDynamics.js +737 -0
- package/dist/physics/worldColliders.d.ts +13 -0
- package/dist/physics/worldColliders.js +128 -0
- package/dist/puzzle/cellGrid.d.ts +15 -9
- package/dist/puzzle/cellGrid.js +13 -9
- package/dist/random/rng.d.ts +12 -1
- package/dist/random/rng.js +20 -3
- package/dist/render/environment.d.ts +23 -0
- package/dist/render/environment.js +1 -0
- package/dist/render/lookPreset.d.ts +19 -6
- package/dist/render/lookPreset.js +56 -4
- package/dist/render/postProcessing.d.ts +40 -1
- package/dist/render/postProcessing.js +1 -1
- package/dist/render/sprite2d.d.ts +38 -0
- package/dist/render/sprite2d.js +40 -0
- package/dist/runtime/adapter.d.ts +20 -1
- package/dist/runtime/adapter.js +8 -1
- package/dist/runtime/cameraDirector.d.ts +17 -3
- package/dist/runtime/cameraDirector.js +25 -0
- package/dist/runtime/commandInput.d.ts +52 -0
- package/dist/runtime/commandInput.js +71 -0
- package/dist/runtime/commandRunner.d.ts +39 -7
- package/dist/runtime/commandRunner.js +35 -5
- package/dist/runtime/context/combat.d.ts +1 -0
- package/dist/runtime/context/combat.js +2 -1
- package/dist/runtime/context/deathLoot.d.ts +2 -0
- package/dist/runtime/context/deathLoot.js +1 -0
- package/dist/runtime/gameContext.js +18 -1
- package/dist/runtime/gameContextTypes.d.ts +33 -7
- package/dist/runtime/gameRuntime.d.ts +23 -5
- package/dist/runtime/gameRuntime.js +21 -4
- package/dist/runtime/headlessRunner.d.ts +10 -0
- package/dist/runtime/headlessRunner.js +26 -8
- package/dist/runtime/hostPolicy.d.ts +3 -2
- package/dist/runtime/hostPolicy.js +8 -10
- package/dist/runtime/hostedGameRunner.js +34 -6
- package/dist/runtime/hostedWorldSession.d.ts +12 -16
- package/dist/runtime/hostedWorldSession.js +29 -6
- package/dist/runtime/hostedWorldStore.d.ts +20 -0
- package/dist/runtime/hostedWorldStore.js +1 -0
- package/dist/runtime/inputRecorder.d.ts +30 -0
- package/dist/runtime/inputRecorder.js +59 -0
- package/dist/runtime/inputSnapshot.d.ts +14 -0
- package/dist/runtime/inputSnapshot.js +11 -0
- package/dist/runtime/localPlayers.d.ts +73 -0
- package/dist/runtime/localPlayers.js +119 -0
- package/dist/runtime/poseInterpolation.d.ts +36 -0
- package/dist/runtime/poseInterpolation.js +91 -0
- package/dist/runtime/prediction.d.ts +45 -0
- package/dist/runtime/prediction.js +62 -0
- package/dist/runtime/simContext.d.ts +45 -0
- package/dist/runtime/simContext.js +65 -0
- package/dist/runtime/simLoop.d.ts +52 -0
- package/dist/runtime/simLoop.js +72 -0
- package/dist/runtime/simSnapshot.d.ts +32 -0
- package/dist/runtime/simSnapshot.js +60 -0
- package/dist/runtime/snapshot.d.ts +8 -0
- package/dist/runtime/snapshotBuffer.d.ts +33 -0
- package/dist/runtime/snapshotBuffer.js +58 -0
- package/dist/runtime/transport.d.ts +41 -2
- package/dist/runtime/transport.js +7 -1
- package/dist/runtime/worldChunks.d.ts +2 -0
- package/dist/runtime/worldChunks.js +14 -0
- package/dist/runtime/worldProjection.d.ts +9 -0
- package/dist/runtime/worldProjection.js +17 -1
- package/dist/runtime/worldSnapshot.d.ts +6 -0
- package/dist/runtime/worldSnapshot.js +3 -0
- package/dist/scene/behaviorRuntime.d.ts +29 -1
- package/dist/scene/behaviorRuntime.js +71 -4
- package/dist/scene/behaviors.d.ts +12 -1
- package/dist/scene/builtinSceneKinds.js +10 -0
- package/dist/scene/sceneKinds.d.ts +9 -0
- package/dist/scene/vehicleSeat.d.ts +5 -1
- package/dist/scene/vehicleSeat.js +5 -1
- package/dist/sensor/concealment.d.ts +6 -0
- package/dist/sensor/concealment.js +8 -0
- package/dist/sensor/freezeMonitor.d.ts +6 -0
- package/dist/sensor/freezeMonitor.js +8 -0
- package/dist/sensor/perception.d.ts +70 -0
- package/dist/sensor/perception.js +189 -0
- package/dist/sensor/recordingBuffer.d.ts +3 -0
- package/dist/sensor/recordingBuffer.js +8 -0
- package/dist/session/roundState.d.ts +4 -0
- package/dist/session/roundState.js +11 -0
- package/dist/settings/frameRateLimit.d.ts +16 -0
- package/dist/settings/frameRateLimit.js +37 -0
- package/dist/settings/graphicsProfile.d.ts +21 -0
- package/dist/settings/graphicsProfile.js +48 -0
- package/dist/settings/graphicsSettings.d.ts +40 -0
- package/dist/settings/graphicsSettings.js +81 -0
- package/dist/settings/settingsModel.d.ts +9 -1
- package/dist/settings/settingsModel.js +10 -0
- package/dist/stats/eventMeter.d.ts +1 -1
- package/dist/stats/eventMeter.js +1 -1
- package/dist/time/accrueSince.d.ts +10 -0
- package/dist/time/accrueSince.js +9 -0
- package/dist/time/rateWindow.d.ts +16 -0
- package/dist/time/rateWindow.js +14 -0
- package/dist/time/serverTick.d.ts +21 -3
- package/dist/time/serverTick.js +14 -13
- package/dist/vfx/feedbackMixer.d.ts +61 -0
- package/dist/vfx/feedbackMixer.js +106 -0
- package/dist/vfx/particleDirector.d.ts +68 -0
- package/dist/vfx/particleDirector.js +81 -0
- package/dist/visibility/simulationCulling.d.ts +8 -1
- package/dist/visibility/simulationCulling.js +7 -0
- package/dist/visibility/spatialIndex.d.ts +21 -0
- package/dist/visibility/spatialIndex.js +16 -0
- package/dist/world/authoredSolids.d.ts +46 -0
- package/dist/world/authoredSolids.js +75 -0
- package/dist/world/buildingGenerator.js +2 -2
- package/dist/world/buildingKit.d.ts +3 -1
- package/dist/world/buildings.d.ts +46 -2
- package/dist/world/buildings.js +53 -3
- package/dist/world/cityContent.js +103 -25
- package/dist/world/cityKind.d.ts +139 -0
- package/dist/world/cityKind.js +367 -16
- package/dist/world/features.d.ts +56 -3
- package/dist/world/features.js +13 -2
- package/dist/world/footprintGrid.d.ts +7 -0
- package/dist/world/footprintGrid.js +16 -0
- package/dist/world/interiors.d.ts +1 -0
- package/dist/world/interiors.js +5 -3
- package/dist/world/lod.d.ts +6 -0
- package/dist/world/lod.js +8 -0
- package/dist/world/placement.d.ts +7 -0
- package/dist/world/placement.js +2 -0
- package/dist/world/placementController.d.ts +1 -1
- package/dist/world/placementController.js +7 -0
- package/dist/world/raceCircuit.d.ts +168 -0
- package/dist/world/raceCircuit.js +797 -0
- package/dist/world/terraform.d.ts +8 -0
- package/dist/world/terraform.js +7 -0
- package/dist/world/terrain.d.ts +5 -1
- package/dist/world/terrain.js +5 -0
- package/dist/world/territory.d.ts +97 -0
- package/dist/world/territory.js +182 -0
- package/dist/world/walls.d.ts +7 -0
- package/dist/world/walls.js +7 -0
- package/dist/world/worldSolids.d.ts +84 -0
- package/dist/world/worldSolids.js +240 -0
- package/dist/world.d.ts +5 -3
- package/dist/world.js +4 -2
- package/package.json +1 -1
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/game-design/SKILL.md +11 -1
- package/skills/jgengine/SKILL.md +9 -5
- package/skills/jgengine/api.md +205 -101
- package/skills/jgengine/capabilities.md +56 -0
- package/skills/jgengine/recipes/minimal-game.md +3 -0
- package/skills/jgengine-combat/SKILL.md +5 -0
- package/skills/jgengine-combat/api.md +138 -103
- package/skills/jgengine-combat/capabilities.md +29 -1
- package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
- package/skills/jgengine-gameplay/SKILL.md +10 -0
- package/skills/jgengine-gameplay/api.md +501 -453
- package/skills/jgengine-gameplay/capabilities.md +36 -0
- package/skills/jgengine-gameplay/reference-systems.md +4 -0
- package/skills/jgengine-world/SKILL.md +21 -3
- package/skills/jgengine-world/api.md +1172 -625
- package/skills/jgengine-world/capabilities.md +229 -3
- package/skills/jgengine-world/recipes/character-animation.md +39 -0
- package/skills/jgengine-world/recipes/controls.md +44 -0
- package/skills/jgengine-world/recipes/flight-feel.md +76 -0
- package/skills/jgengine-world/recipes/npc-senses.md +43 -0
- package/skills/jgengine-world/recipes/vehicle-feel.md +85 -0
- package/skills/jgengine-world/reference.md +31 -2
- package/skills/jgengine-world/visibility.md +112 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { resolveStructureBuildings } from "./environmentSummary.js";
|
|
2
|
+
const DEFAULT_CELL_SIZE = 16;
|
|
3
|
+
/** A solid covering more cells than this goes on an always-checked list instead of flooding the grid. */
|
|
4
|
+
const MAX_CELLS_PER_SOLID = 256;
|
|
5
|
+
const CELL_OFFSET = 32768;
|
|
6
|
+
/**
|
|
7
|
+
* Yaw-expanded world AABB of an oriented solid box.
|
|
8
|
+
* @capability world-solid-bounds world AABB and nav footprint of a world solid
|
|
9
|
+
*/
|
|
10
|
+
export function worldSolidBounds(solid) {
|
|
11
|
+
const yaw = solid.rotationY ?? 0;
|
|
12
|
+
const cos = Math.abs(Math.cos(yaw));
|
|
13
|
+
const sin = Math.abs(Math.sin(yaw));
|
|
14
|
+
const [hx, hy, hz] = solid.halfExtents;
|
|
15
|
+
const ex = hx * cos + hz * sin;
|
|
16
|
+
const ez = hx * sin + hz * cos;
|
|
17
|
+
const [cx, cy, cz] = solid.center;
|
|
18
|
+
return { min: [cx - ex, cy - hy, cz - ez], max: [cx + ex, cy + hy, cz + ez] };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* XZ footprint of a solid's world AABB, for 2D consumers such as nav grids.
|
|
22
|
+
* @capability world-solid-bounds world AABB and nav footprint of a world solid
|
|
23
|
+
*/
|
|
24
|
+
export function worldSolidFootprint(solid) {
|
|
25
|
+
const { min, max } = worldSolidBounds(solid);
|
|
26
|
+
return { minX: min[0], minZ: min[2], maxX: max[0], maxZ: max[2] };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A store of static world solids in named layers.
|
|
30
|
+
* @capability world-solids collision for generated and authored world geometry (buildings, city lots, walls)
|
|
31
|
+
*/
|
|
32
|
+
export function createWorldSolids(options = {}) {
|
|
33
|
+
const cellSize = options.cellSize ?? DEFAULT_CELL_SIZE;
|
|
34
|
+
const layerMap = new Map();
|
|
35
|
+
const grid = new Map();
|
|
36
|
+
const oversize = [];
|
|
37
|
+
const listeners = new Set();
|
|
38
|
+
let stamp = 0;
|
|
39
|
+
let total = 0;
|
|
40
|
+
let revision = 0;
|
|
41
|
+
let batchDepth = 0;
|
|
42
|
+
let pending = false;
|
|
43
|
+
const cellOf = (value) => Math.floor(value / cellSize);
|
|
44
|
+
const keyOf = (ix, iz) => (ix + CELL_OFFSET) * 65536 + (iz + CELL_OFFSET);
|
|
45
|
+
function index(entry) {
|
|
46
|
+
const x0 = cellOf(entry.minX);
|
|
47
|
+
const x1 = cellOf(entry.maxX);
|
|
48
|
+
const z0 = cellOf(entry.minZ);
|
|
49
|
+
const z1 = cellOf(entry.maxZ);
|
|
50
|
+
if ((x1 - x0 + 1) * (z1 - z0 + 1) > MAX_CELLS_PER_SOLID) {
|
|
51
|
+
oversize.push(entry);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (let ix = x0; ix <= x1; ix += 1) {
|
|
55
|
+
for (let iz = z0; iz <= z1; iz += 1) {
|
|
56
|
+
const key = keyOf(ix, iz);
|
|
57
|
+
const bucket = grid.get(key);
|
|
58
|
+
if (bucket === undefined)
|
|
59
|
+
grid.set(key, [entry]);
|
|
60
|
+
else
|
|
61
|
+
bucket.push(entry);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function rebuildIndex() {
|
|
66
|
+
grid.clear();
|
|
67
|
+
oversize.length = 0;
|
|
68
|
+
total = 0;
|
|
69
|
+
for (const entries of layerMap.values()) {
|
|
70
|
+
for (const entry of entries)
|
|
71
|
+
index(entry);
|
|
72
|
+
total += entries.length;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function changed() {
|
|
76
|
+
if (batchDepth > 0) {
|
|
77
|
+
pending = true;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
pending = false;
|
|
81
|
+
rebuildIndex();
|
|
82
|
+
revision += 1;
|
|
83
|
+
for (const listener of listeners)
|
|
84
|
+
listener();
|
|
85
|
+
}
|
|
86
|
+
function indexed(solid) {
|
|
87
|
+
const { min, max } = worldSolidBounds(solid);
|
|
88
|
+
return { solid, minX: min[0], minY: min[1], minZ: min[2], maxX: max[0], maxY: max[1], maxZ: max[2], stamp: 0 };
|
|
89
|
+
}
|
|
90
|
+
function overlaps(entry, min, max) {
|
|
91
|
+
return (entry.maxX >= min[0] &&
|
|
92
|
+
entry.minX <= max[0] &&
|
|
93
|
+
entry.maxY >= min[1] &&
|
|
94
|
+
entry.minY <= max[1] &&
|
|
95
|
+
entry.maxZ >= min[2] &&
|
|
96
|
+
entry.minZ <= max[2]);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
set(layer, solids) {
|
|
100
|
+
if (solids.length === 0) {
|
|
101
|
+
if (!layerMap.delete(layer))
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
layerMap.set(layer, solids.map(indexed));
|
|
106
|
+
}
|
|
107
|
+
changed();
|
|
108
|
+
},
|
|
109
|
+
remove(layer) {
|
|
110
|
+
if (layerMap.delete(layer))
|
|
111
|
+
changed();
|
|
112
|
+
},
|
|
113
|
+
batch(apply) {
|
|
114
|
+
batchDepth += 1;
|
|
115
|
+
try {
|
|
116
|
+
apply();
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
batchDepth -= 1;
|
|
120
|
+
}
|
|
121
|
+
if (batchDepth === 0 && pending)
|
|
122
|
+
changed();
|
|
123
|
+
},
|
|
124
|
+
layer: (layer) => layerMap.get(layer)?.map((entry) => entry.solid) ?? [],
|
|
125
|
+
layers: () => [...layerMap.keys()],
|
|
126
|
+
inBox(min, max) {
|
|
127
|
+
stamp += 1;
|
|
128
|
+
const out = [];
|
|
129
|
+
if (total === 0)
|
|
130
|
+
return out;
|
|
131
|
+
const x0 = cellOf(min[0]);
|
|
132
|
+
const x1 = cellOf(max[0]);
|
|
133
|
+
const z0 = cellOf(min[2]);
|
|
134
|
+
const z1 = cellOf(max[2]);
|
|
135
|
+
if ((x1 - x0 + 1) * (z1 - z0 + 1) > grid.size) {
|
|
136
|
+
for (const entries of layerMap.values()) {
|
|
137
|
+
for (const entry of entries)
|
|
138
|
+
if (overlaps(entry, min, max))
|
|
139
|
+
out.push(entry.solid);
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
for (let ix = x0; ix <= x1; ix += 1) {
|
|
144
|
+
for (let iz = z0; iz <= z1; iz += 1) {
|
|
145
|
+
const bucket = grid.get(keyOf(ix, iz));
|
|
146
|
+
if (bucket === undefined)
|
|
147
|
+
continue;
|
|
148
|
+
for (const entry of bucket) {
|
|
149
|
+
if (entry.stamp === stamp)
|
|
150
|
+
continue;
|
|
151
|
+
entry.stamp = stamp;
|
|
152
|
+
if (overlaps(entry, min, max))
|
|
153
|
+
out.push(entry.solid);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const entry of oversize)
|
|
158
|
+
if (overlaps(entry, min, max))
|
|
159
|
+
out.push(entry.solid);
|
|
160
|
+
return out;
|
|
161
|
+
},
|
|
162
|
+
all: () => [...layerMap.values()].flatMap((entries) => entries.map((entry) => entry.solid)),
|
|
163
|
+
count: () => total,
|
|
164
|
+
version: () => revision,
|
|
165
|
+
subscribe(listener) {
|
|
166
|
+
listeners.add(listener);
|
|
167
|
+
return () => {
|
|
168
|
+
listeners.delete(listener);
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
snapshot() {
|
|
172
|
+
const layers = {};
|
|
173
|
+
for (const [layer, entries] of layerMap)
|
|
174
|
+
layers[layer] = entries.map((entry) => entry.solid);
|
|
175
|
+
return { layers };
|
|
176
|
+
},
|
|
177
|
+
restore(state) {
|
|
178
|
+
layerMap.clear();
|
|
179
|
+
for (const [layer, solids] of Object.entries(state.layers)) {
|
|
180
|
+
if (solids.length > 0)
|
|
181
|
+
layerMap.set(layer, solids.map(indexed));
|
|
182
|
+
}
|
|
183
|
+
changed();
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* One solid per generated building: its `bounds` footprint turned by `rotationY` about `center`,
|
|
189
|
+
* from the ground under its center up through its floors. `groundHeight` defaults to flat `0`.
|
|
190
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
191
|
+
*/
|
|
192
|
+
export function buildingSolids(buildings, groundHeight = () => 0) {
|
|
193
|
+
return buildings.map((building) => {
|
|
194
|
+
const { bounds, center } = building;
|
|
195
|
+
const yaw = building.rotationY ?? 0;
|
|
196
|
+
const localX = (bounds.minX + bounds.maxX) / 2 - center[0];
|
|
197
|
+
const localZ = (bounds.minZ + bounds.maxZ) / 2 - center[1];
|
|
198
|
+
const cos = Math.cos(yaw);
|
|
199
|
+
const sin = Math.sin(yaw);
|
|
200
|
+
const base = groundHeight(center[0], center[1]);
|
|
201
|
+
const halfHeight = (building.floors * building.floorHeight) / 2;
|
|
202
|
+
return {
|
|
203
|
+
center: [center[0] + localX * cos + localZ * sin, base + halfHeight, center[1] - localX * sin + localZ * cos],
|
|
204
|
+
halfExtents: [(bounds.maxX - bounds.minX) / 2, halfHeight, (bounds.maxZ - bounds.minZ) / 2],
|
|
205
|
+
...(yaw === 0 ? {} : { rotationY: yaw }),
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Solids for every `structures` descriptor on an environment feature, skipping any marked `solid: false`.
|
|
211
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
212
|
+
*/
|
|
213
|
+
export function structureSolids(world, groundHeight) {
|
|
214
|
+
const solids = [];
|
|
215
|
+
for (const descriptor of world.structures ?? []) {
|
|
216
|
+
if (descriptor.solid === false)
|
|
217
|
+
continue;
|
|
218
|
+
solids.push(...buildingSolids(resolveStructureBuildings(descriptor), groundHeight));
|
|
219
|
+
}
|
|
220
|
+
return solids;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* One oriented solid per wall segment (see `wallSegments` in `world/walls`).
|
|
224
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
225
|
+
*/
|
|
226
|
+
export function wallSolids(segments, options) {
|
|
227
|
+
return segments
|
|
228
|
+
.filter((segment) => segment.length > 0)
|
|
229
|
+
.map((segment) => {
|
|
230
|
+
const mid = [(segment.from[0] + segment.to[0]) / 2, (segment.from[1] + segment.to[1]) / 2];
|
|
231
|
+
const base = options.groundHeight?.(mid[0], mid[1]) ?? 0;
|
|
232
|
+
// Local x runs along the segment: rotationY maps local +x to (cos, -sin) in XZ.
|
|
233
|
+
const yaw = -Math.atan2(segment.to[1] - segment.from[1], segment.to[0] - segment.from[0]);
|
|
234
|
+
return {
|
|
235
|
+
center: [mid[0], base + options.height / 2, mid[1]],
|
|
236
|
+
halfExtents: [segment.length / 2, options.height / 2, options.thickness / 2],
|
|
237
|
+
rotationY: yaw,
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
}
|
package/dist/world.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { evaluateQteSequence, pendingQteStep, type QteStep } from "./interaction
|
|
|
21
21
|
export { evaluateSkillCheck, skillCheckZoneAt, type SkillCheckConfig, type SkillCheckResult, } from "./interaction/skillCheck.js";
|
|
22
22
|
export { resolveLocalAvoidance, type AvoidanceAgent, type LocalAvoidanceOptions } from "./movement/avoidance.js";
|
|
23
23
|
export { assignFormationSlots, boxFormation, circleFormation, facingYaw, lineFormation, placeFormation, wedgeFormation, type BoxFormationOptions, type CircleFormationOptions, type FormationSlotGenerator, type LineFormationOptions, type SlotAssignmentOptions, type WedgeFormationOptions, } from "./movement/formation.js";
|
|
24
|
+
export { CREATIVE_FLIGHT_TUNING, HOVER_FLIGHT_TUNING, NOCLIP_FLIGHT_TUNING, SPECTATOR_FLIGHT_TUNING, advanceFreeFlight, createFreeFlightController, createFreeFlightState, resolveFlightStep, resolveFreeFlightIntent, resolveFreeFlightIntentFromInput, type FreeFlightBindings, type FreeFlightController, type FreeFlightIntent, type FreeFlightMode, type FreeFlightState, type FreeFlightStep, type FreeFlightTuning, } from "./movement/freeFlight.js";
|
|
24
25
|
export { createGlideModel } from "./movement/glideModel.js";
|
|
25
26
|
export { createGrappleSwing } from "./movement/grappleSwing.js";
|
|
26
27
|
export { createLeaderTrail } from "./movement/leaderTrail.js";
|
|
@@ -31,6 +32,7 @@ export { steerYaw } from "./movement/steering.js";
|
|
|
31
32
|
export { constrainToNavGrid } from "./nav/navConstrain.js";
|
|
32
33
|
export { populateNavGridFromEnvironment } from "./nav/navFromEnvironment.js";
|
|
33
34
|
export { createNavGrid, findPath, slopeStepCost, type NavGrid, type NavPoint } from "./nav/navGrid.js";
|
|
35
|
+
export { buildNavAdjacency, closestPoint, createNavMeshQuery, raycastNav, type NavMeshAdjacency, type NavMeshData, type NavMeshLink, type NavMeshPath, type NavMeshQuery, type NavMeshQueryOptions, type NavMeshQuerySnapshot, } from "./nav/navMesh.js";
|
|
34
36
|
export { advancePathFollow, createPathFollow, pathFollowProgress, pathFollowSeek, pathFromNav, pathLength, type PathFollowConfig, type PathFollowProgress, type PathFollowState, type PathProgress, type Waypoint, } from "./nav/pathFollow.js";
|
|
35
37
|
export { defineAttackMoveOrder, defineHoldOrder, defineMoveOrder, definePatrolOrder, defineStopOrder, defineTargetedOrder, type AttackMoveOrderPayload, type EmptyOrderPayload, type EngagementKindConfig, type EngagementOrderState, type MoveOrderPayload, type OrderKindConfig, type OrderMoveResult, type OrderMover, type OrderTargeting, type PatrolOrderPayload, type PatrolOrderState, type TargetedOrderPayload, } from "./orders/orderKinds.js";
|
|
36
38
|
export { createOrderQueue, createOrderRegistry, type Order, type OrderCancelReason, type OrderEvent, type OrderIssueResult, type OrderKind, type OrderOutcome, type OrderPhase, type OrderProgress, type OrderQueue, type OrderQueueOptions, type OrderQueuePolicy, type OrderQueueState, type OrderRegistry, type OrderRejection, type OrderRequest, type OrderStartResult, type OrderTickReport, type OrderVec3, } from "./orders/orderQueue.js";
|
|
@@ -39,7 +41,7 @@ export { createBuoyantBody } from "./physics/buoyancy.js";
|
|
|
39
41
|
export { Carryable, carrySpeedMultiplier } from "./physics/carryable.js";
|
|
40
42
|
export { createDamageModel } from "./physics/damageZones.js";
|
|
41
43
|
export { tickDrivableVehicle } from "./physics/drivableVehicle.js";
|
|
42
|
-
export { createAircraftDynamics, type AircraftDynamics, type AircraftKind, type AircraftOptions, type AircraftStep, type AircraftTuning, type FlightControlInput, type FlightControlRates, type FlightVector, } from "./physics/flightDynamics.js";
|
|
44
|
+
export { createAircraftDynamics, type AircraftAxis, type AircraftDynamics, type AircraftKind, type AircraftOptions, type AircraftStep, type AircraftTuning, type FlightControlInput, type FlightControlRates, type FlightVector, } from "./physics/flightDynamics.js";
|
|
43
45
|
export { ForceVolume, PlatformCarry } from "./physics/forceVolume.js";
|
|
44
46
|
export { combineGravity, pointGravity, uniformGravity, type GravityField, type GravityVector, type PointGravityOptions, } from "./physics/gravityField.js";
|
|
45
47
|
export { createKinematicVehicle, type KinematicChassisTuning, type KinematicDynamicsTuning, type KinematicPowertrainTuning, type KinematicSteeringTuning, type KinematicVehicle, type KinematicVehicleStep, type KinematicVehicleTuning, } from "./physics/kinematicVehicle.js";
|
|
@@ -56,8 +58,8 @@ export { partsBounds, registerAssetGenerator, type GeneratedAsset, type Generate
|
|
|
56
58
|
export { applyRotationPolicy, headingToRotationY, normalizeDegrees, parseAssetSpace, parseRotationPolicy, resolveAnchorOffset, resolveFacingRotationY, rotatedFootprint, rotationYToHeading, snapHeading, toEngineUnits, validateAssetSpace, type AssetAnchor, type AssetSpace, type AssetSpaceIssue, type PlacementRotationPolicy, } from "./scene/assetSpace.js";
|
|
57
59
|
export { collectAuthoredTriggers, createAuthoredTriggerRuntime, getTriggerAction, listTriggerActions, pointInVolume, registerTriggerAction, type AuthoredTrigger, type AuthoredTriggerRuntime, type TriggerActionDefinition, type TriggerDispatchEvent, type TriggerEvent, type TriggerHandlers, type TriggerSourceKind, } from "./scene/authoredTriggers.js";
|
|
58
60
|
export { selectAutoTarget, type AutoTargetPolicy } from "./scene/autoTarget.js";
|
|
59
|
-
export { advanceBehaviors, behaviorControl, type BehaviorControl, type BehaviorInspection, type BehaviorResumePolicy, type BehaviorSnapshot, type BehaviorStatus, } from "./scene/behaviorRuntime.js";
|
|
60
|
-
export { patrol, player, talkable, wander, type BehaviorDescriptor } from "./scene/behaviors.js";
|
|
61
|
+
export { advanceBehaviors, behaviorControl, registerBehaviorActions, type BehaviorAction, type BehaviorActionContext, type BehaviorActionOptions, type BehaviorControl, type BehaviorInspection, type BehaviorResumePolicy, type BehaviorSnapshot, type BehaviorStatus, } from "./scene/behaviorRuntime.js";
|
|
62
|
+
export { patrol, player, talkable, wander, type BehaviorDescriptor, type DecisionGraphBehavior, } from "./scene/behaviors.js";
|
|
61
63
|
export { createBodyBind } from "./scene/bodyBind.js";
|
|
62
64
|
export { type ColliderPurpose, type EntityColliderSet, type ResolvedCollider } from "./scene/colliders.js";
|
|
63
65
|
export { type StatCatalog, type StatValue } from "./scene/entityStats.js";
|
package/dist/world.js
CHANGED
|
@@ -21,6 +21,7 @@ export { evaluateQteSequence, pendingQteStep } from "./interaction/qte.js";
|
|
|
21
21
|
export { evaluateSkillCheck, skillCheckZoneAt, } from "./interaction/skillCheck.js";
|
|
22
22
|
export { resolveLocalAvoidance } from "./movement/avoidance.js";
|
|
23
23
|
export { assignFormationSlots, boxFormation, circleFormation, facingYaw, lineFormation, placeFormation, wedgeFormation, } from "./movement/formation.js";
|
|
24
|
+
export { CREATIVE_FLIGHT_TUNING, HOVER_FLIGHT_TUNING, NOCLIP_FLIGHT_TUNING, SPECTATOR_FLIGHT_TUNING, advanceFreeFlight, createFreeFlightController, createFreeFlightState, resolveFlightStep, resolveFreeFlightIntent, resolveFreeFlightIntentFromInput, } from "./movement/freeFlight.js";
|
|
24
25
|
export { createGlideModel } from "./movement/glideModel.js";
|
|
25
26
|
export { createGrappleSwing } from "./movement/grappleSwing.js";
|
|
26
27
|
export { createLeaderTrail } from "./movement/leaderTrail.js";
|
|
@@ -31,6 +32,7 @@ export { steerYaw } from "./movement/steering.js";
|
|
|
31
32
|
export { constrainToNavGrid } from "./nav/navConstrain.js";
|
|
32
33
|
export { populateNavGridFromEnvironment } from "./nav/navFromEnvironment.js";
|
|
33
34
|
export { createNavGrid, findPath, slopeStepCost } from "./nav/navGrid.js";
|
|
35
|
+
export { buildNavAdjacency, closestPoint, createNavMeshQuery, raycastNav, } from "./nav/navMesh.js";
|
|
34
36
|
export { advancePathFollow, createPathFollow, pathFollowProgress, pathFollowSeek, pathFromNav, pathLength, } from "./nav/pathFollow.js";
|
|
35
37
|
export { defineAttackMoveOrder, defineHoldOrder, defineMoveOrder, definePatrolOrder, defineStopOrder, defineTargetedOrder, } from "./orders/orderKinds.js";
|
|
36
38
|
export { createOrderQueue, createOrderRegistry, } from "./orders/orderQueue.js";
|
|
@@ -56,8 +58,8 @@ export { partsBounds, registerAssetGenerator } from "./scene/assetGenerator.js";
|
|
|
56
58
|
export { applyRotationPolicy, headingToRotationY, normalizeDegrees, parseAssetSpace, parseRotationPolicy, resolveAnchorOffset, resolveFacingRotationY, rotatedFootprint, rotationYToHeading, snapHeading, toEngineUnits, validateAssetSpace, } from "./scene/assetSpace.js";
|
|
57
59
|
export { collectAuthoredTriggers, createAuthoredTriggerRuntime, getTriggerAction, listTriggerActions, pointInVolume, registerTriggerAction, } from "./scene/authoredTriggers.js";
|
|
58
60
|
export { selectAutoTarget } from "./scene/autoTarget.js";
|
|
59
|
-
export { advanceBehaviors, behaviorControl, } from "./scene/behaviorRuntime.js";
|
|
60
|
-
export { patrol, player, talkable, wander } from "./scene/behaviors.js";
|
|
61
|
+
export { advanceBehaviors, behaviorControl, registerBehaviorActions, } from "./scene/behaviorRuntime.js";
|
|
62
|
+
export { patrol, player, talkable, wander, } from "./scene/behaviors.js";
|
|
61
63
|
export { createBodyBind } from "./scene/bodyBind.js";
|
|
62
64
|
export {} from "./scene/colliders.js";
|
|
63
65
|
export {} from "./scene/entityStats.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jgengine/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "jgengine core — pure-TypeScript game framework SDK (npm @jgengine/core). Entity stores, commands, combat, inventory, multiplayer seams. Zero dependencies. Not an ECS. Agent skills ship in the tarball. https://jgengine.com",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jgengine",
|
|
@@ -143,7 +143,7 @@ When sufficient, return a concise orientation: objective, progress, decisions, c
|
|
|
143
143
|
|
|
144
144
|
## JGengine notes
|
|
145
145
|
|
|
146
|
-
- Multi-session engine work
|
|
146
|
+
- Multi-session engine work spans GitHub issues and PRs — point at those; do not paste full plan bodies.
|
|
147
147
|
- Prefer `bun run agent:bootstrap --check` status, branch names, and PR links as state anchors.
|
|
148
148
|
- Local parallelism uses `.claude/worktrees/`; never invent `C:\tmp\…` Codex-shared trees.
|
|
149
|
-
-
|
|
149
|
+
- Durable process changes belong in skills, not only the handoff.
|
|
@@ -11,7 +11,7 @@ Own the intended player experience and the rules that produce it: fantasy, pilla
|
|
|
11
11
|
|
|
12
12
|
Use `level-design` for spatial realization; route implementation to `jgengine-gameplay`, `jgengine-world`, `jgengine-combat`, `jgengine-ui`, `jgengine-multiplayer` once intent is coherent.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
For a greenfield build, read [references/application-playbook.md](references/application-playbook.md) and produce its greenfield contract (promise, pillars, anti-pillars, core decision, and falsifier) before writing code. Audits may read only the playbook's audit sections. Read [references/field-guide.md](references/field-guide.md) when the task needs deeper loop, economy, progression, genre, accessibility, or research guidance.
|
|
15
15
|
|
|
16
16
|
## Choose the mode
|
|
17
17
|
|
|
@@ -28,3 +28,13 @@ Every design pass yields an observed journey, a north star (promise, pillars, an
|
|
|
28
28
|
An audit is not completion for a build/improve request. Finish when the slice is playable, a fresh player can state goal/choice/consequence, failure/recovery behave as intended, and evidence supports the pillars. Use `jgengine-verify` and `workflow` to ship.
|
|
29
29
|
|
|
30
30
|
**Required: player death is a designed, visible moment.** If the game can kill or down the player, death is part of the experience contract, not an invisible state reset. A lethal hit must resolve into an authored beat the player perceives and understands — a death or downed moment, the stakes it carries, and a legible path back into play (respawn, revive, restart) — never a silent teleport to spawn. Design what death means for this pitch (permadeath, checkpoint, bleed-out-and-revive, run reset) and treat "player dies with no acknowledged consequence" as a failure/recovery defect. `jgengine-ui` owns building the screen and respawn feedback.
|
|
31
|
+
|
|
32
|
+
## Persistent-builder checks
|
|
33
|
+
|
|
34
|
+
Before content, write a first-hour balance sheet: starting cash, time to first income, net income per hour at starting hardware and at ten times that hardware, bill cadence versus income, and the insolvency recovery path. Insolvency resets the affected player or changes their options; it never deletes the world. Express clicks and event rewards as a fraction of the designed income rate, never an unrelated flat payout.
|
|
35
|
+
|
|
36
|
+
Currency precision, elapsed-time anchoring, and reset mechanics are implemented per `jgengine-gameplay` "Persistent economies and input"; test fractional income over real tick cadences before tuning prices.
|
|
37
|
+
|
|
38
|
+
The first-60-seconds gate requires the first tutorial verb to be executable from spawn with starting inventory. Grant dependencies such as land, power, and slots or let players buy them in-context; the tutorial cannot lock the surface needed to complete itself. Placement previews show cost and affordability inline.
|
|
39
|
+
|
|
40
|
+
For a persistent shared-world builder, verify capacity and first-player onboarding before scaling the content catalog; presence, command read scopes, territory, chat, and join retry UI come from their owners in `jgengine-world`, `jgengine-ui`, and `jgengine-multiplayer`.
|
package/skills/jgengine/SKILL.md
CHANGED
|
@@ -5,10 +5,14 @@ description: Route game work to the smallest useful JGengine guidance set.
|
|
|
5
5
|
|
|
6
6
|
# JGengine intake and router
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
This skill decides what to load; it is not an engine manual. Package map, commands, layering, and license live in the JGengine README (repo-root [`README.md`](../../../README.md) in the monorepo, [jgengine.com](https://jgengine.com) from a created project); open it when you need one of those facts.
|
|
9
|
+
|
|
10
|
+
A created project installs only `jgengine`, `jgengine-editor`, `jgengine-verify`, `game-design`, and `jgengine-ui`. Run `npx jgengine skills -p --all` before loading any other domain named below. Those projects do not ship `api.md`; read exact signatures from the `.d.ts` files under `node_modules/@jgengine/<pkg>/dist/`.
|
|
9
11
|
|
|
10
12
|
## 1. Establish the target
|
|
11
13
|
|
|
14
|
+
For greenfield builds, write `src/art-direction.md` before any code.
|
|
15
|
+
|
|
12
16
|
Treat the pitch as a unique composition of needs, not a genre to fill in — never reach for a genre kit, preset, archetype, or class template ("default sports car", "default RPG", "default FPS") in the SDK or skills (see [AGENTS.md](../../../AGENTS.md)). Use `game-design` to turn the pitch into a testable player promise, verbs, loops, progression, failure, and completion scenario. Use `level-design` when play depends on authored spaces, routes, encounters, exploration, or spatial pacing. Capture only decisions that change architecture:
|
|
13
17
|
|
|
14
18
|
- player point of view and controls
|
|
@@ -18,7 +22,7 @@ Treat the pitch as a unique composition of needs, not a genre to fill in — nev
|
|
|
18
22
|
- HUD/menu states and **custom** UI art direction (compose shipped building blocks + HudTheme; no unskinned stock face)
|
|
19
23
|
- one observable completion scenario
|
|
20
24
|
|
|
21
|
-
For a new in-repo game, scaffold with `bun run new:game "<id-or-title>"` (thin script alias for `jgengine create`, auto-detects the in-repo variant). Outside this monorepo, start with `npx jgengine create`; never copy `Games/*`.
|
|
25
|
+
Pick the dimension first: `create` defaults to a 3D world (terrain, sky, player model, editor scene); a grid, card, tile, or other board game with no 3D scene takes `create --2d` (a `board` world drawn by GameUI over `@jgengine/core/puzzle/cellGrid`). For a new in-repo game, scaffold with `bun run new:game "<id-or-title>"` (thin script alias for `jgengine create`, auto-detects the in-repo variant). Outside this monorepo, start with `npx jgengine create`; never copy `Games/*`.
|
|
22
26
|
|
|
23
27
|
For an existing game asked to pick up a new engine release ("jgengine published a new version, grab it"), run `npx jgengine upgrade` in the project first: it diffs installed `@jgengine/*` versions against the latest release and prints every Migrate step and Adopt-worthy addition in between (`--json` for structured output). Bump, migrate oldest-first, then work the Adopt lists instead of reconstructing the changelog by hand.
|
|
24
28
|
|
|
@@ -44,9 +48,9 @@ World content routes editor-first: any request that adds, moves, restyles, or re
|
|
|
44
48
|
|
|
45
49
|
Within each selected domain:
|
|
46
50
|
|
|
47
|
-
0. Fastest start for a common composition: `npx jgengine recipe <name>` prints a vetted, SDK-typechecked snippet (imports + wired code)
|
|
48
|
-
1. Search
|
|
49
|
-
2. Open `api.md` only when exact signatures
|
|
51
|
+
0. Fastest start for a common composition: `npx jgengine recipe <name>` prints a vetted, SDK-typechecked snippet (imports + wired code) (`combat-loop`, `loot`, `world-drops`, `click-target`, `ability-bar`, `hitscan-weapon`, `rolled-gear`, `enter-vehicle` and more); `npx jgengine recipe` lists them. Copy that instead of reconning per-file.
|
|
52
|
+
1. Search capabilities by intent; do not read `capabilities.md` top to bottom. `npx jgengine find <intent>` searches every domain's index and every recipe at once, installed or not, and prints the primitive and its import (or the recipe to open); in the monorepo, `grep -i "<intent>" .claude/skills/*/capabilities.md` does the same. Search the moment you are tempted to hand-roll a HUD window, inventory grid, paperdoll, hotkey listener, minimap, stat bar, or character motion. A `z-index`, a `keydown` for a panel, a `<div>` inventory, or a limb bob almost certainly has a shipped drop-in (`usePanels`/`PanelHost`, `InventoryGrid`, `CharacterSheet`/`Paperdoll`, `PartMotionRig`, `EntityPreview`); games own the *skin*, not the re-derivation.
|
|
53
|
+
2. Open `api.md` (monorepo) or the package `.d.ts` only when exact signatures are needed; grep it, never read it whole.
|
|
50
54
|
3. Open the linked reference only for a deeper recipe or trap.
|
|
51
55
|
4. For how several primitives wire into a running loop, read the domain's `recipes/` — connected, genre-free walkthroughs organized by composition seam; this skill's own [recipes/minimal-game.md](recipes/minimal-game.md) is the default whole-game walkthrough. Prefer a recipe over reading a game's source; the games under `Games/*` are not templates or references, and a hybrid game is just a different composition of the same primitives.
|
|
52
56
|
|