@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.js CHANGED
@@ -14,7 +14,11 @@ function useCameraContext() {
14
14
 
15
15
  // src/camera/useCamera.ts
16
16
  import { useRef as useRef2, useCallback as useCallback2, useEffect, useMemo } from "react";
17
- import { buildPolySceneTransform, createIsometricCamera } from "@layoutit/polycss-core";
17
+ import {
18
+ buildPolyCameraSceneTransform,
19
+ capturePolyCameraSnapshot,
20
+ createIsometricCamera
21
+ } from "@layoutit/polycss-core";
18
22
 
19
23
  // src/store/sceneStore.ts
20
24
  import { useSyncExternalStore, useRef, useCallback } from "react";
@@ -60,6 +64,18 @@ function useStoreSelector(store, selector) {
60
64
  }
61
65
 
62
66
  // src/camera/useCamera.ts
67
+ function writeCameraSnapshotAttrs(el, camera, projection, perspectiveStyle) {
68
+ if (!el) return;
69
+ const snapshot = capturePolyCameraSnapshot(camera, { projection, perspectiveStyle });
70
+ el.dataset.polycssCameraProjection = snapshot.projection;
71
+ el.dataset.polycssCameraPerspective = snapshot.perspectiveStyle;
72
+ el.dataset.polycssCameraAppliedPerspective = snapshot.appliedPerspectiveStyle;
73
+ el.dataset.polycssCameraZoom = String(snapshot.state.zoom);
74
+ el.dataset.polycssCameraDistance = String(snapshot.state.distance);
75
+ el.dataset.polycssCameraRotX = String(snapshot.state.rotX);
76
+ el.dataset.polycssCameraRotY = String(snapshot.state.rotY);
77
+ el.dataset.polycssCameraTarget = snapshot.state.target.join(",");
78
+ }
63
79
  function usePolyCamera(options) {
64
80
  const handleRef = useRef2(null);
65
81
  if (!handleRef.current) {
@@ -89,24 +105,33 @@ function usePolyCamera(options) {
89
105
  handle.update(next);
90
106
  const el = sceneElRef.current;
91
107
  if (el) {
92
- el.style.transform = buildPolySceneTransform({
93
- ...handle.state,
108
+ el.style.transform = buildPolyCameraSceneTransform(handle.state, {
94
109
  autoCenterOffset: store.getState().autoCenterOffset
95
110
  });
96
111
  }
97
112
  store.updateCameraFromRef(handle);
98
113
  store.notifyAll();
99
114
  }
100
- }, [options.zoom, options.target, options.rotX, options.rotY, options.distance, store]);
115
+ writeCameraSnapshotAttrs(cameraElRef.current, handle, options.projection, options.perspectiveStyle);
116
+ }, [
117
+ options.zoom,
118
+ options.target,
119
+ options.rotX,
120
+ options.rotY,
121
+ options.distance,
122
+ options.projection,
123
+ options.perspectiveStyle,
124
+ store
125
+ ]);
101
126
  const applyTransformDirect = useCallback2(() => {
102
127
  const el = sceneElRef.current;
103
128
  if (!el) return;
104
129
  const handle = handleRef.current;
105
- el.style.transform = buildPolySceneTransform({
106
- ...handle.state,
130
+ el.style.transform = buildPolyCameraSceneTransform(handle.state, {
107
131
  autoCenterOffset: store.getState().autoCenterOffset
108
132
  });
109
- }, [store]);
133
+ writeCameraSnapshotAttrs(cameraElRef.current, handle, options.projection, options.perspectiveStyle);
134
+ }, [store, options.projection, options.perspectiveStyle]);
110
135
  return {
111
136
  store,
112
137
  cameraRef: handleRef,
@@ -130,18 +155,26 @@ function PolyPerspectiveCameraInner({
130
155
  className,
131
156
  style
132
157
  }) {
158
+ const perspectiveValue = `${typeof perspective === "number" ? perspective : DEFAULT_PERSPECTIVE}px`;
133
159
  const {
134
160
  store,
135
161
  cameraRef,
136
162
  sceneElRef,
137
163
  cameraElRef,
138
164
  applyTransformDirect
139
- } = usePolyCamera({ zoom, target, rotX, rotY, distance });
165
+ } = usePolyCamera({
166
+ zoom,
167
+ target,
168
+ rotX,
169
+ rotY,
170
+ distance,
171
+ projection: "perspective",
172
+ perspectiveStyle: perspectiveValue
173
+ });
140
174
  const contextValue = useMemo2(
141
175
  () => ({ store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect }),
142
176
  [store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect]
143
177
  );
144
- const perspectiveValue = `${typeof perspective === "number" ? perspective : DEFAULT_PERSPECTIVE}px`;
145
178
  const cameraStyle = {
146
179
  ...style,
147
180
  perspective: perspectiveValue
@@ -152,6 +185,14 @@ function PolyPerspectiveCameraInner({
152
185
  ref: cameraElRef,
153
186
  className: `polycss-camera${className ? ` ${className}` : ""}`,
154
187
  style: cameraStyle,
188
+ "data-polycss-camera-projection": "perspective",
189
+ "data-polycss-camera-perspective": perspectiveValue,
190
+ "data-polycss-camera-applied-perspective": perspectiveValue,
191
+ "data-polycss-camera-zoom": cameraRef.current.state.zoom,
192
+ "data-polycss-camera-distance": cameraRef.current.state.distance,
193
+ "data-polycss-camera-rot-x": cameraRef.current.state.rotX,
194
+ "data-polycss-camera-rot-y": cameraRef.current.state.rotY,
195
+ "data-polycss-camera-target": cameraRef.current.state.target.join(","),
155
196
  children
156
197
  }
157
198
  ) });
@@ -177,7 +218,15 @@ function PolyOrthographicCameraInner({
177
218
  sceneElRef,
178
219
  cameraElRef,
179
220
  applyTransformDirect
180
- } = usePolyCamera({ zoom, target, rotX, rotY, distance });
221
+ } = usePolyCamera({
222
+ zoom,
223
+ target,
224
+ rotX,
225
+ rotY,
226
+ distance,
227
+ projection: "orthographic",
228
+ perspectiveStyle: "none"
229
+ });
181
230
  const contextValue = useMemo3(
182
231
  () => ({ store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect }),
183
232
  [store, cameraRef, sceneElRef, cameraElRef, applyTransformDirect]
@@ -197,6 +246,14 @@ function PolyOrthographicCameraInner({
197
246
  ref: cameraElRef,
198
247
  className: `polycss-camera${className ? ` ${className}` : ""}`,
199
248
  style: cameraStyle,
249
+ "data-polycss-camera-projection": "orthographic",
250
+ "data-polycss-camera-perspective": "none",
251
+ "data-polycss-camera-applied-perspective": "1000000px",
252
+ "data-polycss-camera-zoom": cameraRef.current.state.zoom,
253
+ "data-polycss-camera-distance": cameraRef.current.state.distance,
254
+ "data-polycss-camera-rot-x": cameraRef.current.state.rotX,
255
+ "data-polycss-camera-rot-y": cameraRef.current.state.rotY,
256
+ "data-polycss-camera-target": cameraRef.current.state.target.join(","),
200
257
  children
201
258
  }
202
259
  ) });
@@ -205,7 +262,13 @@ var PolyOrthographicCamera = memo2(PolyOrthographicCameraInner);
205
262
 
206
263
  // src/scene/PolyScene.tsx
207
264
  import { memo as memo8, useCallback as useCallback5, useEffect as useEffect3, useLayoutEffect, useMemo as useMemo6, useRef as useRef4, useState as useState2 } from "react";
208
- import { BASE_TILE, DEFAULT_SEAM_BLEED, parseHexColor, worldDirectionToCss } from "@layoutit/polycss-core";
265
+ import {
266
+ BASE_TILE,
267
+ DEFAULT_SEAM_BLEED,
268
+ parseHexColor,
269
+ resolvePolyTextureLeafGeometry,
270
+ worldDirectionToCss
271
+ } from "@layoutit/polycss-core";
209
272
 
210
273
  // src/scene/useSceneContext.ts
211
274
  import { useMemo as useMemo4 } from "react";
