@jgengine/core 0.31.0 → 0.33.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 +67 -0
- package/dist/audio/feedbackCues.d.ts +30 -0
- package/dist/audio/feedbackCues.js +119 -0
- package/dist/combat/damageRuntime.d.ts +10 -1
- package/dist/combat/damageRuntime.js +8 -1
- package/dist/combat/effects.d.ts +2 -0
- package/dist/combat/effects.js +2 -0
- package/dist/devtools/report.d.ts +13 -0
- package/dist/game/events.d.ts +17 -0
- package/dist/game/playableGame.d.ts +3 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +61 -1
- package/dist/movement/solidObstacles.d.ts +34 -5
- package/dist/movement/solidObstacles.js +146 -27
- package/dist/runtime/context/combat.js +1 -0
- package/dist/runtime/context/scene.js +7 -2
- package/dist/runtime/gameContext.js +3 -0
- package/dist/runtime/gameContextTypes.d.ts +16 -0
- package/dist/scene/objectStore.d.ts +4 -0
- package/dist/scene/objectStore.js +103 -15
- package/dist/settings/graphicsSettings.js +3 -2
- package/dist/settings/settingsModel.d.ts +18 -0
- package/dist/settings/settingsModel.js +67 -15
- package/package.json +1 -1
- package/skills/jgengine/api.md +3 -2
- package/skills/jgengine-combat/api.md +2 -2
- package/skills/jgengine-gameplay/api.md +3 -2
- package/skills/jgengine-world/api.md +18 -8
- package/skills/jgengine-world/capabilities.md +4 -0
|
@@ -60,30 +60,81 @@ function defaultStorage() {
|
|
|
60
60
|
}
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
/** A stored setting holds a value the read asked for as another type, so no honest value exists. */
|
|
64
|
+
export class SettingsTypeError extends Error {
|
|
65
|
+
settingId;
|
|
66
|
+
storedType;
|
|
67
|
+
fallbackType;
|
|
68
|
+
constructor(settingId, storedType, fallbackType) {
|
|
69
|
+
super(`Setting "${settingId}" stores ${storedType} but was read as ${fallbackType}.`);
|
|
70
|
+
this.name = "SettingsTypeError";
|
|
71
|
+
this.settingId = settingId;
|
|
72
|
+
this.storedType = storedType;
|
|
73
|
+
this.fallbackType = fallbackType;
|
|
67
74
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return
|
|
75
|
+
}
|
|
76
|
+
function storedTypeName(raw) {
|
|
77
|
+
if (raw === null)
|
|
78
|
+
return "null";
|
|
79
|
+
if (Array.isArray(raw))
|
|
80
|
+
return "array";
|
|
81
|
+
return typeof raw;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read a stored value as the type the caller asked for. A value of another primitive type converts
|
|
85
|
+
* when the result is the same value in the asked-for type (a number as its digits, a boolean as
|
|
86
|
+
* `"true"`/`"false"`); otherwise it throws {@link SettingsTypeError}, naming the key and both types,
|
|
87
|
+
* instead of handing back the fallback as if nothing were stored.
|
|
88
|
+
*/
|
|
89
|
+
export function asSettingType(id, stored, fallback) {
|
|
90
|
+
const wanted = typeof fallback;
|
|
91
|
+
const storedType = storedTypeName(stored);
|
|
92
|
+
if (storedType === wanted) {
|
|
93
|
+
if (wanted === "number" && !Number.isFinite(stored)) {
|
|
94
|
+
throw new SettingsTypeError(id, storedType, wanted);
|
|
95
|
+
}
|
|
96
|
+
return stored;
|
|
97
|
+
}
|
|
98
|
+
if (wanted === "number" && storedType === "string") {
|
|
99
|
+
const text = stored.trim();
|
|
100
|
+
const parsed = text === "" ? Number.NaN : Number(text);
|
|
101
|
+
if (Number.isFinite(parsed))
|
|
102
|
+
return parsed;
|
|
72
103
|
}
|
|
73
|
-
|
|
104
|
+
else if (wanted === "string" && (storedType === "number" || storedType === "boolean")) {
|
|
105
|
+
return String(stored);
|
|
106
|
+
}
|
|
107
|
+
else if (wanted === "boolean" && storedType === "string" && (stored === "true" || stored === "false")) {
|
|
108
|
+
return (stored === "true");
|
|
109
|
+
}
|
|
110
|
+
throw new SettingsTypeError(id, storedType, wanted);
|
|
74
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Read one persisted setting as `fallback`'s type. An absent or unreadable cell yields the
|
|
114
|
+
* fallback; a stored value of an incompatible type throws {@link SettingsTypeError}.
|
|
115
|
+
*/
|
|
75
116
|
export function loadSettingValue(id, fallback, storage = defaultStorage()) {
|
|
76
117
|
if (storage == null)
|
|
77
118
|
return fallback;
|
|
119
|
+
let raw;
|
|
78
120
|
try {
|
|
79
|
-
|
|
80
|
-
if (raw === null)
|
|
81
|
-
return fallback;
|
|
82
|
-
return coerce(JSON.parse(raw), fallback);
|
|
121
|
+
raw = storage.getItem(settingStorageKey(id));
|
|
83
122
|
}
|
|
84
123
|
catch {
|
|
85
124
|
return fallback;
|
|
86
125
|
}
|
|
126
|
+
if (raw === null)
|
|
127
|
+
return fallback;
|
|
128
|
+
let parsed;
|
|
129
|
+
try {
|
|
130
|
+
parsed = JSON.parse(raw);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return fallback;
|
|
134
|
+
}
|
|
135
|
+
if (parsed === null)
|
|
136
|
+
return fallback;
|
|
137
|
+
return asSettingType(id, parsed, fallback);
|
|
87
138
|
}
|
|
88
139
|
export function saveSettingValue(id, value, storage = defaultStorage()) {
|
|
89
140
|
if (storage == null)
|
|
@@ -100,8 +151,9 @@ export function createSettingsStore(storage = defaultStorage()) {
|
|
|
100
151
|
const mem = createObservableKeyedStore();
|
|
101
152
|
return {
|
|
102
153
|
get(id, fallback) {
|
|
103
|
-
|
|
104
|
-
|
|
154
|
+
const stored = mem.get(id);
|
|
155
|
+
if (stored !== undefined)
|
|
156
|
+
return asSettingType(id, stored, fallback);
|
|
105
157
|
return loadSettingValue(id, fallback, storage ?? undefined);
|
|
106
158
|
},
|
|
107
159
|
set(id, value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jgengine/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "jgengine core — pure-TypeScript game framework SDK (npm @jgengine/core). Entity stores, commands, combat, inventory, multiplayer seams. Zero dependencies. Not an ECS. Agent skills ship in the tarball. https://jgengine.com",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jgengine",
|
package/skills/jgengine/api.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
8
8
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
9
|
-
- `VERSION` (const): const VERSION: "0.
|
|
9
|
+
- `VERSION` (const): const VERSION: "0.33.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
10
10
|
|
|
11
11
|
## @jgengine/core/authoring
|
|
12
12
|
|
|
@@ -285,7 +285,7 @@
|
|
|
285
285
|
|
|
286
286
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
287
287
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
288
|
-
- `VERSION` (const): const VERSION: "0.
|
|
288
|
+
- `VERSION` (const): const VERSION: "0.33.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
289
289
|
|
|
290
290
|
## @jgengine/core/runtime/adapter
|
|
291
291
|
|
|
@@ -410,6 +410,7 @@
|
|
|
410
410
|
- `GameContextRace` (interface): interface GameContextRace { state(id: string, config?: RaceStateConfig): RaceState } — ⚠ undocumented
|
|
411
411
|
- `GameContextTurn` (interface): interface GameContextTurn { loop(id: string, config?: TurnLoopConfig): TurnLoop } — ⚠ undocumented
|
|
412
412
|
- `GameContextWorld` (interface): interface GameContextWorld { ground: TerrainField; groundHeightAt(x: number, z: number): number; solids: WorldSolids } — ⚠ undocumented
|
|
413
|
+
- `GameFeedback` (interface): interface GameFeedback — The game-announced feel seam on `ctx.game`: name a moment the engine has no event for and the shell plays its cue's sound, rumble, camera kick and caption. The reaction table lives in the shell, so a game never encodes what a hit or a wave should sound like.
|
|
413
414
|
- `HitReactionInput` (interface): interface HitReactionInput { from: string; to: string; config: HitReactionConfig | ImpactPresetName; power?: number } — ⚠ undocumented · used by `resolveHitReaction` (@jgengine/core/combat): Resolves hit feel (hitstop, knockback impulse, camera shake) from either a named `impactPresets` event (`resolveHitReaction("explosion", inp…
|
|
414
415
|
- `MoveTowardCommitOptions` (interface): interface MoveTowardCommitOptions extends MoveTowardOptions — Options for {@link SceneEntityContext.moveTowardCommit}: {@link MoveTowardOptions} plus an optional facing turn.
|
|
415
416
|
- `SceneEntityContext` (interface): interface SceneEntityContext { spawn(name: string, options?: SpawnOptions): string; despawn(instanceId: string): boolean; update: EntityStore["update"]; setPose(instanceId: string, pose: EntityPose): boolean; setVelocity: EntityStore["setVelocity"]; setPoseConstraint: … — ⚠ undocumented
|
|
@@ -243,7 +243,7 @@
|
|
|
243
243
|
- `createCoverField` (function): function createCoverField(options: CoverFieldOptions): CoverField — Cover over authored boxes: derive the stand points once, re-derive them after an edit, and answer bounded nearest-cover queries. `walkable` is injected, so the seam checks the game's own ground test (`nav.findPolygon(point) !== null`) instead of assuming a flat floor.
|
|
244
244
|
- `createDamageClamp` (function): function createDamageClamp(config: DamageClampConfig): DamageInterceptor — A stateless interceptor that caps any single application at `maxPerHit`.
|
|
245
245
|
- `createDamagePipeline` (function): function createDamagePipeline(initial?: readonly DamageInterceptor[]): DamagePipeline — Create a mutable damage interception chain that state transitions install into and remove from — e.g. add an invulnerability interceptor on phase enter and drop it on phase exit. Evaluation order is install order.
|
|
246
|
-
- `createDamageRuntime` (function): function createDamageRuntime(config: DamageRuntimeConfig): DamageRuntime — Build a damage model from data. The number a hit lands is `base × zone multiplier × type multiplier × (1 − armor mitigation)`; statuses tick through the same table and armor, so a burn on an armored target is mitigated like a bullet. Every application — a hit or a status tick — is announced as `combat.damage` carrying the target, source, type, amount, absorbed, remaining health
|
|
246
|
+
- `createDamageRuntime` (function): function createDamageRuntime(config: DamageRuntimeConfig): DamageRuntime — Build a damage model from data. The number a hit lands is `base × zone multiplier × type multiplier × (1 − armor mitigation)`; statuses tick through the same table and armor, so a burn on an armored target is mitigated like a bullet. Every application — a hit or a status tick — is announced as `combat.damage` carrying the target, source, type, amount, absorbed, remaining health, a lethal flag and, when `positionOf` or the hit names one, where the blow landed, so a HUD names the blow and a cue pans instead of guessing.
|
|
247
247
|
- `createDeathSystem` (function): function createDeathSystem(deps: DeathSystemDeps): DeathSystem — Resolve entity death and the on-death consequences — drops, respawn eligibility, kill credit.
|
|
248
248
|
- `createDefensiveWindow` (function): function createDefensiveWindow(config: DefensiveWindowConfig): DefensiveWindow — Open a timed defensive window — block, parry, or i-frames — and test incoming hits against it.
|
|
249
249
|
- `createDotField` (function): function createDotField(): DotField — Builds an empty {@link DotField}; `apply` DoTs onto it and drain damage each frame with `tick`.
|
|
@@ -462,7 +462,7 @@
|
|
|
462
462
|
- `TargetProfile` (interface): interface TargetProfile — What a target presents to the table: one resistance class and its armor points.
|
|
463
463
|
- `TimeToKill` (interface): interface TimeToKill — A quoted time to kill for one fixed hit against one health pool.
|
|
464
464
|
- `UnknownTargetProfileError` (class): class UnknownTargetProfileError extends Error — Raised when a hit names a target that was never registered — a wiring error, not a 0-damage hit.
|
|
465
|
-
- `createDamageRuntime` (function): function createDamageRuntime(config: DamageRuntimeConfig): DamageRuntime — Build a damage model from data. The number a hit lands is `base × zone multiplier × type multiplier × (1 − armor mitigation)`; statuses tick through the same table and armor, so a burn on an armored target is mitigated like a bullet. Every application — a hit or a status tick — is announced as `combat.damage` carrying the target, source, type, amount, absorbed, remaining health
|
|
465
|
+
- `createDamageRuntime` (function): function createDamageRuntime(config: DamageRuntimeConfig): DamageRuntime — Build a damage model from data. The number a hit lands is `base × zone multiplier × type multiplier × (1 − armor mitigation)`; statuses tick through the same table and armor, so a burn on an armored target is mitigated like a bullet. Every application — a hit or a status tick — is announced as `combat.damage` carrying the target, source, type, amount, absorbed, remaining health, a lethal flag and, when `positionOf` or the hit names one, where the blow landed, so a HUD names the blow and a cue pans instead of guessing.
|
|
466
466
|
|
|
467
467
|
## @jgengine/core/combat/damageTable
|
|
468
468
|
|
|
@@ -604,6 +604,7 @@
|
|
|
604
604
|
- `EntityAnimationEvent` (interface): interface EntityAnimationEvent — Request that an entity's rig play a one-shot animation clip bound to `event` in its `animation.oneShots` (e.g. an "attack" swing); the shell resolves the clip and plays it once over the locomotion state. With an `animation.graph`, `event` arms the trigger of that name.
|
|
605
605
|
- `EntityDiedEvent` (interface): interface EntityDiedEvent { instanceId: string; catalogId: string; userId?: string; displayName?: string; reason: DeathReason; source?: string; position: [number, number, number]; serverId?: string } — ⚠ undocumented
|
|
606
606
|
- `EntityFloatTextEvent` (interface): interface EntityFloatTextEvent { instanceId?: string; position: [number, number, number]; text: string; kind: string; amount?: number; hitType?: string; element?: string; crit?: boolean; scale?: number } — ⚠ undocumented
|
|
607
|
+
- `FeedbackCueEvent` (interface): interface FeedbackCueEvent — A gameplay moment the game announces itself, for the moments no engine event covers (a wave starting, a scripted beat). The shell reacts with the cue's sound, rumble, camera kick and caption.
|
|
607
608
|
- `FormChangedEvent` (interface): interface FormChangedEvent { instanceId: string; formId: string | null } — ⚠ undocumented
|
|
608
609
|
- `GameEventHandler` (type): type GameEventHandler<TPayload> = (payload: TPayload) => void — ⚠ undocumented
|
|
609
610
|
- `GameEventMap` (interface): interface GameEventMap { "entity.died": EntityDiedEvent; "combat.damage": DamageAppliedEvent; "entity.floatText": EntityFloatTextEvent; "combat.telegraph": CombatTelegraphEvent; "combat.vfx": CombatVfxEvent; "combat.vfxInstance": CombatVfxInstanceEvent; "combat.t… — ⚠ undocumented · used by `createGameEvents`: A typed publish/subscribe bus for gameplay events that systems and HUDs subscribe to.
|
|
@@ -1072,7 +1073,7 @@
|
|
|
1072
1073
|
- `EmoteSpatialLookup` (interface): interface EmoteSpatialLookup { inRadius(center: readonly [number, number, number], radius: number, filter?: (id: string) => boolean): readonly string[] } — ⚠ undocumented
|
|
1073
1074
|
- `Emotes` (interface): interface Emotes { play(fromUserId: string, emoteId: string, radius?: number): EmoteBroadcastResult | {reason: string} } — ⚠ undocumented
|
|
1074
1075
|
- `EmotesDeps` (interface): interface EmotesDeps { entities: EmoteEntityLookup; spatial: EmoteSpatialLookup } — ⚠ undocumented
|
|
1075
|
-
- `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
|
|
1076
|
+
- `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented · used by `useFriends` (@jgengine/react): The local player's friends with their presence: the list keeps one identity until a request is accepted, a friend is removed or a friend's p…
|
|
1076
1077
|
- `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
|
|
1077
1078
|
- `Friends` (interface): interface Friends { canRequest(fromUserId: string, toUserId: string): {reason: string} | null; request(fromUserId: string, toUserId: string): {requestId: string} | {reason: string}; accept(userId: string, requestId: string): {reason: string} | null; decline(… — ⚠ undocumented
|
|
1078
1079
|
- `FriendsSnapshot` (interface): interface FriendsSnapshot { friends: string[]; blocked: string[] } — ⚠ undocumented
|
|
@@ -1350,7 +1351,7 @@
|
|
|
1350
1351
|
- `FirstPersonCameraConfig` (interface): interface FirstPersonCameraConfig { eyeHeight?: number; sensitivity?: number; maxPitch?: number; reticle?: boolean; viewmodel?: boolean; collision?: false | FirstPersonCollisionConfig } — ⚠ undocumented
|
|
1351
1352
|
- `FirstPersonCollisionConfig` (interface): interface FirstPersonCollisionConfig — Clearance tuning for the first-person camera's collision pull-in.
|
|
1352
1353
|
- `ForbidRule` (interface): interface ForbidRule — A rule that forbids a combination — e.g. "an incendiary barrel cannot pair with a cryo core". A forbid rule can never become satisfiable by adding more parts, so it is the check a backtracking generator runs on each candidate.
|
|
1353
|
-
- `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented
|
|
1354
|
+
- `FriendEntry` (interface): interface FriendEntry { userId: string; online: boolean } — ⚠ undocumented · used by `useFriends` (@jgengine/react): The local player's friends with their presence: the list keeps one identity until a request is accepted, a friend is removed or a friend's p…
|
|
1354
1355
|
- `FriendRequestEntry` (interface): interface FriendRequestEntry { requestId: string; fromUserId: string } — ⚠ undocumented
|
|
1355
1356
|
- `Friends` (interface): interface Friends { canRequest(fromUserId: string, toUserId: string): {reason: string} | null; request(fromUserId: string, toUserId: string): {requestId: string} | {reason: string}; accept(userId: string, requestId: string): {reason: string} | null; decline(… — ⚠ undocumented
|
|
1356
1357
|
- `GAME_SAVE_VERSION` (const): const GAME_SAVE_VERSION: 1 — Current save-format version of {@link GameSaveDocument}. Bump it with {@link GameSaveConfig.migrate} when the shape changes.
|
|
@@ -455,11 +455,11 @@
|
|
|
455
455
|
|
|
456
456
|
## @jgengine/core/audio/audioFalloff
|
|
457
457
|
|
|
458
|
-
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented · used by `
|
|
458
|
+
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented · used by `withFeedbackCueSounds` (@jgengine/core/audio/feedbackCues): Merge the default feedback reactions into a game's sound catalog.
|
|
459
459
|
- `AudioBusId` (type): type AudioBusId = string — ⚠ undocumented
|
|
460
460
|
- `AudioFalloffConfig` (interface): interface AudioFalloffConfig { minDistance?: number; maxDistance?: number; curve?: FalloffCurve } — ⚠ undocumented
|
|
461
461
|
- `FalloffCurve` (type): type FalloffCurve = "linear" | "inverse" | "none" — ⚠ undocumented
|
|
462
|
-
- `SoundDef` (interface): interface SoundDef { id: string; url?: string; synth?: SynthPatch; bus: AudioBusId; gain?: number; loop?: boolean; maxVoices?: number; priority?: number; positional?: boolean; falloff?: AudioFalloffConfig; doppler?: number; spatial?: {panning: "hrtf" | "equal… — ⚠ undocumented · used by `
|
|
462
|
+
- `SoundDef` (interface): interface SoundDef { id: string; url?: string; synth?: SynthPatch; bus: AudioBusId; gain?: number; loop?: boolean; maxVoices?: number; priority?: number; positional?: boolean; falloff?: AudioFalloffConfig; doppler?: number; spatial?: {panning: "hrtf" | "equal… — ⚠ undocumented · used by `DEFAULT_FEEDBACK_CUE_SOUNDS` (@jgengine/core/audio/feedbackCues): Short procedural reactions - no samples to load, so every game has impact feedback without authoring audio.
|
|
463
463
|
- `computeFalloffGain` (function): function computeFalloffGain(distance: number, config: AudioFalloffConfig = {}): number — ⚠ undocumented
|
|
464
464
|
- `distance3` (function): function distance3(a: { x: number; y: number; z: number }, b: { x: number; y: number; z: number }): number — ⚠ undocumented
|
|
465
465
|
- `resolveEmitterGain` (function): function resolveEmitterGain(distance: number, sound: Pick<SoundDef, "gain" | "positional" | "falloff">, busGain: number): number — ⚠ undocumented
|
|
@@ -481,6 +481,16 @@
|
|
|
481
481
|
- `EngineLayersState` (interface): interface EngineLayersState — Serializable {@link EngineLayers} state.
|
|
482
482
|
- `createEngineLayers` (function): function createEngineLayers(initial: EngineLayersConfig): EngineLayers — Layered engine sound: each set of rpm-keyed samples is equal-power crossfaded between the two samples bracketing the current rpm and pitched by `rpm / layer.rpm`; the on- and off-load sets are equal-power crossfaded by smoothed `engineLoad`. A config with only one load set plays it at every load. `play` drives `ctx.game.audio` directly, so a game needs no per-layer glue.
|
|
483
483
|
|
|
484
|
+
## @jgengine/core/audio/feedbackCues
|
|
485
|
+
|
|
486
|
+
- `DEFAULT_FEEDBACK_CUE_SOUNDS` (const): const DEFAULT_FEEDBACK_CUE_SOUNDS: Readonly<Record<FeedbackCue, SoundDef>> — Short procedural reactions - no samples to load, so every game has impact feedback without authoring audio. Loud enough to read, quiet enough to sit under a weapon's own sound.
|
|
487
|
+
- `FEEDBACK_CUES` (const): const FEEDBACK_CUES: readonly FeedbackCue[] — Every {@link FeedbackCue}, in a stable order.
|
|
488
|
+
- `FEEDBACK_CUE_BUS` (const): const FEEDBACK_CUE_BUS: "sfx" — Bus the default feedback cues mix through; the settings menu shows its volume and mute.
|
|
489
|
+
- `FeedbackCue` (type): type FeedbackCue = "hit" | "hurt" | "kill" | "pickup" | "objective" | "wave" | "deny" — A gameplay moment the engine reacts to: taking or dealing a hit, a kill, a pickup, an objective, a wave starting, or a refused action. The game names the moment; the engine owns the reaction.
|
|
490
|
+
- `FeedbackCueOverrides` (type): type FeedbackCueOverrides = false | Partial<Record<FeedbackCue, SoundDef | false>> — Per-cue override: a replacement sound, or `false` to silence that cue. `false` for the whole map silences all.
|
|
491
|
+
- `feedbackCueSoundId` (function): function feedbackCueSoundId(cue: FeedbackCue): string — Catalog id a cue plays under: `feel.hit`, `feel.kill`, ... A game sound with that id replaces the default.
|
|
492
|
+
- `withFeedbackCueSounds` (function): function withFeedbackCueSounds(sounds: Readonly<Record<string, SoundDef>> | undefined, buses: Readonly<Record<string, AudioBusDef>> | undefined, overrides?: FeedbackCueOverrides): { sounds: Record<string, SoundDef>; buses: Record<string, AudioBusDef> | undefined } — Merge the default feedback reactions into a game's sound catalog. A game sound already named `feel.<cue>` wins, then `overrides`, then the default. Adds the `sfx` bus (gain 0.9) when the game did not declare one, so the impact layer has its own volume and mute row.
|
|
493
|
+
|
|
484
494
|
## @jgengine/core/audio/music
|
|
485
495
|
|
|
486
496
|
- `MusicInstrument` (type): type MusicInstrument = | "strings" | "flute" | "harp" | "horn" | "choir" | "bell" | "timpani" | "bass" | "stacc" | "pad" | "lute" | "dulcimer" | "frameDrum" | "warDrum" | "reed" | "pipe" | "squareLead" | "woodBlock" | "tinyBell" | "piano" | "shaker" | "brassStab" | "cymSwell" | "oboe" — Named synthesised instrument. Each maps to a voice in the shell's instrument library (`@jgengine/shell/audio/musicVoices`); an unknown name falls back to a plain sine voice so a theme is never silent.
|
|
@@ -991,7 +1001,7 @@
|
|
|
991
1001
|
## @jgengine/core/movement/solidObstacles
|
|
992
1002
|
|
|
993
1003
|
- `ObstacleReach` (interface): interface ObstacleReach — Largest blocking-collider extent in the scene, split so tower height cannot inflate the XZ query.
|
|
994
|
-
- `ObstacleReachCache` (interface): interface ObstacleReachCache — Mutable reach cache; one per source, invalidated by object count.
|
|
1004
|
+
- `ObstacleReachCache` (interface): interface ObstacleReachCache — Mutable reach cache; one per source, invalidated by object count or by the source's version.
|
|
995
1005
|
- `SolidObstacleSource` (interface): interface SolidObstacleSource — The slice of the scene's object store this query needs. Narrow on purpose: the scene context wires its own store here while it is still being constructed, `ctx.scene.object` satisfies it as-is, and a pure rules package with no `GameContext` to import can satisfy it from its own object list.
|
|
996
1006
|
- `createObstacleReachCache` (function): function createObstacleReachCache(): ObstacleReachCache — A fresh {@link ObstacleReachCache} for a caller that owns its own source.
|
|
997
1007
|
- `obstacleFromSolid` (function): function obstacleFromSolid(solid: WorldSolid): CollisionObstacle — A {@link WorldSolid} as a {@link CollisionObstacle}. Axis-aligned solids are one box; a yawed solid is cut into strips along its long axis, each fitted with an AABB, so a turned building does not block the street beside it the way a single enclosing box would.
|
|
@@ -1000,7 +1010,7 @@
|
|
|
1000
1010
|
- `slideStep` (function): function slideStep(position: EntityPosition, stepX: number, stepZ: number, obstacles: readonly CollisionObstacle[], radius = DEFAULT_OBSTACLE_PLAYER_RADIUS, stepUpHeight = 0): { stepX: number; stepZ: number } — {@link resolveWalkerStep} against an already-gathered obstacle set.
|
|
1001
1011
|
- `solidObstaclesNear` (function): function solidObstaclesNear(ctx: GameContext, position: EntityPosition, reachX: number, reachZ: number, height = WALKER_HEIGHT): CollisionObstacle[] — Every blocking physical obstacle overlapping the box `position` ± `reachX`/`reachZ`, read from the scene's resolved colliders and `ctx.world.solids`.
|
|
1002
1012
|
- `sourceObstacleReach` (function): function sourceObstacleReach(source: SolidObstacleSource, cache: ObstacleReachCache): ObstacleReach — {@link solidObstacleReach} against a bare source and caller-owned cache.
|
|
1003
|
-
- `sourceObstaclesNear` (function): function sourceObstaclesNear(source: SolidObstacleSource, reach: ObstacleReach, position: EntityPosition, reachX: number, reachZ: number, height = WALKER_HEIGHT): CollisionObstacle[] — {@link solidObstaclesNear} against a bare source and an already-resolved reach.
|
|
1013
|
+
- `sourceObstaclesNear` (function): function sourceObstaclesNear(source: SolidObstacleSource, reach: ObstacleReach, position: EntityPosition, reachX: number, reachZ: number, height = WALKER_HEIGHT, cache?: ObstacleReachCache): CollisionObstacle[] — {@link solidObstaclesNear} against a bare source and an already-resolved reach. Pass the source's {@link ObstacleReachCache} to use the version-keyed obstacle index; a source that reports no `version()` keeps the per-query `inBox` gather.
|
|
1004
1014
|
|
|
1005
1015
|
## @jgengine/core/movement/steering
|
|
1006
1016
|
|
|
@@ -2027,7 +2037,7 @@
|
|
|
2027
2037
|
|
|
2028
2038
|
## @jgengine/core/sensor/revealQuery
|
|
2029
2039
|
|
|
2030
|
-
- `RevealHit` (interface): interface RevealHit { instanceId: string; distance: number; tags: readonly string[] } — ⚠ undocumented · used by `useRevealHits` (@jgengine/shell/vision/RevealVision): Occlusion-ignoring tagged-entity radius query (#115), bound to the live scene.
|
|
2040
|
+
- `RevealHit` (interface): interface RevealHit { instanceId: string; distance: number; tags: readonly string[] } — ⚠ undocumented · used by `useRevealHits` (@jgengine/shell/vision/RevealVision): Occlusion-ignoring tagged-entity radius query (#115), bound to the live scene and refreshed on render.
|
|
2031
2041
|
- `RevealQuery` (interface): interface RevealQuery { inRadius(center: EntityPosition | string, radius: number, tags: readonly string[]): RevealHit[] } — ⚠ undocumented
|
|
2032
2042
|
- `RevealQueryOptions` (interface): interface RevealQueryOptions { resolvePosition: (instanceId: string) => EntityPosition | undefined; resolveTags: (instanceId: string) => readonly string[]; candidates: () => string[] } — ⚠ undocumented
|
|
2033
2043
|
|
|
@@ -2358,7 +2368,7 @@
|
|
|
2358
2368
|
- `AssetSpace` (interface): interface AssetSpace — Catalog-level asset-space metadata: how a model is authored relative to the engine, owned by the catalog entry rather than re-derived per game. Every field is optional so an unmeasured asset stays valid; {@link resolveFacingRotationY}/{@link assetUnitScale}/{@link resolveAnchorOffset} supply the documented defaults.
|
|
2359
2369
|
- `AssetSpaceIssue` (interface): interface AssetSpaceIssue — One problem found by {@link validateAssetSpace}: which metadata field and why it is invalid.
|
|
2360
2370
|
- `AttackMoveOrderPayload` (interface): interface AttackMoveOrderPayload — Payload for an attack-move: advance toward `point`, engaging hostiles encountered en route.
|
|
2361
|
-
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented · used by `
|
|
2371
|
+
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented · used by `withFeedbackCueSounds` (@jgengine/core/audio/feedbackCues): Merge the default feedback reactions into a game's sound catalog.
|
|
2362
2372
|
- `AudioFalloffConfig` (interface): interface AudioFalloffConfig { minDistance?: number; maxDistance?: number; curve?: FalloffCurve } — ⚠ undocumented
|
|
2363
2373
|
- `AuthoredNavLink` (interface): interface AuthoredNavLink — A connection the scene author places between two spots — a door through a wall, a ladder to a deck, a jump across a gap. Authored as world points, not polygon ids, so it survives a re-bake: {@link NavRuntime.applyMesh} resolves each end onto the nearest walkable polygon.
|
|
2364
2374
|
- `AuthoredTrigger` (interface): interface AuthoredTrigger — One resolved trigger binding from a document object.
|
|
@@ -2772,7 +2782,7 @@
|
|
|
2772
2782
|
- `ResolvedTerrainDetail` (type): type ResolvedTerrainDetail = Required<Omit<TerrainDetailConfig, "waterLevel" | "material" | "sweeps">> & { waterLevel: number; material?: ResolvedTerrainDetailMaterial; sweeps: { dry: readonly [number, number, number]; wet: readonly [number, number, number] }; } — A {@link TerrainDetailConfig} with every field resolved to a concrete value — the shape the shell's detail material consumes.
|
|
2773
2783
|
- `ResolvedWeather` (interface): interface ResolvedWeather { grip: number; visibility: number; structureDamage: number; chill: number; ignition: number; spread: number } — ⚠ undocumented
|
|
2774
2784
|
- `ResponseCurve` (type): type ResponseCurve = | { readonly kind: "linear"; readonly from: number; readonly to: number } /** Same shape as `linear`, raised to `exponent` (default `2`), so appeal stays flat until it matters. */ | { readonly kind: "quadratic"; readonly from: number; readonly to: number; readonly exponent?: num… — How one need's satisfaction maps to an option's appeal: `1` at `from`, `0` at `to`, clamped outside. Read satisfaction `1` as a full meter; pair with {@link UtilityTerm.invert} when a full meter is what makes the option attractive.
|
|
2775
|
-
- `RevealHit` (interface): interface RevealHit { instanceId: string; distance: number; tags: readonly string[] } — ⚠ undocumented · used by `useRevealHits` (@jgengine/shell/vision/RevealVision): Occlusion-ignoring tagged-entity radius query (#115), bound to the live scene.
|
|
2785
|
+
- `RevealHit` (interface): interface RevealHit { instanceId: string; distance: number; tags: readonly string[] } — ⚠ undocumented · used by `useRevealHits` (@jgengine/shell/vision/RevealVision): Occlusion-ignoring tagged-entity radius query (#115), bound to the live scene and refreshed on render.
|
|
2776
2786
|
- `RevealQuery` (interface): interface RevealQuery { inRadius(center: EntityPosition | string, radius: number, tags: readonly string[]): RevealHit[] } — ⚠ undocumented
|
|
2777
2787
|
- `RoadCut` (interface): interface RoadCut — One trim of a ribbon end back to a junction boundary — the seam the welded surface attaches to.
|
|
2778
2788
|
- `RoadEnvironmentDescriptor` (type): type RoadEnvironmentDescriptor = { kind: "road" } & Required< Pick<RoadEnvironmentConfig, "path" | "width" | "color" | "markings" | "markingColor" | "elevation"> > & { /** Resolved sidewalk band, or `false` when the road has none. */ sidewalk: { width: number; color: string } | false; /** Procedural… — Resolved road descriptor produced by {@link road} and rendered by the shell environment scene.
|
|
@@ -2847,7 +2857,7 @@
|
|
|
2847
2857
|
- `SnapMode` (type): type SnapMode = "grid" | "free" | "surface" — ⚠ undocumented
|
|
2848
2858
|
- `SnowEnvironmentDescriptor` (type): type SnowEnvironmentDescriptor = { kind: "snow" } & Required< Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity"> > — ⚠ undocumented · used by `snow`: Declares a snowfall weather effect for `environment()` — area, density, drift, wind, and flake opacity.
|
|
2849
2859
|
- `SoilRules` (interface): interface SoilRules — Fully-defaulted soil params parsed from a volume's `meta`.
|
|
2850
|
-
- `SoundDef` (interface): interface SoundDef { id: string; url?: string; synth?: SynthPatch; bus: AudioBusId; gain?: number; loop?: boolean; maxVoices?: number; priority?: number; positional?: boolean; falloff?: AudioFalloffConfig; doppler?: number; spatial?: {panning: "hrtf" | "equal… — ⚠ undocumented · used by `
|
|
2860
|
+
- `SoundDef` (interface): interface SoundDef { id: string; url?: string; synth?: SynthPatch; bus: AudioBusId; gain?: number; loop?: boolean; maxVoices?: number; priority?: number; positional?: boolean; falloff?: AudioFalloffConfig; doppler?: number; spatial?: {panning: "hrtf" | "equal… — ⚠ undocumented · used by `DEFAULT_FEEDBACK_CUE_SOUNDS` (@jgengine/core/audio/feedbackCues): Short procedural reactions - no samples to load, so every game has impact feedback without authoring audio.
|
|
2851
2861
|
- `SpatialGrid` (class): class SpatialGrid — A uniform-grid broad-phase over the x/z plane, separate from the rigid-body sim, for cheap same-tick proximity across hundreds–thousands of simple movers (swarm enemies). Rebuild each tick from the caller's own position arrays, then `queryCircle` (enemies hitting the player / an AoE) or `forEachPair` (mutual separation). Both are precise: no false negatives, no false positives beyond the exact distance test.
|
|
2852
2862
|
- `SpawnDirectorConfig` (interface): interface SpawnDirectorConfig { waves: readonly WaveManifest[]; maxAlive?: number; escalationPerSecond?: number; alertBudgetPerSecond?: number; alertDecayPerSecond?: number; playerBudgetPerSecond?: number; maxSpawnsPerTick?: number; loop?: boolean; seed?: number; spawnP… — ⚠ undocumented
|
|
2853
2863
|
- `SpawnDirectorState` (interface): interface SpawnDirectorState { wave: number; elapsed: number; waveElapsed: number; budget: number; alert: number; spawnedThisWave: number; spawnedTotal: number; rng: RandomSeed; done: boolean } — ⚠ undocumented
|
|
@@ -370,6 +370,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
370
370
|
|
|
371
371
|
- `createFastTravelNetwork` (function) · `import { createFastTravelNetwork } from "@jgengine/core/world"`
|
|
372
372
|
|
|
373
|
+
## feedback-cue-sounds — default procedural hit/hurt/kill/pickup/objective/wave/deny reactions on an "sfx" bus, overridable per game
|
|
374
|
+
|
|
375
|
+
- `withFeedbackCueSounds` (function) · `import { withFeedbackCueSounds } from "@jgengine/core/audio/feedbackCues"`
|
|
376
|
+
|
|
373
377
|
## feedback-mixer — map sim telemetry to camera, audio and haptic parameters through curves, smoothing and threshold events
|
|
374
378
|
|
|
375
379
|
- `createFeedbackMixer` (function) · `import { createFeedbackMixer } from "@jgengine/core/vfx/feedbackMixer"`
|