@react-three-dom/core 0.1.0 → 0.2.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.ts CHANGED
@@ -2,6 +2,27 @@ import { Object3D, Camera, WebGLRenderer, Vector3 } from 'three';
2
2
 
3
3
  declare const version = "0.1.0";
4
4
 
5
+ /**
6
+ * Enable or disable debug logging globally.
7
+ * When enabled, all r3fLog calls will output to console.log.
8
+ */
9
+ declare function enableDebug(on?: boolean): void;
10
+ /**
11
+ * Check if debug logging is currently enabled.
12
+ */
13
+ declare function isDebugEnabled(): boolean;
14
+ /**
15
+ * Log a debug message. Only outputs when debug is enabled via:
16
+ * - enableDebug(true)
17
+ * - window.__R3F_DOM_DEBUG__ = true
18
+ * - <ThreeDom debug /> prop
19
+ *
20
+ * @param area - Module area (e.g. 'setup', 'store', 'patch', 'click', 'drag')
21
+ * @param msg - Human-readable message
22
+ * @param data - Optional data payload (object, error, etc.)
23
+ */
24
+ declare function r3fLog(area: string, msg: string, data?: unknown): void;
25
+
5
26
  interface ObjectMetadata {
6
27
  /** Three.js internal UUID */
7
28
  uuid: string;
@@ -96,6 +117,16 @@ interface SnapshotNode {
96
117
  position: [number, number, number];
97
118
  rotation: [number, number, number];
98
119
  scale: [number, number, number];
120
+ /** Geometry class name (meshes only) */
121
+ geometryType?: string;
122
+ /** Material class name (meshes only) */
123
+ materialType?: string;
124
+ /** Total vertex count (meshes only) */
125
+ vertexCount?: number;
126
+ /** Triangle count (meshes only) */
127
+ triangleCount?: number;
128
+ /** Instance count (InstancedMesh only) */
129
+ instanceCount?: number;
99
130
  children: SnapshotNode[];
100
131
  }
101
132
  interface SceneSnapshot {
@@ -114,6 +145,19 @@ interface StoreEvent {
114
145
  }
115
146
  type StoreListener = (event: StoreEvent) => void;
116
147
  interface R3FDOM {
148
+ /**
149
+ * Whether the bridge is fully initialized and ready to use.
150
+ * - `true`: ThreeDom setup completed successfully, all methods are live.
151
+ * - `false`: Bridge exists but setup failed or is still initializing.
152
+ *
153
+ * Test waiters should check `_ready === true` instead of just `typeof !== 'undefined'`.
154
+ */
155
+ _ready: boolean;
156
+ /**
157
+ * If `_ready` is false, contains the error message from the failed setup.
158
+ * Undefined when `_ready` is true.
159
+ */
160
+ _error?: string;
117
161
  /** Tier 1: O(1) lookup by testId */
118
162
  getByTestId(id: string): ObjectMetadata | null;
119
163
  /** Tier 1: O(1) lookup by uuid */
@@ -122,6 +166,14 @@ interface R3FDOM {
122
166
  getByName(name: string): ObjectMetadata[];
123
167
  /** Total number of tracked objects */
124
168
  getCount(): number;
169
+ /** Get all objects of a given Three.js type (Mesh, Group, Line, Points, etc.) */
170
+ getByType(type: string): ObjectMetadata[];
171
+ /** Get objects that have a specific userData key (and optionally matching value) */
172
+ getByUserData(key: string, value?: unknown): ObjectMetadata[];
173
+ /** Count objects of a given Three.js type */
174
+ getCountByType(type: string): number;
175
+ /** Batch lookup: get metadata for multiple objects by testId or uuid in one call */
176
+ getObjects(ids: string[]): Record<string, ObjectMetadata | null>;
125
177
  /** Full structured JSON snapshot from Tier 1 store */
126
178
  snapshot(): SceneSnapshot;
127
179
  /** Tier 2: on-demand heavy inspection (reads live Three.js object) */
@@ -134,12 +186,12 @@ interface R3FDOM {
134
186
  contextMenu(idOrUuid: string): void;
135
187
  /** Deterministic hover on a 3D object */
136
188
  hover(idOrUuid: string): void;
137
- /** Deterministic drag on a 3D object */
189
+ /** Deterministic drag on a 3D object (async — dispatches multi-step pointer sequence) */
138
190
  drag(idOrUuid: string, delta: {
139
191
  x: number;
140
192
  y: number;
141
193
  z: number;
142
- }): void;
194
+ }): Promise<void>;
143
195
  /** Dispatch a wheel/scroll event on a 3D object */
144
196
  wheel(idOrUuid: string, options?: {
145
197
  deltaY?: number;
@@ -147,10 +199,25 @@ interface R3FDOM {
147
199
  }): void;
148
200
  /** Click empty space to trigger onPointerMissed */
149
201
  pointerMiss(): void;
202
+ /** Draw a freeform path on the canvas (for drawing/annotation apps) */
203
+ drawPath(points: Array<{
204
+ x: number;
205
+ y: number;
206
+ pressure?: number;
207
+ }>, options?: {
208
+ stepDelayMs?: number;
209
+ pointerType?: 'mouse' | 'pen' | 'touch';
210
+ clickAtEnd?: boolean;
211
+ }): Promise<{
212
+ eventCount: number;
213
+ pointCount: number;
214
+ }>;
150
215
  /** Select an object (shows highlight wireframe in scene) */
151
216
  select(idOrUuid: string): void;
152
217
  /** Clear selection */
153
218
  clearSelection(): void;
219
+ /** Get uuids of currently selected objects (for DevTools panel sync) */
220
+ getSelection(): string[];
154
221
  /** Raw Three.js object access (for advanced debugging) */
155
222
  getObject3D(idOrUuid: string): Object3D | null;
156
223
  /** Library version */
@@ -159,6 +226,8 @@ interface R3FDOM {
159
226
  declare global {
160
227
  interface Window {
161
228
  __R3F_DOM__?: R3FDOM;
229
+ /** Set to true to enable debug logging from @react-three-dom/core */
230
+ __R3F_DOM_DEBUG__?: boolean;
162
231
  }
163
232
  }
164
233
 
@@ -179,6 +248,9 @@ declare class ObjectStore {
179
248
  register(obj: Object3D): ObjectMetadata;
180
249
  /**
181
250
  * Register an entire subtree (object + all descendants).
251
+ * Individual objects that fail to register are skipped (logged when debug
252
+ * is enabled) so that one bad object doesn't prevent the rest from being
253
+ * tracked.
182
254
  */
183
255
  registerTree(root: Object3D): void;
184
256
  /**
@@ -192,6 +264,8 @@ declare class ObjectStore {
192
264
  /**
193
265
  * Refresh Tier 1 metadata from the live Three.js object.
194
266
  * Returns true if any values changed.
267
+ * Returns false (no change) if extracting metadata throws so that the
268
+ * previous metadata is preserved.
195
269
  */
196
270
  update(obj: Object3D): boolean;
197
271
  /**
@@ -206,6 +280,32 @@ declare class ObjectStore {
206
280
  getByUuid(uuid: string): ObjectMetadata | null;
207
281
  /** Get metadata by name (returns array since names aren't unique). O(1). */
208
282
  getByName(name: string): ObjectMetadata[];
283
+ /**
284
+ * Batch lookup: get metadata for multiple objects by testId or uuid.
285
+ * Returns a Map from the requested id to its metadata (or null if not found).
286
+ * Single round-trip — much more efficient than calling getByTestId/getByUuid
287
+ * in a loop for BIM/CAD scenes with many objects.
288
+ * O(k) where k is the number of requested ids.
289
+ */
290
+ getObjects(ids: string[]): Map<string, ObjectMetadata | null>;
291
+ /**
292
+ * Get all objects of a given Three.js type (e.g. "Mesh", "Group", "Line").
293
+ * Linear scan — O(n) where n is total tracked objects.
294
+ */
295
+ getByType(type: string): ObjectMetadata[];
296
+ /**
297
+ * Get all objects that have a specific userData key.
298
+ * If `value` is provided, only returns objects where `userData[key]` matches.
299
+ * Uses JSON.stringify for deep equality on complex values.
300
+ * Linear scan — O(n).
301
+ */
302
+ getByUserData(key: string, value?: unknown): ObjectMetadata[];
303
+ /**
304
+ * Count objects of a given Three.js type.
305
+ * More efficient than getByType().length — no array allocation.
306
+ * Linear scan — O(n).
307
+ */
308
+ getCountByType(type: string): number;
209
309
  /** Get the raw Three.js Object3D by testId or uuid. */
210
310
  getObject3D(idOrUuid: string): Object3D | null;
211
311
  /** Get metadata for a known Object3D reference. */
@@ -565,12 +665,14 @@ interface ThreeDomProps {
565
665
  initialDepth?: number;
566
666
  /** Disable all sync. Default: true */
567
667
  enabled?: boolean;
668
+ /** Enable debug logging to browser console. Default: false */
669
+ debug?: boolean;
568
670
  }
569
671
  declare function getStore(): ObjectStore | null;
570
672
  declare function getMirror(): DomMirror | null;
571
673
  declare function getSelectionManager(): SelectionManager | null;
572
674
  declare function getHighlighter(): Highlighter | null;
573
- declare function ThreeDom({ root, batchSize, timeBudgetMs, maxDomNodes, initialDepth, enabled, }?: ThreeDomProps): null;
675
+ declare function ThreeDom({ root, batchSize, timeBudgetMs, maxDomNodes, initialDepth, enabled, debug, }?: ThreeDomProps): null;
574
676
 
575
677
  /**
576
678
  * Patch Object3D.prototype.add and Object3D.prototype.remove to intercept
@@ -1045,10 +1147,176 @@ interface PointerMiss3DOptions {
1045
1147
  */
1046
1148
  declare function pointerMiss3D(options?: PointerMiss3DOptions): void;
1047
1149
 
1150
+ /** A 2D screen-space point in CSS pixels, relative to the canvas top-left. */
1151
+ interface DrawPoint {
1152
+ /** X coordinate in CSS pixels from canvas left edge. */
1153
+ x: number;
1154
+ /** Y coordinate in CSS pixels from canvas top edge. */
1155
+ y: number;
1156
+ /** Optional pressure (0–1). Default: 0.5 */
1157
+ pressure?: number;
1158
+ }
1159
+ /** Options for drawPath. */
1160
+ interface DrawPathOptions {
1161
+ /**
1162
+ * Delay in milliseconds between successive pointermove events.
1163
+ * Useful for apps that sample pointer events per-frame.
1164
+ * Default: 0 (dispatch all moves synchronously, which is fastest)
1165
+ */
1166
+ stepDelayMs?: number;
1167
+ /**
1168
+ * Pointer type. Some drawing apps differentiate between mouse and pen.
1169
+ * Default: 'mouse'
1170
+ */
1171
+ pointerType?: 'mouse' | 'pen' | 'touch';
1172
+ /**
1173
+ * If true, also dispatches a 'click' event at the end of the path.
1174
+ * Useful if the app interprets short strokes as clicks.
1175
+ * Default: false
1176
+ */
1177
+ clickAtEnd?: boolean;
1178
+ /**
1179
+ * If provided, draws on a specific canvas element.
1180
+ * Default: the R3F canvas (from the current renderer).
1181
+ */
1182
+ canvas?: HTMLCanvasElement;
1183
+ }
1184
+ /** Result of a drawPath operation. */
1185
+ interface DrawPathResult {
1186
+ /** Total number of pointer events dispatched. */
1187
+ eventCount: number;
1188
+ /** The number of points in the path. */
1189
+ pointCount: number;
1190
+ /** First point of the path. */
1191
+ startPoint: DrawPoint;
1192
+ /** Last point of the path. */
1193
+ endPoint: DrawPoint;
1194
+ }
1195
+ /**
1196
+ * Simulate a freeform drawing stroke on the canvas.
1197
+ *
1198
+ * Dispatches a full pointer sequence through the provided path of points:
1199
+ * `pointerdown` at the first point, `pointermove` at each subsequent point,
1200
+ * and `pointerup` at the last point.
1201
+ *
1202
+ * This is designed for canvas drawing applications (e.g. whiteboard, annotation
1203
+ * tools, CAD sketch mode) that respond to pointer events to create geometry.
1204
+ *
1205
+ * @param points Array of screen-space points (min 2 required)
1206
+ * @param options Drawing options
1207
+ * @returns Result with event counts and start/end points
1208
+ * @throws If fewer than 2 points are provided
1209
+ *
1210
+ * @example
1211
+ * ```typescript
1212
+ * // Draw a simple line from (100, 100) to (300, 200)
1213
+ * await drawPath([
1214
+ * { x: 100, y: 100 },
1215
+ * { x: 200, y: 150 },
1216
+ * { x: 300, y: 200 },
1217
+ * ]);
1218
+ *
1219
+ * // Draw with pen pressure simulation
1220
+ * await drawPath([
1221
+ * { x: 50, y: 50, pressure: 0.2 },
1222
+ * { x: 100, y: 80, pressure: 0.6 },
1223
+ * { x: 150, y: 70, pressure: 0.9 },
1224
+ * { x: 200, y: 60, pressure: 0.4 },
1225
+ * ], { pointerType: 'pen', stepDelayMs: 16 });
1226
+ * ```
1227
+ */
1228
+ declare function drawPath(points: DrawPoint[], options?: DrawPathOptions): Promise<DrawPathResult>;
1229
+ /**
1230
+ * Generate an array of DrawPoints along a straight line.
1231
+ * Useful for creating uniform stroke paths programmatically.
1232
+ *
1233
+ * @param start Start point (screen-space CSS pixels)
1234
+ * @param end End point (screen-space CSS pixels)
1235
+ * @param steps Number of intermediate points (excluding start/end). Default: 10
1236
+ * @param pressure Uniform pressure for all points. Default: 0.5
1237
+ * @returns Array of DrawPoints including start and end
1238
+ *
1239
+ * @example
1240
+ * ```typescript
1241
+ * const points = linePath({ x: 0, y: 0 }, { x: 200, y: 200 }, 20);
1242
+ * await drawPath(points);
1243
+ * ```
1244
+ */
1245
+ declare function linePath(start: {
1246
+ x: number;
1247
+ y: number;
1248
+ }, end: {
1249
+ x: number;
1250
+ y: number;
1251
+ }, steps?: number, pressure?: number): DrawPoint[];
1252
+ /**
1253
+ * Generate an array of DrawPoints along a quadratic bezier curve.
1254
+ * Great for simulating smooth freehand drawing strokes.
1255
+ *
1256
+ * @param start Start point
1257
+ * @param control Control point (determines curve shape)
1258
+ * @param end End point
1259
+ * @param steps Number of steps. Default: 20
1260
+ * @param pressure Uniform pressure. Default: 0.5
1261
+ * @returns Array of DrawPoints along the curve
1262
+ *
1263
+ * @example
1264
+ * ```typescript
1265
+ * const points = curvePath(
1266
+ * { x: 50, y: 200 }, // start
1267
+ * { x: 150, y: 50 }, // control (peak of the curve)
1268
+ * { x: 250, y: 200 }, // end
1269
+ * 30,
1270
+ * );
1271
+ * await drawPath(points);
1272
+ * ```
1273
+ */
1274
+ declare function curvePath(start: {
1275
+ x: number;
1276
+ y: number;
1277
+ }, control: {
1278
+ x: number;
1279
+ y: number;
1280
+ }, end: {
1281
+ x: number;
1282
+ y: number;
1283
+ }, steps?: number, pressure?: number): DrawPoint[];
1284
+ /**
1285
+ * Generate an array of DrawPoints forming a rectangle.
1286
+ * Useful for drawing rectangular selections or bounding boxes.
1287
+ *
1288
+ * @param topLeft Top-left corner
1289
+ * @param bottomRight Bottom-right corner
1290
+ * @param pointsPerSide Number of points per side. Default: 5
1291
+ * @param pressure Uniform pressure. Default: 0.5
1292
+ * @returns Array of DrawPoints tracing the rectangle
1293
+ */
1294
+ declare function rectPath(topLeft: {
1295
+ x: number;
1296
+ y: number;
1297
+ }, bottomRight: {
1298
+ x: number;
1299
+ y: number;
1300
+ }, pointsPerSide?: number, pressure?: number): DrawPoint[];
1301
+ /**
1302
+ * Generate an array of DrawPoints forming a circle/ellipse.
1303
+ *
1304
+ * @param center Center of the circle (screen-space)
1305
+ * @param radiusX Horizontal radius in CSS pixels
1306
+ * @param radiusY Vertical radius in CSS pixels. Default: same as radiusX (circle)
1307
+ * @param steps Number of points. Default: 36 (10° increments)
1308
+ * @param pressure Uniform pressure. Default: 0.5
1309
+ * @returns Array of DrawPoints forming the circle
1310
+ */
1311
+ declare function circlePath(center: {
1312
+ x: number;
1313
+ y: number;
1314
+ }, radiusX: number, radiusY?: number, steps?: number, pressure?: number): DrawPoint[];
1315
+
1048
1316
  /**
1049
1317
  * Resolve a testId or uuid to a live Object3D reference.
1050
1318
  * Throws a descriptive error if the object is not found.
1051
1319
  */
1052
1320
  declare function resolveObject(idOrUuid: string): Object3D;
1053
1321
 
1054
- export { type CanvasSize, type Click3DOptions, type Click3DResult, DomMirror, type Drag3DOptions, type Drag3DResult, type DragOptions, type GeometryInspection, Highlighter, type HighlighterOptions, type Hover3DOptions, type Hover3DResult, MANAGED_ATTRIBUTES, type MaterialInspection, type ObjectInspection, type ObjectMetadata, ObjectStore, type PointerMiss3DOptions, type ProjectionResult, type R3FDOM, 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, click3D, computeAttributes, contextMenu3D, createFlatSnapshot, createSnapshot, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, drag3D, ensureCustomElements, getHighlighter, getMirror, getSelectionManager, getStore, getTagForType, hover3D, isInFrustum, isPatched, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
1322
+ export { 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, MANAGED_ATTRIBUTES, type MaterialInspection, type ObjectInspection, type ObjectMetadata, ObjectStore, type PointerMiss3DOptions, type ProjectionResult, type R3FDOM, 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, getHighlighter, getMirror, getSelectionManager, getStore, getTagForType, hover3D, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };