telperion 0.0.1 → 0.1.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 +532 -0
- package/dist/browser/core.d.ts +195 -0
- package/dist/browser/leaf.d.ts +39 -0
- package/dist/browser/presets.generated.d.ts +278 -0
- package/dist/browser/render.d.ts +165 -0
- package/dist/browser/specimen-wire.d.ts +22 -0
- package/dist/browser/specimen.d.ts +106 -0
- package/dist/field/index.d.ts +43 -0
- package/dist/field/voxelize.d.ts +44 -0
- package/dist/field.js +62 -0
- package/dist/index.d.ts +7 -0
- package/dist/telperion-field.wasm +0 -0
- package/dist/telperion-render.wasm +0 -0
- package/dist/telperion.js +3463 -0
- package/dist/telperion.wasm +0 -0
- package/dist/voxelize.js +98 -0
- package/dist/wasm-source.d.ts +1 -0
- package/dist/wasm-source.js +12 -0
- package/package.json +79 -8
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { LeafReference } from "./leaf";
|
|
2
|
+
import { type SpecimenHandle, type SpecimenSnapshot } from "./specimen";
|
|
3
|
+
import { type Family } from "./presets.generated";
|
|
4
|
+
export type { Family } from "./presets.generated";
|
|
5
|
+
export interface TreePreset extends Family {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
note: string;
|
|
9
|
+
}
|
|
10
|
+
/** Explicit identity lookup; unknown identities never fall back to Ordinary. */
|
|
11
|
+
export declare function presetById(id: string): TreePreset;
|
|
12
|
+
/** Plain parameter baseline, usable directly at the native request boundary. */
|
|
13
|
+
export declare const ORDINARY: Family;
|
|
14
|
+
export declare const OREGON_WHITE_OAK: TreePreset;
|
|
15
|
+
export declare const NORWAY_SPRUCE: TreePreset;
|
|
16
|
+
export declare const SILVER_BIRCH: TreePreset;
|
|
17
|
+
export declare const TELPERION: TreePreset;
|
|
18
|
+
export declare const LAURELIN: TreePreset;
|
|
19
|
+
export declare const TWO_TREES: TreePreset[];
|
|
20
|
+
export declare const PRESETS: TreePreset[];
|
|
21
|
+
export interface Outputs {
|
|
22
|
+
surface?: boolean;
|
|
23
|
+
foliage?: boolean;
|
|
24
|
+
structure?: boolean;
|
|
25
|
+
/** Wood and foliage occupancy from the solved tree and the leaf plan: no
|
|
26
|
+
* leaf is placed for a family the plan describes. A family without a plan
|
|
27
|
+
* places and culls its leaves for the field; no render buffers transfer
|
|
28
|
+
* unless surface/foliage are requested separately. `true` names limbs at
|
|
29
|
+
* the family's `clumpSystemOrder`; `{ limbOrder }` at that lateral order,
|
|
30
|
+
* a higher one parting the crown into more and smaller systems. */
|
|
31
|
+
field?: boolean | {
|
|
32
|
+
limbOrder: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface Bounds {
|
|
36
|
+
min: [number, number, number];
|
|
37
|
+
max: [number, number, number];
|
|
38
|
+
}
|
|
39
|
+
export interface Timings {
|
|
40
|
+
growthMs: number;
|
|
41
|
+
surfaceMs: number;
|
|
42
|
+
planMs: number;
|
|
43
|
+
foliageMs: number;
|
|
44
|
+
fieldMs: number;
|
|
45
|
+
coreMs: number;
|
|
46
|
+
transferMs: number;
|
|
47
|
+
buildMs: number;
|
|
48
|
+
}
|
|
49
|
+
/** Which stages a build ran. `foliage` is the placement and the cull together;
|
|
50
|
+
* `contacts` the wood's contact surface under placement; `plan` the leaf plan
|
|
51
|
+
* a field request read. `fieldSource` names the field's foliage path. */
|
|
52
|
+
export interface Stages {
|
|
53
|
+
surface: boolean;
|
|
54
|
+
foliage: boolean;
|
|
55
|
+
placement: boolean;
|
|
56
|
+
cull: boolean;
|
|
57
|
+
contacts: boolean;
|
|
58
|
+
plan: boolean;
|
|
59
|
+
field: boolean;
|
|
60
|
+
fieldSource: "plan" | "placed" | null;
|
|
61
|
+
}
|
|
62
|
+
/** Half-open prototype ranges exclude connectors; indices are scalar offsets. */
|
|
63
|
+
export interface FoliageAnatomy {
|
|
64
|
+
unit: "leaf" | "needle";
|
|
65
|
+
vertices: [number, number];
|
|
66
|
+
indices: [number, number];
|
|
67
|
+
sections: [number, number][];
|
|
68
|
+
}
|
|
69
|
+
export interface Diagnostics {
|
|
70
|
+
biologicalUnits: number | null;
|
|
71
|
+
foliageAnatomy: FoliageAnatomy | null;
|
|
72
|
+
nodes: number;
|
|
73
|
+
crossover: number;
|
|
74
|
+
shed: number;
|
|
75
|
+
capped: boolean;
|
|
76
|
+
levelCapped: boolean;
|
|
77
|
+
attractionCapped: boolean;
|
|
78
|
+
complete: boolean;
|
|
79
|
+
handoffs: number;
|
|
80
|
+
generationCounts: number[];
|
|
81
|
+
levelCappedHandoffs: number;
|
|
82
|
+
twigs: number;
|
|
83
|
+
leavesPlaced: number;
|
|
84
|
+
instances: number;
|
|
85
|
+
/** Stations the leaf plan counts before any cull; zero without a plan. */
|
|
86
|
+
leavesPlanned: number;
|
|
87
|
+
surfaceBounds: Bounds | null;
|
|
88
|
+
foliageBounds: Bounds | null;
|
|
89
|
+
/** The box every packed leaf position is quantised against. */
|
|
90
|
+
foliageReference: LeafReference | null;
|
|
91
|
+
fieldBounds: Bounds | null;
|
|
92
|
+
fieldBytes: number;
|
|
93
|
+
revision: number;
|
|
94
|
+
timings: Timings;
|
|
95
|
+
stages: Stages;
|
|
96
|
+
}
|
|
97
|
+
/** One batch query's answers, one entry per cell. `flags` bits: wood=1,
|
|
98
|
+
* foliage=2. `woodRadius` is the thickest wood sweep reaching the cell in
|
|
99
|
+
* metres, zero without wood. `leaves` estimates the stations in the cell
|
|
100
|
+
* before the crown cull (the retained leaves overlapping it on the placed
|
|
101
|
+
* path). `limbs` is the owning limb system, UINT32_MAX where no foliage
|
|
102
|
+
* reaches. */
|
|
103
|
+
export interface FieldQuery {
|
|
104
|
+
flags: Uint8Array;
|
|
105
|
+
woodRadius: Float32Array;
|
|
106
|
+
leaves: Float32Array;
|
|
107
|
+
limbs: Uint32Array;
|
|
108
|
+
}
|
|
109
|
+
/** Owned canonical f64 CPU BVH data for generation experiments; survives release,
|
|
110
|
+
* rebuild and disposal. Mutating these arrays cannot alter the native field.
|
|
111
|
+
* Bounds: six f64 min/max xyz per node then item. Topology: four u32 per
|
|
112
|
+
* node [start,end,left,right], then primitive IDs; UINT32_MAX children = leaf. */
|
|
113
|
+
export interface FieldIndexSnapshot {
|
|
114
|
+
bounds: Float64Array;
|
|
115
|
+
topology: Uint32Array;
|
|
116
|
+
nodeCount: number;
|
|
117
|
+
}
|
|
118
|
+
export interface FieldSnapshot {
|
|
119
|
+
schema: 2;
|
|
120
|
+
revision: number;
|
|
121
|
+
bounds: Bounds | null;
|
|
122
|
+
/** Eight f64: a xyz, b xyz, proximal and distal radius. */
|
|
123
|
+
wood: Float64Array;
|
|
124
|
+
woodIndex: FieldIndexSnapshot;
|
|
125
|
+
/** Placed-leaf boxes; empty on a planned field. */
|
|
126
|
+
leaves: FieldIndexSnapshot;
|
|
127
|
+
/** The leaf plan's sweeps: seven f64 (a xyz, b xyz, reach) and two u32
|
|
128
|
+
* (station count, limb system) a sweep, with their index. Empty on a
|
|
129
|
+
* placed field. */
|
|
130
|
+
plan: {
|
|
131
|
+
segments: Float64Array;
|
|
132
|
+
stations: Uint32Array;
|
|
133
|
+
index: FieldIndexSnapshot;
|
|
134
|
+
};
|
|
135
|
+
timings: {
|
|
136
|
+
extractionMs: number;
|
|
137
|
+
copyMs: number;
|
|
138
|
+
totalMs: number;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export interface TreeOutput {
|
|
142
|
+
surface?: {
|
|
143
|
+
positions: Float32Array;
|
|
144
|
+
normals: Float32Array;
|
|
145
|
+
indices: Uint32Array;
|
|
146
|
+
bounds: Bounds | null;
|
|
147
|
+
};
|
|
148
|
+
/** Three u32 words a leaf, decoded against `reference` by `./leaf`. The
|
|
149
|
+
* sixteen-float form is never built here: twelve bytes are the storage. */
|
|
150
|
+
foliage?: {
|
|
151
|
+
positions: Float32Array;
|
|
152
|
+
indices: Uint32Array;
|
|
153
|
+
leaves: Uint32Array;
|
|
154
|
+
reference: LeafReference | null;
|
|
155
|
+
anatomy: FoliageAnatomy | null;
|
|
156
|
+
bounds: Bounds | null;
|
|
157
|
+
};
|
|
158
|
+
/** Six f64 values per node: xyz, distal radius, proximal radius, base radius.
|
|
159
|
+
* Three u32 values per node: parent (UINT32_MAX for root), branch, kind (0/1/2). */
|
|
160
|
+
structure?: {
|
|
161
|
+
values: Float64Array;
|
|
162
|
+
topology: Uint32Array;
|
|
163
|
+
};
|
|
164
|
+
/** Query packed x,y,z,halfExtent cells. Invalid after this engine's next
|
|
165
|
+
* build or release; copied results remain owned. */
|
|
166
|
+
field?: {
|
|
167
|
+
query(cells: Float64Array): FieldQuery;
|
|
168
|
+
snapshot(): FieldSnapshot;
|
|
169
|
+
};
|
|
170
|
+
diagnostics: Diagnostics;
|
|
171
|
+
}
|
|
172
|
+
export declare class TreeEngine {
|
|
173
|
+
private exports;
|
|
174
|
+
private get e();
|
|
175
|
+
get disposed(): boolean;
|
|
176
|
+
private constructor();
|
|
177
|
+
/** Drop the instance, allowing its linear memory to be reclaimed by the host. */
|
|
178
|
+
dispose(): void;
|
|
179
|
+
static create(source?: BufferSource | Response): Promise<TreeEngine>;
|
|
180
|
+
private metadata;
|
|
181
|
+
private check;
|
|
182
|
+
/** Releases native outputs and invalidates fields; JS copies remain usable.
|
|
183
|
+
* Wasm linear memory retains its high-water capacity for allocator reuse. */
|
|
184
|
+
release(): void;
|
|
185
|
+
private specimens;
|
|
186
|
+
buildSpecimen(family: Family | string, historyCap?: number): SpecimenHandle;
|
|
187
|
+
importSpecimen(snapshot: SpecimenSnapshot): SpecimenHandle;
|
|
188
|
+
get memoryBytes(): number;
|
|
189
|
+
build(family: Family | string, outputs: Outputs): TreeOutput;
|
|
190
|
+
private snapshot;
|
|
191
|
+
private query;
|
|
192
|
+
}
|
|
193
|
+
/** Harness convenience; independent consumers can create their own TreeEngine. */
|
|
194
|
+
export declare function initializeTreeCore(source?: BufferSource | Response): Promise<TreeEngine>;
|
|
195
|
+
export declare function treeCore(): TreeEngine;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** One leaf in twelve bytes, read exactly as the core packed it.
|
|
2
|
+
*
|
|
3
|
+
* The three words are the storage on both sides of the wire, so this is the
|
|
4
|
+
* only place in the browser source that knows the bit layout: a second copy
|
|
5
|
+
* would be a reader free to drift from the writer. The Rust encoder of record
|
|
6
|
+
* is `telperion-core`'s `foliage::packed`, and the shader that draws these
|
|
7
|
+
* words is `leaf.wgsl`; all three decode one leaf one way.
|
|
8
|
+
*
|
|
9
|
+
* Word 0 is the rotation as a smallest-three quaternion - the index of the
|
|
10
|
+
* dropped largest component in the top two bits, the other three below it, ten
|
|
11
|
+
* bits each, over plus or minus one over root two. Word 1 is x and y as
|
|
12
|
+
* unsigned normals over the reference box, word 2 is z in its low half and the
|
|
13
|
+
* uniform scale as a half float in its high half. */
|
|
14
|
+
/** Words one stored leaf occupies. */
|
|
15
|
+
export declare const LEAF_WORDS = 3;
|
|
16
|
+
export type Vector = [number, number, number];
|
|
17
|
+
/** The three words of one leaf, in storage order: rotation, xy, z and scale. */
|
|
18
|
+
export type LeafWords = readonly [number, number, number];
|
|
19
|
+
/** The box leaf positions are quantised against. It comes from the family's
|
|
20
|
+
* parameters, not from the tree that grew, so one box decodes a species at
|
|
21
|
+
* every age; the build metadata and a specimen read both carry it. */
|
|
22
|
+
export interface LeafReference {
|
|
23
|
+
min: Vector;
|
|
24
|
+
extent: Vector;
|
|
25
|
+
}
|
|
26
|
+
/** The words of one leaf in a packed buffer, by instance index. */
|
|
27
|
+
export declare function leafWords(leaves: Uint32Array, index: number): LeafWords;
|
|
28
|
+
/** Where a leaf stands. The crown's bounds and any spatial pass read nothing
|
|
29
|
+
* else, so neither pays for a rotation it never uses. */
|
|
30
|
+
export declare function leafPosition(words: LeafWords, reference: LeafReference): Vector;
|
|
31
|
+
/** The uniform scale a leaf carries, out of the high half of word 2. */
|
|
32
|
+
export declare function leafScale(words: LeafWords): number;
|
|
33
|
+
/** The rotation word 0 carries, as the three columns of its matrix: side, the
|
|
34
|
+
* leaf's own axis, face. */
|
|
35
|
+
export declare function leafRotation(words: LeafWords): [Vector, Vector, Vector];
|
|
36
|
+
/** The whole transform three words stand for, column-major, as the sixteen
|
|
37
|
+
* floats the core used to write: the rotation's columns at the stored scale,
|
|
38
|
+
* and the stored position in column three. */
|
|
39
|
+
export declare function leafTransform(words: LeafWords, reference: LeafReference): Float32Array;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
export interface Family {
|
|
2
|
+
age: number;
|
|
3
|
+
canopy: {
|
|
4
|
+
acanthophyllLength: number;
|
|
5
|
+
acanthophyllPitch: number;
|
|
6
|
+
acanthophylls: number;
|
|
7
|
+
clump: number;
|
|
8
|
+
clumpNeighbours: number;
|
|
9
|
+
clumpSpan: number;
|
|
10
|
+
clumpSystemOrder: number;
|
|
11
|
+
divergence: number;
|
|
12
|
+
forwardLean: number;
|
|
13
|
+
leafBaseLength: number;
|
|
14
|
+
leafBasePitch: number;
|
|
15
|
+
leafBaseRadius: number;
|
|
16
|
+
leafBaseWeathering: number;
|
|
17
|
+
leafBases: number;
|
|
18
|
+
leafletCount: number;
|
|
19
|
+
leafletPitch: number;
|
|
20
|
+
leanRise: number;
|
|
21
|
+
limbClumping: number;
|
|
22
|
+
maxInstances: number;
|
|
23
|
+
outward: number;
|
|
24
|
+
rachisArch: number;
|
|
25
|
+
rachisLength: number;
|
|
26
|
+
rosetteDepth: number;
|
|
27
|
+
rosetteDivergence: number;
|
|
28
|
+
rosetteFronds: number;
|
|
29
|
+
rosettePitch: number;
|
|
30
|
+
rosettePitchSpread: number;
|
|
31
|
+
scatter: number;
|
|
32
|
+
shootRadius: number;
|
|
33
|
+
shortShootLeaves: number;
|
|
34
|
+
shortShootLength: number;
|
|
35
|
+
shortShootRadius: number;
|
|
36
|
+
shortShootSpacing: number;
|
|
37
|
+
shortShootSpread: number;
|
|
38
|
+
size: number;
|
|
39
|
+
sizeVariation: number;
|
|
40
|
+
spacing: number;
|
|
41
|
+
surfaceContact: number;
|
|
42
|
+
terminalLeaflet: number;
|
|
43
|
+
upward: number;
|
|
44
|
+
};
|
|
45
|
+
element: {
|
|
46
|
+
axialSegments: number;
|
|
47
|
+
baseFullness: number;
|
|
48
|
+
card: boolean;
|
|
49
|
+
connectorLength: number;
|
|
50
|
+
crossSegments: number;
|
|
51
|
+
cup: number;
|
|
52
|
+
curl: number;
|
|
53
|
+
length: number;
|
|
54
|
+
lobeCount: number;
|
|
55
|
+
lobeDepth: number;
|
|
56
|
+
sectionRoundness: number;
|
|
57
|
+
tipSharpness: number;
|
|
58
|
+
widestAt: number;
|
|
59
|
+
width: number;
|
|
60
|
+
};
|
|
61
|
+
growth: {
|
|
62
|
+
apicalControlLoss: number;
|
|
63
|
+
leafLifetime: number;
|
|
64
|
+
rate: number;
|
|
65
|
+
resizeTolerance: number;
|
|
66
|
+
shape: number;
|
|
67
|
+
sheddingTolerance: number;
|
|
68
|
+
workBudget: number;
|
|
69
|
+
};
|
|
70
|
+
material: {
|
|
71
|
+
barkBlue: number;
|
|
72
|
+
barkGrainScale: number;
|
|
73
|
+
barkGrainStrength: number;
|
|
74
|
+
barkGreen: number;
|
|
75
|
+
barkMottleScale: number;
|
|
76
|
+
barkMottleStrength: number;
|
|
77
|
+
barkRed: number;
|
|
78
|
+
barkReflectance: number;
|
|
79
|
+
barkRoughness: number;
|
|
80
|
+
bladeGrainScale: number;
|
|
81
|
+
bladeGrainStrength: number;
|
|
82
|
+
bladeMottleScale: number;
|
|
83
|
+
bladeMottleStrength: number;
|
|
84
|
+
brightnessRangeHigh: number;
|
|
85
|
+
brightnessRangeLow: number;
|
|
86
|
+
canopyNormal: number;
|
|
87
|
+
cavityStrength: number;
|
|
88
|
+
crestBlue: number;
|
|
89
|
+
crestGreen: number;
|
|
90
|
+
crestRed: number;
|
|
91
|
+
crestStrength: number;
|
|
92
|
+
crownShade: number;
|
|
93
|
+
cuticleGloss: number;
|
|
94
|
+
depthStrength: number;
|
|
95
|
+
diffuseTransmission: number;
|
|
96
|
+
directionalOcclusion: number;
|
|
97
|
+
fissureBlue: number;
|
|
98
|
+
fissureGreen: number;
|
|
99
|
+
fissureRed: number;
|
|
100
|
+
fissureStrength: number;
|
|
101
|
+
furrowStrength: number;
|
|
102
|
+
hueRangeHigh: number;
|
|
103
|
+
hueRangeLow: number;
|
|
104
|
+
interiorDarkening: number;
|
|
105
|
+
leafBackBlue: number;
|
|
106
|
+
leafBackGreen: number;
|
|
107
|
+
leafBackRed: number;
|
|
108
|
+
leafFrontBlue: number;
|
|
109
|
+
leafFrontGreen: number;
|
|
110
|
+
leafFrontRed: number;
|
|
111
|
+
leafReflectance: number;
|
|
112
|
+
leafSheen: number;
|
|
113
|
+
lenticelDensity: number;
|
|
114
|
+
lenticelLength: number;
|
|
115
|
+
lenticelStrength: number;
|
|
116
|
+
lenticelTint: number;
|
|
117
|
+
lichenBlue: number;
|
|
118
|
+
lichenCoverage: number;
|
|
119
|
+
lichenGreen: number;
|
|
120
|
+
lichenRed: number;
|
|
121
|
+
lichenScale: number;
|
|
122
|
+
lichenStrength: number;
|
|
123
|
+
lightWrap: number;
|
|
124
|
+
lobeShade: number;
|
|
125
|
+
marginBlue: number;
|
|
126
|
+
marginGreen: number;
|
|
127
|
+
marginRed: number;
|
|
128
|
+
marginWidth: number;
|
|
129
|
+
orientationBlue: number;
|
|
130
|
+
orientationGreen: number;
|
|
131
|
+
orientationRed: number;
|
|
132
|
+
orientationStrength: number;
|
|
133
|
+
peelBlue: number;
|
|
134
|
+
peelCurl: number;
|
|
135
|
+
peelGreen: number;
|
|
136
|
+
peelRed: number;
|
|
137
|
+
plateCellScale: number;
|
|
138
|
+
plateDome: number;
|
|
139
|
+
plateEdgeLift: number;
|
|
140
|
+
plateEdgeShape: number;
|
|
141
|
+
plateElongation: number;
|
|
142
|
+
plateFurrowWidth: number;
|
|
143
|
+
plateIdentity: number;
|
|
144
|
+
plateScale: number;
|
|
145
|
+
ridgeScale: number;
|
|
146
|
+
roughnessDetail: number;
|
|
147
|
+
shootBlue: number;
|
|
148
|
+
shootGreen: number;
|
|
149
|
+
shootRadius: number;
|
|
150
|
+
shootRed: number;
|
|
151
|
+
skyOcclusionStrength: number;
|
|
152
|
+
thickness: number;
|
|
153
|
+
transmissionBlue: number;
|
|
154
|
+
transmissionGreen: number;
|
|
155
|
+
transmissionRed: number;
|
|
156
|
+
transmissionStrength: number;
|
|
157
|
+
veinContrast: number;
|
|
158
|
+
veinScale: number;
|
|
159
|
+
weatheringBlue: number;
|
|
160
|
+
weatheringGreen: number;
|
|
161
|
+
weatheringRed: number;
|
|
162
|
+
weatheringStrength: number;
|
|
163
|
+
};
|
|
164
|
+
radii: {
|
|
165
|
+
forkExponent: number;
|
|
166
|
+
lengthTaper: number;
|
|
167
|
+
maxTaperExponent: number;
|
|
168
|
+
trunkRadius: number;
|
|
169
|
+
};
|
|
170
|
+
shellDepth: number;
|
|
171
|
+
skeleton: {
|
|
172
|
+
attractors: number;
|
|
173
|
+
bias: {
|
|
174
|
+
gravitropism: number;
|
|
175
|
+
lean: number;
|
|
176
|
+
supernatural: {
|
|
177
|
+
enabled: boolean;
|
|
178
|
+
maxWritheMagnitude: number;
|
|
179
|
+
spiralRate: number;
|
|
180
|
+
writheAmplitude: number;
|
|
181
|
+
writheWavelength: number;
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
envelope: {
|
|
185
|
+
crownBase: number;
|
|
186
|
+
fullness: number;
|
|
187
|
+
height: number;
|
|
188
|
+
irregularity: number;
|
|
189
|
+
lobeScale: number;
|
|
190
|
+
shoulder: number;
|
|
191
|
+
spread: number;
|
|
192
|
+
};
|
|
193
|
+
growth: {
|
|
194
|
+
influenceRadius?: number;
|
|
195
|
+
killDistance?: number;
|
|
196
|
+
maxNodes?: number;
|
|
197
|
+
maxTurnPerStep: number;
|
|
198
|
+
stepDistance?: number;
|
|
199
|
+
trunkHeight?: number;
|
|
200
|
+
};
|
|
201
|
+
habit: {
|
|
202
|
+
apicalDominance: number;
|
|
203
|
+
attractorWeight: number;
|
|
204
|
+
crookedness: number;
|
|
205
|
+
lateralLengthRatio: number;
|
|
206
|
+
lateralOrders: number;
|
|
207
|
+
lateralPitch: number;
|
|
208
|
+
lateralSpacing: number;
|
|
209
|
+
lateralsPerStation: number;
|
|
210
|
+
leaderInternode: number;
|
|
211
|
+
pitchVariation: number;
|
|
212
|
+
reachProbeSteps: number;
|
|
213
|
+
risePrimary: number;
|
|
214
|
+
riseSecondary: number;
|
|
215
|
+
sheddingThreshold: number;
|
|
216
|
+
stemDivergence: number;
|
|
217
|
+
stemForkHeight: number;
|
|
218
|
+
stemLean: number;
|
|
219
|
+
stemLeanSpread: number;
|
|
220
|
+
stems: number;
|
|
221
|
+
twigTipTaper: number;
|
|
222
|
+
whorlStrength: number;
|
|
223
|
+
};
|
|
224
|
+
samplingAttemptsPerAttractor: number;
|
|
225
|
+
seed: number;
|
|
226
|
+
step: number;
|
|
227
|
+
twigs: {
|
|
228
|
+
angle: number;
|
|
229
|
+
angleVariation: number;
|
|
230
|
+
curtainClearance: number;
|
|
231
|
+
curtainDrop: number;
|
|
232
|
+
curtainSeparation: number;
|
|
233
|
+
curtainStepClearance: number;
|
|
234
|
+
divergence: number;
|
|
235
|
+
generations: number;
|
|
236
|
+
hang: number;
|
|
237
|
+
internodeFactor: number;
|
|
238
|
+
laterals: number;
|
|
239
|
+
lengthRatio: number;
|
|
240
|
+
limbRadius: number;
|
|
241
|
+
maxDroop: number;
|
|
242
|
+
maxInternodes: number;
|
|
243
|
+
pendulousLength: number;
|
|
244
|
+
pendulousRadius: number;
|
|
245
|
+
pendulousVariation: number;
|
|
246
|
+
ratioPower: number;
|
|
247
|
+
reach: number;
|
|
248
|
+
sag: number;
|
|
249
|
+
twig: {
|
|
250
|
+
bearingDiameter: number;
|
|
251
|
+
diameter: number;
|
|
252
|
+
internodeLength: number;
|
|
253
|
+
length: number;
|
|
254
|
+
stationsPerInternode: number;
|
|
255
|
+
};
|
|
256
|
+
vigourVariation: number;
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
surface: {
|
|
260
|
+
flareDepth: number;
|
|
261
|
+
flareFalloff: number;
|
|
262
|
+
flareRadius: number;
|
|
263
|
+
forkSocket: number;
|
|
264
|
+
forkSwell: number;
|
|
265
|
+
lobeDepth: number;
|
|
266
|
+
lobes: number;
|
|
267
|
+
radialSegments: number;
|
|
268
|
+
socketContainment: number;
|
|
269
|
+
twistRate: number;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
export declare const CATALOGUE: {
|
|
273
|
+
abiId: number;
|
|
274
|
+
id: string;
|
|
275
|
+
name: string;
|
|
276
|
+
note: string;
|
|
277
|
+
family: Family;
|
|
278
|
+
}[];
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/** Metres, Y up, right-handed - the renderer's own frame. */
|
|
2
|
+
export type Point = readonly [number, number, number];
|
|
3
|
+
export interface Submitted {
|
|
4
|
+
woodVertices: number;
|
|
5
|
+
woodTriangles: number;
|
|
6
|
+
foliageInstances: number;
|
|
7
|
+
bounds: {
|
|
8
|
+
min: Point;
|
|
9
|
+
max: Point;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** Host wall-clock milliseconds (`Ms`) and selected allocation capacities (`Bytes`).
|
|
13
|
+
* Timings can nest/overlap; memory snapshots share allocations and are not additive.
|
|
14
|
+
* These omit some transient scratch, allocator-retained Wasm memory, upload staging,
|
|
15
|
+
* driver allocations and deferred destruction; they are not whole-process peaks.
|
|
16
|
+
* Zero/default fields can mean an unused stage. */
|
|
17
|
+
export interface GenerationStages {
|
|
18
|
+
positionPrepareMs: number;
|
|
19
|
+
positionUploadMs: number;
|
|
20
|
+
/** Admission wait remaining after overlapping CPU station work. */
|
|
21
|
+
positionWaitMs: number;
|
|
22
|
+
positionCpuBytes: number;
|
|
23
|
+
positionGpuPeakBytes: number;
|
|
24
|
+
positionRetainedMetadataBytes: number;
|
|
25
|
+
/** Unstable diagnostic text; do not branch on its wording. */
|
|
26
|
+
positionFallback: string | null;
|
|
27
|
+
gpuPositions: boolean;
|
|
28
|
+
skeletonMs: number;
|
|
29
|
+
descriptorsMs: number;
|
|
30
|
+
uploadDispatchMs: number;
|
|
31
|
+
placementWaitMs: number;
|
|
32
|
+
compactMs: number;
|
|
33
|
+
massMs: number;
|
|
34
|
+
readbackMs: number;
|
|
35
|
+
woodMs: number;
|
|
36
|
+
woodPrepareMs: number;
|
|
37
|
+
woodUploadDispatchMs: number;
|
|
38
|
+
woodWaitMs: number;
|
|
39
|
+
woodPreparedCpuBytes: number;
|
|
40
|
+
woodMetadataCpuBytes: number;
|
|
41
|
+
woodGpuPeakBytes: number;
|
|
42
|
+
woodBackend: "Cpu" | "Gpu" | "CpuFallback" | null;
|
|
43
|
+
/** Unstable diagnostic text; do not branch on its wording. */
|
|
44
|
+
woodFallback: string | null;
|
|
45
|
+
/** Preparation only; excludes adoption, drawing and completed-frame fencing. */
|
|
46
|
+
totalMs: number;
|
|
47
|
+
baseCpuBytes: number;
|
|
48
|
+
woodCpuBytes: number;
|
|
49
|
+
descriptorCpuBytes: number;
|
|
50
|
+
sharedContactCpuBytes: number;
|
|
51
|
+
sharedPrepareCpuBytes: number;
|
|
52
|
+
sharedMetadataCpuBytes: number;
|
|
53
|
+
gpuComputePeakBytes: number;
|
|
54
|
+
retainedGpuBytes: number;
|
|
55
|
+
}
|
|
56
|
+
/** A tree adopted by the renderer; this promise does not fence a completed frame. */
|
|
57
|
+
export interface GpuSubmitted extends Submitted {
|
|
58
|
+
backend: "Gpu" | "CpuFallback";
|
|
59
|
+
stages: GenerationStages;
|
|
60
|
+
/** Allocated live-tree GPU buffer bytes before adoption; excludes textures/pipelines. */
|
|
61
|
+
previousTreeGpuBytes: number;
|
|
62
|
+
/** Allocated live-tree GPU buffer bytes after adoption, with the same exclusions. */
|
|
63
|
+
treeGpuBytes: number;
|
|
64
|
+
}
|
|
65
|
+
export interface FrameStats {
|
|
66
|
+
drawCalls: number;
|
|
67
|
+
triangles: number;
|
|
68
|
+
instances: number;
|
|
69
|
+
}
|
|
70
|
+
export interface Pose {
|
|
71
|
+
position: Point;
|
|
72
|
+
target: Point;
|
|
73
|
+
}
|
|
74
|
+
/** The timing session's record, as the Rust report writes it, field for
|
|
75
|
+
* field. The GPU percentiles exist only on a valid verdict, so nothing
|
|
76
|
+
* in an invalid record can be read as a number that passed. The wall
|
|
77
|
+
* clock is the page's own and not the GPU's, so an orbit reports it even
|
|
78
|
+
* where there was no GPU clock to read. */
|
|
79
|
+
export interface TimingReport {
|
|
80
|
+
adapter: string;
|
|
81
|
+
driver: string;
|
|
82
|
+
backend: string;
|
|
83
|
+
conditioning: number;
|
|
84
|
+
warmup: number;
|
|
85
|
+
measured: number;
|
|
86
|
+
samples: number;
|
|
87
|
+
multisample: number;
|
|
88
|
+
caster_triangles: number;
|
|
89
|
+
caster_instances: number;
|
|
90
|
+
verdict: "valid" | "unavailable" | "disjoint" | "contended";
|
|
91
|
+
reason?: string;
|
|
92
|
+
p50_ms?: number;
|
|
93
|
+
p95_ms?: number;
|
|
94
|
+
/** The selection compute pass that decides what the vegetation pass draws. */
|
|
95
|
+
selection_p50_ms?: number;
|
|
96
|
+
selection_p95_ms?: number;
|
|
97
|
+
shadow_p50_ms?: number;
|
|
98
|
+
shadow_p95_ms?: number;
|
|
99
|
+
/** Three passes added frame by frame and then ranked: a frame's own cost. */
|
|
100
|
+
total_p50_ms?: number;
|
|
101
|
+
total_p95_ms?: number;
|
|
102
|
+
/** What each level drew, coarsest first, and last the bucket of leaves
|
|
103
|
+
* no level drew - which approximated nothing, so it has no deviation.
|
|
104
|
+
* Read back only where a session can read the counters. */
|
|
105
|
+
levels?: {
|
|
106
|
+
deviation_m: number | null;
|
|
107
|
+
instances_p50: number;
|
|
108
|
+
}[];
|
|
109
|
+
/** Frame to frame on the page's own animation clock, over an orbit. */
|
|
110
|
+
wall_frames?: number;
|
|
111
|
+
wall_p50_ms?: number;
|
|
112
|
+
wall_p95_ms?: number;
|
|
113
|
+
wall_max_ms?: number;
|
|
114
|
+
}
|
|
115
|
+
export type View = "whole" | "bare" | "leaf" | "clay";
|
|
116
|
+
/** The sun, the sky and the ground, as the renderer states them. The row is
|
|
117
|
+
* defined in Rust and read back out of the renderer, so nothing on this side
|
|
118
|
+
* keeps a second copy of its fields or of their default values: a field the
|
|
119
|
+
* row grows appears in the panel with no line here. */
|
|
120
|
+
export type SceneRow = Record<string, number>;
|
|
121
|
+
/** Devices created minus devices disposed, on the window, for the soak
|
|
122
|
+
* test to read. React's development double-mount builds one renderer
|
|
123
|
+
* and disposes it before the live one, so "one canvas, one device" is
|
|
124
|
+
* a claim only a counter that survives both mounts can check. */
|
|
125
|
+
declare global {
|
|
126
|
+
interface Window {
|
|
127
|
+
telperionLiveDevices?: number;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** One canvas drawn by the Rust renderer, sized to the display and
|
|
131
|
+
* disposed with the page element it belongs to. */
|
|
132
|
+
export interface GrowthSubmitted extends Submitted {
|
|
133
|
+
age: number;
|
|
134
|
+
frontier: number;
|
|
135
|
+
}
|
|
136
|
+
export interface Renderer {
|
|
137
|
+
setTree(family: string): Submitted;
|
|
138
|
+
/** Experimental GPU foliage; unsupported inputs report CpuFallback. */
|
|
139
|
+
setTreeGpu(family: string): Promise<GpuSubmitted>;
|
|
140
|
+
buildSpecimen(family: string, age: number): GrowthSubmitted;
|
|
141
|
+
seekSpecimen(age: number): GrowthSubmitted;
|
|
142
|
+
setView(view: View): void;
|
|
143
|
+
/** The sun, sky and ground the next frame is drawn under. */
|
|
144
|
+
scene(): SceneRow;
|
|
145
|
+
/** Stands the sun somewhere else, on top of the row already set. Throws the
|
|
146
|
+
* renderer's own words for a value it will not have, and the sky the
|
|
147
|
+
* renderer is drawing under stays exactly where it was. */
|
|
148
|
+
setScene(row: SceneRow): void;
|
|
149
|
+
/** Puts the camera at the judging pose for what is on the canvas, and
|
|
150
|
+
* reports where that left it. Null before a tree has been submitted. */
|
|
151
|
+
hero(): Pose | null;
|
|
152
|
+
setCamera(pose: Pose): void;
|
|
153
|
+
frame(): void;
|
|
154
|
+
stats(): FrameStats;
|
|
155
|
+
timing(): Promise<TimingReport>;
|
|
156
|
+
/** The same session while the camera makes one full turn about the pose
|
|
157
|
+
* it stands at, ending with ten seconds of frames drawn the way this
|
|
158
|
+
* loop draws them - which is where the record's wall numbers come from. */
|
|
159
|
+
orbit(): Promise<TimingReport>;
|
|
160
|
+
dispose(): void;
|
|
161
|
+
}
|
|
162
|
+
/** Loads the module once per page and puts a renderer on this canvas.
|
|
163
|
+
* Rejects with the renderer's own words when there is no WebGPU, only a
|
|
164
|
+
* software adapter, or the device is refused. */
|
|
165
|
+
export declare function createRenderer(canvas: HTMLCanvasElement): Promise<Renderer>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ChangeRecord, NodeIdentity, PlacementIdentity } from './specimen';
|
|
2
|
+
/** The fixed little-endian record ABI, not a view into retained wasm memory. */
|
|
3
|
+
export declare class SpecimenWire {
|
|
4
|
+
private offset;
|
|
5
|
+
private view;
|
|
6
|
+
constructor(bytes: Uint8Array);
|
|
7
|
+
private u8;
|
|
8
|
+
private u32;
|
|
9
|
+
private u64;
|
|
10
|
+
private f64;
|
|
11
|
+
private vector;
|
|
12
|
+
private node;
|
|
13
|
+
private identity;
|
|
14
|
+
private placement;
|
|
15
|
+
private run;
|
|
16
|
+
identities(): {
|
|
17
|
+
nodes: NodeIdentity[];
|
|
18
|
+
placements: PlacementIdentity[];
|
|
19
|
+
shed: NodeIdentity[];
|
|
20
|
+
};
|
|
21
|
+
changes(): ChangeRecord;
|
|
22
|
+
}
|