@geometra/renderer-three 0.1.3 → 1.3.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 (39) hide show
  1. package/dist/host-css-coerce.d.ts +39 -0
  2. package/dist/host-css-coerce.d.ts.map +1 -0
  3. package/dist/host-css-coerce.js +69 -0
  4. package/dist/host-css-coerce.js.map +1 -0
  5. package/dist/host-layout-plain.d.ts +164 -0
  6. package/dist/host-layout-plain.d.ts.map +1 -0
  7. package/dist/host-layout-plain.js +255 -0
  8. package/dist/host-layout-plain.js.map +1 -0
  9. package/dist/index.d.ts +43 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +42 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/layout-sync.d.ts +51 -0
  14. package/dist/layout-sync.d.ts.map +1 -0
  15. package/dist/layout-sync.js +59 -0
  16. package/dist/layout-sync.js.map +1 -0
  17. package/dist/scene3d-manager.d.ts +29 -0
  18. package/dist/scene3d-manager.d.ts.map +1 -0
  19. package/dist/scene3d-manager.js +339 -0
  20. package/dist/scene3d-manager.js.map +1 -0
  21. package/dist/split-host.d.ts +58 -17
  22. package/dist/split-host.d.ts.map +1 -1
  23. package/dist/split-host.js +105 -46
  24. package/dist/split-host.js.map +1 -1
  25. package/dist/stacked-host.d.ts +109 -0
  26. package/dist/stacked-host.d.ts.map +1 -0
  27. package/dist/stacked-host.js +218 -0
  28. package/dist/stacked-host.js.map +1 -0
  29. package/dist/three-scene-basics.d.ts +338 -0
  30. package/dist/three-scene-basics.d.ts.map +1 -0
  31. package/dist/three-scene-basics.js +435 -0
  32. package/dist/three-scene-basics.js.map +1 -0
  33. package/dist/utils.d.ts +165 -1
  34. package/dist/utils.d.ts.map +1 -1
  35. package/dist/utils.js +219 -3
  36. package/dist/utils.js.map +1 -1
  37. package/package.json +15 -16
  38. package/LICENSE +0 -21
  39. package/README.md +0 -81
@@ -1,38 +1,57 @@
1
1
  import * as THREE from 'three';
2
2
  import { type BrowserCanvasClientHandle, type BrowserCanvasClientOptions } from '@geometra/renderer-canvas';
