@expofp/renderer 3.2.5 → 3.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/README.md +111 -0
  2. package/dist/Renderer.d.ts +88 -0
  3. package/dist/Renderer.js +53 -0
  4. package/dist/controls/CameraControls.d.ts +102 -0
  5. package/dist/controls/CameraControls.js +239 -0
  6. package/dist/controls/camera-api.d.ts +206 -0
  7. package/dist/controls/camera-api.js +181 -0
  8. package/dist/controls/camera-move.d.ts +13 -0
  9. package/dist/controls/camera-move.js +18 -0
  10. package/dist/controls/camera-state.d.ts +40 -0
  11. package/dist/controls/camera-state.js +65 -0
  12. package/dist/controls/gestures.d.ts +70 -0
  13. package/dist/controls/gestures.js +84 -0
  14. package/dist/controls/handlers/Inertia.d.ts +111 -0
  15. package/dist/controls/handlers/Inertia.js +215 -0
  16. package/dist/controls/handlers/Pan.d.ts +23 -0
  17. package/dist/controls/handlers/Pan.js +32 -0
  18. package/dist/controls/handlers/Pitch.d.ts +94 -0
  19. package/dist/controls/handlers/Pitch.js +191 -0
  20. package/dist/controls/handlers/Roll.d.ts +103 -0
  21. package/dist/controls/handlers/Roll.js +182 -0
  22. package/dist/controls/handlers/Zoom.d.ts +15 -0
  23. package/dist/controls/handlers/Zoom.js +26 -0
  24. package/dist/controls/index.d.ts +56 -0
  25. package/dist/controls/index.js +58 -0
  26. package/dist/controls/zoom-to.d.ts +89 -0
  27. package/dist/controls/zoom-to.js +91 -0
  28. package/dist/core/InstanceUniforms.d.ts +93 -0
  29. package/dist/core/InstanceUniforms.js +266 -0
  30. package/dist/core/SquareDataTexture.d.ts +277 -0
  31. package/dist/core/SquareDataTexture.js +476 -0
  32. package/dist/core/batch/BatchedMesh.d.ts +74 -0
  33. package/dist/core/batch/BatchedMesh.js +149 -0
  34. package/dist/core/instanced/FrustumCulling.d.ts +141 -0
  35. package/dist/core/instanced/FrustumCulling.js +246 -0
  36. package/dist/core/instanced/InstancedMesh.d.ts +302 -0
  37. package/dist/core/instanced/InstancedMesh.js +497 -0
  38. package/dist/core/instanced/Instances.d.ts +119 -0
  39. package/dist/core/instanced/Instances.js +230 -0
  40. package/dist/core/instanced/Raycasting.d.ts +118 -0
  41. package/dist/core/instanced/Raycasting.js +134 -0
  42. package/dist/core/instanced/instanced-material.d.ts +77 -0
  43. package/dist/core/instanced/instanced-material.js +224 -0
  44. package/dist/core/lines/BatchedLines.d.ts +135 -0
  45. package/dist/core/lines/BatchedLines.js +213 -0
  46. package/dist/core/lines/FrustumCulling.d.ts +43 -0
  47. package/dist/core/lines/FrustumCulling.js +85 -0
  48. package/dist/core/lines/Raycasting.d.ts +44 -0
  49. package/dist/core/lines/Raycasting.js +91 -0
  50. package/dist/core/lines/lines-material.d.ts +47 -0
  51. package/dist/core/lines/lines-material.js +115 -0
  52. package/dist/core/shader-source.d.ts +50 -0
  53. package/dist/core/shader-source.js +84 -0
  54. package/dist/core/text/BatchedText.d.ts +227 -0
  55. package/dist/core/text/BatchedText.js +467 -0
  56. package/dist/core/text/MemberTexture.d.ts +90 -0
  57. package/dist/core/text/MemberTexture.js +194 -0
  58. package/dist/core/text/Text.d.ts +73 -0
  59. package/dist/core/text/Text.js +215 -0
  60. package/dist/core/text/batched-text-material.d.ts +56 -0
  61. package/dist/core/text/batched-text-material.js +121 -0
  62. package/dist/core/text/glyph-packing.d.ts +17 -0
  63. package/dist/core/text/glyph-packing.js +61 -0
  64. package/dist/core/typed-array.d.ts +16 -0
  65. package/dist/core/typed-array.js +20 -0
  66. package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
  67. package/dist/debug/components/DebugPanelProvider.js +38 -0
  68. package/dist/debug/components/DebugTools.d.ts +22 -0
  69. package/dist/debug/components/DebugTools.js +28 -0
  70. package/dist/debug/components/Gui.d.ts +20 -0
  71. package/dist/debug/components/Gui.js +32 -0
  72. package/dist/debug/components/MemoryInfo.d.ts +22 -0
  73. package/dist/debug/components/MemoryInfo.js +42 -0
  74. package/dist/debug/components/Panel.d.ts +31 -0
  75. package/dist/debug/components/Panel.js +98 -0
  76. package/dist/debug/components/Stats.d.ts +9 -0
  77. package/dist/debug/components/Stats.js +24 -0
  78. package/dist/debug/debug-context.d.ts +41 -0
  79. package/dist/debug/debug-context.js +59 -0
  80. package/dist/debug/index.d.ts +51 -0
  81. package/dist/debug/index.js +64 -0
  82. package/dist/events/LayoutDriver.d.ts +31 -0
  83. package/dist/events/LayoutDriver.js +88 -0
  84. package/dist/events/PointerMissed.d.ts +23 -0
  85. package/dist/events/PointerMissed.js +58 -0
  86. package/dist/events/def-culling.d.ts +46 -0
  87. package/dist/events/def-culling.js +69 -0
  88. package/dist/events/layout-targets.d.ts +104 -0
  89. package/dist/events/layout-targets.js +245 -0
  90. package/dist/events/pointer.d.ts +118 -0
  91. package/dist/events/pointer.js +168 -0
  92. package/dist/external/ExternalCanvas.d.ts +56 -0
  93. package/dist/external/ExternalCanvas.js +178 -0
  94. package/dist/external/external-camera.d.ts +17 -0
  95. package/dist/external/external-camera.js +82 -0
  96. package/dist/external/external-events.d.ts +14 -0
  97. package/dist/external/external-events.js +33 -0
  98. package/dist/index.d.ts +11 -783
  99. package/dist/index.js +12 -8031
  100. package/dist/objects/Background.d.ts +31 -0
  101. package/dist/objects/Background.js +37 -0
  102. package/dist/objects/Lighting.d.ts +20 -0
  103. package/dist/objects/Lighting.js +85 -0
  104. package/dist/objects/containers/SlotContainer.d.ts +266 -0
  105. package/dist/objects/containers/SlotContainer.js +251 -0
  106. package/dist/objects/containers/hooks.d.ts +46 -0
  107. package/dist/objects/containers/hooks.js +118 -0
  108. package/dist/objects/containers/index.d.ts +6 -0
  109. package/dist/objects/containers/index.js +4 -0
  110. package/dist/objects/containers/keys.d.ts +10 -0
  111. package/dist/objects/containers/keys.js +18 -0
  112. package/dist/objects/containers/mesh-writes.d.ts +106 -0
  113. package/dist/objects/containers/mesh-writes.js +97 -0
  114. package/dist/objects/containers/props.d.ts +23 -0
  115. package/dist/objects/containers/props.js +1 -0
  116. package/dist/objects/images/ImageInstance.d.ts +29 -0
  117. package/dist/objects/images/ImageInstance.js +83 -0
  118. package/dist/objects/images/Images.d.ts +37 -0
  119. package/dist/objects/images/Images.js +204 -0
  120. package/dist/objects/images/atlas-packer.d.ts +128 -0
  121. package/dist/objects/images/atlas-packer.js +315 -0
  122. package/dist/objects/images/image-container.d.ts +51 -0
  123. package/dist/objects/images/image-container.js +70 -0
  124. package/dist/objects/images/index.d.ts +2 -0
  125. package/dist/objects/images/index.js +1 -0
  126. package/dist/objects/images/texture-budget.d.ts +120 -0
  127. package/dist/objects/images/texture-budget.js +215 -0
  128. package/dist/objects/layer/Layer.d.ts +27 -0
  129. package/dist/objects/layer/Layer.js +114 -0
  130. package/dist/objects/layer/index.d.ts +2 -0
  131. package/dist/objects/layer/index.js +1 -0
  132. package/dist/objects/layer/mount-scheduler.d.ts +102 -0
  133. package/dist/objects/layer/mount-scheduler.js +145 -0
  134. package/dist/objects/layer/visibility-gui.d.ts +19 -0
  135. package/dist/objects/layer/visibility-gui.js +93 -0
  136. package/dist/objects/lines/LineInstance.d.ts +21 -0
  137. package/dist/objects/lines/LineInstance.js +73 -0
  138. package/dist/objects/lines/Lines.d.ts +17 -0
  139. package/dist/objects/lines/Lines.js +29 -0
  140. package/dist/objects/lines/index.d.ts +2 -0
  141. package/dist/objects/lines/index.js +1 -0
  142. package/dist/objects/lines/line-container.d.ts +35 -0
  143. package/dist/objects/lines/line-container.js +40 -0
  144. package/dist/objects/materials/ColorMaterial.d.ts +85 -0
  145. package/dist/objects/materials/ColorMaterial.js +89 -0
  146. package/dist/objects/materials/LineMaterial.d.ts +44 -0
  147. package/dist/objects/materials/LineMaterial.js +72 -0
  148. package/dist/objects/materials/ModelMaterial.d.ts +41 -0
  149. package/dist/objects/materials/ModelMaterial.js +84 -0
  150. package/dist/objects/materials/TextureMaterial.d.ts +30 -0
  151. package/dist/objects/materials/TextureMaterial.js +29 -0
  152. package/dist/objects/materials/dim.d.ts +123 -0
  153. package/dist/objects/materials/dim.js +213 -0
  154. package/dist/objects/materials/shared.d.ts +6 -0
  155. package/dist/objects/materials/shared.js +51 -0
  156. package/dist/objects/models/ModelInstance.d.ts +22 -0
  157. package/dist/objects/models/ModelInstance.js +33 -0
  158. package/dist/objects/models/Models.d.ts +22 -0
  159. package/dist/objects/models/Models.js +177 -0
  160. package/dist/objects/models/gltf-cache.d.ts +17 -0
  161. package/dist/objects/models/gltf-cache.js +50 -0
  162. package/dist/objects/models/index.d.ts +2 -0
  163. package/dist/objects/models/index.js +1 -0
  164. package/dist/objects/models/model-asset.d.ts +48 -0
  165. package/dist/objects/models/model-asset.js +77 -0
  166. package/dist/objects/models/model-container.d.ts +139 -0
  167. package/dist/objects/models/model-container.js +227 -0
  168. package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
  169. package/dist/objects/shapes/ShapeInstance.js +40 -0
  170. package/dist/objects/shapes/Shapes.d.ts +21 -0
  171. package/dist/objects/shapes/Shapes.js +120 -0
  172. package/dist/objects/shapes/index.d.ts +2 -0
  173. package/dist/objects/shapes/index.js +1 -0
  174. package/dist/objects/shapes/shape-container.d.ts +165 -0
  175. package/dist/objects/shapes/shape-container.js +272 -0
  176. package/dist/objects/shapes/shape-geometry.d.ts +27 -0
  177. package/dist/objects/shapes/shape-geometry.js +94 -0
  178. package/dist/objects/text/TextInstance.d.ts +22 -0
  179. package/dist/objects/text/TextInstance.js +95 -0
  180. package/dist/objects/text/Texts.d.ts +30 -0
  181. package/dist/objects/text/Texts.js +41 -0
  182. package/dist/objects/text/index.d.ts +2 -0
  183. package/dist/objects/text/index.js +1 -0
  184. package/dist/objects/text/text-container.d.ts +105 -0
  185. package/dist/objects/text/text-container.js +206 -0
  186. package/dist/objects/text/text-layout.d.ts +83 -0
  187. package/dist/objects/text/text-layout.js +154 -0
  188. package/dist/space/Camera.d.ts +103 -0
  189. package/dist/space/Camera.js +321 -0
  190. package/dist/space/Scene.d.ts +44 -0
  191. package/dist/space/Scene.js +112 -0
  192. package/dist/space/Space.d.ts +288 -0
  193. package/dist/space/Space.js +329 -0
  194. package/dist/space/VisibleRect.d.ts +72 -0
  195. package/dist/space/VisibleRect.js +129 -0
  196. package/dist/space/camera-handle.d.ts +67 -0
  197. package/dist/space/camera-handle.js +63 -0
  198. package/dist/space/camera-kind.d.ts +26 -0
  199. package/dist/space/camera-kind.js +30 -0
  200. package/dist/space/canvas-size.d.ts +24 -0
  201. package/dist/space/canvas-size.js +20 -0
  202. package/dist/space/clipping.d.ts +55 -0
  203. package/dist/space/clipping.js +108 -0
  204. package/dist/space/layout-measure.d.ts +65 -0
  205. package/dist/space/layout-measure.js +173 -0
  206. package/dist/space/viewport.d.ts +112 -0
  207. package/dist/space/viewport.js +67 -0
  208. package/dist/types/defs.d.ts +169 -0
  209. package/dist/types/defs.js +1 -0
  210. package/dist/types/events.d.ts +183 -0
  211. package/dist/types/events.js +1 -0
  212. package/dist/types/guards.d.ts +14 -0
  213. package/dist/types/guards.js +42 -0
  214. package/dist/update/index.d.ts +3 -0
  215. package/dist/update/index.js +2 -0
  216. package/dist/update/slot-writers.d.ts +30 -0
  217. package/dist/update/slot-writers.js +72 -0
  218. package/dist/update/store.d.ts +41 -0
  219. package/dist/update/store.js +98 -0
  220. package/dist/utils/arrays.d.ts +13 -0
  221. package/dist/utils/arrays.js +20 -0
  222. package/dist/utils/colors.d.ts +19 -0
  223. package/dist/utils/colors.js +27 -0
  224. package/dist/utils/logging.d.ts +26 -0
  225. package/dist/utils/logging.js +47 -0
  226. package/dist/utils/math.d.ts +24 -0
  227. package/dist/utils/math.js +27 -0
  228. package/package.json +67 -19
