@jgengine/shell 0.10.0 → 0.11.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 +13 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/GamePhaseStamp.d.ts +1 -0
- package/dist/GamePhaseStamp.js +9 -0
- package/dist/GamePlayerShell.d.ts +0 -12
- package/dist/GamePlayerShell.js +88 -1043
- package/dist/GameUiPreview.js +0 -2
- package/dist/audio/audioEngine.js +30 -8
- package/dist/audio/audioWire.d.ts +22 -0
- package/dist/audio/audioWire.js +19 -0
- package/dist/behaviour.d.ts +2 -1
- package/dist/behaviour.js +2 -1
- package/dist/behaviourAttach.d.ts +1 -0
- package/dist/behaviourAttach.js +1 -0
- package/dist/behaviourDriver.d.ts +1 -0
- package/dist/behaviourDriver.js +1 -0
- package/dist/boundActionDispatch.d.ts +13 -0
- package/dist/boundActionDispatch.js +37 -0
- package/dist/camera/GameCameraRig.d.ts +5 -2
- package/dist/camera/GameCameraRig.js +2 -2
- package/dist/camera/GameFirstPersonCamera.d.ts +9 -2
- package/dist/camera/GameFirstPersonCamera.js +8 -3
- package/dist/camera/GameInspectionCamera.d.ts +1 -1
- package/dist/camera/GameInspectionCamera.js +2 -2
- package/dist/camera/GameOrbitCamera.js +24 -9
- package/dist/camera/cameraBlendMath.d.ts +3 -0
- package/dist/camera/cameraBlendMath.js +3 -0
- package/dist/camera/fovPreference.d.ts +6 -1
- package/dist/camera/fovPreference.js +6 -1
- package/dist/camera/index.d.ts +4 -7
- package/dist/camera/index.js +4 -7
- package/dist/camera/inspectionCameraMath.d.ts +7 -2
- package/dist/camera/inspectionCameraMath.js +7 -2
- package/dist/camera/orbitCameraMath.d.ts +36 -6
- package/dist/camera/orbitCameraMath.js +56 -6
- package/dist/camera/rigMath.d.ts +94 -24
- package/dist/camera/rigMath.js +100 -24
- package/dist/camera/rigResolve.d.ts +4 -2
- package/dist/camera/rigResolve.js +4 -2
- package/dist/camera/shakeChannel.d.ts +6 -2
- package/dist/camera/shakeChannel.js +6 -2
- package/dist/camera/shakeChannelMath.d.ts +1 -0
- package/dist/camera/shakeChannelMath.js +1 -0
- package/dist/cartridge/runtime.d.ts +15 -0
- package/dist/cartridge/runtime.js +556 -0
- package/dist/cartridge/spec.d.ts +188 -0
- package/dist/cartridge/spec.js +19 -0
- package/dist/cartridge/validate.d.ts +2 -0
- package/dist/cartridge/validate.js +78 -0
- package/dist/cartridge.d.ts +1 -1
- package/dist/cartridge.js +3 -3
- package/dist/commandSink.d.ts +8 -3
- package/dist/commandSink.js +8 -3
- package/dist/defineGame.js +25 -6
- package/dist/devtools/ColPanel.d.ts +1 -0
- package/dist/devtools/ColPanel.js +14 -0
- package/dist/devtools/DevtoolsOverlay.d.ts +7 -3
- package/dist/devtools/DevtoolsOverlay.js +19 -450
- package/dist/devtools/KeysPanel.d.ts +4 -0
- package/dist/devtools/KeysPanel.js +31 -0
- package/dist/devtools/LogsPanel.d.ts +1 -0
- package/dist/devtools/LogsPanel.js +12 -0
- package/dist/devtools/NetPanel.d.ts +4 -0
- package/dist/devtools/NetPanel.js +10 -0
- package/dist/devtools/PerfPanel.d.ts +4 -0
- package/dist/devtools/PerfPanel.js +53 -0
- package/dist/devtools/TunePanel.d.ts +3 -0
- package/dist/devtools/TunePanel.js +309 -0
- package/dist/devtools/agentBridge.d.ts +41 -0
- package/dist/devtools/agentBridge.js +262 -0
- package/dist/devtools/collisionDebug.d.ts +6 -0
- package/dist/devtools/collisionDebug.js +6 -0
- package/dist/devtools/collisionDebugMath.d.ts +8 -2
- package/dist/devtools/collisionDebugMath.js +24 -5
- package/dist/devtools/devtoolsOverrides.d.ts +6 -0
- package/dist/devtools/devtoolsOverrides.js +48 -0
- package/dist/devtools/panelAtoms.d.ts +9 -0
- package/dist/devtools/panelAtoms.js +10 -0
- package/dist/devtools/perfDiagnose.d.ts +2 -0
- package/dist/devtools/perfDiagnose.js +43 -0
- package/dist/diagnostics/RuntimeDiagnostics.d.ts +29 -0
- package/dist/diagnostics/RuntimeDiagnostics.js +69 -0
- package/dist/drivers/FrameDriver.d.ts +37 -0
- package/dist/drivers/FrameDriver.js +232 -0
- package/dist/drivers/HudOnlyDriver.d.ts +16 -0
- package/dist/drivers/HudOnlyDriver.js +60 -0
- package/dist/environment/Daylight.d.ts +23 -7
- package/dist/environment/Daylight.js +106 -13
- package/dist/environment/EnvironmentScene.js +32 -6
- package/dist/environment/VolumetricClouds.d.ts +17 -0
- package/dist/environment/VolumetricClouds.js +202 -0
- package/dist/environment/daylightCycle.d.ts +3 -1
- package/dist/environment/daylightCycle.js +3 -1
- package/dist/environment/groundPadMath.d.ts +3 -0
- package/dist/environment/groundPadMath.js +3 -0
- package/dist/environment/index.d.ts +1 -0
- package/dist/environment/index.js +1 -0
- package/dist/environment/skyLightingPolicy.d.ts +2 -0
- package/dist/environment/skyLightingPolicy.js +2 -0
- package/dist/hotbarActions.d.ts +26 -0
- package/dist/hotbarActions.js +27 -0
- package/dist/inputSink.d.ts +16 -4
- package/dist/inputSink.js +57 -7
- package/dist/materialOverride.d.ts +10 -0
- package/dist/materialOverride.js +15 -3
- package/dist/multiplayer.js +8 -2
- package/dist/postfx/PostProcessing.js +47 -9
- package/dist/postfx/gradeShader.js +9 -1
- package/dist/registry.d.ts +3 -2
- package/dist/render/EnvironmentLighting.d.ts +10 -0
- package/dist/render/EnvironmentLighting.js +34 -0
- package/dist/render/SceneLighting.d.ts +7 -0
- package/dist/render/SceneLighting.js +18 -0
- package/dist/render/SceneModels.d.ts +14 -0
- package/dist/render/SceneModels.js +337 -0
- package/dist/render/defaultSurface.d.ts +29 -0
- package/dist/render/defaultSurface.js +101 -0
- package/dist/render/modelLoad.d.ts +24 -0
- package/dist/render/modelLoad.js +73 -0
- package/dist/render/modelRender.d.ts +11 -0
- package/dist/render/modelRender.js +15 -0
- package/dist/render/resolveModel.d.ts +39 -3
- package/dist/render/resolveModel.js +79 -2
- package/dist/render/useEntityRenderCues.d.ts +13 -0
- package/dist/render/useEntityRenderCues.js +62 -0
- package/dist/scatter/InstancedScatter.d.ts +24 -0
- package/dist/scatter/InstancedScatter.js +130 -0
- package/dist/scatter/scatterModels.d.ts +25 -0
- package/dist/scatter/scatterModels.js +61 -0
- package/dist/scatter/scatterProxies.d.ts +6 -0
- package/dist/scatter/scatterProxies.js +94 -0
- package/dist/scatter.d.ts +1 -0
- package/dist/scatter.js +1 -0
- package/dist/scene/AuthoredScene.d.ts +82 -0
- package/dist/scene/AuthoredScene.js +173 -0
- package/dist/scene/GeneratedAssetRenderer.d.ts +14 -0
- package/dist/scene/GeneratedAssetRenderer.js +59 -0
- package/dist/scene/GrassFieldRenderer.d.ts +2 -0
- package/dist/scene/GrassFieldRenderer.js +25 -0
- package/dist/scene/SoilPatchRenderer.d.ts +2 -0
- package/dist/scene/SoilPatchRenderer.js +21 -0
- package/dist/scene/StudioStage.d.ts +37 -0
- package/dist/scene/StudioStage.js +42 -0
- package/dist/scene/WaterRenderer.d.ts +2 -0
- package/dist/scene/WaterRenderer.js +37 -0
- package/dist/scene/builtinSceneKindRenderers.d.ts +2 -0
- package/dist/scene/builtinSceneKindRenderers.js +22 -0
- package/dist/scene/sceneKindRenderers.d.ts +28 -0
- package/dist/scene/sceneKindRenderers.js +17 -0
- package/dist/scene.d.ts +1 -0
- package/dist/scene.js +1 -0
- package/dist/settings/appliedSettings.d.ts +5 -0
- package/dist/settings/appliedSettings.js +9 -0
- package/dist/settings/settingsController.d.ts +2 -0
- package/dist/settings/settingsController.js +22 -1
- package/dist/shellConstants.d.ts +4 -0
- package/dist/shellConstants.js +4 -0
- package/dist/shellMovement.d.ts +8 -0
- package/dist/shellMovement.js +11 -0
- package/dist/shellPointer.d.ts +20 -0
- package/dist/shellPointer.js +28 -0
- package/dist/structures/PlacementGhost.d.ts +4 -0
- package/dist/structures/PlacementGhost.js +4 -0
- package/dist/structures/TransformGizmo.d.ts +43 -0
- package/dist/structures/TransformGizmo.js +55 -0
- package/dist/structures/index.d.ts +1 -0
- package/dist/structures/index.js +1 -0
- package/dist/terrain/GrassField.js +1 -1
- package/dist/terrain/TerraformBrushCursor.js +3 -0
- package/dist/terrain/grassBudget.d.ts +11 -2
- package/dist/terrain/grassBudget.js +20 -4
- package/dist/terrain/grassGeometry.d.ts +3 -0
- package/dist/terrain/grassGeometry.js +3 -0
- package/dist/terrain/grassMaterial.d.ts +2 -0
- package/dist/terrain/grassMaterial.js +2 -0
- package/dist/terrain/random.d.ts +3 -0
- package/dist/terrain/random.js +3 -0
- package/dist/terrain/soilPatchMaterial.d.ts +10 -0
- package/dist/terrain/soilPatchMaterial.js +109 -0
- package/dist/terrain/terrainDetailMaterial.d.ts +19 -2
- package/dist/terrain/terrainDetailMaterial.js +72 -5
- package/dist/terrain/terrainMath.d.ts +8 -1
- package/dist/terrain/terrainMath.js +8 -1
- package/dist/touch/TouchControlsOverlay.d.ts +9 -5
- package/dist/touch/TouchControlsOverlay.js +201 -22
- package/dist/useShellMultiplayerSync.d.ts +9 -0
- package/dist/useShellMultiplayerSync.js +98 -0
- package/dist/visibility/CullingProvider.js +1 -1
- package/dist/water/OceanConfig.d.ts +2 -0
- package/dist/water/OceanConfig.js +2 -0
- package/dist/weather/fireSpreadPose.d.ts +1 -0
- package/dist/weather/fireSpreadPose.js +1 -0
- package/dist/weather/weatherGeometry.d.ts +1 -0
- package/dist/weather/weatherGeometry.js +1 -0
- package/dist/weather/weatherMath.d.ts +3 -0
- package/dist/weather/weatherMath.js +3 -0
- package/dist/weather/weatherUniforms.d.ts +3 -0
- package/dist/weather/weatherUniforms.js +3 -0
- package/dist/world/RetainedVfx.d.ts +10 -0
- package/dist/world/RetainedVfx.js +136 -0
- package/dist/world/WorldHud.d.ts +49 -2
- package/dist/world/WorldHud.js +87 -2
- package/dist/world/WorldScene.d.ts +21 -0
- package/dist/world/WorldScene.js +159 -0
- package/dist/world/WorldVfx.d.ts +9 -0
- package/dist/world/WorldVfx.js +184 -0
- package/dist/world/entityPose.d.ts +2 -0
- package/dist/world/entityPose.js +2 -0
- package/dist/world/floatTextStyle.d.ts +1 -0
- package/dist/world/floatTextStyle.js +1 -0
- package/dist/world/telegraphPulse.d.ts +1 -0
- package/dist/world/telegraphPulse.js +1 -0
- package/dist/world/worldBarSamples.d.ts +25 -0
- package/dist/world/worldBarSamples.js +38 -0
- package/dist/worldSky.d.ts +5 -0
- package/dist/worldSky.js +11 -0
- package/dist/worldSync.d.ts +2 -1
- package/dist/worldSync.js +2 -1
- package/package.json +6 -6
- package/skills/jgengine/SKILL.md +51 -0
- package/skills/jgengine/api.md +434 -0
- package/skills/jgengine/capabilities.md +29 -0
- package/skills/jgengine/reference-cartridge.md +72 -0
- package/skills/jgengine-ui/SKILL.md +36 -0
- package/skills/jgengine-ui/api.md +1852 -0
- package/skills/jgengine-ui/capabilities.md +142 -0
- package/skills/jgengine-ui/reference.md +500 -0
- package/skills/jgengine-ui/references/visual-scorecard.md +73 -0
- package/skills/jgengine-world/SKILL.md +38 -0
- package/skills/jgengine-world/api.md +2652 -0
- package/skills/jgengine-world/capabilities.md +370 -0
- package/skills/jgengine-world/reference.md +222 -0
- package/llms.txt +0 -2761
package/dist/camera/rigMath.js
CHANGED
|
@@ -6,28 +6,36 @@ function actionCodeList(codes) {
|
|
|
6
6
|
const modes = codes;
|
|
7
7
|
return [...(modes.hold ?? []), ...(modes.toggle ?? [])];
|
|
8
8
|
}
|
|
9
|
+
/** @internal */
|
|
9
10
|
export function rtsPanKeysConflict(input) {
|
|
10
11
|
if (input === undefined)
|
|
11
12
|
return false;
|
|
12
13
|
return Object.values(input).some((codes) => actionCodeList(codes).some((code) => RTS_WASD_CODES.includes(code)));
|
|
13
14
|
}
|
|
15
|
+
/** @internal */
|
|
14
16
|
export function clamp(value, min, max) {
|
|
15
17
|
return value < min ? min : value > max ? max : value;
|
|
16
18
|
}
|
|
19
|
+
/** @internal */
|
|
17
20
|
export function lerp(from, to, blend) {
|
|
18
21
|
return from + (to - from) * blend;
|
|
19
22
|
}
|
|
23
|
+
/** @internal */
|
|
20
24
|
export function smoothstep(t) {
|
|
21
25
|
const clamped = clamp(t, 0, 1);
|
|
22
26
|
return clamped * clamped * (3 - 2 * clamped);
|
|
23
27
|
}
|
|
28
|
+
/** @internal */
|
|
24
29
|
export function forwardVector(yaw) {
|
|
25
30
|
return { x: Math.sin(yaw), y: 0, z: Math.cos(yaw) };
|
|
26
31
|
}
|
|
27
|
-
/** Screen-right of a yaw: `forward × up` with up = +Y.
|
|
32
|
+
/** Screen-right of a yaw: `forward × up` with up = +Y.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
28
35
|
export function rightVector(yaw) {
|
|
29
36
|
return { x: -Math.cos(yaw), y: 0, z: Math.sin(yaw) };
|
|
30
37
|
}
|
|
38
|
+
/** @internal */
|
|
31
39
|
export function resolveTopDown(config) {
|
|
32
40
|
return {
|
|
33
41
|
height: config?.height ?? 18,
|
|
@@ -46,7 +54,8 @@ export function resolveTopDown(config) {
|
|
|
46
54
|
* the camera→target ray above the ground (PI/2 = straight down); `yaw` is the
|
|
47
55
|
* fixed azimuth (PI/4 reads isometric). Height sets zoom; horizontal boom is
|
|
48
56
|
* derived so the look angle stays constant as height changes.
|
|
49
|
-
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
50
59
|
export function topDownPose(follow, resolved, fov) {
|
|
51
60
|
const lookAt = {
|
|
52
61
|
x: follow.x + resolved.offset.x,
|
|
@@ -65,10 +74,13 @@ export function topDownPose(follow, resolved, fov) {
|
|
|
65
74
|
fov,
|
|
66
75
|
};
|
|
67
76
|
}
|
|
68
|
-
/** Exponential spring-arm approach toward a desired point (frame-rate independent).
|
|
77
|
+
/** Exponential spring-arm approach toward a desired point (frame-rate independent).
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
69
80
|
export function springArmStep(current, desired, damping, dt) {
|
|
70
81
|
return lerpVec3(current, desired, smoothBlend(dt, damping));
|
|
71
82
|
}
|
|
83
|
+
/** @internal */
|
|
72
84
|
export function resolveSideScroll(config) {
|
|
73
85
|
return {
|
|
74
86
|
axis: config?.axis ?? "x",
|
|
@@ -78,7 +90,9 @@ export function resolveSideScroll(config) {
|
|
|
78
90
|
followSmoothing: config?.followSmoothing ?? 8,
|
|
79
91
|
};
|
|
80
92
|
}
|
|
81
|
-
/** Frame-rate independent follow blend for the side-scroll rig; `followSmoothing <= 0` hard-locks (blend 1) instead of freezing.
|
|
93
|
+
/** Frame-rate independent follow blend for the side-scroll rig; `followSmoothing <= 0` hard-locks (blend 1) instead of freezing.
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
82
96
|
export function sideScrollFollowBlend(followSmoothing, dt) {
|
|
83
97
|
return followSmoothing <= 0 ? 1 : smoothBlend(dt, followSmoothing);
|
|
84
98
|
}
|
|
@@ -86,7 +100,8 @@ export function sideScrollFollowBlend(followSmoothing, dt) {
|
|
|
86
100
|
* Fixed lateral 2.5D follow pose: the camera sits perpendicular to the travel
|
|
87
101
|
* axis at `distance`, above the entity by `height`, and looks at the entity
|
|
88
102
|
* raised by `lookHeight`. Axis "x" watches from +z; axis "z" watches from +x.
|
|
89
|
-
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
90
105
|
export function resolveSideScrollPose(entityPos, resolved, fov) {
|
|
91
106
|
const perpendicular = resolved.axis === "x" ? { x: 0, y: 0, z: 1 } : { x: 1, y: 0, z: 0 };
|
|
92
107
|
return {
|
|
@@ -99,7 +114,9 @@ export function resolveSideScrollPose(entityPos, resolved, fov) {
|
|
|
99
114
|
fov,
|
|
100
115
|
};
|
|
101
116
|
}
|
|
102
|
-
/** Speed→FOV curve: FOV climbs from base to max as speed rises to `speedForMax`.
|
|
117
|
+
/** Speed→FOV curve: FOV climbs from base to max as speed rises to `speedForMax`.
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
103
120
|
export function speedToFov(speed, curve) {
|
|
104
121
|
const base = curve?.base ?? 55;
|
|
105
122
|
const max = curve?.max ?? 78;
|
|
@@ -108,11 +125,15 @@ export function speedToFov(speed, curve) {
|
|
|
108
125
|
return base;
|
|
109
126
|
return lerp(base, max, clamp(speed / speedForMax, 0, 1));
|
|
110
127
|
}
|
|
111
|
-
/** Yaw that points from `from` toward `to` on the XZ plane (matches shell forward = (sin, cos)).
|
|
128
|
+
/** Yaw that points from `from` toward `to` on the XZ plane (matches shell forward = (sin, cos)).
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
112
131
|
export function yawTo(from, to) {
|
|
113
132
|
return Math.atan2(to.x - from.x, to.z - from.z);
|
|
114
133
|
}
|
|
115
|
-
/** Shortest signed angular delta from `a` to `b`, wrapped to (-PI, PI].
|
|
134
|
+
/** Shortest signed angular delta from `a` to `b`, wrapped to (-PI, PI].
|
|
135
|
+
* @internal
|
|
136
|
+
*/
|
|
116
137
|
export function angleDelta(a, b) {
|
|
117
138
|
let delta = (b - a) % (Math.PI * 2);
|
|
118
139
|
if (delta > Math.PI)
|
|
@@ -121,10 +142,13 @@ export function angleDelta(a, b) {
|
|
|
121
142
|
delta += Math.PI * 2;
|
|
122
143
|
return delta;
|
|
123
144
|
}
|
|
124
|
-
/** Exponential yaw smoothing that respects wrap-around.
|
|
145
|
+
/** Exponential yaw smoothing that respects wrap-around.
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
125
148
|
export function smoothYaw(current, desired, speed, dt) {
|
|
126
149
|
return current + angleDelta(current, desired) * smoothBlend(dt, speed);
|
|
127
150
|
}
|
|
151
|
+
/** @internal */
|
|
128
152
|
export function resolveShoulder(config, aiming) {
|
|
129
153
|
const hip = {
|
|
130
154
|
shoulderOffset: config?.shoulderOffset ?? 0.6,
|
|
@@ -142,7 +166,9 @@ export function resolveShoulder(config, aiming) {
|
|
|
142
166
|
fov: ads?.fov ?? hip.fov * 0.75,
|
|
143
167
|
};
|
|
144
168
|
}
|
|
145
|
-
/** Blend two shoulder framings by an ADS factor in [0,1].
|
|
169
|
+
/** Blend two shoulder framings by an ADS factor in [0,1].
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
146
172
|
export function blendShoulder(hip, ads, t) {
|
|
147
173
|
return {
|
|
148
174
|
shoulderOffset: lerp(hip.shoulderOffset, ads.shoulderOffset, t),
|
|
@@ -155,7 +181,8 @@ export function blendShoulder(hip, ads, t) {
|
|
|
155
181
|
* Over-the-shoulder camera pose. The boom sits behind the follow point along
|
|
156
182
|
* `yaw`, raised by `heightOffset`, and pushed sideways by `shoulderOffset`
|
|
157
183
|
* (sign set by `sideSign`: +1 right, -1 left). `pitch` tilts the look point.
|
|
158
|
-
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
159
186
|
export function shoulderPose(follow, yaw, pitch, sideSign, shoulder) {
|
|
160
187
|
const forward = forwardVector(yaw);
|
|
161
188
|
const right = rightVector(yaw);
|
|
@@ -181,7 +208,8 @@ export function shoulderPose(follow, yaw, pitch, sideSign, shoulder) {
|
|
|
181
208
|
* Lock-on pose: camera sits behind the player along the player→target vector so
|
|
182
209
|
* the target stays framed. The look point is biased between player and target
|
|
183
210
|
* by `framingBias`.
|
|
184
|
-
|
|
211
|
+
* @internal
|
|
212
|
+
*/
|
|
185
213
|
export function lockOnPose(player, target, config, fov) {
|
|
186
214
|
const distance = config?.distance ?? 5;
|
|
187
215
|
const height = config?.height ?? 2.4;
|
|
@@ -201,6 +229,7 @@ export function lockOnPose(player, target, config, fov) {
|
|
|
201
229
|
};
|
|
202
230
|
return { pose: { position, lookAt: focus, fov }, yaw };
|
|
203
231
|
}
|
|
232
|
+
/** @internal */
|
|
204
233
|
export function resolveChase(config) {
|
|
205
234
|
return {
|
|
206
235
|
distance: config?.distance ?? 6,
|
|
@@ -215,7 +244,9 @@ export function resolveChase(config) {
|
|
|
215
244
|
bankDamping: config?.bank?.damping ?? 8,
|
|
216
245
|
};
|
|
217
246
|
}
|
|
218
|
-
/** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`.
|
|
247
|
+
/** Velocity-lead the follow point (#286.9): aim `leadTime` seconds along the target's frame velocity, clamped to `leadMax`.
|
|
248
|
+
* @internal
|
|
249
|
+
*/
|
|
219
250
|
export function leadFollowPoint(follow, previous, dt, resolved) {
|
|
220
251
|
if (resolved.leadTime <= 0 || dt <= 0)
|
|
221
252
|
return follow;
|
|
@@ -236,7 +267,9 @@ function wrapAngle(angle) {
|
|
|
236
267
|
wrapped += Math.PI * 2;
|
|
237
268
|
return wrapped;
|
|
238
269
|
}
|
|
239
|
-
/** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped.
|
|
270
|
+
/** One smoothing step of the chase rig's turn-bank roll (#286.10): roll opposes yaw rate, clamped and exponentially damped.
|
|
271
|
+
* @internal
|
|
272
|
+
*/
|
|
240
273
|
export function bankRollStep(currentRoll, yaw, previousYaw, dt, resolved) {
|
|
241
274
|
if (resolved.bankPerYawRate <= 0)
|
|
242
275
|
return 0;
|
|
@@ -244,6 +277,7 @@ export function bankRollStep(currentRoll, yaw, previousYaw, dt, resolved) {
|
|
|
244
277
|
const target = clamp(-yawRate * resolved.bankPerYawRate, -resolved.bankMax, resolved.bankMax);
|
|
245
278
|
return currentRoll + (target - currentRoll) * Math.min(1, resolved.bankDamping * dt);
|
|
246
279
|
}
|
|
280
|
+
/** @internal */
|
|
247
281
|
export function resolveObserver(config) {
|
|
248
282
|
return {
|
|
249
283
|
distance: config?.distance ?? 8,
|
|
@@ -252,7 +286,9 @@ export function resolveObserver(config) {
|
|
|
252
286
|
orbitSpeed: config?.orbitSpeed ?? 0.2,
|
|
253
287
|
};
|
|
254
288
|
}
|
|
255
|
-
/** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input.
|
|
289
|
+
/** Detached spectator pose: orbits `subject` at a fixed distance/height, never reading player input.
|
|
290
|
+
* @internal
|
|
291
|
+
*/
|
|
256
292
|
export function observerPose(subject, angle, resolved, fov) {
|
|
257
293
|
const position = {
|
|
258
294
|
x: subject.x + Math.sin(angle) * resolved.distance,
|
|
@@ -265,7 +301,9 @@ export function observerPose(subject, angle, resolved, fov) {
|
|
|
265
301
|
fov,
|
|
266
302
|
};
|
|
267
303
|
}
|
|
268
|
-
/** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing).
|
|
304
|
+
/** Desired chase-camera position behind a vehicle facing `yaw` (before spring smoothing).
|
|
305
|
+
* @internal
|
|
306
|
+
*/
|
|
269
307
|
export function chaseDesiredPosition(follow, yaw, resolved) {
|
|
270
308
|
const back = forwardVector(yaw);
|
|
271
309
|
return {
|
|
@@ -274,7 +312,9 @@ export function chaseDesiredPosition(follow, yaw, resolved) {
|
|
|
274
312
|
z: follow.z - back.z * resolved.distance,
|
|
275
313
|
};
|
|
276
314
|
}
|
|
277
|
-
/** Look point ahead of / above a chased vehicle.
|
|
315
|
+
/** Look point ahead of / above a chased vehicle.
|
|
316
|
+
* @internal
|
|
317
|
+
*/
|
|
278
318
|
export function chaseLookAt(follow, yaw, resolved) {
|
|
279
319
|
const forward = forwardVector(yaw);
|
|
280
320
|
return {
|
|
@@ -283,7 +323,9 @@ export function chaseLookAt(follow, yaw, resolved) {
|
|
|
283
323
|
z: follow.z + forward.z * 2,
|
|
284
324
|
};
|
|
285
325
|
}
|
|
286
|
-
/** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle.
|
|
326
|
+
/** World-space seat pose (cockpit/hood/rear) rigidly attached to the vehicle.
|
|
327
|
+
* @internal
|
|
328
|
+
*/
|
|
287
329
|
export function seatPose(follow, yaw, local, fov) {
|
|
288
330
|
const forward = forwardVector(yaw);
|
|
289
331
|
const right = rightVector(yaw);
|
|
@@ -301,14 +343,19 @@ export function seatPose(follow, yaw, local, fov) {
|
|
|
301
343
|
fov,
|
|
302
344
|
};
|
|
303
345
|
}
|
|
346
|
+
/** @internal */
|
|
304
347
|
export function createTrauma() {
|
|
305
348
|
return { trauma: 0, time: 0 };
|
|
306
349
|
}
|
|
307
|
-
/** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1.
|
|
350
|
+
/** Add trauma (0..1) and clamp; larger hits raise the ceiling toward 1.
|
|
351
|
+
* @internal
|
|
352
|
+
*/
|
|
308
353
|
export function addTrauma(state, amount) {
|
|
309
354
|
state.trauma = clamp(state.trauma + amount, 0, 1);
|
|
310
355
|
}
|
|
311
|
-
/** Decay trauma linearly toward 0 and advance the shake clock.
|
|
356
|
+
/** Decay trauma linearly toward 0 and advance the shake clock.
|
|
357
|
+
* @internal
|
|
358
|
+
*/
|
|
312
359
|
export function stepTrauma(state, decayPerSecond, dt) {
|
|
313
360
|
state.time += dt;
|
|
314
361
|
state.trauma = clamp(state.trauma - decayPerSecond * dt, 0, 1);
|
|
@@ -321,7 +368,8 @@ function hashNoise(seed, time, frequency) {
|
|
|
321
368
|
* Positional + roll shake for the current trauma. Shake magnitude is
|
|
322
369
|
* `trauma^exponent` so small hits stay subtle; the oscillation is deterministic
|
|
323
370
|
* per-seed pseudo-noise (no per-frame RNG, so identical inputs reproduce).
|
|
324
|
-
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
325
373
|
export function shakeOffset(state, config) {
|
|
326
374
|
const maxOffset = config?.maxOffset ?? 0.5;
|
|
327
375
|
const maxRoll = config?.maxRoll ?? 0.06;
|
|
@@ -336,7 +384,33 @@ export function shakeOffset(state, config) {
|
|
|
336
384
|
roll: maxRoll * shake * hashNoise(3, state.time, frequency),
|
|
337
385
|
};
|
|
338
386
|
}
|
|
339
|
-
/**
|
|
387
|
+
/** Calibrated trauma decay for `traumaShake`/`impactPresets` (trauma/second). */
|
|
388
|
+
export const CALIBRATED_TRAUMA_SHAKE_DECAY_PER_SECOND = 1.4;
|
|
389
|
+
/** Calibrated positional shake amplitude at full trauma (world units) for `traumaShake`. */
|
|
390
|
+
export const CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET = 0.55;
|
|
391
|
+
/** Calibrated rotational shake amplitude at full trauma (radians) for `traumaShake`. */
|
|
392
|
+
export const CALIBRATED_TRAUMA_SHAKE_MAX_ROLL = 0.1;
|
|
393
|
+
/** Calibrated shake noise frequency (Hz) for `traumaShake`. */
|
|
394
|
+
export const CALIBRATED_TRAUMA_SHAKE_FREQUENCY = 32;
|
|
395
|
+
/**
|
|
396
|
+
* Calibrated trauma² camera shake: offset scales with `trauma` squared using
|
|
397
|
+
* game-feel defaults (decay 1.4/s, max offset 0.55, max roll 0.1 rad, noise
|
|
398
|
+
* freq 32×t) — the curve `impactPresets` trauma values are calibrated
|
|
399
|
+
* against, so an impact "just looks right" without hand-tuning `shakeOffset`.
|
|
400
|
+
*
|
|
401
|
+
* @capability camera-shake calibrated trauma² camera kick with zero tuning
|
|
402
|
+
* @internal
|
|
403
|
+
*/
|
|
404
|
+
export function traumaShake(trauma, time = 0) {
|
|
405
|
+
return shakeOffset({ trauma: clamp(trauma, 0, 1), time }, {
|
|
406
|
+
maxOffset: CALIBRATED_TRAUMA_SHAKE_MAX_OFFSET,
|
|
407
|
+
maxRoll: CALIBRATED_TRAUMA_SHAKE_MAX_ROLL,
|
|
408
|
+
frequency: CALIBRATED_TRAUMA_SHAKE_FREQUENCY,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
/** Linear cross-fade between two full camera poses (position, lookAt, fov).
|
|
412
|
+
* @internal
|
|
413
|
+
*/
|
|
340
414
|
export function crossfadePose(from, to, t) {
|
|
341
415
|
const blend = clamp(t, 0, 1);
|
|
342
416
|
return {
|
|
@@ -350,7 +424,8 @@ export function crossfadePose(from, to, t) {
|
|
|
350
424
|
* (#196.2). `director` omitted, or its fields `undefined`/`null`, is a pure
|
|
351
425
|
* passthrough to `staticConfig` so mounting a director with no active override
|
|
352
426
|
* changes nothing.
|
|
353
|
-
|
|
427
|
+
* @internal
|
|
428
|
+
*/
|
|
354
429
|
export function resolveDirectedCamera(director, staticConfig) {
|
|
355
430
|
const directedFollow = director?.followEntityId;
|
|
356
431
|
const followEntityId = directedFollow === undefined ? staticConfig.followEntityId : directedFollow;
|
|
@@ -363,7 +438,8 @@ export function resolveDirectedCamera(director, staticConfig) {
|
|
|
363
438
|
* travel time from the previous keyframe into it; segment easing is per the
|
|
364
439
|
* destination keyframe. Reports `done` once past the final keyframe (unless
|
|
365
440
|
* looping, which wraps `elapsed` into the total path duration).
|
|
366
|
-
|
|
441
|
+
* @internal
|
|
442
|
+
*/
|
|
367
443
|
export function cinematicSample(keyframes, elapsed, loop, fallbackFov) {
|
|
368
444
|
if (keyframes.length === 0) {
|
|
369
445
|
const zero = { x: 0, y: 0, z: 0 };
|
|
@@ -6,10 +6,12 @@ import type { CameraRigKind, GameCameraConfig } from "@jgengine/core/game/playab
|
|
|
6
6
|
* of a rig's own config block selects that rig, checked in the fixed order below
|
|
7
7
|
* (#207.8) so a config carrying more than one block resolves deterministically
|
|
8
8
|
* instead of depending on object key order. Set `rig` explicitly to break a tie.
|
|
9
|
-
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
10
11
|
export declare function resolveRigKind(config: GameCameraConfig | undefined): CameraRigKind;
|
|
11
12
|
/**
|
|
12
13
|
* The turntable rig is a flat facade over the observer's point-orbit mode: map
|
|
13
14
|
* its `target`/`distance`/… onto an observer block so ObserverRig runs unchanged.
|
|
14
|
-
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
15
17
|
export declare function turntableAsObserver(config: GameCameraConfig | undefined): GameCameraConfig;
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* of a rig's own config block selects that rig, checked in the fixed order below
|
|
6
6
|
* (#207.8) so a config carrying more than one block resolves deterministically
|
|
7
7
|
* instead of depending on object key order. Set `rig` explicitly to break a tie.
|
|
8
|
-
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
9
10
|
export function resolveRigKind(config) {
|
|
10
11
|
if (config?.rig !== undefined)
|
|
11
12
|
return config.rig;
|
|
@@ -34,7 +35,8 @@ export function resolveRigKind(config) {
|
|
|
34
35
|
/**
|
|
35
36
|
* The turntable rig is a flat facade over the observer's point-orbit mode: map
|
|
36
37
|
* its `target`/`distance`/… onto an observer block so ObserverRig runs unchanged.
|
|
37
|
-
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
38
40
|
export function turntableAsObserver(config) {
|
|
39
41
|
const t = config?.turntable;
|
|
40
42
|
if (t === undefined)
|
|
@@ -8,8 +8,12 @@ export { createCameraShakeChannel } from "./shakeChannelMath.js";
|
|
|
8
8
|
* default channel directly.
|
|
9
9
|
*/
|
|
10
10
|
export declare const defaultCameraShakeChannel: CameraShakeChannel;
|
|
11
|
-
/** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut).
|
|
11
|
+
/** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut).
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
12
14
|
export declare function cameraShake(amplitude: number, decayPerSecond?: number): void;
|
|
13
15
|
export declare const CameraShakeContext: import("react").Context<CameraShakeChannel>;
|
|
14
|
-
/** The active rig's shake channel — call `.shake(...)` to add trauma from React UI.
|
|
16
|
+
/** The active rig's shake channel — call `.shake(...)` to add trauma from React UI.
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
15
19
|
export declare function useCameraShake(): CameraShakeChannel;
|
|
@@ -8,12 +8,16 @@ export { createCameraShakeChannel } from "./shakeChannelMath.js";
|
|
|
8
8
|
* default channel directly.
|
|
9
9
|
*/
|
|
10
10
|
export const defaultCameraShakeChannel = createCameraShakeChannel();
|
|
11
|
-
/** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut).
|
|
11
|
+
/** Feed the default camera-shake channel from anywhere (see G7 hitstop cross-cut).
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
12
14
|
export function cameraShake(amplitude, decayPerSecond) {
|
|
13
15
|
defaultCameraShakeChannel.shake(amplitude, decayPerSecond);
|
|
14
16
|
}
|
|
15
17
|
export const CameraShakeContext = createContext(defaultCameraShakeChannel);
|
|
16
|
-
/** The active rig's shake channel — call `.shake(...)` to add trauma from React UI.
|
|
18
|
+
/** The active rig's shake channel — call `.shake(...)` to add trauma from React UI.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
17
21
|
export function useCameraShake() {
|
|
18
22
|
return useContext(CameraShakeContext);
|
|
19
23
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AbilityKit } from "@jgengine/core/combat/abilityKit";
|
|
2
|
+
import type { GameLoop } from "@jgengine/core/game/defineGame";
|
|
3
|
+
import type { GameContext, GameContextContent } from "@jgengine/core/runtime/gameContext";
|
|
4
|
+
import { type CartridgeRun, type CartridgeSpec } from "./spec.js";
|
|
5
|
+
export interface CartridgeRuntime {
|
|
6
|
+
content: GameContextContent;
|
|
7
|
+
loop: GameLoop<GameContext>;
|
|
8
|
+
run(ctx: GameContext): CartridgeRun;
|
|
9
|
+
weaponKit(ctx: GameContext): AbilityKit;
|
|
10
|
+
chooseUpgrade(ctx: GameContext, offerId: string): void;
|
|
11
|
+
begin(ctx: GameContext): void;
|
|
12
|
+
reset(ctx: GameContext): void;
|
|
13
|
+
spec: CartridgeSpec;
|
|
14
|
+
}
|
|
15
|
+
export declare function createCartridge(spec: CartridgeSpec): CartridgeRuntime;
|