@expofp/renderer 0.0.0-experimental.2d6c681

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,249 @@
1
+ /* eslint-disable-next-line import/default -- Vite answers this specifier with a module it
2
+ generates, whose default export is a `Worker` subclass. The ESLint resolver drops the query and
3
+ reads the worker entry instead, which exports no default of its own. `vite/client` declares the
4
+ real shape, so tsc sees it. */
5
+ import AtlasWorker from './atlas-worker?worker&inline';
6
+ /**
7
+ * Packs a set of sources in a web worker.
8
+ *
9
+ * **One worker serves every pack, and no pack ever stops it.** The atlases come back as
10
+ * `ImageBitmap`s that `OffscreenCanvas.transferToImageBitmap()` produced, and Chrome backs those
11
+ * with GPU memory the worker owns. `Images` re-reads an atlas's pixels on every texture-budget
12
+ * move, and disposing a texture forces a fresh upload, so the producing worker has to outlive every
13
+ * bitmap it made, not only the first upload of it. Terminating the worker used to run before this
14
+ * function resolved, which destroyed those pixels and left booth logos blank on real GPUs.
15
+ *
16
+ * The one `terminate()` in this file is in `retire`, and it only ever stops a worker that broke
17
+ * before it handed out an atlas. A worker that has produced pixels is dropped from the pool and
18
+ * left running. The worker script is inlined into the bundle, so starting one resolves no URL at
19
+ * runtime, which matters because the SDK is loaded from origins it does not control.
20
+ *
21
+ * Each pack carries an `id`, because a shared worker can hold two layers' packs at once and a reply
22
+ * has to find its own caller. An abandoned pack is settled here and its `id` forgotten, so a reply
23
+ * that still arrives is discarded — and its atlases are closed, or each superseded pack would leak
24
+ * a layer's worth of GPU memory.
25
+ *
26
+ * The sources go over in batches so the main thread is never blocked for long by one structured
27
+ * clone, and so the worker can decode the early batches while the later ones are still being sent.
28
+ * A closing message tells it every source has arrived.
29
+ * @param sources - The unique sources to pack, in the caller's order; placements address them by
30
+ * their index in this array.
31
+ * @param maxDimension - Largest atlas edge in pixels.
32
+ * @param options - The abort signal, and the worker factory a spec overrides.
33
+ * @returns The packed atlases and one report per source.
34
+ */
35
+ export function packInWorker(sources, maxDimension, options = {}) {
36
+ const { signal, createWorker = createAtlasWorker } = options;
37
+ return new Promise((resolve, reject) => {
38
+ // Read the signal before anything is sent. A pack that is already abandoned must cost the
39
+ // worker nothing, so it posts no message at all.
40
+ if (signal?.aborted) {
41
+ reject(abandoned());
42
+ return;
43
+ }
44
+ let worker;
45
+ try {
46
+ worker = pooledWorker(createWorker);
47
+ }
48
+ catch (error) {
49
+ // A host page whose `script-src` forbids `blob:` and `data:` makes `new Worker()` throw. The
50
+ // caller falls back to an inline pack.
51
+ reject(asError(error));
52
+ return;
53
+ }
54
+ const id = ++lastRequestId;
55
+ // Every exit runs through here. Dropping this pack's entry is what stops delivery, because the
56
+ // worker is shared and goes on running.
57
+ const done = (settle) => {
58
+ signal?.removeEventListener('abort', onAbort);
59
+ pending.delete(id);
60
+ settle();
61
+ };
62
+ // A plain Error, not `signal.reason`, which Chrome 66 and Safari 15 do not have. Nothing
63
+ // branches on the error's type: every caller reads `signal.aborted` instead.
64
+ const onAbort = () => {
65
+ done(() => {
66
+ cancel(worker, id);
67
+ reject(abandoned());
68
+ });
69
+ };
70
+ pending.set(id, (message) => {
71
+ done(() => {
72
+ if (message.type === 'failed')
73
+ reject(new Error(message.message));
74
+ else
75
+ resolve({ atlases: message.atlases, reports: message.reports });
76
+ });
77
+ });
78
+ signal?.addEventListener('abort', onAbort);
79
+ try {
80
+ for (let start = 0; start < sources.length; start += SOURCE_CHUNK_SIZE) {
81
+ post(worker, {
82
+ type: 'sources',
83
+ id,
84
+ sources: sources.slice(start, start + SOURCE_CHUNK_SIZE),
85
+ });
86
+ }
87
+ post(worker, { type: 'pack', id, maxDimension });
88
+ }
89
+ catch (error) {
90
+ // `postMessage` throws when the platform refuses to copy a source. The worker keeps the
91
+ // batches that did arrive until it is told otherwise, and the closing message never comes.
92
+ done(() => {
93
+ cancel(worker, id);
94
+ reject(asError(error));
95
+ });
96
+ }
97
+ });
98
+ }
99
+ /**
100
+ * Forgets the pooled worker without stopping it, and abandons every pack waiting on it.
101
+ *
102
+ * Only a spec calls this. Each spec drives its own fake worker, and the pool would otherwise hand
103
+ * the first spec's fake to every spec after it.
104
+ */
105
+ export function resetAtlasWorkerPool() {
106
+ pool = null;
107
+ pending.clear();
108
+ }
109
+ /**
110
+ * Hands back the one worker every pack runs on, starting it on the first call.
111
+ *
112
+ * The reply handler lives on the worker and not on a pack, because the worker outlives every pack
113
+ * it serves and a reply for a pack nobody wants still has pixels to free.
114
+ * @param createWorker - Makes the worker, if there is not one yet.
115
+ * @returns The pooled worker.
116
+ */
117
+ function pooledWorker(createWorker) {
118
+ if (pool)
119
+ return pool.worker;
120
+ // Not stored until it exists: a factory that throws must be retried by the next pack, not cached.
121
+ const started = { worker: createWorker(), produced: false };
122
+ started.worker.onmessage = (event) => {
123
+ const message = event.data;
124
+ const deliver = pending.get(message.id);
125
+ if (deliver) {
126
+ // These pixels are about to be mounted, so from here on this worker must not be stopped.
127
+ if (message.type === 'packed' && message.atlases.length > 0)
128
+ started.produced = true;
129
+ deliver(message);
130
+ return;
131
+ }
132
+ // Nobody is waiting: this pack was abandoned after the worker had already replied. An
133
+ // `ImageBitmap` holds its pixels outside the JavaScript heap and nothing else will ever close
134
+ // these, so every superseded pack would leak a layer's worth of GPU memory.
135
+ if (message.type === 'packed')
136
+ for (const atlas of message.atlases)
137
+ atlas.bitmap.close();
138
+ };
139
+ started.worker.onerror = (event) => {
140
+ retire(started);
141
+ failAll(event.message || 'atlas-worker: failed to start');
142
+ };
143
+ started.worker.onmessageerror = () => {
144
+ // This never fires on the primary target. `Worker`'s `messageerror` is `false` for Chrome,
145
+ // Chrome Android and Android WebView, and Safari only added it in 16.4, which is above the
146
+ // `safari15`/`ios15` floor (checked against `@mdn/browser-compat-data@6.1.5`, as installed
147
+ // here). Assigning it is free and Firefox has had it since 57, so it is kept for the browsers
148
+ // that do support it. It is not a guard the build targets can rely on.
149
+ //
150
+ // A reply that does not deserialize is lost, and it carries no id, so there is no way to tell
151
+ // whose it was. Without this the layer waits for a reply that never comes and stays blank.
152
+ retire(started);
153
+ failAll('atlas-worker: a reply could not be read');
154
+ };
155
+ pool = started;
156
+ return started.worker;
157
+ }
158
+ /**
159
+ * Drops a broken worker, so the next pack starts a fresh one.
160
+ *
161
+ * A worker that has handed out an atlas is dropped and left running. Stopping it would destroy the
162
+ * GPU memory behind every bitmap it made, which is the failure this whole file is shaped around. A
163
+ * worker that produced nothing is stopped, because nothing depends on it.
164
+ * @param broken - The pooled worker to drop.
165
+ */
166
+ function retire(broken) {
167
+ if (pool === broken)
168
+ pool = null;
169
+ if (!broken.produced)
170
+ broken.worker.terminate();
171
+ }
172
+ /**
173
+ * Abandons every pack waiting on the worker that just broke.
174
+ * @param message - What to reject each of them with.
175
+ */
176
+ function failAll(message) {
177
+ for (const [id, deliver] of [...pending])
178
+ deliver({ type: 'failed', id, message });
179
+ }
180
+ /**
181
+ * Tells the worker to drop a pack nobody wants any more.
182
+ *
183
+ * Termination used to do this. Now that the worker outlives its packs, a superseded pack would
184
+ * otherwise run to the end and hold the worker off the next one.
185
+ * @param worker - The pooled worker.
186
+ * @param id - The pack to drop.
187
+ */
188
+ function cancel(worker, id) {
189
+ try {
190
+ post(worker, { type: 'cancel', id });
191
+ }
192
+ catch {
193
+ // A worker that will not take this message is already unusable, and the pack it would have
194
+ // dropped is dropped either way.
195
+ }
196
+ }
197
+ /**
198
+ * Sends one request to the worker.
199
+ *
200
+ * **Nothing is ever transferred.** A `Blob` is a handle to an immutable, reference-counted byte
201
+ * store, so a structured clone copies the handle and not the bytes. Being cheap to clone is the
202
+ * property that matters here; being transferable is not, and transferring a Blob is not a thing the
203
+ * platform offers. A `Blob` is also the only source that reaches this function, so no object a def
204
+ * owns is ever detached by a pack.
205
+ *
206
+ * The typed parameter is why this function exists: `postMessage` takes `any`, so a message built at
207
+ * the call site would go unchecked.
208
+ * @param worker - The worker to send to.
209
+ * @param request - The message.
210
+ */
211
+ function post(worker, request) {
212
+ worker.postMessage(request);
213
+ }
214
+ /**
215
+ * Makes the bundled atlas worker.
216
+ * @returns A fresh worker.
217
+ */
218
+ function createAtlasWorker() {
219
+ return new AtlasWorker();
220
+ }
221
+ /**
222
+ * The error every abandoned pack rejects with.
223
+ * @returns The error.
224
+ */
225
+ function abandoned() {
226
+ return new Error('atlas-worker: the pack was abandoned');
227
+ }
228
+ /**
229
+ * Turns whatever was thrown into an `Error`.
230
+ * @param error - What was thrown.
231
+ * @returns An error.
232
+ */
233
+ function asError(error) {
234
+ return error instanceof Error ? error : new Error(String(error));
235
+ }
236
+ /**
237
+ * How many sources one `postMessage` carries.
238
+ *
239
+ * Sending every source in one message left 18 dropped frames at a thousand logos on a 4x-throttled
240
+ * CPU; sending them in batches of 25 left one. Chunking is what removes the last stall, so this is
241
+ * the number that matters most in this file — tune it against the benchmark, not by taste.
242
+ */
243
+ export const SOURCE_CHUNK_SIZE = 25;
244
+ /** Every pack that has been sent and is waiting for its reply, by request id. */
245
+ const pending = new Map();
246
+ /** The worker every pack runs on, once the first pack has started it. */
247
+ let pool = null;
248
+ /** The last id handed to a pack. Ids only ever climb, so no reply can find the wrong caller. */
249
+ let lastRequestId = 0;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The worker's public face: the main thread's half only.
3
+ *
4
+ * The worker entry is deliberately absent. It imports `packSources` and carries the
5
+ * `?worker&inline` specifier, and nothing outside this directory should pull either in by
6
+ * reaching past the barrel. Types are the exception, because they are erased at emit.
7
+ */
8
+ export { type WorkerAtlas, type WorkerSource } from './atlas-worker';
9
+ export { packInWorker, type PackInWorkerOptions, SOURCE_CHUNK_SIZE } from './client';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { packInWorker, SOURCE_CHUNK_SIZE } from './client';
@@ -0,0 +1,28 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type LayerDef } from '../../types/defs';
3
+ /** Props for {@link Layer}. */
4
+ export interface LayerProps {
5
+ /** The layer definition to render, together with its descendants. */
6
+ layer: LayerDef;
7
+ /**
8
+ * Rendered inside the root group, before the tree's own content. This sits under the root
9
+ * layer's dim and overlay providers. The scene's background quad mounts here for that reason:
10
+ * the root's dim reaches it like any layer's, and its material exists before every layer's,
11
+ * which its draw order relies on.
12
+ */
13
+ children?: ReactNode;
14
+ }
15
+ /**
16
+ * Renders a {@link LayerDef} tree, mapping defs onto the scene-graph hierarchy.
17
+ *
18
+ * This root component owns the tree-wide concerns — in debug mode the layer-visibility GUI, a
19
+ * "Main layers" folder for its direct child layers and a "Content layers" folder mirroring the
20
+ * scheduler's leaf queue (see `visibility-gui.ts`) — and seeds the recursion {@link LayerNode}
21
+ * carries with `hidden`, at `false`. Dim and overlay need no seed: `LayerDimContext` and
22
+ * `LayerOverlayContext` already default to undimmed and plan tier, which is what "no layer above
23
+ * me" means for either one. The whole tree's draw order lives inside `[0, 1)`.
24
+ * @param props - The layer props.
25
+ * @returns The tree's root group.
26
+ */
27
+ export declare function Layer(props: LayerProps): import("react").JSX.Element;
28
+ //# sourceMappingURL=Layer.d.ts.map
@@ -0,0 +1,134 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo, Suspense } from 'react';
3
+ import { useLayoutTargets } from '../../events/layout-targets';
4
+ import { usePointerProps } from '../../events/pointer';
5
+ import { isImageDefs, isLayerDefs, isLineDefs, isModelDefs, isShapeDefs, isTextDefs, } from '../../types/guards';
6
+ import { Images } from '../images';
7
+ import { Lines } from '../lines';
8
+ import { Models } from '../models';
9
+ import { Shapes } from '../shapes';
10
+ import { Texts } from '../text';
11
+ import { LayerDimContext, LayerOverlayContext, useDimChain, useLayerOverlay, } from './layer-context';
12
+ import { useStagedChildren } from './mount-scheduler';
13
+ import { useVisibilityGui } from './visibility-gui';
14
+ /**
15
+ * Renders a {@link LayerDef} tree, mapping defs onto the scene-graph hierarchy.
16
+ *
17
+ * This root component owns the tree-wide concerns — in debug mode the layer-visibility GUI, a
18
+ * "Main layers" folder for its direct child layers and a "Content layers" folder mirroring the
19
+ * scheduler's leaf queue (see `visibility-gui.ts`) — and seeds the recursion {@link LayerNode}
20
+ * carries with `hidden`, at `false`. Dim and overlay need no seed: `LayerDimContext` and
21
+ * `LayerOverlayContext` already default to undimmed and plan tier, which is what "no layer above
22
+ * me" means for either one. The whole tree's draw order lives inside `[0, 1)`.
23
+ * @param props - The layer props.
24
+ * @returns The tree's root group.
25
+ */
26
+ export function Layer(props) {
27
+ const { layer, children } = props;
28
+ useVisibilityGui(layer);
29
+ return (_jsx(MemoLayerNode, { layer: layer, hidden: false, orderBase: 0, orderStep: 1, children: children }));
30
+ }
31
+ /**
32
+ * The content of one leaf layer: the container for its defs' kind, inside a Suspense boundary of
33
+ * the leaf's own.
34
+ *
35
+ * The boundary means a content component that suspends — a loader hook, a lazily imported one —
36
+ * costs this leaf alone. Without it the nearest boundary is the one R3F's `<Canvas>` wraps
37
+ * everything in, and falling back to it hides *every* object in the scene (R3F's `hideInstance`
38
+ * writes `visible = false`) while the admission queue stalls forever, since the leaf never commits
39
+ * and so never reports mounted. With it, a suspended leaf behaves exactly like an empty one: the
40
+ * layer still commits, still reports, the next leaf is admitted on schedule, and the content mounts
41
+ * when it resolves.
42
+ * @param props - The leaf's defs.
43
+ * @returns The container for the defs' kind.
44
+ */
45
+ function LeafContent(props) {
46
+ const { defs, mounted } = props;
47
+ let content = null;
48
+ if (isShapeDefs(defs))
49
+ content = _jsx(Shapes, { defs: defs, mounted: mounted });
50
+ else if (isImageDefs(defs))
51
+ content = _jsx(Images, { defs: defs, mounted: mounted });
52
+ else if (isTextDefs(defs))
53
+ content = _jsx(Texts, { defs: defs, mounted: mounted });
54
+ else if (isLineDefs(defs))
55
+ content = _jsx(Lines, { defs: defs, mounted: mounted });
56
+ else if (isModelDefs(defs))
57
+ content = _jsx(Models, { defs: defs, mounted: mounted });
58
+ return _jsx(Suspense, { fallback: null, children: content });
59
+ }
60
+ /**
61
+ * One layer of the tree as a three.js `<group>`, recursing into its child layers.
62
+ *
63
+ * Everything layer-shaped is handled here as group state — the name, visibility from
64
+ * `layer.hidden`, the dim the subtree inherits, and the pointer props that make the group
65
+ * interactive and picked (see `usePointerProps`) — so the containers below stay free of layer
66
+ * semantics and receive only their child defs. The children arrive through `useStagedChildren`,
67
+ * which is what makes `layer.hidden = true; update(layer)` flip a group prop instead of rebuilding
68
+ * anything, defers a membership change's instance-list sweep to transition priority, and stages
69
+ * leaf mounting one commit per frame — see the hook for all three.
70
+ *
71
+ * **Re-layout is registered, not rendered.** A layer registers the defs that declare an `onScale`
72
+ * with the renderer's re-layout targets — the children it holds, and itself, which is how a layer
73
+ * whose membership depends on the camera re-derives it. From then on a pixel-size change reaches
74
+ * those defs through the frame loop, with no render of this component involved.
75
+ *
76
+ * Draw order is a pair: the tier, then the layer's own place. `overlay` adds a whole band above
77
+ * every plan-tier value. Array order still decides strictly within each band.
78
+ *
79
+ * **Dim is handed down as a source, and the node is rendered memoized.** An `update(layer)` renders this node
80
+ * alone: its child layers receive identical props, and the dim they inherit reaches its consumers
81
+ * through subscriptions to the layers themselves rather than a context value, so an eased dim — an update per frame
82
+ * on the root — renders one node instead of the whole tree.
83
+ * @param props - The node props.
84
+ * @returns The `<group>` for a layer def.
85
+ */
86
+ function LayerNode(props) {
87
+ const { layer, children: prelude, hidden: parentHidden, orderBase, orderStep } = props;
88
+ // What the nearest ancestor already resolved for dim and overlay. A layer cannot see its
89
+ // ancestors any other way.
90
+ const parentChain = useDimChain();
91
+ const parentOverlay = useLayerOverlay();
92
+ // Once hidden or once in the overlay tier, a subtree stays that way. A descendant that dropped
93
+ // back into the plan tier would invert the nesting, and a descendant of a hidden layer is not on
94
+ // screen whatever it says about itself.
95
+ const hidden = parentHidden || layer.hidden === true;
96
+ const overlay = parentOverlay || layer.overlay === true;
97
+ // Nearest first, so the chain resolves to this layer's own dim when it declares one. Stable for a
98
+ // mounted layer, so the consumers below follow its dim by subscription, never by render.
99
+ const dimChain = [layer, ...parentChain];
100
+ // On screen only if nothing above hides it either. This is the value picking hangs off.
101
+ const visible = !hidden;
102
+ const { children, mounted } = useStagedChildren(layer);
103
+ useLayoutTargets(layer, children);
104
+ const pointerProps = usePointerProps(layer, visible);
105
+ let contents = null;
106
+ if (isLayerDefs(children)) {
107
+ const childStep = orderStep / children.length;
108
+ contents = children.map((child, index) => (_jsx(MemoLayerNode, { layer: child, hidden: hidden, orderBase: orderBase + index * childStep, orderStep: childStep }, child.name)));
109
+ }
110
+ else if (mounted > 0) {
111
+ contents = _jsx(LeafContent, { defs: children, mounted: mounted });
112
+ }
113
+ const group = (_jsxs("group", { name: layer.name, visible: !layer.hidden, renderOrder: (overlay ? OVERLAY_TIER : PLAN_TIER) + orderBase, ...pointerProps, children: [prelude, contents] }));
114
+ // Always provided, never only when the layer declares one. Making a provider appear on first use
115
+ // would change this component's element type and remount the subtree, which releases and re-claims
116
+ // every GPU slot beneath it.
117
+ return (_jsx(LayerDimContext, { value: dimChain, children: _jsx(LayerOverlayContext, { value: overlay, children: group }) }));
118
+ }
119
+ /**
120
+ * {@link LayerNode}, memoized — what both the root and the recursion render, so an update renders
121
+ * the one node it names and its child layers bail out on equal props.
122
+ */
123
+ const MemoLayerNode = memo(LayerNode);
124
+ /**
125
+ * Where the plan's own layers are numbered from. The tree subdivides `[0, 1)` depth first, so the
126
+ * mantissa stays free for nesting.
127
+ */
128
+ const PLAN_TIER = 0;
129
+ /**
130
+ * Where an overlay subtree is numbered from, which puts it in `[1, 2)`. That is after every
131
+ * plan-tier layer, whatever renderOrder those layers hold. The whole cost is one bit of mantissa for
132
+ * subdivision.
133
+ */
134
+ const OVERLAY_TIER = 1;
@@ -0,0 +1,2 @@
1
+ export { Layer, type LayerProps } from './Layer';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { Layer } from './Layer';
@@ -0,0 +1,74 @@
1
+ import { type LayerDef } from '../../types/defs';
2
+ /**
3
+ * The layers whose `dim` decides a subtree's, nearest first: the enclosing layer, then each of its
4
+ * ancestors. Nearest declaration wins, and a layer's own `0` un-dims it inside a dimmed ancestor.
5
+ *
6
+ * The chain rather than the resolved amount, because the amount animates — floorplan eases the
7
+ * venue's dim over 300ms, an `update(layer)` per frame — and a number in context re-rendered every
8
+ * consumer and every layer between on each of those frames. A chain never changes for a mounted
9
+ * layer, so the tree stays still: consumers read it with {@link resolveDim} and follow it with
10
+ * {@link subscribeDim}, which is the def store's own notification.
11
+ */
12
+ export type DimChain = readonly LayerDef[];
13
+ /**
14
+ * The dim amount a layer draws at, as a value, so the caller re-renders whenever it changes. A
15
+ * consumer that only writes the amount somewhere reads {@link useDimChain} and subscribes instead.
16
+ * @returns The nearest declared amount, or `0` with no layer above.
17
+ */
18
+ export declare function useLayerDim(): number;
19
+ /**
20
+ * The enclosing layer's {@link DimChain}, for consumers that follow the dim without rendering: a
21
+ * material writing it into a uniform, a container re-running paint order when it crosses zero.
22
+ * @returns The chain, empty outside any layer.
23
+ */
24
+ export declare function useDimChain(): DimChain;
25
+ /**
26
+ * Whether the current layer draws in the overlay tier.
27
+ * @returns `true` if this layer or an ancestor opted into the overlay tier, `false` otherwise.
28
+ */
29
+ export declare function useLayerOverlay(): boolean;
30
+ /**
31
+ * Resolves a chain's dim amount.
32
+ * @param chain - The layers, nearest first.
33
+ * @returns The nearest declared dim, or `0` when none declares one.
34
+ */
35
+ export declare function resolveDim(chain: DimChain): number;
36
+ /**
37
+ * Follows every `update()` of a chain's layers — each one a possible dim change. The listener
38
+ * compares for itself; a membership update reaches it too and changes nothing.
39
+ * @param chain - The layers, nearest first.
40
+ * @param listener - Called after an update of any of them.
41
+ * @returns The unsubscribe function.
42
+ */
43
+ export declare function subscribeDim(chain: DimChain, listener: () => void): () => void;
44
+ /**
45
+ * The {@link DimChain} the current layer hands down to its descendants.
46
+ *
47
+ * Context rather than a prop, because the value crosses the whole subtree and concerns none of the
48
+ * components between. A container hands its material nothing about layers, and a material that
49
+ * never asked about them still dims correctly. Threading it as a prop would put a `dim` on every
50
+ * material, every container, and every one of their inner components.
51
+ *
52
+ * Read through {@link useLayerDim} or {@link useDimChain} instead of directly. A `LayerNode` provides it, always, never
53
+ * only when it declares a `dim` of its own. See `Layer.tsx` for why.
54
+ *
55
+ * Defaults to an empty chain, which reads `0`, undimmed, which is what "no layer above me" means for a component rendered
56
+ * outside a `Layer` tree. A fourth inherited field belongs in a context and a hook of its own here,
57
+ * not folded into this one.
58
+ */
59
+ export declare const LayerDimContext: import("react").Context<DimChain>;
60
+ /**
61
+ * Whether the current layer hands its overlay tier down to its descendants.
62
+ *
63
+ * Context rather than a prop, for the reason {@link LayerDimContext} is. It is also not a shading
64
+ * term, which is why `overlayParams`, the material parameters this tier unlocks, stays in
65
+ * `objects/materials/shared.ts` instead of moving here.
66
+ *
67
+ * Read through {@link useLayerOverlay} instead of directly. A `LayerNode` provides it, always,
68
+ * never only when it declares an `overlay` of its own. See `Layer.tsx` for why.
69
+ *
70
+ * Defaults to `false`, the plan tier, which is what "no layer above me" means for a component
71
+ * rendered outside a `Layer` tree.
72
+ */
73
+ export declare const LayerOverlayContext: import("react").Context<boolean>;
74
+ //# sourceMappingURL=layer-context.d.ts.map
@@ -0,0 +1,82 @@
1
+ import { createContext, use, useSyncExternalStore } from 'react';
2
+ import { subscribeDef } from '../../update';
3
+ /**
4
+ * The dim amount a layer draws at, as a value, so the caller re-renders whenever it changes. A
5
+ * consumer that only writes the amount somewhere reads {@link useDimChain} and subscribes instead.
6
+ * @returns The nearest declared amount, or `0` with no layer above.
7
+ */
8
+ export function useLayerDim() {
9
+ const chain = use(LayerDimContext);
10
+ return useSyncExternalStore((listener) => subscribeDim(chain, listener), () => resolveDim(chain));
11
+ }
12
+ /**
13
+ * The enclosing layer's {@link DimChain}, for consumers that follow the dim without rendering: a
14
+ * material writing it into a uniform, a container re-running paint order when it crosses zero.
15
+ * @returns The chain, empty outside any layer.
16
+ */
17
+ export function useDimChain() {
18
+ return use(LayerDimContext);
19
+ }
20
+ /**
21
+ * Whether the current layer draws in the overlay tier.
22
+ * @returns `true` if this layer or an ancestor opted into the overlay tier, `false` otherwise.
23
+ */
24
+ export function useLayerOverlay() {
25
+ return use(LayerOverlayContext);
26
+ }
27
+ /**
28
+ * Resolves a chain's dim amount.
29
+ * @param chain - The layers, nearest first.
30
+ * @returns The nearest declared dim, or `0` when none declares one.
31
+ */
32
+ export function resolveDim(chain) {
33
+ for (const layer of chain) {
34
+ if (layer.dim !== undefined)
35
+ return layer.dim;
36
+ }
37
+ return 0;
38
+ }
39
+ /**
40
+ * Follows every `update()` of a chain's layers — each one a possible dim change. The listener
41
+ * compares for itself; a membership update reaches it too and changes nothing.
42
+ * @param chain - The layers, nearest first.
43
+ * @param listener - Called after an update of any of them.
44
+ * @returns The unsubscribe function.
45
+ */
46
+ export function subscribeDim(chain, listener) {
47
+ const unsubscribes = chain.map((layer) => subscribeDef(layer, listener));
48
+ return () => {
49
+ for (const unsubscribe of unsubscribes)
50
+ unsubscribe();
51
+ };
52
+ }
53
+ /**
54
+ * The {@link DimChain} the current layer hands down to its descendants.
55
+ *
56
+ * Context rather than a prop, because the value crosses the whole subtree and concerns none of the
57
+ * components between. A container hands its material nothing about layers, and a material that
58
+ * never asked about them still dims correctly. Threading it as a prop would put a `dim` on every
59
+ * material, every container, and every one of their inner components.
60
+ *
61
+ * Read through {@link useLayerDim} or {@link useDimChain} instead of directly. A `LayerNode` provides it, always, never
62
+ * only when it declares a `dim` of its own. See `Layer.tsx` for why.
63
+ *
64
+ * Defaults to an empty chain, which reads `0`, undimmed, which is what "no layer above me" means for a component rendered
65
+ * outside a `Layer` tree. A fourth inherited field belongs in a context and a hook of its own here,
66
+ * not folded into this one.
67
+ */
68
+ export const LayerDimContext = createContext([]);
69
+ /**
70
+ * Whether the current layer hands its overlay tier down to its descendants.
71
+ *
72
+ * Context rather than a prop, for the reason {@link LayerDimContext} is. It is also not a shading
73
+ * term, which is why `overlayParams`, the material parameters this tier unlocks, stays in
74
+ * `objects/materials/shared.ts` instead of moving here.
75
+ *
76
+ * Read through {@link useLayerOverlay} instead of directly. A `LayerNode` provides it, always,
77
+ * never only when it declares an `overlay` of its own. See `Layer.tsx` for why.
78
+ *
79
+ * Defaults to `false`, the plan tier, which is what "no layer above me" means for a component
80
+ * rendered outside a `Layer` tree.
81
+ */
82
+ export const LayerOverlayContext = createContext(false);