3
- export interface ThreeGeometraSplitHostOptions extends Omit<BrowserCanvasClientOptions, 'canvas'> {
3
+ import { type GeometraThreeSceneBasicsOptions } from './three-scene-basics.js';
4
+ /**
5
+ * Every {@link createBrowserCanvasClient} option except `canvas`, which split/stacked hosts create
6
+ * internally. Includes `url`, `binaryFraming`, optional explicit `window` for tests/iframes, and
7
+ * the rest of {@link BrowserCanvasClientOptions}.
8
+ */
9
+ export type GeometraHostBrowserCanvasClientOptions = Omit<BrowserCanvasClientOptions, 'canvas'>;
10
+ /**
11
+ * Default Geometra column width for {@link createThreeGeometraSplitHost}; same value as the
12
+ * `geometraWidth` option fallback and README.
13
+ */
14
+ export declare const GEOMETRA_SPLIT_HOST_LAYOUT_DEFAULTS: {
15
+ readonly geometraWidth: 420;
16
+ };
17
+ export interface ThreeGeometraSplitHostOptions extends GeometraHostBrowserCanvasClientOptions, GeometraThreeSceneBasicsOptions {
4
18
  /** Host element; a flex row is appended as a child (existing children are left untouched). */
5
19
  container: HTMLElement;
6
- /** Geometra column width in CSS pixels. Default: 420. */
20
+ /**
21
+ * Geometra column width in CSS pixels. Default: 420 ({@link GEOMETRA_SPLIT_HOST_LAYOUT_DEFAULTS}).
22
+ * Non-finite or negative values fall back to the default so layout does not emit invalid `px` styles.
23
+ */
7
24
  geometraWidth?: number;
8
25
  /** When true, Geometra panel is on the left. Default: false (Three.js left, Geometra right). */
9
26
  geometraOnLeft?: boolean;
10
- /** Clear color for the Three.js scene. Default: `0x000000`. */
11
- threeBackground?: THREE.ColorRepresentation;
12
- /** Perspective camera FOV in degrees. Default: 50. */
13
- cameraFov?: number;
14
- /** Near plane. Default: 0.1. */
15
- cameraNear?: number;
16
- /** Far plane. Default: 2000. */
17
- cameraFar?: number;
18
- /** Initial camera position. Default: `(0, 0, 5)`. */
19
- cameraPosition?: THREE.Vector3Tuple;
27
+ /**
28
+ * Upper bound for `window.devicePixelRatio` when sizing the WebGL drawing buffer (e.g. `2` on retina
29
+ * to cut memory and fragment cost). When omitted, the full device pixel ratio is used.
30
+ */
31
+ maxDevicePixelRatio?: number;
20
32
  /**
21
33
  * Called once after scene, camera, and renderer are created.
22
- * Add meshes, lights, controls, etc.
34
+ * Add meshes, lights, controls, etc. Call `ctx.destroy()` to tear down immediately; the render loop
35
+ * will not start if the host is already destroyed. If this callback throws, the host is fully torn
36
+ * down and the error is rethrown.
23
37
  */
24
38
  onThreeReady?: (ctx: ThreeRuntimeContext) => void;
25
39
  /**
26
40
  * Called every frame before `renderer.render`.
27
- * Use for animations; return nothing.
41
+ * Use for animations. Return **`false`** to skip `render` for this frame only (same idea as
42
+ * {@link tickGeometraThreeWebGLWithSceneBasicsFrame}). If you call {@link ThreeRuntimeContext.destroy} here,
43
+ * teardown runs and this frame’s `render` is skipped (avoids rendering after WebGL dispose).
44
+ * If this callback throws, the host is fully torn down and the error is rethrown (same as {@link onThreeReady}).
28
45
  */
29
- onThreeFrame?: (ctx: ThreeFrameContext) => void;
46
+ onThreeFrame?: (ctx: ThreeFrameContext) => void | false;
30
47
  }
31
48
  export interface ThreeRuntimeContext {
32
49
  renderer: THREE.WebGLRenderer;
33
50
  scene: THREE.Scene;
34
51
  camera: THREE.PerspectiveCamera;
35
52
  threeCanvas: HTMLCanvasElement;
53
+ /** Same as `ThreeGeometraSplitHostHandle.destroy` — idempotent full teardown. */
54
+ destroy(): void;
36
55
  }
37
56
  export interface ThreeFrameContext extends ThreeRuntimeContext {
38
57
  clock: THREE.Clock;
@@ -50,7 +69,12 @@ export interface ThreeGeometraSplitHostHandle {
50
69
  camera: THREE.PerspectiveCamera;
51
70
  clock: THREE.Clock;
52
71
  geometra: BrowserCanvasClientHandle;
53
- /** Stops the render loop, disconnects observers, disposes WebGL, and tears down the Geometra client. */
72
+ /**
73
+ * Stops the render loop, tears down WebGL via {@link disposeGeometraThreeWebGLWithSceneBasics} (clock stop +
74
+ * the same renderer registration headless {@link renderGeometraThreeWebGLWithSceneBasicsFrame} /
75
+ * {@link tickGeometraThreeWebGLWithSceneBasicsFrame} use to skip draws after dispose), disconnects observers,
76
+ * and tears down the Geometra client.
77
+ */
54
78
  destroy(): void;
55
79
  }
56
80
  /**
@@ -58,7 +82,24 @@ export interface ThreeGeometraSplitHostHandle {
58
82
  *
59
83
  * This is the recommended **hybrid** layout: 3D stays in Three; chrome and data panes stay in Geometra’s protocol.
60
84
  * Geometra’s client still uses `resizeTarget: window` by default; when only the Geometra column changes size,
61
- * a `ResizeObserver` dispatches a synthetic `resize` on `window` so layout width/height track the panel.
85
+ * a `ResizeObserver` schedules a synthetic `resize` on `window` so layout width/height track the panel.
86
+ * The host `root` and both flex panes are observed (same idea as {@link createThreeGeometraStackedHost} observing
87
+ * its `root`) so container-driven root box changes still coalesce into the same rAF pass even if a panel callback
88
+ * ordering quirk would otherwise miss a tick.
89
+ * Panel-driven updates coalesce to at most **one** animation frame per burst: a single `requestAnimationFrame`
90
+ * pass runs the Three.js buffer resize and (when needed) that synthetic `resize`, so both flex panes firing
91
+ * in the same frame do not call `renderer.setSize` twice.
92
+ *
93
+ * Real `window` `resize` events schedule the same coalesced Three.js pass **without** an extra synthetic
94
+ * `resize`, so the thin client is not double-notified when the browser already fired `resize`.
95
+ *
96
+ * The Three.js pane listens to `window` `resize` as well so `devicePixelRatio` updates (zoom / display changes)
97
+ * refresh the WebGL drawing buffer without relying on panel `ResizeObserver` alone. Optional
98
+ * {@link ThreeGeometraSplitHostOptions.maxDevicePixelRatio} caps the ratio used for the WebGL buffer.
99
+ *
100
+ * Pass through {@link BrowserCanvasClientOptions} from `@geometra/renderer-canvas` / `@geometra/client`
101
+ * (for example `binaryFraming`, `onError`, `onFrameMetrics`, `onData` for JSON side-channels on the same
102
+ * socket as layout; channel names are defined by your app and the Geometra server).
62
103
  */
63
104
  export declare function createThreeGeometraSplitHost(options: ThreeGeometraSplitHostOptions): ThreeGeometraSplitHostHandle;
64
105
  //# sourceMappingURL=split-host.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"split-host.d.ts","sourceRoot":"","sources":["../src/split-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAChC,MAAM,2BAA2B,CAAA;AAElC,MAAM,WAAW,6BAA8B,SAAQ,IAAI,CAAC,0BAA0B,EAAE,QAAQ,CAAC;IAC/F,8FAA8F;IAC9F,SAAS,EAAE,WAAW,CAAA;IACtB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gGAAgG;IAChG,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAA;IAC3C,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qDAAqD;IACrD,cAAc,CAAC,EAAE,KAAK,CAAC,YAAY,CAAA;IACnC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAA;IACjD;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAA;CAChD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAA;IAC/B,WAAW,EAAE,iBAAiB,CAAA;CAC/B;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,cAAc,CAAA;IACpB,UAAU,EAAE,cAAc,CAAA;IAC1B,aAAa,EAAE,cAAc,CAAA;IAC7B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,cAAc,EAAE,iBAAiB,CAAA;IACjC,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,QAAQ,EAAE,yBAAyB,CAAA;IACnC,wGAAwG;IACxG,OAAO,IAAI,IAAI,CAAA;CAChB;AAgBD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,4BAA4B,CAgJ9B"}
1
+ {"version":3,"file":"split-host.d.ts","sourceRoot":"","sources":["../src/split-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAChC,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAIL,KAAK,+BAA+B,EACrC,MAAM,yBAAyB,CAAA;AAKhC;;;;GAIG;AACH,MAAM,MAAM,sCAAsC,GAAG,IAAI,CAAC,0BAA0B,EAAE,QAAQ,CAAC,CAAA;AAE/F;;;GAGG;AACH,eAAO,MAAM,mCAAmC;;CAEtC,CAAA;AAEV,MAAM,WAAW,6BACf,SAAQ,sCAAsC,EAC5C,+BAA+B;IACjC,8FAA8F;IAC9F,SAAS,EAAE,WAAW,CAAA;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gGAAgG;IAChG,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAA;IACjD;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,KAAK,CAAA;CACxD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAA;IAC/B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,iFAAiF;IACjF,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,cAAc,CAAA;IACpB,UAAU,EAAE,cAAc,CAAA;IAC1B,aAAa,EAAE,cAAc,CAAA;IAC7B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,cAAc,EAAE,iBAAiB,CAAA;IACjC,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,QAAQ,EAAE,yBAAyB,CAAA;IACnC;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,4BAA4B,CA0L9B"}
@@ -1,5 +1,15 @@
1
- import * as THREE from 'three';
2
1
  import { createBrowserCanvasClient, } from '@geometra/renderer-canvas';
2
+ import { GEOMETRA_THREE_HOST_SCENE_DEFAULTS, createGeometraThreeWebGLWithSceneBasics, disposeGeometraThreeWebGLWithSceneBasics, } from './three-scene-basics.js';
3
+ import { createGeometraHostLayoutSyncRaf } from './layout-sync.js';
4
+ import { coerceHostNonNegativeCssPx } from './host-css-coerce.js';
5
+ import { resizeGeometraThreePerspectiveView, resolveHostDevicePixelRatio } from './utils.js';
6
+ /**
7
+ * Default Geometra column width for {@link createThreeGeometraSplitHost}; same value as the
8
+ * `geometraWidth` option fallback and README.
9
+ */
10
+ export const GEOMETRA_SPLIT_HOST_LAYOUT_DEFAULTS = {
11
+ geometraWidth: 420,
12
+ };
3
13
  function panelStyle(el, flex) {
4
14
  el.style.flex = flex;
5
15
  el.style.minWidth = '0';
@@ -17,10 +27,28 @@ function fullSizeCanvas(canvas) {
17
27
  *
18
28
  * This is the recommended **hybrid** layout: 3D stays in Three; chrome and data panes stay in Geometra’s protocol.
19
29
  * Geometra’s client still uses `resizeTarget: window` by default; when only the Geometra column changes size,
20
- * a `ResizeObserver` dispatches a synthetic `resize` on `window` so layout width/height track the panel.
30
+ * a `ResizeObserver` schedules a synthetic `resize` on `window` so layout width/height track the panel.
31
+ * The host `root` and both flex panes are observed (same idea as {@link createThreeGeometraStackedHost} observing
32
+ * its `root`) so container-driven root box changes still coalesce into the same rAF pass even if a panel callback
33
+ * ordering quirk would otherwise miss a tick.
34
+ * Panel-driven updates coalesce to at most **one** animation frame per burst: a single `requestAnimationFrame`
35
+ * pass runs the Three.js buffer resize and (when needed) that synthetic `resize`, so both flex panes firing
36
+ * in the same frame do not call `renderer.setSize` twice.
37
+ *
38
+ * Real `window` `resize` events schedule the same coalesced Three.js pass **without** an extra synthetic
39
+ * `resize`, so the thin client is not double-notified when the browser already fired `resize`.
40
+ *
41
+ * The Three.js pane listens to `window` `resize` as well so `devicePixelRatio` updates (zoom / display changes)
42
+ * refresh the WebGL drawing buffer without relying on panel `ResizeObserver` alone. Optional
43
+ * {@link ThreeGeometraSplitHostOptions.maxDevicePixelRatio} caps the ratio used for the WebGL buffer.
44
+ *
45
+ * Pass through {@link BrowserCanvasClientOptions} from `@geometra/renderer-canvas` / `@geometra/client`
46
+ * (for example `binaryFraming`, `onError`, `onFrameMetrics`, `onData` for JSON side-channels on the same
47
+ * socket as layout; channel names are defined by your app and the Geometra server).
21
48
  */
22
49
  export function createThreeGeometraSplitHost(options) {
23
- const { container, geometraWidth = 420, geometraOnLeft = false, threeBackground = 0x000000, cameraFov = 50, cameraNear = 0.1, cameraFar = 2000, cameraPosition = [0, 0, 5], onThreeReady, onThreeFrame, window: providedWindow, ...browserOptions } = options;
50
+ const { container, geometraWidth: geometraWidthOpt = GEOMETRA_SPLIT_HOST_LAYOUT_DEFAULTS.geometraWidth, geometraOnLeft = false, maxDevicePixelRatio, threeBackground = GEOMETRA_THREE_HOST_SCENE_DEFAULTS.threeBackground, cameraFov = GEOMETRA_THREE_HOST_SCENE_DEFAULTS.cameraFov, cameraNear = GEOMETRA_THREE_HOST_SCENE_DEFAULTS.cameraNear, cameraFar = GEOMETRA_THREE_HOST_SCENE_DEFAULTS.cameraFar, cameraPosition = GEOMETRA_THREE_HOST_SCENE_DEFAULTS.cameraPosition, onThreeReady, onThreeFrame, window: providedWindow, ...browserOptions } = options;
51
+ const geometraWidth = coerceHostNonNegativeCssPx(geometraWidthOpt, GEOMETRA_SPLIT_HOST_LAYOUT_DEFAULTS.geometraWidth);
24
52
  const doc = container.ownerDocument;
25
53
  const win = providedWindow ?? doc.defaultView;
26
54
  if (!win) {
@@ -52,72 +80,103 @@ export function createThreeGeometraSplitHost(options) {
52
80
  const geometraCanvas = doc.createElement('canvas');
53
81
  fullSizeCanvas(geometraCanvas);
54
82
  geometraPanel.appendChild(geometraCanvas);
55
- const glRenderer = new THREE.WebGLRenderer({
56
- canvas: threeCanvas,
57
- antialias: true,
58
- alpha: false,
83
+ const { renderer: glRenderer, scene, camera, clock } = createGeometraThreeWebGLWithSceneBasics(threeCanvas, {
84
+ threeBackground,
85
+ cameraFov,
86
+ cameraNear,
87
+ cameraFar,
88
+ cameraPosition,
59
89
  });
60
- glRenderer.setPixelRatio(win.devicePixelRatio || 1);
61
- const scene = new THREE.Scene();
62
- scene.background = new THREE.Color(threeBackground);
63
- const camera = new THREE.PerspectiveCamera(cameraFov, 1, cameraNear, cameraFar);
64
- camera.position.set(cameraPosition[0], cameraPosition[1], cameraPosition[2]);
65
- const clock = new THREE.Clock();
66
90
  const resizeThree = () => {
67
- const w = Math.max(1, Math.floor(threePanel.clientWidth));
68
- const h = Math.max(1, Math.floor(threePanel.clientHeight));
69
- camera.aspect = w / h;
70
- camera.updateProjectionMatrix();
71
- glRenderer.setSize(w, h, false);
91
+ resizeGeometraThreePerspectiveView(glRenderer, camera, threePanel.clientWidth, threePanel.clientHeight, resolveHostDevicePixelRatio(win.devicePixelRatio || 1, maxDevicePixelRatio));
72
92
  };
73
- resizeThree();
74
- const geometraHandle = createBrowserCanvasClient({
75
- ...browserOptions,
76
- canvas: geometraCanvas,
77
- window: win,
78
- });
79
- const triggerGeometraResize = () => {
80
- win.requestAnimationFrame(() => {
93
+ let destroyed = false;
94
+ const layoutSync = createGeometraHostLayoutSyncRaf(win, {
95
+ isDestroyed: () => destroyed,
96
+ syncLayout: resizeThree,
97
+ dispatchGeometraResize: () => {
81
98
  win.dispatchEvent(new Event('resize'));
82
- });
99
+ },
100
+ });
101
+ const onWindowResize = () => {
102
+ layoutSync.schedule(false);
83
103
  };
104
+ win.addEventListener('resize', onWindowResize, { passive: true });
105
+ resizeThree();
106
+ const geometraHandle = (() => {
107
+ try {
108
+ return createBrowserCanvasClient({
109
+ ...browserOptions,
110
+ canvas: geometraCanvas,
111
+ window: win,
112
+ });
113
+ }
114
+ catch (err) {
115
+ layoutSync.cancel();
116
+ win.removeEventListener('resize', onWindowResize);
117
+ disposeGeometraThreeWebGLWithSceneBasics({ renderer: glRenderer, clock });
118
+ root.remove();
119
+ throw err;
120
+ }
121
+ })();
84
122
  const roContainer = new ResizeObserver(() => {
85
- resizeThree();
86
- triggerGeometraResize();
123
+ layoutSync.schedule(true);
87
124
  });
125
+ roContainer.observe(root);
88
126
  roContainer.observe(threePanel);
89
127
  roContainer.observe(geometraPanel);
128
+ let rafId;
129
+ const destroy = () => {
130
+ if (destroyed)
131
+ return;
132
+ destroyed = true;
133
+ if (rafId !== undefined) {
134
+ win.cancelAnimationFrame(rafId);
135
+ rafId = undefined;
136
+ }
137
+ layoutSync.cancel();
138
+ win.removeEventListener('resize', onWindowResize);
139
+ roContainer.disconnect();
140
+ geometraHandle.destroy();
141
+ disposeGeometraThreeWebGLWithSceneBasics({ renderer: glRenderer, clock });
142
+ root.remove();
143
+ };
90
144
  const ctxBase = {
91
145
  renderer: glRenderer,
92
146
  scene,
93
147
  camera,
94
148
  threeCanvas,
149
+ destroy,
95
150
  };
96
- onThreeReady?.(ctxBase);
97
- let raf = 0;
98
- let destroyed = false;
151
+ try {
152
+ onThreeReady?.(ctxBase);
153
+ }
154
+ catch (err) {
155
+ destroy();
156
+ throw err;
157
+ }
99
158
  const loop = () => {
100
159
  if (destroyed)
101
160
  return;
102
- raf = win.requestAnimationFrame(loop);
161
+ rafId = win.requestAnimationFrame(loop);
103
162
  const delta = clock.getDelta();
104
163
  const elapsed = clock.elapsedTime;
105
- onThreeFrame?.({ ...ctxBase, clock, delta, elapsed });
106
- glRenderer.render(scene, camera);
107
- };
108
- raf = win.requestAnimationFrame(loop);
109
- const destroy = () => {
164
+ try {
165
+ if (onThreeFrame?.({ ...ctxBase, clock, delta, elapsed }) === false) {
166
+ return;
167
+ }
168
+ }
169
+ catch (err) {
170
+ destroy();
171
+ throw err;
172
+ }
110
173
  if (destroyed)
111
174
  return;
112
- destroyed = true;
113
- win.cancelAnimationFrame(raf);
114
- roContainer.disconnect();
115
- geometraHandle.destroy();
116
- glRenderer.dispose();
117
- if (root.parentNode === container) {
118
- container.removeChild(root);
119
- }
175
+ glRenderer.render(scene, camera);
120
176
  };
177
+ if (!destroyed) {
178
+ rafId = win.requestAnimationFrame(loop);
179
+ }
121
180
  return {
122
181
  root,
123
182
  threePanel,
@@ -1 +1 @@
1
- {"version":3,"file":"split-host.js","sourceRoot":"","sources":["../src/split-host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"split-host.js","sourceRoot":"","sources":["../src/split-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ import * as THREE from 'three';
2
+ import { type BrowserCanvasClientHandle } from '@geometra/renderer-canvas';
3
+ import type { GeometraHostBrowserCanvasClientOptions, ThreeFrameContext, ThreeRuntimeContext } from './split-host.js';
4
+ import { type GeometraThreeSceneBasicsOptions } from './three-scene-basics.js';
5
+ import { type GeometraHudPlacement } from './host-css-coerce.js';
6
+ export type { GeometraHudPlacement } from './host-css-coerce.js';
7
+ /**
8
+ * Default HUD width, height, corner, and margin for {@link createThreeGeometraStackedHost}; same as
9
+ * those option fallbacks and README.
10
+ */
11
+ export declare const GEOMETRA_STACKED_HOST_LAYOUT_DEFAULTS: {
12
+ readonly geometraHudWidth: 420;
13
+ readonly geometraHudHeight: 320;
14
+ readonly geometraHudPlacement: "bottom-right";
15
+ readonly geometraHudMargin: 12;
16
+ };
17
+ export interface ThreeGeometraStackedHostOptions extends GeometraHostBrowserCanvasClientOptions, GeometraThreeSceneBasicsOptions {
18
+ /** Host element; a full-size stacking context is appended (existing children are left untouched). */
19
+ container: HTMLElement;
20
+ /**
21
+ * HUD width in CSS pixels. Default: {@link GEOMETRA_STACKED_HOST_LAYOUT_DEFAULTS.geometraHudWidth}.
22
+ * Non-finite or negative values fall back to the default so layout does not emit invalid `px` styles.
23
+ */
24
+ geometraHudWidth?: number;
25
+ /**
26
+ * HUD height in CSS pixels. Default: {@link GEOMETRA_STACKED_HOST_LAYOUT_DEFAULTS.geometraHudHeight}.
27
+ * Non-finite or negative values fall back to the default.
28
+ */
29
+ geometraHudHeight?: number;
30
+ /**
31
+ * HUD corner. Default: {@link GEOMETRA_STACKED_HOST_LAYOUT_DEFAULTS.geometraHudPlacement}.
32
+ * Runtime strings (e.g. from JSON or agents) are normalized with {@link coerceGeometraHudPlacement}
33
+ * (trim + case-insensitive match for the four literals; anything else uses the default).
34
+ */
35
+ geometraHudPlacement?: GeometraHudPlacement;
36
+ /**
37
+ * Inset from the chosen corner in CSS pixels. Default: {@link GEOMETRA_STACKED_HOST_LAYOUT_DEFAULTS.geometraHudMargin}.
38
+ * Non-finite or negative values fall back to the default.
39
+ */
40
+ geometraHudMargin?: number;
41
+ /**
42
+ * CSS `pointer-events` on the HUD wrapper (e.g. `'none'` so input falls through to the WebGL canvas).
43
+ * Default: `'auto'`. Blank or whitespace-only strings fall back to the default; use
44
+ * {@link coerceGeometraHudPointerEvents} in custom layouts for the same rules.
45
+ */
46
+ geometraHudPointerEvents?: string;
47
+ /**
48
+ * CSS `z-index` on the HUD wrapper when you stack other siblings in {@link ThreeGeometraStackedHostOptions.container}
49
+ * or need a fixed order above the WebGL layer (Three canvas uses `0`). Default: `1`.
50
+ * Non-finite numbers and blank/whitespace-only strings fall back to the default so the HUD keeps a predictable stack order.
51
+ */
52
+ geometraHudZIndex?: string | number;
53
+ /**
54
+ * Upper bound for `window.devicePixelRatio` when sizing the WebGL drawing buffer (e.g. `2` on retina
55
+ * to cut memory and fragment cost). When omitted, the full device pixel ratio is used.
56
+ */
57
+ maxDevicePixelRatio?: number;
58
+ /**
59
+ * Called once after scene, camera, and renderer are created.
60
+ * Call `ctx.destroy()` to tear down immediately; the render loop will not start if the host is already destroyed.
61
+ * If this callback throws, the host is fully torn down and the error is rethrown.
62
+ */
63
+ onThreeReady?: (ctx: ThreeRuntimeContext) => void;
64
+ /**
65
+ * Called every frame before `renderer.render`.
66
+ * Return **`false`** to skip `render` for this frame only (same idea as
67
+ * {@link tickGeometraThreeWebGLWithSceneBasicsFrame}). If you call {@link ThreeRuntimeContext.destroy} here,
68
+ * teardown runs and this frame’s `render` is skipped.
69
+ * If this callback throws, the host is fully torn down and the error is rethrown (same as {@link onThreeReady}).
70
+ */
71
+ onThreeFrame?: (ctx: ThreeFrameContext) => void | false;
72
+ }
73
+ export interface ThreeGeometraStackedHostHandle {
74
+ root: HTMLDivElement;
75
+ /** Absolutely positioned wrapper around the Geometra canvas (stacked HUD). */
76
+ geometraHud: HTMLDivElement;
77
+ threeCanvas: HTMLCanvasElement;
78
+ geometraCanvas: HTMLCanvasElement;
79
+ renderer: THREE.WebGLRenderer;
80
+ scene: THREE.Scene;
81
+ camera: THREE.PerspectiveCamera;
82
+ clock: THREE.Clock;
83
+ geometra: BrowserCanvasClientHandle;
84
+ /**
85
+ * Stops the render loop, tears down WebGL via {@link disposeGeometraThreeWebGLWithSceneBasics} (clock stop +
86
+ * the same renderer registration headless {@link renderGeometraThreeWebGLWithSceneBasicsFrame} /
87
+ * {@link tickGeometraThreeWebGLWithSceneBasicsFrame} use to skip draws after dispose), disconnects observers,
88
+ * and tears down the Geometra client.
89
+ */
90
+ destroy(): void;
91
+ }
92
+ /**
93
+ * Stacked host: full-viewport Three.js `WebGLRenderer` with a positioned Geometra canvas **HUD** on top.
94
+ *
95
+ * Pointer routing follows normal hit-testing: events hit the Geometra canvas where it overlaps the WebGL layer
96
+ * (HUD `z-index` above the Three canvas, which uses `0`); elsewhere, the Three canvas receives input. Override with
97
+ * {@link ThreeGeometraStackedHostOptions.geometraHudPointerEvents} (e.g. `'none'` for a click-through HUD) or
98
+ * {@link ThreeGeometraStackedHostOptions.geometraHudZIndex} when you add other positioned siblings.
99
+ *
100
+ * Geometra’s client still uses `resizeTarget: window` by default; when only the HUD box changes size,
101
+ * a coalesced synthetic `resize` is dispatched on `window` (same pattern as {@link createThreeGeometraSplitHost}).
102
+ * `ResizeObserver` callbacks and real `window` `resize` share one rAF-coalesced Three.js buffer pass; the
103
+ * synthetic `resize` is emitted only from observer-driven layout changes, not from real window resizes.
104
+ * The Three.js layer listens to `window` `resize` for `devicePixelRatio` changes and uses the host `root` size
105
+ * for the drawing buffer. Optional {@link ThreeGeometraStackedHostOptions.maxDevicePixelRatio} caps the ratio
106
+ * used for the WebGL buffer.
107
+ */
108
+ export declare function createThreeGeometraStackedHost(options: ThreeGeometraStackedHostOptions): ThreeGeometraStackedHostHandle;
109
+ //# sourceMappingURL=stacked-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stacked-host.d.ts","sourceRoot":"","sources":["../src/stacked-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EACV,sCAAsC,EACtC,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAIL,KAAK,+BAA+B,EACrC,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAA;AAG7B,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAEhE;;;GAGG;AACH,eAAO,MAAM,qCAAqC;;;;;CAUjD,CAAA;AAED,MAAM,WAAW,+BACf,SAAQ,sCAAsC,EAC5C,+BAA+B;IACjC,qGAAqG;IACrG,SAAS,EAAE,WAAW,CAAA;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACnC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAA;IACjD;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,KAAK,CAAA;CACxD;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,cAAc,CAAA;IACpB,8EAA8E;IAC9E,WAAW,EAAE,cAAc,CAAA;IAC3B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,cAAc,EAAE,iBAAiB,CAAA;IACjC,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAA;IAClB,QAAQ,EAAE,yBAAyB,CAAA;IACnC;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAsCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,8BAA8B,CAkNhC"}