scena3d 0.1.0 → 0.3.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/README.md +14 -8
- package/dist/index.cjs +786 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +280 -3
- package/dist/index.d.ts +280 -3
- package/dist/index.js +774 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vector3, Group, Mesh, DirectionalLight, AmbientLight, HemisphereLight, Scene } from 'three';
|
|
1
|
+
import { Vector3, Group, Mesh, DirectionalLight, AmbientLight, HemisphereLight, Scene, Object3D, Material } from 'three';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Deterministic seeded randomness — the backbone of SCENA. Same seed,
|
|
@@ -48,8 +48,15 @@ interface Palette {
|
|
|
48
48
|
skyTop: number;
|
|
49
49
|
skyBottom: number;
|
|
50
50
|
fog: number;
|
|
51
|
+
water: number;
|
|
52
|
+
sand: number;
|
|
53
|
+
path: number;
|
|
54
|
+
/** Building plaster/wall color. */
|
|
55
|
+
wall: number;
|
|
56
|
+
/** Building roof color. */
|
|
57
|
+
roof: number;
|
|
51
58
|
}
|
|
52
|
-
declare const PALETTES: Record<'meadow' | 'autumn' | 'dusk', Palette>;
|
|
59
|
+
declare const PALETTES: Record<'meadow' | 'autumn' | 'dusk' | 'winter', Palette>;
|
|
53
60
|
declare const DEFAULT_PALETTE: Palette;
|
|
54
61
|
|
|
55
62
|
/**
|
|
@@ -135,6 +142,65 @@ interface LampOptions {
|
|
|
135
142
|
/** A street lamp: post, head, glowing bulb, optional real PointLight. */
|
|
136
143
|
declare function createLamp(options?: LampOptions): Prop;
|
|
137
144
|
|
|
145
|
+
interface GrassOptions {
|
|
146
|
+
seed?: number;
|
|
147
|
+
/** Blades per tuft. Default 4–6 by seed. */
|
|
148
|
+
blades?: number;
|
|
149
|
+
palette?: Palette;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A tuft of grass blades — pure scatter fodder (zero obstacle footprint,
|
|
153
|
+
* walk straight through). Sways beautifully under `applyWind`.
|
|
154
|
+
*/
|
|
155
|
+
declare function createGrassTuft(options?: GrassOptions): Prop;
|
|
156
|
+
interface BushOptions {
|
|
157
|
+
seed?: number;
|
|
158
|
+
size?: number;
|
|
159
|
+
palette?: Palette;
|
|
160
|
+
}
|
|
161
|
+
/** A low foliage bush: two or three squashed blobs. Small footprint. */
|
|
162
|
+
declare function createBush(options?: BushOptions): Prop;
|
|
163
|
+
|
|
164
|
+
interface HouseOptions {
|
|
165
|
+
seed?: number;
|
|
166
|
+
/** Footprint width (gable side). Default seeded 3.2–4.2. */
|
|
167
|
+
width?: number;
|
|
168
|
+
depth?: number;
|
|
169
|
+
wallHeight?: number;
|
|
170
|
+
palette?: Palette;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A cottage: plastered walls, gabled roof, door, chimney and emissive
|
|
174
|
+
* windows. Pass the house in `createDayCycle`'s `lamps` list and its
|
|
175
|
+
* windows glow at night along with the street lamps. A stone foundation
|
|
176
|
+
* extends below ground so sloped terrain never shows a gap.
|
|
177
|
+
*/
|
|
178
|
+
declare function createHouse(options?: HouseOptions): Prop;
|
|
179
|
+
interface TowerOptions {
|
|
180
|
+
seed?: number;
|
|
181
|
+
height?: number;
|
|
182
|
+
palette?: Palette;
|
|
183
|
+
}
|
|
184
|
+
/** A wooden watchtower: splayed legs, platform with railing, pyramid roof. */
|
|
185
|
+
declare function createTower(options?: TowerOptions): Prop;
|
|
186
|
+
interface WellOptions {
|
|
187
|
+
seed?: number;
|
|
188
|
+
palette?: Palette;
|
|
189
|
+
}
|
|
190
|
+
/** A stone well: ring, posts, little gabled roof, hanging bucket. */
|
|
191
|
+
declare function createWell(options?: WellOptions): Prop;
|
|
192
|
+
interface RuinOptions {
|
|
193
|
+
seed?: number;
|
|
194
|
+
/** Footprint width. Default seeded 3.5–5. */
|
|
195
|
+
size?: number;
|
|
196
|
+
palette?: Palette;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* A ruined building: a partial rectangle of crumbling wall segments with
|
|
200
|
+
* seeded gaps and heights, and tumbled blocks around the floor.
|
|
201
|
+
*/
|
|
202
|
+
declare function createRuin(options?: RuinOptions): Prop;
|
|
203
|
+
|
|
138
204
|
interface TerrainOptions {
|
|
139
205
|
seed?: number;
|
|
140
206
|
/** Square side length. Default 80. */
|
|
@@ -148,6 +214,8 @@ interface TerrainOptions {
|
|
|
148
214
|
octaves?: number;
|
|
149
215
|
/** Flatten low areas into meadows (0–1, higher = flatter valleys). Default 0.55. */
|
|
150
216
|
valleyFlatness?: number;
|
|
217
|
+
/** Blend low bands toward sand below (waterLevel + shore margin). */
|
|
218
|
+
waterLevel?: number;
|
|
151
219
|
palette?: Palette;
|
|
152
220
|
}
|
|
153
221
|
interface Terrain {
|
|
@@ -200,6 +268,215 @@ type FogPreset = 'clear' | 'haze' | 'thick' | 'eerie';
|
|
|
200
268
|
/** Distance fog matched to the palette's fog color. 'clear' removes it. */
|
|
201
269
|
declare function applyFog(scene: Scene, preset: FogPreset, palette?: Palette): void;
|
|
202
270
|
|
|
271
|
+
interface WaterOptions {
|
|
272
|
+
/** World-space water surface height. Default 0.8. */
|
|
273
|
+
level?: number;
|
|
274
|
+
size?: number;
|
|
275
|
+
resolution?: number;
|
|
276
|
+
/** Wave height. Default 0.06. */
|
|
277
|
+
amplitude?: number;
|
|
278
|
+
/** Wave speed multiplier. Default 1. */
|
|
279
|
+
speed?: number;
|
|
280
|
+
palette?: Palette;
|
|
281
|
+
}
|
|
282
|
+
interface Water {
|
|
283
|
+
mesh: Mesh;
|
|
284
|
+
level: number;
|
|
285
|
+
/** Advance the wave animation. Call from your frame loop. */
|
|
286
|
+
update(dt: number): void;
|
|
287
|
+
/** Is ground at this height below the surface? */
|
|
288
|
+
isUnderwater(groundHeight: number): boolean;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* A low-poly animated water plane at a fixed level. Pair it with a
|
|
292
|
+
* terrain built using the same `waterLevel` so shores blend to sand, and
|
|
293
|
+
* keep scatter/agents ashore with `aboveWater(terrain, water)`.
|
|
294
|
+
*/
|
|
295
|
+
declare function createWater(options?: WaterOptions): Water;
|
|
296
|
+
/**
|
|
297
|
+
* A scatter mask keeping placements on dry land: true when the terrain
|
|
298
|
+
* at (x, z) sits above the water level plus `margin`.
|
|
299
|
+
*/
|
|
300
|
+
declare function aboveWater(terrain: Terrain, water: Pick<Water, 'level'>, margin?: number): (x: number, z: number) => boolean;
|
|
301
|
+
|
|
302
|
+
interface DayCycleOptions {
|
|
303
|
+
sky?: Sky;
|
|
304
|
+
rig?: LightingRig;
|
|
305
|
+
/** Scene whose fog color should track the cycle. */
|
|
306
|
+
scene?: Scene;
|
|
307
|
+
/** Lamp props/objects whose PointLights + glow bulbs ignite at night. */
|
|
308
|
+
lamps?: Array<{
|
|
309
|
+
object: Object3D;
|
|
310
|
+
} | Object3D>;
|
|
311
|
+
palette?: Palette;
|
|
312
|
+
/** Seconds per full day. Default 60. */
|
|
313
|
+
dayLength?: number;
|
|
314
|
+
/** Initial time: 0 = midnight, 0.25 = dawn, 0.5 = noon, 0.75 = dusk. */
|
|
315
|
+
timeOfDay?: number;
|
|
316
|
+
}
|
|
317
|
+
interface DayCycle {
|
|
318
|
+
timeOfDay: number;
|
|
319
|
+
/** Sun elevation in [-1, 1]; negative = below the horizon. */
|
|
320
|
+
readonly sunElevation: number;
|
|
321
|
+
readonly isNight: boolean;
|
|
322
|
+
/** Advance by dt seconds of real time and re-apply everything. */
|
|
323
|
+
update(dt: number): void;
|
|
324
|
+
/** Jump to a time of day and re-apply everything. */
|
|
325
|
+
set(t: number): void;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* One `timeOfDay` parameter driving the whole environment in lockstep:
|
|
329
|
+
* sun position/color/intensity, sky gradient, ambient level, fog color,
|
|
330
|
+
* and lamps that ignite as the sun drops below the horizon.
|
|
331
|
+
*
|
|
332
|
+
* ```ts
|
|
333
|
+
* const cycle = createDayCycle({ sky, rig, scene, lamps: [lampA, lampB], dayLength: 120 });
|
|
334
|
+
* game.onUpdate((t) => cycle.update(t.delta));
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
declare function createDayCycle(options?: DayCycleOptions): DayCycle;
|
|
338
|
+
|
|
339
|
+
interface WindOptions {
|
|
340
|
+
/** Sway amplitude in world units at the top of a prop. Default 0.06. */
|
|
341
|
+
strength?: number;
|
|
342
|
+
/** Oscillation speed. Default 1.2. */
|
|
343
|
+
frequency?: number;
|
|
344
|
+
/** Local height where sway begins (keeps trunks planted). Default 0.6. */
|
|
345
|
+
anchorHeight?: number;
|
|
346
|
+
}
|
|
347
|
+
interface Wind {
|
|
348
|
+
/** Advance the animation. Call from your frame loop. */
|
|
349
|
+
update(dt: number): void;
|
|
350
|
+
/** Materials that were patched (for debugging/cleanup). */
|
|
351
|
+
materials: Material[];
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Vertex-shader wind sway for scattered vegetation: displacement grows
|
|
355
|
+
* with local height (trunk bases stay planted), phase varies per
|
|
356
|
+
* instance so a forest shimmers instead of marching in step. Works on
|
|
357
|
+
* meshes and InstancedMeshes; patches each unique material once via
|
|
358
|
+
* onBeforeCompile.
|
|
359
|
+
*
|
|
360
|
+
* ```ts
|
|
361
|
+
* const wind = applyWind(forest.group, { strength: 0.08 });
|
|
362
|
+
* game.onUpdate((t) => wind.update(t.delta));
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
declare function applyWind(target: Object3D, options?: WindOptions): Wind;
|
|
366
|
+
|
|
367
|
+
interface PathOptions {
|
|
368
|
+
/** Ribbon width. Default 1.8. */
|
|
369
|
+
width?: number;
|
|
370
|
+
/** Ground height lookup; a number means flat ground. Default 0. */
|
|
371
|
+
surface?: number | ((x: number, z: number) => number);
|
|
372
|
+
/** Samples per world unit of path length. Default 1. */
|
|
373
|
+
samplesPerUnit?: number;
|
|
374
|
+
/** Close the path into a loop. Default false. */
|
|
375
|
+
loop?: boolean;
|
|
376
|
+
/** Extra clearance added to scatter keep-out circles. Default 0.6. */
|
|
377
|
+
keepOutMargin?: number;
|
|
378
|
+
palette?: Palette;
|
|
379
|
+
}
|
|
380
|
+
interface WorldPath {
|
|
381
|
+
mesh: Mesh;
|
|
382
|
+
/** Smoothed centerline draped on the surface — feed straight into a
|
|
383
|
+
* GAMA `Path` for patrols, or use as camera dolly points. */
|
|
384
|
+
route: Vector3[];
|
|
385
|
+
/** Keep-out circles for `scatter()` so nothing grows on the road. */
|
|
386
|
+
keepOut: Array<{
|
|
387
|
+
center: {
|
|
388
|
+
x: number;
|
|
389
|
+
z: number;
|
|
390
|
+
};
|
|
391
|
+
radius: number;
|
|
392
|
+
}>;
|
|
393
|
+
/** Is (x, z) on the path surface? (e.g. to exclude grass) */
|
|
394
|
+
contains(x: number, z: number): boolean;
|
|
395
|
+
loop: boolean;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* A dirt path: a Catmull-Rom-smoothed ribbon draped over the surface.
|
|
399
|
+
* One authored polyline feeds three things at once — the visual ribbon,
|
|
400
|
+
* scatter keep-out, and a patrol route for agents. That's the SCENA
|
|
401
|
+
* handshake applied to level design.
|
|
402
|
+
*
|
|
403
|
+
* ```ts
|
|
404
|
+
* const road = createPath([a, b, c], { surface: terrain.heightAt, loop: true });
|
|
405
|
+
* scene.add(road.mesh);
|
|
406
|
+
* scatter({ ..., keepOut: road.keepOut });
|
|
407
|
+
* agent.addBehavior(new FollowPath(new Path(road.route, road.loop), 1.5));
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
declare function createPath(points: Array<Vector3 | {
|
|
411
|
+
x: number;
|
|
412
|
+
z: number;
|
|
413
|
+
}>, options?: PathOptions): WorldPath;
|
|
414
|
+
|
|
415
|
+
interface VillageOptions {
|
|
416
|
+
seed?: number;
|
|
417
|
+
/** Village center in the XZ plane. Default origin. */
|
|
418
|
+
center?: {
|
|
419
|
+
x: number;
|
|
420
|
+
z: number;
|
|
421
|
+
};
|
|
422
|
+
/** Ring radius the houses settle on. Default 12. */
|
|
423
|
+
radius?: number;
|
|
424
|
+
/** House count. Default 5. */
|
|
425
|
+
houses?: number;
|
|
426
|
+
/** Ground height lookup; a number means flat ground. Default 0. */
|
|
427
|
+
surface?: number | ((x: number, z: number) => number);
|
|
428
|
+
/** Veto candidate spots (e.g. water, roads). Return false to reject. */
|
|
429
|
+
mask?: (x: number, z: number, y: number) => boolean;
|
|
430
|
+
/** Add real PointLights to this many street lamps. Default 3. */
|
|
431
|
+
lampLights?: number;
|
|
432
|
+
/** Add a watchtower at the edge. Default true. */
|
|
433
|
+
tower?: boolean;
|
|
434
|
+
/** Add a ruin outside the ring. Default true. */
|
|
435
|
+
ruin?: boolean;
|
|
436
|
+
palette?: Palette;
|
|
437
|
+
}
|
|
438
|
+
interface Village {
|
|
439
|
+
group: Group;
|
|
440
|
+
/** Every placed prop (houses, well, lamps, crates, tower, ruin). */
|
|
441
|
+
props: Prop[];
|
|
442
|
+
/** World-space steering obstacles — feed GAMA's ObstacleAvoidance. */
|
|
443
|
+
obstacles: Obstacle[];
|
|
444
|
+
/**
|
|
445
|
+
* Props with something to ignite at night (street lamps AND house
|
|
446
|
+
* windows). Pass straight to `createDayCycle({ lamps })`.
|
|
447
|
+
*/
|
|
448
|
+
lamps: Prop[];
|
|
449
|
+
/** One clearing circle covering the village — feed `scatter`'s keepOut. */
|
|
450
|
+
keepOut: Array<{
|
|
451
|
+
center: {
|
|
452
|
+
x: number;
|
|
453
|
+
z: number;
|
|
454
|
+
};
|
|
455
|
+
radius: number;
|
|
456
|
+
}>;
|
|
457
|
+
center: {
|
|
458
|
+
x: number;
|
|
459
|
+
z: number;
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* A seeded hamlet: a well at the center, houses ringed around it facing
|
|
464
|
+
* inward, street lamps between them, crates by the doors, a watchtower on
|
|
465
|
+
* the edge and a ruin beyond. Everything is placed on the given surface
|
|
466
|
+
* (steep or masked spots are rejected and re-rolled), and the result
|
|
467
|
+
* carries the full gameplay handshake: `obstacles` for steering,
|
|
468
|
+
* `keepOut` for scatter, and `lamps` for the day-night cycle — windows
|
|
469
|
+
* and lamps ignite together at dusk.
|
|
470
|
+
*
|
|
471
|
+
* ```ts
|
|
472
|
+
* const village = createVillage({ seed: 5, radius: 10, surface: terrain.heightAt, palette });
|
|
473
|
+
* scene.add(village.group);
|
|
474
|
+
* const cycle = createDayCycle({ sky, rig, scene, lamps: village.lamps, palette });
|
|
475
|
+
* const forest = scatter({ ..., keepOut: village.keepOut });
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
declare function createVillage(options?: VillageOptions): Village;
|
|
479
|
+
|
|
203
480
|
interface ScatterItem {
|
|
204
481
|
/** Prop factory, called once per visual variant with a seeded Rng. */
|
|
205
482
|
create(rng: Rng): Prop;
|
|
@@ -285,4 +562,4 @@ interface ScatterResult {
|
|
|
285
562
|
*/
|
|
286
563
|
declare function scatter(options: ScatterOptions): ScatterResult;
|
|
287
564
|
|
|
288
|
-
export { type CrateOptions, DEFAULT_PALETTE, type FenceOptions, type FogPreset, type LampOptions, type LightingPreset, type LightingRig, type Obstacle, PALETTES, type Palette, type Placement, type Prop, Rng, type RockOptions, type ScatterItem, type ScatterOptions, type ScatterResult, type Sky, type SkyOptions, type Terrain, type TerrainOptions, type TreeOptions, applyFog, collectObstacles, createCrate, createFence, createLamp, createLightingRig, createRock, createSky, createTerrain, createTree, fractalNoise2, hash2, scatter, valueNoise2 };
|
|
565
|
+
export { type BushOptions, type CrateOptions, DEFAULT_PALETTE, type DayCycle, type DayCycleOptions, type FenceOptions, type FogPreset, type GrassOptions, type HouseOptions, type LampOptions, type LightingPreset, type LightingRig, type Obstacle, PALETTES, type Palette, type PathOptions, type Placement, type Prop, Rng, type RockOptions, type RuinOptions, type ScatterItem, type ScatterOptions, type ScatterResult, type Sky, type SkyOptions, type Terrain, type TerrainOptions, type TowerOptions, type TreeOptions, type Village, type VillageOptions, type Water, type WaterOptions, type WellOptions, type Wind, type WindOptions, type WorldPath, aboveWater, applyFog, applyWind, collectObstacles, createBush, createCrate, createDayCycle, createFence, createGrassTuft, createHouse, createLamp, createLightingRig, createPath, createRock, createRuin, createSky, createTerrain, createTower, createTree, createVillage, createWater, createWell, fractalNoise2, hash2, scatter, valueNoise2 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vector3, Group, Mesh, DirectionalLight, AmbientLight, HemisphereLight, Scene } from 'three';
|
|
1
|
+
import { Vector3, Group, Mesh, DirectionalLight, AmbientLight, HemisphereLight, Scene, Object3D, Material } from 'three';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Deterministic seeded randomness — the backbone of SCENA. Same seed,
|
|
@@ -48,8 +48,15 @@ interface Palette {
|
|
|
48
48
|
skyTop: number;
|
|
49
49
|
skyBottom: number;
|
|
50
50
|
fog: number;
|
|
51
|
+
water: number;
|
|
52
|
+
sand: number;
|
|
53
|
+
path: number;
|
|
54
|
+
/** Building plaster/wall color. */
|
|
55
|
+
wall: number;
|
|
56
|
+
/** Building roof color. */
|
|
57
|
+
roof: number;
|
|
51
58
|
}
|
|
52
|
-
declare const PALETTES: Record<'meadow' | 'autumn' | 'dusk', Palette>;
|
|
59
|
+
declare const PALETTES: Record<'meadow' | 'autumn' | 'dusk' | 'winter', Palette>;
|
|
53
60
|
declare const DEFAULT_PALETTE: Palette;
|
|
54
61
|
|
|
55
62
|
/**
|
|
@@ -135,6 +142,65 @@ interface LampOptions {
|
|
|
135
142
|
/** A street lamp: post, head, glowing bulb, optional real PointLight. */
|
|
136
143
|
declare function createLamp(options?: LampOptions): Prop;
|
|
137
144
|
|
|
145
|
+
interface GrassOptions {
|
|
146
|
+
seed?: number;
|
|
147
|
+
/** Blades per tuft. Default 4–6 by seed. */
|
|
148
|
+
blades?: number;
|
|
149
|
+
palette?: Palette;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A tuft of grass blades — pure scatter fodder (zero obstacle footprint,
|
|
153
|
+
* walk straight through). Sways beautifully under `applyWind`.
|
|
154
|
+
*/
|
|
155
|
+
declare function createGrassTuft(options?: GrassOptions): Prop;
|
|
156
|
+
interface BushOptions {
|
|
157
|
+
seed?: number;
|
|
158
|
+
size?: number;
|
|
159
|
+
palette?: Palette;
|
|
160
|
+
}
|
|
161
|
+
/** A low foliage bush: two or three squashed blobs. Small footprint. */
|
|
162
|
+
declare function createBush(options?: BushOptions): Prop;
|
|
163
|
+
|
|
164
|
+
interface HouseOptions {
|
|
165
|
+
seed?: number;
|
|
166
|
+
/** Footprint width (gable side). Default seeded 3.2–4.2. */
|
|
167
|
+
width?: number;
|
|
168
|
+
depth?: number;
|
|
169
|
+
wallHeight?: number;
|
|
170
|
+
palette?: Palette;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A cottage: plastered walls, gabled roof, door, chimney and emissive
|
|
174
|
+
* windows. Pass the house in `createDayCycle`'s `lamps` list and its
|
|
175
|
+
* windows glow at night along with the street lamps. A stone foundation
|
|
176
|
+
* extends below ground so sloped terrain never shows a gap.
|
|
177
|
+
*/
|
|
178
|
+
declare function createHouse(options?: HouseOptions): Prop;
|
|
179
|
+
interface TowerOptions {
|
|
180
|
+
seed?: number;
|
|
181
|
+
height?: number;
|
|
182
|
+
palette?: Palette;
|
|
183
|
+
}
|
|
184
|
+
/** A wooden watchtower: splayed legs, platform with railing, pyramid roof. */
|
|
185
|
+
declare function createTower(options?: TowerOptions): Prop;
|
|
186
|
+
interface WellOptions {
|
|
187
|
+
seed?: number;
|
|
188
|
+
palette?: Palette;
|
|
189
|
+
}
|
|
190
|
+
/** A stone well: ring, posts, little gabled roof, hanging bucket. */
|
|
191
|
+
declare function createWell(options?: WellOptions): Prop;
|
|
192
|
+
interface RuinOptions {
|
|
193
|
+
seed?: number;
|
|
194
|
+
/** Footprint width. Default seeded 3.5–5. */
|
|
195
|
+
size?: number;
|
|
196
|
+
palette?: Palette;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* A ruined building: a partial rectangle of crumbling wall segments with
|
|
200
|
+
* seeded gaps and heights, and tumbled blocks around the floor.
|
|
201
|
+
*/
|
|
202
|
+
declare function createRuin(options?: RuinOptions): Prop;
|
|
203
|
+
|
|
138
204
|
interface TerrainOptions {
|
|
139
205
|
seed?: number;
|
|
140
206
|
/** Square side length. Default 80. */
|
|
@@ -148,6 +214,8 @@ interface TerrainOptions {
|
|
|
148
214
|
octaves?: number;
|
|
149
215
|
/** Flatten low areas into meadows (0–1, higher = flatter valleys). Default 0.55. */
|
|
150
216
|
valleyFlatness?: number;
|
|
217
|
+
/** Blend low bands toward sand below (waterLevel + shore margin). */
|
|
218
|
+
waterLevel?: number;
|
|
151
219
|
palette?: Palette;
|
|
152
220
|
}
|
|
153
221
|
interface Terrain {
|
|
@@ -200,6 +268,215 @@ type FogPreset = 'clear' | 'haze' | 'thick' | 'eerie';
|
|
|
200
268
|
/** Distance fog matched to the palette's fog color. 'clear' removes it. */
|
|
201
269
|
declare function applyFog(scene: Scene, preset: FogPreset, palette?: Palette): void;
|
|
202
270
|
|
|
271
|
+
interface WaterOptions {
|
|
272
|
+
/** World-space water surface height. Default 0.8. */
|
|
273
|
+
level?: number;
|
|
274
|
+
size?: number;
|
|
275
|
+
resolution?: number;
|
|
276
|
+
/** Wave height. Default 0.06. */
|
|
277
|
+
amplitude?: number;
|
|
278
|
+
/** Wave speed multiplier. Default 1. */
|
|
279
|
+
speed?: number;
|
|
280
|
+
palette?: Palette;
|
|
281
|
+
}
|
|
282
|
+
interface Water {
|
|
283
|
+
mesh: Mesh;
|
|
284
|
+
level: number;
|
|
285
|
+
/** Advance the wave animation. Call from your frame loop. */
|
|
286
|
+
update(dt: number): void;
|
|
287
|
+
/** Is ground at this height below the surface? */
|
|
288
|
+
isUnderwater(groundHeight: number): boolean;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* A low-poly animated water plane at a fixed level. Pair it with a
|
|
292
|
+
* terrain built using the same `waterLevel` so shores blend to sand, and
|
|
293
|
+
* keep scatter/agents ashore with `aboveWater(terrain, water)`.
|
|
294
|
+
*/
|
|
295
|
+
declare function createWater(options?: WaterOptions): Water;
|
|
296
|
+
/**
|
|
297
|
+
* A scatter mask keeping placements on dry land: true when the terrain
|
|
298
|
+
* at (x, z) sits above the water level plus `margin`.
|
|
299
|
+
*/
|
|
300
|
+
declare function aboveWater(terrain: Terrain, water: Pick<Water, 'level'>, margin?: number): (x: number, z: number) => boolean;
|
|
301
|
+
|
|
302
|
+
interface DayCycleOptions {
|
|
303
|
+
sky?: Sky;
|
|
304
|
+
rig?: LightingRig;
|
|
305
|
+
/** Scene whose fog color should track the cycle. */
|
|
306
|
+
scene?: Scene;
|
|
307
|
+
/** Lamp props/objects whose PointLights + glow bulbs ignite at night. */
|
|
308
|
+
lamps?: Array<{
|
|
309
|
+
object: Object3D;
|
|
310
|
+
} | Object3D>;
|
|
311
|
+
palette?: Palette;
|
|
312
|
+
/** Seconds per full day. Default 60. */
|
|
313
|
+
dayLength?: number;
|
|
314
|
+
/** Initial time: 0 = midnight, 0.25 = dawn, 0.5 = noon, 0.75 = dusk. */
|
|
315
|
+
timeOfDay?: number;
|
|
316
|
+
}
|
|
317
|
+
interface DayCycle {
|
|
318
|
+
timeOfDay: number;
|
|
319
|
+
/** Sun elevation in [-1, 1]; negative = below the horizon. */
|
|
320
|
+
readonly sunElevation: number;
|
|
321
|
+
readonly isNight: boolean;
|
|
322
|
+
/** Advance by dt seconds of real time and re-apply everything. */
|
|
323
|
+
update(dt: number): void;
|
|
324
|
+
/** Jump to a time of day and re-apply everything. */
|
|
325
|
+
set(t: number): void;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* One `timeOfDay` parameter driving the whole environment in lockstep:
|
|
329
|
+
* sun position/color/intensity, sky gradient, ambient level, fog color,
|
|
330
|
+
* and lamps that ignite as the sun drops below the horizon.
|
|
331
|
+
*
|
|
332
|
+
* ```ts
|
|
333
|
+
* const cycle = createDayCycle({ sky, rig, scene, lamps: [lampA, lampB], dayLength: 120 });
|
|
334
|
+
* game.onUpdate((t) => cycle.update(t.delta));
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
declare function createDayCycle(options?: DayCycleOptions): DayCycle;
|
|
338
|
+
|
|
339
|
+
interface WindOptions {
|
|
340
|
+
/** Sway amplitude in world units at the top of a prop. Default 0.06. */
|
|
341
|
+
strength?: number;
|
|
342
|
+
/** Oscillation speed. Default 1.2. */
|
|
343
|
+
frequency?: number;
|
|
344
|
+
/** Local height where sway begins (keeps trunks planted). Default 0.6. */
|
|
345
|
+
anchorHeight?: number;
|
|
346
|
+
}
|
|
347
|
+
interface Wind {
|
|
348
|
+
/** Advance the animation. Call from your frame loop. */
|
|
349
|
+
update(dt: number): void;
|
|
350
|
+
/** Materials that were patched (for debugging/cleanup). */
|
|
351
|
+
materials: Material[];
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Vertex-shader wind sway for scattered vegetation: displacement grows
|
|
355
|
+
* with local height (trunk bases stay planted), phase varies per
|
|
356
|
+
* instance so a forest shimmers instead of marching in step. Works on
|
|
357
|
+
* meshes and InstancedMeshes; patches each unique material once via
|
|
358
|
+
* onBeforeCompile.
|
|
359
|
+
*
|
|
360
|
+
* ```ts
|
|
361
|
+
* const wind = applyWind(forest.group, { strength: 0.08 });
|
|
362
|
+
* game.onUpdate((t) => wind.update(t.delta));
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
declare function applyWind(target: Object3D, options?: WindOptions): Wind;
|
|
366
|
+
|
|
367
|
+
interface PathOptions {
|
|
368
|
+
/** Ribbon width. Default 1.8. */
|
|
369
|
+
width?: number;
|
|
370
|
+
/** Ground height lookup; a number means flat ground. Default 0. */
|
|
371
|
+
surface?: number | ((x: number, z: number) => number);
|
|
372
|
+
/** Samples per world unit of path length. Default 1. */
|
|
373
|
+
samplesPerUnit?: number;
|
|
374
|
+
/** Close the path into a loop. Default false. */
|
|
375
|
+
loop?: boolean;
|
|
376
|
+
/** Extra clearance added to scatter keep-out circles. Default 0.6. */
|
|
377
|
+
keepOutMargin?: number;
|
|
378
|
+
palette?: Palette;
|
|
379
|
+
}
|
|
380
|
+
interface WorldPath {
|
|
381
|
+
mesh: Mesh;
|
|
382
|
+
/** Smoothed centerline draped on the surface — feed straight into a
|
|
383
|
+
* GAMA `Path` for patrols, or use as camera dolly points. */
|
|
384
|
+
route: Vector3[];
|
|
385
|
+
/** Keep-out circles for `scatter()` so nothing grows on the road. */
|
|
386
|
+
keepOut: Array<{
|
|
387
|
+
center: {
|
|
388
|
+
x: number;
|
|
389
|
+
z: number;
|
|
390
|
+
};
|
|
391
|
+
radius: number;
|
|
392
|
+
}>;
|
|
393
|
+
/** Is (x, z) on the path surface? (e.g. to exclude grass) */
|
|
394
|
+
contains(x: number, z: number): boolean;
|
|
395
|
+
loop: boolean;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* A dirt path: a Catmull-Rom-smoothed ribbon draped over the surface.
|
|
399
|
+
* One authored polyline feeds three things at once — the visual ribbon,
|
|
400
|
+
* scatter keep-out, and a patrol route for agents. That's the SCENA
|
|
401
|
+
* handshake applied to level design.
|
|
402
|
+
*
|
|
403
|
+
* ```ts
|
|
404
|
+
* const road = createPath([a, b, c], { surface: terrain.heightAt, loop: true });
|
|
405
|
+
* scene.add(road.mesh);
|
|
406
|
+
* scatter({ ..., keepOut: road.keepOut });
|
|
407
|
+
* agent.addBehavior(new FollowPath(new Path(road.route, road.loop), 1.5));
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
declare function createPath(points: Array<Vector3 | {
|
|
411
|
+
x: number;
|
|
412
|
+
z: number;
|
|
413
|
+
}>, options?: PathOptions): WorldPath;
|
|
414
|
+
|
|
415
|
+
interface VillageOptions {
|
|
416
|
+
seed?: number;
|
|
417
|
+
/** Village center in the XZ plane. Default origin. */
|
|
418
|
+
center?: {
|
|
419
|
+
x: number;
|
|
420
|
+
z: number;
|
|
421
|
+
};
|
|
422
|
+
/** Ring radius the houses settle on. Default 12. */
|
|
423
|
+
radius?: number;
|
|
424
|
+
/** House count. Default 5. */
|
|
425
|
+
houses?: number;
|
|
426
|
+
/** Ground height lookup; a number means flat ground. Default 0. */
|
|
427
|
+
surface?: number | ((x: number, z: number) => number);
|
|
428
|
+
/** Veto candidate spots (e.g. water, roads). Return false to reject. */
|
|
429
|
+
mask?: (x: number, z: number, y: number) => boolean;
|
|
430
|
+
/** Add real PointLights to this many street lamps. Default 3. */
|
|
431
|
+
lampLights?: number;
|
|
432
|
+
/** Add a watchtower at the edge. Default true. */
|
|
433
|
+
tower?: boolean;
|
|
434
|
+
/** Add a ruin outside the ring. Default true. */
|
|
435
|
+
ruin?: boolean;
|
|
436
|
+
palette?: Palette;
|
|
437
|
+
}
|
|
438
|
+
interface Village {
|
|
439
|
+
group: Group;
|
|
440
|
+
/** Every placed prop (houses, well, lamps, crates, tower, ruin). */
|
|
441
|
+
props: Prop[];
|
|
442
|
+
/** World-space steering obstacles — feed GAMA's ObstacleAvoidance. */
|
|
443
|
+
obstacles: Obstacle[];
|
|
444
|
+
/**
|
|
445
|
+
* Props with something to ignite at night (street lamps AND house
|
|
446
|
+
* windows). Pass straight to `createDayCycle({ lamps })`.
|
|
447
|
+
*/
|
|
448
|
+
lamps: Prop[];
|
|
449
|
+
/** One clearing circle covering the village — feed `scatter`'s keepOut. */
|
|
450
|
+
keepOut: Array<{
|
|
451
|
+
center: {
|
|
452
|
+
x: number;
|
|
453
|
+
z: number;
|
|
454
|
+
};
|
|
455
|
+
radius: number;
|
|
456
|
+
}>;
|
|
457
|
+
center: {
|
|
458
|
+
x: number;
|
|
459
|
+
z: number;
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* A seeded hamlet: a well at the center, houses ringed around it facing
|
|
464
|
+
* inward, street lamps between them, crates by the doors, a watchtower on
|
|
465
|
+
* the edge and a ruin beyond. Everything is placed on the given surface
|
|
466
|
+
* (steep or masked spots are rejected and re-rolled), and the result
|
|
467
|
+
* carries the full gameplay handshake: `obstacles` for steering,
|
|
468
|
+
* `keepOut` for scatter, and `lamps` for the day-night cycle — windows
|
|
469
|
+
* and lamps ignite together at dusk.
|
|
470
|
+
*
|
|
471
|
+
* ```ts
|
|
472
|
+
* const village = createVillage({ seed: 5, radius: 10, surface: terrain.heightAt, palette });
|
|
473
|
+
* scene.add(village.group);
|
|
474
|
+
* const cycle = createDayCycle({ sky, rig, scene, lamps: village.lamps, palette });
|
|
475
|
+
* const forest = scatter({ ..., keepOut: village.keepOut });
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
declare function createVillage(options?: VillageOptions): Village;
|
|
479
|
+
|
|
203
480
|
interface ScatterItem {
|
|
204
481
|
/** Prop factory, called once per visual variant with a seeded Rng. */
|
|
205
482
|
create(rng: Rng): Prop;
|
|
@@ -285,4 +562,4 @@ interface ScatterResult {
|
|
|
285
562
|
*/
|
|
286
563
|
declare function scatter(options: ScatterOptions): ScatterResult;
|
|
287
564
|
|
|
288
|
-
export { type CrateOptions, DEFAULT_PALETTE, type FenceOptions, type FogPreset, type LampOptions, type LightingPreset, type LightingRig, type Obstacle, PALETTES, type Palette, type Placement, type Prop, Rng, type RockOptions, type ScatterItem, type ScatterOptions, type ScatterResult, type Sky, type SkyOptions, type Terrain, type TerrainOptions, type TreeOptions, applyFog, collectObstacles, createCrate, createFence, createLamp, createLightingRig, createRock, createSky, createTerrain, createTree, fractalNoise2, hash2, scatter, valueNoise2 };
|
|
565
|
+
export { type BushOptions, type CrateOptions, DEFAULT_PALETTE, type DayCycle, type DayCycleOptions, type FenceOptions, type FogPreset, type GrassOptions, type HouseOptions, type LampOptions, type LightingPreset, type LightingRig, type Obstacle, PALETTES, type Palette, type PathOptions, type Placement, type Prop, Rng, type RockOptions, type RuinOptions, type ScatterItem, type ScatterOptions, type ScatterResult, type Sky, type SkyOptions, type Terrain, type TerrainOptions, type TowerOptions, type TreeOptions, type Village, type VillageOptions, type Water, type WaterOptions, type WellOptions, type Wind, type WindOptions, type WorldPath, aboveWater, applyFog, applyWind, collectObstacles, createBush, createCrate, createDayCycle, createFence, createGrassTuft, createHouse, createLamp, createLightingRig, createPath, createRock, createRuin, createSky, createTerrain, createTower, createTree, createVillage, createWater, createWell, fractalNoise2, hash2, scatter, valueNoise2 };
|