@jgengine/core 0.7.0 → 0.8.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 +47 -0
- package/README.md +2 -0
- package/dist/ai/spawnDirector.d.ts +5 -0
- package/dist/ai/spawnDirector.js +13 -1
- package/dist/anim/easing.d.ts +14 -0
- package/dist/anim/easing.js +55 -0
- package/dist/behaviour/behaviour.d.ts +136 -0
- package/dist/behaviour/behaviour.js +388 -0
- package/dist/cards/cardPile.d.ts +1 -0
- package/dist/cards/cardPile.js +12 -3
- package/dist/combat/abilityKit.d.ts +5 -0
- package/dist/combat/abilityKit.js +10 -0
- package/dist/combat/effects.d.ts +1 -1
- package/dist/combat/effects.js +9 -6
- package/dist/combat/projectiles.d.ts +42 -5
- package/dist/combat/projectiles.js +98 -12
- package/dist/combat/telegraph.d.ts +5 -1
- package/dist/combat/telegraph.js +14 -0
- package/dist/commands/commandRegistry.d.ts +1 -1
- package/dist/commands/commandRegistry.js +2 -1
- package/dist/data/dataSource.d.ts +26 -0
- package/dist/data/dataSource.js +93 -0
- package/dist/data/devProxy.d.ts +11 -0
- package/dist/data/devProxy.js +38 -0
- package/dist/data/fetchJson.d.ts +20 -0
- package/dist/data/fetchJson.js +43 -0
- package/dist/data/jsonDataSource.d.ts +4 -0
- package/dist/data/jsonDataSource.js +6 -0
- package/dist/devtools/devtools.d.ts +157 -0
- package/dist/devtools/devtools.js +484 -0
- package/dist/devtools/transformTunables.d.ts +14 -0
- package/dist/devtools/transformTunables.js +38 -0
- package/dist/game/chat.d.ts +66 -0
- package/dist/game/chat.js +165 -0
- package/dist/game/defineGame.d.ts +8 -2
- package/dist/game/defineGame.js +2 -1
- package/dist/game/events.d.ts +25 -0
- package/dist/game/levelSequence.d.ts +44 -0
- package/dist/game/levelSequence.js +78 -0
- package/dist/game/playableGame.d.ts +237 -6
- package/dist/game/playableGame.js +6 -1
- package/dist/game/progression.d.ts +1 -0
- package/dist/game/progression.js +23 -2
- package/dist/game/race.d.ts +5 -0
- package/dist/game/race.js +20 -0
- package/dist/game/social.d.ts +42 -0
- package/dist/game/social.js +122 -0
- package/dist/game/spawnPoints.d.ts +19 -0
- package/dist/game/spawnPoints.js +23 -0
- package/dist/game/worldItem.d.ts +3 -0
- package/dist/game/worldItem.js +12 -6
- package/dist/input/actionBindings.d.ts +10 -0
- package/dist/input/actionBindings.js +14 -0
- package/dist/input/gestureSurface.d.ts +31 -0
- package/dist/input/gestureSurface.js +120 -0
- package/dist/input/pointer.d.ts +45 -0
- package/dist/input/pointer.js +48 -0
- package/dist/input/touchScheme.d.ts +83 -0
- package/dist/input/touchScheme.js +115 -0
- package/dist/item/affix.d.ts +1 -1
- package/dist/item/affix.js +1 -19
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +37 -1
- package/dist/movement/movementModel.d.ts +36 -3
- package/dist/movement/movementModel.js +81 -5
- package/dist/movement/voxelController.d.ts +61 -0
- package/dist/movement/voxelController.js +229 -0
- package/dist/multiplayer/chatContract.d.ts +42 -0
- package/dist/multiplayer/chatContract.js +57 -0
- package/dist/multiplayer/identity.d.ts +13 -0
- package/dist/multiplayer/identity.js +20 -0
- package/dist/multiplayer/poseSyncGate.d.ts +1 -0
- package/dist/multiplayer/poseSyncGate.js +13 -1
- package/dist/multiplayer/presenceModel.d.ts +3 -0
- package/dist/multiplayer/presenceModel.js +15 -1
- package/dist/multiplayer/voiceContract.d.ts +44 -0
- package/dist/multiplayer/voiceContract.js +108 -0
- package/dist/nav/navConstrain.d.ts +14 -0
- package/dist/nav/navConstrain.js +26 -0
- package/dist/nav/navFromEnvironment.d.ts +11 -0
- package/dist/nav/navFromEnvironment.js +16 -0
- package/dist/nav/navGrid.d.ts +10 -0
- package/dist/nav/navGrid.js +18 -1
- package/dist/nav/pathFollow.d.ts +4 -2
- package/dist/nav/pathFollow.js +5 -3
- package/dist/physics/ballisticSweep.d.ts +18 -0
- package/dist/physics/ballisticSweep.js +49 -0
- package/dist/physics/forceVolume.js +5 -5
- package/dist/physics/physicsWorld.d.ts +41 -2
- package/dist/physics/physicsWorld.js +232 -40
- package/dist/physics/spatialGrid.d.ts +1 -1
- package/dist/physics/spatialGrid.js +5 -0
- package/dist/physics/vehicleBody.d.ts +6 -0
- package/dist/physics/vehicleBody.js +16 -17
- package/dist/puzzle/cellGrid.d.ts +26 -0
- package/dist/puzzle/cellGrid.js +110 -0
- package/dist/puzzle/fallingPiece.d.ts +24 -0
- package/dist/puzzle/fallingPiece.js +51 -0
- package/dist/random/nameGen.d.ts +18 -0
- package/dist/random/nameGen.js +35 -0
- package/dist/random/rng.d.ts +2 -0
- package/dist/random/rng.js +23 -0
- package/dist/runtime/adapter.d.ts +35 -0
- package/dist/runtime/adapter.js +37 -1
- package/dist/runtime/cameraDirector.d.ts +10 -0
- package/dist/runtime/cameraDirector.js +25 -0
- package/dist/runtime/gameContext.d.ts +44 -2
- package/dist/runtime/gameContext.js +100 -4
- package/dist/runtime/hostPersistence.d.ts +21 -0
- package/dist/runtime/hostPersistence.js +50 -0
- package/dist/runtime/inputSnapshot.d.ts +7 -0
- package/dist/runtime/inputSnapshot.js +12 -0
- package/dist/runtime/motionIntents.d.ts +25 -0
- package/dist/runtime/motionIntents.js +25 -0
- package/dist/runtime/transport.d.ts +32 -0
- package/dist/scene/entityStore.d.ts +8 -0
- package/dist/scene/entityStore.js +25 -2
- package/dist/scene/movementSpeed.d.ts +35 -0
- package/dist/scene/movementSpeed.js +20 -0
- package/dist/scene/objectQuery.d.ts +18 -0
- package/dist/scene/objectQuery.js +108 -0
- package/dist/scene/objectStore.d.ts +11 -0
- package/dist/scene/objectStore.js +109 -4
- package/dist/scene/paintLayer.d.ts +15 -0
- package/dist/scene/paintLayer.js +53 -0
- package/dist/scene/spatial.d.ts +21 -0
- package/dist/scene/spatial.js +63 -1
- package/dist/sensor/concealment.d.ts +21 -0
- package/dist/sensor/concealment.js +63 -0
- package/dist/sensor/freezeMonitor.d.ts +17 -0
- package/dist/sensor/freezeMonitor.js +35 -0
- package/dist/session/roles.d.ts +6 -0
- package/dist/session/roles.js +32 -0
- package/dist/session/roundState.d.ts +41 -17
- package/dist/session/roundState.js +67 -38
- package/dist/tactics/fallingGrid.d.ts +62 -0
- package/dist/tactics/fallingGrid.js +158 -0
- package/dist/tactics/tacticalGrid.d.ts +11 -0
- package/dist/tactics/tacticalGrid.js +17 -0
- package/dist/time/simClock.d.ts +25 -1
- package/dist/time/simClock.js +28 -3
- package/dist/turn/intent.d.ts +14 -0
- package/dist/turn/intent.js +29 -0
- package/dist/turn/turnLoop.d.ts +2 -0
- package/dist/turn/turnLoop.js +8 -1
- package/dist/world/environmentSummary.d.ts +53 -0
- package/dist/world/environmentSummary.js +129 -0
- package/dist/world/features.d.ts +87 -6
- package/dist/world/features.js +52 -2
- package/dist/world/gridInstances.d.ts +13 -0
- package/dist/world/gridInstances.js +22 -0
- package/dist/world/placementController.d.ts +22 -1
- package/dist/world/placementController.js +56 -0
- package/dist/world/terrain.d.ts +23 -1
- package/dist/world/terrain.js +64 -1
- package/dist/world/voxelField.d.ts +54 -0
- package/dist/world/voxelField.js +241 -0
- package/llms.txt +4102 -0
- package/package.json +3 -2
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { AudioBusDef, SoundDef } from "../audio/audioFalloff.js";
|
|
2
|
+
import type { TouchControlsConfig } from "../input/touchScheme.js";
|
|
2
3
|
import type { PositionedPrompt } from "../interaction/proximityPrompt.js";
|
|
3
|
-
import type { GameContext, GameContextContent } from "../runtime/gameContext.js";
|
|
4
|
+
import type { CatalogEntityRole, GameContext, GameContextContent } from "../runtime/gameContext.js";
|
|
4
5
|
import type { ModelDims } from "../scene/assetCatalog.js";
|
|
6
|
+
import type { SkyEnvironmentConfig } from "../world/features.js";
|
|
5
7
|
import type { GameDefinition, GameLoop } from "./defineGame.js";
|
|
6
8
|
import type { LootFilterRule } from "./lootFilter.js";
|
|
7
9
|
import type { RarityStyle } from "./worldItem.js";
|
|
@@ -25,6 +27,8 @@ export interface PointerConfig {
|
|
|
25
27
|
grabWorldItems?: boolean;
|
|
26
28
|
/** Press the bound `ping` action → `worldHit()` → run this command with `{ point, entity, object, normal }` (contextual ping, #94). */
|
|
27
29
|
pingCommand?: string;
|
|
30
|
+
/** Right-click runs this command with `{ point, entity, object, aim }` when neither `orderCommand` nor `contextMenu` claims the click (#164.4). */
|
|
31
|
+
secondaryCommand?: string;
|
|
28
32
|
}
|
|
29
33
|
export interface CameraFollowState {
|
|
30
34
|
entityId: string;
|
|
@@ -65,13 +69,31 @@ export interface FirstPersonCameraConfig {
|
|
|
65
69
|
* - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe.
|
|
66
70
|
* - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views.
|
|
67
71
|
* - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input.
|
|
72
|
+
* - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`.
|
|
73
|
+
* - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input.
|
|
74
|
+
* - `inspection` — model-viewer rig (#207.7): left-drag orbit, middle/right-drag pan, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input.
|
|
75
|
+
* - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
|
|
68
76
|
*/
|
|
69
|
-
export type CameraRigKind = "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer";
|
|
77
|
+
export type CameraRigKind = "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none";
|
|
78
|
+
/** Fixed lateral 2.5D follow (side-on platformer cam): the camera sits perpendicular to the travel axis, tracks the followed entity, and never reads player look input. */
|
|
79
|
+
export interface SideScrollCameraConfig {
|
|
80
|
+
/** World axis the action travels along; the camera watches from the perpendicular side. Default "x". */
|
|
81
|
+
axis?: "x" | "z";
|
|
82
|
+
/** Camera distance from the followed entity along the perpendicular axis. Default 10. */
|
|
83
|
+
distance?: number;
|
|
84
|
+
/** Camera height above the followed entity. Default 3. */
|
|
85
|
+
height?: number;
|
|
86
|
+
/** Height of the look point above the entity. Default 1. */
|
|
87
|
+
lookHeight?: number;
|
|
88
|
+
/** Per-second smoothing factor for the follow (0 hard-locks). Default 8. */
|
|
89
|
+
followSmoothing?: number;
|
|
90
|
+
fov?: number;
|
|
91
|
+
}
|
|
70
92
|
/** Fixed top-down / isometric rig (#23) — height/pitch/yaw + decoupled follow. */
|
|
71
93
|
export interface TopDownCameraConfig {
|
|
72
94
|
/** Camera height above the follow point. Default 18. */
|
|
73
95
|
height?: number;
|
|
74
|
-
/**
|
|
96
|
+
/** Elevation of the camera above the ground plane in radians (PI/2 = straight down, near 0 = grazing; values below 0.05 clamp to 0.05). Default ~1.02 (~58°, ARPG iso). */
|
|
75
97
|
pitch?: number;
|
|
76
98
|
/** Fixed azimuth in radians; ~PI/4 reads as isometric, 0 as straight top-down. Default PI/4. */
|
|
77
99
|
yaw?: number;
|
|
@@ -113,6 +135,8 @@ export interface RtsCameraConfig extends TopDownCameraConfig {
|
|
|
113
135
|
x?: number;
|
|
114
136
|
z?: number;
|
|
115
137
|
};
|
|
138
|
+
/** Read WASD/arrow pan, edge-scroll, Q/E rotate, and wheel zoom. `false` sits static at the start/bounds position — a backdrop camera, no input at all. Default true. */
|
|
139
|
+
pan?: boolean;
|
|
116
140
|
}
|
|
117
141
|
/** Over-the-shoulder combat rig (#25) — offset, ADS, shoulder swap, decoupled reticle. */
|
|
118
142
|
export interface ShoulderCameraConfig {
|
|
@@ -225,6 +249,70 @@ export interface ObserverCameraConfig {
|
|
|
225
249
|
startAngle?: number;
|
|
226
250
|
fov?: number;
|
|
227
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Turntable / showcase rig — slowly auto-orbits a fixed world point (no player
|
|
254
|
+
* input), the way a museum turntable rotates an object on display. A flat,
|
|
255
|
+
* self-describing spelling of `observer`'s point-orbit mode: `target` names the
|
|
256
|
+
* point directly instead of `bind: { kind: "point", position }`. Set
|
|
257
|
+
* `camera.turntable` and the rig is inferred — you don't also write `rig`.
|
|
258
|
+
*/
|
|
259
|
+
export interface TurntableCameraConfig {
|
|
260
|
+
/** World point the camera circles. Default the world origin. */
|
|
261
|
+
target?: {
|
|
262
|
+
x: number;
|
|
263
|
+
y: number;
|
|
264
|
+
z: number;
|
|
265
|
+
};
|
|
266
|
+
/** Orbit radius from the target. Default 8. */
|
|
267
|
+
distance?: number;
|
|
268
|
+
/** Camera height above the target. Default 3. */
|
|
269
|
+
height?: number;
|
|
270
|
+
/** Height of the look point above the target. Default 1.2. */
|
|
271
|
+
lookHeight?: number;
|
|
272
|
+
/** Radians/second of rotation; 0 holds a fixed angle. Default 0.2. */
|
|
273
|
+
orbitSpeed?: number;
|
|
274
|
+
/** Starting angle in radians. Default 0. */
|
|
275
|
+
startAngle?: number;
|
|
276
|
+
fov?: number;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* How scroll-zoom re-anchors the view for the inspection rig (#207.7):
|
|
280
|
+
* - `target` — dolly toward the orbit target (classic OrbitControls behavior).
|
|
281
|
+
* - `cursor` — dolly toward the point under the pointer.
|
|
282
|
+
* - `center` — dolly toward the viewport center; equivalent to `target` for an
|
|
283
|
+
* OrbitControls-driven rig, since the camera always faces `target` and that
|
|
284
|
+
* point already projects to the exact center of the viewport.
|
|
285
|
+
*/
|
|
286
|
+
export type InspectionZoomAnchor = "target" | "cursor" | "center";
|
|
287
|
+
/** Model-viewer / inspection rig (#207.7) — orbit + pan + anchored zoom around a fixed point, never reads player input. */
|
|
288
|
+
export interface InspectionCameraConfig {
|
|
289
|
+
/** Where scroll-zoom re-anchors the view. Default "target". */
|
|
290
|
+
anchor?: InspectionZoomAnchor;
|
|
291
|
+
/** Orbit target (the point orbited/panned around). Default origin. */
|
|
292
|
+
target?: {
|
|
293
|
+
x?: number;
|
|
294
|
+
y?: number;
|
|
295
|
+
z?: number;
|
|
296
|
+
};
|
|
297
|
+
/** Camera distance from `target` used to seed the initial camera position when `initialPosition` is unset. Default 6. */
|
|
298
|
+
initialDistance?: number;
|
|
299
|
+
/** Explicit starting camera world position; overrides `initialDistance` when set. */
|
|
300
|
+
initialPosition?: {
|
|
301
|
+
x?: number;
|
|
302
|
+
y?: number;
|
|
303
|
+
z?: number;
|
|
304
|
+
};
|
|
305
|
+
minDistance?: number;
|
|
306
|
+
maxDistance?: number;
|
|
307
|
+
/** Vertical orbit clamp (radians). Unset allows a full pole-to-pole orbit, unlike the tighter default on the classic orbit rig. */
|
|
308
|
+
minPolarAngle?: number;
|
|
309
|
+
maxPolarAngle?: number;
|
|
310
|
+
/** Middle-mouse/right-drag pan. Default true for this rig. */
|
|
311
|
+
pan?: boolean;
|
|
312
|
+
rotateSpeed?: number;
|
|
313
|
+
zoomSpeed?: number;
|
|
314
|
+
dampingFactor?: number;
|
|
315
|
+
}
|
|
228
316
|
/** One stop on a scripted camera path (#29). */
|
|
229
317
|
export interface CameraKeyframe {
|
|
230
318
|
position: {
|
|
@@ -262,9 +350,20 @@ export interface CameraShakeConfig {
|
|
|
262
350
|
/** Noise frequency (Hz) of the shake oscillation. Default 24. */
|
|
263
351
|
frequency?: number;
|
|
264
352
|
}
|
|
353
|
+
export declare const CAMERA_FRUSTUM_DEFAULTS: {
|
|
354
|
+
readonly fov: 55;
|
|
355
|
+
readonly near: 0.1;
|
|
356
|
+
readonly far: 300;
|
|
357
|
+
};
|
|
265
358
|
export interface GameCameraConfig {
|
|
266
359
|
/** Selects the rig. Overrides `perspective`; leave unset to fall back to `perspective`. */
|
|
267
360
|
rig?: CameraRigKind;
|
|
361
|
+
/** Render frustum overrides applied to the canvas camera. `far` defaults to 300 — raise it for worlds whose content spans more than a few hundred units, or distant scenery silently clips. */
|
|
362
|
+
frustum?: {
|
|
363
|
+
fov?: number;
|
|
364
|
+
near?: number;
|
|
365
|
+
far?: number;
|
|
366
|
+
};
|
|
268
367
|
/** "third" mounts the orbit camera (default); "first" mounts pointer-lock mouse-look. Shorthand for `rig: "orbit" | "first"`. */
|
|
269
368
|
perspective?: "third" | "first";
|
|
270
369
|
/** First-person tuning; only read when the rig resolves to "first". */
|
|
@@ -281,6 +380,12 @@ export interface GameCameraConfig {
|
|
|
281
380
|
chase?: ChaseCameraConfig;
|
|
282
381
|
/** Detached spectator/photo cam tuning (#120); read when `rig: "observer"`. */
|
|
283
382
|
observer?: ObserverCameraConfig;
|
|
383
|
+
/** Turntable / showcase tuning; setting this selects the `turntable` rig on its own. */
|
|
384
|
+
turntable?: TurntableCameraConfig;
|
|
385
|
+
/** Fixed side-on follow tuning; read when `rig: "sideScroll"`. */
|
|
386
|
+
sideScroll?: SideScrollCameraConfig;
|
|
387
|
+
/** Model-viewer / inspection tuning (#207.7); read when `rig: "inspection"`. */
|
|
388
|
+
inspection?: InspectionCameraConfig;
|
|
284
389
|
/** Camera-shake / trauma channel defaults (#28); read by every rig. */
|
|
285
390
|
shake?: CameraShakeConfig;
|
|
286
391
|
/** Scripted keyframe path (#29); when set, plays over the active rig. */
|
|
@@ -331,6 +436,47 @@ export interface WorldItemRenderConfig {
|
|
|
331
436
|
pickupRadius?: number;
|
|
332
437
|
/** Beam height above the item's ground position. Default 2.5. */
|
|
333
438
|
beamHeight?: number;
|
|
439
|
+
/** Walk-over collection: the shell grants the nearest dropped item within this radius of the local player each frame (Minecraft-style pickup). `true` uses `pickupRadius`. Omitted/false leaves pickup to `pointer.grabWorldItems` clicks. */
|
|
440
|
+
autoPickup?: boolean | {
|
|
441
|
+
radius?: number;
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Player-vs-world collision for the first-person controller. Without this the
|
|
446
|
+
* shell keeps the player on flat ground at y=0. With `voxel: true` the shell
|
|
447
|
+
* resolves the player as a box against placed scene objects (each treated as a
|
|
448
|
+
* solid unit cell), so they stand on blocks, fall into holes, and are stopped by
|
|
449
|
+
* walls — the controller a block-building/mining game needs.
|
|
450
|
+
*/
|
|
451
|
+
export interface VoxelCollisionConfig {
|
|
452
|
+
voxel: true;
|
|
453
|
+
/** Half the player box width on each horizontal axis. Default 0.3. */
|
|
454
|
+
halfWidth?: number;
|
|
455
|
+
/** Player box height from the feet. Default 1.8. */
|
|
456
|
+
height?: number;
|
|
457
|
+
/** Tallest ledge walked up without jumping. Default 0.6. */
|
|
458
|
+
stepHeight?: number;
|
|
459
|
+
}
|
|
460
|
+
/** Rig playback for a `ModelConfig`'s GLTF animation clips — looping idles, one-shots, and held poses. */
|
|
461
|
+
export interface ModelAnimationConfig {
|
|
462
|
+
/** Clip name to play; defaults to the GLB's first clip. */
|
|
463
|
+
clip?: string;
|
|
464
|
+
/** Loop the clip. Default true. */
|
|
465
|
+
loop?: boolean;
|
|
466
|
+
/** Playback rate multiplier. Default 1. */
|
|
467
|
+
timeScale?: number;
|
|
468
|
+
/** Hold the rig on a fixed frame instead of advancing it each tick. */
|
|
469
|
+
paused?: boolean;
|
|
470
|
+
/** Seek the clip to this time in seconds; combine with `paused: true` to hold a specific pose ("pose library" usage). */
|
|
471
|
+
time?: number;
|
|
472
|
+
}
|
|
473
|
+
/** Per-entity PBR material override (#151.3) applied to every `MeshStandardMaterial` in the model's cloned scene graph. */
|
|
474
|
+
export interface ModelMaterialOverride {
|
|
475
|
+
color?: string;
|
|
476
|
+
metalness?: number;
|
|
477
|
+
roughness?: number;
|
|
478
|
+
emissive?: string;
|
|
479
|
+
emissiveIntensity?: number;
|
|
334
480
|
}
|
|
335
481
|
export interface ModelConfig {
|
|
336
482
|
url: string;
|
|
@@ -340,35 +486,109 @@ export interface ModelConfig {
|
|
|
340
486
|
anchor?: "center" | "origin";
|
|
341
487
|
/** Measured footprint/center/minY; supplied automatically when the model resolves through an `@jgengine/assets` catalog. Required for `anchor: "center"` to take effect. */
|
|
342
488
|
dims?: ModelDims;
|
|
489
|
+
/** Per-entity PBR tint/finish override (#151.3); cloned onto each `MeshStandardMaterial` in the model so shared GLTF caches stay untouched. */
|
|
490
|
+
material?: ModelMaterialOverride;
|
|
491
|
+
/** Plays a GLTF animation clip on the model when the source has any (skinned or not); omit to render the rig's bind pose. */
|
|
492
|
+
animation?: ModelAnimationConfig;
|
|
493
|
+
}
|
|
494
|
+
export interface ObjectStyle {
|
|
495
|
+
color?: string;
|
|
496
|
+
opacity?: number;
|
|
497
|
+
hidden?: boolean;
|
|
498
|
+
}
|
|
499
|
+
export interface AmbientLightingConfig {
|
|
500
|
+
color?: string;
|
|
501
|
+
intensity?: number;
|
|
502
|
+
}
|
|
503
|
+
export interface DirectionalLightingConfig {
|
|
504
|
+
color?: string;
|
|
505
|
+
intensity?: number;
|
|
506
|
+
position: readonly [number, number, number];
|
|
507
|
+
castShadow?: boolean;
|
|
508
|
+
}
|
|
509
|
+
export interface HemisphereLightingConfig {
|
|
510
|
+
skyColor?: string;
|
|
511
|
+
groundColor?: string;
|
|
512
|
+
intensity?: number;
|
|
513
|
+
}
|
|
514
|
+
/** Declarative lighting replacing the shell's hardcoded ambient/directional default (#207.5); mounts regardless of world kind, only when supplied. */
|
|
515
|
+
export interface LightingConfig {
|
|
516
|
+
ambient?: AmbientLightingConfig;
|
|
517
|
+
directional?: readonly DirectionalLightingConfig[];
|
|
518
|
+
hemisphere?: HemisphereLightingConfig;
|
|
519
|
+
}
|
|
520
|
+
export interface BackdropFogConfig {
|
|
521
|
+
color?: string;
|
|
522
|
+
near?: number;
|
|
523
|
+
far?: number;
|
|
524
|
+
/** Exponential (`FogExp2`) falloff instead of linear near/far; when set, `near`/`far` are ignored. */
|
|
525
|
+
density?: number;
|
|
526
|
+
}
|
|
527
|
+
/** Generic sky/background/fog for ANY world kind, including a custom `environment` component (#207.6). */
|
|
528
|
+
export interface BackdropConfig {
|
|
529
|
+
background?: string;
|
|
530
|
+
sky?: SkyEnvironmentConfig;
|
|
531
|
+
fog?: BackdropFogConfig;
|
|
532
|
+
}
|
|
533
|
+
/** Movement-control levers for the shell-driven local player walk controller. */
|
|
534
|
+
export interface PlayerMovementConfig {
|
|
535
|
+
/** "free" (default) moves camera-relative across the plane; "axis" locks travel to one world axis; "grid" snaps each committed position to cell centers. */
|
|
536
|
+
mode?: "free" | "axis" | "grid";
|
|
537
|
+
/** World axis for mode "axis". Default "x". */
|
|
538
|
+
axis?: "x" | "z";
|
|
539
|
+
/** Cell size for mode "grid". Default 1. */
|
|
540
|
+
cellSize?: number;
|
|
541
|
+
/** Collide the walking player against placed scene objects (unit-box AABBs) even without `collision.voxel`. Default false. */
|
|
542
|
+
collideObjects?: boolean;
|
|
543
|
+
/** Intercepts each frame's resolved position before the pose commits (and before onTick): return a replacement [x,y,z] to constrain or redirect the step, or nothing to accept it. */
|
|
544
|
+
beforeCommit?: (frame: MovementCommitFrame) => readonly [number, number, number] | undefined | void;
|
|
545
|
+
}
|
|
546
|
+
/** One frame's movement resolution handed to `PlayerMovementConfig.beforeCommit`. */
|
|
547
|
+
export interface MovementCommitFrame {
|
|
548
|
+
entityId: string;
|
|
549
|
+
current: readonly [number, number, number];
|
|
550
|
+
next: readonly [number, number, number];
|
|
551
|
+
dt: number;
|
|
343
552
|
}
|
|
344
|
-
export interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never> {
|
|
553
|
+
export interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEntity = never, TRenderObject = never> {
|
|
345
554
|
game: GameDefinition;
|
|
346
555
|
content: GameContextContent;
|
|
347
556
|
loop: Required<GameLoop<GameContext>>;
|
|
348
557
|
GameUI: TUi;
|
|
558
|
+
/** Which shell mount to use. Default `"3d"` (canvas, camera rig, pointer, world rendering). `"hud"` mounts no 3D canvas, camera rig, or pointer — the game is `GameUI` plus the command/input loop, for board/card/menu games. */
|
|
559
|
+
presentation?: "3d" | "hud";
|
|
349
560
|
/** Optional canvas-layer VFX component (e.g. traveling projectiles). */
|
|
350
561
|
WorldOverlay?: TWorldOverlay;
|
|
351
|
-
/** Replaces the default demo backdrop (ground + grid + rocks) with the game's own scene — ground, sky, structures. Camera, input, HUD, entity rendering, and the loop stay shell-provided; supply your world without forking the shell. */
|
|
562
|
+
/** Replaces the default demo backdrop (ground + grid + rocks) with the game's own scene — ground, sky, structures. Camera, input, HUD, entity rendering, and the loop stay shell-provided; supply your world without forking the shell. When unset and `game.world` is an `environment()` descriptor, the shell auto-renders that world here — no manual wiring needed. */
|
|
352
563
|
environment?: TWorldOverlay;
|
|
353
564
|
/** Per-entity visual override: return your own mesh for an entity and the shell still positions it and drives selection/targeting. Return null/undefined to fall back to model → sprite → primitive. */
|
|
354
565
|
renderEntity?: TRenderEntity;
|
|
566
|
+
/** Per-object visual override: return your own mesh for a placed scene object and the shell still positions it and drives picking. Return null/undefined to fall back to objectModels → styled box. */
|
|
567
|
+
renderObject?: TRenderObject;
|
|
355
568
|
/** Billboard sprites keyed by entity kind name; unmatched entities get primitive markers. */
|
|
356
569
|
entitySprites?: Record<string, EntitySpriteConfig>;
|
|
357
570
|
/** GLB models keyed by entity kind name; a string resolves as an asset-catalog key via game.assets, a ModelConfig renders directly. Takes priority over sprites, then primitives. */
|
|
358
571
|
entityModels?: Record<string, string | ModelConfig>;
|
|
359
572
|
/** GLB models keyed by object catalog id; a string resolves via game.assets, a ModelConfig renders directly. Replaces the colored box when present. */
|
|
360
573
|
objectModels?: Record<string, string | ModelConfig>;
|
|
574
|
+
/** Styling for the default colored-box object render, keyed by catalog id: color override, opacity (< 1 sets transparent), hidden (skips the mesh but keeps the positioning group + picking). */
|
|
575
|
+
objectStyles?: Record<string, ObjectStyle>;
|
|
361
576
|
/** Optional scroll-selected hotbar index for primary ability (mouse0). */
|
|
362
577
|
hotbarSelection?: () => number;
|
|
363
578
|
/** Positioned proximity prompts for the interact key + HUD; single source shared with useActivePrompt. */
|
|
364
579
|
prompts?: (ctx: GameContext) => readonly PositionedPrompt[];
|
|
365
580
|
/** Camera tuning (perspective, orbit, first-person) for the dev game player shell. */
|
|
366
581
|
camera?: GameCameraConfig;
|
|
582
|
+
/** Cast/receive shadows across the scene (R3F Canvas shadow pass). Default true. */
|
|
583
|
+
shadows?: boolean;
|
|
367
584
|
/** Pointer-driven input: click-to-move, box-select, right-click verbs, cursor aim (#22/#30/#31). */
|
|
368
585
|
pointer?: PointerConfig;
|
|
369
|
-
/**
|
|
586
|
+
/** Touch controls on coarse-pointer devices. Unset derives a scheme from `input` (virtual joystick for movement actions, on-screen buttons for the rest); a config refines it with gestures and curated buttons; `false` opts out. */
|
|
587
|
+
touch?: TouchControlsConfig | false;
|
|
588
|
+
/** Opt in to world-space health bars floating over non-local entities that carry the stat. `roles` restricts bars to entities whose catalog entry declares one of the given roles. */
|
|
370
589
|
worldHealthBars?: boolean | {
|
|
371
590
|
statId?: string;
|
|
591
|
+
roles?: readonly CatalogEntityRole[];
|
|
372
592
|
};
|
|
373
593
|
/** Sound catalog + mix buses (music/sfx/ambient/…) the shell's Web Audio glue plays from. Catalog-first — no per-game audio wiring. */
|
|
374
594
|
audio?: {
|
|
@@ -381,4 +601,15 @@ export interface PlayableGame<TUi = unknown, TWorldOverlay = unknown, TRenderEnt
|
|
|
381
601
|
objectSounds?: Record<string, string>;
|
|
382
602
|
/** Rarity render binding + loot filter for dropped-item ground presentation (#32/#33). */
|
|
383
603
|
worldItem?: WorldItemRenderConfig;
|
|
604
|
+
/** Player-vs-world collision for the first-person controller (block/voxel worlds). Off by default (flat ground). */
|
|
605
|
+
collision?: VoxelCollisionConfig;
|
|
606
|
+
/** Movement-control levers (axis/grid constraints, object collision, pre-commit hook) for the shell-driven walk controller. */
|
|
607
|
+
movement?: PlayerMovementConfig;
|
|
608
|
+
/** Declarative ambient/directional/hemisphere lighting (#207.5); replaces the shell's hardcoded default lights when present, regardless of world kind. */
|
|
609
|
+
lighting?: LightingConfig;
|
|
610
|
+
/** Generic background/sky/fog (#207.6), applied for any world kind including a custom `environment` component. */
|
|
611
|
+
backdrop?: BackdropConfig;
|
|
612
|
+
/** F2 debug overlay (frame/sim timing, logs, backend latency, keybinds, live tunables). On for every game by default; `false` disables the toggle. */
|
|
613
|
+
devtools?: boolean;
|
|
384
614
|
}
|
|
615
|
+
export declare function worldHealthBarAllowsRole(roles: readonly CatalogEntityRole[] | undefined, role: CatalogEntityRole | undefined): boolean;
|
package/dist/game/progression.js
CHANGED
|
@@ -60,8 +60,13 @@ export function leveling(config) {
|
|
|
60
60
|
const startLevel = config.startLevel ?? 1;
|
|
61
61
|
const xpStat = config.xpStat ?? "xp";
|
|
62
62
|
const levelStat = config.levelStat ?? "level";
|
|
63
|
-
const
|
|
64
|
-
const
|
|
63
|
+
const thresholdMode = config.thresholdMode ?? "perLevel";
|
|
64
|
+
const xpForLevel = (level) => {
|
|
65
|
+
if (thresholdMode === "cumulative" && level <= startLevel)
|
|
66
|
+
return 0;
|
|
67
|
+
return evalCurve(config.xpForLevel, level);
|
|
68
|
+
};
|
|
69
|
+
const resolvePerLevel = (level, xp) => {
|
|
65
70
|
let currentLevel = level;
|
|
66
71
|
let currentXp = xp;
|
|
67
72
|
let levelsGained = 0;
|
|
@@ -79,6 +84,22 @@ export function leveling(config) {
|
|
|
79
84
|
levelsGained,
|
|
80
85
|
};
|
|
81
86
|
};
|
|
87
|
+
const resolveCumulative = (level, xp) => {
|
|
88
|
+
let currentLevel = level;
|
|
89
|
+
let levelsGained = 0;
|
|
90
|
+
while (currentLevel < maxLevel && xp >= xpForLevel(currentLevel + 1)) {
|
|
91
|
+
currentLevel += 1;
|
|
92
|
+
levelsGained += 1;
|
|
93
|
+
}
|
|
94
|
+
const capped = currentLevel >= maxLevel;
|
|
95
|
+
return {
|
|
96
|
+
level: currentLevel,
|
|
97
|
+
xp: capped ? xpForLevel(maxLevel) : xp,
|
|
98
|
+
xpMax: capped ? xpForLevel(maxLevel) : xpForLevel(currentLevel + 1),
|
|
99
|
+
levelsGained,
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
const resolve = (level, xp) => thresholdMode === "cumulative" ? resolveCumulative(level, xp) : resolvePerLevel(level, xp);
|
|
82
103
|
const grantXp = (access, userId, amount, onLevelUp) => {
|
|
83
104
|
const xp = access.get(userId, xpStat);
|
|
84
105
|
const level = access.get(userId, levelStat);
|
package/dist/game/race.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ export interface RaceStateConfig {
|
|
|
69
69
|
* volumes. It emits `checkpoint.hit` / `lap.completed` / `position.changed` / `race.finished`, keeps
|
|
70
70
|
* cumulative split times for PB deltas, resolves a pluggable win condition (first-past-post, round-cut,
|
|
71
71
|
* derby last-standing), and `resetToCheckpoint` hands back a respawn pose at the racer's last checkpoint.
|
|
72
|
+
* `removeRacer` drops a racer mid-race and `reset` returns the whole instance to its pre-race state for reuse.
|
|
72
73
|
*/
|
|
73
74
|
export declare class RaceState {
|
|
74
75
|
private readonly track;
|
|
@@ -79,6 +80,10 @@ export declare class RaceState {
|
|
|
79
80
|
private finalRanking;
|
|
80
81
|
constructor(config: RaceStateConfig);
|
|
81
82
|
addRacer(racerId: string, startTime?: number): void;
|
|
83
|
+
/** Removes a racer's progress/standing and renumbers the remaining field's positions; a no-op for an unknown id. */
|
|
84
|
+
removeRacer(racerId: string): void;
|
|
85
|
+
/** Clears all racer progress and finish state back to construction time; `track` and `win` are untouched, so the same instance can run another race. */
|
|
86
|
+
reset(): void;
|
|
82
87
|
eliminate(racerId: string): void;
|
|
83
88
|
get finished(): boolean;
|
|
84
89
|
get ranking(): readonly string[];
|
package/dist/game/race.js
CHANGED
|
@@ -50,6 +50,7 @@ function distanceToNext(point, cp) {
|
|
|
50
50
|
* volumes. It emits `checkpoint.hit` / `lap.completed` / `position.changed` / `race.finished`, keeps
|
|
51
51
|
* cumulative split times for PB deltas, resolves a pluggable win condition (first-past-post, round-cut,
|
|
52
52
|
* derby last-standing), and `resetToCheckpoint` hands back a respawn pose at the racer's last checkpoint.
|
|
53
|
+
* `removeRacer` drops a racer mid-race and `reset` returns the whole instance to its pre-race state for reuse.
|
|
53
54
|
*/
|
|
54
55
|
export class RaceState {
|
|
55
56
|
track;
|
|
@@ -80,6 +81,25 @@ export class RaceState {
|
|
|
80
81
|
});
|
|
81
82
|
this.order.push(racerId);
|
|
82
83
|
}
|
|
84
|
+
/** Removes a racer's progress/standing and renumbers the remaining field's positions; a no-op for an unknown id. */
|
|
85
|
+
removeRacer(racerId) {
|
|
86
|
+
if (!this.racers.delete(racerId))
|
|
87
|
+
return;
|
|
88
|
+
const idx = this.order.indexOf(racerId);
|
|
89
|
+
if (idx >= 0)
|
|
90
|
+
this.order.splice(idx, 1);
|
|
91
|
+
const remaining = this.order.map((id) => this.racers.get(id)).sort((a, b) => this.compare(a, b, null));
|
|
92
|
+
remaining.forEach((r, i) => {
|
|
93
|
+
r.position = i + 1;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/** Clears all racer progress and finish state back to construction time; `track` and `win` are untouched, so the same instance can run another race. */
|
|
97
|
+
reset() {
|
|
98
|
+
this.racers.clear();
|
|
99
|
+
this.order.length = 0;
|
|
100
|
+
this.raceFinished = false;
|
|
101
|
+
this.finalRanking = [];
|
|
102
|
+
}
|
|
83
103
|
eliminate(racerId) {
|
|
84
104
|
const r = this.racers.get(racerId);
|
|
85
105
|
if (r !== undefined)
|
package/dist/game/social.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface SocialDeps {
|
|
|
23
23
|
presence?: (userId: string) => PresenceInfo;
|
|
24
24
|
now?: () => number;
|
|
25
25
|
emotes?: EmotesDeps;
|
|
26
|
+
worldInviteTtlMs?: number;
|
|
26
27
|
}
|
|
27
28
|
export interface FriendEntry {
|
|
28
29
|
userId: string;
|
|
@@ -32,6 +33,10 @@ export interface FriendsSnapshot {
|
|
|
32
33
|
friends: string[];
|
|
33
34
|
blocked: string[];
|
|
34
35
|
}
|
|
36
|
+
export interface FriendRequestEntry {
|
|
37
|
+
requestId: string;
|
|
38
|
+
fromUserId: string;
|
|
39
|
+
}
|
|
35
40
|
export interface Friends {
|
|
36
41
|
canRequest(fromUserId: string, toUserId: string): {
|
|
37
42
|
reason: string;
|
|
@@ -44,9 +49,11 @@ export interface Friends {
|
|
|
44
49
|
accept(userId: string, requestId: string): {
|
|
45
50
|
reason: string;
|
|
46
51
|
} | null;
|
|
52
|
+
decline(userId: string, requestId: string): void;
|
|
47
53
|
remove(userId: string, friendUserId: string): void;
|
|
48
54
|
block(userId: string, targetUserId: string): void;
|
|
49
55
|
list(userId: string): FriendEntry[];
|
|
56
|
+
requestsFor(userId: string): FriendRequestEntry[];
|
|
50
57
|
snapshot(userId: string): FriendsSnapshot;
|
|
51
58
|
hydrate(userId: string, data: FriendsSnapshot): void;
|
|
52
59
|
}
|
|
@@ -59,6 +66,11 @@ export interface PartyConfig {
|
|
|
59
66
|
maxMembers: number;
|
|
60
67
|
inviteTtlMs?: number;
|
|
61
68
|
}
|
|
69
|
+
export interface PartyInviteEntry {
|
|
70
|
+
inviteId: string;
|
|
71
|
+
fromUserId: string;
|
|
72
|
+
createdAt: number;
|
|
73
|
+
}
|
|
62
74
|
export interface Party {
|
|
63
75
|
register(config: PartyConfig): void;
|
|
64
76
|
canInvite(fromUserId: string, toUserId: string): {
|
|
@@ -72,6 +84,7 @@ export interface Party {
|
|
|
72
84
|
accept(userId: string, inviteId: string): {
|
|
73
85
|
reason: string;
|
|
74
86
|
} | null;
|
|
87
|
+
decline(userId: string, inviteId: string): void;
|
|
75
88
|
kick(leaderUserId: string, memberUserId: string): {
|
|
76
89
|
reason: string;
|
|
77
90
|
} | null;
|
|
@@ -81,6 +94,7 @@ export interface Party {
|
|
|
81
94
|
} | null;
|
|
82
95
|
list(userId: string): PartyMemberEntry[];
|
|
83
96
|
membersOf(userId: string): string[];
|
|
97
|
+
invitesFor(userId: string): PartyInviteEntry[];
|
|
84
98
|
}
|
|
85
99
|
export declare const DEFAULT_EMOTE_RADIUS = 20;
|
|
86
100
|
export interface EmoteBroadcastResult {
|
|
@@ -94,6 +108,33 @@ export interface Emotes {
|
|
|
94
108
|
reason: string;
|
|
95
109
|
};
|
|
96
110
|
}
|
|
111
|
+
export interface WorldInviteTarget {
|
|
112
|
+
serverId: string;
|
|
113
|
+
joinCode?: string;
|
|
114
|
+
}
|
|
115
|
+
export interface WorldInvite extends WorldInviteTarget {
|
|
116
|
+
id: string;
|
|
117
|
+
fromUserId: string;
|
|
118
|
+
toUserId: string;
|
|
119
|
+
createdAt: number;
|
|
120
|
+
}
|
|
121
|
+
export interface WorldInvites {
|
|
122
|
+
canInvite(fromUserId: string, toUserId: string): {
|
|
123
|
+
reason: string;
|
|
124
|
+
} | null;
|
|
125
|
+
invite(fromUserId: string, toUserId: string, target: WorldInviteTarget): {
|
|
126
|
+
inviteId: string;
|
|
127
|
+
} | {
|
|
128
|
+
reason: string;
|
|
129
|
+
};
|
|
130
|
+
accept(userId: string, inviteId: string): {
|
|
131
|
+
target: WorldInviteTarget;
|
|
132
|
+
} | {
|
|
133
|
+
reason: string;
|
|
134
|
+
};
|
|
135
|
+
decline(userId: string, inviteId: string): void;
|
|
136
|
+
listFor(userId: string): WorldInvite[];
|
|
137
|
+
}
|
|
97
138
|
export interface Social {
|
|
98
139
|
friends: Friends;
|
|
99
140
|
party: Party;
|
|
@@ -101,5 +142,6 @@ export interface Social {
|
|
|
101
142
|
get(userId: string): PresenceInfo;
|
|
102
143
|
};
|
|
103
144
|
emotes: Emotes;
|
|
145
|
+
worldInvites: WorldInvites;
|
|
104
146
|
}
|
|
105
147
|
export declare function createSocial(deps: SocialDeps): Social;
|