@@ -0,0 +1,178 @@
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: the plan is drawn in three's own defaults — no tonemapping, sRGB
86
+ // output — and anything the renderer would opine on is left unset.
87
+ const glRenderer = new WebGLRenderer({ canvas, context });
88
+ // Never clear: the host's own layers are already on the canvas when this renderer draws.
89
+ glRenderer.autoClear = false;
90
+ // The canvas is the host's, twice over. Three would write the css style along with every resize
91
+ // unless told otherwise each time; and R3F's unmount forces a context loss on the renderer it
92
+ // tears down, which on a shared context would take the host's own drawing with it.
93
+ const applySize = glRenderer.setSize.bind(glRenderer);
94
+ glRenderer.setSize = (width, height) => applySize(width, height, false);
95
+ glRenderer.forceContextLoss = () => undefined;
96
+ const measure = () => {
97
+ const rect = canvas.getBoundingClientRect();
98
+ return { width: rect.width, height: rect.height, top: rect.top, left: rect.left };
99
+ };
100
+ const root = createRoot(canvas);
101
+ let disposed = false;
102
+ let configured = false;
103
+ let pending;
104
+ let unsubscribeFrame;
105
+ let observer;
106
+ void root
107
+ .configure({
108
+ gl: glRenderer,
109
+ // `flat` is not an opinion here but a shield: R3F's first configure force-writes
110
+ // `toneMapping` onto any renderer it is handed — ACES filmic unless flat — and flat is the
111
+ // one value that lands on three's own default, NoToneMapping. Everything else stays as the
112
+ // bare constructor left it.
113
+ flat: true,
114
+ // The cast widens past R3F's frustum-camera union; `manual` above is what keeps R3F's own
115
+ // camera handling off it.
116
+ camera: camera,
117
+ frameloop: 'never',
118
+ events: externalEvents,
119
+ size: measure(),
120
+ dpr: window.devicePixelRatio,
121
+ })
122
+ .then(() => {
123
+ if (disposed)
124
+ return;
125
+ const store = _roots.get(canvas)?.store;
126
+ if (!store)
127
+ return;
128
+ // R3F's invalidate no-ops under `frameloop: 'never'`; the host owns the frames, so demand
129
+ // becomes a repaint request. Replaced after configure, which is what wrote the original.
130
+ store.setState({
131
+ invalidate: () => {
132
+ if (!disposed)
133
+ requestFrame();
134
+ },
135
+ });
136
+ store.getState().events.connect?.(canvas);
137
+ unsubscribeFrame = onFrame((projectionMatrix) => {
138
+ if (disposed)
139
+ return;
140
+ setExternalCameraProjection(camera, projectionMatrix);
141
+ // Three tracks GL state it did not set; sharing a context means resetting that tracking
142
+ // at the start of every frame, or the host's own state reads as three's.
143
+ glRenderer.resetState();
144
+ advance(performance.now(), true, store.getState());
145
+ });
146
+ // The host resizes its own canvas; the root only has to notice. Watching the element beats a
147
+ // host-specific resize event, and a dpr change reaches the same handler through the resize
148
+ // the host performs for it. Feature-detected for the oldest WebViews the SDK still runs in —
149
+ // without the observer the plan still draws, at the size it mounted at.
150
+ if (typeof ResizeObserver === 'function') {
151
+ observer = new ResizeObserver(() => {
152
+ if (disposed)
153
+ return;
154
+ const next = measure();
155
+ store.getState().setSize(next.width, next.height, next.top, next.left);
156
+ store.getState().setDpr(window.devicePixelRatio);
157
+ });
158
+ observer.observe(canvas);
159
+ }
160
+ configured = true;
161
+ if (pending !== undefined)
162
+ root.render(pending);
163
+ requestFrame();
164
+ });
165
+ return {
166
+ render(node) {
167
+ pending = node;
168
+ if (configured)
169
+ root.render(node);
170
+ },
171
+ dispose() {
172
+ disposed = true;
173
+ observer?.disconnect();
174
+ unsubscribeFrame?.();
175
+ root.unmount();
176
+ },
177
+ };
178
+ }
@@ -0,0 +1,17 @@
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.
11
+ * @param camera - The external camera to publish onto; `matrixAutoUpdate` and
12
+ * `matrixWorldAutoUpdate` must be off, since everything here is written by hand.
13
+ * @param mainMatrix - The combined matrix mapping world space directly to clip space, sixteen
14
+ * elements column-major.
15
+ */
16
+ export declare function setExternalCameraProjection(camera: Camera, mainMatrix: ArrayLike<number>): void;
17
+ //# sourceMappingURL=external-camera.d.ts.map
@@ -0,0 +1,82 @@
1
+ import { Matrix3, Matrix4, Vector3 } 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.
11
+ * @param camera - The external camera to publish onto; `matrixAutoUpdate` and
12
+ * `matrixWorldAutoUpdate` must be off, since everything here is written by hand.
13
+ * @param mainMatrix - The combined matrix mapping world space directly to clip space, sixteen
14
+ * elements column-major.
15
+ */
16
+ export function setExternalCameraProjection(camera, mainMatrix) {
17
+ const M = _main.fromArray(mainMatrix);
18
+ const e = M.elements; // column-major storage: M[row, col] = e[row + 4 * col]
19
+ // Step 1: camera world position c.
20
+ //
21
+ // A standard perspective projection P has its fourth column equal to (0, 0, ±f, 0), so
22
+ // P · [0; 0; 0; 1] is zero in rows 0, 1, and 3. The view matrix V maps the camera position to
23
+ // view-space origin: V · [c; 1] = [0; 0; 0; 1]. Composing these:
24
+ //
25
+ // M · [c; 1] = P · V · [c; 1] = P · [0; 0; 0; 1] = (0, 0, k, 0)
26
+ //
27
+ // so rows 0, 1, and 3 of M dotted with [c; 1] all equal zero. That is a 3×3 linear system for
28
+ // the three components of c, independent of NDC z conventions (standard OpenGL vs. reverse-z),
29
+ // so it works for both maplibre and a vanilla GL setup.
30
+ _system.set(e[0], e[4], e[8], e[1], e[5], e[9], e[3], e[7], e[11]);
31
+ _position.set(-e[12], -e[13], -e[15]).applyMatrix3(_system.invert());
32
+ // Step 2: view direction in world space.
33
+ //
34
+ // Unproject two world-space points along the central view ray and take their difference. The
35
+ // clip-space z boundaries (±1) are used rather than an interior NDC z because maplibre's
36
+ // projection has an infinite far plane in a reverse-z arrangement: an interior z (0 in
37
+ // particular) unprojects to a homogeneous direction at infinity and comes back as NaN after the
38
+ // w-divide. z = ±1 always produces finite points, so the subtraction is well-defined.
39
+ //
40
+ // Which of the two is the near plane depends on the projection's z convention — reverse-z under
41
+ // maplibre, standard under vanilla GL — so it is settled by distance to the eye recovered above:
42
+ // the near point is the closer one, and the view looks from it toward the other. (The imperative
43
+ // renderer hardcoded maplibre's ordering; measuring is what makes both conventions work.)
44
+ _mainInverse.copy(M).invert();
45
+ _near.set(0, 0, 1).applyMatrix4(_mainInverse);
46
+ _far.set(0, 0, -1).applyMatrix4(_mainInverse);
47
+ if (_near.distanceToSquared(_position) > _far.distanceToSquared(_position)) {
48
+ _direction.copy(_near).sub(_far).normalize();
49
+ }
50
+ else {
51
+ _direction.copy(_far).sub(_near).normalize();
52
+ }
53
+ // Step 3: synthesize a rigid view matrix via look-at.
54
+ //
55
+ // The choice of "up" is arbitrary as long as it is not parallel to the view direction: any
56
+ // non-degenerate choice yields a valid (P′, V′) pair, because P is recomputed from
57
+ // M · matrixWorld at the end. The fallback handles top-down or bottom-up views where world +z
58
+ // aligns with the view ray.
59
+ _up.set(0, 0, 1);
60
+ if (Math.abs(_up.dot(_direction)) > 0.999)
61
+ _up.set(0, 1, 0);
62
+ _target.copy(_position).add(_direction);
63
+ camera.matrixWorld.lookAt(_position, _target, _up);
64
+ camera.matrixWorld.setPosition(_position);
65
+ camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
66
+ // Step 4: derive projection so that P · V = M exactly.
67
+ //
68
+ // P = M · matrixWorld, because matrixWorld = V⁻¹ and therefore P · V = (M · V⁻¹) · V = M. Any
69
+ // scale or skew that did not fit into the rigid V lives in P.
70
+ camera.projectionMatrix.multiplyMatrices(M, camera.matrixWorld);
71
+ camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();
72
+ }
73
+ // Scratch, reused across calls so a per-frame update allocates nothing.
74
+ const _main = new Matrix4();
75
+ const _mainInverse = new Matrix4();
76
+ const _system = new Matrix3();
77
+ const _position = new Vector3();
78
+ const _near = new Vector3();
79
+ const _far = new Vector3();
80
+ const _direction = new Vector3();
81
+ const _target = new Vector3();
82
+ 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
+ }