@jgengine/core 0.14.0 → 0.15.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.
Files changed (214) hide show
  1. package/CHANGELOG.md +500 -1
  2. package/dist/ai/difficulty.d.ts +154 -0
  3. package/dist/ai/difficulty.js +194 -0
  4. package/dist/ai/driver.d.ts +107 -0
  5. package/dist/ai/driver.js +175 -0
  6. package/dist/ai/flock.js +13 -23
  7. package/dist/ai/laneSelect.js +2 -1
  8. package/dist/ai/mobBrain.js +2 -1
  9. package/dist/ai/waveRunner.d.ts +81 -0
  10. package/dist/ai/waveRunner.js +104 -0
  11. package/dist/audio/musicState.d.ts +47 -0
  12. package/dist/audio/musicState.js +38 -0
  13. package/dist/audio/stepCadence.d.ts +47 -0
  14. package/dist/audio/stepCadence.js +29 -0
  15. package/dist/audio/synth.d.ts +12 -0
  16. package/dist/authoring.d.ts +6 -4
  17. package/dist/authoring.js +6 -4
  18. package/dist/combat/castRunner.d.ts +13 -1
  19. package/dist/combat/castRunner.js +5 -1
  20. package/dist/combat/comboMeter.d.ts +140 -0
  21. package/dist/combat/comboMeter.js +215 -0
  22. package/dist/combat/comboPoints.d.ts +11 -0
  23. package/dist/combat/comboPoints.js +11 -2
  24. package/dist/combat/damageResolution.d.ts +1 -1
  25. package/dist/combat/defensiveWindow.d.ts +5 -0
  26. package/dist/combat/effects.d.ts +24 -0
  27. package/dist/combat/effects.js +6 -1
  28. package/dist/combat/projectiles.d.ts +6 -0
  29. package/dist/combat/projectiles.js +2 -2
  30. package/dist/combat/regenShield.d.ts +40 -2
  31. package/dist/combat/regenShield.js +66 -18
  32. package/dist/combat/resourcePool.d.ts +19 -0
  33. package/dist/combat/resourcePool.js +20 -2
  34. package/dist/combat/shotOrigin.d.ts +5 -0
  35. package/dist/combat/statusApplication.d.ts +1 -1
  36. package/dist/combat/statusApplication.js +2 -1
  37. package/dist/combat/statusEffectView.d.ts +56 -0
  38. package/dist/combat/statusEffectView.js +52 -0
  39. package/dist/combat.d.ts +4 -2
  40. package/dist/combat.js +2 -0
  41. package/dist/devtools/fallbackSeams.d.ts +3 -2
  42. package/dist/devtools/fallbackSeams.js +1 -1
  43. package/dist/devtools/textureErrors.d.ts +40 -0
  44. package/dist/devtools/textureErrors.js +68 -0
  45. package/dist/economy/shopStock.d.ts +110 -0
  46. package/dist/economy/shopStock.js +157 -0
  47. package/dist/economy/wallet.d.ts +6 -0
  48. package/dist/economy/wallet.js +1 -0
  49. package/dist/game/achievements.d.ts +80 -0
  50. package/dist/game/achievements.js +124 -0
  51. package/dist/game/cameraConfig.d.ts +7 -0
  52. package/dist/game/codex.d.ts +60 -0
  53. package/dist/game/codex.js +89 -0
  54. package/dist/game/credits.d.ts +36 -0
  55. package/dist/game/credits.js +0 -0
  56. package/dist/game/defineGame.d.ts +28 -3
  57. package/dist/game/defineGame.js +5 -0
  58. package/dist/game/dialogueGraph.d.ts +116 -0
  59. package/dist/game/dialogueGraph.js +103 -0
  60. package/dist/game/eventTicker.d.ts +95 -0
  61. package/dist/game/eventTicker.js +91 -0
  62. package/dist/game/events.d.ts +24 -5
  63. package/dist/game/events.js +18 -0
  64. package/dist/game/gamePhase.d.ts +1 -1
  65. package/dist/game/gamePhase.js +1 -1
  66. package/dist/game/leaderboardRank.d.ts +71 -0
  67. package/dist/game/leaderboardRank.js +76 -0
  68. package/dist/game/lootTable.d.ts +10 -1
  69. package/dist/game/lootTable.js +4 -2
  70. package/dist/game/notifications.d.ts +57 -0
  71. package/dist/game/notifications.js +107 -0
  72. package/dist/game/playableGame.d.ts +39 -2
  73. package/dist/game/quest.d.ts +26 -0
  74. package/dist/game/quest.js +31 -0
  75. package/dist/game/runDraft.js +2 -1
  76. package/dist/game/saveSlots.d.ts +102 -0
  77. package/dist/game/saveSlots.js +136 -0
  78. package/dist/game/talentTreeView.d.ts +106 -0
  79. package/dist/game/talentTreeView.js +114 -0
  80. package/dist/game/worldItem.js +2 -1
  81. package/dist/gameplay.d.ts +15 -4
  82. package/dist/gameplay.js +13 -2
  83. package/dist/i18n/i18n.d.ts +51 -0
  84. package/dist/i18n/i18n.js +82 -0
  85. package/dist/input/axisInput.d.ts +1 -1
  86. package/dist/input/axisInput.js +18 -2
  87. package/dist/input/rebindSession.d.ts +141 -0
  88. package/dist/input/rebindSession.js +235 -0
  89. package/dist/input/touchControlsMode.d.ts +16 -0
  90. package/dist/input/touchControlsMode.js +23 -0
  91. package/dist/input/touchScheme.d.ts +30 -1
  92. package/dist/input/touchScheme.js +31 -1
  93. package/dist/interaction/promptRegistry.d.ts +78 -0
  94. package/dist/interaction/promptRegistry.js +130 -0
  95. package/dist/inventory/storageTier.js +3 -2
  96. package/dist/meta/changelog.d.ts +1 -1
  97. package/dist/meta/changelog.js +145 -1
  98. package/dist/movement/movementModel.d.ts +26 -3
  99. package/dist/movement/movementModel.js +121 -15
  100. package/dist/movement/playerMovement.js +161 -25
  101. package/dist/physics/drivableVehicle.js +3 -1
  102. package/dist/physics/kinematicVehicle.d.ts +56 -1
  103. package/dist/physics/kinematicVehicle.js +99 -10
  104. package/dist/physics/vehicleObstacles.js +19 -0
  105. package/dist/random/resolveRng.d.ts +14 -0
  106. package/dist/random/resolveRng.js +31 -0
  107. package/dist/render/postProcessing.d.ts +12 -1
  108. package/dist/runtime/cameraDirector.d.ts +2 -2
  109. package/dist/runtime/context/combat.js +8 -0
  110. package/dist/runtime/gameContext.js +6 -1
  111. package/dist/runtime/gameContextTypes.d.ts +18 -0
  112. package/dist/runtime/inputSnapshot.d.ts +10 -1
  113. package/dist/runtime/inputSnapshot.js +13 -1
  114. package/dist/runtime/runtimeSave.d.ts +3 -3
  115. package/dist/runtime/runtimeSave.js +11 -2
  116. package/dist/scene/assetDiagnostics.js +2 -2
  117. package/dist/scene/autoTarget.js +2 -1
  118. package/dist/scene/captureCheck.js +3 -2
  119. package/dist/scene/entityStore.d.ts +4 -1
  120. package/dist/scene/entityStore.js +3 -0
  121. package/dist/scene/objectStore.d.ts +10 -0
  122. package/dist/scene/objectStore.js +29 -6
  123. package/dist/scene/sceneKinds.d.ts +18 -0
  124. package/dist/scene/sceneKinds.js +19 -0
  125. package/dist/scene/sequenceDirector.d.ts +110 -0
  126. package/dist/scene/sequenceDirector.js +146 -0
  127. package/dist/session/roles.js +3 -2
  128. package/dist/settings/settingsModel.d.ts +1 -0
  129. package/dist/settings/settingsModel.js +1 -0
  130. package/dist/stats/rollCheck.js +4 -2
  131. package/dist/time/dayNightCycle.d.ts +114 -0
  132. package/dist/time/dayNightCycle.js +208 -0
  133. package/dist/time/timerSet.d.ts +132 -0
  134. package/dist/time/timerSet.js +243 -0
  135. package/dist/ui/accessibility.d.ts +51 -0
  136. package/dist/ui/accessibility.js +83 -0
  137. package/dist/ui/coachMarks.d.ts +99 -0
  138. package/dist/ui/coachMarks.js +126 -0
  139. package/dist/ui/floatingText.d.ts +114 -0
  140. package/dist/ui/floatingText.js +203 -0
  141. package/dist/ui/modalStack.d.ts +143 -0
  142. package/dist/ui/modalStack.js +160 -0
  143. package/dist/ui/objectiveBanner.d.ts +123 -0
  144. package/dist/ui/objectiveBanner.js +162 -0
  145. package/dist/ui/photoMode.d.ts +32 -0
  146. package/dist/ui/photoMode.js +51 -0
  147. package/dist/ui/radialMenu.d.ts +47 -0
  148. package/dist/ui/radialMenu.js +74 -0
  149. package/dist/ui/screenMarkers.d.ts +128 -0
  150. package/dist/ui/screenMarkers.js +118 -0
  151. package/dist/ui.d.ts +8 -0
  152. package/dist/ui.js +8 -0
  153. package/dist/vfx/cameraShake.d.ts +97 -0
  154. package/dist/vfx/cameraShake.js +136 -0
  155. package/dist/vfx/damageDirection.d.ts +102 -0
  156. package/dist/vfx/damageDirection.js +188 -0
  157. package/dist/vfx/particles.d.ts +103 -0
  158. package/dist/vfx/particles.js +256 -0
  159. package/dist/vfx/screenEffects.d.ts +149 -0
  160. package/dist/vfx/screenEffects.js +191 -0
  161. package/dist/world/authoredObjects.d.ts +18 -0
  162. package/dist/world/authoredObjects.js +21 -0
  163. package/dist/world/authoredSpawn.js +19 -0
  164. package/dist/world/buildingLots.d.ts +54 -11
  165. package/dist/world/buildingLots.js +116 -30
  166. package/dist/world/cityBlocks.d.ts +45 -0
  167. package/dist/world/cityBlocks.js +159 -0
  168. package/dist/world/cityContent.d.ts +46 -2
  169. package/dist/world/cityContent.js +160 -2
  170. package/dist/world/cityGenerator.d.ts +261 -23
  171. package/dist/world/cityGenerator.js +643 -33
  172. package/dist/world/cityGeometry.d.ts +20 -0
  173. package/dist/world/cityGeometry.js +91 -0
  174. package/dist/world/cityKind.js +1 -44
  175. package/dist/world/fastTravel.d.ts +64 -0
  176. package/dist/world/fastTravel.js +108 -0
  177. package/dist/world/features.d.ts +16 -0
  178. package/dist/world/features.js +2 -0
  179. package/dist/world/grounded.d.ts +11 -0
  180. package/dist/world/grounded.js +12 -0
  181. package/dist/world/mapAnnotations.d.ts +75 -0
  182. package/dist/world/mapAnnotations.js +139 -0
  183. package/dist/world/markers.js +1 -0
  184. package/dist/world/resourceNode.d.ts +1 -1
  185. package/dist/world/resourceNode.js +2 -1
  186. package/dist/world/roads.d.ts +294 -5
  187. package/dist/world/roads.js +1262 -21
  188. package/dist/world/sharedAnnotations.d.ts +84 -0
  189. package/dist/world/sharedAnnotations.js +76 -0
  190. package/dist/world/spawnOverride.d.ts +37 -0
  191. package/dist/world/spawnOverride.js +50 -0
  192. package/dist/world/streetGenerator.d.ts +60 -11
  193. package/dist/world/streetGenerator.js +1786 -129
  194. package/dist/world/terrain.d.ts +1 -0
  195. package/dist/world/terrain.js +2 -0
  196. package/dist/world/waypoints.d.ts +63 -0
  197. package/dist/world/waypoints.js +137 -0
  198. package/dist/world.d.ts +17 -2
  199. package/dist/world.js +17 -2
  200. package/package.json +1 -1
  201. package/skills/ce-handoff/SKILL.md +149 -0
  202. package/skills/game-design/SKILL.md +2 -0
  203. package/skills/jgengine/SKILL.md +3 -1
  204. package/skills/jgengine/api.md +17 -7
  205. package/skills/jgengine/capabilities.md +12 -0
  206. package/skills/jgengine/recipes/minimal-game.md +7 -4
  207. package/skills/jgengine-combat/api.md +40 -4
  208. package/skills/jgengine-combat/capabilities.md +12 -0
  209. package/skills/jgengine-combat/reference.md +2 -0
  210. package/skills/jgengine-gameplay/api.md +212 -11
  211. package/skills/jgengine-gameplay/capabilities.md +66 -1
  212. package/skills/jgengine-world/api.md +397 -11
  213. package/skills/jgengine-world/capabilities.md +123 -2
  214. package/skills/jgengine-world/reference.md +15 -1
