@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.cjs +610 -193
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +272 -4
- package/dist/index.d.ts +272 -4
- package/dist/index.js +603 -194
- package/dist/index.js.map +1 -1
- package/package.json +11 -9
package/dist/index.js
CHANGED
|
@@ -4,6 +4,25 @@ import { useThree, useFrame } from '@react-three/fiber';
|
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
6
|
var version = "0.1.0";
|
|
7
|
+
|
|
8
|
+
// src/debug.ts
|
|
9
|
+
var _enabled = false;
|
|
10
|
+
function enableDebug(on = true) {
|
|
11
|
+
_enabled = on;
|
|
12
|
+
}
|
|
13
|
+
function isDebugEnabled() {
|
|
14
|
+
return _enabled || typeof window !== "undefined" && !!window.__R3F_DOM_DEBUG__;
|
|
15
|
+
}
|
|
16
|
+
function r3fLog(area, msg, data) {
|
|
17
|
+
if (!_enabled && !(typeof window !== "undefined" && window.__R3F_DOM_DEBUG__)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (data !== void 0) {
|
|
21
|
+
console.log(`[r3f-dom:${area}]`, msg, data);
|
|
22
|
+
} else {
|
|
23
|
+
console.log(`[r3f-dom:${area}]`, msg);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
7
26
|
function extractMetadata(obj) {
|
|
8
27
|
const meta = {
|
|
9
28
|
uuid: obj.uuid,
|
|
@@ -18,31 +37,42 @@ function extractMetadata(obj) {
|
|
|
18
37
|
childrenUuids: obj.children.map((c) => c.uuid),
|
|
19
38
|
boundsDirty: true
|
|
20
39
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
try {
|
|
41
|
+
if ("geometry" in obj) {
|
|
42
|
+
const geom = obj.geometry;
|
|
43
|
+
if (geom instanceof BufferGeometry) {
|
|
44
|
+
meta.geometryType = geom.type;
|
|
45
|
+
const posAttr = geom.getAttribute("position");
|
|
46
|
+
if (posAttr) {
|
|
47
|
+
meta.vertexCount = posAttr.count;
|
|
48
|
+
if (geom.index) {
|
|
49
|
+
meta.triangleCount = Math.floor(geom.index.count / 3);
|
|
50
|
+
} else {
|
|
51
|
+
meta.triangleCount = Math.floor(posAttr.count / 3);
|
|
52
|
+
}
|
|
32
53
|
}
|
|
33
54
|
}
|
|
34
55
|
}
|
|
56
|
+
} catch {
|
|
57
|
+
r3fLog("store", `extractMetadata: geometry access failed for "${obj.name || obj.uuid}"`);
|
|
35
58
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
try {
|
|
60
|
+
if ("material" in obj) {
|
|
61
|
+
const mat = obj.material;
|
|
62
|
+
if (mat instanceof Material) {
|
|
63
|
+
meta.materialType = mat.type;
|
|
64
|
+
} else if (Array.isArray(mat) && mat.length > 0) {
|
|
65
|
+
meta.materialType = mat[0].type + (mat.length > 1 ? ` (+${mat.length - 1})` : "");
|
|
66
|
+
}
|
|
42
67
|
}
|
|
68
|
+
} catch {
|
|
69
|
+
r3fLog("store", `extractMetadata: material access failed for "${obj.name || obj.uuid}"`);
|
|
43
70
|
}
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
try {
|
|
72
|
+
if (obj instanceof InstancedMesh) {
|
|
73
|
+
meta.instanceCount = obj.count;
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
46
76
|
}
|
|
47
77
|
return meta;
|
|
48
78
|
}
|
|
@@ -51,81 +81,101 @@ function hasChanged(prev, curr) {
|
|
|
51
81
|
}
|
|
52
82
|
var _box3 = new Box3();
|
|
53
83
|
function inspectObject(obj, metadata) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
84
|
+
let worldMatrix = Array(16).fill(0);
|
|
85
|
+
let boundsMin = [0, 0, 0];
|
|
86
|
+
let boundsMax = [0, 0, 0];
|
|
87
|
+
try {
|
|
88
|
+
obj.updateWorldMatrix(true, false);
|
|
89
|
+
worldMatrix = Array.from(obj.matrixWorld.elements);
|
|
90
|
+
_box3.setFromObject(obj);
|
|
91
|
+
boundsMin = [_box3.min.x, _box3.min.y, _box3.min.z];
|
|
92
|
+
boundsMax = [_box3.max.x, _box3.max.y, _box3.max.z];
|
|
93
|
+
} catch {
|
|
94
|
+
r3fLog("store", `inspectObject: world matrix / bounds failed for "${obj.name || obj.uuid}"`);
|
|
95
|
+
}
|
|
59
96
|
const inspection = {
|
|
60
97
|
metadata,
|
|
61
98
|
worldMatrix,
|
|
62
99
|
bounds: { min: boundsMin, max: boundsMax },
|
|
63
|
-
userData: {
|
|
100
|
+
userData: {}
|
|
64
101
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
102
|
+
try {
|
|
103
|
+
inspection.userData = { ...obj.userData };
|
|
104
|
+
} catch {
|
|
105
|
+
r3fLog("store", `inspectObject: userData copy failed for "${obj.name || obj.uuid}"`);
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
if ("geometry" in obj) {
|
|
109
|
+
const geom = obj.geometry;
|
|
110
|
+
if (geom instanceof BufferGeometry) {
|
|
111
|
+
const geoInspection = {
|
|
112
|
+
type: geom.type,
|
|
113
|
+
attributes: {}
|
|
76
114
|
};
|
|
115
|
+
for (const [name, attr] of Object.entries(geom.attributes)) {
|
|
116
|
+
geoInspection.attributes[name] = {
|
|
117
|
+
itemSize: attr.itemSize,
|
|
118
|
+
count: attr.count
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
if (geom.index) {
|
|
122
|
+
geoInspection.index = { count: geom.index.count };
|
|
123
|
+
}
|
|
124
|
+
geom.computeBoundingSphere();
|
|
125
|
+
const sphere = geom.boundingSphere;
|
|
126
|
+
if (sphere) {
|
|
127
|
+
geoInspection.boundingSphere = {
|
|
128
|
+
center: [sphere.center.x, sphere.center.y, sphere.center.z],
|
|
129
|
+
radius: sphere.radius
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
inspection.geometry = geoInspection;
|
|
77
133
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
r3fLog("store", `inspectObject: geometry inspection failed for "${obj.name || obj.uuid}"`);
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
if ("material" in obj) {
|
|
140
|
+
const rawMat = obj.material;
|
|
141
|
+
const mat = Array.isArray(rawMat) ? rawMat[0] : rawMat;
|
|
142
|
+
if (mat instanceof Material) {
|
|
143
|
+
const matInspection = {
|
|
144
|
+
type: mat.type,
|
|
145
|
+
transparent: mat.transparent,
|
|
146
|
+
opacity: mat.opacity,
|
|
147
|
+
side: mat.side
|
|
87
148
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if ("material" in obj) {
|
|
93
|
-
const rawMat = obj.material;
|
|
94
|
-
const mat = Array.isArray(rawMat) ? rawMat[0] : rawMat;
|
|
95
|
-
if (mat instanceof Material) {
|
|
96
|
-
const matInspection = {
|
|
97
|
-
type: mat.type,
|
|
98
|
-
transparent: mat.transparent,
|
|
99
|
-
opacity: mat.opacity,
|
|
100
|
-
side: mat.side
|
|
101
|
-
};
|
|
102
|
-
if ("color" in mat && mat.color instanceof Color) {
|
|
103
|
-
matInspection.color = "#" + mat.color.getHexString();
|
|
104
|
-
}
|
|
105
|
-
if ("map" in mat) {
|
|
106
|
-
const map = mat.map;
|
|
107
|
-
if (map) {
|
|
108
|
-
matInspection.map = map.name || map.uuid || "unnamed";
|
|
149
|
+
if ("color" in mat && mat.color instanceof Color) {
|
|
150
|
+
matInspection.color = "#" + mat.color.getHexString();
|
|
109
151
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
if ("map" in mat) {
|
|
153
|
+
const map = mat.map;
|
|
154
|
+
if (map) {
|
|
155
|
+
matInspection.map = map.name || map.uuid || "unnamed";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if ("uniforms" in mat) {
|
|
159
|
+
const uniforms = mat.uniforms;
|
|
160
|
+
matInspection.uniforms = {};
|
|
161
|
+
for (const [key, uniform] of Object.entries(uniforms)) {
|
|
162
|
+
const val = uniform.value;
|
|
163
|
+
if (val === null || val === void 0) {
|
|
164
|
+
matInspection.uniforms[key] = val;
|
|
165
|
+
} else if (typeof val === "number" || typeof val === "boolean" || typeof val === "string") {
|
|
166
|
+
matInspection.uniforms[key] = val;
|
|
167
|
+
} else if (typeof val === "object" && "toArray" in val) {
|
|
168
|
+
matInspection.uniforms[key] = val.toArray();
|
|
169
|
+
} else {
|
|
170
|
+
matInspection.uniforms[key] = `[${typeof val}]`;
|
|
171
|
+
}
|
|
124
172
|
}
|
|
125
173
|
}
|
|
174
|
+
inspection.material = matInspection;
|
|
126
175
|
}
|
|
127
|
-
inspection.material = matInspection;
|
|
128
176
|
}
|
|
177
|
+
} catch {
|
|
178
|
+
r3fLog("store", `inspectObject: material inspection failed for "${obj.name || obj.uuid}"`);
|
|
129
179
|
}
|
|
130
180
|
return inspection;
|
|
131
181
|
}
|
|
@@ -175,15 +225,25 @@ var ObjectStore = class {
|
|
|
175
225
|
nameSet.add(obj);
|
|
176
226
|
}
|
|
177
227
|
this._emit({ type: "add", object: obj, metadata: meta });
|
|
228
|
+
if (meta.testId) {
|
|
229
|
+
r3fLog("store", `Registered "${meta.testId}" (${meta.type})`);
|
|
230
|
+
}
|
|
178
231
|
return meta;
|
|
179
232
|
}
|
|
180
233
|
/**
|
|
181
234
|
* Register an entire subtree (object + all descendants).
|
|
235
|
+
* Individual objects that fail to register are skipped (logged when debug
|
|
236
|
+
* is enabled) so that one bad object doesn't prevent the rest from being
|
|
237
|
+
* tracked.
|
|
182
238
|
*/
|
|
183
239
|
registerTree(root) {
|
|
184
240
|
this._trackedRoots.add(root);
|
|
185
241
|
root.traverse((obj) => {
|
|
186
|
-
|
|
242
|
+
try {
|
|
243
|
+
this.register(obj);
|
|
244
|
+
} catch (err) {
|
|
245
|
+
r3fLog("store", `registerTree: failed to register "${obj.name || obj.uuid}"`, err);
|
|
246
|
+
}
|
|
187
247
|
});
|
|
188
248
|
}
|
|
189
249
|
/**
|
|
@@ -208,6 +268,9 @@ var ObjectStore = class {
|
|
|
208
268
|
}
|
|
209
269
|
}
|
|
210
270
|
}
|
|
271
|
+
if (meta.testId) {
|
|
272
|
+
r3fLog("store", `Unregistered "${meta.testId}" (${meta.type})`);
|
|
273
|
+
}
|
|
211
274
|
this._emit({ type: "remove", object: obj, metadata: meta });
|
|
212
275
|
}
|
|
213
276
|
/**
|
|
@@ -225,13 +288,22 @@ var ObjectStore = class {
|
|
|
225
288
|
/**
|
|
226
289
|
* Refresh Tier 1 metadata from the live Three.js object.
|
|
227
290
|
* Returns true if any values changed.
|
|
291
|
+
* Returns false (no change) if extracting metadata throws so that the
|
|
292
|
+
* previous metadata is preserved.
|
|
228
293
|
*/
|
|
229
294
|
update(obj) {
|
|
230
295
|
const prev = this._metaByObject.get(obj);
|
|
231
296
|
if (!prev) return false;
|
|
232
|
-
|
|
297
|
+
let curr;
|
|
298
|
+
try {
|
|
299
|
+
curr = extractMetadata(obj);
|
|
300
|
+
} catch (err) {
|
|
301
|
+
r3fLog("store", `update: extractMetadata failed for "${obj.name || obj.uuid}"`, err);
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
233
304
|
if (hasChanged(prev, curr)) {
|
|
234
305
|
if (prev.testId !== curr.testId) {
|
|
306
|
+
r3fLog("store", `testId changed: "${prev.testId}" \u2192 "${curr.testId}" (${curr.type})`);
|
|
235
307
|
if (prev.testId) this._objectsByTestId.delete(prev.testId);
|
|
236
308
|
if (curr.testId) this._objectsByTestId.set(curr.testId, obj);
|
|
237
309
|
}
|
|
@@ -299,6 +371,64 @@ var ObjectStore = class {
|
|
|
299
371
|
}
|
|
300
372
|
return results;
|
|
301
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* Batch lookup: get metadata for multiple objects by testId or uuid.
|
|
376
|
+
* Returns a Map from the requested id to its metadata (or null if not found).
|
|
377
|
+
* Single round-trip — much more efficient than calling getByTestId/getByUuid
|
|
378
|
+
* in a loop for BIM/CAD scenes with many objects.
|
|
379
|
+
* O(k) where k is the number of requested ids.
|
|
380
|
+
*/
|
|
381
|
+
getObjects(ids) {
|
|
382
|
+
const results = /* @__PURE__ */ new Map();
|
|
383
|
+
for (const id of ids) {
|
|
384
|
+
const meta = this.getByTestId(id) ?? this.getByUuid(id);
|
|
385
|
+
results.set(id, meta);
|
|
386
|
+
}
|
|
387
|
+
return results;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Get all objects of a given Three.js type (e.g. "Mesh", "Group", "Line").
|
|
391
|
+
* Linear scan — O(n) where n is total tracked objects.
|
|
392
|
+
*/
|
|
393
|
+
getByType(type) {
|
|
394
|
+
const results = [];
|
|
395
|
+
for (const obj of this.getFlatList()) {
|
|
396
|
+
const meta = this._metaByObject.get(obj);
|
|
397
|
+
if (meta && meta.type === type) results.push(meta);
|
|
398
|
+
}
|
|
399
|
+
return results;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Get all objects that have a specific userData key.
|
|
403
|
+
* If `value` is provided, only returns objects where `userData[key]` matches.
|
|
404
|
+
* Uses JSON.stringify for deep equality on complex values.
|
|
405
|
+
* Linear scan — O(n).
|
|
406
|
+
*/
|
|
407
|
+
getByUserData(key, value) {
|
|
408
|
+
const results = [];
|
|
409
|
+
const checkValue = value !== void 0;
|
|
410
|
+
const valueJson = checkValue ? JSON.stringify(value) : "";
|
|
411
|
+
for (const obj of this.getFlatList()) {
|
|
412
|
+
if (!(key in obj.userData)) continue;
|
|
413
|
+
if (checkValue && JSON.stringify(obj.userData[key]) !== valueJson) continue;
|
|
414
|
+
const meta = this._metaByObject.get(obj);
|
|
415
|
+
if (meta) results.push(meta);
|
|
416
|
+
}
|
|
417
|
+
return results;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Count objects of a given Three.js type.
|
|
421
|
+
* More efficient than getByType().length — no array allocation.
|
|
422
|
+
* Linear scan — O(n).
|
|
423
|
+
*/
|
|
424
|
+
getCountByType(type) {
|
|
425
|
+
let count = 0;
|
|
426
|
+
for (const obj of this.getFlatList()) {
|
|
427
|
+
const meta = this._metaByObject.get(obj);
|
|
428
|
+
if (meta && meta.type === type) count++;
|
|
429
|
+
}
|
|
430
|
+
return count;
|
|
431
|
+
}
|
|
302
432
|
/** Get the raw Three.js Object3D by testId or uuid. */
|
|
303
433
|
getObject3D(idOrUuid) {
|
|
304
434
|
return this._objectsByTestId.get(idOrUuid) ?? this._objectByUuid.get(idOrUuid) ?? null;
|
|
@@ -1032,6 +1162,7 @@ function registerSubtree(obj, store, mirror) {
|
|
|
1032
1162
|
function patchObject3D(store, mirror) {
|
|
1033
1163
|
_activePairs.push({ store, mirror });
|
|
1034
1164
|
if (!_patched) {
|
|
1165
|
+
r3fLog("patch", "Patching Object3D.prototype.add and .remove");
|
|
1035
1166
|
_originalAdd = Object3D.prototype.add;
|
|
1036
1167
|
_originalRemove = Object3D.prototype.remove;
|
|
1037
1168
|
Object3D.prototype.add = function patchedAdd(...objects) {
|
|
@@ -1040,8 +1171,15 @@ function patchObject3D(store, mirror) {
|
|
|
1040
1171
|
if (pair) {
|
|
1041
1172
|
for (const obj of objects) {
|
|
1042
1173
|
if (obj === this) continue;
|
|
1043
|
-
|
|
1174
|
+
try {
|
|
1175
|
+
r3fLog("patch", `patchedAdd: "${obj.name || obj.type}" added to "${this.name || this.type}"`);
|
|
1176
|
+
registerSubtree(obj, pair.store, pair.mirror);
|
|
1177
|
+
} catch (err) {
|
|
1178
|
+
r3fLog("patch", `patchedAdd: failed to register "${obj.name || obj.type}"`, err);
|
|
1179
|
+
}
|
|
1044
1180
|
}
|
|
1181
|
+
pair.store.update(this);
|
|
1182
|
+
pair.store.markDirty(this);
|
|
1045
1183
|
}
|
|
1046
1184
|
return this;
|
|
1047
1185
|
};
|
|
@@ -1050,11 +1188,18 @@ function patchObject3D(store, mirror) {
|
|
|
1050
1188
|
if (pair) {
|
|
1051
1189
|
for (const obj of objects) {
|
|
1052
1190
|
if (obj === this) continue;
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
pair.
|
|
1056
|
-
|
|
1191
|
+
try {
|
|
1192
|
+
r3fLog("patch", `patchedRemove: "${obj.name || obj.type}" removed from "${this.name || this.type}"`);
|
|
1193
|
+
pair.mirror.onObjectRemoved(obj);
|
|
1194
|
+
obj.traverse((child) => {
|
|
1195
|
+
pair.store.unregister(child);
|
|
1196
|
+
});
|
|
1197
|
+
} catch (err) {
|
|
1198
|
+
r3fLog("patch", `patchedRemove: failed to unregister "${obj.name || obj.type}"`, err);
|
|
1199
|
+
}
|
|
1057
1200
|
}
|
|
1201
|
+
pair.store.update(this);
|
|
1202
|
+
pair.store.markDirty(this);
|
|
1058
1203
|
}
|
|
1059
1204
|
_originalRemove.call(this, ...objects);
|
|
1060
1205
|
return this;
|
|
@@ -1075,6 +1220,7 @@ function patchObject3D(store, mirror) {
|
|
|
1075
1220
|
}
|
|
1076
1221
|
function restoreObject3D() {
|
|
1077
1222
|
if (!_patched) return;
|
|
1223
|
+
r3fLog("patch", "Restoring original Object3D.prototype.add and .remove");
|
|
1078
1224
|
if (_originalAdd) {
|
|
1079
1225
|
Object3D.prototype.add = _originalAdd;
|
|
1080
1226
|
_originalAdd = null;
|
|
@@ -1098,7 +1244,7 @@ function buildNodeTree(store, meta) {
|
|
|
1098
1244
|
children.push(buildNodeTree(store, childMeta));
|
|
1099
1245
|
}
|
|
1100
1246
|
}
|
|
1101
|
-
|
|
1247
|
+
const node = {
|
|
1102
1248
|
uuid: meta.uuid,
|
|
1103
1249
|
name: meta.name,
|
|
1104
1250
|
type: meta.type,
|
|
@@ -1109,6 +1255,12 @@ function buildNodeTree(store, meta) {
|
|
|
1109
1255
|
scale: [...meta.scale],
|
|
1110
1256
|
children
|
|
1111
1257
|
};
|
|
1258
|
+
if (meta.geometryType) node.geometryType = meta.geometryType;
|
|
1259
|
+
if (meta.materialType) node.materialType = meta.materialType;
|
|
1260
|
+
if (meta.vertexCount != null) node.vertexCount = meta.vertexCount;
|
|
1261
|
+
if (meta.triangleCount != null) node.triangleCount = meta.triangleCount;
|
|
1262
|
+
if (meta.instanceCount != null) node.instanceCount = meta.instanceCount;
|
|
1263
|
+
return node;
|
|
1112
1264
|
}
|
|
1113
1265
|
function findRoot(store) {
|
|
1114
1266
|
const allObjects = store.getFlatList();
|
|
@@ -1697,6 +1849,7 @@ function click3D(idOrUuid, options = {}) {
|
|
|
1697
1849
|
const camera = getCamera();
|
|
1698
1850
|
const gl = getRenderer();
|
|
1699
1851
|
const size = getCanvasSize();
|
|
1852
|
+
r3fLog("click", `click3D("${idOrUuid}") \u2014 resolving projection`);
|
|
1700
1853
|
const projection = projectToScreen(obj, camera, size);
|
|
1701
1854
|
if (!projection) {
|
|
1702
1855
|
throw new Error(
|
|
@@ -1789,6 +1942,7 @@ function hover3D(idOrUuid, options = {}) {
|
|
|
1789
1942
|
const camera = getCamera();
|
|
1790
1943
|
const gl = getRenderer();
|
|
1791
1944
|
const size = getCanvasSize();
|
|
1945
|
+
r3fLog("hover", `hover3D("${idOrUuid}") \u2014 resolving projection`);
|
|
1792
1946
|
const projection = projectToScreen(obj, camera, size);
|
|
1793
1947
|
if (!projection) {
|
|
1794
1948
|
throw new Error(
|
|
@@ -1823,6 +1977,7 @@ async function drag3D(idOrUuid, delta, options = {}) {
|
|
|
1823
1977
|
const camera = getCamera();
|
|
1824
1978
|
const gl = getRenderer();
|
|
1825
1979
|
const size = getCanvasSize();
|
|
1980
|
+
r3fLog("drag", `drag3D("${idOrUuid}") mode=${mode}`, delta);
|
|
1826
1981
|
const projection = projectToScreen(obj, camera, size);
|
|
1827
1982
|
if (!projection) {
|
|
1828
1983
|
throw new Error(
|
|
@@ -1892,6 +2047,162 @@ function pointerMiss3D(options = {}) {
|
|
|
1892
2047
|
dispatchPointerMiss(canvas, options.point);
|
|
1893
2048
|
}
|
|
1894
2049
|
|
|
2050
|
+
// src/interactions/drawPath.ts
|
|
2051
|
+
var _nextDrawPointerId = 5e3;
|
|
2052
|
+
function makeDrawPointerInit(canvas, point, pointerId, pointerType, overrides) {
|
|
2053
|
+
const rect = canvas.getBoundingClientRect();
|
|
2054
|
+
const clientX = rect.left + point.x;
|
|
2055
|
+
const clientY = rect.top + point.y;
|
|
2056
|
+
return {
|
|
2057
|
+
bubbles: true,
|
|
2058
|
+
cancelable: true,
|
|
2059
|
+
composed: true,
|
|
2060
|
+
clientX,
|
|
2061
|
+
clientY,
|
|
2062
|
+
screenX: clientX,
|
|
2063
|
+
screenY: clientY,
|
|
2064
|
+
pointerId,
|
|
2065
|
+
pointerType,
|
|
2066
|
+
isPrimary: true,
|
|
2067
|
+
button: 0,
|
|
2068
|
+
buttons: 1,
|
|
2069
|
+
width: 1,
|
|
2070
|
+
height: 1,
|
|
2071
|
+
pressure: point.pressure ?? 0.5,
|
|
2072
|
+
...overrides
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
async function drawPath(points, options = {}) {
|
|
2076
|
+
if (points.length < 2) {
|
|
2077
|
+
throw new Error(
|
|
2078
|
+
`[react-three-dom] drawPath requires at least 2 points, got ${points.length}.`
|
|
2079
|
+
);
|
|
2080
|
+
}
|
|
2081
|
+
const {
|
|
2082
|
+
stepDelayMs = 0,
|
|
2083
|
+
pointerType = "mouse",
|
|
2084
|
+
clickAtEnd = false,
|
|
2085
|
+
canvas: explicitCanvas
|
|
2086
|
+
} = options;
|
|
2087
|
+
const canvas = explicitCanvas ?? getRenderer().domElement;
|
|
2088
|
+
const pointerId = _nextDrawPointerId++;
|
|
2089
|
+
let eventCount = 0;
|
|
2090
|
+
r3fLog("draw", `drawPath \u2014 ${points.length} points, delay=${stepDelayMs}ms, pointerType=${pointerType}`);
|
|
2091
|
+
const first = points[0];
|
|
2092
|
+
canvas.dispatchEvent(
|
|
2093
|
+
new PointerEvent("pointerdown", makeDrawPointerInit(canvas, first, pointerId, pointerType))
|
|
2094
|
+
);
|
|
2095
|
+
eventCount++;
|
|
2096
|
+
for (let i = 1; i < points.length; i++) {
|
|
2097
|
+
if (stepDelayMs > 0) {
|
|
2098
|
+
await sleep2(stepDelayMs);
|
|
2099
|
+
}
|
|
2100
|
+
canvas.dispatchEvent(
|
|
2101
|
+
new PointerEvent(
|
|
2102
|
+
"pointermove",
|
|
2103
|
+
makeDrawPointerInit(canvas, points[i], pointerId, pointerType)
|
|
2104
|
+
)
|
|
2105
|
+
);
|
|
2106
|
+
eventCount++;
|
|
2107
|
+
}
|
|
2108
|
+
const last = points[points.length - 1];
|
|
2109
|
+
canvas.dispatchEvent(
|
|
2110
|
+
new PointerEvent(
|
|
2111
|
+
"pointerup",
|
|
2112
|
+
makeDrawPointerInit(canvas, last, pointerId, pointerType, {
|
|
2113
|
+
buttons: 0,
|
|
2114
|
+
pressure: 0
|
|
2115
|
+
})
|
|
2116
|
+
)
|
|
2117
|
+
);
|
|
2118
|
+
eventCount++;
|
|
2119
|
+
if (clickAtEnd) {
|
|
2120
|
+
const rect = canvas.getBoundingClientRect();
|
|
2121
|
+
canvas.dispatchEvent(
|
|
2122
|
+
new MouseEvent("click", {
|
|
2123
|
+
bubbles: true,
|
|
2124
|
+
cancelable: true,
|
|
2125
|
+
clientX: rect.left + last.x,
|
|
2126
|
+
clientY: rect.top + last.y,
|
|
2127
|
+
button: 0
|
|
2128
|
+
})
|
|
2129
|
+
);
|
|
2130
|
+
eventCount++;
|
|
2131
|
+
}
|
|
2132
|
+
r3fLog("draw", `drawPath complete \u2014 ${eventCount} events dispatched`);
|
|
2133
|
+
return {
|
|
2134
|
+
eventCount,
|
|
2135
|
+
pointCount: points.length,
|
|
2136
|
+
startPoint: first,
|
|
2137
|
+
endPoint: last
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
function linePath(start, end, steps = 10, pressure = 0.5) {
|
|
2141
|
+
const points = [];
|
|
2142
|
+
const totalSteps = steps + 1;
|
|
2143
|
+
for (let i = 0; i <= totalSteps; i++) {
|
|
2144
|
+
const t = i / totalSteps;
|
|
2145
|
+
points.push({
|
|
2146
|
+
x: start.x + (end.x - start.x) * t,
|
|
2147
|
+
y: start.y + (end.y - start.y) * t,
|
|
2148
|
+
pressure
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
return points;
|
|
2152
|
+
}
|
|
2153
|
+
function curvePath(start, control, end, steps = 20, pressure = 0.5) {
|
|
2154
|
+
const points = [];
|
|
2155
|
+
for (let i = 0; i <= steps; i++) {
|
|
2156
|
+
const t = i / steps;
|
|
2157
|
+
const invT = 1 - t;
|
|
2158
|
+
points.push({
|
|
2159
|
+
x: invT * invT * start.x + 2 * invT * t * control.x + t * t * end.x,
|
|
2160
|
+
y: invT * invT * start.y + 2 * invT * t * control.y + t * t * end.y,
|
|
2161
|
+
pressure
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
return points;
|
|
2165
|
+
}
|
|
2166
|
+
function rectPath(topLeft, bottomRight, pointsPerSide = 5, pressure = 0.5) {
|
|
2167
|
+
const topRight = { x: bottomRight.x, y: topLeft.y };
|
|
2168
|
+
const bottomLeft = { x: topLeft.x, y: bottomRight.y };
|
|
2169
|
+
const sides = [
|
|
2170
|
+
[topLeft, topRight],
|
|
2171
|
+
[topRight, bottomRight],
|
|
2172
|
+
[bottomRight, bottomLeft],
|
|
2173
|
+
[bottomLeft, topLeft]
|
|
2174
|
+
];
|
|
2175
|
+
const points = [];
|
|
2176
|
+
for (const [from, to] of sides) {
|
|
2177
|
+
for (let i = 0; i < pointsPerSide; i++) {
|
|
2178
|
+
const t = i / pointsPerSide;
|
|
2179
|
+
points.push({
|
|
2180
|
+
x: from.x + (to.x - from.x) * t,
|
|
2181
|
+
y: from.y + (to.y - from.y) * t,
|
|
2182
|
+
pressure
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
points.push({ x: topLeft.x, y: topLeft.y, pressure });
|
|
2187
|
+
return points;
|
|
2188
|
+
}
|
|
2189
|
+
function circlePath(center, radiusX, radiusY, steps = 36, pressure = 0.5) {
|
|
2190
|
+
const ry = radiusY ?? radiusX;
|
|
2191
|
+
const points = [];
|
|
2192
|
+
for (let i = 0; i <= steps; i++) {
|
|
2193
|
+
const angle = i / steps * Math.PI * 2;
|
|
2194
|
+
points.push({
|
|
2195
|
+
x: center.x + Math.cos(angle) * radiusX,
|
|
2196
|
+
y: center.y + Math.sin(angle) * ry,
|
|
2197
|
+
pressure
|
|
2198
|
+
});
|
|
2199
|
+
}
|
|
2200
|
+
return points;
|
|
2201
|
+
}
|
|
2202
|
+
function sleep2(ms) {
|
|
2203
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2204
|
+
}
|
|
2205
|
+
|
|
1895
2206
|
// src/highlight/SelectionManager.ts
|
|
1896
2207
|
var SelectionManager = class {
|
|
1897
2208
|
constructor() {
|
|
@@ -2046,10 +2357,22 @@ function projectToScreenRect(obj, camera, canvasRect) {
|
|
|
2046
2357
|
}
|
|
2047
2358
|
function exposeGlobalAPI(store) {
|
|
2048
2359
|
const api = {
|
|
2360
|
+
_ready: true,
|
|
2049
2361
|
getByTestId: (id) => store.getByTestId(id),
|
|
2050
2362
|
getByUuid: (uuid) => store.getByUuid(uuid),
|
|
2051
2363
|
getByName: (name) => store.getByName(name),
|
|
2052
2364
|
getCount: () => store.getCount(),
|
|
2365
|
+
getByType: (type) => store.getByType(type),
|
|
2366
|
+
getByUserData: (key, value) => store.getByUserData(key, value),
|
|
2367
|
+
getCountByType: (type) => store.getCountByType(type),
|
|
2368
|
+
getObjects: (ids) => {
|
|
2369
|
+
const map = store.getObjects(ids);
|
|
2370
|
+
const result = {};
|
|
2371
|
+
for (const [id, meta] of map) {
|
|
2372
|
+
result[id] = meta;
|
|
2373
|
+
}
|
|
2374
|
+
return result;
|
|
2375
|
+
},
|
|
2053
2376
|
snapshot: () => createSnapshot(store),
|
|
2054
2377
|
inspect: (idOrUuid) => store.inspect(idOrUuid),
|
|
2055
2378
|
click: (idOrUuid) => {
|
|
@@ -2064,8 +2387,8 @@ function exposeGlobalAPI(store) {
|
|
|
2064
2387
|
hover: (idOrUuid) => {
|
|
2065
2388
|
hover3D(idOrUuid);
|
|
2066
2389
|
},
|
|
2067
|
-
drag: (idOrUuid, delta) => {
|
|
2068
|
-
|
|
2390
|
+
drag: async (idOrUuid, delta) => {
|
|
2391
|
+
await drag3D(idOrUuid, delta);
|
|
2069
2392
|
},
|
|
2070
2393
|
wheel: (idOrUuid, options) => {
|
|
2071
2394
|
wheel3D(idOrUuid, options);
|
|
@@ -2073,6 +2396,10 @@ function exposeGlobalAPI(store) {
|
|
|
2073
2396
|
pointerMiss: () => {
|
|
2074
2397
|
pointerMiss3D();
|
|
2075
2398
|
},
|
|
2399
|
+
drawPath: async (points, options) => {
|
|
2400
|
+
const result = await drawPath(points, options);
|
|
2401
|
+
return { eventCount: result.eventCount, pointCount: result.pointCount };
|
|
2402
|
+
},
|
|
2076
2403
|
select: (idOrUuid) => {
|
|
2077
2404
|
const obj = store.getObject3D(idOrUuid);
|
|
2078
2405
|
if (obj && _selectionManager) _selectionManager.select(obj);
|
|
@@ -2080,13 +2407,28 @@ function exposeGlobalAPI(store) {
|
|
|
2080
2407
|
clearSelection: () => {
|
|
2081
2408
|
_selectionManager?.clearSelection();
|
|
2082
2409
|
},
|
|
2410
|
+
getSelection: () => _selectionManager ? _selectionManager.getSelected().map((o) => o.uuid) : [],
|
|
2083
2411
|
getObject3D: (idOrUuid) => store.getObject3D(idOrUuid),
|
|
2084
2412
|
version
|
|
2085
2413
|
};
|
|
2086
2414
|
window.__R3F_DOM__ = api;
|
|
2087
2415
|
}
|
|
2088
|
-
function removeGlobalAPI() {
|
|
2089
|
-
|
|
2416
|
+
function removeGlobalAPI(onlyIfEquals) {
|
|
2417
|
+
r3fLog("bridge", "removeGlobalAPI called (deferred)");
|
|
2418
|
+
if (onlyIfEquals !== void 0) {
|
|
2419
|
+
const ref = onlyIfEquals;
|
|
2420
|
+
queueMicrotask(() => {
|
|
2421
|
+
if (window.__R3F_DOM__ === ref) {
|
|
2422
|
+
delete window.__R3F_DOM__;
|
|
2423
|
+
r3fLog("bridge", "Global API removed");
|
|
2424
|
+
} else {
|
|
2425
|
+
r3fLog("bridge", "Global API not removed \u2014 replaced by new instance (Strict Mode remount)");
|
|
2426
|
+
}
|
|
2427
|
+
});
|
|
2428
|
+
} else {
|
|
2429
|
+
delete window.__R3F_DOM__;
|
|
2430
|
+
r3fLog("bridge", "Global API removed (immediate)");
|
|
2431
|
+
}
|
|
2090
2432
|
}
|
|
2091
2433
|
function setElementRect(el, l, t, w, h) {
|
|
2092
2434
|
const d = el.dataset;
|
|
@@ -2107,7 +2449,8 @@ function ThreeDom({
|
|
|
2107
2449
|
timeBudgetMs = 0.5,
|
|
2108
2450
|
maxDomNodes = 2e3,
|
|
2109
2451
|
initialDepth = 3,
|
|
2110
|
-
enabled = true
|
|
2452
|
+
enabled = true,
|
|
2453
|
+
debug = false
|
|
2111
2454
|
} = {}) {
|
|
2112
2455
|
const scene = useThree((s) => s.scene);
|
|
2113
2456
|
const camera = useThree((s) => s.camera);
|
|
@@ -2117,6 +2460,8 @@ function ThreeDom({
|
|
|
2117
2460
|
const positionCursorRef = useRef(0);
|
|
2118
2461
|
useEffect(() => {
|
|
2119
2462
|
if (!enabled) return;
|
|
2463
|
+
if (debug) enableDebug(true);
|
|
2464
|
+
r3fLog("setup", "ThreeDom effect started", { enabled, debug, root, maxDomNodes });
|
|
2120
2465
|
const canvas = gl.domElement;
|
|
2121
2466
|
const canvasParent = canvas.parentElement;
|
|
2122
2467
|
let rootElement = null;
|
|
@@ -2143,57 +2488,115 @@ function ThreeDom({
|
|
|
2143
2488
|
"overflow: hidden",
|
|
2144
2489
|
"z-index: 10"
|
|
2145
2490
|
].join(";");
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
if (obj.
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2491
|
+
let store = null;
|
|
2492
|
+
let mirror = null;
|
|
2493
|
+
let unpatch = null;
|
|
2494
|
+
let selectionManager = null;
|
|
2495
|
+
let currentApi;
|
|
2496
|
+
try {
|
|
2497
|
+
store = new ObjectStore();
|
|
2498
|
+
mirror = new DomMirror(store, maxDomNodes);
|
|
2499
|
+
mirror.setRoot(rootElement);
|
|
2500
|
+
r3fLog("setup", "Store and mirror created");
|
|
2501
|
+
ensureCustomElements(store);
|
|
2502
|
+
store.registerTree(scene);
|
|
2503
|
+
r3fLog("setup", `Registered scene tree: ${store.getCount()} objects`);
|
|
2504
|
+
mirror.materializeSubtree(scene.uuid, initialDepth);
|
|
2505
|
+
unpatch = patchObject3D(store, mirror);
|
|
2506
|
+
setInteractionState(store, camera, gl, size);
|
|
2507
|
+
r3fLog("setup", "Object3D patched, interaction state set");
|
|
2508
|
+
selectionManager = new SelectionManager();
|
|
2509
|
+
_selectionManager = selectionManager;
|
|
2510
|
+
_highlighter = null;
|
|
2511
|
+
exposeGlobalAPI(store);
|
|
2512
|
+
r3fLog("bridge", "exposeGlobalAPI called \u2014 bridge is live, _ready=true");
|
|
2513
|
+
currentApi = window.__R3F_DOM__;
|
|
2514
|
+
_store3 = store;
|
|
2515
|
+
_mirror = mirror;
|
|
2516
|
+
const initialCanvasRect = canvas.getBoundingClientRect();
|
|
2517
|
+
const allObjects = store.getFlatList();
|
|
2518
|
+
for (const obj of allObjects) {
|
|
2519
|
+
if (obj.userData?.__r3fdom_internal) continue;
|
|
2520
|
+
const el = mirror.getElement(obj.uuid);
|
|
2521
|
+
if (!el) continue;
|
|
2522
|
+
if (obj.type === "Scene") {
|
|
2523
|
+
setElementRect(el, 0, 0, Math.round(initialCanvasRect.width), Math.round(initialCanvasRect.height));
|
|
2524
|
+
continue;
|
|
2525
|
+
}
|
|
2526
|
+
const rect = projectToScreenRect(obj, camera, initialCanvasRect);
|
|
2527
|
+
if (rect) {
|
|
2528
|
+
let parentLeft = 0;
|
|
2529
|
+
let parentTop = 0;
|
|
2530
|
+
if (obj.parent && obj.parent.type !== "Scene") {
|
|
2531
|
+
const parentRect = projectToScreenRect(obj.parent, camera, initialCanvasRect);
|
|
2532
|
+
if (parentRect) {
|
|
2533
|
+
parentLeft = Math.round(parentRect.left);
|
|
2534
|
+
parentTop = Math.round(parentRect.top);
|
|
2535
|
+
}
|
|
2179
2536
|
}
|
|
2537
|
+
setElementRect(
|
|
2538
|
+
el,
|
|
2539
|
+
Math.round(rect.left) - parentLeft,
|
|
2540
|
+
Math.round(rect.top) - parentTop,
|
|
2541
|
+
Math.round(rect.width),
|
|
2542
|
+
Math.round(rect.height)
|
|
2543
|
+
);
|
|
2180
2544
|
}
|
|
2181
|
-
setElementRect(
|
|
2182
|
-
el,
|
|
2183
|
-
Math.round(rect.left) - parentLeft,
|
|
2184
|
-
Math.round(rect.top) - parentTop,
|
|
2185
|
-
Math.round(rect.width),
|
|
2186
|
-
Math.round(rect.height)
|
|
2187
|
-
);
|
|
2188
2545
|
}
|
|
2546
|
+
} catch (err) {
|
|
2547
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
2548
|
+
r3fLog("setup", "ThreeDom setup failed", err);
|
|
2549
|
+
console.error("[react-three-dom] Setup failed:", err);
|
|
2550
|
+
window.__R3F_DOM__ = {
|
|
2551
|
+
_ready: false,
|
|
2552
|
+
_error: errorMsg,
|
|
2553
|
+
getByTestId: () => null,
|
|
2554
|
+
getByUuid: () => null,
|
|
2555
|
+
getByName: () => [],
|
|
2556
|
+
getCount: () => 0,
|
|
2557
|
+
getByType: () => [],
|
|
2558
|
+
getByUserData: () => [],
|
|
2559
|
+
getCountByType: () => 0,
|
|
2560
|
+
getObjects: (ids) => {
|
|
2561
|
+
const result = {};
|
|
2562
|
+
for (const id of ids) result[id] = null;
|
|
2563
|
+
return result;
|
|
2564
|
+
},
|
|
2565
|
+
snapshot: () => ({ timestamp: 0, objectCount: 0, tree: { uuid: "", name: "", type: "Scene", visible: true, position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1], children: [] } }),
|
|
2566
|
+
inspect: () => null,
|
|
2567
|
+
click: () => {
|
|
2568
|
+
},
|
|
2569
|
+
doubleClick: () => {
|
|
2570
|
+
},
|
|
2571
|
+
contextMenu: () => {
|
|
2572
|
+
},
|
|
2573
|
+
hover: () => {
|
|
2574
|
+
},
|
|
2575
|
+
drag: async () => {
|
|
2576
|
+
},
|
|
2577
|
+
wheel: () => {
|
|
2578
|
+
},
|
|
2579
|
+
pointerMiss: () => {
|
|
2580
|
+
},
|
|
2581
|
+
drawPath: async () => ({ eventCount: 0, pointCount: 0 }),
|
|
2582
|
+
select: () => {
|
|
2583
|
+
},
|
|
2584
|
+
clearSelection: () => {
|
|
2585
|
+
},
|
|
2586
|
+
getSelection: () => [],
|
|
2587
|
+
getObject3D: () => null,
|
|
2588
|
+
version
|
|
2589
|
+
};
|
|
2590
|
+
currentApi = window.__R3F_DOM__;
|
|
2189
2591
|
}
|
|
2190
2592
|
return () => {
|
|
2191
|
-
|
|
2192
|
-
|
|
2593
|
+
r3fLog("setup", "ThreeDom cleanup started");
|
|
2594
|
+
if (unpatch) unpatch();
|
|
2595
|
+
removeGlobalAPI(currentApi);
|
|
2193
2596
|
clearInteractionState();
|
|
2194
|
-
selectionManager.dispose();
|
|
2195
|
-
mirror.dispose();
|
|
2196
|
-
store.dispose();
|
|
2597
|
+
if (selectionManager) selectionManager.dispose();
|
|
2598
|
+
if (mirror) mirror.dispose();
|
|
2599
|
+
if (store) store.dispose();
|
|
2197
2600
|
if (createdRoot && rootElement?.parentNode) {
|
|
2198
2601
|
rootElement.parentNode.removeChild(rootElement);
|
|
2199
2602
|
}
|
|
@@ -2201,69 +2604,75 @@ function ThreeDom({
|
|
|
2201
2604
|
_mirror = null;
|
|
2202
2605
|
_selectionManager = null;
|
|
2203
2606
|
_highlighter = null;
|
|
2607
|
+
if (debug) enableDebug(false);
|
|
2608
|
+
r3fLog("setup", "ThreeDom cleanup complete");
|
|
2204
2609
|
};
|
|
2205
|
-
}, [scene, camera, gl, size, enabled, root, maxDomNodes, initialDepth]);
|
|
2610
|
+
}, [scene, camera, gl, size, enabled, root, maxDomNodes, initialDepth, debug]);
|
|
2206
2611
|
useFrame(() => {
|
|
2207
2612
|
if (!enabled || !_store3 || !_mirror) return;
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
const budgetRemaining = timeBudgetMs - (performance.now() - start);
|
|
2220
|
-
if (budgetRemaining > 0.1) {
|
|
2221
|
-
const objects2 = store.getFlatList();
|
|
2222
|
-
if (objects2.length > 0) {
|
|
2223
|
-
const end = Math.min(cursorRef.current + batchSize, objects2.length);
|
|
2224
|
-
for (let i = cursorRef.current; i < end; i++) {
|
|
2225
|
-
if (performance.now() - start > timeBudgetMs) break;
|
|
2226
|
-
const obj = objects2[i];
|
|
2227
|
-
const changed = store.update(obj);
|
|
2228
|
-
if (changed) mirror.syncAttributes(obj);
|
|
2229
|
-
}
|
|
2230
|
-
cursorRef.current = end >= objects2.length ? 0 : end;
|
|
2613
|
+
try {
|
|
2614
|
+
setInteractionState(_store3, camera, gl, size);
|
|
2615
|
+
const store = _store3;
|
|
2616
|
+
const mirror = _mirror;
|
|
2617
|
+
const canvas = gl.domElement;
|
|
2618
|
+
const canvasRect = canvas.getBoundingClientRect();
|
|
2619
|
+
const start = performance.now();
|
|
2620
|
+
const dirtyObjects = store.drainDirtyQueue();
|
|
2621
|
+
for (const obj of dirtyObjects) {
|
|
2622
|
+
store.update(obj);
|
|
2623
|
+
mirror.syncAttributes(obj);
|
|
2231
2624
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2625
|
+
const budgetRemaining = timeBudgetMs - (performance.now() - start);
|
|
2626
|
+
if (budgetRemaining > 0.1) {
|
|
2627
|
+
const objects2 = store.getFlatList();
|
|
2628
|
+
if (objects2.length > 0) {
|
|
2629
|
+
const end = Math.min(cursorRef.current + batchSize, objects2.length);
|
|
2630
|
+
for (let i = cursorRef.current; i < end; i++) {
|
|
2631
|
+
if (performance.now() - start > timeBudgetMs) break;
|
|
2632
|
+
const obj = objects2[i];
|
|
2633
|
+
const changed = store.update(obj);
|
|
2634
|
+
if (changed) mirror.syncAttributes(obj);
|
|
2635
|
+
}
|
|
2636
|
+
cursorRef.current = end >= objects2.length ? 0 : end;
|
|
2244
2637
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2638
|
+
}
|
|
2639
|
+
const objects = store.getFlatList();
|
|
2640
|
+
if (objects.length > 0) {
|
|
2641
|
+
const posEnd = Math.min(positionCursorRef.current + 50, objects.length);
|
|
2642
|
+
for (let i = positionCursorRef.current; i < posEnd; i++) {
|
|
2643
|
+
const obj = objects[i];
|
|
2644
|
+
if (obj.userData?.__r3fdom_internal) continue;
|
|
2645
|
+
const el = mirror.getElement(obj.uuid);
|
|
2646
|
+
if (!el) continue;
|
|
2647
|
+
if (obj.type === "Scene") {
|
|
2648
|
+
setElementRect(el, 0, 0, Math.round(canvasRect.width), Math.round(canvasRect.height));
|
|
2649
|
+
continue;
|
|
2650
|
+
}
|
|
2651
|
+
const rect = projectToScreenRect(obj, camera, canvasRect);
|
|
2652
|
+
if (rect) {
|
|
2653
|
+
let parentLeft = 0;
|
|
2654
|
+
let parentTop = 0;
|
|
2655
|
+
if (obj.parent && obj.parent.type !== "Scene") {
|
|
2656
|
+
const parentRect = projectToScreenRect(obj.parent, camera, canvasRect);
|
|
2657
|
+
if (parentRect) {
|
|
2658
|
+
parentLeft = Math.round(parentRect.left);
|
|
2659
|
+
parentTop = Math.round(parentRect.top);
|
|
2660
|
+
}
|
|
2254
2661
|
}
|
|
2662
|
+
const l = Math.round(rect.left) - parentLeft;
|
|
2663
|
+
const t = Math.round(rect.top) - parentTop;
|
|
2664
|
+
const w = Math.round(rect.width);
|
|
2665
|
+
const h = Math.round(rect.height);
|
|
2666
|
+
setElementRect(el, l, t, w, h);
|
|
2667
|
+
if (el.style.display === "none") el.style.display = "block";
|
|
2668
|
+
} else {
|
|
2669
|
+
if (el.style.display !== "none") el.style.display = "none";
|
|
2255
2670
|
}
|
|
2256
|
-
const l = Math.round(rect.left) - parentLeft;
|
|
2257
|
-
const t = Math.round(rect.top) - parentTop;
|
|
2258
|
-
const w = Math.round(rect.width);
|
|
2259
|
-
const h = Math.round(rect.height);
|
|
2260
|
-
setElementRect(el, l, t, w, h);
|
|
2261
|
-
if (el.style.display === "none") el.style.display = "block";
|
|
2262
|
-
} else {
|
|
2263
|
-
if (el.style.display !== "none") el.style.display = "none";
|
|
2264
2671
|
}
|
|
2672
|
+
positionCursorRef.current = posEnd >= objects.length ? 0 : posEnd;
|
|
2265
2673
|
}
|
|
2266
|
-
|
|
2674
|
+
} catch (err) {
|
|
2675
|
+
r3fLog("sync", "Per-frame sync error", err);
|
|
2267
2676
|
}
|
|
2268
2677
|
});
|
|
2269
2678
|
return null;
|
|
@@ -2614,6 +3023,6 @@ var Highlighter = class {
|
|
|
2614
3023
|
}
|
|
2615
3024
|
};
|
|
2616
3025
|
|
|
2617
|
-
export { DomMirror, Highlighter, MANAGED_ATTRIBUTES, ObjectStore, SelectionManager, TAG_MAP, ThreeDom, ThreeElement, applyAttributes, click3D, computeAttributes, contextMenu3D, createFlatSnapshot, createSnapshot, dispatchClick, dispatchContextMenu, dispatchDoubleClick, dispatchDrag, dispatchHover, dispatchPointerMiss, dispatchUnhover, dispatchWheel, doubleClick3D, drag3D, ensureCustomElements, getHighlighter, getMirror, getSelectionManager, getStore2 as getStore, getTagForType, hover3D, isInFrustum, isPatched, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
|
|
3026
|
+
export { DomMirror, Highlighter, MANAGED_ATTRIBUTES, ObjectStore, 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, getHighlighter, getMirror, getSelectionManager, getStore2 as getStore, getTagForType, hover3D, isDebugEnabled, isInFrustum, isPatched, linePath, patchObject3D, pointerMiss3D, previewDragWorldDelta, projectAllSamplePoints, projectToScreen, r3fLog, rectPath, resolveObject, restoreObject3D, screenDeltaToWorld, unhover3D, verifyRaycastHit, verifyRaycastHitMultiPoint, version, wheel3D };
|
|
2618
3027
|
//# sourceMappingURL=index.js.map
|
|
2619
3028
|
//# sourceMappingURL=index.js.map
|