@expofp/renderer 0.0.0-experimental.cf063fc

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 (280) hide show
  1. package/README.md +145 -0
  2. package/dist/Renderer.d.ts +102 -0
  3. package/dist/Renderer.js +96 -0
  4. package/dist/controls/CameraControls.d.ts +108 -0
  5. package/dist/controls/CameraControls.js +203 -0
  6. package/dist/controls/Controls.d.ts +53 -0
  7. package/dist/controls/Controls.js +54 -0
  8. package/dist/controls/camera-api.d.ts +226 -0
  9. package/dist/controls/camera-api.js +179 -0
  10. package/dist/controls/gestures.d.ts +71 -0
  11. package/dist/controls/gestures.js +98 -0
  12. package/dist/controls/handlers/DoubleTapZoom.d.ts +23 -0
  13. package/dist/controls/handlers/DoubleTapZoom.js +82 -0
  14. package/dist/controls/handlers/Inertia.d.ts +60 -0
  15. package/dist/controls/handlers/Inertia.js +222 -0
  16. package/dist/controls/handlers/Pan.d.ts +23 -0
  17. package/dist/controls/handlers/Pan.js +212 -0
  18. package/dist/controls/handlers/Pitch.d.ts +19 -0
  19. package/dist/controls/handlers/Pitch.js +200 -0
  20. package/dist/controls/handlers/Roll.d.ts +30 -0
  21. package/dist/controls/handlers/Roll.js +196 -0
  22. package/dist/controls/handlers/Zoom.d.ts +28 -0
  23. package/dist/controls/handlers/Zoom.js +34 -0
  24. package/dist/controls/hooks.d.ts +136 -0
  25. package/dist/controls/hooks.js +200 -0
  26. package/dist/controls/index.d.ts +9 -0
  27. package/dist/controls/index.js +7 -0
  28. package/dist/controls/zoom-to.d.ts +89 -0
  29. package/dist/controls/zoom-to.js +91 -0
  30. package/dist/core/InstanceUniforms.d.ts +108 -0
  31. package/dist/core/InstanceUniforms.js +298 -0
  32. package/dist/core/SquareDataTexture.d.ts +277 -0
  33. package/dist/core/SquareDataTexture.js +476 -0
  34. package/dist/core/batch/BatchedMesh.d.ts +74 -0
  35. package/dist/core/batch/BatchedMesh.js +155 -0
  36. package/dist/core/instanced/FrustumCulling.d.ts +141 -0
  37. package/dist/core/instanced/FrustumCulling.js +246 -0
  38. package/dist/core/instanced/InstancedMesh.d.ts +302 -0
  39. package/dist/core/instanced/InstancedMesh.js +497 -0
  40. package/dist/core/instanced/Instances.d.ts +119 -0
  41. package/dist/core/instanced/Instances.js +230 -0
  42. package/dist/core/instanced/Raycasting.d.ts +118 -0
  43. package/dist/core/instanced/Raycasting.js +134 -0
  44. package/dist/core/instanced/instanced-material.d.ts +77 -0
  45. package/dist/core/instanced/instanced-material.js +228 -0
  46. package/dist/core/lines/BatchedLines.d.ts +137 -0
  47. package/dist/core/lines/BatchedLines.js +215 -0
  48. package/dist/core/lines/FrustumCullingLines.d.ts +44 -0
  49. package/dist/core/lines/FrustumCullingLines.js +85 -0
  50. package/dist/core/lines/RaycastingLines.d.ts +45 -0
  51. package/dist/core/lines/RaycastingLines.js +91 -0
  52. package/dist/core/lines/lines-material.d.ts +47 -0
  53. package/dist/core/lines/lines-material.js +124 -0
  54. package/dist/core/shader-source.d.ts +70 -0
  55. package/dist/core/shader-source.js +110 -0
  56. package/dist/core/sprites/BatchedSprites.d.ts +115 -0
  57. package/dist/core/sprites/BatchedSprites.js +173 -0
  58. package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
  59. package/dist/core/sprites/RaycastingSprites.js +71 -0
  60. package/dist/core/sprites/sprite-material.d.ts +59 -0
  61. package/dist/core/sprites/sprite-material.js +192 -0
  62. package/dist/core/text/BatchedText.d.ts +233 -0
  63. package/dist/core/text/BatchedText.js +473 -0
  64. package/dist/core/text/MemberTexture.d.ts +90 -0
  65. package/dist/core/text/MemberTexture.js +289 -0
  66. package/dist/core/text/Text.d.ts +88 -0
  67. package/dist/core/text/Text.js +230 -0
  68. package/dist/core/text/batched-text-material.d.ts +56 -0
  69. package/dist/core/text/batched-text-material.js +123 -0
  70. package/dist/core/text/glyph-packing.d.ts +17 -0
  71. package/dist/core/text/glyph-packing.js +61 -0
  72. package/dist/core/typed-array.d.ts +16 -0
  73. package/dist/core/typed-array.js +20 -0
  74. package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
  75. package/dist/debug/components/DebugPanelProvider.js +50 -0
  76. package/dist/debug/components/DebugTools.d.ts +22 -0
  77. package/dist/debug/components/DebugTools.js +28 -0
  78. package/dist/debug/components/Gui.d.ts +22 -0
  79. package/dist/debug/components/Gui.js +42 -0
  80. package/dist/debug/components/MemoryInfo.d.ts +22 -0
  81. package/dist/debug/components/MemoryInfo.js +42 -0
  82. package/dist/debug/components/Panel.d.ts +31 -0
  83. package/dist/debug/components/Panel.js +104 -0
  84. package/dist/debug/components/Stats.d.ts +9 -0
  85. package/dist/debug/components/Stats.js +24 -0
  86. package/dist/debug/debug-chunk.d.ts +26 -0
  87. package/dist/debug/debug-chunk.js +32 -0
  88. package/dist/debug/debug-context.d.ts +41 -0
  89. package/dist/debug/debug-context.js +59 -0
  90. package/dist/debug/index.d.ts +41 -0
  91. package/dist/debug/index.js +43 -0
  92. package/dist/events/LayoutDriver.d.ts +36 -0
  93. package/dist/events/LayoutDriver.js +192 -0
  94. package/dist/events/PointerMissed.d.ts +23 -0
  95. package/dist/events/PointerMissed.js +58 -0
  96. package/dist/events/def-culling.d.ts +46 -0
  97. package/dist/events/def-culling.js +69 -0
  98. package/dist/events/layout-targets.d.ts +151 -0
  99. package/dist/events/layout-targets.js +397 -0
  100. package/dist/events/placement/box.d.ts +59 -0
  101. package/dist/events/placement/box.js +96 -0
  102. package/dist/events/placement/grid.d.ts +161 -0
  103. package/dist/events/placement/grid.js +235 -0
  104. package/dist/events/placement/index.d.ts +2 -0
  105. package/dist/events/placement/index.js +1 -0
  106. package/dist/events/placement/pass.d.ts +70 -0
  107. package/dist/events/placement/pass.js +617 -0
  108. package/dist/events/pointer.d.ts +194 -0
  109. package/dist/events/pointer.js +356 -0
  110. package/dist/external/ExternalCanvas.d.ts +56 -0
  111. package/dist/external/ExternalCanvas.js +177 -0
  112. package/dist/external/external-camera.d.ts +18 -0
  113. package/dist/external/external-camera.js +103 -0
  114. package/dist/external/external-events.d.ts +14 -0
  115. package/dist/external/external-events.js +33 -0
  116. package/dist/index.d.ts +13 -0
  117. package/dist/index.js +14 -0
  118. package/dist/objects/Background.d.ts +31 -0
  119. package/dist/objects/Background.js +37 -0
  120. package/dist/objects/containers/SlotContainer.d.ts +312 -0
  121. package/dist/objects/containers/SlotContainer.js +311 -0
  122. package/dist/objects/containers/hooks.d.ts +61 -0
  123. package/dist/objects/containers/hooks.js +196 -0
  124. package/dist/objects/containers/index.d.ts +6 -0
  125. package/dist/objects/containers/index.js +4 -0
  126. package/dist/objects/containers/keys.d.ts +10 -0
  127. package/dist/objects/containers/keys.js +18 -0
  128. package/dist/objects/containers/mesh-writes.d.ts +106 -0
  129. package/dist/objects/containers/mesh-writes.js +97 -0
  130. package/dist/objects/containers/props.d.ts +33 -0
  131. package/dist/objects/containers/props.js +1 -0
  132. package/dist/objects/images/ImageInstance.d.ts +29 -0
  133. package/dist/objects/images/ImageInstance.js +152 -0
  134. package/dist/objects/images/Images.d.ts +49 -0
  135. package/dist/objects/images/Images.js +394 -0
  136. package/dist/objects/images/atlas-packer.d.ts +129 -0
  137. package/dist/objects/images/atlas-packer.js +287 -0
  138. package/dist/objects/images/image-container.d.ts +74 -0
  139. package/dist/objects/images/image-container.js +100 -0
  140. package/dist/objects/images/index.d.ts +2 -0
  141. package/dist/objects/images/index.js +1 -0
  142. package/dist/objects/images/pack-sources.d.ts +190 -0
  143. package/dist/objects/images/pack-sources.js +272 -0
  144. package/dist/objects/images/texture-budget.d.ts +120 -0
  145. package/dist/objects/images/texture-budget.js +215 -0
  146. package/dist/objects/images/worker/atlas-worker.d.ts +56 -0
  147. package/dist/objects/images/worker/atlas-worker.js +123 -0
  148. package/dist/objects/images/worker/client.d.ts +62 -0
  149. package/dist/objects/images/worker/client.js +249 -0
  150. package/dist/objects/images/worker/index.d.ts +10 -0
  151. package/dist/objects/images/worker/index.js +1 -0
  152. package/dist/objects/layer/Layer.d.ts +28 -0
  153. package/dist/objects/layer/Layer.js +134 -0
  154. package/dist/objects/layer/index.d.ts +2 -0
  155. package/dist/objects/layer/index.js +1 -0
  156. package/dist/objects/layer/layer-context.d.ts +74 -0
  157. package/dist/objects/layer/layer-context.js +82 -0
  158. package/dist/objects/layer/mount-scheduler.d.ts +131 -0
  159. package/dist/objects/layer/mount-scheduler.js +289 -0
  160. package/dist/objects/layer/visibility-gui.d.ts +19 -0
  161. package/dist/objects/layer/visibility-gui.js +93 -0
  162. package/dist/objects/lighting/Lighting.d.ts +92 -0
  163. package/dist/objects/lighting/Lighting.js +384 -0
  164. package/dist/objects/lighting/OcclusionPasses.d.ts +23 -0
  165. package/dist/objects/lighting/OcclusionPasses.js +271 -0
  166. package/dist/objects/lighting/index.d.ts +11 -0
  167. package/dist/objects/lighting/index.js +10 -0
  168. package/dist/objects/lighting/lighting-gui.d.ts +24 -0
  169. package/dist/objects/lighting/lighting-gui.js +114 -0
  170. package/dist/objects/lighting/occluder.d.ts +34 -0
  171. package/dist/objects/lighting/occluder.js +62 -0
  172. package/dist/objects/lighting/occlusion-targets.d.ts +143 -0
  173. package/dist/objects/lighting/occlusion-targets.js +276 -0
  174. package/dist/objects/lines/LineInstance.d.ts +21 -0
  175. package/dist/objects/lines/LineInstance.js +73 -0
  176. package/dist/objects/lines/Lines.d.ts +17 -0
  177. package/dist/objects/lines/Lines.js +31 -0
  178. package/dist/objects/lines/index.d.ts +2 -0
  179. package/dist/objects/lines/index.js +1 -0
  180. package/dist/objects/lines/line-container.d.ts +35 -0
  181. package/dist/objects/lines/line-container.js +40 -0
  182. package/dist/objects/materials/ColorMaterial.d.ts +92 -0
  183. package/dist/objects/materials/ColorMaterial.js +124 -0
  184. package/dist/objects/materials/LineMaterial.d.ts +44 -0
  185. package/dist/objects/materials/LineMaterial.js +74 -0
  186. package/dist/objects/materials/ModelMaterial.d.ts +53 -0
  187. package/dist/objects/materials/ModelMaterial.js +111 -0
  188. package/dist/objects/materials/TextureMaterial.d.ts +33 -0
  189. package/dist/objects/materials/TextureMaterial.js +48 -0
  190. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.d.ts +77 -0
  191. package/dist/objects/materials/effects/ao/ambient-occlusion-pass.js +296 -0
  192. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.d.ts +29 -0
  193. package/dist/objects/materials/effects/ao/ambient-occlusion-patch.js +115 -0
  194. package/dist/objects/materials/effects/ao/blur-pass.d.ts +61 -0
  195. package/dist/objects/materials/effects/ao/blur-pass.js +101 -0
  196. package/dist/objects/materials/effects/ao/index.d.ts +129 -0
  197. package/dist/objects/materials/effects/ao/index.js +72 -0
  198. package/dist/objects/materials/effects/color-dim.d.ts +115 -0
  199. package/dist/objects/materials/effects/color-dim.js +206 -0
  200. package/dist/objects/materials/effects/contact-shadow.d.ts +100 -0
  201. package/dist/objects/materials/effects/contact-shadow.js +167 -0
  202. package/dist/objects/materials/effects/effects-context.d.ts +53 -0
  203. package/dist/objects/materials/effects/effects-context.js +24 -0
  204. package/dist/objects/materials/shared.d.ts +24 -0
  205. package/dist/objects/materials/shared.js +72 -0
  206. package/dist/objects/models/ModelInstance.d.ts +22 -0
  207. package/dist/objects/models/ModelInstance.js +33 -0
  208. package/dist/objects/models/Models.d.ts +22 -0
  209. package/dist/objects/models/Models.js +186 -0
  210. package/dist/objects/models/gltf-cache.d.ts +17 -0
  211. package/dist/objects/models/gltf-cache.js +50 -0
  212. package/dist/objects/models/index.d.ts +2 -0
  213. package/dist/objects/models/index.js +1 -0
  214. package/dist/objects/models/model-asset.d.ts +48 -0
  215. package/dist/objects/models/model-asset.js +77 -0
  216. package/dist/objects/models/model-container.d.ts +123 -0
  217. package/dist/objects/models/model-container.js +207 -0
  218. package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
  219. package/dist/objects/shapes/ShapeInstance.js +39 -0
  220. package/dist/objects/shapes/Shapes.d.ts +21 -0
  221. package/dist/objects/shapes/Shapes.js +131 -0
  222. package/dist/objects/shapes/index.d.ts +2 -0
  223. package/dist/objects/shapes/index.js +1 -0
  224. package/dist/objects/shapes/shape-container.d.ts +141 -0
  225. package/dist/objects/shapes/shape-container.js +242 -0
  226. package/dist/objects/shapes/shape-geometry.d.ts +27 -0
  227. package/dist/objects/shapes/shape-geometry.js +94 -0
  228. package/dist/objects/text/TextInstance.d.ts +22 -0
  229. package/dist/objects/text/TextInstance.js +95 -0
  230. package/dist/objects/text/Texts.d.ts +30 -0
  231. package/dist/objects/text/Texts.js +43 -0
  232. package/dist/objects/text/index.d.ts +2 -0
  233. package/dist/objects/text/index.js +1 -0
  234. package/dist/objects/text/text-container.d.ts +121 -0
  235. package/dist/objects/text/text-container.js +229 -0
  236. package/dist/objects/text/text-layout.d.ts +92 -0
  237. package/dist/objects/text/text-layout.js +180 -0
  238. package/dist/space/Camera.d.ts +103 -0
  239. package/dist/space/Camera.js +321 -0
  240. package/dist/space/Scene.d.ts +47 -0
  241. package/dist/space/Scene.js +127 -0
  242. package/dist/space/Space.d.ts +325 -0
  243. package/dist/space/Space.js +359 -0
  244. package/dist/space/VisibleRect.d.ts +45 -0
  245. package/dist/space/VisibleRect.js +129 -0
  246. package/dist/space/camera-handle.d.ts +67 -0
  247. package/dist/space/camera-handle.js +63 -0
  248. package/dist/space/camera-kind.d.ts +26 -0
  249. package/dist/space/camera-kind.js +30 -0
  250. package/dist/space/canvas-size.d.ts +24 -0
  251. package/dist/space/canvas-size.js +20 -0
  252. package/dist/space/clipping.d.ts +69 -0
  253. package/dist/space/clipping.js +130 -0
  254. package/dist/space/layout-measure.d.ts +67 -0
  255. package/dist/space/layout-measure.js +175 -0
  256. package/dist/space/viewport.d.ts +112 -0
  257. package/dist/space/viewport.js +67 -0
  258. package/dist/types/defs.d.ts +234 -0
  259. package/dist/types/defs.js +1 -0
  260. package/dist/types/events.d.ts +198 -0
  261. package/dist/types/events.js +1 -0
  262. package/dist/types/guards.d.ts +21 -0
  263. package/dist/types/guards.js +52 -0
  264. package/dist/update/index.d.ts +3 -0
  265. package/dist/update/index.js +2 -0
  266. package/dist/update/slot-writers.d.ts +30 -0
  267. package/dist/update/slot-writers.js +76 -0
  268. package/dist/update/store.d.ts +41 -0
  269. package/dist/update/store.js +104 -0
  270. package/dist/utils/arrays.d.ts +13 -0
  271. package/dist/utils/arrays.js +20 -0
  272. package/dist/utils/colors.d.ts +19 -0
  273. package/dist/utils/colors.js +27 -0
  274. package/dist/utils/hot-state.d.ts +41 -0
  275. package/dist/utils/hot-state.js +37 -0
  276. package/dist/utils/logging.d.ts +29 -0
  277. package/dist/utils/logging.js +55 -0
  278. package/dist/utils/math.d.ts +52 -0
  279. package/dist/utils/math.js +76 -0
  280. package/package.json +79 -0
