@expofp/renderer 3.2.5 → 3.27.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.
Files changed (228) hide show
  1. package/README.md +111 -0
  2. package/dist/Renderer.d.ts +88 -0
  3. package/dist/Renderer.js +53 -0
  4. package/dist/controls/CameraControls.d.ts +102 -0
  5. package/dist/controls/CameraControls.js +239 -0
  6. package/dist/controls/camera-api.d.ts +206 -0
  7. package/dist/controls/camera-api.js +181 -0
  8. package/dist/controls/camera-move.d.ts +13 -0
  9. package/dist/controls/camera-move.js +18 -0
  10. package/dist/controls/camera-state.d.ts +40 -0
  11. package/dist/controls/camera-state.js +65 -0
  12. package/dist/controls/gestures.d.ts +70 -0
  13. package/dist/controls/gestures.js +84 -0
  14. package/dist/controls/handlers/Inertia.d.ts +111 -0
  15. package/dist/controls/handlers/Inertia.js +215 -0
  16. package/dist/controls/handlers/Pan.d.ts +23 -0
  17. package/dist/controls/handlers/Pan.js +32 -0
  18. package/dist/controls/handlers/Pitch.d.ts +94 -0
  19. package/dist/controls/handlers/Pitch.js +191 -0
  20. package/dist/controls/handlers/Roll.d.ts +103 -0
  21. package/dist/controls/handlers/Roll.js +182 -0
  22. package/dist/controls/handlers/Zoom.d.ts +15 -0
  23. package/dist/controls/handlers/Zoom.js +26 -0
  24. package/dist/controls/index.d.ts +56 -0
  25. package/dist/controls/index.js +58 -0
  26. package/dist/controls/zoom-to.d.ts +89 -0
  27. package/dist/controls/zoom-to.js +91 -0
  28. package/dist/core/InstanceUniforms.d.ts +93 -0
  29. package/dist/core/InstanceUniforms.js +266 -0
  30. package/dist/core/SquareDataTexture.d.ts +277 -0
  31. package/dist/core/SquareDataTexture.js +476 -0
  32. package/dist/core/batch/BatchedMesh.d.ts +74 -0
  33. package/dist/core/batch/BatchedMesh.js +149 -0
  34. package/dist/core/instanced/FrustumCulling.d.ts +141 -0
  35. package/dist/core/instanced/FrustumCulling.js +246 -0
  36. package/dist/core/instanced/InstancedMesh.d.ts +302 -0
  37. package/dist/core/instanced/InstancedMesh.js +497 -0
  38. package/dist/core/instanced/Instances.d.ts +119 -0
  39. package/dist/core/instanced/Instances.js +230 -0
  40. package/dist/core/instanced/Raycasting.d.ts +118 -0
  41. package/dist/core/instanced/Raycasting.js +134 -0
  42. package/dist/core/instanced/instanced-material.d.ts +77 -0
  43. package/dist/core/instanced/instanced-material.js +224 -0
  44. package/dist/core/lines/BatchedLines.d.ts +135 -0
  45. package/dist/core/lines/BatchedLines.js +213 -0
  46. package/dist/core/lines/FrustumCulling.d.ts +43 -0
  47. package/dist/core/lines/FrustumCulling.js +85 -0
  48. package/dist/core/lines/Raycasting.d.ts +44 -0
  49. package/dist/core/lines/Raycasting.js +91 -0
  50. package/dist/core/lines/lines-material.d.ts +47 -0
  51. package/dist/core/lines/lines-material.js +115 -0
  52. package/dist/core/shader-source.d.ts +50 -0
  53. package/dist/core/shader-source.js +84 -0
  54. package/dist/core/text/BatchedText.d.ts +227 -0
  55. package/dist/core/text/BatchedText.js +467 -0
  56. package/dist/core/text/MemberTexture.d.ts +90 -0
  57. package/dist/core/text/MemberTexture.js +194 -0
  58. package/dist/core/text/Text.d.ts +73 -0
  59. package/dist/core/text/Text.js +215 -0
  60. package/dist/core/text/batched-text-material.d.ts +56 -0
  61. package/dist/core/text/batched-text-material.js +121 -0
  62. package/dist/core/text/glyph-packing.d.ts +17 -0
  63. package/dist/core/text/glyph-packing.js +61 -0
  64. package/dist/core/typed-array.d.ts +16 -0
  65. package/dist/core/typed-array.js +20 -0
  66. package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
  67. package/dist/debug/components/DebugPanelProvider.js +38 -0
  68. package/dist/debug/components/DebugTools.d.ts +22 -0
  69. package/dist/debug/components/DebugTools.js +28 -0
  70. package/dist/debug/components/Gui.d.ts +20 -0
  71. package/dist/debug/components/Gui.js +32 -0
  72. package/dist/debug/components/MemoryInfo.d.ts +22 -0
  73. package/dist/debug/components/MemoryInfo.js +42 -0
  74. package/dist/debug/components/Panel.d.ts +31 -0
  75. package/dist/debug/components/Panel.js +98 -0
  76. package/dist/debug/components/Stats.d.ts +9 -0
  77. package/dist/debug/components/Stats.js +24 -0
  78. package/dist/debug/debug-context.d.ts +41 -0
  79. package/dist/debug/debug-context.js +59 -0
  80. package/dist/debug/index.d.ts +51 -0
  81. package/dist/debug/index.js +64 -0
  82. package/dist/events/LayoutDriver.d.ts +31 -0
  83. package/dist/events/LayoutDriver.js +88 -0
  84. package/dist/events/PointerMissed.d.ts +23 -0
  85. package/dist/events/PointerMissed.js +58 -0
  86. package/dist/events/def-culling.d.ts +46 -0
  87. package/dist/events/def-culling.js +69 -0
  88. package/dist/events/layout-targets.d.ts +104 -0
  89. package/dist/events/layout-targets.js +245 -0
  90. package/dist/events/pointer.d.ts +118 -0
  91. package/dist/events/pointer.js +168 -0
  92. package/dist/external/ExternalCanvas.d.ts +56 -0
  93. package/dist/external/ExternalCanvas.js +178 -0
  94. package/dist/external/external-camera.d.ts +17 -0
  95. package/dist/external/external-camera.js +82 -0
  96. package/dist/external/external-events.d.ts +14 -0
  97. package/dist/external/external-events.js +33 -0
  98. package/dist/index.d.ts +11 -783
  99. package/dist/index.js +12 -8031
  100. package/dist/objects/Background.d.ts +31 -0
  101. package/dist/objects/Background.js +37 -0
  102. package/dist/objects/Lighting.d.ts +20 -0
  103. package/dist/objects/Lighting.js +85 -0
  104. package/dist/objects/containers/SlotContainer.d.ts +266 -0
  105. package/dist/objects/containers/SlotContainer.js +251 -0
  106. package/dist/objects/containers/hooks.d.ts +46 -0
  107. package/dist/objects/containers/hooks.js +118 -0
  108. package/dist/objects/containers/index.d.ts +6 -0
  109. package/dist/objects/containers/index.js +4 -0
  110. package/dist/objects/containers/keys.d.ts +10 -0
  111. package/dist/objects/containers/keys.js +18 -0
  112. package/dist/objects/containers/mesh-writes.d.ts +106 -0
  113. package/dist/objects/containers/mesh-writes.js +97 -0
  114. package/dist/objects/containers/props.d.ts +23 -0
  115. package/dist/objects/containers/props.js +1 -0
  116. package/dist/objects/images/ImageInstance.d.ts +29 -0
  117. package/dist/objects/images/ImageInstance.js +83 -0
  118. package/dist/objects/images/Images.d.ts +37 -0
  119. package/dist/objects/images/Images.js +204 -0
  120. package/dist/objects/images/atlas-packer.d.ts +128 -0
  121. package/dist/objects/images/atlas-packer.js +315 -0
  122. package/dist/objects/images/image-container.d.ts +51 -0
  123. package/dist/objects/images/image-container.js +70 -0
  124. package/dist/objects/images/index.d.ts +2 -0
  125. package/dist/objects/images/index.js +1 -0
  126. package/dist/objects/images/texture-budget.d.ts +120 -0
  127. package/dist/objects/images/texture-budget.js +215 -0
  128. package/dist/objects/layer/Layer.d.ts +27 -0
  129. package/dist/objects/layer/Layer.js +114 -0
  130. package/dist/objects/layer/index.d.ts +2 -0
  131. package/dist/objects/layer/index.js +1 -0
  132. package/dist/objects/layer/mount-scheduler.d.ts +102 -0
  133. package/dist/objects/layer/mount-scheduler.js +145 -0
  134. package/dist/objects/layer/visibility-gui.d.ts +19 -0
  135. package/dist/objects/layer/visibility-gui.js +93 -0
  136. package/dist/objects/lines/LineInstance.d.ts +21 -0
  137. package/dist/objects/lines/LineInstance.js +73 -0
  138. package/dist/objects/lines/Lines.d.ts +17 -0
  139. package/dist/objects/lines/Lines.js +29 -0
  140. package/dist/objects/lines/index.d.ts +2 -0
  141. package/dist/objects/lines/index.js +1 -0
  142. package/dist/objects/lines/line-container.d.ts +35 -0
  143. package/dist/objects/lines/line-container.js +40 -0
  144. package/dist/objects/materials/ColorMaterial.d.ts +85 -0
  145. package/dist/objects/materials/ColorMaterial.js +89 -0
  146. package/dist/objects/materials/LineMaterial.d.ts +44 -0
  147. package/dist/objects/materials/LineMaterial.js +72 -0
  148. package/dist/objects/materials/ModelMaterial.d.ts +41 -0
  149. package/dist/objects/materials/ModelMaterial.js +84 -0
  150. package/dist/objects/materials/TextureMaterial.d.ts +30 -0
  151. package/dist/objects/materials/TextureMaterial.js +29 -0
  152. package/dist/objects/materials/dim.d.ts +123 -0
  153. package/dist/objects/materials/dim.js +213 -0
  154. package/dist/objects/materials/shared.d.ts +6 -0
  155. package/dist/objects/materials/shared.js +51 -0
  156. package/dist/objects/models/ModelInstance.d.ts +22 -0
  157. package/dist/objects/models/ModelInstance.js +33 -0
  158. package/dist/objects/models/Models.d.ts +22 -0
  159. package/dist/objects/models/Models.js +177 -0
  160. package/dist/objects/models/gltf-cache.d.ts +17 -0
  161. package/dist/objects/models/gltf-cache.js +50 -0
  162. package/dist/objects/models/index.d.ts +2 -0
  163. package/dist/objects/models/index.js +1 -0
  164. package/dist/objects/models/model-asset.d.ts +48 -0
  165. package/dist/objects/models/model-asset.js +77 -0
  166. package/dist/objects/models/model-container.d.ts +139 -0
  167. package/dist/objects/models/model-container.js +227 -0
  168. package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
  169. package/dist/objects/shapes/ShapeInstance.js +40 -0
  170. package/dist/objects/shapes/Shapes.d.ts +21 -0
  171. package/dist/objects/shapes/Shapes.js +120 -0
  172. package/dist/objects/shapes/index.d.ts +2 -0
  173. package/dist/objects/shapes/index.js +1 -0
  174. package/dist/objects/shapes/shape-container.d.ts +165 -0
  175. package/dist/objects/shapes/shape-container.js +272 -0
  176. package/dist/objects/shapes/shape-geometry.d.ts +27 -0
  177. package/dist/objects/shapes/shape-geometry.js +94 -0
  178. package/dist/objects/text/TextInstance.d.ts +22 -0
  179. package/dist/objects/text/TextInstance.js +95 -0
  180. package/dist/objects/text/Texts.d.ts +30 -0
  181. package/dist/objects/text/Texts.js +41 -0
  182. package/dist/objects/text/index.d.ts +2 -0
  183. package/dist/objects/text/index.js +1 -0
  184. package/dist/objects/text/text-container.d.ts +105 -0
  185. package/dist/objects/text/text-container.js +206 -0
  186. package/dist/objects/text/text-layout.d.ts +83 -0
  187. package/dist/objects/text/text-layout.js +154 -0
  188. package/dist/space/Camera.d.ts +103 -0
  189. package/dist/space/Camera.js +321 -0
  190. package/dist/space/Scene.d.ts +44 -0
  191. package/dist/space/Scene.js +112 -0
  192. package/dist/space/Space.d.ts +288 -0
  193. package/dist/space/Space.js +329 -0
  194. package/dist/space/VisibleRect.d.ts +72 -0
  195. package/dist/space/VisibleRect.js +129 -0
  196. package/dist/space/camera-handle.d.ts +67 -0
  197. package/dist/space/camera-handle.js +63 -0
  198. package/dist/space/camera-kind.d.ts +26 -0
  199. package/dist/space/camera-kind.js +30 -0
  200. package/dist/space/canvas-size.d.ts +24 -0
  201. package/dist/space/canvas-size.js +20 -0
  202. package/dist/space/clipping.d.ts +55 -0
  203. package/dist/space/clipping.js +108 -0
  204. package/dist/space/layout-measure.d.ts +65 -0
  205. package/dist/space/layout-measure.js +173 -0
  206. package/dist/space/viewport.d.ts +112 -0
  207. package/dist/space/viewport.js +67 -0
  208. package/dist/types/defs.d.ts +169 -0
  209. package/dist/types/defs.js +1 -0
  210. package/dist/types/events.d.ts +183 -0
  211. package/dist/types/events.js +1 -0
  212. package/dist/types/guards.d.ts +14 -0
  213. package/dist/types/guards.js +42 -0
  214. package/dist/update/index.d.ts +3 -0
  215. package/dist/update/index.js +2 -0
  216. package/dist/update/slot-writers.d.ts +30 -0
  217. package/dist/update/slot-writers.js +72 -0
  218. package/dist/update/store.d.ts +41 -0
  219. package/dist/update/store.js +98 -0
  220. package/dist/utils/arrays.d.ts +13 -0
  221. package/dist/utils/arrays.js +20 -0
  222. package/dist/utils/colors.d.ts +19 -0
  223. package/dist/utils/colors.js +27 -0
  224. package/dist/utils/logging.d.ts +26 -0
  225. package/dist/utils/logging.js +47 -0
  226. package/dist/utils/math.d.ts +24 -0
  227. package/dist/utils/math.js +27 -0
  228. package/package.json +67 -19
