phoria2 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +70 -13
  2. package/dist/bloom.js +4 -4
  3. package/dist/bloom.js.map +1 -1
  4. package/dist/charts.js +538 -508
  5. package/dist/charts.js.map +1 -1
  6. package/dist/core.js +4270 -3652
  7. package/dist/core.js.map +1 -1
  8. package/dist/edit.js +65 -65
  9. package/dist/edit.js.map +1 -1
  10. package/dist/explain.js +6 -2
  11. package/dist/explain.js.map +1 -1
  12. package/dist/gltf.js +116 -116
  13. package/dist/gltf.js.map +1 -1
  14. package/dist/keyboard.js +188 -0
  15. package/dist/keyboard.js.map +1 -0
  16. package/dist/motion.js +35 -35
  17. package/dist/motion.js.map +1 -1
  18. package/dist/particles.js +188 -115
  19. package/dist/particles.js.map +1 -1
  20. package/dist/passes.js +29 -29
  21. package/dist/passes.js.map +1 -1
  22. package/dist/phoria2.js +1 -1
  23. package/dist/picking.js +32 -16
  24. package/dist/picking.js.map +1 -1
  25. package/dist/snapshot.js +1 -1
  26. package/dist/tooltip.js +1 -1
  27. package/dist/types/OrbitControl.d.ts +6 -2
  28. package/dist/types/Raycaster.d.ts +10 -0
  29. package/dist/types/View.d.ts +70 -1
  30. package/dist/types/area.d.ts +18 -0
  31. package/dist/types/charts/Chart.d.ts +7 -0
  32. package/dist/types/explain.d.ts +3 -0
  33. package/dist/types/frame.d.ts +7 -0
  34. package/dist/types/geometry/Geometry.d.ts +24 -2
  35. package/dist/types/index.d.ts +2 -0
  36. package/dist/types/keyboard.d.ts +48 -0
  37. package/dist/types/labels.d.ts +4 -0
  38. package/dist/types/material/Material.d.ts +15 -0
  39. package/dist/types/material/Texture.d.ts +18 -2
  40. package/dist/types/particles/Emitter.d.ts +39 -2
  41. package/dist/types/scene/Node.d.ts +19 -14
  42. package/dist/types/scene/drawables.d.ts +54 -15
  43. package/dist/types/scene/lights.d.ts +16 -2
  44. package/dist/types/shadow.d.ts +2 -1
  45. package/dist/types/types.d.ts +14 -0
  46. package/dist/types/value/Color.d.ts +0 -4
  47. package/dist/types/value/Quat.d.ts +4 -2
  48. package/dist/types/webgl/resources.d.ts +12 -2
  49. package/dist/types/webgl/shaders.d.ts +7 -2
  50. package/llms-full.txt +106 -10
  51. package/package.json +4 -1
  52. package/schema/scene.schema.json +67 -1
  53. package/src/OrbitControl.js +7 -3
  54. package/src/Raycaster.js +58 -0
  55. package/src/View.js +220 -41
  56. package/src/area.js +131 -0
  57. package/src/charts/Chart.js +20 -2
  58. package/src/charts/marks.js +29 -2
  59. package/src/explain.js +6 -2
  60. package/src/frame.js +29 -9
  61. package/src/geometry/Geometry.js +32 -4
  62. package/src/index.js +1 -0
  63. package/src/keyboard.js +298 -0
  64. package/src/labels.js +4 -1
  65. package/src/material/Material.js +9 -2
  66. package/src/material/Texture.js +55 -2
  67. package/src/particles/Emitter.js +121 -10
  68. package/src/scene/Node.js +20 -9
  69. package/src/scene/Scene.js +2 -0
  70. package/src/scene/cameras.js +4 -1
  71. package/src/scene/drawables.js +115 -15
  72. package/src/scene/lights.js +40 -6
  73. package/src/shadow.js +27 -4
  74. package/src/types.js +6 -0
  75. package/src/value/Color.js +21 -0
  76. package/src/value/Quat.js +15 -6
  77. package/src/watch.js +14 -2
  78. package/src/webgl/WebGLRenderer.js +36 -5
  79. package/src/webgl/picking.js +22 -1
  80. package/src/webgl/resources.js +168 -14
  81. package/src/webgl/shaders.js +110 -11
