@react-three/fiber 10.0.0-canary.2b511a5 → 10.0.0-canary.aecbafb

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.
@@ -1006,6 +1006,9 @@ function applyProps(object, props) {
1006
1006
  else target.set(value);
1007
1007
  } else {
1008
1008
  root[key] = value;
1009
+ if (key.endsWith("Node") && root.isMaterial) {
1010
+ root.needsUpdate = true;
1011
+ }
1009
1012
  if (rootState && rootState.renderer?.outputColorSpace === webgpu.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
1010
1013
  root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
1011
1014
  root[key].colorSpace = rootState.textureColorSpace;
@@ -1039,38 +1042,60 @@ function applyProps(object, props) {
1039
1042
  return object;
1040
1043
  }
1041
1044
 
1045
+ const DEFAULT_POINTER_ID = 0;
1046
+ const XR_POINTER_ID_START = 1e3;
1047
+ function getPointerState(internal, pointerId) {
1048
+ let state = internal.pointerMap.get(pointerId);
1049
+ if (!state) {
1050
+ state = {
1051
+ hovered: /* @__PURE__ */ new Map(),
1052
+ captured: /* @__PURE__ */ new Map(),
1053
+ initialClick: [0, 0],
1054
+ initialHits: []
1055
+ };
1056
+ internal.pointerMap.set(pointerId, state);
1057
+ }
1058
+ return state;
1059
+ }
1060
+ function getPointerId(event) {
1061
+ return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
1062
+ }
1042
1063
  function makeId(event) {
1043
1064
  return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
1044
1065
  }
1045
- function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
1046
- const captureData = captures.get(obj);
1066
+ function releaseInternalPointerCapture(internal, obj, pointerId) {
1067
+ const pointerState = internal.pointerMap.get(pointerId);
1068
+ if (!pointerState) return;
1069
+ const captureData = pointerState.captured.get(obj);
1047
1070
  if (captureData) {
1048
- captures.delete(obj);
1049
- if (captures.size === 0) {
1050
- capturedMap.delete(pointerId);
1051
- captureData.target.releasePointerCapture(pointerId);
1052
- }
1071
+ pointerState.captured.delete(obj);
1072
+ captureData.target.releasePointerCapture(pointerId);
1053
1073
  }
1054
1074
  }
1055
1075
  function removeInteractivity(store, object) {
1056
1076
  const { internal } = store.getState();
1057
1077
  internal.interaction = internal.interaction.filter((o) => o !== object);
1058
- internal.initialHits = internal.initialHits.filter((o) => o !== object);
1059
- internal.hovered.forEach((value, key) => {
1060
- if (value.eventObject === object || value.object === object) {
1061
- internal.hovered.delete(key);
1078
+ for (const [pointerId, pointerState] of internal.pointerMap) {
1079
+ pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
1080
+ pointerState.hovered.forEach((value, key) => {
1081
+ if (value.eventObject === object || value.object === object) {
1082
+ pointerState.hovered.delete(key);
1083
+ }
1084
+ });
1085
+ if (pointerState.captured.has(object)) {
1086
+ releaseInternalPointerCapture(internal, object, pointerId);
1062
1087
  }
1063
- });
1064
- internal.capturedMap.forEach((captures, pointerId) => {
1065
- releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
1066
- });
1088
+ }
1067
1089
  unregisterVisibility(store, object);
1068
1090
  }
1069
1091
  function createEvents(store) {
1070
- function calculateDistance(event) {
1092
+ function calculateDistance(event, pointerId) {
1071
1093
  const { internal } = store.getState();
1072
- const dx = event.offsetX - internal.initialClick[0];
1073
- const dy = event.offsetY - internal.initialClick[1];
1094
+ const pointerState = internal.pointerMap.get(pointerId);
1095
+ if (!pointerState) return 0;
1096
+ const [initialX, initialY] = pointerState.initialClick;
1097
+ const dx = event.offsetX - initialX;
1098
+ const dy = event.offsetY - initialY;
1074
1099
  return Math.round(Math.sqrt(dx * dx + dy * dy));
1075
1100
  }
1076
1101
  function filterPointerEvents(objects) {
@@ -1106,6 +1131,15 @@ function createEvents(store) {
1106
1131
  return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
1107
1132
  }
1108
1133
  let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
1134
+ const aInteractivePriority = a.object.userData?.interactivePriority;
1135
+ const bInteractivePriority = b.object.userData?.interactivePriority;
1136
+ if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
1137
+ if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
1138
+ if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
1139
+ if (aInteractivePriority !== bInteractivePriority) {
1140
+ return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
1141
+ }
1142
+ }
1109
1143
  const aState = getRootState(a.object);
1110
1144
  const bState = getRootState(b.object);
1111
1145
  const aPriority = aState?.events?.priority ?? 1;
@@ -1127,9 +1161,13 @@ function createEvents(store) {
1127
1161
  eventObject = eventObject.parent;
1128
1162
  }
1129
1163
  }
1130
- if ("pointerId" in event && state.internal.capturedMap.has(event.pointerId)) {
1131
- for (const captureData of state.internal.capturedMap.get(event.pointerId).values()) {
1132
- if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
1164
+ if ("pointerId" in event) {
1165
+ const pointerId = event.pointerId;
1166
+ const pointerState = state.internal.pointerMap.get(pointerId);
1167
+ if (pointerState?.captured.size) {
1168
+ for (const captureData of pointerState.captured.values()) {
1169
+ if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
1170
+ }
1133
1171
  }
1134
1172
  }
1135
1173
  return intersections;
@@ -1142,27 +1180,25 @@ function createEvents(store) {
1142
1180
  if (state) {
1143
1181
  const { raycaster, pointer, camera, internal } = state;
1144
1182
  const unprojectedPoint = new webgpu.Vector3(pointer.x, pointer.y, 0).unproject(camera);
1145
- const hasPointerCapture = (id) => internal.capturedMap.get(id)?.has(hit.eventObject) ?? false;
1183
+ const hasPointerCapture = (id) => {
1184
+ const pointerState = internal.pointerMap.get(id);
1185
+ return pointerState?.captured.has(hit.eventObject) ?? false;
1186
+ };
1146
1187
  const setPointerCapture = (id) => {
1147
1188
  const captureData = { intersection: hit, target: event.target };
1148
- if (internal.capturedMap.has(id)) {
1149
- internal.capturedMap.get(id).set(hit.eventObject, captureData);
1150
- } else {
1151
- internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
1152
- }
1189
+ const pointerState = getPointerState(internal, id);
1190
+ pointerState.captured.set(hit.eventObject, captureData);
1153
1191
  event.target.setPointerCapture(id);
1154
1192
  };
1155
1193
  const releasePointerCapture = (id) => {
1156
- const captures = internal.capturedMap.get(id);
1157
- if (captures) {
1158
- releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
1159
- }
1194
+ releaseInternalPointerCapture(internal, hit.eventObject, id);
1160
1195
  };
1161
1196
  const extractEventProps = {};
1162
1197
  for (const prop in event) {
1163
1198
  const property = event[prop];
1164
1199
  if (typeof property !== "function") extractEventProps[prop] = property;
1165
1200
  }
1201
+ const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
1166
1202
  const raycastEvent = {
1167
1203
  ...hit,
1168
1204
  ...extractEventProps,
@@ -1173,18 +1209,19 @@ function createEvents(store) {
1173
1209
  unprojectedPoint,
1174
1210
  ray: raycaster.ray,
1175
1211
  camera,
1212
+ pointerId: eventPointerId,
1176
1213
  // Hijack stopPropagation, which just sets a flag
1177
1214
  stopPropagation() {
1178
- const capturesForPointer = "pointerId" in event && internal.capturedMap.get(event.pointerId);
1215
+ const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
1179
1216
  if (
1180
1217
  // ...if this pointer hasn't been captured
1181
- !capturesForPointer || // ... or if the hit object is capturing the pointer
1182
- capturesForPointer.has(hit.eventObject)
1218
+ !pointerState?.captured.size || // ... or if the hit object is capturing the pointer
1219
+ pointerState.captured.has(hit.eventObject)
1183
1220
  ) {
1184
1221
  raycastEvent.stopped = localState.stopped = true;
1185
- if (internal.hovered.size && Array.from(internal.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
1222
+ if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
1186
1223
  const higher = intersections.slice(0, intersections.indexOf(hit));
1187
- cancelPointer([...higher, hit]);
1224
+ cancelPointer([...higher, hit], eventPointerId);
1188
1225
  }
1189
1226
  }
1190
1227
  },
@@ -1200,15 +1237,18 @@ function createEvents(store) {
1200
1237
  }
1201
1238
  return intersections;
1202
1239
  }
1203
- function cancelPointer(intersections) {
1240
+ function cancelPointer(intersections, pointerId) {
1204
1241
  const { internal } = store.getState();
1205
- for (const hoveredObj of internal.hovered.values()) {
1242
+ const pid = pointerId ?? DEFAULT_POINTER_ID;
1243
+ const pointerState = internal.pointerMap.get(pid);
1244
+ if (!pointerState) return;
1245
+ for (const [hoveredId, hoveredObj] of pointerState.hovered) {
1206
1246
  if (!intersections.length || !intersections.find(
1207
1247
  (hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
1208
1248
  )) {
1209
1249
  const eventObject = hoveredObj.eventObject;
1210
1250
  const instance = eventObject.__r3f;
1211
- internal.hovered.delete(makeId(hoveredObj));
1251
+ pointerState.hovered.delete(hoveredId);
1212
1252
  if (instance?.eventCount) {
1213
1253
  const handlers = instance.handlers;
1214
1254
  const data = { ...hoveredObj, intersections };
@@ -1237,41 +1277,118 @@ function createEvents(store) {
1237
1277
  instance?.handlers.onDropMissed?.(event);
1238
1278
  }
1239
1279
  }
1280
+ function cleanupPointer(pointerId) {
1281
+ const { internal } = store.getState();
1282
+ const pointerState = internal.pointerMap.get(pointerId);
1283
+ if (pointerState) {
1284
+ for (const [, hoveredObj] of pointerState.hovered) {
1285
+ const eventObject = hoveredObj.eventObject;
1286
+ const instance = eventObject.__r3f;
1287
+ if (instance?.eventCount) {
1288
+ const handlers = instance.handlers;
1289
+ const data = { ...hoveredObj, intersections: [] };
1290
+ handlers.onPointerOut?.(data);
1291
+ handlers.onPointerLeave?.(data);
1292
+ }
1293
+ }
1294
+ internal.pointerMap.delete(pointerId);
1295
+ }
1296
+ internal.pointerDirty.delete(pointerId);
1297
+ }
1298
+ function processDeferredPointer(event, pointerId) {
1299
+ const state = store.getState();
1300
+ const { onPointerMissed, onDragOverMissed, internal } = state;
1301
+ if (!state.events.enabled) return;
1302
+ const filter = filterPointerEvents;
1303
+ const hits = intersect(event, filter);
1304
+ cancelPointer(hits, pointerId);
1305
+ function onIntersect(data) {
1306
+ const eventObject = data.eventObject;
1307
+ const instance = eventObject.__r3f;
1308
+ if (!instance?.eventCount) return;
1309
+ const handlers = instance.handlers;
1310
+ if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1311
+ const id = makeId(data);
1312
+ const pointerState = getPointerState(internal, pointerId);
1313
+ const hoveredItem = pointerState.hovered.get(id);
1314
+ if (!hoveredItem) {
1315
+ pointerState.hovered.set(id, data);
1316
+ handlers.onPointerOver?.(data);
1317
+ handlers.onPointerEnter?.(data);
1318
+ } else if (hoveredItem.stopped) {
1319
+ data.stopPropagation();
1320
+ }
1321
+ }
1322
+ handlers.onPointerMove?.(data);
1323
+ }
1324
+ handleIntersects(hits, event, 0, onIntersect);
1325
+ }
1240
1326
  function handlePointer(name) {
1241
1327
  switch (name) {
1242
1328
  case "onPointerLeave":
1243
- case "onPointerCancel":
1244
1329
  case "onDragLeave":
1245
1330
  return () => cancelPointer([]);
1331
+ // Global cancel of these events
1332
+ case "onPointerCancel":
1333
+ return (event) => {
1334
+ const pointerId = getPointerId(event);
1335
+ cleanupPointer(pointerId);
1336
+ };
1246
1337
  case "onLostPointerCapture":
1247
1338
  return (event) => {
1248
1339
  const { internal } = store.getState();
1249
- if ("pointerId" in event && internal.capturedMap.has(event.pointerId)) {
1340
+ const pointerId = getPointerId(event);
1341
+ const pointerState = internal.pointerMap.get(pointerId);
1342
+ if (pointerState?.captured.size) {
1250
1343
  requestAnimationFrame(() => {
1251
- if (internal.capturedMap.has(event.pointerId)) {
1252
- internal.capturedMap.delete(event.pointerId);
1253
- cancelPointer([]);
1344
+ const pointerState2 = internal.pointerMap.get(pointerId);
1345
+ if (pointerState2?.captured.size) {
1346
+ pointerState2.captured.clear();
1254
1347
  }
1348
+ cancelPointer([], pointerId);
1255
1349
  });
1256
1350
  }
1257
1351
  };
1258
1352
  }
1259
1353
  return function handleEvent(event) {
1260
1354
  const state = store.getState();
1261
- const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
1355
+ const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
1356
+ const pointerId = getPointerId(event);
1262
1357
  internal.lastEvent.current = event;
1263
- if (!state.events.enabled) return;
1358
+ if (!events.enabled) return;
1264
1359
  const isPointerMove = name === "onPointerMove";
1265
1360
  const isDragOver = name === "onDragOver";
1266
1361
  const isDrop = name === "onDrop";
1267
1362
  const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
1363
+ const isPointerDown = name === "onPointerDown";
1364
+ const isPointerUp = name === "onPointerUp";
1365
+ const isWheel = name === "onWheel";
1366
+ const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
1367
+ if (isPointerMove && canDeferRaycasts) {
1368
+ events.compute?.(event, state);
1369
+ internal.pointerDirty.set(pointerId, event);
1370
+ return;
1371
+ }
1372
+ if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
1373
+ events.compute?.(event, state);
1374
+ internal.pointerDirty.set(pointerId, event);
1375
+ return;
1376
+ }
1377
+ if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
1378
+ const deferredEvent = internal.pointerDirty.get(pointerId);
1379
+ internal.pointerDirty.delete(pointerId);
1380
+ processDeferredPointer(deferredEvent, pointerId);
1381
+ }
1268
1382
  const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
1269
1383
  const hits = intersect(event, filter);
1270
- const delta = isClickEvent ? calculateDistance(event) : 0;
1271
- if (name === "onPointerDown") {
1272
- internal.initialClick = [event.offsetX, event.offsetY];
1273
- internal.initialHits = hits.map((hit) => hit.eventObject);
1274
- }
1384
+ const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
1385
+ if (isPointerDown) {
1386
+ const pointerState2 = getPointerState(internal, pointerId);
1387
+ pointerState2.initialClick = [event.offsetX, event.offsetY];
1388
+ pointerState2.initialHits = hits.map((hit) => hit.eventObject);
1389
+ }
1390
+ const pointerState = internal.pointerMap.get(pointerId);
1391
+ const initialHits = pointerState?.initialHits ?? [];
1275
1392
  if (isClickEvent && !hits.length) {
1276
1393
  if (delta <= 2) {
1277
1394
  pointerMissed(event, internal.interaction);
@@ -1286,7 +1403,9 @@ function createEvents(store) {
1286
1403
  dropMissed(event, internal.interaction);
1287
1404
  if (onDropMissed) onDropMissed(event);
1288
1405
  }
1289
- if (isPointerMove || isDragOver) cancelPointer(hits);
1406
+ if (isPointerMove || isDragOver) {
1407
+ cancelPointer(hits, pointerId);
1408
+ }
1290
1409
  function onIntersect(data) {
1291
1410
  const eventObject = data.eventObject;
1292
1411
  const instance = eventObject.__r3f;
@@ -1295,9 +1414,10 @@ function createEvents(store) {
1295
1414
  if (isPointerMove) {
1296
1415
  if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1297
1416
  const id = makeId(data);
1298
- const hoveredItem = internal.hovered.get(id);
1417
+ const pointerState2 = getPointerState(internal, pointerId);
1418
+ const hoveredItem = pointerState2.hovered.get(id);
1299
1419
  if (!hoveredItem) {
1300
- internal.hovered.set(id, data);
1420
+ pointerState2.hovered.set(id, data);
1301
1421
  handlers.onPointerOver?.(data);
1302
1422
  handlers.onPointerEnter?.(data);
1303
1423
  } else if (hoveredItem.stopped) {
@@ -1307,9 +1427,10 @@ function createEvents(store) {
1307
1427
  handlers.onPointerMove?.(data);
1308
1428
  } else if (isDragOver) {
1309
1429
  const id = makeId(data);
1310
- const hoveredItem = internal.hovered.get(id);
1430
+ const pointerState2 = getPointerState(internal, pointerId);
1431
+ const hoveredItem = pointerState2.hovered.get(id);
1311
1432
  if (!hoveredItem) {
1312
- internal.hovered.set(id, data);
1433
+ pointerState2.hovered.set(id, data);
1313
1434
  handlers.onDragOverEnter?.(data);
1314
1435
  } else if (hoveredItem.stopped) {
1315
1436
  data.stopPropagation();
@@ -1320,18 +1441,18 @@ function createEvents(store) {
1320
1441
  } else {
1321
1442
  const handler = handlers[name];
1322
1443
  if (handler) {
1323
- if (!isClickEvent || internal.initialHits.includes(eventObject)) {
1444
+ if (!isClickEvent || initialHits.includes(eventObject)) {
1324
1445
  pointerMissed(
1325
1446
  event,
1326
- internal.interaction.filter((object) => !internal.initialHits.includes(object))
1447
+ internal.interaction.filter((object) => !initialHits.includes(object))
1327
1448
  );
1328
1449
  handler(data);
1329
1450
  }
1330
1451
  } else {
1331
- if (isClickEvent && internal.initialHits.includes(eventObject)) {
1452
+ if (isClickEvent && initialHits.includes(eventObject)) {
1332
1453
  pointerMissed(
1333
1454
  event,
1334
- internal.interaction.filter((object) => !internal.initialHits.includes(object))
1455
+ internal.interaction.filter((object) => !initialHits.includes(object))
1335
1456
  );
1336
1457
  }
1337
1458
  }
@@ -1340,7 +1461,15 @@ function createEvents(store) {
1340
1461
  handleIntersects(hits, event, delta, onIntersect);
1341
1462
  };
1342
1463
  }
1343
- return { handlePointer };
1464
+ function flushDeferredPointers() {
1465
+ const { internal, events } = store.getState();
1466
+ if (!events.frameTimedRaycasts) return;
1467
+ for (const [pointerId, event] of internal.pointerDirty) {
1468
+ processDeferredPointer(event, pointerId);
1469
+ }
1470
+ internal.pointerDirty.clear();
1471
+ }
1472
+ return { handlePointer, flushDeferredPointers, processDeferredPointer };
1344
1473
  }
1345
1474
  const DOM_EVENTS = {
1346
1475
  onClick: ["click", false],
@@ -1359,10 +1488,15 @@ const DOM_EVENTS = {
1359
1488
  onLostPointerCapture: ["lostpointercapture", true]
1360
1489
  };
1361
1490
  function createPointerEvents(store) {
1362
- const { handlePointer } = createEvents(store);
1491
+ const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
1492
+ let nextXRPointerId = XR_POINTER_ID_START;
1493
+ const xrPointers = /* @__PURE__ */ new Map();
1363
1494
  return {
1364
1495
  priority: 1,
1365
1496
  enabled: true,
1497
+ frameTimedRaycasts: true,
1498
+ alwaysFireOnScroll: true,
1499
+ updateOnFrame: false,
1366
1500
  compute(event, state) {
1367
1501
  state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
1368
1502
  state.raycaster.setFromCamera(state.pointer, state.camera);
@@ -1372,9 +1506,30 @@ function createPointerEvents(store) {
1372
1506
  (acc, key) => ({ ...acc, [key]: handlePointer(key) }),
1373
1507
  {}
1374
1508
  ),
1375
- update: () => {
1509
+ update: (pointerId) => {
1510
+ const { events, internal } = store.getState();
1511
+ if (!events.handlers) return;
1512
+ if (pointerId !== void 0) {
1513
+ const event = internal.pointerDirty.get(pointerId);
1514
+ if (event) {
1515
+ internal.pointerDirty.delete(pointerId);
1516
+ processDeferredPointer(event, pointerId);
1517
+ } else if (internal.lastEvent?.current) {
1518
+ processDeferredPointer(internal.lastEvent.current, pointerId);
1519
+ }
1520
+ } else {
1521
+ flushDeferredPointers();
1522
+ if (internal.lastEvent?.current) {
1523
+ events.handlers.onPointerMove(internal.lastEvent.current);
1524
+ }
1525
+ }
1526
+ },
1527
+ flush: () => {
1376
1528
  const { events, internal } = store.getState();
1377
- if (internal.lastEvent?.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current);
1529
+ flushDeferredPointers();
1530
+ if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
1531
+ events.handlers.onPointerMove(internal.lastEvent.current);
1532
+ }
1378
1533
  },
1379
1534
  connect: (target) => {
1380
1535
  const { set, events } = store.getState();
@@ -1400,6 +1555,32 @@ function createPointerEvents(store) {
1400
1555
  }
1401
1556
  set((state) => ({ events: { ...state.events, connected: void 0 } }));
1402
1557
  }
1558
+ },
1559
+ registerPointer: (config) => {
1560
+ const pointerId = nextXRPointerId++;
1561
+ xrPointers.set(pointerId, config);
1562
+ const { internal } = store.getState();
1563
+ getPointerState(internal, pointerId);
1564
+ return pointerId;
1565
+ },
1566
+ unregisterPointer: (pointerId) => {
1567
+ xrPointers.delete(pointerId);
1568
+ const { internal } = store.getState();
1569
+ const pointerState = internal.pointerMap.get(pointerId);
1570
+ if (pointerState) {
1571
+ for (const [, hoveredObj] of pointerState.hovered) {
1572
+ const eventObject = hoveredObj.eventObject;
1573
+ const instance = eventObject.__r3f;
1574
+ if (instance?.eventCount) {
1575
+ const handlers = instance.handlers;
1576
+ const data = { ...hoveredObj, intersections: [] };
1577
+ handlers.onPointerOut?.(data);
1578
+ handlers.onPointerLeave?.(data);
1579
+ }
1580
+ }
1581
+ internal.pointerMap.delete(pointerId);
1582
+ }
1583
+ internal.pointerDirty.delete(pointerId);
1403
1584
  }
1404
1585
  };
1405
1586
  }
@@ -2530,7 +2711,14 @@ const createStore = (invalidate, advance) => {
2530
2711
  frustum: new webgpu.Frustum(),
2531
2712
  autoUpdateFrustum: true,
2532
2713
  raycaster: null,
2533
- events: { priority: 1, enabled: true, connected: false },
2714
+ events: {
2715
+ priority: 1,
2716
+ enabled: true,
2717
+ connected: false,
2718
+ frameTimedRaycasts: true,
2719
+ alwaysFireOnScroll: true,
2720
+ updateOnFrame: false
2721
+ },
2534
2722
  scene: null,
2535
2723
  rootScene: null,
2536
2724
  xr: null,
@@ -2621,11 +2809,13 @@ const createStore = (invalidate, advance) => {
2621
2809
  },
2622
2810
  setError: (error) => set(() => ({ error })),
2623
2811
  error: null,
2624
- //* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
2812
+ //* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
2625
2813
  uniforms: {},
2626
2814
  nodes: {},
2815
+ buffers: {},
2816
+ gpuStorage: {},
2627
2817
  textures: /* @__PURE__ */ new Map(),
2628
- postProcessing: null,
2818
+ renderPipeline: null,
2629
2819
  passes: {},
2630
2820
  _hmrVersion: 0,
2631
2821
  _sizeImperative: false,
@@ -2634,12 +2824,16 @@ const createStore = (invalidate, advance) => {
2634
2824
  internal: {
2635
2825
  // Events
2636
2826
  interaction: [],
2637
- hovered: /* @__PURE__ */ new Map(),
2638
2827
  subscribers: [],
2828
+ // Per-pointer state (new unified structure)
2829
+ pointerMap: /* @__PURE__ */ new Map(),
2830
+ pointerDirty: /* @__PURE__ */ new Map(),
2831
+ lastEvent: React__namespace.createRef(),
2832
+ // Deprecated but kept for backwards compatibility
2833
+ hovered: /* @__PURE__ */ new Map(),
2639
2834
  initialClick: [0, 0],
2640
2835
  initialHits: [],
2641
2836
  capturedMap: /* @__PURE__ */ new Map(),
2642
- lastEvent: React__namespace.createRef(),
2643
2837
  // Visibility tracking (onFramed, onOccluded, onVisible)
2644
2838
  visibilityRegistry: /* @__PURE__ */ new Map(),
2645
2839
  // Occlusion system (WebGPU only)
@@ -15071,6 +15265,12 @@ function createRoot(canvas) {
15071
15265
  } else if (!state.internal.actualRenderer) {
15072
15266
  renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
15073
15267
  if (!renderer.hasInitialized?.()) {
15268
+ const size2 = computeInitialSize(canvas, propsSize);
15269
+ if (size2.width > 0 && size2.height > 0) {
15270
+ const pixelRatio = calculateDpr(dpr);
15271
+ canvas.width = size2.width * pixelRatio;
15272
+ canvas.height = size2.height * pixelRatio;
15273
+ }
15074
15274
  await renderer.init();
15075
15275
  }
15076
15276
  const backend = renderer.backend;
@@ -15272,6 +15472,18 @@ function createRoot(canvas) {
15272
15472
  system: true
15273
15473
  }
15274
15474
  );
15475
+ const unregisterEventsFlush = scheduler.register(
15476
+ () => {
15477
+ const state2 = store.getState();
15478
+ state2.events.flush?.();
15479
+ },
15480
+ {
15481
+ id: `${newRootId}_events`,
15482
+ rootId: newRootId,
15483
+ phase: "input",
15484
+ system: true
15485
+ }
15486
+ );
15275
15487
  const unregisterFrustum = scheduler.register(
15276
15488
  () => {
15277
15489
  const state2 = store.getState();
@@ -15306,7 +15518,7 @@ function createRoot(canvas) {
15306
15518
  const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
15307
15519
  if (userHandlesRender || state2.internal.priority) return;
15308
15520
  try {
15309
- if (state2.postProcessing?.render) state2.postProcessing.render();
15521
+ if (state2.renderPipeline?.render) state2.renderPipeline.render();
15310
15522
  else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
15311
15523
  } catch (error) {
15312
15524
  state2.setError(error instanceof Error ? error : new Error(String(error)));
@@ -15331,6 +15543,7 @@ function createRoot(canvas) {
15331
15543
  unregisterRoot: () => {
15332
15544
  unregisterRoot();
15333
15545
  unregisterCanvasTarget();
15546
+ unregisterEventsFlush();
15334
15547
  unregisterFrustum();
15335
15548
  unregisterVisibility();
15336
15549
  unregisterRender();
@@ -15496,9 +15709,13 @@ function PortalInner({ state = {}, children, container }) {
15496
15709
  const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
15497
15710
  const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
15498
15711
  onMutate(previousRoot.getState());
15499
- previousRoot.subscribe(onMutate);
15500
15712
  return store;
15501
15713
  }, [previousRoot, container]);
15714
+ useIsomorphicLayoutEffect(() => {
15715
+ const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
15716
+ const unsubscribe = previousRoot.subscribe(onMutate);
15717
+ return unsubscribe;
15718
+ }, [previousRoot, usePortalStore]);
15502
15719
  return (
15503
15720
  // @ts-ignore, reconciler types are not maintained
15504
15721
  /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
@@ -15719,6 +15936,7 @@ function CanvasImpl({
15719
15936
  queueMicrotask(() => {
15720
15937
  const rootEntry = _roots.get(canvas);
15721
15938
  if (rootEntry?.store) {
15939
+ console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
15722
15940
  rootEntry.store.setState((state) => ({
15723
15941
  nodes: {},
15724
15942
  uniforms: {},
@@ -15730,8 +15948,7 @@ function CanvasImpl({
15730
15948
  if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
15731
15949
  const hot = undefined;
15732
15950
  hot.on("vite:afterUpdate", handleHMR);
15733
- return () => hot.dispose?.(() => {
15734
- });
15951
+ return () => hot.off?.("vite:afterUpdate", handleHMR);
15735
15952
  }
15736
15953
  if (typeof module !== "undefined" && module.hot) {
15737
15954
  const hot = module.hot;
@@ -15830,6 +16047,8 @@ function createScopedStore(data) {
15830
16047
  function createLazyCreatorState(state) {
15831
16048
  let _uniforms = null;
15832
16049
  let _nodes = null;
16050
+ let _buffers = null;
16051
+ let _gpuStorage = null;
15833
16052
  return Object.create(state, {
15834
16053
  uniforms: {
15835
16054
  get() {
@@ -15840,6 +16059,16 @@ function createLazyCreatorState(state) {
15840
16059
  get() {
15841
16060
  return _nodes ?? (_nodes = createScopedStore(state.nodes));
15842
16061
  }
16062
+ },
16063
+ buffers: {
16064
+ get() {
16065
+ return _buffers ?? (_buffers = createScopedStore(state.buffers));
16066
+ }
16067
+ },
16068
+ gpuStorage: {
16069
+ get() {
16070
+ return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
16071
+ }
15843
16072
  }
15844
16073
  });
15845
16074
  }
@@ -15922,6 +16151,10 @@ function vectorize(inObject) {
15922
16151
  if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
15923
16152
  if (obj.isMatrix3 || obj.isMatrix4) return inObject;
15924
16153
  if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
16154
+ if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
16155
+ const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
16156
+ return new webgpu.Color(obj.r * scale, obj.g * scale, obj.b * scale);
16157
+ }
15925
16158
  if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
15926
16159
  if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
15927
16160
  return new webgpu.Vector4(obj.x, obj.y, obj.z, obj.w);
@@ -16377,7 +16610,351 @@ function useLocalNodes(creator) {
16377
16610
  }, [store, creator, uniforms, nodes, textures, hmrVersion]);
16378
16611
  }
16379
16612
 
16380
- function usePostProcessing(mainCB, setupCB) {
16613
+ const isBufferLike = (value) => {
16614
+ if (value === null || typeof value !== "object") return false;
16615
+ if (ArrayBuffer.isView(value)) return true;
16616
+ if ("isBufferAttribute" in value) return true;
16617
+ if ("uuid" in value || "nodeType" in value) return true;
16618
+ return false;
16619
+ };
16620
+ const disposeBuffer = (buffer) => {
16621
+ if (buffer === null || typeof buffer !== "object") return;
16622
+ if ("dispose" in buffer && typeof buffer.dispose === "function") {
16623
+ buffer.dispose();
16624
+ }
16625
+ };
16626
+ function useBuffers(creatorOrScope, scope) {
16627
+ const store = useStore();
16628
+ const removeBuffers = React.useCallback(
16629
+ (names, targetScope) => {
16630
+ const nameArray = Array.isArray(names) ? names : [names];
16631
+ store.setState((state) => {
16632
+ if (targetScope) {
16633
+ const currentScope = { ...state.buffers[targetScope] };
16634
+ for (const name of nameArray) delete currentScope[name];
16635
+ return { buffers: { ...state.buffers, [targetScope]: currentScope } };
16636
+ }
16637
+ const buffers2 = { ...state.buffers };
16638
+ for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
16639
+ return { buffers: buffers2 };
16640
+ });
16641
+ },
16642
+ [store]
16643
+ );
16644
+ const clearBuffers = React.useCallback(
16645
+ (targetScope) => {
16646
+ store.setState((state) => {
16647
+ if (targetScope && targetScope !== "root") {
16648
+ const { [targetScope]: _, ...rest } = state.buffers;
16649
+ return { buffers: rest };
16650
+ }
16651
+ if (targetScope === "root") {
16652
+ const buffers2 = {};
16653
+ for (const [key, value] of Object.entries(state.buffers)) {
16654
+ if (!isBufferLike(value)) buffers2[key] = value;
16655
+ }
16656
+ return { buffers: buffers2 };
16657
+ }
16658
+ return { buffers: {} };
16659
+ });
16660
+ },
16661
+ [store]
16662
+ );
16663
+ const rebuildBuffers = React.useCallback(
16664
+ (targetScope) => {
16665
+ store.setState((state) => {
16666
+ let newBuffers = state.buffers;
16667
+ if (targetScope && targetScope !== "root") {
16668
+ const { [targetScope]: _, ...rest } = state.buffers;
16669
+ newBuffers = rest;
16670
+ } else if (targetScope === "root") {
16671
+ newBuffers = {};
16672
+ for (const [key, value] of Object.entries(state.buffers)) {
16673
+ if (!isBufferLike(value)) newBuffers[key] = value;
16674
+ }
16675
+ } else {
16676
+ newBuffers = {};
16677
+ }
16678
+ return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
16679
+ });
16680
+ },
16681
+ [store]
16682
+ );
16683
+ const disposeBuffers = React.useCallback(
16684
+ (names, targetScope) => {
16685
+ const nameArray = Array.isArray(names) ? names : [names];
16686
+ const state = store.getState();
16687
+ for (const name of nameArray) {
16688
+ const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
16689
+ if (buffer && isBufferLike(buffer)) {
16690
+ disposeBuffer(buffer);
16691
+ }
16692
+ }
16693
+ removeBuffers(names, targetScope);
16694
+ },
16695
+ [store, removeBuffers]
16696
+ );
16697
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16698
+ const storeBuffers = useThree((s) => s.buffers);
16699
+ const hmrVersion = useThree((s) => s._hmrVersion);
16700
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16701
+ const readerDep = isReader ? storeBuffers : null;
16702
+ const creatorDep = isReader ? null : hmrVersion;
16703
+ const buffers = React.useMemo(() => {
16704
+ if (creatorOrScope === void 0) {
16705
+ return storeBuffers;
16706
+ }
16707
+ if (typeof creatorOrScope === "string") {
16708
+ const scopeData = storeBuffers[creatorOrScope];
16709
+ if (scopeData && !isBufferLike(scopeData)) return scopeData;
16710
+ return {};
16711
+ }
16712
+ const state = store.getState();
16713
+ const set = store.setState;
16714
+ const creator = creatorOrScope;
16715
+ const wrappedState = createLazyCreatorState(state);
16716
+ const created = creator(wrappedState);
16717
+ const result = {};
16718
+ let hasNewBuffers = false;
16719
+ if (scope) {
16720
+ const currentScope = state.buffers[scope] ?? {};
16721
+ for (const [name, buffer] of Object.entries(created)) {
16722
+ if (currentScope[name]) {
16723
+ result[name] = currentScope[name];
16724
+ } else {
16725
+ if ("setName" in buffer && typeof buffer.setName === "function") {
16726
+ buffer.setName(`${scope}.${name}`);
16727
+ }
16728
+ result[name] = buffer;
16729
+ hasNewBuffers = true;
16730
+ }
16731
+ }
16732
+ if (hasNewBuffers) {
16733
+ set((s) => ({
16734
+ buffers: {
16735
+ ...s.buffers,
16736
+ [scope]: { ...s.buffers[scope], ...result }
16737
+ }
16738
+ }));
16739
+ }
16740
+ return result;
16741
+ }
16742
+ for (const [name, buffer] of Object.entries(created)) {
16743
+ const existing = state.buffers[name];
16744
+ if (existing && isBufferLike(existing)) {
16745
+ result[name] = existing;
16746
+ } else {
16747
+ if ("setName" in buffer && typeof buffer.setName === "function") {
16748
+ buffer.setName(name);
16749
+ }
16750
+ result[name] = buffer;
16751
+ hasNewBuffers = true;
16752
+ }
16753
+ }
16754
+ if (hasNewBuffers) {
16755
+ set((s) => ({ buffers: { ...s.buffers, ...result } }));
16756
+ }
16757
+ return result;
16758
+ }, [store, scopeDep, readerDep, creatorDep]);
16759
+ return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
16760
+ }
16761
+ function rebuildAllBuffers(store, scope) {
16762
+ store.setState((state) => {
16763
+ let newBuffers = state.buffers;
16764
+ if (scope && scope !== "root") {
16765
+ const { [scope]: _, ...rest } = state.buffers;
16766
+ newBuffers = rest;
16767
+ } else if (scope === "root") {
16768
+ newBuffers = {};
16769
+ for (const [key, value] of Object.entries(state.buffers)) {
16770
+ if (!isBufferLike(value)) newBuffers[key] = value;
16771
+ }
16772
+ } else {
16773
+ newBuffers = {};
16774
+ }
16775
+ return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
16776
+ });
16777
+ }
16778
+
16779
+ const isStorageLike = (value) => {
16780
+ if (value === null || typeof value !== "object") return false;
16781
+ if ("isTexture" in value) return true;
16782
+ if ("isData3DTexture" in value) return true;
16783
+ if ("uuid" in value || "nodeType" in value) return true;
16784
+ return false;
16785
+ };
16786
+ const disposeStorage = (storage) => {
16787
+ if (storage === null || typeof storage !== "object") return;
16788
+ if ("dispose" in storage && typeof storage.dispose === "function") {
16789
+ storage.dispose();
16790
+ }
16791
+ };
16792
+ function useGPUStorage(creatorOrScope, scope) {
16793
+ const store = useStore();
16794
+ const removeStorage = React.useCallback(
16795
+ (names, targetScope) => {
16796
+ const nameArray = Array.isArray(names) ? names : [names];
16797
+ store.setState((state) => {
16798
+ if (targetScope) {
16799
+ const currentScope = { ...state.gpuStorage[targetScope] };
16800
+ for (const name of nameArray) delete currentScope[name];
16801
+ return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
16802
+ }
16803
+ const gpuStorage2 = { ...state.gpuStorage };
16804
+ for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
16805
+ return { gpuStorage: gpuStorage2 };
16806
+ });
16807
+ },
16808
+ [store]
16809
+ );
16810
+ const clearStorage = React.useCallback(
16811
+ (targetScope) => {
16812
+ store.setState((state) => {
16813
+ if (targetScope && targetScope !== "root") {
16814
+ const { [targetScope]: _, ...rest } = state.gpuStorage;
16815
+ return { gpuStorage: rest };
16816
+ }
16817
+ if (targetScope === "root") {
16818
+ const gpuStorage2 = {};
16819
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16820
+ if (!isStorageLike(value)) gpuStorage2[key] = value;
16821
+ }
16822
+ return { gpuStorage: gpuStorage2 };
16823
+ }
16824
+ return { gpuStorage: {} };
16825
+ });
16826
+ },
16827
+ [store]
16828
+ );
16829
+ const rebuildStorage = React.useCallback(
16830
+ (targetScope) => {
16831
+ store.setState((state) => {
16832
+ let newStorage = state.gpuStorage;
16833
+ if (targetScope && targetScope !== "root") {
16834
+ const { [targetScope]: _, ...rest } = state.gpuStorage;
16835
+ newStorage = rest;
16836
+ } else if (targetScope === "root") {
16837
+ newStorage = {};
16838
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16839
+ if (!isStorageLike(value)) newStorage[key] = value;
16840
+ }
16841
+ } else {
16842
+ newStorage = {};
16843
+ }
16844
+ return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
16845
+ });
16846
+ },
16847
+ [store]
16848
+ );
16849
+ const disposeStorageFn = React.useCallback(
16850
+ (names, targetScope) => {
16851
+ const nameArray = Array.isArray(names) ? names : [names];
16852
+ const state = store.getState();
16853
+ for (const name of nameArray) {
16854
+ const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
16855
+ if (storage && isStorageLike(storage)) {
16856
+ disposeStorage(storage);
16857
+ }
16858
+ }
16859
+ removeStorage(names, targetScope);
16860
+ },
16861
+ [store, removeStorage]
16862
+ );
16863
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16864
+ const storeStorage = useThree((s) => s.gpuStorage);
16865
+ const hmrVersion = useThree((s) => s._hmrVersion);
16866
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16867
+ const readerDep = isReader ? storeStorage : null;
16868
+ const creatorDep = isReader ? null : hmrVersion;
16869
+ const gpuStorage = React.useMemo(() => {
16870
+ if (creatorOrScope === void 0) {
16871
+ return storeStorage;
16872
+ }
16873
+ if (typeof creatorOrScope === "string") {
16874
+ const scopeData = storeStorage[creatorOrScope];
16875
+ if (scopeData && !isStorageLike(scopeData)) return scopeData;
16876
+ return {};
16877
+ }
16878
+ const state = store.getState();
16879
+ const set = store.setState;
16880
+ const creator = creatorOrScope;
16881
+ const wrappedState = createLazyCreatorState(state);
16882
+ const created = creator(wrappedState);
16883
+ const result = {};
16884
+ let hasNewStorage = false;
16885
+ if (scope) {
16886
+ const currentScope = state.gpuStorage[scope] ?? {};
16887
+ for (const [name, storage] of Object.entries(created)) {
16888
+ if (currentScope[name]) {
16889
+ result[name] = currentScope[name];
16890
+ } else {
16891
+ if ("setName" in storage && typeof storage.setName === "function") {
16892
+ storage.setName(`${scope}.${name}`);
16893
+ }
16894
+ if ("name" in storage && typeof storage.name === "string") {
16895
+ storage.name = `${scope}.${name}`;
16896
+ }
16897
+ result[name] = storage;
16898
+ hasNewStorage = true;
16899
+ }
16900
+ }
16901
+ if (hasNewStorage) {
16902
+ set((s) => ({
16903
+ gpuStorage: {
16904
+ ...s.gpuStorage,
16905
+ [scope]: { ...s.gpuStorage[scope], ...result }
16906
+ }
16907
+ }));
16908
+ }
16909
+ return result;
16910
+ }
16911
+ for (const [name, storage] of Object.entries(created)) {
16912
+ const existing = state.gpuStorage[name];
16913
+ if (existing && isStorageLike(existing)) {
16914
+ result[name] = existing;
16915
+ } else {
16916
+ if ("setName" in storage && typeof storage.setName === "function") {
16917
+ storage.setName(name);
16918
+ }
16919
+ if ("name" in storage && typeof storage.name === "string") {
16920
+ storage.name = name;
16921
+ }
16922
+ result[name] = storage;
16923
+ hasNewStorage = true;
16924
+ }
16925
+ }
16926
+ if (hasNewStorage) {
16927
+ set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
16928
+ }
16929
+ return result;
16930
+ }, [store, scopeDep, readerDep, creatorDep]);
16931
+ return {
16932
+ ...gpuStorage,
16933
+ removeStorage,
16934
+ clearStorage,
16935
+ rebuildStorage,
16936
+ disposeStorage: disposeStorageFn
16937
+ };
16938
+ }
16939
+ function rebuildAllStorage(store, scope) {
16940
+ store.setState((state) => {
16941
+ let newStorage = state.gpuStorage;
16942
+ if (scope && scope !== "root") {
16943
+ const { [scope]: _, ...rest } = state.gpuStorage;
16944
+ newStorage = rest;
16945
+ } else if (scope === "root") {
16946
+ newStorage = {};
16947
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16948
+ if (!isStorageLike(value)) newStorage[key] = value;
16949
+ }
16950
+ } else {
16951
+ newStorage = {};
16952
+ }
16953
+ return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
16954
+ });
16955
+ }
16956
+
16957
+ function useRenderPipeline(mainCB, setupCB) {
16381
16958
  const store = useStore();
16382
16959
  const { scene, camera, renderer, isLegacy } = useThree();
16383
16960
  const callbacksRanRef = React.useRef(false);
@@ -16396,7 +16973,7 @@ function usePostProcessing(mainCB, setupCB) {
16396
16973
  }, [store]);
16397
16974
  const reset = React.useCallback(() => {
16398
16975
  store.setState({
16399
- postProcessing: null,
16976
+ renderPipeline: null,
16400
16977
  passes: {}
16401
16978
  });
16402
16979
  callbacksRanRef.current = false;
@@ -16409,13 +16986,13 @@ function usePostProcessing(mainCB, setupCB) {
16409
16986
  }, []);
16410
16987
  React.useLayoutEffect(() => {
16411
16988
  if (isLegacy) {
16412
- throw new Error("usePostProcessing is only available with WebGPU renderer. Set renderer prop on Canvas.");
16989
+ throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
16413
16990
  }
16414
16991
  if (!renderer || !scene || !camera) return;
16415
16992
  const state = store.getState();
16416
16993
  const set = store.setState;
16417
16994
  try {
16418
- let pp = state.postProcessing;
16995
+ let pp = state.renderPipeline;
16419
16996
  let currentPasses = { ...state.passes };
16420
16997
  let justCreatedPP = false;
16421
16998
  if (!pp) {
@@ -16432,7 +17009,7 @@ function usePostProcessing(mainCB, setupCB) {
16432
17009
  }
16433
17010
  currentPasses.scenePass = scenePass;
16434
17011
  if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
16435
- set({ postProcessing: pp, passes: currentPasses });
17012
+ set({ renderPipeline: pp, passes: currentPasses });
16436
17013
  const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
16437
17014
  if (shouldRunCallbacks) {
16438
17015
  if (setupCBRef.current) {
@@ -16454,19 +17031,19 @@ function usePostProcessing(mainCB, setupCB) {
16454
17031
  callbacksRanRef.current = true;
16455
17032
  }
16456
17033
  } catch (error) {
16457
- console.error("[usePostProcessing] Setup error:", error);
17034
+ console.error("[useRenderPipeline] Setup error:", error);
16458
17035
  }
16459
17036
  }, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
16460
17037
  const passes = useThree((s) => s.passes);
16461
- const postProcessing = useThree((s) => s.postProcessing);
17038
+ const renderPipeline = useThree((s) => s.renderPipeline);
16462
17039
  return {
16463
17040
  passes,
16464
- postProcessing,
17041
+ renderPipeline,
16465
17042
  clearPasses,
16466
17043
  reset,
16467
17044
  rebuild,
16468
- // isReady indicates if PostProcessing is configured and ready for rendering
16469
- isReady: postProcessing !== null
17045
+ // isReady indicates if RenderPipeline is configured and ready for rendering
17046
+ isReady: renderPipeline !== null
16470
17047
  };
16471
17048
  }
16472
17049
 
@@ -16543,7 +17120,9 @@ exports.isVectorLike = isVectorLike;
16543
17120
  exports.once = once;
16544
17121
  exports.prepare = prepare;
16545
17122
  exports.presetsObj = presetsObj;
17123
+ exports.rebuildAllBuffers = rebuildAllBuffers;
16546
17124
  exports.rebuildAllNodes = rebuildAllNodes;
17125
+ exports.rebuildAllStorage = rebuildAllStorage;
16547
17126
  exports.rebuildAllUniforms = rebuildAllUniforms;
16548
17127
  exports.reconciler = reconciler;
16549
17128
  exports.registerPrimary = registerPrimary;
@@ -16556,8 +17135,10 @@ exports.unregisterPrimary = unregisterPrimary;
16556
17135
  exports.updateCamera = updateCamera;
16557
17136
  exports.updateFrustum = updateFrustum;
16558
17137
  exports.useBridge = useBridge;
17138
+ exports.useBuffers = useBuffers;
16559
17139
  exports.useEnvironment = useEnvironment;
16560
17140
  exports.useFrame = useFrame;
17141
+ exports.useGPUStorage = useGPUStorage;
16561
17142
  exports.useGraph = useGraph;
16562
17143
  exports.useInstanceHandle = useInstanceHandle;
16563
17144
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
@@ -16565,7 +17146,7 @@ exports.useLoader = useLoader;
16565
17146
  exports.useLocalNodes = useLocalNodes;
16566
17147
  exports.useMutableCallback = useMutableCallback;
16567
17148
  exports.useNodes = useNodes;
16568
- exports.usePostProcessing = usePostProcessing;
17149
+ exports.useRenderPipeline = useRenderPipeline;
16569
17150
  exports.useRenderTarget = useRenderTarget;
16570
17151
  exports.useStore = useStore;
16571
17152
  exports.useTexture = useTexture;