@yali-engine/physics 0.0.0-stage → 0.4.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.
@@ -0,0 +1,129 @@
1
+ import { type ComponentValues } from '@yali-engine/core';
2
+ /** `physics.CharacterController`'s fields (ADR-0091), as the core declares them. */
3
+ export declare const CHARACTER_FIELDS: {
4
+ readonly radius: "f32";
5
+ readonly height: "f32";
6
+ readonly crouchHeight: "f32";
7
+ readonly stepHeight: "f32";
8
+ readonly maxSlope: "f32";
9
+ readonly snapDistance: "f32";
10
+ readonly skin: "f32";
11
+ readonly gravity: "vec3<f32>";
12
+ readonly jumpSpeed: "f32";
13
+ readonly accel: "f32";
14
+ readonly airControl: "f32";
15
+ readonly pushForce: "f32";
16
+ readonly mode: "u8";
17
+ readonly crouch: "u8";
18
+ readonly wishVel: "vec3<f32>";
19
+ readonly jump: "u8";
20
+ readonly velocity: "vec3<f32>";
21
+ readonly grounded: "u8";
22
+ readonly groundNormal: "vec3<f32>";
23
+ readonly groundEntity: "entity";
24
+ readonly crouched: "u8";
25
+ readonly handle: "u32";
26
+ };
27
+ /** `physics.ForceField`'s fields. */
28
+ export declare const FIELD_FIELDS: {
29
+ readonly kind: "u8";
30
+ readonly strength: "f32";
31
+ readonly radius: "f32";
32
+ readonly falloff: "f32";
33
+ readonly dir: "vec3<f32>";
34
+ readonly halfExtents: "vec3<f32>";
35
+ readonly density: "f32";
36
+ readonly drag: "f32";
37
+ readonly mask: "u32";
38
+ };
39
+ /** What `characterController` takes; every field optional (the defaults: a 1.8 m, 0.3 m capsule). */
40
+ export interface CharacterOptions {
41
+ readonly radius?: number;
42
+ readonly height?: number;
43
+ readonly crouchHeight?: number;
44
+ /** Highest step it walks up (default 0.35 m). */
45
+ readonly stepHeight?: number;
46
+ /** Steepest walkable slope, radians (default 50°). */
47
+ readonly maxSlope?: number;
48
+ /** How far down it snaps to ground while walking (default 0.3 m). */
49
+ readonly snapDistance?: number;
50
+ readonly gravity?: readonly [number, number, number];
51
+ readonly jumpSpeed?: number;
52
+ /** Acceleration towards `wishVel` (m/s², default 40). */
53
+ readonly accel?: number;
54
+ /** Share of `accel` in the air (default 0.3). */
55
+ readonly airControl?: number;
56
+ /** Newtons per m/s it wants to go into a dynamic body (default 400). */
57
+ readonly pushForce?: number;
58
+ /** `'fly'`: no gravity, 3D `wishVel`. */
59
+ readonly mode?: 'walk' | 'fly';
60
+ }
61
+ /**
62
+ * `physics.CharacterController` values (ADR-0091): a kinematic capsule moved by sweeps, before the
63
+ * physics step. Its `Transform` is the feet. Steer it by writing `wishVel` (m/s; horizontal when
64
+ * walking), `jump` (1 for one step) and `crouch`; read `velocity`, `grounded`, `groundNormal`,
65
+ * `groundEntity`, `crouched`.
66
+ *
67
+ * @example
68
+ * world.insert(player, CharacterController, characterController({ stepHeight: 0.4 }));
69
+ * world.insert(player, CharacterController, { ...current, wishVel: [2, 0, 0], jump: 1 });
70
+ */
71
+ export declare function characterController(o?: CharacterOptions): ComponentValues;
72
+ /** `physics.ForceField.kind`. */
73
+ export declare const FieldKind: {
74
+ readonly Directional: 0;
75
+ readonly Point: 1;
76
+ readonly Vortex: 2;
77
+ readonly Drag: 3;
78
+ readonly Buoyancy: 4;
79
+ };
80
+ /** A force field's shape and strength (ADR-0091). */
81
+ export type ForceFieldOptions =
82
+ /** An acceleration (m/s²) along `dir`, within `radius`. */
83
+ {
84
+ readonly directional: {
85
+ readonly dir: readonly [number, number, number];
86
+ readonly strength: number;
87
+ readonly radius: number;
88
+ };
89
+ }
90
+ /** Towards the field's centre (negative: away), within `radius`, falling off by `falloff`. */
91
+ | {
92
+ readonly point: {
93
+ readonly strength: number;
94
+ readonly radius: number;
95
+ readonly falloff?: number;
96
+ };
97
+ }
98
+ /** Around `axis` through the centre. */
99
+ | {
100
+ readonly vortex: {
101
+ readonly axis: readonly [number, number, number];
102
+ readonly strength: number;
103
+ readonly radius: number;
104
+ readonly falloff?: number;
105
+ };
106
+ }
107
+ /** Against the velocity, `strength` per second. */
108
+ | {
109
+ readonly drag: {
110
+ readonly strength: number;
111
+ readonly radius: number;
112
+ };
113
+ }
114
+ /** Water: a box of `halfExtents` around the field's centre (its top is the surface). */
115
+ | {
116
+ readonly buoyancy: {
117
+ readonly halfExtents: readonly [number, number, number];
118
+ readonly density?: number;
119
+ readonly drag?: number;
120
+ };
121
+ };
122
+ /**
123
+ * `physics.ForceField` values: put on an entity with a `Transform` (its centre); it acts on the
124
+ * dynamic bodies in its region every step.
125
+ *
126
+ * @example
127
+ * world.insert(pool, ForceField, forceField({ buoyancy: { halfExtents: [10, 2, 10], drag: 3 } }));
128
+ */
129
+ export declare function forceField(o: ForceFieldOptions, mask?: number): ComponentValues;
@@ -0,0 +1,96 @@
1
+ import { YaliError } from '@yali-engine/core';
2
+ /** `physics.CharacterController`'s fields (ADR-0091), as the core declares them. */
3
+ export const CHARACTER_FIELDS = {
4
+ radius: 'f32',
5
+ height: 'f32',
6
+ crouchHeight: 'f32',
7
+ stepHeight: 'f32',
8
+ maxSlope: 'f32',
9
+ snapDistance: 'f32',
10
+ skin: 'f32',
11
+ gravity: 'vec3<f32>',
12
+ jumpSpeed: 'f32',
13
+ accel: 'f32',
14
+ airControl: 'f32',
15
+ pushForce: 'f32',
16
+ mode: 'u8',
17
+ crouch: 'u8',
18
+ wishVel: 'vec3<f32>',
19
+ jump: 'u8',
20
+ velocity: 'vec3<f32>',
21
+ grounded: 'u8',
22
+ groundNormal: 'vec3<f32>',
23
+ groundEntity: 'entity',
24
+ crouched: 'u8',
25
+ handle: 'u32',
26
+ };
27
+ /** `physics.ForceField`'s fields. */
28
+ export const FIELD_FIELDS = {
29
+ kind: 'u8',
30
+ strength: 'f32',
31
+ radius: 'f32',
32
+ falloff: 'f32',
33
+ dir: 'vec3<f32>',
34
+ halfExtents: 'vec3<f32>',
35
+ density: 'f32',
36
+ drag: 'f32',
37
+ mask: 'u32',
38
+ };
39
+ /**
40
+ * `physics.CharacterController` values (ADR-0091): a kinematic capsule moved by sweeps, before the
41
+ * physics step. Its `Transform` is the feet. Steer it by writing `wishVel` (m/s; horizontal when
42
+ * walking), `jump` (1 for one step) and `crouch`; read `velocity`, `grounded`, `groundNormal`,
43
+ * `groundEntity`, `crouched`.
44
+ *
45
+ * @example
46
+ * world.insert(player, CharacterController, characterController({ stepHeight: 0.4 }));
47
+ * world.insert(player, CharacterController, { ...current, wishVel: [2, 0, 0], jump: 1 });
48
+ */
49
+ export function characterController(o = {}) {
50
+ const radius = o.radius ?? 0.3;
51
+ const height = o.height ?? 1.8;
52
+ if (!(radius > 0) || !(height >= 2 * radius)) {
53
+ throw Object.assign(new YaliError('PHYSICS_INVALID', `A controller of radius ${radius} and height ${height}.`, 'Give a positive radius and a height of at least twice it.'), { path: o.radius !== undefined && !(radius > 0) ? 'radius' : 'height' });
54
+ }
55
+ return {
56
+ radius,
57
+ height,
58
+ crouchHeight: o.crouchHeight ?? Math.max(2 * radius, 1),
59
+ stepHeight: o.stepHeight ?? 0.35,
60
+ maxSlope: o.maxSlope ?? (50 * Math.PI) / 180,
61
+ snapDistance: o.snapDistance ?? 0.3,
62
+ skin: 0.02,
63
+ gravity: o.gravity ?? [0, -9.81, 0],
64
+ jumpSpeed: o.jumpSpeed ?? 5,
65
+ accel: o.accel ?? 40,
66
+ airControl: o.airControl ?? 0.3,
67
+ pushForce: o.pushForce ?? 400,
68
+ mode: o.mode === 'fly' ? 2 : 0,
69
+ groundNormal: [0, 1, 0],
70
+ groundEntity: 0xffffffff,
71
+ };
72
+ }
73
+ /** `physics.ForceField.kind`. */
74
+ export const FieldKind = { Directional: 0, Point: 1, Vortex: 2, Drag: 3, Buoyancy: 4 };
75
+ /**
76
+ * `physics.ForceField` values: put on an entity with a `Transform` (its centre); it acts on the
77
+ * dynamic bodies in its region every step.
78
+ *
79
+ * @example
80
+ * world.insert(pool, ForceField, forceField({ buoyancy: { halfExtents: [10, 2, 10], drag: 3 } }));
81
+ */
82
+ export function forceField(o, mask = 0xffffffff) {
83
+ const base = { strength: 0, radius: 0, falloff: 0, dir: [0, 0, 0], halfExtents: [0, 0, 0], density: 0, drag: 0, mask };
84
+ if ('directional' in o)
85
+ return { ...base, kind: FieldKind.Directional, dir: o.directional.dir, strength: o.directional.strength, radius: o.directional.radius };
86
+ if ('point' in o)
87
+ return { ...base, kind: FieldKind.Point, strength: o.point.strength, radius: o.point.radius, falloff: o.point.falloff ?? 1 };
88
+ if ('vortex' in o)
89
+ return { ...base, kind: FieldKind.Vortex, dir: o.vortex.axis, strength: o.vortex.strength, radius: o.vortex.radius, falloff: o.vortex.falloff ?? 1 };
90
+ if ('drag' in o)
91
+ return { ...base, kind: FieldKind.Drag, strength: o.drag.strength, radius: o.drag.radius };
92
+ if ('buoyancy' in o)
93
+ return { ...base, kind: FieldKind.Buoyancy, halfExtents: o.buoyancy.halfExtents, density: o.buoyancy.density ?? 1000, drag: o.buoyancy.drag ?? 1 };
94
+ throw Object.assign(new YaliError('PHYSICS_INVALID', 'A force field needs one of directional, point, vortex, drag, buoyancy.', 'Pass e.g. forceField({ point: { strength: 10, radius: 5 } }).'), { path: 'kind' });
95
+ }
96
+ //# sourceMappingURL=character.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"character.js","sourceRoot":"","sources":["../src/character.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,296 @@
1
+ /** A cloth's rest mesh, in its entity's mesh space. */
2
+ export interface ClothMesh {
3
+ /** xyz per vertex. */
4
+ readonly positions: Float32Array;
5
+ /** Triangles, counter-clockwise from the front. */
6
+ readonly indices: Uint32Array;
7
+ /** uv per vertex (default 0). */
8
+ readonly uvs?: Float32Array;
9
+ /** Vertices held to the entity (they follow its pose). */
10
+ readonly pinned?: ArrayLike<number>;
11
+ }
12
+ /** The solver's view of a cloth mesh (`clothTopology`). */
13
+ export interface ClothTopology {
14
+ readonly mesh: ClothMesh;
15
+ readonly vertices: number;
16
+ readonly triangles: number;
17
+ /** 1 for a pinned vertex. */
18
+ readonly pinned: Uint8Array;
19
+ /** A third of the area of the triangles around each vertex (m², unscaled): its share of the mass. */
20
+ readonly area: Float64Array;
21
+ /** Vertex → triangles (CSR): `adjacency[adjOffsets[v] .. adjOffsets[v + 1]]`. */
22
+ readonly adjOffsets: Uint32Array;
23
+ readonly adjacency: Uint32Array;
24
+ /** Constraints: `kinds[c]` 0 stretch (edge), 1 bending (stencil); four vertices each (stretch: the last two unused). */
25
+ readonly kinds: Uint8Array;
26
+ readonly vertexIds: Uint32Array;
27
+ /** Stretch: the rest length; bending: Bergou's four cotangent weights, scaled by √κ (`κ = 3 / (A0 + A1)`). Unscaled mesh units. */
28
+ readonly rest: Float32Array;
29
+ /** Constraint ids in colour order, and where each colour starts (`colourOffsets[k] .. [k + 1]`). */
30
+ readonly order: Uint32Array;
31
+ readonly colourOffsets: Uint32Array;
32
+ /** How many of the colour ranges are stretch constraints (the rest, one range, the bending stencils; ADR-0110). */
33
+ readonly stretchColours: number;
34
+ /**
35
+ * VBD (ADR-0105): the free vertices in colour order (no two of a colour share a triangle or a
36
+ * bending stencil), and where each colour starts (`vertexColourOffsets[k] .. [k + 1]`).
37
+ */
38
+ readonly vertexOrder: Uint32Array;
39
+ readonly vertexColourOffsets: Uint32Array;
40
+ /**
41
+ * Each triangle's rest frame for the membrane (ADR-0105): the inverse of its 2 × 2 rest edge
42
+ * matrix in the pattern frame (warp along +u, weft across it), row-major, then its area: five
43
+ * floats a triangle, unscaled mesh units.
44
+ */
45
+ readonly restFrames: Float32Array;
46
+ /** Tethers (ADR-0105): each vertex's nearest pinned vertex over the mesh (NO_VERTEX: none) and that geodesic length (unscaled). */
47
+ readonly tetherAnchor: Uint32Array;
48
+ readonly tetherLength: Float32Array;
49
+ }
50
+ /** Marks a constraint's unused vertex slots. */
51
+ export declare const NO_VERTEX = 4294967295;
52
+ /** Words per packed constraint (`solve` in shaders/kanduka/cloth.wesl). */
53
+ export declare const CONSTRAINT_WORDS = 12;
54
+ /**
55
+ * A fabric: what the solver needs to know about a material (ADR-0101). Compliances are XPBD's
56
+ * (the inverse of a stiffness): 0 is perfectly stiff.
57
+ */
58
+ export interface ClothFabric {
59
+ /** Mass per area, kg/m². */
60
+ readonly density: number;
61
+ /** Stretch compliance (m/N), and the far softer compression compliance (cloth buckles instead). */
62
+ readonly stretch: number;
63
+ readonly compression: number;
64
+ /** Bending compliance (1/(N·m)): the inverse of the bending stiffness. */
65
+ readonly bend: number;
66
+ /** Velocity damping, 1/s (the air does most of it). */
67
+ readonly damping: number;
68
+ /** Friction against colliders (combined with theirs as √(μa μb)). */
69
+ readonly friction: number;
70
+ /** How far from a collider the cloth stays, m. */
71
+ readonly thickness: number;
72
+ /** Drag coefficients across the surface (pressure) and along it (skin friction). */
73
+ readonly drag: number;
74
+ readonly skinDrag: number;
75
+ /**
76
+ * The VBD membrane (ADR-0105, orthotropic StVK in the pattern frame), N/m: stiffness along the
77
+ * warp (+u), along the weft (+v), and in shear; `poisson` couples warp and weft. Defaults:
78
+ * warp 1 / `stretch`, weft = warp, shear a tenth of it, poisson 0.2. XPBD ignores them.
79
+ */
80
+ readonly warp?: number;
81
+ readonly weft?: number;
82
+ readonly shear?: number;
83
+ readonly poisson?: number;
84
+ }
85
+ /**
86
+ * A fabric's KES-F (Kawabata) measurements, as textile papers report them. A pair is (warp, weft);
87
+ * one number is both.
88
+ */
89
+ export interface KesFabric {
90
+ /** Areal weight W, g/m² (KES-F's mg/cm² × 10). */
91
+ readonly weight: number;
92
+ /** Bending rigidity B, gf·cm²/cm. */
93
+ readonly bending: number | readonly [number, number];
94
+ /** Shear rigidity G, gf/(cm·degree). */
95
+ readonly shear: number | readonly [number, number];
96
+ /** The tensile test: extension at the maximum load EMT (%), its linearity LT, the load (gf/cm, KES-F's default 500). */
97
+ readonly tensile?: {
98
+ readonly emt: number | readonly [number, number];
99
+ readonly lt: number | readonly [number, number];
100
+ readonly load?: number;
101
+ };
102
+ }
103
+ /**
104
+ * The isometric stencils' energy over a flat grid rolled to curvature k is
105
+ * `Σ ½ |Σ w x|² / compliance = ½ (r / compliance) k² × area`, where r depends on the fold's angle to
106
+ * the grid: 2.92 along the warp or weft, 4.46 along a cell diagonal (the grid's own anisotropy),
107
+ * 3.69 averaged over every angle (at 5 mm–2 cm cells). A drape folds at every angle, so a plate's
108
+ * bending rigidity B (N·m) is the compliance STENCIL_BEND / B with the average (ADR-0120; a test
109
+ * re-measures it).
110
+ */
111
+ export declare const STENCIL_BEND = 3.69;
112
+ /**
113
+ * A fabric from KES-F measurements (ADR-0120): density from W; XPBD's bending compliance from B
114
+ * (warp and weft averaged; `STENCIL_BEND`); VBD's shear modulus from G (N/m per radian); warp and
115
+ * weft stiffness, if measured, as the linear spring storing the tensile test's energy at EMT
116
+ * (`LT × load / EMT`), and XPBD's stretch compliance their geometric mean's inverse. What KES-F does
117
+ * not measure (damping, friction against colliders, collision thickness, the air, Poisson's ratio)
118
+ * comes from `base`; compression keeps `base`'s ratio to stretch.
119
+ *
120
+ * @example
121
+ * const habotai = fabricFromKes({ weight: 72.1, bending: [0.019, 0.063], shear: [0.23, 0.26], tensile: { emt: [7.11, 1.72], lt: [0.554, 0.867] } }, FABRICS.silk);
122
+ */
123
+ export declare function fabricFromKes(kes: KesFabric, base: ClothFabric): ClothFabric;
124
+ /**
125
+ * Published KES-F measurements behind the presets (ADR-0120, ADR-0131). `canvas` is data only: built
126
+ * from it, the preset drapes 0.51 against its source's 0.91 (XPBD has no shear rigidity, which is
127
+ * what holds a stiff weave up), so the canvas preset stays fitted. `leather` is data only too: built from it
128
+ * the preset drapes 0.80 against the fitted 0.98, and its source measured no drape to referee (ADR-0138).
129
+ */
130
+ export declare const KES: {
131
+ /** Habotai, plain weave, 72.1 g/m² (sample 8): Hu X. et al., "Comparison of silk fabric dynamic drapability…", Industria Textila 71(1), 2020, pp. 55–61, Tables 1–5 (doi:10.35530/IT.071.01.1536). Drape coefficient 42.7% (YG811, 24 cm). */
132
+ readonly silk: {
133
+ readonly weight: 72.067;
134
+ readonly bending: readonly [0.019, 0.063];
135
+ readonly shear: readonly [0.23, 0.26];
136
+ readonly tensile: {
137
+ readonly emt: readonly [7.11, 1.723];
138
+ readonly lt: readonly [0.554, 0.867];
139
+ };
140
+ };
141
+ /** 100% cotton plain weave, Ne 30, 70 ppi, 138.6 g/m² (sample 6): Alam M.S., Majumdar A., Ghosh A., Indian J. Fibre Text. Res. 44, 2019, pp. 9–15, Table 2. No tensile data. */
142
+ readonly cotton: {
143
+ readonly weight: 138.6;
144
+ readonly bending: 0.07;
145
+ readonly shear: 1.75;
146
+ };
147
+ /** 100% cotton indigo denim (sample A), 246 g/m² and 0.62 mm (Table 2; Table 5 prints W 104 mg/cm², which contradicts it): Kumari A., Khurana K., Journal of Textiles 2016, 4614168, Table 5 (doi:10.1155/2016/4614168). */
148
+ readonly denim: {
149
+ readonly weight: 246;
150
+ readonly bending: 0.172;
151
+ readonly shear: 2.18;
152
+ readonly tensile: {
153
+ readonly emt: 5.515;
154
+ readonly lt: 0.712;
155
+ };
156
+ };
157
+ /** A heavy 100% cotton plain weave, 279 g/m², 16 × 23 threads/cm, 0.88 mm (sample C3; no source measures a fabric sold as canvas, ADR-0131): Kuijpers A., "Evaluation of physical and virtual fabric drape created from objective fabric properties", MPhil thesis, University of Manchester, 2017, Table 3.1 and Appendix 7 (KES-FB). Drape coefficient 91% (Cusick, 30 cm on 18 cm, Table 5.1). */
158
+ readonly canvas: {
159
+ readonly weight: 279;
160
+ readonly bending: readonly [0.33, 0.275];
161
+ readonly shear: readonly [4.58, 4.41];
162
+ readonly tensile: {
163
+ readonly emt: readonly [4.16, 8.03];
164
+ readonly lt: readonly [0.905, 0.773];
165
+ };
166
+ };
167
+ /** Cowhide grain leather for bags (the butt), the mean of nine samples C1–C9, 1.21 mm: Roh E.K., "Mechanical properties and preferences of natural and artificial leathers…", J. Eng. Fibers Fabr. 15, 2020, Tables 1 and 3 (doi:10.1177/1558925020968825, CC BY). KES-FB: W 706.5 g/m², B 2.67 gf·cm²/cm (2 × 2 cm specimens), G 12.52 gf/cm·deg; the tensile test is reported as WT, RT and EM 4.13% without LT (none here); no drape measured. */
168
+ readonly leather: {
169
+ readonly weight: 706.47;
170
+ readonly bending: 2.67;
171
+ readonly shear: 12.52;
172
+ };
173
+ };
174
+ /**
175
+ * Fabric presets. Silk, cotton and denim are fitted to published KES-F measurements (`KES`,
176
+ * `fabricFromKes`, ADR-0120); their drape matches the published drape coefficients when the solve
177
+ * converges. Canvas is fitted to a published drape (ADR-0131: its KES-F values alone drape far too
178
+ * softly under XPBD); leather is fitted by eye (ADR-0101, ADR-0105) and stays so beside `KES.leather` (ADR-0138).
179
+ * Cotton's warp / weft stiffness is fitted too (its source has no tensile test). Woven fabrics are
180
+ * stiffer along the warp than the weft and far softer in shear; leather has no weave.
181
+ */
182
+ export declare const FABRICS: {
183
+ readonly silk: ClothFabric;
184
+ readonly cotton: ClothFabric;
185
+ readonly canvas: {
186
+ readonly density: 0.22;
187
+ readonly stretch: 0.00005;
188
+ readonly compression: 0.002;
189
+ readonly bend: 5000;
190
+ readonly damping: 0.05;
191
+ readonly friction: 0.5;
192
+ readonly thickness: 0.008;
193
+ readonly drag: 1.2;
194
+ readonly skinDrag: 0.03;
195
+ readonly warp: 20000;
196
+ readonly weft: 18000;
197
+ readonly shear: 2500;
198
+ readonly poisson: 0.2;
199
+ };
200
+ readonly denim: ClothFabric;
201
+ readonly leather: {
202
+ readonly density: 0.9;
203
+ readonly stretch: 0.00001;
204
+ readonly compression: 0.0005;
205
+ readonly bend: 300;
206
+ readonly damping: 0.1;
207
+ readonly friction: 0.7;
208
+ readonly thickness: 0.012;
209
+ readonly drag: 1;
210
+ readonly skinDrag: 0.05;
211
+ readonly warp: 100000;
212
+ readonly weft: 100000;
213
+ readonly shear: 35000;
214
+ readonly poisson: 0.4;
215
+ };
216
+ };
217
+ /** A preset's name. */
218
+ export type FabricName = keyof typeof FABRICS;
219
+ /** What `clothGrid` takes. */
220
+ export interface ClothGridOptions {
221
+ /** Size in metres (along X, then along Y or Z). */
222
+ readonly width: number;
223
+ readonly height: number;
224
+ /** Quads along each side (default about 32 per metre, at least 2). */
225
+ readonly segments?: readonly [number, number];
226
+ /** `xy`: hanging, facing +Z (a flag, a curtain); `xz`: lying flat, facing +Y (a sheet). Default `xy`. */
227
+ readonly plane?: 'xy' | 'xz';
228
+ /**
229
+ * Which vertices hold: `top` (the edge at +Y, or −Z for `xz`), `left` (the edge at −X),
230
+ * `corners` (the two top corners), `none`, or a test on (u, v), each 0–1 from the left and top.
231
+ */
232
+ readonly pin?: 'top' | 'left' | 'corners' | 'none' | ((u: number, v: number) => boolean);
233
+ }
234
+ /**
235
+ * A rectangular cloth centred on its entity's origin, its cells cut along alternating diagonals
236
+ * (no preferred shear direction).
237
+ *
238
+ * @example
239
+ * const flag = clothGrid({ width: 3, height: 2, segments: [60, 40], pin: 'left' });
240
+ */
241
+ export declare function clothGrid(o: ClothGridOptions): ClothMesh;
242
+ /**
243
+ * Builds a mesh's solver topology: a stretch constraint per edge, a bending stencil per edge two
244
+ * triangles share (isometric bending, Bergou et al., *A Quadratic Bending Model for Inextensible
245
+ * Surfaces*, 2006; it assumes a flat rest shape), adjacency, per-vertex areas, and a greedy
246
+ * colouring of all constraints together.
247
+ */
248
+ export declare function clothTopology(mesh: ClothMesh): ClothTopology;
249
+ /** Where each part of a packed cloth starts, in words from its base (the `Cloth` struct's offsets). */
250
+ export interface PackedCloth {
251
+ readonly words: Uint32Array;
252
+ readonly tris: number;
253
+ readonly adj: number;
254
+ readonly colours: number;
255
+ readonly ncolours: number;
256
+ readonly cons: number;
257
+ /** The inverse mass of each vertex (0: pinned). */
258
+ readonly invMass: Float32Array;
259
+ /** Where each triangle's three edge constraints are listed (words from the base): tearing (ADR-0104). */
260
+ readonly triEdges: number;
261
+ /** Where the VBD section's header starts (words from the base; ADR-0105, `VBD_HEADER`). */
262
+ readonly vbd: number;
263
+ }
264
+ /**
265
+ * The VBD section's header (ADR-0105), words from its start: where the triangles' rest frames, the
266
+ * vertex colours, the per-vertex bending and edge lists and the tethers are (words from the cloth's
267
+ * base; tethers 0: none), the vertex colour count, then the membrane's c11, c22, c12, c33 and the
268
+ * compression scale (f32); word 11: where the per-vertex skinned anchors are (ADR-0108; 0: none);
269
+ * word 12: where the compact tear flags are, one word per constraint in colour order, which the
270
+ * solver sets with the constraint's own flag so a readback is small (vertex splitting, ADR-0108);
271
+ * word 13: how many colour ranges are stretch constraints (the bending range follows, ADR-0110).
272
+ */
273
+ export declare const VBD_HEADER = 16;
274
+ /**
275
+ * Packs a topology for the GPU with a fabric at a uniform scale (the entity's): the rest
276
+ * positions (unscaled, the inverse masses in w), adjacency, triangles, colour ranges and the
277
+ * constraints in colour order with their compliances (shaders/kanduka/cloth.wesl `solve`).
278
+ */
279
+ export declare function packCloth(topo: ClothTopology, fabric: ClothFabric, scale: number, tether?: number, anchors?: Uint32Array | null): PackedCloth;
280
+ /**
281
+ * Splits a cloth mesh along torn edges (ADR-0108): around each vertex on a torn edge its triangles
282
+ * fall into pieces that meet only across torn edges (or not at all); the first piece keeps the
283
+ * vertex, each other piece gets a copy of it (appended, same rest position, uv and pin), and its
284
+ * triangles are re-indexed to it. The torn edges become two boundary edges, one per side, so the
285
+ * pieces separate cleanly. Null when nothing splits. `source[k]` is the vertex copy k came from.
286
+ */
287
+ export declare function splitTorn(mesh: ClothMesh, torn: Iterable<readonly [number, number]>): {
288
+ mesh: ClothMesh;
289
+ source: Uint32Array;
290
+ } | null;
291
+ /**
292
+ * Bergou's bending weights for the stencil (edge x0–x1, opposite vertices x2 and x3), scaled by
293
+ * √κ, κ = 3 / (A0 + A1): `Σ k_i x_i` is the stencil's discrete mean-curvature vector, zero when
294
+ * the two triangles are flat. Null for a degenerate pair.
295
+ */
296
+ export declare function bendWeights(p: Float32Array, i0: number, i1: number, i2: number, i3: number): [number, number, number, number] | null;