@@ -16,6 +16,7 @@ import type { ToneMapping, BloomOptions } from './webgl/WebGLRenderer.js';
16
16
  import type { CameraOptions } from './scene/cameras.js';
17
17
  import type { ColorInput, Vec3Input } from './types.js';
18
18
  import type { Node } from './scene/Node.js';
19
+ import type { KeyboardOptions } from './keyboard.js';
19
20
  export type RenderMode = 'auto' | 'always' | 'manual';
20
21
  export type ViewOptions = {
21
22
  /**
@@ -106,6 +107,24 @@ export type ViewOptions = {
106
107
  * longest frame step in seconds, so a background tab doesn't jump (default 0.1)
107
108
  */
108
109
  maxDelta?: number;
110
+ /**
111
+ * cut motion short, for people it makes unwell: frame() jumps rather
112
+ * than glides, auto-rotation holds, and charts change at once with their flows still. Default 'auto': as the
113
+ * system's setting (prefers-reduced-motion), followed as it changes
114
+ */
115
+ reducedMotion?: 'auto' | boolean;
116
+ /**
117
+ * use without a pointer: the canvas joins the page's tab order, and
118
+ * the arrow keys step through what can be hovered or clicked - each with the hover tint, the tooltip and hover
119
+ * handlers - with Enter or Space to click and Escape to leave. A screen reader hears each one. { label: (hit) =>
120
+ * text } says what it hears (default: the tooltip's text, the data, or the name). Default false
121
+ */
122
+ keyboard?: boolean | KeyboardOptions;
123
+ /**
124
+ * what the view shows, for screen readers: the canvas's label. With keyboard
125
+ * on and no description, one is made from the scene (charts describe themselves)
126
+ */
127
+ description?: string | null;
109
128
  };
110
129
  export type ViewEvent = 'click' | 'hover';
111
130
  export type ViewHandler = (hit: Hit | null, event: PointerEvent | MouseEvent | null) => void;