@@ -0,0 +1,84 @@
1
+ import type { AnnotationLayer } from "./mapAnnotations.js";
2
+ import type { MapLayerTone, MapZoneShape } from "./mapLayers.js";
3
+ import type { WorldXZ } from "./minimap.js";
4
+ /** Feed action shared drawings ride by default (pair with the party feed, like pings). */
5
+ export declare const ANNOTATION_FEED_ACTION = "map.annotation";
6
+ /** A serializable map-annotation edit broadcast to other players. */
7
+ export type AnnotationBroadcast = {
8
+ op: "stroke";
9
+ from: string;
10
+ id: string;
11
+ points: readonly WorldXZ[];
12
+ tone?: MapLayerTone;
13
+ width?: number;
14
+ } | {
15
+ op: "shape";
16
+ from: string;
17
+ id: string;
18
+ shape: MapZoneShape;
19
+ tone?: MapLayerTone;
20
+ label?: string;
21
+ } | {
22
+ op: "note";
23
+ from: string;
24
+ id: string;
25
+ position: WorldXZ;
26
+ text: string;
27
+ tone?: MapLayerTone;
28
+ } | {
29
+ op: "remove";
30
+ from: string;
31
+ id: string;
32
+ } | {
33
+ op: "clear";
34
+ from: string;
35
+ };
36
+ /** The feed sink shared annotations push to — an alias of the ping/feed `push` seam. */
37
+ export interface AnnotationFeedSink {
38
+ push(action: string, entry: unknown): void;
39
+ }
40
+ /** Construction options for {@link createSharedAnnotations}. */
41
+ export interface SharedAnnotationsDeps {
42
+ /** The local annotation layer edits apply to (and inbound edits mirror into). */
43
+ layer: AnnotationLayer;
44
+ /** Feed to broadcast local edits on (typically `ctx.game.feed`). */
45
+ feed: AnnotationFeedSink;
46
+ /** This player's id — stamped on broadcasts and used to drop our own echoes. */
47
+ from: string;
48
+ /** Feed action to publish/consume. Default {@link ANNOTATION_FEED_ACTION}. */
49
+ action?: string;
50
+ }
51
+ /**
52
+ * Local annotation edits that also broadcast, plus `apply` for inbound edits.
53
+ * `add*`/`remove`/`clear` mirror {@link AnnotationLayer} but return globally-unique
54
+ * ids so two clients never collide.
55
+ */
56
+ export interface SharedAnnotations {
57
+ addStroke(points: readonly WorldXZ[], options?: {
58
+ tone?: MapLayerTone;
59
+ width?: number;
60
+ }): string;
61
+ addShape(shape: MapZoneShape, options?: {
62
+ tone?: MapLayerTone;
63
+ label?: string;
64
+ }): string;
65
+ addNote(position: WorldXZ, text: string, options?: {
66
+ tone?: MapLayerTone;
67
+ }): string;
68
+ remove(id: string): boolean;
69
+ clear(): void;
70
+ /** Mirror an inbound broadcast from another player; own echoes (matching `from`) are ignored. */
71
+ apply(payload: AnnotationBroadcast): void;
72
+ feedAction: string;
73
+ }
74
+ /**
75
+ * Make a map annotation layer collaborative: local `addStroke`/`addShape`/
76
+ * `addNote`/`remove`/`clear` apply then broadcast a serializable edit over the
77
+ * party feed (the same seam `createPingSystem` uses), and `apply` mirrors inbound
78
+ * edits from other players — dropping our own echoes. Ids are globally unique per
79
+ * client so two players' strokes never collide. Transport-agnostic: wire `feed`
80
+ * to any replicated feed and route received entries into `apply`.
81
+ *
82
+ * @capability shared-annotations broadcast local map-drawing edits over the party feed and mirror inbound edits — collaborative annotations over any replicated feed
83
+ */
84
+ export declare function createSharedAnnotations(deps: SharedAnnotationsDeps): SharedAnnotations;
@@ -0,0 +1,76 @@
1
+ /** Feed action shared drawings ride by default (pair with the party feed, like pings). */
2
+ export const ANNOTATION_FEED_ACTION = "map.annotation";
3
+ /**
4
+ * Make a map annotation layer collaborative: local `addStroke`/`addShape`/
5
+ * `addNote`/`remove`/`clear` apply then broadcast a serializable edit over the
6
+ * party feed (the same seam `createPingSystem` uses), and `apply` mirrors inbound
7
+ * edits from other players — dropping our own echoes. Ids are globally unique per
8
+ * client so two players' strokes never collide. Transport-agnostic: wire `feed`
9
+ * to any replicated feed and route received entries into `apply`.
10
+ *
11
+ * @capability shared-annotations broadcast local map-drawing edits over the party feed and mirror inbound edits — collaborative annotations over any replicated feed
12
+ */
13
+ export function createSharedAnnotations(deps) {
14
+ const { layer, feed, from } = deps;
15
+ const action = deps.action ?? ANNOTATION_FEED_ACTION;
16
+ let counter = 0;
17
+ function nextId() {
18
+ counter += 1;
19
+ return `${from}:${counter}`;
20
+ }
21
+ function broadcast(payload) {
22
+ feed.push(action, payload);
23
+ }
24
+ return {
25
+ feedAction: action,
26
+ addStroke(points, options = {}) {
27
+ const id = nextId();
28
+ layer.addStroke(points, { id, ...options });
29
+ broadcast({ op: "stroke", from, id, points: points.map((p) => [p[0], p[1]]), ...options });
30
+ return id;
31
+ },
32
+ addShape(shape, options = {}) {
33
+ const id = nextId();
34
+ layer.addShape(shape, { id, ...options });
35
+ broadcast({ op: "shape", from, id, shape, ...options });
36
+ return id;
37
+ },
38
+ addNote(position, text, options = {}) {
39
+ const id = nextId();
40
+ layer.addNote(position, text, { id, ...options });
41
+ broadcast({ op: "note", from, id, position: [position[0], position[1]], text, ...options });
42
+ return id;
43
+ },
44
+ remove(id) {
45
+ const existed = layer.remove(id);
46
+ if (existed)
47
+ broadcast({ op: "remove", from, id });
48
+ return existed;
49
+ },
50
+ clear() {
51
+ layer.clear();
52
+ broadcast({ op: "clear", from });
53
+ },
54
+ apply(payload) {
55
+ if (payload.from === from)
56
+ return; // ignore our own echo
57
+ switch (payload.op) {
58
+ case "stroke":
59
+ layer.addStroke(payload.points, { id: payload.id, tone: payload.tone, width: payload.width });
60
+ return;
61
+ case "shape":
62
+ layer.addShape(payload.shape, { id: payload.id, tone: payload.tone, label: payload.label });
63
+ return;
64
+ case "note":
65
+ layer.addNote(payload.position, payload.text, { id: payload.id, tone: payload.tone });
66
+ return;
67
+ case "remove":
68
+ layer.remove(payload.id);
69
+ return;
70
+ case "clear":
71
+ layer.clear();
72
+ return;
73
+ }
74
+ },
75
+ };
76
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Per-session player-spawn override — a capture-harness ergonomics seam that lets a single
3
+ * screenshot or drive run place the player somewhere other than the authored `player_spawn`
4
+ * marker *without mutating `editor.scene.json`*. The runner installs one from the `?spawn=` URL
5
+ * overlay (mirroring `?cam=`); {@link authoredSpawnPosition} consults it for the default
6
+ * player-spawn resolution only, so authored content is untouched and the override evaporates the
7
+ * moment the page reloads without the param.
8
+ *
9
+ * Genre-agnostic: it moves whatever a game treats as its player spawn. It never changes markers of
10
+ * other kinds or an explicit marker `id`, so an override taken for a close-up cannot perturb enemy
11
+ * or prop placement queries that share {@link authoredSpawnPosition}.
12
+ *
13
+ * Install-style module state is the established runner pattern here (`installAssetBase`,
14
+ * `installEditorHost`, `installSaveEndpoint`); the default is `null`, so nothing changes and every
15
+ * pure query stays deterministic until a runner explicitly installs an override.
16
+ */
17
+ /** A spawn point that replaces the authored player spawn for one capture session. */
18
+ export interface SpawnOverride {
19
+ x: number;
20
+ y: number;
21
+ z: number;
22
+ /** Optional facing (yaw radians); when omitted the authored/`0` rotation is kept. */
23
+ rotationY?: number;
24
+ }
25
+ /** Install (or, with `null`, clear) the active player-spawn override. Idempotent; last write wins. */
26
+ export declare function installSpawnOverride(override: SpawnOverride | null): void;
27
+ /** Clear any installed player-spawn override. */
28
+ export declare function clearSpawnOverride(): void;
29
+ /** The currently installed player-spawn override, or `null` when none is active. */
30
+ export declare function readSpawnOverride(): SpawnOverride | null;
31
+ /**
32
+ * Parse a `?spawn=` / `--spawn` value into a {@link SpawnOverride}, or `null` when it is absent or
33
+ * malformed. Accepts `"x,y,z"` and `"x,y,z,yaw"` (yaw in radians); whitespace around components is
34
+ * tolerated. A non-finite or short tuple yields `null` so a typo never silently teleports the
35
+ * player to `NaN`.
36
+ */
37
+ export declare function parseSpawnOverride(raw: string | null | undefined): SpawnOverride | null;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Per-session player-spawn override — a capture-harness ergonomics seam that lets a single
3
+ * screenshot or drive run place the player somewhere other than the authored `player_spawn`
4
+ * marker *without mutating `editor.scene.json`*. The runner installs one from the `?spawn=` URL
5
+ * overlay (mirroring `?cam=`); {@link authoredSpawnPosition} consults it for the default
6
+ * player-spawn resolution only, so authored content is untouched and the override evaporates the
7
+ * moment the page reloads without the param.
8
+ *
9
+ * Genre-agnostic: it moves whatever a game treats as its player spawn. It never changes markers of
10
+ * other kinds or an explicit marker `id`, so an override taken for a close-up cannot perturb enemy
11
+ * or prop placement queries that share {@link authoredSpawnPosition}.
12
+ *
13
+ * Install-style module state is the established runner pattern here (`installAssetBase`,
14
+ * `installEditorHost`, `installSaveEndpoint`); the default is `null`, so nothing changes and every
15
+ * pure query stays deterministic until a runner explicitly installs an override.
16
+ */
17
+ let installed = null;
18
+ /** Install (or, with `null`, clear) the active player-spawn override. Idempotent; last write wins. */
19
+ export function installSpawnOverride(override) {
20
+ installed = override;
21
+ }
22
+ /** Clear any installed player-spawn override. */
23
+ export function clearSpawnOverride() {
24
+ installed = null;
25
+ }
26
+ /** The currently installed player-spawn override, or `null` when none is active. */
27
+ export function readSpawnOverride() {
28
+ return installed;
29
+ }
30
+ /**
31
+ * Parse a `?spawn=` / `--spawn` value into a {@link SpawnOverride}, or `null` when it is absent or
32
+ * malformed. Accepts `"x,y,z"` and `"x,y,z,yaw"` (yaw in radians); whitespace around components is
33
+ * tolerated. A non-finite or short tuple yields `null` so a typo never silently teleports the
34
+ * player to `NaN`.
35
+ */
36
+ export function parseSpawnOverride(raw) {
37
+ if (raw === null || raw === undefined)
38
+ return null;
39
+ const parts = raw
40
+ .split(",")
41
+ .map((part) => part.trim())
42
+ .filter((part) => part.length > 0);
43
+ if (parts.length < 3 || parts.length > 4)
44
+ return null;
45
+ const nums = parts.map((part) => Number(part));
46
+ if (nums.some((value) => !Number.isFinite(value)))
47
+ return null;
48
+ const [x, y, z, rotationY] = nums;
49
+ return rotationY === undefined ? { x, y, z } : { x, y, z, rotationY };
50
+ }
@@ -25,6 +25,10 @@ export interface StreetEdge {
25
25
  level: StreetLevel;
26
26
  /** True when this edge belongs to the main closed loop (circuit mode). */
27
27
  loop: boolean;
28
+ /** Per-point road-surface height (one per `points`), present only when `elevation > 0`. Raw
29
+ * (uncapped) samples of {@link StreetNetwork.elevationAt}; the grade-limited profile lives on the
30
+ * owning {@link Street.heights}. */
31
+ heights?: number[];
28
32
  }
29
33
  /** A feature span carried by a street: a `[from, to]` index window into the street's `points`. */
30
34
  export interface StreetFeatureSpan {
@@ -34,12 +38,19 @@ export interface StreetFeatureSpan {
34
38
  /** Ground height at each bank/portal — the deck/floor reference the renderer drapes to. */
35
39
  bankHeight: number;
36
40
  }
41
+ /** Left/right pedestrian bands flanking a street's asphalt, as offset polylines. */
42
+ export interface StreetSidewalks {
43
+ /** Polyline offset to the left of travel (parallel to `points`). */
44
+ left: StreetVec2[];
45
+ /** Polyline offset to the right of travel. */
46
+ right: StreetVec2[];
47
+ }
37
48
  /** One chained through-street: a maximal run of edges through degree-2 nodes, for rendering + furniture. */
38
49
  export interface Street {
39
50
  id: number;
40
51
  /** Ordered node ids the chain visits; first === last when `loop`. */
41
52
  nodes: number[];
42
- /** Smoothed, turn-clamped centerline. */
53
+ /** Smoothed, arc-filleted centerline. */
43
54
  points: StreetVec2[];
44
55
  width: number;
45
56
  level: StreetLevel;
@@ -49,6 +60,12 @@ export interface Street {
49
60
  bulb?: StreetVec2;
50
61
  /** Bridge/tunnel spans along this street, if any. */
51
62
  features: StreetFeatureSpan[];
63
+ /** Flanking pedestrian bands, present on boulevard/avenue/street levels (not lanes). */
64
+ sidewalks?: StreetSidewalks;
65
+ /** Per-point road-surface height (one per `points`), present only when `elevation > 0`. Grade-limited
66
+ * so no consecutive pair exceeds `maxGrade`; a loop stays continuous (`heights[0] === heights.at(-1)`).
67
+ * This is ROAD elevation, not the `context.heightAt` terrain that drives bridges/tunnels. */
68
+ heights?: number[];
52
69
  }
53
70
  /** One crossing of three or more streets: patch center/radius plus outgoing arm directions. */
54
71
  export interface StreetJunction {
@@ -92,36 +109,60 @@ export interface StreetNetwork {
92
109
  tunnels: StreetFeature[];
93
110
  /** Independent cycle count (E − V + components): 0 = pure tree, ≥1 = has loops. */
94
111
  loops: number;
112
+ /** The shared road-surface height FIELD (volume-local), present only when `elevation > 0`. Sample it
113
+ * to drape junction welds, sidewalks, and building bases so every surface meets the road continuously
114
+ * — the streets/edges sample this exact field. Distinct from the `context.heightAt` terrain sampler. */
115
+ elevationAt?: (x: number, z: number) => number;
95
116
  }
96
117
  /** Fully-defaulted slider set the generator reads. */
97
118
  export interface StreetNetworkRules {
98
119
  seed: string;
120
+ /** Organic boundary clipping amount, when supported by the caller. */
121
+ outline?: number;
99
122
  /** 1 = regular lattice nodes; 0 = organic scatter. */
100
123
  gridness: number;
101
124
  /** 0 = tree (dead-ends); 1 = a single closed circuit. */
102
125
  loopiness: number;
103
126
  /** Extra chord edges between neighbors → mesh density. */
104
127
  connectivity: number;
105
- /** Spur-lane density forking off the mains. */
128
+ /** Spur-lane density forking off the mains (and, in a circuit, the pit-lane trigger). */
106
129
  branching: number;
130
+ /** Share of branch streets that use residential side-street rules. */
131
+ residentialBranches?: number;
107
132
  /** Fraction of dangling ends kept as cul-de-sacs (vs reconnected). */
108
133
  deadEnds: number;
109
134
  /** Target node spacing / block size, world units. */
110
135
  segmentLength: number;
111
136
  /** Cross-axis spacing multiplier (≥1 = long skinny Manhattan blocks). */
112
137
  aspect: number;
113
- /** Sideways wander amplitude, 0..1. */
138
+ /** Sideways wander amplitude, 0..1 (and circuit corner-template density). */
114
139
  winding: number;
115
- /** Minimum curve radius (m) — caps wander curvature and corner tightness. */
140
+ /** Minimum curve radius (m) — caps wander curvature and sets the corner-fillet radius. */
116
141
  minCurveRadius: number;
117
142
  /** Shallowest corner (degrees) a street keeps — gentler bends are straightened. */
118
143
  minTurnAngle: number;
119
- /** Sharpest corner (degrees) a street may take — tighter ones are beveled away. */
144
+ /** Sharpest corner (degrees) between consecutive centerline samples — sharper corners are filleted. */
120
145
  maxTurnAngle: number;
121
146
  /** Base street width; the hierarchy scales off it. */
122
147
  width: number;
123
148
  /** Share of avenues upgraded to boulevards, 0..1. */
124
149
  boulevards: number;
150
+ /** Pedestrian band width paved on each side of boulevard/avenue/street levels. Default ~2. */
151
+ sidewalkWidth?: number;
152
+ /** Road-surface relief amplitude, 0..1. 0 (default) = dead flat and byte-identical to a pre-elevation
153
+ * network; 1 ≈ 22 m of relief across a ~520 m volume (scaled to the footprint). */
154
+ elevation?: number;
155
+ /** Maximum road slope (rise/run) the grade cap enforces on every street's height sequence. Default 0.07. */
156
+ maxGrade?: number;
157
+ /** SPACE-FILLING circuit layout dial, 0..1. 0 (default) = the hull construction (a flowing loop around
158
+ * an empty middle), BYTE-IDENTICAL to a pre-compactness network. Rising values switch the circuit
159
+ * LAYOUT stage to a grid spanning-tree CYCLE that folds back through its own interior: parallel
160
+ * adjacent runs one corridor pitch apart, switchback esses, consecutive hairpins, and long straights
161
+ * from straight tree branches, with footprint coverage rising with the dial (~45% of grid cells at
162
+ * 0.5, ~85% at 1). Everything downstream — spline fit, curvature floor, straight designation,
163
+ * self-clearance, edge distribution, elevation, pit lane — is reused unchanged. Only meaningful in
164
+ * circuit mode; ignored by the street net. */
165
+ compactness?: number;
125
166
  }
126
167
  /** Ground sampler + feature toggles enabling bridges/tunnels; omit for a flat, feature-free network. */
127
168
  export interface StreetNetworkContext {
@@ -137,13 +178,21 @@ export interface StreetNetworkContext {
137
178
  tunnelClearance?: number;
138
179
  }
139
180
  /**
140
- * Hard turn-angle clamp on a polyline with fixed endpoints: interior corners gentler than `minRad`
141
- * are straightened away (deliberate winding only, no micro-wiggle) and corners sharper than `maxRad`
142
- * are beveled — the corner vertex is replaced by two points pulled back along each leg, which
143
- * strictly reduces the angle. Endpoints never move, so a graph node stays welded.
181
+ * Replace every real corner of a polyline with a sampled **circular-arc fillet** so bends read as
182
+ * smooth curves instead of polygonal notches, while enforcing two hard limits with fixed endpoints:
183
+ * interior corners gentler than `minRad` are straightened away (deliberate winding only, no
184
+ * micro-wiggle), and each remaining corner is rounded with an arc of radius `curveRadius` (clamped to
185
+ * half the shorter adjacent leg) sampled finely enough that no discrete turn between consecutive
186
+ * samples exceeds `maxRad` — a corner sharper than the ceiling is still reduced, now to a fillet
187
+ * rather than a bevel. Open-chain endpoints never move (a graph node stays welded); pass `closed` for
188
+ * a ring (first === last) so its wrap corner is filleted too and the loop stays closed.
189
+ *
190
+ * Pass `radiusFor` to vary the fillet radius PER CORNER (returning the target radius from the corner's
191
+ * deflection and adjacent leg lengths) instead of the single `curveRadius` — the circuit loop uses this
192
+ * to mix hairpins, standard corners, and sweepers; every other caller keeps the scalar radius.
144
193
  * @internal
145
194
  */
146
- export declare function clampTurns(points: readonly StreetVec2[], minRad: number, maxRad: number): StreetVec2[];
195
+ export declare function clampTurns(points: readonly StreetVec2[], minRad: number, maxRad: number, curveRadius?: number, closed?: boolean, radiusFor?: (deflection: number, la: number, lb: number) => number): StreetVec2[];
147
196
  /** Decide which topology family the sliders call for. Circuit wins when loops dominate and both
148
197
  * branching and mesh connectivity are low — exactly the "race track" corner of the slider space.
149
198
  * @internal */
@@ -154,6 +203,6 @@ export declare function streetNetworkMode(rules: StreetNetworkRules): StreetNetw
154
203
  * water gaps into bridges and ridges into tunnels. Coordinates are volume-local; the caller maps to
155
204
  * world space.
156
205
  *
157
- * @capability street-generator build a deterministic street/track graph (nodes, edges, streets, junctions, bridges, tunnels) from sliders
206
+ * @capability street-generator build a deterministic street/track graph (nodes, edges, streets, junctions, sidewalks, bridges, tunnels) from sliders
158
207
  */
159
208
  export declare function generateStreets(rules: StreetNetworkRules, hx: number, hz: number, context?: StreetNetworkContext): StreetNetwork;