@layoutit/polycss-react 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -20,15 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
- BASE_TILE: () => import_polycss_core27.BASE_TILE,
24
- CAMERA_BACKFACE_CULL_EPS: () => import_polycss_core27.CAMERA_BACKFACE_CULL_EPS,
25
- DEFAULT_CAMERA_STATE: () => import_polycss_core27.DEFAULT_CAMERA_STATE,
26
- DEFAULT_PROJECTION: () => import_polycss_core27.DEFAULT_PROJECTION,
27
- DEFAULT_SEAM_FACET_SPLIT_OPTIONS: () => import_polycss_core27.DEFAULT_SEAM_FACET_SPLIT_OPTIONS,
28
- DEFAULT_SEAM_OVERLAP_OPTIONS: () => import_polycss_core27.DEFAULT_SEAM_OVERLAP_OPTIONS,
29
- LoopOnce: () => import_polycss_core27.LoopOnce,
30
- LoopPingPong: () => import_polycss_core27.LoopPingPong,
31
- LoopRepeat: () => import_polycss_core27.LoopRepeat,
23
+ BASE_TILE: () => import_polycss_core28.BASE_TILE,
24
+ CAMERA_BACKFACE_CULL_EPS: () => import_polycss_core28.CAMERA_BACKFACE_CULL_EPS,
25
+ DEFAULT_CAMERA_STATE: () => import_polycss_core28.DEFAULT_CAMERA_STATE,
26
+ DEFAULT_PROJECTION: () => import_polycss_core28.DEFAULT_PROJECTION,
27
+ DEFAULT_SEAM_FACET_SPLIT_OPTIONS: () => import_polycss_core28.DEFAULT_SEAM_FACET_SPLIT_OPTIONS,
28
+ DEFAULT_SEAM_OVERLAP_OPTIONS: () => import_polycss_core28.DEFAULT_SEAM_OVERLAP_OPTIONS,
29
+ LoopOnce: () => import_polycss_core28.LoopOnce,
30
+ LoopPingPong: () => import_polycss_core28.LoopPingPong,
31
+ LoopRepeat: () => import_polycss_core28.LoopRepeat,
32
32
  Poly: () => Poly,
33
33
  PolyAxesHelper: () => PolyAxesHelper,
34
34
  PolyBox: () => PolyBox,
