@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
|
@@ -13,18 +13,18 @@ export const CITY_LOT_CLASSES = [
|
|
|
13
13
|
/** All filler classes, for validation and interior-pass allow-lists. */
|
|
14
14
|
export const CITY_FILLER_CLASSES = ["garage", "depot"];
|
|
15
15
|
const CLASS_PROFILES = {
|
|
16
|
-
tower: { width: [
|
|
17
|
-
slab: { width: [
|
|
18
|
-
shop: { width: [
|
|
19
|
-
rowhouse: { width: [
|
|
16
|
+
tower: { width: [14, 22], depth: [12, 20], setbackFactor: 0.15, spacingFactor: 0.35, floors: [12, 34], backRow: true },
|
|
17
|
+
slab: { width: [12, 20], depth: [10, 16], setbackFactor: 0.2, spacingFactor: 0.4, floors: [4, 9], backRow: true },
|
|
18
|
+
shop: { width: [8, 14], depth: [8, 12], setbackFactor: 0.05, spacingFactor: 0.15, floors: [1, 2], backRow: true },
|
|
19
|
+
rowhouse: { width: [5.5, 8], depth: [9, 13], setbackFactor: 0.2, spacingFactor: 0.05, floors: [2, 3], backRow: true },
|
|
20
20
|
house: { width: [9, 12], depth: [8, 11], setbackFactor: 1, spacingFactor: 1, floors: [1, 2], backRow: true },
|
|
21
21
|
mansion: { width: [18, 26], depth: [14, 20], setbackFactor: 2, spacingFactor: 1.6, floors: [2, 3], backRow: false },
|
|
22
22
|
farmhouse: { width: [11, 14], depth: [9, 12], setbackFactor: 2.8, spacingFactor: 4, floors: [2, 2], backRow: false },
|
|
23
23
|
barn: { width: [12, 16], depth: [9, 13], setbackFactor: 3.6, spacingFactor: 5, floors: [1, 1], backRow: false },
|
|
24
24
|
silo: { width: [5, 6], depth: [5, 6], setbackFactor: 4, spacingFactor: 3, floors: [1, 1], backRow: false },
|
|
25
25
|
// Interior-fill fillers: broad, plain footprints that pack the backs of dense blocks.
|
|
26
|
-
garage: { width: [
|
|
27
|
-
depot: { width: [
|
|
26
|
+
garage: { width: [16, 24], depth: [14, 20], setbackFactor: 0.2, spacingFactor: 0.3, floors: [2, 6], backRow: true },
|
|
27
|
+
depot: { width: [18, 28], depth: [16, 24], setbackFactor: 0.25, spacingFactor: 0.35, floors: [1, 2], backRow: true },
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
30
|
* Natural frontage-width range (meters) of a class's massing — what the plot-size class bias reads
|
|
@@ -131,6 +131,59 @@ function box(offset, size, role, options = {}) {
|
|
|
131
131
|
function gable(offset, size, rotationY = 0) {
|
|
132
132
|
return { shape: "gable", offset, size, rotationY, role: "roof", grounded: false, banded: false };
|
|
133
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Finish a flat roof at height `top`: a recessed dark deck, a parapet upstand on all four edges,
|
|
136
|
+
* and seeded rooftop plant (mechanical units, a stair bulkhead, a tank). A city skyline is mostly
|
|
137
|
+
* roofs seen from above, so every flat-capped class runs through here instead of a bare slab.
|
|
138
|
+
*/
|
|
139
|
+
function flatRoofTop(pieces, width, depth, top, rng) {
|
|
140
|
+
const rail = Math.min(1.15, 0.55 + rng() * 0.55);
|
|
141
|
+
const wall = Math.min(0.55, Math.max(0.18, Math.min(width, depth) * 0.035));
|
|
142
|
+
const innerW = Math.max(0.4, width - wall * 2);
|
|
143
|
+
const innerD = Math.max(0.4, depth - wall * 2);
|
|
144
|
+
pieces.push(box([0, top, 0], [innerW, 0.14, innerD], "roof"));
|
|
145
|
+
pieces.push(box([0, top, (depth - wall) / 2], [width, rail, wall], "trim"));
|
|
146
|
+
pieces.push(box([0, top, -(depth - wall) / 2], [width, rail, wall], "trim"));
|
|
147
|
+
pieces.push(box([(width - wall) / 2, top, 0], [wall, rail, innerD], "trim"));
|
|
148
|
+
pieces.push(box([-(width - wall) / 2, top, 0], [wall, rail, innerD], "trim"));
|
|
149
|
+
const deck = top + 0.14;
|
|
150
|
+
const units = innerW * innerD > 110 ? 1 + Math.floor(rng() * 3) : rng() < 0.7 ? 1 : 0;
|
|
151
|
+
for (let i = 0; i < units; i += 1) {
|
|
152
|
+
const uw = Math.min(innerW * 0.34, 1.6 + rng() * 2.4);
|
|
153
|
+
const ud = Math.min(innerD * 0.34, 1.4 + rng() * 2);
|
|
154
|
+
pieces.push(box([(rng() - 0.5) * Math.max(0, innerW - uw), deck, (rng() - 0.5) * Math.max(0, innerD - ud)], [uw, 0.6 + rng() * 0.9, ud], "roof"));
|
|
155
|
+
}
|
|
156
|
+
if (rng() < 0.55) {
|
|
157
|
+
const bw = Math.min(innerW * 0.34, 2.2 + rng() * 1.6);
|
|
158
|
+
const bd = Math.min(innerD * 0.36, 2 + rng() * 1.4);
|
|
159
|
+
pieces.push(box([(rng() - 0.5) * Math.max(0, innerW - bw), deck, (rng() - 0.5) * Math.max(0, innerD - bd)], [bw, 1.9 + rng() * 1.1, bd], "trim"));
|
|
160
|
+
}
|
|
161
|
+
if (rng() < 0.4) {
|
|
162
|
+
const r = Math.min(2.2, Math.min(innerW, innerD) * 0.26);
|
|
163
|
+
pieces.push({
|
|
164
|
+
shape: "cylinder",
|
|
165
|
+
offset: [(rng() - 0.5) * Math.max(0, innerW - r), deck, (rng() - 0.5) * Math.max(0, innerD - r)],
|
|
166
|
+
size: [r, 1.4 + rng() * 1.2, r],
|
|
167
|
+
rotationY: 0,
|
|
168
|
+
role: "trim",
|
|
169
|
+
grounded: false,
|
|
170
|
+
banded: false,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Street-level treatment for a commercial frontage: a plinth course wrapping the base, a recessed
|
|
176
|
+
* dark entrance on the street face, and a canopy over the sidewalk — so floor 1 never reads like
|
|
177
|
+
* floor 30. `overhang` is the plinth's outward step (0 keeps it flush for terraced classes).
|
|
178
|
+
*/
|
|
179
|
+
function streetLevel(pieces, width, depth, bandHeight, overhang, rng) {
|
|
180
|
+
pieces.push(box([0, 0, 0], [width + overhang, bandHeight, depth + overhang], "trim", { grounded: true }));
|
|
181
|
+
const doorW = Math.min(width * 0.32, 3.4);
|
|
182
|
+
const doorX = (rng() - 0.5) * Math.max(0, width - doorW * 1.6) * 0.5;
|
|
183
|
+
const face = depth / 2 + overhang / 2;
|
|
184
|
+
pieces.push(box([doorX, 0, face], [doorW, bandHeight * 0.76, 0.5], "roof", { grounded: true }));
|
|
185
|
+
pieces.push(box([doorX, bandHeight * 0.8, face + 0.6], [doorW * 1.5, 0.22, 1.3], "accent"));
|
|
186
|
+
}
|
|
134
187
|
/**
|
|
135
188
|
* Compose the massing pieces for one lot. Deterministic per `rng` stream: the same class, size,
|
|
136
189
|
* floors, and stream always yield the identical silhouette. Sizes are in meters, lot-local.
|
|
@@ -147,17 +200,22 @@ export function buildLotPieces(cls, width, depth, floors, floorHeight, rng) {
|
|
|
147
200
|
const h2 = H * (0.24 + rng() * 0.08);
|
|
148
201
|
const h3 = H - h1 - h2;
|
|
149
202
|
pieces.push(box([0, 0, 0], [width, h1, depth], "wall", { grounded: true, banded: true }));
|
|
203
|
+
// Occasional attached wing breaks the identical-rect streetwall without replacing the shaft.
|
|
204
|
+
if (width >= 16 && depth >= 14 && rng() < 0.42) {
|
|
205
|
+
const wingW = width * (0.34 + rng() * 0.1);
|
|
206
|
+
const side = rng() < 0.5 ? 1 : -1;
|
|
207
|
+
pieces.push(box([side * (width / 2 - wingW / 2), 0, depth * 0.28], [wingW, h1 * (0.55 + rng() * 0.2), depth * 0.42], "wall", { grounded: true, banded: true }));
|
|
208
|
+
}
|
|
150
209
|
const w2 = width * (0.78 + rng() * 0.08);
|
|
151
210
|
const d2 = depth * (0.78 + rng() * 0.08);
|
|
152
211
|
pieces.push(box([0, h1, 0], [w2, h2, d2], "wall", { banded: true }));
|
|
153
212
|
const w3 = width * (0.55 + rng() * 0.1);
|
|
154
213
|
const d3 = depth * (0.55 + rng() * 0.1);
|
|
155
214
|
pieces.push(box([0, h1 + h2, 0], [w3, h3, d3], "wall", { banded: true }));
|
|
156
|
-
pieces
|
|
215
|
+
flatRoofTop(pieces, w3 * 1.04, d3 * 1.04, H, rng);
|
|
157
216
|
if (rng() < 0.35)
|
|
158
217
|
pieces.push(box([0, H + 0.5, 0], [1.2, 3 + rng() * 5, 1.2], "trim"));
|
|
159
|
-
|
|
160
|
-
pieces.push(box([0, H + 0.5, 0], [w3 * 0.4, 1.6, d3 * 0.4], "roof"));
|
|
218
|
+
streetLevel(pieces, width, depth, Math.min(floorHeight * 1.1, H * 0.5), 0.35, rng);
|
|
161
219
|
}
|
|
162
220
|
else {
|
|
163
221
|
const h1 = H * (0.66 + rng() * 0.1);
|
|
@@ -165,32 +223,58 @@ export function buildLotPieces(cls, width, depth, floors, floorHeight, rng) {
|
|
|
165
223
|
const w2 = width * (0.72 + rng() * 0.1);
|
|
166
224
|
const d2 = depth * (0.72 + rng() * 0.1);
|
|
167
225
|
pieces.push(box([0, h1, 0], [w2, H - h1, d2], "wall", { banded: true }));
|
|
168
|
-
pieces
|
|
226
|
+
flatRoofTop(pieces, w2 * 1.05, d2 * 1.05, H, rng);
|
|
227
|
+
streetLevel(pieces, width, depth, Math.min(floorHeight * 1.1, H * 0.5), 0.35, rng);
|
|
169
228
|
}
|
|
170
229
|
return pieces;
|
|
171
230
|
}
|
|
172
231
|
case "slab": {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
232
|
+
// Full streetwall depth; irregular plans break the identical-cell silhouette.
|
|
233
|
+
if (width >= 14 && depth >= 12 && rng() < 0.55) {
|
|
234
|
+
const wing = width * (0.38 + rng() * 0.14);
|
|
235
|
+
const side = rng() < 0.5 ? 1 : -1;
|
|
236
|
+
const frontH = H * (0.92 + rng() * 0.12);
|
|
237
|
+
const wingH = H * (0.7 + rng() * 0.25);
|
|
238
|
+
pieces.push(box([0, 0, depth * 0.08], [width, frontH, depth * 0.62], "wall", { grounded: true, banded: true }));
|
|
239
|
+
pieces.push(box([side * (width / 2 - wing / 2), 0, -depth * 0.08], [wing, wingH, depth * 0.82], "wall", { grounded: true, banded: true }));
|
|
240
|
+
flatRoofTop(pieces, width * 0.98, depth * 0.62, frontH, rng);
|
|
241
|
+
if (rng() < 0.45)
|
|
242
|
+
flatRoofTop(pieces, wing * 1.02, depth * 0.78, wingH, rng);
|
|
243
|
+
streetLevel(pieces, width, depth * 0.62, Math.min(floorHeight * 1.05, frontH * 0.5), 0.25, rng);
|
|
244
|
+
}
|
|
245
|
+
else if (width >= 16 && depth >= 14 && rng() < 0.35) {
|
|
246
|
+
// Open mid-block court: street wall + two side wings, rear open as a service yard.
|
|
247
|
+
const wallT = Math.min(width, depth) * 0.28;
|
|
248
|
+
pieces.push(box([0, 0, (depth - wallT) / 2], [width, H, wallT], "wall", { grounded: true, banded: true }));
|
|
249
|
+
pieces.push(box([(width - wallT) / 2, 0, -wallT * 0.15], [wallT, H * (0.75 + rng() * 0.2), depth - wallT], "wall", { grounded: true, banded: true }));
|
|
250
|
+
pieces.push(box([-(width - wallT) / 2, 0, -wallT * 0.15], [wallT, H * (0.7 + rng() * 0.2), depth - wallT], "wall", { grounded: true, banded: true }));
|
|
251
|
+
flatRoofTop(pieces, width * 1.01, wallT * 1.02, H, rng);
|
|
252
|
+
streetLevel(pieces, width, wallT, Math.min(floorHeight * 1.05, H * 0.5), 0.25, rng);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
pieces.push(box([0, 0, 0], [width, H, depth], "wall", { grounded: true, banded: true }));
|
|
256
|
+
flatRoofTop(pieces, width * 1.02, depth * 1.02, H, rng);
|
|
257
|
+
streetLevel(pieces, width, depth, Math.min(floorHeight * 1.05, H * 0.5), 0.25, rng);
|
|
258
|
+
}
|
|
177
259
|
return pieces;
|
|
178
260
|
}
|
|
179
261
|
case "shop": {
|
|
180
262
|
pieces.push(box([0, 0, 0], [width, H, depth], "wall", { grounded: true }));
|
|
181
|
-
pieces
|
|
263
|
+
flatRoofTop(pieces, width * 1.03, depth * 1.03, H, rng);
|
|
182
264
|
// Front awning strip over the sidewalk face.
|
|
183
265
|
pieces.push(box([0, Math.min(H - 0.4, 2.6), depth / 2 + 0.35], [width * 0.9, 0.35, 0.9], "accent"));
|
|
266
|
+
pieces.push(box([0, 0, depth / 2 - 0.05], [width * 0.82, Math.min(H * 0.62, 2.5), 0.4], "roof", { grounded: true }));
|
|
184
267
|
return pieces;
|
|
185
268
|
}
|
|
186
269
|
case "rowhouse": {
|
|
187
|
-
pieces.push(box([0, 0, 0], [width * 0.
|
|
270
|
+
pieces.push(box([0, 0, 0], [width * 0.98, H, depth * 0.92], "wall", { grounded: true, banded: true }));
|
|
188
271
|
if (rng() < 0.55) {
|
|
189
|
-
pieces.push(gable([0, H, 0], [width * 0.
|
|
272
|
+
pieces.push(gable([0, H, 0], [width * 0.98, 1.6 + rng() * 0.8, depth * 0.96]));
|
|
190
273
|
}
|
|
191
274
|
else {
|
|
192
|
-
pieces.push(box([0, H, 0], [width * 1.0, 0.45, depth * 0.
|
|
275
|
+
pieces.push(box([0, H, 0], [width * 1.0, 0.45, depth * 0.94], "trim"));
|
|
193
276
|
}
|
|
277
|
+
streetLevel(pieces, width * 0.98, depth * 0.92, Math.min(floorHeight * 0.95, H * 0.5), 0.04, rng);
|
|
194
278
|
return pieces;
|
|
195
279
|
}
|
|
196
280
|
case "house": {
|
|
@@ -273,13 +357,7 @@ export function buildLotPieces(cls, width, depth, floors, floorHeight, rng) {
|
|
|
273
357
|
case "garage": {
|
|
274
358
|
// Parking structure: a plain banded box (the window bands read as deck slots) with a flat cap.
|
|
275
359
|
pieces.push(box([0, 0, 0], [width, H, depth], "wall", { grounded: true, banded: true }));
|
|
276
|
-
pieces
|
|
277
|
-
if (rng() < 0.6) {
|
|
278
|
-
// Stair/lift core poking above the roof deck.
|
|
279
|
-
const cx = (rng() - 0.5) * width * 0.5;
|
|
280
|
-
const cz = (rng() - 0.5) * depth * 0.4;
|
|
281
|
-
pieces.push(box([cx, H + 0.4, cz], [width * 0.16, 1.6 + rng() * 1.2, depth * 0.16], "accent"));
|
|
282
|
-
}
|
|
360
|
+
flatRoofTop(pieces, width * 1.02, depth * 1.02, H, rng);
|
|
283
361
|
return pieces;
|
|
284
362
|
}
|
|
285
363
|
case "depot": {
|
package/dist/world/cityKind.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type ParamSchema, type SceneKindObject, type SceneKindResolveContext, type WeightedParamEntry } from "../scene/sceneKinds.js";
|
|
2
2
|
import { type BuildingStyle } from "./buildings.js";
|
|
3
3
|
import { type CityLotClass, type CityLotPiece, type CityTreeSpecies, type CityZoneBand, type CityZoneProfile } from "./cityContent.js";
|
|
4
|
+
import { type CircuitCorner, type CircuitGate, type CircuitSealKind } from "./raceCircuit.js";
|
|
5
|
+
import type { WorldSolid } from "./worldSolids.js";
|
|
4
6
|
import type { RoadPoint } from "./roads.js";
|
|
5
7
|
import { type StreetFeatureKind } from "./streetGenerator.js";
|
|
6
8
|
import { type CityBlockKind } from "./cityBlocks.js";
|
|
@@ -29,6 +31,17 @@ export interface CityRules {
|
|
|
29
31
|
minTurnAngle: number;
|
|
30
32
|
/** Sharpest corner (degrees) a street may take — tighter ones are beveled away. */
|
|
31
33
|
maxTurnAngle: number;
|
|
34
|
+
/** Organic boundary clipping, 0..1. 0 fills the volume's rectangle; higher grows lobes and bays. */
|
|
35
|
+
outline: number;
|
|
36
|
+
/** Share of branch lanes grown as winding residential side streets, 0..1. */
|
|
37
|
+
residentialBranches: number;
|
|
38
|
+
/** Road-surface relief, 0..1. 0 is dead flat; 1 is ~22 m of rise and fall across a ~520 m district. */
|
|
39
|
+
elevation: number;
|
|
40
|
+
/** Steepest road grade (rise/run) the elevation pass allows on any street. */
|
|
41
|
+
maxGrade: number;
|
|
42
|
+
/** Circuit space-filling, 0..1. 0 is a flowing loop around an empty middle; higher folds the lap
|
|
43
|
+
* back through its own interior (switchbacks, hairpins, parallel runs). Circuit mode only. */
|
|
44
|
+
compactness: number;
|
|
32
45
|
/** Lay parcels + buildings against the streets (city fabric). Off = bare roads/track, no plots. */
|
|
33
46
|
fabric: boolean;
|
|
34
47
|
/** Streets bore through ridges on tunnel decks instead of climbing over them. */
|
|
@@ -84,6 +97,10 @@ export interface CityRules {
|
|
|
84
97
|
treeMix: WeightedParamEntry[];
|
|
85
98
|
/** Street-light density along non-lane streets, 0..1. */
|
|
86
99
|
lightDensity: number;
|
|
100
|
+
/** Parked-vehicle density along street curbs and inside parking pads, 0..1. */
|
|
101
|
+
parkedCars: number;
|
|
102
|
+
/** Junction control density, 0..1: mast-arm signals on arterial crossings, sign posts below them. */
|
|
103
|
+
signals: number;
|
|
87
104
|
/** Ring estate lots (mansions) with perimeter hedges and a gated gap. */
|
|
88
105
|
hedges: boolean;
|
|
89
106
|
/** Connect houses/estates/farms to their street with driveways. */
|
|
@@ -104,6 +121,22 @@ export interface CityRules {
|
|
|
104
121
|
sidewalks: boolean;
|
|
105
122
|
/** Sidewalk band width in meters at "street" hierarchy (boulevards scale up, lanes down). */
|
|
106
123
|
sidewalkWidth: number;
|
|
124
|
+
/** Lift an instanced street race out of the district's own streets (see {@link ResolvedRace}). */
|
|
125
|
+
race: boolean;
|
|
126
|
+
/** Target race lap length in meters — the search keeps the cycle closest to this. */
|
|
127
|
+
raceLapLength: number;
|
|
128
|
+
/** 0 races any street; 1 keeps the lap on avenues and boulevards only. */
|
|
129
|
+
raceArterial: number;
|
|
130
|
+
/** Ordered checkpoint gates placed around the lap. */
|
|
131
|
+
raceCheckpoints: number;
|
|
132
|
+
/** Laps the race runs. */
|
|
133
|
+
raceLaps: number;
|
|
134
|
+
/** Close every side street leaving the lap with barriers — what makes it an instanced event. */
|
|
135
|
+
raceSeals: boolean;
|
|
136
|
+
/** Starting grid slots behind the line (0 = no grid). */
|
|
137
|
+
raceGridSlots: number;
|
|
138
|
+
/** Radius (m) the racing line is worked toward at the lap's junction corners. */
|
|
139
|
+
raceCornerRadius: number;
|
|
107
140
|
/** Building style palette id (see {@link BUILDING_STYLE_PALETTES}). */
|
|
108
141
|
style: BuildingStyle;
|
|
109
142
|
/**
|
|
@@ -132,6 +165,9 @@ export interface CityStreet {
|
|
|
132
165
|
surface: "asphalt" | "gravel";
|
|
133
166
|
/** Whether sidewalk ribbons flank this street. */
|
|
134
167
|
sidewalk: boolean;
|
|
168
|
+
/** Grade-limited road-surface height per point, present only when `elevation` is above 0. This is
|
|
169
|
+
* ROAD relief, not the terrain the district stands on. */
|
|
170
|
+
heights?: readonly number[];
|
|
135
171
|
/** Cul-de-sac turning bulb at a dangling end, when the lane never reconnected. */
|
|
136
172
|
bulb?: RoadPoint;
|
|
137
173
|
/** Bridge/tunnel spans along this street as `[from, to]` index windows into `points`. */
|
|
@@ -277,6 +313,97 @@ export interface CityParking {
|
|
|
277
313
|
size: readonly [number, number];
|
|
278
314
|
rotationY: number;
|
|
279
315
|
}
|
|
316
|
+
/** Silhouette class of a parked vehicle — sizes the body the renderer instances. */
|
|
317
|
+
export type CityVehicleKind = "car" | "van" | "truck";
|
|
318
|
+
/** One parked vehicle standing at a curb or nose-in inside a parking pad. */
|
|
319
|
+
export interface CityVehicle {
|
|
320
|
+
x: number;
|
|
321
|
+
z: number;
|
|
322
|
+
/** Yaw the body points down (engine rotationY convention). */
|
|
323
|
+
rotationY: number;
|
|
324
|
+
kind: CityVehicleKind;
|
|
325
|
+
/** Seeded body-paint index; the renderer maps it into its own palette. */
|
|
326
|
+
paint: number;
|
|
327
|
+
/** Where it stands, so the renderer drapes it onto carriageway or pad height. */
|
|
328
|
+
stall: "curb" | "lot";
|
|
329
|
+
}
|
|
330
|
+
/** One junction control on an approach arm: an arterial mast-arm signal, or a plain sign post. */
|
|
331
|
+
export interface CitySignal {
|
|
332
|
+
x: number;
|
|
333
|
+
z: number;
|
|
334
|
+
/** Yaw the head faces — into the traffic approaching down this arm. */
|
|
335
|
+
heading: number;
|
|
336
|
+
kind: "signal" | "sign";
|
|
337
|
+
/** How far the mast arm reaches over the carriageway, to the right of {@link CitySignal.heading}. */
|
|
338
|
+
reach: number;
|
|
339
|
+
}
|
|
340
|
+
/** One street closed off where it leaves the race lap: world XZ, the yaw down the sealed street, and
|
|
341
|
+
* the width the barrier run spans. */
|
|
342
|
+
export interface CityRaceSeal {
|
|
343
|
+
x: number;
|
|
344
|
+
z: number;
|
|
345
|
+
heading: number;
|
|
346
|
+
width: number;
|
|
347
|
+
kind: CircuitSealKind;
|
|
348
|
+
}
|
|
349
|
+
/** One kerb strip hugging a corner's road edge, as a world-space polyline to stripe. */
|
|
350
|
+
export interface CityRaceKerb {
|
|
351
|
+
points: readonly RoadPoint[];
|
|
352
|
+
/** Strip width across, meters. */
|
|
353
|
+
width: number;
|
|
354
|
+
/** Which side of travel the strip sits on: -1 left, 1 right. */
|
|
355
|
+
side: -1 | 1;
|
|
356
|
+
/** Alternating stripe length along the run, meters. */
|
|
357
|
+
stripe: number;
|
|
358
|
+
/** Corner this kerb belongs to (index into {@link ResolvedRace.corners}). */
|
|
359
|
+
corner: number;
|
|
360
|
+
}
|
|
361
|
+
/** The start/finish line: where it is, which way cars face, and the painted line across the road. */
|
|
362
|
+
export interface CityRaceStart {
|
|
363
|
+
x: number;
|
|
364
|
+
z: number;
|
|
365
|
+
/** Yaw cars face on the grid (direction of travel). */
|
|
366
|
+
heading: number;
|
|
367
|
+
/** The two road-edge ends of the painted line. */
|
|
368
|
+
line: readonly [RoadPoint, RoadPoint];
|
|
369
|
+
/** Arc-length position of the line along the lap, meters. */
|
|
370
|
+
distance: number;
|
|
371
|
+
width: number;
|
|
372
|
+
}
|
|
373
|
+
/** One staggered spawn behind the start line. */
|
|
374
|
+
export interface CityRaceGridSlot {
|
|
375
|
+
x: number;
|
|
376
|
+
z: number;
|
|
377
|
+
heading: number;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* An instanced street race lifted out of the district's OWN streets: a closed lap through the city,
|
|
381
|
+
* with every side street leaving it sealed off. World space, like the rest of {@link ResolvedCity}.
|
|
382
|
+
*/
|
|
383
|
+
export interface ResolvedRace {
|
|
384
|
+
/** Closed lap centerline — the last point joins the first. */
|
|
385
|
+
centerline: readonly RoadPoint[];
|
|
386
|
+
/** Road width at each centerline point, inherited from the streets the lap follows. */
|
|
387
|
+
widths: readonly number[];
|
|
388
|
+
/** Road-surface height per point, present only when the district carries `elevation`. */
|
|
389
|
+
heights?: readonly number[];
|
|
390
|
+
/** Lap length, meters. */
|
|
391
|
+
length: number;
|
|
392
|
+
/** Ids of the district streets the lap runs on — style exactly these as track surface. */
|
|
393
|
+
streets: readonly string[];
|
|
394
|
+
seals: readonly CityRaceSeal[];
|
|
395
|
+
corners: readonly CircuitCorner[];
|
|
396
|
+
kerbs: readonly CityRaceKerb[];
|
|
397
|
+
/** Ordered gates, finish last — ready for `raceTrack({ checkpoints, laps })`. */
|
|
398
|
+
checkpoints: readonly CircuitGate[];
|
|
399
|
+
laps: number;
|
|
400
|
+
start: CityRaceStart;
|
|
401
|
+
grid: readonly CityRaceGridSlot[];
|
|
402
|
+
/** Arc-length fractions (0..1) where each timing sector begins; the first is always 0. */
|
|
403
|
+
sectors: readonly number[];
|
|
404
|
+
/** Tightest radius (m) the finished racing line actually holds. */
|
|
405
|
+
tightestRadius: number;
|
|
406
|
+
}
|
|
280
407
|
/** A resolved city district: world-space network, zoned lots, parks, and furniture. */
|
|
281
408
|
export interface ResolvedCity {
|
|
282
409
|
center: readonly [number, number, number];
|
|
@@ -299,7 +426,19 @@ export interface ResolvedCity {
|
|
|
299
426
|
hedges: readonly CityHedge[];
|
|
300
427
|
driveways: readonly CityDriveway[];
|
|
301
428
|
parkingLots: readonly CityParking[];
|
|
429
|
+
/** Parked vehicles along the curbs and inside the parking pads. */
|
|
430
|
+
vehicles: readonly CityVehicle[];
|
|
431
|
+
/** Traffic signals and sign posts, one per controlled junction approach. */
|
|
432
|
+
signals: readonly CitySignal[];
|
|
433
|
+
/** The instanced street race through these streets, when `race` is on and a lap could be found. */
|
|
434
|
+
race?: ResolvedRace;
|
|
302
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* One solid per wall and roof piece of every lot, grounded the way the city renderer grounds it:
|
|
438
|
+
* grade at the highest lot corner, foundations down to half a metre under the lowest.
|
|
439
|
+
* @capability city-district editor-authorable procedural city district (streets, zoning, buildings, furniture)
|
|
440
|
+
*/
|
|
441
|
+
export declare function citySolids(city: ResolvedCity, sampleHeight?: (x: number, z: number) => number): WorldSolid[];
|
|
303
442
|
/** Extended resolve context: sibling `cityzone` volumes that override the band/mix locally. */
|
|
304
443
|
export interface CityResolveContext extends SceneKindResolveContext {
|
|
305
444
|
zoneOverrides?: readonly SceneKindObject[];
|