@react-three-dom/core 0.4.0 → 0.6.0

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.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Object3D, Scene, Camera, WebGLRenderer, Intersection, Vector3 } from 'three';
2
2
 
3
- declare const version = "0.4.0";
3
+ declare const version = "0.5.0";
4
4
 
5
5
  /**
6
6
  * Enable or disable debug logging globally.
@@ -239,6 +239,97 @@ interface R3FDOM {
239
239
  eventCount: number;
240
240
  pointCount: number;
241
241
  }>;
242
+ /** Click at an arbitrary world coordinate (projects to screen, dispatches click) */
243
+ clickAtWorld(point: {
244
+ x: number;
245
+ y: number;
246
+ z: number;
247
+ }, options?: {
248
+ shiftKey?: boolean;
249
+ ctrlKey?: boolean;
250
+ altKey?: boolean;
251
+ metaKey?: boolean;
252
+ }): {
253
+ dispatched: boolean;
254
+ screenPoint: {
255
+ x: number;
256
+ y: number;
257
+ };
258
+ behindCamera: boolean;
259
+ };
260
+ /** Double-click at an arbitrary world coordinate */
261
+ doubleClickAtWorld(point: {
262
+ x: number;
263
+ y: number;
264
+ z: number;
265
+ }, options?: {
266
+ shiftKey?: boolean;
267
+ ctrlKey?: boolean;
268
+ altKey?: boolean;
269
+ metaKey?: boolean;
270
+ }): {
271
+ dispatched: boolean;
272
+ screenPoint: {
273
+ x: number;
274
+ y: number;
275
+ };
276
+ behindCamera: boolean;
277
+ };
278
+ /** Right-click (context menu) at an arbitrary world coordinate */
279
+ contextMenuAtWorld(point: {
280
+ x: number;
281
+ y: number;
282
+ z: number;
283
+ }, options?: {
284
+ shiftKey?: boolean;
285
+ ctrlKey?: boolean;
286
+ altKey?: boolean;
287
+ metaKey?: boolean;
288
+ }): {
289
+ dispatched: boolean;
290
+ screenPoint: {
291
+ x: number;
292
+ y: number;
293
+ };
294
+ behindCamera: boolean;
295
+ };
296
+ /** Hover at an arbitrary world coordinate */
297
+ hoverAtWorld(point: {
298
+ x: number;
299
+ y: number;
300
+ z: number;
301
+ }, options?: {
302
+ shiftKey?: boolean;
303
+ ctrlKey?: boolean;
304
+ altKey?: boolean;
305
+ metaKey?: boolean;
306
+ }): {
307
+ dispatched: boolean;
308
+ screenPoint: {
309
+ x: number;
310
+ y: number;
311
+ };
312
+ behindCamera: boolean;
313
+ };
314
+ /** Click a sequence of world coordinates with delay between each (for drawing tools) */
315
+ clickAtWorldSequence(points: Array<{
316
+ x: number;
317
+ y: number;
318
+ z: number;
319
+ }>, options?: {
320
+ delayMs?: number;
321
+ shiftKey?: boolean;
322
+ ctrlKey?: boolean;
323
+ altKey?: boolean;
324
+ metaKey?: boolean;
325
+ }): Promise<Array<{
326
+ dispatched: boolean;
327
+ screenPoint: {
328
+ x: number;
329
+ y: number;
330
+ };
331
+ behindCamera: boolean;
332
+ }>>;
242
333
  /** Select an object (shows highlight wireframe in scene) */
243
334
  select(idOrUuid: string): void;
244
335
  /** Clear selection */
