@pascal-app/viewer 1.0.0-beta.5 → 1.0.1

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.
Files changed (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/capture/asset-url.d.ts +2 -0
  4. package/dist/capture/asset-url.d.ts.map +1 -0
  5. package/dist/capture/asset-url.js +13 -0
  6. package/dist/capture/capture-runtime.d.ts +43 -0
  7. package/dist/capture/capture-runtime.d.ts.map +1 -0
  8. package/dist/capture/capture-runtime.js +198 -0
  9. package/dist/capture/frame.d.ts +4 -0
  10. package/dist/capture/frame.d.ts.map +1 -0
  11. package/dist/capture/frame.js +21 -0
  12. package/dist/capture/index.d.ts +12 -0
  13. package/dist/capture/index.d.ts.map +1 -0
  14. package/dist/capture/index.js +11 -0
  15. package/dist/capture/layer-visibility.d.ts +5 -0
  16. package/dist/capture/layer-visibility.d.ts.map +1 -0
  17. package/dist/capture/layer-visibility.js +11 -0
  18. package/dist/capture/layers/clay-matcap.d.ts +3 -0
  19. package/dist/capture/layers/clay-matcap.d.ts.map +1 -0
  20. package/dist/capture/layers/clay-matcap.js +26 -0
  21. package/dist/capture/layers/device-motion-layer.d.ts +7 -0
  22. package/dist/capture/layers/device-motion-layer.d.ts.map +1 -0
  23. package/dist/capture/layers/device-motion-layer.js +76 -0
  24. package/dist/capture/layers/point-cloud-layer.d.ts +15 -0
  25. package/dist/capture/layers/point-cloud-layer.d.ts.map +1 -0
  26. package/dist/capture/layers/point-cloud-layer.js +106 -0
  27. package/dist/capture/layers/room-model-layer.d.ts +9 -0
  28. package/dist/capture/layers/room-model-layer.d.ts.map +1 -0
  29. package/dist/capture/layers/room-model-layer.js +71 -0
  30. package/dist/capture/layers/surface-mesh-data.d.ts +9 -0
  31. package/dist/capture/layers/surface-mesh-data.d.ts.map +1 -0
  32. package/dist/capture/layers/surface-mesh-data.js +74 -0
  33. package/dist/capture/layers/surface-mesh-layer.d.ts +7 -0
  34. package/dist/capture/layers/surface-mesh-layer.d.ts.map +1 -0
  35. package/dist/capture/layers/surface-mesh-layer.js +16 -0
  36. package/dist/capture/preview.d.ts +3 -0
  37. package/dist/capture/preview.d.ts.map +1 -0
  38. package/dist/capture/preview.js +2 -0
  39. package/dist/capture/source-state.d.ts +22 -0
  40. package/dist/capture/source-state.d.ts.map +1 -0
  41. package/dist/capture/source-state.js +182 -0
  42. package/dist/capture/stream-rendering.d.ts +14 -0
  43. package/dist/capture/stream-rendering.d.ts.map +1 -0
  44. package/dist/capture/stream-rendering.js +70 -0
  45. package/dist/capture/trajectory.d.ts +20 -0
  46. package/dist/capture/trajectory.d.ts.map +1 -0
  47. package/dist/capture/trajectory.js +77 -0
  48. package/dist/capture/use-json-artifact.d.ts +2 -0
  49. package/dist/capture/use-json-artifact.d.ts.map +1 -0
  50. package/dist/capture/use-json-artifact.js +42 -0
  51. package/dist/components/viewer/batched-mesh-spike.d.ts +14 -0
  52. package/dist/components/viewer/batched-mesh-spike.d.ts.map +1 -0
  53. package/dist/components/viewer/batched-mesh-spike.js +64 -0
  54. package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
  55. package/dist/components/viewer/frame-limiter.js +4 -3
  56. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  57. package/dist/components/viewer/glb-scene.js +3 -1
  58. package/dist/components/viewer/index.d.ts.map +1 -1
  59. package/dist/components/viewer/index.js +70 -62
  60. package/dist/components/viewer/lights.d.ts.map +1 -1
  61. package/dist/components/viewer/lights.js +123 -89
  62. package/dist/components/viewer/perf-monitor.d.ts +6 -1
  63. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  64. package/dist/components/viewer/perf-monitor.js +307 -116
  65. package/dist/components/viewer/perf-panel.d.ts +3 -0
  66. package/dist/components/viewer/perf-panel.d.ts.map +1 -0
  67. package/dist/components/viewer/perf-panel.js +178 -0
  68. package/dist/components/viewer/pointer-raycast-layers.d.ts +15 -0
  69. package/dist/components/viewer/pointer-raycast-layers.d.ts.map +1 -0
  70. package/dist/components/viewer/pointer-raycast-layers.js +28 -0
  71. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  72. package/dist/components/viewer/post-processing.js +130 -83
  73. package/dist/components/viewer/registered-systems.d.ts +14 -5
  74. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  75. package/dist/components/viewer/registered-systems.js +22 -10
  76. package/dist/components/viewer/scene-atmosphere.d.ts +30 -0
  77. package/dist/components/viewer/scene-atmosphere.d.ts.map +1 -0
  78. package/dist/components/viewer/scene-atmosphere.js +89 -0
  79. package/dist/components/viewer/scene-environment.d.ts.map +1 -1
  80. package/dist/components/viewer/scene-environment.js +19 -5
  81. package/dist/components/viewer/scene-ground-replacement.d.ts +5 -0
  82. package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -0
  83. package/dist/components/viewer/scene-ground-replacement.js +35 -0
  84. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  85. package/dist/components/viewer/selection-manager.js +8 -16
  86. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  87. package/dist/components/viewer/viewer-camera.js +4 -1
  88. package/dist/components/viewer/viewer-presentations.d.ts +67 -0
  89. package/dist/components/viewer/viewer-presentations.d.ts.map +1 -0
  90. package/dist/components/viewer/viewer-presentations.js +120 -0
  91. package/dist/hooks/use-library-materials-version.d.ts +7 -0
  92. package/dist/hooks/use-library-materials-version.d.ts.map +1 -0
  93. package/dist/hooks/use-library-materials-version.js +10 -0
  94. package/dist/hooks/use-node-events.d.ts.map +1 -1
  95. package/dist/hooks/use-node-events.js +1 -0
  96. package/dist/index.d.ts +16 -7
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +16 -7
  99. package/dist/lib/csg-utils.d.ts +1 -0
  100. package/dist/lib/csg-utils.d.ts.map +1 -1
  101. package/dist/lib/csg-utils.js +6 -1
  102. package/dist/lib/gpu-perf.d.ts +0 -2
  103. package/dist/lib/gpu-perf.d.ts.map +1 -1
  104. package/dist/lib/gpu-perf.js +7 -21
  105. package/dist/lib/isolation.d.ts +14 -30
  106. package/dist/lib/isolation.d.ts.map +1 -1
  107. package/dist/lib/isolation.js +62 -66
  108. package/dist/lib/layer-pass.d.ts +28 -0
  109. package/dist/lib/layer-pass.d.ts.map +1 -0
  110. package/dist/lib/layer-pass.js +254 -0
  111. package/dist/lib/materials.d.ts +12 -0
  112. package/dist/lib/materials.d.ts.map +1 -1
  113. package/dist/lib/materials.js +52 -17
  114. package/dist/lib/merged-outline-node.d.ts +17 -8
  115. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  116. package/dist/lib/merged-outline-node.js +194 -52
  117. package/dist/lib/perf-actions.d.ts +55 -0
  118. package/dist/lib/perf-actions.d.ts.map +1 -0
  119. package/dist/lib/perf-actions.js +211 -0
  120. package/dist/lib/perf-observers.d.ts +2 -0
  121. package/dist/lib/perf-observers.d.ts.map +1 -0
  122. package/dist/lib/perf-observers.js +17 -0
  123. package/dist/lib/perf-panel-store.d.ts +71 -0
  124. package/dist/lib/perf-panel-store.d.ts.map +1 -0
  125. package/dist/lib/perf-panel-store.js +29 -0
  126. package/dist/lib/perf-tracks.d.ts +43 -0
  127. package/dist/lib/perf-tracks.d.ts.map +1 -0
  128. package/dist/lib/perf-tracks.js +113 -0
  129. package/dist/lib/pointer-events.d.ts +7 -0
  130. package/dist/lib/pointer-events.d.ts.map +1 -0
  131. package/dist/lib/pointer-events.js +680 -0
  132. package/dist/lib/post-processing-resources.d.ts +12 -0
  133. package/dist/lib/post-processing-resources.d.ts.map +1 -0
  134. package/dist/lib/post-processing-resources.js +19 -0
  135. package/dist/lib/renderer-capability.d.ts.map +1 -1
  136. package/dist/lib/renderer-capability.js +4 -2
  137. package/dist/lib/scene-visibility.d.ts +2 -1
  138. package/dist/lib/scene-visibility.d.ts.map +1 -1
  139. package/dist/lib/scene-visibility.js +25 -2
  140. package/dist/lib/snapshot-pipeline.d.ts +3 -1
  141. package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
  142. package/dist/lib/snapshot-pipeline.js +32 -16
  143. package/dist/store/use-viewer.d.ts +5 -3
  144. package/dist/store/use-viewer.d.ts.map +1 -1
  145. package/dist/store/use-viewer.js +2 -0
  146. package/dist/systems/ceiling/ceiling-system.js +1 -1
  147. package/dist/systems/door/door-animation-system.d.ts.map +1 -1
  148. package/dist/systems/door/door-animation-system.js +6 -9
  149. package/dist/systems/door/door-system.d.ts.map +1 -1
  150. package/dist/systems/door/door-system.js +13 -2
  151. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
  152. package/dist/systems/floor-elevation/floor-elevation-system.js +7 -3
  153. package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
  154. package/dist/systems/geometry/geometry-system.js +7 -2
  155. package/dist/systems/level/level-system.d.ts.map +1 -1
  156. package/dist/systems/level/level-system.js +1 -1
  157. package/dist/systems/level/level-utils.d.ts +9 -0
  158. package/dist/systems/level/level-utils.d.ts.map +1 -1
  159. package/dist/systems/level/level-utils.js +14 -0
  160. package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts +8 -0
  161. package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts.map +1 -0
  162. package/dist/systems/perf-action-settle/perf-action-settle-system.js +32 -0
  163. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  164. package/dist/systems/roof/roof-system.js +1196 -58
  165. package/dist/systems/scan/scan-system.js +6 -5
  166. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  167. package/dist/systems/slab/slab-system.js +1 -2
  168. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  169. package/dist/systems/stair/stair-system.js +9 -8
  170. package/dist/systems/surface-hole-geometry.d.ts +1 -1
  171. package/dist/systems/surface-hole-geometry.d.ts.map +1 -1
  172. package/dist/systems/surface-hole-geometry.js +1 -1
  173. package/dist/systems/wall/level-miter-cache.d.ts.map +1 -1
  174. package/dist/systems/wall/wall-build-lifecycle.d.ts +9 -0
  175. package/dist/systems/wall/wall-build-lifecycle.d.ts.map +1 -0
  176. package/dist/systems/wall/wall-build-lifecycle.js +74 -0
  177. package/dist/systems/wall/wall-cutout-cache.d.ts +57 -0
  178. package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -0
  179. package/dist/systems/wall/wall-cutout-cache.js +304 -0
  180. package/dist/systems/wall/wall-cutout.d.ts +12 -1
  181. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  182. package/dist/systems/wall/wall-cutout.js +24 -161
  183. package/dist/systems/wall/wall-material-variant.d.ts +31 -0
  184. package/dist/systems/wall/wall-material-variant.d.ts.map +1 -0
  185. package/dist/systems/wall/wall-material-variant.js +10 -0
  186. package/dist/systems/wall/wall-materials.d.ts +6 -0
  187. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  188. package/dist/systems/wall/wall-materials.js +29 -13
  189. package/dist/systems/wall/wall-placeholder-sweep.d.ts +50 -0
  190. package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -0
  191. package/dist/systems/wall/wall-placeholder-sweep.js +51 -0
  192. package/dist/systems/wall/wall-rebuild-notifications.d.ts +5 -0
  193. package/dist/systems/wall/wall-rebuild-notifications.d.ts.map +1 -0
  194. package/dist/systems/wall/wall-rebuild-notifications.js +23 -0
  195. package/dist/systems/wall/wall-system.d.ts +11 -4
  196. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  197. package/dist/systems/wall/wall-system.js +405 -153
  198. package/dist/systems/window/window-animation-system.d.ts.map +1 -1
  199. package/dist/systems/window/window-animation-system.js +9 -8
  200. package/dist/systems/window/window-system.d.ts +1 -0
  201. package/dist/systems/window/window-system.d.ts.map +1 -1
  202. package/dist/systems/window/window-system.js +16 -2
  203. package/dist/systems/zone/zone-system.d.ts.map +1 -1
  204. package/dist/systems/zone/zone-system.js +28 -2
  205. package/package.json +17 -4
  206. package/dist/lib/polygon-union.d.ts +0 -4
  207. package/dist/lib/polygon-union.d.ts.map +0 -1
  208. package/dist/lib/polygon-union.js +0 -289
@@ -0,0 +1,55 @@
1
+ export type PerfActionReceipt = {
2
+ name: string;
3
+ /** Free-form context, e.g. the node id or kind. */
4
+ detail: string;
5
+ /** begin → commit (the human gesture; 0 for instant actions like undo). */
6
+ dragMs: number;
7
+ /** commit → fully settled (rebuilds + one GPU sample after quiet). */
8
+ settleMs: number;
9
+ /** begin → settled. */
10
+ totalMs: number;
11
+ /** Frames observed between commit and settled. */
12
+ settleFrames: number;
13
+ /** Per-track attribution over begin → settled, sorted by totalMs desc. */
14
+ tracks: Array<{
15
+ name: string;
16
+ totalMs: number;
17
+ count: number;
18
+ }>;
19
+ outcome: 'settled' | 'interrupted' | 'timeout';
20
+ endedAt: number;
21
+ };
22
+ /**
23
+ * Start attributing samples to a named action. Interrupts any active one.
24
+ * Returns an id the caller can compare against `getActivePerfActionId()` to
25
+ * commit only the action it actually began.
26
+ */
27
+ export declare function beginPerfAction(name: string, detail?: string): number | null;
28
+ /** The gesture ended (pointer up / operation dispatched); settling begins. */
29
+ export declare function commitPerfAction(): void;
30
+ /** The gesture was aborted (Escape mid-drag); discard without a settle wait. */
31
+ export declare function cancelPerfAction(): void;
32
+ /** Convenience for instant actions (undo, level switch): begin + commit. */
33
+ export declare function markPerfAction(name: string, detail?: string): void;
34
+ /**
35
+ * Whether an action is currently being attributed. Lets a generic call site
36
+ * (the interaction scope) yield to a more specific one that began first.
37
+ */
38
+ export declare function hasActivePerfAction(): boolean;
39
+ /**
40
+ * Like `hasActivePerfAction`, but false once the active action has committed.
41
+ * A generic bracket yields to an UNCOMMITTED action (a gesture in flight) but
42
+ * must be free to start a new receipt while the previous one is merely
43
+ * settling — beginPerfAction then finalizes the settling one as interrupted.
44
+ */
45
+ export declare function hasUncommittedPerfAction(): boolean;
46
+ /** Id of the action currently attributing samples, if any. */
47
+ export declare function getActivePerfActionId(): number | null;
48
+ /**
49
+ * Called once per frame by the viewer settle system with the current dirty
50
+ * count and the wall system's deferred-neighbour backlog. Also the ledger's
51
+ * only heartbeat, so it is where a stuck action gets released.
52
+ */
53
+ export declare function notifyPerfActionFrame(dirtyCount: number, pendingRebuilds: number): void;
54
+ export declare function usePerfActionReceipts(): PerfActionReceipt[];
55
+ //# sourceMappingURL=perf-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-actions.d.ts","sourceRoot":"","sources":["../../src/lib/perf-actions.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAA;IACd,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAA;IAChB,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAA;IACpB,0EAA0E;IAC1E,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC/D,OAAO,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS,CAAA;IAC9C,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AA8FD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,GAAG,IAAI,CAmCxE;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,IAAI,CAG9D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED,8DAA8D;AAC9D,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAgBvF;AAgBD,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAE3D"}
@@ -0,0 +1,211 @@
1
+ // Action-cost ledger for `?perf`.
2
+ //
3
+ // An "action" is one user edit gesture: a wall-endpoint drag, a door move, an
4
+ // undo, a level switch. The editor package brackets the gesture with
5
+ // `beginPerfAction` / `commitPerfAction`; every perf-tracks sample recorded in
6
+ // between (wall-csg, geometry, react-render, gpu-render, …) is attributed to
7
+ // it. The action is "settled" only when the scene has finished digesting the
8
+ // edit: dirty queue empty, deferred wall neighbour rebuilds flushed, and one
9
+ // more GPU sample resolved after that — i.e. the user actually sees the final
10
+ // result. The settle system in the viewer feeds that state per frame via
11
+ // `notifyPerfActionFrame`.
12
+ //
13
+ // Everything is a no-op without `?perf`.
14
+ import { useSyncExternalStore } from 'react';
15
+ import { PERF_OVERLAY_ENABLED } from './gpu-perf';
16
+ import { subscribePerfSamples } from './perf-tracks';
17
+ const SETTLE_TIMEOUT_MS = 5000;
18
+ // A gesture that begins and never commits (a hover preview, a drag whose
19
+ // pointerup never reached the caller) is never settle-checked, so without an
20
+ // absolute cap it would hold its sample subscription — and keep growing its
21
+ // buckets — for the rest of the session.
22
+ const UNCOMMITTED_TIMEOUT_MS = 60_000;
23
+ const MAX_RECEIPTS = 5;
24
+ let active = null;
25
+ let actionSeq = 0;
26
+ // Whether this device has ever produced a real timestamp-query sample. Without
27
+ // `timestamp-query` support no 'gpu-render' sample can ever arrive, so settle
28
+ // falls back to the queue fence — see the sample listener below.
29
+ let gpuTimestampsSeen = false;
30
+ let receipts = [];
31
+ const listeners = new Set();
32
+ function emitReceipts() {
33
+ for (const listener of listeners)
34
+ listener();
35
+ }
36
+ function finalize(outcome) {
37
+ const action = active;
38
+ if (!action)
39
+ return;
40
+ active = null;
41
+ action.unsubscribe();
42
+ const now = performance.now();
43
+ const committedAt = action.committedAt ?? now;
44
+ const receipt = {
45
+ name: action.name,
46
+ detail: action.detail,
47
+ dragMs: committedAt - action.startedAt,
48
+ settleMs: now - committedAt,
49
+ totalMs: now - action.startedAt,
50
+ settleFrames: action.settleFrames,
51
+ tracks: [...action.buckets.entries()]
52
+ .map(([name, b]) => ({ name, totalMs: b.totalMs, count: b.count }))
53
+ .sort((a, b) => b.totalMs - a.totalMs),
54
+ outcome,
55
+ endedAt: now,
56
+ };
57
+ receipts = [receipt, ...receipts].slice(0, MAX_RECEIPTS);
58
+ emitReceipts();
59
+ // One timeline entry per action so recordings show the full span with its
60
+ // breakdown attached.
61
+ try {
62
+ performance.measure(`${action.name}${action.detail ? ` ${action.detail}` : ''}`, {
63
+ start: action.startedAt,
64
+ end: now,
65
+ detail: {
66
+ devtools: {
67
+ dataType: 'track-entry',
68
+ track: 'Actions',
69
+ trackGroup: 'Pascal',
70
+ color: outcome === 'settled' ? 'secondary' : 'error',
71
+ properties: [
72
+ ['outcome', outcome],
73
+ ['drag ms', receipt.dragMs.toFixed(1)],
74
+ ['settle ms', receipt.settleMs.toFixed(1)],
75
+ ...receipt.tracks
76
+ .slice(0, 6)
77
+ .map((t) => [t.name, `${t.totalMs.toFixed(1)}ms (${t.count}×)`]),
78
+ ],
79
+ },
80
+ },
81
+ });
82
+ }
83
+ catch { }
84
+ // eslint-disable-next-line no-console
85
+ console.log(`[perf] ${action.name}${action.detail ? ` (${action.detail})` : ''}: ` +
86
+ `${receipt.totalMs.toFixed(0)}ms total — drag ${receipt.dragMs.toFixed(0)}, ` +
87
+ `settle ${receipt.settleMs.toFixed(0)} over ${receipt.settleFrames} frames [${outcome}] — ` +
88
+ receipt.tracks
89
+ .slice(0, 6)
90
+ .map((t) => `${t.name} ${t.totalMs.toFixed(1)}ms`)
91
+ .join(', '));
92
+ }
93
+ /**
94
+ * Start attributing samples to a named action. Interrupts any active one.
95
+ * Returns an id the caller can compare against `getActivePerfActionId()` to
96
+ * commit only the action it actually began.
97
+ */
98
+ export function beginPerfAction(name, detail = '') {
99
+ if (!PERF_OVERLAY_ENABLED)
100
+ return null;
101
+ if (active)
102
+ finalize('interrupted');
103
+ const id = ++actionSeq;
104
+ const buckets = new Map();
105
+ active = {
106
+ id,
107
+ name,
108
+ detail,
109
+ startedAt: performance.now(),
110
+ committedAt: null,
111
+ settleFrames: 0,
112
+ awaitingGpu: false,
113
+ buckets,
114
+ unsubscribe: subscribePerfSamples((track, ms) => {
115
+ const bucket = buckets.get(track);
116
+ if (bucket) {
117
+ bucket.totalMs += ms;
118
+ bucket.count += 1;
119
+ }
120
+ else {
121
+ buckets.set(track, { totalMs: ms, count: 1 });
122
+ }
123
+ if (track === 'gpu-render')
124
+ gpuTimestampsSeen = true;
125
+ // A GPU sample landing after the quiet point is the settle signal. On
126
+ // devices without timestamp-query no 'gpu-render' sample ever arrives —
127
+ // the queue fence is the closest "the user saw it" stand-in there.
128
+ if (active?.awaitingGpu &&
129
+ (track === 'gpu-render' || (!gpuTimestampsSeen && track === 'gpu-queue'))) {
130
+ finalize('settled');
131
+ }
132
+ }),
133
+ };
134
+ return id;
135
+ }
136
+ /** The gesture ended (pointer up / operation dispatched); settling begins. */
137
+ export function commitPerfAction() {
138
+ if (!active || active.committedAt !== null)
139
+ return;
140
+ active.committedAt = performance.now();
141
+ }
142
+ /** The gesture was aborted (Escape mid-drag); discard without a settle wait. */
143
+ export function cancelPerfAction() {
144
+ if (!active)
145
+ return;
146
+ finalize('interrupted');
147
+ }
148
+ /** Convenience for instant actions (undo, level switch): begin + commit. */
149
+ export function markPerfAction(name, detail = '') {
150
+ beginPerfAction(name, detail);
151
+ commitPerfAction();
152
+ }
153
+ /**
154
+ * Whether an action is currently being attributed. Lets a generic call site
155
+ * (the interaction scope) yield to a more specific one that began first.
156
+ */
157
+ export function hasActivePerfAction() {
158
+ return active !== null;
159
+ }
160
+ /**
161
+ * Like `hasActivePerfAction`, but false once the active action has committed.
162
+ * A generic bracket yields to an UNCOMMITTED action (a gesture in flight) but
163
+ * must be free to start a new receipt while the previous one is merely
164
+ * settling — beginPerfAction then finalizes the settling one as interrupted.
165
+ */
166
+ export function hasUncommittedPerfAction() {
167
+ return active !== null && active.committedAt === null;
168
+ }
169
+ /** Id of the action currently attributing samples, if any. */
170
+ export function getActivePerfActionId() {
171
+ return active?.id ?? null;
172
+ }
173
+ /**
174
+ * Called once per frame by the viewer settle system with the current dirty
175
+ * count and the wall system's deferred-neighbour backlog. Also the ledger's
176
+ * only heartbeat, so it is where a stuck action gets released.
177
+ */
178
+ export function notifyPerfActionFrame(dirtyCount, pendingRebuilds) {
179
+ const action = active;
180
+ if (!action)
181
+ return;
182
+ const now = performance.now();
183
+ if (action.committedAt === null) {
184
+ if (now - action.startedAt > UNCOMMITTED_TIMEOUT_MS)
185
+ finalize('interrupted');
186
+ return;
187
+ }
188
+ action.settleFrames += 1;
189
+ if (now - action.committedAt > SETTLE_TIMEOUT_MS) {
190
+ finalize('timeout');
191
+ return;
192
+ }
193
+ if (!action.awaitingGpu && dirtyCount === 0 && pendingRebuilds === 0) {
194
+ action.awaitingGpu = true;
195
+ }
196
+ }
197
+ // Module-level so the panel's twice-a-second re-render doesn't tear the
198
+ // subscription down and rebuild it; `receipts` is replaced, never mutated, so
199
+ // the snapshot is stable between finalizes.
200
+ function subscribeReceipts(listener) {
201
+ listeners.add(listener);
202
+ return () => {
203
+ listeners.delete(listener);
204
+ };
205
+ }
206
+ function getReceipts() {
207
+ return receipts;
208
+ }
209
+ export function usePerfActionReceipts() {
210
+ return useSyncExternalStore(subscribeReceipts, getReceipts, getReceipts);
211
+ }
@@ -0,0 +1,2 @@
1
+ export declare function initPerfObservers(): void;
2
+ //# sourceMappingURL=perf-observers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-observers.d.ts","sourceRoot":"","sources":["../../src/lib/perf-observers.ts"],"names":[],"mappings":"AAKA,wBAAgB,iBAAiB,IAAI,IAAI,CAYxC"}
@@ -0,0 +1,17 @@
1
+ import { PERF_OVERLAY_ENABLED } from './gpu-perf';
2
+ import { recordPerfSample } from './perf-tracks';
3
+ let initialized = false;
4
+ export function initPerfObservers() {
5
+ if (!PERF_OVERLAY_ENABLED || initialized)
6
+ return;
7
+ initialized = true;
8
+ try {
9
+ const observer = new PerformanceObserver((list) => {
10
+ for (const entry of list.getEntries()) {
11
+ recordPerfSample('long-task', entry.duration);
12
+ }
13
+ });
14
+ observer.observe({ type: 'longtask', buffered: true });
15
+ }
16
+ catch { }
17
+ }
@@ -0,0 +1,71 @@
1
+ export type PerfTrackLine = {
2
+ name: string;
3
+ totalMs: number;
4
+ count: number;
5
+ maxMs: number;
6
+ };
7
+ export type PerfStats = {
8
+ fps: number;
9
+ frameMs: number;
10
+ frameMaxMs: number;
11
+ encodeMs: number;
12
+ encodeMaxMs: number;
13
+ gpuMs: number;
14
+ gpuMaxMs: number;
15
+ gpuTracked: boolean;
16
+ queueMs: number;
17
+ queueMaxMs: number;
18
+ drawCalls: number;
19
+ triangles: number;
20
+ batch: PerfBatchStats;
21
+ dirty: number;
22
+ dirtyDetail: string;
23
+ geometries: number;
24
+ textures: number;
25
+ gpuBytes: number;
26
+ heapBytes: number;
27
+ meshes: number;
28
+ lines: number;
29
+ sprites: number;
30
+ lights: number;
31
+ tracks: PerfTrackLine[];
32
+ };
33
+ export declare function publishPerfStats(stats: PerfStats): void;
34
+ export declare function usePerfStats(): PerfStats | null;
35
+ /**
36
+ * Batch membership, published by the batch systems themselves (the panel's
37
+ * collector cannot read their stores across packages). Stable truth — items
38
+ * and instances currently drawn through batch containers — unlike the
39
+ * per-pass `_multiDrawCount`, which snapshots whichever camera (main, shadow,
40
+ * outline) culled the batch last and flips between passes. On WebGPU each
41
+ * batched instance still counts once in `drawCalls` (the backend loops
42
+ * drawIndexed per visible instance), so without this row a batched scene
43
+ * looks no cheaper than an unbatched one — the saving is encode cost per
44
+ * call, not call count.
45
+ */
46
+ export type PerfBatchStats = {
47
+ items: number;
48
+ instances: number;
49
+ containers: number;
50
+ releases?: number;
51
+ joins?: number;
52
+ geometryReplacements?: number;
53
+ overflowRebuilds?: number;
54
+ wallDrain?: {
55
+ initialBuildActive: boolean;
56
+ wallsConsumedThisFrame: number;
57
+ budgetExits: number;
58
+ heavyExits: number;
59
+ drainedExits: number;
60
+ capExits: number;
61
+ pendingNeighbours: number;
62
+ firstBuilds: number;
63
+ reinvalidationBuilds: number;
64
+ neighbourEnqueues: number;
65
+ };
66
+ geometryBytesCopied?: number;
67
+ };
68
+ export declare function publishPerfBatchStats(stats: Partial<PerfBatchStats>): void;
69
+ export declare function publishPerfWallDrainStats(stats: NonNullable<PerfBatchStats['wallDrain']>): void;
70
+ export declare function readPerfBatchStats(): PerfBatchStats;
71
+ //# sourceMappingURL=perf-panel-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-panel-store.d.ts","sourceRoot":"","sources":["../../src/lib/perf-panel-store.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3F,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,cAAc,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,aAAa,EAAE,CAAA;CACxB,CAAA;AAKD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAGvD;AAOD,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAM/C;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE;QACV,kBAAkB,EAAE,OAAO,CAAA;QAC3B,sBAAsB,EAAE,MAAM,CAAA;QAC9B,WAAW,EAAE,MAAM,CAAA;QACnB,UAAU,EAAE,MAAM,CAAA;QAClB,YAAY,EAAE,MAAM,CAAA;QACpB,QAAQ,EAAE,MAAM,CAAA;QAChB,iBAAiB,EAAE,MAAM,CAAA;QACzB,WAAW,EAAE,MAAM,CAAA;QACnB,oBAAoB,EAAE,MAAM,CAAA;QAC5B,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAID,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAE1E;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,WAAW,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,GAAG,IAAI,CAE/F;AAED,wBAAgB,kBAAkB,IAAI,cAAc,CAEnD"}
@@ -0,0 +1,29 @@
1
+ // Bridge between the in-canvas collector (perf-monitor.tsx, R3F reconciler)
2
+ // and the DOM panel (perf-panel.tsx). react-dom portals can't cross the R3F
3
+ // renderer boundary, so the collector publishes here and the panel — mounted
4
+ // outside <Canvas> — subscribes via useSyncExternalStore.
5
+ import { useSyncExternalStore } from 'react';
6
+ let current = null;
7
+ const listeners = new Set();
8
+ export function publishPerfStats(stats) {
9
+ current = stats;
10
+ for (const listener of listeners)
11
+ listener();
12
+ }
13
+ function subscribe(listener) {
14
+ listeners.add(listener);
15
+ return () => listeners.delete(listener);
16
+ }
17
+ export function usePerfStats() {
18
+ return useSyncExternalStore(subscribe, () => current, () => null);
19
+ }
20
+ let batchStats = { items: 0, instances: 0, containers: 0 };
21
+ export function publishPerfBatchStats(stats) {
22
+ batchStats = { ...batchStats, ...stats };
23
+ }
24
+ export function publishPerfWallDrainStats(stats) {
25
+ batchStats.wallDrain = stats;
26
+ }
27
+ export function readPerfBatchStats() {
28
+ return batchStats;
29
+ }
@@ -0,0 +1,43 @@
1
+ export type PerfCounterBucket = {
2
+ totalMs: number;
3
+ maxMs: number;
4
+ count: number;
5
+ };
6
+ /** DevTools palette names accepted by the extensibility API. */
7
+ export type PerfTrackColor = 'primary' | 'primary-light' | 'primary-dark' | 'secondary' | 'secondary-light' | 'secondary-dark' | 'tertiary' | 'tertiary-light' | 'tertiary-dark' | 'error';
8
+ type PerfSampleListener = (track: string, ms: number) => void;
9
+ export declare function subscribePerfSamples(listener: PerfSampleListener): () => void;
10
+ /**
11
+ * Time a synchronous block and file it under `track`. The label defaults to
12
+ * the track name; pass `name` for per-entry granularity (e.g. a node id) —
13
+ * it only affects the DevTools lane, not the aggregate bucket.
14
+ */
15
+ export declare function timeSpan<T>(track: string, fn: () => T, opts?: {
16
+ name?: string;
17
+ color?: PerfTrackColor;
18
+ properties?: Array<[string, string]>;
19
+ }): T;
20
+ /**
21
+ * Span for non-callback shapes (spans crossing await points or frames).
22
+ * `beginSpan` returns null when perf is off — callers pass the handle back to
23
+ * `endSpan`, which no-ops on null.
24
+ */
25
+ export type PerfSpanHandle = {
26
+ track: string;
27
+ name: string;
28
+ start: number;
29
+ color: PerfTrackColor;
30
+ };
31
+ export declare function beginSpan(track: string, opts?: {
32
+ name?: string;
33
+ color?: PerfTrackColor;
34
+ }): PerfSpanHandle | null;
35
+ export declare function endSpan(handle: PerfSpanHandle | null, properties?: Array<[string, string]>): void;
36
+ /** Record a duration measured externally (no measure emitted). */
37
+ export declare function recordPerfSample(track: string, ms: number): void;
38
+ /** Hand the current window's buckets to the overlay and start a new window. */
39
+ export declare function drainPerfCounters(): Map<string, PerfCounterBucket>;
40
+ /** Drop accumulated timeline entries so long `?perf` sessions don't leak. */
41
+ export declare function clearPerfMeasures(): void;
42
+ export {};
43
+ //# sourceMappingURL=perf-tracks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-tracks.d.ts","sourceRoot":"","sources":["../../src/lib/perf-tracks.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,gEAAgE;AAChE,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,eAAe,GACf,cAAc,GACd,WAAW,GACX,iBAAiB,GACjB,gBAAgB,GAChB,UAAU,GACV,gBAAgB,GAChB,eAAe,GACf,OAAO,CAAA;AAOX,KAAK,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;AAG7D,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAG7E;AAyCD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,CAAC,EACX,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,GACrF,CAAC,CAUH;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAA;AAElG,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,cAAc,CAAA;CAAE,GAC/C,cAAc,GAAG,IAAI,CAQvB;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAKjG;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAGhE;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAIlE;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,IAAI,IAAI,CAOxC"}
@@ -0,0 +1,113 @@
1
+ // Shared sink for `?perf` instrumentation.
2
+ //
3
+ // Two outputs from one call site:
4
+ // 1. Chrome DevTools Performance panel custom tracks — every span becomes a
5
+ // `performance.measure` with a `detail.devtools` payload, so Pascal systems
6
+ // show up as named lanes in the flame chart while recording.
7
+ // 2. Per-window aggregates — `drainPerfCounters()` hands the overlay one
8
+ // bucket per track (total/max/count since the last drain), so the panel can
9
+ // print "wall-csg 9.8ms" without touching the timeline.
10
+ //
11
+ // Everything is gated on PERF_OVERLAY_ENABLED: when `?perf` is absent the
12
+ // helpers reduce to calling `fn()` directly / returning early, so hot paths pay
13
+ // only a boolean check. Measures otherwise accumulate in the browser's
14
+ // timeline buffer indefinitely — the overlay is responsible for calling
15
+ // `clearPerfMeasures()` on its drain tick.
16
+ import { PERF_OVERLAY_ENABLED } from './gpu-perf';
17
+ const counters = new Map();
18
+ const sampleListeners = new Set();
19
+ export function subscribePerfSamples(listener) {
20
+ sampleListeners.add(listener);
21
+ return () => sampleListeners.delete(listener);
22
+ }
23
+ function record(track, ms) {
24
+ const bucket = counters.get(track);
25
+ if (bucket) {
26
+ bucket.totalMs += ms;
27
+ bucket.count += 1;
28
+ if (ms > bucket.maxMs)
29
+ bucket.maxMs = ms;
30
+ }
31
+ else {
32
+ counters.set(track, { totalMs: ms, maxMs: ms, count: 1 });
33
+ }
34
+ for (const listener of sampleListeners)
35
+ listener(track, ms);
36
+ }
37
+ function emitMeasure(track, name, start, end, color, properties) {
38
+ try {
39
+ performance.measure(name, {
40
+ start,
41
+ end,
42
+ detail: {
43
+ devtools: {
44
+ dataType: 'track-entry',
45
+ track,
46
+ trackGroup: 'Pascal',
47
+ color,
48
+ ...(properties ? { properties } : {}),
49
+ },
50
+ },
51
+ });
52
+ }
53
+ catch {
54
+ // Older browsers reject the options bag — aggregates still work.
55
+ }
56
+ }
57
+ /**
58
+ * Time a synchronous block and file it under `track`. The label defaults to
59
+ * the track name; pass `name` for per-entry granularity (e.g. a node id) —
60
+ * it only affects the DevTools lane, not the aggregate bucket.
61
+ */
62
+ export function timeSpan(track, fn, opts) {
63
+ if (!PERF_OVERLAY_ENABLED)
64
+ return fn();
65
+ const start = performance.now();
66
+ try {
67
+ return fn();
68
+ }
69
+ finally {
70
+ const end = performance.now();
71
+ record(track, end - start);
72
+ emitMeasure(track, opts?.name ?? track, start, end, opts?.color ?? 'primary', opts?.properties);
73
+ }
74
+ }
75
+ export function beginSpan(track, opts) {
76
+ if (!PERF_OVERLAY_ENABLED)
77
+ return null;
78
+ return {
79
+ track,
80
+ name: opts?.name ?? track,
81
+ start: performance.now(),
82
+ color: opts?.color ?? 'primary',
83
+ };
84
+ }
85
+ export function endSpan(handle, properties) {
86
+ if (!handle)
87
+ return;
88
+ const end = performance.now();
89
+ record(handle.track, end - handle.start);
90
+ emitMeasure(handle.track, handle.name, handle.start, end, handle.color, properties);
91
+ }
92
+ /** Record a duration measured externally (no measure emitted). */
93
+ export function recordPerfSample(track, ms) {
94
+ if (!PERF_OVERLAY_ENABLED)
95
+ return;
96
+ record(track, ms);
97
+ }
98
+ /** Hand the current window's buckets to the overlay and start a new window. */
99
+ export function drainPerfCounters() {
100
+ const out = new Map(counters);
101
+ counters.clear();
102
+ return out;
103
+ }
104
+ /** Drop accumulated timeline entries so long `?perf` sessions don't leak. */
105
+ export function clearPerfMeasures() {
106
+ try {
107
+ performance.clearMeasures();
108
+ performance.clearMarks();
109
+ }
110
+ catch {
111
+ // ignore
112
+ }
113
+ }
@@ -0,0 +1,7 @@
1
+ import { events as createWebEvents, type EventManager, type RootStore } from '@react-three/fiber';
2
+ import * as THREE from 'three';
3
+ /** Opt in only when the raycast appends hits without reading prior hits or mutating scene/query state. */
4
+ export declare function markPureRaycast<T extends THREE.Object3D['raycast']>(raycast: T): T;
5
+ export declare function choosePointerEvents(search?: string): typeof createWebEvents;
6
+ export declare function createPascalPointerEvents(store: RootStore): EventManager<HTMLElement>;
7
+ //# sourceMappingURL=pointer-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer-events.d.ts","sourceRoot":"","sources":["../../src/lib/pointer-events.ts"],"names":[],"mappings":"AA6BA,OAAO,EACL,MAAM,IAAI,eAAe,EAGzB,KAAK,YAAY,EAMjB,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqC9B,0GAA0G;AAC1G,wBAAgB,eAAe,CAAC,CAAC,SAAS,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAGlF;AAYD,wBAAgB,mBAAmB,CACjC,MAAM,SAA8D,GACnE,OAAO,eAAe,CAIxB;AAiLD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,CAAC,WAAW,CAAC,CAmBrF"}