@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
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
Reach for these before hand-rolling. Each row is *the thing you need* → *the primitive that already does it*.
|
|
6
6
|
|
|
7
|
+
## action-contexts — Swap bindings live for on-foot, driving, menu or build modes by pushing and popping layered action maps.
|
|
8
|
+
|
|
9
|
+
- `createActionContextStack` (function) · `import { createActionContextStack } from "@jgengine/core/input/actionContexts"`
|
|
10
|
+
|
|
11
|
+
## ai-decision-graph — Evaluate serializable selector, sequence, condition, action, utility, timer, and random AI decisions with interrupt hooks.
|
|
12
|
+
|
|
13
|
+
- `createDecisionGraphRuntime` (function) · `import { createDecisionGraphRuntime } from "@jgengine/core/ai/decisionGraph"`
|
|
14
|
+
|
|
7
15
|
## ai-driver — difficulty-aware chase/route driving step producing throttle/brake/steer for the vehicle sim
|
|
8
16
|
|
|
9
17
|
- `driveStep` (function) · `import { driveStep } from "@jgengine/core/ai/driver"`
|
|
@@ -16,6 +24,25 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
16
24
|
|
|
17
25
|
- `createDriverState` (function) · `import { createDriverState } from "@jgengine/core/ai/driver"`
|
|
18
26
|
|
|
27
|
+
## air-metrics — measure a vehicle's jumps and air control — apex height and time, double jump, air rotation rates
|
|
28
|
+
|
|
29
|
+
- `measureAir` (function) · `import { measureAir } from "@jgengine/core/physics/handlingProbe"`
|
|
30
|
+
|
|
31
|
+
## anim-graph — data-first animation state machine with blend trees, crossfades, layers, and clip events
|
|
32
|
+
|
|
33
|
+
- `createAnimGraphRuntime` (function) · `import { createAnimGraphRuntime } from "@jgengine/core/anim/animGraph"`
|
|
34
|
+
- `parseAnimGraph` (function) · `import { parseAnimGraph } from "@jgengine/core/anim/animGraph"`
|
|
35
|
+
|
|
36
|
+
## animation — find thigh, shin and foot bones on a humanoid rig for foot IK
|
|
37
|
+
|
|
38
|
+
- `inferLegChains` (function) · `import { inferLegChains } from "@jgengine/core/anim/footPlacement"`
|
|
39
|
+
- `lookAt` (function) · `import { lookAt } from "@jgengine/core/anim/ikSolver"`
|
|
40
|
+
- `placeFeet` (function) · `import { placeFeet } from "@jgengine/core/anim/footPlacement"`
|
|
41
|
+
- `planBoneTexture` (function) · `import { planBoneTexture } from "@jgengine/core/anim/boneTexture"`
|
|
42
|
+
- `sampleBoneTexture` (function) · `import { sampleBoneTexture } from "@jgengine/core/anim/boneTexture"`
|
|
43
|
+
- `solveFabrik` (function) · `import { solveFabrik } from "@jgengine/core/anim/ikSolver"`
|
|
44
|
+
- `solveTwoBone` (function) · `import { solveTwoBone } from "@jgengine/core/anim/ikSolver"`
|
|
45
|
+
|
|
19
46
|
## area-effect-field — source-following area membership with enter/refresh/leave edges, stacking, and cleanup
|
|
20
47
|
|
|
21
48
|
- `createAreaEffectField` (function) · `import { createAreaEffectField } from "@jgengine/core/world"`
|
|
@@ -87,6 +114,11 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
87
114
|
- `placeAuthoredObjects` (function) · `import { placeAuthoredObjects } from "@jgengine/core/world"`
|
|
88
115
|
- `resolveAuthoredObjects` (function) · `import { resolveAuthoredObjects } from "@jgengine/core/world"`
|
|
89
116
|
|
|
117
|
+
## authored-solids — collision for studio-authored world content such as city volumes
|
|
118
|
+
|
|
119
|
+
- `resolveAuthoredSolids` (function) · `import { resolveAuthoredSolids } from "@jgengine/core/world/authoredSolids"`
|
|
120
|
+
- `syncAuthoredSolids` (function) · `import { syncAuthoredSolids } from "@jgengine/core/world/authoredSolids"`
|
|
121
|
+
|
|
90
122
|
## authored-spawn — read spawn points and markers from the editor document
|
|
91
123
|
|
|
92
124
|
- `authoredSpawnPosition` (function) · `import { authoredSpawnPosition } from "@jgengine/core/world/authoredSpawn"`
|
|
@@ -102,6 +134,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
102
134
|
- `registerBuiltinTriggerActions` (function) · `import { registerBuiltinTriggerActions } from "@jgengine/core/scene/authoredTriggers"`
|
|
103
135
|
- `registerTriggerAction` (function) · `import { registerTriggerAction } from "@jgengine/core/world"`
|
|
104
136
|
|
|
137
|
+
## axis-shaping — shape raw input per axis — deadzone, response curve, keyboard ramp, self-centring, speed-sensitive scaling
|
|
138
|
+
|
|
139
|
+
- `createAxisShaper` (function) · `import { createAxisShaper } from "@jgengine/core/input/axisShaper"`
|
|
140
|
+
|
|
141
|
+
## behavior-actions — register named callbacks for decision graph behavior descriptors
|
|
142
|
+
|
|
143
|
+
- `registerBehaviorActions` (function) · `import { registerBehaviorActions } from "@jgengine/core/world"`
|
|
144
|
+
|
|
105
145
|
## behavior-control — pause/disable/resume/seek/inspect behavior instances per entity
|
|
106
146
|
|
|
107
147
|
- `behaviorControl` (function) · `import { behaviorControl } from "@jgengine/core/world"`
|
|
@@ -110,6 +150,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
110
150
|
|
|
111
151
|
- `advanceBehaviors` (function) · `import { advanceBehaviors } from "@jgengine/core/world"`
|
|
112
152
|
|
|
153
|
+
## boat-dynamics — force-based powered hull — hull-speed drag hump, planing, keel, rudder that needs flow or outboard thrust
|
|
154
|
+
|
|
155
|
+
- `createBoatDynamics` (function) · `import { createBoatDynamics } from "@jgengine/core/physics/boatDynamics"`
|
|
156
|
+
|
|
113
157
|
## body-bind — mirror sim-body snapshots onto scene entities each tick, no per-body setPose
|
|
114
158
|
|
|
115
159
|
- `createBodyBind` (function) · `import { createBodyBind } from "@jgengine/core/world"`
|
|
@@ -142,9 +186,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
142
186
|
|
|
143
187
|
- `createCameraShake` (function) · `import { createCameraShake } from "@jgengine/core/world"`
|
|
144
188
|
|
|
189
|
+
## character-controller — capsule walk over the physics backend — slide, step-up, slopes, crouch, platforms
|
|
190
|
+
|
|
191
|
+
- `createCharacterController` (function) · `import { createCharacterController } from "@jgengine/core/movement/characterController"`
|
|
192
|
+
|
|
145
193
|
## city-district — polygon math for road-derived blocks, parcels, and buildable footprints
|
|
146
194
|
|
|
147
195
|
- `Vec2` (type) · `import { Vec2 } from "@jgengine/core/world/cityGeometry"`
|
|
196
|
+
- `citySolids` (function) · `import { citySolids } from "@jgengine/core/world/cityKind"`
|
|
148
197
|
- `extractGraphBlocks` (function) · `import { extractGraphBlocks } from "@jgengine/core/world/cityBlocks"`
|
|
149
198
|
- `rectClearsPolyline` (function) · `import { rectClearsPolyline } from "@jgengine/core/world/cityGeometry"`
|
|
150
199
|
- `rectsSeparated` (function) · `import { rectsSeparated } from "@jgengine/core/world/cityGeometry"`
|
|
@@ -171,6 +220,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
171
220
|
|
|
172
221
|
- `createTimerSet` (function) · `import { createTimerSet } from "@jgengine/core/world"`
|
|
173
222
|
|
|
223
|
+
## course-metrics — measure a vehicle on driven tests — understeer gradient, skidpad g, slalom speed
|
|
224
|
+
|
|
225
|
+
- `measureCourse` (function) · `import { measureCourse } from "@jgengine/core/physics/handlingProbe"`
|
|
226
|
+
|
|
174
227
|
## crouch-prone — stance/pose transitions that change the hitbox
|
|
175
228
|
|
|
176
229
|
- `createPoseState` (function) · `import { createPoseState } from "@jgengine/core/world"`
|
|
@@ -219,6 +272,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
219
272
|
|
|
220
273
|
- `DIFFICULTY_TIERS` (const) · `import { DIFFICULTY_TIERS } from "@jgengine/core/ai/difficulty"`
|
|
221
274
|
|
|
275
|
+
## doppler-pitch — pitch a moving sound up as it approaches and down as it passes, from listener and emitter velocity
|
|
276
|
+
|
|
277
|
+
- `dopplerRate` (function) · `import { dopplerRate } from "@jgengine/core/audio/doppler"`
|
|
278
|
+
|
|
279
|
+
## drivable-vehicle — drive a car from throttle/steer/handbrake input each tick: step the vehicle sim and pose its entity
|
|
280
|
+
|
|
281
|
+
- `tickDrivableVehicle` (function) · `import { tickDrivableVehicle } from "@jgengine/core/world"`
|
|
282
|
+
|
|
222
283
|
## elevation-readout — cursor height and delta-from-reference feedback
|
|
223
284
|
|
|
224
285
|
- `sampleElevation` (function) · `import { sampleElevation } from "@jgengine/core/world"`
|
|
@@ -227,6 +288,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
227
288
|
|
|
228
289
|
- `summarizeElevation` (function) · `import { summarizeElevation } from "@jgengine/core/world"`
|
|
229
290
|
|
|
291
|
+
## engine-layers — layered engine audio: rpm-keyed samples crossfaded, with on-load and off-load sets picked by engine load
|
|
292
|
+
|
|
293
|
+
- `createEngineLayers` (function) · `import { createEngineLayers } from "@jgengine/core/audio/engineLayers"`
|
|
294
|
+
|
|
230
295
|
## entity-meta — cast-free narrow of SceneEntity.meta via a type guard
|
|
231
296
|
|
|
232
297
|
- `entityMetaOf` (function) · `import { entityMetaOf } from "@jgengine/core/world"`
|
|
@@ -235,9 +300,17 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
235
300
|
|
|
236
301
|
- `createFastTravelNetwork` (function) · `import { createFastTravelNetwork } from "@jgengine/core/world"`
|
|
237
302
|
|
|
238
|
-
##
|
|
303
|
+
## feedback-mixer — map sim telemetry to camera, audio and haptic parameters through curves, smoothing and threshold events
|
|
304
|
+
|
|
305
|
+
- `createFeedbackMixer` (function) · `import { createFeedbackMixer } from "@jgengine/core/vfx/feedbackMixer"`
|
|
306
|
+
|
|
307
|
+
## fire-input — bind a key or mouse button to a named action that runs the same-named command with the aim; repeatMs auto-fires while held
|
|
308
|
+
|
|
309
|
+
- `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/input/actionBindings"`
|
|
239
310
|
|
|
240
|
-
-
|
|
311
|
+
## flight-metrics — measure an aircraft's feel as numbers — roll rate, sustained turn, stall speed, climb, throttle response, hover drift
|
|
312
|
+
|
|
313
|
+
- `measureFlight` (function) · `import { measureFlight } from "@jgengine/core/physics/handlingProbe"`
|
|
241
314
|
|
|
242
315
|
## follow-trail — trailing follower/snake formation that chases a leader
|
|
243
316
|
|
|
@@ -279,6 +352,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
279
352
|
|
|
280
353
|
- `DEFAULT_FORWARD` (const) · `import { DEFAULT_FORWARD } from "@jgengine/core/world"`
|
|
281
354
|
|
|
355
|
+
## free-flight — camera-relative creative/spectator/noclip/hover flight with correct strafe, sprint, and optional gravity
|
|
356
|
+
|
|
357
|
+
- `createFreeFlightController` (function) · `import { createFreeFlightController } from "@jgengine/core/world"`
|
|
358
|
+
|
|
359
|
+
## gamepad-input — Resolve sampled gamepad input into actions with deadzones and response curves.
|
|
360
|
+
|
|
361
|
+
- `resolveGamepadFrame` (function) · `import { resolveGamepadFrame } from "@jgengine/core/input/gamepadModel"`
|
|
362
|
+
|
|
282
363
|
## glide — gliding/wingsuit descent control from a launch
|
|
283
364
|
|
|
284
365
|
- `createGlideModel` (function) · `import { createGlideModel } from "@jgengine/core/world"`
|
|
@@ -297,10 +378,22 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
297
378
|
|
|
298
379
|
- `grounded` (function) · `import { grounded } from "@jgengine/core/world"`
|
|
299
380
|
|
|
381
|
+
## handling-metrics — measure a vehicle's feel as numbers — 0–100, braking, lateral g, turn-in, sideslip, spin
|
|
382
|
+
|
|
383
|
+
- `measureHandling` (function) · `import { measureHandling } from "@jgengine/core/physics/handlingProbe"`
|
|
384
|
+
|
|
385
|
+
## haptics — Continuous gamepad rumble from named channels (engine, road, impact) mixed by priority, plus fading pulses.
|
|
386
|
+
|
|
387
|
+
- `createHapticChannels` (function) · `import { createHapticChannels } from "@jgengine/core/input/haptics"`
|
|
388
|
+
|
|
300
389
|
## hold-order — stand-ground order that holds position until preempted or canceled
|
|
301
390
|
|
|
302
391
|
- `defineHoldOrder` (function) · `import { defineHoldOrder } from "@jgengine/core/world"`
|
|
303
392
|
|
|
393
|
+
## input-buffer — buffer early presses, coyote time, hold duration and double tap for responsive controls
|
|
394
|
+
|
|
395
|
+
- `createInputBuffer` (function) · `import { createInputBuffer } from "@jgengine/core/input/inputBuffer"`
|
|
396
|
+
|
|
304
397
|
## interaction-prompt — observable nearest-interactable prompt registry over the proximity-prompt resolver — register/resolve/active with priority+range and change-notified snapshot/restore
|
|
305
398
|
|
|
306
399
|
- `createPromptRegistry` (function) · `import { createPromptRegistry } from "@jgengine/core/world"`
|
|
@@ -325,6 +418,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
325
418
|
|
|
326
419
|
- `createRebindSession` (function) · `import { createRebindSession } from "@jgengine/core/input/rebindSession"`
|
|
327
420
|
|
|
421
|
+
## kinematic-vehicle — arcade car/kart driving physics with throttle, brake, steer and retunable handling
|
|
422
|
+
|
|
423
|
+
- `createKinematicVehicle` (function) · `import { createKinematicVehicle } from "@jgengine/core/world"`
|
|
424
|
+
|
|
425
|
+
## lean-metrics — measure a motorcycle's lean — steady lean, time to lean, countersteer tip-in
|
|
426
|
+
|
|
427
|
+
- `measureLean` (function) · `import { measureLean } from "@jgengine/core/physics/handlingProbe"`
|
|
428
|
+
|
|
328
429
|
## limb-health — per-body-part/region health tracked separately
|
|
329
430
|
|
|
330
431
|
- `createMultiRegionHealth` (function) · `import { createMultiRegionHealth } from "@jgengine/core/procedural"`
|
|
@@ -337,6 +438,11 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
337
438
|
|
|
338
439
|
- `generateLock` (function) · `import { generateLock } from "@jgengine/core/world"`
|
|
339
440
|
|
|
441
|
+
## locomotion-graph — resolve the animation graph a model config plays
|
|
442
|
+
|
|
443
|
+
- `animGraphFromConfig` (function) · `import { animGraphFromConfig } from "@jgengine/core/anim/locomotionGraph"`
|
|
444
|
+
- `locomotionGraph` (function) · `import { locomotionGraph } from "@jgengine/core/anim/locomotionGraph"`
|
|
445
|
+
|
|
340
446
|
## map-annotations — player-drawn map annotation layer — freehand strokes, area shapes, and pinned notes, projected into the map's routes/zones props and serializable
|
|
341
447
|
|
|
342
448
|
- `createAnnotationLayer` (function) · `import { createAnnotationLayer } from "@jgengine/core/world"`
|
|
@@ -366,6 +472,22 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
366
472
|
|
|
367
473
|
- `defineMoveOrder` (function) · `import { defineMoveOrder } from "@jgengine/core/world"`
|
|
368
474
|
|
|
475
|
+
## movement-metrics — measure a walking character's feel as numbers — time to top speed, stop distance, jump height and apex, air control, turn-around
|
|
476
|
+
|
|
477
|
+
- `measureMovement` (function) · `import { measureMovement } from "@jgengine/core/movement/movementProbe"`
|
|
478
|
+
|
|
479
|
+
## nav-from-solids — block world solids on a nav grid
|
|
480
|
+
|
|
481
|
+
- `populateNavGridFromSolids` (function) · `import { populateNavGridFromSolids } from "@jgengine/core/nav/navFromEnvironment"`
|
|
482
|
+
|
|
483
|
+
## navmesh-bake — voxelize scene triangles into an agent-sized polygon nav mesh
|
|
484
|
+
|
|
485
|
+
- `bakeNavMesh` (function) · `import { bakeNavMesh } from "@jgengine/navbake"`
|
|
486
|
+
|
|
487
|
+
## navmesh-query — route, snap, and raycast on a polygon navmesh with retunable area costs and a bounded search
|
|
488
|
+
|
|
489
|
+
- `createNavMeshQuery` (function) · `import { createNavMeshQuery } from "@jgengine/core/world"`
|
|
490
|
+
|
|
369
491
|
## object-slot-inventory — placed objects hold validated per-instance container contents that replicate and save with the placement
|
|
370
492
|
|
|
371
493
|
- `SceneObjectSlots` (interface) · `import { SceneObjectSlots } from "@jgengine/core/world"`
|
|
@@ -378,6 +500,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
378
500
|
|
|
379
501
|
- `createOrderRegistry` (function) · `import { createOrderRegistry } from "@jgengine/core/world"`
|
|
380
502
|
|
|
503
|
+
## particle-director — game-reachable VFX seam: queue one-shot particle bursts and keyed follow-capable standing emitters as serializable data for the shell to render
|
|
504
|
+
|
|
505
|
+
- `createParticleDirector` (function) · `import { createParticleDirector } from "@jgengine/core/vfx/particleDirector"`
|
|
506
|
+
|
|
381
507
|
## particle-system — deterministic pooled particle emitter with SoA render buffers, burst/continuous emission, gravity/drag, size/color/alpha-over-life, and serializable state
|
|
382
508
|
|
|
383
509
|
- `createParticleSystem` (function) · `import { createParticleSystem } from "@jgengine/core/world"`
|
|
@@ -403,6 +529,22 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
403
529
|
|
|
404
530
|
- `definePatrolOrder` (function) · `import { definePatrolOrder } from "@jgengine/core/world"`
|
|
405
531
|
|
|
532
|
+
## perception-service — retain sight, sound, and damage observations with range, cone, occlusion, and decay policy
|
|
533
|
+
|
|
534
|
+
- `createPerception` (function) · `import { createPerception } from "@jgengine/core/sensor/perception"`
|
|
535
|
+
|
|
536
|
+
## physics-backend — one interface over interchangeable rigid-body solvers — bodies, joints, raycast, shapecast, snapshot
|
|
537
|
+
|
|
538
|
+
- `PhysicsBackend` (interface) · `import { PhysicsBackend } from "@jgengine/core/physics/physicsBackend"`
|
|
539
|
+
|
|
540
|
+
## physics-backend-conformance — the shared test contract a physics adapter runs to prove it matches the seam
|
|
541
|
+
|
|
542
|
+
- `runPhysicsBackendConformance` (function) · `import { runPhysicsBackendConformance } from "@jgengine/core/physics/physicsBackendConformance"`
|
|
543
|
+
|
|
544
|
+
## physics-world-backend — the zero-dependency PhysicsWorld solver exposed through the PhysicsBackend seam
|
|
545
|
+
|
|
546
|
+
- `createPhysicsWorldBackend` (function) · `import { createPhysicsWorldBackend } from "@jgengine/core/physics/physicsWorldBackend"`
|
|
547
|
+
|
|
406
548
|
## piece-sockets-from-model — derive build-piece snap sockets from a model's named attach points
|
|
407
549
|
|
|
408
550
|
- `pieceSocketsFromModel` (function) · `import { pieceSocketsFromModel } from "@jgengine/core/world/buildSockets"`
|
|
@@ -443,7 +585,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
443
585
|
|
|
444
586
|
- `resolveActivePrompt` (function) · `import { resolveActivePrompt } from "@jgengine/core/world"`
|
|
445
587
|
|
|
446
|
-
## pursuit — chase-to-reach cooldown-gated attack
|
|
588
|
+
## pursuit — enemy/mob aggro chase-to-reach with a cooldown-gated attack and optional leash-to-home; owns the attack cooldown
|
|
447
589
|
|
|
448
590
|
- `advancePursuit` (function) · `import { advancePursuit } from "@jgengine/core/ai/pursuit"`
|
|
449
591
|
|
|
@@ -451,6 +593,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
451
593
|
|
|
452
594
|
- `evaluateQteSequence` (function) · `import { evaluateQteSequence } from "@jgengine/core/world"`
|
|
453
595
|
|
|
596
|
+
## rapier-physics-backend — native capsules, shapecasts, rotation, CCD, joints, and collision queries
|
|
597
|
+
|
|
598
|
+
- `createRapierBackend` (function) · `import { createRapierBackend } from "@jgengine/rapier"`
|
|
599
|
+
|
|
600
|
+
## rate-window-policy — Evaluate deterministic request windows with retry timing.
|
|
601
|
+
|
|
602
|
+
- `decideRateWindow` (function) · `import { decideRateWindow } from "@jgengine/core/time/rateWindow"`
|
|
603
|
+
|
|
454
604
|
## reputation — faction standing that crosses named reputation tiers
|
|
455
605
|
|
|
456
606
|
- `tierForStanding` (function) · `import { tierForStanding } from "@jgengine/core/world"`
|
|
@@ -459,6 +609,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
459
609
|
|
|
460
610
|
- `createResourceNodeField` (function) · `import { createResourceNodeField } from "@jgengine/core/world/resourceNode"`
|
|
461
611
|
|
|
612
|
+
## ride-metrics — measure a sprung vehicle's ride — settle time, dive, roll per g, landing bounce
|
|
613
|
+
|
|
614
|
+
- `measureRide` (function) · `import { measureRide } from "@jgengine/core/physics/handlingProbe"`
|
|
615
|
+
|
|
616
|
+
## rigid-aircraft — force-and-torque aircraft — lifting surfaces with stall and drag polar, control surfaces, inertia, loops and rolls
|
|
617
|
+
|
|
618
|
+
- `createRigidAircraft` (function) · `import { createRigidAircraft } from "@jgengine/core/physics/aircraftDynamics"`
|
|
619
|
+
|
|
462
620
|
## rts-control-groups — map Ctrl+digit / digit / double-tap presses onto selection-bookmark bind / recall / focus intents
|
|
463
621
|
|
|
464
622
|
- `controlGroupKey` (function) · `import { controlGroupKey } from "@jgengine/core/world"`
|
|
@@ -498,6 +656,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
498
656
|
|
|
499
657
|
## solid-obstacles — the one blocking-geometry query the player resolver and NPC movers share
|
|
500
658
|
|
|
659
|
+
- `obstacleFromSolid` (function) · `import { obstacleFromSolid } from "@jgengine/core/movement/solidObstacles"`
|
|
501
660
|
- `solidObstaclesNear` (function) · `import { solidObstaclesNear } from "@jgengine/core/movement/solidObstacles"`
|
|
502
661
|
|
|
503
662
|
## spatial-region-box — sample uniformly within an axis-aligned 3D box
|
|
@@ -560,6 +719,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
560
719
|
|
|
561
720
|
- `surfaceRing` (function) · `import { surfaceRing } from "@jgengine/core/world"`
|
|
562
721
|
|
|
722
|
+
## tactical-cover-points — derive cover candidates from navigation-mesh boundaries
|
|
723
|
+
|
|
724
|
+
- `coverPoints` (function) · `import { coverPoints } from "@jgengine/core/ai/tacticalQueries"`
|
|
725
|
+
|
|
726
|
+
## tactical-position-score — rank bounded tactical positions with caller-defined weights
|
|
727
|
+
|
|
728
|
+
- `scorePositions` (function) · `import { scorePositions } from "@jgengine/core/ai/tacticalQueries"`
|
|
729
|
+
|
|
563
730
|
## target-acquirer — stateful held-target wrapper over an acquisition policy with retention
|
|
564
731
|
|
|
565
732
|
- `createTargetAcquirer` (function) · `import { createTargetAcquirer } from "@jgengine/core/world"`
|
|
@@ -584,11 +751,47 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
584
751
|
|
|
585
752
|
- `raycastHeightField` (function) · `import { raycastHeightField } from "@jgengine/core/world/terrain"`
|
|
586
753
|
|
|
754
|
+
## territory-cell-chunk — Map ownership cells to persisted world chunks.
|
|
755
|
+
|
|
756
|
+
- `territoryChunkKey` (function) · `import { territoryChunkKey } from "@jgengine/core/world/territory"`
|
|
757
|
+
|
|
758
|
+
## territory-footprint — Resolve exactly the ownership cells touched by a placement footprint.
|
|
759
|
+
|
|
760
|
+
- `territoryFootprintCells` (function) · `import { territoryFootprintCells } from "@jgengine/core/world/territory"`
|
|
761
|
+
|
|
762
|
+
## territory-owner-query — Read a loaded land cell owner for authoritative placement checks.
|
|
763
|
+
|
|
764
|
+
- `territoryOwnerOf` (function) · `import { territoryOwnerOf } from "@jgengine/core/world/territory"`
|
|
765
|
+
|
|
766
|
+
## territory-ownership — Claim, release and query land through host-owned snapshot storage.
|
|
767
|
+
|
|
768
|
+
- `createTerritory` (function) · `import { createTerritory } from "@jgengine/core/world/territory"`
|
|
769
|
+
|
|
770
|
+
## territory-placement — Purchase footprint cells atomically with object placement.
|
|
771
|
+
|
|
772
|
+
- `placeWithTerritory` (function) · `import { placeWithTerritory } from "@jgengine/core/world/territory"`
|
|
773
|
+
|
|
774
|
+
## territory-read-scope — Load the footprint and foreign-owner gap without scanning the world.
|
|
775
|
+
|
|
776
|
+
- `territoryChunkKeys` (function) · `import { territoryChunkKeys } from "@jgengine/core/world/territory"`
|
|
777
|
+
|
|
587
778
|
## touch-controls — switch the on-screen touch control set when gameplay context changes (enter/exit vehicle, mount, build mode)
|
|
588
779
|
|
|
589
780
|
- `setTouchControlsMode` (function) · `import { setTouchControlsMode } from "@jgengine/core/input/touchControlsMode"`
|
|
590
781
|
- `touchButtonShape` (function) · `import { touchButtonShape } from "@jgengine/core/input/touchScheme"`
|
|
591
782
|
|
|
783
|
+
## vehicle-backend-link — collide a vehicle sim with a physics backend — shove props, stop at walls, slide along them
|
|
784
|
+
|
|
785
|
+
- `createVehicleBackendLink` (function) · `import { createVehicleBackendLink } from "@jgengine/core/physics/vehicleBackendLink"`
|
|
786
|
+
|
|
787
|
+
## vehicle-dynamics — force-based car handling — tires, load transfer, drivetrain, assists — tuned with physical numbers
|
|
788
|
+
|
|
789
|
+
- `createVehicleDynamics` (function) · `import { createVehicleDynamics } from "@jgengine/core/physics/vehicleDynamics"`
|
|
790
|
+
|
|
791
|
+
## vehicle-seats — enter, exit and swap seats in a car or mount (GTA-style boarding) with driver and passenger slots
|
|
792
|
+
|
|
793
|
+
- `createVehicleSeats` (function) · `import { createVehicleSeats } from "@jgengine/core/world"`
|
|
794
|
+
|
|
592
795
|
## visibility-field — per-viewer-group observed/remembered/hidden fog-of-war knowledge with terrain memory and authoritative entity disclosure
|
|
593
796
|
|
|
594
797
|
- `createVisibilityField` (function) · `import { createVisibilityField } from "@jgengine/core/world"`
|
|
@@ -601,6 +804,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
601
804
|
|
|
602
805
|
- `resolveWalkerStep` (function) · `import { resolveWalkerStep } from "@jgengine/core/movement/solidObstacles"`
|
|
603
806
|
|
|
807
|
+
## walker-solid-step-source — slide a step against solid geometry from a pure rules package
|
|
808
|
+
|
|
809
|
+
- `resolveSourceWalkerStep` (function) · `import { resolveSourceWalkerStep } from "@jgengine/core/movement/solidObstacles"`
|
|
810
|
+
|
|
604
811
|
## wave-runner — observable serializable wave/spawn runner over the seeded spawn director — WAVE N, wave progress, budget/alert readout, onSpawn sink, snapshot/restore
|
|
605
812
|
|
|
606
813
|
- `createWaveRunner` (function) · `import { createWaveRunner } from "@jgengine/core/world"`
|
|
@@ -620,6 +827,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
620
827
|
- `buildTrimmedIntersections` (function) · `import { buildTrimmedIntersections } from "@jgengine/core/world"`
|
|
621
828
|
- `trimBandAtJunctions` (function) · `import { trimBandAtJunctions } from "@jgengine/core/world"`
|
|
622
829
|
|
|
830
|
+
## world-physics-colliders — Synchronize terrain and authored static colliders with a physics backend.
|
|
831
|
+
|
|
832
|
+
- `syncWorldColliders` (function) · `import { syncWorldColliders } from "@jgengine/core/physics/worldColliders"`
|
|
833
|
+
|
|
623
834
|
## world-place — declare the place a game happens in — flat/round/voxel/board ground, surface laws, per-place physics
|
|
624
835
|
|
|
625
836
|
- `world` (function) · `import { world } from "@jgengine/core/world"`
|
|
@@ -627,3 +838,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
627
838
|
## world-seed — derive a deterministic generator/scatter seed from world id + save/run seed
|
|
628
839
|
|
|
629
840
|
- `seedForPlace` (function) · `import { seedForPlace } from "@jgengine/core/world"`
|
|
841
|
+
|
|
842
|
+
## world-solid-bounds — world AABB and nav footprint of a world solid
|
|
843
|
+
|
|
844
|
+
- `worldSolidBounds` (function) · `import { worldSolidBounds } from "@jgengine/core/world/worldSolids"`
|
|
845
|
+
- `worldSolidFootprint` (function) · `import { worldSolidFootprint } from "@jgengine/core/world/worldSolids"`
|
|
846
|
+
|
|
847
|
+
## world-solids — collision for generated and authored world geometry (buildings, city lots, walls)
|
|
848
|
+
|
|
849
|
+
- `createWorldSolids` (function) · `import { createWorldSolids } from "@jgengine/core/world/worldSolids"`
|
|
850
|
+
|
|
851
|
+
## world-solids-from-data — derive collision boxes from generated buildings and wall runs
|
|
852
|
+
|
|
853
|
+
- `buildingSolids` (function) · `import { buildingSolids } from "@jgengine/core/world/worldSolids"`
|
|
854
|
+
- `structureSolids` (function) · `import { structureSolids } from "@jgengine/core/world/worldSolids"`
|
|
855
|
+
- `wallSolids` (function) · `import { wallSolids } from "@jgengine/core/world/worldSolids"`
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Recipe — character animation (graph → rig → ground)
|
|
2
|
+
|
|
3
|
+
**What this wires:** a rigged character that moves the way the game plays: clips chosen by data, feet that meet the ground, and gameplay moments keyed to animation frames. There is no default hero, soldier or NPC rig: every game picks its clips, parameters and corrections.
|
|
4
|
+
|
|
5
|
+
## The seams
|
|
6
|
+
|
|
7
|
+
- **Clips on a model.** `ModelConfig.animation` on an entity kind. A catalog model with indexed `clips` animates automatically through semantic clip roles; `"none"` holds the bind pose. `{ clip, paused, time }` holds one pose.
|
|
8
|
+
- **Graph.** `animation.graph` is an `AnimGraph` (`@jgengine/core/anim/animGraph`): layers, each a state machine of `clip`, `blend1D` and `blend2D` states joined by transitions with `when` conditions, `trigger`s, crossfade `duration` and `exitTime`. It is plain data, so it saves, diffs and can be authored in the editor.
|
|
9
|
+
- `locomotionGraph({ idle, walk, run, walkSpeed, runSpeed, fadeSec, oneShots })` builds the idle/walk/run blend plus one-shots; `states`/`oneShots` configs are converted through it.
|
|
10
|
+
- Upper-body actions (aim, reload, wave) go on a second layer with `mask: ["spine", "arm", ...]` bone prefixes, `additive` for recoil or breathing on top of the base.
|
|
11
|
+
- `createAnimGraphRuntime(graph)` runs the same graph headless: `advance(dt, params, clips)`, `trigger`, `snapshot`/`restore`, `retune`. Test transitions with it before looking at pixels.
|
|
12
|
+
- **Authoring in the editor.** A placement's graph is inspected, previewed and stored from the editor's Animation workspace (see `jgengine-editor` reference, "Placement animation"). `animGraphFromConfig(config)` gives the graph any config plays, so tools and tests see what the shell plays. `parseAnimGraph(json)` validates a stored one.
|
|
13
|
+
- **Parameters.** The shell feeds the entity's smoothed ground speed as `speed`. Anything else (aiming, crouched, strafe x/y) goes on the entity blackboard under `ANIM_PARAMS_KEY`.
|
|
14
|
+
- **Triggers.** `ctx.game.playEntityAnimation(id, name)` arms a trigger; `hit` and `death` arm from their combat events.
|
|
15
|
+
- **Events.** `graph.events: [{ clip, atSec, name }]` emit `animation.event` when a clip crosses that time. Hook footstep audio, the damage frame of a swing or the magazine swap of a reload to the event, not to a timer.
|
|
16
|
+
- **Root motion.** `rootMotion: true` on a state moves the entity by the clip's horizontal root-bone travel, turned by the entity's facing and scaled with the model, instead of playing it in place. The root bone's vertical motion stays in the clip, and other states keep their root animation untouched. Use it for dodges, vaults and attacks with lunges whose distance must match the feet. `output.rootMotion` reports when a root-motion state is current.
|
|
17
|
+
- **Foot IK.** `ModelConfig.ik` runs after the mixer each frame.
|
|
18
|
+
- `ik: "auto"` finds thigh → shin → foot chains by bone name. Pass `{ feet: [{ root, mid, tip }] }` when the rig's names are unusual, and `feet: []` to keep only `lookAt`.
|
|
19
|
+
- Each foot keeps its animated swing and moves by its ground's height above or below the model origin. The pelvis drops so the lower leg can reach, soles never end under the ground, and planted feet tilt to the ground normal (`alignToGround`, `0..1`). The correction fades out while the feet are clear of the ground.
|
|
20
|
+
- `maxAdjust` caps the correction as a fraction of leg length (default `0.4`). Probes hit terrain and blocking physical objects, never the model's own entity.
|
|
21
|
+
- The pure pieces are `placeFeet` and `inferLegChains` (`@jgengine/core/anim/footPlacement`) and `solveTwoBone`/`solveFabrik`/`lookAt` (`@jgengine/core/anim/ikSolver`), for a custom host or a non-leg chain (a hand on a ledge, a tail).
|
|
22
|
+
- **Crowds.** `<SkinnedInstances url instances clips once fps modelScale />` (`@jgengine/shell/render/SkinnedInstances`) draws hundreds of animated copies of one rig in one instanced draw per material. Each `CrowdInstance` has `position`, `rotationY`, `scale`, `clip`, `timeOffset` and `speed`.
|
|
23
|
+
- Every clip is baked once to a bone-matrix texture (layout from `planBoneTexture`, `@jgengine/core/anim/boneTexture`) and sampled on the GPU. Clips in `once` hold their last pose. A member changes clip when the game passes a new `instances` array.
|
|
24
|
+
- Only skinned meshes are baked. Static props parented to bones (a weapon in a hand slot, a hat) are dropped, and a mesh with several materials keeps its first.
|
|
25
|
+
- Crowd members have no graph, IK or attachments. Promote the few near the camera or near the player to entity models.
|
|
26
|
+
- `bakeSkinnedCrowd` and `patchCrowdMaterial` are exported for a custom renderer.
|
|
27
|
+
|
|
28
|
+
## Symptom → knob
|
|
29
|
+
|
|
30
|
+
| Symptom | Knob |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| Feet slide at walk or run speed | `walkSpeed`/`runSpeed` to the clip's authored stride speed, or blend1D `at` points |
|
|
33
|
+
| Pop between states | transition `duration`; `exitTime` on one-shots returning to locomotion |
|
|
34
|
+
| Feet float or sink on slopes and steps | `ik: "auto"` |
|
|
35
|
+
| Knees buckle on steep ground | lower `ik.maxAdjust` |
|
|
36
|
+
| Feet tilt wrongly on rubble or props | lower `ik.alignToGround` |
|
|
37
|
+
| Attack damage lands before the swing | `graph.events` on the hit frame instead of a timer |
|
|
38
|
+
| Lunge distance doesn't match the feet | `rootMotion: true` on that state |
|
|
39
|
+
| Hundreds of animated characters cost thousands of draw calls | `SkinnedInstances` for the background crowd |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Recipe — controls (bindings → contexts → devices → feel)
|
|
2
|
+
|
|
3
|
+
**What this wires:** a game's controls from small parts: named actions, layered contexts that swap bindings live, keyboard/mouse and gamepad on the same actions, and per-axis feel. There are no control presets; every game names its own actions and codes.
|
|
4
|
+
|
|
5
|
+
## The seams
|
|
6
|
+
|
|
7
|
+
- **Actions.** `defineGame({ input: { action: codes } })` maps action names to codes. Keyboard codes are `KeyboardEvent.code` (`KeyW`), pad buttons are `pad:<index>` and stick or trigger directions are `padaxis:<index>+`/`-` in the standard mapping. `bindingLabel(code, "xbox")` gives the glyph text for prompts. Sim code reads actions only: `ctx.input.isDown`, `justPressed`, `value` (0..1, analog when a stick or trigger drives it) and `axis(bindings)`.
|
|
8
|
+
- **Contexts.** `actionContextStack(ctx)` (`@jgengine/core/game/controlGate`) layers action maps over the base input. `push({ id, codes, passthrough, axes?, shaping? })` swaps bindings immediately: the shell re-binds keyboard, touch and pad on the next frame, and a key held across the swap keeps counting toward whatever it maps to now. `passthrough: false` hides everything below (menus, a parked vehicle); `passthrough: true` adds or overrides a few actions (a build mode on top of on-foot). The stack has `snapshot`/`restore`, so the current mode survives a save.
|
|
9
|
+
- **Axes and feel per context.** A context can carry `axes` (axis bindings by action name) and `shaping` (serializable `createAxisShaper` profiles). Read them with `activeAxes()` when `version()` changes and `retune` the shaper, so on-foot movement and driving steer each get their own ramp and curve without a branch per mode.
|
|
10
|
+
- **Pad feel.** `defineGame({ gamepad: { deadzone, curve, triggerDeadzone } })` shapes sticks and triggers before values reach `ctx.input`; the axis shaper only adds ramps and speed scaling on top.
|
|
11
|
+
- **Timing.** `createInputBuffer` (`@jgengine/core/input/inputBuffer`) buffers early presses, coyote time, hold duration and double taps.
|
|
12
|
+
- **Local seats (couch co-op).** `defineGame({ localPlayers: { maxSlots: 4 } })` opens seats on one screen. The first pad to press a button shares the primary seat with keyboard and touch (`claimPrimary: "none"` keeps the primary keyboard-only); each further pad hot-joins its own seat, and the shell calls `loop.onNewPlayer(ctx, { userId, isNew: true })` for it, so spawn with `player?.userId ?? ctx.player.userId`. Read a seat with `localPlayers(ctx).local(slotId)` → `{ userId, input }` (`@jgengine/core/runtime/localPlayers`); iterate `slots()` in `onTick`. Seats use the same bindings and contexts as the primary, and the shell's walk controller moves every seat's entity. The table has `snapshot`/`restore`/`retune`.
|
|
13
|
+
- **Split-screen.** `defineGame({ viewports: { layout: "auto", split: "vertical" } })` draws one viewport per joined seat (`@jgengine/core/game/viewports`: `splitViewports`, `resolveViewports`, `viewportPixels`). The primary seat keeps the main camera rig; other seats get a chase or top-down follow camera (`viewports.camera`, defaulting to top-down when the main rig is), and the walk controller moves each seat relative to its own camera. `ViewportHuds` (`@jgengine/shell/camera/Viewports`) gives each seat its own HUD root. Post-processing is skipped while the screen is split. `bun run drive couch --param gamepad=2` shows two seats.
|
|
14
|
+
- **Haptics.** `ctx.input.haptics(userId)` holds named rumble channels: `set(name, { strong, weak }, priority?)` each tick for continuous feel, `pulse(name, { strong, weak, ms }, priority?)` for a fading hit. Higher priority ducks lower channels. The shell drives each seat's own pad; channels are local and never saved or sent.
|
|
15
|
+
- **Rebinding.** `createRebindSession` drives a conflict-aware "press a key" flow; overrides persist per game and apply under the context stack.
|
|
16
|
+
|
|
17
|
+
## Wiring a mode swap
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
const DRIVING: ActionContext = {
|
|
21
|
+
id: "driving",
|
|
22
|
+
codes: { exit: ["KeyF", "pad:3"] },
|
|
23
|
+
passthrough: true,
|
|
24
|
+
axes: { steer: { positive: ["steerRight"], negative: ["steerLeft"] } },
|
|
25
|
+
shaping: { steer: { digital: { riseRate: 3, returnRate: 6 }, analog: { deadzone: 0.08, curve: 1.5 } } },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// enter: actionContextStack(ctx).push(DRIVING); leave: actionContextStack(ctx).pop("driving")
|
|
29
|
+
if (state.contextVersion !== contexts.version()) {
|
|
30
|
+
state.contextVersion = contexts.version();
|
|
31
|
+
const layer = contexts.activeAxes();
|
|
32
|
+
state.bindings = { steer: layer.bindings.steer ?? { positive: [] } };
|
|
33
|
+
state.shaper.retune({ axes: { steer: layer.shaping.steer ?? {} } });
|
|
34
|
+
}
|
|
35
|
+
const raw = ctx.input.axis(state.bindings);
|
|
36
|
+
const axis = state.shaper.shape(dt, raw, { analog: analogAxes(state.bindings, ctx.input.analog()) });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`bun run drive handling` runs this: F pops the driving context and a held W stops reaching the engine.
|
|
40
|
+
|
|
41
|
+
## Pitfalls
|
|
42
|
+
|
|
43
|
+
- Actions that exist only inside a context are published to `ctx.input` while the context is active, but the base `input` map is what the touch dock and settings menu list. Keep an action in the base map when touch players need it.
|
|
44
|
+
- `shaping` has no `scale` callback because contexts are serializable; apply speed-sensitive scaling on the shaper the game owns.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Recipe — flight feel (aircraft as physical numbers)
|
|
2
|
+
|
|
3
|
+
**What this wires:** an aircraft that flies the way the brief says. There is no default jet or plane: every aircraft is a mass, an inertia tensor, a set of surfaces and an engine the game picks, checked against numbers it writes down first.
|
|
4
|
+
|
|
5
|
+
## The seams
|
|
6
|
+
|
|
7
|
+
- **Sim.** `createRigidAircraft(tuning, { position, velocity, heading | orientation, wind?, groundHeight?, gravityField?, airDensity? })` from `@jgengine/core/physics/aircraftDynamics`. It is a quaternion rigid body: surface forces act at their mount points on the inertia tensor, so nothing commands a rotation rate. `snapshot()`/`restore()` for prediction and replay, `retune()` for damage, upgrades and staging, per-tick `modifiers` (`thrustScale`, `liftScale`, `dragScale`, extra `force`/`torque`).
|
|
8
|
+
- **Body frame.** `[left, up, forward]` about the centre of mass. A wing panel sits at `[±semiSpan/2, 0, 0]`, a tailplane at `[0, 0, -tailArm]`, a fin at `[0, finHeight, -tailArm]` with `normal: [1, 0, 0]`.
|
|
9
|
+
- **Surfaces.** Each one has `area` (m²), `liftSlope` (per rad), `stallAngle` (rad), `postStallLift` (share of peak kept past the stall), `incidence` (trim), and the drag polar `cd0` + `inducedDrag·CL²`. Split the wing into left and right panels so ailerons have a roll arm.
|
|
10
|
+
- **Controls.** `control: { pitch?, roll?, yaw? }` on a surface is AoA change per rad of that channel's deflection. The sim signs it from the lever arm, so positive input is always nose up, right roll, nose right. Elevons are one surface with both `pitch` and `roll`. `controls.<channel>` sets `maxDeflection` and actuator `rate`.
|
|
11
|
+
- **Rotors.** A `rotor` block makes the same body a helicopter: `maxThrust` (N, full collective and rotor speed), `radius` (m), hub `at`, `torque` (N·m at full collective, positive yaws the nose left), `cyclic` disc tilt, `damping`, `spoolRate` and an optional `tail` rotor (`maxThrust`, `at`, `sideDamping`).
|
|
12
|
+
- Throttle spins the rotor up; `input.collective` sets thrust; the pitch and roll channels tilt the disc; yaw drives the tail rotor.
|
|
13
|
+
- Neutral pedal gives no tail thrust, so the nose swings with the torque until the pilot (or SAS) holds it. Hover pedal is `torque·collective / (tail.maxThrust · tailArm)`.
|
|
14
|
+
- Thrust follows momentum theory: translational lift once clean air reaches the induced velocity `√(T/2ρA)`, less thrust while climbing through the disc, and Cheeseman–Bennett ground effect below about one rotor diameter.
|
|
15
|
+
- The step's `rotor` telemetry (`speed`, `thrust`, `torque`, `groundEffect`, `translationalLift`) drives rotor sound, dust and HUD.
|
|
16
|
+
- **Rockets.** A `motor` block: `thrustCurve` (`[seconds, N]` points over burn time), `propellantKg` on top of `massKg`, `massFlow` (kg/s at peak thrust; it scales with thrust), nozzle `at` and `gimbal` (rad, on the pitch and yaw actuators).
|
|
17
|
+
- Throttle above zero burns and advances the burn clock; throttle `0` coasts with the clock held.
|
|
18
|
+
- Mass and inertia fall as propellant leaves (inertia scales with total over dry mass), so acceleration and turn rate rise through the burn.
|
|
19
|
+
- Stage by `retune(nextStage)`: a new `motor` object loads its propellant and restarts its clock; the same object keeps both. Move the pose to the new stage's centre of mass with `restore` first if the stages differ in length.
|
|
20
|
+
- The step reports `massKg` and `motor` (`thrust`, `burnTime`, `propellantKg`, `burnedOut`).
|
|
21
|
+
- **Assists.** An `assists` block is a flight computer on the same actuators, so it never exceeds the airframe's authority, and full stick on an axis is always the pilot's.
|
|
22
|
+
- `sas: { pitch, roll, yaw }` (`0..1`) damps body rates and, hands-off, holds the attitude or heading at release with a learned trim. `sasRate` sets how firm (rad/s for full control). On a helicopter, `sas.yaw` holds heading against rotor torque with no pedal.
|
|
23
|
+
- `autoLevel` (`0..1`) flies the wings level and the nose to the horizon hands-off.
|
|
24
|
+
- `maxAngleOfAttack` (rad) and `maxG` cut the pitch command before the limit; `step.limited` reports it.
|
|
25
|
+
- `hoverHold` (`0..1`) flies hands-off cyclic to a stop over the ground: position → velocity → attitude → rate.
|
|
26
|
+
- `policy(context, command)` runs last and returns the command the actuators get: replace any built-in with the game's own.
|
|
27
|
+
- `step.command` is what the actuators got. Toggle assists with `retune({ ...aircraft.tuning(), assists })`.
|
|
28
|
+
- **Pose.** Set the entity's `rotationY` from `step.heading` and apply the rest of `step.orientation` to the mesh (the heading-free part: `qY(-heading) · orientation`). `step.pitch`/`step.bank` match three.js `Euler(-pitch, heading, bank, "YXZ")`; `aircraftAttitudeQuaternion(heading, pitch, bank)` goes the other way for spawns.
|
|
29
|
+
- **Camera.** The chase rig (`rig: "chase"`) follows heading; give it `frustum: { far }` in the thousands and a `yawResponse` around 4 so the boom swings smoothly over the top of a loop.
|
|
30
|
+
- **Telemetry.** `airspeed`, `angleOfAttack`, `sideslip`, `gLoad`, `stalled`/`stallFraction`, `thrust`, body rates and `deflection` drive the HUD, stall horn, wind noise and camera shake.
|
|
31
|
+
|
|
32
|
+
## Workflow
|
|
33
|
+
|
|
34
|
+
1. **Write the feel as numbers** on the `FlightReport` fields. Some examples:
|
|
35
|
+
- "Nimble aerobatic" is `rollRateDeg > 300` and `sustainedTurnRateDeg > 18`.
|
|
36
|
+
- "Heavy transport" is `rollRateDeg` 40–80 and `stallSpeed` 50–70.
|
|
37
|
+
- "Responsive jet" is `throttleResponse < 2`.
|
|
38
|
+
- "Easy hover" is `hoverDriftMeters < 5` with the game's assists on.
|
|
39
|
+
2. **Put them in a test** next to the tuning: `measureFlight((spawn) => createRigidAircraft(tuning, spawn), { cruiseSpeed })` from `@jgengine/core/physics/handlingProbe`. It flies deterministic autopilots through a full-aileron roll, full-throttle banked turns, an idle deceleration, a speed-held climb, a throttle step and a hands-off hover. Fields that don't apply are `NaN`: turn and stall need wings, hover drift needs a rotor.
|
|
40
|
+
3. **Start from the real aircraft**: mass, wing area, span, tail arm, thrust. Inertia is roughly `m·(span/4)²` for roll and `m·(length/4)²` for pitch and yaw.
|
|
41
|
+
4. **Trim it.** With the wing on the centre of mass, set wing `incidence` to the cruise lift coefficient over the lift slope, `W / (½ρV²·S·a)`, and leave the tail at `0`. It then flies level hands-off at that speed.
|
|
42
|
+
5. **Drive it**: `bun run drive flight --key KeyR+KeyS:10500 --key KeyD:1500 --record <name> --record-fps 20`, or `bun run drive flight-heli --key KeyR:1500 --wait 3000 --key KeyE:3500 --record <name> --record-fps 20` for the helicopter, or `bun run drive flight-rocket --key KeyR:400 --wait 12000 --record <name> --record-fps 20` for the two-stage rocket.
|
|
43
|
+
|
|
44
|
+
## Symptom → knob
|
|
45
|
+
|
|
46
|
+
| Symptom | Knob (direction) |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| Pitches up or down hands-off | wing `incidence` ↓ / ↑; wing further aft of the centre of mass ↑ stability |
|
|
49
|
+
| Loops too slowly | tail `control.pitch` ↑ (more AoA), entry speed or thrust ↑, `inertia.pitch` ↓ |
|
|
50
|
+
| Stalls in every hard pull | tail `control.pitch` ↓ so the elevator can't reach the stall angle, or wing `stallAngle` ↑ |
|
|
51
|
+
| Stall is a cliff / too gentle | `postStallLift` ↓ / ↑ |
|
|
52
|
+
| Rolls too slowly / too fast | aileron `control.roll` ↑ / ↓, wing panel `at` further out ↑ damping; `inertia.roll` sets how fast it gets there |
|
|
53
|
+
| Nose wanders, won't track | fin `area` ↑ or fin further aft |
|
|
54
|
+
| Controls feel laggy | `controls.<channel>.rate` ↑ |
|
|
55
|
+
| Top speed wrong | `engine.maxThrust`, `dragArea`, surface `cd0` |
|
|
56
|
+
| Bleeds speed in turns | `inducedDrag` ↓, wing `area` ↑ (lower CL for the same lift) |
|
|
57
|
+
| Throttle feels sluggish | `engine.spoolRate` ↑ |
|
|
58
|
+
| Helicopter won't hover / climbs away | hover collective is `weight / maxThrust` out of ground effect; `rotor.maxThrust` sets how much margin there is |
|
|
59
|
+
| Nose swings too hard without pedal | `rotor.torque` ↓, `inertia.yaw` ↑, `tail.sideDamping` ↑ |
|
|
60
|
+
| Pedal too weak to stop a swing | `tail.maxThrust` ↑ or tail rotor further aft |
|
|
61
|
+
| Cyclic twitchy / sluggish | `rotor.cyclic` ↓ / ↑, hub height (`rotor.at[1]`) ↓ / ↑, `rotor.damping` ↑ / ↓ |
|
|
62
|
+
| Pedal also rolls the body | tail rotor `at[1]` above the centre of mass; move it down or trim with cyclic |
|
|
63
|
+
| Rocket weathercocks too hard / tumbles | fin `area` ↓ / ↑, fins further aft for more stability |
|
|
64
|
+
| Gimbal too twitchy / can't steer | `motor.gimbal` ↓ / ↑; lighter late in the burn it turns faster on its own |
|
|
65
|
+
| Burns too long / short | `propellantKg` over `massFlow` sets burn time; the curve's last point cuts it off first |
|
|
66
|
+
| Helicopter too hard to hover on a keyboard | `assists.sas.yaw` 1 for heading hold, `assists.hoverHold` for cyclic; collective stays the pilot's |
|
|
67
|
+
| Assisted aircraft oscillates | `assists.sasRate` ↑ (softer), strengths ↓ |
|
|
68
|
+
| Players stall it pulling hard | `assists.maxAngleOfAttack` just under the wing `stallAngle`, or `maxG` |
|
|
69
|
+
| Sinks when it slows down | that is translational lift going away; `rotor.translationalLift` sets how much |
|
|
70
|
+
|
|
71
|
+
## Traps
|
|
72
|
+
|
|
73
|
+
- `createAircraftDynamics` (`physics/flightDynamics`) is deprecated: it commands rotation and can't loop. The CHANGELOG Migrate note maps its fields onto `createRigidAircraft`.
|
|
74
|
+
- Setting orientation or angular velocity by hand defeats the model. Change a surface, the inertia or the control authority.
|
|
75
|
+
- A single centreline wing has no roll arm, so ailerons on it do nothing. Split it into left and right panels.
|
|
76
|
+
- For multiplayer, send inputs, not poses. Predict with the same tuning and `restore(serverState)` on correction.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Recipe — NPC senses (perceive → remember → decide → route)
|
|
2
|
+
|
|
3
|
+
**What this wires:** an NPC that notices things, remembers where they were, acts on
|
|
4
|
+
that memory, and gives up when it goes stale. A guard that hears a sprint and
|
|
5
|
+
checks it out, a mob that leashes home, a pedestrian that flees a gunshot and a
|
|
6
|
+
patrol car that drives to the last sighting are all this loop with different
|
|
7
|
+
facts, graphs and speeds. No archetypes: the NPC is data plus a few named actions.
|
|
8
|
+
|
|
9
|
+
Working example: the `guard-probe` dev demo (`apps/dev/src/demo/guardProbe.ts`),
|
|
10
|
+
`bun run drive guard-probe`.
|
|
11
|
+
|
|
12
|
+
## The seams
|
|
13
|
+
|
|
14
|
+
- **Perceive → memory.** One `createPerception` per group of NPCs that share
|
|
15
|
+
senses. Each tick, push the stimuli your game produces (`sound` with a
|
|
16
|
+
`loudness` that scales range, `damage`) and call `observe(npc, candidates, nowMs)`
|
|
17
|
+
with a *bounded* candidate list from a spatial query, never every entity. Pass
|
|
18
|
+
`occluded` for walls. Memory decays linearly over `memorySeconds`; each observer
|
|
19
|
+
judges a stimulus once.
|
|
20
|
+
- **Memory → blackboard.** A small system copies the facts the graph needs into
|
|
21
|
+
the NPC's persistent blackboard: `behaviorControl(ctx).blackboard(id)`. Write
|
|
22
|
+
plain scalars (`alerted`, `lastKnownX`, `lastKnownZ`, `confidence`). Actions
|
|
23
|
+
and conditions read facts; they do not query the world for them.
|
|
24
|
+
- **Blackboard → decision.** The NPC's `decisionGraph` behavior is data:
|
|
25
|
+
conditions on blackboard keys, `memory` sequences for multi-step errands
|
|
26
|
+
(go → `wait` → give up), `cooldown` for barks, `random` (drawn from `ctx.rng`)
|
|
27
|
+
for idle variety. Register actions by name with `registerBehaviorActions`, and
|
|
28
|
+
release movement or claims in `onAbort` when a higher branch pre-empts them.
|
|
29
|
+
Set `thinkInterval` so a crowd thinks a few times a second.
|
|
30
|
+
- **Decision → route.** Actions that move ask one `createNavMeshQuery(mesh)` per
|
|
31
|
+
mesh for `findPath` and replan only when the goal moves. Bake the mesh from
|
|
32
|
+
scene geometry with `@jgengine/navbake` (`await initNavBake()`, then
|
|
33
|
+
`bakeNavMesh`) and store it as an editor `nav` bake; price hazards or lock doors
|
|
34
|
+
with `areaCosts` through `retune`.
|
|
35
|
+
|
|
36
|
+
## Gotchas
|
|
37
|
+
|
|
38
|
+
- Hand the graph facts, not objects: the blackboard serializes with the behavior,
|
|
39
|
+
so saves and replays keep an NPC mid-investigation.
|
|
40
|
+
- Judge footstep noise on speed averaged over a window, not one frame; frame-time
|
|
41
|
+
jitter otherwise reads as a sprint.
|
|
42
|
+
- Record the stimulus you handled (`handledAt`) so giving up does not
|
|
43
|
+
re-alert on the same memory next tick.
|