@@ -916,6 +1007,16 @@ declare class Highlighter {
916
1007
  isHighlighted(obj: Object3D): boolean;
917
1008
  /** Remove all hover and selection highlights. */
918
1009
  clearAll(): void;
1010
+ /** When true, the hover poll is paused and showHoverHighlight is blocked. */
1011
+ private _hoverPollSuppressed;
1012
+ private _suppressTimer;
1013
+ /**
1014
+ * Stop the hover poll, clear all hover state, and restart after a delay.
1015
+ * This prevents the DevTools extension from re-applying highlights after
1016
+ * inspect mode is disabled (the extension polls `$0` every 200ms and
1017
+ * keeps writing `__r3fdom_hovered__`).
1018
+ */
1019
+ suppressHoverPoll(durationMs?: number): void;
919
1020
  private _syncSelectionHighlights;
920
1021
  private _addSelectionHighlight;
921
1022
  private _removeSelectionHighlight;
@@ -1777,6 +1878,62 @@ declare function circlePath(center: {
1777
1878
  y: number;
1778
1879
  }, radiusX: number, radiusY?: number, steps?: number, pressure?: number): DrawPoint[];
1779
1880
 
1881
+ /** A 3D world-space coordinate. */
1882
+ interface WorldPoint {
1883
+ x: number;
1884
+ y: number;
1885
+ z: number;
1886
+ }
1887
+ /** Options shared by all world-coordinate interactions. */
1888
+ interface WorldInteractionOptions {
1889
+ /** Modifier keys to include on the synthetic events. */
1890
+ shiftKey?: boolean;
1891
+ ctrlKey?: boolean;
1892
+ altKey?: boolean;
1893
+ metaKey?: boolean;
1894
+ }
1895
+ /** Result returned by world-coordinate interactions. */
1896
+ interface WorldInteractionResult {
1897
+ dispatched: boolean;
1898
+ screenPoint: ScreenPoint;
1899
+ behindCamera: boolean;
1900
+ }
1901
+ /**
1902
+ * Click at an arbitrary world coordinate.
1903
+ *
1904
+ * Projects the point to screen space and dispatches a full click sequence
1905
+ * (pointerdown → pointerup → click) on the canvas. R3F's event system will
1906
+ * raycast from that screen position and fire onClick on whatever mesh is hit.
1907
+ *
1908
+ * @returns Result with the screen point used and whether the point was behind the camera.
1909
+ */
1910
+ declare function clickAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1911
+ /**
1912
+ * Double-click at an arbitrary world coordinate.
1913
+ */
1914
+ declare function doubleClickAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1915
+ /**
1916
+ * Right-click (context menu) at an arbitrary world coordinate.
1917
+ */
1918
+ declare function contextMenuAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1919
+ /**
1920
+ * Hover at an arbitrary world coordinate.
1921
+ *
1922
+ * Dispatches pointermove → pointerover → pointerenter at the projected
1923
+ * screen position. R3F will raycast and fire onPointerEnter/onPointerOver
1924
+ * on whatever mesh is at that position.
1925
+ */
1926
+ declare function hoverAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1927
+ /**
1928
+ * Click a sequence of world coordinates with optional delay between each.
1929
+ * Useful for BIM drawing tools (polyline, measurement, etc.).
1930
+ *
1931
+ * @returns Array of results, one per point.
1932
+ */
1933
+ declare function clickAtWorldSequence(points: WorldPoint[], options?: {
1934
+ delayMs?: number;
1935
+ } & WorldInteractionOptions): Promise<WorldInteractionResult[]>;
1936
+
1780
1937
  /**
1781
1938
  * @module resolve
1782
1939
  *
@@ -1824,4 +1981,4 @@ declare function resolveObject(idOrUuid: string): Object3D;
1824
1981
  */
1825
1982
  declare function useR3FRegister(ref: React.RefObject<Object3D | null>, canvasId?: string): void;
1826
1983
 
1827
- export { type CameraState, type CanvasSize, type Click3DOptions, type Click3DResult, DomMirror, type Drag3DOptions, type Drag3DResult, type DragOptions, type DrawPathOptions, type DrawPathResult, type DrawPoint, type GeometryInspection, Highlighter, type HighlighterOptions, type Hover3DOptions, type Hover3DResult, InspectController, type InspectOptions, MANAGED_ATTRIBUTES, type MaterialInspection, type ObjectInspection, type ObjectMetadata, ObjectStore, type PointerMiss3DOptions, type ProjectionResult, type R3FDOM, RaycastAccelerator, type RaycastResult, type SceneSnapshot, type ScreenDelta, type ScreenPoint, type SelectionListener, SelectionManager, type SnapshotNode, type StoreEvent, type StoreEventType, type StoreListener, TAG_MAP, ThreeDom, type ThreeDomProps, ThreeElement, type ThreeTagName, type Wheel3DOptions, type Wheel3DResult, type WheelOptions, type WorldDelta, applyAttributes, circlePath, click3D, computeAttributes, contextMenu3D, createFlatSnapshot, createSnapshot, curvePath, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, drag3D, drawPath, enableDebug, ensureCustomElements, getCanvasIds, getHighlighter, getInspectController, getMirror, getSelectionManager, getStore, getTagForType, hover3D, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, useR3FRegister, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
1984
+ export { type CameraState, type CanvasSize, type Click3DOptions, type Click3DResult, DomMirror, type Drag3DOptions, type Drag3DResult, type DragOptions, type DrawPathOptions, type DrawPathResult, type DrawPoint, type GeometryInspection, Highlighter, type HighlighterOptions, type Hover3DOptions, type Hover3DResult, InspectController, type InspectOptions, MANAGED_ATTRIBUTES, type MaterialInspection, type ObjectInspection, type ObjectMetadata, ObjectStore, type PointerMiss3DOptions, type ProjectionResult, type R3FDOM, RaycastAccelerator, type RaycastResult, type SceneSnapshot, type ScreenDelta, type ScreenPoint, type SelectionListener, SelectionManager, type SnapshotNode, type StoreEvent, type StoreEventType, type StoreListener, TAG_MAP, ThreeDom, type ThreeDomProps, ThreeElement, type ThreeTagName, type Wheel3DOptions, type Wheel3DResult, type WheelOptions, type WorldDelta, type WorldInteractionOptions, type WorldInteractionResult, type WorldPoint, applyAttributes, circlePath, click3D, clickAtWorld, clickAtWorldSequence, computeAttributes, contextMenu3D, contextMenuAtWorld, createFlatSnapshot, createSnapshot, curvePath, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, doubleClickAtWorld, drag3D, drawPath, enableDebug, ensureCustomElements, getCanvasIds, getHighlighter, getInspectController, getMirror, getSelectionManager, getStore, getTagForType, hover3D, hoverAtWorld, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, useR3FRegister, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Object3D, Scene, Camera, WebGLRenderer, Intersection, Vector3 } from 'three';
2
2
 
3
- declare const version = "0.4.0";
3
+ declare const version = "0.5.0";
4
4
 
5
5
  /**
6
6
  * Enable or disable debug logging globally.
@@ -239,6 +239,97 @@ interface R3FDOM {
239
239
  eventCount: number;
240
240
  pointCount: number;
241
241
  }>;
242
+ /** Click at an arbitrary world coordinate (projects to screen, dispatches click) */
243
+ clickAtWorld(point: {
244
+ x: number;
245
+ y: number;
246
+ z: number;
247
+ }, options?: {
248
+ shiftKey?: boolean;
249
+ ctrlKey?: boolean;
250
+ altKey?: boolean;
251
+ metaKey?: boolean;
252
+ }): {
253
+ dispatched: boolean;
254
+ screenPoint: {
255
+ x: number;
256
+ y: number;
257
+ };
258
+ behindCamera: boolean;
259
+ };
260
+ /** Double-click at an arbitrary world coordinate */
261
+ doubleClickAtWorld(point: {
262
+ x: number;
263
+ y: number;
264
+ z: number;
265
+ }, options?: {
266
+ shiftKey?: boolean;
267
+ ctrlKey?: boolean;
268
+ altKey?: boolean;
269
+ metaKey?: boolean;
270
+ }): {
271
+ dispatched: boolean;
272
+ screenPoint: {
273
+ x: number;
274
+ y: number;
275
+ };
276
+ behindCamera: boolean;
277
+ };
278
+ /** Right-click (context menu) at an arbitrary world coordinate */
279
+ contextMenuAtWorld(point: {
280
+ x: number;
281
+ y: number;
282
+ z: number;
283
+ }, options?: {
284
+ shiftKey?: boolean;
285
+ ctrlKey?: boolean;
286
+ altKey?: boolean;
287
+ metaKey?: boolean;
288
+ }): {
289
+ dispatched: boolean;
290
+ screenPoint: {
291
+ x: number;
292
+ y: number;
293
+ };
294
+ behindCamera: boolean;
295
+ };
296
+ /** Hover at an arbitrary world coordinate */
297
+ hoverAtWorld(point: {
298
+ x: number;
299
+ y: number;
300
+ z: number;
301
+ }, options?: {
302
+ shiftKey?: boolean;
303
+ ctrlKey?: boolean;
304
+ altKey?: boolean;
305
+ metaKey?: boolean;
306
+ }): {
307
+ dispatched: boolean;
308
+ screenPoint: {
309
+ x: number;
310
+ y: number;
311
+ };
312
+ behindCamera: boolean;
313
+ };
314
+ /** Click a sequence of world coordinates with delay between each (for drawing tools) */
315
+ clickAtWorldSequence(points: Array<{
316
+ x: number;
317
+ y: number;
318
+ z: number;
319
+ }>, options?: {
320
+ delayMs?: number;
321
+ shiftKey?: boolean;
322
+ ctrlKey?: boolean;
323
+ altKey?: boolean;
324
+ metaKey?: boolean;
325
+ }): Promise<Array<{
326
+ dispatched: boolean;
327
+ screenPoint: {
328
+ x: number;
329
+ y: number;
330
+ };
331
+ behindCamera: boolean;
332
+ }>>;
242
333
  /** Select an object (shows highlight wireframe in scene) */
243
334
  select(idOrUuid: string): void;
244
335
  /** Clear selection */
@@ -916,6 +1007,16 @@ declare class Highlighter {
916
1007
  isHighlighted(obj: Object3D): boolean;
917
1008
  /** Remove all hover and selection highlights. */
918
1009
  clearAll(): void;
1010
+ /** When true, the hover poll is paused and showHoverHighlight is blocked. */
1011
+ private _hoverPollSuppressed;
1012
+ private _suppressTimer;
1013
+ /**
1014
+ * Stop the hover poll, clear all hover state, and restart after a delay.
1015
+ * This prevents the DevTools extension from re-applying highlights after
1016
+ * inspect mode is disabled (the extension polls `$0` every 200ms and
1017
+ * keeps writing `__r3fdom_hovered__`).
1018
+ */
1019
+ suppressHoverPoll(durationMs?: number): void;
919
1020
  private _syncSelectionHighlights;
920
1021
  private _addSelectionHighlight;
921
1022
  private _removeSelectionHighlight;
@@ -1777,6 +1878,62 @@ declare function circlePath(center: {
1777
1878
  y: number;
1778
1879
  }, radiusX: number, radiusY?: number, steps?: number, pressure?: number): DrawPoint[];
1779
1880
 
1881
+ /** A 3D world-space coordinate. */
1882
+ interface WorldPoint {
1883
+ x: number;
1884
+ y: number;
1885
+ z: number;
1886
+ }
1887
+ /** Options shared by all world-coordinate interactions. */
1888
+ interface WorldInteractionOptions {
1889
+ /** Modifier keys to include on the synthetic events. */
1890
+ shiftKey?: boolean;
1891
+ ctrlKey?: boolean;
1892
+ altKey?: boolean;
1893
+ metaKey?: boolean;
1894
+ }
1895
+ /** Result returned by world-coordinate interactions. */
1896
+ interface WorldInteractionResult {
1897
+ dispatched: boolean;
1898
+ screenPoint: ScreenPoint;
1899
+ behindCamera: boolean;
1900
+ }
1901
+ /**
1902
+ * Click at an arbitrary world coordinate.
1903
+ *
1904
+ * Projects the point to screen space and dispatches a full click sequence
1905
+ * (pointerdown → pointerup → click) on the canvas. R3F's event system will
1906
+ * raycast from that screen position and fire onClick on whatever mesh is hit.
1907
+ *
1908
+ * @returns Result with the screen point used and whether the point was behind the camera.
1909
+ */
1910
+ declare function clickAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1911
+ /**
1912
+ * Double-click at an arbitrary world coordinate.
1913
+ */
1914
+ declare function doubleClickAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1915
+ /**
1916
+ * Right-click (context menu) at an arbitrary world coordinate.
1917
+ */
1918
+ declare function contextMenuAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1919
+ /**
1920
+ * Hover at an arbitrary world coordinate.
1921
+ *
1922
+ * Dispatches pointermove → pointerover → pointerenter at the projected
1923
+ * screen position. R3F will raycast and fire onPointerEnter/onPointerOver
1924
+ * on whatever mesh is at that position.
1925
+ */
1926
+ declare function hoverAtWorld(point: WorldPoint, _options?: WorldInteractionOptions): WorldInteractionResult;
1927
+ /**
1928
+ * Click a sequence of world coordinates with optional delay between each.
1929
+ * Useful for BIM drawing tools (polyline, measurement, etc.).
1930
+ *
1931
+ * @returns Array of results, one per point.
1932
+ */
1933
+ declare function clickAtWorldSequence(points: WorldPoint[], options?: {
1934
+ delayMs?: number;
1935
+ } & WorldInteractionOptions): Promise<WorldInteractionResult[]>;
1936
+
1780
1937
  /**
1781
1938
  * @module resolve
1782
1939
  *
@@ -1824,4 +1981,4 @@ declare function resolveObject(idOrUuid: string): Object3D;
1824
1981
  */
1825
1982
  declare function useR3FRegister(ref: React.RefObject<Object3D | null>, canvasId?: string): void;
1826
1983
 
1827
- export { type CameraState, type CanvasSize, type Click3DOptions, type Click3DResult, DomMirror, type Drag3DOptions, type Drag3DResult, type DragOptions, type DrawPathOptions, type DrawPathResult, type DrawPoint, type GeometryInspection, Highlighter, type HighlighterOptions, type Hover3DOptions, type Hover3DResult, InspectController, type InspectOptions, MANAGED_ATTRIBUTES, type MaterialInspection, type ObjectInspection, type ObjectMetadata, ObjectStore, type PointerMiss3DOptions, type ProjectionResult, type R3FDOM, RaycastAccelerator, type RaycastResult, type SceneSnapshot, type ScreenDelta, type ScreenPoint, type SelectionListener, SelectionManager, type SnapshotNode, type StoreEvent, type StoreEventType, type StoreListener, TAG_MAP, ThreeDom, type ThreeDomProps, ThreeElement, type ThreeTagName, type Wheel3DOptions, type Wheel3DResult, type WheelOptions, type WorldDelta, applyAttributes, circlePath, click3D, computeAttributes, contextMenu3D, createFlatSnapshot, createSnapshot, curvePath, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, drag3D, drawPath, enableDebug, ensureCustomElements, getCanvasIds, getHighlighter, getInspectController, getMirror, getSelectionManager, getStore, getTagForType, hover3D, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, useR3FRegister, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
1984
+ export { type CameraState, type CanvasSize, type Click3DOptions, type Click3DResult, DomMirror, type Drag3DOptions, type Drag3DResult, type DragOptions, type DrawPathOptions, type DrawPathResult, type DrawPoint, type GeometryInspection, Highlighter, type HighlighterOptions, type Hover3DOptions, type Hover3DResult, InspectController, type InspectOptions, MANAGED_ATTRIBUTES, type MaterialInspection, type ObjectInspection, type ObjectMetadata, ObjectStore, type PointerMiss3DOptions, type ProjectionResult, type R3FDOM, RaycastAccelerator, type RaycastResult, type SceneSnapshot, type ScreenDelta, type ScreenPoint, type SelectionListener, SelectionManager, type SnapshotNode, type StoreEvent, type StoreEventType, type StoreListener, TAG_MAP, ThreeDom, type ThreeDomProps, ThreeElement, type ThreeTagName, type Wheel3DOptions, type Wheel3DResult, type WheelOptions, type WorldDelta, type WorldInteractionOptions, type WorldInteractionResult, type WorldPoint, applyAttributes, circlePath, click3D, clickAtWorld, clickAtWorldSequence, computeAttributes, contextMenu3D, contextMenuAtWorld, createFlatSnapshot, createSnapshot, curvePath, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, doubleClickAtWorld, drag3D, drawPath, enableDebug, ensureCustomElements, getCanvasIds, getHighlighter, getInspectController, getMirror, getSelectionManager, getStore, getTagForType, hover3D, hoverAtWorld, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, useR3FRegister, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { Box3, Object3D, Vector3, Matrix4, Frustum, Raycaster, Vector2, BufferGeometry, Material, Color, MeshBasicMaterial, DoubleSide, Mesh, BoxGeometry, EdgesGeometry, LineBasicMaterial, LineSegments, InstancedMesh, PerspectiveCamera, OrthographicCamera } from 'three';
1
+ import { Box3, Vector3, Object3D, Matrix4, Frustum, Raycaster, Vector2, BufferGeometry, Material, Color, MeshBasicMaterial, DoubleSide, Mesh, BoxGeometry, EdgesGeometry, LineBasicMaterial, LineSegments, InstancedMesh, PerspectiveCamera, OrthographicCamera } from 'three';
2
2
  import { useRef, useEffect, useCallback } from 'react';
3
3
  import { useThree, useFrame } from '@react-three/fiber';
4
4
  import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three-mesh-bvh';
5
5
 
6
6
  // src/version.ts
7
- var version = "0.4.0";
7
+ var version = "0.5.0";
8
8
 
9
9
  // src/debug.ts
10
10
  var _enabled = false;
@@ -1523,6 +1523,7 @@ function findTrackingPair(obj) {
1523
1523
  function registerSubtree(obj, store, mirror, instanceKey) {
1524
1524
  obj.traverse((child) => {
1525
1525
  if (!store.has(child) && shouldRegister(instanceKey, child)) {
1526
+ ensureAncestorChain(child, store, mirror);
1526
1527
  store.register(child);
1527
1528
  mirror.onObjectAdded(child);
1528
1529
  }
@@ -2571,6 +2572,82 @@ function circlePath(center, radiusX, radiusY, steps = 36, pressure = 0.5) {
2571
2572
  function sleep2(ms) {
2572
2573
  return new Promise((resolve) => setTimeout(resolve, ms));
2573
2574
  }
2575
+ var _v = new Vector3();
2576
+ function projectWorld(point, camera, size) {
2577
+ _v.set(point.x, point.y, point.z).project(camera);
2578
+ if (_v.z > 1) return null;
2579
+ return {
2580
+ x: (_v.x + 1) / 2 * size.width,
2581
+ y: (-_v.y + 1) / 2 * size.height
2582
+ };
2583
+ }
2584
+ function clickAtWorld(point, _options = {}) {
2585
+ const camera = getCamera();
2586
+ const gl = getRenderer();
2587
+ const size = getCanvasSize();
2588
+ const canvas = gl.domElement;
2589
+ const screen = projectWorld(point, camera, size);
2590
+ if (!screen) {
2591
+ r3fLog("interaction", `clickAtWorld(${point.x}, ${point.y}, ${point.z}) \u2014 behind camera, skipped`);
2592
+ return { dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: true };
2593
+ }
2594
+ r3fLog("interaction", `clickAtWorld(${point.x}, ${point.y}, ${point.z}) \u2192 screen(${Math.round(screen.x)}, ${Math.round(screen.y)})`);
2595
+ dispatchClick(canvas, screen);
2596
+ return { dispatched: true, screenPoint: screen, behindCamera: false };
2597
+ }
2598
+ function doubleClickAtWorld(point, _options = {}) {
2599
+ const camera = getCamera();
2600
+ const gl = getRenderer();
2601
+ const size = getCanvasSize();
2602
+ const canvas = gl.domElement;
2603
+ const screen = projectWorld(point, camera, size);
2604
+ if (!screen) {
2605
+ r3fLog("interaction", `doubleClickAtWorld(${point.x}, ${point.y}, ${point.z}) \u2014 behind camera, skipped`);
2606
+ return { dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: true };
2607
+ }
2608
+ r3fLog("interaction", `doubleClickAtWorld(${point.x}, ${point.y}, ${point.z}) \u2192 screen(${Math.round(screen.x)}, ${Math.round(screen.y)})`);
2609
+ dispatchDoubleClick(canvas, screen);
2610
+ return { dispatched: true, screenPoint: screen, behindCamera: false };
2611
+ }
2612
+ function contextMenuAtWorld(point, _options = {}) {
2613
+ const camera = getCamera();
2614
+ const gl = getRenderer();
2615
+ const size = getCanvasSize();
2616
+ const canvas = gl.domElement;
2617
+ const screen = projectWorld(point, camera, size);
2618
+ if (!screen) {
2619
+ r3fLog("interaction", `contextMenuAtWorld(${point.x}, ${point.y}, ${point.z}) \u2014 behind camera, skipped`);
2620
+ return { dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: true };
2621
+ }
2622
+ r3fLog("interaction", `contextMenuAtWorld(${point.x}, ${point.y}, ${point.z}) \u2192 screen(${Math.round(screen.x)}, ${Math.round(screen.y)})`);
2623
+ dispatchContextMenu(canvas, screen);
2624
+ return { dispatched: true, screenPoint: screen, behindCamera: false };
2625
+ }
2626
+ function hoverAtWorld(point, _options = {}) {
2627
+ const camera = getCamera();
2628
+ const gl = getRenderer();
2629
+ const size = getCanvasSize();
2630
+ const canvas = gl.domElement;
2631
+ const screen = projectWorld(point, camera, size);
2632
+ if (!screen) {
2633
+ r3fLog("interaction", `hoverAtWorld(${point.x}, ${point.y}, ${point.z}) \u2014 behind camera, skipped`);
2634
+ return { dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: true };
2635
+ }
2636
+ r3fLog("interaction", `hoverAtWorld(${point.x}, ${point.y}, ${point.z}) \u2192 screen(${Math.round(screen.x)}, ${Math.round(screen.y)})`);
2637
+ dispatchHover(canvas, screen);
2638
+ return { dispatched: true, screenPoint: screen, behindCamera: false };
2639
+ }
2640
+ async function clickAtWorldSequence(points, options = {}) {
2641
+ const { delayMs = 50, ...interactionOpts } = options;
2642
+ const results = [];
2643
+ for (let i = 0; i < points.length; i++) {
2644
+ results.push(clickAtWorld(points[i], interactionOpts));
2645
+ if (delayMs > 0 && i < points.length - 1) {
2646
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
2647
+ }
2648
+ }
2649
+ return results;
2650
+ }
2574
2651
 
2575
2652
  // src/highlight/SelectionManager.ts
2576
2653
  var SelectionManager = class {
@@ -2826,6 +2903,9 @@ var Highlighter = class {
2826
2903
  this._hoverPollId = null;
2827
2904
  this._lastHoveredUuid = null;
2828
2905
  this._store = null;
2906
+ /** When true, the hover poll is paused and showHoverHighlight is blocked. */
2907
+ this._hoverPollSuppressed = false;
2908
+ this._suppressTimer = null;
2829
2909
  }
2830
2910
  // -----------------------------------------------------------------------
2831
2911
  // Lifecycle
@@ -2848,6 +2928,11 @@ var Highlighter = class {
2848
2928
  this._unsubscribe = null;
2849
2929
  }
2850
2930
  this._stopHoverPolling();
2931
+ if (this._suppressTimer) {
2932
+ clearTimeout(this._suppressTimer);
2933
+ this._suppressTimer = null;
2934
+ }
2935
+ this._hoverPollSuppressed = false;
2851
2936
  this.clearHoverHighlight();
2852
2937
  this._clearAllSelectionHighlights();
2853
2938
  this._scene = null;
@@ -2875,6 +2960,7 @@ var Highlighter = class {
2875
2960
  // -----------------------------------------------------------------------
2876
2961
  /** Show a hover highlight on the given object (replaces any previous hover). */
2877
2962
  showHoverHighlight(obj) {
2963
+ if (this._hoverPollSuppressed) return;
2878
2964
  if (obj === this._hoverTarget) return;
2879
2965
  this._clearHoverVisuals();
2880
2966
  if (!this._scene) return;
@@ -2913,6 +2999,26 @@ var Highlighter = class {
2913
2999
  this.clearHoverHighlight();
2914
3000
  this._clearAllSelectionHighlights();
2915
3001
  }
3002
+ /**
3003
+ * Stop the hover poll, clear all hover state, and restart after a delay.
3004
+ * This prevents the DevTools extension from re-applying highlights after
3005
+ * inspect mode is disabled (the extension polls `$0` every 200ms and
3006
+ * keeps writing `__r3fdom_hovered__`).
3007
+ */
3008
+ suppressHoverPoll(durationMs = 1500) {
3009
+ this._hoverPollSuppressed = true;
3010
+ this._stopHoverPolling();
3011
+ this._clearHoverVisuals();
3012
+ this._lastHoveredUuid = null;
3013
+ window.__r3fdom_hovered__ = null;
3014
+ if (this._suppressTimer) clearTimeout(this._suppressTimer);
3015
+ this._suppressTimer = setTimeout(() => {
3016
+ this._hoverPollSuppressed = false;
3017
+ this._suppressTimer = null;
3018
+ window.__r3fdom_hovered__ = null;
3019
+ this._startHoverPolling();
3020
+ }, durationMs);
3021
+ }
2916
3022
  // -----------------------------------------------------------------------
2917
3023
  // Internal: selection highlights
2918
3024
  // -----------------------------------------------------------------------
@@ -2995,6 +3101,16 @@ var Highlighter = class {
2995
3101
  try {
2996
3102
  const hoveredEl = window.__r3fdom_hovered__;
2997
3103
  const uuid = hoveredEl?.getAttribute?.("data-uuid") ?? null;
3104
+ if (this._hoverPollSuppressed) {
3105
+ if (uuid) {
3106
+ window.__r3fdom_hovered__ = null;
3107
+ }
3108
+ if (this._hoverTarget) {
3109
+ this._clearHoverVisuals();
3110
+ }
3111
+ this._lastHoveredUuid = null;
3112
+ return;
3113
+ }
2998
3114
  if (uuid === this._lastHoveredUuid) return;
2999
3115
  this._lastHoveredUuid = uuid;
3000
3116
  if (!uuid) {
@@ -3117,9 +3233,12 @@ var InspectController = class {
3117
3233
  this._boundContextMenu = null;
3118
3234
  this._hoveredObject = null;
3119
3235
  this._cancelHoverReveal();
3120
- this._highlighter.clearHoverHighlight();
3236
+ this._highlighter.clearAll();
3237
+ this._highlighter.suppressHoverPoll();
3238
+ this._selectionManager.clearSelection();
3239
+ window.__r3fdom_hovered__ = null;
3121
3240
  window.__r3fdom_selected_element__ = null;
3122
- r3fLog("inspect", "InspectController disabled");
3241
+ r3fLog("inspect", "InspectController disabled \u2014 highlights and selection cleared");
3123
3242
  }
3124
3243
  /** Disable and release all resources. */
3125
3244
  dispose() {
@@ -3357,6 +3476,21 @@ function shouldRegister(instanceKey, obj) {
3357
3476
  if (filter) return filter(obj);
3358
3477
  return true;
3359
3478
  }
3479
+ function ensureAncestorChain(obj, store, mirror) {
3480
+ const chain = [];
3481
+ let cursor = obj.parent;
3482
+ while (cursor) {
3483
+ if (store.has(cursor)) break;
3484
+ chain.push(cursor);
3485
+ cursor = cursor.parent;
3486
+ }
3487
+ for (let i = chain.length - 1; i >= 0; i--) {
3488
+ const ancestor = chain[i];
3489
+ store.register(ancestor);
3490
+ mirror.onObjectAdded(ancestor);
3491
+ mirror.materialize(ancestor.uuid);
3492
+ }
3493
+ }
3360
3494
  function getStore2(canvasId = "") {
3361
3495
  return _stores.get(canvasId) ?? null;
3362
3496
  }
@@ -3428,6 +3562,11 @@ function exposeGlobalAPI(store, gl, cameraRef, selMgr, inspCtrl, mirror, canvasI
3428
3562
  const result = await drawPath(points, options);
3429
3563
  return { eventCount: result.eventCount, pointCount: result.pointCount };
3430
3564
  },
3565
+ clickAtWorld: (point, options) => clickAtWorld(point, options),
3566
+ doubleClickAtWorld: (point, options) => doubleClickAtWorld(point, options),
3567
+ contextMenuAtWorld: (point, options) => contextMenuAtWorld(point, options),
3568
+ hoverAtWorld: (point, options) => hoverAtWorld(point, options),
3569
+ clickAtWorldSequence: (points, options) => clickAtWorldSequence(points, options),
3431
3570
  select: (idOrUuid) => {
3432
3571
  const obj = store.getObject3D(idOrUuid);
3433
3572
  if (obj && selMgr) selMgr.select(obj);
@@ -3516,10 +3655,17 @@ function exposeGlobalAPI(store, gl, cameraRef, selMgr, inspCtrl, mirror, canvasI
3516
3655
  return;
3517
3656
  }
3518
3657
  obj.userData.__r3fdom_manual = true;
3519
- store.register(obj);
3520
- mirror?.onObjectAdded(obj);
3521
- mirror?.materialize(obj.uuid);
3522
- r3fLog("bridge", `r3fRegister: "${obj.userData?.testId || obj.name || obj.uuid.slice(0, 8)}" (${obj.type})`);
3658
+ ensureAncestorChain(obj, store, mirror);
3659
+ let count = 0;
3660
+ obj.traverse((child) => {
3661
+ if (!store.has(child)) {
3662
+ store.register(child);
3663
+ mirror?.onObjectAdded(child);
3664
+ mirror?.materialize(child.uuid);
3665
+ count++;
3666
+ }
3667
+ });
3668
+ r3fLog("bridge", `r3fRegister: "${obj.userData?.testId || obj.name || obj.uuid.slice(0, 8)}" (${obj.type}) \u2014 ${count} objects`);
3523
3669
  },
3524
3670
  r3fUnregister: (obj) => {
3525
3671
  if (!store.has(obj)) return;
@@ -3644,6 +3790,11 @@ function createStubBridge(error, canvasId) {
3644
3790
  pointerMiss: () => {
3645
3791
  },
3646
3792
  drawPath: async () => ({ eventCount: 0, pointCount: 0 }),
3793
+ clickAtWorld: () => ({ dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: false }),
3794
+ doubleClickAtWorld: () => ({ dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: false }),
3795
+ contextMenuAtWorld: () => ({ dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: false }),
3796
+ hoverAtWorld: () => ({ dispatched: false, screenPoint: { x: 0, y: 0 }, behindCamera: false }),
3797
+ clickAtWorldSequence: async () => [],
3647
3798
  select: () => {
3648
3799
  },
3649
3800
  clearSelection: () => {
@@ -3776,8 +3927,12 @@ function ThreeDom({
3776
3927
  if (mode === "auto") {
3777
3928
  if (filter) {
3778
3929
  store.addTrackedRoot(scene);
3930
+ store.register(scene);
3931
+ mirror.onObjectAdded(scene);
3779
3932
  scene.traverse((obj) => {
3933
+ if (obj === scene) return;
3780
3934
  if (filter(obj)) {
3935
+ ensureAncestorChain(obj, store, mirror);
3781
3936
  store.register(obj);
3782
3937
  mirror.onObjectAdded(obj);
3783
3938
  }
@@ -3956,6 +4111,6 @@ function useR3FRegister(ref, canvasId) {
3956
4111
  });
3957
4112
  }
3958
4113
 
3959
- export { DomMirror, Highlighter, InspectController, MANAGED_ATTRIBUTES, ObjectStore, RaycastAccelerator, SelectionManager, TAG_MAP, ThreeDom, ThreeElement, applyAttributes, circlePath, click3D, computeAttributes, contextMenu3D, createFlatSnapshot, createSnapshot, curvePath, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, drag3D, drawPath, enableDebug, ensureCustomElements, getCanvasIds, getHighlighter, getInspectController, getMirror, getSelectionManager, getStore2 as getStore, getTagForType, hover3D, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, useR3FRegister, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
4114
+ export { DomMirror, Highlighter, InspectController, MANAGED_ATTRIBUTES, ObjectStore, RaycastAccelerator, SelectionManager, TAG_MAP, ThreeDom, ThreeElement, applyAttributes, circlePath, click3D, clickAtWorld, clickAtWorldSequence, computeAttributes, contextMenu3D, contextMenuAtWorld, createFlatSnapshot, createSnapshot, curvePath, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, doubleClickAtWorld, drag3D, drawPath, enableDebug, ensureCustomElements, getCanvasIds, getHighlighter, getInspectController, getMirror, getSelectionManager, getStore2 as getStore, getTagForType, hover3D, hoverAtWorld, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, useR3FRegister, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
3960
4115
  //# sourceMappingURL=index.js.map
3961
4116
  //# sourceMappingURL=index.js.map