@aethervtt/shard-scatter 0.0.0-stage → 0.2.1
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/LICENSE +21 -0
- package/README.md +2 -2
- package/dist/components.d.ts +44 -0
- package/dist/components.js +98 -0
- package/dist/foliage.d.ts +43 -0
- package/dist/foliage.js +175 -0
- package/dist/heightfield-surface.d.ts +35 -0
- package/dist/heightfield-surface.js +61 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +120 -0
- package/dist/material.d.ts +20 -0
- package/dist/material.js +149 -0
- package/dist/mesh-surface.d.ts +79 -0
- package/dist/mesh-surface.js +470 -0
- package/dist/methods.d.ts +10 -0
- package/dist/methods.js +341 -0
- package/dist/overlays.d.ts +4 -0
- package/dist/overlays.js +84 -0
- package/dist/planet.d.ts +74 -0
- package/dist/planet.js +675 -0
- package/dist/plugin.d.ts +17 -0
- package/dist/plugin.js +265 -0
- package/dist/preview-render.d.ts +10 -0
- package/dist/preview-render.js +155 -0
- package/dist/preview.d.ts +5 -0
- package/dist/preview.js +11 -0
- package/dist/rules.d.ts +97 -0
- package/dist/rules.js +170 -0
- package/dist/runtime.d.ts +138 -0
- package/dist/runtime.js +702 -0
- package/dist/set.d.ts +45 -0
- package/dist/set.js +131 -0
- package/dist/surface.d.ts +124 -0
- package/dist/surface.js +20 -0
- package/dist/testing.d.ts +236 -0
- package/dist/testing.js +231 -0
- package/dist/viewers.d.ts +9 -0
- package/dist/viewers.js +22 -0
- package/package.json +49 -4
package/dist/set.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Collider shapes a prop rule can give its items (fixed bodies; none by default). */
|
|
2
|
+
export declare const PROP_COLLIDERS: readonly ['none', 'convex', 'trimesh', 'ball', 'cuboid'];
|
|
3
|
+
export type PropCollider = (typeof PROP_COLLIDERS)[number];
|
|
4
|
+
/**
|
|
5
|
+
* Rules that place props and foliage on a surface (spec 0045): a planet everywhere
|
|
6
|
+
* (`Planet.scatter`), a planet's biome where it dominates (`Biome.scatter`), or a mesh
|
|
7
|
+
* (`scatter/ScatterSurface`). Rule order is priority: `avoid` names earlier rules.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ScatterSet: import("@aethervtt/shard-assets").DataType<{
|
|
10
|
+
readonly rules: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
11
|
+
name: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
12
|
+
kind: import("@aethervtt/shard-core").FieldType<"foliage" | "prop", "u8">;
|
|
13
|
+
items: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
14
|
+
prefab: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").AssetRef<"Prefab"> | null, "object">;
|
|
15
|
+
generator: import("@aethervtt/shard-core").FieldType<string, "object">;
|
|
16
|
+
params: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").JsonValue, "object">;
|
|
17
|
+
variants: import("@aethervtt/shard-core").FieldType<number, "u8">;
|
|
18
|
+
material: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").AssetRef<"Material"> | null, "object">;
|
|
19
|
+
weight: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
20
|
+
radius: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
21
|
+
}>[], "object">;
|
|
22
|
+
density: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
23
|
+
spacing: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
24
|
+
masks: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
25
|
+
slope: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
26
|
+
height: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
27
|
+
noise: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").InferFields<{
|
|
28
|
+
graph: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").AssetRef<"NoiseGraph"> | null, "object">;
|
|
29
|
+
above: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
30
|
+
}>, "object">;
|
|
31
|
+
}>, "object">;
|
|
32
|
+
align: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
33
|
+
scale: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
34
|
+
sink: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
35
|
+
collider: import("@aethervtt/shard-core").FieldType<"ball" | "convex" | "cuboid" | "none" | "trimesh", "u8">;
|
|
36
|
+
range: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
37
|
+
avoid: import("@aethervtt/shard-core").FieldType<string[], "object">;
|
|
38
|
+
wind: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
39
|
+
shadowRange: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
40
|
+
}>[], "object">;
|
|
41
|
+
readonly seed: import("@aethervtt/shard-core").FieldType<number, "u32">;
|
|
42
|
+
}, "scatter/ScatterSet">;
|
|
43
|
+
export type ScatterSetValue = ReturnType<typeof ScatterSet.defaults>;
|
|
44
|
+
export type ScatterRuleValue = ScatterSetValue['rules'][number];
|
|
45
|
+
export type ScatterItemValue = ScatterRuleValue['items'][number];
|
package/dist/set.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { defineDataType } from "@aethervtt/shard-assets";
|
|
2
|
+
import { t } from "@aethervtt/shard-core";
|
|
3
|
+
const PROP_COLLIDERS = ["none", "convex", "trimesh", "ball", "cuboid"];
|
|
4
|
+
const item = t.struct({
|
|
5
|
+
prefab: t.handle("Prefab", {
|
|
6
|
+
description: "A prefab to place (its root gets the placement transform). Or use generator."
|
|
7
|
+
}),
|
|
8
|
+
generator: t.string({
|
|
9
|
+
description: 'A mesh generator by name: "shard/Rock", "shard/Tree", "shard/Bush", "shard/GrassClump", "shard/Crystal", or a project\u2019s ("star-explorer/Rock").'
|
|
10
|
+
}),
|
|
11
|
+
params: t.json({ description: "The generator\u2019s params (missing ones take its defaults)." }),
|
|
12
|
+
variants: t.u8({
|
|
13
|
+
default: 1,
|
|
14
|
+
min: 1,
|
|
15
|
+
max: 32,
|
|
16
|
+
description: "Distinct meshes generated (seeds are the rule\u2019s child seeds 0 \u2026 n\u22121); each placement picks one. 4\u20138 read as unique once scaled and rotated."
|
|
17
|
+
}),
|
|
18
|
+
material: t.handle("Material", {
|
|
19
|
+
description: "The generator item\u2019s material (default: scatter/Vegetation tinted for the generator)."
|
|
20
|
+
}),
|
|
21
|
+
weight: t.f32({
|
|
22
|
+
default: 1,
|
|
23
|
+
min: 0,
|
|
24
|
+
description: "Relative chance among the rule\u2019s items."
|
|
25
|
+
}),
|
|
26
|
+
radius: t.f32({
|
|
27
|
+
min: 0,
|
|
28
|
+
unit: "m",
|
|
29
|
+
description: "Footprint radius for `avoid` and `sink` before scale (0: from the mesh\u2019s bounds; prefabs: half the rule\u2019s spacing)."
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
const range = (what, unit, typical) => t.vec2({
|
|
33
|
+
unit,
|
|
34
|
+
description: `[min, max] ${what}. Equal ends (the default): anywhere. ${typical}`
|
|
35
|
+
});
|
|
36
|
+
const rule = t.struct({
|
|
37
|
+
name: t.string({
|
|
38
|
+
required: true,
|
|
39
|
+
description: "Unique in the set: `avoid` lists, saves, and scatter.describe use it."
|
|
40
|
+
}),
|
|
41
|
+
kind: t.enum(["prop", "foliage"], {
|
|
42
|
+
description: "prop: entities (colliders, saves, gameplay), a few thousand near the player. foliage: GPU instances only (grass, flowers), millions, no entities."
|
|
43
|
+
}),
|
|
44
|
+
items: t.list(item, { description: "What it places, picked by weight." }),
|
|
45
|
+
density: t.f32({
|
|
46
|
+
default: 0.01,
|
|
47
|
+
min: 0,
|
|
48
|
+
unit: "1/m\xB2",
|
|
49
|
+
description: "Items per square metre where the masks pass. Typical: boulders 0.002\u20130.01, trees 0.005\u20130.05, bushes 0.02\u20130.1, grass 4\u201310, flowers 0.5\u20132."
|
|
50
|
+
}),
|
|
51
|
+
spacing: t.f32({
|
|
52
|
+
min: 0,
|
|
53
|
+
unit: "m",
|
|
54
|
+
description: "Least distance between two items of this rule (0: none). Typical: about an item\u2019s diameter (trees 3\u20136, boulders 4\u20138)."
|
|
55
|
+
}),
|
|
56
|
+
masks: t.struct(
|
|
57
|
+
{
|
|
58
|
+
slope: range("slope", "deg", "Grass 0\u201325, trees 0\u201330, boulders 0\u201335, cliff rocks 35\u201390."),
|
|
59
|
+
height: range(
|
|
60
|
+
"height",
|
|
61
|
+
"m",
|
|
62
|
+
"Metres above the planet radius (a mesh surface: its local y). Beaches \u22122\u20134, treeline below 1 200."
|
|
63
|
+
),
|
|
64
|
+
noise: t.struct(
|
|
65
|
+
{
|
|
66
|
+
graph: t.handle("NoiseGraph", {
|
|
67
|
+
description: "A noise graph (*.noise.json) sampled where items would go."
|
|
68
|
+
}),
|
|
69
|
+
above: t.f32({
|
|
70
|
+
description: "Items only where the graph\u2019s value is above this (\u22121 to 1). 0.2 makes patches."
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
{ description: "Patches: items only where a noise graph is above a threshold." }
|
|
74
|
+
)
|
|
75
|
+
},
|
|
76
|
+
{ description: "Where items may go, on top of the biome the set belongs to." }
|
|
77
|
+
),
|
|
78
|
+
align: t.f32({
|
|
79
|
+
min: 0,
|
|
80
|
+
max: 1,
|
|
81
|
+
description: "Up axis from world up (0, radial on a planet) to the surface normal (1). Trees 0, rocks 0.6\u20131, grass 0.3."
|
|
82
|
+
}),
|
|
83
|
+
scale: t.vec2({
|
|
84
|
+
default: [1, 1],
|
|
85
|
+
min: 0,
|
|
86
|
+
description: "Uniform scale range [min, max] per item. Typical [0.7, 1.4]."
|
|
87
|
+
}),
|
|
88
|
+
sink: t.f32({
|
|
89
|
+
min: 0,
|
|
90
|
+
max: 1,
|
|
91
|
+
description: "Pushes items into the ground by this fraction of their height. Rocks 0.1\u20130.3."
|
|
92
|
+
}),
|
|
93
|
+
collider: t.enum(PROP_COLLIDERS, {
|
|
94
|
+
description: "Props: a fixed collider from the item\u2019s coarsest mesh (convex, trimesh) or its bounds (ball, cuboid). Foliage ignores it."
|
|
95
|
+
}),
|
|
96
|
+
range: t.f32({
|
|
97
|
+
default: 200,
|
|
98
|
+
min: 1,
|
|
99
|
+
unit: "m",
|
|
100
|
+
description: "Distance from the camera (or a TerrainAnchor, for props) at which items exist. Grass 40\u201380, bushes 100\u2013200, trees 300\u2013800, boulders 300\u2013600."
|
|
101
|
+
}),
|
|
102
|
+
avoid: t.list(t.string, {
|
|
103
|
+
description: 'Earlier rules whose items keep this one out of their footprint (by the placed item\u2019s radius): ["boulders"] keeps grass off rocks.'
|
|
104
|
+
}),
|
|
105
|
+
wind: t.f32({
|
|
106
|
+
default: 1,
|
|
107
|
+
min: 0,
|
|
108
|
+
description: "Foliage: how much the wind sways it (0 rigid, 1 grass)."
|
|
109
|
+
}),
|
|
110
|
+
shadowRange: t.f32({
|
|
111
|
+
default: 30,
|
|
112
|
+
min: 0,
|
|
113
|
+
unit: "m",
|
|
114
|
+
description: "Foliage: casts shadows within this distance of the camera (0: never)."
|
|
115
|
+
})
|
|
116
|
+
});
|
|
117
|
+
const ScatterSet = defineDataType(
|
|
118
|
+
"scatter/ScatterSet",
|
|
119
|
+
{
|
|
120
|
+
rules: t.list(rule, { description: "Placement rules, highest priority first." }),
|
|
121
|
+
seed: t.u32({ description: "Mixed into every rule\u2019s seed: the same rules, new places." })
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
extension: "scatter",
|
|
125
|
+
description: "Scatter rules: props (entities) and foliage (GPU instances) placed by density, spacing, masks, alignment, and random transforms, the same on every visit and machine."
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
export {
|
|
129
|
+
PROP_COLLIDERS,
|
|
130
|
+
ScatterSet
|
|
131
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Entity, World } from '@aethervtt/shard-core';
|
|
2
|
+
import type { NoiseGraph } from '@aethervtt/shard-noise';
|
|
3
|
+
import type { Workers } from '@aethervtt/shard-platform';
|
|
4
|
+
import type { CompiledRule } from './rules.js';
|
|
5
|
+
/**
|
|
6
|
+
* Floats per placement in a chunk's placements: item, variant, position (xyz, relative to the
|
|
7
|
+
* chunk's center, in the surface's frame, before sink), rotation (xyzw), scale, cell index (the
|
|
8
|
+
* placement's stable id in the chunk), footprint radius (scaled, for `avoid`; 0 until the item's
|
|
9
|
+
* bounds are known), and the shade variation in [0, 1].
|
|
10
|
+
*/
|
|
11
|
+
export declare const PLACEMENT_STRIDE = 13;
|
|
12
|
+
export declare const P_ITEM = 0;
|
|
13
|
+
export declare const P_VARIANT = 1;
|
|
14
|
+
export declare const P_X = 2;
|
|
15
|
+
export declare const P_QX = 5;
|
|
16
|
+
export declare const P_SCALE = 9;
|
|
17
|
+
export declare const P_CELL = 10;
|
|
18
|
+
export declare const P_RADIUS = 11;
|
|
19
|
+
export declare const P_SHADE = 12;
|
|
20
|
+
/** A chunk of one rule's lattice: a quadtree node on a planet, a square on a mesh. */
|
|
21
|
+
export interface SurfaceChunk {
|
|
22
|
+
/** The chunk's address as text: `face/depth/x/y` on a planet, `x/z` on a mesh. */
|
|
23
|
+
key: string;
|
|
24
|
+
rule: number;
|
|
25
|
+
face: number;
|
|
26
|
+
depth: number;
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
/** Center at zero height, in the surface's frame. */
|
|
30
|
+
center: Float64Array;
|
|
31
|
+
/** Half the chunk's diagonal (m): a chunk is in range when its center is within range + this. */
|
|
32
|
+
extent: number;
|
|
33
|
+
}
|
|
34
|
+
/** A chunk's placements, cached per (surface version, rule, chunk). */
|
|
35
|
+
export interface ChunkPlacements {
|
|
36
|
+
chunk: SurfaceChunk;
|
|
37
|
+
count: number;
|
|
38
|
+
data: Float32Array;
|
|
39
|
+
/** Candidates tested (lattice cells), for scatter.describe. */
|
|
40
|
+
candidates: number;
|
|
41
|
+
}
|
|
42
|
+
/** Placement in progress: sampling on the pool, assembled on the main thread when due. */
|
|
43
|
+
export interface PlacementJob {
|
|
44
|
+
chunk: SurfaceChunk;
|
|
45
|
+
/** Frame it must be finished by (placed inline then if the pool hasn't answered). */
|
|
46
|
+
due: number;
|
|
47
|
+
/** The pool's samples arrived. */
|
|
48
|
+
ready: boolean;
|
|
49
|
+
cancelled: boolean;
|
|
50
|
+
/** Surface-specific state (candidates, samples). */
|
|
51
|
+
state: unknown;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What placement needs from a surface: its frame, its chunk grid per rule, and its heights, normals
|
|
55
|
+
* and masks at candidate points. Planets (0043), meshes (`ScatterSurface`) and heightfield terrains
|
|
56
|
+
* (0071, `Terrain.scatter`) implement it.
|
|
57
|
+
*/
|
|
58
|
+
export interface Surface {
|
|
59
|
+
readonly entity: Entity;
|
|
60
|
+
readonly kind: 'planet' | 'mesh' | 'heightfield';
|
|
61
|
+
/** Bumps when anything placements depend on changes (rules, seed, heights). */
|
|
62
|
+
readonly version: number;
|
|
63
|
+
readonly rules: readonly CompiledRule[];
|
|
64
|
+
/** Lattice cells per chunk side, per rule. */
|
|
65
|
+
readonly cells: readonly number[];
|
|
66
|
+
/** Each rule's noise mask graph, loaded (undefined: no mask). */
|
|
67
|
+
readonly masks: readonly (NoiseGraph | undefined)[];
|
|
68
|
+
/** Takes new rules (and their loaded masks); bumps `version`. */
|
|
69
|
+
configure(rules: CompiledRule[], masks: (NoiseGraph | undefined)[], version: number): void;
|
|
70
|
+
/** Whether the surface can place (its graphs and sets are loaded). */
|
|
71
|
+
readonly ready: boolean;
|
|
72
|
+
/** Viewer positions in the surface's frame: cameras, then (for props) anchors. Returns the count of each. */
|
|
73
|
+
viewers(world: World, out: {
|
|
74
|
+
points: Float64Array;
|
|
75
|
+
cameras: number;
|
|
76
|
+
anchors: number;
|
|
77
|
+
}): void;
|
|
78
|
+
/** Visits every chunk of `rule` whose center is within `range` (+ its extent) of a viewer. */
|
|
79
|
+
chunksNear(rule: CompiledRule, viewers: Float64Array, first: number, count: number, range: number, visit: (chunk: SurfaceChunk, distance: number) => void): void;
|
|
80
|
+
/** The chunk of `rule` containing a surface-frame point (avoid lookups, scatter.sample). */
|
|
81
|
+
chunkAt(rule: CompiledRule, x: number, y: number, z: number): SurfaceChunk;
|
|
82
|
+
/** Starts placing a chunk: candidates now, samples on the pool when `workers` has threads. */
|
|
83
|
+
startPlacement(chunk: SurfaceChunk, due: number, workers: Workers | undefined): PlacementJob;
|
|
84
|
+
/**
|
|
85
|
+
* Finishes a job (sampling inline if the pool hasn't answered) into placements, without
|
|
86
|
+
* `avoid` (the runtime applies that once the avoided chunks are placed).
|
|
87
|
+
*/
|
|
88
|
+
finishPlacement(job: PlacementJob): ChunkPlacements;
|
|
89
|
+
/** Parents a chunk's root entity: a child of the surface at the chunk's center. */
|
|
90
|
+
placeChunkRoot(world: World, root: Entity, chunk: SurfaceChunk): void;
|
|
91
|
+
/** The surface's up (unit) at a surface-frame point: radial on a planet, +Y on a mesh. */
|
|
92
|
+
upAt(x: number, y: number, z: number, out: Float64Array): Float64Array;
|
|
93
|
+
/**
|
|
94
|
+
* Starts building a foliage chunk's ground patch: its grid of positions, normals and the rule's
|
|
95
|
+
* density per vertex (masks, biome), on the pool where there is one.
|
|
96
|
+
*/
|
|
97
|
+
startPatch(chunk: SurfaceChunk, workers: Workers | undefined): PatchJob;
|
|
98
|
+
/** The patch (built inline if the pool hasn't answered). */
|
|
99
|
+
finishPatch(job: PatchJob): FoliagePatch;
|
|
100
|
+
/**
|
|
101
|
+
* The chunk's frame (surface axes, metres, origin at its center) in origin-relative world space:
|
|
102
|
+
* an affine's three rows (12 floats) into `out`. Changes with the floating origin.
|
|
103
|
+
*/
|
|
104
|
+
chunkTransform(world: World, chunk: SurfaceChunk, out: Float32Array): void;
|
|
105
|
+
}
|
|
106
|
+
/** A foliage chunk's ground: what the GPU places instances on (render's FoliageChunk). */
|
|
107
|
+
export interface FoliagePatch {
|
|
108
|
+
grid: number;
|
|
109
|
+
positions: Float32Array;
|
|
110
|
+
normals: Float32Array;
|
|
111
|
+
density: Float32Array;
|
|
112
|
+
cell0: [number, number];
|
|
113
|
+
domain: number;
|
|
114
|
+
accept: number;
|
|
115
|
+
jitter: number;
|
|
116
|
+
radial: [number, number, number] | undefined;
|
|
117
|
+
}
|
|
118
|
+
/** A patch being built. */
|
|
119
|
+
export interface PatchJob {
|
|
120
|
+
chunk: SurfaceChunk;
|
|
121
|
+
ready: boolean;
|
|
122
|
+
cancelled: boolean;
|
|
123
|
+
state: unknown;
|
|
124
|
+
}
|
package/dist/surface.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const PLACEMENT_STRIDE = 13;
|
|
2
|
+
const P_ITEM = 0;
|
|
3
|
+
const P_VARIANT = 1;
|
|
4
|
+
const P_X = 2;
|
|
5
|
+
const P_QX = 5;
|
|
6
|
+
const P_SCALE = 9;
|
|
7
|
+
const P_CELL = 10;
|
|
8
|
+
const P_RADIUS = 11;
|
|
9
|
+
const P_SHADE = 12;
|
|
10
|
+
export {
|
|
11
|
+
PLACEMENT_STRIDE,
|
|
12
|
+
P_CELL,
|
|
13
|
+
P_ITEM,
|
|
14
|
+
P_QX,
|
|
15
|
+
P_RADIUS,
|
|
16
|
+
P_SCALE,
|
|
17
|
+
P_SHADE,
|
|
18
|
+
P_VARIANT,
|
|
19
|
+
P_X
|
|
20
|
+
};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import type { AssetRef, World } from '@aethervtt/shard-core';
|
|
2
|
+
import type { GpuContext } from '@aethervtt/shard-gpu';
|
|
3
|
+
import type { Platform } from '@aethervtt/shard-platform';
|
|
4
|
+
import type { Plugin } from '@aethervtt/shard-runtime';
|
|
5
|
+
import { type PlanetApp } from '@aethervtt/shard-terrain/testing';
|
|
6
|
+
/** Radius of the test planet (m): small, so tests are quick, with relief and three biomes. */
|
|
7
|
+
export declare const TEST_RADIUS = 20000;
|
|
8
|
+
export declare const TEST_HEIGHT: {
|
|
9
|
+
output: string;
|
|
10
|
+
nodes: {
|
|
11
|
+
hills: {
|
|
12
|
+
fbm: {
|
|
13
|
+
source: string;
|
|
14
|
+
octaves: number;
|
|
15
|
+
frequency: number;
|
|
16
|
+
seed: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
ridges: {
|
|
20
|
+
ridged: {
|
|
21
|
+
source: string;
|
|
22
|
+
octaves: number;
|
|
23
|
+
frequency: number;
|
|
24
|
+
seed: number;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
h: {
|
|
28
|
+
add: (string | {
|
|
29
|
+
multiply: (string | number)[];
|
|
30
|
+
})[];
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export declare const TEST_CLIMATE: {
|
|
35
|
+
output: string;
|
|
36
|
+
nodes: {
|
|
37
|
+
temperature: {
|
|
38
|
+
add: (number | {
|
|
39
|
+
fbm: {
|
|
40
|
+
octaves: number;
|
|
41
|
+
frequency: number;
|
|
42
|
+
seed: number;
|
|
43
|
+
};
|
|
44
|
+
})[];
|
|
45
|
+
};
|
|
46
|
+
moisture: {
|
|
47
|
+
fbm: {
|
|
48
|
+
octaves: number;
|
|
49
|
+
frequency: number;
|
|
50
|
+
seed: number;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/** Grassland: grass, bushes, the odd boulder. */
|
|
56
|
+
export declare const GRASSLAND_SET: {
|
|
57
|
+
rules: ({
|
|
58
|
+
name: string;
|
|
59
|
+
items: {
|
|
60
|
+
generator: string;
|
|
61
|
+
params: {
|
|
62
|
+
radius: number;
|
|
63
|
+
detail: number;
|
|
64
|
+
};
|
|
65
|
+
variants: number;
|
|
66
|
+
}[];
|
|
67
|
+
density: number;
|
|
68
|
+
spacing: number;
|
|
69
|
+
align: number;
|
|
70
|
+
scale: number[];
|
|
71
|
+
sink: number;
|
|
72
|
+
collider: string;
|
|
73
|
+
range: number;
|
|
74
|
+
kind?: undefined;
|
|
75
|
+
masks?: undefined;
|
|
76
|
+
avoid?: undefined;
|
|
77
|
+
} | {
|
|
78
|
+
sink?: undefined;
|
|
79
|
+
collider?: undefined;
|
|
80
|
+
name: string;
|
|
81
|
+
items: {
|
|
82
|
+
generator: string;
|
|
83
|
+
variants: number;
|
|
84
|
+
}[];
|
|
85
|
+
density: number;
|
|
86
|
+
spacing: number;
|
|
87
|
+
masks: {
|
|
88
|
+
slope: number[];
|
|
89
|
+
};
|
|
90
|
+
scale: number[];
|
|
91
|
+
avoid: string[];
|
|
92
|
+
range: number;
|
|
93
|
+
kind?: undefined;
|
|
94
|
+
align?: undefined;
|
|
95
|
+
} | {
|
|
96
|
+
sink?: undefined;
|
|
97
|
+
collider?: undefined;
|
|
98
|
+
spacing?: undefined;
|
|
99
|
+
name: string;
|
|
100
|
+
kind: string;
|
|
101
|
+
items: {
|
|
102
|
+
generator: string;
|
|
103
|
+
variants: number;
|
|
104
|
+
}[];
|
|
105
|
+
density: number;
|
|
106
|
+
masks: {
|
|
107
|
+
slope: number[];
|
|
108
|
+
};
|
|
109
|
+
align: number;
|
|
110
|
+
scale: number[];
|
|
111
|
+
avoid: string[];
|
|
112
|
+
range: number;
|
|
113
|
+
})[];
|
|
114
|
+
};
|
|
115
|
+
/** Forest: trees, undergrowth, sparse grass. */
|
|
116
|
+
export declare const FOREST_SET: {
|
|
117
|
+
rules: ({
|
|
118
|
+
kind?: undefined;
|
|
119
|
+
avoid?: undefined;
|
|
120
|
+
name: string;
|
|
121
|
+
items: {
|
|
122
|
+
generator: string;
|
|
123
|
+
variants: number;
|
|
124
|
+
}[];
|
|
125
|
+
density: number;
|
|
126
|
+
spacing: number;
|
|
127
|
+
masks: {
|
|
128
|
+
slope: number[];
|
|
129
|
+
};
|
|
130
|
+
scale: number[];
|
|
131
|
+
sink: number;
|
|
132
|
+
collider: string;
|
|
133
|
+
range: number;
|
|
134
|
+
} | {
|
|
135
|
+
sink?: undefined;
|
|
136
|
+
collider?: undefined;
|
|
137
|
+
kind?: undefined;
|
|
138
|
+
masks?: undefined;
|
|
139
|
+
scale?: undefined;
|
|
140
|
+
name: string;
|
|
141
|
+
items: {
|
|
142
|
+
generator: string;
|
|
143
|
+
params: {
|
|
144
|
+
radius: number;
|
|
145
|
+
};
|
|
146
|
+
variants: number;
|
|
147
|
+
}[];
|
|
148
|
+
density: number;
|
|
149
|
+
spacing: number;
|
|
150
|
+
avoid: string[];
|
|
151
|
+
range: number;
|
|
152
|
+
} | {
|
|
153
|
+
sink?: undefined;
|
|
154
|
+
collider?: undefined;
|
|
155
|
+
spacing?: undefined;
|
|
156
|
+
masks?: undefined;
|
|
157
|
+
scale?: undefined;
|
|
158
|
+
name: string;
|
|
159
|
+
kind: string;
|
|
160
|
+
items: {
|
|
161
|
+
generator: string;
|
|
162
|
+
params: {
|
|
163
|
+
height: number;
|
|
164
|
+
};
|
|
165
|
+
variants: number;
|
|
166
|
+
}[];
|
|
167
|
+
density: number;
|
|
168
|
+
avoid: string[];
|
|
169
|
+
range: number;
|
|
170
|
+
})[];
|
|
171
|
+
};
|
|
172
|
+
/** Rock: boulders and crystals on the slopes. */
|
|
173
|
+
export declare const ROCK_SET: {
|
|
174
|
+
rules: ({
|
|
175
|
+
avoid?: undefined;
|
|
176
|
+
name: string;
|
|
177
|
+
items: {
|
|
178
|
+
generator: string;
|
|
179
|
+
params: {
|
|
180
|
+
radius: number;
|
|
181
|
+
roughness: number;
|
|
182
|
+
};
|
|
183
|
+
variants: number;
|
|
184
|
+
}[];
|
|
185
|
+
density: number;
|
|
186
|
+
spacing: number;
|
|
187
|
+
align: number;
|
|
188
|
+
scale: number[];
|
|
189
|
+
sink: number;
|
|
190
|
+
collider: string;
|
|
191
|
+
range: number;
|
|
192
|
+
} | {
|
|
193
|
+
sink?: undefined;
|
|
194
|
+
collider?: undefined;
|
|
195
|
+
scale?: undefined;
|
|
196
|
+
name: string;
|
|
197
|
+
items: {
|
|
198
|
+
generator: string;
|
|
199
|
+
variants: number;
|
|
200
|
+
}[];
|
|
201
|
+
density: number;
|
|
202
|
+
spacing: number;
|
|
203
|
+
align: number;
|
|
204
|
+
avoid: string[];
|
|
205
|
+
range: number;
|
|
206
|
+
})[];
|
|
207
|
+
};
|
|
208
|
+
export interface ScatterPlanet extends PlanetApp {
|
|
209
|
+
sets: AssetRef[];
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The three-biome test planet with scatter (and procgen, which makes the items' meshes). With a
|
|
213
|
+
* GPU it renders (and draws foliage); without one, props alone are placed and spawned.
|
|
214
|
+
*/
|
|
215
|
+
export declare function scatterPlanet(gpu: GpuContext | undefined, platform: Platform, options?: {
|
|
216
|
+
width?: number;
|
|
217
|
+
height?: number;
|
|
218
|
+
extra?: Plugin[];
|
|
219
|
+
workers?: boolean;
|
|
220
|
+
/** MSAA samples (the playground's #scatter page draws with 4). Default 1. */
|
|
221
|
+
msaa?: 1 | 4;
|
|
222
|
+
/** A fixed render scale, upscaled after (the page's window view). */
|
|
223
|
+
renderScale?: number;
|
|
224
|
+
/** A set for the whole planet (Planet.scatter), on top of the biomes'. */
|
|
225
|
+
planetSet?: unknown;
|
|
226
|
+
}): Promise<ScatterPlanet>;
|
|
227
|
+
/** Steps until every surface's scatter is ready and nothing is placing (or the frames run out). */
|
|
228
|
+
export declare function settleScatter(p: PlanetApp, maxFrames?: number): Promise<number>;
|
|
229
|
+
/**
|
|
230
|
+
* FNV-1a over every spawned prop: its rule, chunk, index and local transform (f32 bits), sorted.
|
|
231
|
+
* The same planet and viewers give the same number on every host.
|
|
232
|
+
*/
|
|
233
|
+
export declare function placementChecksum(world: World): {
|
|
234
|
+
checksum: string;
|
|
235
|
+
props: number;
|
|
236
|
+
};
|