@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,177 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { _roots, advance, createRoot, extend } from '@react-three/fiber';
3
+ import { StrictMode, useEffect, useEffectEvent, useRef } from 'react';
4
+ import * as THREE from 'three';
5
+ import { Camera, WebGLRenderer } from 'three';
6
+ import { createLogger } from '../utils/logging';
7
+ import { setExternalCameraProjection } from './external-camera';
8
+ import { externalEvents } from './external-events';
9
+ const logger = createLogger('external');
10
+ /**
11
+ * `<Canvas>`'s stand-in for a host that already owns the canvas: everything the Canvas component
12
+ * does — boot an R3F root, configure the renderer, the events, the size — minus the one thing it
13
+ * cannot share, creating the canvas element. It knows nothing of the scene: `children` render into
14
+ * the root verbatim, so `Renderer` composes one tree and only the mount differs.
15
+ *
16
+ * The bootstrap is imperative because the host's contract is: there is no React tree to mount into
17
+ * until a context exists. R3F's `<Canvas>` cannot serve here — it creates and owns its own canvas
18
+ * element inside a wrapper it renders, and has no way to adopt a foreign one — so this takes R3F's
19
+ * own escape hatch for exactly that, `createRoot(canvas)`, which is all `<Canvas>` wraps anyway.
20
+ * It is configured once per context, while the tree re-renders through props like any other.
21
+ *
22
+ * The camera half is the mount's as well, because the host owns it: one bare camera carries
23
+ * whatever matrix the host handed the frame hook, decomposed into a rigid view and a projection so
24
+ * that everything reading a camera's transform — culling, raycasts, lighting — works unchanged.
25
+ * There is no viewbox fit, no controls and no camera commands; the tree above simply mounts none
26
+ * of them.
27
+ *
28
+ * The demand loop inverts. R3F's own `invalidate` is a no-op under `frameloop: 'never'`, so the
29
+ * store's copy is replaced with the host's `requestFrame` — and every host frame redraws in full,
30
+ * as a shared canvas requires, starting from `resetState()` so three's GL-state tracking never
31
+ * trusts what the host's own drawing left behind.
32
+ * @param props - The host's hooks, and the tree to render into the root.
33
+ * @returns Nothing; the tree renders on the host's canvas, not in this one.
34
+ */
35
+ export function ExternalCanvas(props) {
36
+ const { gl, requestFrame, onFrame, children } = props;
37
+ // A ref rather than state: nothing renders from the root — the tree renders *into* it — and the
38
+ // forwarding effect always runs after this one within a commit, so it never reads it stale.
39
+ const mountedRef = useRef(undefined);
40
+ // Effect events, so the host handing over a fresh function identity neither re-bootstraps the
41
+ // root nor goes stale: the bootstrap captures these two, and they read the latest props.
42
+ const askFrame = useEffectEvent(() => requestFrame());
43
+ const subscribeFrames = useEffectEvent((draw) => onFrame(draw));
44
+ useEffect(() => {
45
+ const external = mountExternal(gl, askFrame, subscribeFrames);
46
+ mountedRef.current = external;
47
+ return () => {
48
+ mountedRef.current = undefined;
49
+ external?.dispose();
50
+ };
51
+ }, [gl]);
52
+ // The tree flows into the foreign root exactly as it would into a Canvas: every children change
53
+ // re-renders it, and only a context change re-bootstraps — `gl` is a dependency here for exactly
54
+ // that case, so a fresh root receives the tree the moment it exists.
55
+ useEffect(() => {
56
+ mountedRef.current?.render(_jsx(StrictMode, { children: children }));
57
+ }, [gl, children]);
58
+ return null;
59
+ }
60
+ /**
61
+ * Boots an R3F root on the host's canvas and wires it to the host's frame loop.
62
+ * @param context - The host's WebGL context.
63
+ * @param requestFrame - Asks the host for a frame.
64
+ * @param onFrame - Subscribes the per-frame draw to the host.
65
+ * @returns The root and its teardown, or `undefined` when the context has no usable canvas.
66
+ */
67
+ function mountExternal(context, requestFrame, onFrame) {
68
+ const canvas = context.canvas;
69
+ if (!(canvas instanceof HTMLCanvasElement)) {
70
+ logger.warn('external mode needs a context bound to an HTMLCanvasElement');
71
+ return undefined;
72
+ }
73
+ // `<Canvas>` extends R3F's element catalog with the whole THREE namespace itself; a manual root
74
+ // has to do the same. Idempotent, and the namespace is a module the renderer already ships. The
75
+ // cast steps past the catalog's constructors-only typing — the namespace carries plain values
76
+ // too, which `extend` skips at runtime, exactly as the Canvas path relies on.
77
+ extend(THREE);
78
+ // Deliberately a bare camera: three's frustum cameras derive their projection, and this one's
79
+ // arrives whole from the host each frame. Marked manual so R3F's resize handling leaves it
80
+ // alone; both auto-updates are off because the decomposition writes every matrix by hand.
81
+ const camera = new Camera();
82
+ camera.matrixAutoUpdate = false;
83
+ camera.matrixWorldAutoUpdate = false;
84
+ camera.manual = true;
85
+ // Constructed bare on purpose: anything the renderer would opine on is left unset.
86
+ const glRenderer = new WebGLRenderer({ canvas, context });
87
+ // Never clear: the host's own layers are already on the canvas when this renderer draws.
88
+ glRenderer.autoClear = false;
89
+ // The canvas is the host's, twice over. Three would write the css style along with every resize
90
+ // unless told otherwise each time; and R3F's unmount forces a context loss on the renderer it
91
+ // tears down, which on a shared context would take the host's own drawing with it.
92
+ const applySize = glRenderer.setSize.bind(glRenderer);
93
+ glRenderer.setSize = (width, height) => applySize(width, height, false);
94
+ glRenderer.forceContextLoss = () => undefined;
95
+ const measure = () => {
96
+ const rect = canvas.getBoundingClientRect();
97
+ return { width: rect.width, height: rect.height, top: rect.top, left: rect.left };
98
+ };
99
+ const root = createRoot(canvas);
100
+ let disposed = false;
101
+ let configured = false;
102
+ let pending;
103
+ let unsubscribeFrame;
104
+ let observer;
105
+ void root
106
+ .configure({
107
+ gl: glRenderer,
108
+ // R3F force-writes ACES filmic tone mapping onto a fresh renderer unless `flat` is set, which
109
+ // is the one value landing on three's own default, `NoToneMapping`. This renderer does not
110
+ // tone map: `Lighting` keeps the rig's light sum in range by construction, rather than
111
+ // compressing an unbounded one back into range afterward.
112
+ flat: true,
113
+ // The cast widens past R3F's frustum-camera union; `manual` above is what keeps R3F's own
114
+ // camera handling off it.
115
+ camera: camera,
116
+ frameloop: 'never',
117
+ events: externalEvents,
118
+ size: measure(),
119
+ dpr: window.devicePixelRatio,
120
+ })
121
+ .then(() => {
122
+ if (disposed)
123
+ return;
124
+ const store = _roots.get(canvas)?.store;
125
+ if (!store)
126
+ return;
127
+ // R3F's invalidate no-ops under `frameloop: 'never'`; the host owns the frames, so demand
128
+ // becomes a repaint request. Replaced after configure, which is what wrote the original.
129
+ store.setState({
130
+ invalidate: () => {
131
+ if (!disposed)
132
+ requestFrame();
133
+ },
134
+ });
135
+ store.getState().events.connect?.(canvas);
136
+ unsubscribeFrame = onFrame((projectionMatrix) => {
137
+ if (disposed)
138
+ return;
139
+ setExternalCameraProjection(camera, projectionMatrix);
140
+ // Three tracks GL state it did not set; sharing a context means resetting that tracking
141
+ // at the start of every frame, or the host's own state reads as three's.
142
+ glRenderer.resetState();
143
+ advance(performance.now(), true, store.getState());
144
+ });
145
+ // The host resizes its own canvas; the root only has to notice. Watching the element beats a
146
+ // host-specific resize event, and a dpr change reaches the same handler through the resize
147
+ // the host performs for it. Feature-detected for the oldest WebViews the SDK still runs in —
148
+ // without the observer the plan still draws, at the size it mounted at.
149
+ if (typeof ResizeObserver === 'function') {
150
+ observer = new ResizeObserver(() => {
151
+ if (disposed)
152
+ return;
153
+ const next = measure();
154
+ store.getState().setSize(next.width, next.height, next.top, next.left);
155
+ store.getState().setDpr(window.devicePixelRatio);
156
+ });
157
+ observer.observe(canvas);
158
+ }
159
+ configured = true;
160
+ if (pending !== undefined)
161
+ root.render(pending);
162
+ requestFrame();
163
+ });
164
+ return {
165
+ render(node) {
166
+ pending = node;
167
+ if (configured)
168
+ root.render(node);
169
+ },
170
+ dispose() {
171
+ disposed = true;
172
+ observer?.disconnect();
173
+ unsubscribeFrame?.();
174
+ root.unmount();
175
+ },
176
+ };
177
+ }
@@ -0,0 +1,18 @@
1
+ import { type Camera } from 'three';
2
+ /**
3
+ * Decomposes the host's combined world-to-clip matrix into a rigid view matrix and a projection
4
+ * matrix, publishing all four matrices (and their inverses) on the camera.
5
+ *
6
+ * Ported from the imperative renderer's `ExternalCameraSystem`. The split is not unique — many
7
+ * (P′, V′) pairs multiply to the same M — but the *rigid* split is the one three's `Camera` class
8
+ * assumes for `getWorldDirection`, frustum culling, raycasting and the lighting that reads the
9
+ * camera's world matrix. Any extra scale or skew in M (mercator-unit conversion, say) ends up
10
+ * absorbed into P, where it breaks none of those — a *reflection* being the exception, which is why
11
+ * the host's world is mirrored into three's before any of this runs.
12
+ * @param camera - The external camera to publish onto; `matrixAutoUpdate` and
13
+ * `matrixWorldAutoUpdate` must be off, since everything here is written by hand.
14
+ * @param mainMatrix - The combined matrix mapping world space directly to clip space, sixteen
15
+ * elements column-major.
16
+ */
17
+ export declare function setExternalCameraProjection(camera: Camera, mainMatrix: ArrayLike<number>): void;
18
+ //# sourceMappingURL=external-camera.d.ts.map
@@ -0,0 +1,103 @@
1
+ import { Matrix3, Matrix4, Vector3 } from 'three';
2
+ import { HANDEDNESS_FLIP } from '../space/Space';
3
+ /**
4
+ * Decomposes the host's combined world-to-clip matrix into a rigid view matrix and a projection
5
+ * matrix, publishing all four matrices (and their inverses) on the camera.
6
+ *
7
+ * Ported from the imperative renderer's `ExternalCameraSystem`. The split is not unique — many
8
+ * (P′, V′) pairs multiply to the same M — but the *rigid* split is the one three's `Camera` class
9
+ * assumes for `getWorldDirection`, frustum culling, raycasting and the lighting that reads the
10
+ * camera's world matrix. Any extra scale or skew in M (mercator-unit conversion, say) ends up
11
+ * absorbed into P, where it breaks none of those — a *reflection* being the exception, which is why
12
+ * the host's world is mirrored into three's before any of this runs.
13
+ * @param camera - The external camera to publish onto; `matrixAutoUpdate` and
14
+ * `matrixWorldAutoUpdate` must be off, since everything here is written by hand.
15
+ * @param mainMatrix - The combined matrix mapping world space directly to clip space, sixteen
16
+ * elements column-major.
17
+ */
18
+ export function setExternalCameraProjection(camera, mainMatrix) {
19
+ // The host's matrix reads the host's world; the space mirrors that world into three's, so undo
20
+ // the mirror here. The two cancel: the plan lands exactly where the host put it, and what is left
21
+ // is a plan → world matrix that reverses orientation, which is the whole point — see
22
+ // {@link HANDEDNESS_FLIP}.
23
+ const M = _main.fromArray(mainMatrix).multiply(HANDEDNESS_FLIP);
24
+ const e = M.elements; // column-major storage: M[row, col] = e[row + 4 * col]
25
+ // Step 1: camera world position c.
26
+ //
27
+ // A standard perspective projection P has its fourth column equal to (0, 0, ±f, 0), so
28
+ // P · [0; 0; 0; 1] is zero in rows 0, 1, and 3. The view matrix V maps the camera position to
29
+ // view-space origin: V · [c; 1] = [0; 0; 0; 1]. Composing these:
30
+ //
31
+ // M · [c; 1] = P · V · [c; 1] = P · [0; 0; 0; 1] = (0, 0, k, 0)
32
+ //
33
+ // so rows 0, 1, and 3 of M dotted with [c; 1] all equal zero. That is a 3×3 linear system for
34
+ // the three components of c, independent of NDC z conventions (standard OpenGL vs. reverse-z),
35
+ // so it works for both maplibre and a vanilla GL setup.
36
+ _system.set(e[0], e[4], e[8], e[1], e[5], e[9], e[3], e[7], e[11]);
37
+ _position.set(-e[12], -e[13], -e[15]).applyMatrix3(_system.invert());
38
+ // Step 2: view direction in world space.
39
+ //
40
+ // Unproject two world-space points along the central view ray and take their difference. The
41
+ // clip-space z boundaries (±1) are used rather than an interior NDC z because maplibre's
42
+ // projection has an infinite far plane in a reverse-z arrangement: an interior z (0 in
43
+ // particular) unprojects to a homogeneous direction at infinity and comes back as NaN after the
44
+ // w-divide. z = ±1 always produces finite points, so the subtraction is well-defined.
45
+ //
46
+ // Which of the two is the near plane depends on the projection's z convention — reverse-z under
47
+ // maplibre, standard under vanilla GL — so it is settled by distance to the eye recovered above:
48
+ // the near point is the closer one, and the view looks from it toward the other. (The imperative
49
+ // renderer hardcoded maplibre's ordering; measuring is what makes both conventions work.)
50
+ _mainInverse.copy(M).invert();
51
+ _near.set(0, 0, 1).applyMatrix4(_mainInverse);
52
+ _far.set(0, 0, -1).applyMatrix4(_mainInverse);
53
+ const nearZ = _near.distanceToSquared(_position) <= _far.distanceToSquared(_position) ? 1 : -1;
54
+ if (nearZ === 1) {
55
+ _direction.copy(_far).sub(_near).normalize();
56
+ }
57
+ else {
58
+ _direction.copy(_near).sub(_far).normalize();
59
+ }
60
+ // Step 3: the camera's up axis, measured rather than chosen, and a rigid view matrix from it.
61
+ //
62
+ // Any up not parallel to the view direction gives a valid (P′, V′) pair for *drawing*, because P
63
+ // is recomputed from M · matrixWorld at the end and absorbs whatever roll V′ was given. The axis
64
+ // is also *read*, though: `Lighting` takes the plan's heading from the camera's up axis, so a
65
+ // chosen one aims the key light at an angle the host never had — a fixed world +z aimed it from
66
+ // the far side of the plan at every bearing, and every face turned toward the camera lost its
67
+ // direct light.
68
+ //
69
+ // Two points at one clip x and one clip z, one at the top of the screen and one at the bottom,
70
+ // differ by a vector along the camera's up axis alone: a constant clip z is a constant view-space
71
+ // z, so the forward components cancel and the difference is (0, Δy, 0) in view space. Clip y
72
+ // grows upward under every projection, maplibre's reverse-z included, so this reads none of the
73
+ // host's own conventions — and unlike a chosen axis it has no degenerate view to fall back from,
74
+ // since the axis it recovers is perpendicular to the view direction by construction.
75
+ //
76
+ // Unprojected at `nearZ`, the near plane's own clip z: a point there is finite under either z
77
+ // convention, which an interior z is not.
78
+ _screenTop.set(0, 1, nearZ).applyMatrix4(_mainInverse);
79
+ _screenBottom.set(0, -1, nearZ).applyMatrix4(_mainInverse);
80
+ _up.copy(_screenTop).sub(_screenBottom).normalize();
81
+ _target.copy(_position).add(_direction);
82
+ camera.matrixWorld.lookAt(_position, _target, _up);
83
+ camera.matrixWorld.setPosition(_position);
84
+ camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
85
+ // Step 4: derive projection so that P · V = M exactly.
86
+ //
87
+ // P = M · matrixWorld, because matrixWorld = V⁻¹ and therefore P · V = (M · V⁻¹) · V = M. Any
88
+ // scale or skew that did not fit into the rigid V lives in P.
89
+ camera.projectionMatrix.multiplyMatrices(M, camera.matrixWorld);
90
+ camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();
91
+ }
92
+ // Scratch, reused across calls so a per-frame update allocates nothing.
93
+ const _main = new Matrix4();
94
+ const _mainInverse = new Matrix4();
95
+ const _system = new Matrix3();
96
+ const _position = new Vector3();
97
+ const _near = new Vector3();
98
+ const _far = new Vector3();
99
+ const _direction = new Vector3();
100
+ const _screenTop = new Vector3();
101
+ const _screenBottom = new Vector3();
102
+ const _target = new Vector3();
103
+ const _up = new Vector3();
@@ -0,0 +1,14 @@
1
+ import { type EventManager, type RootStore } from '@react-three/fiber';
2
+ /**
3
+ * R3F's DOM event manager, aiming its rays through the hosted camera.
4
+ *
5
+ * The default manager computes its ray with three's `setFromCamera`, which refuses a camera that is
6
+ * neither perspective nor orthographic — and the external camera is deliberately neither, one folded
7
+ * matrix with no transform of its own. Only the computation changes: hit testing, hover tracking,
8
+ * capture and the missed-click path all stay R3F's, so picking under a host behaves exactly as it
9
+ * does under the renderer's own canvas.
10
+ * @param store - The root the manager serves.
11
+ * @returns The event manager.
12
+ */
13
+ export declare function externalEvents(store: RootStore): EventManager<HTMLElement>;
14
+ //# sourceMappingURL=external-events.d.ts.map
@@ -0,0 +1,33 @@
1
+ import { events as createDomEvents } from '@react-three/fiber';
2
+ import { castRay } from '../space/Space';
3
+ /**
4
+ * R3F's DOM event manager, aiming its rays through the hosted camera.
5
+ *
6
+ * The default manager computes its ray with three's `setFromCamera`, which refuses a camera that is
7
+ * neither perspective nor orthographic — and the external camera is deliberately neither, one folded
8
+ * matrix with no transform of its own. Only the computation changes: hit testing, hover tracking,
9
+ * capture and the missed-click path all stay R3F's, so picking under a host behaves exactly as it
10
+ * does under the renderer's own canvas.
11
+ * @param store - The root the manager serves.
12
+ * @returns The event manager.
13
+ */
14
+ export function externalEvents(store) {
15
+ const manager = createDomEvents(store);
16
+ return {
17
+ ...manager,
18
+ // The canvas is the host's and carries the host's own pointer handling; listening one element
19
+ // up leaves it alone, while `offsetX` stays canvas-relative — the events still target the
20
+ // canvas, which sits alone in its container.
21
+ connect(target) {
22
+ manager.connect?.(target.parentElement ?? target);
23
+ },
24
+ compute(event, state) {
25
+ state.pointer.set((event.offsetX / state.size.width) * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
26
+ // R3F's pointer is a bare Vector2; the set above is what put it in NDC.
27
+ castRay(state.raycaster, state.pointer, state.camera);
28
+ // Screen-space raycasts — a route line answering at its drawn width — read the camera off the
29
+ // raycaster; `setFromCamera` writes it and the general-camera path must too.
30
+ state.raycaster.camera = state.camera;
31
+ },
32
+ };
33
+ }
@@ -0,0 +1,13 @@
1
+ export { type CameraAPI, type CameraAxes, type CameraState, type ControlsConfig, type InertiaConfig, type PanConfig, type RollConfig, type TransitionOptions, useCameraAPI, useCameraGesture, useCameraMoveEnd, useCameraState, type ZoomConfig, type ZoomToOptions, } from './controls';
2
+ export { prepareDebug } from './debug/debug-chunk';
3
+ export { useDebugPanel } from './debug/debug-context';
4
+ export { type LightingProps, type ShadowProps } from './objects/lighting';
5
+ export * from './Renderer';
6
+ export { type CameraProps, type SmoothTime } from './space/Camera';
7
+ export { type CanvasPoint, type CanvasPointLike, type PlanPoint, type PlanPointLike, } from './space/Space';
8
+ export { useViewport, type ViewportAPI } from './space/viewport';
9
+ export * from './types/defs';
10
+ export * from './types/events';
11
+ export * from './types/guards';
12
+ export { update } from './update';
13
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ // The camera's public surface: commands, a state reader, and the two movement events — the user's
2
+ // own hand on the camera, and any movement coming to rest. Deliberately not `useControlsEffect` or
3
+ // the controls themselves — those hand out `camera-controls`, which is this renderer's internals.
4
+ export { useCameraAPI, useCameraGesture, useCameraMoveEnd, useCameraState, } from './controls';
5
+ // The debug chunk's preload, for an external host that must create its context instrumented.
6
+ export { prepareDebug } from './debug/debug-chunk';
7
+ // Publishing a host's own values into the debug panel.
8
+ export { useDebugPanel } from './debug/debug-context';
9
+ export * from './Renderer';
10
+ export { useViewport } from './space/viewport';
11
+ export * from './types/defs';
12
+ export * from './types/events';
13
+ export * from './types/guards';
14
+ export { update } from './update';
@@ -0,0 +1,31 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type ColorInput } from '../types/defs';
3
+ /** Props for {@link Background}. */
4
+ export interface BackgroundProps {
5
+ /** The background color. */
6
+ color: ColorInput;
7
+ }
8
+ /**
9
+ * The scene's background: a screen-space quad drawn below every layer, replacing what a clear
10
+ * color would paint — and unlike one, dimmed with the venue. The root `Layer` renders it inside
11
+ * its own group, under the root layer's dim provider, so the dim reaches this material exactly as
12
+ * it reaches a layer's.
13
+ *
14
+ * **Screen-space in the vertex shader**, as the imperative renderer drew it: projection is
15
+ * replaced with the quad's own xy in clip space at the far plane, so it covers the canvas edge to
16
+ * edge under any camera — fit, zoom, roll, pitch — and no matrix above it is ever read.
17
+ *
18
+ * It draws through the same {@link ColorMaterial} as the layers, with one addition through the
19
+ * material's pre-dim hook: a quad has no batch prologue, so the per-instance dim uniform the
20
+ * unmodified dim patch looks for is declared here as a constant pinned to "inherit" — every
21
+ * fragment defers to the layer amount, which is the point.
22
+ *
23
+ * **Draw order**: `renderOrder` 0 puts it level with the first layer group, and the tie falls to
24
+ * `material.id` — this material is created as the root layer mounts, before the scheduler admits
25
+ * any leaf, so it draws first. That ordering is load-bearing: flat content writes no depth, so
26
+ * anything drawn after the quad simply paints over it.
27
+ * @param props - The color.
28
+ * @returns The quad.
29
+ */
30
+ export declare function Background(props: BackgroundProps): ReactNode;
31
+ //# sourceMappingURL=Background.d.ts.map
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { declareBeforeMain } from '../core/shader-source';
4
+ import { ColorMaterial } from './materials/ColorMaterial';
5
+ import { DIM_INHERIT, DIM_UNIFORM } from './materials/effects/color-dim';
6
+ /**
7
+ * The scene's background: a screen-space quad drawn below every layer, replacing what a clear
8
+ * color would paint — and unlike one, dimmed with the venue. The root `Layer` renders it inside
9
+ * its own group, under the root layer's dim provider, so the dim reaches this material exactly as
10
+ * it reaches a layer's.
11
+ *
12
+ * **Screen-space in the vertex shader**, as the imperative renderer drew it: projection is
13
+ * replaced with the quad's own xy in clip space at the far plane, so it covers the canvas edge to
14
+ * edge under any camera — fit, zoom, roll, pitch — and no matrix above it is ever read.
15
+ *
16
+ * It draws through the same {@link ColorMaterial} as the layers, with one addition through the
17
+ * material's pre-dim hook: a quad has no batch prologue, so the per-instance dim uniform the
18
+ * unmodified dim patch looks for is declared here as a constant pinned to "inherit" — every
19
+ * fragment defers to the layer amount, which is the point.
20
+ *
21
+ * **Draw order**: `renderOrder` 0 puts it level with the first layer group, and the tie falls to
22
+ * `material.id` — this material is created as the root layer mounts, before the scheduler admits
23
+ * any leaf, so it draws first. That ordering is load-bearing: flat content writes no depth, so
24
+ * anything drawn after the quad simply paints over it.
25
+ * @param props - The color.
26
+ * @returns The quad.
27
+ */
28
+ export function Background(props) {
29
+ // One handler for the material's life, per `ColorMaterial`'s contract for its pre-dim hook.
30
+ const [onBeforeCompile] = useState(() => (parameters) => {
31
+ parameters.vertexShader = parameters.vertexShader.replace('#include <project_vertex>',
32
+ /* glsl */ `gl_Position = vec4(transformed.xy, 1.0, 1.0);`);
33
+ parameters.fragmentShader = declareBeforeMain(parameters.fragmentShader,
34
+ /* glsl */ `const float ${DIM_UNIFORM} = ${DIM_INHERIT}.0;`);
35
+ });
36
+ return (_jsxs("mesh", { name: "background", renderOrder: 0, frustumCulled: false, children: [_jsx("planeGeometry", { args: [2, 2] }), _jsx(ColorMaterial, { color: props.color, onBeforeCompile: onBeforeCompile })] }));
37
+ }