@adatechnology/game-urban 0.0.0-stage → 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1087 @@
1
+ // src/budget.ts
2
+ function createLightBudget(count) {
3
+ const budget = {
4
+ left: count,
5
+ take() {
6
+ return budget.left-- > 0;
7
+ }
8
+ };
9
+ return budget;
10
+ }
11
+
12
+ // src/scene.ts
13
+ import { boxRadius } from "@adatechnology/game-floorplan";
14
+ var ROOT = -1;
15
+ var DEFAULT_CYLINDER_SEGMENTS = 14;
16
+ var DEFAULT_CONE_SEGMENTS = 6;
17
+ var DEFAULT_FENCE_WIRE = 9079950;
18
+ var DEFAULT_FENCE_POST = 6974574;
19
+ var DEFAULT_LABEL_FONT = '700 56px "Arial Narrow", Arial, sans-serif';
20
+ function createUrbanBuilder(random, options = {}) {
21
+ const parts = [];
22
+ const items = [];
23
+ const windows = { lit: [], dark: [] };
24
+ const lights = options.budget ?? createLightBudget(Number.POSITIVE_INFINITY);
25
+ const pick = (list) => list[Math.floor(random() * list.length)];
26
+ const group = (x, y, z, ry = 0, parent = ROOT) => parts.push({ shape: "group", parent, x, y, z, ry }) - 1;
27
+ const box = (x, y, z, width, height, depth, color, o = {}) => {
28
+ const part = { shape: "box", parent: o.parent ?? ROOT, x, y: y + height / 2, z, width, height, depth, color, emissive: o.emissive ?? false, ry: o.ry ?? 0, rz: o.rz ?? 0, radius: boxRadius(width, height, depth) };
29
+ if (o.style) part.style = o.style;
30
+ parts.push(part);
31
+ };
32
+ const cylinder = (x, y, z, radiusTop, radiusBottom, height, color, parent = ROOT, segments = DEFAULT_CYLINDER_SEGMENTS, style) => {
33
+ const part = { shape: "cylinder", parent, x, y: y + height / 2, z, radiusTop, radiusBottom, height, color, segments };
34
+ if (style) part.style = style;
35
+ parts.push(part);
36
+ };
37
+ const cone = (x, y, z, radius, height, color, parent = ROOT, segments = DEFAULT_CONE_SEGMENTS) => {
38
+ parts.push({ shape: "cone", parent, x, y: y + height / 2, z, radius, height, color, segments });
39
+ };
40
+ const prism = (x, y, z, width, height, depth, color, parent = ROOT, ry = 0) => {
41
+ parts.push({ shape: "prism", parent, x, y, z, width, height, depth, color, ry });
42
+ };
43
+ const plane = (x, y, z, width, depth, color, style, parent = ROOT) => {
44
+ const part = { shape: "plane", parent, x, y, z, width, depth, color };
45
+ if (style) part.style = style;
46
+ parts.push(part);
47
+ };
48
+ const vault = (part) => {
49
+ parts.push({ shape: "vault", ...part, parent: part.parent ?? ROOT });
50
+ };
51
+ const terrain = (grid, parent = ROOT) => {
52
+ parts.push({ shape: "terrain", parent, grid });
53
+ };
54
+ const crown = (x, y, z, radius, color, parent = ROOT) => {
55
+ parts.push({ shape: "crown", parent, x, y, z, radius, color });
56
+ };
57
+ const line = (points, color, parent = ROOT) => {
58
+ parts.push({ shape: "line", parent, points, color });
59
+ };
60
+ const label = (lines, x, y, z, width, height, ry, o, parent = ROOT) => {
61
+ parts.push({ shape: "label", parent, x, y, z, width, height, ry, lines, background: o.background, foreground: o.foreground, font: o.font ?? DEFAULT_LABEL_FONT, canvas: o.canvas ?? { width: 512, height: 128 } });
62
+ };
63
+ const light = (part) => {
64
+ parts.push({ shape: "light", kind: "point", parent: ROOT, decay: 2, flicker: false, ...part });
65
+ };
66
+ const spot = (part) => {
67
+ parts.push({ shape: "light", kind: "spot", parent: ROOT, ...part });
68
+ };
69
+ const place = (kind, id, x, z, o = {}) => {
70
+ const part = { shape: "placement", parent: o.parent ?? ROOT, kind, id, x, y: o.y ?? 0, z, ry: o.ry ?? 0, scale: o.scale ?? 1, seed: o.seed ?? `${id}:${x}:${z}` };
71
+ if (o.color !== void 0) part.color = o.color;
72
+ parts.push(part);
73
+ };
74
+ const item = (x, y, z, width, height, depth, color, ry = 0, rx = 0, rz = 0) => {
75
+ items.push({ x, y, z, width, height, depth, color, rx, ry, rz });
76
+ };
77
+ const fence = (x0, z0, x1, z1, height, color = DEFAULT_FENCE_POST) => {
78
+ const count = Math.ceil(Math.hypot(x1 - x0, z1 - z0) / 3);
79
+ for (let index = 0; index <= count; index++) {
80
+ const t = index / count;
81
+ cylinder(x0 + (x1 - x0) * t, 0, z0 + (z1 - z0) * t, 0.05, 0.05, height, color, ROOT, 5);
82
+ }
83
+ for (const level of [height * 0.35, height * 0.65, height * 0.98]) line([[x0, level, z0], [x1, level, z1]], DEFAULT_FENCE_WIRE);
84
+ };
85
+ const add = (silhouette) => {
86
+ const offset = parts.length;
87
+ for (const part of silhouette.parts) parts.push(part.parent < 0 ? part : { ...part, parent: part.parent + offset });
88
+ for (const window of silhouette.windows) (window.isLit ? windows.lit : windows.dark).push(window);
89
+ };
90
+ const scene = () => ({ parts, items, windows });
91
+ return { random, pick, lights, parts, items, windows, group, box, cylinder, cone, prism, plane, vault, terrain, crown, line, label, light, spot, place, item, fence, add, scene };
92
+ }
93
+
94
+ // src/poles.ts
95
+ var on = (o) => o.on ?? true;
96
+ function drawMast(b, mast, x, z, parent = -1) {
97
+ b.cylinder(x, 0, z, mast.radiusTop, mast.radiusBottom, mast.height, mast.color, parent, mast.segments, mast.style);
98
+ }
99
+ function spendLight(b, light, x, z, o) {
100
+ if (on(o) && b.lights.take()) b.light({ x: x + (light.reach ?? 0), y: light.y, z: z + (light.z ?? 0), color: light.color, intensity: light.intensity, distance: light.distance, flicker: o.flicker ?? false });
101
+ }
102
+ var doubleArm = (b, spec, o) => {
103
+ const group = b.group(o.x, 0, o.z, o.ry ?? 0);
104
+ drawMast(b, spec.mast, 0, 0, group);
105
+ for (const side of [-1, 1]) {
106
+ b.box(side * spec.arm.reach, spec.arm.y, 0, spec.arm.width, spec.arm.height, spec.arm.depth, spec.arm.color, { parent: group });
107
+ b.box(side * spec.lamp.reach, spec.lamp.y, 0, spec.lamp.width, spec.lamp.height, spec.lamp.depth, on(o) ? spec.lens.lit : spec.lens.unlit, { parent: group, emissive: on(o) });
108
+ }
109
+ spendLight(b, spec.light, o.x, o.z, o);
110
+ };
111
+ var singleArm = (b, spec, o) => {
112
+ const dir = o.dir ?? 1;
113
+ drawMast(b, spec.mast, o.x, o.z);
114
+ b.box(o.x + dir * spec.arm.reach, spec.arm.y, o.z, spec.arm.width, spec.arm.height, spec.arm.depth, spec.arm.color);
115
+ b.box(o.x + dir * spec.lamp.reach, spec.lamp.y, o.z, spec.lamp.width, spec.lamp.height, spec.lamp.depth, on(o) ? spec.lens.lit : spec.lens.unlit, { emissive: on(o) });
116
+ if (o.transformer) b.cylinder(o.x - dir * spec.transformer.offset, spec.transformer.y, o.z, spec.transformer.radius, spec.transformer.radius, spec.transformer.height, spec.transformer.color, -1, spec.transformer.segments);
117
+ spendLight(b, { ...spec.light, reach: dir * (spec.light.reach ?? spec.lamp.reach) }, o.x, o.z, o);
118
+ };
119
+ var lantern = (b, spec, o) => {
120
+ drawMast(b, spec.mast, o.x, o.z);
121
+ b.box(o.x + spec.lamp.reach, spec.lamp.y, o.z, spec.lamp.width, spec.lamp.height, spec.lamp.depth, on(o) ? spec.lens.lit : spec.lens.unlit, { emissive: on(o) });
122
+ b.cone(o.x, spec.cap.y, o.z, spec.cap.radius, spec.cap.height, spec.cap.color, -1, spec.cap.segments);
123
+ spendLight(b, spec.light, o.x, o.z, o);
124
+ };
125
+ var crossarm = (b, spec, o) => {
126
+ drawMast(b, spec.mast, o.x, o.z);
127
+ b.box(o.x + spec.arm.reach, spec.arm.y, o.z, spec.arm.width, spec.arm.height, spec.arm.depth, spec.arm.color);
128
+ b.box(o.x + spec.lamp.reach, spec.lamp.y, o.z, spec.lamp.width, spec.lamp.height, spec.lamp.depth, on(o) ? spec.lens.lit : spec.lens.unlit, { emissive: on(o) });
129
+ spendLight(b, { ...spec.light, reach: spec.light.reach ?? spec.lamp.reach }, o.x, o.z, o);
130
+ };
131
+ var floodTower = (b, spec, o) => {
132
+ for (const a of [-1, 1]) for (const c of [-1, 1]) b.box(o.x + a * spec.legs.offset, 0, o.z + c * spec.legs.offset, spec.legs.size, spec.legs.height, spec.legs.size, spec.legs.color);
133
+ b.box(o.x + spec.deck.reach, spec.deck.y, o.z, spec.deck.width, spec.deck.height, spec.deck.depth, spec.deck.color);
134
+ for (let index = 0; index < spec.heads.count; index++) {
135
+ b.box(o.x + spec.heads.start + index * spec.heads.spacing, spec.heads.y, o.z + spec.heads.z, spec.heads.width, spec.heads.height, spec.heads.depth, on(o) ? spec.lens.lit : spec.lens.unlit, { emissive: on(o) });
136
+ }
137
+ spendLight(b, spec.light, o.x, o.z, o);
138
+ };
139
+ var POLE_SHAPES = { double_arm: doubleArm, single_arm: singleArm, lantern, crossarm, flood_tower: floodTower };
140
+ var LED = {
141
+ mast: { radiusTop: 0.1, radiusBottom: 0.14, height: 9, color: 5593438, style: { metalness: 0.6, roughness: 0.5 } },
142
+ arm: { reach: 0.8, y: 8.8, width: 1.6, height: 0.1, depth: 0.12, color: 5593438 },
143
+ lamp: { reach: 1.5, y: 8.6, width: 0.6, height: 0.12, depth: 0.3 },
144
+ lens: { lit: 15660287, unlit: 3815994 },
145
+ light: { color: 14674175, intensity: 1.3, distance: 24, y: 8 }
146
+ };
147
+ var CONCRETE = {
148
+ mast: { radiusTop: 0.12, radiusBottom: 0.2, height: 8, color: 9079428, segments: 4 },
149
+ arm: { reach: 0.7, y: 7.6, width: 1.4, height: 0.1, depth: 0.1, color: 6974054 },
150
+ lamp: { reach: 1.35, y: 7.45, width: 0.5, height: 0.16, depth: 0.3 },
151
+ lens: { lit: 16752704, unlit: 3815994 },
152
+ light: { color: 16751168, intensity: 1.3, distance: 20, y: 7.2 },
153
+ transformer: { offset: 0.35, y: 6.2, radius: 0.28, height: 0.7, color: 5922402, segments: 8 }
154
+ };
155
+ var IRON = {
156
+ mast: { radiusTop: 0.06, radiusBottom: 0.12, height: 4, color: 1974306, segments: 8 },
157
+ lamp: { reach: 0, y: 4, width: 0.42, height: 0.5, depth: 0.42 },
158
+ cap: { y: 4.5, radius: 0.36, height: 0.3, color: 1974306, segments: 4 },
159
+ lens: { lit: 16765072, unlit: 2763306 },
160
+ light: { color: 16763008, intensity: 1, distance: 14, y: 3.9 }
161
+ };
162
+ var WOOD = {
163
+ mast: { radiusTop: 0.11, radiusBottom: 0.14, height: 7, color: 5916208, segments: 6 },
164
+ arm: { reach: 0, y: 6.6, width: 1.2, height: 0.08, depth: 0.08, color: 4864552 },
165
+ lamp: { reach: 0.5, y: 6.35, width: 0.16, height: 0.22, depth: 0.16 },
166
+ lens: { lit: 16769162, unlit: 3815994 },
167
+ light: { color: 16765562, intensity: 0.9, distance: 16, y: 6.2 }
168
+ };
169
+ var FLOOD = {
170
+ legs: { offset: 0.4, height: 12, size: 0.12, color: 6974574 },
171
+ deck: { reach: 0, y: 12, width: 2, height: 0.15, depth: 1.2, color: 6974574 },
172
+ heads: { count: 3, start: -0.6, spacing: 0.6, y: 12.2, z: 0.4, width: 0.45, height: 0.35, depth: 0.2 },
173
+ lens: { lit: 16773848, unlit: 3815994 },
174
+ light: { color: 16773328, intensity: 1.6, distance: 34, y: 11.5, z: 2 }
175
+ };
176
+ var DEFAULT_POLES = [
177
+ { id: "led_double", shape: "double_arm", spec: LED },
178
+ { id: "concrete_arm", shape: "single_arm", spec: CONCRETE },
179
+ { id: "cast_iron", shape: "lantern", spec: IRON },
180
+ { id: "wood_crossarm", shape: "crossarm", spec: WOOD },
181
+ { id: "flood_tower", shape: "flood_tower", spec: FLOOD }
182
+ ];
183
+
184
+ // src/streets.ts
185
+ var DEFAULT_ROAD_STYLE = { color: 2237480, dash: { color: 9404239, every: 5, first: 2, length: 1.8, width: 0.16, height: 0.01, y: 0.025 } };
186
+ var DEFAULT_WALK_STYLE = { color: 3816252, height: 0.15, castShadow: false };
187
+ var ROAD_LEVEL = 0.02;
188
+ var DEFAULT_GROUND_COLOR = 1382426;
189
+ var DEFAULT_GROUND_SIZE = 600;
190
+ var roadStyle = (o) => ({ ...DEFAULT_ROAD_STYLE, ...o?.road, dash: { ...DEFAULT_ROAD_STYLE.dash, ...o?.road?.dash } });
191
+ var walkStyle = (o) => ({ ...DEFAULT_WALK_STYLE, ...o?.walk });
192
+ function drawRoad(b, x, z, w, l, along, options) {
193
+ const style = roadStyle(options);
194
+ const alongX = along === "x";
195
+ b.plane(x, ROAD_LEVEL, z, alongX ? l : w, alongX ? w : l, style.color);
196
+ const { dash } = style;
197
+ for (let u = -l / 2 + dash.first; u < l / 2; u += dash.every) {
198
+ b.item(alongX ? x + u : x, dash.y, alongX ? z : z + u, alongX ? dash.length : dash.width, dash.height, alongX ? dash.width : dash.length, dash.color);
199
+ }
200
+ }
201
+ function drawWalk(b, x, z, w, d, options) {
202
+ const style = walkStyle(options);
203
+ b.box(x, 0, z, w, style.height, d, style.color, { style: { castShadow: style.castShadow } });
204
+ }
205
+ function drawGround(b, color = DEFAULT_GROUND_COLOR, size = DEFAULT_GROUND_SIZE) {
206
+ b.plane(0, 0, 0, size, size, color);
207
+ }
208
+ function drawStreetGrid(b, block, count, width, options) {
209
+ for (let k = -count; k <= count; k++) {
210
+ drawRoad(b, k * block, 0, width, block * 2 * count + width, "z", options);
211
+ drawRoad(b, 0, k * block, width, block * 2 * count + width, "x", options);
212
+ }
213
+ for (let i = -count; i < count; i++) for (let j = -count; j < count; j++) drawWalk(b, i * block + block / 2, j * block + block / 2, block - width, block - width, options);
214
+ }
215
+
216
+ // src/block.ts
217
+ import { createCityBuilding } from "@adatechnology/game-floorplan";
218
+ var DEFAULT_FACADES = [3882821, 4866104, 3489853, 4602426, 4143924, 3093561, 5327167, 5920334];
219
+ var DEFAULT_PARTITIONS = 2;
220
+ var DEFAULT_GAP = 0.08;
221
+ var STREET_MARGIN = 2;
222
+ var FOOTPRINT_TRIM = 1.2;
223
+ var FOOTPRINT_JITTER = 1.5;
224
+ var HEIGHT_CURVE = 1.6;
225
+ function drawBuilding(b, x, z, width, depth, height, color, options = {}) {
226
+ b.add(createCityBuilding({ x, z, width, depth, height, color, random: b.random, shopChance: options.shop, litChance: options.lit }));
227
+ return { x, z, width, depth, height, color };
228
+ }
229
+ var lerp = (a, b, t) => a + (b - a) * t;
230
+ function fillBlock(b, cx, cz, size, minHeight, maxHeight, options = {}) {
231
+ const placed = [];
232
+ const palette = options.palette ?? DEFAULT_FACADES;
233
+ const half = (size - STREET_MARGIN) / 2;
234
+ const k = options.k || DEFAULT_PARTITIONS;
235
+ const lot = (size - STREET_MARGIN) / k;
236
+ for (let i = 0; i < k; i++) {
237
+ for (let j = 0; j < k; j++) {
238
+ if (b.random() < (options.gap || DEFAULT_GAP)) continue;
239
+ const width = lot - FOOTPRINT_TRIM - b.random() * FOOTPRINT_JITTER;
240
+ const depth = lot - FOOTPRINT_TRIM - b.random() * FOOTPRINT_JITTER;
241
+ const height = lerp(minHeight, maxHeight, Math.pow(b.random(), HEIGHT_CURVE));
242
+ const x = cx - half + lot * (i + 0.5);
243
+ const z = cz - half + lot * (j + 0.5);
244
+ const color = b.pick(palette);
245
+ placed.push(drawBuilding(b, x, z, width, depth, height, color, options));
246
+ }
247
+ }
248
+ return placed;
249
+ }
250
+
251
+ // src/props.ts
252
+ var DEFAULT_PROP_COLORS = {
253
+ tent: 5199416,
254
+ trunk: 3811868,
255
+ pines: [2044708, 2373674, 1781024],
256
+ crowns: [3425578, 4016684, 3095846],
257
+ sandbags: 9075290,
258
+ fence: 6974574,
259
+ wire: 2763306,
260
+ label: { background: "rgba(16,18,22,.9)", foreground: "#e8dfcf" },
261
+ watchtower: { leg: 4864554, cabin: 5199416, deck: 3815978 }
262
+ };
263
+ var LABEL_FONT = '700 44px "Arial Narrow", Arial, sans-serif';
264
+ var LABEL_CANVAS = { width: 1024, height: 200 };
265
+ var SANDBAG_LENGTH = 0.56;
266
+ var colors = (c) => ({ ...DEFAULT_PROP_COLORS, ...c });
267
+ function drawFence(b, x0, z0, x1, z1, height, color) {
268
+ b.fence(x0, z0, x1, z1, height, color);
269
+ }
270
+ function drawTent(b, x, z, ry, w, d, color, c) {
271
+ b.prism(x, 0, z, w, w * 0.7, d, color ?? colors(c).tent, -1, ry);
272
+ }
273
+ function drawPine(b, x, z, scale = 1, y = 0, c) {
274
+ const palette = colors(c);
275
+ b.cylinder(x, y, z, 0.12 * scale, 0.16 * scale, 1 * scale, palette.trunk);
276
+ const green = b.pick(palette.pines);
277
+ b.cone(x, y + 0.8 * scale, z, 1.1 * scale, 2.2 * scale, green);
278
+ b.cone(x, y + 2.1 * scale, z, 0.8 * scale, 1.8 * scale, green);
279
+ }
280
+ function drawTree(b, x, z, scale = 1, c) {
281
+ const palette = colors(c);
282
+ b.cylinder(x, 0, z, 0.12 * scale, 0.18 * scale, 1.8 * scale, palette.trunk);
283
+ b.crown(x, 2.6 * scale, z, 1.3 * scale, b.pick(palette.crowns));
284
+ }
285
+ function drawContainer(b, x, y, z, ry, color) {
286
+ const group = b.group(x, y, z, ry);
287
+ b.box(0, 0, 0, 2.44, 2.6, 6.06, color, { parent: group, style: { roughness: 0.7, metalness: 0.3 } });
288
+ for (let k = -2; k <= 2; k++) b.box(k * 0.5, 0, 3.04, 0.06, 2.6, 0.04, 1710618, { parent: group });
289
+ }
290
+ function drawWatchtower(b, x, z, searchlight = false, c) {
291
+ const palette = colors(c).watchtower;
292
+ for (const a of [-1, 1]) for (const d of [-1, 1]) b.box(x + a * 1.2, 0, z + d * 1.2, 0.25, 7, 0.25, palette.leg);
293
+ b.box(x, 7, z, 3.2, 1.2, 3.2, palette.cabin);
294
+ b.box(x, 8.2, z, 3.6, 0.15, 3.6, palette.deck);
295
+ for (const side of [-1.5, 1.5]) b.box(x + side, 8.2, z, 0.15, 1.6, 0.15, palette.deck);
296
+ if (searchlight) b.spot({ x, y: 9, z, color: 15134463, intensity: 2.4, distance: 70, decay: 1.2, angle: 0.35, penumbra: 0.5, target: { x: x + 20, y: 0, z: z + 20 }, sweep: { speed: 0.5, radius: 25 } });
297
+ }
298
+ function drawSandbags(b, x, z, length, along, rows = 3, c) {
299
+ const color = colors(c).sandbags;
300
+ for (let r = 0; r < rows; r++) {
301
+ for (let i = 0; i < length / SANDBAG_LENGTH; i++) {
302
+ const u = -length / 2 + 0.28 + i * SANDBAG_LENGTH + r % 2 * 0.28;
303
+ b.item(along === "x" ? x + u : x, r * 0.21, along === "x" ? z : z + u, along === "x" ? 0.55 : 0.32, 0.22, along === "x" ? 0.32 : 0.55, color);
304
+ }
305
+ }
306
+ }
307
+ function drawStripLabel(b, x, z, title, subtitle, c) {
308
+ const { background, foreground } = colors(c).label;
309
+ b.label([title, subtitle], x, 2.4, z, 22, 4.4, 0, { background, foreground, font: LABEL_FONT, canvas: LABEL_CANVAS });
310
+ }
311
+ function drawWires(b, points, y, color, c) {
312
+ b.line(points.map(([px, pz]) => [px, y, pz]), color ?? colors(c).wire);
313
+ }
314
+
315
+ // src/kit.ts
316
+ import { applyPatches, mergeById, removeIds } from "@adatechnology/game-contracts";
317
+ import { createSilhouetteRandom } from "@adatechnology/game-floorplan";
318
+
319
+ // src/neighbourhoods/houses.ts
320
+ import { createChalet, createColonialHouse, createCompanyHouse, createDetachedHouse, createFarmhouse, createSlabHouse, createStiltHouse, createTwoStoreyHouse } from "@adatechnology/game-floorplan";
321
+ var DEFAULT_WIDTH = 8;
322
+ var DEFAULT_DEPTH = 10;
323
+ var DEFAULT_COLOR = 13154456;
324
+ function turned(silhouette, ry) {
325
+ const first = silhouette.parts[0];
326
+ if (ry === void 0 || !first || first.shape !== "group") return silhouette;
327
+ return { ...silhouette, parts: [{ ...first, ry }, ...silhouette.parts.slice(1)] };
328
+ }
329
+ var SILHOUETTE_TYPOLOGIES = {
330
+ two_storey: (r, random) => createTwoStoreyHouse({ x: r.x, z: r.z, width: r.width ?? DEFAULT_WIDTH, depth: r.depth ?? DEFAULT_DEPTH, color: r.color ?? DEFAULT_COLOR, roofColor: r.roofColor, ry: r.ry, random }),
331
+ detached: (r, random) => createDetachedHouse({ x: r.x, z: r.z, width: r.width ?? DEFAULT_WIDTH, depth: r.depth ?? DEFAULT_DEPTH, color: r.color ?? DEFAULT_COLOR, roofColor: r.roofColor, ry: r.ry, isBoarded: r.isBoarded, random }),
332
+ slab: (r, random) => createSlabHouse({ x: r.x, z: r.z, width: r.width ?? 7, depth: r.depth ?? 8, floors: r.floors ?? 1, color: r.color ?? 11052188, random }),
333
+ colonial: (r, random) => turned(createColonialHouse({ x: r.x, z: r.z, width: r.width ?? 7, color: r.color ?? 13681832, hasDoor: r.hasDoor ?? false, random }), r.ry),
334
+ chalet: (r, random) => createChalet({ x: r.x, z: r.z, color: r.color, ry: r.ry, random }),
335
+ company_house: (r, random) => turned(createCompanyHouse({ x: r.x, z: r.z, color: r.color, random }), r.ry),
336
+ stilt: (r, random) => createStiltHouse({ x: r.x, z: r.z, color: r.color, random }),
337
+ farmhouse: (r, random) => createFarmhouse({ x: r.x, z: r.z, random })
338
+ };
339
+ function createSilhouetteHouses(typologies = SILHOUETTE_TYPOLOGIES) {
340
+ return (typology, request, b) => {
341
+ const factory = typologies[typology];
342
+ if (!factory) throw new Error(`The house provider has no typology "${typology}"`);
343
+ b.add(factory(request, b.random));
344
+ };
345
+ }
346
+
347
+ // src/neighbourhoods/compose.ts
348
+ var LABEL_OFFSET_Z = 28;
349
+ var DEFAULT_LOCALE = "pt-BR";
350
+ var SAMPLE_GROUND = { color: 1974564, size: 500 };
351
+ function composePattern(kit, pattern, composer, b, origin, options = {}) {
352
+ const locale = options.locale ?? DEFAULT_LOCALE;
353
+ const providers = options.providers ?? {};
354
+ const house = providers.house ?? createSilhouetteHouses();
355
+ const plan = { id: pattern.id, origin: { ...origin }, houses: [], buildings: [], poles: [], vehicles: [], plants: [] };
356
+ const context = {
357
+ kit,
358
+ b,
359
+ pattern,
360
+ params: pattern.params,
361
+ x0: origin.x,
362
+ z0: origin.z,
363
+ plan,
364
+ isLit: (share) => share >= 1 || b.random() < share,
365
+ pole: ({ id, ...rest }) => {
366
+ kit.poles.get(id ?? pattern.pole).build(b, rest);
367
+ plan.poles.push({ pole: id ?? pattern.pole, x: rest.x, z: rest.z, on: rest.on ?? true });
368
+ },
369
+ house: (typology, request) => {
370
+ house(typology, request, b);
371
+ plan.houses.push({ typology, x: request.x, z: request.z, ry: request.ry ?? 0 });
372
+ },
373
+ vehicle: (request) => {
374
+ providers.vehicle?.(request, b);
375
+ plan.vehicles.push(request);
376
+ },
377
+ plant: (request) => {
378
+ if (providers.plant) providers.plant(request, b);
379
+ else if (request.kind === "pine") kit.props.pine(b, request.x, request.z, request.scale);
380
+ else kit.props.tree(b, request.x, request.z, request.scale);
381
+ plan.plants.push(request);
382
+ },
383
+ building: (x, z, width, depth, height, color, o) => {
384
+ plan.buildings.push(kit.block.building(b, x, z, width, depth, height, color, o));
385
+ }
386
+ };
387
+ composer(context);
388
+ const text = pattern.text[locale] ?? pattern.text[DEFAULT_LOCALE];
389
+ kit.props.label(b, origin.x, origin.z + LABEL_OFFSET_Z, text.title, text.caption);
390
+ return plan;
391
+ }
392
+ function patternMarker(pattern, origin, locale = DEFAULT_LOCALE) {
393
+ const text = pattern.text[locale] ?? pattern.text[DEFAULT_LOCALE];
394
+ return { x: origin.x, y: pattern.marker.height, z: origin.z + (pattern.marker.dz ?? 0), label: text.label, detail: text.detail };
395
+ }
396
+
397
+ // src/neighbourhoods/composers.ts
398
+ var composeDowntown = ({ b, kit, pattern, params, x0, z0, pole, building, vehicle }) => {
399
+ b.plane(x0, 0.02, z0, params.roadLength, pattern.streetWidth, params.roadColor);
400
+ b.box(x0, 0, z0, params.roadLength, params.median.height, params.median.width, params.median.color);
401
+ for (let u = params.poles.from; u <= params.poles.to; u += pattern.spacing) pole({ x: x0 + u, z: z0, on: true });
402
+ const { buildings } = params;
403
+ for (let i = 0; i < buildings.perRow; i++) {
404
+ const x = x0 + buildings.first + i * buildings.pitch;
405
+ const northHeight = buildings.north.minHeight + b.random() * buildings.north.range;
406
+ building(x, z0 - buildings.rowOffset, buildings.size, buildings.size, northHeight, b.pick(kit.block.facades), { lit: buildings.north.lit });
407
+ building(x, z0 + buildings.rowOffset, buildings.size, buildings.size, buildings.south.minHeight + b.random() * buildings.south.range, b.pick(kit.block.facades), { lit: buildings.south.lit });
408
+ }
409
+ kit.streets.walk(b, x0, z0 - params.walks.offset, params.walks.length, pattern.walkWidth);
410
+ kit.streets.walk(b, x0, z0 + params.walks.offset, params.walks.length, pattern.walkWidth);
411
+ vehicle({ x: x0 + params.car.dx, z: z0 + params.car.dz, ry: params.car.ry, color: params.car.color });
412
+ };
413
+ var composeSuburb = ({ b, kit, pattern, params, x0, z0, pole, house, isLit }) => {
414
+ kit.streets.road(b, x0, z0, pattern.streetWidth, params.roadLength, "x");
415
+ kit.streets.walk(b, x0, z0 - params.walkOffset, params.roadLength, pattern.walkWidth);
416
+ kit.streets.walk(b, x0, z0 + params.walkOffset, params.roadLength, pattern.walkWidth);
417
+ const { houses, walls } = params;
418
+ for (let i = 0; i < houses.count; i++) {
419
+ const x = x0 + houses.first + i * houses.pitch;
420
+ house(houses.north.typologies[i % 2 ? 0 : 1], { x, z: z0 + houses.north.z, width: houses.width, depth: houses.depth, color: b.pick(houses.north.colors), roofColor: houses.roofColor, ry: 0 });
421
+ b.box(x, 0, z0 - walls.offset, walls.length, walls.height, walls.thickness, walls.color);
422
+ b.box(x + walls.gateOffset, 0, z0 - walls.gateInset, walls.gateWidth, walls.gateHeight, 0.06, walls.gateColor);
423
+ b.box(x, 0, z0 + walls.offset, walls.length, walls.height, walls.thickness, walls.color);
424
+ b.box(x - walls.gateOffset, 0, z0 + walls.gateInset, walls.gateWidth, walls.gateHeight, 0.06, walls.gateColor);
425
+ }
426
+ for (const u of params.poles.at) pole({ x: x0 + u, z: z0 + params.poles.z, dir: 1, on: isLit(pattern.lit), transformer: u > params.poles.transformerFrom });
427
+ kit.props.wires(b, [[x0 - params.wires.half, z0 + params.poles.z], [x0 + params.wires.half, z0 + params.poles.z]], params.wires.height);
428
+ for (let i = 0; i < houses.count; i++) {
429
+ house("detached", { x: x0 + houses.first + i * houses.pitch, z: z0 + houses.south.z, width: houses.width, depth: houses.depth, color: b.pick(houses.south.colors), roofColor: houses.roofColor, ry: Math.PI });
430
+ }
431
+ };
432
+ var composeWorkingClass = ({ b, kit, pattern, params, x0, z0, pole, house, isLit }) => {
433
+ kit.streets.road(b, x0, z0, pattern.streetWidth, 60, "x");
434
+ const { houses } = params;
435
+ for (let i = 0; i < houses.count; i++) {
436
+ const x = x0 + houses.first + i * houses.pitch;
437
+ house("slab", { x, z: z0 + houses.north.z, width: houses.width, depth: houses.depth, floors: 1 + Math.floor(b.random() * houses.maxFloors), color: b.pick(houses.north.colors) });
438
+ house("slab", { x, z: z0 + houses.south.z, width: houses.width, depth: houses.depth, floors: 1 + Math.floor(b.random() * houses.maxFloors), color: b.pick(houses.south.colors) });
439
+ }
440
+ for (let u = params.poles.from; u <= params.poles.to; u += pattern.spacing + b.random() * params.poles.jitter) pole({ x: x0 + u, z: z0 + params.poles.z, dir: 1, on: isLit(pattern.lit), transformer: true });
441
+ const { wires } = params;
442
+ for (let k = 0; k < wires.count; k++) {
443
+ kit.props.wires(b, [[x0 + wires.from, z0 + wires.z + k * wires.step], [x0 + wires.to, z0 + wires.z + (b.random() - 0.5) * wires.sag]], wires.height + k * wires.heightStep, wires.color);
444
+ }
445
+ };
446
+ var composeHistoricStreet = ({ b, pattern, params, x0, z0, pole, house, isLit }) => {
447
+ const { cobbles, rows } = params;
448
+ b.plane(x0, cobbles.y, z0, cobbles.length, pattern.streetWidth, cobbles.color);
449
+ for (let u = cobbles.from; u < cobbles.to; u += cobbles.step) b.item(x0 + u, cobbles.y, z0 + (b.random() - 0.5) * cobbles.spread, cobbles.sizes[0], cobbles.sizes[1], cobbles.sizes[2], b.pick(cobbles.colors));
450
+ for (const side of [rows.north, rows.south]) {
451
+ let x = x0 + rows.from;
452
+ while (x < x0 + rows.to) {
453
+ const width = rows.minWidth + Math.floor(b.random() * rows.widthSteps);
454
+ house("colonial", { x: x + width / 2, z: z0 + side.z, width, color: b.pick(side.colors), hasDoor: true, ry: side === rows.south ? Math.PI : void 0 });
455
+ x += width;
456
+ }
457
+ }
458
+ for (let u = params.poles.from; u <= params.poles.to; u += params.poles.step) {
459
+ for (const s of [-1, 1]) pole({ x: x0 + u + (s > 0 ? params.poles.sideOffset : 0), z: z0 + s * params.poles.z, on: isLit(pattern.lit) });
460
+ }
461
+ };
462
+ var composeIndustrial = ({ b, kit, pattern, params, x0, z0, pole }) => {
463
+ b.plane(x0, 0.02, z0, params.yard.length, pattern.streetWidth, params.yard.color);
464
+ const { hangar } = params;
465
+ for (const s of [-1, 1]) {
466
+ const g = b.group(x0 + s * hangar.x, 0, z0 + hangar.z);
467
+ b.box(0, 0, 0, hangar.width, hangar.height, hangar.depth, hangar.color, { parent: g });
468
+ b.vault({ x: 0, y: hangar.roofY, z: 0, radius: hangar.roofRadius, length: hangar.depth, arc: Math.PI, segments: 16, color: hangar.roofColor, rotation: { x: Math.PI / 2, y: 0, z: Math.PI / 2 }, scale: { x: 1, y: 1, z: 0.25 }, parent: g });
469
+ b.box(0, 0, hangar.depth / 2 + 0.05, hangar.doorWidth, hangar.doorHeight, 0.1, hangar.doorColor, { parent: g });
470
+ b.box(0, 6, hangar.depth / 2 + 0.06, 10, 1.2, 0.05, hangar.stripeColor, { parent: g });
471
+ }
472
+ for (const tower of params.towers) pole({ x: x0 + tower.dx, z: z0 + tower.dz, on: tower.on });
473
+ kit.props.container(b, x0 + params.container.dx, 0, z0 + params.container.dz, params.container.ry, params.container.color);
474
+ };
475
+ var composeRailwayVillage = ({ b, kit, pattern, params, x0, z0, pole, house, isLit }) => {
476
+ kit.streets.road(b, x0, z0, pattern.streetWidth, 60, "x");
477
+ const { houses } = params;
478
+ for (let i = 0; i < houses.count; i++) {
479
+ const x = x0 + houses.first + i * houses.pitch;
480
+ house("company_house", { x, z: z0 + houses.north.z, color: b.pick(houses.north.colors) });
481
+ house("company_house", { x, z: z0 + houses.south.z, color: houses.south.color, ry: Math.PI });
482
+ }
483
+ for (const u of params.poles.at) pole({ x: x0 + u, z: z0 + params.poles.z, dir: 1, on: isLit(pattern.lit), transformer: u > params.poles.transformerFrom });
484
+ kit.props.wires(b, [[x0 - params.wires.half, z0 + params.poles.z], [x0 + params.wires.half, z0 + params.poles.z]], params.wires.height);
485
+ };
486
+ var composeMountainResort = ({ b, pattern, params, x0, z0, pole, house, plant, isLit }) => {
487
+ b.plane(x0, params.road.y, z0, params.road.length, pattern.streetWidth, params.road.color);
488
+ const { chalets } = params;
489
+ for (let i = 0; i < chalets.count; i++) {
490
+ house("chalet", { x: x0 + chalets.first + i * chalets.pitch, z: z0 + chalets.northZ, color: b.pick(chalets.northColors) });
491
+ house("chalet", { x: x0 + chalets.first + i * chalets.pitch + chalets.southShift, z: z0 + chalets.southZ, color: b.pick(chalets.southColors), ry: Math.PI });
492
+ }
493
+ for (let u = params.poles.from; u <= params.poles.to; u += params.poles.step) {
494
+ for (const s of [-1, 1]) pole({ x: x0 + u + (s > 0 ? params.poles.sideOffset : 0), z: z0 + s * params.poles.z, on: isLit(pattern.lit) });
495
+ }
496
+ const { pines } = params;
497
+ for (let i = 0; i < pines.count; i++) plant({ kind: "pine", x: x0 + pines.first + b.random() * pines.span, z: z0 + (b.random() < 0.5 ? -pines.rowZ : pines.rowZ), scale: pines.minScale + b.random() * pines.scaleRange });
498
+ };
499
+ var composeStiltVillage = ({ b, params, x0, z0, house }) => {
500
+ const { water, bank, boardwalk, houses } = params;
501
+ b.plane(x0, water.y, z0 + water.z, water.length, water.depth, water.color, { roughness: water.roughness, metalness: water.metalness });
502
+ b.box(x0, 0, z0 + bank.z, bank.length, 0.2, bank.depth, bank.color);
503
+ b.box(x0, boardwalk.y, z0, boardwalk.length, 0.2, boardwalk.width, boardwalk.color);
504
+ for (let u = boardwalk.pilesFrom; u <= boardwalk.pilesTo; u += boardwalk.pilesStep) b.cylinder(x0 + u, -1.5, z0 + 0.9, 0.1, 0.1, 2.9, 3811868, -1, 5);
505
+ for (let i = 0; i < houses.count; i++) {
506
+ const x = x0 + houses.first + i * houses.pitch;
507
+ house("stilt", { x, z: z0 + houses.z, color: b.pick(houses.colors) });
508
+ const lit = i % 2 === 1;
509
+ b.box(x + houses.lantern.dx, houses.lantern.y, z0 + houses.lantern.dz, 0.2, 0.28, 0.2, lit ? houses.lantern.lit : houses.lantern.unlit, { emissive: lit });
510
+ }
511
+ b.light({ x: x0 + params.lamp.dx, y: params.lamp.y, z: z0 + params.lamp.dz, color: params.lamp.color, intensity: params.lamp.intensity, distance: params.lamp.distance });
512
+ b.box(x0 + params.boat.dx, -0.2, z0 + params.boat.dz, 1.6, 0.5, 4.6, params.boat.color);
513
+ };
514
+ var composeMilitary = ({ b, kit, pattern, params, x0, z0 }) => {
515
+ b.plane(x0, 0.02, z0, params.yard.length, pattern.streetWidth, params.yard.color);
516
+ const { fence } = params;
517
+ for (let u = fence.from; u <= fence.to; u += fence.step) b.cylinder(x0 + u, 0, z0 + fence.z, 0.06, 0.06, 3, fence.color, -1, 4);
518
+ b.line([[x0 + fence.from, 2.9, z0 + fence.z], [x0 + fence.to, 2.9, z0 + fence.z]], fence.wireColor);
519
+ for (const u of params.towers.dx) kit.props.watchtower(b, x0 + u, z0 + params.towers.dz, true);
520
+ const { alarm } = params;
521
+ b.light({ x: x0, y: alarm.y, z: z0 + alarm.dz, color: alarm.color, intensity: alarm.intensity, distance: alarm.distance });
522
+ b.box(x0, alarm.lampY, z0 + alarm.lampDz, 0.3, 0.3, 0.3, alarm.color, { emissive: true });
523
+ kit.props.sandbags(b, x0, z0 + params.sandbags.dz, params.sandbags.length, "x", params.sandbags.rows);
524
+ for (let i = 0; i < params.tents.count; i++) kit.props.tent(b, x0 + params.tents.first + i * params.tents.pitch, z0 + params.tents.dz, 0, params.tents.width, params.tents.depth);
525
+ };
526
+ var composeRural = ({ b, pattern, params, x0, z0, pole, house, plant }) => {
527
+ b.plane(x0, 0.02, z0, params.road.length, pattern.streetWidth, params.road.color);
528
+ b.plane(x0, params.field.y, z0 + params.field.dz, params.field.length, params.field.depth, params.field.color);
529
+ house("farmhouse", { x: x0 + params.farmhouse.dx, z: z0 + params.farmhouse.dz });
530
+ pole({ x: x0 + params.pole.dx, z: z0 + params.pole.dz, on: true });
531
+ b.fence(x0 - params.fence.half, z0 + params.fence.dz, x0 + params.fence.half, z0 + params.fence.dz, params.fence.height, params.fence.color);
532
+ const { trees, crops } = params;
533
+ for (let i = 0; i < trees.count; i++) plant({ kind: "tree", x: x0 + trees.first + b.random() * trees.span, z: z0 + trees.dz + b.random() * trees.spread, scale: trees.minScale + b.random() * trees.scaleRange });
534
+ for (let r = 0; r < crops.rows; r++) {
535
+ for (let i = 0; i < crops.perRow; i++) b.item(x0 + crops.first + i * crops.pitch, 0, z0 + crops.dz + r * crops.rowPitch, crops.width, crops.minHeight + b.random() * crops.heightRange, crops.width, crops.color);
536
+ }
537
+ };
538
+ var COMPOSERS = {
539
+ downtown: composeDowntown,
540
+ suburb: composeSuburb,
541
+ working_class: composeWorkingClass,
542
+ historic_street: composeHistoricStreet,
543
+ industrial_port: composeIndustrial,
544
+ railway_village: composeRailwayVillage,
545
+ mountain_resort: composeMountainResort,
546
+ stilt_village: composeStiltVillage,
547
+ military: composeMilitary,
548
+ rural: composeRural
549
+ };
550
+
551
+ // src/neighbourhoods/patterns.ts
552
+ var suburb = {
553
+ id: "suburb",
554
+ streetWidth: 7,
555
+ walkWidth: 2,
556
+ typologies: ["detached", "two_storey"],
557
+ pole: "concrete_arm",
558
+ lightColor: 16751168,
559
+ spacing: 35,
560
+ lit: 0.75,
561
+ compose: "suburb",
562
+ marker: { height: 10 },
563
+ text: {
564
+ "pt-BR": { label: "Sub\xFArbio", title: "SUB\xDARBIO", caption: "casa t\xE9rrea e sobrado \xB7 muro 1,8 m \xB7 s\xF3dio a cada 35 m", detail: "Casa t\xE9rrea e sobrado, muro de 1,8 m. Poste de concreto com s\xF3dio laranja." },
565
+ en: { label: "Suburb", title: "SUBURB", caption: "one-storey and two-storey houses \xB7 1.8 m wall \xB7 sodium every 35 m", detail: "One-storey and two-storey houses behind a 1.8 m wall. Concrete pole with an orange sodium lamp." }
566
+ },
567
+ params: {
568
+ roadLength: 60,
569
+ walkOffset: 4.5,
570
+ houses: { count: 5, first: -24, pitch: 12, north: { z: -15, typologies: ["two_storey", "detached"], colors: [13154458, 11055264, 13680800, 12101776] }, south: { z: 15, colors: [13154458, 11055264, 13680800] }, roofColor: 6961706, width: 8, depth: 10 },
571
+ walls: { color: 12235424, height: 1.8, thickness: 0.2, offset: 5.8, gateColor: 3815994, gateWidth: 2.4, gateHeight: 1.6, gateOffset: 3.5, gateInset: 5.7, length: 10 },
572
+ poles: { at: [-26, 9], z: -4.8, transformerFrom: 0 },
573
+ wires: { half: 28, height: 6.9 }
574
+ }
575
+ };
576
+ var downtown = {
577
+ id: "downtown",
578
+ streetWidth: 14,
579
+ walkWidth: 3,
580
+ typologies: ["city_building"],
581
+ pole: "led_double",
582
+ lightColor: 14674175,
583
+ spacing: 25,
584
+ lit: 1,
585
+ compose: "downtown",
586
+ marker: { height: 14 },
587
+ text: {
588
+ "pt-BR": { label: "Centro", title: "CENTRO", caption: "avenida 2 \xD7 7 m \xB7 LED branco a cada 25 m", detail: "Pr\xE9dio residencial e comercial de 4 a 12 andares. Poste met\xE1lico duplo, LED branco." },
589
+ en: { label: "Downtown", title: "DOWNTOWN", caption: "avenue 2 \xD7 7 m \xB7 white LED every 25 m", detail: "Residential and commercial buildings of 4 to 12 floors. Double steel pole, white LED." }
590
+ },
591
+ params: {
592
+ roadLength: 60,
593
+ roadColor: 2237480,
594
+ median: { width: 1.6, height: 0.18, color: 3820076 },
595
+ poles: { from: -26, to: 26 },
596
+ buildings: { perRow: 4, first: -21, pitch: 14, rowOffset: 18, size: 12, north: { minHeight: 12, range: 24, lit: 0.1 }, south: { minHeight: 12, range: 18, lit: 0.08 } },
597
+ walks: { offset: 10, length: 60 },
598
+ car: { dx: -8, dz: -3, ry: 1.57, color: 7038032 }
599
+ }
600
+ };
601
+ var workingClass = {
602
+ id: "working_class",
603
+ streetWidth: 6,
604
+ walkWidth: 0,
605
+ typologies: ["slab"],
606
+ pole: "concrete_arm",
607
+ lightColor: 16751168,
608
+ spacing: 36,
609
+ lit: 0.5,
610
+ compose: "working_class",
611
+ marker: { height: 10 },
612
+ text: {
613
+ "pt-BR": { label: "Bairro popular", title: "BAIRRO POPULAR", caption: "lajes de 1 a 3 \xB7 caixa d'\xE1gua azul \xB7 metade das luzes queimadas", detail: "Casas geminadas de laje, fios emaranhados, metade das luzes queimadas." },
614
+ en: { label: "Working-class quarter", title: "WORKING-CLASS QUARTER", caption: "slab houses of 1 to 3 floors \xB7 blue water tank \xB7 half the lamps burnt out", detail: "Row slab houses, tangled wires, half the lamps burnt out." }
615
+ },
616
+ params: {
617
+ houses: { count: 10, first: -27, pitch: 6, width: 5.6, depth: 10, north: { z: -9, colors: [10510922, 10119764, 9067076] }, south: { z: 9, colors: [10510922, 10119764, 13156528] }, maxFloors: 3 },
618
+ poles: { from: -24, to: 26, z: -3.5, jitter: 8 },
619
+ wires: { count: 4, from: -26, to: 26, z: -3.5, step: 0.15, height: 6.3, heightStep: 0.25, sag: 2, color: 1710618 }
620
+ }
621
+ };
622
+ var historicStreet = {
623
+ id: "historic_street",
624
+ streetWidth: 5,
625
+ walkWidth: 0,
626
+ typologies: ["colonial"],
627
+ pole: "cast_iron",
628
+ lightColor: 16763008,
629
+ spacing: 20,
630
+ lit: 0.8,
631
+ compose: "historic_street",
632
+ marker: { height: 8 },
633
+ text: {
634
+ "pt-BR": { label: "Rua hist\xF3rica", title: "RUA HIST\xD3RICA", caption: "casas coloniais coladas \xB7 pedra 5 m \xB7 ferro fundido a cada 20 m", detail: "Casas coloniais coladas, rua de pedra, lumin\xE1ria de ferro fundido." },
635
+ en: { label: "Historic street", title: "HISTORIC STREET", caption: "colonial houses wall to wall \xB7 5 m cobbles \xB7 cast iron every 20 m", detail: "Colonial houses wall to wall, cobbled street, cast-iron lanterns." }
636
+ },
637
+ params: {
638
+ cobbles: { y: 0.03, length: 60, color: 4867650, from: -28, to: 28, step: 0.9, spread: 4, sizes: [0.8, 0.04, 0.6], colors: [5920336, 5130822, 6446680] },
639
+ rows: { from: -28, to: 26, minWidth: 5, widthSteps: 3, north: { z: -8, colors: [14207136, 11059392, 14727312, 12626104, 13684928] }, south: { z: 8, colors: [14207136, 11059392, 14727312, 12626104] } },
640
+ poles: { from: -25, to: 25, step: 20, z: 2.9, sideOffset: 10 }
641
+ }
642
+ };
643
+ var industrialPort = {
644
+ id: "industrial_port",
645
+ streetWidth: 40,
646
+ walkWidth: 0,
647
+ typologies: ["hangar"],
648
+ pole: "flood_tower",
649
+ lightColor: 16773328,
650
+ spacing: 60,
651
+ lit: 1,
652
+ compose: "industrial_port",
653
+ marker: { height: 16 },
654
+ text: {
655
+ "pt-BR": { label: "Industrial e porto", title: "INDUSTRIAL E PORTO", caption: "galp\xE3o (amostra encurtada) \xB7 torre de refletor a cada 60 m", detail: "Galp\xF5es e torres de refletor de 12 m." },
656
+ en: { label: "Industrial and port", title: "INDUSTRIAL AND PORT", caption: "warehouse (shortened sample) \xB7 floodlight tower every 60 m", detail: "Warehouses and 12 m floodlight towers." }
657
+ },
658
+ params: {
659
+ yard: { length: 60, color: 2763564 },
660
+ hangar: { x: 15, z: -6, width: 26, height: 10, depth: 30, color: 6974568, roofColor: 5921880, roofRadius: 13, roofY: 10, doorColor: 3815994, doorWidth: 6, doorHeight: 5, stripeColor: 14200874 },
661
+ towers: [{ dx: -30, dz: 14, on: true }, { dx: 30, dz: 14, on: false }],
662
+ container: { dx: 20, dz: 14, ry: 0.2, color: 9058858 }
663
+ }
664
+ };
665
+ var railwayVillage = {
666
+ id: "railway_village",
667
+ streetWidth: 6,
668
+ walkWidth: 0,
669
+ typologies: ["company_house"],
670
+ pole: "concrete_arm",
671
+ lightColor: 16751168,
672
+ spacing: 35,
673
+ lit: 0.7,
674
+ compose: "railway_village",
675
+ marker: { height: 8 },
676
+ text: {
677
+ "pt-BR": { label: "Vila ferrovi\xE1ria", title: "VILA FERROVI\xC1RIA", caption: "casas da companhia, todas iguais \xB7 poste residencial a cada 35 m", detail: "Casas da companhia em fila, todas iguais." },
678
+ en: { label: "Railway village", title: "RAILWAY VILLAGE", caption: "company houses, all alike \xB7 residential pole every 35 m", detail: "Company houses in a row, all alike." }
679
+ },
680
+ params: {
681
+ houses: { count: 6, first: -25, pitch: 10, north: { z: -12, colors: [14209216, 13682868] }, south: { z: 12, color: 14209216 } },
682
+ poles: { at: [-26, 9], z: -4, transformerFrom: 0 },
683
+ wires: { half: 26, height: 6.9 }
684
+ }
685
+ };
686
+ var mountainResort = {
687
+ id: "mountain_resort",
688
+ streetWidth: 6,
689
+ walkWidth: 0,
690
+ typologies: ["chalet"],
691
+ pole: "cast_iron",
692
+ lightColor: 16763008,
693
+ spacing: 20,
694
+ lit: 0.7,
695
+ compose: "mountain_resort",
696
+ marker: { height: 10 },
697
+ text: {
698
+ "pt-BR": { label: "Serra", title: "SERRA \xB7 RUA DAS POUSADAS", caption: "chal\xE9 de madeira e pedra \xB7 telhado 45\xB0 \xB7 ferro fundido a cada 20 m", detail: "Rua das Pousadas: chal\xE9s de madeira e pedra com telhado \xEDngreme e lumin\xE1ria de ferro fundido. Na Encosta, sem ilumina\xE7\xE3o." },
699
+ en: { label: "Mountain", title: "MOUNTAIN \xB7 INN STREET", caption: "wood and stone chalets \xB7 45\xB0 roof \xB7 cast iron every 20 m", detail: "Inn Street: wood and stone chalets with a steep roof and cast-iron lanterns. Up the slope there is no lighting." }
700
+ },
701
+ params: {
702
+ road: { y: 0.02, length: 60, color: 2763304 },
703
+ chalets: { count: 5, first: -24, pitch: 12, northZ: -12, southZ: 12, southShift: 6, northColors: [7031344, 5914152, 8018490], southColors: [7031344, 5914152] },
704
+ poles: { from: -25, to: 25, step: 20, z: 2.6, sideOffset: 10 },
705
+ pines: { count: 10, first: -28, span: 56, rowZ: 22, minScale: 1.4, scaleRange: 1 }
706
+ }
707
+ };
708
+ var stiltVillage = {
709
+ id: "stilt_village",
710
+ streetWidth: 2,
711
+ walkWidth: 0,
712
+ typologies: ["stilt"],
713
+ pole: "",
714
+ lightColor: 16756832,
715
+ spacing: 0,
716
+ lit: 1,
717
+ compose: "stilt_village",
718
+ marker: { height: 7 },
719
+ text: {
720
+ "pt-BR": { label: "Palafitas", title: "PALAFITAS", caption: "madeira sobre estacas \xB7 sem luz p\xFAblica \xB7 lampi\xE3o", detail: "Vila dos Pescadores: sem ilumina\xE7\xE3o p\xFAblica, s\xF3 lampi\xE3o." },
721
+ en: { label: "Stilt village", title: "STILT VILLAGE", caption: "timber on piles \xB7 no public lighting \xB7 lanterns", detail: "Fishermen's village: no public lighting, only lanterns." }
722
+ },
723
+ params: {
724
+ water: { y: 0.04, z: -2, length: 60, depth: 30, color: 2241598, roughness: 0.25, metalness: 0.3 },
725
+ bank: { z: 14, length: 60, depth: 8, color: 4867126 },
726
+ boardwalk: { y: 1.3, length: 56, width: 2, color: 5916208, pilesFrom: -26, pilesTo: 26, pilesStep: 4 },
727
+ houses: { count: 5, first: -22, pitch: 11, z: -7, colors: [6969926, 5925482, 8018502], lantern: { dx: 1.5, y: 3.2, dz: -3.4, lit: 16760944, unlit: 3815994 } },
728
+ lamp: { dx: -11, y: 3, dz: -3, color: 16756832, intensity: 0.9, distance: 10 },
729
+ boat: { dx: 14, dz: 6, color: 5913130 }
730
+ }
731
+ };
732
+ var military = {
733
+ id: "military",
734
+ streetWidth: 40,
735
+ walkWidth: 0,
736
+ typologies: ["tent"],
737
+ pole: "",
738
+ lightColor: 15134463,
739
+ spacing: 40,
740
+ lit: 1,
741
+ compose: "military",
742
+ marker: { height: 12, dz: -14 },
743
+ text: {
744
+ "pt-BR": { label: "Militar", title: "MILITAR", caption: "torre de vigia e trip\xE9 \xB7 holofote branco \xB7 luz vermelha \xB7 a cada 40 m", detail: "Base, bloqueio e penitenci\xE1ria: torres com holofote branco e luz vermelha de emerg\xEAncia no per\xEDmetro." },
745
+ en: { label: "Military", title: "MILITARY", caption: "watch tower and tripod \xB7 white searchlight \xB7 red lamp \xB7 every 40 m", detail: "Base, roadblock and penitentiary: towers with a white searchlight and a red emergency lamp on the perimeter." }
746
+ },
747
+ params: {
748
+ yard: { length: 60, color: 3815984 },
749
+ fence: { from: -28, to: 28, step: 4, z: -12, height: 3, color: 6974574, wireColor: 10132122 },
750
+ towers: { dx: [-20, 20], dz: -14 },
751
+ alarm: { dz: -10, color: 16722458, intensity: 1.2, distance: 16, y: 3, lampDz: -11.7, lampY: 2.6 },
752
+ sandbags: { dz: -6, length: 10, rows: 3 },
753
+ tents: { count: 3, first: -14, pitch: 14, dz: 8, width: 6, depth: 8 }
754
+ }
755
+ };
756
+ var rural = {
757
+ id: "rural",
758
+ streetWidth: 6,
759
+ walkWidth: 0,
760
+ typologies: ["farmhouse"],
761
+ pole: "wood_crossarm",
762
+ lightColor: 16765562,
763
+ spacing: 0,
764
+ lit: 1,
765
+ compose: "rural",
766
+ marker: { height: 7 },
767
+ text: {
768
+ "pt-BR": { label: "Rural", title: "RURAL", caption: "casa sede com varanda \xB7 poste de madeira s\xF3 no cruzamento", detail: "Casa sede com varanda. Luz s\xF3 em cruzamentos e sedes." },
769
+ en: { label: "Rural", title: "RURAL", caption: "farmhouse with a veranda \xB7 wooden pole only at the junction", detail: "Farmhouse with a veranda. Light only at junctions and farmhouses." }
770
+ },
771
+ params: {
772
+ road: { length: 60, color: 4864554 },
773
+ field: { y: 0.01, dz: 15, length: 60, depth: 22, color: 3820074 },
774
+ farmhouse: { dx: -10, dz: -14 },
775
+ pole: { dx: 6, dz: -4 },
776
+ fence: { dz: -4, half: 28, height: 1.2, color: 5916208 },
777
+ trees: { count: 8, first: 8, span: 20, dz: -16, spread: 10, minScale: 1, scaleRange: 0.5 },
778
+ crops: { rows: 6, perRow: 20, first: -26, pitch: 2.7, dz: 8, rowPitch: 2.2, width: 0.4, minHeight: 0.6, heightRange: 0.3, color: 4872746 }
779
+ }
780
+ };
781
+ var DEFAULT_PATTERNS = [downtown, suburb, workingClass, historicStreet, industrialPort, railwayVillage, mountainResort, stiltVillage, military, rural];
782
+ var SAMPLE_CELLS = {
783
+ downtown: { x: -80, z: -56 },
784
+ suburb: { x: 0, z: -56 },
785
+ working_class: { x: 80, z: -56 },
786
+ historic_street: { x: -80, z: 0 },
787
+ industrial_port: { x: 0, z: 0 },
788
+ railway_village: { x: 80, z: 0 },
789
+ mountain_resort: { x: -80, z: 56 },
790
+ stilt_village: { x: 0, z: 56 },
791
+ rural: { x: 80, z: 56 },
792
+ military: { x: 160, z: 0 }
793
+ };
794
+
795
+ // src/terrain/math.ts
796
+ var clamp = (v, a, b) => v < a ? a : v > b ? b : v;
797
+ var lerp2 = (a, b, t) => a + (b - a) * t;
798
+ var smoothstep = (a, b, x) => {
799
+ const t = clamp((x - a) / (b - a), 0, 1);
800
+ return t * t * (3 - 2 * t);
801
+ };
802
+ var hash2 = (a, b) => {
803
+ const n = Math.sin(a * 127.1 + b * 311.7) * 43758.5453;
804
+ return n - Math.floor(n);
805
+ };
806
+ function distanceToPolyline(px, py, points) {
807
+ let best = 1e9;
808
+ for (let index = 0; index < points.length - 1; index++) {
809
+ const [ax, ay] = points[index];
810
+ const [bx, by] = points[index + 1];
811
+ const dx = bx - ax;
812
+ const dy = by - ay;
813
+ const t = clamp(((px - ax) * dx + (py - ay) * dy) / (dx * dx + dy * dy), 0, 1);
814
+ const d = Math.hypot(px - ax - t * dx, py - ay - t * dy);
815
+ if (d < best) best = d;
816
+ }
817
+ return best;
818
+ }
819
+ var insideRect = (px, py, r, margin) => px > r[0] - margin && px < r[2] + margin && py > r[1] - margin && py < r[3] + margin;
820
+ var insideEllipse = (px, py, center, radius) => Math.hypot((px - center[0]) / radius[0], (py - center[1]) / radius[1]) < 1;
821
+
822
+ // src/terrain/terrain.ts
823
+ var TRIG = { sin: Math.sin, cos: Math.cos };
824
+ function wave(w, px, py) {
825
+ return w.kind === "product" ? TRIG[w.x[0]](px * w.x[1]) * TRIG[w.y[0]](py * w.y[1]) * w.amplitude : Math.sin(px * w.kx + py * w.ky) * w.amplitude;
826
+ }
827
+ function ramp(r, px, py) {
828
+ const v = r.axis === "x" ? px : py;
829
+ return r.fullUntil !== void 0 && v < r.fullUntil ? 1 : smoothstep(r.from, r.to, v);
830
+ }
831
+ function mask(ramps, px, py) {
832
+ let m = 1;
833
+ for (const r of ramps) m *= ramp(r, px, py);
834
+ return m;
835
+ }
836
+ var sum = (start, waves, px, py) => {
837
+ let total = start;
838
+ for (const w of waves) total += wave(w, px, py);
839
+ return total;
840
+ };
841
+ function createTerrain(options) {
842
+ const { world } = options;
843
+ const toWorld = (px, py) => [px * world.scale + world.origin, py * world.scale + world.origin];
844
+ const fromWorld = (x, z) => [(x - world.origin) / world.scale, (z - world.origin) / world.scale];
845
+ function heightAt(px, py) {
846
+ let h = sum(options.base.level, options.base.waves, px, py);
847
+ for (const layer of options.layers) h += mask(layer.mask, px, py) * sum(layer.level, layer.waves, px, py);
848
+ for (const f of options.flatten) {
849
+ if (!insideRect(px, py, f.rect, f.margin)) continue;
850
+ const inside = Math.min(smoothstep(f.edge[0], f.edge[1], Math.min(px - f.rect[0], f.rect[2] - px, py - f.rect[1], f.rect[3] - py)), 1);
851
+ h = lerp2(h, f.level, inside);
852
+ }
853
+ const land = h;
854
+ for (const river of options.rivers) {
855
+ const bed = "fixed" in river.bed ? river.bed.fixed : Math.max(river.bed.floor, land - river.bed.below);
856
+ h = lerp2(bed, h, smoothstep(river.width[0], river.width[1], distanceToPolyline(px, py, river.points)));
857
+ }
858
+ for (const lake of options.lakes) {
859
+ const d = Math.hypot((px - lake.center[0]) / lake.radius[0], (py - lake.center[1]) / lake.radius[1]);
860
+ if (d < lake.reach) h = lerp2(lake.level, h, smoothstep(lake.edge[0], lake.edge[1], d));
861
+ }
862
+ return options.custom ? options.custom(px, py, h) : h;
863
+ }
864
+ function forestAt(px, py) {
865
+ let density = 0;
866
+ for (const zone of options.forest.zones) density = Math.max(density, mask(zone.mask, px, py));
867
+ const patch = options.forest.patch;
868
+ if (patch) density = Math.max(density, smoothstep(patch.edge[0], patch.edge[1], sum(0, patch.waves, px, py) * 0.5 + 0.5) * patch.weight);
869
+ return density;
870
+ }
871
+ const nearRiver = (px, py, margin) => options.rivers.some((river) => distanceToPolyline(px, py, river.points) < margin);
872
+ function matches(rule, px, py, h, forest) {
873
+ switch (rule.kind) {
874
+ case "below":
875
+ return h < rule.height;
876
+ case "above":
877
+ return h > rule.height;
878
+ case "ellipse":
879
+ return insideEllipse(px, py, rule.center, rule.radius);
880
+ case "rects":
881
+ return rule.rects.some((r) => insideRect(px, py, r, rule.margin));
882
+ case "forest":
883
+ return forest > rule.above;
884
+ }
885
+ }
886
+ function colorAt(px, py, h = heightAt(px, py)) {
887
+ const forest = forestAt(px, py);
888
+ for (const rule of options.colors) if (matches(rule, px, py, h, forest)) return rule.color;
889
+ const { colors: colors2, cell } = options.fields;
890
+ return colors2[Math.floor(hash2(Math.floor(px / cell[0]), Math.floor(py / cell[1])) * colors2.length)];
891
+ }
892
+ function grid(segments = world.segments) {
893
+ const count = (segments + 1) * (segments + 1);
894
+ const x = new Float32Array(count);
895
+ const z = new Float32Array(count);
896
+ const heights = new Float32Array(count);
897
+ const colors2 = new Uint32Array(count);
898
+ const half = world.size / 2;
899
+ const step = world.size / segments;
900
+ for (let iy = 0; iy <= segments; iy++) {
901
+ for (let ix = 0; ix <= segments; ix++) {
902
+ const i = iy * (segments + 1) + ix;
903
+ x[i] = ix * step - half;
904
+ z[i] = iy * step - half;
905
+ const [px, py] = fromWorld(x[i], z[i]);
906
+ const h = heightAt(px, py);
907
+ heights[i] = h;
908
+ colors2[i] = colorAt(px, py, h);
909
+ }
910
+ }
911
+ return { segments, size: world.size, x, z, heights, colors: colors2 };
912
+ }
913
+ return { options, toWorld, fromWorld, heightAt, forestAt, nearRiver, colorAt, grid };
914
+ }
915
+ function drawTerrain(b, terrain, segments) {
916
+ b.terrain(terrain.grid(segments));
917
+ const { water, world } = terrain.options;
918
+ b.plane(0, water.level, 0, world.size, world.size, water.color, { roughness: water.roughness, metalness: water.metalness });
919
+ }
920
+
921
+ // src/kit.ts
922
+ var DEFAULT_LIGHT_BUDGET = 16;
923
+ var DEFAULT_URBAN_SEED = 7;
924
+ function createUrban(options = {}) {
925
+ const entries = mergeById(DEFAULT_POLES, options.packs?.poles);
926
+ applyPatches(entries, options.patch?.poles);
927
+ removeIds(entries, options.remove?.poles);
928
+ const shapes = { ...POLE_SHAPES, ...options.shapes };
929
+ const patterns = mergeById(DEFAULT_PATTERNS, options.packs?.neighbourhoods);
930
+ applyPatches(patterns, options.patch?.neighbourhoods);
931
+ removeIds(patterns, options.remove?.neighbourhoods);
932
+ const composers = { ...COMPOSERS, ...options.composers };
933
+ const lightBudget = options.lights?.budget ?? DEFAULT_LIGHT_BUDGET;
934
+ const facades = options.facades ?? DEFAULT_FACADES;
935
+ const propColors = { ...DEFAULT_PROP_COLORS, ...options.props };
936
+ const poles = {
937
+ ids: () => [...entries.keys()],
938
+ list: () => [...entries.values()],
939
+ get(id) {
940
+ const def = entries.get(id);
941
+ if (!def) throw new Error(`Unknown pole "${id}"`);
942
+ const shape = shapes[def.shape];
943
+ if (!shape) throw new Error(`Pole "${id}" needs the shape "${def.shape}", which is not registered`);
944
+ return { def, build: (b, o) => shape(b, def.spec, o) };
945
+ }
946
+ };
947
+ const core = {
948
+ poles,
949
+ streets: {
950
+ road: (b, x, z, w, l, along) => drawRoad(b, x, z, w, l, along, options.streets),
951
+ walk: (b, x, z, w, d) => drawWalk(b, x, z, w, d, options.streets),
952
+ ground: drawGround,
953
+ grid: (b, g) => drawStreetGrid(b, g.block, g.count, g.width, options.streets)
954
+ },
955
+ block: {
956
+ facades,
957
+ building: (b, x, z, width, depth, height, color, o) => drawBuilding(b, x, z, width, depth, height, color, o),
958
+ fill: (b, g) => fillBlock(b, g.cx, g.cz, g.size, g.minHeight, g.maxHeight, { palette: facades, ...g })
959
+ },
960
+ props: {
961
+ fence: drawFence,
962
+ tent: (b, x, z, ry, w, d, color) => drawTent(b, x, z, ry, w, d, color, propColors),
963
+ pine: (b, x, z, scale, y) => drawPine(b, x, z, scale, y, propColors),
964
+ tree: (b, x, z, scale) => drawTree(b, x, z, scale, propColors),
965
+ container: drawContainer,
966
+ watchtower: (b, x, z, searchlight) => drawWatchtower(b, x, z, searchlight, propColors),
967
+ sandbags: (b, x, z, length, along, rows) => drawSandbags(b, x, z, length, along, rows, propColors),
968
+ label: (b, x, z, title, subtitle) => drawStripLabel(b, x, z, title, subtitle, propColors),
969
+ wires: (b, points, y, color) => drawWires(b, points, y, color, propColors)
970
+ }
971
+ };
972
+ const builder = (o = {}) => createUrbanBuilder(o.random ?? createSilhouetteRandom(o.seed ?? DEFAULT_URBAN_SEED), { budget: createLightBudget(o.budget ?? lightBudget) });
973
+ const neighbourhoods = {
974
+ ids: () => [...patterns.keys()],
975
+ get(id) {
976
+ const pattern = patterns.get(id);
977
+ if (!pattern) throw new Error(`Unknown neighbourhood pattern "${id}"`);
978
+ const composer = composers[pattern.compose];
979
+ if (!composer) throw new Error(`Pattern "${id}" needs the composer "${pattern.compose}", which is not registered`);
980
+ return {
981
+ pattern,
982
+ /** Draws the pattern at `origin` and gives back what it put there. */
983
+ compose: (b, origin, o) => composePattern(core, pattern, composer, b, origin, o),
984
+ marker: (origin, locale) => patternMarker(pattern, origin, locale)
985
+ };
986
+ },
987
+ /** The Galeria's sample sheet: the ground, then each pattern in its cell, in the order the page builds them. */
988
+ composeSampleSheet(b, o = {}) {
989
+ if (o.ground !== false) drawGround(b, (o.ground ?? SAMPLE_GROUND).color, (o.ground ?? SAMPLE_GROUND).size);
990
+ const cells = { ...SAMPLE_CELLS, ...o.cells };
991
+ const plans = [];
992
+ for (const id of o.ids ?? [...patterns.keys()]) {
993
+ const cell = cells[id];
994
+ if (!cell) throw new Error(`The sample sheet has no cell for "${id}"`);
995
+ plans.push(neighbourhoods.get(id).compose(b, cell, o));
996
+ }
997
+ return { plans, markers: plans.map((plan) => neighbourhoods.get(plan.id).marker(plan.origin, o.locale)) };
998
+ }
999
+ };
1000
+ const terrain = (o) => createTerrain(o);
1001
+ return { ...core, poles, builder, neighbourhoods, terrain, drawTerrain };
1002
+ }
1003
+
1004
+ // src/neighbourhoods/providers.ts
1005
+ import { cars, pickups, suvs, vans } from "@adatechnology/game-vehicles-fleet";
1006
+ import { pickForContext, regions } from "@adatechnology/game-vegetation-species";
1007
+ var PARKED_VEHICLE_IDS = [...cars, ...suvs, ...pickups.filter((id) => id !== "monster_truck"), ...vans];
1008
+ var hashSpot = (x, z, ry) => {
1009
+ let h = 2166136261;
1010
+ for (const value of [Math.round(x * 100), Math.round(z * 100), Math.round(ry * 100)]) {
1011
+ h ^= value & 65535;
1012
+ h = Math.imul(h, 16777619);
1013
+ h ^= value >> 16 & 65535;
1014
+ h = Math.imul(h, 16777619);
1015
+ }
1016
+ return h >>> 0;
1017
+ };
1018
+ function createVehicleProvider(options = {}) {
1019
+ const ids = options.ids ?? PARKED_VEHICLE_IDS;
1020
+ if (ids.length === 0) throw new Error("The vehicle provider needs at least one vehicle id");
1021
+ return (request, b) => {
1022
+ const id = options.pick ? options.pick(request, ids) : ids[hashSpot(request.x, request.z, request.ry) % ids.length];
1023
+ const color = options.paint ? options.paint(request) : request.color;
1024
+ b.place("vehicle", id, request.x, request.z, { ry: request.ry, ...color === void 0 ? {} : { color }, seed: `${id}:${request.x}:${request.z}` });
1025
+ };
1026
+ }
1027
+ var DEFAULT_PLANT_CONTEXTS = { tree: "sidewalk_tree", pine: "square" };
1028
+ function createPlantProvider(options = {}) {
1029
+ const region = options.region ?? regions.br;
1030
+ const contexts = { ...DEFAULT_PLANT_CONTEXTS, ...options.contexts };
1031
+ const seed = options.seed ?? 1;
1032
+ return (request, b) => {
1033
+ const context = contexts[request.kind];
1034
+ const key = `${seed}:${request.kind}:${request.x}:${request.z}`;
1035
+ const id = options.pick ? options.pick(request, context, key) : pickForContext(region, context, key);
1036
+ b.place("plant", id, request.x, request.z, { scale: request.scale, seed: key });
1037
+ };
1038
+ }
1039
+ export {
1040
+ COMPOSERS,
1041
+ DEFAULT_FACADES,
1042
+ DEFAULT_LIGHT_BUDGET,
1043
+ DEFAULT_PATTERNS,
1044
+ DEFAULT_PLANT_CONTEXTS,
1045
+ DEFAULT_POLES,
1046
+ DEFAULT_PROP_COLORS,
1047
+ DEFAULT_ROAD_STYLE,
1048
+ DEFAULT_URBAN_SEED,
1049
+ DEFAULT_WALK_STYLE,
1050
+ PARKED_VEHICLE_IDS,
1051
+ POLE_SHAPES,
1052
+ SAMPLE_CELLS,
1053
+ SILHOUETTE_TYPOLOGIES,
1054
+ clamp,
1055
+ composePattern,
1056
+ createLightBudget,
1057
+ createPlantProvider,
1058
+ createSilhouetteHouses,
1059
+ createTerrain,
1060
+ createUrban,
1061
+ createUrbanBuilder,
1062
+ createVehicleProvider,
1063
+ distanceToPolyline,
1064
+ drawBuilding,
1065
+ drawContainer,
1066
+ drawFence,
1067
+ drawGround,
1068
+ drawPine,
1069
+ drawRoad,
1070
+ drawSandbags,
1071
+ drawStreetGrid,
1072
+ drawStripLabel,
1073
+ drawTent,
1074
+ drawTerrain,
1075
+ drawTree,
1076
+ drawWalk,
1077
+ drawWatchtower,
1078
+ drawWires,
1079
+ fillBlock,
1080
+ hash2,
1081
+ insideEllipse,
1082
+ insideRect,
1083
+ lerp2 as lerp,
1084
+ patternMarker,
1085
+ smoothstep
1086
+ };
1087
+ //# sourceMappingURL=index.js.map