@nayan-ui/engine 1.0.0-beta.5 → 1.0.0-beta.6

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.
Files changed (77) hide show
  1. package/README.md +95 -4
  2. package/lib/module/assets/ProceduralCache.js +5 -0
  3. package/lib/module/assets/loft.js +15 -63
  4. package/lib/module/assets/procedural.js +500 -0
  5. package/lib/module/assets/shape.js +147 -245
  6. package/lib/module/assets/texture.js +65 -0
  7. package/lib/module/drawing/DrawingDocument.js +1 -1
  8. package/lib/module/index.js +4 -1
  9. package/lib/module/media/audio-worklet.js +27 -0
  10. package/lib/module/media/audio.js +20 -0
  11. package/lib/module/media/input.web.js +107 -0
  12. package/lib/module/media/microphone.js +89 -0
  13. package/lib/module/media/speech.js +80 -0
  14. package/lib/module/media/speechPlatform.js +12 -0
  15. package/lib/module/media/speechPlatform.web.js +16 -0
  16. package/lib/module/native/BrowserEngine.js +122 -0
  17. package/lib/module/native/NativeNayanEngine.web.js +2 -0
  18. package/lib/module/render/GameView.js +45 -13
  19. package/lib/module/render/quality.js +151 -17
  20. package/lib/module/world/World.js +63 -0
  21. package/lib/typescript/src/assets/ProceduralCache.d.ts +2 -0
  22. package/lib/typescript/src/assets/loft.d.ts +3 -1
  23. package/lib/typescript/src/assets/procedural.d.ts +394 -0
  24. package/lib/typescript/src/assets/shape.d.ts +13 -7
  25. package/lib/typescript/src/assets/texture.d.ts +63 -0
  26. package/lib/typescript/src/index.d.ts +8 -2
  27. package/lib/typescript/src/media/audio.d.ts +13 -0
  28. package/lib/typescript/src/media/input.web.d.ts +4 -0
  29. package/lib/typescript/src/media/microphone.d.ts +51 -0
  30. package/lib/typescript/src/media/speech.d.ts +38 -0
  31. package/lib/typescript/src/media/speechPlatform.d.ts +5 -0
  32. package/lib/typescript/src/media/speechPlatform.web.d.ts +5 -0
  33. package/lib/typescript/src/native/EngineBridge.d.ts +7 -1
  34. package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +72 -0
  35. package/lib/typescript/src/render/GameView.d.ts +30 -3
  36. package/lib/typescript/src/render/quality.d.ts +54 -2
  37. package/lib/typescript/src/types.d.ts +9 -2
  38. package/lib/typescript/src/world/World.d.ts +16 -0
  39. package/lib/typescript/src/world/types.d.ts +8 -0
  40. package/lib/web/audio-worklet.js +27 -0
  41. package/lib/web/engine_core_bg.wasm +0 -0
  42. package/lib/web/index.js +1181 -422
  43. package/lib/web/types/src/assets/ProceduralCache.d.ts +2 -0
  44. package/lib/web/types/src/assets/loft.d.ts +3 -1
  45. package/lib/web/types/src/assets/procedural.d.ts +393 -0
  46. package/lib/web/types/src/assets/shape.d.ts +13 -7
  47. package/lib/web/types/src/assets/texture.d.ts +63 -0
  48. package/lib/web/types/src/index.d.ts +8 -2
  49. package/lib/web/types/src/media/audio.d.ts +13 -0
  50. package/lib/web/types/src/media/input.d.ts +3 -0
  51. package/lib/web/types/src/media/microphone.d.ts +50 -0
  52. package/lib/web/types/src/media/speech.d.ts +37 -0
  53. package/lib/web/types/src/media/speechPlatform.d.ts +4 -0
  54. package/lib/web/types/src/native/EngineBridge.d.ts +7 -1
  55. package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +72 -0
  56. package/lib/web/types/src/render/GameView.d.ts +30 -3
  57. package/lib/web/types/src/render/quality.d.ts +54 -2
  58. package/lib/web/types/src/types.d.ts +9 -2
  59. package/lib/web/types/src/world/World.d.ts +16 -0
  60. package/lib/web/types/src/world/types.d.ts +8 -0
  61. package/native/android/src/main/AndroidManifest.xml +10 -0
  62. package/native/android/src/main/java/com/nayanui/engine/EngineMicrophone.java +60 -0
  63. package/native/android/src/main/java/com/nayanui/engine/EngineSpeech.java +28 -0
  64. package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +1 -0
  65. package/native/android/src/main/java/com/nayanui/engine/NayanEnginePackage.java +2 -0
  66. package/native/core/build/EngineCore.xcframework/ios-arm64/libengine_core.a +0 -0
  67. package/native/core/build/EngineCore.xcframework/ios-arm64-simulator/libengine_core.a +0 -0
  68. package/native/core/build/android/arm64-v8a/libengine_core.a +0 -0
  69. package/native/core/build/android/armeabi-v7a/libengine_core.a +0 -0
  70. package/native/core/build/android/x86/libengine_core.a +0 -0
  71. package/native/core/build/android/x86_64/libengine_core.a +0 -0
  72. package/native/core/include/engine_core.h +63 -1
  73. package/native/cpp/NayanEngineModule.cpp +296 -0
  74. package/native/cpp/NayanEngineModule.h +40 -0
  75. package/native/cpp/generated/NayanEngineSpecJSI.h +397 -0
  76. package/package.json +1 -1
  77. package/src/native/spec/NativeNayanEngine.ts +77 -0
