@jgengine/core 0.18.0 → 0.19.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 +265 -2
- package/dist/ai/decisionGraph.d.ts +96 -0
- package/dist/ai/decisionGraph.js +212 -0
- package/dist/ai/groupAssist.d.ts +10 -0
- package/dist/ai/groupAssist.js +11 -0
- package/dist/ai/mobBrainGraph.d.ts +3 -0
- package/dist/ai/mobBrainGraph.js +25 -0
- package/dist/ai/pursuit.d.ts +1 -1
- package/dist/ai/pursuit.js +1 -1
- package/dist/ai/tacticalQueries.d.ts +30 -0
- package/dist/ai/tacticalQueries.js +45 -0
- package/dist/ai/threat.d.ts +8 -0
- package/dist/ai/threat.js +10 -0
- package/dist/anim/animGraph.d.ts +155 -0
- package/dist/anim/animGraph.js +414 -0
- package/dist/anim/boneTexture.d.ts +55 -0
- package/dist/anim/boneTexture.js +43 -0
- package/dist/anim/footPlacement.d.ts +57 -0
- package/dist/anim/footPlacement.js +67 -0
- package/dist/anim/ikSolver.d.ts +51 -0
- package/dist/anim/ikSolver.js +124 -0
- package/dist/anim/locomotionGraph.d.ts +35 -0
- package/dist/anim/locomotionGraph.js +62 -0
- package/dist/assets/spriteAtlas.d.ts +21 -0
- package/dist/assets/spriteAtlas.js +103 -0
- package/dist/audio/audioFalloff.d.ts +12 -0
- package/dist/audio/doppler.d.ts +21 -0
- package/dist/audio/doppler.js +32 -0
- package/dist/audio/engineLayers.d.ts +83 -0
- package/dist/audio/engineLayers.js +115 -0
- package/dist/combat/abilityKit.d.ts +1 -0
- package/dist/combat/abilityKit.js +1 -0
- package/dist/combat/death.d.ts +7 -0
- package/dist/combat/shotOrigin.d.ts +6 -0
- package/dist/combat/shotOrigin.js +6 -0
- package/dist/combat/weaponFeedback.d.ts +36 -0
- package/dist/combat/weaponFeedback.js +42 -0
- package/dist/combat/weaponHandling.d.ts +161 -0
- package/dist/combat/weaponHandling.js +202 -0
- package/dist/combat/weaponPresentation.d.ts +115 -0
- package/dist/combat/weaponPresentation.js +96 -0
- package/dist/devtools/warnOnce.d.ts +8 -0
- package/dist/devtools/warnOnce.js +18 -0
- package/dist/economy/currency.d.ts +16 -2
- package/dist/economy/currency.js +55 -14
- package/dist/economy/wallet.d.ts +5 -4
- package/dist/economy/wallet.js +8 -4
- package/dist/editor/commandApply.js +1 -0
- package/dist/editor/commands.d.ts +4 -1
- package/dist/editor/document.d.ts +2 -1
- package/dist/editor/document.js +92 -1
- package/dist/editor/environment.d.ts +3 -0
- package/dist/editor/environment.js +24 -0
- package/dist/editor/index.d.ts +4 -2
- package/dist/editor/index.js +1 -1
- package/dist/editor/types.d.ts +20 -0
- package/dist/faction/reputation.d.ts +6 -0
- package/dist/faction/reputation.js +11 -0
- package/dist/game/cameraConfig.d.ts +59 -1
- package/dist/game/chat.d.ts +22 -1
- package/dist/game/chat.js +48 -19
- package/dist/game/controlGate.d.ts +6 -0
- package/dist/game/controlGate.js +30 -1
- package/dist/game/defineGame.d.ts +10 -1
- package/dist/game/events.d.ts +14 -1
- package/dist/game/lootTable.d.ts +4 -0
- package/dist/game/lootTable.js +16 -0
- package/dist/game/pixelPerfect.d.ts +25 -0
- package/dist/game/pixelPerfect.js +29 -0
- package/dist/game/playableGame.d.ts +167 -6
- package/dist/game/systemRuntime.js +6 -1
- package/dist/game/toasts.d.ts +8 -0
- package/dist/game/toasts.js +7 -0
- package/dist/game/vfxInstance.d.ts +9 -0
- package/dist/game/vfxInstance.js +12 -1
- package/dist/game/viewports.d.ts +43 -0
- package/dist/game/viewports.js +46 -0
- package/dist/game/worldItem.d.ts +5 -1
- package/dist/game/worldItem.js +0 -1
- package/dist/input/actionBindings.d.ts +17 -2
- package/dist/input/actionBindings.js +24 -11
- package/dist/input/actionContexts.d.ts +45 -0
- package/dist/input/actionContexts.js +113 -0
- package/dist/input/axisInput.d.ts +4 -0
- package/dist/input/axisInput.js +4 -0
- package/dist/input/axisShaper.d.ts +73 -0
- package/dist/input/axisShaper.js +105 -0
- package/dist/input/gamepadModel.d.ts +79 -0
- package/dist/input/gamepadModel.js +108 -0
- package/dist/input/haptics.d.ts +50 -0
- package/dist/input/haptics.js +74 -0
- package/dist/input/inputBuffer.d.ts +40 -0
- package/dist/input/inputBuffer.js +59 -0
- package/dist/input/lookChannel.d.ts +10 -0
- package/dist/input/lookChannel.js +6 -0
- package/dist/input/pointer.d.ts +2 -0
- package/dist/input/pointer.js +4 -0
- package/dist/item/affix.d.ts +6 -0
- package/dist/item/affix.js +6 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +196 -1
- package/dist/movement/characterController.d.ts +76 -0
- package/dist/movement/characterController.js +216 -0
- package/dist/movement/freeFlight.d.ts +119 -0
- package/dist/movement/freeFlight.js +294 -0
- package/dist/movement/glideModel.d.ts +3 -0
- package/dist/movement/glideModel.js +6 -0
- package/dist/movement/grappleSwing.d.ts +2 -0
- package/dist/movement/grappleSwing.js +5 -1
- package/dist/movement/movementModel.d.ts +39 -0
- package/dist/movement/movementModel.js +62 -19
- package/dist/movement/movementProbe.d.ts +51 -0
- package/dist/movement/movementProbe.js +119 -0
- package/dist/movement/playerMovement.d.ts +30 -3
- package/dist/movement/playerMovement.js +304 -7
- package/dist/movement/serverStep.d.ts +5 -0
- package/dist/movement/serverStep.js +6 -0
- package/dist/movement/solidObstacles.d.ts +39 -8
- package/dist/movement/solidObstacles.js +71 -6
- package/dist/movement/voxelController.js +7 -7
- package/dist/multiplayer/poseSyncGate.d.ts +3 -1
- package/dist/multiplayer/poseSyncGate.js +9 -1
- package/dist/multiplayer/presenceContract.d.ts +6 -0
- package/dist/multiplayer/presenceModel.d.ts +2 -0
- package/dist/multiplayer/presenceModel.js +11 -0
- package/dist/nav/navFromEnvironment.d.ts +9 -3
- package/dist/nav/navFromEnvironment.js +18 -12
- package/dist/nav/navMesh.d.ts +74 -0
- package/dist/nav/navMesh.js +570 -0
- package/dist/physics/aircraftDynamics.d.ts +390 -0
- package/dist/physics/aircraftDynamics.js +704 -0
- package/dist/physics/boatDynamics.d.ts +116 -0
- package/dist/physics/boatDynamics.js +160 -0
- package/dist/physics/drivableVehicle.d.ts +22 -8
- package/dist/physics/drivableVehicle.js +4 -2
- package/dist/physics/flightDynamics.d.ts +29 -4
- package/dist/physics/flightDynamics.js +28 -5
- package/dist/physics/handlingProbe.d.ts +249 -0
- package/dist/physics/handlingProbe.js +606 -0
- package/dist/physics/kinematicVehicle.d.ts +37 -2
- package/dist/physics/kinematicVehicle.js +15 -0
- package/dist/physics/physicsBackend.d.ts +203 -0
- package/dist/physics/physicsBackend.js +49 -0
- package/dist/physics/physicsBackendConformance.d.ts +27 -0
- package/dist/physics/physicsBackendConformance.js +151 -0
- package/dist/physics/physicsWorldBackend.d.ts +45 -0
- package/dist/physics/physicsWorldBackend.js +518 -0
- package/dist/physics/vehicleBackendLink.d.ts +49 -0
- package/dist/physics/vehicleBackendLink.js +102 -0
- package/dist/physics/vehicleDynamics.d.ts +374 -0
- package/dist/physics/vehicleDynamics.js +737 -0
- package/dist/physics/worldColliders.d.ts +13 -0
- package/dist/physics/worldColliders.js +128 -0
- package/dist/puzzle/cellGrid.d.ts +15 -9
- package/dist/puzzle/cellGrid.js +13 -9
- package/dist/random/rng.d.ts +12 -1
- package/dist/random/rng.js +20 -3
- package/dist/render/environment.d.ts +23 -0
- package/dist/render/environment.js +1 -0
- package/dist/render/lookPreset.d.ts +19 -6
- package/dist/render/lookPreset.js +56 -4
- package/dist/render/postProcessing.d.ts +40 -1
- package/dist/render/postProcessing.js +1 -1
- package/dist/render/sprite2d.d.ts +38 -0
- package/dist/render/sprite2d.js +40 -0
- package/dist/runtime/adapter.d.ts +20 -1
- package/dist/runtime/adapter.js +8 -1
- package/dist/runtime/cameraDirector.d.ts +17 -3
- package/dist/runtime/cameraDirector.js +25 -0
- package/dist/runtime/commandInput.d.ts +52 -0
- package/dist/runtime/commandInput.js +71 -0
- package/dist/runtime/commandRunner.d.ts +39 -7
- package/dist/runtime/commandRunner.js +35 -5
- package/dist/runtime/context/combat.d.ts +1 -0
- package/dist/runtime/context/combat.js +2 -1
- package/dist/runtime/context/deathLoot.d.ts +2 -0
- package/dist/runtime/context/deathLoot.js +1 -0
- package/dist/runtime/gameContext.js +18 -1
- package/dist/runtime/gameContextTypes.d.ts +33 -7
- package/dist/runtime/gameRuntime.d.ts +23 -5
- package/dist/runtime/gameRuntime.js +21 -4
- package/dist/runtime/headlessRunner.d.ts +10 -0
- package/dist/runtime/headlessRunner.js +26 -8
- package/dist/runtime/hostPolicy.d.ts +3 -2
- package/dist/runtime/hostPolicy.js +8 -10
- package/dist/runtime/hostedGameRunner.js +34 -6
- package/dist/runtime/hostedWorldSession.d.ts +12 -16
- package/dist/runtime/hostedWorldSession.js +29 -6
- package/dist/runtime/hostedWorldStore.d.ts +20 -0
- package/dist/runtime/hostedWorldStore.js +1 -0
- package/dist/runtime/inputRecorder.d.ts +30 -0
- package/dist/runtime/inputRecorder.js +59 -0
- package/dist/runtime/inputSnapshot.d.ts +14 -0
- package/dist/runtime/inputSnapshot.js +11 -0
- package/dist/runtime/localPlayers.d.ts +73 -0
- package/dist/runtime/localPlayers.js +119 -0
- package/dist/runtime/poseInterpolation.d.ts +36 -0
- package/dist/runtime/poseInterpolation.js +91 -0
- package/dist/runtime/prediction.d.ts +45 -0
- package/dist/runtime/prediction.js +62 -0
- package/dist/runtime/simContext.d.ts +45 -0
- package/dist/runtime/simContext.js +65 -0
- package/dist/runtime/simLoop.d.ts +52 -0
- package/dist/runtime/simLoop.js +72 -0
- package/dist/runtime/simSnapshot.d.ts +32 -0
- package/dist/runtime/simSnapshot.js +60 -0
- package/dist/runtime/snapshot.d.ts +8 -0
- package/dist/runtime/snapshotBuffer.d.ts +33 -0
- package/dist/runtime/snapshotBuffer.js +58 -0
- package/dist/runtime/transport.d.ts +41 -2
- package/dist/runtime/transport.js +7 -1
- package/dist/runtime/worldChunks.d.ts +2 -0
- package/dist/runtime/worldChunks.js +14 -0
- package/dist/runtime/worldProjection.d.ts +9 -0
- package/dist/runtime/worldProjection.js +17 -1
- package/dist/runtime/worldSnapshot.d.ts +6 -0
- package/dist/runtime/worldSnapshot.js +3 -0
- package/dist/scene/behaviorRuntime.d.ts +29 -1
- package/dist/scene/behaviorRuntime.js +71 -4
- package/dist/scene/behaviors.d.ts +12 -1
- package/dist/scene/builtinSceneKinds.js +10 -0
- package/dist/scene/sceneKinds.d.ts +9 -0
- package/dist/scene/vehicleSeat.d.ts +5 -1
- package/dist/scene/vehicleSeat.js +5 -1
- package/dist/sensor/concealment.d.ts +6 -0
- package/dist/sensor/concealment.js +8 -0
- package/dist/sensor/freezeMonitor.d.ts +6 -0
- package/dist/sensor/freezeMonitor.js +8 -0
- package/dist/sensor/perception.d.ts +70 -0
- package/dist/sensor/perception.js +189 -0
- package/dist/sensor/recordingBuffer.d.ts +3 -0
- package/dist/sensor/recordingBuffer.js +8 -0
- package/dist/session/roundState.d.ts +4 -0
- package/dist/session/roundState.js +11 -0
- package/dist/settings/frameRateLimit.d.ts +16 -0
- package/dist/settings/frameRateLimit.js +37 -0
- package/dist/settings/graphicsProfile.d.ts +21 -0
- package/dist/settings/graphicsProfile.js +48 -0
- package/dist/settings/graphicsSettings.d.ts +40 -0
- package/dist/settings/graphicsSettings.js +81 -0
- package/dist/settings/settingsModel.d.ts +9 -1
- package/dist/settings/settingsModel.js +10 -0
- package/dist/stats/eventMeter.d.ts +1 -1
- package/dist/stats/eventMeter.js +1 -1
- package/dist/time/accrueSince.d.ts +10 -0
- package/dist/time/accrueSince.js +9 -0
- package/dist/time/rateWindow.d.ts +16 -0
- package/dist/time/rateWindow.js +14 -0
- package/dist/time/serverTick.d.ts +21 -3
- package/dist/time/serverTick.js +14 -13
- package/dist/vfx/feedbackMixer.d.ts +61 -0
- package/dist/vfx/feedbackMixer.js +106 -0
- package/dist/vfx/particleDirector.d.ts +68 -0
- package/dist/vfx/particleDirector.js +81 -0
- package/dist/visibility/simulationCulling.d.ts +8 -1
- package/dist/visibility/simulationCulling.js +7 -0
- package/dist/visibility/spatialIndex.d.ts +21 -0
- package/dist/visibility/spatialIndex.js +16 -0
- package/dist/world/authoredSolids.d.ts +46 -0
- package/dist/world/authoredSolids.js +75 -0
- package/dist/world/buildingGenerator.js +2 -2
- package/dist/world/buildingKit.d.ts +3 -1
- package/dist/world/buildings.d.ts +46 -2
- package/dist/world/buildings.js +53 -3
- package/dist/world/cityContent.js +103 -25
- package/dist/world/cityKind.d.ts +139 -0
- package/dist/world/cityKind.js +367 -16
- package/dist/world/features.d.ts +56 -3
- package/dist/world/features.js +13 -2
- package/dist/world/footprintGrid.d.ts +7 -0
- package/dist/world/footprintGrid.js +16 -0
- package/dist/world/interiors.d.ts +1 -0
- package/dist/world/interiors.js +5 -3
- package/dist/world/lod.d.ts +6 -0
- package/dist/world/lod.js +8 -0
- package/dist/world/placement.d.ts +7 -0
- package/dist/world/placement.js +2 -0
- package/dist/world/placementController.d.ts +1 -1
- package/dist/world/placementController.js +7 -0
- package/dist/world/raceCircuit.d.ts +168 -0
- package/dist/world/raceCircuit.js +797 -0
- package/dist/world/terraform.d.ts +8 -0
- package/dist/world/terraform.js +7 -0
- package/dist/world/terrain.d.ts +5 -1
- package/dist/world/terrain.js +5 -0
- package/dist/world/territory.d.ts +97 -0
- package/dist/world/territory.js +182 -0
- package/dist/world/walls.d.ts +7 -0
- package/dist/world/walls.js +7 -0
- package/dist/world/worldSolids.d.ts +84 -0
- package/dist/world/worldSolids.js +240 -0
- package/dist/world.d.ts +5 -3
- package/dist/world.js +4 -2
- package/package.json +1 -1
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/game-design/SKILL.md +11 -1
- package/skills/jgengine/SKILL.md +9 -5
- package/skills/jgengine/api.md +205 -101
- package/skills/jgengine/capabilities.md +56 -0
- package/skills/jgengine/recipes/minimal-game.md +3 -0
- package/skills/jgengine-combat/SKILL.md +5 -0
- package/skills/jgengine-combat/api.md +138 -103
- package/skills/jgengine-combat/capabilities.md +29 -1
- package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
- package/skills/jgengine-gameplay/SKILL.md +10 -0
- package/skills/jgengine-gameplay/api.md +501 -453
- package/skills/jgengine-gameplay/capabilities.md +36 -0
- package/skills/jgengine-gameplay/reference-systems.md +4 -0
- package/skills/jgengine-world/SKILL.md +21 -3
- package/skills/jgengine-world/api.md +1172 -625
- package/skills/jgengine-world/capabilities.md +229 -3
- package/skills/jgengine-world/recipes/character-animation.md +39 -0
- package/skills/jgengine-world/recipes/controls.md +44 -0
- package/skills/jgengine-world/recipes/flight-feel.md +76 -0
- package/skills/jgengine-world/recipes/npc-senses.md +43 -0
- package/skills/jgengine-world/recipes/vehicle-feel.md +85 -0
- package/skills/jgengine-world/reference.md +31 -2
- package/skills/jgengine-world/visibility.md +112 -0
package/dist/world/features.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { AvoidZone } from "./geometry.js";
|
|
|
4
4
|
import type { TerrainPathProfile } from "./pathTerrain.js";
|
|
5
5
|
import type { PlaceWorldFeature } from "./place.js";
|
|
6
6
|
import type { TerraformSnapshot } from "./terraform.js";
|
|
7
|
+
import type { SpriteAtlas } from "../assets/spriteAtlas.js";
|
|
7
8
|
import type { VolumetricCloudsConfig } from "./volumetricClouds.js";
|
|
8
9
|
export interface WorldBounds {
|
|
9
10
|
w: number;
|
|
@@ -48,6 +49,16 @@ export interface TerrainDetailConfig {
|
|
|
48
49
|
roughness?: number;
|
|
49
50
|
/** Overall detail intensity 0..1. Default 1. */
|
|
50
51
|
strength?: number;
|
|
52
|
+
/**
|
|
53
|
+
* RGB multipliers for the two macro colour sweeps painted over the base ground. `dry` tints the
|
|
54
|
+
* sun-bleached patches, `wet` the cooler pockets between them. The defaults ([1.14, 1.05, 0.76]
|
|
55
|
+
* and [0.78, 1.0, 0.86]) suit temperate meadows; the green-leaning `wet` default paints mossy
|
|
56
|
+
* pockets onto any biome that keeps it, so arid/ashen worlds should supply warm or neutral tints.
|
|
57
|
+
*/
|
|
58
|
+
sweeps?: {
|
|
59
|
+
dry?: readonly [number, number, number];
|
|
60
|
+
wet?: readonly [number, number, number];
|
|
61
|
+
};
|
|
51
62
|
/** Real PBR texture maps blended over the procedural detail — the seam for `@jgengine/assets` `buildMaterialCatalog` output. Omit to keep the procedural-only look. */
|
|
52
63
|
material?: TerrainDetailMaterialConfig;
|
|
53
64
|
}
|
|
@@ -259,6 +270,14 @@ export interface GrassEnvironmentConfig {
|
|
|
259
270
|
windStrength?: number;
|
|
260
271
|
colors?: readonly string[];
|
|
261
272
|
seed?: string;
|
|
273
|
+
/** Blade curl range (arc amount, min..max). Shell default [0.12, 0.42] — raise for wind-combed scrub, lower for stiff turf. */
|
|
274
|
+
bladeBend?: readonly [number, number];
|
|
275
|
+
/** Tuft spread radius in meters — how far a clump's blades splay from its root. Shell default 0.16; wider reads as bushy clumps rather than lone blades. */
|
|
276
|
+
tuftRadius?: number;
|
|
277
|
+
/** Per-tuft brightness jitter 0..1 (shell default 0.28) — higher breaks up the field so it never reads as one repeated blade. */
|
|
278
|
+
colorVariation?: number;
|
|
279
|
+
/** 0..1 blend of blade normals toward straight-up (shell default 0.6). Low values light each blade plane individually and go dark when side-lit; high values light the field like a soft carpet. */
|
|
280
|
+
normalLift?: number;
|
|
262
281
|
}
|
|
263
282
|
export interface OceanEnvironmentConfig {
|
|
264
283
|
bounds?: WorldBounds;
|
|
@@ -277,16 +296,38 @@ export interface OceanEnvironmentConfig {
|
|
|
277
296
|
waveSpeed?: number;
|
|
278
297
|
color?: string;
|
|
279
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Where the sun sits, as a compass bearing and a height above the horizon, both in degrees.
|
|
301
|
+
* `azimuth` 0 points toward -Z (north), 90 toward +X (east); `elevation` 90 is straight overhead.
|
|
302
|
+
*/
|
|
303
|
+
export interface SkySunConfig {
|
|
304
|
+
/** Compass bearing of the sun in degrees; 0 = -Z, 90 = +X. Default 0. */
|
|
305
|
+
azimuth?: number;
|
|
306
|
+
/** Height above the horizon in degrees; 0 sits on the horizon, 90 is overhead. Default 68. */
|
|
307
|
+
elevation?: number;
|
|
308
|
+
}
|
|
280
309
|
export interface SkyEnvironmentConfig {
|
|
281
310
|
/** Fixed look used when `timeOfDay` is off (or no clock is available); default "day". */
|
|
282
311
|
preset?: "day" | "dusk" | "night";
|
|
283
312
|
/** Drive sun/sky from the world clock's `calendar().dayFraction` instead of the fixed `preset`. */
|
|
284
313
|
timeOfDay?: boolean;
|
|
314
|
+
/**
|
|
315
|
+
* Horizon tint at noon. Under `timeOfDay` this only sets the noon keyframe; dawn, dusk, and night
|
|
316
|
+
* still crossfade through the engine presets, so an authored tint is visible for part of the day.
|
|
317
|
+
*/
|
|
285
318
|
horizonColor?: string;
|
|
319
|
+
/** Zenith tint at noon; same `timeOfDay` crossfade caveat as `horizonColor`. */
|
|
286
320
|
zenithColor?: string;
|
|
287
321
|
sunIntensity?: number;
|
|
288
322
|
ambientIntensity?: number;
|
|
289
|
-
/**
|
|
323
|
+
/**
|
|
324
|
+
* Sun placement for the dome glow and the sky-owned sun light. With a fixed `preset` this is the
|
|
325
|
+
* sun's exact direction; under `timeOfDay` it is where the sun stands at noon and the day arc
|
|
326
|
+
* swings around that bearing. Unset with an authored `lighting.directional` light, the shell takes
|
|
327
|
+
* the first directional light's direction so the dome sun agrees with the shadows.
|
|
328
|
+
*/
|
|
329
|
+
sun?: SkySunConfig;
|
|
330
|
+
/** Sky-dome sphere radius in world units. Enlarge for a playfield sited far from the origin so the viewer never exits the dome. Must stay below the camera far plane or the dome depth-clips to black. Default 260. */
|
|
290
331
|
radius?: number;
|
|
291
332
|
/** Horizon haze-band strength: 0 removes the dusty band, ~1 makes it heavy. Default 0.5. */
|
|
292
333
|
hazeStrength?: number;
|
|
@@ -358,6 +399,11 @@ export interface BuildingEnvironmentConfig {
|
|
|
358
399
|
* untextured block; without a kit the whole facade stays blocks, as before.
|
|
359
400
|
*/
|
|
360
401
|
kit?: BuildingKit;
|
|
402
|
+
/**
|
|
403
|
+
* Whether the buildings block movement and physics through `ctx.world.solids` (default `true`).
|
|
404
|
+
* `false` keeps them render-only, e.g. a distant skyline nobody can reach.
|
|
405
|
+
*/
|
|
406
|
+
solid?: boolean;
|
|
361
407
|
}
|
|
362
408
|
export type PadSize = readonly [number, number] | {
|
|
363
409
|
radius: number;
|
|
@@ -393,13 +439,13 @@ export type SnowEnvironmentDescriptor = {
|
|
|
393
439
|
} & Required<Pick<SnowEnvironmentConfig, "area" | "density" | "speed" | "flakeSize" | "drift" | "wind" | "color" | "opacity">>;
|
|
394
440
|
export type GrassEnvironmentDescriptor = {
|
|
395
441
|
kind: "grass";
|
|
396
|
-
} & Required<Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors">> & Pick<GrassEnvironmentConfig, "seed">;
|
|
442
|
+
} & Required<Pick<GrassEnvironmentConfig, "area" | "density" | "bladeHeight" | "bladeWidth" | "windStrength" | "colors">> & Pick<GrassEnvironmentConfig, "seed" | "bladeBend" | "tuftRadius" | "colorVariation" | "normalLift">;
|
|
397
443
|
export type OceanEnvironmentDescriptor = {
|
|
398
444
|
kind: "ocean";
|
|
399
445
|
} & Required<Pick<OceanEnvironmentConfig, "bounds" | "level" | "waveHeight" | "waveScale" | "waveSpeed" | "color">> & Pick<OceanEnvironmentConfig, "position" | "levelAt">;
|
|
400
446
|
export type BuildingEnvironmentDescriptor = {
|
|
401
447
|
kind: "building";
|
|
402
|
-
} & Required<Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style">> & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit">;
|
|
448
|
+
} & Required<Pick<BuildingEnvironmentConfig, "count" | "footprint" | "stories" | "storyHeight" | "spacing" | "style">> & Pick<BuildingEnvironmentConfig, "seed" | "position" | "palette" | "along" | "kit" | "solid">;
|
|
403
449
|
export type PadEnvironmentDescriptor = {
|
|
404
450
|
kind: "pad";
|
|
405
451
|
} & Required<Pick<PadEnvironmentConfig, "center" | "size" | "height" | "color">> & Pick<PadEnvironmentConfig, "rotationY" | "elevation">;
|
|
@@ -519,6 +565,13 @@ export interface PlotsWorldConfig extends WorldGridConfig {
|
|
|
519
565
|
}
|
|
520
566
|
export interface TilemapWorldConfig extends WorldGridConfig {
|
|
521
567
|
map: string;
|
|
568
|
+
/** Atlas-backed tile rendering; cell glyphs map to atlas frame ids. */
|
|
569
|
+
tileSet?: {
|
|
570
|
+
atlas: SpriteAtlas;
|
|
571
|
+
tiles: Record<string, string>;
|
|
572
|
+
};
|
|
573
|
+
/** Render ordering key consumed by the shell tile renderer. */
|
|
574
|
+
sortingLayer?: string;
|
|
522
575
|
}
|
|
523
576
|
/**
|
|
524
577
|
* A declared world shape passed to `defineGame`. The preferred model is the place feature from
|
package/dist/world/features.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { warnOnce } from "../devtools/warnOnce.js";
|
|
1
2
|
function list(value) {
|
|
2
3
|
if (value === undefined) {
|
|
3
4
|
return undefined;
|
|
@@ -110,6 +111,9 @@ export function terrain(config = {}) {
|
|
|
110
111
|
});
|
|
111
112
|
}
|
|
112
113
|
export function sky(config = {}) {
|
|
114
|
+
if (config.timeOfDay === true && (config.zenithColor !== undefined || config.horizonColor !== undefined)) {
|
|
115
|
+
warnOnce("sky-timeofday-tint", "[jgengine] sky(): zenithColor/horizonColor only set the noon keyframe under timeOfDay; dawn, dusk, and night crossfade through the engine presets. Drop timeOfDay for a fixed tint.");
|
|
116
|
+
}
|
|
113
117
|
return withOptional({
|
|
114
118
|
kind: "sky",
|
|
115
119
|
preset: config.preset ?? "day",
|
|
@@ -119,6 +123,7 @@ export function sky(config = {}) {
|
|
|
119
123
|
...(config.zenithColor === undefined ? {} : { zenithColor: config.zenithColor }),
|
|
120
124
|
...(config.sunIntensity === undefined ? {} : { sunIntensity: config.sunIntensity }),
|
|
121
125
|
...(config.ambientIntensity === undefined ? {} : { ambientIntensity: config.ambientIntensity }),
|
|
126
|
+
...(config.sun === undefined ? {} : { sun: { ...config.sun } }),
|
|
122
127
|
...(config.radius === undefined ? {} : { radius: config.radius }),
|
|
123
128
|
...(config.hazeStrength === undefined ? {} : { hazeStrength: config.hazeStrength }),
|
|
124
129
|
...(config.sunGlowStrength === undefined ? {} : { sunGlowStrength: config.sunGlowStrength }),
|
|
@@ -183,7 +188,7 @@ export function snow(config = {}) {
|
|
|
183
188
|
}
|
|
184
189
|
/** Declares a grass vegetation patch for `environment()` — area, blade sizing, density, and colors. */
|
|
185
190
|
export function grass(config = {}) {
|
|
186
|
-
return
|
|
191
|
+
return {
|
|
187
192
|
kind: "grass",
|
|
188
193
|
area: withAreaPosition(config.area ?? { w: 128, d: 128 }, config.position),
|
|
189
194
|
density: config.density ?? 4,
|
|
@@ -191,7 +196,12 @@ export function grass(config = {}) {
|
|
|
191
196
|
bladeWidth: config.bladeWidth ?? 0.035,
|
|
192
197
|
windStrength: config.windStrength ?? 0.35,
|
|
193
198
|
colors: config.colors ?? ["#3f7d2d", "#66a83f"],
|
|
194
|
-
|
|
199
|
+
...(config.seed === undefined ? {} : { seed: config.seed }),
|
|
200
|
+
...(config.bladeBend === undefined ? {} : { bladeBend: config.bladeBend }),
|
|
201
|
+
...(config.tuftRadius === undefined ? {} : { tuftRadius: config.tuftRadius }),
|
|
202
|
+
...(config.colorVariation === undefined ? {} : { colorVariation: config.colorVariation }),
|
|
203
|
+
...(config.normalLift === undefined ? {} : { normalLift: config.normalLift }),
|
|
204
|
+
};
|
|
195
205
|
}
|
|
196
206
|
/** Declares an ocean water body for `environment()` — bounds, level, and wave tuning. */
|
|
197
207
|
export function ocean(config = {}) {
|
|
@@ -248,6 +258,7 @@ export function building(config = {}) {
|
|
|
248
258
|
...(config.palette === undefined ? {} : { palette: config.palette }),
|
|
249
259
|
...(config.along === undefined ? {} : { along: config.along }),
|
|
250
260
|
...(config.kit === undefined ? {} : { kit: config.kit }),
|
|
261
|
+
...(config.solid === undefined ? {} : { solid: config.solid }),
|
|
251
262
|
});
|
|
252
263
|
}
|
|
253
264
|
export function pad(config) {
|
|
@@ -16,6 +16,10 @@ export interface FootprintReservation {
|
|
|
16
16
|
kind: string;
|
|
17
17
|
cells: readonly GridCell[];
|
|
18
18
|
}
|
|
19
|
+
/** Plain JSON state of a {@link FootprintGrid}: live reservations in claim order. */
|
|
20
|
+
export interface FootprintGridState {
|
|
21
|
+
reservations: FootprintReservation[];
|
|
22
|
+
}
|
|
19
23
|
/** Handle returned by {@link createFootprintGrid}. */
|
|
20
24
|
export interface FootprintGrid {
|
|
21
25
|
readonly cellSize: number;
|
|
@@ -30,6 +34,9 @@ export interface FootprintGrid {
|
|
|
30
34
|
reservationOf(id: string): FootprintReservation | null;
|
|
31
35
|
list(): readonly FootprintReservation[];
|
|
32
36
|
clear(): void;
|
|
37
|
+
snapshot(): FootprintGridState;
|
|
38
|
+
/** Replaces every reservation with `next`'s and rebuilds cell occupancy from them. */
|
|
39
|
+
restore(next: FootprintGridState): void;
|
|
33
40
|
}
|
|
34
41
|
/**
|
|
35
42
|
* Multi-cell footprint occupancy/reservation on a shared build grid — `world/placementController`
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
function cellKey(cell) {
|
|
2
2
|
return `${cell.col}:${cell.row}`;
|
|
3
3
|
}
|
|
4
|
+
function copyReservation(reservation) {
|
|
5
|
+
return { id: reservation.id, kind: reservation.kind, cells: reservation.cells.map((cell) => ({ col: cell.col, row: cell.row })) };
|
|
6
|
+
}
|
|
4
7
|
/**
|
|
5
8
|
* Multi-cell footprint occupancy/reservation on a shared build grid — `world/placementController`
|
|
6
9
|
* only owns the ghost preview; this is the persistent claim a committed placement holds so the next
|
|
@@ -70,6 +73,19 @@ export function createFootprintGrid(options = {}) {
|
|
|
70
73
|
occupied.clear();
|
|
71
74
|
reservations.clear();
|
|
72
75
|
},
|
|
76
|
+
snapshot() {
|
|
77
|
+
return { reservations: Array.from(reservations.values(), copyReservation) };
|
|
78
|
+
},
|
|
79
|
+
restore(next) {
|
|
80
|
+
occupied.clear();
|
|
81
|
+
reservations.clear();
|
|
82
|
+
for (const reservation of next.reservations) {
|
|
83
|
+
const copy = copyReservation(reservation);
|
|
84
|
+
reservations.set(copy.id, copy);
|
|
85
|
+
for (const cell of copy.cells)
|
|
86
|
+
occupied.set(cellKey(cell), copy.id);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
73
89
|
};
|
|
74
90
|
}
|
|
75
91
|
const CARDINAL_OFFSETS = [
|
|
@@ -32,4 +32,5 @@ export interface Interiors {
|
|
|
32
32
|
toInterior(id: string, exterior: Vec2): Vec2 | null;
|
|
33
33
|
toExterior(id: string, interior: Vec2): Vec2 | null;
|
|
34
34
|
}
|
|
35
|
+
/** Frame conversion and bounded movement across an exterior and its interiors; holds config only, no play state. */
|
|
35
36
|
export declare function createInteriors(config?: InteriorsConfig): Interiors;
|
package/dist/world/interiors.js
CHANGED
|
@@ -14,12 +14,14 @@ function toExteriorFrame(interior, local) {
|
|
|
14
14
|
const rotated = rotate(local, interior.rotation ?? 0);
|
|
15
15
|
return [rotated[0] + interior.origin[0], rotated[1] + interior.origin[1]];
|
|
16
16
|
}
|
|
17
|
+
function indexInteriors(interiors) {
|
|
18
|
+
return new Map(interiors.map((interior) => [interior.id, interior]));
|
|
19
|
+
}
|
|
20
|
+
/** Frame conversion and bounded movement across an exterior and its interiors; holds config only, no play state. */
|
|
17
21
|
export function createInteriors(config = {}) {
|
|
18
22
|
const radius = config.radius ?? 0;
|
|
19
23
|
const exterior = config.exterior ?? {};
|
|
20
|
-
const byId =
|
|
21
|
-
for (const interior of config.interiors ?? [])
|
|
22
|
-
byId.set(interior.id, interior);
|
|
24
|
+
const byId = indexInteriors(config.interiors ?? []);
|
|
23
25
|
return {
|
|
24
26
|
move(location, delta) {
|
|
25
27
|
if (location.space.kind === "exterior") {
|
package/dist/world/lod.d.ts
CHANGED
|
@@ -7,11 +7,17 @@ export interface LodSchedulerConfig {
|
|
|
7
7
|
beyondInterval?: number | null;
|
|
8
8
|
stagger?: boolean;
|
|
9
9
|
}
|
|
10
|
+
/** Plain JSON state of a {@link LodScheduler}: each id's accumulated seconds. */
|
|
11
|
+
export interface LodSchedulerState {
|
|
12
|
+
buckets: Record<string, number>;
|
|
13
|
+
}
|
|
10
14
|
export interface LodScheduler {
|
|
11
15
|
bandIndex(distance: number): number;
|
|
12
16
|
step(id: string, distance: number, dtSeconds: number): number;
|
|
13
17
|
remove(id: string): void;
|
|
14
18
|
clear(): void;
|
|
15
19
|
size(): number;
|
|
20
|
+
snapshot(): LodSchedulerState;
|
|
21
|
+
restore(next: LodSchedulerState): void;
|
|
16
22
|
}
|
|
17
23
|
export declare function createLodScheduler(config: LodSchedulerConfig): LodScheduler;
|
package/dist/world/lod.js
CHANGED
|
@@ -62,5 +62,13 @@ export function createLodScheduler(config) {
|
|
|
62
62
|
size() {
|
|
63
63
|
return buckets.size;
|
|
64
64
|
},
|
|
65
|
+
snapshot() {
|
|
66
|
+
return { buckets: Object.fromEntries(buckets) };
|
|
67
|
+
},
|
|
68
|
+
restore(next) {
|
|
69
|
+
buckets.clear();
|
|
70
|
+
for (const [id, seconds] of Object.entries(next.buckets))
|
|
71
|
+
buckets.set(id, seconds);
|
|
72
|
+
},
|
|
65
73
|
};
|
|
66
74
|
}
|
|
@@ -12,6 +12,10 @@ export interface PlacementRules {
|
|
|
12
12
|
bounds?: Aabb;
|
|
13
13
|
obstacles?: readonly PlacementObstacle[];
|
|
14
14
|
snap?: number;
|
|
15
|
+
/** Authoritative ownership/claim validation for this footprint. */
|
|
16
|
+
territory?: (aabb: Aabb) => {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
};
|
|
15
19
|
}
|
|
16
20
|
export type PlacementResult = {
|
|
17
21
|
status: "ok";
|
|
@@ -20,6 +24,9 @@ export type PlacementResult = {
|
|
|
20
24
|
} | {
|
|
21
25
|
status: "rejected";
|
|
22
26
|
reason: "out-of-bounds";
|
|
27
|
+
} | {
|
|
28
|
+
status: "rejected";
|
|
29
|
+
reason: "territory.blocked";
|
|
23
30
|
} | {
|
|
24
31
|
status: "rejected";
|
|
25
32
|
reason: "overlap";
|
package/dist/world/placement.js
CHANGED
|
@@ -16,6 +16,8 @@ export function validatePlacement(request, rules = {}) {
|
|
|
16
16
|
return { status: "rejected", reason: "overlap", obstacle, index };
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
if (rules.territory && !rules.territory(aabb).ok)
|
|
20
|
+
return { status: "rejected", reason: "territory.blocked" };
|
|
19
21
|
return { status: "ok", center, aabb };
|
|
20
22
|
}
|
|
21
23
|
export function footprintObstacle(request, id) {
|
|
@@ -32,7 +32,7 @@ export interface PlacementPreview {
|
|
|
32
32
|
footprint: Footprint;
|
|
33
33
|
aabb: Aabb;
|
|
34
34
|
valid: boolean;
|
|
35
|
-
reason?: "out-of-bounds" | "overlap" | "no-slot";
|
|
35
|
+
reason?: "out-of-bounds" | "overlap" | "no-slot" | "territory.blocked";
|
|
36
36
|
snapMode: SnapMode;
|
|
37
37
|
normal: PlacementVec3;
|
|
38
38
|
/** Id of the resolved slot, when the controller is in slot mode and a slot matched. */
|
|
@@ -59,6 +59,13 @@ export function createPlacementController(config) {
|
|
|
59
59
|
normal: hit.normal,
|
|
60
60
|
...(slot === null ? { reason: "no-slot" } : { slotId: slot.id }),
|
|
61
61
|
};
|
|
62
|
+
if (slot !== null) {
|
|
63
|
+
const result = validatePlacement({ center, footprint, quarterTurns }, { ...rules, snap: undefined });
|
|
64
|
+
if (result.status === "rejected") {
|
|
65
|
+
next.valid = false;
|
|
66
|
+
next.reason = result.reason;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
62
69
|
preview = next;
|
|
63
70
|
return next;
|
|
64
71
|
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { StreetNetwork, StreetVec2 } from "./streetGenerator.js";
|
|
2
|
+
/** How a sealed-off side street is closed: hard barriers, a cone line, or temporary fencing. */
|
|
3
|
+
export type CircuitSealKind = "barrier" | "cones" | "fence";
|
|
4
|
+
/** Fully-defaulted sliders the route search answers to. */
|
|
5
|
+
export interface CircuitRouteRules {
|
|
6
|
+
seed: string;
|
|
7
|
+
/** Target lap length in meters — the search keeps the cycle closest to this. */
|
|
8
|
+
lapLength: number;
|
|
9
|
+
/** 0 races any street; 1 keeps the lap on avenues and boulevards only. */
|
|
10
|
+
arterialBias: number;
|
|
11
|
+
/**
|
|
12
|
+
* Radius (m) the corner-rounding pass works the racing line toward. Bounded by `cornerCut` and the
|
|
13
|
+
* road width — the line never leaves the street — so the achieved figure is reported back as
|
|
14
|
+
* {@link CircuitRoute.tightestRadius} rather than enforced here.
|
|
15
|
+
*/
|
|
16
|
+
minCornerRadius: number;
|
|
17
|
+
/** Ordered checkpoint gates placed around the lap. */
|
|
18
|
+
checkpoints: number;
|
|
19
|
+
/** Laps the produced race runs. */
|
|
20
|
+
laps: number;
|
|
21
|
+
/** Half-height of a checkpoint gate volume (m) — how tall the trigger box reaches. */
|
|
22
|
+
gateHeight: number;
|
|
23
|
+
/** Starting grid slots behind the line (0 = no grid). */
|
|
24
|
+
gridSlots: number;
|
|
25
|
+
/** How the side streets leaving the lap are closed off. */
|
|
26
|
+
sealKind: CircuitSealKind;
|
|
27
|
+
/** Timing sectors the lap splits into. */
|
|
28
|
+
sectors: number;
|
|
29
|
+
/**
|
|
30
|
+
* Arc-length spacing (m) the lap is resampled to. City streets are sampled coarsely enough for a
|
|
31
|
+
* road ribbon but far too coarsely for a racing surface, corner analysis, or kerbs.
|
|
32
|
+
*/
|
|
33
|
+
sampleStep: number;
|
|
34
|
+
/**
|
|
35
|
+
* How far the racing line may be pulled off the street centerline while rounding a junction, as a
|
|
36
|
+
* fraction of the local half-width. 0 keeps the hard kink; ~0.5 uses the full lane either side.
|
|
37
|
+
*/
|
|
38
|
+
cornerCut: number;
|
|
39
|
+
}
|
|
40
|
+
/** Defaults: a ~2.4 km arterial street lap with 12 gates, 3 laps, and barriered side streets. */
|
|
41
|
+
export declare const CIRCUIT_ROUTE_DEFAULTS: CircuitRouteRules;
|
|
42
|
+
/**
|
|
43
|
+
* One street closed off where it leaves the lap — the thing that turns public roads into an
|
|
44
|
+
* instanced event. Stands just off the junction, spanning the sealed street's full width.
|
|
45
|
+
*/
|
|
46
|
+
export interface CircuitSeal {
|
|
47
|
+
/** Volume-local XZ of the barrier run's center. */
|
|
48
|
+
x: number;
|
|
49
|
+
z: number;
|
|
50
|
+
/** Yaw (radians) pointing down the sealed street, away from the lap. */
|
|
51
|
+
heading: number;
|
|
52
|
+
/** Width of the street being closed — the run spans it plus a shoulder. */
|
|
53
|
+
width: number;
|
|
54
|
+
kind: CircuitSealKind;
|
|
55
|
+
/** Graph node the seal stands at. */
|
|
56
|
+
node: number;
|
|
57
|
+
}
|
|
58
|
+
/** One analyzed corner: where the lap turns, how hard, and which way. */
|
|
59
|
+
export interface CircuitCorner {
|
|
60
|
+
/** `centerline` index at the apex (tightest point). */
|
|
61
|
+
apex: number;
|
|
62
|
+
/** Radius of curvature at the apex, meters. */
|
|
63
|
+
radius: number;
|
|
64
|
+
/** Total turn through the corner, radians. */
|
|
65
|
+
angle: number;
|
|
66
|
+
/** -1 = left-hand, 1 = right-hand. */
|
|
67
|
+
direction: -1 | 1;
|
|
68
|
+
/** `centerline` index where the corner starts. */
|
|
69
|
+
entry: number;
|
|
70
|
+
/** `centerline` index where it ends. */
|
|
71
|
+
exit: number;
|
|
72
|
+
}
|
|
73
|
+
/** One checkpoint trigger volume, shaped to hand straight to `raceTrack({ checkpoints })`. */
|
|
74
|
+
export interface CircuitGate {
|
|
75
|
+
id: string;
|
|
76
|
+
center: readonly [number, number, number];
|
|
77
|
+
half: readonly [number, number, number];
|
|
78
|
+
}
|
|
79
|
+
/** The start/finish line: where it is, which way cars face, and the painted line across the road. */
|
|
80
|
+
export interface CircuitStart {
|
|
81
|
+
x: number;
|
|
82
|
+
z: number;
|
|
83
|
+
/** Yaw cars face on the grid (direction of travel). */
|
|
84
|
+
heading: number;
|
|
85
|
+
/** The two road-edge ends of the painted line. */
|
|
86
|
+
line: readonly [StreetVec2, StreetVec2];
|
|
87
|
+
/** Arc-length position of the line along the lap, meters. */
|
|
88
|
+
distance: number;
|
|
89
|
+
/** Road width at the line. */
|
|
90
|
+
width: number;
|
|
91
|
+
}
|
|
92
|
+
/** One grid slot: a staggered spawn behind the start line. */
|
|
93
|
+
export interface CircuitGridSlot {
|
|
94
|
+
x: number;
|
|
95
|
+
z: number;
|
|
96
|
+
/** Yaw facing down the start straight. */
|
|
97
|
+
heading: number;
|
|
98
|
+
}
|
|
99
|
+
/** One kerb strip on the outside or inside of a corner, as an offset polyline to stripe. */
|
|
100
|
+
export interface CircuitKerb {
|
|
101
|
+
/** Polyline along the road edge the kerb hugs. */
|
|
102
|
+
points: StreetVec2[];
|
|
103
|
+
/** Strip width across, meters. */
|
|
104
|
+
width: number;
|
|
105
|
+
/** Which side of travel the strip sits on: -1 left, 1 right. */
|
|
106
|
+
side: -1 | 1;
|
|
107
|
+
/** Alternating stripe length along the run, meters. */
|
|
108
|
+
stripe: number;
|
|
109
|
+
/** Corner this kerb belongs to (index into {@link CircuitRoute.corners}). */
|
|
110
|
+
corner: number;
|
|
111
|
+
}
|
|
112
|
+
/** A closed race lap lifted out of a street network, with everything a race needs hung off it. */
|
|
113
|
+
export interface CircuitRoute {
|
|
114
|
+
/** Closed lap centerline in volume-local XZ. Implicitly closed: the last point joins the first. */
|
|
115
|
+
centerline: StreetVec2[];
|
|
116
|
+
/** Road width at each centerline point, inherited from the streets the lap follows. */
|
|
117
|
+
widths: number[];
|
|
118
|
+
/** Road-surface height per point, present only when the network carries elevation. */
|
|
119
|
+
heights?: number[];
|
|
120
|
+
/** Lap length, meters. */
|
|
121
|
+
length: number;
|
|
122
|
+
/** Graph edge ids the lap runs on — style exactly these streets as track surface. */
|
|
123
|
+
edges: number[];
|
|
124
|
+
/** Graph node ids the lap visits in order (no repeat of the closing node). */
|
|
125
|
+
nodes: number[];
|
|
126
|
+
/** Every street leaving the lap that is not part of it, closed off. */
|
|
127
|
+
seals: CircuitSeal[];
|
|
128
|
+
corners: CircuitCorner[];
|
|
129
|
+
/** Ordered gates, finish line last — ready for `raceTrack({ checkpoints, laps })`. */
|
|
130
|
+
checkpoints: CircuitGate[];
|
|
131
|
+
laps: number;
|
|
132
|
+
start: CircuitStart;
|
|
133
|
+
grid: CircuitGridSlot[];
|
|
134
|
+
/** Arc-length fractions (0..1) where each timing sector begins; `sectors[0]` is always 0. */
|
|
135
|
+
sectors: number[];
|
|
136
|
+
/** Share of lap length running on avenue-or-wider streets, 0..1. */
|
|
137
|
+
arterialShare: number;
|
|
138
|
+
/**
|
|
139
|
+
* Tightest radius (m) the finished racing line actually holds. `minCornerRadius` is a TARGET the
|
|
140
|
+
* rounding pass works toward, not a guarantee: rounding may not pull the line outside the street it
|
|
141
|
+
* inherited, so a 90° junction on a narrow road stays tighter than any target can ask for. Read
|
|
142
|
+
* this to report what the lap really is — widen `streetWidth` to buy a smoother one.
|
|
143
|
+
*/
|
|
144
|
+
tightestRadius: number;
|
|
145
|
+
}
|
|
146
|
+
/** Kerb strips on the outside and inside of every real corner. */
|
|
147
|
+
export interface CircuitKerbOptions {
|
|
148
|
+
/** Strip width across, meters. Defaults to 1.1. */
|
|
149
|
+
width?: number;
|
|
150
|
+
/** Alternating stripe length along the run, meters. Defaults to 2.2. */
|
|
151
|
+
stripe?: number;
|
|
152
|
+
/** Only kerb corners at or below this radius (m). Defaults to 6× the route's tightest corner. */
|
|
153
|
+
maxRadius?: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Red/white kerb strips hugging both road edges through each corner. Returns the polylines and
|
|
157
|
+
* stripe pitch as data; the renderer owns the mesh and the colors.
|
|
158
|
+
*/
|
|
159
|
+
export declare function circuitKerbs(route: CircuitRoute, options?: CircuitKerbOptions): CircuitKerb[];
|
|
160
|
+
/**
|
|
161
|
+
* Lift a closed, sealed-off race lap out of an existing street network. Returns `null` when the
|
|
162
|
+
* network has no drivable cycle (a pure tree of dead-end streets), so callers can fall back or warn
|
|
163
|
+
* rather than render a broken race.
|
|
164
|
+
*
|
|
165
|
+
* On a `circuit`-mode network the generated loop is used directly. On a `net` (a city) the graph is
|
|
166
|
+
* searched for the cycle closest to `lapLength` that respects `arterialBias` and `minCornerRadius`.
|
|
167
|
+
*/
|
|
168
|
+
export declare function extractCircuitRoute(network: StreetNetwork, rules?: Partial<CircuitRouteRules>): CircuitRoute | null;
|