@@ -0,0 +1,227 @@
1
+ import { Matrix4, Quaternion, Vector3 } from 'three';
2
+ import { SlotContainer } from '../containers';
3
+ import { DIM_SCHEMA } from '../materials/dim';
4
+ /**
5
+ * The per-instance uniform a model mesh reads its opacity from. The container owns the name: it
6
+ * declares the schema on bind and writes each slot's value, and hands the name to `ModelMaterial`,
7
+ * which patches its shader to multiply by it.
8
+ */
9
+ export const OPACITY_UNIFORM = 'instanceOpacity';
10
+ /**
11
+ * Every kind of model batch, **in the order they draw within a layer** — which is what `Models`
12
+ * numbers them by.
13
+ */
14
+ export const MODEL_KINDS = ['opaque', 'translucent'];
15
+ /**
16
+ * Which batch a model belongs in: `translucent` exactly when its `opacity` is below 1.
17
+ *
18
+ * A partition rather than a per-instance flag, because `transparent` is a **material** property —
19
+ * three decides which render list an *object* belongs to, never which instance — so two copies of
20
+ * one model differing only in opacity cannot share a mesh. `opacity` is updatable, so a def can
21
+ * cross the boundary at any time; that is what `reportKindMismatch` is for.
22
+ * @param def - The model to classify.
23
+ * @returns The kind of batch it draws from.
24
+ */
25
+ export function modelKindOf(def) {
26
+ return (def.opacity ?? 1) < 1 ? 'translucent' : 'opaque';
27
+ }
28
+ /**
29
+ * One model part's slot bookkeeping: every def in the layer drawing that part gets an instance, so
30
+ * twenty copies of a chair are one draw call rather than twenty.
31
+ *
32
+ * Much simpler than a shape container. The geometry is the part's — shared, never per instance — so
33
+ * there is no geometry cache and no capacity pre-scan, and `InstancedMeshExt` grows its own buffers,
34
+ * so nothing here has to size anything. What is left is a slot per def and the transform each one
35
+ * draws with.
36
+ */
37
+ export class ModelContainer extends SlotContainer {
38
+ /** The constructor args R3F builds the mesh from; a frozen snapshot, never mutated. */
39
+ args;
40
+ /** Which kind of member this container holds, and so which render list its mesh draws from. */
41
+ kind;
42
+ /**
43
+ * What the mesh drawing this part must carry, so that three sees the mirror the plan's frame
44
+ * requires and {@link place}'s plan-space answers land where they say. See {@link PLAN_FROM_GLTF}.
45
+ */
46
+ meshMatrix = PLAN_FROM_GLTF;
47
+ /** The model's bounds in plan units; every instance is fitted against them. */
48
+ extents;
49
+ kindMismatchHandler;
50
+ /**
51
+ * Builds the bookkeeping for one model part.
52
+ * @param extents - The model's own bounds, y-up, as `bakeGltf` left them.
53
+ * @param count - How many defs the layer holds for this part, used as the mesh's initial capacity.
54
+ * @param kind - Which of the layer's batches this is; its material is built for that one alone.
55
+ */
56
+ constructor(extents, count, kind = 'opaque') {
57
+ super({ schema: MODEL_SCHEMA });
58
+ // Mapped once, here, so that everything below reads plan units — `fitToBounds` included.
59
+ this.extents = extents.clone().applyMatrix4(PLAN_FROM_GLTF);
60
+ this.kind = kind;
61
+ this.args = [{ capacity: Math.max(count, 1) }];
62
+ }
63
+ /**
64
+ * Paint order is not implemented for models, so this does nothing.
65
+ *
66
+ * Not an omission, and not a limitation either — the mesh takes a `customSort` like any other, and
67
+ * wiring the inherited pass to it would take a line. Def order is simply the wrong rule here. It
68
+ * is the 2D painter's rule, and it earns its keep only where nothing writes depth; a model does
69
+ * write depth, so which of two overlapping models is in front is settled by the depth buffer
70
+ * whatever order they draw in, and a *translucent* one wants farthest-first — depth order, which
71
+ * def order cannot express and which the mesh already applies for itself (`sortObjects`, see
72
+ * `Models`). Nor would def order reach across a layer: a model layer is one mesh per source
73
+ * material, and no sort inside a mesh orders a def against one drawn from another part.
74
+ *
75
+ * A no-op rather than the inherited pass, so a caller that orders every other layer kind does not
76
+ * quietly appear to order this one.
77
+ */
78
+ setPaintOrder() {
79
+ // Nothing: the depth buffer orders models, and a layer's parts are separate meshes regardless.
80
+ }
81
+ /**
82
+ * Registers what to do when a member turns out to be the wrong kind. `Models` supplies a re-split;
83
+ * `undefined` clears it.
84
+ *
85
+ * A method rather than an assignable field because the container is held in `useState`, and the
86
+ * React Compiler rejects writing to a property of a state value.
87
+ * @param handler - The re-split to run, or `undefined` to clear it.
88
+ */
89
+ setKindMismatchHandler(handler) {
90
+ this.kindMismatchHandler = handler;
91
+ }
92
+ /**
93
+ * Reports that a member no longer matches {@link kind} — its `opacity` crossed 1 — so it is
94
+ * drawing from a mesh whose material describes the wrong render list. Runs the registered handler,
95
+ * if any; a container mounted outside `Models` has none and the report is simply dropped.
96
+ */
97
+ reportKindMismatch() {
98
+ this.kindMismatchHandler?.();
99
+ }
100
+ /**
101
+ * Writes a def's placement into its slot: the model's extents fitted into `bounds`.
102
+ *
103
+ * The mesh carries {@link PLAN_FROM_GLTF}, so its instances are placed in the model's own space,
104
+ * while {@link fitToBounds} answers in the plan's. Conjugating moves the placement across — undo
105
+ * the mesh's map, place, redo it — and is unavoidable: the instance matrix is innermost, so
106
+ * anything the mesh applies outside it has to be taken back inside.
107
+ * @param slot - The instance's slot.
108
+ * @param def - The def supplying the bounds.
109
+ */
110
+ place(slot, def) {
111
+ this.mesh.setMatrixAt(slot,
112
+ // Read right to left: into the plan, placed there, and back out again.
113
+ _placement
114
+ .multiplyMatrices(GLTF_FROM_PLAN, fitToBounds(this.extents, def.bounds))
115
+ .multiply(PLAN_FROM_GLTF));
116
+ }
117
+ /**
118
+ * Writes a def's opacity into its slot — **clamped to opaque unless this batch blends**.
119
+ *
120
+ * An opaque batch's material is `transparent: false`, which three answers by dropping
121
+ * `NormalBlending` to `NoBlending` (`WebGLState.setMaterial`). With blending off a fragment alpha
122
+ * below 1 is not composited but *written*, into a framebuffer the page shows through — so the
123
+ * model does not fade, it turns white.
124
+ *
125
+ * That is not a hypothetical: an opacity leaving 1 re-splits the layer, and until React commits it
126
+ * the def is still in this batch with its new opacity already written. Clamping is what makes the
127
+ * gap invisible — the model simply stays solid until the batch that can blend it takes over —
128
+ * without anything having to be fast enough.
129
+ * @param slot - The instance's slot.
130
+ * @param def - The def supplying the opacity.
131
+ */
132
+ setOpacity(slot, def) {
133
+ const opacity = this.kind === 'translucent' ? (def.opacity ?? 1) : 1;
134
+ this.mesh.setUniformAt(slot, OPACITY_UNIFORM, opacity);
135
+ }
136
+ addInstance() {
137
+ // `addInstances` grows the buffers itself if the layer outgrows its sized capacity, so there is
138
+ // nothing to pre-scan; the id comes back through the creation callback.
139
+ let slot = -1;
140
+ this.mesh.addInstances(1, (id) => {
141
+ slot = id;
142
+ });
143
+ return slot;
144
+ }
145
+ removeInstance(slot) {
146
+ this.mesh.removeInstances(slot);
147
+ }
148
+ }
149
+ /**
150
+ * Composes the transform that lands a baked model inside a def's bounds.
151
+ *
152
+ * The model is scaled uniformly — by the *smaller* of the two axis ratios, so it fits inside the
153
+ * rect rather than being stretched to it — then spun about z by the bounds' rotation and moved so its
154
+ * center sits at the bounds' center with its base at the bounds' elevation.
155
+ *
156
+ * Uniform scale is what keeps a model's proportions: a chair placed in a rect twice as wide as it is
157
+ * deep should not become a wide chair.
158
+ *
159
+ * Plan units throughout, in and out — {@link ModelContainer.place} is what carries the answer into
160
+ * the frame the mesh draws in.
161
+ * @param extents - The model's bounds, in plan units.
162
+ * @param bounds - Where the def wants it, in plan space.
163
+ * @returns The shared scratch matrix, composed. Valid until the next call.
164
+ */
165
+ export function fitToBounds(extents, bounds) {
166
+ extents.getSize(_size);
167
+ extents.getCenter(_center);
168
+ const scale = Math.min(_size.x > 0 ? bounds.size.x / _size.x : 1, _size.y > 0 ? bounds.size.y / _size.y : 1);
169
+ // Centered on xy and sitting on its base in z, before anything else moves it.
170
+ _recenter.makeTranslation(-_center.x, -_center.y, -extents.min.z);
171
+ _position.set(bounds.center.x, bounds.center.y, bounds.elevation);
172
+ _quaternion.setFromAxisAngle(Z_AXIS, bounds.rotation);
173
+ _scale.setScalar(scale);
174
+ return _matrix.compose(_position, _quaternion, _scale).multiply(_recenter);
175
+ }
176
+ /**
177
+ * glTF → plan, and its own inverse.
178
+ *
179
+ * glTF is y-up with +z toward the viewer; the plan reads x right, y down, z up. Composed rather than
180
+ * written out as sixteen numbers because it *is* the pair legacy applies to a loaded scene — a mirror
181
+ * on y, then a quarter turn about x — and three composes a matrix as `T·R·S`, so the scale is the
182
+ * one that goes first: `(x, y, z)_gltf → (x, z, y)_plan`.
183
+ *
184
+ * The determinant is negative, and has to be: on screen the plan is left-handed — x right, y down, z
185
+ * toward the viewer — while glTF is right-handed, so the only maps between them that leave a model
186
+ * **unmirrored** are themselves mirrors.
187
+ *
188
+ * Which is why a **mesh** carries this and the geometry does not. three decides face orientation
189
+ * from `matrixWorld.determinant()` alone: a mirror baked into vertices is invisible to it and
190
+ * culling comes out inverted, drawing a closed model as a hollow shell; a mirror living only in the
191
+ * instance matrix is invisible to it too, and — worse — leaves the CPU raycaster correct while the
192
+ * rasterizer is wrong. The mesh transform is the one place three accounts for it.
193
+ *
194
+ * {@link ModelContainer.place} conjugates with it and with {@link GLTF_FROM_PLAN}.
195
+ */
196
+ const PLAN_FROM_GLTF = new Matrix4()
197
+ .makeRotationX(-Math.PI / 2)
198
+ .multiply(new Matrix4().makeScale(1, -1, 1));
199
+ /**
200
+ * Plan → glTF, the way back.
201
+ *
202
+ * It happens to equal {@link PLAN_FROM_GLTF} — swapping two axes twice returns you to where you
203
+ * started — so the inverse could be spelled with the same constant and cost nothing. It is not,
204
+ * because {@link ModelContainer.place} is a conjugation and should look like one: written with a
205
+ * single constant on both sides, it reads as an error, and it would quietly *become* one the day the
206
+ * mapping stops being its own inverse.
207
+ */
208
+ const GLTF_FROM_PLAN = PLAN_FROM_GLTF.clone().invert();
209
+ /**
210
+ * The schema the mesh declares so it can hold an {@link OPACITY_UNIFORM} and a dim per slot.
211
+ *
212
+ * Both in one call although the two come from different places: `InstanceUniforms.add` merges and
213
+ * rebuilds the backing texture, so declaring them separately would build it twice per bind.
214
+ */
215
+ const MODEL_SCHEMA = {
216
+ fragment: { [OPACITY_UNIFORM]: 'float' },
217
+ vertex: { ...DIM_SCHEMA.vertex },
218
+ };
219
+ const Z_AXIS = new Vector3(0, 0, 1);
220
+ const _size = new Vector3();
221
+ const _center = new Vector3();
222
+ const _position = new Vector3();
223
+ const _scale = new Vector3();
224
+ const _quaternion = new Quaternion();
225
+ const _recenter = new Matrix4();
226
+ const _matrix = new Matrix4();
227
+ const _placement = new Matrix4();
@@ -0,0 +1,26 @@
1
+ import { type ShapeDef } from '../../types/defs';
2
+ import { type InstanceProps } from '../containers';
3
+ import { type ShapeContainer } from './shape-container';
4
+ /** Props for {@link ShapeInstance}. */
5
+ export type ShapeInstanceProps = InstanceProps<ShapeDef, ShapeContainer>;
6
+ /**
7
+ * Keeps one shape's instance current: claims a slot on mount, writes the def's transform, color,
8
+ * and visibility on mount and after every `update(def)`, and releases the slot on unmount.
9
+ *
10
+ * Renders no scene node — the mesh belongs to the container. All shape-specific knowledge lives
11
+ * here rather than in the container, so "how does one `ShapeDef` become GPU state" is answered by
12
+ * the file you would open to ask it; visibility is the exception, because `hidden` is common to
13
+ * every def type and `useDefSync` writes it for all of them.
14
+ *
15
+ * Memoized at declaration, deliberately, despite the React Compiler: a structural change hands the
16
+ * layer a fresh `defs` snapshot, so its compiled cache rebuilds every instance element and
17
+ * element-identity bailout never applies — only `memo`'s prop-equality bailout keeps the unchanged
18
+ * siblings from re-rendering. The bailout works because both props are identity-stable across
19
+ * structural changes — paint order is deliberately not a prop; the container writes it for the
20
+ * whole sibling list in one pass (`useContainer`). Correctness never depends on the memo: without
21
+ * it every instance re-renders to the same result.
22
+ * @param props - The def and its container.
23
+ * @returns `null`; the instance lives in the mesh, not the scene graph.
24
+ */
25
+ export declare const ShapeInstance: import("react").MemoExoticComponent<(props: ShapeInstanceProps) => null>;
26
+ //# sourceMappingURL=ShapeInstance.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { memo } from 'react';
2
+ import { createLogger } from '../../utils/logging';
3
+ import { shapeToMatrix, useDefSync, writeColorIfChanged, writeMatrixIfChanged, } from '../containers';
4
+ import { shapeKindOf } from './shape-container';
5
+ const logger = createLogger('shape-instance');
6
+ /**
7
+ * Keeps one shape's instance current: claims a slot on mount, writes the def's transform, color,
8
+ * and visibility on mount and after every `update(def)`, and releases the slot on unmount.
9
+ *
10
+ * Renders no scene node — the mesh belongs to the container. All shape-specific knowledge lives
11
+ * here rather than in the container, so "how does one `ShapeDef` become GPU state" is answered by
12
+ * the file you would open to ask it; visibility is the exception, because `hidden` is common to
13
+ * every def type and `useDefSync` writes it for all of them.
14
+ *
15
+ * Memoized at declaration, deliberately, despite the React Compiler: a structural change hands the
16
+ * layer a fresh `defs` snapshot, so its compiled cache rebuilds every instance element and
17
+ * element-identity bailout never applies — only `memo`'s prop-equality bailout keeps the unchanged
18
+ * siblings from re-rendering. The bailout works because both props are identity-stable across
19
+ * structural changes — paint order is deliberately not a prop; the container writes it for the
20
+ * whole sibling list in one pass (`useContainer`). Correctness never depends on the memo: without
21
+ * it every instance re-renders to the same result.
22
+ * @param props - The def and its container.
23
+ * @returns `null`; the instance lives in the mesh, not the scene graph.
24
+ */
25
+ export const ShapeInstance = memo(function ShapeInstance(props) {
26
+ const { def, container } = props;
27
+ const geometry = container.geometryFor(def.shape);
28
+ useDefSync(container, def, geometry, (slot) => {
29
+ writeMatrixIfChanged(container.mesh, slot, shapeToMatrix(def.shape));
30
+ writeColorIfChanged(container.mesh, slot, def, logger);
31
+ // Checked on every sync rather than only behind a color write, because a def leaves its batch's
32
+ // kind two ways: its alpha crosses 1, or its `shape` is replaced with one of another kind.
33
+ // Neither re-renders this layer on its own — an update reaches the instance and stops there — so
34
+ // this is where a batch learns it is holding something it should not. `shapeKindOf` returns
35
+ // before it looks at the color for a planar shape, so a flat layer pays nothing for the check.
36
+ if (shapeKindOf(def) !== container.kind)
37
+ container.reportKindMismatch();
38
+ });
39
+ return null;
40
+ });
@@ -0,0 +1,21 @@
1
+ import { type ShapeDef } from '../../types/defs';
2
+ import { type DefsProps } from '../containers';
3
+ /** Props for {@link Shapes}. */
4
+ export type ShapesProps = DefsProps<ShapeDef>;
5
+ /**
6
+ * Draws a collection of shapes as instances of one `BatchedMesh`, so they render in a single draw
7
+ * call.
8
+ *
9
+ * The container owns the capacity, the geometry cache, and paint order; the mesh itself is created
10
+ * by R3F from the container's capacity and bound back through `ref`, so R3F owns its lifetime —
11
+ * including
12
+ * disposal on unmount and StrictMode's simulated remount, where the mesh survives because the
13
+ * element is never deleted. Each def gets a {@link ShapeInstance} that owns the writes for its own
14
+ * slot; refs attach before passive effects run, so the mesh is bound before the first claim.
15
+ * Membership is reconciled by React: a new `defs` array re-renders this component, and React mounts
16
+ * or unmounts exactly the defs that entered or left — there is no differ of our own.
17
+ * @param props - The shapes to draw.
18
+ * @returns The mesh and one instance component per shape.
19
+ */
20
+ export declare function Shapes(props: ShapesProps): import("react").JSX.Element;
21
+ //# sourceMappingURL=Shapes.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { BatchedMesh } from '../../core/batch/BatchedMesh';
4
+ import { defKey, useContainer } from '../containers';
5
+ import { ColorMaterial } from '../materials/ColorMaterial';
6
+ import { SHAPE_KINDS, ShapeContainer, shapeKindOf } from './shape-container';
7
+ import { ShapeInstance } from './ShapeInstance';
8
+ /**
9
+ * Draws a collection of shapes as instances of one `BatchedMesh`, so they render in a single draw
10
+ * call.
11
+ *
12
+ * The container owns the capacity, the geometry cache, and paint order; the mesh itself is created
13
+ * by R3F from the container's capacity and bound back through `ref`, so R3F owns its lifetime —
14
+ * including
15
+ * disposal on unmount and StrictMode's simulated remount, where the mesh survives because the
16
+ * element is never deleted. Each def gets a {@link ShapeInstance} that owns the writes for its own
17
+ * slot; refs attach before passive effects run, so the mesh is bound before the first claim.
18
+ * Membership is reconciled by React: a new `defs` array re-renders this component, and React mounts
19
+ * or unmounts exactly the defs that entered or left — there is no differ of our own.
20
+ * @param props - The shapes to draw.
21
+ * @returns The mesh and one instance component per shape.
22
+ */
23
+ export function Shapes(props) {
24
+ const { defs } = props;
25
+ // Held in state rather than derived each render, the same "adjust on prop change" shape `Images`
26
+ // uses for its pack — because the split has a second trigger besides `defs`. A def's color and its
27
+ // shape are ordinary slot writes that never re-render this component, so either one crossing a
28
+ // kind boundary would otherwise leave the def in a batch that no longer suits it. `repartition` is
29
+ // what the containers call when they notice. It is also what carries the mounted batches forward,
30
+ // so the updater form is load-bearing in both places: a re-split must not forget which exist.
31
+ const [partition, setPartition] = useState(() => partitionShapes(defs, {}));
32
+ if (partition.defs !== defs)
33
+ setPartition((current) => partitionShapes(defs, current.batches));
34
+ /** Re-splits the current membership, for a batch that found a member of the wrong kind. */
35
+ function repartition() {
36
+ setPartition((current) => partitionShapes(defs, current.batches));
37
+ }
38
+ const { batches } = partition;
39
+ // A batch is **sticky**: once mounted it stays, standing empty rather than unmounting when its
40
+ // last member leaves. A color whose alpha oscillates across 1 (a selection pulse) would otherwise
41
+ // tear down and rebuild a batch per crossing — a `ShapeContainer`, a `BatchedMesh` with its typed
42
+ // arrays and data textures, and a material whose compiled program three frees along with the last
43
+ // reference to it. Between two batches that both already exist, the same crossing is a
44
+ // `deleteInstance` and an `addInstance`. That is what an entry in `batches` means: the kind has
45
+ // held a member at some point, so its batch renders whether or not it holds one now.
46
+ //
47
+ // Mounting all three up front was rejected instead: the tax is the material, not the mesh, and it
48
+ // would fall on every shape layer of every plan, including the many with no solid content at all.
49
+ // Stickiness charges it once, and only to a layer that has actually held that kind. An emptied
50
+ // batch keeps its buffers, since the container never shrinks, and draws nothing — three's
51
+ // multi-draw path returns early at zero draws.
52
+ //
53
+ // `renderOrder` is each kind's place in `SHAPE_KINDS` rather than insertion order, for the reason
54
+ // layers carry one: these batches tie on `groupOrder`, so the tiebreak would fall to
55
+ // `material.id`, which ascends in *mount* order. A layer that starts with only solids and later
56
+ // gains a flat rect would mount the planar batch second, give it the higher id, and draw it after
57
+ // the solid — the inversion Phase 1 removed at layer level, reappearing one level down.
58
+ //
59
+ // The translucent batch's number barely matters on its own: `transparent: true` puts it in three's
60
+ // transparent list, drawn after every opaque object in the scene whatever the order says. It is
61
+ // numbered anyway so the intent reads correctly and so it still orders against any other
62
+ // translucent batch tying with it.
63
+ return (_jsx(_Fragment, { children: SHAPE_KINDS.map((kind, renderOrder) => {
64
+ const members = batches[kind];
65
+ if (!members)
66
+ return null;
67
+ return (_jsx(ShapeBatch, { defs: members, kind: kind, renderOrder: renderOrder, onKindMismatch: repartition }, kind));
68
+ }) }));
69
+ }
70
+ /**
71
+ * Splits a layer's shapes three ways — the flat ones, the opaque volumes, and the translucent
72
+ * volumes — by the same {@link shapeKindOf} an instance checks itself against.
73
+ * @param defs - The layer's shapes, in paint order.
74
+ * @param mounted - The batches already mounted, whose entries are carried forward emptied.
75
+ * @returns The membership and the batches to render, each still in paint order.
76
+ */
77
+ function partitionShapes(defs, mounted) {
78
+ const batches = {};
79
+ for (const kind of SHAPE_KINDS)
80
+ if (mounted[kind])
81
+ batches[kind] = [];
82
+ for (const def of defs)
83
+ (batches[shapeKindOf(def)] ??= []).push(def);
84
+ return { defs, batches };
85
+ }
86
+ /**
87
+ * One `BatchedMesh` and its instances — a layer's flat shapes or its volumes, never both. It may
88
+ * hold none: `Shapes` keeps a batch mounted after its last member leaves, and an empty one draws
89
+ * nothing until a def of its kind arrives.
90
+ * @param props - The shapes, and which kind they are.
91
+ * @returns The mesh and one instance component per shape.
92
+ */
93
+ function ShapeBatch(props) {
94
+ const { defs, kind, renderOrder, onKindMismatch } = props;
95
+ // Sized from the first render's defs; membership changes grow the mesh in place, never rebuild
96
+ // it. The container is bookkeeping plus CPU-side template geometries, so the copy StrictMode's
97
+ // double-invoked initializer discards and the one an unmount strands are both plain garbage.
98
+ //
99
+ // Stickiness costs this nothing: a batch mounts on the render that first fills it, so the defs
100
+ // sizing the container are a real membership rather than the empty one it may later stand at.
101
+ const container = useContainer(() => new ShapeContainer(defs, kind), defs);
102
+ // Assigned after mount rather than passed to the constructor: the container is built once and
103
+ // outlives every render, so it cannot close over a current callback. Nothing can fire before this
104
+ // runs — the split that placed these defs was computed from the same colors they mount with.
105
+ useEffect(() => {
106
+ container.setKindMismatchHandler(onKindMismatch);
107
+ return () => container.setKindMismatchHandler(undefined);
108
+ }, [container, onKindMismatch]);
109
+ // Declares the incoming membership before React mounts the delta, so a change that outgrows the
110
+ // mesh resizes each buffer once, to exactly this size, instead of once per claiming instance.
111
+ // During render on purpose: instances claim in their mount effects, which run before any effect
112
+ // of this component could — and the call writes idempotent bookkeeping, so a repeated or
113
+ // discarded render is harmless.
114
+ container.reserve(defs);
115
+ // `args` is diffed element-wise and a change would dispose and rebuild the mesh, orphaning every
116
+ // claimed slot — `capacity` is a frozen snapshot, so that never happens. The `ref` arrow is
117
+ // deliberate: `ref={container.bind}` would make the React Compiler infer `container` itself as a
118
+ // ref and reject its render-time reads.
119
+ return (_jsxs(_Fragment, { children: [_jsx(BatchedMesh, { args: container.capacity, ref: (mesh) => container.bind(mesh), customSort: container.customSort, renderOrder: renderOrder, children: _jsx(ColorMaterial, { solid: kind !== 'planar', translucent: kind === 'translucent' }) }), defs.map((def) => (_jsx(ShapeInstance, { def: def, container: container }, defKey(def))))] }));
120
+ }
@@ -0,0 +1,2 @@
1
+ export { Shapes, type ShapesProps } from './Shapes';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { Shapes } from './Shapes';
@@ -0,0 +1,165 @@
1
+ import { type Shape } from '@expofp/geometry';
2
+ import { type BufferGeometry, type Intersection } from 'three';
3
+ import { type BatchedMeshExt } from '../../core/batch/BatchedMesh';
4
+ import { type RenderableDef, type ShapeDef } from '../../types/defs';
5
+ import { SlotContainer } from '../containers';
6
+ /**
7
+ * Every kind of shape batch, **in the order they draw within a layer** — which is what `Shapes`
8
+ * takes each batch's `renderOrder` from, so this list is the one place that order is stated.
9
+ *
10
+ * Solids draw after the flat shapes, so a volume occludes the flat content of its own layer rather
11
+ * than being painted over by it — the same rule that governs whole layers, applied within one.
12
+ */
13
+ export declare const SHAPE_KINDS: readonly ['planar', 'solid', 'translucent'];
14
+ /**
15
+ * Which of a layer's three shape batches a def belongs in, and what that batch is for:
16
+ *
17
+ * - `planar` — flat content: unlit, no depth writes, placed by draw order alone.
18
+ * - `solid` — opaque volumes: lit and depth-writing, drawn in the ordered stream.
19
+ * - `translucent` — the same volumes, drawn in three's transparent pass.
20
+ *
21
+ * One value rather than the `solid`/`translucent` pair it replaces. The pair could express a
22
+ * translucent-but-flat batch, which nothing partitions for and no material describes, and it split
23
+ * one fact across a field each reader needed and a field none did. This is also the "kind" that
24
+ * {@link ShapeContainer.reportKindMismatch} and its handler have always named.
25
+ *
26
+ * Derived from {@link SHAPE_KINDS} rather than listed again, so the two cannot drift.
27
+ */
28
+ export type ShapeKind = (typeof SHAPE_KINDS)[number];
29
+ /**
30
+ * The batch a def belongs in.
31
+ *
32
+ * A shape is **solid** exactly when it is a `Mesh` whose vertices span more than one z — elevation is
33
+ * placement, not volume, so a quad or a lifted-but-flat mesh stays planar and is placed correctly by
34
+ * draw order alone. A solid is **translucent** when its color carries an alpha below 1. That has to
35
+ * be a partition rather than a per-instance flag because `transparent` is a *material* property:
36
+ * three decides which render list an object belongs to, never which instance, so two solids of
37
+ * differing transparency cannot share a mesh.
38
+ *
39
+ * **Only volumes split on translucency.** A flat shape with an alpha below 1 stays `planar`, because
40
+ * flat content already blends without leaving the opaque list: `sharedParams` reaches alpha blending
41
+ * through `CustomBlending` rather than through `transparent: true`, which three honors either way,
42
+ * and nothing planar writes depth. So array order is the whole of it — a translucent flat shape
43
+ * blends over whatever precedes it, and an opaque one authored later paints straight over it. That
44
+ * last part is a capability, not an accident: ordering an opaque fill after a translucent one is how
45
+ * a caller occludes it, and a batch of its own would take that away by forcing it after every opaque
46
+ * object in the scene, where nothing in its layer could cover it again.
47
+ *
48
+ * A volume has no such freedom. It writes depth and is depth-tested, so what ends up on top is the
49
+ * depth buffer's answer rather than the author's, and blending correctly means being drawn after the
50
+ * opaque content it blends with — which is a render pass, and therefore a batch.
51
+ *
52
+ * One function rather than a predicate in `Shapes` that places a def and another in `ShapeInstance`
53
+ * that notices it no longer belongs. Those are the same question, and two expressions of it can
54
+ * drift — a def placed by one rule and checked by the other would either sit in the wrong batch or
55
+ * ask to be re-split forever. A planar shape returns before the color is looked at, so the parse
56
+ * costs nothing on the many layers holding only flat content.
57
+ * @param def - The def to classify.
58
+ * @returns The kind of batch it draws from.
59
+ */
60
+ export declare function shapeKindOf(def: ShapeDef): ShapeKind;
61
+ /**
62
+ * One shape layer's mesh bookkeeping: reserved buffer space, slot allocation, which geometries the
63
+ * mesh has registered, and the paint-order table.
64
+ *
65
+ * Slot allocation is the mesh's own — `addInstance`/`deleteInstance` maintain its free list — so
66
+ * what this adds is what the mesh will not track: how much vertex and index space is reserved, and
67
+ * which of its geometry ids each template was given. Building the templates is not its work either;
68
+ * they come from {@link shapeGeometry}, which caches them across every container.
69
+ */
70
+ export declare class ShapeContainer extends SlotContainer<BufferGeometry, BatchedMeshExt, ShapeDef> {
71
+ /**
72
+ * The mesh's constructor args, sized to hold the defs the container was created with exactly.
73
+ * Passed as `<batchedMesh args={container.capacity}>`; R3F diffs `args` element-wise and a change
74
+ * disposes and rebuilds the mesh, orphaning every claimed slot — so this is a snapshot taken at
75
+ * creation, which growth never mutates.
76
+ */
77
+ readonly capacity: [instances: number, vertices: number, indices: number];
78
+ /**
79
+ * Which kind of member this container holds, and so what its mesh is laid out for: a volume batch
80
+ * carries creased normals for the lit material and is non-indexed because that is what
81
+ * `toCreasedNormals` produces, and a translucent one draws in three's transparent pass. A member
82
+ * whose color stops matching is in the wrong pass, which is what {@link reportKindMismatch} exists
83
+ * to correct.
84
+ */
85
+ readonly kind: ShapeKind;
86
+ /**
87
+ * Which id the mesh gave each geometry it has registered. Per container even though the templates
88
+ * behind them are shared, because an id is the mesh's own numbering into its own buffers.
89
+ */
90
+ private readonly geometryIds;
91
+ /** What is allocated now, which growth mutates — unlike the {@link capacity} snapshot. */
92
+ private readonly allocated;
93
+ /**
94
+ * What the next growth jumps to, refreshed by {@link reserve}. Kept apart from {@link allocated}:
95
+ * a reservation must not resize anything by itself, only size the resize an overflowing claim was
96
+ * going to do anyway.
97
+ */
98
+ private readonly target;
99
+ private kindMismatchHandler;
100
+ /**
101
+ * Builds a shape layer's container, sized to hold `defs` exactly so a layer that mounts full never
102
+ * reallocates. The mesh itself is R3F's: the component renders `<batchedMesh>` from
103
+ * {@link capacity} and hands it over through {@link SlotContainer.bind}, and R3F disposes it on
104
+ * unmount. Nothing else needs disposal — `addGeometry` copies the template geometries' data into
105
+ * the mesh, so the templates are never uploaded to the GPU. They are not this container's to free
106
+ * in any case: {@link shapeGeometry} shares them across every container, and each is collected
107
+ * with the shape that keyed it.
108
+ * @param defs - The layer's shapes, used only to size the initial capacity.
109
+ * @param kind - Which of the layer's batches this is. A batched mesh mirrors its first geometry's
110
+ * attributes *and* its index-ness, and three rejects any later geometry that disagrees — so this
111
+ * decides the layout for every geometry in it, the shared unit plane included. It also decides
112
+ * the render pass its members belong to, and therefore which colors are at home in it.
113
+ */
114
+ constructor(defs: readonly ShapeDef[], kind?: ShapeKind);
115
+ /**
116
+ * The geometry a shape draws with, in this container's layout. Resolved through the shared cache,
117
+ * so a shape drawn by two containers — the same volume in the opaque and the translucent batch —
118
+ * is built once and handed to both.
119
+ * @param shape - The shape to resolve.
120
+ * @returns The geometry, built on first use.
121
+ */
122
+ geometryFor(shape: Shape): BufferGeometry;
123
+ /**
124
+ * Declares the membership this container is about to hold, setting the size the next growth jumps
125
+ * to. The component calls this from render, before React mounts the instances that will claim in
126
+ * their effects — so a membership change that outgrows the buffers costs one resize per buffer,
127
+ * sized exactly, instead of one per claim. Bookkeeping only: nothing resizes until a claim or
128
+ * geometry registration actually overflows, so a reservation from a discarded or repeated render
129
+ * is harmless.
130
+ * @param defs - The shapes this container is about to hold.
131
+ */
132
+ reserve(defs: readonly ShapeDef[]): void;
133
+ /**
134
+ * Registers what to do when a member turns out to be the wrong kind. `Shapes` supplies a re-split;
135
+ * `undefined` clears it.
136
+ *
137
+ * A method rather than an assignable field because the container is held in `useState`, and the
138
+ * React Compiler rejects writing to a property of a state value ("This value cannot be modified").
139
+ * Calling a method is fine, which is how {@link reserve} already mutates.
140
+ * @param handler - The re-split to run, or `undefined` to clear it.
141
+ */
142
+ setKindMismatchHandler(handler: (() => void) | undefined): void;
143
+ /**
144
+ * Reports that a member no longer matches {@link kind} — its color crossed alpha 1, or its shape
145
+ * was replaced with one of another kind — so it is drawing from the wrong batch. Runs the registered handler, if any;
146
+ * a container mounted outside `Shapes` has none and the report is simply dropped.
147
+ */
148
+ reportKindMismatch(): void;
149
+ /**
150
+ * A batched mesh reports the instance it hit as `batchId`, which is the slot this container
151
+ * allocated.
152
+ * @param hit - The intersection to trace.
153
+ * @returns The def, or `undefined` when the hit cannot be traced to one.
154
+ */
155
+ defFromHit(hit: Intersection): RenderableDef | undefined;
156
+ protected addInstance(geometry: BufferGeometry): number;
157
+ protected removeInstance(slot: number): void;
158
+ /**
159
+ * Registers a geometry with the mesh if it is not already, growing the buffers first.
160
+ * @param geometry - The geometry to register.
161
+ * @returns The mesh's geometry id.
162
+ */
163
+ private geometryIdFor;
164
+ }
165
+ //# sourceMappingURL=shape-container.d.ts.map