@jgengine/shell 0.22.0 → 0.24.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 +110 -0
- package/dist/GamePlayerShell.js +18 -3
- package/dist/GameUiPreview.js +2 -1
- package/dist/Shell3dPresentation.js +13 -8
- package/dist/ShellChrome.d.ts +1 -1
- package/dist/ShellChrome.js +4 -2
- package/dist/ShellHudPresentation.js +2 -1
- package/dist/ShellNotices.d.ts +26 -0
- package/dist/ShellNotices.js +51 -0
- package/dist/audio/AudioComponents.d.ts +3 -1
- package/dist/audio/AudioComponents.js +5 -2
- package/dist/audio/listenerAnchor.d.ts +15 -0
- package/dist/audio/listenerAnchor.js +17 -0
- package/dist/audio/playableAudio.d.ts +9 -0
- package/dist/audio/playableAudio.js +11 -0
- package/dist/commandSink.d.ts +1 -1
- package/dist/commandSink.js +8 -3
- package/dist/defineGame.js +3 -1
- package/dist/devtools/DevtoolsOverlay.js +1 -0
- package/dist/devtools/agentBridge.d.ts +21 -0
- package/dist/devtools/agentBridge.js +95 -3
- package/dist/devtools/devtoolsReports.d.ts +32 -0
- package/dist/devtools/devtoolsReports.js +26 -0
- package/dist/devtools/simStepper.d.ts +21 -0
- package/dist/devtools/simStepper.js +37 -0
- package/dist/drivers/FrameDriver.js +26 -14
- package/dist/drivers/HudOnlyDriver.js +16 -5
- package/dist/environment/EnvironmentScene.js +19 -7
- package/dist/environment/RoadJunctions.d.ts +3 -1
- package/dist/environment/RoadJunctions.js +9 -2
- package/dist/environment/RoadRibbons.d.ts +3 -1
- package/dist/environment/RoadRibbons.js +16 -3
- package/dist/environment/terrainGroundColor.js +3 -3
- package/dist/materialOverride.js +4 -2
- package/dist/playSurfaceFocus.d.ts +16 -0
- package/dist/playSurfaceFocus.js +42 -0
- package/dist/postfx/PostProcessing.d.ts +3 -1
- package/dist/postfx/PostProcessing.js +14 -6
- package/dist/registry.d.ts +5 -1
- package/dist/render/CascadedShadows.d.ts +2 -0
- package/dist/render/CascadedShadows.js +4 -0
- package/dist/render/EntityPreview.js +1 -1
- package/dist/render/EnvironmentLighting.d.ts +26 -7
- package/dist/render/EnvironmentLighting.js +40 -27
- package/dist/render/SceneLighting.js +2 -2
- package/dist/render/modelLoad.d.ts +7 -0
- package/dist/render/modelLoad.js +13 -0
- package/dist/render/modelRender.d.ts +1 -0
- package/dist/render/modelRender.js +3 -0
- package/dist/render/modelSurface.d.ts +39 -0
- package/dist/render/modelSurface.js +206 -0
- package/dist/render/useModelInstance.d.ts +1 -1
- package/dist/render/useModelInstance.js +2 -2
- package/dist/scatter/scatterModels.js +3 -1
- package/dist/scene/AuthoredScene.d.ts +11 -3
- package/dist/scene/AuthoredScene.js +17 -9
- package/dist/scene/CityRenderer.js +142 -25
- package/dist/scene/cityJunctionSurface.d.ts +7 -0
- package/dist/scene/cityJunctionSurface.js +34 -0
- package/dist/settings/settingsController.js +1 -1
- package/dist/terrain/groundEdgeFade.d.ts +67 -0
- package/dist/terrain/groundEdgeFade.js +234 -0
- package/dist/terrain/index.d.ts +5 -0
- package/dist/terrain/index.js +5 -0
- package/dist/terrain/surfaceRibbonMaterial.d.ts +62 -0
- package/dist/terrain/surfaceRibbonMaterial.js +227 -0
- package/dist/terrain/terrainDetailMaterial.d.ts +33 -10
- package/dist/terrain/terrainDetailMaterial.js +149 -63
- package/dist/terrain/terrainPaintColor.d.ts +12 -3
- package/dist/terrain/terrainPaintColor.js +46 -1
- package/dist/terrain/terrainQuality.d.ts +5 -0
- package/dist/terrain/terrainQuality.js +7 -0
- package/dist/terrain/terrainSurfaceShader.d.ts +16 -0
- package/dist/terrain/terrainSurfaceShader.js +266 -0
- package/dist/terrain/terrainSurfaces.d.ts +59 -0
- package/dist/terrain/terrainSurfaces.js +199 -0
- package/dist/world/StaticObjectModels.d.ts +1 -1
- package/dist/world/StaticObjectModels.js +1 -1
- package/dist/world/WorldScene.js +1 -1
- package/dist/world/staticObjectBatches.d.ts +5 -1
- package/dist/world/staticObjectBatches.js +9 -5
- package/dist/world/worldBarSamples.d.ts +13 -1
- package/dist/world/worldBarSamples.js +40 -8
- package/package.json +5 -5
- package/skills/jgengine/api.md +18 -18
- package/skills/jgengine-ui/SKILL.md +4 -0
- package/skills/jgengine-ui/api.md +254 -37
- package/skills/jgengine-ui/capabilities.md +58 -0
- package/skills/jgengine-ui/reference-primitives.md +4 -4
- package/skills/jgengine-world/api.md +27 -14
- package/skills/jgengine-world/capabilities.md +4 -0
- package/skills/jgengine-world/reference.md +27 -8
|
@@ -69,6 +69,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
69
69
|
|
|
70
70
|
- `useAutoScroll` (function) · `import { useAutoScroll } from "@jgengine/react"`
|
|
71
71
|
|
|
72
|
+
## balance-ibl-lighting — trim flat ambient under IBL and add a key light to directionless lighting
|
|
73
|
+
|
|
74
|
+
- `balanceLightingForIbl` (function) · `import { balanceLightingForIbl } from "@jgengine/core/render/lightingBalance"`
|
|
75
|
+
|
|
72
76
|
## bounded-spatial-audio — play positional or flat cues with listener orientation, voice budgets, and per-source cleanup
|
|
73
77
|
|
|
74
78
|
- `createAudioEngine` (function) · `import { createAudioEngine } from "@jgengine/shell/audio/audioEngine"`
|
|
@@ -210,6 +214,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
210
214
|
|
|
211
215
|
- `useDragLayer` (function) · `import { useDragLayer } from "@jgengine/react"`
|
|
212
216
|
|
|
217
|
+
## engine-styles — inject the engine stylesheet (jg-* keyframes, interaction states, reduced motion) once
|
|
218
|
+
|
|
219
|
+
- `useEngineStyles` (function) · `import { useEngineStyles } from "@jgengine/react/engineStyles"`
|
|
220
|
+
|
|
213
221
|
## entity-frames — overlay that renders caller-composed frames over on-screen entities
|
|
214
222
|
|
|
215
223
|
- `EntityFrames` (function) · `import { EntityFrames } from "@jgengine/react"`
|
|
@@ -258,6 +266,12 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
258
266
|
|
|
259
267
|
- `GameContextBridge` (function) · `import { GameContextBridge } from "@jgengine/react"`
|
|
260
268
|
|
|
269
|
+
## ground-edge-fade — fade merged ground layers into the terrain at their outer edge, keeping inner seams crisp
|
|
270
|
+
|
|
271
|
+
- `applyGroundEdgeFade` (function) · `import { applyGroundEdgeFade } from "@jgengine/shell/terrain"`
|
|
272
|
+
- `buildGroundCoverageMask` (function) · `import { buildGroundCoverageMask } from "@jgengine/shell/terrain"`
|
|
273
|
+
- `createGroundEdgeFade` (function) · `import { createGroundEdgeFade } from "@jgengine/shell/terrain"`
|
|
274
|
+
|
|
261
275
|
## heavy-models — models over the per-model triangle budget, for perf probes and smoke assertions
|
|
262
276
|
|
|
263
277
|
- `heavyModels` (function) · `import { heavyModels } from "@jgengine/shell/render/modelLoad"`
|
|
@@ -266,6 +280,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
266
280
|
|
|
267
281
|
- `displaceHeightfieldGeometry` (function) · `import { displaceHeightfieldGeometry } from "@jgengine/shell/terrain"`
|
|
268
282
|
|
|
283
|
+
## hud-button — themed button with hover lift, press scale, focus ring, disabled state, and an interaction cue seam
|
|
284
|
+
|
|
285
|
+
- `HudButton` (const) · `import { HudButton } from "@jgengine/react/hudButton"`
|
|
286
|
+
|
|
269
287
|
## hud-canvas — the HUD root surface — design-resolution scaling plus live panel-placement editing (F2+C)
|
|
270
288
|
|
|
271
289
|
- `HudCanvas` (function) · `import { HudCanvas } from "@jgengine/react"`
|
|
@@ -290,6 +308,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
290
308
|
|
|
291
309
|
- `IconSchool` (type) · `import { IconSchool } from "@jgengine/react"`
|
|
292
310
|
|
|
311
|
+
## hud-interact — one listener for hover/press/activate/open/close from every engine HUD primitive
|
|
312
|
+
|
|
313
|
+
- `HudInteractProvider` (function) · `import { HudInteractProvider } from "@jgengine/react/hudInteract"`
|
|
314
|
+
|
|
293
315
|
## hud-layout — persistent, live-editable HUD panel layout state for `HudCanvas`
|
|
294
316
|
|
|
295
317
|
- `useHudLayout` (function) · `import { useHudLayout } from "@jgengine/react"`
|
|
@@ -326,10 +348,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
326
348
|
|
|
327
349
|
- `deriveHudTheme` (function) · `import { deriveHudTheme } from "@jgengine/react"`
|
|
328
350
|
|
|
351
|
+
## hud-theme-root — apply the default (or a game) HudTheme and the engine stylesheet at the HUD root
|
|
352
|
+
|
|
353
|
+
- `HudThemeRoot` (function) · `import { HudThemeRoot } from "@jgengine/react/hudThemeRoot"`
|
|
354
|
+
|
|
329
355
|
## hud-ticker — re-render a HUD element at a steady hz for time-derived readouts (cooldowns, cast/swing bars) — no hand-rolled setInterval effects
|
|
330
356
|
|
|
331
357
|
- `useTicker` (function) · `import { useTicker } from "@jgengine/react"`
|
|
332
358
|
|
|
359
|
+
## hud-tokens — inline-style accessors for the HudTheme type scale, spacing, motion, elevation, and focus ring
|
|
360
|
+
|
|
361
|
+
- `HudTypeStep` (type) · `import { HudTypeStep } from "@jgengine/react/hudTokens"`
|
|
362
|
+
|
|
333
363
|
## hud-vitals — atomic purpose-named vitals bars (token-themed parts, not a finished HUD)
|
|
334
364
|
|
|
335
365
|
- `BarTokens` (interface) · `import { BarTokens } from "@jgengine/react"`
|
|
@@ -414,6 +444,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
414
444
|
|
|
415
445
|
- `menuStackReducer` (function) · `import { menuStackReducer } from "@jgengine/react/menuRouter"`
|
|
416
446
|
|
|
447
|
+
## merge-post-processing — layer a partial post chain over a look preset without losing its stages
|
|
448
|
+
|
|
449
|
+
- `mergePostProcessing` (function) · `import { mergePostProcessing } from "@jgengine/core/render/lookPreset"`
|
|
450
|
+
|
|
417
451
|
## minimap — framed circular minimap with terrain bake, fog, markers, and facing arrow
|
|
418
452
|
|
|
419
453
|
- `Minimap` (function) · `import { Minimap } from "@jgengine/react"`
|
|
@@ -456,6 +490,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
456
490
|
|
|
457
491
|
- `modelLoadIdleMs` (function) · `import { modelLoadIdleMs } from "@jgengine/shell/render/modelLoad"`
|
|
458
492
|
|
|
493
|
+
## model-load-starts — count of model streaming bursts, for capture quiescence checks
|
|
494
|
+
|
|
495
|
+
- `modelLoadStarts` (function) · `import { modelLoadStarts } from "@jgengine/shell/render/modelLoad"`
|
|
496
|
+
|
|
459
497
|
## multiplayer-p2p — bootstrap a playable authoritative world for browser peer co-op
|
|
460
498
|
|
|
461
499
|
- `resolvePeerShellMultiplayer` (function) · `import { resolvePeerShellMultiplayer } from "@jgengine/shell/multiplayer"`
|
|
@@ -464,6 +502,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
464
502
|
|
|
465
503
|
- `WorldNameplates` (function) · `import { WorldNameplates } from "@jgengine/shell/world/WorldHud"`
|
|
466
504
|
|
|
505
|
+
## notice-feed — render ctx.game.notices as an animated toned stack (enter/exit motion, ×N stacking)
|
|
506
|
+
|
|
507
|
+
- `NoticeStack` (function) · `import { NoticeStack } from "@jgengine/react/notices"`
|
|
508
|
+
|
|
467
509
|
## notification-bell — icon button with a live unread-count badge over a notification store
|
|
468
510
|
|
|
469
511
|
- `NotificationBell` (function) · `import { NotificationBell } from "@jgengine/react"`
|
|
@@ -553,6 +595,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
553
595
|
|
|
554
596
|
- `Popover` (function) · `import { Popover } from "@jgengine/react"`
|
|
555
597
|
|
|
598
|
+
## presence — keep a closing element mounted through its exit transition
|
|
599
|
+
|
|
600
|
+
- `usePresence` (function) · `import { usePresence } from "@jgengine/react/presence"`
|
|
601
|
+
|
|
556
602
|
## projected-overdraw — sample actual mesh/camera fragment overlap with native coverage and explicit depth/blending/transmission limits
|
|
557
603
|
|
|
558
604
|
- `measureProjectedOverdraw` (function) · `import { measureProjectedOverdraw } from "@jgengine/shell/render/projectedOverdraw"`
|
|
@@ -698,6 +744,18 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
698
744
|
|
|
699
745
|
- `TransformGizmo` (const) · `import { TransformGizmo } from "@jgengine/shell/structures"`
|
|
700
746
|
|
|
747
|
+
## tween-number — rolling number readout with an up/down delta flash
|
|
748
|
+
|
|
749
|
+
- `TweenNumber` (function) · `import { TweenNumber } from "@jgengine/react/tweenNumber"`
|
|
750
|
+
|
|
751
|
+
## tweened-value — animate a displayed number toward its target, honouring reduced motion
|
|
752
|
+
|
|
753
|
+
- `useTweenedValue` (function) · `import { useTweenedValue } from "@jgengine/react/tweenNumber"`
|
|
754
|
+
|
|
755
|
+
## ui-sound-cues — play click/hover/open/close/confirm/deny/notify UI sounds from any component
|
|
756
|
+
|
|
757
|
+
- `useUiCue` (function) · `import { useUiCue } from "@jgengine/react/uiCues"`
|
|
758
|
+
|
|
701
759
|
## use-camera-shake — React hook binding a camera-shake controller — subscribes for live trauma/kind and can self-drive its decay on a frame loop
|
|
702
760
|
|
|
703
761
|
- `useCameraShake` (function) · `import { useCameraShake } from "@jgengine/react"`
|
|
@@ -70,7 +70,7 @@ instead of mirroring external entities into `createMarkerSet`.
|
|
|
70
70
|
|
|
71
71
|
**Toggleable game windows** are already shipped, not hand-rolled open/close state: `usePanels(defs)` + `<PanelHost>` + `<Window>` (`@jgengine/react`) over the headless `@jgengine/core/ui/panelModel` are THE way to build openable windows — bag (`B`), character (`C`), spellbook, quest log — with keybind toggles, drag-to-move, close buttons, ESC-to-close, and z-stack ordering all handled. Declare each window in `defs` (id, keybind, title), mount one `<PanelHost>`, and render each panel's body inside a `<Window>`; the game owns the body content and skin, the model owns focus/stacking/keybind wiring. Never re-derive window toggling from local `useState` booleans and hand-rolled keydown listeners.
|
|
72
72
|
|
|
73
|
-
Window title-bar movement belongs to one primary pointer. Release, cancellation, capture loss, blur, and window unmount retire that gesture's listeners; another pointer cannot move it. Controlled positions and panel z-order remain caller-owned.
|
|
73
|
+
Window title-bar movement belongs to one primary pointer. Release, cancellation, capture loss, blur, and window unmount retire that gesture's listeners; another pointer cannot move it. Controlled positions and panel z-order remain caller-owned. Windows without a `variation` render on `HudPanel` (theme frame plus modal elevation) and rise in on open; `PanelHost` keeps a closed window mounted for its short exit transition, and closing retires any drag in progress. `ModalHost` fades its backdrop and lifts the dialog in, and plays the same exit when the stack empties; `ConfirmDialog` and `PauseMenu` are built from `HudPanel` and `HudButton`.
|
|
74
74
|
|
|
75
75
|
**Character sheet / paperdoll** is already shipped, not hand-rolled: `<CharacterSheet>` / `<Paperdoll>` / `<StatList>` (`@jgengine/react`) compose the paperdoll equip layout (worn `EquipmentSlots` arranged around a portrait) and the derived-stat readout into one window body. `Paperdoll` is the equip-slot arrangement, `StatList` the derived-stat rows, `CharacterSheet` the batteries-included default that pairs them — the game composes and reskins them (slot layout, stat labels/terminology, skin) rather than re-deriving a paperdoll from raw divs and manual stat math.
|
|
76
76
|
|
|
@@ -80,21 +80,21 @@ Do not create a primitive whose only value is wrapping a `div` with border radiu
|
|
|
80
80
|
|
|
81
81
|
## Rendering — post-processing, lighting, shadows
|
|
82
82
|
|
|
83
|
-
**Look presets.** Unset `look` is `"neutral"` (#1719): the game's own `lighting`/`backdrop`/`postProcessing` with an AgX tone-map and no styling. One field picks a whole art direction: `"photoreal"` (high-contrast PBR post), `"cinematic"` (day sky, view-following shadow-casting sun, tone-map/bloom/SSAO/vignette), `"toon"` (clean graphic grade), `"comic"` (ink outlines + cel bands + saturated grade — Borderlands-style), `"retro"` (pixelated, posterized, no smoothing), and `"flat"` (bare ambient+directional rig, no post). Non-neutral presets add a day sky unless the world declares one. The preset only fills knobs you didn't set — any explicit `lighting`/`backdrop
|
|
83
|
+
**Look presets.** Unset `look` is `"neutral"` (#1719): the game's own `lighting`/`backdrop`/`postProcessing` with an AgX tone-map and no styling. One field picks a whole art direction: `"photoreal"` (high-contrast PBR post), `"cinematic"` (day sky, view-following shadow-casting sun, tone-map/bloom/SSAO/vignette), `"toon"` (clean graphic grade), `"comic"` (ink outlines + cel bands + saturated grade — Borderlands-style), `"retro"` (pixelated, posterized, no smoothing), and `"flat"` (bare ambient+directional rig, no post). Non-neutral presets add a day sky unless the world declares one. The preset only fills knobs you didn't set — any explicit `lighting`/`backdrop` wins, and a styled preset's post stages deep-merge under a partial `postProcessing` (`mergePostProcessing`): fields you set, including `false`, win; stages you omit come from the preset. Under `"neutral"` your chain is used as authored. `resolveGameLook` (`@jgengine/core/render/lookPreset`) is the pure resolver; assert on it in a `bun test` (the post/sky layers are not visible to `summarizeEnvironment`). HUD-presentation and no-camera games are unaffected.
|
|
84
84
|
|
|
85
85
|
The post chain itself is never hand-wired render passes. Set `defineGame({ postProcessing })` (`PostProcessingConfig` from `@jgengine/core/render/postProcessing`) and the shell mounts an `EffectComposer` and owns the render: RenderPass → AO → Bloom → tone-map output → Stylize → Grade. Each stage is a config object, `false` to skip, or omitted for its tuned default:
|
|
86
86
|
|
|
87
87
|
- `toneMapping: "aces" | "agx" | "reinhard" | "cineon" | "linear" | "none"` (default `aces`) + `exposure`.
|
|
88
88
|
- `bloom: { strength, radius, threshold }` — HDR glow around bright pixels (defaults 0.32 / 0.55 / 0.85).
|
|
89
89
|
- `grade: { lift, gain, gamma, saturation, vignette, grain }` — display-space colour grade: cool-shadow/warm-highlight split, vignette, animated film grain.
|
|
90
|
-
- `ao: { radius, intensity, distanceFalloff, blend }` — ground-truth ambient occlusion
|
|
90
|
+
- `ao: { radius, intensity, distanceFalloff, blend }` — ground-truth ambient occlusion. Omitted runs `DEFAULT_AO` on tiers whose `postStages.ao` is on (medium and up; low skips it); `ao: false` turns it off everywhere. It adds a normal/depth prepass (one extra draw per opaque mesh) and is fill-heavy: 8 samples on medium, 12 on high, 16 on ultra.
|
|
91
91
|
- `stylize: { outline, bands, pixelSize }` — art style without touching materials. `outline: { color, thickness, opacity, depthThreshold, normalThreshold, fadeDistance }` traces ink lines from depth and normal edges (one extra normal/depth scene render, shadow maps reused); `bands` quantizes brightness into cel bands keeping hue; `pixelSize` snaps the frame to retro blocks. Mix freely: outline alone is a clean comic ink, `bands: 3` plus outline is cartoon, `pixelSize` plus `bands` is retro. Mark custom overlay effects with `POSTFX_OVERLAY_USERDATA` so they are not outlined; transparent, alpha-cut, points, lines and sprites are skipped automatically.
|
|
92
92
|
|
|
93
93
|
AO and depth-of-field prepasses reuse the beauty pass's shadow maps; they do not redraw shadow casters. Prepass failure restores shadow update policy and marked overlay visibility. The composer resizes passes through `setSize`, and graph cleanup calls each pass's `dispose` once; avoid reading a pass's internal targets or materials.
|
|
94
94
|
|
|
95
95
|
**Orbit camera occlusion:** the third-person orbit rig takes `camera: { collision: { enabled, padding?, minTargetDistance? } }` — a spring-arm that raycasts target→camera each frame and pulls the boom in past walls/terrain so the camera never clips inside geometry. Off by default (unchanged chase feel); enable it for any world with interiors or dense structures.
|
|
96
96
|
|
|
97
|
-
Lighting is `defineGame({ lighting })` (`LightingConfig`): ambient / hemisphere / directional, replacing the shell's default lights when set. A `DirectionalLightingConfig` with `castShadow` takes `shadowMapSize`, `shadowCameraSize`, `shadowBias`, `shadowNormalBias`
|
|
97
|
+
Lighting is `defineGame({ lighting })` (`LightingConfig`): ambient / hemisphere / directional, replacing the shell's default lights when set. A `DirectionalLightingConfig` with `castShadow` takes `shadowMapSize`, `shadowCameraSize`, `shadowBias`, `shadowNormalBias` and `shadowRadius` (PCF penumbra in texels, default 1.25; the shell uses `PCFShadowMap` — in three r182 `PCFSoftShadowMap` silently compiles as unfiltered basic shadows). Every look but `"flat"` adds image-based light from a procedural sky probe (sky/horizon/ground from `hemisphere`, an HDR sun lobe from the first directional light, horizon leaning toward the ambient colour, intensity 0.45); `environmentSource` swaps in an HDRI or cube map. Under that IBL, `ambient` intensity is scaled by `iblAmbientScale` (default 0.5; set 1 to keep it), and lighting with no `directional` entry gets a soft shadowless key tinted by the ambient colour unless `fallbackKey: false` (`balanceLightingForIbl` in `@jgengine/core/render/lightingBalance`). Sky-lit worlds (a `sky()` world feature) get a high-res sun whose shadow camera follows the view each frame, so grounded shadows stay sharp under the player anywhere in a large world.
|
|
98
98
|
|
|
99
99
|
## First-person viewmodel, WorldOverlay props, render cues (#542)
|
|
100
100
|
|
|
@@ -303,11 +303,11 @@
|
|
|
303
303
|
|
|
304
304
|
## @jgengine/core/audio/audioFalloff
|
|
305
305
|
|
|
306
|
-
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented
|
|
306
|
+
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented · used by `withUiCueSounds` (@jgengine/core/audio/uiCues): Merge the default UI cue patches into a game's sound catalog.
|
|
307
307
|
- `AudioBusId` (type): type AudioBusId = string — ⚠ undocumented
|
|
308
308
|
- `AudioFalloffConfig` (interface): interface AudioFalloffConfig { minDistance?: number; maxDistance?: number; curve?: FalloffCurve } — ⚠ undocumented
|
|
309
309
|
- `FalloffCurve` (type): type FalloffCurve = "linear" | "inverse" | "none" — ⚠ undocumented
|
|
310
|
-
- `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
|
|
310
|
+
- `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_UI_CUE_SOUNDS` (@jgengine/core/audio/uiCues): Short, soft procedural patches: no samples to load, quiet enough to sit under game audio.
|
|
311
311
|
- `computeFalloffGain` (function): function computeFalloffGain(distance: number, config: AudioFalloffConfig = {}): number — ⚠ undocumented
|
|
312
312
|
- `distance3` (function): function distance3(a: { x: number; y: number; z: number }, b: { x: number; y: number; z: number }): number — ⚠ undocumented
|
|
313
313
|
- `resolveEmitterGain` (function): function resolveEmitterGain(distance: number, sound: Pick<SoundDef, "gain" | "positional" | "falloff">, busGain: number): number — ⚠ undocumented
|
|
@@ -368,6 +368,17 @@
|
|
|
368
368
|
- `ToneVoice` (interface): interface ToneVoice — A pitched oscillator voice: a 12ms linear attack to `gain`, then an exponential decay to silence across `duration`, with an optional exponential pitch slide from `freq` to `slideTo`.
|
|
369
369
|
- `patchDuration` (function): function patchDuration(patch: SynthPatch): number — Total wall-clock length of a patch in seconds — the latest voice end across all voices.
|
|
370
370
|
|
|
371
|
+
## @jgengine/core/audio/uiCues
|
|
372
|
+
|
|
373
|
+
- `DEFAULT_UI_CUE_SOUNDS` (const): const DEFAULT_UI_CUE_SOUNDS: Readonly<Record<UiCue, SoundDef>> — Short, soft procedural patches: no samples to load, quiet enough to sit under game audio.
|
|
374
|
+
- `NOTICE_TONE_CUES` (const): const NOTICE_TONE_CUES: Readonly<Record<NoticeTone, UiCue>> — The cue a notice of each tone plays when it appears.
|
|
375
|
+
- `UI_CUES` (const): const UI_CUES: readonly UiCue[] — Every {@link UiCue}, in a stable order.
|
|
376
|
+
- `UI_CUE_BUS` (const): const UI_CUE_BUS: "ui" — Bus the default UI cues mix through; the settings menu shows its volume.
|
|
377
|
+
- `UiCue` (type): type UiCue = "click" | "hover" | "open" | "close" | "confirm" | "deny" | "notify" — Interface sound cues every game gets: press, hover, panel open/close, confirm, refusal, notification.
|
|
378
|
+
- `UiCueOverrides` (type): type UiCueOverrides = false | Partial<Record<UiCue, SoundDef | false>> — Per-cue override: a replacement sound, or `false` to silence that cue. `false` for the whole map silences all.
|
|
379
|
+
- `uiCueSoundId` (function): function uiCueSoundId(cue: UiCue): string — Catalog id a cue plays under: `ui.click`, `ui.deny`, ... A game sound with that id replaces the default.
|
|
380
|
+
- `withUiCueSounds` (function): function withUiCueSounds(sounds: Readonly<Record<string, SoundDef>> | undefined, buses: Readonly<Record<string, AudioBusDef>> | undefined, overrides?: UiCueOverrides): { sounds: Record<string, SoundDef>; buses: Record<string, AudioBusDef> | undefined } — Merge the default UI cue patches into a game's sound catalog. A game sound already named `ui.<cue>` wins, then `overrides`, then the default. Adds the `ui` bus (gain 0.8) when the game did not declare one.
|
|
381
|
+
|
|
371
382
|
## @jgengine/core/audio/voiceAllocator
|
|
372
383
|
|
|
373
384
|
- `AudioVoice` (interface): interface AudioVoice — One reserved playback slot, including sources still loading.
|
|
@@ -2092,7 +2103,7 @@
|
|
|
2092
2103
|
- `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.
|
|
2093
2104
|
- `AssetSpaceIssue` (interface): interface AssetSpaceIssue — One problem found by {@link validateAssetSpace}: which metadata field and why it is invalid.
|
|
2094
2105
|
- `AttackMoveOrderPayload` (interface): interface AttackMoveOrderPayload — Payload for an attack-move: advance toward `point`, engaging hostiles encountered en route.
|
|
2095
|
-
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented
|
|
2106
|
+
- `AudioBusDef` (interface): interface AudioBusDef { id: AudioBusId; gain?: number } — ⚠ undocumented · used by `withUiCueSounds` (@jgengine/core/audio/uiCues): Merge the default UI cue patches into a game's sound catalog.
|
|
2096
2107
|
- `AudioFalloffConfig` (interface): interface AudioFalloffConfig { minDistance?: number; maxDistance?: number; curve?: FalloffCurve } — ⚠ undocumented
|
|
2097
2108
|
- `AuthoredTrigger` (interface): interface AuthoredTrigger — One resolved trigger binding from a document object.
|
|
2098
2109
|
- `AuthoredTriggerRuntime` (interface): interface AuthoredTriggerRuntime — Runtime handle that watches authored triggers against moving actors each tick.
|
|
@@ -2119,10 +2130,10 @@
|
|
|
2119
2130
|
- `BoundsSpec` (type): type BoundsSpec = | { readonly kind: "sphere"; readonly radius: number; readonly offset?: Vec3 } | { readonly kind: "aabb"; readonly half: Vec3; readonly offset?: Vec3 } | { readonly kind: "rect"; readonly halfWidth: number; readonly halfDepth: number; readonly halfHeight?: number; readonly offset?:… — How a renderable declares its extent. AABB, bounding sphere, and 2D rectangle cover the common cases; `point` is the degenerate zero-size default for objects that never override. `offset` shifts the volume from the object origin (e.g. a tall model whose pivot is at its feet).
|
|
2120
2131
|
- `BoxFormationOptions` (interface): interface BoxFormationOptions — Options for {@link boxFormation}.
|
|
2121
2132
|
- `BuildRole` (type): type BuildRole = "owner" | "editor" | "viewer" — ⚠ undocumented
|
|
2122
|
-
- `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit" | "solid"> — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
|
|
2133
|
+
- `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "probabilities" | "along" | "kit" | "solid"> — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
|
|
2123
2134
|
- `BuildingIndex` (interface): interface BuildingIndex { readonly buildings: readonly GeneratedBuilding[]; at(point: Vec2): GeneratedBuilding | undefined; within(area: Aabb): GeneratedBuilding[]; nearest(point: Vec2): BuildingHit | undefined; isInside(point: Vec2): boolean; blockers(margin?: nu… — ⚠ undocumented
|
|
2124
2135
|
- `BuildingPaletteOverrides` (type): type BuildingPaletteOverrides = Partial<BuildingPalette> — ⚠ undocumented
|
|
2125
|
-
- `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented · used by `
|
|
2136
|
+
- `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented · used by `BUILDING_STYLE_PROBABILITIES` (@jgengine/core/world/buildings): Facade part probabilities per style, so an industrial yard, a ruined block and a coastal strip differ in shape as well as colour.
|
|
2126
2137
|
- `CITY_BUILDING_BUDGET` (const): const CITY_BUILDING_BUDGET: 2600 — Max buildings a single `city` district generates — the block/parcel pipeline's bounded lot cap.
|
|
2127
2138
|
- `CITY_DEFAULTS` (const): const CITY_DEFAULTS: CityRules — City defaults: a zoned mixed metropolis — towers downtown, slabs mid-ring, houses at the edge.
|
|
2128
2139
|
- `CITY_FILLER_CLASSES` (const): const CITY_FILLER_CLASSES: readonly CityFillerClass[] — All filler classes, for validation and interior-pass allow-lists.
|
|
@@ -2215,7 +2226,7 @@
|
|
|
2215
2226
|
- `DayNightSnapshot` (interface): interface DayNightSnapshot — Serializable day-night position — accumulated clock offset, pause state, and speed — for save/load.
|
|
2216
2227
|
- `DecisionGraphBehavior` (interface): interface DecisionGraphBehavior — Decision graph behavior descriptor using a named registered action set.
|
|
2217
2228
|
- `DrapeOptions` (interface): interface DrapeOptions — Shaping for surface draping: subdivision spacing and a lift to keep the line off the ground.
|
|
2218
|
-
- `EditableTerrain` (interface): interface EditableTerrain extends TerrainField { readonly cols: number; readonly rows: number; readonly cellSize: number; apply(edit: TerraformEdit): number; applyRecording(edit: TerraformEdit, record: TerraformDeltaRecorder): number; editDelta(edit:
|
|
2229
|
+
- `EditableTerrain` (interface): interface EditableTerrain extends TerrainField { readonly cols: number; readonly rows: number; readonly cellSize: number; readonly gridBounds: Aabb; apply(edit: TerraformEdit): number; applyRecording(edit: TerraformEdit, record: TerraformDeltaRecorder): number; editDelta(edit: Terraform… — ⚠ undocumented · used by `beginSurfaceStroke`: Opens a paint-stroke recorder over `terrain`; stamp paint edits into it, then read one net delta.
|
|
2219
2230
|
- `ElevationReadout` (interface): interface ElevationReadout — Measurable elevation readout at a single world point — the cursor/hover feedback value.
|
|
2220
2231
|
- `ElevationSummary` (interface): interface ElevationSummary — Aggregate elevation statistics over a region — the selection min/max/mean and legend range.
|
|
2221
2232
|
- `EmittedCue` (interface): interface EmittedCue<Payload = unknown> — A cue plus the resolved firing context passed to {@link SequenceDirector.onCue} listeners.
|
|
@@ -2452,7 +2463,7 @@
|
|
|
2452
2463
|
- `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.
|
|
2453
2464
|
- `RevealQuery` (interface): interface RevealQuery { inRadius(center: EntityPosition | string, radius: number, tags: readonly string[]): RevealHit[] } — ⚠ undocumented
|
|
2454
2465
|
- `RoadCut` (interface): interface RoadCut — One trim of a ribbon end back to a junction boundary — the seam the welded surface attaches to.
|
|
2455
|
-
- `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;
|
|
2466
|
+
- `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.
|
|
2456
2467
|
- `RoadJunctionInput` (interface): interface RoadJunctionInput — The minimal junction shape this geometry needs — a node position plus its outgoing arms. Matches the structural subset of `StreetJunction` (streetGenerator) so a network's `junctions` can be fed straight in. Arm `angle` follows the generator convention `atan2(dx, dz)`, i.e. the outward unit direction of an arm is `[sin(angle), cos(angle)]`.
|
|
2457
2468
|
- `RoadSurfaceOptions` (interface): interface RoadSurfaceOptions — Grip levels and blend width for {@link roadSurfaceSampler}; each field is optional and defaulted.
|
|
2458
2469
|
- `RoofPlan` (interface): interface RoofPlan { style: RoofStyle; ridge: readonly [Vec2, Vec2]; apexHeight: number; eaveHeight: number; faces: readonly (readonly WallVec3[])[] } — ⚠ undocumented
|
|
@@ -2517,7 +2528,7 @@
|
|
|
2517
2528
|
- `SnapMode` (type): type SnapMode = "grid" | "free" | "surface" — ⚠ undocumented
|
|
2518
2529
|
- `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.
|
|
2519
2530
|
- `SoilRules` (interface): interface SoilRules — Fully-defaulted soil params parsed from a volume's `meta`.
|
|
2520
|
-
- `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
|
|
2531
|
+
- `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_UI_CUE_SOUNDS` (@jgengine/core/audio/uiCues): Short, soft procedural patches: no samples to load, quiet enough to sit under game audio.
|
|
2521
2532
|
- `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.
|
|
2522
2533
|
- `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
|
|
2523
2534
|
- `SpawnDirectorState` (interface): interface SpawnDirectorState { wave: number; elapsed: number; waveElapsed: number; budget: number; alert: number; spawnedThisWave: number; spawnedTotal: number; rng: RandomSeed; done: boolean } — ⚠ undocumented
|
|
@@ -3116,6 +3127,7 @@
|
|
|
3116
3127
|
## @jgengine/core/world/buildings
|
|
3117
3128
|
|
|
3118
3129
|
- `BUILDING_STYLE_PALETTES` (const): const BUILDING_STYLE_PALETTES: Record<BuildingStyle, Record<BuildingPartKind, string>> — ⚠ undocumented
|
|
3130
|
+
- `BUILDING_STYLE_PROBABILITIES` (const): const BUILDING_STYLE_PROBABILITIES: Record<BuildingStyle, Partial<BuildingProbabilities>> — Facade part probabilities per style, so an industrial yard, a ruined block and a coastal strip differ in shape as well as colour. Unset parts keep the generic probabilities.
|
|
3119
3131
|
- `BUILDING_STYLE_WALL_TONES` (const): const BUILDING_STYLE_WALL_TONES: Record<BuildingStyle, readonly string[]> — Per-style facade-tone family: the wall colours a district spreads across its buildings so neighbours differ in hue and value while the block stays one palette. Index 0 is the palette's own `wall`; the rest fan warmer/cooler and lighter/darker around it.
|
|
3120
3132
|
- `BuildingCellRef` (interface): interface BuildingCellRef { facade: BuildingFacade; level: number; bay: number } — ⚠ undocumented
|
|
3121
3133
|
- `BuildingConfig` (interface): interface BuildingConfig { id: string; seed: BuildingSeed; center: Vec2; floors: number; baysWide: number; baysDeep: number; bayWidth: number; floorHeight: number; facadeDepth: number; roofOverhang: number; probabilities: BuildingProbabilities; variants: BuildingVa… — ⚠ undocumented · used by `createBuildingConfig`: Fill a partial building description out to a complete {@link BuildingConfig}, clamping counts and probabilities.
|
|
@@ -3129,9 +3141,9 @@
|
|
|
3129
3141
|
- `BuildingPartKind` (type): type BuildingPartKind = | "wall" | "window" | "awning" | "airConditioner" | "clothesline" | "storefront" | "shutter" | "storeSign" | "roof" | "roofProp" | "guardrail" | "corner" — ⚠ undocumented · used by `resolveBuildingKitPart` (@jgengine/core/world/buildingKit): Resolves one generated part against a kit.
|
|
3130
3142
|
- `BuildingPartPlacement` (interface): interface BuildingPartPlacement { id: string; buildingId: string; kind: BuildingPartKind; facade: BuildingFacade; position: Vec3; rotationY: number; scale: Vec3; kit: BuildingKitSlot; cell?: BuildingCellRef; tags?: readonly BuildingPartTag[] } — ⚠ undocumented
|
|
3131
3143
|
- `BuildingPartTag` (type): type BuildingPartTag = "ground" | "upper" | "open" | "closed" | "decor" | "structure" — ⚠ undocumented
|
|
3132
|
-
- `BuildingProbabilities` (interface): interface BuildingProbabilities { window: number; openStore: number; awning: number; airConditioner: number; clothesline: number; storeSign: number; roofProp: number } — ⚠ undocumented
|
|
3144
|
+
- `BuildingProbabilities` (interface): interface BuildingProbabilities { window: number; openStore: number; awning: number; airConditioner: number; clothesline: number; storeSign: number; roofProp: number } — ⚠ undocumented · used by `BUILDING_STYLE_PROBABILITIES`: Facade part probabilities per style, so an industrial yard, a ruined block and a coastal strip differ in shape as well as colour.
|
|
3133
3145
|
- `BuildingSeed` (type): type BuildingSeed = number | string — ⚠ undocumented
|
|
3134
|
-
- `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented · used by `
|
|
3146
|
+
- `BuildingStyle` (type): type BuildingStyle = | "generic" | "capital" | "village" | "desert" | "industrial" | "coastal" | "neon" | "ruin" | "frontier" | "aerial" — ⚠ undocumented · used by `BUILDING_STYLE_PROBABILITIES`: Facade part probabilities per style, so an industrial yard, a ruined block and a coastal strip differ in shape as well as colour.
|
|
3135
3147
|
- `BuildingSurface` (type): type BuildingSurface = string | BuildingSurfaceMaterial — What a building part kind is painted with: a hex colour, or a colour plus tiled PBR maps.
|
|
3136
3148
|
- `BuildingSurfaceMaps` (interface): interface BuildingSurfaceMaps — URLs of the PBR maps a building surface tiles; `buildMaterialCatalog(...).resolve(id)!.maps` fits directly.
|
|
3137
3149
|
- `BuildingSurfaceMaterial` (interface): interface BuildingSurfaceMaterial — A textured building surface: a base colour plus optional tiled PBR maps. With `maps`, `color` multiplies the albedo (leave it light to show the map as authored); without, it is the flat colour the part has always had.
|
|
@@ -3144,6 +3156,7 @@
|
|
|
3144
3156
|
- `createBuildingConfig` (function): function createBuildingConfig(input: BuildingConfigInput = {}): BuildingConfig — Fill a partial building description out to a complete {@link BuildingConfig}, clamping counts and probabilities. Use it to inspect or adjust the resolved shape before generating.
|
|
3145
3157
|
- `generateBuilding` (function): function generateBuilding(input: BuildingConfigInput = {}): GeneratedBuilding — Generate one building as a flat list of placed facade parts: bays × floors per facade, a ground row, corners, and a roof, with every decorative part rolled from `probabilities` and every part tagged with a `kit` slot the renderer binds to a model (see `world/buildingKit`). Deterministic from `seed`.
|
|
3146
3158
|
- `generateBuildingDistrict` (function): function generateBuildingDistrict(config: BuildingGridConfig): GeneratedBuilding[] — Generate a grid of buildings on lots sized by `lotSize` and separated by `streetWidth`, each with its floor count rolled from `floorRange`.
|
|
3159
|
+
- `resolveBuildingProbabilities` (function): function resolveBuildingProbabilities(style: BuildingStyle = DEFAULT_BUILDING_STYLE, overrides?: Partial<BuildingProbabilities>): Partial<BuildingProbabilities> — Style facade probabilities with explicit overrides applied on top.
|
|
3147
3160
|
- `resolveBuildingSurface` (function): function resolveBuildingSurface(surface: BuildingSurface): BuildingSurfaceMaterial — Normalises a surface to its material form so a renderer reads one shape.
|
|
3148
3161
|
|
|
3149
3162
|
## @jgengine/core/world/carve
|
|
@@ -3367,8 +3380,8 @@
|
|
|
3367
3380
|
- `BiomeFog` (interface): interface BiomeFog — Per-band fog override cross-faded along z by `createBiomeFogSampler`; unset fields fall through to the base sky fog.
|
|
3368
3381
|
- `BiomeSky` (interface): interface BiomeSky — Per-band sky/light override cross-faded along z by `createBiomeSkySampler`; unset fields fall through to the base sky.
|
|
3369
3382
|
- `BiomesWorldConfig` (interface): interface BiomesWorldConfig extends WorldGridConfig { map: string; zones: string; bounds?: WorldBounds } — ⚠ undocumented · used by `biomes`: Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain.
|
|
3370
|
-
- `BuildingEnvironmentConfig` (interface): interface BuildingEnvironmentConfig { count?: number; position?: EnvironmentVec2; footprint?: WorldBounds; stories?: readonly [number, number]; storyHeight?: number; spacing?: number; style?: BuildingStyle; palette?: BuildingPaletteOverrides;
|
|
3371
|
-
- `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit" | "solid"> — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
|
|
3383
|
+
- `BuildingEnvironmentConfig` (interface): interface BuildingEnvironmentConfig { count?: number; position?: EnvironmentVec2; footprint?: WorldBounds; stories?: readonly [number, number]; storyHeight?: number; spacing?: number; style?: BuildingStyle; palette?: BuildingPaletteOverrides; probabilities?: Partial<BuildingP… — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
|
|
3384
|
+
- `BuildingEnvironmentDescriptor` (type): type BuildingEnvironmentDescriptor = { kind: "building" } & Required< Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style"> > & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "probabilities" | "along" | "kit" | "solid"> — ⚠ undocumented · used by `building`: Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
|
|
3372
3385
|
- `BuildingFrontageConfig` (interface): interface BuildingFrontageConfig — Street-aware placement for `building()`: instead of a grid scattered around `position`, lots are stepped along each road's frontage, offset by a consistent setback (a curb + sidewalk strip), and turned so every building FRONT faces its road. `footprint` (`w` = frontage width, `d` = depth) and `spacing` (along-road gap) are shared with the grid mode. Deterministic and bounded by `maxLots`.
|
|
3373
3386
|
- `BuildingFrontageRoad` (interface): interface BuildingFrontageRoad — One road a `building({ along })` frontage lines with buildings: centerline + full width.
|
|
3374
3387
|
- `EnvironmentArea` (interface): interface EnvironmentArea extends WorldBounds { h?: number; position?: EnvironmentVec2 } — ⚠ undocumented
|
|
@@ -3387,7 +3400,7 @@
|
|
|
3387
3400
|
- `RainEnvironmentConfig` (interface): interface RainEnvironmentConfig { area?: EnvironmentArea; position?: EnvironmentVec2; density?: number; speed?: number; dropLength?: number; wind?: EnvironmentVec2; color?: string; width?: number; opacity?: number } — ⚠ undocumented · used by `rain`: Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
|
|
3388
3401
|
- `RainEnvironmentDescriptor` (type): type RainEnvironmentDescriptor = { kind: "rain" } & Required< Pick<RainEnvironmentConfig, "area" | "density" | "speed" | "dropLength" | "wind" | "color" | "width" | "opacity"> > — ⚠ undocumented · used by `rain`: Declares a rainfall weather effect for `environment()` — area, density, speed, wind, and drop width/opacity.
|
|
3389
3402
|
- `RoadEnvironmentConfig` (interface): interface RoadEnvironmentConfig — Config for {@link road}: a flat asphalt ribbon draped over the terrain along a centerline.
|
|
3390
|
-
- `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;
|
|
3403
|
+
- `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.
|
|
3391
3404
|
- `SkyEnvironmentConfig` (interface): interface SkyEnvironmentConfig { preset?: "day" | "dusk" | "night"; timeOfDay?: boolean; horizonColor?: string; zenithColor?: string; sunIntensity?: number; ambientIntensity?: number; sun?: SkySunConfig; radius?: number; hazeStrength?: number; sunGlowStrength?: number; g… — ⚠ undocumented · used by `CINEMATIC_SKY` (@jgengine/core/render/lookPreset): A static day sky: a real dome plus the shell's view-following shadow-casting sun and hemisphere fill.
|
|
3392
3405
|
- `SkyEnvironmentDescriptor` (type): type SkyEnvironmentDescriptor = { kind: "sky" } & Required< Pick<SkyEnvironmentConfig, "preset" | "timeOfDay"> > & Omit<SkyEnvironmentConfig, "preset" | "timeOfDay"> — ⚠ undocumented
|
|
3393
3406
|
- `SkySunConfig` (interface): interface SkySunConfig — Where the sun sits, as a compass bearing and a height above the horizon, both in degrees. `azimuth` 0 points toward -Z (north), 90 toward +X (east); `elevation` 90 is straight overhead.
|
|
@@ -3966,7 +3979,7 @@
|
|
|
3966
3979
|
## @jgengine/core/world/terraform
|
|
3967
3980
|
|
|
3968
3981
|
- `BlendStroke` (interface): interface BlendStroke — Accumulates a whole blend-paint drag into one compact {@link WeightDelta}. Keeps each weight slot's first `before` and latest `after`, so undo replays the blend as a single step.
|
|
3969
|
-
- `EditableTerrain` (interface): interface EditableTerrain extends TerrainField { readonly cols: number; readonly rows: number; readonly cellSize: number; apply(edit: TerraformEdit): number; applyRecording(edit: TerraformEdit, record: TerraformDeltaRecorder): number; editDelta(edit:
|
|
3982
|
+
- `EditableTerrain` (interface): interface EditableTerrain extends TerrainField { readonly cols: number; readonly rows: number; readonly cellSize: number; readonly gridBounds: Aabb; apply(edit: TerraformEdit): number; applyRecording(edit: TerraformEdit, record: TerraformDeltaRecorder): number; editDelta(edit: Terraform… — ⚠ undocumented · used by `beginSurfaceStroke`: Opens a paint-stroke recorder over `terrain`; stamp paint edits into it, then read one net delta.
|
|
3970
3983
|
- `EditableTerrainConfig` (interface): interface EditableTerrainConfig { bounds: Aabb; base?: TerrainField; cellSize?: number } — ⚠ undocumented · used by `createTerrainSnapshot`: A fresh, unedited terrain snapshot sized to `bounds`/`cellSize` — the seed for a new sculpt document.
|
|
3971
3984
|
- `SurfaceDelta` (interface): interface SurfaceDelta — A compact record of the surface-material cells a paint stroke touched: parallel `indices`/`before`/`after` arrays into the per-cell surface grid. One per stroke keeps paint undo history small.
|
|
3972
3985
|
- `SurfaceDeltaRecorder` (type): type SurfaceDeltaRecorder = (index: number, before: string | null, after: string | null) => void — Reports each changed cell during a recorded paint: grid index, prior surface id, new surface id.
|
|
@@ -881,6 +881,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
881
881
|
- `setTouchControlsMode` (function) · `import { setTouchControlsMode } from "@jgengine/core/input/touchControlsMode"`
|
|
882
882
|
- `touchButtonShape` (function) · `import { touchButtonShape } from "@jgengine/core/input/touchScheme"`
|
|
883
883
|
|
|
884
|
+
## ui-sound-cues — default procedural click/hover/open/close/confirm/deny/notify cues on a "ui" bus, overridable per game
|
|
885
|
+
|
|
886
|
+
- `withUiCueSounds` (function) · `import { withUiCueSounds } from "@jgengine/core/audio/uiCues"`
|
|
887
|
+
|
|
884
888
|
## uphill-grade-step — constrain sampled heightfield ascent with axis sliding and a configurable terrain-policy sampler
|
|
885
889
|
|
|
886
890
|
- `resolveTerrainGradeStep` (function) · `import { resolveTerrainGradeStep } from "@jgengine/core/movement/terrainGrade"`
|
|
@@ -29,14 +29,31 @@ export const overworld = world({
|
|
|
29
29
|
## Legacy world features
|
|
30
30
|
|
|
31
31
|
Authored terrain paint carried by `environmentContentFromDocument(document).sculpt` renders on
|
|
32
|
-
the normal environment ground
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
the normal environment ground through the terrain surface material, in play and in the editor
|
|
33
|
+
viewport alike. Each layer keeps its hue (`tint`, else `TERRAIN_MATERIAL_COLORS`) and draws its
|
|
34
|
+
`surface` type's procedural ground: grass, dirt, gravel, rock, sand, mud, snow and road each get
|
|
35
|
+
their own albedo variation, roughness and micro-normal (`terrainSurfaceClass` maps ids such as
|
|
36
|
+
`path` → dirt or `stone` → rock; unknown ids get generic ground). Layer weights × `opacity` meet
|
|
37
|
+
along noise-warped, height-aware edges, so the 1–2 m paint grid never shows. Steep slopes turn to
|
|
38
|
+
rock, and macro sweeps break up large single-hue fields. Layer `roughness` sets the base roughness
|
|
39
|
+
and `tiling` scales the pattern; `triplanar` is not needed (rock is sampled in 3D). Unpainted cells
|
|
40
|
+
keep the descriptor palette with procedural detail. Paint changes color, never ground height or
|
|
41
|
+
collision. A terrain without `detail` still renders this way; `detail.surfaceStrength: 0` keeps
|
|
42
|
+
flat painted colour, and `detail: false` opts out to the old flat vertex-colour ground. The
|
|
43
|
+
`low` graphics tier draws one cheap mottle per surface and skips micro-normals.
|
|
44
|
+
|
|
45
|
+
Paths and roads share those surface functions. An authored path (`<AuthoredPaths>`) shades by
|
|
46
|
+
`meta.surface`, else its kind (`road` paves), else dirt: soft ground gets wheel ruts and a
|
|
47
|
+
noise-warped edge that fades into the terrain around the authored width; pavement keeps a crisp
|
|
48
|
+
edge with tyre lanes and cracks. Tune with `meta.edgeSoftness` (0 = hard) and `meta.wear` (0..1);
|
|
49
|
+
`meta.surfaceDetail: false` or `<AuthoredScene pathSurfaceDetail={false}>` keeps flat ribbons.
|
|
50
|
+
`road({ surface })` picks the carriageway surface (default `"road"`, `false` for flat colour), and
|
|
51
|
+
city studio ground takes `meta.surfaceDetail: false` on its volume. City ground layers fade out
|
|
52
|
+
where the district's merged footprint meets bare terrain, keeping seams between layers crisp;
|
|
53
|
+
`meta.edgeFade: false` on the volume keeps hard outer edges. Custom ribbons use
|
|
54
|
+
`createSurfaceRibbonMaterial` with `ribbonSurfaceFrame` from `@jgengine/shell/terrain`; custom
|
|
55
|
+
ground meshes get the same outer-edge fade from `buildGroundCoverageMask`, `createGroundEdgeFade`
|
|
56
|
+
and `applyGroundEdgeFade`.
|
|
40
57
|
|
|
41
58
|
Custom ground consumers can use `createTerrainPaintColorSampler` from `@jgengine/shell/terrain`
|
|
42
59
|
with a `TerrainPaintSource` (an editable terrain's layer/surface/weight channels). The returned
|
|
@@ -437,6 +454,8 @@ Custom authored primitive renderers use `StaticShapeInstances` (`@jgengine/shell
|
|
|
437
454
|
|
|
438
455
|
`ModelMaterialMaps` derives its URL fields from `MaterialTextureRole`; ordinary models and authored surfaces accept all 20 supported roles, including alpha, sheen, anisotropy, clearcoat, specular, transmission, thickness and iridescence maps. `modelAssetRequests` discovers supplied maps through inline parts and attachments; unknown roles remain outside its request list. Legacy color/normal/roughness/ao/metalness/emissive/height order stays stable, followed by the remaining authority-defined roles. Authored surfaces keep their owned resources for equivalent config/map ordering and reload when a supported URL changes. Omitted model roles retain imported maps; games choose URLs and physical response parameters. This is the simple all-slot override seam; per-slot `MaterialAsset` assignments retain their own selectors and metadata.
|
|
439
456
|
|
|
457
|
+
Every model the shared loader resolves gets a default painted finish at load: eligible materials (opaque standard/physical, no normal map, no alpha cutout — flat colour, vertex colour or a KayKit-style palette atlas) have exported roughness remapped into 0.6–0.95, exporter-default metal (metallic 1 / roughness 1, no map) dropped to 0.1 and `envMapIntensity` capped at 0.8, plus one shared object-space detail shader (mottling, paler wear, roughness break-up, micro-normal, down-facing cavity). `GraphicsProfile.surfaceDetail` picks the level per tier (`"lite"` on low drops the micro-normal; `"off"` compiles plain); programs are shared per level. `ModelConfig.material` overrides still win. Opt out per model with `surfaceDetail: false` on the `ModelConfig`, or per game with `defineGame({ surfaceDetail: false })`.
|
|
458
|
+
|
|
440
459
|
`AuthoredSurfaceMaterial` / `useAuthoredSurfaceMaterial` (`@jgengine/shell/render/authoredSurfaceMaterial`) share model-material map roles and material application. They own material/texture clones; cached loader textures remain shared and untouched. Colour, emissive, sheen-colour and specular-colour maps are sRGB; normal and numeric roles are linear, following `MATERIAL_TEXTURE_SEMANTICS` from `@jgengine/core/material/materialAsset`. `wrapping` selects repeat (default), clamp or mirror; `anisotropy` defaults to 1. `normalScale` is explicit, `repeatMetres` optionally tiles unit shapes in physical metres including instance/parent scale (cylinder sides approximate an elliptical circumference). Omitting it retains authored UVs. Height maps must be normalized to [0,1]; `displacementScale`/`displacementBias` use local shape units and expand batch bounds. Compose local palette, asset URLs, opacity/depthWrite and emission in the game. No scene coordinates or surface families belong in these primitives; editor placement stays authoritative. Deepward's prefab-authoring fallback is tracked by #1937 and should be removed when editor composition can express it.
|
|
441
460
|
|
|
442
461
|
### Baked authored prefab assets
|