@@ -0,0 +1,129 @@
1
+ import { type ImageDef, type ImageSource } from '../../types/defs';
2
+ import { type AtlasCanvas, type CreateAtlasCanvas, type SourceRect, type UvRect } from './pack-sources';
3
+ export { type AtlasCanvas, type CreateAtlasCanvas, isResizableSource, type SourceRect, type UvRect, } from './pack-sources';
4
+ /**
5
+ * The pixels an atlas can hold: a canvas, or a bitmap transferred out of one.
6
+ *
7
+ * `AtlasCanvas` stays narrow on purpose. `CreateAtlasCanvas` and `contextOf` both need a type they
8
+ * can open a 2D context on, and an `ImageBitmap` has no context to open.
9
+ */
10
+ export type AtlasImage = AtlasCanvas | ImageBitmap;
11
+ /** One image, or one tile of a split image, placed in an atlas. */
12
+ export interface PackedImage {
13
+ /**
14
+ * The def that these pixels belong to. Defs whose sources dedupe appear as separate entries
15
+ * that share one region, so the list maps one-to-one onto the instances that an atlas must
16
+ * draw.
17
+ */
18
+ def: ImageDef;
19
+ /** Where the pixels sit in the atlas. */
20
+ uv: UvRect;
21
+ /**
22
+ * Which part of `def.source` this entry holds. This is undefined when the source packs whole,
23
+ * which is the common case. It is set only on the tiles of a split source, where a consumer
24
+ * needs it to work out the fraction of `def.bounds` that this tile covers.
25
+ */
26
+ source?: SourceRect;
27
+ /**
28
+ * The intrinsic pixel size of `def.source`. The packer measures this once and carries it on the
29
+ * placement, because a `Blob` source cannot be measured again later. A tile's consumer reads
30
+ * this field to find the fraction of the image the tile covers. The field spares that consumer
31
+ * from decoding the source a second time.
32
+ */
33
+ size: {
34
+ width: number;
35
+ height: number;
36
+ };
37
+ }
38
+ /** One packed atlas: its pixels, and a record of what landed where on it. */
39
+ export interface Atlas {
40
+ /**
41
+ * The atlas's packed pixels: a canvas, or a bitmap a worker transferred out of one. Its
42
+ * `width`/`height` are the atlas's size.
43
+ */
44
+ image: AtlasImage;
45
+ /** Every def placement on this atlas. */
46
+ images: PackedImage[];
47
+ /**
48
+ * Whether this atlas's pixels can shrink to fit a memory budget. Image and bitmap sources pack
49
+ * into resizable atlases. Canvas sources pack into fixed ones. An atlas never mixes the two
50
+ * kinds, because the code packs them as separate groups. So this one flag applies to every
51
+ * placement on the atlas. It lets a memory budget scale a whole resizable canvas at once,
52
+ * without changing a canvas source's pixels. See {@link isResizableSource}.
53
+ */
54
+ resizable: boolean;
55
+ }
56
+ /** Options for {@link packAtlases}. */
57
+ export interface AtlasPackerOptions {
58
+ /** Creates each atlas canvas. Defaults to {@link createAtlasCanvas}. */
59
+ createCanvas?: CreateAtlasCanvas;
60
+ /**
61
+ * Abandons the pack. A repack that supersedes a pack still in flight aborts that pack. The
62
+ * worker is told to drop it and goes on running, and a result that still arrives is thrown away
63
+ * instead of mounted.
64
+ */
65
+ signal?: AbortSignal;
66
+ }
67
+ /**
68
+ * Where a pack draws its atlases.
69
+ *
70
+ * There are two tiers and not three. Both tiers decode with `createImageBitmap`, because every
71
+ * build target has it (the plan's Global Constraints hold the compat data). What changes between
72
+ * the tiers is whether the drawing can leave the main thread. That turns on `OffscreenCanvas`,
73
+ * which Chrome 66 and Safari 15 do not have. The inline tier is a normal path for those targets
74
+ * and not an edge case. It is already around five times cheaper than the code it replaces, because
75
+ * it no longer decodes an `<img>`.
76
+ */
77
+ export type PackTier =
78
+ /** `Worker` and `OffscreenCanvas` are present, and every source is a `Blob`: pack off-thread. */
79
+ 'worker'
80
+ /** Anything else: decode and pack on the main thread. */
81
+ | 'inline';
82
+ /**
83
+ * Packs image defs into atlas canvases and reports where each def's pixels landed.
84
+ *
85
+ * The code first dedupes the defs. Two defs that point at the same URL, or that hold the same
86
+ * object, draw once and share one region. The code then decodes every source that is not drawable
87
+ * yet, which is what makes this function asynchronous: a `Blob` holds bytes and not pixels. The
88
+ * code then hands the decoded sources to {@link packSources}, which does the pixel work. The
89
+ * placements come back addressed by source index, and this function expands them into one entry
90
+ * per def.
91
+ *
92
+ * Packing reads only the sources' pixel dimensions, never `bounds`. So a def that later moves or
93
+ * resizes keeps its region: the quad's matrix scales it, and nothing needs repacking. A change in
94
+ * membership is different. This is a batch call with no incremental path, so an added or removed
95
+ * def needs a fresh call.
96
+ *
97
+ * A worker that fails for any reason other than an abort falls back to the inline tier once. The
98
+ * worker is an optimization, and no host page may cost a layer its images by refusing one.
99
+ * @param defs - The images to pack.
100
+ * @param maxDimension - The largest atlas edge, in pixels. The function floors this to a positive
101
+ * integer.
102
+ * @param options - Overrides for how atlas canvases are made, and the signal that abandons the
103
+ * pack.
104
+ * @returns One entry for each atlas, in packing order: resizable atlases first, then fixed ones.
105
+ */
106
+ export declare function packAtlases(defs: readonly ImageDef[], maxDimension: number, options?: AtlasPackerOptions): Promise<Atlas[]>;
107
+ /**
108
+ * Picks the higher tier when this environment and this set of sources both allow it.
109
+ *
110
+ * A layer packs in the worker only when **every** source is a `Blob`. One source of any other kind
111
+ * keeps the whole layer on the main thread.
112
+ *
113
+ * The test names what may cross, never what must stay. A test that only excludes the known-bad
114
+ * kinds admits every kind nobody thought of, and this code shipped that mistake once: it asked
115
+ * whether a source was not a DOM canvas, which let an `<img>` through. An `<img>` neither clones
116
+ * nor moves, so `postMessage` threw on it and the layer drew nothing.
117
+ *
118
+ * A `Blob` is also the only source the worker can take without taking it from the def that owns it.
119
+ * Its handle clones, so the def keeps its bytes. Every other kind would have to move, and a moved
120
+ * source is dead on the main thread, so the next repack would find nothing to draw. Those sources
121
+ * lose nothing by packing inline. A canvas cannot cross at all — `transferControlToOffscreen` throws
122
+ * on a canvas that already holds a 2D context, and every floorplan canvas source holds one — and
123
+ * `createImageBitmap(canvas)` costs more than a pack of that canvas on the main thread (this is
124
+ * measured, see the design spec).
125
+ * @param sources - The unique sources that this pack will draw.
126
+ * @returns The tier to run.
127
+ */
128
+ export declare function selectTier(sources: readonly ImageSource[]): PackTier;
129
+ //# sourceMappingURL=atlas-packer.d.ts.map
@@ -0,0 +1,287 @@
1
+ import { createLogger } from '../../utils/logging';
2
+ import { createAtlasCanvas, isBlob, packSources, } from './pack-sources';
3
+ import { packInWorker } from './worker';
4
+ const logger = createLogger('atlas-packer');
5
+ /**
6
+ * How many source pixels per square unit of `bounds` a def can carry before code calls it
7
+ * over-sampled. Past this limit, the extra resolution cannot reach the screen at any reasonable
8
+ * zoom. The atlas space and texture memory are then wasted, usually on a full-size logo that
9
+ * stands in for a marker icon.
10
+ */
11
+ const MAX_AREA_RATIO = 1000;
12
+ export { isResizableSource, } from './pack-sources';
13
+ /**
14
+ * Packs image defs into atlas canvases and reports where each def's pixels landed.
15
+ *
16
+ * The code first dedupes the defs. Two defs that point at the same URL, or that hold the same
17
+ * object, draw once and share one region. The code then decodes every source that is not drawable
18
+ * yet, which is what makes this function asynchronous: a `Blob` holds bytes and not pixels. The
19
+ * code then hands the decoded sources to {@link packSources}, which does the pixel work. The
20
+ * placements come back addressed by source index, and this function expands them into one entry
21
+ * per def.
22
+ *
23
+ * Packing reads only the sources' pixel dimensions, never `bounds`. So a def that later moves or
24
+ * resizes keeps its region: the quad's matrix scales it, and nothing needs repacking. A change in
25
+ * membership is different. This is a batch call with no incremental path, so an added or removed
26
+ * def needs a fresh call.
27
+ *
28
+ * A worker that fails for any reason other than an abort falls back to the inline tier once. The
29
+ * worker is an optimization, and no host page may cost a layer its images by refusing one.
30
+ * @param defs - The images to pack.
31
+ * @param maxDimension - The largest atlas edge, in pixels. The function floors this to a positive
32
+ * integer.
33
+ * @param options - Overrides for how atlas canvases are made, and the signal that abandons the
34
+ * pack.
35
+ * @returns One entry for each atlas, in packing order: resizable atlases first, then fixed ones.
36
+ */
37
+ export async function packAtlases(defs, maxDimension, options = {}) {
38
+ const startedAt = performance.now();
39
+ const { createCanvas = createAtlasCanvas, signal } = options;
40
+ const entries = collectSources(defs);
41
+ const sources = entries.map((entry) => entry.source);
42
+ let tier = selectTier(sources);
43
+ let packed = null;
44
+ if (tier === 'worker') {
45
+ try {
46
+ packed = await packWorkerTier(entries, sources, maxDimension, signal);
47
+ }
48
+ catch (error) {
49
+ // An abort is the caller's own decision, and nothing may run after it.
50
+ if (signal?.aborted)
51
+ throw error;
52
+ // Any other failure is the worker alone failing, and the main thread can still do the work.
53
+ // The case that matters is a host page whose `script-src` forbids `blob:` and `data:`:
54
+ // `new Worker()` throws there, this SDK runs on origins it does not control, and without
55
+ // this the layer would stay blank on that site.
56
+ logger.warn('the worker could not pack, packing inline instead %O', error);
57
+ tier = 'inline';
58
+ }
59
+ }
60
+ // Only if the worker tier did not run, or ran and failed. `??=` does not evaluate its right side
61
+ // when the left side already holds the atlases.
62
+ packed ??= await packInlineTier(entries, sources, maxDimension, createCanvas, signal);
63
+ const elapsed = (performance.now() - startedAt).toFixed(1);
64
+ logger.debug('packed defs: %d, sources: %d, atlases: %d, tier: %s (%sms)', packed.reduce((count, atlas) => count + atlas.images.length, 0), entries.length, packed.length, tier, elapsed);
65
+ return packed;
66
+ }
67
+ /**
68
+ * Picks the higher tier when this environment and this set of sources both allow it.
69
+ *
70
+ * A layer packs in the worker only when **every** source is a `Blob`. One source of any other kind
71
+ * keeps the whole layer on the main thread.
72
+ *
73
+ * The test names what may cross, never what must stay. A test that only excludes the known-bad
74
+ * kinds admits every kind nobody thought of, and this code shipped that mistake once: it asked
75
+ * whether a source was not a DOM canvas, which let an `<img>` through. An `<img>` neither clones
76
+ * nor moves, so `postMessage` threw on it and the layer drew nothing.
77
+ *
78
+ * A `Blob` is also the only source the worker can take without taking it from the def that owns it.
79
+ * Its handle clones, so the def keeps its bytes. Every other kind would have to move, and a moved
80
+ * source is dead on the main thread, so the next repack would find nothing to draw. Those sources
81
+ * lose nothing by packing inline. A canvas cannot cross at all — `transferControlToOffscreen` throws
82
+ * on a canvas that already holds a 2D context, and every floorplan canvas source holds one — and
83
+ * `createImageBitmap(canvas)` costs more than a pack of that canvas on the main thread (this is
84
+ * measured, see the design spec).
85
+ * @param sources - The unique sources that this pack will draw.
86
+ * @returns The tier to run.
87
+ */
88
+ export function selectTier(sources) {
89
+ const offthread = typeof Worker === 'function' && typeof OffscreenCanvas !== 'undefined' && sources.every(isBlob);
90
+ return offthread ? 'worker' : 'inline';
91
+ }
92
+ /**
93
+ * Packs in a worker, off the main thread.
94
+ *
95
+ * The worker decodes every source itself and builds its own offscreen canvases, so this tier
96
+ * ignores {@link AtlasPackerOptions.createCanvas}. A test that passes one is testing the inline
97
+ * tier: {@link selectTier} never picks this tier in jsdom, which has neither `Worker` nor
98
+ * `OffscreenCanvas`.
99
+ * @param entries - The unique sources, and the defs that draw each one.
100
+ * @param sources - The unique sources, aligned by index with `entries`.
101
+ * @param maxDimension - The largest atlas edge, in pixels.
102
+ * @param signal - Abandons the pack. The worker is told to drop it and goes on running.
103
+ * @returns One entry for each atlas, in packing order.
104
+ */
105
+ async function packWorkerTier(entries, sources, maxDimension, signal) {
106
+ // `selectTier` picked this tier only because every source is a `Blob`, which is what a
107
+ // `WorkerSource` is. The compiler cannot follow that, so the cast states it.
108
+ const { atlases, reports } = await packInWorker(sources, maxDimension, {
109
+ signal,
110
+ });
111
+ // `packInWorker` already rejects on abort, so the pack still stands here. The code checks again
112
+ // because an abort raised in the same turn as the reply is a real ordering.
113
+ if (signal?.aborted) {
114
+ // Nothing will mount these atlases, and an `ImageBitmap` holds its pixels outside the
115
+ // JavaScript heap, so close them here.
116
+ for (const atlas of atlases)
117
+ atlas.bitmap.close();
118
+ throw new Error('atlas-packer: the pack was aborted');
119
+ }
120
+ reportSources(entries, reports);
121
+ return atlases.map((atlas) => ({
122
+ image: atlas.bitmap,
123
+ resizable: atlas.resizable,
124
+ images: expandPlacements(atlas.placements, entries, reports),
125
+ }));
126
+ }
127
+ /**
128
+ * Packs on the main thread. This tier decodes the sources here and draws the atlases here.
129
+ * @param entries - The unique sources, and the defs that draw each one.
130
+ * @param sources - The unique sources, aligned by index with `entries`.
131
+ * @param maxDimension - The largest atlas edge, in pixels.
132
+ * @param createCanvas - Makes each atlas canvas.
133
+ * @param signal - Abandons the pack.
134
+ * @returns One entry for each atlas, in packing order.
135
+ */
136
+ async function packInlineTier(entries, sources, maxDimension, createCanvas, signal) {
137
+ const decoded = await decodeSources(sources);
138
+ // The caller abandoned the pack while the decodes were in flight, so nothing here is wanted any
139
+ // more. The code reads `signal.aborted` and not `throwIfAborted()`, which Chrome 66 and Safari
140
+ // 15 do not have.
141
+ if (signal?.aborted) {
142
+ closeDecoded(sources, decoded);
143
+ throw new Error('atlas-packer: the pack was aborted');
144
+ }
145
+ const { atlases, reports } = packSources(decoded, maxDimension, createCanvas);
146
+ // The atlases hold the pixels now, so the decoded bitmaps are dead.
147
+ closeDecoded(sources, decoded);
148
+ reportSources(entries, reports);
149
+ return atlases.map((atlas) => ({
150
+ image: atlas.canvas,
151
+ resizable: atlas.resizable,
152
+ images: expandPlacements(atlas.placements, entries, reports),
153
+ }));
154
+ }
155
+ /**
156
+ * Groups defs by the source they draw, so the pack draws identical images once.
157
+ *
158
+ * Identity is the source object itself. Two defs share a region only when they hold the exact same
159
+ * object. That is why floorplan hands two booths with one logo a single `Blob`, instead of two
160
+ * Blobs that hold the same bytes.
161
+ * @param defs - The defs to group.
162
+ * @returns One entry per unique source, in first-seen order.
163
+ */
164
+ function collectSources(defs) {
165
+ const sources = new Map();
166
+ for (const def of defs) {
167
+ let entry = sources.get(def.source);
168
+ if (!entry) {
169
+ entry = { source: def.source, defs: [], bounds: { width: 0, height: 0 } };
170
+ sources.set(def.source, entry);
171
+ }
172
+ entry.defs.push(def);
173
+ // The code copies this size instead of keeping a reference to it. `Rect` exposes an in-place
174
+ // `set` method. A kept reference lets a later bounds change rewrite what this function
175
+ // already measured.
176
+ const { width, height } = def.bounds.size;
177
+ if (width * height > entry.bounds.width * entry.bounds.height) {
178
+ entry.bounds = { width, height };
179
+ }
180
+ }
181
+ return [...sources.values()];
182
+ }
183
+ /**
184
+ * Turns the packer's index-addressed placements into one entry per def. Deduped defs all share
185
+ * the one region, which is the whole point of deduping them.
186
+ * @param placements - One atlas's placements.
187
+ * @param entries - The unique sources, aligned by index with what the code gave the packer.
188
+ * @param reports - Per-source measurements, aligned by index with `entries`. Supplies each
189
+ * placement's `size`.
190
+ * @returns One packed image for each def at each placement.
191
+ */
192
+ function expandPlacements(placements, entries, reports) {
193
+ const images = [];
194
+ for (const { index, uv, source } of placements) {
195
+ const { width, height } = reports[index];
196
+ const size = { width, height };
197
+ for (const def of entries[index].defs) {
198
+ images.push(source ? { def, uv, source, size } : { def, uv, size });
199
+ }
200
+ }
201
+ return images;
202
+ }
203
+ /**
204
+ * Reports what the pack was unable to use. This covers sources with no pixels, and sources that
205
+ * carry far more resolution than their bounds can ever show. The function warns once for each
206
+ * source, not once for each def, because deduped defs all share the one texture region.
207
+ * @param entries - The unique sources, aligned by index with `reports`.
208
+ * @param reports - What the packer measured and placed.
209
+ */
210
+ function reportSources(entries, reports) {
211
+ for (let index = 0; index < entries.length; index++) {
212
+ const entry = entries[index];
213
+ const { width, height, tiles } = reports[index];
214
+ if (tiles === 0) {
215
+ logger.warn('skipping source with no pixels (%dx%d) %O', width, height, entry.source);
216
+ continue;
217
+ }
218
+ if (tiles > 1) {
219
+ logger.warn('source %dx%d exceeds the atlas limit, split into %d tiles', width, height, tiles);
220
+ }
221
+ const boundsArea = entry.bounds.width * entry.bounds.height;
222
+ // Degenerate bounds divide out to Infinity. That triggers a warning for every such def, but
223
+ // the warning says nothing about resolution. It only points to a bug in the bounds, and this
224
+ // function does not report that kind of bug.
225
+ if (boundsArea <= 0)
226
+ continue;
227
+ const ratio = (width * height) / boundsArea;
228
+ if (ratio <= MAX_AREA_RATIO)
229
+ continue;
230
+ logger.warn('over-sampled source: %dx%d px drawn into %sx%s units — %d px per unit², limit %d', width, height,
231
+ // At most two decimals, trailing zeros dropped: 4 → 4, 4.1 → 4.1, 4.2999 → 4.3.
232
+ Number(entry.bounds.width.toFixed(2)), Number(entry.bounds.height.toFixed(2)), Math.round(ratio), MAX_AREA_RATIO);
233
+ }
234
+ }
235
+ /**
236
+ * Decodes every source that is not drawable yet, and leaves the drawable ones as they are.
237
+ *
238
+ * The code starts every decode before it waits for any one of them, so the browser decoder
239
+ * overlaps them. Each decode gives back a bitmap. The packer draws that bitmap, and the caller
240
+ * closes it.
241
+ *
242
+ * One source that does not decode must not take the layer with it. A drawing can carry an
243
+ * `<image>` whose bytes are not an image at all. A `Promise.all` over the decodes rejects the whole
244
+ * pack, so a plan with one bad graphic draws none of its graphics. A failed decode becomes `null`
245
+ * instead. {@link packSources} already treats `null` as a source with no pixels: it skips that
246
+ * source, and `reportSources` warns about it by name.
247
+ * @param sources - The unique sources to decode.
248
+ * @returns The decoded sources, aligned by index with the input. An entry is `null` where the bytes
249
+ * did not decode.
250
+ */
251
+ async function decodeSources(sources) {
252
+ return Promise.all(sources.map((source) => decodeSource(source).catch(() => null)));
253
+ }
254
+ /**
255
+ * Frees the bitmaps that this pack decoded.
256
+ *
257
+ * An `ImageBitmap` holds its pixels outside the JavaScript heap, and garbage collection does not
258
+ * reclaim that memory promptly. A pack of a thousand logos would otherwise sit on a thousand
259
+ * decoded images until it did.
260
+ *
261
+ * The pack closes only what it decoded itself, which is every source that arrived as a `Blob`. A
262
+ * def is free to hold an `ImageBitmap` of its own, and {@link decodeSource} hands such a source
263
+ * straight back. Those pixels belong to the def: the next repack draws them again, and a pack that
264
+ * closed them would empty the layer instead.
265
+ * @param sources - The unique sources, aligned by index with `decoded`.
266
+ * @param decoded - What each source decoded into.
267
+ */
268
+ function closeDecoded(sources, decoded) {
269
+ for (let index = 0; index < decoded.length; index++) {
270
+ const source = decoded[index];
271
+ if (source && isBlob(sources[index]) && 'close' in source)
272
+ source.close();
273
+ }
274
+ }
275
+ /**
276
+ * Decodes one source. Anything that is not a `Blob` is drawable already and comes back as it went
277
+ * in. A `Blob` goes through `createImageBitmap`, which every build target has.
278
+ * @param source - The source to decode.
279
+ * @returns A source that the packer can draw.
280
+ */
281
+ async function decodeSource(source) {
282
+ // A `Blob` is the only member of the union with no size and no draw. Everything else is drawable
283
+ // already.
284
+ if (!isBlob(source))
285
+ return source;
286
+ return createImageBitmap(source);
287
+ }
@@ -0,0 +1,74 @@
1
+ import { type InstancedMeshImpl, type InstancedMeshImplParams } from '../../core/instanced/InstancedMesh';
2
+ import { type ImageDef } from '../../types/defs';
3
+ import { SlotContainer } from '../containers';
4
+ import { type PackedImage } from './atlas-packer';
5
+ /**
6
+ * The per-instance uniform each atlas mesh reads its texture region from. The container owns the
7
+ * name: it writes each slot's region here (`setUniformAt`) and hands it to the mesh's
8
+ * `TextureMaterial` as the `uvOffset` prop, so the material patches its shader to sample the region
9
+ * without knowing the name itself. `xy` is the region's origin in uv space and `zw` its size, so
10
+ * `uv * zw + xy` maps the quad's unit uv onto the region.
11
+ */
12
+ export declare const UV_OFFSET_UNIFORM = "uvOffset";
13
+ /**
14
+ * The per-instance uniform each atlas mesh reads its opacity from. The container owns the name and
15
+ * hands it to the mesh's `TextureMaterial` as the `opacityUniform` prop, so the material patches its shader
16
+ * without knowing the name itself.
17
+ */
18
+ export declare const OPACITY_UNIFORM = "instanceOpacity";
19
+ /**
20
+ * The constructor tuple R3F builds one atlas's mesh from, passed as `<instancedMesh args={…}>`.
21
+ * R3F diffs `args` element-wise and rebuilds the object when any element changes, so this is
22
+ * snapshotted once and never mutated.
23
+ *
24
+ * Only the options: `InstancedMeshImpl` takes no geometry or material, seeding throwaways that the
25
+ * element's `<planeGeometry>` and `<TextureMaterial>` children replace (R3F creates, attaches, and
26
+ * disposes those).
27
+ */
28
+ export type ImageMeshArgs = [params: InstancedMeshImplParams];
29
+ /**
30
+ * One atlas's mesh bookkeeping.
31
+ *
32
+ * Simpler than a shape container, and deliberately so: an atlas draws one shared quad, so there is
33
+ * no geometry cache and no geometry-id juggling, and `InstancedMeshImpl` grows its own buffers, so
34
+ * there is no capacity pre-scan — the mesh is merely sized to the atlas's packed-image count and
35
+ * left to resize itself if a claim ever overflows it. What remains is a slot per packed image and
36
+ * the uv region each one samples, written once at claim since a def's source never changes.
37
+ *
38
+ * Paint order is incremental, like the shape container's, because packing is order-independent: a
39
+ * reorder of the same images keeps this container and only re-labels its slots, never repacking. A
40
+ * change to the *set* of images is the harder case and still repacks into a fresh container —
41
+ * packing has no incremental path for that — but a pure reorder does not.
42
+ */
43
+ export declare class ImageContainer extends SlotContainer<PackedImage, InstancedMeshImpl, ImageDef> {
44
+ /** The constructor args R3F builds the mesh from; a frozen snapshot, never mutated. */
45
+ readonly args: ImageMeshArgs;
46
+ /**
47
+ * Builds one atlas's bookkeeping. The mesh, its quad, and its material are all R3F's — the atlas
48
+ * component renders `<instancedMesh args={container.args}>` with the geometry and material as
49
+ * children, and hands the mesh back through {@link SlotContainer.bind} — so R3F owns their
50
+ * lifetimes, including disposal on unmount and survival across StrictMode's simulated remount.
51
+ * @param capacity - How many instances to size the mesh for. This is the atlas's whole placement
52
+ * count, not one kind's share of it, so moving a def between the two meshes never resizes a
53
+ * buffer. The mesh grows past it on demand in any case.
54
+ */
55
+ constructor(capacity: number);
56
+ /**
57
+ * Whether the bound mesh draws its members facing the camera.
58
+ *
59
+ * Read off the mesh rather than stored, so one field cannot disagree with another. `screenSpace` is
60
+ * an ordinary def field, so flipping it re-renders nothing and only an instance can notice that it
61
+ * is drawing from the wrong mesh.
62
+ * @returns Whether this container holds a sprite batch.
63
+ */
64
+ get facesCamera(): boolean;
65
+ /**
66
+ * Writes a def's opacity into its slot, clamped, treating an absent value as fully opaque.
67
+ * @param slot - The instance's slot.
68
+ * @param opacity - The def's opacity, or `undefined` for the default.
69
+ */
70
+ setOpacityAt(slot: number, opacity: number | undefined): void;
71
+ protected addInstance(packed: PackedImage): number;
72
+ protected removeInstance(slot: number): void;
73
+ }
74
+ //# sourceMappingURL=image-container.d.ts.map
@@ -0,0 +1,100 @@
1
+ import { Vector4 } from 'three';
2
+ import { isBatchedSprites } from '../../core/sprites/BatchedSprites';
3
+ import { SlotContainer } from '../containers';
4
+ import { DIM_SCHEMA } from '../materials/effects/color-dim';
5
+ /**
6
+ * The per-instance uniform each atlas mesh reads its texture region from. The container owns the
7
+ * name: it writes each slot's region here (`setUniformAt`) and hands it to the mesh's
8
+ * `TextureMaterial` as the `uvOffset` prop, so the material patches its shader to sample the region
9
+ * without knowing the name itself. `xy` is the region's origin in uv space and `zw` its size, so
10
+ * `uv * zw + xy` maps the quad's unit uv onto the region.
11
+ */
12
+ export const UV_OFFSET_UNIFORM = 'uvOffset';
13
+ /**
14
+ * The per-instance uniform each atlas mesh reads its opacity from. The container owns the name and
15
+ * hands it to the mesh's `TextureMaterial` as the `opacityUniform` prop, so the material patches its shader
16
+ * without knowing the name itself.
17
+ */
18
+ export const OPACITY_UNIFORM = 'instanceOpacity';
19
+ /**
20
+ * One atlas's mesh bookkeeping.
21
+ *
22
+ * Simpler than a shape container, and deliberately so: an atlas draws one shared quad, so there is
23
+ * no geometry cache and no geometry-id juggling, and `InstancedMeshImpl` grows its own buffers, so
24
+ * there is no capacity pre-scan — the mesh is merely sized to the atlas's packed-image count and
25
+ * left to resize itself if a claim ever overflows it. What remains is a slot per packed image and
26
+ * the uv region each one samples, written once at claim since a def's source never changes.
27
+ *
28
+ * Paint order is incremental, like the shape container's, because packing is order-independent: a
29
+ * reorder of the same images keeps this container and only re-labels its slots, never repacking. A
30
+ * change to the *set* of images is the harder case and still repacks into a fresh container —
31
+ * packing has no incremental path for that — but a pure reorder does not.
32
+ */
33
+ export class ImageContainer extends SlotContainer {
34
+ /** The constructor args R3F builds the mesh from; a frozen snapshot, never mutated. */
35
+ args;
36
+ /**
37
+ * Builds one atlas's bookkeeping. The mesh, its quad, and its material are all R3F's — the atlas
38
+ * component renders `<instancedMesh args={container.args}>` with the geometry and material as
39
+ * children, and hands the mesh back through {@link SlotContainer.bind} — so R3F owns their
40
+ * lifetimes, including disposal on unmount and survival across StrictMode's simulated remount.
41
+ * @param capacity - How many instances to size the mesh for. This is the atlas's whole placement
42
+ * count, not one kind's share of it, so moving a def between the two meshes never resizes a
43
+ * buffer. The mesh grows past it on demand in any case.
44
+ */
45
+ constructor(capacity) {
46
+ super({ schema: IMAGE_SCHEMA });
47
+ this.args = [{ capacity: Math.max(1, capacity) }];
48
+ }
49
+ /**
50
+ * Whether the bound mesh draws its members facing the camera.
51
+ *
52
+ * Read off the mesh rather than stored, so one field cannot disagree with another. `screenSpace` is
53
+ * an ordinary def field, so flipping it re-renders nothing and only an instance can notice that it
54
+ * is drawing from the wrong mesh.
55
+ * @returns Whether this container holds a sprite batch.
56
+ */
57
+ get facesCamera() {
58
+ return isBatchedSprites(this.mesh);
59
+ }
60
+ /**
61
+ * Writes a def's opacity into its slot, clamped, treating an absent value as fully opaque.
62
+ * @param slot - The instance's slot.
63
+ * @param opacity - The def's opacity, or `undefined` for the default.
64
+ */
65
+ setOpacityAt(slot, opacity) {
66
+ const value = opacity === undefined ? 1 : Math.min(Math.max(opacity, 0), 1);
67
+ this.mesh.setUniformAt(slot, OPACITY_UNIFORM, value);
68
+ }
69
+ addInstance(packed) {
70
+ // `addInstances` grows the buffers itself if the atlas ever overflows its sized capacity, so
71
+ // there is nothing to pre-scan; the id is captured from the creation callback.
72
+ let slot = -1;
73
+ this.mesh.addInstances(1, (id) => {
74
+ slot = id;
75
+ });
76
+ // The uv region is fixed for the instance's life — a def's source never changes, and a set
77
+ // change repacks into a fresh container — so it is written once, here, rather than on every
78
+ // sync.
79
+ const { u0, v0, u1, v1 } = packed.uv;
80
+ this.mesh.setUniformAt(slot, UV_OFFSET_UNIFORM, _uvOffset.set(u0, v0, u1 - u0, v1 - v0));
81
+ return slot;
82
+ }
83
+ removeInstance(slot) {
84
+ this.mesh.removeInstances(slot);
85
+ }
86
+ }
87
+ /**
88
+ * The schema the mesh declares (via `addUniforms`) so it can hold a {@link UV_OFFSET_UNIFORM}, a
89
+ * {@link OPACITY_UNIFORM} and a dim per slot. The opacity float keeps the schema at two texels: a flat
90
+ * mesh is `vec4` + `float` + `float` = 6 floats, and a sprite mesh's own `anchor` brings it to 8.
91
+ *
92
+ * All in one call although they come from different places: `InstanceUniforms.add` merges and
93
+ * rebuilds the backing texture, so declaring them separately would build it twice per bind.
94
+ */
95
+ const IMAGE_SCHEMA = {
96
+ vertex: { [UV_OFFSET_UNIFORM]: 'vec4', [OPACITY_UNIFORM]: 'float', ...DIM_SCHEMA.vertex },
97
+ };
98
+ // Scratch for the one uv-region upload a claim performs, filled and read within a single synchronous
99
+ // statement.
100
+ const _uvOffset = new Vector4();
@@ -0,0 +1,2 @@
1
+ export { Images, type ImagesProps } from './Images';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { Images } from './Images';