@@ -168,6 +187,22 @@ export declare class View {
168
187
  get highlight(): Color | null;
169
188
  /** @param {ColorInput | null} v */
170
189
  set highlight(v: ColorInput | null);
190
+ /**
191
+ * Is motion cut short - glides, auto-rotation, chart transitions? Set true or false, or 'auto' (the
192
+ * default) to follow the system's setting. Read it for motion of your own, such as a timeline.
193
+ * @returns {boolean}
194
+ */
195
+ get reducedMotion(): boolean;
196
+ /** @param {'auto' | boolean} v */
197
+ set reducedMotion(v: 'auto' | boolean);
198
+ /**
199
+ * What the view shows, for screen readers - the canvas's label - or null. With keyboard on and no
200
+ * description, one is made from the scene.
201
+ * @returns {string | null}
202
+ */
203
+ get description(): string | null;
204
+ /** @param {string | null} v */
205
+ set description(v: string | null);
171
206
  /** Canvas width in CSS pixels. */
172
207
  get width(): number;
173
208
  /** Canvas height in CSS pixels. */
@@ -220,7 +255,8 @@ export declare class View {
220
255
  * @param {Node | Box3} [target] (default the scene)
221
256
  * @param {{ padding?: number, direction?: CameraPreset | Vec3Input, duration?: number }} [options] padding is
222
257
  * the margin around it, as a fraction of its size: 0 is a tight fit, 0.2 (the default) leaves a fifth.
223
- * duration is in seconds (default 0: straight there); a press or the wheel stops the glide
258
+ * duration is in seconds (default 0: straight there); a press or the wheel stops the glide, and with
259
+ * reducedMotion it goes straight there
224
260
  * @returns {this}
225
261
  */
226
262
  frame(target?: Node | Box3, { padding, direction: towards, duration }?: {
@@ -228,6 +264,28 @@ export declare class View {
228
264
  direction?: CameraPreset | Vec3Input;
229
265
  duration?: number;
230
266
  }): this;
267
+ /**
268
+ * Where frame() would put the camera, without moving it: its position, target and - for an
269
+ * orthographic camera - height, or null when there is nothing to frame. For a camera of your own
270
+ * that eases after something moving rather than jumping each frame:
271
+ *
272
+ * const aim = view.framing(debris)
273
+ * if (aim) {
274
+ * view.camera.position.lerp(aim.position, 0.1)
275
+ * view.camera.target.lerp(aim.target, 0.1)
276
+ * }
277
+ * @param {Node | Box3} [target] (default the scene)
278
+ * @param {{ padding?: number, direction?: CameraPreset | Vec3Input }} [options] as frame()
279
+ * @returns {{ position: Vec3, target: Vec3, height?: number } | null}
280
+ */
281
+ framing(target?: Node | Box3, { padding, direction }?: {
282
+ padding?: number;
283
+ direction?: CameraPreset | Vec3Input;
284
+ }): {
285
+ position: Vec3;
286
+ target: Vec3;
287
+ height?: number;
288
+ } | null;
231
289
  /**
232
290
  * The nearest hit under a canvas position - CSS pixels from the canvas's top left, or a pointer
233
291
  * event. Found on the GPU from the last frame drawn (one pass, however many instances), then made
@@ -281,6 +339,17 @@ export declare class View {
281
339
  width: number;
282
340
  height: number;
283
341
  } | null;
342
+ /**
343
+ * Everything inside an area of the canvas, nearest first: a box `{ x, y, width, height }` or a
344
+ * lasso of `[x, y]` points, CSS pixels from the canvas's top left. Each point, instance and line
345
+ * segment is its own hit, found by where it is (a mesh by its middle) - hidden behind others or
346
+ * not - so a box dragged over a scatter selects that region of it.
347
+ *
348
+ * const picked = view.pickArea({ x: 40, y: 30, width: 200, height: 120 }).map((h) => h.datum)
349
+ * @param {import('./area.js').PickArea} area
350
+ * @returns {Hit[]}
351
+ */
352
+ pickArea(area: import('./area.js').PickArea): Hit[];
284
353
  /** Every hit under a canvas position, nearest first. @param {number | MouseEvent} x @param {number} [y] @returns {Hit[]} */
285
354
  pickAll(x: number | MouseEvent, y?: number): Hit[];
286
355
  /**
@@ -0,0 +1,18 @@
1
+ import type { Hit } from './Raycaster.js';
2
+ import type { Node } from './scene/Node.js';
3
+ import type { Camera } from './scene/cameras.js';
4
+ export type PickArea = {
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ } | [number, number][];
10
+ /**
11
+ * Everything in the scene the camera shows, pickable, whose place falls inside the area - nearest
12
+ * the camera first.
13
+ * @param {Node} scene @param {Camera} camera @param {Float32Array} viewProjection
14
+ * @param {number} width @param {number} height the canvas, CSS pixels
15
+ * @param {PickArea} area
16
+ * @returns {Hit[]}
17
+ */
18
+ export declare function pickArea(scene: Node, camera: Camera, viewProjection: Float32Array, width: number, height: number, area: PickArea): Hit[];
@@ -45,6 +45,13 @@ export declare class Chart extends Group {
45
45
  filter(fn: ((row: any) => boolean) | null): this;
46
46
  /** One line about this chart, for view.explain(). */
47
47
  explain(): string;
48
+ /**
49
+ * One sentence about this chart for screen readers - the spec's description, or its title and what
50
+ * it shows: "Sales by month: bar chart of 12 rows by Month, Sales". A View with keyboard: true labels
51
+ * its canvas with this.
52
+ * @returns {string}
53
+ */
54
+ summary(): string;
48
55
  toJSON(): Record<string, unknown>;
49
56
  /** A new chart from the same spec and transform. @returns {any} */
50
57
  clone(): any;
@@ -36,6 +36,9 @@ export type ExplainInfo = {
36
36
  click: number;
37
37
  tooltip: boolean;
38
38
  highlight: boolean;
39
+ keyboard?: boolean;
40
+ reducedMotion?: boolean;
41
+ description?: string | null;
39
42
  };
40
43
  /**
41
44
  * lines from nodes that describe themselves, such as charts
@@ -146,6 +146,11 @@ export type FrameLabel = {
146
146
  * in front of the camera and inside the view
147
147
  */
148
148
  visible: boolean;
149
+ /**
150
+ * how far zoomed in at the point: half the view's height, in world units, is 1 / scale -
151
+ * the layer turns it into pixels to one world unit, for minScale
152
+ */
153
+ scale: number;
149
154
  };
150
155
  export type ShadowFrame = {
151
156
  light: FrameLight;
@@ -353,6 +358,8 @@ export type FrameDescription = {
353
358
  * @property {[number, number]} ndc [x, y] in -1..1
354
359
  * @property {number} depth
355
360
  * @property {boolean} visible in front of the camera and inside the view
361
+ * @property {number} scale how far zoomed in at the point: half the view's height, in world units, is 1 / scale -
362
+ * the layer turns it into pixels to one world unit, for minScale
356
363
  */
357
364
  /**
358
365
  * The shadow-casting directional light's view of the scene: what to draw into its depth map.
@@ -21,6 +21,19 @@ export type GeometryOptions = {
21
21
  * rgb per vertex, sRGB 0-1 like every colour input
22
22
  */
23
23
  colors?: ArrayLike<number>;
24
+ /**
25
+ * points: one per vertex, a multiple of the material's size
26
+ */
27
+ sizes?: ArrayLike<number>;
28
+ /**
29
+ * points: one per vertex, 0-1, multiplying the material's opacity
30
+ */
31
+ opacities?: ArrayLike<number>;
32
+ /**
33
+ * points: one per vertex, radians anticlockwise on screen - turns
34
+ * each point's texture
35
+ */
36
+ angles?: ArrayLike<number>;
24
37
  /**
25
38
  * vertex indices; triangles for meshes, pairs for lines
26
39
  */
@@ -38,6 +51,9 @@ export declare class Geometry {
38
51
  /** @type {Float32Array | null} */ uvs: Float32Array | null;
39
52
  /** A second UV set, for baked occlusion and light maps. @type {Float32Array | null} */ uvs2: Float32Array | null;
40
53
  /** @type {Float32Array | null} */ colors: Float32Array | null;
54
+ /** Points: each one's size, as a multiple of the material's. @type {Float32Array | null} */ sizes: Float32Array | null;
55
+ /** Points: each one's opacity, 0-1, times the material's. @type {Float32Array | null} */ opacities: Float32Array | null;
56
+ /** Points: each one's turn on screen, in radians anticlockwise. @type {Float32Array | null} */ angles: Float32Array | null;
41
57
  /** @type {Uint16Array | Uint32Array | null} */ indices: Uint16Array | Uint32Array | null;
42
58
  /**
43
59
  * Draw only the first `drawCount` vertices (indices, when indexed), or all of them when null -
@@ -56,7 +72,9 @@ export declare class Geometry {
56
72
  constructor(options: GeometryOptions);
57
73
  /**
58
74
  * xyz per vertex. Computed (smooth) from the triangles on first read when not supplied, so
59
- * points and lines - whose geometry has no triangles - never pay for them.
75
+ * points and lines - whose geometry has no triangles - never pay for them - and computed again after
76
+ * needsUpdate(), so they follow positions edited in place. Normals that were supplied, assigned or
77
+ * made by calling computeNormals() are kept as they are.
60
78
  * @type {Float32Array}
61
79
  */
62
80
  get normals(): Float32Array;
@@ -77,7 +95,11 @@ export declare class Geometry {
77
95
  get drawnVertices(): number;
78
96
  /** Local space bounds, cached until needsUpdate(). @returns {Box3} */
79
97
  get bounds(): Box3;
80
- /** Call after editing the arrays in place. It is no longer what its generator made, so toJSON() saves the arrays. @returns {this} */
98
+ /**
99
+ * Call after editing the arrays in place. It is no longer what its generator made, so toJSON() saves
100
+ * the arrays; normals that were worked out on first read are worked out again on the next.
101
+ * @returns {this}
102
+ */
81
103
  needsUpdate(): this;
82
104
  /**
83
105
  * Compute vertex normals from the triangles. Smooth normals average the faces sharing each vertex;
@@ -37,6 +37,7 @@ export type RenderMode = import('./View.js').RenderMode;
37
37
  export type CameraPreset = import('./presets.js').CameraPreset;
38
38
  export type TooltipContent = import('./tooltip.js').TooltipContent;
39
39
  export type Hit = import('./Raycaster.js').Hit;
40
+ export type PickArea = import('./area.js').PickArea;
40
41
  export type LabelPlacement = import('./scene/drawables.js').LabelPlacement;
41
42
  export type LabelPlace = import('./scene/drawables.js').LabelPlace;
42
43
  export type InstanceLabels = import('./scene/drawables.js').InstanceLabels;
@@ -49,6 +50,7 @@ export type ImageOptions = import('./snapshot.js').ImageOptions;
49
50
  /** @typedef {import('./presets.js').CameraPreset} CameraPreset */
50
51
  /** @typedef {import('./tooltip.js').TooltipContent} TooltipContent */
51
52
  /** @typedef {import('./Raycaster.js').Hit} Hit */
53
+ /** @typedef {import('./area.js').PickArea} PickArea */
52
54
  /** @typedef {import('./scene/drawables.js').LabelPlacement} LabelPlacement */
53
55
  /** @typedef {import('./scene/drawables.js').LabelPlace} LabelPlace */
54
56
  /** @typedef {import('./scene/drawables.js').InstanceLabels} InstanceLabels */
@@ -0,0 +1,48 @@
1
+ import type { Hit } from './Raycaster.js';
2
+ import type { TooltipContent } from './tooltip.js';
3
+ import type { Node } from './scene/Node.js';
4
+ import type { View } from './View.js';
5
+ export type KeyboardOptions = {
6
+ /**
7
+ * what a screen reader says for each thing stepped to (default: the
8
+ * tooltip's text, then its data, then the node's name)
9
+ */
10
+ label?: (hit: Hit) => string;
11
+ };
12
+ export type KeyboardHooks = {
13
+ /**
14
+ * show this as hovered, or nothing
15
+ */
16
+ focus: (hit: Hit | null) => void;
17
+ /**
18
+ * click it
19
+ */
20
+ press: (hit: Hit) => void;
21
+ /**
22
+ * the tooltip's content for it, if there is a tooltip
23
+ */
24
+ tooltip: (hit: Hit) => TooltipContent;
25
+ /**
26
+ * does the View itself answer hovers or clicks (a tooltip, handlers)?
27
+ */
28
+ viewWide: () => boolean;
29
+ };
30
+ export type Item = {
31
+ node: Node;
32
+ index: number | null;
33
+ whole: Node | null;
34
+ };
35
+ export declare class Keyboard {
36
+ #private;
37
+ /** @param {View} view @param {KeyboardHooks} hooks @param {KeyboardOptions} options */
38
+ constructor(view: View, hooks: KeyboardHooks, options: KeyboardOptions);
39
+ /**
40
+ * The canvas's label for screen readers: the View's description, or - when it has none - one made
41
+ * from the scene: what its charts show, and how many things there are to step through.
42
+ * @param {string | null} text
43
+ */
44
+ setDescription(text: string | null): void;
45
+ /** Step off whatever was stepped to: the pointer has taken over, or focus has gone. */
46
+ clear(): void;
47
+ dispose(): void;
48
+ }
@@ -18,6 +18,10 @@ export type LabelStats = {
18
18
  * behind the camera or outside the view
19
19
  */
20
20
  offscreen: number;
21
+ /**
22
+ * hidden because the view isn't zoomed in to their minScale
23
+ */
24
+ zoomedOut: number;
21
25
  };
22
26
  export type Entry = {
23
27
  el: HTMLDivElement;
@@ -211,6 +211,18 @@ export type MaterialOptions = {
211
211
  * Lines: width in pixels (default 1)
212
212
  */
213
213
  width?: number;
214
+ /**
215
+ * Lines: dashed, with dashes this long in the model's units; 0 is solid (default 0)
216
+ */
217
+ dash?: number;
218
+ /**
219
+ * Lines: the gaps between dashes; 0 is as long as the dashes (default 0)
220
+ */
221
+ gap?: number;
222
+ /**
223
+ * Lines: moves the dashes along the lines - animate it for flow (default 0)
224
+ */
225
+ dashOffset?: number;
214
226
  };
215
227
  /**
216
228
  * The one material: what a surface looks like. Plain objects passed as a `material` become
@@ -275,6 +287,9 @@ export declare class Material {
275
287
  /** @type {number} */ size: number;
276
288
  /** @type {boolean} */ sizeAttenuation: boolean;
277
289
  /** @type {number} */ width: number;
290
+ /** Lines: dash length in the model's units; 0 is solid. @type {number} */ dash: number;
291
+ /** Lines: gap length; 0 is the dash's. @type {number} */ gap: number;
292
+ /** Lines: how far the dashes have moved along. @type {number} */ dashOffset: number;
278
293
  /** @param {MaterialOptions} [options] */
279
294
  constructor(options?: MaterialOptions);
280
295
  /** Base colour; assign any colour input. @returns {Color} */
@@ -64,9 +64,15 @@ export type TextureOptions = {
64
64
  */
65
65
  flipY?: boolean;
66
66
  };
67
+ export type TextureRegion = {
68
+ x: number;
69
+ y: number;
70
+ width: number;
71
+ height: number;
72
+ };
67
73
  /**
68
74
  * An image for a material map. A video's frames upload by themselves as it plays; after drawing on
69
- * a canvas, call `needsUpdate()`.
75
+ * a canvas, call `needsUpdate()` - with the rectangle drawn in, to send only that.
70
76
  */
71
77
  export declare class Texture {
72
78
  #private;
@@ -114,7 +120,17 @@ export declare class Texture {
114
120
  /** 'srgb' for colour (decoded to linear by the GPU), 'linear' for data such as normals and roughness. Call needsUpdate() after changing it. @returns {'srgb' | 'linear'} */
115
121
  get colorSpace(): 'srgb' | 'linear';
116
122
  set colorSpace(v: 'srgb' | 'linear');
117
- needsUpdate(): this;
123
+ /**
124
+ * Upload the image again, after drawing on it (a canvas) or changing its pixels. Give the
125
+ * rectangle that changed - in the image's pixels, from its top left - and only that is sent: for a
126
+ * big canvas drawn on a little at a time, far less to send each frame.
127
+ *
128
+ * ctx.fillRect(x, y, 20, 20)
129
+ * texture.needsUpdate({ x, y, width: 20, height: 20 })
130
+ * @param {TextureRegion} [region]
131
+ * @returns {this}
132
+ */
133
+ needsUpdate(region?: TextureRegion): this;
118
134
  /** Release the GPU copy. @returns {void} */
119
135
  dispose(): void;
120
136
  /** A description (url plus options that differ from the defaults), or null for an in-memory image. */
@@ -61,6 +61,28 @@ export type EmitterOptions = NodeOptions & SpawnOptions & {
61
61
  frustumCulled?: boolean;
62
62
  renderOrder?: number;
63
63
  onParticle?: ((p: Particle) => boolean | void) | null;
64
+ sort?: boolean;
65
+ } & LookOptions;
66
+ export type LookOptions = {
67
+ /**
68
+ * a multiple of the material's size, or several each particle goes
69
+ * through over its life - [0.5, 3] for smoke that billows out (default 1)
70
+ */
71
+ size?: number | number[];
72
+ /**
73
+ * each particle's size varies by up to this share either way, 0-1 (default 0)
74
+ */
75
+ sizeSpread?: number;
76
+ /**
77
+ * 0-1, or several each particle goes through - [0, 1, 0] fades in
78
+ * and out (default 1)
79
+ */
80
+ opacity?: number | number[];
81
+ /**
82
+ * radians per second: a number turns each particle up to that
83
+ * fast either way, [min, max] a range. Spinning particles start at a random angle (default 0)
84
+ */
85
+ spin?: number | [number, number];
64
86
  };
65
87
  /**
66
88
  * Particles drawn as points. Add it to a scene and it runs itself.
@@ -102,11 +124,11 @@ export declare class Emitter extends Points {
102
124
  /**
103
125
  * Change several settings at once - a preset, say. Vectors are copied into the emitter's own,
104
126
  * so anything bound to `emitter.gravity` and friends stays bound. Live particles carry on.
105
- * @param {SpawnOptions & { rate?: number, gravity?: Vec3Input, drag?: number, follow?: Node | null,
127
+ * @param {SpawnOptions & LookOptions & { rate?: number, gravity?: Vec3Input, drag?: number, follow?: Node | null,
106
128
  * onParticle?: ((p: Particle) => boolean | void) | null }} options
107
129
  * @returns {this}
108
130
  */
109
- set(options: SpawnOptions & {
131
+ set(options: SpawnOptions & LookOptions & {
110
132
  rate?: number;
111
133
  gravity?: Vec3Input;
112
134
  drag?: number;
@@ -121,6 +143,21 @@ export declare class Emitter extends Points {
121
143
  set color(v: ColorInput | ColorInput[]);
122
144
  /** @returns {[number, number, number][]} */
123
145
  get color(): [number, number, number][];
146
+ /** Each particle's size over its life, as multiples of the material's. @param {number | number[]} v */
147
+ set size(v: number | number[]);
148
+ /** @returns {number[]} */
149
+ get size(): number[];
150
+ /** How much each particle's size varies, 0-1 either way. @param {number} v */
151
+ set sizeSpread(v: number);
152
+ get sizeSpread(): number;
153
+ /** Each particle's opacity over its life. @param {number | number[]} v */
154
+ set opacity(v: number | number[]);
155
+ /** @returns {number[]} */
156
+ get opacity(): number[];
157
+ /** How fast particles turn, radians per second, as a [min, max] range. @param {number | [number, number]} v */
158
+ set spin(v: number | [number, number]);
159
+ /** @returns {[number, number]} */
160
+ get spin(): [number, number];
124
161
  /**
125
162
  * Birth `count` particles at once - explosions, splashes. Options override the emitter's own
126
163
  * spawn settings for this burst only.
@@ -5,7 +5,7 @@ import { Mat4 } from '../value/Mat4.js';
5
5
  import { Quat } from '../value/Quat.js';
6
6
  import { Vec3 } from '../value/Vec3.js';
7
7
  import { Clip } from '../clip.js';
8
- import type { ColorInput, Vec3Input } from '../types.js';
8
+ import type { ColorInput, QuatInput, Vec3Input } from '../types.js';
9
9
  import type { Hit } from '../Raycaster.js';
10
10
  import type { Camera } from './cameras.js';
11
11
  import type { ClipOptions } from '../clip.js';
@@ -59,9 +59,9 @@ export type NodeOptions = {
59
59
  */
60
60
  rotation?: Vec3Input | Euler;
61
61
  /**
62
- * [x, y, z, w] - instead of rotation
62
+ * [x, y, z, w] or { x, y, z, w } - instead of rotation
63
63
  */
64
- quaternion?: ArrayLike<number>;
64
+ quaternion?: QuatInput;
65
65
  /**
66
66
  * a number scales uniformly
67
67
  */
@@ -87,9 +87,10 @@ export type NodeOptions = {
87
87
  */
88
88
  tooltip?: ((hit: Hit) => any) | null;
89
89
  /**
90
- * hover tint for this subtree, over the View's
90
+ * hover tint for this subtree, over the View's; false for none - a
91
+ * floor or wall left plain under a View that tints everything else (null: the View's)
91
92
  */
92
- highlight?: ColorInput | null;
93
+ highlight?: ColorInput | null | false;
93
94
  /**
94
95
  * hovering any part of this subtree tints all of it, as one thing - a
95
96
  * piece of furniture, a machine - rather than just the part under the pointer (default false)
@@ -127,7 +128,7 @@ export type NodeOptions = {
127
128
  */
128
129
  clip?: ClipOptions | Clip | null;
129
130
  };
130
- /** @import { ColorInput, Vec3Input } from '../types.js' */
131
+ /** @import { ColorInput, QuatInput, Vec3Input } from '../types.js' */
131
132
  /** @import { Hit } from '../Raycaster.js' */
132
133
  /** @import { Camera } from './cameras.js' */
133
134
  /** @import { ClipOptions } from '../clip.js' */
@@ -157,7 +158,7 @@ export type NodeOptions = {
157
158
  * @property {string} [name]
158
159
  * @property {Vec3Input} [position]
159
160
  * @property {Vec3Input | Euler} [rotation] Euler angles in radians, XYZ order
160
- * @property {ArrayLike<number>} [quaternion] [x, y, z, w] - instead of rotation
161
+ * @property {QuatInput} [quaternion] [x, y, z, w] or { x, y, z, w } - instead of rotation
161
162
  * @property {Vec3Input | number} [scale] a number scales uniformly
162
163
  * @property {boolean} [visible]
163
164
  * @property {boolean} [pickable] include in view.pick() (default true)
@@ -167,7 +168,8 @@ export type NodeOptions = {
167
168
  * @property {UpdateHandler | UpdateHandler[]} [onUpdate]
168
169
  * @property {((hit: Hit) => any) | null} [tooltip] tooltip for anything picked in this subtree; nearer nodes win, and
169
170
  * all win over the View's
170
- * @property {ColorInput | null} [highlight] hover tint for this subtree, over the View's
171
+ * @property {ColorInput | null | false} [highlight] hover tint for this subtree, over the View's; false for none - a
172
+ * floor or wall left plain under a View that tints everything else (null: the View's)
171
173
  * @property {boolean} [highlightWhole] hovering any part of this subtree tints all of it, as one thing - a
172
174
  * piece of furniture, a machine - rather than just the part under the pointer (default false)
173
175
  * @property {((hit: Hit | null) => void) | null} [onHover] called as the thing under the pointer in this subtree changes
@@ -244,14 +246,17 @@ export declare class Node {
244
246
  set rotation(v: Vec3Input);
245
247
  /** Kept in sync with rotation. Assigning copies, normalised. @returns {Quat} */
246
248
  get quaternion(): Quat;
247
- /** @param {ArrayLike<number>} v */
248
- set quaternion(v: ArrayLike<number>);
249
+ /** @param {QuatInput} v */
250
+ set quaternion(v: QuatInput);
249
251
  /** @param {NodeOptions} [options] */
250
252
  constructor(options?: NodeOptions);
251
- /** Hover tint for this subtree, over the View's; set any colour, or null. @returns {Color | null} */
252
- get highlight(): Color | null;
253
- /** @param {ColorInput | null} value */
254
- set highlight(value: ColorInput | null);
253
+ /**
254
+ * Hover tint for this subtree, over the View's: a colour, false for none, or null to use the View's.
255
+ * @returns {Color | null | false}
256
+ */
257
+ get highlight(): Color | null | false;
258
+ /** @param {ColorInput | null | false} value */
259
+ set highlight(value: ColorInput | null | false);
255
260
  /**
256
261
  * The section plane cutting this subtree, or null. Set { normal, offset, cap }, a Clip or null;
257
262
  * move the cut by changing its offset or normal in place.