@@ -379,8 +442,8 @@ var CORE_BASE_STYLES = `
379
442
  }
380
443
 
381
444
  .polycss-scene s {
382
- width: var(--polycss-atlas-size, 64px);
383
- height: var(--polycss-atlas-size, 64px);
445
+ width: var(--polycss-atlas-width, var(--polycss-atlas-size, 64px));
446
+ height: var(--polycss-atlas-height, var(--polycss-atlas-size, 64px));
384
447
  }
385
448
 
386
449
  .polycss-scene u {
@@ -791,13 +854,16 @@ function isSolidTriangleSupported(doc) {
791
854
  import {
792
855
  filterAtlasPlans as filterAtlasPlansCore
793
856
  } from "@layoutit/polycss-core";
794
- function filterAtlasPlans(plans, textureLighting, disabled, doc) {
857
+ function filterAtlasPlans(plans, textureLighting, disabled, doc, textureBackend, textureImageRendering, textureProjection) {
795
858
  const d = doc ?? (typeof document !== "undefined" ? document : null);
796
859
  return filterAtlasPlansCore(plans, textureLighting, disabled, {
797
860
  solidTriangleSupported: isSolidTriangleSupported(doc),
798
861
  projectiveQuadSupported: doc ? projectiveQuadSupported(doc) : true,
799
862
  borderShapeSupported: isBorderShapeSupported(doc),
800
- cornerShapeSupported: d ? cornerShapeSupported(d) : false
863
+ cornerShapeSupported: d ? cornerShapeSupported(d) : false,
864
+ textureBackend,
865
+ textureImageRendering,
866
+ textureProjection
801
867
  });
802
868
  }
803
869
 
@@ -812,8 +878,13 @@ function isMobileDocument(doc) {
812
878
  if (!media) return false;
813
879
  return media("(pointer: coarse)").matches || media("(hover: none)").matches;
814
880
  }
815
- function packTextureAtlasPlansWithScale(plans, textureQualityInput, doc) {
816
- return packTextureAtlasPlansWithScaleCore(plans, textureQualityInput, isMobileDocument(doc));
881
+ function packTextureAtlasPlansWithScale(plans, textureQualityInput, doc, textureLeafSizing) {
882
+ return packTextureAtlasPlansWithScaleCore(
883
+ plans,
884
+ textureQualityInput,
885
+ isMobileDocument(doc),
886
+ textureLeafSizing
887
+ );
817
888
  }
818
889
 
819
890
  // src/scene/atlas/buildAtlasPages.ts
@@ -2031,7 +2102,7 @@ function deferRevoke(urls) {
2031
2102
  if (typeof requestAnimationFrame === "function") requestAnimationFrame(run);
2032
2103
  else setTimeout(run, 0);
2033
2104
  }
2034
- function useTextureAtlas(plans, textureLighting, textureQualityInput, strategies, atomic = false) {
2105
+ function useTextureAtlas(plans, textureLighting, textureQualityInput, textureLeafSizing, textureBackend, textureImageRendering, textureProjection, strategies, atomic = false) {
2035
2106
  const disabled = useMemo5(
2036
2107
  () => new Set(strategies?.disable ?? []),
2037
2108
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -2042,17 +2113,21 @@ function useTextureAtlas(plans, textureLighting, textureQualityInput, strategies
2042
2113
  plans,
2043
2114
  textureLighting,
2044
2115
  disabled,
2045
- typeof document !== "undefined" ? document : null
2116
+ typeof document !== "undefined" ? document : null,
2117
+ textureBackend,
2118
+ textureImageRendering,
2119
+ textureProjection
2046
2120
  ),
2047
- [plans, textureLighting, disabled]
2121
+ [plans, textureLighting, disabled, textureBackend, textureImageRendering, textureProjection]
2048
2122
  );
2049
2123
  const { packed, atlasScale } = useMemo5(
2050
2124
  () => packTextureAtlasPlansWithScale(
2051
2125
  atlasPlans,
2052
2126
  textureQualityInput,
2053
- typeof document !== "undefined" ? document : null
2127
+ typeof document !== "undefined" ? document : null,
2128
+ textureLeafSizing
2054
2129
  ),
2055
- [atlasPlans, textureQualityInput]
2130
+ [atlasPlans, textureQualityInput, textureLeafSizing]
2056
2131
  );
2057
2132
  const [pages, setPages] = useState(() => pageShells(packed.pages));
2058
2133
  const [frame, setFrame] = useState(() => ({
@@ -2405,12 +2480,13 @@ var TextureCornerShapeSolidPoly = memo6(function TextureCornerShapeSolidPoly2({
2405
2480
 
2406
2481
  // src/scene/atlas/atlasPoly.tsx
2407
2482
  import { memo as memo7 } from "react";
2408
- import { formatMatrix3d, formatCssLengthPx } from "@layoutit/polycss-core";
2483
+ import { formatMatrix3d, formatCssLengthPx, resolvePolyTextureImageRendering } from "@layoutit/polycss-core";
2409
2484
  import { jsx as jsx7 } from "react/jsx-runtime";
2410
2485
  var TextureAtlasPoly = memo7(function TextureAtlasPoly2({
2411
2486
  entry,
2412
2487
  page,
2413
2488
  textureLighting,
2489
+ textureImageRendering,
2414
2490
  solidPaintDefaults: _solidPaintDefaults,
2415
2491
  className,
2416
2492
  style: styleProp,
@@ -2420,26 +2496,26 @@ var TextureAtlasPoly = memo7(function TextureAtlasPoly2({
2420
2496
  }) {
2421
2497
  const ATLAS_CANONICAL_SIZE_EXPLICIT = 64;
2422
2498
  const dynamic = textureLighting === "dynamic";
2499
+ const resolvedImageRendering = resolvePolyTextureImageRendering(entry.polygon, textureImageRendering);
2423
2500
  const atlasCanonicalSize = entry.atlasCanonicalSize ?? ATLAS_CANONICAL_SIZE_EXPLICIT;
2501
+ const atlasLeafWidth = entry.atlasLeafWidth ?? atlasCanonicalSize;
2502
+ const atlasLeafHeight = entry.atlasLeafHeight ?? atlasCanonicalSize;
2424
2503
  const atlasWidth = entry.canvasW || 1;
2425
2504
  const atlasHeight = entry.canvasH || 1;
2426
- const atlasPosition = page ? `${formatCssLengthPx(-entry.x / atlasWidth * atlasCanonicalSize)} ${formatCssLengthPx(-entry.y / atlasHeight * atlasCanonicalSize)}` : void 0;
2427
- const atlasSize = page ? `${formatCssLengthPx(page.width / atlasWidth * atlasCanonicalSize)} ${formatCssLengthPx(page.height / atlasHeight * atlasCanonicalSize)}` : void 0;
2505
+ const atlasPosition = page ? `${formatCssLengthPx(-entry.x / atlasWidth * atlasLeafWidth)} ${formatCssLengthPx(-entry.y / atlasHeight * atlasLeafHeight)}` : void 0;
2506
+ const atlasSize = page ? `${formatCssLengthPx(page.width / atlasWidth * atlasLeafWidth)} ${formatCssLengthPx(page.height / atlasHeight * atlasLeafHeight)}` : void 0;
2428
2507
  const dynamicMask = dynamic && page?.url ? `url(${page.url})` : void 0;
2429
- const background = !dynamic && page?.url ? `url(${page.url}) ${atlasPosition} / ${atlasSize} no-repeat` : void 0;
2430
2508
  const style = {
2431
2509
  transform: formatMatrix3d(entry.atlasMatrix),
2432
2510
  ["--polycss-atlas-size"]: `${atlasCanonicalSize}px`,
2433
- // Listing the `background` shorthand alongside the `background-*` longhands
2434
- // in one inline style object makes React warn on every update (mixing
2435
- // shorthand and non-shorthand for the same property). Branch so only the
2436
- // current mode's keys are assigned — baked gets `background`, dynamic gets
2437
- // the longhands.
2438
- ...dynamic ? {
2439
- backgroundImage: page?.url ? `url(${page.url})` : void 0,
2440
- backgroundPosition: atlasPosition,
2441
- backgroundSize: atlasSize
2442
- } : { background },
2511
+ ["--polycss-atlas-width"]: formatCssLengthPx(atlasLeafWidth),
2512
+ ["--polycss-atlas-height"]: formatCssLengthPx(atlasLeafHeight),
2513
+ ["--polycss-atlas-leaf-sizing"]: entry.atlasLeafSizing ?? "canonical",
2514
+ backgroundImage: page?.url ? `url(${page.url})` : void 0,
2515
+ backgroundPosition: atlasPosition,
2516
+ backgroundSize: atlasSize,
2517
+ backgroundRepeat: page?.url ? "no-repeat" : void 0,
2518
+ imageRendering: resolvedImageRendering === "pixelated" ? "pixelated" : void 0,
2443
2519
  ...dynamic ? {
2444
2520
  ["--pnx"]: entry.normal[0].toFixed(4),
2445
2521
  ["--pny"]: entry.normal[1].toFixed(4),
@@ -2470,6 +2546,74 @@ var TextureAtlasPoly = memo7(function TextureAtlasPoly2({
2470
2546
  className: elementClassName,
2471
2547
  style,
2472
2548
  "data-poly-index": entry.index,
2549
+ "data-polycss-leaf": "polygon",
2550
+ "data-polycss-texture-backend": "atlas",
2551
+ "data-polycss-texture-leaf-sizing": entry.atlasLeafSizing ?? "canonical",
2552
+ "data-polycss-texture-ready": page?.url ? "true" : "false",
2553
+ "data-polycss-texture-image-rendering": resolvedImageRendering,
2554
+ "data-polycss-texture-projection": "affine",
2555
+ "data-polycss-texture-lighting": textureLighting,
2556
+ "data-polycss-texture-leaf-width": atlasLeafWidth,
2557
+ "data-polycss-texture-leaf-height": atlasLeafHeight,
2558
+ "data-polycss-double-sided": entry.polygon.doubleSided ? "true" : void 0,
2559
+ ...domEventHandlers,
2560
+ ...dataAttrs,
2561
+ ...domAttrs
2562
+ }
2563
+ );
2564
+ });
2565
+ var TextureImagePoly = memo7(function TextureImagePoly2({
2566
+ plan,
2567
+ geometry,
2568
+ className,
2569
+ style: styleProp,
2570
+ domAttrs,
2571
+ domEventHandlers,
2572
+ pointerEvents = "auto"
2573
+ }) {
2574
+ const style = {
2575
+ transform: formatMatrix3d(geometry.matrix),
2576
+ ["--polycss-atlas-width"]: formatCssLengthPx(geometry.leafWidth),
2577
+ ["--polycss-atlas-height"]: formatCssLengthPx(geometry.leafHeight),
2578
+ ["--polycss-atlas-leaf-sizing"]: "image",
2579
+ backgroundImage: `url(${geometry.url})`,
2580
+ backgroundPosition: `${formatCssLengthPx(geometry.backgroundPosition[0])} ${formatCssLengthPx(geometry.backgroundPosition[1])}`,
2581
+ backgroundSize: `${formatCssLengthPx(geometry.backgroundSize[0])} ${formatCssLengthPx(geometry.backgroundSize[1])}`,
2582
+ backgroundRepeat: "no-repeat",
2583
+ backgroundBlendMode: "normal",
2584
+ maskImage: "none",
2585
+ WebkitMaskImage: "none",
2586
+ imageRendering: geometry.imageRendering === "pixelated" ? "pixelated" : void 0,
2587
+ ["--pnx"]: plan.normal[0].toFixed(4),
2588
+ ["--pny"]: plan.normal[1].toFixed(4),
2589
+ ["--pnz"]: plan.normal[2].toFixed(4),
2590
+ pointerEvents: pointerEvents === "none" ? "none" : void 0,
2591
+ ...styleProp
2592
+ };
2593
+ const dataAttrs = plan.polygon.data ? Object.fromEntries(
2594
+ Object.entries(plan.polygon.data).map(([k, v]) => [`data-${k}`, String(v)])
2595
+ ) : {};
2596
+ const elementClassName = className?.trim() || void 0;
2597
+ return /* @__PURE__ */ jsx7(
2598
+ "s",
2599
+ {
2600
+ className: elementClassName,
2601
+ style,
2602
+ "data-poly-index": plan.index,
2603
+ "data-polycss-leaf": "polygon",
2604
+ "data-polycss-texture-backend": "image",
2605
+ "data-polycss-texture-leaf-sizing": "image",
2606
+ "data-polycss-texture-ready": "true",
2607
+ "data-polycss-texture-image-rendering": geometry.imageRendering,
2608
+ "data-polycss-texture-projection": geometry.projection,
2609
+ "data-polycss-texture-lighting": geometry.lighting,
2610
+ "data-polycss-texture-leaf-width": geometry.leafWidth,
2611
+ "data-polycss-texture-leaf-height": geometry.leafHeight,
2612
+ "data-polycss-double-sided": plan.polygon.doubleSided ? "true" : void 0,
2613
+ "data-polycss-texture-source-x": geometry.sourceRect.x,
2614
+ "data-polycss-texture-source-y": geometry.sourceRect.y,
2615
+ "data-polycss-texture-source-width": geometry.sourceRect.width,
2616
+ "data-polycss-texture-source-height": geometry.sourceRect.height,
2473
2617
  ...domEventHandlers,
2474
2618
  ...dataAttrs,
2475
2619
  ...domAttrs
@@ -2494,9 +2638,14 @@ function PolySceneInner({
2494
2638
  rotY: _rotY,
2495
2639
  zoom: _zoom,
2496
2640
  directionalLight,
2641
+ pointLights,
2497
2642
  ambientLight,
2498
2643
  textureLighting = "baked",
2499
2644
  textureQuality,
2645
+ textureLeafSizing,
2646
+ textureImageRendering,
2647
+ textureBackend,
2648
+ textureProjection,
2500
2649
  seamBleed = DEFAULT_SEAM_BLEED,
2501
2650
  strategies,
2502
2651
  autoCenter = false,
@@ -2547,17 +2696,19 @@ function PolySceneInner({
2547
2696
  const sceneBbox = centerInputPolygons ? centerSceneBbox : renderSceneBbox;
2548
2697
  const directionalForAtlas = textureLighting === "dynamic" ? void 0 : directionalLight;
2549
2698
  const ambientForAtlas = textureLighting === "dynamic" ? void 0 : ambientLight;
2699
+ const pointLightsForAtlas = textureLighting === "dynamic" ? void 0 : pointLights;
2550
2700
  const polyContext = useMemo6(() => {
2551
2701
  const tileSize = 50;
2552
2702
  return {
2553
2703
  tileSize,
2554
2704
  layerElevation: tileSize,
2555
2705
  directionalLight: directionalForAtlas,
2706
+ pointLights: pointLightsForAtlas,
2556
2707
  ambientLight: ambientForAtlas,
2557
2708
  textureLighting,
2558
2709
  seamBleed
2559
2710
  };
2560
- }, [directionalForAtlas, ambientForAtlas, textureLighting, seamBleed]);
2711
+ }, [directionalForAtlas, pointLightsForAtlas, ambientForAtlas, textureLighting, seamBleed]);
2561
2712
  const autoCenterOffset = useMemo6(() => {
2562
2713
  if (!autoCenter) return [0, 0, 0];
2563
2714
  return [
@@ -2592,7 +2743,16 @@ function PolySceneInner({
2592
2743
  },
2593
2744
  [polygons, polyContext, seamBleed, directionalForAtlas, ambientForAtlas]
2594
2745
  );
2595
- const textureAtlas = useTextureAtlas(textureAtlasPlans, textureLighting, textureQuality, strategies);
2746
+ const textureAtlas = useTextureAtlas(
2747
+ textureAtlasPlans,
2748
+ textureLighting,
2749
+ textureQuality,
2750
+ textureLeafSizing,
2751
+ textureBackend,
2752
+ textureImageRendering,
2753
+ textureProjection,
2754
+ strategies
2755
+ );
2596
2756
  const dynamicLightVars = useMemo6(() => {
2597
2757
  if (textureLighting !== "dynamic") return null;
2598
2758
  const userDir = directionalLight?.direction ?? [0.4, -0.7, 0.59];
@@ -2690,12 +2850,28 @@ function PolySceneInner({
2690
2850
  {
2691
2851
  entry,
2692
2852
  page: textureAtlas.pages[entry.pageIndex],
2693
- textureLighting
2853
+ textureLighting,
2854
+ textureImageRendering
2694
2855
  },
2695
2856
  entry.index
2696
2857
  );
2697
2858
  }
2698
2859
  const plan = textureAtlasPlans[index];
2860
+ const imageGeometry = plan ? resolvePolyTextureLeafGeometry(plan, {
2861
+ imageRendering: textureImageRendering,
2862
+ backend: textureBackend,
2863
+ projection: textureProjection
2864
+ }) : null;
2865
+ if (plan && imageGeometry) {
2866
+ return /* @__PURE__ */ jsx8(
2867
+ TextureImagePoly,
2868
+ {
2869
+ plan,
2870
+ geometry: imageGeometry
2871
+ },
2872
+ plan.index
2873
+ );
2874
+ }
2699
2875
  if (!plan || plan.texture) return null;
2700
2876
  const useU = !disabledStrategies?.has("u");
2701
2877
  const useProjectiveSolid = !disabledStrategies?.has("b");
@@ -2718,9 +2894,14 @@ function PolySceneInner({
2718
2894
  () => ({
2719
2895
  textureLighting,
2720
2896
  directionalLight,
2897
+ pointLights,
2721
2898
  ambientLight,
2722
2899
  strategies,
2723
2900
  seamBleed,
2901
+ textureLeafSizing,
2902
+ textureImageRendering,
2903
+ textureBackend,
2904
+ textureProjection,
2724
2905
  shadow,
2725
2906
  registerShadowCaster,
2726
2907
  registerShadowReceiver,
@@ -2730,7 +2911,7 @@ function PolySceneInner({
2730
2911
  groundCssZ,
2731
2912
  sceneEl
2732
2913
  }),
2733
- [textureLighting, directionalLight, ambientLight, strategies, seamBleed, shadow, registerShadowCaster, registerShadowReceiver, shadowCastersVersion, hasShadowReceiver, groundCssZ, sceneEl]
2914
+ [textureLighting, directionalLight, pointLights, ambientLight, strategies, seamBleed, textureLeafSizing, textureImageRendering, textureBackend, textureProjection, shadow, registerShadowCaster, registerShadowReceiver, shadowCastersVersion, hasShadowReceiver, groundCssZ, sceneEl]
2734
2915
  );
2735
2916
  return /* @__PURE__ */ jsx8(PolySceneContext.Provider, { value: sceneCtxValue, children: /* @__PURE__ */ jsxs(
2736
2917
  "div",
@@ -2766,9 +2947,10 @@ import {
2766
2947
  } from "react";
2767
2948
  import {
2768
2949
  BASE_TILE as BASE_TILE3,
2950
+ buildParametricCasterOverride,
2769
2951
  buildPolyMeshTransform,
2770
2952
  buildSharedEdgeMap,
2771
- computeReceiverShadowFaces,
2953
+ computeMergedReceiverShadows,
2772
2954
  computeSceneBbox,
2773
2955
  DEFAULT_SEAM_BLEED as DEFAULT_SEAM_BLEED2,
2774
2956
  ensureCcw2D,
@@ -2780,7 +2962,9 @@ import {
2780
2962
  prepareCasterPolyItems,
2781
2963
  prepareReceiverFacePlanes,
2782
2964
  projectCssVertexToGround,
2783
- worldDirectionToCss as worldDirectionToCss2
2965
+ resolvePolyTextureLeafGeometry as resolvePolyTextureLeafGeometry2,
2966
+ worldDirectionToCss as worldDirectionToCss2,
2967
+ worldPositionToCss
2784
2968
  } from "@layoutit/polycss-core";
2785
2969
 
2786
2970
  // src/scene/useMesh.ts
@@ -3648,11 +3832,16 @@ var PolyMesh = forwardRef(function PolyMesh2({
3648
3832
  autoCenter,
3649
3833
  textureLighting,
3650
3834
  textureQuality,
3835
+ textureLeafSizing,
3836
+ textureImageRendering,
3837
+ textureBackend,
3838
+ textureProjection,
3651
3839
  seamBleed,
3652
3840
  atomicAtlas,
3653
3841
  onFrameReady,
3654
3842
  castShadow,
3655
3843
  receiveShadow,
3844
+ shadowDefinition,
3656
3845
  merge = true,
3657
3846
  children,
3658
3847
  fallback,
@@ -3717,6 +3906,12 @@ var PolyMesh = forwardRef(function PolyMesh2({
3717
3906
  const stableTriangleColorFrameRef = useRef6(0);
3718
3907
  const setPolygonsImplRef = useRef6(() => {
3719
3908
  });
3909
+ const textureReadyRef = useRef6(true);
3910
+ const textureReadyWaitersRef = useRef6([]);
3911
+ const resolveTextureReadyWaiters = useCallback7(() => {
3912
+ const waiters = textureReadyWaitersRef.current.splice(0);
3913
+ for (const resolve of waiters) resolve();
3914
+ }, []);
3720
3915
  const handle = useMemo7(() => ({
3721
3916
  get element() {
3722
3917
  return wrapperRef.current;
@@ -3730,6 +3925,12 @@ var PolyMesh = forwardRef(function PolyMesh2({
3730
3925
  setPolygonsImplRef.current(nextPolygons);
3731
3926
  },
3732
3927
  rebakeAtlas: () => setBakedRotation(propsRef.current.rotation),
3928
+ whenTexturesReady() {
3929
+ if (textureReadyRef.current) return Promise.resolve();
3930
+ return new Promise((resolve) => {
3931
+ textureReadyWaitersRef.current.push(resolve);
3932
+ });
3933
+ },
3733
3934
  updatePolygon(target, partial) {
3734
3935
  const current = polygonsRef.current;
3735
3936
  const idx = typeof target === "number" ? target : current.indexOf(target);
@@ -3876,6 +4077,10 @@ var PolyMesh = forwardRef(function PolyMesh2({
3876
4077
  [effectiveStrategies]
3877
4078
  );
3878
4079
  const effectiveSeamBleed = seamBleed ?? sceneCtx?.seamBleed ?? DEFAULT_SEAM_BLEED2;
4080
+ const effectiveTextureLeafSizing = textureLeafSizing ?? sceneCtx?.textureLeafSizing;
4081
+ const effectiveTextureImageRendering = textureImageRendering ?? sceneCtx?.textureImageRendering;
4082
+ const effectiveTextureBackend = textureBackend ?? sceneCtx?.textureBackend;
4083
+ const effectiveTextureProjection = textureProjection ?? sceneCtx?.textureProjection;
3879
4084
  const effectiveDirectional = sceneCtx?.directionalLight;
3880
4085
  const effectiveAmbient = sceneCtx?.ambientLight;
3881
4086
  const directVoxelEnabled = Boolean(
@@ -3905,6 +4110,18 @@ var PolyMesh = forwardRef(function PolyMesh2({
3905
4110
  direction: inverseRotateVec3(cssLight.direction, rot)
3906
4111
  };
3907
4112
  }, [effectiveDirectional, bakedRotation]);
4113
+ const bakedPointLights = useMemo7(() => {
4114
+ const pls = sceneCtx?.pointLights;
4115
+ if (!pls || pls.length === 0) return void 0;
4116
+ const pos = position ?? [0, 0, 0];
4117
+ const rot = bakedRotation ?? [0, 0, 0];
4118
+ const hasRot = rot[0] !== 0 || rot[1] !== 0 || rot[2] !== 0;
4119
+ return pls.map((pl) => {
4120
+ const rel = [pl.position[0] - pos[0], pl.position[1] - pos[1], pl.position[2] - pos[2]];
4121
+ const local = hasRot ? inverseRotateVec3(rel, rot) : rel;
4122
+ return { ...pl, position: local };
4123
+ });
4124
+ }, [sceneCtx?.pointLights, position, bakedRotation]);
3908
4125
  const lightOccludedPolyIndices = void 0;
3909
4126
  const atlasPlans = useMemo7(
3910
4127
  () => {
@@ -3923,6 +4140,7 @@ var PolyMesh = forwardRef(function PolyMesh2({
3923
4140
  i,
3924
4141
  {
3925
4142
  directionalLight: bakedDirectional,
4143
+ pointLights: bakedPointLights,
3926
4144
  ambientLight: effectiveAmbient,
3927
4145
  seamBleed: seamBleedEdges?.has(i) ? effectiveSeamBleed : void 0,
3928
4146
  seamEdges: seamBleedEdges?.get(i),
@@ -3932,15 +4150,24 @@ var PolyMesh = forwardRef(function PolyMesh2({
3932
4150
  basisHints[i]
3933
4151
  ));
3934
4152
  },
3935
- [renderPolygon, directVoxelEnabled, polygons, bakedDirectional, effectiveAmbient, effectiveSeamBleed, lightOccludedPolyIndices]
4153
+ [renderPolygon, directVoxelEnabled, polygons, bakedDirectional, bakedPointLights, effectiveAmbient, effectiveSeamBleed, lightOccludedPolyIndices]
3936
4154
  );
3937
4155
  const textureAtlas = useTextureAtlas(
3938
4156
  atlasPlans,
3939
4157
  effectiveTextureLighting,
3940
4158
  textureQuality,
4159
+ effectiveTextureLeafSizing,
4160
+ effectiveTextureBackend,
4161
+ effectiveTextureImageRendering,
4162
+ effectiveTextureProjection,
3941
4163
  effectiveStrategies,
3942
4164
  atomicAtlas
3943
4165
  );
4166
+ textureReadyRef.current = textureAtlas.ready;
4167
+ useEffect5(() => {
4168
+ if (textureAtlas.ready) resolveTextureReadyWaiters();
4169
+ }, [textureAtlas.ready, resolveTextureReadyWaiters]);
4170
+ useEffect5(() => resolveTextureReadyWaiters, [resolveTextureReadyWaiters]);
3944
4171
  const solidPaintDefaults = useMemo7(
3945
4172
  () => !renderPolygon ? getSolidPaintDefaults(textureAtlas.plans, effectiveTextureLighting, effectiveStrategies) : {},
3946
4173
  [renderPolygon, textureAtlas.plans, effectiveTextureLighting, effectiveStrategies]
@@ -3969,23 +4196,32 @@ var PolyMesh = forwardRef(function PolyMesh2({
3969
4196
  }
3970
4197
  return s;
3971
4198
  }, [atlasPlans, polygons]);
4199
+ const shadowCasterRegisteredRef = useRef6(false);
4200
+ const lastShadowPolyCountRef = useRef6(-1);
3972
4201
  useEffect5(() => {
3973
- if (!sceneRegisterShadowCaster) return;
3974
- if (castShadow) {
3975
- sceneRegisterShadowCaster(meshIdRef.current, {
3976
- polygons,
3977
- position: position ?? [0, 0, 0],
3978
- scale,
3979
- rotation,
3980
- renderedPolygonIndices
3981
- });
3982
- } else {
3983
- sceneRegisterShadowCaster(meshIdRef.current, null);
3984
- }
4202
+ if (!sceneRegisterShadowCaster || !castShadow) return;
3985
4203
  return () => {
3986
4204
  sceneRegisterShadowCaster(meshIdRef.current, null);
4205
+ shadowCasterRegisteredRef.current = false;
4206
+ lastShadowPolyCountRef.current = -1;
3987
4207
  };
3988
- }, [sceneRegisterShadowCaster, castShadow, polygons, position, scale, rotation, renderedPolygonIndices]);
4208
+ }, [sceneRegisterShadowCaster, castShadow]);
4209
+ useEffect5(() => {
4210
+ if (!sceneRegisterShadowCaster || !castShadow) return;
4211
+ const followAnimation = sceneCtx?.shadow?.followAnimation ?? false;
4212
+ const topologyChanged = polygons.length !== lastShadowPolyCountRef.current;
4213
+ if (shadowCasterRegisteredRef.current && !followAnimation && !topologyChanged) return;
4214
+ lastShadowPolyCountRef.current = polygons.length;
4215
+ shadowCasterRegisteredRef.current = true;
4216
+ sceneRegisterShadowCaster(meshIdRef.current, {
4217
+ polygons,
4218
+ position: position ?? [0, 0, 0],
4219
+ scale,
4220
+ rotation,
4221
+ renderedPolygonIndices,
4222
+ shadowDefinition
4223
+ });
4224
+ }, [sceneRegisterShadowCaster, castShadow, polygons, position, scale, rotation, renderedPolygonIndices, shadowDefinition, sceneCtx?.shadow]);
3989
4225
  const sceneRegisterShadowReceiver = sceneCtx?.registerShadowReceiver;
3990
4226
  useEffect5(() => {
3991
4227
  if (!sceneRegisterShadowReceiver) return;
@@ -4111,6 +4347,16 @@ var PolyMesh = forwardRef(function PolyMesh2({
4111
4347
  if (!shadowCasters || shadowCasters.size === 0) return null;
4112
4348
  const userLightDir = sceneDirectionalLight?.direction ?? [0.4, -0.7, 0.59];
4113
4349
  const lightDir = worldDirectionToCss2(userLightDir);
4350
+ const dynamicShading = effectiveTextureLighting === "dynamic";
4351
+ const scenePoints = dynamicShading ? [] : sceneCtx?.pointLights ?? [];
4352
+ const allPointLightsCss = scenePoints.map((pl) => ({
4353
+ position: worldPositionToCss(pl.position),
4354
+ color: pl.color,
4355
+ intensity: pl.intensity
4356
+ }));
4357
+ const shadowPointIndices = scenePoints.map((pl, i) => pl.castShadow ? i : -1).filter((i) => i >= 0);
4358
+ const runDirectionalShadow = !!sceneDirectionalLight?.direction && (sceneDirectionalLight.intensity ?? 1) > 0;
4359
+ const hasShadowPoints = shadowPointIndices.length > 0;
4114
4360
  const shadowLift = sceneShadow?.lift ?? 1e-3;
4115
4361
  const planes = prepareReceiverFacePlanes(
4116
4362
  polygons,
@@ -4123,18 +4369,17 @@ var PolyMesh = forwardRef(function PolyMesh2({
4123
4369
  if (planes.length === 0) return null;
4124
4370
  const casterInputs = [];
4125
4371
  for (const [casterId, data] of shadowCasters) {
4126
- const rendered = data.renderedPolygonIndices;
4127
4372
  const items = prepareCasterPolyItems(
4128
4373
  data.polygons,
4129
4374
  data.position,
4130
4375
  data.scale,
4131
- rendered ? (idx) => rendered.has(idx) : () => true,
4376
+ () => true,
4132
4377
  data.rotation ?? null
4133
4378
  );
4134
4379
  const isSelf = data.polygons === polygons;
4135
4380
  const selfMap = isSelf ? selfShadowEdgeMap : void 0;
4136
4381
  let edgeOwners;
4137
- if (!isSelf && data.polygons.length >= 40) {
4382
+ if (!isSelf && (data.polygons.length >= 40 || hasShadowPoints)) {
4138
4383
  const dposArr = data.position;
4139
4384
  const drot = data.rotation ?? null;
4140
4385
  const dsKey = JSON.stringify(data.scale ?? null);
@@ -4147,12 +4392,29 @@ var PolyMesh = forwardRef(function PolyMesh2({
4147
4392
  }
4148
4393
  edgeOwners = cachedOwners;
4149
4394
  }
4395
+ let overrideSilhouette;
4396
+ let overridePointSilhouettes;
4397
+ if (sceneShadow?.parametric) {
4398
+ const def = data.shadowDefinition ?? sceneShadow.definition ?? 16;
4399
+ const result = buildParametricCasterOverride({
4400
+ polysWorldVerts: items.map((it) => it.wv),
4401
+ lightDir,
4402
+ definition: def,
4403
+ isSelf,
4404
+ style: sceneShadow.style,
4405
+ pointLights: shadowPointIndices.map((i) => ({ position: allPointLightsCss[i].position, index: i }))
4406
+ });
4407
+ overrideSilhouette = result.overrideSilhouette;
4408
+ overridePointSilhouettes = result.overridePointSilhouettes;
4409
+ }
4150
4410
  casterInputs.push({
4151
4411
  id: casterId,
4152
4412
  items,
4153
4413
  selfShadowEdgeMap: selfMap,
4154
4414
  edgeOwners,
4155
- casterPolygonCount: data.polygons.length
4415
+ casterPolygonCount: data.polygons.length,
4416
+ overrideSilhouette,
4417
+ overridePointSilhouettes
4156
4418
  });
4157
4419
  }
4158
4420
  const cameraState = cameraCtx?.store.getState().cameraState;
@@ -4161,27 +4423,31 @@ var PolyMesh = forwardRef(function PolyMesh2({
4161
4423
  rotY: cameraState?.rotY ?? 45,
4162
4424
  meshRotation: rotation
4163
4425
  };
4164
- const specs = computeReceiverShadowFaces({
4426
+ const faces = computeMergedReceiverShadows({
4165
4427
  receiverPlanes: planes,
4166
4428
  receiverPolygons: polygons,
4167
4429
  receiverHasTexture: polygons.some((p) => p.texture !== void 0),
4168
4430
  casters: casterInputs,
4169
4431
  lightDir,
4432
+ runDirectional: runDirectionalShadow,
4433
+ pointPasses: shadowPointIndices.map((i) => ({ lightPos: allPointLightsCss[i].position, index: i })),
4434
+ allPointLights: allPointLightsCss,
4170
4435
  cameraRot,
4171
4436
  ambientLight: sceneCtx?.ambientLight,
4172
4437
  directionalLight: sceneDirectionalLight,
4173
4438
  shadow: { color: sceneShadow?.color, opacity: sceneShadow?.opacity ?? 0.25, maxExtend: sceneShadow?.maxExtend }
4174
4439
  });
4175
- return /* @__PURE__ */ jsx9(Fragment, { children: specs.map((spec) => /* @__PURE__ */ jsx9(
4440
+ if (faces.length === 0) return null;
4441
+ return /* @__PURE__ */ jsx9(Fragment, { children: faces.map((fc) => /* @__PURE__ */ jsxs2(
4176
4442
  "svg",
4177
4443
  {
4178
4444
  className: "polycss-shadow polycss-shadow-svg polycss-shadow-receiver",
4179
4445
  "data-poly-shadow-type": "receiver",
4180
- "data-poly-shadow-receiver-face": spec.faceIndex,
4181
- "data-poly-shadow-receiver-polys": JSON.stringify(spec.memberPolyIndices),
4182
- width: spec.width,
4183
- height: spec.height,
4184
- viewBox: `0 0 ${spec.width} ${spec.height}`,
4446
+ "data-poly-shadow-receiver-face": fc.faceIndex,
4447
+ "data-poly-shadow-receiver-polys": JSON.stringify(fc.memberPolyIndices),
4448
+ width: fc.width,
4449
+ height: fc.height,
4450
+ viewBox: `0 0 ${fc.width} ${fc.height}`,
4185
4451
  style: {
4186
4452
  position: "absolute",
4187
4453
  top: 0,
@@ -4191,25 +4457,27 @@ var PolyMesh = forwardRef(function PolyMesh2({
4191
4457
  transformOrigin: "0 0",
4192
4458
  pointerEvents: "none",
4193
4459
  willChange: "transform",
4194
- transform: spec.matrixCss
4460
+ opacity: fc.svgOpacity,
4461
+ transform: fc.matrixCss
4195
4462
  },
4196
- children: spec.paths.map((p, i) => /* @__PURE__ */ jsx9(
4197
- "path",
4198
- {
4199
- d: p.d,
4200
- fill: spec.fill,
4201
- stroke: spec.fill,
4202
- strokeWidth: "3",
4203
- strokeLinejoin: "round",
4204
- opacity: spec.opacity.toFixed(4),
4205
- "data-poly-shadow-caster-polys": JSON.stringify(p.casterPolygonIndices)
4206
- },
4207
- i
4208
- ))
4463
+ children: [
4464
+ fc.baseFill && fc.baseD ? /* @__PURE__ */ jsx9("path", { d: fc.baseD, fill: fc.baseFill, fillRule: "nonzero" }) : null,
4465
+ fc.layers.map((layer, i) => /* @__PURE__ */ jsx9(
4466
+ "path",
4467
+ {
4468
+ d: layer.d,
4469
+ fill: layer.fill,
4470
+ fillRule: "nonzero",
4471
+ opacity: layer.opacity !== 1 ? layer.opacity.toFixed(4) : void 0,
4472
+ style: layer.multiply ? { mixBlendMode: "multiply" } : void 0
4473
+ },
4474
+ i
4475
+ ))
4476
+ ]
4209
4477
  },
4210
- `receiver-${spec.faceIndex}`
4478
+ `receiver-${fc.faceIndex}`
4211
4479
  )) });
4212
- }, [receiveShadow, shadowCasters, shadowCastersVersion, polygons, position, scale, rotation, sceneDirectionalLight, sceneShadow, sceneCtx?.ambientLight, cameraCtx?.store, cameraTick, selfShadowEdgeMap]);
4480
+ }, [receiveShadow, shadowCasters, shadowCastersVersion, polygons, position, scale, rotation, sceneDirectionalLight, sceneCtx?.pointLights, effectiveTextureLighting, sceneShadow, sceneCtx?.ambientLight, cameraCtx?.store, cameraTick, selfShadowEdgeMap]);
4213
4481
  const portalSceneEl = sceneCtx?.sceneEl ?? null;
4214
4482
  const portaledReceiverShadowSvgs = portalSceneEl && receiverShadowSvgs ? createPortal(receiverShadowSvgs, portalSceneEl) : null;
4215
4483
  setPolygonsImplRef.current = (nextPolygons) => {
@@ -4289,12 +4557,28 @@ var PolyMesh = forwardRef(function PolyMesh2({
4289
4557
  entry,
4290
4558
  page: textureAtlas.pages[entry.pageIndex],
4291
4559
  textureLighting: effectiveTextureLighting,
4560
+ textureImageRendering: effectiveTextureImageRendering,
4292
4561
  solidPaintDefaults
4293
4562
  },
4294
4563
  entry.index
4295
4564
  );
4296
4565
  }
4297
4566
  const plan = textureAtlas.plans[index];
4567
+ const imageGeometry = plan ? resolvePolyTextureLeafGeometry2(plan, {
4568
+ imageRendering: effectiveTextureImageRendering,
4569
+ backend: effectiveTextureBackend,
4570
+ projection: effectiveTextureProjection
4571
+ }) : null;
4572
+ if (plan && imageGeometry) {
4573
+ return /* @__PURE__ */ jsx9(
4574
+ TextureImagePoly,
4575
+ {
4576
+ plan,
4577
+ geometry: imageGeometry
4578
+ },
4579
+ plan.index
4580
+ );
4581
+ }
4298
4582
  if (!plan || plan.texture) return null;
4299
4583
  if (isProjectiveQuadPlan(plan)) {
4300
4584
  return /* @__PURE__ */ jsx9(
@@ -4515,6 +4799,7 @@ function usePolyMaterial(options) {
4515
4799
 
4516
4800
  // src/shapes/Poly.tsx
4517
4801
  import { memo as memo9, useMemo as useMemo10 } from "react";
4802
+ import { resolvePolyTextureLeafGeometry as resolvePolyTextureLeafGeometry3 } from "@layoutit/polycss-core";
4518
4803
  import { jsx as jsx12 } from "react/jsx-runtime";
4519
4804
  var DIRECT_TEXTURE_CSS_DECIMALS = 4;
4520
4805
  function formatCssLength(value, decimals = DIRECT_TEXTURE_CSS_DECIMALS) {
@@ -4545,7 +4830,8 @@ function MaterialDirectPoly({
4545
4830
  style: styleProp,
4546
4831
  domAttrs,
4547
4832
  domEventHandlers,
4548
- pointerEvents = "auto"
4833
+ pointerEvents = "auto",
4834
+ imageRendering
4549
4835
  }) {
4550
4836
  const { u0, u1, v0, v1 } = uvRect;
4551
4837
  const du = u1 - u0;
@@ -4560,6 +4846,8 @@ function MaterialDirectPoly({
4560
4846
  backgroundImage: `url(${material.texture})`,
4561
4847
  backgroundSize: `${formatCssLength(sourceW)} ${formatCssLength(sourceH)}`,
4562
4848
  backgroundPosition: `${formatCssLength(-offsetX)} ${formatCssLength(-offsetY)}`,
4849
+ backgroundRepeat: "no-repeat",
4850
+ imageRendering: imageRendering === "pixelated" ? "pixelated" : void 0,
4563
4851
  pointerEvents: pointerEvents === "none" ? "none" : void 0,
4564
4852
  ...styleProp
4565
4853
  };
@@ -4572,6 +4860,14 @@ function MaterialDirectPoly({
4572
4860
  {
4573
4861
  className: elementClassName,
4574
4862
  style,
4863
+ "data-poly-index": plan.index,
4864
+ "data-polycss-leaf": "polygon",
4865
+ "data-polycss-texture-backend": "image",
4866
+ "data-polycss-texture-ready": "true",
4867
+ "data-polycss-texture-image-rendering": imageRendering ?? "auto",
4868
+ "data-polycss-texture-projection": "affine",
4869
+ "data-polycss-texture-lighting": "source",
4870
+ "data-polycss-double-sided": plan.polygon.doubleSided ? "true" : void 0,
4575
4871
  ...domEventHandlers,
4576
4872
  ...dataAttrs,
4577
4873
  ...domAttrs
@@ -4582,8 +4878,11 @@ function PolyInner({
4582
4878
  vertices,
4583
4879
  color,
4584
4880
  texture,
4881
+ textureImageSource,
4882
+ texturePresentation,
4585
4883
  uvs,
4586
4884
  data,
4885
+ doubleSided,
4587
4886
  material,
4588
4887
  position,
4589
4888
  scale,
@@ -4611,6 +4910,10 @@ function PolyInner({
4611
4910
  context,
4612
4911
  textureLighting: textureLightingProp,
4613
4912
  textureQuality: textureQualityProp,
4913
+ textureLeafSizing: textureLeafSizingProp,
4914
+ textureImageRendering: textureImageRenderingProp,
4915
+ textureBackend: textureBackendProp,
4916
+ textureProjection: textureProjectionProp,
4614
4917
  baseColor: baseColorProp,
4615
4918
  ...dataAttrs
4616
4919
  }) {
@@ -4618,11 +4921,25 @@ function PolyInner({
4618
4921
  const layerElevation = context?.layerElevation ?? tileSize;
4619
4922
  const textureLighting = textureLightingProp ?? context?.textureLighting ?? "baked";
4620
4923
  const textureQuality = textureQualityProp ?? context?.textureQuality;
4924
+ const textureLeafSizing = textureLeafSizingProp ?? context?.textureLeafSizing;
4925
+ const textureImageRendering = textureImageRenderingProp ?? context?.textureImageRendering;
4926
+ const textureBackend = textureBackendProp ?? context?.textureBackend;
4927
+ const textureProjection = textureProjectionProp ?? context?.textureProjection;
4621
4928
  const polygonColor = baseColorProp ?? color;
4622
4929
  const effectiveTexture = material?.texture ?? texture;
4623
4930
  const atlasPlan = useMemo10(
4624
4931
  () => computeTextureAtlasPlan(
4625
- { vertices, color: polygonColor, texture: effectiveTexture, uvs, data },
4932
+ {
4933
+ vertices,
4934
+ color: polygonColor,
4935
+ texture: effectiveTexture,
4936
+ textureImageSource,
4937
+ texturePresentation,
4938
+ uvs,
4939
+ data,
4940
+ doubleSided,
4941
+ material
4942
+ },
4626
4943
  0,
4627
4944
  {
4628
4945
  tileSize,
@@ -4634,8 +4951,12 @@ function PolyInner({
4634
4951
  vertices,
4635
4952
  polygonColor,
4636
4953
  effectiveTexture,
4954
+ textureImageSource,
4955
+ texturePresentation,
4637
4956
  uvs,
4638
4957
  data,
4958
+ doubleSided,
4959
+ material,
4639
4960
  tileSize,
4640
4961
  layerElevation,
4641
4962
  context?.directionalLight
@@ -4649,7 +4970,15 @@ function PolyInner({
4649
4970
  () => materialUvRect ? [] : [atlasPlan],
4650
4971
  [materialUvRect, atlasPlan]
4651
4972
  );
4652
- const textureAtlas = useTextureAtlas(atlasPlans, textureLighting, textureQuality);
4973
+ const textureAtlas = useTextureAtlas(
4974
+ atlasPlans,
4975
+ textureLighting,
4976
+ textureQuality,
4977
+ textureLeafSizing,
4978
+ textureBackend,
4979
+ textureImageRendering,
4980
+ textureProjection
4981
+ );
4653
4982
  const domEventHandlers = {
4654
4983
  onClick,
4655
4984
  onDoubleClick,
@@ -4708,7 +5037,8 @@ function PolyInner({
4708
5037
  style: styleProp,
4709
5038
  domAttrs,
4710
5039
  domEventHandlers,
4711
- pointerEvents: pointerEventsProp ?? "auto"
5040
+ pointerEvents: pointerEventsProp ?? "auto",
5041
+ imageRendering: textureImageRendering
4712
5042
  }
4713
5043
  );
4714
5044
  } else {
@@ -4720,6 +5050,7 @@ function PolyInner({
4720
5050
  entry: atlasEntry,
4721
5051
  page: textureAtlas.pages[atlasEntry.pageIndex],
4722
5052
  textureLighting,
5053
+ textureImageRendering,
4723
5054
  className,
4724
5055
  style: styleProp,
4725
5056
  domAttrs,
@@ -4727,7 +5058,28 @@ function PolyInner({
4727
5058
  pointerEvents: pointerEventsProp ?? "auto"
4728
5059
  }
4729
5060
  );
4730
- } else if (atlasPlan && !atlasPlan.texture) {
5061
+ } else {
5062
+ const imageGeometry = atlasPlan ? resolvePolyTextureLeafGeometry3(atlasPlan, {
5063
+ imageRendering: textureImageRendering,
5064
+ backend: textureBackend,
5065
+ projection: textureProjection
5066
+ }) : null;
5067
+ if (atlasPlan && imageGeometry) {
5068
+ front = /* @__PURE__ */ jsx12(
5069
+ TextureImagePoly,
5070
+ {
5071
+ plan: atlasPlan,
5072
+ geometry: imageGeometry,
5073
+ className,
5074
+ style: styleProp,
5075
+ domAttrs,
5076
+ domEventHandlers,
5077
+ pointerEvents: pointerEventsProp ?? "auto"
5078
+ }
5079
+ );
5080
+ }
5081
+ }
5082
+ if (!front && atlasPlan && !atlasPlan.texture) {
4731
5083
  front = isSolidTrianglePlan2(atlasPlan) ? /* @__PURE__ */ jsx12(
4732
5084
  TextureTrianglePoly,
4733
5085
  {
@@ -7062,11 +7414,56 @@ var ZERO_SURFACE_LEAF_COUNTS = {
7062
7414
  atlas: 0,
7063
7415
  stableTriangle: 0
7064
7416
  };
7417
+ var READY_TEXTURE_READINESS = {
7418
+ ready: true,
7419
+ textureLeafCount: 0,
7420
+ readyTextureLeafCount: 0,
7421
+ pendingTextureLeafCount: 0,
7422
+ atlasTextureLeafCount: 0,
7423
+ imageTextureLeafCount: 0
7424
+ };
7425
+ function emptyTextureStats() {
7426
+ return {
7427
+ ready: true,
7428
+ leafCount: 0,
7429
+ atlasCount: 0,
7430
+ imageCount: 0,
7431
+ pendingCount: 0,
7432
+ sizingCounts: { canonical: 0, local: 0, raster: 0, image: 0, unknown: 0 },
7433
+ imageRenderingCounts: { auto: 0, pixelated: 0, unknown: 0 },
7434
+ projectionCounts: { affine: 0, projective: 0, fallback: 0, unknown: 0 },
7435
+ minLeafWidth: 0,
7436
+ maxLeafWidth: 0,
7437
+ minLeafHeight: 0,
7438
+ maxLeafHeight: 0,
7439
+ doubleSidedCount: 0
7440
+ };
7441
+ }
7442
+ function emptySnapshotStats() {
7443
+ return {
7444
+ runtimeAtlasUrlCount: 0,
7445
+ snapshotAtlasCount: 0,
7446
+ snapshotBackgroundCount: 0,
7447
+ selfContained: true
7448
+ };
7449
+ }
7450
+ function emptyCameraStats() {
7451
+ return {
7452
+ rootFound: false,
7453
+ projection: "unknown",
7454
+ perspectiveStyle: "",
7455
+ appliedPerspectiveStyle: ""
7456
+ };
7457
+ }
7065
7458
  var EMPTY_POLY_RENDER_STATS = {
7066
7459
  polygonCount: 0,
7067
7460
  mountedPolygonLeafCount: 0,
7068
7461
  shadowLeafCount: 0,
7069
7462
  surfaceLeafCounts: ZERO_SURFACE_LEAF_COUNTS,
7463
+ textureReadiness: READY_TEXTURE_READINESS,
7464
+ textureStats: emptyTextureStats(),
7465
+ snapshotStats: emptySnapshotStats(),
7466
+ cameraStats: emptyCameraStats(),
7070
7467
  bucketCount: 0
7071
7468
  };
7072
7469
  function asOptions(optionsOrPolygonCount) {
@@ -7078,6 +7475,28 @@ function asOptions(optionsOrPolygonCount) {
7078
7475
  function queryCount(scope, selector) {
7079
7476
  return scope.querySelectorAll(selector).length;
7080
7477
  }
7478
+ function matchingElementCount(scope, selector) {
7479
+ return (matchesSelector(scope, selector) ? 1 : 0) + queryCount(scope, selector);
7480
+ }
7481
+ function styleHasRuntimeUrl(styleText) {
7482
+ if (!styleText) return false;
7483
+ const urlPattern = /url\((?:"([^"]*)"|'([^']*)'|([^)]*))\)/g;
7484
+ let match;
7485
+ while (match = urlPattern.exec(styleText)) {
7486
+ const raw = (match[1] ?? match[2] ?? match[3] ?? "").trim();
7487
+ if (raw && !raw.startsWith("data:")) return true;
7488
+ }
7489
+ return false;
7490
+ }
7491
+ function runtimeUrlElementCount(scope) {
7492
+ let count = 0;
7493
+ const root = scope instanceof HTMLElement ? scope : null;
7494
+ if (root && styleHasRuntimeUrl(root.getAttribute("style"))) count++;
7495
+ for (const el of Array.from(scope.querySelectorAll("[style]"))) {
7496
+ if (el instanceof HTMLElement && styleHasRuntimeUrl(el.getAttribute("style"))) count++;
7497
+ }
7498
+ return count;
7499
+ }
7081
7500
  function matchesSelector(root, selector) {
7082
7501
  const candidate = root;
7083
7502
  return typeof candidate.matches === "function" && candidate.matches(selector);
@@ -7089,12 +7508,196 @@ function collectScopes(root, selector) {
7089
7508
  scopes.push(...Array.from(root.querySelectorAll(selector)));
7090
7509
  return scopes;
7091
7510
  }
7511
+ function leafStrategyForTag(tagName) {
7512
+ switch (tagName.toLowerCase()) {
7513
+ case "b":
7514
+ return "quad";
7515
+ case "i":
7516
+ return "clippedSolid";
7517
+ case "s":
7518
+ return "atlas";
7519
+ case "u":
7520
+ return "stableTriangle";
7521
+ default:
7522
+ return null;
7523
+ }
7524
+ }
7525
+ function parseOptionalInteger(value) {
7526
+ if (value == null || value === "") return void 0;
7527
+ const parsed = Number.parseInt(value, 10);
7528
+ return Number.isFinite(parsed) ? parsed : void 0;
7529
+ }
7530
+ function parseOptionalNumber(value) {
7531
+ if (value == null || value === "") return void 0;
7532
+ const parsed = Number(value);
7533
+ return Number.isFinite(parsed) ? parsed : void 0;
7534
+ }
7535
+ function parseOptionalVec3(value) {
7536
+ if (value == null || value === "") return void 0;
7537
+ const parts = value.split(",").map((part) => Number(part));
7538
+ if (parts.length !== 3 || parts.some((part) => !Number.isFinite(part))) return void 0;
7539
+ return parts;
7540
+ }
7541
+ function parseCameraProjection(value) {
7542
+ return value === "orthographic" || value === "perspective" ? value : "unknown";
7543
+ }
7544
+ function textureReadyForElement(el, textureBackend) {
7545
+ if (!textureBackend) return void 0;
7546
+ const attr = el.getAttribute("data-polycss-texture-ready");
7547
+ if (attr === "true") return true;
7548
+ if (attr === "false") return false;
7549
+ return el.style.opacity !== "0";
7550
+ }
7551
+ function queryPolyLeaves(root, optionsOrPolygonCount) {
7552
+ if (!root) return [];
7553
+ const options = asOptions(optionsOrPolygonCount);
7554
+ const out = [];
7555
+ for (const scope of collectScopes(root, options.scopeSelector)) {
7556
+ for (const el of Array.from(scope.querySelectorAll("b,i,s,u"))) {
7557
+ const htmlEl = el;
7558
+ const strategy = leafStrategyForTag(htmlEl.tagName);
7559
+ if (!strategy) continue;
7560
+ const textureBackend = htmlEl.getAttribute("data-polycss-texture-backend") ?? (strategy === "atlas" ? "atlas" : void 0);
7561
+ const textureReady = textureReadyForElement(htmlEl, textureBackend);
7562
+ out.push({
7563
+ element: htmlEl,
7564
+ strategy,
7565
+ polygonIndex: parseOptionalInteger(htmlEl.getAttribute("data-poly-index")),
7566
+ textureBackend,
7567
+ textureReady,
7568
+ textureLeafSizing: htmlEl.getAttribute("data-polycss-texture-leaf-sizing") ?? void 0,
7569
+ textureImageRendering: htmlEl.getAttribute("data-polycss-texture-image-rendering") ?? void 0,
7570
+ textureProjection: htmlEl.getAttribute("data-polycss-texture-projection") ?? void 0,
7571
+ textureLeafWidth: parseOptionalNumber(htmlEl.getAttribute("data-polycss-texture-leaf-width")),
7572
+ textureLeafHeight: parseOptionalNumber(htmlEl.getAttribute("data-polycss-texture-leaf-height")),
7573
+ doubleSided: htmlEl.getAttribute("data-polycss-double-sided") === "true"
7574
+ });
7575
+ }
7576
+ }
7577
+ return out;
7578
+ }
7579
+ function collectPolyTextureReadiness(root, optionsOrPolygonCount) {
7580
+ const readiness = { ...READY_TEXTURE_READINESS };
7581
+ for (const leaf of queryPolyLeaves(root, optionsOrPolygonCount)) {
7582
+ if (!leaf.textureBackend) continue;
7583
+ readiness.textureLeafCount++;
7584
+ if (leaf.textureBackend === "image") readiness.imageTextureLeafCount++;
7585
+ else readiness.atlasTextureLeafCount++;
7586
+ if (leaf.textureReady === false) readiness.pendingTextureLeafCount++;
7587
+ else readiness.readyTextureLeafCount++;
7588
+ }
7589
+ readiness.ready = readiness.pendingTextureLeafCount === 0;
7590
+ return readiness;
7591
+ }
7592
+ function collectPolyTextureStats(root, optionsOrPolygonCount) {
7593
+ const stats = emptyTextureStats();
7594
+ let hasWidth = false;
7595
+ let hasHeight = false;
7596
+ for (const leaf of queryPolyLeaves(root, optionsOrPolygonCount)) {
7597
+ if (!leaf.textureBackend) continue;
7598
+ stats.leafCount++;
7599
+ if (leaf.textureBackend === "image") stats.imageCount++;
7600
+ else stats.atlasCount++;
7601
+ if (leaf.textureReady === false) stats.pendingCount++;
7602
+ switch (leaf.textureLeafSizing) {
7603
+ case "canonical":
7604
+ case "local":
7605
+ case "raster":
7606
+ case "image":
7607
+ stats.sizingCounts[leaf.textureLeafSizing]++;
7608
+ break;
7609
+ default:
7610
+ stats.sizingCounts.unknown++;
7611
+ break;
7612
+ }
7613
+ switch (leaf.textureImageRendering) {
7614
+ case "auto":
7615
+ case "pixelated":
7616
+ stats.imageRenderingCounts[leaf.textureImageRendering]++;
7617
+ break;
7618
+ default:
7619
+ stats.imageRenderingCounts.unknown++;
7620
+ break;
7621
+ }
7622
+ switch (leaf.textureProjection) {
7623
+ case "affine":
7624
+ case "projective":
7625
+ case "fallback":
7626
+ stats.projectionCounts[leaf.textureProjection]++;
7627
+ break;
7628
+ default:
7629
+ stats.projectionCounts.unknown++;
7630
+ break;
7631
+ }
7632
+ if (typeof leaf.textureLeafWidth === "number") {
7633
+ stats.minLeafWidth = hasWidth ? Math.min(stats.minLeafWidth, leaf.textureLeafWidth) : leaf.textureLeafWidth;
7634
+ stats.maxLeafWidth = hasWidth ? Math.max(stats.maxLeafWidth, leaf.textureLeafWidth) : leaf.textureLeafWidth;
7635
+ hasWidth = true;
7636
+ }
7637
+ if (typeof leaf.textureLeafHeight === "number") {
7638
+ stats.minLeafHeight = hasHeight ? Math.min(stats.minLeafHeight, leaf.textureLeafHeight) : leaf.textureLeafHeight;
7639
+ stats.maxLeafHeight = hasHeight ? Math.max(stats.maxLeafHeight, leaf.textureLeafHeight) : leaf.textureLeafHeight;
7640
+ hasHeight = true;
7641
+ }
7642
+ if (leaf.doubleSided) stats.doubleSidedCount++;
7643
+ }
7644
+ stats.pendingCount = Math.min(stats.pendingCount, stats.leafCount);
7645
+ stats.ready = stats.pendingCount === 0;
7646
+ return stats;
7647
+ }
7648
+ function collectPolySnapshotStats(root, optionsOrPolygonCount) {
7649
+ const stats = emptySnapshotStats();
7650
+ if (!root) return stats;
7651
+ const options = asOptions(optionsOrPolygonCount);
7652
+ for (const scope of collectScopes(root, options.scopeSelector)) {
7653
+ stats.runtimeAtlasUrlCount += runtimeUrlElementCount(scope);
7654
+ stats.snapshotAtlasCount += matchingElementCount(scope, "[data-polycss-snapshot-atlas]");
7655
+ stats.snapshotBackgroundCount += matchingElementCount(scope, "[data-polycss-snapshot-bg]");
7656
+ }
7657
+ stats.selfContained = stats.runtimeAtlasUrlCount === 0;
7658
+ return stats;
7659
+ }
7660
+ function findCameraRoot(scope) {
7661
+ const element = scope instanceof HTMLElement ? scope : null;
7662
+ if (element) {
7663
+ if (element.classList.contains("polycss-camera")) return element;
7664
+ const closest = element.closest(".polycss-camera");
7665
+ if (closest instanceof HTMLElement) return closest;
7666
+ }
7667
+ const found = scope.querySelector(".polycss-camera");
7668
+ return found instanceof HTMLElement ? found : null;
7669
+ }
7670
+ function collectPolyCameraStats(root, optionsOrPolygonCount) {
7671
+ if (!root) return emptyCameraStats();
7672
+ const options = asOptions(optionsOrPolygonCount);
7673
+ let cameraRoot = null;
7674
+ for (const scope of collectScopes(root, options.scopeSelector)) {
7675
+ cameraRoot = findCameraRoot(scope);
7676
+ if (cameraRoot) break;
7677
+ }
7678
+ if (!cameraRoot) return emptyCameraStats();
7679
+ return {
7680
+ rootFound: true,
7681
+ projection: parseCameraProjection(cameraRoot.getAttribute("data-polycss-camera-projection")),
7682
+ perspectiveStyle: cameraRoot.getAttribute("data-polycss-camera-perspective") ?? "",
7683
+ appliedPerspectiveStyle: cameraRoot.getAttribute("data-polycss-camera-applied-perspective") ?? cameraRoot.style.perspective ?? "",
7684
+ zoom: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-zoom")),
7685
+ distance: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-distance")),
7686
+ rotX: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-rot-x")),
7687
+ rotY: parseOptionalNumber(cameraRoot.getAttribute("data-polycss-camera-rot-y")),
7688
+ target: parseOptionalVec3(cameraRoot.getAttribute("data-polycss-camera-target"))
7689
+ };
7690
+ }
7092
7691
  function collectPolyRenderStats(root, optionsOrPolygonCount) {
7093
7692
  const options = asOptions(optionsOrPolygonCount);
7094
7693
  if (!root) {
7095
7694
  return {
7096
7695
  ...EMPTY_POLY_RENDER_STATS,
7097
7696
  surfaceLeafCounts: { ...ZERO_SURFACE_LEAF_COUNTS },
7697
+ textureReadiness: { ...READY_TEXTURE_READINESS },
7698
+ textureStats: emptyTextureStats(),
7699
+ snapshotStats: emptySnapshotStats(),
7700
+ cameraStats: emptyCameraStats(),
7098
7701
  polygonCount: options.polygonCount ?? 0
7099
7702
  };
7100
7703
  }
@@ -7116,6 +7719,10 @@ function collectPolyRenderStats(root, optionsOrPolygonCount) {
7116
7719
  mountedPolygonLeafCount,
7117
7720
  shadowLeafCount,
7118
7721
  surfaceLeafCounts,
7722
+ textureReadiness: collectPolyTextureReadiness(root, options),
7723
+ textureStats: collectPolyTextureStats(root, options),
7724
+ snapshotStats: collectPolySnapshotStats(root, options),
7725
+ cameraStats: collectPolyCameraStats(root, options),
7119
7726
  bucketCount
7120
7727
  };
7121
7728
  }
@@ -7261,25 +7868,35 @@ import {
7261
7868
  planePolygons as planePolygons3,
7262
7869
  buildSceneContext as buildSceneContext2,
7263
7870
  buildPolyMeshTransform as buildPolyMeshTransform2,
7264
- buildPolySceneTransform as buildPolySceneTransform2,
7871
+ buildPolySceneTransform,
7265
7872
  computeSceneBbox as computeSceneBbox2,
7873
+ cssDistanceToWorld,
7874
+ cssPositionToWorld,
7875
+ polyCssDistanceToWorld,
7876
+ polyCssPositionToWorld,
7877
+ worldDirectionToCss as worldDirectionToCss3,
7878
+ worldDirectionToPolyCss,
7879
+ worldDirectionalLightToCss as worldDirectionalLightToCss2,
7880
+ worldDirectionalLightToPolyCss,
7881
+ worldDistanceToCss,
7882
+ worldDistanceToPolyCss,
7883
+ worldPositionToCss as worldPositionToCss2,
7884
+ worldPositionToPolyCss,
7266
7885
  BASE_TILE as BASE_TILE7,
7267
7886
  DEFAULT_CAMERA_STATE as DEFAULT_CAMERA_STATE2,
7268
7887
  DEFAULT_PROJECTION,
7269
7888
  normalizeInvertMultiplier,
7889
+ buildPolyCameraSceneTransform as buildPolyCameraSceneTransform2,
7890
+ capturePolyCameraSnapshot as capturePolyCameraSnapshot2,
7891
+ polyCameraTargetToCss,
7892
+ resolvePolyCameraAppliedPerspectiveStyle,
7270
7893
  createPolyAnimationMixer as createPolyAnimationMixer2,
7271
7894
  optimizeAnimatedMeshPolygons,
7272
7895
  DEFAULT_SEAM_FACET_SPLIT_OPTIONS,
7273
7896
  DEFAULT_SEAM_OVERLAP_OPTIONS,
7274
7897
  LoopOnce,
7275
7898
  LoopRepeat,
7276
- LoopPingPong,
7277
- cssDistanceToWorld,
7278
- cssPositionToWorld,
7279
- worldDistanceToCss,
7280
- worldDirectionToCss as worldDirectionToCss3,
7281
- worldDirectionalLightToCss as worldDirectionalLightToCss2,
7282
- worldPositionToCss
7899
+ LoopPingPong
7283
7900
  } from "@layoutit/polycss-core";
7284
7901
  export {
7285
7902
  BASE_TILE7 as BASE_TILE,
@@ -7325,16 +7942,19 @@ export {
7325
7942
  bakeSolidTextureSampledPolygons,
7326
7943
  bakeSolidTextureSamples,
7327
7944
  boxPolygons2 as boxPolygons,
7945
+ buildPolyCameraSceneTransform2 as buildPolyCameraSceneTransform,
7328
7946
  buildPolyMeshTransform2 as buildPolyMeshTransform,
7329
- buildPolySceneTransform2 as buildPolySceneTransform,
7947
+ buildPolySceneTransform,
7330
7948
  buildSceneContext2 as buildSceneContext,
7331
7949
  cameraCullNormalGroups,
7332
7950
  cameraCullNormalGroupsFromPolygons,
7333
7951
  cameraCullNormalKey,
7334
7952
  cameraCullVisibleSignature,
7335
7953
  cameraFacingDepth,
7954
+ capturePolyCameraSnapshot2 as capturePolyCameraSnapshot,
7336
7955
  clampChannel2 as clampChannel,
7337
7956
  collectPolyRenderStats,
7957
+ collectPolyTextureReadiness,
7338
7958
  computeSceneBbox2 as computeSceneBbox,
7339
7959
  computeShapeLighting,
7340
7960
  computeTexturePaintMetrics,
@@ -7342,6 +7962,8 @@ export {
7342
7962
  coverPlanarPolygons,
7343
7963
  createIsometricCamera2 as createIsometricCamera,
7344
7964
  createPolyAnimationMixer2 as createPolyAnimationMixer,
7965
+ cssDistanceToWorld,
7966
+ cssPositionToWorld,
7345
7967
  cullInteriorPolygons,
7346
7968
  cylinderPolygons2 as cylinderPolygons,
7347
7969
  dodecahedronPolygons2 as dodecahedronPolygons,
@@ -7373,12 +7995,15 @@ export {
7373
7995
  parseVox,
7374
7996
  planePolygons3 as planePolygons,
7375
7997
  pointInMeshElement,
7376
- cssDistanceToWorld as polyCssDistanceToWorld,
7377
- cssPositionToWorld as polyCssPositionToWorld,
7998
+ polyCameraTargetToCss,
7999
+ polyCssDistanceToWorld,
8000
+ polyCssPositionToWorld,
7378
8001
  polygonCssSurfaceNormal,
7379
8002
  polygonFaces,
7380
8003
  polygonFacesCamera,
8004
+ queryPolyLeaves,
7381
8005
  repairMeshSeams,
8006
+ resolvePolyCameraAppliedPerspectiveStyle,
7382
8007
  ringPolygons2 as ringPolygons,
7383
8008
  rotateVec32 as rotateVec3,
7384
8009
  seamFacetSplitPolygons,
@@ -7398,8 +8023,12 @@ export {
7398
8023
  usePolySceneContext,
7399
8024
  usePolySelect,
7400
8025
  usePolySelectionApi,
7401
- worldDirectionToCss3 as worldDirectionToPolyCss,
7402
- worldDirectionalLightToCss2 as worldDirectionalLightToPolyCss,
7403
- worldDistanceToCss as worldDistanceToPolyCss,
7404
- worldPositionToCss as worldPositionToPolyCss
8026
+ worldDirectionToCss3 as worldDirectionToCss,
8027
+ worldDirectionToPolyCss,
8028
+ worldDirectionalLightToCss2 as worldDirectionalLightToCss,
8029
+ worldDirectionalLightToPolyCss,
8030
+ worldDistanceToCss,
8031
+ worldDistanceToPolyCss,
8032
+ worldPositionToCss2 as worldPositionToCss,
8033
+ worldPositionToPolyCss
7405
8034
  };