@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.
@@ -985,6 +985,9 @@ function applyProps(object, props) {
985
985
  else target.set(value);
986
986
  } else {
987
987
  root[key] = value;
988
+ if (key.endsWith("Node") && root.isMaterial) {
989
+ root.needsUpdate = true;
990
+ }
988
991
  if (rootState && rootState.renderer?.outputColorSpace === SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
989
992
  root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
990
993
  root[key].colorSpace = rootState.textureColorSpace;
@@ -1018,38 +1021,60 @@ function applyProps(object, props) {
1018
1021
  return object;
1019
1022
  }
1020
1023
 
1024
+ const DEFAULT_POINTER_ID = 0;
1025
+ const XR_POINTER_ID_START = 1e3;
1026
+ function getPointerState(internal, pointerId) {
1027
+ let state = internal.pointerMap.get(pointerId);
1028
+ if (!state) {
1029
+ state = {
1030
+ hovered: /* @__PURE__ */ new Map(),
1031
+ captured: /* @__PURE__ */ new Map(),
1032
+ initialClick: [0, 0],
1033
+ initialHits: []
1034
+ };
1035
+ internal.pointerMap.set(pointerId, state);
1036
+ }
1037
+ return state;
1038
+ }
1039
+ function getPointerId(event) {
1040
+ return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
1041
+ }
1021
1042
  function makeId(event) {
1022
1043
  return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
1023
1044
  }
1024
- function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
1025
- const captureData = captures.get(obj);
1045
+ function releaseInternalPointerCapture(internal, obj, pointerId) {
1046
+ const pointerState = internal.pointerMap.get(pointerId);
1047
+ if (!pointerState) return;
1048
+ const captureData = pointerState.captured.get(obj);
1026
1049
  if (captureData) {
1027
- captures.delete(obj);
1028
- if (captures.size === 0) {
1029
- capturedMap.delete(pointerId);
1030
- captureData.target.releasePointerCapture(pointerId);
1031
- }
1050
+ pointerState.captured.delete(obj);
1051
+ captureData.target.releasePointerCapture(pointerId);
1032
1052
  }
1033
1053
  }
1034
1054
  function removeInteractivity(store, object) {
1035
1055
  const { internal } = store.getState();
1036
1056
  internal.interaction = internal.interaction.filter((o) => o !== object);
1037
- internal.initialHits = internal.initialHits.filter((o) => o !== object);
1038
- internal.hovered.forEach((value, key) => {
1039
- if (value.eventObject === object || value.object === object) {
1040
- internal.hovered.delete(key);
1057
+ for (const [pointerId, pointerState] of internal.pointerMap) {
1058
+ pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
1059
+ pointerState.hovered.forEach((value, key) => {
1060
+ if (value.eventObject === object || value.object === object) {
1061
+ pointerState.hovered.delete(key);
1062
+ }
1063
+ });
1064
+ if (pointerState.captured.has(object)) {
1065
+ releaseInternalPointerCapture(internal, object, pointerId);
1041
1066
  }
1042
- });
1043
- internal.capturedMap.forEach((captures, pointerId) => {
1044
- releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
1045
- });
1067
+ }
1046
1068
  unregisterVisibility(store, object);
1047
1069
  }
1048
1070
  function createEvents(store) {
1049
- function calculateDistance(event) {
1071
+ function calculateDistance(event, pointerId) {
1050
1072
  const { internal } = store.getState();
1051
- const dx = event.offsetX - internal.initialClick[0];
1052
- const dy = event.offsetY - internal.initialClick[1];
1073
+ const pointerState = internal.pointerMap.get(pointerId);
1074
+ if (!pointerState) return 0;
1075
+ const [initialX, initialY] = pointerState.initialClick;
1076
+ const dx = event.offsetX - initialX;
1077
+ const dy = event.offsetY - initialY;
1053
1078
  return Math.round(Math.sqrt(dx * dx + dy * dy));
1054
1079
  }
1055
1080
  function filterPointerEvents(objects) {
@@ -1085,6 +1110,15 @@ function createEvents(store) {
1085
1110
  return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
1086
1111
  }
1087
1112
  let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
1113
+ const aInteractivePriority = a.object.userData?.interactivePriority;
1114
+ const bInteractivePriority = b.object.userData?.interactivePriority;
1115
+ if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
1116
+ if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
1117
+ if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
1118
+ if (aInteractivePriority !== bInteractivePriority) {
1119
+ return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
1120
+ }
1121
+ }
1088
1122
  const aState = getRootState(a.object);
1089
1123
  const bState = getRootState(b.object);
1090
1124
  const aPriority = aState?.events?.priority ?? 1;
@@ -1106,9 +1140,13 @@ function createEvents(store) {
1106
1140
  eventObject = eventObject.parent;
1107
1141
  }
1108
1142
  }
1109
- if ("pointerId" in event && state.internal.capturedMap.has(event.pointerId)) {
1110
- for (const captureData of state.internal.capturedMap.get(event.pointerId).values()) {
1111
- if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
1143
+ if ("pointerId" in event) {
1144
+ const pointerId = event.pointerId;
1145
+ const pointerState = state.internal.pointerMap.get(pointerId);
1146
+ if (pointerState?.captured.size) {
1147
+ for (const captureData of pointerState.captured.values()) {
1148
+ if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
1149
+ }
1112
1150
  }
1113
1151
  }
1114
1152
  return intersections;
@@ -1121,27 +1159,25 @@ function createEvents(store) {
1121
1159
  if (state) {
1122
1160
  const { raycaster, pointer, camera, internal } = state;
1123
1161
  const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
1124
- const hasPointerCapture = (id) => internal.capturedMap.get(id)?.has(hit.eventObject) ?? false;
1162
+ const hasPointerCapture = (id) => {
1163
+ const pointerState = internal.pointerMap.get(id);
1164
+ return pointerState?.captured.has(hit.eventObject) ?? false;
1165
+ };
1125
1166
  const setPointerCapture = (id) => {
1126
1167
  const captureData = { intersection: hit, target: event.target };
1127
- if (internal.capturedMap.has(id)) {
1128
- internal.capturedMap.get(id).set(hit.eventObject, captureData);
1129
- } else {
1130
- internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
1131
- }
1168
+ const pointerState = getPointerState(internal, id);
1169
+ pointerState.captured.set(hit.eventObject, captureData);
1132
1170
  event.target.setPointerCapture(id);
1133
1171
  };
1134
1172
  const releasePointerCapture = (id) => {
1135
- const captures = internal.capturedMap.get(id);
1136
- if (captures) {
1137
- releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
1138
- }
1173
+ releaseInternalPointerCapture(internal, hit.eventObject, id);
1139
1174
  };
1140
1175
  const extractEventProps = {};
1141
1176
  for (const prop in event) {
1142
1177
  const property = event[prop];
1143
1178
  if (typeof property !== "function") extractEventProps[prop] = property;
1144
1179
  }
1180
+ const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
1145
1181
  const raycastEvent = {
1146
1182
  ...hit,
1147
1183
  ...extractEventProps,
@@ -1152,18 +1188,19 @@ function createEvents(store) {
1152
1188
  unprojectedPoint,
1153
1189
  ray: raycaster.ray,
1154
1190
  camera,
1191
+ pointerId: eventPointerId,
1155
1192
  // Hijack stopPropagation, which just sets a flag
1156
1193
  stopPropagation() {
1157
- const capturesForPointer = "pointerId" in event && internal.capturedMap.get(event.pointerId);
1194
+ const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
1158
1195
  if (
1159
1196
  // ...if this pointer hasn't been captured
1160
- !capturesForPointer || // ... or if the hit object is capturing the pointer
1161
- capturesForPointer.has(hit.eventObject)
1197
+ !pointerState?.captured.size || // ... or if the hit object is capturing the pointer
1198
+ pointerState.captured.has(hit.eventObject)
1162
1199
  ) {
1163
1200
  raycastEvent.stopped = localState.stopped = true;
1164
- if (internal.hovered.size && Array.from(internal.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
1201
+ if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
1165
1202
  const higher = intersections.slice(0, intersections.indexOf(hit));
1166
- cancelPointer([...higher, hit]);
1203
+ cancelPointer([...higher, hit], eventPointerId);
1167
1204
  }
1168
1205
  }
1169
1206
  },
@@ -1179,15 +1216,18 @@ function createEvents(store) {
1179
1216
  }
1180
1217
  return intersections;
1181
1218
  }
1182
- function cancelPointer(intersections) {
1219
+ function cancelPointer(intersections, pointerId) {
1183
1220
  const { internal } = store.getState();
1184
- for (const hoveredObj of internal.hovered.values()) {
1221
+ const pid = pointerId ?? DEFAULT_POINTER_ID;
1222
+ const pointerState = internal.pointerMap.get(pid);
1223
+ if (!pointerState) return;
1224
+ for (const [hoveredId, hoveredObj] of pointerState.hovered) {
1185
1225
  if (!intersections.length || !intersections.find(
1186
1226
  (hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
1187
1227
  )) {
1188
1228
  const eventObject = hoveredObj.eventObject;
1189
1229
  const instance = eventObject.__r3f;
1190
- internal.hovered.delete(makeId(hoveredObj));
1230
+ pointerState.hovered.delete(hoveredId);
1191
1231
  if (instance?.eventCount) {
1192
1232
  const handlers = instance.handlers;
1193
1233
  const data = { ...hoveredObj, intersections };
@@ -1216,41 +1256,118 @@ function createEvents(store) {
1216
1256
  instance?.handlers.onDropMissed?.(event);
1217
1257
  }
1218
1258
  }
1259
+ function cleanupPointer(pointerId) {
1260
+ const { internal } = store.getState();
1261
+ const pointerState = internal.pointerMap.get(pointerId);
1262
+ if (pointerState) {
1263
+ for (const [, hoveredObj] of pointerState.hovered) {
1264
+ const eventObject = hoveredObj.eventObject;
1265
+ const instance = eventObject.__r3f;
1266
+ if (instance?.eventCount) {
1267
+ const handlers = instance.handlers;
1268
+ const data = { ...hoveredObj, intersections: [] };
1269
+ handlers.onPointerOut?.(data);
1270
+ handlers.onPointerLeave?.(data);
1271
+ }
1272
+ }
1273
+ internal.pointerMap.delete(pointerId);
1274
+ }
1275
+ internal.pointerDirty.delete(pointerId);
1276
+ }
1277
+ function processDeferredPointer(event, pointerId) {
1278
+ const state = store.getState();
1279
+ const { onPointerMissed, onDragOverMissed, internal } = state;
1280
+ if (!state.events.enabled) return;
1281
+ const filter = filterPointerEvents;
1282
+ const hits = intersect(event, filter);
1283
+ cancelPointer(hits, pointerId);
1284
+ function onIntersect(data) {
1285
+ const eventObject = data.eventObject;
1286
+ const instance = eventObject.__r3f;
1287
+ if (!instance?.eventCount) return;
1288
+ const handlers = instance.handlers;
1289
+ if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1290
+ const id = makeId(data);
1291
+ const pointerState = getPointerState(internal, pointerId);
1292
+ const hoveredItem = pointerState.hovered.get(id);
1293
+ if (!hoveredItem) {
1294
+ pointerState.hovered.set(id, data);
1295
+ handlers.onPointerOver?.(data);
1296
+ handlers.onPointerEnter?.(data);
1297
+ } else if (hoveredItem.stopped) {
1298
+ data.stopPropagation();
1299
+ }
1300
+ }
1301
+ handlers.onPointerMove?.(data);
1302
+ }
1303
+ handleIntersects(hits, event, 0, onIntersect);
1304
+ }
1219
1305
  function handlePointer(name) {
1220
1306
  switch (name) {
1221
1307
  case "onPointerLeave":
1222
- case "onPointerCancel":
1223
1308
  case "onDragLeave":
1224
1309
  return () => cancelPointer([]);
1310
+ // Global cancel of these events
1311
+ case "onPointerCancel":
1312
+ return (event) => {
1313
+ const pointerId = getPointerId(event);
1314
+ cleanupPointer(pointerId);
1315
+ };
1225
1316
  case "onLostPointerCapture":
1226
1317
  return (event) => {
1227
1318
  const { internal } = store.getState();
1228
- if ("pointerId" in event && internal.capturedMap.has(event.pointerId)) {
1319
+ const pointerId = getPointerId(event);
1320
+ const pointerState = internal.pointerMap.get(pointerId);
1321
+ if (pointerState?.captured.size) {
1229
1322
  requestAnimationFrame(() => {
1230
- if (internal.capturedMap.has(event.pointerId)) {
1231
- internal.capturedMap.delete(event.pointerId);
1232
- cancelPointer([]);
1323
+ const pointerState2 = internal.pointerMap.get(pointerId);
1324
+ if (pointerState2?.captured.size) {
1325
+ pointerState2.captured.clear();
1233
1326
  }
1327
+ cancelPointer([], pointerId);
1234
1328
  });
1235
1329
  }
1236
1330
  };
1237
1331
  }
1238
1332
  return function handleEvent(event) {
1239
1333
  const state = store.getState();
1240
- const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
1334
+ const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
1335
+ const pointerId = getPointerId(event);
1241
1336
  internal.lastEvent.current = event;
1242
- if (!state.events.enabled) return;
1337
+ if (!events.enabled) return;
1243
1338
  const isPointerMove = name === "onPointerMove";
1244
1339
  const isDragOver = name === "onDragOver";
1245
1340
  const isDrop = name === "onDrop";
1246
1341
  const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
1342
+ const isPointerDown = name === "onPointerDown";
1343
+ const isPointerUp = name === "onPointerUp";
1344
+ const isWheel = name === "onWheel";
1345
+ const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
1346
+ if (isPointerMove && canDeferRaycasts) {
1347
+ events.compute?.(event, state);
1348
+ internal.pointerDirty.set(pointerId, event);
1349
+ return;
1350
+ }
1351
+ if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
1352
+ events.compute?.(event, state);
1353
+ internal.pointerDirty.set(pointerId, event);
1354
+ return;
1355
+ }
1356
+ if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
1357
+ const deferredEvent = internal.pointerDirty.get(pointerId);
1358
+ internal.pointerDirty.delete(pointerId);
1359
+ processDeferredPointer(deferredEvent, pointerId);
1360
+ }
1247
1361
  const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
1248
1362
  const hits = intersect(event, filter);
1249
- const delta = isClickEvent ? calculateDistance(event) : 0;
1250
- if (name === "onPointerDown") {
1251
- internal.initialClick = [event.offsetX, event.offsetY];
1252
- internal.initialHits = hits.map((hit) => hit.eventObject);
1253
- }
1363
+ const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
1364
+ if (isPointerDown) {
1365
+ const pointerState2 = getPointerState(internal, pointerId);
1366
+ pointerState2.initialClick = [event.offsetX, event.offsetY];
1367
+ pointerState2.initialHits = hits.map((hit) => hit.eventObject);
1368
+ }
1369
+ const pointerState = internal.pointerMap.get(pointerId);
1370
+ const initialHits = pointerState?.initialHits ?? [];
1254
1371
  if (isClickEvent && !hits.length) {
1255
1372
  if (delta <= 2) {
1256
1373
  pointerMissed(event, internal.interaction);
@@ -1265,7 +1382,9 @@ function createEvents(store) {
1265
1382
  dropMissed(event, internal.interaction);
1266
1383
  if (onDropMissed) onDropMissed(event);
1267
1384
  }
1268
- if (isPointerMove || isDragOver) cancelPointer(hits);
1385
+ if (isPointerMove || isDragOver) {
1386
+ cancelPointer(hits, pointerId);
1387
+ }
1269
1388
  function onIntersect(data) {
1270
1389
  const eventObject = data.eventObject;
1271
1390
  const instance = eventObject.__r3f;
@@ -1274,9 +1393,10 @@ function createEvents(store) {
1274
1393
  if (isPointerMove) {
1275
1394
  if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1276
1395
  const id = makeId(data);
1277
- const hoveredItem = internal.hovered.get(id);
1396
+ const pointerState2 = getPointerState(internal, pointerId);
1397
+ const hoveredItem = pointerState2.hovered.get(id);
1278
1398
  if (!hoveredItem) {
1279
- internal.hovered.set(id, data);
1399
+ pointerState2.hovered.set(id, data);
1280
1400
  handlers.onPointerOver?.(data);
1281
1401
  handlers.onPointerEnter?.(data);
1282
1402
  } else if (hoveredItem.stopped) {
@@ -1286,9 +1406,10 @@ function createEvents(store) {
1286
1406
  handlers.onPointerMove?.(data);
1287
1407
  } else if (isDragOver) {
1288
1408
  const id = makeId(data);
1289
- const hoveredItem = internal.hovered.get(id);
1409
+ const pointerState2 = getPointerState(internal, pointerId);
1410
+ const hoveredItem = pointerState2.hovered.get(id);
1290
1411
  if (!hoveredItem) {
1291
- internal.hovered.set(id, data);
1412
+ pointerState2.hovered.set(id, data);
1292
1413
  handlers.onDragOverEnter?.(data);
1293
1414
  } else if (hoveredItem.stopped) {
1294
1415
  data.stopPropagation();
@@ -1299,18 +1420,18 @@ function createEvents(store) {
1299
1420
  } else {
1300
1421
  const handler = handlers[name];
1301
1422
  if (handler) {
1302
- if (!isClickEvent || internal.initialHits.includes(eventObject)) {
1423
+ if (!isClickEvent || initialHits.includes(eventObject)) {
1303
1424
  pointerMissed(
1304
1425
  event,
1305
- internal.interaction.filter((object) => !internal.initialHits.includes(object))
1426
+ internal.interaction.filter((object) => !initialHits.includes(object))
1306
1427
  );
1307
1428
  handler(data);
1308
1429
  }
1309
1430
  } else {
1310
- if (isClickEvent && internal.initialHits.includes(eventObject)) {
1431
+ if (isClickEvent && initialHits.includes(eventObject)) {
1311
1432
  pointerMissed(
1312
1433
  event,
1313
- internal.interaction.filter((object) => !internal.initialHits.includes(object))
1434
+ internal.interaction.filter((object) => !initialHits.includes(object))
1314
1435
  );
1315
1436
  }
1316
1437
  }
@@ -1319,7 +1440,15 @@ function createEvents(store) {
1319
1440
  handleIntersects(hits, event, delta, onIntersect);
1320
1441
  };
1321
1442
  }
1322
- return { handlePointer };
1443
+ function flushDeferredPointers() {
1444
+ const { internal, events } = store.getState();
1445
+ if (!events.frameTimedRaycasts) return;
1446
+ for (const [pointerId, event] of internal.pointerDirty) {
1447
+ processDeferredPointer(event, pointerId);
1448
+ }
1449
+ internal.pointerDirty.clear();
1450
+ }
1451
+ return { handlePointer, flushDeferredPointers, processDeferredPointer };
1323
1452
  }
1324
1453
  const DOM_EVENTS = {
1325
1454
  onClick: ["click", false],
@@ -1338,10 +1467,15 @@ const DOM_EVENTS = {
1338
1467
  onLostPointerCapture: ["lostpointercapture", true]
1339
1468
  };
1340
1469
  function createPointerEvents(store) {
1341
- const { handlePointer } = createEvents(store);
1470
+ const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
1471
+ let nextXRPointerId = XR_POINTER_ID_START;
1472
+ const xrPointers = /* @__PURE__ */ new Map();
1342
1473
  return {
1343
1474
  priority: 1,
1344
1475
  enabled: true,
1476
+ frameTimedRaycasts: true,
1477
+ alwaysFireOnScroll: true,
1478
+ updateOnFrame: false,
1345
1479
  compute(event, state) {
1346
1480
  state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
1347
1481
  state.raycaster.setFromCamera(state.pointer, state.camera);
@@ -1351,9 +1485,30 @@ function createPointerEvents(store) {
1351
1485
  (acc, key) => ({ ...acc, [key]: handlePointer(key) }),
1352
1486
  {}
1353
1487
  ),
1354
- update: () => {
1488
+ update: (pointerId) => {
1489
+ const { events, internal } = store.getState();
1490
+ if (!events.handlers) return;
1491
+ if (pointerId !== void 0) {
1492
+ const event = internal.pointerDirty.get(pointerId);
1493
+ if (event) {
1494
+ internal.pointerDirty.delete(pointerId);
1495
+ processDeferredPointer(event, pointerId);
1496
+ } else if (internal.lastEvent?.current) {
1497
+ processDeferredPointer(internal.lastEvent.current, pointerId);
1498
+ }
1499
+ } else {
1500
+ flushDeferredPointers();
1501
+ if (internal.lastEvent?.current) {
1502
+ events.handlers.onPointerMove(internal.lastEvent.current);
1503
+ }
1504
+ }
1505
+ },
1506
+ flush: () => {
1355
1507
  const { events, internal } = store.getState();
1356
- if (internal.lastEvent?.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current);
1508
+ flushDeferredPointers();
1509
+ if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
1510
+ events.handlers.onPointerMove(internal.lastEvent.current);
1511
+ }
1357
1512
  },
1358
1513
  connect: (target) => {
1359
1514
  const { set, events } = store.getState();
@@ -1379,6 +1534,32 @@ function createPointerEvents(store) {
1379
1534
  }
1380
1535
  set((state) => ({ events: { ...state.events, connected: void 0 } }));
1381
1536
  }
1537
+ },
1538
+ registerPointer: (config) => {
1539
+ const pointerId = nextXRPointerId++;
1540
+ xrPointers.set(pointerId, config);
1541
+ const { internal } = store.getState();
1542
+ getPointerState(internal, pointerId);
1543
+ return pointerId;
1544
+ },
1545
+ unregisterPointer: (pointerId) => {
1546
+ xrPointers.delete(pointerId);
1547
+ const { internal } = store.getState();
1548
+ const pointerState = internal.pointerMap.get(pointerId);
1549
+ if (pointerState) {
1550
+ for (const [, hoveredObj] of pointerState.hovered) {
1551
+ const eventObject = hoveredObj.eventObject;
1552
+ const instance = eventObject.__r3f;
1553
+ if (instance?.eventCount) {
1554
+ const handlers = instance.handlers;
1555
+ const data = { ...hoveredObj, intersections: [] };
1556
+ handlers.onPointerOut?.(data);
1557
+ handlers.onPointerLeave?.(data);
1558
+ }
1559
+ }
1560
+ internal.pointerMap.delete(pointerId);
1561
+ }
1562
+ internal.pointerDirty.delete(pointerId);
1382
1563
  }
1383
1564
  };
1384
1565
  }
@@ -2509,7 +2690,14 @@ const createStore = (invalidate, advance) => {
2509
2690
  frustum: new Frustum(),
2510
2691
  autoUpdateFrustum: true,
2511
2692
  raycaster: null,
2512
- events: { priority: 1, enabled: true, connected: false },
2693
+ events: {
2694
+ priority: 1,
2695
+ enabled: true,
2696
+ connected: false,
2697
+ frameTimedRaycasts: true,
2698
+ alwaysFireOnScroll: true,
2699
+ updateOnFrame: false
2700
+ },
2513
2701
  scene: null,
2514
2702
  rootScene: null,
2515
2703
  xr: null,
@@ -2600,11 +2788,13 @@ const createStore = (invalidate, advance) => {
2600
2788
  },
2601
2789
  setError: (error) => set(() => ({ error })),
2602
2790
  error: null,
2603
- //* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
2791
+ //* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
2604
2792
  uniforms: {},
2605
2793
  nodes: {},
2794
+ buffers: {},
2795
+ gpuStorage: {},
2606
2796
  textures: /* @__PURE__ */ new Map(),
2607
- postProcessing: null,
2797
+ renderPipeline: null,
2608
2798
  passes: {},
2609
2799
  _hmrVersion: 0,
2610
2800
  _sizeImperative: false,
@@ -2613,12 +2803,16 @@ const createStore = (invalidate, advance) => {
2613
2803
  internal: {
2614
2804
  // Events
2615
2805
  interaction: [],
2616
- hovered: /* @__PURE__ */ new Map(),
2617
2806
  subscribers: [],
2807
+ // Per-pointer state (new unified structure)
2808
+ pointerMap: /* @__PURE__ */ new Map(),
2809
+ pointerDirty: /* @__PURE__ */ new Map(),
2810
+ lastEvent: React.createRef(),
2811
+ // Deprecated but kept for backwards compatibility
2812
+ hovered: /* @__PURE__ */ new Map(),
2618
2813
  initialClick: [0, 0],
2619
2814
  initialHits: [],
2620
2815
  capturedMap: /* @__PURE__ */ new Map(),
2621
- lastEvent: React.createRef(),
2622
2816
  // Visibility tracking (onFramed, onOccluded, onVisible)
2623
2817
  visibilityRegistry: /* @__PURE__ */ new Map(),
2624
2818
  // Occlusion system (WebGPU only)
@@ -15050,6 +15244,12 @@ function createRoot(canvas) {
15050
15244
  } else if (!state.internal.actualRenderer) {
15051
15245
  renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
15052
15246
  if (!renderer.hasInitialized?.()) {
15247
+ const size2 = computeInitialSize(canvas, propsSize);
15248
+ if (size2.width > 0 && size2.height > 0) {
15249
+ const pixelRatio = calculateDpr(dpr);
15250
+ canvas.width = size2.width * pixelRatio;
15251
+ canvas.height = size2.height * pixelRatio;
15252
+ }
15053
15253
  await renderer.init();
15054
15254
  }
15055
15255
  const backend = renderer.backend;
@@ -15251,6 +15451,18 @@ function createRoot(canvas) {
15251
15451
  system: true
15252
15452
  }
15253
15453
  );
15454
+ const unregisterEventsFlush = scheduler.register(
15455
+ () => {
15456
+ const state2 = store.getState();
15457
+ state2.events.flush?.();
15458
+ },
15459
+ {
15460
+ id: `${newRootId}_events`,
15461
+ rootId: newRootId,
15462
+ phase: "input",
15463
+ system: true
15464
+ }
15465
+ );
15254
15466
  const unregisterFrustum = scheduler.register(
15255
15467
  () => {
15256
15468
  const state2 = store.getState();
@@ -15285,7 +15497,7 @@ function createRoot(canvas) {
15285
15497
  const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
15286
15498
  if (userHandlesRender || state2.internal.priority) return;
15287
15499
  try {
15288
- if (state2.postProcessing?.render) state2.postProcessing.render();
15500
+ if (state2.renderPipeline?.render) state2.renderPipeline.render();
15289
15501
  else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
15290
15502
  } catch (error) {
15291
15503
  state2.setError(error instanceof Error ? error : new Error(String(error)));
@@ -15310,6 +15522,7 @@ function createRoot(canvas) {
15310
15522
  unregisterRoot: () => {
15311
15523
  unregisterRoot();
15312
15524
  unregisterCanvasTarget();
15525
+ unregisterEventsFlush();
15313
15526
  unregisterFrustum();
15314
15527
  unregisterVisibility();
15315
15528
  unregisterRender();
@@ -15475,9 +15688,13 @@ function PortalInner({ state = {}, children, container }) {
15475
15688
  const store = createWithEqualityFn((set, get) => ({ ...rest, set, get }));
15476
15689
  const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
15477
15690
  onMutate(previousRoot.getState());
15478
- previousRoot.subscribe(onMutate);
15479
15691
  return store;
15480
15692
  }, [previousRoot, container]);
15693
+ useIsomorphicLayoutEffect(() => {
15694
+ const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
15695
+ const unsubscribe = previousRoot.subscribe(onMutate);
15696
+ return unsubscribe;
15697
+ }, [previousRoot, usePortalStore]);
15481
15698
  return (
15482
15699
  // @ts-ignore, reconciler types are not maintained
15483
15700
  /* @__PURE__ */ jsx(Fragment, { children: reconciler.createPortal(
@@ -15698,6 +15915,7 @@ function CanvasImpl({
15698
15915
  queueMicrotask(() => {
15699
15916
  const rootEntry = _roots.get(canvas);
15700
15917
  if (rootEntry?.store) {
15918
+ console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
15701
15919
  rootEntry.store.setState((state) => ({
15702
15920
  nodes: {},
15703
15921
  uniforms: {},
@@ -15709,8 +15927,7 @@ function CanvasImpl({
15709
15927
  if (typeof import.meta !== "undefined" && import.meta.hot) {
15710
15928
  const hot = import.meta.hot;
15711
15929
  hot.on("vite:afterUpdate", handleHMR);
15712
- return () => hot.dispose?.(() => {
15713
- });
15930
+ return () => hot.off?.("vite:afterUpdate", handleHMR);
15714
15931
  }
15715
15932
  if (typeof module !== "undefined" && module.hot) {
15716
15933
  const hot = module.hot;
@@ -15809,6 +16026,8 @@ function createScopedStore(data) {
15809
16026
  function createLazyCreatorState(state) {
15810
16027
  let _uniforms = null;
15811
16028
  let _nodes = null;
16029
+ let _buffers = null;
16030
+ let _gpuStorage = null;
15812
16031
  return Object.create(state, {
15813
16032
  uniforms: {
15814
16033
  get() {
@@ -15819,6 +16038,16 @@ function createLazyCreatorState(state) {
15819
16038
  get() {
15820
16039
  return _nodes ?? (_nodes = createScopedStore(state.nodes));
15821
16040
  }
16041
+ },
16042
+ buffers: {
16043
+ get() {
16044
+ return _buffers ?? (_buffers = createScopedStore(state.buffers));
16045
+ }
16046
+ },
16047
+ gpuStorage: {
16048
+ get() {
16049
+ return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
16050
+ }
15822
16051
  }
15823
16052
  });
15824
16053
  }
@@ -15901,6 +16130,10 @@ function vectorize(inObject) {
15901
16130
  if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
15902
16131
  if (obj.isMatrix3 || obj.isMatrix4) return inObject;
15903
16132
  if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
16133
+ if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
16134
+ const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
16135
+ return new Color(obj.r * scale, obj.g * scale, obj.b * scale);
16136
+ }
15904
16137
  if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
15905
16138
  if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
15906
16139
  return new Vector4(obj.x, obj.y, obj.z, obj.w);
@@ -16356,7 +16589,351 @@ function useLocalNodes(creator) {
16356
16589
  }, [store, creator, uniforms, nodes, textures, hmrVersion]);
16357
16590
  }
16358
16591
 
16359
- function usePostProcessing(mainCB, setupCB) {
16592
+ const isBufferLike = (value) => {
16593
+ if (value === null || typeof value !== "object") return false;
16594
+ if (ArrayBuffer.isView(value)) return true;
16595
+ if ("isBufferAttribute" in value) return true;
16596
+ if ("uuid" in value || "nodeType" in value) return true;
16597
+ return false;
16598
+ };
16599
+ const disposeBuffer = (buffer) => {
16600
+ if (buffer === null || typeof buffer !== "object") return;
16601
+ if ("dispose" in buffer && typeof buffer.dispose === "function") {
16602
+ buffer.dispose();
16603
+ }
16604
+ };
16605
+ function useBuffers(creatorOrScope, scope) {
16606
+ const store = useStore();
16607
+ const removeBuffers = useCallback(
16608
+ (names, targetScope) => {
16609
+ const nameArray = Array.isArray(names) ? names : [names];
16610
+ store.setState((state) => {
16611
+ if (targetScope) {
16612
+ const currentScope = { ...state.buffers[targetScope] };
16613
+ for (const name of nameArray) delete currentScope[name];
16614
+ return { buffers: { ...state.buffers, [targetScope]: currentScope } };
16615
+ }
16616
+ const buffers2 = { ...state.buffers };
16617
+ for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
16618
+ return { buffers: buffers2 };
16619
+ });
16620
+ },
16621
+ [store]
16622
+ );
16623
+ const clearBuffers = useCallback(
16624
+ (targetScope) => {
16625
+ store.setState((state) => {
16626
+ if (targetScope && targetScope !== "root") {
16627
+ const { [targetScope]: _, ...rest } = state.buffers;
16628
+ return { buffers: rest };
16629
+ }
16630
+ if (targetScope === "root") {
16631
+ const buffers2 = {};
16632
+ for (const [key, value] of Object.entries(state.buffers)) {
16633
+ if (!isBufferLike(value)) buffers2[key] = value;
16634
+ }
16635
+ return { buffers: buffers2 };
16636
+ }
16637
+ return { buffers: {} };
16638
+ });
16639
+ },
16640
+ [store]
16641
+ );
16642
+ const rebuildBuffers = useCallback(
16643
+ (targetScope) => {
16644
+ store.setState((state) => {
16645
+ let newBuffers = state.buffers;
16646
+ if (targetScope && targetScope !== "root") {
16647
+ const { [targetScope]: _, ...rest } = state.buffers;
16648
+ newBuffers = rest;
16649
+ } else if (targetScope === "root") {
16650
+ newBuffers = {};
16651
+ for (const [key, value] of Object.entries(state.buffers)) {
16652
+ if (!isBufferLike(value)) newBuffers[key] = value;
16653
+ }
16654
+ } else {
16655
+ newBuffers = {};
16656
+ }
16657
+ return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
16658
+ });
16659
+ },
16660
+ [store]
16661
+ );
16662
+ const disposeBuffers = useCallback(
16663
+ (names, targetScope) => {
16664
+ const nameArray = Array.isArray(names) ? names : [names];
16665
+ const state = store.getState();
16666
+ for (const name of nameArray) {
16667
+ const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
16668
+ if (buffer && isBufferLike(buffer)) {
16669
+ disposeBuffer(buffer);
16670
+ }
16671
+ }
16672
+ removeBuffers(names, targetScope);
16673
+ },
16674
+ [store, removeBuffers]
16675
+ );
16676
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16677
+ const storeBuffers = useThree((s) => s.buffers);
16678
+ const hmrVersion = useThree((s) => s._hmrVersion);
16679
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16680
+ const readerDep = isReader ? storeBuffers : null;
16681
+ const creatorDep = isReader ? null : hmrVersion;
16682
+ const buffers = useMemo(() => {
16683
+ if (creatorOrScope === void 0) {
16684
+ return storeBuffers;
16685
+ }
16686
+ if (typeof creatorOrScope === "string") {
16687
+ const scopeData = storeBuffers[creatorOrScope];
16688
+ if (scopeData && !isBufferLike(scopeData)) return scopeData;
16689
+ return {};
16690
+ }
16691
+ const state = store.getState();
16692
+ const set = store.setState;
16693
+ const creator = creatorOrScope;
16694
+ const wrappedState = createLazyCreatorState(state);
16695
+ const created = creator(wrappedState);
16696
+ const result = {};
16697
+ let hasNewBuffers = false;
16698
+ if (scope) {
16699
+ const currentScope = state.buffers[scope] ?? {};
16700
+ for (const [name, buffer] of Object.entries(created)) {
16701
+ if (currentScope[name]) {
16702
+ result[name] = currentScope[name];
16703
+ } else {
16704
+ if ("setName" in buffer && typeof buffer.setName === "function") {
16705
+ buffer.setName(`${scope}.${name}`);
16706
+ }
16707
+ result[name] = buffer;
16708
+ hasNewBuffers = true;
16709
+ }
16710
+ }
16711
+ if (hasNewBuffers) {
16712
+ set((s) => ({
16713
+ buffers: {
16714
+ ...s.buffers,
16715
+ [scope]: { ...s.buffers[scope], ...result }
16716
+ }
16717
+ }));
16718
+ }
16719
+ return result;
16720
+ }
16721
+ for (const [name, buffer] of Object.entries(created)) {
16722
+ const existing = state.buffers[name];
16723
+ if (existing && isBufferLike(existing)) {
16724
+ result[name] = existing;
16725
+ } else {
16726
+ if ("setName" in buffer && typeof buffer.setName === "function") {
16727
+ buffer.setName(name);
16728
+ }
16729
+ result[name] = buffer;
16730
+ hasNewBuffers = true;
16731
+ }
16732
+ }
16733
+ if (hasNewBuffers) {
16734
+ set((s) => ({ buffers: { ...s.buffers, ...result } }));
16735
+ }
16736
+ return result;
16737
+ }, [store, scopeDep, readerDep, creatorDep]);
16738
+ return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
16739
+ }
16740
+ function rebuildAllBuffers(store, scope) {
16741
+ store.setState((state) => {
16742
+ let newBuffers = state.buffers;
16743
+ if (scope && scope !== "root") {
16744
+ const { [scope]: _, ...rest } = state.buffers;
16745
+ newBuffers = rest;
16746
+ } else if (scope === "root") {
16747
+ newBuffers = {};
16748
+ for (const [key, value] of Object.entries(state.buffers)) {
16749
+ if (!isBufferLike(value)) newBuffers[key] = value;
16750
+ }
16751
+ } else {
16752
+ newBuffers = {};
16753
+ }
16754
+ return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
16755
+ });
16756
+ }
16757
+
16758
+ const isStorageLike = (value) => {
16759
+ if (value === null || typeof value !== "object") return false;
16760
+ if ("isTexture" in value) return true;
16761
+ if ("isData3DTexture" in value) return true;
16762
+ if ("uuid" in value || "nodeType" in value) return true;
16763
+ return false;
16764
+ };
16765
+ const disposeStorage = (storage) => {
16766
+ if (storage === null || typeof storage !== "object") return;
16767
+ if ("dispose" in storage && typeof storage.dispose === "function") {
16768
+ storage.dispose();
16769
+ }
16770
+ };
16771
+ function useGPUStorage(creatorOrScope, scope) {
16772
+ const store = useStore();
16773
+ const removeStorage = useCallback(
16774
+ (names, targetScope) => {
16775
+ const nameArray = Array.isArray(names) ? names : [names];
16776
+ store.setState((state) => {
16777
+ if (targetScope) {
16778
+ const currentScope = { ...state.gpuStorage[targetScope] };
16779
+ for (const name of nameArray) delete currentScope[name];
16780
+ return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
16781
+ }
16782
+ const gpuStorage2 = { ...state.gpuStorage };
16783
+ for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
16784
+ return { gpuStorage: gpuStorage2 };
16785
+ });
16786
+ },
16787
+ [store]
16788
+ );
16789
+ const clearStorage = useCallback(
16790
+ (targetScope) => {
16791
+ store.setState((state) => {
16792
+ if (targetScope && targetScope !== "root") {
16793
+ const { [targetScope]: _, ...rest } = state.gpuStorage;
16794
+ return { gpuStorage: rest };
16795
+ }
16796
+ if (targetScope === "root") {
16797
+ const gpuStorage2 = {};
16798
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16799
+ if (!isStorageLike(value)) gpuStorage2[key] = value;
16800
+ }
16801
+ return { gpuStorage: gpuStorage2 };
16802
+ }
16803
+ return { gpuStorage: {} };
16804
+ });
16805
+ },
16806
+ [store]
16807
+ );
16808
+ const rebuildStorage = useCallback(
16809
+ (targetScope) => {
16810
+ store.setState((state) => {
16811
+ let newStorage = state.gpuStorage;
16812
+ if (targetScope && targetScope !== "root") {
16813
+ const { [targetScope]: _, ...rest } = state.gpuStorage;
16814
+ newStorage = rest;
16815
+ } else if (targetScope === "root") {
16816
+ newStorage = {};
16817
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16818
+ if (!isStorageLike(value)) newStorage[key] = value;
16819
+ }
16820
+ } else {
16821
+ newStorage = {};
16822
+ }
16823
+ return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
16824
+ });
16825
+ },
16826
+ [store]
16827
+ );
16828
+ const disposeStorageFn = useCallback(
16829
+ (names, targetScope) => {
16830
+ const nameArray = Array.isArray(names) ? names : [names];
16831
+ const state = store.getState();
16832
+ for (const name of nameArray) {
16833
+ const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
16834
+ if (storage && isStorageLike(storage)) {
16835
+ disposeStorage(storage);
16836
+ }
16837
+ }
16838
+ removeStorage(names, targetScope);
16839
+ },
16840
+ [store, removeStorage]
16841
+ );
16842
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16843
+ const storeStorage = useThree((s) => s.gpuStorage);
16844
+ const hmrVersion = useThree((s) => s._hmrVersion);
16845
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16846
+ const readerDep = isReader ? storeStorage : null;
16847
+ const creatorDep = isReader ? null : hmrVersion;
16848
+ const gpuStorage = useMemo(() => {
16849
+ if (creatorOrScope === void 0) {
16850
+ return storeStorage;
16851
+ }
16852
+ if (typeof creatorOrScope === "string") {
16853
+ const scopeData = storeStorage[creatorOrScope];
16854
+ if (scopeData && !isStorageLike(scopeData)) return scopeData;
16855
+ return {};
16856
+ }
16857
+ const state = store.getState();
16858
+ const set = store.setState;
16859
+ const creator = creatorOrScope;
16860
+ const wrappedState = createLazyCreatorState(state);
16861
+ const created = creator(wrappedState);
16862
+ const result = {};
16863
+ let hasNewStorage = false;
16864
+ if (scope) {
16865
+ const currentScope = state.gpuStorage[scope] ?? {};
16866
+ for (const [name, storage] of Object.entries(created)) {
16867
+ if (currentScope[name]) {
16868
+ result[name] = currentScope[name];
16869
+ } else {
16870
+ if ("setName" in storage && typeof storage.setName === "function") {
16871
+ storage.setName(`${scope}.${name}`);
16872
+ }
16873
+ if ("name" in storage && typeof storage.name === "string") {
16874
+ storage.name = `${scope}.${name}`;
16875
+ }
16876
+ result[name] = storage;
16877
+ hasNewStorage = true;
16878
+ }
16879
+ }
16880
+ if (hasNewStorage) {
16881
+ set((s) => ({
16882
+ gpuStorage: {
16883
+ ...s.gpuStorage,
16884
+ [scope]: { ...s.gpuStorage[scope], ...result }
16885
+ }
16886
+ }));
16887
+ }
16888
+ return result;
16889
+ }
16890
+ for (const [name, storage] of Object.entries(created)) {
16891
+ const existing = state.gpuStorage[name];
16892
+ if (existing && isStorageLike(existing)) {
16893
+ result[name] = existing;
16894
+ } else {
16895
+ if ("setName" in storage && typeof storage.setName === "function") {
16896
+ storage.setName(name);
16897
+ }
16898
+ if ("name" in storage && typeof storage.name === "string") {
16899
+ storage.name = name;
16900
+ }
16901
+ result[name] = storage;
16902
+ hasNewStorage = true;
16903
+ }
16904
+ }
16905
+ if (hasNewStorage) {
16906
+ set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
16907
+ }
16908
+ return result;
16909
+ }, [store, scopeDep, readerDep, creatorDep]);
16910
+ return {
16911
+ ...gpuStorage,
16912
+ removeStorage,
16913
+ clearStorage,
16914
+ rebuildStorage,
16915
+ disposeStorage: disposeStorageFn
16916
+ };
16917
+ }
16918
+ function rebuildAllStorage(store, scope) {
16919
+ store.setState((state) => {
16920
+ let newStorage = state.gpuStorage;
16921
+ if (scope && scope !== "root") {
16922
+ const { [scope]: _, ...rest } = state.gpuStorage;
16923
+ newStorage = rest;
16924
+ } else if (scope === "root") {
16925
+ newStorage = {};
16926
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16927
+ if (!isStorageLike(value)) newStorage[key] = value;
16928
+ }
16929
+ } else {
16930
+ newStorage = {};
16931
+ }
16932
+ return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
16933
+ });
16934
+ }
16935
+
16936
+ function useRenderPipeline(mainCB, setupCB) {
16360
16937
  const store = useStore();
16361
16938
  const { scene, camera, renderer, isLegacy } = useThree();
16362
16939
  const callbacksRanRef = useRef(false);
@@ -16375,7 +16952,7 @@ function usePostProcessing(mainCB, setupCB) {
16375
16952
  }, [store]);
16376
16953
  const reset = useCallback(() => {
16377
16954
  store.setState({
16378
- postProcessing: null,
16955
+ renderPipeline: null,
16379
16956
  passes: {}
16380
16957
  });
16381
16958
  callbacksRanRef.current = false;
@@ -16388,13 +16965,13 @@ function usePostProcessing(mainCB, setupCB) {
16388
16965
  }, []);
16389
16966
  useLayoutEffect(() => {
16390
16967
  if (isLegacy) {
16391
- throw new Error("usePostProcessing is only available with WebGPU renderer. Set renderer prop on Canvas.");
16968
+ throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
16392
16969
  }
16393
16970
  if (!renderer || !scene || !camera) return;
16394
16971
  const state = store.getState();
16395
16972
  const set = store.setState;
16396
16973
  try {
16397
- let pp = state.postProcessing;
16974
+ let pp = state.renderPipeline;
16398
16975
  let currentPasses = { ...state.passes };
16399
16976
  let justCreatedPP = false;
16400
16977
  if (!pp) {
@@ -16411,7 +16988,7 @@ function usePostProcessing(mainCB, setupCB) {
16411
16988
  }
16412
16989
  currentPasses.scenePass = scenePass;
16413
16990
  if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
16414
- set({ postProcessing: pp, passes: currentPasses });
16991
+ set({ renderPipeline: pp, passes: currentPasses });
16415
16992
  const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
16416
16993
  if (shouldRunCallbacks) {
16417
16994
  if (setupCBRef.current) {
@@ -16433,22 +17010,22 @@ function usePostProcessing(mainCB, setupCB) {
16433
17010
  callbacksRanRef.current = true;
16434
17011
  }
16435
17012
  } catch (error) {
16436
- console.error("[usePostProcessing] Setup error:", error);
17013
+ console.error("[useRenderPipeline] Setup error:", error);
16437
17014
  }
16438
17015
  }, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
16439
17016
  const passes = useThree((s) => s.passes);
16440
- const postProcessing = useThree((s) => s.postProcessing);
17017
+ const renderPipeline = useThree((s) => s.renderPipeline);
16441
17018
  return {
16442
17019
  passes,
16443
- postProcessing,
17020
+ renderPipeline,
16444
17021
  clearPasses,
16445
17022
  reset,
16446
17023
  rebuild,
16447
- // isReady indicates if PostProcessing is configured and ready for rendering
16448
- isReady: postProcessing !== null
17024
+ // isReady indicates if RenderPipeline is configured and ready for rendering
17025
+ isReady: renderPipeline !== null
16449
17026
  };
16450
17027
  }
16451
17028
 
16452
17029
  extend(THREE);
16453
17030
 
16454
- export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, rebuildAllNodes, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, usePostProcessing, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms, waitForPrimary };
17031
+ export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getScheduler, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, rebuildAllBuffers, rebuildAllNodes, rebuildAllStorage, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useBuffers, useEnvironment, useFrame, useGPUStorage, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, useRenderPipeline, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms, waitForPrimary };