@@ -56,78 +56,86 @@ __export(src_exports, {
56
56
  PolyTetrahedron: () => PolyTetrahedron,
57
57
  PolyTorus: () => PolyTorus,
58
58
  PolyTransformControls: () => PolyTransformControls,
59
- VOXEL_CAMERA_CULL_AXIS_EPS: () => import_polycss_core27.VOXEL_CAMERA_CULL_AXIS_EPS,
60
- VOXEL_CAMERA_CULL_NORMAL_LIMIT: () => import_polycss_core27.VOXEL_CAMERA_CULL_NORMAL_LIMIT,
61
- arrowPolygons: () => import_polycss_core27.arrowPolygons,
62
- axesHelperPolygons: () => import_polycss_core27.axesHelperPolygons,
63
- bakeSolidTextureSampledPolygons: () => import_polycss_core27.bakeSolidTextureSampledPolygons,
64
- bakeSolidTextureSamples: () => import_polycss_core27.bakeSolidTextureSamples,
65
- boxPolygons: () => import_polycss_core27.boxPolygons,
66
- buildPolyMeshTransform: () => import_polycss_core27.buildPolyMeshTransform,
67
- buildPolySceneTransform: () => import_polycss_core27.buildPolySceneTransform,
68
- buildSceneContext: () => import_polycss_core27.buildSceneContext,
69
- cameraCullNormalGroups: () => import_polycss_core27.cameraCullNormalGroups,
70
- cameraCullNormalGroupsFromPolygons: () => import_polycss_core27.cameraCullNormalGroupsFromPolygons,
71
- cameraCullNormalKey: () => import_polycss_core27.cameraCullNormalKey,
72
- cameraCullVisibleSignature: () => import_polycss_core27.cameraCullVisibleSignature,
73
- cameraFacingDepth: () => import_polycss_core27.cameraFacingDepth,
74
- clampChannel: () => import_polycss_core27.clampChannel,
59
+ VOXEL_CAMERA_CULL_AXIS_EPS: () => import_polycss_core28.VOXEL_CAMERA_CULL_AXIS_EPS,
60
+ VOXEL_CAMERA_CULL_NORMAL_LIMIT: () => import_polycss_core28.VOXEL_CAMERA_CULL_NORMAL_LIMIT,
61
+ arrowPolygons: () => import_polycss_core28.arrowPolygons,
62
+ axesHelperPolygons: () => import_polycss_core28.axesHelperPolygons,
63
+ bakeSolidTextureSampledPolygons: () => import_polycss_core28.bakeSolidTextureSampledPolygons,
64
+ bakeSolidTextureSamples: () => import_polycss_core28.bakeSolidTextureSamples,
65
+ boxPolygons: () => import_polycss_core28.boxPolygons,
66
+ buildPolyCameraSceneTransform: () => import_polycss_core28.buildPolyCameraSceneTransform,
67
+ buildPolyMeshTransform: () => import_polycss_core28.buildPolyMeshTransform,
68
+ buildPolySceneTransform: () => import_polycss_core28.buildPolySceneTransform,
69
+ buildSceneContext: () => import_polycss_core28.buildSceneContext,
70
+ cameraCullNormalGroups: () => import_polycss_core28.cameraCullNormalGroups,
71
+ cameraCullNormalGroupsFromPolygons: () => import_polycss_core28.cameraCullNormalGroupsFromPolygons,
72
+ cameraCullNormalKey: () => import_polycss_core28.cameraCullNormalKey,
73
+ cameraCullVisibleSignature: () => import_polycss_core28.cameraCullVisibleSignature,
74
+ cameraFacingDepth: () => import_polycss_core28.cameraFacingDepth,
75
+ capturePolyCameraSnapshot: () => import_polycss_core28.capturePolyCameraSnapshot,
76
+ clampChannel: () => import_polycss_core28.clampChannel,
75
77
  collectPolyRenderStats: () => collectPolyRenderStats,
76
- computeSceneBbox: () => import_polycss_core27.computeSceneBbox,
77
- computeShapeLighting: () => import_polycss_core27.computeShapeLighting,
78
- computeTexturePaintMetrics: () => import_polycss_core27.computeTexturePaintMetrics,
79
- conePolygons: () => import_polycss_core27.conePolygons,
80
- coverPlanarPolygons: () => import_polycss_core27.coverPlanarPolygons,
81
- createIsometricCamera: () => import_polycss_core27.createIsometricCamera,
82
- createPolyAnimationMixer: () => import_polycss_core27.createPolyAnimationMixer,
83
- cullInteriorPolygons: () => import_polycss_core27.cullInteriorPolygons,
84
- cylinderPolygons: () => import_polycss_core27.cylinderPolygons,
85
- dodecahedronPolygons: () => import_polycss_core27.dodecahedronPolygons,
78
+ collectPolyTextureReadiness: () => collectPolyTextureReadiness,
79
+ computeSceneBbox: () => import_polycss_core28.computeSceneBbox,
80
+ computeShapeLighting: () => import_polycss_core28.computeShapeLighting,
81
+ computeTexturePaintMetrics: () => import_polycss_core28.computeTexturePaintMetrics,
82
+ conePolygons: () => import_polycss_core28.conePolygons,
83
+ coverPlanarPolygons: () => import_polycss_core28.coverPlanarPolygons,
84
+ createIsometricCamera: () => import_polycss_core28.createIsometricCamera,
85
+ createPolyAnimationMixer: () => import_polycss_core28.createPolyAnimationMixer,
86
+ cssDistanceToWorld: () => import_polycss_core28.cssDistanceToWorld,
87
+ cssPositionToWorld: () => import_polycss_core28.cssPositionToWorld,
88
+ cullInteriorPolygons: () => import_polycss_core28.cullInteriorPolygons,
89
+ cylinderPolygons: () => import_polycss_core28.cylinderPolygons,
90
+ dodecahedronPolygons: () => import_polycss_core28.dodecahedronPolygons,
86
91
  findMeshUnderPoint: () => findMeshUnderPoint,
87
92
  findPolyMeshHandle: () => findPolyMeshHandle,
88
- formatColor: () => import_polycss_core27.formatColor,
89
- icosahedronPolygons: () => import_polycss_core27.icosahedronPolygons,
93
+ formatColor: () => import_polycss_core28.formatColor,
94
+ icosahedronPolygons: () => import_polycss_core28.icosahedronPolygons,
90
95
  injectPolyBaseStyles: () => injectPolyBaseStyles,
91
- inverseRotateVec3: () => import_polycss_core27.inverseRotateVec3,
92
- isAxisAlignedSurfaceNormal: () => import_polycss_core27.isAxisAlignedSurfaceNormal,
93
- isVoxelCameraCullableNormalGroups: () => import_polycss_core27.isVoxelCameraCullableNormalGroups,
94
- loadMesh: () => import_polycss_core27.loadMesh,
95
- mergePolygons: () => import_polycss_core27.mergePolygons,
96
- normalFacesCamera: () => import_polycss_core27.normalFacesCamera,
97
- normalizeInvertMultiplier: () => import_polycss_core27.normalizeInvertMultiplier,
98
- normalizePolygons: () => import_polycss_core27.normalizePolygons,
99
- octahedronPolygons: () => import_polycss_core27.octahedronPolygons,
100
- optimizeAnimatedMeshPolygons: () => import_polycss_core27.optimizeAnimatedMeshPolygons,
101
- optimizeMeshParseResult: () => import_polycss_core27.optimizeMeshParseResult,
102
- optimizeMeshPolygons: () => import_polycss_core27.optimizeMeshPolygons,
103
- parseColor: () => import_polycss_core27.parseColor,
104
- parseGltf: () => import_polycss_core27.parseGltf,
105
- parseHexColor: () => import_polycss_core27.parseHexColor,
106
- parseMtl: () => import_polycss_core27.parseMtl,
107
- parseObj: () => import_polycss_core27.parseObj,
108
- parsePureColor: () => import_polycss_core27.parsePureColor,
109
- parseRgbColor: () => import_polycss_core27.parseRgbColor,
110
- parseStl: () => import_polycss_core27.parseStl,
111
- parseVox: () => import_polycss_core27.parseVox,
112
- planePolygons: () => import_polycss_core27.planePolygons,
96
+ inverseRotateVec3: () => import_polycss_core28.inverseRotateVec3,
97
+ isAxisAlignedSurfaceNormal: () => import_polycss_core28.isAxisAlignedSurfaceNormal,
98
+ isVoxelCameraCullableNormalGroups: () => import_polycss_core28.isVoxelCameraCullableNormalGroups,
99
+ loadMesh: () => import_polycss_core28.loadMesh,
100
+ mergePolygons: () => import_polycss_core28.mergePolygons,
101
+ normalFacesCamera: () => import_polycss_core28.normalFacesCamera,
102
+ normalizeInvertMultiplier: () => import_polycss_core28.normalizeInvertMultiplier,
103
+ normalizePolygons: () => import_polycss_core28.normalizePolygons,
104
+ octahedronPolygons: () => import_polycss_core28.octahedronPolygons,
105
+ optimizeAnimatedMeshPolygons: () => import_polycss_core28.optimizeAnimatedMeshPolygons,
106
+ optimizeMeshParseResult: () => import_polycss_core28.optimizeMeshParseResult,
107
+ optimizeMeshPolygons: () => import_polycss_core28.optimizeMeshPolygons,
108
+ parseColor: () => import_polycss_core28.parseColor,
109
+ parseGltf: () => import_polycss_core28.parseGltf,
110
+ parseHexColor: () => import_polycss_core28.parseHexColor,
111
+ parseMtl: () => import_polycss_core28.parseMtl,
112
+ parseObj: () => import_polycss_core28.parseObj,
113
+ parsePureColor: () => import_polycss_core28.parsePureColor,
114
+ parseRgbColor: () => import_polycss_core28.parseRgbColor,
115
+ parseStl: () => import_polycss_core28.parseStl,
116
+ parseVox: () => import_polycss_core28.parseVox,
117
+ planePolygons: () => import_polycss_core28.planePolygons,
113
118
  pointInMeshElement: () => pointInMeshElement,
114
- polyCssDistanceToWorld: () => import_polycss_core27.cssDistanceToWorld,
115
- polyCssPositionToWorld: () => import_polycss_core27.cssPositionToWorld,
116
- polygonCssSurfaceNormal: () => import_polycss_core27.polygonCssSurfaceNormal,
117
- polygonFaces: () => import_polycss_core27.polygonFaces,
118
- polygonFacesCamera: () => import_polycss_core27.polygonFacesCamera,
119
- repairMeshSeams: () => import_polycss_core27.repairMeshSeams,
120
- ringPolygons: () => import_polycss_core27.ringPolygons,
121
- rotateVec3: () => import_polycss_core27.rotateVec3,
122
- seamFacetSplitPolygons: () => import_polycss_core27.seamFacetSplitPolygons,
123
- seamFacetSplitReport: () => import_polycss_core27.seamFacetSplitReport,
124
- seamOverlapDiagnostics: () => import_polycss_core27.seamOverlapDiagnostics,
125
- seamOverlapPolygons: () => import_polycss_core27.seamOverlapPolygons,
126
- seamOverlapReport: () => import_polycss_core27.seamOverlapReport,
127
- shadeColor: () => import_polycss_core27.shadeColor,
128
- simplifyTriangleMeshPolygons: () => import_polycss_core27.simplifyTriangleMeshPolygons,
129
- tetrahedronPolygons: () => import_polycss_core27.tetrahedronPolygons,
130
- torusPolygons: () => import_polycss_core27.torusPolygons,
119
+ polyCameraTargetToCss: () => import_polycss_core28.polyCameraTargetToCss,
120
+ polyCssDistanceToWorld: () => import_polycss_core28.polyCssDistanceToWorld,
121
+ polyCssPositionToWorld: () => import_polycss_core28.polyCssPositionToWorld,
122
+ polygonCssSurfaceNormal: () => import_polycss_core28.polygonCssSurfaceNormal,
123
+ polygonFaces: () => import_polycss_core28.polygonFaces,
124
+ polygonFacesCamera: () => import_polycss_core28.polygonFacesCamera,
125
+ queryPolyLeaves: () => queryPolyLeaves,
126
+ repairMeshSeams: () => import_polycss_core28.repairMeshSeams,
127
+ resolvePolyCameraAppliedPerspectiveStyle: () => import_polycss_core28.resolvePolyCameraAppliedPerspectiveStyle,
128
+ ringPolygons: () => import_polycss_core28.ringPolygons,
129
+ rotateVec3: () => import_polycss_core28.rotateVec3,
130
+ seamFacetSplitPolygons: () => import_polycss_core28.seamFacetSplitPolygons,
131
+ seamFacetSplitReport: () => import_polycss_core28.seamFacetSplitReport,
132
+ seamOverlapDiagnostics: () => import_polycss_core28.seamOverlapDiagnostics,
133
+ seamOverlapPolygons: () => import_polycss_core28.seamOverlapPolygons,
134
+ seamOverlapReport: () => import_polycss_core28.seamOverlapReport,
135
+ shadeColor: () => import_polycss_core28.shadeColor,
136
+ simplifyTriangleMeshPolygons: () => import_polycss_core28.simplifyTriangleMeshPolygons,
137
+ tetrahedronPolygons: () => import_polycss_core28.tetrahedronPolygons,
138
+ torusPolygons: () => import_polycss_core28.torusPolygons,
131
139
  useCameraContext: () => useCameraContext,
132
140
  usePolyAnimation: () => usePolyAnimation,
133
141
  usePolyCamera: () => usePolyCamera,
@@ -136,10 +144,14 @@ __export(src_exports, {
136
144
  usePolySceneContext: () => usePolySceneContext,
137
145
  usePolySelect: () => usePolySelect,
138
146
  usePolySelectionApi: () => usePolySelectionApi,
139
- worldDirectionToPolyCss: () => import_polycss_core27.worldDirectionToCss,
140
- worldDirectionalLightToPolyCss: () => import_polycss_core27.worldDirectionalLightToCss,
141
- worldDistanceToPolyCss: () => import_polycss_core27.worldDistanceToCss,
142
- worldPositionToPolyCss: () => import_polycss_core27.worldPositionToCss
147
+ worldDirectionToCss: () => import_polycss_core28.worldDirectionToCss,
148
+ worldDirectionToPolyCss: () => import_polycss_core28.worldDirectionToPolyCss,
149
+ worldDirectionalLightToCss: () => import_polycss_core28.worldDirectionalLightToCss,
150
+ worldDirectionalLightToPolyCss: () => import_polycss_core28.worldDirectionalLightToPolyCss,
151
+ worldDistanceToCss: () => import_polycss_core28.worldDistanceToCss,
152
+ worldDistanceToPolyCss: () => import_polycss_core28.worldDistanceToPolyCss,
153
+ worldPositionToCss: () => import_polycss_core28.worldPositionToCss,
154
+ worldPositionToPolyCss: () => import_polycss_core28.worldPositionToPolyCss
143
155
  });
144
156
  module.exports = __toCommonJS(src_exports);
145
157
 
@@ -205,6 +217,18 @@ function useStoreSelector(store, selector) {
205
217
  }
206
218
 
207
219
  // src/camera/useCamera.ts
220
+ function writeCameraSnapshotAttrs(el, camera, projection, perspectiveStyle) {
221
+ if (!el) return;
222
+ const snapshot = (0, import_polycss_core.capturePolyCameraSnapshot)(camera, { projection, perspectiveStyle });
223
+ el.dataset.polycssCameraProjection = snapshot.projection;
224
+ el.dataset.polycssCameraPerspective = snapshot.perspectiveStyle;
225
+ el.dataset.polycssCameraAppliedPerspective = snapshot.appliedPerspectiveStyle;
226
+ el.dataset.polycssCameraZoom = String(snapshot.state.zoom);
227
+ el.dataset.polycssCameraDistance = String(snapshot.state.distance);
228
+ el.dataset.polycssCameraRotX = String(snapshot.state.rotX);
229
+ el.dataset.polycssCameraRotY = String(snapshot.state.rotY);
230
+ el.dataset.polycssCameraTarget = snapshot.state.target.join(",");
231
+ }
208
232
  function usePolyCamera(options) {
209
233
  const handleRef = (0, import_react3.useRef)(null);
210
234
  if (!handleRef.current) {
@@ -234,24 +258,33 @@ function usePolyCamera(options) {
234
258
  handle.update(next);
235
259
  const el = sceneElRef.current;
236
260
  if (el) {
237
- el.style.transform = (0, import_polycss_core.buildPolySceneTransform)({
238
- ...handle.state,
261
+ el.style.transform = (0, import_polycss_core.buildPolyCameraSceneTransform)(handle.state, {
239
262
  autoCenterOffset: store.getState().autoCenterOffset
240
263
  });
241
264
  }
242
265
  store.updateCameraFromRef(handle);
243
266
  store.notifyAll();
244
267
  }
245
- }, [options.zoom, options.target, options.rotX, options.rotY, options.distance, store]);
268
+ writeCameraSnapshotAttrs(cameraElRef.current, handle, options.projection, options.perspectiveStyle);
269
+ }, [
270
+ options.zoom,
271
+ options.target,
272
+ options.rotX,
273
+ options.rotY,
274
+ options.distance,
275
+ options.projection,
276
+ options.perspectiveStyle,
277
+ store
278
+ ]);
246
279
  const applyTransformDirect = (0, import_react3.useCallback)(() => {
247
280
  const el = sceneElRef.current;
248
281
  if (!el) return;
249
282
  const handle = handleRef.current;
250
- el.style.transform = (0, import_polycss_core.buildPolySceneTransform)({
251
- ...handle.state,
283
+ el.style.transform = (0, import_polycss_core.buildPolyCameraSceneTransform)(handle.state, {
252
284
  autoCenterOffset: store.getState().autoCenterOffset
253
285
  });
254
- }, [store]);
286
+ writeCameraSnapshotAttrs(cameraElRef.current, handle, options.projection, options.perspectiveStyle);
287
+ }, [store, options.projection, options.perspectiveStyle]);
255
288
  return {
256
289
  store,
257
290
  cameraRef: handleRef,
@@ -275,18 +308,26 @@ function PolyPerspectiveCameraInner({
275
308
  className,
276
309
  style
277
310
  }) {
311
+ const perspectiveValue = `${typeof perspective === "number" ? perspective : DEFAULT_PERSPECTIVE}px`;
278
312
  const {
279
313
  store,
280
314
  cameraRef,
281
315
  sceneElRef,
282
316
  cameraElRef,
283
317
  applyTransformDirect
284
- } = usePolyCamera({ zoom, target, rotX, rotY, distance });
318
+ } = usePolyCamera({
319
+ zoom,
320
+ target,
321
+ rotX,
322
+ rotY,
323
+ distance,
324
+ projection: "perspective",
325
+ perspectiveStyle: perspectiveValue
326
+ });
285
327
  const contextValue = (0, import_react4.useMemo)(
286
328
  () => ({ store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect }),
287
329
  [store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect]
288
330
  );
289
- const perspectiveValue = `${typeof perspective === "number" ? perspective : DEFAULT_PERSPECTIVE}px`;
290
331
  const cameraStyle = {
291
332
  ...style,
292
333
  perspective: perspectiveValue
@@ -297,6 +338,14 @@ function PolyPerspectiveCameraInner({
297
338
  ref: cameraElRef,
298
339
  className: `polycss-camera${className ? ` ${className}` : ""}`,
299
340
  style: cameraStyle,
341
+ "data-polycss-camera-projection": "perspective",
342
+ "data-polycss-camera-perspective": perspectiveValue,
343
+ "data-polycss-camera-applied-perspective": perspectiveValue,
344
+ "data-polycss-camera-zoom": cameraRef.current.state.zoom,
345
+ "data-polycss-camera-distance": cameraRef.current.state.distance,
346
+ "data-polycss-camera-rot-x": cameraRef.current.state.rotX,
347
+ "data-polycss-camera-rot-y": cameraRef.current.state.rotY,
348
+ "data-polycss-camera-target": cameraRef.current.state.target.join(","),
300
349
  children
301
350
  }
302
351
  ) });
@@ -322,7 +371,15 @@ function PolyOrthographicCameraInner({
322
371
  sceneElRef,
323
372
  cameraElRef,
324
373
  applyTransformDirect
325
- } = usePolyCamera({ zoom, target, rotX, rotY, distance });
374
+ } = usePolyCamera({
375
+ zoom,
376
+ target,
377
+ rotX,
378
+ rotY,
379
+ distance,
380
+ projection: "orthographic",
381
+ perspectiveStyle: "none"
382
+ });
326
383
  const contextValue = (0, import_react5.useMemo)(
327
384
  () => ({ store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect }),
328
385
  [store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect]
@@ -342,6 +399,14 @@ function PolyOrthographicCameraInner({
342
399
  ref: cameraElRef,
343
400
  className: `polycss-camera${className ? ` ${className}` : ""}`,
344
401
  style: cameraStyle,
402
+ "data-polycss-camera-projection": "orthographic",
403
+ "data-polycss-camera-perspective": "none",
404
+ "data-polycss-camera-applied-perspective": "1000000px",
405
+ "data-polycss-camera-zoom": cameraRef.current.state.zoom,
406
+ "data-polycss-camera-distance": cameraRef.current.state.distance,
407
+ "data-polycss-camera-rot-x": cameraRef.current.state.rotX,
408
+ "data-polycss-camera-rot-y": cameraRef.current.state.rotY,
409
+ "data-polycss-camera-target": cameraRef.current.state.target.join(","),
345
410
  children
346
411
  }
347
412
  ) });
@@ -524,8 +589,8 @@ var CORE_BASE_STYLES = `
524
589
  }
525
590
 
526
591
  .polycss-scene s {
527
- width: var(--polycss-atlas-size, 64px);
528
- height: var(--polycss-atlas-size, 64px);
592
+ width: var(--polycss-atlas-width, var(--polycss-atlas-size, 64px));
593
+ height: var(--polycss-atlas-height, var(--polycss-atlas-size, 64px));
529
594
  }
530
595
 
531
596
  .polycss-scene u {
@@ -922,13 +987,16 @@ function isSolidTriangleSupported(doc) {
922
987
 
923
988
  // src/scene/atlas/filterPlans.ts
924
989
  var import_polycss_core4 = require("@layoutit/polycss-core");
925
- function filterAtlasPlans(plans, textureLighting, disabled, doc) {
990
+ function filterAtlasPlans(plans, textureLighting, disabled, doc, textureBackend, textureImageRendering, textureProjection) {
926
991
  const d = doc ?? (typeof document !== "undefined" ? document : null);
927
992
  return (0, import_polycss_core4.filterAtlasPlans)(plans, textureLighting, disabled, {
928
993
  solidTriangleSupported: isSolidTriangleSupported(doc),
929
994
  projectiveQuadSupported: doc ? projectiveQuadSupported(doc) : true,
930
995
  borderShapeSupported: isBorderShapeSupported(doc),
931
- cornerShapeSupported: d ? cornerShapeSupported(d) : false
996
+ cornerShapeSupported: d ? cornerShapeSupported(d) : false,
997
+ textureBackend,
998
+ textureImageRendering,
999
+ textureProjection
932
1000
  });
933
1001
  }
934
1002
 
@@ -941,8 +1009,13 @@ function isMobileDocument(doc) {
941
1009
  if (!media) return false;
942
1010
  return media("(pointer: coarse)").matches || media("(hover: none)").matches;
943
1011
  }
944
- function packTextureAtlasPlansWithScale(plans, textureQualityInput, doc) {
945
- return (0, import_polycss_core5.packTextureAtlasPlansWithScaleCore)(plans, textureQualityInput, isMobileDocument(doc));
1012
+ function packTextureAtlasPlansWithScale(plans, textureQualityInput, doc, textureLeafSizing) {
1013
+ return (0, import_polycss_core5.packTextureAtlasPlansWithScaleCore)(
1014
+ plans,
1015
+ textureQualityInput,
1016
+ isMobileDocument(doc),
1017
+ textureLeafSizing
1018
+ );
946
1019
  }
947
1020
 
948
1021
  // src/scene/atlas/buildAtlasPages.ts
@@ -2148,7 +2221,7 @@ function deferRevoke(urls) {
2148
2221
  if (typeof requestAnimationFrame === "function") requestAnimationFrame(run);
2149
2222
  else setTimeout(run, 0);
2150
2223
  }
2151
- function useTextureAtlas(plans, textureLighting, textureQualityInput, strategies, atomic = false) {
2224
+ function useTextureAtlas(plans, textureLighting, textureQualityInput, textureLeafSizing, textureBackend, textureImageRendering, textureProjection, strategies, atomic = false) {
2152
2225
  const disabled = (0, import_react7.useMemo)(
2153
2226
  () => new Set(strategies?.disable ?? []),
2154
2227
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2159,17 +2232,21 @@ function useTextureAtlas(plans, textureLighting, textureQualityInput, strategies
2159
2232
  plans,
2160
2233
  textureLighting,
2161
2234
  disabled,
2162
- typeof document !== "undefined" ? document : null
2235
+ typeof document !== "undefined" ? document : null,
2236
+ textureBackend,
2237
+ textureImageRendering,
2238
+ textureProjection
2163
2239
  ),
2164
- [plans, textureLighting, disabled]
2240
+ [plans, textureLighting, disabled, textureBackend, textureImageRendering, textureProjection]
2165
2241
  );
2166
2242
  const { packed, atlasScale } = (0, import_react7.useMemo)(
2167
2243
  () => packTextureAtlasPlansWithScale(
2168
2244
  atlasPlans,
2169
2245
  textureQualityInput,
2170
- typeof document !== "undefined" ? document : null
2246
+ typeof document !== "undefined" ? document : null,
2247
+ textureLeafSizing
2171
2248
  ),
2172
- [atlasPlans, textureQualityInput]
2249
+ [atlasPlans, textureQualityInput, textureLeafSizing]
2173
2250
  );
2174
2251
  const [pages, setPages] = (0, import_react7.useState)(() => pageShells(packed.pages));
2175
2252
  const [frame, setFrame] = (0, import_react7.useState)(() => ({
@@ -2519,6 +2596,7 @@ var TextureAtlasPoly = (0, import_react12.memo)(function TextureAtlasPoly2({
2519
2596
  entry,
2520
2597
  page,
2521
2598
  textureLighting,
2599
+ textureImageRendering,
2522
2600
  solidPaintDefaults: _solidPaintDefaults,
2523
2601
  className,
2524
2602
  style: styleProp,
@@ -2528,26 +2606,26 @@ var TextureAtlasPoly = (0, import_react12.memo)(function TextureAtlasPoly2({
2528
2606
  }) {
2529
2607
  const ATLAS_CANONICAL_SIZE_EXPLICIT = 64;
2530
2608
  const dynamic = textureLighting === "dynamic";
2609
+ const resolvedImageRendering = (0, import_polycss_core11.resolvePolyTextureImageRendering)(entry.polygon, textureImageRendering);
2531
2610
  const atlasCanonicalSize = entry.atlasCanonicalSize ?? ATLAS_CANONICAL_SIZE_EXPLICIT;
2611
+ const atlasLeafWidth = entry.atlasLeafWidth ?? atlasCanonicalSize;
2612
+ const atlasLeafHeight = entry.atlasLeafHeight ?? atlasCanonicalSize;
2532
2613
  const atlasWidth = entry.canvasW || 1;
2533
2614
  const atlasHeight = entry.canvasH || 1;
2534
- const atlasPosition = page ? `${(0, import_polycss_core11.formatCssLengthPx)(-entry.x / atlasWidth * atlasCanonicalSize)} ${(0, import_polycss_core11.formatCssLengthPx)(-entry.y / atlasHeight * atlasCanonicalSize)}` : void 0;
2535
- const atlasSize = page ? `${(0, import_polycss_core11.formatCssLengthPx)(page.width / atlasWidth * atlasCanonicalSize)} ${(0, import_polycss_core11.formatCssLengthPx)(page.height / atlasHeight * atlasCanonicalSize)}` : void 0;
2615
+ const atlasPosition = page ? `${(0, import_polycss_core11.formatCssLengthPx)(-entry.x / atlasWidth * atlasLeafWidth)} ${(0, import_polycss_core11.formatCssLengthPx)(-entry.y / atlasHeight * atlasLeafHeight)}` : void 0;
2616
+ const atlasSize = page ? `${(0, import_polycss_core11.formatCssLengthPx)(page.width / atlasWidth * atlasLeafWidth)} ${(0, import_polycss_core11.formatCssLengthPx)(page.height / atlasHeight * atlasLeafHeight)}` : void 0;
2536
2617
  const dynamicMask = dynamic && page?.url ? `url(${page.url})` : void 0;
2537
- const background = !dynamic && page?.url ? `url(${page.url}) ${atlasPosition} / ${atlasSize} no-repeat` : void 0;
2538
2618
  const style = {
2539
2619
  transform: (0, import_polycss_core11.formatMatrix3d)(entry.atlasMatrix),
2540
2620
  ["--polycss-atlas-size"]: `${atlasCanonicalSize}px`,
2541
- // Listing the `background` shorthand alongside the `background-*` longhands
2542
- // in one inline style object makes React warn on every update (mixing
2543
- // shorthand and non-shorthand for the same property). Branch so only the
2544
- // current mode's keys are assigned — baked gets `background`, dynamic gets
2545
- // the longhands.
2546
- ...dynamic ? {
2547
- backgroundImage: page?.url ? `url(${page.url})` : void 0,
2548
- backgroundPosition: atlasPosition,
2549
- backgroundSize: atlasSize
2550
- } : { background },
2621
+ ["--polycss-atlas-width"]: (0, import_polycss_core11.formatCssLengthPx)(atlasLeafWidth),
2622
+ ["--polycss-atlas-height"]: (0, import_polycss_core11.formatCssLengthPx)(atlasLeafHeight),
2623
+ ["--polycss-atlas-leaf-sizing"]: entry.atlasLeafSizing ?? "canonical",
2624
+ backgroundImage: page?.url ? `url(${page.url})` : void 0,
2625
+ backgroundPosition: atlasPosition,
2626
+ backgroundSize: atlasSize,
2627
+ backgroundRepeat: page?.url ? "no-repeat" : void 0,
2628
+ imageRendering: resolvedImageRendering === "pixelated" ? "pixelated" : void 0,
2551
2629
  ...dynamic ? {
2552
2630
  ["--pnx"]: entry.normal[0].toFixed(4),
2553
2631
  ["--pny"]: entry.normal[1].toFixed(4),
@@ -2578,6 +2656,74 @@ var TextureAtlasPoly = (0, import_react12.memo)(function TextureAtlasPoly2({
2578
2656
  className: elementClassName,
2579
2657
  style,
2580
2658
  "data-poly-index": entry.index,
2659
+ "data-polycss-leaf": "polygon",
2660
+ "data-polycss-texture-backend": "atlas",
2661
+ "data-polycss-texture-leaf-sizing": entry.atlasLeafSizing ?? "canonical",
2662
+ "data-polycss-texture-ready": page?.url ? "true" : "false",
2663
+ "data-polycss-texture-image-rendering": resolvedImageRendering,
2664
+ "data-polycss-texture-projection": "affine",
2665
+ "data-polycss-texture-lighting": textureLighting,
2666
+ "data-polycss-texture-leaf-width": atlasLeafWidth,
2667
+ "data-polycss-texture-leaf-height": atlasLeafHeight,
2668
+ "data-polycss-double-sided": entry.polygon.doubleSided ? "true" : void 0,
2669
+ ...domEventHandlers,
2670
+ ...dataAttrs,
2671
+ ...domAttrs
2672
+ }
2673
+ );
2674
+ });
2675
+ var TextureImagePoly = (0, import_react12.memo)(function TextureImagePoly2({
2676
+ plan,
2677
+ geometry,
2678
+ className,
2679
+ style: styleProp,
2680
+ domAttrs,
2681
+ domEventHandlers,
2682
+ pointerEvents = "auto"
2683
+ }) {
2684
+ const style = {
2685
+ transform: (0, import_polycss_core11.formatMatrix3d)(geometry.matrix),
2686
+ ["--polycss-atlas-width"]: (0, import_polycss_core11.formatCssLengthPx)(geometry.leafWidth),
2687
+ ["--polycss-atlas-height"]: (0, import_polycss_core11.formatCssLengthPx)(geometry.leafHeight),
2688
+ ["--polycss-atlas-leaf-sizing"]: "image",
2689
+ backgroundImage: `url(${geometry.url})`,
2690
+ backgroundPosition: `${(0, import_polycss_core11.formatCssLengthPx)(geometry.backgroundPosition[0])} ${(0, import_polycss_core11.formatCssLengthPx)(geometry.backgroundPosition[1])}`,
2691
+ backgroundSize: `${(0, import_polycss_core11.formatCssLengthPx)(geometry.backgroundSize[0])} ${(0, import_polycss_core11.formatCssLengthPx)(geometry.backgroundSize[1])}`,
2692
+ backgroundRepeat: "no-repeat",
2693
+ backgroundBlendMode: "normal",
2694
+ maskImage: "none",
2695
+ WebkitMaskImage: "none",
2696
+ imageRendering: geometry.imageRendering === "pixelated" ? "pixelated" : void 0,
2697
+ ["--pnx"]: plan.normal[0].toFixed(4),
2698
+ ["--pny"]: plan.normal[1].toFixed(4),
2699
+ ["--pnz"]: plan.normal[2].toFixed(4),
2700
+ pointerEvents: pointerEvents === "none" ? "none" : void 0,
2701
+ ...styleProp
2702
+ };
2703
+ const dataAttrs = plan.polygon.data ? Object.fromEntries(
2704
+ Object.entries(plan.polygon.data).map(([k, v]) => [`data-${k}`, String(v)])
2705
+ ) : {};
2706
+ const elementClassName = className?.trim() || void 0;
2707
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2708
+ "s",
2709
+ {
2710
+ className: elementClassName,
2711
+ style,
2712
+ "data-poly-index": plan.index,
2713
+ "data-polycss-leaf": "polygon",
2714
+ "data-polycss-texture-backend": "image",
2715
+ "data-polycss-texture-leaf-sizing": "image",
2716
+ "data-polycss-texture-ready": "true",
2717
+ "data-polycss-texture-image-rendering": geometry.imageRendering,
2718
+ "data-polycss-texture-projection": geometry.projection,
2719
+ "data-polycss-texture-lighting": geometry.lighting,
2720
+ "data-polycss-texture-leaf-width": geometry.leafWidth,
2721
+ "data-polycss-texture-leaf-height": geometry.leafHeight,
2722
+ "data-polycss-double-sided": plan.polygon.doubleSided ? "true" : void 0,
2723
+ "data-polycss-texture-source-x": geometry.sourceRect.x,
2724
+ "data-polycss-texture-source-y": geometry.sourceRect.y,
2725
+ "data-polycss-texture-source-width": geometry.sourceRect.width,
2726
+ "data-polycss-texture-source-height": geometry.sourceRect.height,
2581
2727
  ...domEventHandlers,
2582
2728
  ...dataAttrs,
2583
2729
  ...domAttrs
@@ -2602,9 +2748,14 @@ function PolySceneInner({
2602
2748
  rotY: _rotY,
2603
2749
  zoom: _zoom,
2604
2750
  directionalLight,
2751
+ pointLights,
2605
2752
  ambientLight,
2606
2753
  textureLighting = "baked",
2607
2754
  textureQuality,
2755
+ textureLeafSizing,
2756
+ textureImageRendering,
2757
+ textureBackend,
2758
+ textureProjection,
2608
2759
  seamBleed = import_polycss_core13.DEFAULT_SEAM_BLEED,
2609
2760
  strategies,
2610
2761
  autoCenter = false,
@@ -2655,17 +2806,19 @@ function PolySceneInner({
2655
2806
  const sceneBbox = centerInputPolygons ? centerSceneBbox : renderSceneBbox;
2656
2807
  const directionalForAtlas = textureLighting === "dynamic" ? void 0 : directionalLight;
2657
2808
  const ambientForAtlas = textureLighting === "dynamic" ? void 0 : ambientLight;
2809
+ const pointLightsForAtlas = textureLighting === "dynamic" ? void 0 : pointLights;
2658
2810
  const polyContext = (0, import_react14.useMemo)(() => {
2659
2811
  const tileSize = 50;
2660
2812
  return {
2661
2813
  tileSize,
2662
2814
  layerElevation: tileSize,
2663
2815
  directionalLight: directionalForAtlas,
2816
+ pointLights: pointLightsForAtlas,
2664
2817
  ambientLight: ambientForAtlas,
2665
2818
  textureLighting,
2666
2819
  seamBleed
2667
2820
  };
2668
- }, [directionalForAtlas, ambientForAtlas, textureLighting, seamBleed]);
2821
+ }, [directionalForAtlas, pointLightsForAtlas, ambientForAtlas, textureLighting, seamBleed]);
2669
2822
  const autoCenterOffset = (0, import_react14.useMemo)(() => {
2670
2823
  if (!autoCenter) return [0, 0, 0];
2671
2824
  return [
@@ -2700,7 +2853,16 @@ function PolySceneInner({
2700
2853
  },
2701
2854
  [polygons, polyContext, seamBleed, directionalForAtlas, ambientForAtlas]
2702
2855
  );
2703
- const textureAtlas = useTextureAtlas(textureAtlasPlans, textureLighting, textureQuality, strategies);
2856
+ const textureAtlas = useTextureAtlas(
2857
+ textureAtlasPlans,
2858
+ textureLighting,
2859
+ textureQuality,
2860
+ textureLeafSizing,
2861
+ textureBackend,
2862
+ textureImageRendering,
2863
+ textureProjection,
2864
+ strategies
2865
+ );
2704
2866
  const dynamicLightVars = (0, import_react14.useMemo)(() => {
2705
2867
  if (textureLighting !== "dynamic") return null;
2706
2868
  const userDir = directionalLight?.direction ?? [0.4, -0.7, 0.59];
@@ -2798,12 +2960,28 @@ function PolySceneInner({
2798
2960
  {
2799
2961
  entry,
2800
2962
  page: textureAtlas.pages[entry.pageIndex],
2801
- textureLighting
2963
+ textureLighting,
2964
+ textureImageRendering
2802
2965
  },
2803
2966
  entry.index
2804
2967
  );
2805
2968
  }
2806
2969
  const plan = textureAtlasPlans[index];
2970
+ const imageGeometry = plan ? (0, import_polycss_core13.resolvePolyTextureLeafGeometry)(plan, {
2971
+ imageRendering: textureImageRendering,
2972
+ backend: textureBackend,
2973
+ projection: textureProjection
2974
+ }) : null;
2975
+ if (plan && imageGeometry) {
2976
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2977
+ TextureImagePoly,
2978
+ {
2979
+ plan,
2980
+ geometry: imageGeometry
2981
+ },
2982
+ plan.index
2983
+ );
2984
+ }
2807
2985
  if (!plan || plan.texture) return null;
2808
2986
  const useU = !disabledStrategies?.has("u");
2809
2987
  const useProjectiveSolid = !disabledStrategies?.has("b");
@@ -2826,9 +3004,14 @@ function PolySceneInner({
2826
3004
  () => ({
2827
3005
  textureLighting,
2828
3006
  directionalLight,
3007
+ pointLights,
2829
3008
  ambientLight,
2830
3009
  strategies,
2831
3010
  seamBleed,
3011
+ textureLeafSizing,
3012
+ textureImageRendering,
3013
+ textureBackend,
3014
+ textureProjection,
2832
3015
  shadow,
2833
3016
  registerShadowCaster,
2834
3017
  registerShadowReceiver,
@@ -2838,7 +3021,7 @@ function PolySceneInner({
2838
3021
  groundCssZ,
2839
3022
  sceneEl
2840
3023
  }),
2841
- [textureLighting, directionalLight, ambientLight, strategies, seamBleed, shadow, registerShadowCaster, registerShadowReceiver, shadowCastersVersion, hasShadowReceiver, groundCssZ, sceneEl]
3024
+ [textureLighting, directionalLight, pointLights, ambientLight, strategies, seamBleed, textureLeafSizing, textureImageRendering, textureBackend, textureProjection, shadow, registerShadowCaster, registerShadowReceiver, shadowCastersVersion, hasShadowReceiver, groundCssZ, sceneEl]
2842
3025
  );
2843
3026
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PolySceneContext.Provider, { value: sceneCtxValue, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2844
3027
  "div",
@@ -3719,11 +3902,16 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
3719
3902
  autoCenter,
3720
3903
  textureLighting,
3721
3904
  textureQuality,
3905
+ textureLeafSizing,
3906
+ textureImageRendering,
3907
+ textureBackend,
3908
+ textureProjection,
3722
3909
  seamBleed,
3723
3910
  atomicAtlas,
3724
3911
  onFrameReady,
3725
3912
  castShadow,
3726
3913
  receiveShadow,
3914
+ shadowDefinition,
3727
3915
  merge = true,
3728
3916
  children,
3729
3917
  fallback,
@@ -3788,6 +3976,12 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
3788
3976
  const stableTriangleColorFrameRef = (0, import_react16.useRef)(0);
3789
3977
  const setPolygonsImplRef = (0, import_react16.useRef)(() => {
3790
3978
  });
3979
+ const textureReadyRef = (0, import_react16.useRef)(true);
3980
+ const textureReadyWaitersRef = (0, import_react16.useRef)([]);
3981
+ const resolveTextureReadyWaiters = (0, import_react16.useCallback)(() => {
3982
+ const waiters = textureReadyWaitersRef.current.splice(0);
3983
+ for (const resolve of waiters) resolve();
3984
+ }, []);
3791
3985
  const handle = (0, import_react16.useMemo)(() => ({
3792
3986
  get element() {
3793
3987
  return wrapperRef.current;
@@ -3801,6 +3995,12 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
3801
3995
  setPolygonsImplRef.current(nextPolygons);
3802
3996
  },
3803
3997
  rebakeAtlas: () => setBakedRotation(propsRef.current.rotation),
3998
+ whenTexturesReady() {
3999
+ if (textureReadyRef.current) return Promise.resolve();
4000
+ return new Promise((resolve) => {
4001
+ textureReadyWaitersRef.current.push(resolve);
4002
+ });
4003
+ },
3804
4004
  updatePolygon(target, partial) {
3805
4005
  const current = polygonsRef.current;
3806
4006
  const idx = typeof target === "number" ? target : current.indexOf(target);
@@ -3947,6 +4147,10 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
3947
4147
  [effectiveStrategies]
3948
4148
  );
3949
4149
  const effectiveSeamBleed = seamBleed ?? sceneCtx?.seamBleed ?? import_polycss_core16.DEFAULT_SEAM_BLEED;
4150
+ const effectiveTextureLeafSizing = textureLeafSizing ?? sceneCtx?.textureLeafSizing;
4151
+ const effectiveTextureImageRendering = textureImageRendering ?? sceneCtx?.textureImageRendering;
4152
+ const effectiveTextureBackend = textureBackend ?? sceneCtx?.textureBackend;
4153
+ const effectiveTextureProjection = textureProjection ?? sceneCtx?.textureProjection;
3950
4154
  const effectiveDirectional = sceneCtx?.directionalLight;
3951
4155
  const effectiveAmbient = sceneCtx?.ambientLight;
3952
4156
  const directVoxelEnabled = Boolean(
@@ -3976,6 +4180,18 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
3976
4180
  direction: (0, import_polycss_core16.inverseRotateVec3)(cssLight.direction, rot)
3977
4181
  };
3978
4182
  }, [effectiveDirectional, bakedRotation]);
4183
+ const bakedPointLights = (0, import_react16.useMemo)(() => {
4184
+ const pls = sceneCtx?.pointLights;
4185
+ if (!pls || pls.length === 0) return void 0;
4186
+ const pos = position ?? [0, 0, 0];
4187
+ const rot = bakedRotation ?? [0, 0, 0];
4188
+ const hasRot = rot[0] !== 0 || rot[1] !== 0 || rot[2] !== 0;
4189
+ return pls.map((pl) => {
4190
+ const rel = [pl.position[0] - pos[0], pl.position[1] - pos[1], pl.position[2] - pos[2]];
4191
+ const local = hasRot ? (0, import_polycss_core16.inverseRotateVec3)(rel, rot) : rel;
4192
+ return { ...pl, position: local };
4193
+ });
4194
+ }, [sceneCtx?.pointLights, position, bakedRotation]);
3979
4195
  const lightOccludedPolyIndices = void 0;
3980
4196
  const atlasPlans = (0, import_react16.useMemo)(
3981
4197
  () => {
@@ -3994,6 +4210,7 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
3994
4210
  i,
3995
4211
  {
3996
4212
  directionalLight: bakedDirectional,
4213
+ pointLights: bakedPointLights,
3997
4214
  ambientLight: effectiveAmbient,
3998
4215
  seamBleed: seamBleedEdges?.has(i) ? effectiveSeamBleed : void 0,
3999
4216
  seamEdges: seamBleedEdges?.get(i),
@@ -4003,15 +4220,24 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4003
4220
  basisHints[i]
4004
4221
  ));
4005
4222
  },
4006
- [renderPolygon, directVoxelEnabled, polygons, bakedDirectional, effectiveAmbient, effectiveSeamBleed, lightOccludedPolyIndices]
4223
+ [renderPolygon, directVoxelEnabled, polygons, bakedDirectional, bakedPointLights, effectiveAmbient, effectiveSeamBleed, lightOccludedPolyIndices]
4007
4224
  );
4008
4225
  const textureAtlas = useTextureAtlas(
4009
4226
  atlasPlans,
4010
4227
  effectiveTextureLighting,
4011
4228
  textureQuality,
4229
+ effectiveTextureLeafSizing,
4230
+ effectiveTextureBackend,
4231
+ effectiveTextureImageRendering,
4232
+ effectiveTextureProjection,
4012
4233
  effectiveStrategies,
4013
4234
  atomicAtlas
4014
4235
  );
4236
+ textureReadyRef.current = textureAtlas.ready;
4237
+ (0, import_react16.useEffect)(() => {
4238
+ if (textureAtlas.ready) resolveTextureReadyWaiters();
4239
+ }, [textureAtlas.ready, resolveTextureReadyWaiters]);
4240
+ (0, import_react16.useEffect)(() => resolveTextureReadyWaiters, [resolveTextureReadyWaiters]);
4015
4241
  const solidPaintDefaults = (0, import_react16.useMemo)(
4016
4242
  () => !renderPolygon ? getSolidPaintDefaults(textureAtlas.plans, effectiveTextureLighting, effectiveStrategies) : {},
4017
4243
  [renderPolygon, textureAtlas.plans, effectiveTextureLighting, effectiveStrategies]
@@ -4040,23 +4266,32 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4040
4266
  }
4041
4267
  return s;
4042
4268
  }, [atlasPlans, polygons]);
4269
+ const shadowCasterRegisteredRef = (0, import_react16.useRef)(false);
4270
+ const lastShadowPolyCountRef = (0, import_react16.useRef)(-1);
4043
4271
  (0, import_react16.useEffect)(() => {
4044
- if (!sceneRegisterShadowCaster) return;
4045
- if (castShadow) {
4046
- sceneRegisterShadowCaster(meshIdRef.current, {
4047
- polygons,
4048
- position: position ?? [0, 0, 0],
4049
- scale,
4050
- rotation,
4051
- renderedPolygonIndices
4052
- });
4053
- } else {
4054
- sceneRegisterShadowCaster(meshIdRef.current, null);
4055
- }
4272
+ if (!sceneRegisterShadowCaster || !castShadow) return;
4056
4273
  return () => {
4057
4274
  sceneRegisterShadowCaster(meshIdRef.current, null);
4275
+ shadowCasterRegisteredRef.current = false;
4276
+ lastShadowPolyCountRef.current = -1;
4058
4277
  };
4059
- }, [sceneRegisterShadowCaster, castShadow, polygons, position, scale, rotation, renderedPolygonIndices]);
4278
+ }, [sceneRegisterShadowCaster, castShadow]);
4279
+ (0, import_react16.useEffect)(() => {
4280
+ if (!sceneRegisterShadowCaster || !castShadow) return;
4281
+ const followAnimation = sceneCtx?.shadow?.followAnimation ?? false;
4282
+ const topologyChanged = polygons.length !== lastShadowPolyCountRef.current;
4283
+ if (shadowCasterRegisteredRef.current && !followAnimation && !topologyChanged) return;
4284
+ lastShadowPolyCountRef.current = polygons.length;
4285
+ shadowCasterRegisteredRef.current = true;
4286
+ sceneRegisterShadowCaster(meshIdRef.current, {
4287
+ polygons,
4288
+ position: position ?? [0, 0, 0],
4289
+ scale,
4290
+ rotation,
4291
+ renderedPolygonIndices,
4292
+ shadowDefinition
4293
+ });
4294
+ }, [sceneRegisterShadowCaster, castShadow, polygons, position, scale, rotation, renderedPolygonIndices, shadowDefinition, sceneCtx?.shadow]);
4060
4295
  const sceneRegisterShadowReceiver = sceneCtx?.registerShadowReceiver;
4061
4296
  (0, import_react16.useEffect)(() => {
4062
4297
  if (!sceneRegisterShadowReceiver) return;
@@ -4182,6 +4417,16 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4182
4417
  if (!shadowCasters || shadowCasters.size === 0) return null;
4183
4418
  const userLightDir = sceneDirectionalLight?.direction ?? [0.4, -0.7, 0.59];
4184
4419
  const lightDir = (0, import_polycss_core16.worldDirectionToCss)(userLightDir);
4420
+ const dynamicShading = effectiveTextureLighting === "dynamic";
4421
+ const scenePoints = dynamicShading ? [] : sceneCtx?.pointLights ?? [];
4422
+ const allPointLightsCss = scenePoints.map((pl) => ({
4423
+ position: (0, import_polycss_core16.worldPositionToCss)(pl.position),
4424
+ color: pl.color,
4425
+ intensity: pl.intensity
4426
+ }));
4427
+ const shadowPointIndices = scenePoints.map((pl, i) => pl.castShadow ? i : -1).filter((i) => i >= 0);
4428
+ const runDirectionalShadow = !!sceneDirectionalLight?.direction && (sceneDirectionalLight.intensity ?? 1) > 0;
4429
+ const hasShadowPoints = shadowPointIndices.length > 0;
4185
4430
  const shadowLift = sceneShadow?.lift ?? 1e-3;
4186
4431
  const planes = (0, import_polycss_core16.prepareReceiverFacePlanes)(
4187
4432
  polygons,
@@ -4194,18 +4439,17 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4194
4439
  if (planes.length === 0) return null;
4195
4440
  const casterInputs = [];
4196
4441
  for (const [casterId, data] of shadowCasters) {
4197
- const rendered = data.renderedPolygonIndices;
4198
4442
  const items = (0, import_polycss_core16.prepareCasterPolyItems)(
4199
4443
  data.polygons,
4200
4444
  data.position,
4201
4445
  data.scale,
4202
- rendered ? (idx) => rendered.has(idx) : () => true,
4446
+ () => true,
4203
4447
  data.rotation ?? null
4204
4448
  );
4205
4449
  const isSelf = data.polygons === polygons;
4206
4450
  const selfMap = isSelf ? selfShadowEdgeMap : void 0;
4207
4451
  let edgeOwners;
4208
- if (!isSelf && data.polygons.length >= 40) {
4452
+ if (!isSelf && (data.polygons.length >= 40 || hasShadowPoints)) {
4209
4453
  const dposArr = data.position;
4210
4454
  const drot = data.rotation ?? null;
4211
4455
  const dsKey = JSON.stringify(data.scale ?? null);
@@ -4218,12 +4462,29 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4218
4462
  }
4219
4463
  edgeOwners = cachedOwners;
4220
4464
  }
4465
+ let overrideSilhouette;
4466
+ let overridePointSilhouettes;
4467
+ if (sceneShadow?.parametric) {
4468
+ const def = data.shadowDefinition ?? sceneShadow.definition ?? 16;
4469
+ const result = (0, import_polycss_core16.buildParametricCasterOverride)({
4470
+ polysWorldVerts: items.map((it) => it.wv),
4471
+ lightDir,
4472
+ definition: def,
4473
+ isSelf,
4474
+ style: sceneShadow.style,
4475
+ pointLights: shadowPointIndices.map((i) => ({ position: allPointLightsCss[i].position, index: i }))
4476
+ });
4477
+ overrideSilhouette = result.overrideSilhouette;
4478
+ overridePointSilhouettes = result.overridePointSilhouettes;
4479
+ }
4221
4480
  casterInputs.push({
4222
4481
  id: casterId,
4223
4482
  items,
4224
4483
  selfShadowEdgeMap: selfMap,
4225
4484
  edgeOwners,
4226
- casterPolygonCount: data.polygons.length
4485
+ casterPolygonCount: data.polygons.length,
4486
+ overrideSilhouette,
4487
+ overridePointSilhouettes
4227
4488
  });
4228
4489
  }
4229
4490
  const cameraState = cameraCtx?.store.getState().cameraState;
@@ -4232,27 +4493,31 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4232
4493
  rotY: cameraState?.rotY ?? 45,
4233
4494
  meshRotation: rotation
4234
4495
  };
4235
- const specs = (0, import_polycss_core16.computeReceiverShadowFaces)({
4496
+ const faces = (0, import_polycss_core16.computeMergedReceiverShadows)({
4236
4497
  receiverPlanes: planes,
4237
4498
  receiverPolygons: polygons,
4238
4499
  receiverHasTexture: polygons.some((p) => p.texture !== void 0),
4239
4500
  casters: casterInputs,
4240
4501
  lightDir,
4502
+ runDirectional: runDirectionalShadow,
4503
+ pointPasses: shadowPointIndices.map((i) => ({ lightPos: allPointLightsCss[i].position, index: i })),
4504
+ allPointLights: allPointLightsCss,
4241
4505
  cameraRot,
4242
4506
  ambientLight: sceneCtx?.ambientLight,
4243
4507
  directionalLight: sceneDirectionalLight,
4244
4508
  shadow: { color: sceneShadow?.color, opacity: sceneShadow?.opacity ?? 0.25, maxExtend: sceneShadow?.maxExtend }
4245
4509
  });
4246
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: specs.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4510
+ if (faces.length === 0) return null;
4511
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: faces.map((fc) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4247
4512
  "svg",
4248
4513
  {
4249
4514
  className: "polycss-shadow polycss-shadow-svg polycss-shadow-receiver",
4250
4515
  "data-poly-shadow-type": "receiver",
4251
- "data-poly-shadow-receiver-face": spec.faceIndex,
4252
- "data-poly-shadow-receiver-polys": JSON.stringify(spec.memberPolyIndices),
4253
- width: spec.width,
4254
- height: spec.height,
4255
- viewBox: `0 0 ${spec.width} ${spec.height}`,
4516
+ "data-poly-shadow-receiver-face": fc.faceIndex,
4517
+ "data-poly-shadow-receiver-polys": JSON.stringify(fc.memberPolyIndices),
4518
+ width: fc.width,
4519
+ height: fc.height,
4520
+ viewBox: `0 0 ${fc.width} ${fc.height}`,
4256
4521
  style: {
4257
4522
  position: "absolute",
4258
4523
  top: 0,
@@ -4262,25 +4527,27 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4262
4527
  transformOrigin: "0 0",
4263
4528
  pointerEvents: "none",
4264
4529
  willChange: "transform",
4265
- transform: spec.matrixCss
4530
+ opacity: fc.svgOpacity,
4531
+ transform: fc.matrixCss
4266
4532
  },
4267
- children: spec.paths.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4268
- "path",
4269
- {
4270
- d: p.d,
4271
- fill: spec.fill,
4272
- stroke: spec.fill,
4273
- strokeWidth: "3",
4274
- strokeLinejoin: "round",
4275
- opacity: spec.opacity.toFixed(4),
4276
- "data-poly-shadow-caster-polys": JSON.stringify(p.casterPolygonIndices)
4277
- },
4278
- i
4279
- ))
4533
+ children: [
4534
+ fc.baseFill && fc.baseD ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: fc.baseD, fill: fc.baseFill, fillRule: "nonzero" }) : null,
4535
+ fc.layers.map((layer, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4536
+ "path",
4537
+ {
4538
+ d: layer.d,
4539
+ fill: layer.fill,
4540
+ fillRule: "nonzero",
4541
+ opacity: layer.opacity !== 1 ? layer.opacity.toFixed(4) : void 0,
4542
+ style: layer.multiply ? { mixBlendMode: "multiply" } : void 0
4543
+ },
4544
+ i
4545
+ ))
4546
+ ]
4280
4547
  },
4281
- `receiver-${spec.faceIndex}`
4548
+ `receiver-${fc.faceIndex}`
4282
4549
  )) });
4283
- }, [receiveShadow, shadowCasters, shadowCastersVersion, polygons, position, scale, rotation, sceneDirectionalLight, sceneShadow, sceneCtx?.ambientLight, cameraCtx?.store, cameraTick, selfShadowEdgeMap]);
4550
+ }, [receiveShadow, shadowCasters, shadowCastersVersion, polygons, position, scale, rotation, sceneDirectionalLight, sceneCtx?.pointLights, effectiveTextureLighting, sceneShadow, sceneCtx?.ambientLight, cameraCtx?.store, cameraTick, selfShadowEdgeMap]);
4284
4551
  const portalSceneEl = sceneCtx?.sceneEl ?? null;
4285
4552
  const portaledReceiverShadowSvgs = portalSceneEl && receiverShadowSvgs ? (0, import_react_dom.createPortal)(receiverShadowSvgs, portalSceneEl) : null;
4286
4553
  setPolygonsImplRef.current = (nextPolygons) => {
@@ -4360,12 +4627,28 @@ var PolyMesh = (0, import_react16.forwardRef)(function PolyMesh2({
4360
4627
  entry,
4361
4628
  page: textureAtlas.pages[entry.pageIndex],
4362
4629
  textureLighting: effectiveTextureLighting,
4630
+ textureImageRendering: effectiveTextureImageRendering,
4363
4631
  solidPaintDefaults
4364
4632
  },
4365
4633
  entry.index
4366
4634
  );
4367
4635
  }
4368
4636
  const plan = textureAtlas.plans[index];
4637
+ const imageGeometry = plan ? (0, import_polycss_core16.resolvePolyTextureLeafGeometry)(plan, {
4638
+ imageRendering: effectiveTextureImageRendering,
4639
+ backend: effectiveTextureBackend,
4640
+ projection: effectiveTextureProjection
4641
+ }) : null;
4642
+ if (plan && imageGeometry) {
4643
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4644
+ TextureImagePoly,
4645
+ {
4646
+ plan,
4647
+ geometry: imageGeometry
4648
+ },
4649
+ plan.index
4650
+ );
4651
+ }
4369
4652
  if (!plan || plan.texture) return null;
4370
4653
  if ((0, import_polycss_core12.isProjectiveQuadPlan)(plan)) {
4371
4654
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -4586,6 +4869,7 @@ function usePolyMaterial(options) {
4586
4869
 
4587
4870
  // src/shapes/Poly.tsx
4588
4871
  var import_react19 = require("react");
4872
+ var import_polycss_core19 = require("@layoutit/polycss-core");
4589
4873
  var import_jsx_runtime12 = require("react/jsx-runtime");
4590
4874
  var DIRECT_TEXTURE_CSS_DECIMALS = 4;
4591
4875
  function formatCssLength(value, decimals = DIRECT_TEXTURE_CSS_DECIMALS) {
@@ -4616,7 +4900,8 @@ function MaterialDirectPoly({
4616
4900
  style: styleProp,
4617
4901
  domAttrs,
4618
4902
  domEventHandlers,
4619
- pointerEvents = "auto"
4903
+ pointerEvents = "auto",
4904
+ imageRendering
4620
4905
  }) {
4621
4906
  const { u0, u1, v0, v1 } = uvRect;
4622
4907
  const du = u1 - u0;
@@ -4631,6 +4916,8 @@ function MaterialDirectPoly({
4631
4916
  backgroundImage: `url(${material.texture})`,
4632
4917
  backgroundSize: `${formatCssLength(sourceW)} ${formatCssLength(sourceH)}`,
4633
4918
  backgroundPosition: `${formatCssLength(-offsetX)} ${formatCssLength(-offsetY)}`,
4919
+ backgroundRepeat: "no-repeat",
4920
+ imageRendering: imageRendering === "pixelated" ? "pixelated" : void 0,
4634
4921
  pointerEvents: pointerEvents === "none" ? "none" : void 0,
4635
4922
  ...styleProp
4636
4923
  };
@@ -4643,6 +4930,14 @@ function MaterialDirectPoly({
4643
4930
  {
4644
4931
  className: elementClassName,
4645
4932
  style,
4933
+ "data-poly-index": plan.index,
4934
+ "data-polycss-leaf": "polygon",
4935
+ "data-polycss-texture-backend": "image",
4936
+ "data-polycss-texture-ready": "true",
4937
+ "data-polycss-texture-image-rendering": imageRendering ?? "auto",
4938
+ "data-polycss-texture-projection": "affine",
4939
+ "data-polycss-texture-lighting": "source",
4940
+ "data-polycss-double-sided": plan.polygon.doubleSided ? "true" : void 0,
4646
4941
  ...domEventHandlers,
4647
4942
  ...dataAttrs,
4648
4943
  ...domAttrs
@@ -4653,8 +4948,11 @@ function PolyInner({
4653
4948
  vertices,
4654
4949
  color,
4655
4950
  texture,
4951
+ textureImageSource,
4952
+ texturePresentation,
4656
4953
  uvs,
4657
4954
  data,
4955
+ doubleSided,
4658
4956
  material,
4659
4957
  position,
4660
4958
  scale,
@@ -4682,6 +4980,10 @@ function PolyInner({
4682
4980
  context,
4683
4981
  textureLighting: textureLightingProp,
4684
4982
  textureQuality: textureQualityProp,
4983
+ textureLeafSizing: textureLeafSizingProp,
4984
+ textureImageRendering: textureImageRenderingProp,
4985
+ textureBackend: textureBackendProp,
4986
+ textureProjection: textureProjectionProp,
4685
4987
  baseColor: baseColorProp,
4686
4988
  ...dataAttrs
4687
4989
  }) {
@@ -4689,11 +4991,25 @@ function PolyInner({
4689
4991
  const layerElevation = context?.layerElevation ?? tileSize;
4690
4992
  const textureLighting = textureLightingProp ?? context?.textureLighting ?? "baked";
4691
4993
  const textureQuality = textureQualityProp ?? context?.textureQuality;
4994
+ const textureLeafSizing = textureLeafSizingProp ?? context?.textureLeafSizing;
4995
+ const textureImageRendering = textureImageRenderingProp ?? context?.textureImageRendering;
4996
+ const textureBackend = textureBackendProp ?? context?.textureBackend;
4997
+ const textureProjection = textureProjectionProp ?? context?.textureProjection;
4692
4998
  const polygonColor = baseColorProp ?? color;
4693
4999
  const effectiveTexture = material?.texture ?? texture;
4694
5000
  const atlasPlan = (0, import_react19.useMemo)(
4695
5001
  () => computeTextureAtlasPlan(
4696
- { vertices, color: polygonColor, texture: effectiveTexture, uvs, data },
5002
+ {
5003
+ vertices,
5004
+ color: polygonColor,
5005
+ texture: effectiveTexture,
5006
+ textureImageSource,
5007
+ texturePresentation,
5008
+ uvs,
5009
+ data,
5010
+ doubleSided,
5011
+ material
5012
+ },
4697
5013
  0,
4698
5014
  {
4699
5015
  tileSize,
@@ -4705,8 +5021,12 @@ function PolyInner({
4705
5021
  vertices,
4706
5022
  polygonColor,
4707
5023
  effectiveTexture,
5024
+ textureImageSource,
5025
+ texturePresentation,
4708
5026
  uvs,
4709
5027
  data,
5028
+ doubleSided,
5029
+ material,
4710
5030
  tileSize,
4711
5031
  layerElevation,
4712
5032
  context?.directionalLight
@@ -4720,7 +5040,15 @@ function PolyInner({
4720
5040
  () => materialUvRect ? [] : [atlasPlan],
4721
5041
  [materialUvRect, atlasPlan]
4722
5042
  );
4723
- const textureAtlas = useTextureAtlas(atlasPlans, textureLighting, textureQuality);
5043
+ const textureAtlas = useTextureAtlas(
5044
+ atlasPlans,
5045
+ textureLighting,
5046
+ textureQuality,
5047
+ textureLeafSizing,
5048
+ textureBackend,
5049
+ textureImageRendering,
5050
+ textureProjection
5051
+ );
4724
5052
  const domEventHandlers = {
4725
5053
  onClick,
4726
5054
  onDoubleClick,
@@ -4779,7 +5107,8 @@ function PolyInner({
4779
5107
  style: styleProp,
4780
5108
  domAttrs,
4781
5109
  domEventHandlers,
4782
- pointerEvents: pointerEventsProp ?? "auto"
5110
+ pointerEvents: pointerEventsProp ?? "auto",
5111
+ imageRendering: textureImageRendering
4783
5112
  }
4784
5113
  );
4785
5114
  } else {
@@ -4791,6 +5120,7 @@ function PolyInner({
4791
5120
  entry: atlasEntry,
4792
5121
  page: textureAtlas.pages[atlasEntry.pageIndex],
4793
5122
  textureLighting,
5123
+ textureImageRendering,
4794
5124
  className,
4795
5125
  style: styleProp,
4796
5126
  domAttrs,
@@ -4798,7 +5128,28 @@ function PolyInner({
4798
5128
  pointerEvents: pointerEventsProp ?? "auto"
4799
5129
  }
4800
5130
  );
4801
- } else if (atlasPlan && !atlasPlan.texture) {
5131
+ } else {
5132
+ const imageGeometry = atlasPlan ? (0, import_polycss_core19.resolvePolyTextureLeafGeometry)(atlasPlan, {
5133
+ imageRendering: textureImageRendering,
5134
+ backend: textureBackend,
5135
+ projection: textureProjection
5136
+ }) : null;
5137
+ if (atlasPlan && imageGeometry) {
5138
+ front = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5139
+ TextureImagePoly,
5140
+ {
5141
+ plan: atlasPlan,
5142
+ geometry: imageGeometry,
5143
+ className,
5144
+ style: styleProp,
5145
+ domAttrs,
5146
+ domEventHandlers,
5147
+ pointerEvents: pointerEventsProp ?? "auto"
5148
+ }
5149
+ );
5150
+ }
5151
+ }
5152
+ if (!front && atlasPlan && !atlasPlan.texture) {
4802
5153
  front = (0, import_polycss_core12.isSolidTrianglePlan)(atlasPlan) ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4803
5154
  TextureTrianglePoly,
4804
5155
  {
@@ -4854,7 +5205,7 @@ var Poly = (0, import_react19.memo)(PolyInner);
4854
5205
 
4855
5206
  // src/shapes/PolyShapes.tsx
4856
5207
  var import_react20 = require("react");
4857
- var import_polycss_core19 = require("@layoutit/polycss-core");
5208
+ var import_polycss_core20 = require("@layoutit/polycss-core");
4858
5209
  var import_jsx_runtime13 = require("react/jsx-runtime");
4859
5210
  function PolyBox({
4860
5211
  size,
@@ -4870,7 +5221,7 @@ function PolyBox({
4870
5221
  ...meshProps
4871
5222
  }) {
4872
5223
  const polygons = (0, import_react20.useMemo)(
4873
- () => (0, import_polycss_core19.boxPolygons)({ size, center, min, max, color, texture, material, uvs, data, faces }),
5224
+ () => (0, import_polycss_core20.boxPolygons)({ size, center, min, max, color, texture, material, uvs, data, faces }),
4874
5225
  // eslint-disable-next-line react-hooks/exhaustive-deps
4875
5226
  [size, center, min, max, color, texture, material, uvs, data, faces]
4876
5227
  );
@@ -4885,7 +5236,7 @@ function PolyPlane({
4885
5236
  ...meshProps
4886
5237
  }) {
4887
5238
  const polygons = (0, import_react20.useMemo)(
4888
- () => (0, import_polycss_core19.planePolygons)({ axis, size, offset, along, color }),
5239
+ () => (0, import_polycss_core20.planePolygons)({ axis, size, offset, along, color }),
4889
5240
  // eslint-disable-next-line react-hooks/exhaustive-deps
4890
5241
  [axis, size, offset, along, color]
4891
5242
  );
@@ -4900,7 +5251,7 @@ function PolyRing({
4900
5251
  ...meshProps
4901
5252
  }) {
4902
5253
  const polygons = (0, import_react20.useMemo)(
4903
- () => (0, import_polycss_core19.ringPolygons)({ axis, radius, halfThickness, segments, color }),
5254
+ () => (0, import_polycss_core20.ringPolygons)({ axis, radius, halfThickness, segments, color }),
4904
5255
  // eslint-disable-next-line react-hooks/exhaustive-deps
4905
5256
  [axis, radius, halfThickness, segments, color]
4906
5257
  );
@@ -4913,7 +5264,7 @@ function PolyOctahedron({
4913
5264
  ...meshProps
4914
5265
  }) {
4915
5266
  const polygons = (0, import_react20.useMemo)(
4916
- () => (0, import_polycss_core19.octahedronPolygons)({ center, size, color }),
5267
+ () => (0, import_polycss_core20.octahedronPolygons)({ center, size, color }),
4917
5268
  // eslint-disable-next-line react-hooks/exhaustive-deps
4918
5269
  [center, size, color]
4919
5270
  );
@@ -4925,7 +5276,7 @@ function PolyTetrahedron({
4925
5276
  ...meshProps
4926
5277
  }) {
4927
5278
  const polygons = (0, import_react20.useMemo)(
4928
- () => (0, import_polycss_core19.tetrahedronPolygons)({ size, color }),
5279
+ () => (0, import_polycss_core20.tetrahedronPolygons)({ size, color }),
4929
5280
  // eslint-disable-next-line react-hooks/exhaustive-deps
4930
5281
  [size, color]
4931
5282
  );
@@ -4937,7 +5288,7 @@ function PolyIcosahedron({
4937
5288
  ...meshProps
4938
5289
  }) {
4939
5290
  const polygons = (0, import_react20.useMemo)(
4940
- () => (0, import_polycss_core19.icosahedronPolygons)({ size, color }),
5291
+ () => (0, import_polycss_core20.icosahedronPolygons)({ size, color }),
4941
5292
  // eslint-disable-next-line react-hooks/exhaustive-deps
4942
5293
  [size, color]
4943
5294
  );
@@ -4949,7 +5300,7 @@ function PolyDodecahedron({
4949
5300
  ...meshProps
4950
5301
  }) {
4951
5302
  const polygons = (0, import_react20.useMemo)(
4952
- () => (0, import_polycss_core19.dodecahedronPolygons)({ size, color }),
5303
+ () => (0, import_polycss_core20.dodecahedronPolygons)({ size, color }),
4953
5304
  // eslint-disable-next-line react-hooks/exhaustive-deps
4954
5305
  [size, color]
4955
5306
  );
@@ -4962,7 +5313,7 @@ function PolySphere({
4962
5313
  ...meshProps
4963
5314
  }) {
4964
5315
  const polygons = (0, import_react20.useMemo)(
4965
- () => (0, import_polycss_core19.spherePolygons)({ radius, subdivisions, color }),
5316
+ () => (0, import_polycss_core20.spherePolygons)({ radius, subdivisions, color }),
4966
5317
  // eslint-disable-next-line react-hooks/exhaustive-deps
4967
5318
  [radius, subdivisions, color]
4968
5319
  );
@@ -4977,7 +5328,7 @@ function PolyCylinder({
4977
5328
  ...meshProps
4978
5329
  }) {
4979
5330
  const polygons = (0, import_react20.useMemo)(
4980
- () => (0, import_polycss_core19.cylinderPolygons)({ radius, radiusTop, height, radialSegments, color }),
5331
+ () => (0, import_polycss_core20.cylinderPolygons)({ radius, radiusTop, height, radialSegments, color }),
4981
5332
  // eslint-disable-next-line react-hooks/exhaustive-deps
4982
5333
  [radius, radiusTop, height, radialSegments, color]
4983
5334
  );
@@ -4991,7 +5342,7 @@ function PolyCone({
4991
5342
  ...meshProps
4992
5343
  }) {
4993
5344
  const polygons = (0, import_react20.useMemo)(
4994
- () => (0, import_polycss_core19.conePolygons)({ radius, height, radialSegments, color }),
5345
+ () => (0, import_polycss_core20.conePolygons)({ radius, height, radialSegments, color }),
4995
5346
  // eslint-disable-next-line react-hooks/exhaustive-deps
4996
5347
  [radius, height, radialSegments, color]
4997
5348
  );
@@ -5006,7 +5357,7 @@ function PolyTorus({
5006
5357
  ...meshProps
5007
5358
  }) {
5008
5359
  const polygons = (0, import_react20.useMemo)(
5009
- () => (0, import_polycss_core19.torusPolygons)({ radius, tube, radialSegments, tubularSegments, color }),
5360
+ () => (0, import_polycss_core20.torusPolygons)({ radius, tube, radialSegments, tubularSegments, color }),
5010
5361
  // eslint-disable-next-line react-hooks/exhaustive-deps
5011
5362
  [radius, tube, radialSegments, tubularSegments, color]
5012
5363
  );
@@ -5015,7 +5366,7 @@ function PolyTorus({
5015
5366
 
5016
5367
  // src/controls/PolyFirstPersonControls.tsx
5017
5368
  var import_react21 = require("react");
5018
- var import_polycss_core20 = require("@layoutit/polycss-core");
5369
+ var import_polycss_core21 = require("@layoutit/polycss-core");
5019
5370
  var DEFAULTS = {
5020
5371
  enabled: true,
5021
5372
  lookEnabled: true,
@@ -5191,7 +5542,7 @@ var PolyFirstPersonControls = (0, import_react21.forwardRef)(function PolyFirstP
5191
5542
  const host = cameraElRef.current;
5192
5543
  const perspStr = host ? getComputedStyle(host).perspective : "";
5193
5544
  const n = parseFloat(perspStr);
5194
- return (Number.isFinite(n) && n > 0 ? n : 32e3) / import_polycss_core20.BASE_TILE;
5545
+ return (Number.isFinite(n) && n > 0 ? n : 32e3) / import_polycss_core21.BASE_TILE;
5195
5546
  }
5196
5547
  function deriveTarget() {
5197
5548
  const s = cameraRef.current.state;
@@ -5432,7 +5783,7 @@ var PolyFirstPersonControls = (0, import_react21.forwardRef)(function PolyFirstP
5432
5783
  var import_react22 = require("react");
5433
5784
 
5434
5785
  // src/controls/sharedControls.ts
5435
- var import_polycss_core21 = require("@layoutit/polycss-core");
5786
+ var import_polycss_core22 = require("@layoutit/polycss-core");
5436
5787
  var POINTER_DRAG_SPEED = 4;
5437
5788
  function invertFactor(invert) {
5438
5789
  if (invert === true) return -1;
@@ -5453,7 +5804,7 @@ function applyPan(dx, dy, s, handle, _invert) {
5453
5804
  const cosRotX = cosRotXRaw >= 0 ? Math.max(0.1, cosRotXRaw) : Math.min(-0.1, cosRotXRaw);
5454
5805
  const cZ = Math.cos(s.rotY * Math.PI / 180);
5455
5806
  const sZ = Math.sin(s.rotY * Math.PI / 180);
5456
- const k = z * import_polycss_core21.BASE_TILE;
5807
+ const k = z * import_polycss_core22.BASE_TILE;
5457
5808
  const targetD0 = (dx * sZ - dy * cZ / cosRotX) / k;
5458
5809
  const targetD1 = -(dx * cZ + dy * sZ / cosRotX) / k;
5459
5810
  const t = s.target;
@@ -5983,9 +6334,9 @@ function PolyOrbitControls({
5983
6334
 
5984
6335
  // src/controls/TransformControls.tsx
5985
6336
  var import_react24 = require("react");
5986
- var import_polycss_core22 = require("@layoutit/polycss-core");
6337
+ var import_polycss_core23 = require("@layoutit/polycss-core");
5987
6338
  var import_jsx_runtime14 = require("react/jsx-runtime");
5988
- var FALLBACK_CAMERA_STORE = createSceneStore(import_polycss_core22.DEFAULT_CAMERA_STATE);
6339
+ var FALLBACK_CAMERA_STORE = createSceneStore(import_polycss_core23.DEFAULT_CAMERA_STATE);
5989
6340
  var COLOR_X = "#ff3653";
5990
6341
  var COLOR_Y = "#8adb00";
5991
6342
  var COLOR_Z = "#2c8fff";
@@ -6262,7 +6613,7 @@ function startRingDrag(opts) {
6262
6613
  const startRotation = target.getRotation() ?? [0, 0, 0];
6263
6614
  onMouseDown?.();
6264
6615
  onDraggingChanged?.(true);
6265
- const qStart = (0, import_polycss_core22.quatFromEulerXYZ)(startRotation);
6616
+ const qStart = (0, import_polycss_core23.quatFromEulerXYZ)(startRotation);
6266
6617
  const handleMove = (ev) => {
6267
6618
  const a = Math.atan2(ev.clientY - centerY, ev.clientX - centerX);
6268
6619
  let d = a - lastAngle;
@@ -6274,8 +6625,8 @@ function startRingDrag(opts) {
6274
6625
  degrees = snap(degrees, rotationSnap);
6275
6626
  const axisVec = [0, 0, 0];
6276
6627
  axisVec[cssAxis] = 1;
6277
- const qDelta = (0, import_polycss_core22.quatFromAxisAngle)(axisVec, degrees * Math.PI / 180);
6278
- const newRotation = (0, import_polycss_core22.eulerXYZFromQuat)((0, import_polycss_core22.quatMultiply)(qDelta, qStart));
6628
+ const qDelta = (0, import_polycss_core23.quatFromAxisAngle)(axisVec, degrees * Math.PI / 180);
6629
+ const newRotation = (0, import_polycss_core23.eulerXYZFromQuat)((0, import_polycss_core23.quatMultiply)(qDelta, qStart));
6279
6630
  onObjectChange?.({ object: target, rotation: newRotation });
6280
6631
  onChange?.();
6281
6632
  };
@@ -6646,7 +6997,7 @@ function TranslateArrow({
6646
6997
  };
6647
6998
  const polygons = (0, import_react24.useMemo)(() => {
6648
6999
  const lengthWorld = shaftLengthCss / SCENE_TILE_SIZE;
6649
- return (0, import_polycss_core22.arrowPolygons)({
7000
+ return (0, import_polycss_core23.arrowPolygons)({
6650
7001
  axis: WORLD_AXIS_FOR_CSS[cssAxis],
6651
7002
  sign,
6652
7003
  shaftLength: lengthWorld,
@@ -6751,7 +7102,7 @@ function TranslatePlane({
6751
7102
  const signA = isAxisBackFacing(cssAForOffset, 1, rotX, rotY) ? -1 : 1;
6752
7103
  const signB = isAxisBackFacing(cssBForOffset, 1, rotX, rotY) ? -1 : 1;
6753
7104
  const mag = lengthWorld * PLANE_OFFSET_RATIO;
6754
- return (0, import_polycss_core22.planePolygons)({
7105
+ return (0, import_polycss_core23.planePolygons)({
6755
7106
  axis: worldPerp,
6756
7107
  size: lengthWorld * PLANE_HALF_SIZE_RATIO,
6757
7108
  offset: [signA * mag, signB * mag],
@@ -6841,7 +7192,7 @@ function RotateRing({
6841
7192
  const polygons = (0, import_react24.useMemo)(() => {
6842
7193
  const radiusWorld = radiusCss / SCENE_TILE_SIZE;
6843
7194
  const outerWorld = radiusWorld * RING_QUAD_OUTER_RATIO;
6844
- return (0, import_polycss_core22.ringQuadPolygons)({
7195
+ return (0, import_polycss_core23.ringQuadPolygons)({
6845
7196
  axis: WORLD_AXIS_FOR_CSS[cssAxis],
6846
7197
  outerRadius: outerWorld,
6847
7198
  color
@@ -7039,7 +7390,7 @@ function usePolySelectionApi() {
7039
7390
 
7040
7391
  // src/helpers/PolyAxesHelper.tsx
7041
7392
  var import_react26 = require("react");
7042
- var import_polycss_core23 = require("@layoutit/polycss-core");
7393
+ var import_polycss_core24 = require("@layoutit/polycss-core");
7043
7394
  var import_jsx_runtime16 = require("react/jsx-runtime");
7044
7395
  function PolyAxesHelper({
7045
7396
  size,
@@ -7050,7 +7401,7 @@ function PolyAxesHelper({
7050
7401
  zColor
7051
7402
  }) {
7052
7403
  const polygons = (0, import_react26.useMemo)(
7053
- () => (0, import_polycss_core23.axesHelperPolygons)({ size, thickness, negative, xColor, yColor, zColor }),
7404
+ () => (0, import_polycss_core24.axesHelperPolygons)({ size, thickness, negative, xColor, yColor, zColor }),
7054
7405
  [size, thickness, negative, xColor, yColor, zColor]
7055
7406
  );
7056
7407
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PolyMesh, { polygons, merge: false });
@@ -7058,7 +7409,7 @@ function PolyAxesHelper({
7058
7409
 
7059
7410
  // src/helpers/PolyDirectionalLightHelper.tsx
7060
7411
  var import_react27 = require("react");
7061
- var import_polycss_core24 = require("@layoutit/polycss-core");
7412
+ var import_polycss_core25 = require("@layoutit/polycss-core");
7062
7413
  var import_jsx_runtime17 = require("react/jsx-runtime");
7063
7414
  function PolyDirectionalLightHelper({
7064
7415
  light,
@@ -7069,7 +7420,7 @@ function PolyDirectionalLightHelper({
7069
7420
  }) {
7070
7421
  const swatch = color ?? light.color ?? "#ffd54a";
7071
7422
  const polygons = (0, import_react27.useMemo)(
7072
- () => (0, import_polycss_core24.octahedronPolygons)({ center: [0, 0, 0], size, color: swatch }),
7423
+ () => (0, import_polycss_core25.octahedronPolygons)({ center: [0, 0, 0], size, color: swatch }),
7073
7424
  [size, swatch]
7074
7425
  );
7075
7426
  const meshPosition = (0, import_react27.useMemo)(() => {
@@ -7088,7 +7439,7 @@ function PolyDirectionalLightHelper({
7088
7439
  }
7089
7440
 
7090
7441
  // src/styles/colorResolver.ts
7091
- var import_polycss_core25 = require("@layoutit/polycss-core");
7442
+ var import_polycss_core26 = require("@layoutit/polycss-core");
7092
7443
 
7093
7444
  // src/renderStats.ts
7094
7445
  var ZERO_SURFACE_LEAF_COUNTS = {
@@ -7097,11 +7448,56 @@ var ZERO_SURFACE_LEAF_COUNTS = {
7097
7448
  atlas: 0,
7098
7449
  stableTriangle: 0
7099
7450
  };
7451
+ var READY_TEXTURE_READINESS = {
7452
+ ready: true,
7453
+ textureLeafCount: 0,
7454
+ readyTextureLeafCount: 0,
7455
+ pendingTextureLeafCount: 0,
7456
+ atlasTextureLeafCount: 0,
7457
+ imageTextureLeafCount: 0
7458
+ };
7459
+ function emptyTextureStats() {
7460
+ return {
7461
+ ready: true,
7462
+ leafCount: 0,
7463
+ atlasCount: 0,
7464
+ imageCount: 0,
7465
+ pendingCount: 0,
7466
+ sizingCounts: { canonical: 0, local: 0, raster: 0, image: 0, unknown: 0 },
7467
+ imageRenderingCounts: { auto: 0, pixelated: 0, unknown: 0 },
7468
+ projectionCounts: { affine: 0, projective: 0, fallback: 0, unknown: 0 },
7469
+ minLeafWidth: 0,
7470
+ maxLeafWidth: 0,
7471
+ minLeafHeight: 0,
7472
+ maxLeafHeight: 0,
7473
+ doubleSidedCount: 0
7474
+ };
7475
+ }
7476
+ function emptySnapshotStats() {
7477
+ return {
7478
+ runtimeAtlasUrlCount: 0,
7479
+ snapshotAtlasCount: 0,
7480
+ snapshotBackgroundCount: 0,
7481
+ selfContained: true
7482
+ };
7483
+ }
7484
+ function emptyCameraStats() {
7485
+ return {
7486
+ rootFound: false,
7487
+ projection: "unknown",
7488
+ perspectiveStyle: "",
7489
+ appliedPerspectiveStyle: ""
7490
+ };
7491
+ }
7100
7492
  var EMPTY_POLY_RENDER_STATS = {
7101
7493
  polygonCount: 0,
7102
7494
  mountedPolygonLeafCount: 0,
7103
7495
  shadowLeafCount: 0,
7104
7496
  surfaceLeafCounts: ZERO_SURFACE_LEAF_COUNTS,
7497
+ textureReadiness: READY_TEXTURE_READINESS,
7498
+ textureStats: emptyTextureStats(),
7499
+ snapshotStats: emptySnapshotStats(),
7500
+ cameraStats: emptyCameraStats(),
7105
7501
  bucketCount: 0
7106
7502
  };
7107
7503
  function asOptions(optionsOrPolygonCount) {
@@ -7113,6 +7509,28 @@ function asOptions(optionsOrPolygonCount) {
7113
7509
  function queryCount(scope, selector) {
7114
7510
  return scope.querySelectorAll(selector).length;
7115
7511
  }
7512
+ function matchingElementCount(scope, selector) {
7513
+ return (matchesSelector(scope, selector) ? 1 : 0) + queryCount(scope, selector);
7514
+ }
7515
+ function styleHasRuntimeUrl(styleText) {
7516
+ if (!styleText) return false;
7517
+ const urlPattern = /url\((?:"([^"]*)"|'([^']*)'|([^)]*))\)/g;
7518
+ let match;
7519
+ while (match = urlPattern.exec(styleText)) {
7520
+ const raw = (match[1] ?? match[2] ?? match[3] ?? "").trim();
7521
+ if (raw && !raw.startsWith("data:")) return true;
7522
+ }
7523
+ return false;
7524
+ }
7525
+ function runtimeUrlElementCount(scope) {
7526
+ let count = 0;
7527
+ const root = scope instanceof HTMLElement ? scope : null;
7528
+ if (root && styleHasRuntimeUrl(root.getAttribute("style"))) count++;
7529
+ for (const el of Array.from(scope.querySelectorAll("[style]"))) {
7530
+ if (el instanceof HTMLElement && styleHasRuntimeUrl(el.getAttribute("style"))) count++;
7531
+ }
7532
+ return count;
7533
+ }
7116
7534
  function matchesSelector(root, selector) {
7117
7535
  const candidate = root;
7118
7536
  return typeof candidate.matches === "function" && candidate.matches(selector);
@@ -7124,12 +7542,196 @@ function collectScopes(root, selector) {
7124
7542
  scopes.push(...Array.from(root.querySelectorAll(selector)));
7125
7543
  return scopes;
7126
7544
  }
7545
+ function leafStrategyForTag(tagName) {
7546
+ switch (tagName.toLowerCase()) {
7547
+ case "b":
7548
+ return "quad";
7549
+ case "i":
7550
+ return "clippedSolid";
7551
+ case "s":
7552
+ return "atlas";
7553
+ case "u":
7554
+ return "stableTriangle";
7555
+ default:
7556
+ return null;
7557
+ }
7558
+ }
7559
+ function parseOptionalInteger(value) {
7560
+ if (value == null || value === "") return void 0;
7561
+ const parsed = Number.parseInt(value, 10);
7562
+ return Number.isFinite(parsed) ? parsed : void 0;
7563
+ }
7564
+ function parseOptionalNumber(value) {
7565
+ if (value == null || value === "") return void 0;
7566
+ const parsed = Number(value);
7567
+ return Number.isFinite(parsed) ? parsed : void 0;
7568
+ }
7569
+ function parseOptionalVec3(value) {
7570
+ if (value == null || value === "") return void 0;
7571
+ const parts = value.split(",").map((part) => Number(part));
7572
+ if (parts.length !== 3 || parts.some((part) => !Number.isFinite(part))) return void 0;
7573
+ return parts;
7574
+ }
7575
+ function parseCameraProjection(value) {
7576
+ return value === "orthographic" || value === "perspective" ? value : "unknown";
7577
+ }
7578
+ function textureReadyForElement(el, textureBackend) {
7579
+ if (!textureBackend) return void 0;
7580
+ const attr = el.getAttribute("data-polycss-texture-ready");
7581
+ if (attr === "true") return true;
7582
+ if (attr === "false") return false;
7583
+ return el.style.opacity !== "0";
7584
+ }
7585
+ function queryPolyLeaves(root, optionsOrPolygonCount) {
7586
+ if (!root) return [];
7587
+ const options = asOptions(optionsOrPolygonCount);
7588
+ const out = [];
7589
+ for (const scope of collectScopes(root, options.scopeSelector)) {
7590
+ for (const el of Array.from(scope.querySelectorAll("b,i,s,u"))) {
7591
+ const htmlEl = el;
7592
+ const strategy = leafStrategyForTag(htmlEl.tagName);
7593
+ if (!strategy) continue;
7594
+ const textureBackend = htmlEl.getAttribute("data-polycss-texture-backend") ?? (strategy === "atlas" ? "atlas" : void 0);
7595
+ const textureReady = textureReadyForElement(htmlEl, textureBackend);
7596
+ out.push({
7597
+ element: htmlEl,
7598
+ strategy,
7599
+ polygonIndex: parseOptionalInteger(htmlEl.getAttribute("data-poly-index")),
7600
+ textureBackend,
7601
+ textureReady,
7602
+ textureLeafSizing: htmlEl.getAttribute("data-polycss-texture-leaf-sizing") ?? void 0,
7603
+ textureImageRendering: htmlEl.getAttribute("data-polycss-texture-image-rendering") ?? void 0,
7604
+ textureProjection: htmlEl.getAttribute("data-polycss-texture-projection") ?? void 0,
7605
+ textureLeafWidth: parseOptionalNumber(htmlEl.getAttribute("data-polycss-texture-leaf-width")),
7606
+ textureLeafHeight: parseOptionalNumber(htmlEl.getAttribute("data-polycss-texture-leaf-height")),
7607
+ doubleSided: htmlEl.getAttribute("data-polycss-double-sided") === "true"
7608
+ });
7609
+ }
7610
+ }
7611
+ return out;
7612
+ }
7613
+ function collectPolyTextureReadiness(root, optionsOrPolygonCount) {
7614
+ const readiness = { ...READY_TEXTURE_READINESS };
7615
+ for (const leaf of queryPolyLeaves(root, optionsOrPolygonCount)) {
7616
+ if (!leaf.textureBackend) continue;
7617
+ readiness.textureLeafCount++;
7618
+ if (leaf.textureBackend === "image") readiness.imageTextureLeafCount++;
7619
+ else readiness.atlasTextureLeafCount++;
7620
+ if (leaf.textureReady === false) readiness.pendingTextureLeafCount++;
7621
+ else readiness.readyTextureLeafCount++;
7622
+ }
7623
+ readiness.ready = readiness.pendingTextureLeafCount === 0;
7624
+ return readiness;
7625
+ }
7626
+ function collectPolyTextureStats(root, optionsOrPolygonCount) {
7627
+ const stats = emptyTextureStats();
7628
+ let hasWidth = false;
7629
+ let hasHeight = false;
7630
+ for (const leaf of queryPolyLeaves(root, optionsOrPolygonCount)) {
7631
+ if (!leaf.textureBackend) continue;
7632
+ stats.leafCount++;
7633
+ if (leaf.textureBackend === "image") stats.imageCount++;
7634
+ else stats.atlasCount++;
7635
+ if (leaf.textureReady === false) stats.pendingCount++;
7636
+ switch (leaf.textureLeafSizing) {
7637
+ case "canonical":
7638
+ case "local":
7639
+ case "raster":
7640
+ case "image":
7641
+ stats.sizingCounts[leaf.textureLeafSizing]++;
7642
+ break;
7643
+ default:
7644
+ stats.sizingCounts.unknown++;
7645
+ break;
7646
+ }
7647
+ switch (leaf.textureImageRendering) {
7648
+ case "auto":
7649
+ case "pixelated":
7650
+ stats.imageRenderingCounts[leaf.textureImageRendering]++;
7651
+ break;
7652
+ default:
7653
+ stats.imageRenderingCounts.unknown++;
7654
+ break;
7655
+ }
7656
+ switch (leaf.textureProjection) {
7657
+ case "affine":
7658
+ case "projective":
7659
+ case "fallback":
7660
+ stats.projectionCounts[leaf.textureProjection]++;
7661
+ break;
7662
+ default:
7663
+ stats.projectionCounts.unknown++;
7664
+ break;
7665
+ }
7666
+ if (typeof leaf.textureLeafWidth === "number") {
7667
+ stats.minLeafWidth = hasWidth ? Math.min(stats.minLeafWidth, leaf.textureLeafWidth) : leaf.textureLeafWidth;
7668
+ stats.maxLeafWidth = hasWidth ? Math.max(stats.maxLeafWidth, leaf.textureLeafWidth) : leaf.textureLeafWidth;
7669
+ hasWidth = true;
7670
+ }
7671
+ if (typeof leaf.textureLeafHeight === "number") {
7672
+ stats.minLeafHeight = hasHeight ? Math.min(stats.minLeafHeight, leaf.textureLeafHeight) : leaf.textureLeafHeight;
7673
+ stats.maxLeafHeight = hasHeight ? Math.max(stats.maxLeafHeight, leaf.textureLeafHeight) : leaf.textureLeafHeight;
7674
+ hasHeight = true;
7675
+ }
7676
+ if (leaf.doubleSided) stats.doubleSidedCount++;
7677
+ }
7678
+ stats.pendingCount = Math.min(stats.pendingCount, stats.leafCount);
7679
+ stats.ready = stats.pendingCount === 0;
7680
+ return stats;
7681
+ }
7682
+ function collectPolySnapshotStats(root, optionsOrPolygonCount) {
7683
+ const stats = emptySnapshotStats();
7684
+ if (!root) return stats;
7685
+ const options = asOptions(optionsOrPolygonCount);
7686
+ for (const scope of collectScopes(root, options.scopeSelector)) {
7687
+ stats.runtimeAtlasUrlCount += runtimeUrlElementCount(scope);
7688
+ stats.snapshotAtlasCount += matchingElementCount(scope, "[data-polycss-snapshot-atlas]");
7689
+ stats.snapshotBackgroundCount += matchingElementCount(scope, "[data-polycss-snapshot-bg]");
7690
+ }
7691
+ stats.selfContained = stats.runtimeAtlasUrlCount === 0;
7692
+ return stats;
7693
+ }
7694
+ function findCameraRoot(scope) {
7695
+ const element = scope instanceof HTMLElement ? scope : null;
7696
+ if (element) {
7697
+ if (element.classList.contains("polycss-camera")) return element;
7698
+ const closest = element.closest(".polycss-camera");
7699
+ if (closest instanceof HTMLElement) return closest;
7700
+ }
7701
+ const found = scope.querySelector(".polycss-camera");
7702
+ return found instanceof HTMLElement ? found : null;
7703
+ }
7704
+ function collectPolyCameraStats(root, optionsOrPolygonCount) {
7705
+ if (!root) return emptyCameraStats();
7706
+ const options = asOptions(optionsOrPolygonCount);
7707
+ let cameraRoot = null;
7708
+ for (const scope of collectScopes(root, options.scopeSelector)) {
7709
+ cameraRoot = findCameraRoot(scope);
7710
+ if (cameraRoot) break;
7711
+ }
7712
+ if (!cameraRoot) return emptyCameraStats();
7713
+ return {
7714
+ rootFound: true,
7715
+ projection: parseCameraProjection(cameraRoot.getAttribute("data-polycss-camera-projection")),
7716
+ perspectiveStyle: cameraRoot.getAttribute("data-polycss-camera-perspective") ?? "",
7717
+ appliedPerspectiveStyle: cameraRoot.getAttribute("data-polycss-camera-applied-perspective") ?? cameraRoot.style.perspective ?? "",
7718
+ zoom: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-zoom")),
7719
+ distance: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-distance")),
7720
+ rotX: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-rot-x")),
7721
+ rotY: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-rot-y")),
7722
+ target: parseOptionalVec3(cameraRoot.getAttribute("data-polycss-camera-target"))
7723
+ };
7724
+ }
7127
7725
  function collectPolyRenderStats(root, optionsOrPolygonCount) {
7128
7726
  const options = asOptions(optionsOrPolygonCount);
7129
7727
  if (!root) {
7130
7728
  return {
7131
7729
  ...EMPTY_POLY_RENDER_STATS,
7132
7730
  surfaceLeafCounts: { ...ZERO_SURFACE_LEAF_COUNTS },
7731
+ textureReadiness: { ...READY_TEXTURE_READINESS },
7732
+ textureStats: emptyTextureStats(),
7733
+ snapshotStats: emptySnapshotStats(),
7734
+ cameraStats: emptyCameraStats(),
7133
7735
  polygonCount: options.polygonCount ?? 0
7134
7736
  };
7135
7737
  }
@@ -7151,13 +7753,17 @@ function collectPolyRenderStats(root, optionsOrPolygonCount) {
7151
7753
  mountedPolygonLeafCount,
7152
7754
  shadowLeafCount,
7153
7755
  surfaceLeafCounts,
7756
+ textureReadiness: collectPolyTextureReadiness(root, options),
7757
+ textureStats: collectPolyTextureStats(root, options),
7758
+ snapshotStats: collectPolySnapshotStats(root, options),
7759
+ cameraStats: collectPolyCameraStats(root, options),
7154
7760
  bucketCount
7155
7761
  };
7156
7762
  }
7157
7763
 
7158
7764
  // src/animation/usePolyAnimation.ts
7159
7765
  var import_react28 = require("react");
7160
- var import_polycss_core26 = require("@layoutit/polycss-core");
7766
+ var import_polycss_core27 = require("@layoutit/polycss-core");
7161
7767
  function resolveRoot(rootArg) {
7162
7768
  if (!rootArg) return null;
7163
7769
  if ("current" in rootArg) return rootArg.current;
@@ -7176,7 +7782,7 @@ function usePolyAnimation(clips, controller, root) {
7176
7782
  mixerRef.current = null;
7177
7783
  return;
7178
7784
  }
7179
- mixerRef.current = (0, import_polycss_core26.createPolyAnimationMixer)(resolvedRoot, controller);
7785
+ mixerRef.current = (0, import_polycss_core27.createPolyAnimationMixer)(resolvedRoot, controller);
7180
7786
  return () => {
7181
7787
  mixerRef.current?.stopAllAction();
7182
7788
  mixerRef.current?.uncacheRoot();
@@ -7234,7 +7840,7 @@ function usePolyAnimation(clips, controller, root) {
7234
7840
  }
7235
7841
 
7236
7842
  // src/index.ts
7237
- var import_polycss_core27 = require("@layoutit/polycss-core");
7843
+ var import_polycss_core28 = require("@layoutit/polycss-core");
7238
7844
  // Annotate the CommonJS export names for ESM import in node:
7239
7845
  0 && (module.exports = {
7240
7846
  BASE_TILE,
@@ -7280,6 +7886,7 @@ var import_polycss_core27 = require("@layoutit/polycss-core");
7280
7886
  bakeSolidTextureSampledPolygons,
7281
7887
  bakeSolidTextureSamples,
7282
7888
  boxPolygons,
7889
+ buildPolyCameraSceneTransform,
7283
7890
  buildPolyMeshTransform,
7284
7891
  buildPolySceneTransform,
7285
7892
  buildSceneContext,
@@ -7288,8 +7895,10 @@ var import_polycss_core27 = require("@layoutit/polycss-core");
7288
7895
  cameraCullNormalKey,
7289
7896
  cameraCullVisibleSignature,
7290
7897
  cameraFacingDepth,
7898
+ capturePolyCameraSnapshot,
7291
7899
  clampChannel,
7292
7900
  collectPolyRenderStats,
7901
+ collectPolyTextureReadiness,
7293
7902
  computeSceneBbox,
7294
7903
  computeShapeLighting,
7295
7904
  computeTexturePaintMetrics,
@@ -7297,6 +7906,8 @@ var import_polycss_core27 = require("@layoutit/polycss-core");
7297
7906
  coverPlanarPolygons,
7298
7907
  createIsometricCamera,
7299
7908
  createPolyAnimationMixer,
7909
+ cssDistanceToWorld,
7910
+ cssPositionToWorld,
7300
7911
  cullInteriorPolygons,
7301
7912
  cylinderPolygons,
7302
7913
  dodecahedronPolygons,
@@ -7328,12 +7939,15 @@ var import_polycss_core27 = require("@layoutit/polycss-core");
7328
7939
  parseVox,
7329
7940
  planePolygons,
7330
7941
  pointInMeshElement,
7942
+ polyCameraTargetToCss,
7331
7943
  polyCssDistanceToWorld,
7332
7944
  polyCssPositionToWorld,
7333
7945
  polygonCssSurfaceNormal,
7334
7946
  polygonFaces,
7335
7947
  polygonFacesCamera,
7948
+ queryPolyLeaves,
7336
7949
  repairMeshSeams,
7950
+ resolvePolyCameraAppliedPerspectiveStyle,
7337
7951
  ringPolygons,
7338
7952
  rotateVec3,
7339
7953
  seamFacetSplitPolygons,
@@ -7353,8 +7967,12 @@ var import_polycss_core27 = require("@layoutit/polycss-core");
7353
7967
  usePolySceneContext,
7354
7968
  usePolySelect,
7355
7969
  usePolySelectionApi,
7970
+ worldDirectionToCss,
7356
7971
  worldDirectionToPolyCss,
7972
+ worldDirectionalLightToCss,
7357
7973
  worldDirectionalLightToPolyCss,
7974
+ worldDistanceToCss,
7358
7975
  worldDistanceToPolyCss,
7976
+ worldPositionToCss,
7359
7977
  worldPositionToPolyCss
7360
7978
  });