@expofp/renderer 3.44.8 → 3.45.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/dist/Renderer.js +7 -1
- package/dist/controls/hooks.d.ts +2 -1
- package/dist/core/sprites/BatchedSprites.js +2 -34
- package/dist/core/text/MemberTexture.js +49 -8
- package/dist/events/LayoutDriver.d.ts +5 -0
- package/dist/events/LayoutDriver.js +136 -29
- package/dist/events/layout-targets.d.ts +45 -3
- package/dist/events/layout-targets.js +129 -9
- package/dist/events/placement/box.d.ts +59 -0
- package/dist/events/placement/box.js +96 -0
- package/dist/events/placement/grid.d.ts +161 -0
- package/dist/events/placement/grid.js +235 -0
- package/dist/events/placement/index.d.ts +2 -0
- package/dist/events/placement/index.js +1 -0
- package/dist/events/placement/pass.d.ts +70 -0
- package/dist/events/placement/pass.js +617 -0
- package/dist/objects/images/ImageInstance.js +1 -0
- package/dist/objects/images/Images.js +2 -2
- package/dist/objects/images/image-container.d.ts +12 -0
- package/dist/objects/images/image-container.js +20 -4
- package/dist/objects/materials/TextureMaterial.d.ts +11 -8
- package/dist/objects/materials/TextureMaterial.js +24 -17
- package/dist/objects/text/text-container.d.ts +16 -1
- package/dist/objects/text/text-container.js +23 -1
- package/dist/space/layout-measure.d.ts +12 -10
- package/dist/space/layout-measure.js +18 -16
- package/dist/types/defs.d.ts +157 -147
- package/dist/types/events.d.ts +5 -1
- package/dist/types/guards.d.ts +7 -0
- package/dist/types/guards.js +10 -0
- package/dist/utils/math.d.ts +18 -1
- package/dist/utils/math.js +35 -0
- package/package.json +2 -2
package/dist/types/defs.d.ts
CHANGED
|
@@ -1,224 +1,234 @@
|
|
|
1
1
|
import { type Box, type LineLike, type Rect, type Shape } from '@expofp/geometry';
|
|
2
|
-
import { type LayoutHandlers, type PointerHandlers } from './events';
|
|
3
|
-
/** A color as a
|
|
2
|
+
import { type LayoutHandlers, type LayoutView, type PointerHandlers } from './events';
|
|
3
|
+
/** A color as a CSS string or a packed number. */
|
|
4
4
|
export type ColorInput = string | number;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* A `Blob` is how anything fetched over the network arrives. It is a handle to an immutable byte
|
|
9
|
-
* store that the browser reference-counts. `postMessage` clones the handle, not the bytes. That is
|
|
10
|
-
* what lets atlas packing move to a worker. The renderer decodes the `Blob` itself, off the main
|
|
11
|
-
* thread wherever the environment allows it.
|
|
12
|
-
*
|
|
13
|
-
* `HTMLImageElement` is deliberately absent. Decoding one costs the main thread more than the
|
|
14
|
-
* packing it feeds: at a thousand logos on a throttled CPU, it stalled the page for two seconds.
|
|
15
|
-
* Leaving the member in the union would keep that slow path reachable. Pass a `Blob` instead.
|
|
16
|
-
*
|
|
17
|
-
* There is no `string` member either. The caller keeps all networking, so the renderer never
|
|
18
|
-
* learns about URLs, retries, or CORS.
|
|
6
|
+
* An image the renderer can upload as a texture. Pass fetched images as a `Blob`: the renderer
|
|
7
|
+
* decodes it off the main thread. `HTMLImageElement` and URL strings are not accepted.
|
|
19
8
|
*/
|
|
20
9
|
export type ImageSource = HTMLCanvasElement | ImageBitmap | OffscreenCanvas | Blob;
|
|
21
|
-
/** Scene definition */
|
|
10
|
+
/** Scene definition. */
|
|
22
11
|
export interface SceneDef {
|
|
23
|
-
/**
|
|
12
|
+
/** The root layer of the scene tree. */
|
|
24
13
|
rootLayer: LayerDef;
|
|
25
|
-
/**
|
|
14
|
+
/** The background color. */
|
|
26
15
|
background?: ColorInput;
|
|
27
|
-
/** SVG viewbox */
|
|
16
|
+
/** The SVG viewbox. */
|
|
28
17
|
viewbox: Box;
|
|
29
18
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* renderer adds on top to reach three's.
|
|
19
|
+
* A plan-to-world matrix that replaces the viewbox fit, in the host's coordinates. It must keep
|
|
20
|
+
* plan space's handedness.
|
|
33
21
|
*/
|
|
34
22
|
staticTransform?: number[];
|
|
35
23
|
}
|
|
36
|
-
/**
|
|
24
|
+
/** Fields every renderable def shares. */
|
|
37
25
|
export interface SharedDef extends LayoutHandlers {
|
|
38
|
-
/** Whether the def is hidden */
|
|
26
|
+
/** Whether the def is hidden. */
|
|
39
27
|
hidden?: boolean;
|
|
40
28
|
/**
|
|
41
|
-
* How
|
|
42
|
-
* `
|
|
43
|
-
*
|
|
44
|
-
* `undefined` inherits from the nearest ancestor that sets one, and only `undefined` inherits: a
|
|
45
|
-
* def's own `0` un-dims it inside a dimmed layer, and its own `1` dims it inside an undimmed one.
|
|
46
|
-
* A layer and a single def carry the same field with the same meaning, so dimming a whole floor
|
|
47
|
-
* and un-dimming one booth on it are the same operation at two levels. The root defaults to `0`.
|
|
48
|
-
*
|
|
49
|
-
* Values outside `[0, 1]` are clamped. Being a number rather than a flag is what lets a dim be
|
|
50
|
-
* animated — easing a layer's value from `0` to `1` costs one uniform per layer per frame,
|
|
51
|
-
* whatever the layer holds.
|
|
29
|
+
* How much the def is dimmed, from `0` (none) to `1` (full). `undefined` inherits from the
|
|
30
|
+
* nearest ancestor, so a def can set `0` to stay undimmed inside a dimmed layer. Animate it
|
|
31
|
+
* freely: a change costs one uniform write per layer.
|
|
52
32
|
*/
|
|
53
33
|
dim?: number;
|
|
54
34
|
}
|
|
55
35
|
/** Any def that can be rendered into a scene. */
|
|
56
36
|
export type RenderableDef = LayerDef | ShapeDef | ImageDef | TextDef | LineDef | ModelDef;
|
|
57
|
-
/**
|
|
58
|
-
* An array of a single {@link RenderableDef} kind (never a mixed union). The conditional
|
|
59
|
-
* distributes over {@link RenderableDef}, so even the default is a union of single-kind arrays —
|
|
60
|
-
* a mixed array is unrepresentable, which is what lets a first-element guard speak for the whole
|
|
61
|
-
* collection. `Readonly<RenderableDefCollection<T>>` distributes the same way, into readonly
|
|
62
|
-
* single-kind arrays.
|
|
63
|
-
*/
|
|
37
|
+
/** An array of one {@link RenderableDef} kind. Mixed arrays do not type-check. */
|
|
64
38
|
export type RenderableDefCollection<T = RenderableDef> = T extends RenderableDef ? T[] : never;
|
|
65
39
|
/**
|
|
66
|
-
* Layer definition.
|
|
67
|
-
*
|
|
68
|
-
* A layer is also where interaction lives: the handlers it inherits from {@link PointerHandlers} are
|
|
69
|
-
* what make its subtree pickable, and each event names the def it hit. Layout is the other way round
|
|
70
|
-
* — a layer carries its own {@link LayoutHandlers} through {@link SharedDef}, like any other def, and
|
|
71
|
-
* that is how a layer whose contents depend on the camera re-derives them.
|
|
40
|
+
* Layer definition. Its {@link PointerHandlers} make its subtree pickable, and its
|
|
41
|
+
* {@link LayoutHandlers} run like any other def's.
|
|
72
42
|
*/
|
|
73
43
|
export interface LayerDef<T extends RenderableDef = RenderableDef> extends SharedDef, PointerHandlers<T> {
|
|
74
|
-
/**
|
|
44
|
+
/** The layer's name. */
|
|
75
45
|
readonly name: string;
|
|
76
|
-
/**
|
|
46
|
+
/** The layer's children, all of one kind. */
|
|
77
47
|
children: RenderableDefCollection<T>;
|
|
78
48
|
/**
|
|
79
|
-
* Draws
|
|
80
|
-
*
|
|
49
|
+
* Draws the subtree above 3D content, with depth testing off. For flat content only: solid
|
|
50
|
+
* shapes and models ignore it. Descendants cannot opt out.
|
|
51
|
+
*/
|
|
52
|
+
overlay?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Placement defs compete only with defs in layers that share this key. Without it, the layer
|
|
55
|
+
* competes only with itself. Prefix the key with its owner.
|
|
56
|
+
*/
|
|
57
|
+
collisionGroup?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Turns collisions in this layer's collision scope into clusters. Both colliding defs are hidden
|
|
60
|
+
* through their own `onPlace`, and the cluster is reported to {@link ClusterOptions.onCluster}.
|
|
61
|
+
*/
|
|
62
|
+
clustering?: ClusterOptions;
|
|
63
|
+
}
|
|
64
|
+
/** Clustering options of a layer. */
|
|
65
|
+
export interface ClusterOptions {
|
|
66
|
+
/**
|
|
67
|
+
* The size of the marker you draw for a cluster. Any def or cluster that this marker would
|
|
68
|
+
* cover joins the cluster. Without it, the marker takes the size of the cluster's first member.
|
|
69
|
+
* When several clustering layers share a scope, the first layer's marker is used.
|
|
70
|
+
*/
|
|
71
|
+
marker?: ClusterMarker;
|
|
72
|
+
/**
|
|
73
|
+
* Receives the full current set of clusters whenever it changes. A layer that loses all its
|
|
74
|
+
* clusters receives an empty array once.
|
|
81
75
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
76
|
+
* Changes are held while the plan moves on screen and are reported once it has stood still for a
|
|
77
|
+
* moment. A registration, an unregistration or a def whose bounds you update is reported at once.
|
|
78
|
+
* `onPlace` calls arrive first, in the same synchronous call.
|
|
85
79
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
80
|
+
* Return the defs that changed. Never call `update()` here. Keep the options object stable: a
|
|
81
|
+
* new object is not noticed while the set stays the same.
|
|
82
|
+
* @param clusters - A new array on each call, in placement order.
|
|
83
|
+
* @param view - The current camera view.
|
|
84
|
+
* @returns The defs that changed, or nothing.
|
|
85
|
+
*/
|
|
86
|
+
onCluster(this: void, clusters: readonly Cluster[], view: LayoutView): readonly RenderableDef[] | void;
|
|
87
|
+
}
|
|
88
|
+
/** The screen box of a cluster's marker. */
|
|
89
|
+
export interface ClusterMarker {
|
|
90
|
+
/** The width in CSS pixels. */
|
|
91
|
+
width: number;
|
|
92
|
+
/** The height in CSS pixels. */
|
|
93
|
+
height: number;
|
|
94
|
+
/** The point that stands on the cluster's anchor, as in {@link ImageDef.origin}. */
|
|
95
|
+
origin?: [number, number];
|
|
96
|
+
}
|
|
97
|
+
/** One cluster of colliding defs. */
|
|
98
|
+
export interface Cluster {
|
|
99
|
+
/** How many units it holds, at least two. A `placement.group` counts as one unit. */
|
|
100
|
+
readonly unitCount: number;
|
|
101
|
+
/** The mean x of the units' anchors, in plan units. */
|
|
102
|
+
readonly x: number;
|
|
103
|
+
/** The mean y of the units' anchors, in plan units. */
|
|
104
|
+
readonly y: number;
|
|
105
|
+
/** The greatest elevation of its members, in plan units. */
|
|
106
|
+
readonly elevation: number;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* How a def competes for room on screen.
|
|
110
|
+
*
|
|
111
|
+
* - `never` (default): it is placed only where nothing placed before covers it, and then it
|
|
112
|
+
* blocks the defs after it.
|
|
113
|
+
* - `always`: it is always placed, blocks nothing and never clusters. In a group, it takes the
|
|
114
|
+
* group's verdict.
|
|
115
|
+
*/
|
|
116
|
+
export type OverlapMode = 'never' | 'always';
|
|
117
|
+
/** Placement options of a screen-space def. */
|
|
118
|
+
export interface PlacementOptions {
|
|
119
|
+
/**
|
|
120
|
+
* Receives the placement verdict: on the first pass after the def registers, then each time the
|
|
121
|
+
* verdict changes. Changes are reported when the camera stops, as for
|
|
122
|
+
* {@link ClusterOptions.onCluster}.
|
|
89
123
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
124
|
+
* Return the defs that changed. Never call `update()` here.
|
|
125
|
+
* @param placed - Whether the def got room on screen.
|
|
126
|
+
* @param view - The current camera view.
|
|
127
|
+
* @returns The defs that changed, or nothing.
|
|
92
128
|
*/
|
|
93
|
-
|
|
129
|
+
onPlace(this: void, placed: boolean, view: LayoutView): readonly RenderableDef[] | void;
|
|
130
|
+
/**
|
|
131
|
+
* Defs that share this key compete and cluster as one unit, with the union of their boxes. All
|
|
132
|
+
* members get the same verdict. The first member in order sets the unit's priority. Keys apply
|
|
133
|
+
* per collision scope. Prefix the key with its owner, and unregister old defs before you reuse
|
|
134
|
+
* their key.
|
|
135
|
+
*/
|
|
136
|
+
group?: string;
|
|
137
|
+
/** CSS pixels added around the tested box: one value, or `[horizontal, vertical]`. */
|
|
138
|
+
padding?: number | [number, number];
|
|
139
|
+
/** How the def competes. Defaults to `never`. */
|
|
140
|
+
overlap?: OverlapMode;
|
|
141
|
+
}
|
|
142
|
+
/** Fields of the def kinds that can face the camera: {@link ImageDef} and {@link TextDef}. */
|
|
143
|
+
export interface ScreenSpaceDef extends SharedDef {
|
|
144
|
+
/**
|
|
145
|
+
* Faces the def toward the camera. It pivots about `bounds.center` at `bounds.elevation`, sized
|
|
146
|
+
* by `bounds.size` in plan units. `bounds.rotation` spins it in the screen plane. Use an
|
|
147
|
+
* `onScale` rule to keep a constant pixel size.
|
|
148
|
+
*/
|
|
149
|
+
screenSpace?: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Enters the def into the placement pass, which hides it where a def earlier in order already
|
|
152
|
+
* covers the screen. Works only when {@link screenSpace} is true.
|
|
153
|
+
*/
|
|
154
|
+
placement?: PlacementOptions;
|
|
94
155
|
}
|
|
95
156
|
/** Shape definition. */
|
|
96
157
|
export interface ShapeDef extends SharedDef {
|
|
97
158
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* (rect ↔ polygon). Mutating the existing shape in place is more limited — a rect's or box's
|
|
101
|
-
* transform (center, size, rotation) is re-read every update, but a polygon's vertices and indices
|
|
102
|
-
* are cached by shape identity and will not rebuild in place.
|
|
159
|
+
* The shape to render. To change it, assign a new `Shape` and call `update(def)`. A polygon
|
|
160
|
+
* changed in place does not rebuild.
|
|
103
161
|
*/
|
|
104
162
|
shape: Shape;
|
|
105
|
-
/**
|
|
163
|
+
/** The shape's color. */
|
|
106
164
|
color: ColorInput;
|
|
107
165
|
}
|
|
108
|
-
/** Image definition */
|
|
109
|
-
export interface ImageDef extends
|
|
110
|
-
/**
|
|
111
|
-
* Image source. Write-once — a def's pixels are fixed for its lifetime: the atlas packs and
|
|
112
|
-
* uploads them at claim time and never re-reads the source, so a new image is a new def, not a
|
|
113
|
-
* reassignment. `readonly` makes that the type's guarantee (see {@link SceneDef.memoryLimit},
|
|
114
|
-
* which relies on a pack's byte totals staying stable until a repack).
|
|
115
|
-
*/
|
|
166
|
+
/** Image definition. */
|
|
167
|
+
export interface ImageDef extends ScreenSpaceDef {
|
|
168
|
+
/** The image source. Fixed for the def's life: use a new def for a new image. */
|
|
116
169
|
readonly source: ImageSource;
|
|
117
|
-
/**
|
|
170
|
+
/** The image's bounds. */
|
|
118
171
|
bounds: Rect;
|
|
119
172
|
/**
|
|
120
|
-
*
|
|
121
|
-
* [0
|
|
173
|
+
* The point of the image that `bounds.center` names. `[0, 0]` is the top-left corner,
|
|
174
|
+
* `[0.5, 0.5]` the center (default), `[1, 1]` the bottom-right corner.
|
|
122
175
|
*/
|
|
123
176
|
origin?: [number, number];
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
* gives in **plan units**. That is the same meaning `bounds.size` has for a flat def. A caller that
|
|
127
|
-
* wants a constant on-screen size keeps doing what markers do today, which is an `onScale` rule
|
|
128
|
-
* that rebuilds the bounds from the pixel size.
|
|
129
|
-
*
|
|
130
|
-
* `bounds.rotation` keeps its meaning, which is a spin about the content plane's normal. For a
|
|
131
|
-
* screen-space def that plane is the screen, so there is no separate spin field. An `onRoll` rule
|
|
132
|
-
* still runs, so keep this off where the rotation carries a plan bearing. Such a def would point
|
|
133
|
-
* at one screen direction however the plan is turned.
|
|
134
|
-
*
|
|
135
|
-
* Changing this at runtime is supported. The def moves between the layer's flat mesh and its
|
|
136
|
-
* camera-facing mesh, which never touches the atlas packing.
|
|
137
|
-
*/
|
|
138
|
-
screenSpace?: boolean;
|
|
177
|
+
/** How opaque the image is, from `0` to `1`. Defaults to `1`. It blends as alpha does. */
|
|
178
|
+
opacity?: number;
|
|
139
179
|
}
|
|
140
|
-
/** Text definition */
|
|
141
|
-
export interface TextDef extends
|
|
142
|
-
/**
|
|
143
|
-
* Array of text lines, drawn as a block stacked inside {@link bounds}.
|
|
144
|
-
*
|
|
145
|
-
* Updatable in both directions: a line's own fields are re-read on every `update(def)`, and
|
|
146
|
-
* changing the array's *length* re-claims the def's batch members against the new count. (The
|
|
147
|
-
* imperative renderer allocated members once and so required this to be fixed; React reconciles
|
|
148
|
-
* it instead.) A line whose `fontSize` is `0` is not drawn.
|
|
149
|
-
*/
|
|
180
|
+
/** Text definition. */
|
|
181
|
+
export interface TextDef extends ScreenSpaceDef {
|
|
182
|
+
/** The text lines, stacked inside {@link bounds}. A line with `fontSize` `0` is not drawn. */
|
|
150
183
|
lines: TextLineDef[];
|
|
151
|
-
/**
|
|
184
|
+
/** The text's bounds. */
|
|
152
185
|
bounds: Rect;
|
|
153
|
-
/**
|
|
186
|
+
/** The text's padding, `[horizontal, vertical]`. */
|
|
154
187
|
padding: [number, number];
|
|
155
|
-
/**
|
|
188
|
+
/** How the text is aligned. */
|
|
156
189
|
alignment: TextAlignment;
|
|
157
|
-
/**
|
|
158
|
-
* As `ImageDef.screenSpace`. The block faces the camera and keeps its plan anchor and its
|
|
159
|
-
* plan-unit font sizes. The whole block pivots about `bounds.center`, on one anchor shared by
|
|
160
|
-
* every line, which is what keeps a stack from splaying under tilt.
|
|
161
|
-
*/
|
|
162
|
-
screenSpace?: boolean;
|
|
163
190
|
}
|
|
164
|
-
/**
|
|
191
|
+
/** One line of a text def. */
|
|
165
192
|
export interface TextLineDef {
|
|
166
|
-
/**
|
|
193
|
+
/** The line's text. */
|
|
167
194
|
text: string;
|
|
168
|
-
/**
|
|
195
|
+
/** The line's color. */
|
|
169
196
|
color: ColorInput;
|
|
170
|
-
/**
|
|
197
|
+
/** The font URL. Not updatable. Supports .ttf, .otf and .woff, not .woff2. */
|
|
171
198
|
fontUrl: string;
|
|
172
|
-
/**
|
|
173
|
-
* Line's font size: its em height in plan units, the same units as the def's `bounds` and
|
|
174
|
-
* `padding`.
|
|
175
|
-
*
|
|
176
|
-
* Nothing here converts from pixels. A plan sizing a line to hold an on-screen size does that
|
|
177
|
-
* itself, against the pixel size the renderer publishes — as it does for every other
|
|
178
|
-
* pixel-authored thing it draws. `0` means the line is not drawn.
|
|
179
|
-
*/
|
|
199
|
+
/** The em height in plan units. `0` hides the line. */
|
|
180
200
|
fontSize: number;
|
|
181
|
-
/**
|
|
201
|
+
/** The stroke color, and its width in the same units as {@link fontSize}. */
|
|
182
202
|
stroke?: {
|
|
183
203
|
color: ColorInput;
|
|
184
204
|
width: number;
|
|
185
205
|
};
|
|
186
206
|
}
|
|
187
|
-
/** Text alignment */
|
|
207
|
+
/** Text alignment. */
|
|
188
208
|
export interface TextAlignment {
|
|
189
|
-
/**
|
|
209
|
+
/** The horizontal alignment. */
|
|
190
210
|
horizontal: 'left' | 'center' | 'right';
|
|
191
|
-
/**
|
|
211
|
+
/** The vertical alignment. */
|
|
192
212
|
vertical: 'top' | 'center' | 'bottom';
|
|
193
|
-
/**
|
|
213
|
+
/** The alignment of text inside a line. */
|
|
194
214
|
text?: 'left' | 'center' | 'right';
|
|
195
215
|
}
|
|
196
|
-
/** Line definition */
|
|
216
|
+
/** Line definition. */
|
|
197
217
|
export interface LineDef extends SharedDef {
|
|
198
|
-
/**
|
|
199
|
-
* The segment's endpoints, with an optional `elevation` placing it on its layer's plane.
|
|
200
|
-
*
|
|
201
|
-
* Updatable: both ends are re-read on every `update(def)` and written only when they moved,
|
|
202
|
-
* so a line can be animated in place rather than replaced. A `LineLike` exposes readonly coordinates,
|
|
203
|
-
* so an update means replacing this with a new one — or moving the `Line` behind it,
|
|
204
|
-
* whose own setters do the same job.
|
|
205
|
-
*/
|
|
218
|
+
/** The endpoints, with an optional elevation. Assign a new value and call `update(def)`. */
|
|
206
219
|
points: LineLike;
|
|
207
|
-
/**
|
|
220
|
+
/** The line's color. */
|
|
208
221
|
color: ColorInput;
|
|
209
|
-
/**
|
|
210
|
-
* Line's width in screen-space units (pixels), so it holds its thickness as the plan zooms.
|
|
211
|
-
* `0` draws nothing.
|
|
212
|
-
*/
|
|
222
|
+
/** The width in screen pixels, constant at every zoom. `0` draws nothing. */
|
|
213
223
|
width: number;
|
|
214
224
|
}
|
|
215
|
-
/** External 3D model definition */
|
|
225
|
+
/** External 3D model definition. */
|
|
216
226
|
export interface ModelDef extends SharedDef {
|
|
217
|
-
/**
|
|
227
|
+
/** The model URL. Not updatable. */
|
|
218
228
|
url: string;
|
|
219
|
-
/**
|
|
229
|
+
/** The model's bounds. */
|
|
220
230
|
bounds: Rect;
|
|
221
|
-
/**
|
|
231
|
+
/** The model's opacity, from `0` to `1`. */
|
|
222
232
|
opacity?: number;
|
|
223
233
|
}
|
|
224
234
|
//# sourceMappingURL=defs.d.ts.map
|
package/dist/types/events.d.ts
CHANGED
|
@@ -119,8 +119,12 @@ export type RollHandler = NonNullable<LayoutHandlers['onRoll']>;
|
|
|
119
119
|
*/
|
|
120
120
|
export interface LayoutView {
|
|
121
121
|
/**
|
|
122
|
-
* How much of the plan one
|
|
122
|
+
* How much of the plan one CSS pixel spans, in plan units — the factor anything sized in
|
|
123
123
|
* pixels is laid out against, and the quantity the imperative renderer published as `ptScale`.
|
|
124
|
+
*
|
|
125
|
+
* CSS pixels, so a size authored in them comes out the same at every screen density. The device
|
|
126
|
+
* ratio never reaches a rule because a rule never needs it: the ratio sets how crisp a def is
|
|
127
|
+
* drawn, not how big.
|
|
124
128
|
*/
|
|
125
129
|
readonly pixelSize: number;
|
|
126
130
|
/**
|
package/dist/types/guards.d.ts
CHANGED
|
@@ -5,6 +5,13 @@ export declare function isTextDef(def: RenderableDef): def is TextDef;
|
|
|
5
5
|
export declare function isLineDef(def: RenderableDef): def is LineDef;
|
|
6
6
|
export declare function isModelDef(def: RenderableDef): def is ModelDef;
|
|
7
7
|
export declare function isLayerDef(def: RenderableDef): def is LayerDef;
|
|
8
|
+
/**
|
|
9
|
+
* Whether a def takes part in the placement pass: it declares placement options, and it faces the
|
|
10
|
+
* camera. A flat def carrying options is not a target, which is what the pass warns about.
|
|
11
|
+
* @param def - The def to test.
|
|
12
|
+
* @returns Whether the pass tests it.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isPlacementTarget(def: RenderableDef): def is ImageDef | TextDef;
|
|
8
15
|
export declare function isLayerDefs(defs: Readonly<RenderableDefCollection>): defs is readonly LayerDef[];
|
|
9
16
|
export declare function isShapeDefs(defs: Readonly<RenderableDefCollection>): defs is readonly ShapeDef[];
|
|
10
17
|
export declare function isImageDefs(defs: Readonly<RenderableDefCollection>): defs is readonly ImageDef[];
|
package/dist/types/guards.js
CHANGED
|
@@ -16,6 +16,16 @@ export function isModelDef(def) {
|
|
|
16
16
|
export function isLayerDef(def) {
|
|
17
17
|
return def.children !== undefined;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Whether a def takes part in the placement pass: it declares placement options, and it faces the
|
|
21
|
+
* camera. A flat def carrying options is not a target, which is what the pass warns about.
|
|
22
|
+
* @param def - The def to test.
|
|
23
|
+
* @returns Whether the pass tests it.
|
|
24
|
+
*/
|
|
25
|
+
export function isPlacementTarget(def) {
|
|
26
|
+
const target = def;
|
|
27
|
+
return target.placement !== undefined && target.screenSpace === true;
|
|
28
|
+
}
|
|
19
29
|
// The array guards below take the collection type, not `readonly RenderableDef[]`: the collection
|
|
20
30
|
// is a union of single-kind arrays, so a first-element check is sound for the whole array. A plain
|
|
21
31
|
// `RenderableDef[]` parameter would admit mixed arrays the check cannot speak for. The `Readonly`
|
package/dist/utils/math.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Matrix4 } from 'three';
|
|
1
|
+
import { type Camera, type Matrix4 } from 'three';
|
|
2
2
|
/**
|
|
3
3
|
* Holds a value inside an inclusive range.
|
|
4
4
|
*
|
|
@@ -32,4 +32,21 @@ export declare function euclideanModulo(value: number, modulus: number): number;
|
|
|
32
32
|
* @returns The transformed axis's length.
|
|
33
33
|
*/
|
|
34
34
|
export declare function axisLength(matrix: Matrix4, axis: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* How far the camera's own axis travels before it meets a batch's own plane, in world units.
|
|
37
|
+
*
|
|
38
|
+
* That is the depth a plan-unit size is exact at, so it is what the shader cancels the perspective
|
|
39
|
+
* divide against. It has to agree with the depth `measurePixelSize` in `space/layout-measure.ts`
|
|
40
|
+
* works at, because a caller's `onScale` rule sizes a def in plan units from the pixel size that
|
|
41
|
+
* function reports. Without controls mounted that function reads this same crossing point. With
|
|
42
|
+
* them it reads their distance to their target, and the two agree while the target sits on the
|
|
43
|
+
* plan, which is what orbiting a floor plan keeps true.
|
|
44
|
+
*
|
|
45
|
+
* The plane is the batch's own, taken from its world matrix, because a sprite batch draws at plan
|
|
46
|
+
* `z = 0` and whatever places the plan places the mesh with it.
|
|
47
|
+
* @param camera - The camera this draw uses.
|
|
48
|
+
* @param planToWorld - The batch's world matrix.
|
|
49
|
+
* @returns The distance in world units, or `0` for a camera that never meets the plane ahead of it.
|
|
50
|
+
*/
|
|
51
|
+
export declare function aimDepth(camera: Camera, planToWorld: Matrix4): number;
|
|
35
52
|
//# sourceMappingURL=math.d.ts.map
|
package/dist/utils/math.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Vector3 } from 'three';
|
|
1
2
|
/**
|
|
2
3
|
* Holds a value inside an inclusive range.
|
|
3
4
|
*
|
|
@@ -39,3 +40,37 @@ export function axisLength(matrix, axis) {
|
|
|
39
40
|
const at = axis * 4;
|
|
40
41
|
return Math.hypot(elements[at], elements[at + 1], elements[at + 2]);
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* How far the camera's own axis travels before it meets a batch's own plane, in world units.
|
|
45
|
+
*
|
|
46
|
+
* That is the depth a plan-unit size is exact at, so it is what the shader cancels the perspective
|
|
47
|
+
* divide against. It has to agree with the depth `measurePixelSize` in `space/layout-measure.ts`
|
|
48
|
+
* works at, because a caller's `onScale` rule sizes a def in plan units from the pixel size that
|
|
49
|
+
* function reports. Without controls mounted that function reads this same crossing point. With
|
|
50
|
+
* them it reads their distance to their target, and the two agree while the target sits on the
|
|
51
|
+
* plan, which is what orbiting a floor plan keeps true.
|
|
52
|
+
*
|
|
53
|
+
* The plane is the batch's own, taken from its world matrix, because a sprite batch draws at plan
|
|
54
|
+
* `z = 0` and whatever places the plan places the mesh with it.
|
|
55
|
+
* @param camera - The camera this draw uses.
|
|
56
|
+
* @param planToWorld - The batch's world matrix.
|
|
57
|
+
* @returns The distance in world units, or `0` for a camera that never meets the plane ahead of it.
|
|
58
|
+
*/
|
|
59
|
+
export function aimDepth(camera, planToWorld) {
|
|
60
|
+
// A camera looks down its own negative z.
|
|
61
|
+
const direction = _direction.setFromMatrixColumn(camera.matrixWorld, 2).normalize().negate();
|
|
62
|
+
const normal = _normal.setFromMatrixColumn(planToWorld, 2).normalize();
|
|
63
|
+
const facing = direction.dot(normal);
|
|
64
|
+
// The camera looks along the plane and never meets it.
|
|
65
|
+
if (facing === 0)
|
|
66
|
+
return 0;
|
|
67
|
+
const eye = _eye.setFromMatrixPosition(camera.matrixWorld);
|
|
68
|
+
const depth = _origin.setFromMatrixPosition(planToWorld).sub(eye).dot(normal) / facing;
|
|
69
|
+
// Behind the camera is no measurement, so the shader keeps its plan-unit sizing instead.
|
|
70
|
+
return depth > 0 ? depth : 0;
|
|
71
|
+
}
|
|
72
|
+
// Scratch for aimDepth, filled and consumed within one call.
|
|
73
|
+
const _direction = new Vector3();
|
|
74
|
+
const _normal = new Vector3();
|
|
75
|
+
const _eye = new Vector3();
|
|
76
|
+
const _origin = new Vector3();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expofp/renderer",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.45.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/expofp/efp-app.git",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"troika-three-text": "^0.52.5",
|
|
43
43
|
"tslib": "^2.3.0",
|
|
44
44
|
"webgl-memory": "^1.1.3",
|
|
45
|
-
"@expofp/geometry": "3.
|
|
45
|
+
"@expofp/geometry": "3.45.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@react-three/test-renderer": "^9.1.0",
|