@react-three-dom/core 0.5.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
@@ -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
@@ -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,4 +1,4 @@
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';
@@ -2572,6 +2572,82 @@ function circlePath(center, radiusX, radiusY, steps = 36, pressure = 0.5) {
2572
2572
  function sleep2(ms) {
2573
2573
  return new Promise((resolve) => setTimeout(resolve, ms));
2574
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
+ }
2575
2651
 
2576
2652
  // src/highlight/SelectionManager.ts
2577
2653
  var SelectionManager = class {
@@ -2827,6 +2903,9 @@ var Highlighter = class {
2827
2903
  this._hoverPollId = null;
2828
2904
  this._lastHoveredUuid = null;
2829
2905
  this._store = null;
2906
+ /** When true, the hover poll is paused and showHoverHighlight is blocked. */
2907
+ this._hoverPollSuppressed = false;
2908
+ this._suppressTimer = null;
2830
2909
  }
2831
2910
  // -----------------------------------------------------------------------
2832
2911
  // Lifecycle
@@ -2849,6 +2928,11 @@ var Highlighter = class {
2849
2928
  this._unsubscribe = null;
2850
2929
  }
2851
2930
  this._stopHoverPolling();
2931
+ if (this._suppressTimer) {
2932
+ clearTimeout(this._suppressTimer);
2933
+ this._suppressTimer = null;
2934
+ }
2935
+ this._hoverPollSuppressed = false;
2852
2936
  this.clearHoverHighlight();
2853
2937
  this._clearAllSelectionHighlights();
2854
2938
  this._scene = null;
@@ -2876,6 +2960,7 @@ var Highlighter = class {
2876
2960
  // -----------------------------------------------------------------------
2877
2961
  /** Show a hover highlight on the given object (replaces any previous hover). */
2878
2962
  showHoverHighlight(obj) {
2963
+ if (this._hoverPollSuppressed) return;
2879
2964
  if (obj === this._hoverTarget) return;
2880
2965
  this._clearHoverVisuals();
2881
2966
  if (!this._scene) return;
@@ -2914,6 +2999,26 @@ var Highlighter = class {
2914
2999
  this.clearHoverHighlight();
2915
3000
  this._clearAllSelectionHighlights();
2916
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
+ }
2917
3022
  // -----------------------------------------------------------------------
2918
3023
  // Internal: selection highlights
2919
3024
  // -----------------------------------------------------------------------
@@ -2996,6 +3101,16 @@ var Highlighter = class {
2996
3101
  try {
2997
3102
  const hoveredEl = window.__r3fdom_hovered__;
2998
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
+ }
2999
3114
  if (uuid === this._lastHoveredUuid) return;
3000
3115
  this._lastHoveredUuid = uuid;
3001
3116
  if (!uuid) {
@@ -3118,9 +3233,12 @@ var InspectController = class {
3118
3233
  this._boundContextMenu = null;
3119
3234
  this._hoveredObject = null;
3120
3235
  this._cancelHoverReveal();
3121
- this._highlighter.clearHoverHighlight();
3236
+ this._highlighter.clearAll();
3237
+ this._highlighter.suppressHoverPoll();
3238
+ this._selectionManager.clearSelection();
3239
+ window.__r3fdom_hovered__ = null;
3122
3240
  window.__r3fdom_selected_element__ = null;
3123
- r3fLog("inspect", "InspectController disabled");
3241
+ r3fLog("inspect", "InspectController disabled \u2014 highlights and selection cleared");
3124
3242
  }
3125
3243
  /** Disable and release all resources. */
3126
3244
  dispose() {
@@ -3444,6 +3562,11 @@ function exposeGlobalAPI(store, gl, cameraRef, selMgr, inspCtrl, mirror, canvasI
3444
3562
  const result = await drawPath(points, options);
3445
3563
  return { eventCount: result.eventCount, pointCount: result.pointCount };
3446
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),
3447
3570
  select: (idOrUuid) => {
3448
3571
  const obj = store.getObject3D(idOrUuid);
3449
3572
  if (obj && selMgr) selMgr.select(obj);
@@ -3667,6 +3790,11 @@ function createStubBridge(error, canvasId) {
3667
3790
  pointerMiss: () => {
3668
3791
  },
3669
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 () => [],
3670
3798
  select: () => {
3671
3799
  },
3672
3800
  clearSelection: () => {
@@ -3983,6 +4111,6 @@ function useR3FRegister(ref, canvasId) {
3983
4111
  });
3984
4112
  }
3985
4113
 
3986
- 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 };
3987
4115
  //# sourceMappingURL=index.js.map
3988
4116
  //# sourceMappingURL=index.js.map