@@ -0,0 +1,394 @@
1
+ import type { MeshGeometry } from '../render/meshes.js';
2
+ /** A node of a field graph. Plain numbers are constants wherever a field is expected. */
3
+ export declare class FieldRef {
4
+ readonly id: number;
5
+ constructor(id: number);
6
+ }
7
+ export type FieldInput = FieldRef | number;
8
+ /** A 2D primitive in a field's (x, z) plane; `offset` is subtracted from its distance, `width` is its fade length. */
9
+ export type FieldShape = {
10
+ kind: 'point';
11
+ x: number;
12
+ z: number;
13
+ offset?: number;
14
+ width?: number;
15
+ } | {
16
+ kind: 'segment';
17
+ ax: number;
18
+ az: number;
19
+ bx: number;
20
+ bz: number;
21
+ offset?: number;
22
+ width?: number;
23
+ } | {
24
+ kind: 'box';
25
+ x: number;
26
+ z: number;
27
+ halfX: number;
28
+ halfZ: number;
29
+ yaw?: number;
30
+ offset?: number;
31
+ width?: number;
32
+ };
33
+ type Node = {
34
+ op: string;
35
+ } & Record<string, unknown>;
36
+ /**
37
+ * Builds a field graph: generic math and geometry nodes evaluated by the native core. Shared nodes
38
+ * are computed once per sample point and `select` evaluates only the branch it takes.
39
+ *
40
+ * ```ts
41
+ * const f = new FieldGraph();
42
+ * const bank = f.sub(f.abs(f.sub(f.x, f.sines(f.x, f.z, 10, [[0, 0.035, 0, 11]]))), 5);
43
+ * f.output('bank', bank);
44
+ * ```
45
+ */
46
+ export declare class FieldGraph {
47
+ private nodes;
48
+ private outputs;
49
+ private constants;
50
+ private inputs;
51
+ private node;
52
+ private ref;
53
+ private refs;
54
+ constant(value: number): FieldRef;
55
+ /** A named input: `x`/`z` (local frame) for terrain fields; u, v, row, col, i, count, r0… elsewhere. */
56
+ input(name: string): FieldRef;
57
+ get x(): FieldRef;
58
+ get z(): FieldRef;
59
+ add(a: FieldInput, b: FieldInput): FieldRef;
60
+ sub(a: FieldInput, b: FieldInput): FieldRef;
61
+ mul(a: FieldInput, b: FieldInput): FieldRef;
62
+ div(a: FieldInput, b: FieldInput): FieldRef;
63
+ /** a + b + c… left to right. */
64
+ sum(...values: FieldInput[]): FieldRef;
65
+ /** a · b · c… left to right. */
66
+ product(...values: FieldInput[]): FieldRef;
67
+ min(...args: FieldInput[]): FieldRef;
68
+ max(...args: FieldInput[]): FieldRef;
69
+ neg(a: FieldInput): FieldRef;
70
+ abs(a: FieldInput): FieldRef;
71
+ sqrt(a: FieldInput): FieldRef;
72
+ floor(a: FieldInput): FieldRef;
73
+ square(a: FieldInput): FieldRef;
74
+ sin(a: FieldInput): FieldRef;
75
+ cos(a: FieldInput): FieldRef;
76
+ exp(a: FieldInput): FieldRef;
77
+ /** `a` to the power `b`. */
78
+ pow(a: FieldInput, b: FieldInput): FieldRef;
79
+ /** `a − floor(a)`. */
80
+ fract(a: FieldInput): FieldRef;
81
+ /**
82
+ * Value noise in 0..1 on a unit lattice: the common sine-hash shader noise, smoothstep-blended.
83
+ * With `period`, it repeats every `period` cells in x (to wrap around a lathe without a seam).
84
+ */
85
+ noise(x: FieldInput, z: FieldInput, period?: number): FieldRef;
86
+ /** a + (b − a) · t, componentwise on numbers or fields. */
87
+ mix(a: FieldInput, b: FieldInput, t: FieldInput): FieldRef;
88
+ hypot(...args: FieldInput[]): FieldRef;
89
+ /** Hermite smoothstep of `a` clamped to 0..1. */
90
+ smooth(a: FieldInput): FieldRef;
91
+ clamp(a: FieldInput, lo: FieldInput, hi: FieldInput): FieldRef;
92
+ /** `le` where `test` <= 0, otherwise `gt` (only the chosen branch is evaluated). */
93
+ select(test: FieldInput, le: FieldInput, gt: FieldInput): FieldRef;
94
+ /** base + Σ amp · sin(fx·x + fz·z + phase), terms as [fx, fz, phase, amp]. */
95
+ sines(x: FieldInput, z: FieldInput, base: number, terms: readonly (readonly [number, number, number, number])[]): FieldRef;
96
+ /** Σ height · max(0, 1 − u² − v²)^power over oriented ellipses [x, z, height, radiusU, radiusV, yaw]. */
97
+ bumps(x: FieldInput, z: FieldInput, items: readonly (readonly [number, number, number, number, number, number])[], power?: number): FieldRef;
98
+ /** The smallest signed distance to the shapes (minus each one's offset); +∞ with none. */
99
+ distance(x: FieldInput, z: FieldInput, shapes: readonly FieldShape[]): FieldRef;
100
+ /** Π smoothstep((distance − offset) / width): 0 at the shapes, 1 beyond their fade. */
101
+ falloff(x: FieldInput, z: FieldInput, shapes: readonly FieldShape[]): FieldRef;
102
+ /** The largest depth inside any of the boxes (min of side clearances, minus offset); −∞ with none. */
103
+ depth(x: FieldInput, z: FieldInput, shapes: readonly FieldShape[]): FieldRef;
104
+ /** Names a field so recipes can refer to it. Returns the name. */
105
+ output(name: string, value: FieldInput): string;
106
+ toJSON(): {
107
+ nodes: Node[];
108
+ outputs: Record<string, number>;
109
+ };
110
+ }
111
+ type Inputs<K extends string> = {
112
+ readonly [P in K]: FieldRef;
113
+ };
114
+ type Color3 = readonly [FieldInput, FieldInput, FieldInput];
115
+ /**
116
+ * A function of named inputs written as a field graph, for model options that would otherwise call
117
+ * a JS function per vertex: `lathe`/`tube`/`loft` colors and `lathe` displacement, `recolor`. Build
118
+ * one with `surfaceColor`, `faceColor`, `sectionColor` or `surfaceDisplacement`.
119
+ */
120
+ export declare class FieldFunction {
121
+ readonly fields: FieldGraph;
122
+ readonly outputs: number;
123
+ constructor(fields: FieldGraph, outputs: number);
124
+ toJSON(): {
125
+ fields: FieldGraph;
126
+ out: string[];
127
+ };
128
+ }
129
+ /**
130
+ * A color of each surface point: `u`, `v` (texture coordinates; around and along a lathe or tube),
131
+ * position `x`, `y`, `z` and normal `nx`, `ny`, `nz`. Returns [r, g, b].
132
+ */
133
+ export declare const surfaceColor: (build: (f: FieldGraph, p: Inputs<"u" | "v" | "x" | "y" | "z" | "nx" | "ny" | "nz">) => Color3) => FieldFunction;
134
+ /** A color across a round end face: `r` from its center (0) to its rim (1), `angle` around it (radians). */
135
+ export declare const faceColor: (build: (f: FieldGraph, p: Inputs<"r" | "angle">) => Color3) => FieldFunction;
136
+ /** A color across a lathe's cut face: `r` from the axis (0) to the skin (1) at that height, and the height `y`. */
137
+ export declare const sectionColor: (build: (f: FieldGraph, p: Inputs<"r" | "y">) => Color3) => FieldFunction;
138
+ /** A lathe's displacement along its normal at (`u` around, `v` down the profile). */
139
+ export declare const surfaceDisplacement: (build: (f: FieldGraph, p: Inputs<"u" | "v">) => FieldInput) => FieldFunction;
140
+ type Three = readonly [string, string, string];
141
+ export type MeshPart = {
142
+ kind: 'surface';
143
+ rows: number;
144
+ cols: number;
145
+ position: Three;
146
+ normal: Three;
147
+ uv: readonly [string, string];
148
+ color: Three;
149
+ double?: boolean;
150
+ flip?: boolean;
151
+ } | {
152
+ kind: 'cards';
153
+ count: number;
154
+ seed: number;
155
+ randoms: number;
156
+ /** [cu, cv, texU, texV] per corner (3 or 4): center + right·cu + up·cv. */
157
+ corners: readonly (readonly [number, number, number, number])[];
158
+ center: Three;
159
+ right: Three;
160
+ up: Three;
161
+ normal: Three;
162
+ color: Three;
163
+ double?: boolean;
164
+ };
165
+ export interface MeshRecipe {
166
+ fields: FieldGraph;
167
+ parts: readonly MeshPart[];
168
+ }
169
+ export type Frame = 'local' | 'world';
170
+ export interface TerrainRecipe {
171
+ /** Grid lines along both axes, ascending. */
172
+ axis: readonly number[];
173
+ height: string;
174
+ normalStep?: number;
175
+ uvSize?: readonly [number, number];
176
+ shade?: string;
177
+ tint?: readonly [number, number, number];
178
+ /** Tested in order: a point belongs to the first region whose field is <= 0. */
179
+ regions?: readonly {
180
+ field: string;
181
+ surface: number;
182
+ material: number;
183
+ }[];
184
+ fallback: {
185
+ surface: number;
186
+ material: number;
187
+ };
188
+ materials: number;
189
+ }
190
+ export type SolidRecipe = {
191
+ kind: 'box';
192
+ x: number;
193
+ z: number;
194
+ halfX: number;
195
+ halfZ: number;
196
+ yaw?: number;
197
+ bottom: number;
198
+ top: number;
199
+ frame?: Frame;
200
+ } | {
201
+ kind: 'circle';
202
+ x: number;
203
+ z: number;
204
+ radius: number;
205
+ bottom: number;
206
+ top: number;
207
+ frame?: Frame;
208
+ } | {
209
+ kind: 'hull';
210
+ template: number;
211
+ x: number;
212
+ y: number;
213
+ z: number;
214
+ scale: readonly [number, number, number];
215
+ yaw?: number;
216
+ frame?: Frame;
217
+ };
218
+ export type ScatterFilter = {
219
+ kind: 'field';
220
+ field: string;
221
+ min?: number;
222
+ max?: number;
223
+ } | {
224
+ kind: 'walkable';
225
+ radius: number;
226
+ } | {
227
+ kind: 'surface';
228
+ surfaces: readonly number[];
229
+ } | {
230
+ kind: 'spawn';
231
+ minDistance: number;
232
+ };
233
+ export type ItemSolid = {
234
+ kind: 'none';
235
+ } | {
236
+ kind: 'circle';
237
+ radius: string;
238
+ bottom: string;
239
+ top: string;
240
+ } | {
241
+ kind: 'hull';
242
+ template: string;
243
+ scale: Three;
244
+ y: string;
245
+ yaw: string;
246
+ };
247
+ export interface ScatterLayer {
248
+ name: string;
249
+ count: number;
250
+ randoms?: number;
251
+ /** Layers with the same salt draw the same random values (paired scenery); by default each step has its own. */
252
+ salt?: number;
253
+ source?: 'none' | 'reachable' | {
254
+ anchors: readonly (readonly number[])[];
255
+ };
256
+ frame?: Frame;
257
+ x: string;
258
+ z: string;
259
+ filters?: readonly ScatterFilter[];
260
+ y: string;
261
+ attributes?: readonly string[];
262
+ solid?: {
263
+ variant?: string;
264
+ shapes: readonly ItemSolid[];
265
+ };
266
+ }
267
+ export type WorldStep = {
268
+ kind: 'spawn';
269
+ near: readonly [number, number];
270
+ rings: number;
271
+ samples: number;
272
+ radius: number;
273
+ surfaces?: readonly number[];
274
+ } | ({
275
+ kind: 'scatter';
276
+ } & ScatterLayer) | {
277
+ kind: 'reach';
278
+ cell: number;
279
+ steps: number;
280
+ radius: number;
281
+ extent: number;
282
+ } | {
283
+ kind: 'pick';
284
+ groups: readonly {
285
+ name: string;
286
+ count: number;
287
+ spacing: number;
288
+ fromSpawn?: number;
289
+ }[];
290
+ attempts?: number;
291
+ } | {
292
+ kind: 'overview';
293
+ size: number;
294
+ extent: number;
295
+ };
296
+ export interface WorldRecipe {
297
+ seed: number;
298
+ /** Turns the local frame (fields, platforms, local solids) into the world. */
299
+ rotation?: number;
300
+ fields: FieldGraph;
301
+ terrain: TerrainRecipe;
302
+ platforms?: readonly {
303
+ x: number;
304
+ z: number;
305
+ halfX: number;
306
+ halfZ: number;
307
+ y: number;
308
+ surface: number;
309
+ }[];
310
+ /** Mesh recipes whose convex hulls are solid templates (rendered rocks block exactly their outline). */
311
+ templates?: readonly MeshRecipe[];
312
+ solids?: readonly SolidRecipe[];
313
+ walk: {
314
+ boundary: number;
315
+ clearance: string;
316
+ footprint?: number;
317
+ step?: readonly [number, number];
318
+ height: number;
319
+ lift?: number;
320
+ cell?: number;
321
+ };
322
+ steps: readonly WorldStep[];
323
+ }
324
+ export interface WorldOptions {
325
+ /** Saves the world under this storage key, and restores one saved there from the same recipe. */
326
+ key?: string;
327
+ /** Also builds the terrain meshes (on the build's thread with `generateWorldAsync`). */
328
+ prepareTerrain?: boolean;
329
+ }
330
+ export interface Spot {
331
+ x: number;
332
+ z: number;
333
+ }
334
+ /** A generated world held by the native core; queries take world coordinates. */
335
+ export declare class ProceduralWorld {
336
+ readonly handle: number;
337
+ readonly spawn: Spot;
338
+ /** True when it was restored from storage rather than generated. */
339
+ readonly restored: boolean;
340
+ readonly layers: Readonly<Record<string, {
341
+ stride: number;
342
+ count: number;
343
+ }>>;
344
+ picks: Record<string, Spot[]>;
345
+ private fields;
346
+ private disposed;
347
+ constructor(handle: number);
348
+ private get id();
349
+ /** A scatter layer's items: [x, y, z, ...attributes] per item (see `layers[name].stride`). */
350
+ layer(name: string): Float64Array;
351
+ /** Reachable cells as [x, z] pairs. */
352
+ reachable(): Float64Array;
353
+ /** The overview step's surface codes, row by row (0 outside the walk boundary). */
354
+ overview(): Uint8Array;
355
+ /** Re-picks the spots for run `run` (0 = as generated); false keeps the previous ones. */
356
+ pick(run: number): boolean;
357
+ /** The terrain mesh of `material` (built once; each material is handed over once). */
358
+ terrain(material: number): MeshGeometry;
359
+ ground(x: number, z: number): number;
360
+ surface(x: number, z: number): number;
361
+ /** The platform (recipe index) under a point, or -1. */
362
+ platformAt(x: number, z: number): number;
363
+ walkable(x: number, z: number, radius: number): boolean;
364
+ /** How far a walker of `radius` is from anything blocking it (negative when blocked). */
365
+ clearance(x: number, z: number, radius: number): number;
366
+ solidClearance(x: number, z: number, radius: number, bottom: number, top: number): number;
367
+ /** A named field of the recipe at a world point. */
368
+ field(name: string, x: number, z: number): number;
369
+ /** The ground's tilt as a quaternion [x, y, z, w], in a frame turned by `yaw`. */
370
+ tilt(x: number, z: number, yaw?: number): [number, number, number, number];
371
+ /** Whether a walker of `radius` could walk straight from a to b, ends at most `rise` apart in height. */
372
+ canSee(a: Spot, b: Spot, { radius, step, rise }?: {
373
+ radius?: number;
374
+ step?: number;
375
+ rise?: number;
376
+ }): boolean;
377
+ /** Sweeps a walker by (dx, dz), sliding along obstacles and other `bodies`; updates `point`. */
378
+ move(point: Spot, dx: number, dz: number, radius: number, bodies?: readonly (Spot & {
379
+ radius: number;
380
+ })[]): void;
381
+ dispose(): void;
382
+ }
383
+ /** Generates (or restores, see `WorldOptions.key`) a world on this thread. */
384
+ export declare function generateWorld(recipe: WorldRecipe, options?: WorldOptions): ProceduralWorld;
385
+ /** `generateWorld` on a background native thread (the web core builds at once). */
386
+ export declare function generateWorldAsync(recipe: WorldRecipe, options?: WorldOptions): Promise<ProceduralWorld>;
387
+ /** Whether a world was saved under `key` (cheap: doesn't read the world). */
388
+ export declare function isWorldKept(key: string): boolean;
389
+ /** Builds a procedural mesh (parametric surfaces and seeded cards) in the native core. */
390
+ export declare function generateMesh(recipe: MeshRecipe): MeshGeometry;
391
+ /** Recolors geometry in place (and returns it) by a `surfaceColor`, in the native core. */
392
+ export declare function paintGeometry<G extends MeshGeometry>(geometry: G, color: FieldFunction): G;
393
+ export {};
394
+ //# sourceMappingURL=procedural.d.ts.map
@@ -3,6 +3,7 @@ import { type Shape, type Vec3 } from '../types.js';
3
3
  import type { Color, Quat } from '../world/types.js';
