@jgengine/shell 0.18.1 → 0.21.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 +504 -7
- package/dist/GameHost.d.ts +12 -1
- package/dist/GameHost.js +14 -1
- package/dist/GamePlayerShell.js +132 -17
- package/dist/Shell3dPresentation.d.ts +5 -11
- package/dist/Shell3dPresentation.js +73 -11
- package/dist/ShellChrome.d.ts +2 -1
- package/dist/ShellChrome.js +22 -6
- package/dist/ShellHudPresentation.d.ts +20 -2
- package/dist/ShellHudPresentation.js +41 -6
- package/dist/audio/AudioComponents.js +6 -2
- package/dist/audio/audioEngine.d.ts +24 -0
- package/dist/audio/audioEngine.js +231 -83
- package/dist/audio/audioWire.d.ts +3 -0
- package/dist/audio/audioWire.js +9 -3
- package/dist/audio/loopParams.d.ts +39 -0
- package/dist/audio/loopParams.js +43 -0
- package/dist/audio/synthEngine.d.ts +7 -1
- package/dist/audio/synthEngine.js +103 -38
- package/dist/camera/GameCameraRig.js +3 -2
- package/dist/camera/GameFirstPersonCamera.d.ts +6 -4
- package/dist/camera/GameFirstPersonCamera.js +68 -27
- package/dist/camera/Viewports.d.ts +34 -0
- package/dist/camera/Viewports.js +123 -0
- package/dist/camera/cameraRigs.js +76 -62
- package/dist/camera/chaseHeading.d.ts +9 -0
- package/dist/camera/chaseHeading.js +10 -0
- package/dist/camera/customMuzzle.d.ts +14 -0
- package/dist/camera/customMuzzle.js +68 -0
- package/dist/camera/index.d.ts +1 -0
- package/dist/camera/index.js +1 -0
- package/dist/camera/orbitCameraMath.js +2 -2
- package/dist/camera/rigMath.d.ts +82 -4
- package/dist/camera/rigMath.js +133 -15
- package/dist/camera/rigResolve.d.ts +3 -0
- package/dist/camera/rigResolve.js +11 -0
- package/dist/combat/ProjectileModels.d.ts +31 -0
- package/dist/combat/ProjectileModels.js +70 -0
- package/dist/commandSink.d.ts +1 -2
- package/dist/commandSink.js +3 -2
- package/dist/defineGame.d.ts +19 -3
- package/dist/defineGame.js +39 -7
- package/dist/devtools/DevtoolsOverlay.d.ts +2 -69
- package/dist/devtools/DevtoolsOverlay.js +15 -167
- package/dist/devtools/DevtoolsRuntime.d.ts +7 -0
- package/dist/devtools/DevtoolsRuntime.js +61 -0
- package/dist/devtools/agentBridge.d.ts +6 -0
- package/dist/devtools/agentBridge.js +16 -2
- package/dist/devtools/devtoolsReports.d.ts +68 -0
- package/dist/devtools/devtoolsReports.js +100 -0
- package/dist/devtools/latencyInstrumentation.d.ts +3 -0
- package/dist/devtools/latencyInstrumentation.js +11 -0
- package/dist/devtools/playtestProbe.d.ts +4 -0
- package/dist/devtools/playtestProbe.js +22 -0
- package/dist/diagnostics/FpsCounter.d.ts +17 -0
- package/dist/diagnostics/FpsCounter.js +32 -0
- package/dist/drivers/FrameDriver.js +35 -20
- package/dist/drivers/FrameRateLimiter.d.ts +9 -0
- package/dist/drivers/FrameRateLimiter.js +39 -0
- package/dist/drivers/HudOnlyDriver.d.ts +6 -1
- package/dist/drivers/HudOnlyDriver.js +32 -14
- package/dist/environment/DayNightSky.js +5 -5
- package/dist/environment/Daylight.d.ts +35 -1
- package/dist/environment/Daylight.js +98 -28
- package/dist/environment/EnvironmentScene.js +11 -10
- package/dist/environment/VolumetricClouds.js +20 -2
- package/dist/environment/daylightCycle.d.ts +20 -0
- package/dist/environment/daylightCycle.js +59 -7
- package/dist/environment/sunShadowMath.d.ts +45 -0
- package/dist/environment/sunShadowMath.js +50 -0
- package/dist/input/gamepadPoll.d.ts +47 -0
- package/dist/input/gamepadPoll.js +142 -0
- package/dist/input/gamepadSource.d.ts +11 -1
- package/dist/input/gamepadSource.js +117 -71
- package/dist/input/mouseLook.js +2 -1
- package/dist/input/padHaptics.d.ts +17 -0
- package/dist/input/padHaptics.js +32 -0
- package/dist/input/pointerLock.d.ts +11 -0
- package/dist/input/pointerLock.js +19 -0
- package/dist/inputSink.d.ts +6 -6
- package/dist/inputSink.js +60 -21
- package/dist/lazyShell3dPresentation.d.ts +9 -0
- package/dist/lazyShell3dPresentation.js +24 -0
- package/dist/materialOverride.d.ts +42 -0
- package/dist/materialOverride.js +95 -36
- package/dist/multiplayer.d.ts +33 -3
- package/dist/multiplayer.js +105 -22
- package/dist/pointer/pointerService.d.ts +2 -0
- package/dist/pointer/pointerService.js +12 -2
- package/dist/postfx/PostProcessing.d.ts +11 -1
- package/dist/postfx/PostProcessing.js +14 -42
- package/dist/postfx/gradeShader.d.ts +1 -1
- package/dist/postfx/gradeShader.js +30 -2
- package/dist/postfx/shadowPrepass.d.ts +3 -0
- package/dist/postfx/shadowPrepass.js +18 -0
- package/dist/postfx/stylizePass.d.ts +23 -0
- package/dist/postfx/stylizePass.js +216 -0
- package/dist/presentationRecovery.d.ts +75 -0
- package/dist/presentationRecovery.js +204 -0
- package/dist/presentationRecovery3d.d.ts +4 -0
- package/dist/presentationRecovery3d.js +32 -0
- package/dist/presentationResolve.d.ts +8 -1
- package/dist/presentationResolve.js +5 -2
- package/dist/render/CascadedShadows.d.ts +7 -2
- package/dist/render/CascadedShadows.js +98 -20
- package/dist/render/EnvironmentLighting.js +74 -35
- package/dist/render/HairCards.d.ts +7 -0
- package/dist/render/HairCards.js +23 -0
- package/dist/render/SceneModels.js +52 -78
- package/dist/render/SkinnedInstances.d.ts +91 -0
- package/dist/render/SkinnedInstances.js +249 -0
- package/dist/render/TextureFiltering.d.ts +16 -0
- package/dist/render/TextureFiltering.js +64 -0
- package/dist/render/authoredSurfaceMaterial.d.ts +43 -0
- package/dist/render/authoredSurfaceMaterial.js +108 -0
- package/dist/render/displayColor.d.ts +33 -0
- package/dist/render/displayColor.js +138 -0
- package/dist/render/materialAppearanceSignals.d.ts +23 -0
- package/dist/render/materialAppearanceSignals.js +58 -0
- package/dist/render/materialAsset.d.ts +98 -0
- package/dist/render/materialAsset.js +454 -0
- package/dist/render/measureBounds.js +16 -3
- package/dist/render/measureCollisionMesh.js +8 -1
- package/dist/render/modelAssets.d.ts +8 -0
- package/dist/render/modelAssets.js +43 -0
- package/dist/render/modelBindPose.d.ts +5 -0
- package/dist/render/modelBindPose.js +35 -0
- package/dist/render/modelLoad.d.ts +32 -0
- package/dist/render/modelLoad.js +70 -1
- package/dist/render/modelNodeVisibility.d.ts +6 -0
- package/dist/render/modelNodeVisibility.js +18 -0
- package/dist/render/modelRender.d.ts +18 -1
- package/dist/render/modelRender.js +81 -3
- package/dist/render/projectedOverdraw.d.ts +35 -0
- package/dist/render/projectedOverdraw.js +204 -0
- package/dist/render/resolveModel.d.ts +12 -2
- package/dist/render/resolveModel.js +25 -4
- package/dist/render/rigNode.d.ts +26 -0
- package/dist/render/rigNode.js +32 -0
- package/dist/render/spriteRender.d.ts +4 -0
- package/dist/render/spriteRender.js +5 -0
- package/dist/render/staticShapeInstances.d.ts +34 -0
- package/dist/render/staticShapeInstances.js +78 -0
- package/dist/render/useFootIk.d.ts +53 -4
- package/dist/render/useFootIk.js +262 -70
- package/dist/render/useModelAnimation.d.ts +50 -0
- package/dist/render/useModelAnimation.js +245 -99
- package/dist/render/useModelInstance.d.ts +25 -0
- package/dist/render/useModelInstance.js +43 -0
- package/dist/scatter/scatterModels.d.ts +3 -2
- package/dist/scatter/scatterModels.js +15 -7
- package/dist/scene/AuthoredScene.d.ts +23 -6
- package/dist/scene/AuthoredScene.js +46 -9
- package/dist/scene/CityRenderer.js +6 -6
- package/dist/scene/GeneratedAssetRenderer.js +11 -42
- package/dist/settings/QuickControls.js +1 -1
- package/dist/settings/SettingsMenu.js +11 -18
- package/dist/settings/SettingsRuntime.d.ts +5 -0
- package/dist/settings/SettingsRuntime.js +29 -2
- package/dist/settings/appliedSettings.d.ts +9 -3
- package/dist/settings/appliedSettings.js +6 -5
- package/dist/settings/settingsController.d.ts +3 -0
- package/dist/settings/settingsController.js +47 -3
- package/dist/shellControlSuspension.d.ts +18 -0
- package/dist/shellControlSuspension.js +28 -0
- package/dist/shellInputPublication.d.ts +28 -0
- package/dist/shellInputPublication.js +49 -0
- package/dist/shellPointerInput.d.ts +18 -0
- package/dist/shellPointerInput.js +49 -0
- package/dist/structures/BuildingKitBatch.d.ts +3 -1
- package/dist/structures/BuildingKitBatch.js +35 -56
- package/dist/structures/BuildingRenderBudget.d.ts +23 -0
- package/dist/structures/BuildingRenderBudget.js +54 -0
- package/dist/structures/GeneratedBuilding.d.ts +3 -15
- package/dist/structures/GeneratedBuilding.js +33 -22
- package/dist/structures/buildingKitMaterials.d.ts +20 -0
- package/dist/structures/buildingKitMaterials.js +70 -0
- package/dist/structures/buildingSpatialBatch.d.ts +11 -0
- package/dist/structures/buildingSpatialBatch.js +45 -0
- package/dist/structures/buildingSurface.d.ts +21 -0
- package/dist/structures/buildingSurface.js +134 -0
- package/dist/terrain/GrassField.d.ts +2 -1
- package/dist/terrain/GrassField.js +59 -5
- package/dist/terrain/grassGeometry.d.ts +10 -0
- package/dist/terrain/grassGeometry.js +55 -0
- package/dist/terrain/grassMaterial.js +2 -2
- package/dist/terrain/terrainDetailMaterial.d.ts +3 -3
- package/dist/terrain/terrainDetailMaterial.js +7 -7
- package/dist/touch/TouchControlsOverlay.js +4 -4
- package/dist/useShellMultiplayerSync.d.ts +1 -1
- package/dist/useShellMultiplayerSync.js +9 -3
- package/dist/vfx/ParticleField.d.ts +23 -20
- package/dist/vfx/ParticleField.js +168 -50
- package/dist/visibility/CullingProvider.js +2 -62
- package/dist/visibility/cullingDriver.d.ts +9 -0
- package/dist/visibility/cullingDriver.js +68 -0
- package/dist/weather/AuthoredWeatherLayer.d.ts +16 -0
- package/dist/weather/AuthoredWeatherLayer.js +31 -0
- package/dist/weather/DustField.d.ts +2 -1
- package/dist/weather/DustField.js +17 -3
- package/dist/weather/FireSpreadLayer.d.ts +4 -2
- package/dist/weather/FireSpreadLayer.js +5 -11
- package/dist/weather/LightningStrike.d.ts +4 -1
- package/dist/weather/LightningStrike.js +13 -17
- package/dist/weather/RainField.d.ts +2 -1
- package/dist/weather/RainField.js +17 -3
- package/dist/weather/RainImpactField.d.ts +16 -0
- package/dist/weather/RainImpactField.js +89 -0
- package/dist/weather/SnowField.d.ts +2 -1
- package/dist/weather/SnowField.js +17 -3
- package/dist/weather/WeatherLayer.d.ts +11 -2
- package/dist/weather/WeatherLayer.js +30 -6
- package/dist/weather/index.d.ts +2 -0
- package/dist/weather/index.js +2 -0
- package/dist/weather/weatherMath.d.ts +2 -0
- package/dist/weather/weatherMath.js +8 -0
- package/dist/weather/weatherShelter.d.ts +18 -0
- package/dist/weather/weatherShelter.js +75 -0
- package/dist/weather/weatherUniforms.d.ts +40 -1
- package/dist/weather/weatherUniforms.js +29 -9
- package/dist/world/AuthoredFlocks.d.ts +22 -0
- package/dist/world/AuthoredFlocks.js +87 -0
- package/dist/world/StaticObjectModels.d.ts +8 -0
- package/dist/world/StaticObjectModels.js +75 -0
- package/dist/world/WorldHud.d.ts +14 -6
- package/dist/world/WorldHud.js +25 -12
- package/dist/world/WorldParticles.d.ts +10 -23
- package/dist/world/WorldParticles.js +210 -62
- package/dist/world/WorldScene.d.ts +3 -1
- package/dist/world/WorldScene.js +41 -26
- package/dist/world/staticObjectBatches.d.ts +35 -0
- package/dist/world/staticObjectBatches.js +163 -0
- package/dist/world/worldBarSamples.d.ts +37 -33
- package/dist/world/worldBarSamples.js +117 -75
- package/package.json +4 -4
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/game-design/SKILL.md +2 -2
- package/skills/jgengine/SKILL.md +28 -6
- package/skills/jgengine/api.md +139 -99
- package/skills/jgengine/capabilities.md +28 -0
- package/skills/jgengine/recipes/minimal-game.md +10 -2
- package/skills/jgengine-ui/SKILL.md +16 -17
- package/skills/jgengine-ui/api.md +603 -365
- package/skills/jgengine-ui/capabilities.md +131 -1
- package/skills/jgengine-ui/reference-primitives.md +179 -0
- package/skills/jgengine-ui/reference.md +4 -81
- package/skills/jgengine-world/SKILL.md +25 -4
- package/skills/jgengine-world/api.md +1045 -655
- package/skills/jgengine-world/capabilities.md +246 -9
- package/skills/jgengine-world/recipes/character-animation.md +62 -0
- package/skills/jgengine-world/recipes/controls.md +48 -0
- package/skills/jgengine-world/recipes/flight-feel.md +76 -0
- package/skills/jgengine-world/recipes/npc-senses.md +55 -0
- package/skills/jgengine-world/recipes/vehicle-feel.md +87 -0
- package/skills/jgengine-world/reference.md +180 -4
- package/skills/jgengine-world/visibility.md +139 -0
- package/skills/level-design/SKILL.md +1 -1
- package/dist/render/testFixtures/proceduralSpriteAtlas.d.ts +0 -15
- package/dist/render/testFixtures/proceduralSpriteAtlas.js +0 -30
- package/dist/render/testFixtures/proceduralTileLayer.d.ts +0 -13
- package/dist/render/testFixtures/proceduralTileLayer.js +0 -30
|
@@ -4,7 +4,11 @@
|
|
|
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
|
-
##
|
|
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.
|
|
8
12
|
|
|
9
13
|
- `createDecisionGraphRuntime` (function) · `import { createDecisionGraphRuntime } from "@jgengine/core/ai/decisionGraph"`
|
|
10
14
|
|
|
@@ -20,13 +24,23 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
20
24
|
|
|
21
25
|
- `createDriverState` (function) · `import { createDriverState } from "@jgengine/core/ai/driver"`
|
|
22
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
|
+
|
|
23
31
|
## anim-graph — data-first animation state machine with blend trees, crossfades, layers, and clip events
|
|
24
32
|
|
|
25
33
|
- `createAnimGraphRuntime` (function) · `import { createAnimGraphRuntime } from "@jgengine/core/anim/animGraph"`
|
|
34
|
+
- `parseAnimGraph` (function) · `import { parseAnimGraph } from "@jgengine/core/anim/animGraph"`
|
|
35
|
+
- `validateAnimGraph` (function) · `import { validateAnimGraph } from "@jgengine/core/anim/animGraph"`
|
|
26
36
|
|
|
27
|
-
## animation —
|
|
37
|
+
## animation — find thigh, shin and foot bones on a humanoid rig for foot IK
|
|
28
38
|
|
|
39
|
+
- `inferLegChains` (function) · `import { inferLegChains } from "@jgengine/core/anim/footPlacement"`
|
|
29
40
|
- `lookAt` (function) · `import { lookAt } from "@jgengine/core/anim/ikSolver"`
|
|
41
|
+
- `placeFeet` (function) · `import { placeFeet } from "@jgengine/core/anim/footPlacement"`
|
|
42
|
+
- `planBoneTexture` (function) · `import { planBoneTexture } from "@jgengine/core/anim/boneTexture"`
|
|
43
|
+
- `sampleBoneTexture` (function) · `import { sampleBoneTexture } from "@jgengine/core/anim/boneTexture"`
|
|
30
44
|
- `solveFabrik` (function) · `import { solveFabrik } from "@jgengine/core/anim/ikSolver"`
|
|
31
45
|
- `solveTwoBone` (function) · `import { solveTwoBone } from "@jgengine/core/anim/ikSolver"`
|
|
32
46
|
|
|
@@ -89,10 +103,24 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
89
103
|
|
|
90
104
|
- `defineAttackMoveOrder` (function) · `import { defineAttackMoveOrder } from "@jgengine/core/world"`
|
|
91
105
|
|
|
106
|
+
## audio-voice-budget — bound simultaneous sound playback with per-sound caps, priorities, and deterministic stealing
|
|
107
|
+
|
|
108
|
+
- `createVoiceAllocator` (function) · `import { createVoiceAllocator } from "@jgengine/core/audio/voiceAllocator"`
|
|
109
|
+
|
|
110
|
+
## authored-animation — consume live authored character animation with bounded per-frame work
|
|
111
|
+
|
|
112
|
+
- `createAuthoredAnimationReader` (function) · `import { createAuthoredAnimationReader } from "@jgengine/core/world/authoredAnimation"`
|
|
113
|
+
- `readAuthoredAnimation` (function) · `import { readAuthoredAnimation } from "@jgengine/core/world/authoredAnimation"`
|
|
114
|
+
- `readAuthoredAnimationValue` (function) · `import { readAuthoredAnimationValue } from "@jgengine/core/world/authoredAnimation"`
|
|
115
|
+
|
|
92
116
|
## authored-entities — spawn authored mob/boss markers from the editor document at runtime
|
|
93
117
|
|
|
94
118
|
- `authoredEntitySpawns` (function) · `import { authoredEntitySpawns } from "@jgengine/core/world/authoredEntities"`
|
|
95
119
|
|
|
120
|
+
## authored-environment — compose authored weather, shelter, accumulation, fire, flocks and effects using one simulation clock
|
|
121
|
+
|
|
122
|
+
- `createAuthoredSimulation` (function) · `import { createAuthoredSimulation } from "@jgengine/core/world/authoredSimulation"`
|
|
123
|
+
|
|
96
124
|
## authored-objects — marker kinds resolved as entity spawns, not static props
|
|
97
125
|
|
|
98
126
|
- `ENTITY_MARKER_KINDS` (const) · `import { ENTITY_MARKER_KINDS } from "@jgengine/core/world/authoredObjects"`
|
|
@@ -100,6 +128,12 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
100
128
|
- `markerCatalogId` (function) · `import { markerCatalogId } from "@jgengine/core/world"`
|
|
101
129
|
- `placeAuthoredObjects` (function) · `import { placeAuthoredObjects } from "@jgengine/core/world"`
|
|
102
130
|
- `resolveAuthoredObjects` (function) · `import { resolveAuthoredObjects } from "@jgengine/core/world"`
|
|
131
|
+
- `resolveAuthoredObjectsWithDiagnostics` (function) · `import { resolveAuthoredObjectsWithDiagnostics } from "@jgengine/core/world/authoredObjects"`
|
|
132
|
+
|
|
133
|
+
## authored-solids — collision for studio-authored world content such as city volumes
|
|
134
|
+
|
|
135
|
+
- `resolveAuthoredSolids` (function) · `import { resolveAuthoredSolids } from "@jgengine/core/world/authoredSolids"`
|
|
136
|
+
- `syncAuthoredSolids` (function) · `import { syncAuthoredSolids } from "@jgengine/core/world/authoredSolids"`
|
|
103
137
|
|
|
104
138
|
## authored-spawn — read spawn points and markers from the editor document
|
|
105
139
|
|
|
@@ -116,6 +150,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
116
150
|
- `registerBuiltinTriggerActions` (function) · `import { registerBuiltinTriggerActions } from "@jgengine/core/scene/authoredTriggers"`
|
|
117
151
|
- `registerTriggerAction` (function) · `import { registerTriggerAction } from "@jgengine/core/world"`
|
|
118
152
|
|
|
153
|
+
## authored-weather — Sample scheduled precipitation and local wind from one authored document and simulation clock.
|
|
154
|
+
|
|
155
|
+
- `createAuthoredWeather` (function) · `import { createAuthoredWeather } from "@jgengine/core/world/authoredWeather"`
|
|
156
|
+
|
|
157
|
+
## authored-weather-validation — Reject invalid weather profiles, schedules, zones and wind before authoring mutations.
|
|
158
|
+
|
|
159
|
+
- `validateAuthoredWeather` (function) · `import { validateAuthoredWeather } from "@jgengine/core/world/authoredWeather"`
|
|
160
|
+
|
|
161
|
+
## axis-shaping — shape raw input per axis — deadzone, response curve, keyboard ramp, self-centring, speed-sensitive scaling
|
|
162
|
+
|
|
163
|
+
- `createAxisShaper` (function) · `import { createAxisShaper } from "@jgengine/core/input/axisShaper"`
|
|
164
|
+
|
|
119
165
|
## behavior-actions — register named callbacks for decision graph behavior descriptors
|
|
120
166
|
|
|
121
167
|
- `registerBehaviorActions` (function) · `import { registerBehaviorActions } from "@jgengine/core/world"`
|
|
@@ -124,14 +170,26 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
124
170
|
|
|
125
171
|
- `behaviorControl` (function) · `import { behaviorControl } from "@jgengine/core/world"`
|
|
126
172
|
|
|
127
|
-
## behavior-tick — auto-advance patrol
|
|
173
|
+
## behavior-tick — auto-advance spawned patrol, wander, pursuit and decision graph behaviors with lifecycle control
|
|
128
174
|
|
|
129
175
|
- `advanceBehaviors` (function) · `import { advanceBehaviors } from "@jgengine/core/world"`
|
|
130
176
|
|
|
177
|
+
## board-vehicle — board a rideable, freeze/hide its rider and apply caller camera policy
|
|
178
|
+
|
|
179
|
+
- `boardVehicle` (function) · `import { boardVehicle } from "@jgengine/core/world"`
|
|
180
|
+
|
|
181
|
+
## boat-dynamics — force-based powered hull — hull-speed drag hump, planing, keel, rudder that needs flow or outboard thrust
|
|
182
|
+
|
|
183
|
+
- `createBoatDynamics` (function) · `import { createBoatDynamics } from "@jgengine/core/physics/boatDynamics"`
|
|
184
|
+
|
|
131
185
|
## body-bind — mirror sim-body snapshots onto scene entities each tick, no per-body setPose
|
|
132
186
|
|
|
133
187
|
- `createBodyBind` (function) · `import { createBodyBind } from "@jgengine/core/world"`
|
|
134
188
|
|
|
189
|
+
## bounded-grid-route — distinguish no path from exhausted grid search work
|
|
190
|
+
|
|
191
|
+
- `findPathResult` (function) · `import { findPathResult } from "@jgengine/core/nav/navGrid"`
|
|
192
|
+
|
|
135
193
|
## build-footprint-cells — grid cells a snapped build piece footprint covers (footprintGrid occupancy bridge)
|
|
136
194
|
|
|
137
195
|
- `footprintCells` (function) · `import { footprintCells } from "@jgengine/core/world/buildSockets"`
|
|
@@ -167,6 +225,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
167
225
|
## city-district — polygon math for road-derived blocks, parcels, and buildable footprints
|
|
168
226
|
|
|
169
227
|
- `Vec2` (type) · `import { Vec2 } from "@jgengine/core/world/cityGeometry"`
|
|
228
|
+
- `citySolids` (function) · `import { citySolids } from "@jgengine/core/world/cityKind"`
|
|
170
229
|
- `extractGraphBlocks` (function) · `import { extractGraphBlocks } from "@jgengine/core/world/cityBlocks"`
|
|
171
230
|
- `rectClearsPolyline` (function) · `import { rectClearsPolyline } from "@jgengine/core/world/cityGeometry"`
|
|
172
231
|
- `rectsSeparated` (function) · `import { rectsSeparated } from "@jgengine/core/world/cityGeometry"`
|
|
@@ -193,6 +252,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
193
252
|
|
|
194
253
|
- `createTimerSet` (function) · `import { createTimerSet } from "@jgengine/core/world"`
|
|
195
254
|
|
|
255
|
+
## course-metrics — measure a vehicle on driven tests — understeer gradient, skidpad g, slalom speed
|
|
256
|
+
|
|
257
|
+
- `measureCourse` (function) · `import { measureCourse } from "@jgengine/core/physics/handlingProbe"`
|
|
258
|
+
|
|
196
259
|
## crouch-prone — stance/pose transitions that change the hitbox
|
|
197
260
|
|
|
198
261
|
- `createPoseState` (function) · `import { createPoseState } from "@jgengine/core/world"`
|
|
@@ -241,6 +304,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
241
304
|
|
|
242
305
|
- `DIFFICULTY_TIERS` (const) · `import { DIFFICULTY_TIERS } from "@jgengine/core/ai/difficulty"`
|
|
243
306
|
|
|
307
|
+
## doppler-pitch — pitch a moving sound up as it approaches and down as it passes, from listener and emitter velocity
|
|
308
|
+
|
|
309
|
+
- `dopplerRate` (function) · `import { dopplerRate } from "@jgengine/core/audio/doppler"`
|
|
310
|
+
|
|
311
|
+
## drivable-vehicle — drive a car from throttle/steer/handbrake input each tick: step the vehicle sim and pose its entity
|
|
312
|
+
|
|
313
|
+
- `tickDrivableVehicle` (function) · `import { tickDrivableVehicle } from "@jgengine/core/world"`
|
|
314
|
+
|
|
244
315
|
## elevation-readout — cursor height and delta-from-reference feedback
|
|
245
316
|
|
|
246
317
|
- `sampleElevation` (function) · `import { sampleElevation } from "@jgengine/core/world"`
|
|
@@ -249,17 +320,33 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
249
320
|
|
|
250
321
|
- `summarizeElevation` (function) · `import { summarizeElevation } from "@jgengine/core/world"`
|
|
251
322
|
|
|
323
|
+
## engine-layers — layered engine audio: rpm-keyed samples crossfaded, with on-load and off-load sets picked by engine load
|
|
324
|
+
|
|
325
|
+
- `createEngineLayers` (function) · `import { createEngineLayers } from "@jgengine/core/audio/engineLayers"`
|
|
326
|
+
|
|
252
327
|
## entity-meta — cast-free narrow of SceneEntity.meta via a type guard
|
|
253
328
|
|
|
254
329
|
- `entityMetaOf` (function) · `import { entityMetaOf } from "@jgengine/core/world"`
|
|
255
330
|
|
|
331
|
+
## environment-motion — apply capped spatial wind and vortex forces to game-selected actors through shared motion intents
|
|
332
|
+
|
|
333
|
+
- `installEnvironmentMotion` (function) · `import { installEnvironmentMotion } from "@jgengine/core/world/environmentForces"`
|
|
334
|
+
|
|
256
335
|
## fast-travel — network of fast-travel destinations with discovery, distance-sorted queries, nearest lookup, a travel gate, and serializable state
|
|
257
336
|
|
|
258
337
|
- `createFastTravelNetwork` (function) · `import { createFastTravelNetwork } from "@jgengine/core/world"`
|
|
259
338
|
|
|
260
|
-
##
|
|
339
|
+
## feedback-mixer — map sim telemetry to camera, audio and haptic parameters through curves, smoothing and threshold events
|
|
340
|
+
|
|
341
|
+
- `createFeedbackMixer` (function) · `import { createFeedbackMixer } from "@jgengine/core/vfx/feedbackMixer"`
|
|
261
342
|
|
|
262
|
-
-
|
|
343
|
+
## 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
|
|
344
|
+
|
|
345
|
+
- `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/input/actionBindings"`
|
|
346
|
+
|
|
347
|
+
## flight-metrics — measure an aircraft's feel as numbers — roll rate, sustained turn, stall speed, climb, throttle response, hover drift
|
|
348
|
+
|
|
349
|
+
- `measureFlight` (function) · `import { measureFlight } from "@jgengine/core/physics/handlingProbe"`
|
|
263
350
|
|
|
264
351
|
## follow-trail — trailing follower/snake formation that chases a leader
|
|
265
352
|
|
|
@@ -269,6 +356,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
269
356
|
|
|
270
357
|
- `createFootprintGrid` (function) · `import { createFootprintGrid } from "@jgengine/core/world"`
|
|
271
358
|
|
|
359
|
+
## force-field-validation — reject invalid localized force authoring before simulation
|
|
360
|
+
|
|
361
|
+
- `validateForceField` (function) · `import { validateForceField } from "@jgengine/core/physics/forceVolume"`
|
|
362
|
+
|
|
272
363
|
## formation-assignment — stable deterministic member-to-slot matching for a group formation
|
|
273
364
|
|
|
274
365
|
- `assignFormationSlots` (function) · `import { assignFormationSlots } from "@jgengine/core/world"`
|
|
@@ -327,10 +418,22 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
327
418
|
|
|
328
419
|
- `grounded` (function) · `import { grounded } from "@jgengine/core/world"`
|
|
329
420
|
|
|
421
|
+
## handling-metrics — measure a vehicle's feel as numbers — 0–100, braking, lateral g, turn-in, sideslip, spin
|
|
422
|
+
|
|
423
|
+
- `measureHandling` (function) · `import { measureHandling } from "@jgengine/core/physics/handlingProbe"`
|
|
424
|
+
|
|
425
|
+
## haptics — Continuous gamepad rumble from named channels (engine, road, impact) mixed by priority, plus fading pulses.
|
|
426
|
+
|
|
427
|
+
- `createHapticChannels` (function) · `import { createHapticChannels } from "@jgengine/core/input/haptics"`
|
|
428
|
+
|
|
330
429
|
## hold-order — stand-ground order that holds position until preempted or canceled
|
|
331
430
|
|
|
332
431
|
- `defineHoldOrder` (function) · `import { defineHoldOrder } from "@jgengine/core/world"`
|
|
333
432
|
|
|
433
|
+
## input-buffer — buffer early presses, coyote time, hold duration and double tap for responsive controls
|
|
434
|
+
|
|
435
|
+
- `createInputBuffer` (function) · `import { createInputBuffer } from "@jgengine/core/input/inputBuffer"`
|
|
436
|
+
|
|
334
437
|
## interaction-prompt — observable nearest-interactable prompt registry over the proximity-prompt resolver — register/resolve/active with priority+range and change-notified snapshot/restore
|
|
335
438
|
|
|
336
439
|
- `createPromptRegistry` (function) · `import { createPromptRegistry } from "@jgengine/core/world"`
|
|
@@ -355,6 +458,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
355
458
|
|
|
356
459
|
- `createRebindSession` (function) · `import { createRebindSession } from "@jgengine/core/input/rebindSession"`
|
|
357
460
|
|
|
461
|
+
## kinematic-vehicle — arcade car/kart driving physics with throttle, brake, steer and retunable handling
|
|
462
|
+
|
|
463
|
+
- `createKinematicVehicle` (function) · `import { createKinematicVehicle } from "@jgengine/core/world"`
|
|
464
|
+
|
|
465
|
+
## lean-metrics — measure a motorcycle's lean — steady lean, time to lean, countersteer tip-in
|
|
466
|
+
|
|
467
|
+
- `measureLean` (function) · `import { measureLean } from "@jgengine/core/physics/handlingProbe"`
|
|
468
|
+
|
|
469
|
+
## leave-vehicle — leave a rideable beside its current pose and restore on-foot camera/movement
|
|
470
|
+
|
|
471
|
+
- `leaveVehicle` (function) · `import { leaveVehicle } from "@jgengine/core/world"`
|
|
472
|
+
|
|
358
473
|
## limb-health — per-body-part/region health tracked separately
|
|
359
474
|
|
|
360
475
|
- `createMultiRegionHealth` (function) · `import { createMultiRegionHealth } from "@jgengine/core/procedural"`
|
|
@@ -363,18 +478,36 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
363
478
|
|
|
364
479
|
- `resolveLocalAvoidance` (function) · `import { resolveLocalAvoidance } from "@jgengine/core/world"`
|
|
365
480
|
|
|
481
|
+
## localized-forces — sample signed attraction, directional force, vortex spin and axial lift with target masks and caps
|
|
482
|
+
|
|
483
|
+
- `sampleForceField` (function) · `import { sampleForceField } from "@jgengine/core/physics/forceVolume"`
|
|
484
|
+
|
|
366
485
|
## lockpick — a solvable grid depth-puzzle with fog-of-war, gates, and hidden traps
|
|
367
486
|
|
|
368
487
|
- `generateLock` (function) · `import { generateLock } from "@jgengine/core/world"`
|
|
369
488
|
|
|
370
|
-
## locomotion-graph —
|
|
489
|
+
## locomotion-graph — resolve the animation graph a model config plays
|
|
371
490
|
|
|
491
|
+
- `animGraphFromConfig` (function) · `import { animGraphFromConfig } from "@jgengine/core/anim/locomotionGraph"`
|
|
372
492
|
- `locomotionGraph` (function) · `import { locomotionGraph } from "@jgengine/core/anim/locomotionGraph"`
|
|
373
493
|
|
|
374
494
|
## map-annotations — player-drawn map annotation layer — freehand strokes, area shapes, and pinned notes, projected into the map's routes/zones props and serializable
|
|
375
495
|
|
|
376
496
|
- `createAnnotationLayer` (function) · `import { createAnnotationLayer } from "@jgengine/core/world"`
|
|
377
497
|
|
|
498
|
+
## material-appearance-signals — adapt selected surface response to sampled wetness and local card exposure
|
|
499
|
+
|
|
500
|
+
- `resolveMaterialAppearance` (function) · `import { resolveMaterialAppearance } from "@jgengine/core/material/appearanceSignals"`
|
|
501
|
+
- `sampleMaterialAppearance` (function) · `import { sampleMaterialAppearance } from "@jgengine/core/material/appearanceSignals"`
|
|
502
|
+
|
|
503
|
+
## merge-footprint-regions — pool adjacent compatible footprints with serializable capacity provenance
|
|
504
|
+
|
|
505
|
+
- `mergeFootprints` (function) · `import { mergeFootprints } from "@jgengine/core/world"`
|
|
506
|
+
|
|
507
|
+
## mergeable-footprint-regions — check compatible adjacent regions within caller work budgets
|
|
508
|
+
|
|
509
|
+
- `canMerge` (function) · `import { canMerge } from "@jgengine/core/world"`
|
|
510
|
+
|
|
378
511
|
## mesh-hitboxes — shots pass through holes in concave models — opted-in catalog assets raycast their actual triangles instead of the fitted box.
|
|
379
512
|
|
|
380
513
|
- `ColliderShape` (type) · `import { ColliderShape } from "@jgengine/core/scene/colliders"`
|
|
@@ -400,6 +533,34 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
400
533
|
|
|
401
534
|
- `defineMoveOrder` (function) · `import { defineMoveOrder } from "@jgengine/core/world"`
|
|
402
535
|
|
|
536
|
+
## movement-metrics — measure a walking character's feel as numbers — time to top speed, stop distance, jump height and apex, air control, turn-around
|
|
537
|
+
|
|
538
|
+
- `measureMovement` (function) · `import { measureMovement } from "@jgengine/core/movement/movementProbe"`
|
|
539
|
+
|
|
540
|
+
## movement-telemetry — read physical grounded, vertical velocity and crouch state without animation-store writes
|
|
541
|
+
|
|
542
|
+
- `playerMovementTelemetry` (function) · `import { playerMovementTelemetry } from "@jgengine/core/movement/playerMovement"`
|
|
543
|
+
|
|
544
|
+
## moving-box-sweep — detect contact with boxes crossing a projectile segment between simulation poses
|
|
545
|
+
|
|
546
|
+
- `sweepMovingBounds` (function) · `import { sweepMovingBounds } from "@jgengine/core/physics/ballisticSweep"`
|
|
547
|
+
|
|
548
|
+
## moving-sphere-sweep — detect contact with spheres crossing a projectile segment between simulation poses
|
|
549
|
+
|
|
550
|
+
- `sweepMovingSphere` (function) · `import { sweepMovingSphere } from "@jgengine/core/physics/ballisticSweep"`
|
|
551
|
+
|
|
552
|
+
## nav-from-solids — block world solids on a nav grid
|
|
553
|
+
|
|
554
|
+
- `populateNavGridFromSolids` (function) · `import { populateNavGridFromSolids } from "@jgengine/core/nav/navFromEnvironment"`
|
|
555
|
+
|
|
556
|
+
## navmesh-bake — voxelize scene triangles into an agent-sized polygon nav mesh
|
|
557
|
+
|
|
558
|
+
- `bakeNavMesh` (function) · `import { bakeNavMesh } from "@jgengine/navbake"`
|
|
559
|
+
|
|
560
|
+
## navmesh-query — route, snap, and raycast on a polygon navmesh with retunable area costs and a bounded search
|
|
561
|
+
|
|
562
|
+
- `createNavMeshQuery` (function) · `import { createNavMeshQuery } from "@jgengine/core/world"`
|
|
563
|
+
|
|
403
564
|
## object-slot-inventory — placed objects hold validated per-instance container contents that replicate and save with the placement
|
|
404
565
|
|
|
405
566
|
- `SceneObjectSlots` (interface) · `import { SceneObjectSlots } from "@jgengine/core/world"`
|
|
@@ -412,11 +573,19 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
412
573
|
|
|
413
574
|
- `createOrderRegistry` (function) · `import { createOrderRegistry } from "@jgengine/core/world"`
|
|
414
575
|
|
|
415
|
-
## particle-
|
|
576
|
+
## particle-binding-validation — validate named particle follow spaces, render outputs, environment influence, and bounded collision child effects
|
|
577
|
+
|
|
578
|
+
- `validateParticleAttachOptions` (function) · `import { validateParticleAttachOptions } from "@jgengine/core/vfx/particleDirector"`
|
|
579
|
+
|
|
580
|
+
## particle-director — named particle start/stop/burst/retune lifecycle, local/world following, render outputs, bounded cosmetic event exchange, and serializable emitter definitions
|
|
416
581
|
|
|
417
582
|
- `createParticleDirector` (function) · `import { createParticleDirector } from "@jgengine/core/vfx/particleDirector"`
|
|
418
583
|
|
|
419
|
-
## particle-
|
|
584
|
+
## particle-emitter-validation — validate finite spawn volumes, force fields, lifetimes, appearance curves, and bounded particle collision policies
|
|
585
|
+
|
|
586
|
+
- `validateEmitterConfig` (function) · `import { validateEmitterConfig } from "@jgengine/core/vfx/particles"`
|
|
587
|
+
|
|
588
|
+
## particle-system — deterministic pooled particle emitter with spawn volumes, force fields, bounded collision/death events, live tuning, SoA render buffers, and serializable state
|
|
420
589
|
|
|
421
590
|
- `createParticleSystem` (function) · `import { createParticleSystem } from "@jgengine/core/world"`
|
|
422
591
|
|
|
@@ -497,7 +666,11 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
497
666
|
|
|
498
667
|
- `resolveActivePrompt` (function) · `import { resolveActivePrompt } from "@jgengine/core/world"`
|
|
499
668
|
|
|
500
|
-
##
|
|
669
|
+
## pursue-behavior — scheduled pursuit with bounded target acquisition and saved cooldown/leash state
|
|
670
|
+
|
|
671
|
+
- `pursue` (function) · `import { pursue } from "@jgengine/core/world"`
|
|
672
|
+
|
|
673
|
+
## pursuit — enemy/mob aggro chase-to-reach with a cooldown-gated attack and optional leash-to-home; owns the attack cooldown
|
|
501
674
|
|
|
502
675
|
- `advancePursuit` (function) · `import { advancePursuit } from "@jgengine/core/ai/pursuit"`
|
|
503
676
|
|
|
@@ -521,6 +694,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
521
694
|
|
|
522
695
|
- `createResourceNodeField` (function) · `import { createResourceNodeField } from "@jgengine/core/world/resourceNode"`
|
|
523
696
|
|
|
697
|
+
## ride-metrics — measure a sprung vehicle's ride — settle time, dive, roll per g, landing bounce
|
|
698
|
+
|
|
699
|
+
- `measureRide` (function) · `import { measureRide } from "@jgengine/core/physics/handlingProbe"`
|
|
700
|
+
|
|
701
|
+
## rigid-aircraft — force-and-torque aircraft — lifting surfaces with stall and drag polar, control surfaces, inertia, loops and rolls
|
|
702
|
+
|
|
703
|
+
- `createRigidAircraft` (function) · `import { createRigidAircraft } from "@jgengine/core/physics/aircraftDynamics"`
|
|
704
|
+
|
|
524
705
|
## rts-control-groups — map Ctrl+digit / digit / double-tap presses onto selection-bookmark bind / recall / focus intents
|
|
525
706
|
|
|
526
707
|
- `controlGroupKey` (function) · `import { controlGroupKey } from "@jgengine/core/world"`
|
|
@@ -560,8 +741,17 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
560
741
|
|
|
561
742
|
## solid-obstacles — the one blocking-geometry query the player resolver and NPC movers share
|
|
562
743
|
|
|
744
|
+
- `obstacleFromSolid` (function) · `import { obstacleFromSolid } from "@jgengine/core/movement/solidObstacles"`
|
|
563
745
|
- `solidObstaclesNear` (function) · `import { solidObstaclesNear } from "@jgengine/core/movement/solidObstacles"`
|
|
564
746
|
|
|
747
|
+
## solid-route — bounded local planning over indexed collision geometry
|
|
748
|
+
|
|
749
|
+
- `planSolidRoute` (function) · `import { planSolidRoute } from "@jgengine/core/nav/solidRoute"`
|
|
750
|
+
|
|
751
|
+
## spatial-incremental — Update one entity's spatial cell after a committed write without scanning the population
|
|
752
|
+
|
|
753
|
+
- `createSpatialApi` (function) · `import { createSpatialApi } from "@jgengine/core/scene/spatial"`
|
|
754
|
+
|
|
565
755
|
## spatial-region-box — sample uniformly within an axis-aligned 3D box
|
|
566
756
|
|
|
567
757
|
- `boxRegion` (function) · `import { boxRegion } from "@jgengine/core/world"`
|
|
@@ -602,6 +792,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
602
792
|
|
|
603
793
|
- `sampleStratified` (function) · `import { sampleStratified } from "@jgengine/core/world"`
|
|
604
794
|
|
|
795
|
+
## split-footprint-regions — split pooled regions along retained contributions without area-based capacity loss
|
|
796
|
+
|
|
797
|
+
- `splitRegion` (function) · `import { splitRegion } from "@jgengine/core/world"`
|
|
798
|
+
|
|
605
799
|
## stop-order — halt-and-complete order that brings a unit to an immediate standstill
|
|
606
800
|
|
|
607
801
|
- `defineStopOrder` (function) · `import { defineStopOrder } from "@jgengine/core/world"`
|
|
@@ -622,6 +816,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
622
816
|
|
|
623
817
|
- `surfaceRing` (function) · `import { surfaceRing } from "@jgengine/core/world"`
|
|
624
818
|
|
|
819
|
+
## sync-authored-objects — synchronize edited catalog prop poses, elevation and removal through the existing object store
|
|
820
|
+
|
|
821
|
+
- `syncAuthoredObjects` (function) · `import { syncAuthoredObjects } from "@jgengine/core/world/authoredObjects"`
|
|
822
|
+
|
|
625
823
|
## tactical-cover-points — derive cover candidates from navigation-mesh boundaries
|
|
626
824
|
|
|
627
825
|
- `coverPoints` (function) · `import { coverPoints } from "@jgengine/core/ai/tacticalQueries"`
|
|
@@ -683,6 +881,22 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
683
881
|
- `setTouchControlsMode` (function) · `import { setTouchControlsMode } from "@jgengine/core/input/touchControlsMode"`
|
|
684
882
|
- `touchButtonShape` (function) · `import { touchButtonShape } from "@jgengine/core/input/touchScheme"`
|
|
685
883
|
|
|
884
|
+
## uphill-grade-step — constrain sampled heightfield ascent with axis sliding and a configurable terrain-policy sampler
|
|
885
|
+
|
|
886
|
+
- `resolveTerrainGradeStep` (function) · `import { resolveTerrainGradeStep } from "@jgengine/core/movement/terrainGrade"`
|
|
887
|
+
|
|
888
|
+
## vehicle-backend-link — collide a vehicle sim with a physics backend — shove props, stop at walls, slide along them
|
|
889
|
+
|
|
890
|
+
- `createVehicleBackendLink` (function) · `import { createVehicleBackendLink } from "@jgengine/core/physics/vehicleBackendLink"`
|
|
891
|
+
|
|
892
|
+
## vehicle-dynamics — force-based car handling — tires, load transfer, drivetrain, assists — tuned with physical numbers
|
|
893
|
+
|
|
894
|
+
- `createVehicleDynamics` (function) · `import { createVehicleDynamics } from "@jgengine/core/physics/vehicleDynamics"`
|
|
895
|
+
|
|
896
|
+
## vehicle-seats — enter, exit and swap seats in a car or mount (GTA-style boarding) with driver and passenger slots
|
|
897
|
+
|
|
898
|
+
- `createVehicleSeats` (function) · `import { createVehicleSeats } from "@jgengine/core/world"`
|
|
899
|
+
|
|
686
900
|
## visibility-field — per-viewer-group observed/remembered/hidden fog-of-war knowledge with terrain memory and authoritative entity disclosure
|
|
687
901
|
|
|
688
902
|
- `createVisibilityField` (function) · `import { createVisibilityField } from "@jgengine/core/world"`
|
|
@@ -707,6 +921,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
707
921
|
|
|
708
922
|
- `createWaypointStore` (function) · `import { createWaypointStore } from "@jgengine/core/world"`
|
|
709
923
|
|
|
924
|
+
## weather-environment-field — Connect authored precipitation and temperature changes to spatial environment queries.
|
|
925
|
+
|
|
926
|
+
- `createWeatherEnvironmentField` (function) · `import { createWeatherEnvironmentField } from "@jgengine/core/world/authoredWeather"`
|
|
927
|
+
|
|
928
|
+
## weather-surface-accumulation — Persist and retune bounded surface wetness, snow, temperature and exposure independently of rendering.
|
|
929
|
+
|
|
930
|
+
- `createWeatherExposure` (function) · `import { createWeatherExposure } from "@jgengine/core/world/authoredWeather"`
|
|
931
|
+
|
|
710
932
|
## world-environment — compose editor/preset-derived outdoor dressing — terrain, weather, water, structures — into a legacy environment feature
|
|
711
933
|
|
|
712
934
|
- `environment` (function) · `import { environment } from "@jgengine/core/world"`
|
|
@@ -729,3 +951,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
729
951
|
## world-seed — derive a deterministic generator/scatter seed from world id + save/run seed
|
|
730
952
|
|
|
731
953
|
- `seedForPlace` (function) · `import { seedForPlace } from "@jgengine/core/world"`
|
|
954
|
+
|
|
955
|
+
## world-solid-bounds — world AABB and nav footprint of a world solid
|
|
956
|
+
|
|
957
|
+
- `worldSolidBounds` (function) · `import { worldSolidBounds } from "@jgengine/core/world/worldSolids"`
|
|
958
|
+
- `worldSolidFootprint` (function) · `import { worldSolidFootprint } from "@jgengine/core/world/worldSolids"`
|
|
959
|
+
|
|
960
|
+
## world-solids — collision for generated and authored world geometry (buildings, city lots, walls)
|
|
961
|
+
|
|
962
|
+
- `createWorldSolids` (function) · `import { createWorldSolids } from "@jgengine/core/world/worldSolids"`
|
|
963
|
+
|
|
964
|
+
## world-solids-from-data — derive collision boxes from generated buildings and wall runs
|
|
965
|
+
|
|
966
|
+
- `buildingSolids` (function) · `import { buildingSolids } from "@jgengine/core/world/worldSolids"`
|
|
967
|
+
- `structureSolids` (function) · `import { structureSolids } from "@jgengine/core/world/worldSolids"`
|
|
968
|
+
- `wallSolids` (function) · `import { wallSolids } from "@jgengine/core/world/worldSolids"`
|
|
@@ -0,0 +1,62 @@
|
|
|
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. Equivalent same-order animation data survives ordinary React rerenders without restarting gait, pending triggers or visual variant choices. The hook retains a private serialized snapshot; intentional clip, playback or graph edits restart that model’s playback. Keep authored one-shot order: it decides priority among simultaneous non-death triggers. Changing the scene, imported clips, context or instance identity starts a new animation lifecycle.
|
|
8
|
+
- **Playback clock.** An entity-bound model (`instanceId` with a game context) holds its animation while game time is paused or has zero timescale. Resume continues the existing mixer/graph and queued triggers. Omitted `animation.clock` or `clock: "real"` retains real-time playback. Choose `{ auto: true, clock: "game" }` for a character whose gait and clip progress should follow locally accepted simulation time. The shell samples `ctx.time.advancedSeconds()` rather than multiplying the raw render delta: clamped frames, fixed steps with no accepted tick and dropped catch-up time cannot advance clips ahead of movement. Accepted seconds already include play speed and timescale, exclude calendar compression, and never hydrate or serialize with saved clock offsets. Held frames checkpoint progress so resume does not replay their elapsed time; `animation.timeScale` remains a separate authored visual rate. Context-hosted unbound previews and previews without a context keep using real time.
|
|
9
|
+
- `createSimClock` supplies the allocation-free progress getter. The getter is optional on external structural clocks; selecting game playback without one produces a repair warning and holds the pose. Provide that clock capability or choose real-time playback.
|
|
10
|
+
- This is local accepted progress. Hosted prediction with `advanceTime: false` contributes no progress; it does not supply an accepted remote timeline. Keep real-time playback for those clients unless their clock supplies the intended progress. No snapshot, persistence or signaling format changes are required by the local policy.
|
|
11
|
+
- **Automatic roles with controls.** `animation: "auto"` retains the existing defaults. `{ auto: true, clock: "game" }` derives those same roles and one-shot variants from the loaded rig, then applies explicit configuration fields. Explicit `states`, `oneShots` and `graph` replace their whole fields rather than merging mappings; empty maps retain their meaning. A rig without an identifiable idle does not acquire a guessed first-clip fallback. In the inspector's Custom playback controls, select the clock and optionally derive loaded clip roles; selecting a single clip clears automatic derivation. Both settings are ordinary `meta.animation` data and use the same strict reader, undo, save and reload path as other animation controls.
|
|
12
|
+
- **Modular visibility.** `ModelConfig.hiddenNodes: ["Knife", "Rogue_Cape"]` hides named visual subtrees on that model instance. Ordinary entity models and custom `useModelInstance` hosts share the selection. Names resolve through `resolveRigNode`; missing or ambiguous names warn and leave the body intact. Malformed lists reject before model or texture allocation. Imported invisible nodes stay invisible, and omitting the field or passing `[]` preserves imported visibility. This does not delete bones, retarget clips or mask skinned vertices. The selected visible bind bounds drive `targetHeight` and grounding before animation; catalog dimensions remain source metadata. Reordered or duplicate names retain the clone; a changed selection replaces only that instance and restarts its visual animation lifecycle. Choose names from the actual asset; instanced crowd/scatter renderers do not implement this selection.
|
|
13
|
+
- **Placement.** `targetHeight` normalizes skin-applied imported bind bounds and grounds them at `ModelConfig.y`, then `scale` multiplies that height. The renderer caches skin-applied vertices before animation and shares them between clones, so skin deformation cannot change normalization or fitted collision triangles. Imported root transforms stay inside a separate placement frame shared by render bounds and collision triangles; clips keep binding to the imported root.
|
|
14
|
+
- Editor clip and graph previews use this same placement frame through `useModelInstance`; they pose its `content` and mount its `scene` with the returned `scale` and `position`. Clip metadata uses the shared loader cache, and closing a preview releases only its own materials and bone textures.
|
|
15
|
+
- Heightfield player collision has its own `movement.collisionHeight` (positive meters from feet; default 1.8). Choose it for the game's physical body and author it through a supplied `createMovementSchema` catalog field. Rendered `targetHeight`/`scale` and camera target/eye height remain independent; they do not silently resize the motor. Capsule and voxel controllers keep their declared dimensions.
|
|
16
|
+
- **Movement authoring.** A game-named movement catalog can expose the motor's existing jump buffer, coyote grace, release factor, apex/fall gravity and landing recovery controls through supplied `createMovementSchema` defaults. Deeper controls appear in a collapsed **Jump response** group; the common setup does not acquire unused controls. Consume the saved row with `bindAuthoredMovement` to tune `movement.feel` live while retaining the game's callbacks and physics. These are physical movement controls; graph clips and transition choices remain authored separately.
|
|
17
|
+
- **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.
|
|
18
|
+
- `locomotionGraph({ idle, walk, run, walkSpeed, runSpeed, fadeSec, oneShots })` builds the idle/walk/run blend plus one-shots; `states`/`oneShots` configs are converted through it. One-shot arrays retain every variant. `death` takes priority over simultaneous triggers and holds until the graph is reset; later hit/attack triggers cannot release it.
|
|
19
|
+
- 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.
|
|
20
|
+
- Each layer owns its clip times and weights. Within one layer, two states using the same clip still resolve to one clip time; blending separate times of that same clip is unsupported.
|
|
21
|
+
- `createAnimGraphRuntime(graph, { rng })` runs the same graph headless: `advance(dt, params, clips)`, `trigger`, `snapshot`/`restore`, `retune`. A clip state's `variants` are chosen once on entry; snapshots preserve that choice. Omit `rng` for the first variant. Runtime models use independent seeded visual streams keyed by instance id and imported clip names, so rendering or culling models cannot advance gameplay randomness. Remounting restarts that visual stream; gameplay-critical clip choices belong in a caller-owned headless runtime and its saved state. Outgoing clips keep advancing during crossfades. Test transitions with it before looking at pixels.
|
|
22
|
+
- **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. A missing/blank idle role leaves a named single clip active (or the bind pose if none is named); a missing/blank walk role holds the named idle at walking speeds. The inspector seeds supported semantic roles from the actual asset when enabling locomotion; imported assets without such roles need explicit choices. `validateAnimGraph(json)` rejects malformed saved graphs with located repairs, preserving valid graph data and transition order. `parseAnimGraph(json)` remains the permissive import path that drops malformed entries.
|
|
23
|
+
- **Static character placements.** Catalog placements validate saved `meta.animation` with the same strict value reader as dynamic characters and the inspector. A malformed override is omitted so the original catalog animation remains active; the saved document and placement stay unchanged. `resolveAuthoredObjectsWithDiagnostics(document)` returns the ordinary objects plus located repairs in one scan, and `<AuthoredObjects>` reports those repairs at runtime. Valid partial roles, empty maps, signed rates, ordered variants and extension fields keep their authored meaning. Asset clip and rig compatibility still belongs to the model diagnostics.
|
|
24
|
+
- **Dynamic character authoring.** Store animation on the game-selected marker at `meta.animation` through ordinary editor commands, then use `createAuthoredAnimationReader(() => getDocumentLiveSync()?.getDocument() ?? editorLayers, markerId, gameDefault)` (`@jgengine/core/world/authoredAnimation`). A game-owned `ModelConfig.animation` getter returns `read().animation`; the game chooses the actor-to-marker association, rig and defaults. The reader validates only after immutable document identity changes. Authored objects replace defaults rather than merging their roles, graph or combat triggers; explicit `"auto"`/`"none"` and in-progress empty/partial roles survive save/reload. Omitted or malformed overrides retain the exact game default, and `read().diagnostics` supplies document paths and repairs. Surface those diagnostics during inspection; asset clip and rig compatibility still use `diagnoseModelAnimation`.
|
|
25
|
+
- **Parameters.** The shell feeds the entity's smoothed ground speed as `speed`. For shared player movement it also reads physically resolved `grounded`, `verticalSpeed` and `crouched` through `playerMovementTelemetry(ctx, entityId)`; these values override conflicting blackboard extras. Custom movers retain their authored extras under `ANIM_PARAMS_KEY` when telemetry is unavailable. `readModelAnimationParams(ctx, entityId, speed, out)` gives custom render hosts the same rule, clearing and reusing their own dictionary without writing game state. The names are exported as `LOCOMOTION_SPEED_PARAM`, `LOCOMOTION_GROUNDED_PARAM`, `LOCOMOTION_VERTICAL_SPEED_PARAM` and `LOCOMOTION_CROUCHED_PARAM`.
|
|
26
|
+
- Jump clips remain explicit rig choices in the game's graph. A supported rig can enter its start clip on `!grounded && verticalSpeed > 0`, its air loop at the physical apex, and its landing clip on ground contact. Let an airborne or landing state return to takeoff when vertical speed becomes positive so a buffered re-jump is visible even if rendering misses the grounded frame. Use `verticalSpeed < 0` for falling from locomotion so unavailable movement data does not invent a fall. Verify those transitions against that rig and the game's physical motor; no automatic jump mapping or universal compatibility is supplied.
|
|
27
|
+
- **Placement discontinuities.** The shell uses the live simulation `snapDistance` to discard inferred gait speed when a character moves farther than that distance in three dimensions between visual samples. Retune it through `ctx.sim.retune({ snapDistance })` with the game's existing interpolation policy; `Infinity` permits continuous fast motion. Sampling resets the speed history while preserving graph time, triggers, variants and terminal states. The shared motor clears its retained state when its driven actor despawns. Raw position updates retain physical motor state; a reconstruction policy can call `forgetPlayerMovement` explicitly.
|
|
28
|
+
- **Triggers.** `ctx.game.playEntityAnimation(id, name)` arms a trigger; `hit` and `death` arm from their combat events.
|
|
29
|
+
- **Events.** `graph.events: [{ clip, atSec, name }]` emit `animation.event` when an influencing clip crosses that time. Full-cycle frames still fire; multiple missed cycles coalesce to one event per advance. Hook footstep audio, the damage frame of a swing or the magazine swap of a reload to the event, not to a timer.
|
|
30
|
+
- **Root motion.** `rootMotion: true` extracts local root-bone travel into `output.rootDelta` and plays the rig in place horizontally. The in-place flag remains active while a fading-out root-motion clip influences the pose, including interrupted fades and restored graph snapshots. The renderer never changes entity position: the movement/collision owner must consume the headless delta, transform it through the imported rig's parent/facing/scale with `takeRootMotion`, and resolve it through its controller. The bone's vertical motion remains animated. `createGraphPose.apply(output.clips, output.rootMotion)` gives editor/custom previews the same in-place policy. Existing graphs that relied on renderer-driven movement must migrate to a collision-authoritative host; no automatic vault or dodge motor is supplied. Extraction currently assumes the first bone has a matching `.position` track. Root deltas sample the current state's travel; they do not integrate outgoing travel or transition fade weights. Hosts needing collision-authoritative blended root travel must implement that policy explicitly; the in-place visual guarantee does not imply blended root-delta support.
|
|
31
|
+
- **Diagnostics.** `diagnoseModelAnimation(scene, config, clips)` checks incomplete locomotion roles, missing active clip mappings, masks that match no used tracks and unsupported root-track assumptions. Explicit graphs take precedence over dormant role/single-clip settings, so inactive settings do not produce misleading warnings. Runtime and graph previews warn with the same repair guidance. An explicit invalid single clip retains the bind pose rather than playing an arbitrary first clip.
|
|
32
|
+
- Inspector and Graph panels validate saved `meta.animation` with the same strict reader. A malformed override shows its document path and repair, leaves the saved data intact, and blocks ordinary playback edits and graph preview. Diagnostics remain visible without imported clip metadata. Explicit replacement discards the invalid override through an undoable marker edit; Custom derivation requires the rig's real clip list. Valid partial roles, signed playback values, variant order and extension fields survive unrelated edits.
|
|
33
|
+
- **Imported rig slots.** `ModelConfig.attachments[].slot` uses an exact runtime node name first, then a unique original imported name (`userData.name`). GLTFLoader can sanitize `handslot.r` to `handslotr`; authored slot references keep working without renaming animated bones.
|
|
34
|
+
- `resolveRigNode(rig, name)` (`@jgengine/shell/render/rigNode`) returns the instance node or a missing/ambiguous-name diagnostic. Duplicate references need a unique runtime name or repaired imported names; no arbitrary target is selected.
|
|
35
|
+
- Resolve on model load or slot changes and keep the node with its own instance. Attachments retain their local offsets under the animated slot and the model's placement, facing and scale; cleanup removes only that instance's attachment.
|
|
36
|
+
- This resolves node identity; it does not retarget animations or make different rigs share attachment proportions.
|
|
37
|
+
- **Foot IK.** `ModelConfig.ik` runs after the mixer each frame.
|
|
38
|
+
- `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`.
|
|
39
|
+
- Explicit joint, `pelvis` and `lookAt.bone` references use exact runtime names first, then the same unique original imported-name lookup as attachments. A name such as `upperleg.r` can resolve after GLTFLoader sanitizes it to `upperlegr`; this preserves node identity and does not supply rig retargeting.
|
|
40
|
+
- Each named joint must resolve uniquely and descend from the preceding joint; intermediate helper transforms are allowed. Missing, ambiguous, disconnected or overlapping chains produce a resolution warning and are skipped. Missing `pelvis` and `lookAt.bone` names also warn. Automatic pelvis correction uses the resolved legs' common ancestor; an explicit `pelvis` retains the authored selection. Auto detection is a naming convention, not compatibility with every rig.
|
|
41
|
+
- 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.
|
|
42
|
+
- `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.
|
|
43
|
+
- Disabling or replacing IK clears its previous corrections and resets smoothing; unmount restores untouched joint poses while preserving newer animation writes. This keeps editor play/adjust loops from leaving an offset pelvis after IK is removed.
|
|
44
|
+
- 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).
|
|
45
|
+
- **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`.
|
|
46
|
+
- 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.
|
|
47
|
+
- 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.
|
|
48
|
+
- Crowd members have no graph, IK or attachments. Promote the few near the camera or near the player to entity models.
|
|
49
|
+
- `bakeSkinnedCrowd` and `patchCrowdMaterial` are exported for a custom renderer.
|
|
50
|
+
|
|
51
|
+
## Symptom → knob
|
|
52
|
+
|
|
53
|
+
| Symptom | Knob |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| Feet slide at walk or run speed | `walkSpeed`/`runSpeed` to the clip's authored stride speed, or blend1D `at` points |
|
|
56
|
+
| Pop between states | transition `duration`; `exitTime` on one-shots returning to locomotion |
|
|
57
|
+
| Feet float or sink on slopes and steps | `ik: "auto"` |
|
|
58
|
+
| Knees buckle on steep ground | lower `ik.maxAdjust` |
|
|
59
|
+
| Feet tilt wrongly on rubble or props | lower `ik.alignToGround` |
|
|
60
|
+
| Attack damage lands before the swing | `graph.events` on the hit frame instead of a timer |
|
|
61
|
+
| Lunge distance doesn't match the feet | extract `rootMotion: true` travel and resolve it through the collision owner |
|
|
62
|
+
| Hundreds of animated characters cost thousands of draw calls | `SkinnedInstances` for the background crowd |
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
- **Overlapping menus.** `suspendPlayControls(ctx)` returns one idempotent release function per owner. Acquire while a menu is open and release on close, context replacement or unmount; controls resume only after the final owner releases and the existing play gate permits it. Shell settings own this lease automatically. Binding snapshots omit leases, and restoring bindings preserves the current context's live owners. Suspension clears held keyboard, pointer and analog input, so resuming requires fresh input; it does not pause a shared realm. Ordinary binding-context swaps retain held input.
|
|
10
|
+
- **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.
|
|
11
|
+
- **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.
|
|
12
|
+
- **Timing.** `createInputBuffer` (`@jgengine/core/input/inputBuffer`) buffers early presses, coyote time, hold duration and double taps.
|
|
13
|
+
- **Simulation edges.** The shell retains a press released before the next fixed step; `ctx.input.justPressed` samples it on that step while `isDown` already reflects release. Headless callers can supply `presses` to `publishInput`; record/replay applies those edges only on the recorded tick. Canvas mouse bindings use `mouse0`/`mouse1`/`mouse2`, including native button chords; overlays do not begin gameplay presses. Focus loss, suspension and owner teardown clear pending local presses.
|
|
14
|
+
- **Hosted saves.** Persist `HostedGameRunner.state()` for reconstruction. Its host-only input admission and pending-edge state prevents retransmitted stored input from replaying a consumed press; `snapshot()` and client replication omit that bookkeeping.
|
|
15
|
+
- **Hosted retention.** Join or resume a member before publishing input; nonmember frames are ignored. The runner compacts elapsed input in memory while retaining continuous intent and every unconsumed future replay tick; a standalone `InputRecorder` keeps its full log. `inputRetention` configures departed admission marks (default 256 users, 5 minutes; either limit can be zero), with `nowMs` in wall-clock milliseconds. Recent reconnect protection is process-local and ends on expiry or oldest-entry eviction. `inputStats()` reports actual retained recorders, frames and admission marks for host health checks.
|
|
16
|
+
- **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`.
|
|
17
|
+
- **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.
|
|
18
|
+
- **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.
|
|
19
|
+
- **Rebinding.** `createRebindSession` drives a conflict-aware "press a key" flow; overrides persist per game and apply under the context stack.
|
|
20
|
+
|
|
21
|
+
## Wiring a mode swap
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const DRIVING: ActionContext = {
|
|
25
|
+
id: "driving",
|
|
26
|
+
codes: { exit: ["KeyF", "pad:3"] },
|
|
27
|
+
passthrough: true,
|
|
28
|
+
axes: { steer: { positive: ["steerRight"], negative: ["steerLeft"] } },
|
|
29
|
+
shaping: { steer: { digital: { riseRate: 3, returnRate: 6 }, analog: { deadzone: 0.08, curve: 1.5 } } },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// enter: actionContextStack(ctx).push(DRIVING); leave: actionContextStack(ctx).pop("driving")
|
|
33
|
+
if (state.contextVersion !== contexts.version()) {
|
|
34
|
+
state.contextVersion = contexts.version();
|
|
35
|
+
const layer = contexts.activeAxes();
|
|
36
|
+
state.bindings = { steer: layer.bindings.steer ?? { positive: [] } };
|
|
37
|
+
state.shaper.retune({ axes: { steer: layer.shaping.steer ?? {} } });
|
|
38
|
+
}
|
|
39
|
+
const raw = ctx.input.axis(state.bindings);
|
|
40
|
+
const axis = state.shaper.shape(dt, raw, { analog: analogAxes(state.bindings, ctx.input.analog()) });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`bun run drive handling` runs this: F pops the driving context and a held W stops reaching the engine.
|
|
44
|
+
|
|
45
|
+
## Pitfalls
|
|
46
|
+
|
|
47
|
+
- 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.
|
|
48
|
+
- `shaping` has no `scale` callback because contexts are serializable; apply speed-sensitive scaling on the shaper the game owns.
|