4
4
  import { type Model } from './model.js';
5
5
  import type { OptimizeOptions } from './modelling.js';
6
+ import { FieldFunction } from './procedural.js';
6
7
  type P2 = [number, number];
7
8
  /**
8
9
  * A 2D outline, built like an SVG path: x right, y down. Solids made from it
@@ -87,10 +88,13 @@ export type SurfacePoint = {
87
88
  position: Vec3;
88
89
  normal: Vec3;
89
90
  };
90
- /** A flat color, or one per point of the surface: blushes, stripes, speckles, spots. */
91
- export type SurfaceColor = Color | ((p: SurfacePoint) => Color);
92
- /** A flat color, or one per point of a round face: `r` from its center (0) to its rim (1), `angle` around it. */
93
- export type FaceColor = Color | ((r: number, angle: number) => Color);
91
+ /**
92
+ * A flat color, or one per point of the surface: blushes, stripes, speckles, spots. Prefer a
93
+ * `surfaceColor` field function (evaluated by the native core) to a JS function for detailed models.
94
+ */
95
+ export type SurfaceColor = Color | ((p: SurfacePoint) => Color) | FieldFunction;
96
+ /** A flat color, or one per point of a round face (`faceColor`): `r` from its center (0) to its rim (1), `angle` around it. */
97
+ export type FaceColor = Color | ((r: number, angle: number) => Color) | FieldFunction;
94
98
  export type LatheOptions = {
95
99
  /** Steps around the axis. Default 32. */
96
100
  segments?: number;
@@ -103,7 +107,7 @@ export type LatheOptions = {
103
107
  * ribs, ridges, bumps. Normals are recomputed so the bumps catch the light. Make it repeat in u
104
108
  * (equal at u = 0 and 1) to avoid a seam.
105
109
  */
106
- displace?: (u: number, v: number) => number;
110
+ displace?: ((u: number, v: number) => number) | FieldFunction;
107
111
  /** Color of the flat ends where the profile stops away from the axis (the face of a fruit cut across). Default `color`. */
108
112
  capColor?: FaceColor;
109
113
  /** Rings across each end cap, for patterned `capColor`. Default 1, or 12 for a function. */
@@ -112,7 +116,7 @@ export type LatheOptions = {
112
116
  * Color of the faces where a partial sweep is cut open (the flesh of a fruit cut through its core).
113
117
  * As a function: `r` from the axis (0) to the skin (1) at that height, and the height `y`. Default `color`.
114
118
  */
115
- cutColor?: Color | ((r: number, y: number) => Color);
119
+ cutColor?: Color | ((r: number, y: number) => Color) | FieldFunction;
116
120
  /** Steps from the axis to the skin across each cut face, for a detailed `cutColor`. Default 12 for a function. */
117
121
  cutSteps?: number;
118
122
  };
@@ -120,7 +124,9 @@ export type LatheOptions = {
120
124
  * Recolors geometry point by point (in place, and returned): two-tone leaves, painted tips, stripes on
121
125
  * an extrusion. `u` and `v` are the texture coordinates there.
122
126
  */
123
- export declare function recolor(geometry: Geometry, color: (p: SurfacePoint) => Color): Geometry;
127
+ export declare function recolor(geometry: Geometry, color: ((p: SurfacePoint) => Color) | FieldFunction): Geometry;
128
+ /** Builds a sweep (lathe, tube or loft) part in the native core. */
129
+ export declare function nativeSweep(part: Record<string, unknown>): Geometry;
124
130
  /**
125
131
  * Recomputes corner-angle-weighted normals in place, welding UV seams and poles at 1e-5 units.
126
132
  * Uses Rust when available. Call on a sculpted surface before merging caps or other hard edges:
@@ -1,3 +1,5 @@
1
+ import type { Light } from '../types.js';
2
+ import { type ColorInput } from '../world/color.js';
1
3
  import type { AssetSource } from './source';
2
4
  /** A loaded image. Pass it as an entity's `texture`. */
3
5
  export type Texture = {
@@ -27,4 +29,65 @@ export declare function textureImage(id: number): TextureImage;
27
29
  * (it shares the geometry, colliders and picking of the original).
28
30
  */
29
31
  export declare function texturedMesh(mesh: number, texture: Texture): number;
32
+ export type BakeOptions = {
33
+ /** The picture's width and height in pixels: about the size it's shown at (textures have no mipmaps). */
34
+ size: number;
35
+ /** The scene's light, as passed to `GameView`: the picture is shaded as the model would be. */
36
+ light: Light;
37
+ /** The scene's background, which glossy models reflect. Default black. */
38
+ background?: ColorInput;
39
+ /** Glossiness 0..1. Default: the model's own (its `createShape` shine). */
40
+ shine?: number;
41
+ /** Samples per pixel along each side, for smooth edges. Default 4. */
42
+ supersample?: number;
43
+ /** Empty margin around the model, as a fraction of its larger side. Default 0.04. */
44
+ padding?: number;
45
+ /**
46
+ * Draw several models together (a tile and the fruit on it) instead of `model` alone: each scaled
47
+ * then moved (no rotation), tinted and glossy as an entity would be.
48
+ */
49
+ parts?: readonly BakePart[];
50
+ /** The square of x/y to draw, instead of one around the models (with `padding`). */
51
+ frame?: {
52
+ center: [x: number, y: number];
53
+ extent: number;
54
+ };
55
+ /**
56
+ * Keep the picture in the engine's cache under this key (a `ProceduralCache.storageKey`, so app
57
+ * updates rebake it), and restore it from there: check `isBakeKept(key)` to skip building the models.
58
+ */
59
+ key?: string;
60
+ };
61
+ /** One model in a bake. */
62
+ export type BakePart = {
63
+ model: {
64
+ readonly id: number;
65
+ } | number;
66
+ position?: readonly [number, number, number];
67
+ scale?: number | readonly [number, number, number];
68
+ color?: ColorInput;
69
+ /** Glossiness 0..1. Default: the model's own. */
70
+ shine?: number;
71
+ };
72
+ /** A model's baked picture: its texture, and the square of the model's x/y it covers. */
73
+ export type BakedModel = {
74
+ texture: Texture;
75
+ /** The square's centre, in model units. */
76
+ center: [x: number, y: number];
77
+ /** Half the square's side, in model units. */
78
+ extent: number;
79
+ };
80
+ /**
81
+ * Draws a model once, in the native core, into an anti-aliased picture with a transparent
82
+ * background: seen from +z (orthographic), shaded as the renderer shades it under `light`. Show it
83
+ * instead of the model where it only ever faces the camera (icons, tiles, cards): on the built-in
84
+ * `"plane"` turned to face +z, scaled to `2 * extent`, under a `frontLight` (which shows camera-facing
85
+ * surfaces at exactly their color), with an alpha just below 1 so its soft edges blend. One quad
86
+ * then draws what took thousands of triangles, with smooth edges at every quality level.
87
+ */
88
+ export declare function bakeModel(model: {
89
+ readonly id: number;
90
+ } | number | null, options: BakeOptions): BakedModel;
91
+ /** Whether a picture was kept under `key` by `bakeModel` (so it can be restored without its models). */
92
+ export declare function isBakeKept(key: string): boolean;
30
93
  //# sourceMappingURL=texture.d.ts.map
@@ -16,20 +16,26 @@ export { loadModel } from './assets/model.js';
16
16
  export { clearAssetCache } from './assets/AssetCache.js';
17
17
  export { ProceduralCache, type ProceduralStorage } from './assets/ProceduralCache.js';
18
18
  export type { Model, ModelOptions, ModelClip, LoadedModel } from './assets/model.js';
19
- export { loadTexture } from './assets/texture.js';
19
+ export { bakeModel, isBakeKept, loadTexture } from './assets/texture.js';
20
20
  export { Solid, solidGeometry, createSolid, optimizeGeometry, createGeometryLods, getGeometryStats, deformGeometry } from './assets/modelling.js';
21
21
  export type { DisplacementOptions, SolidOptions, OptimizeOptions, GeometryStats } from './assets/modelling.js';
22
22
  export { loft, block, ellipsoid, smoothCurve } from './assets/loft.js';
23
23
  export type { LoftSection, LoftOptions } from './assets/loft.js';
24
24
  export { parametricSurface } from './assets/surface.js';
25
+ export { faceColor, FieldFunction, FieldGraph, FieldRef, generateMesh, generateWorld, generateWorldAsync, isWorldKept, ProceduralWorld, sectionColor, surfaceColor, surfaceDisplacement } from './assets/procedural.js';
26
+ export type { FieldInput, FieldShape, ItemSolid, MeshPart, MeshRecipe, ScatterFilter, ScatterLayer, SolidRecipe, Spot, TerrainRecipe, WorldOptions, WorldRecipe, WorldStep } from './assets/procedural.js';
25
27
  export type { ParametricSurfaceOptions } from './assets/surface.js';
26
- export type { Texture } from './assets/texture.js';
28
+ export type { BakedModel, BakeOptions, BakePart, Texture } from './assets/texture.js';
27
29
  export { createShape, extrude, lathe, merge, Path, recolor, shapeGeometry, smoothNormals, tube } from './assets/shape.js';
28
30
  export type { ExtrudeOptions, FaceColor, Geometry, LatheOptions, GeometryPart, ShapeOptions, SurfaceColor, SurfacePoint, TubeOptions } from './assets/shape.js';
29
31
  export { loadFont, measureText } from './assets/font.js';
30
32
  export type { Font, FontOptions, TextAlign, TextLayout } from './assets/font.js';
31
33
  export { audio } from './media/audio.js';
32
34
  export type { AudioPlayOptions, Sound, SoundBank, SoundSource, Voice } from './media/audio.js';
35
+ export { speech } from './media/speech.js';
36
+ export type { SpeechOptions, SpeechVoice } from './media/speech.js';
37
+ export { microphone } from './media/microphone.js';
38
+ export type { MicrophoneOptions, MicrophonePermission, MicrophoneState, Recording, TakeOptions } from './media/microphone.js';
33
39
  export { haptics } from './media/haptics.js';
34
40
  export type { HapticTap } from './media/haptics.js';
35
41
  export { Joystick, useJoystick } from './input/Joystick';
@@ -35,6 +35,19 @@ export declare const audio: {
35
35
  /** Plays a sound (low latency: mixed in Rust on the audio thread). Returns null if it couldn't play. */
36
36
  play(sound: Sound, { volume: v, pan, pitch, loop }?: AudioPlayOptions): Voice | null;
37
37
  stop(voice: Voice | null | undefined): void;
38
+ /**
39
+ * Frees a sound's samples, for sounds made at runtime (a `microphone.take` recording, once played).
40
+ * Its id then plays nothing; voices already playing it finish first. Don't release a bank's sounds.
41
+ */
42
+ release(sound: Sound | null | undefined): void;
43
+ /** A sound's length in seconds (0 if unknown or released). */
44
+ duration(sound: Sound): number;
45
+ /**
46
+ * A sound's loudness (RMS, 0..1) over time, one value per `1 / perSecond` seconds from its start:
47
+ * drive a talking mouth, a bobbing body or a meter from it while the sound plays (at `pitch` p,
48
+ * value i plays at i / (perSecond * p) seconds).
49
+ */
50
+ levels(sound: Sound, perSecond?: number): Float32Array;
38
51
  muted: boolean;
39
52
  /** The inverse of `muted`, matching `haptics.enabled` (e.g. `audio.enabled = settings.enableSounds`). */
40
53
  enabled: boolean;
@@ -0,0 +1,4 @@
1
+ import type { WasmCore } from '../native/BrowserEngine.js';
2
+ import type { EngineBridge } from '../native/EngineBridge.js';
3
+ export declare function installMicrophoneInput(core: WasmCore, bridge: EngineBridge): void;
4
+ //# sourceMappingURL=input.web.d.ts.map
@@ -0,0 +1,51 @@
1
+ import type { Sound } from './audio.js';
2
+ export type MicrophoneState = 'off' | 'starting' | 'listening' | 'failed';
3
+ export type MicrophonePermission = 'granted' | 'undetermined' | 'denied';
4
+ /** What `microphone.take` returns: a sound to play, how long it lasts and its loudness over time. */
5
+ export type Recording = {
6
+ sound: Sound;
7
+ /** Seconds at pitch 1. */
8
+ duration: number;
9
+ /** RMS loudness, `levelsPerSecond` values a second (see `audio.levels`). */
10
+ levels: Float32Array;
11
+ levelsPerSecond: number;
12
+ };
13
+ export type MicrophoneOptions = {
14
+ /** Seconds of input kept (0.5..30). Default 10. */
15
+ maxSeconds?: number;
16
+ };
17
+ export type TakeOptions = {
18
+ /** Leave out the last `skipEnd` seconds (the silence after someone stops talking). Default 0. */
19
+ skipEnd?: number;
20
+ /** Loudness values per second in `levels`. Default 30. */
21
+ levelsPerSecond?: number;
22
+ };
23
+ export declare const microphone: {
24
+ /** Whether this engine build can record (false on older app builds and without a native module). */
25
+ readonly supported: boolean;
26
+ /** Whether the app may record. On Android, 'undetermined' also covers a denial (it can't tell). */
27
+ readonly permission: MicrophonePermission;
28
+ /** Shows the system prompt the first time (answering at once after that); true if recording is allowed. */
29
+ requestPermission(): Promise<boolean>;
30
+ /** Starts listening (asynchronously: see `state`). Ask for the permission first. */
31
+ start({ maxSeconds }?: MicrophoneOptions): boolean;
32
+ /** Stops listening and releases the microphone (its system indicator turns off); forgets what was heard. */
33
+ stop(): void;
34
+ /** 'failed' when there's no microphone, no permission or the input couldn't open. */
35
+ readonly state: MicrophoneState;
36
+ /**
37
+ * How loud the input is now: 0 at -60 dBFS or quieter, 1 at full scale; speech close to a phone
38
+ * is usually 0.4..0.8, a quiet room under 0.3. Rises at once and falls back over ~0.15 s. Cheap
39
+ * enough to read every frame.
40
+ */
41
+ readonly level: number;
42
+ /** Seconds of input held (up to `maxSeconds`), since starting or the last `take`. */
43
+ readonly held: number;
44
+ /**
45
+ * The last `seconds` of input (ending `skipEnd` seconds ago) as a new Sound, and forgets
46
+ * everything heard so far so the next take starts fresh. Null if nothing was heard. Release the
47
+ * sound with `audio.release` once it has played: each take holds its samples until then.
48
+ */
49
+ take(seconds?: number, { skipEnd, levelsPerSecond }?: TakeOptions): Recording | null;
50
+ };
51
+ //# sourceMappingURL=microphone.d.ts.map
@@ -0,0 +1,38 @@
1
+ export type SpeechOptions = {
2
+ /** BCP 47 language tag, such as en-US or hi-IN. Defaults to the system language. */
3
+ language?: string;
4
+ /** Identifier returned by getAvailableVoicesAsync. */
5
+ voice?: string;
6
+ /** Speed relative to the platform default, 0.1..2. Default 1. */
7
+ rate?: number;
8
+ /** Pitch multiplier, 0.5..2. Default 1. */
9
+ pitch?: number;
10
+ /** Loudness, 0..1. Default 1. */
11
+ volume?: number;
12
+ };
13
+ export type SpeechVoice = {
14
+ identifier: string;
15
+ name: string;
16
+ language: string;
17
+ quality: 'Default' | 'Enhanced';
18
+ };
19
+ /** System text-to-speech. Independent of the engine mixer, microphone and asset loading. */
20
+ export declare const speech: {
21
+ /** API availability; installed voices and Android TTS initialization may still fail. */
22
+ readonly supported: boolean;
23
+ /**
24
+ * Queues text using the system synthesizer. Resolves when queued, not when speech finishes.
25
+ * No audio files are created. Call stop on leaving a screen to cancel its queued speech.
26
+ */
27
+ speak(text: string, options?: SpeechOptions): Promise<void>;
28
+ /** Stops current speech and clears the entire speech queue. */
29
+ stop(): Promise<void>;
30
+ /** iOS and web only; rejects on Android, which has no system pause API. */
31
+ pause(): Promise<void>;
32
+ /** iOS and web only; rejects on Android. */
33
+ resume(): Promise<void>;
34
+ /** Includes speech paused on iOS/web. */
35
+ isSpeakingAsync(): Promise<boolean>;
36
+ getAvailableVoicesAsync(): Promise<SpeechVoice[]>;
37
+ };
38
+ //# sourceMappingURL=speech.d.ts.map
@@ -0,0 +1,5 @@
1
+ export declare const speechPlatform: {
2
+ readonly supported: boolean;
3
+ request(command: string): Promise<string>;
4
+ };
5
+ //# sourceMappingURL=speechPlatform.d.ts.map