@wildo-ai/presets-components-3d 1.1.6

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 (102) hide show
  1. package/LICENSE +34 -0
  2. package/dist/esm/frame/frame-3d-style.d.ts +156 -0
  3. package/dist/esm/frame/frame-3d-style.d.ts.map +1 -0
  4. package/dist/esm/frame/frame-3d-style.js +229 -0
  5. package/dist/esm/frame/frame-3d-style.js.map +1 -0
  6. package/dist/esm/frame/frame-appearance.d.ts +99 -0
  7. package/dist/esm/frame/frame-appearance.d.ts.map +1 -0
  8. package/dist/esm/frame/frame-appearance.js +207 -0
  9. package/dist/esm/frame/frame-appearance.js.map +1 -0
  10. package/dist/esm/frame/frame-canvas.d.ts +63 -0
  11. package/dist/esm/frame/frame-canvas.d.ts.map +1 -0
  12. package/dist/esm/frame/frame-canvas.js +134 -0
  13. package/dist/esm/frame/frame-canvas.js.map +1 -0
  14. package/dist/esm/frame/frame-canvas.lazy.d.ts +21 -0
  15. package/dist/esm/frame/frame-canvas.lazy.d.ts.map +1 -0
  16. package/dist/esm/frame/frame-canvas.lazy.js +31 -0
  17. package/dist/esm/frame/frame-canvas.lazy.js.map +1 -0
  18. package/dist/esm/frame/frame-color.d.ts +24 -0
  19. package/dist/esm/frame/frame-color.d.ts.map +1 -0
  20. package/dist/esm/frame/frame-color.js +52 -0
  21. package/dist/esm/frame/frame-color.js.map +1 -0
  22. package/dist/esm/frame/frame-driver.d.ts +60 -0
  23. package/dist/esm/frame/frame-driver.d.ts.map +1 -0
  24. package/dist/esm/frame/frame-driver.js +207 -0
  25. package/dist/esm/frame/frame-driver.js.map +1 -0
  26. package/dist/esm/frame/frame-renderer.d.ts +141 -0
  27. package/dist/esm/frame/frame-renderer.d.ts.map +1 -0
  28. package/dist/esm/frame/frame-renderer.js +635 -0
  29. package/dist/esm/frame/frame-renderer.js.map +1 -0
  30. package/dist/esm/frame/frame-shaders.d.ts +30 -0
  31. package/dist/esm/frame/frame-shaders.d.ts.map +1 -0
  32. package/dist/esm/frame/frame-shaders.js +97 -0
  33. package/dist/esm/frame/frame-shaders.js.map +1 -0
  34. package/dist/esm/frame/use-frame-appearance.d.ts +17 -0
  35. package/dist/esm/frame/use-frame-appearance.d.ts.map +1 -0
  36. package/dist/esm/frame/use-frame-appearance.js +38 -0
  37. package/dist/esm/frame/use-frame-appearance.js.map +1 -0
  38. package/dist/esm/index.d.ts +14 -0
  39. package/dist/esm/index.d.ts.map +1 -0
  40. package/dist/esm/index.js +14 -0
  41. package/dist/esm/index.js.map +1 -0
  42. package/dist/esm/layout/header-first-shell-container.d.ts +22 -0
  43. package/dist/esm/layout/header-first-shell-container.d.ts.map +1 -0
  44. package/dist/esm/layout/header-first-shell-container.js +31 -0
  45. package/dist/esm/layout/header-first-shell-container.js.map +1 -0
  46. package/dist/esm/layout/layout-3d-definition.d.ts +54 -0
  47. package/dist/esm/layout/layout-3d-definition.d.ts.map +1 -0
  48. package/dist/esm/layout/layout-3d-definition.js +106 -0
  49. package/dist/esm/layout/layout-3d-definition.js.map +1 -0
  50. package/dist/esm/layout/layout-3d-transition-choreography.d.ts +30 -0
  51. package/dist/esm/layout/layout-3d-transition-choreography.d.ts.map +1 -0
  52. package/dist/esm/layout/layout-3d-transition-choreography.js +43 -0
  53. package/dist/esm/layout/layout-3d-transition-choreography.js.map +1 -0
  54. package/dist/esm/layout/layout-3d-vocabulary.d.ts +118 -0
  55. package/dist/esm/layout/layout-3d-vocabulary.d.ts.map +1 -0
  56. package/dist/esm/layout/layout-3d-vocabulary.js +104 -0
  57. package/dist/esm/layout/layout-3d-vocabulary.js.map +1 -0
  58. package/dist/esm/layout/shell-layout-placement.d.ts +26 -0
  59. package/dist/esm/layout/shell-layout-placement.d.ts.map +1 -0
  60. package/dist/esm/layout/shell-layout-placement.js +18 -0
  61. package/dist/esm/layout/shell-layout-placement.js.map +1 -0
  62. package/dist/esm/layout-3d-main-container.d.ts +73 -0
  63. package/dist/esm/layout-3d-main-container.d.ts.map +1 -0
  64. package/dist/esm/layout-3d-main-container.js +124 -0
  65. package/dist/esm/layout-3d-main-container.js.map +1 -0
  66. package/dist/esm/register-3d-layout.d.ts +40 -0
  67. package/dist/esm/register-3d-layout.d.ts.map +1 -0
  68. package/dist/esm/register-3d-layout.js +72 -0
  69. package/dist/esm/register-3d-layout.js.map +1 -0
  70. package/dist/esm/shell-region-measurement.d.ts +75 -0
  71. package/dist/esm/shell-region-measurement.d.ts.map +1 -0
  72. package/dist/esm/shell-region-measurement.js +75 -0
  73. package/dist/esm/shell-region-measurement.js.map +1 -0
  74. package/dist/esm/spatial/spatial-camera.d.ts +106 -0
  75. package/dist/esm/spatial/spatial-camera.d.ts.map +1 -0
  76. package/dist/esm/spatial/spatial-camera.js +151 -0
  77. package/dist/esm/spatial/spatial-camera.js.map +1 -0
  78. package/dist/esm/spatial/spatial-environment.d.ts +6 -0
  79. package/dist/esm/spatial/spatial-environment.d.ts.map +1 -0
  80. package/dist/esm/spatial/spatial-environment.js +166 -0
  81. package/dist/esm/spatial/spatial-environment.js.map +1 -0
  82. package/dist/esm/spatial/spatial-environment.lazy.d.ts +10 -0
  83. package/dist/esm/spatial/spatial-environment.lazy.d.ts.map +1 -0
  84. package/dist/esm/spatial/spatial-environment.lazy.js +13 -0
  85. package/dist/esm/spatial/spatial-environment.lazy.js.map +1 -0
  86. package/dist/esm/spatial/spatial-shell-container.d.ts +21 -0
  87. package/dist/esm/spatial/spatial-shell-container.d.ts.map +1 -0
  88. package/dist/esm/spatial/spatial-shell-container.js +231 -0
  89. package/dist/esm/spatial/spatial-shell-container.js.map +1 -0
  90. package/dist/esm/spatial/spatial-stage-store.d.ts +27 -0
  91. package/dist/esm/spatial/spatial-stage-store.d.ts.map +1 -0
  92. package/dist/esm/spatial/spatial-stage-store.js +33 -0
  93. package/dist/esm/spatial/spatial-stage-store.js.map +1 -0
  94. package/dist/esm/tokens/design-token-resolution.d.ts +110 -0
  95. package/dist/esm/tokens/design-token-resolution.d.ts.map +1 -0
  96. package/dist/esm/tokens/design-token-resolution.js +410 -0
  97. package/dist/esm/tokens/design-token-resolution.js.map +1 -0
  98. package/dist/esm/tokens/use-design-token-resolution.d.ts +22 -0
  99. package/dist/esm/tokens/use-design-token-resolution.d.ts.map +1 -0
  100. package/dist/esm/tokens/use-design-token-resolution.js +49 -0
  101. package/dist/esm/tokens/use-design-token-resolution.js.map +1 -0
  102. package/package.json +61 -0
@@ -0,0 +1,231 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
3
+ import { HorizontalPlacement, ShellRegion, SurfaceVariant, VerticalPlacement } from '@wildo-ai/presets-components-models';
4
+ import { AppShellContentOutlet, AppShellLoadingState, AppShellOverlayPortalLayer, AppShellOverlaysOutlet, AppShellProviders, AppShellRegionOutlet, NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE, Surface, useAppShellFirstReady, useAppShellLayout, useNavigationState, useUI, } from '@wildo-ai/saas-frontend-lib';
5
+ import { cameraMoveFor, cssCameraTransform, layoutSpatialPanels, panelTransform, restPose, sampleMove, SPATIAL_CAMERA_DISTANCE_PX, SpatialCameraCue, SpatialPanelId, } from './spatial-camera.js';
6
+ import { SpatialEnvironmentDoor } from './spatial-environment.lazy.js';
7
+ import { SpatialStageStore } from './spatial-stage-store.js';
8
+ /**
9
+ * The spatial layout's placement (PROTOTYPE, Paul 2026-09-30: "something futurist, with a real camera aspect and
10
+ * transitions" — clean spatial, side panels angled, content frontal).
11
+ *
12
+ * The regions are the application's own, rendered by the standard outlets with every context; this container only
13
+ * groups them into five glass panels and stands those panels in a CSS 3D stage:
14
+ *
15
+ * - a perspective root the size of the viewport;
16
+ * - a CAMERA element at its centre, `preserve-3d`, whose transform is the inverse of the camera pose;
17
+ * - the panels, each centred on that element and moved/turned to its place (`layoutSpatialPanels`).
18
+ *
19
+ * At rest the camera faces the centre panel from exactly the perspective distance, so the content is drawn at its CSS
20
+ * size — crisp. The camera moves on the shell's transitions and always returns to rest.
21
+ *
22
+ * Overlays render in `AppShellOverlayPortalLayer`, OUTSIDE the stage: a dialog inside a transformed panel would be
23
+ * confined to it, and a menu would be placed in the wrong coordinates.
24
+ */
25
+ export function SpatialShellContainer({ children }) {
26
+ const layoutInfo = useAppShellLayout();
27
+ const hasLayoutBeenReady = useAppShellFirstReady(layoutInfo.isLayoutReady);
28
+ if (!layoutInfo.isLayoutReady && !hasLayoutBeenReady)
29
+ return _jsx(AppShellLoadingState, {});
30
+ return (_jsx(AppShellProviders, { layout: layoutInfo, children: _jsx(SpatialStage, { children: children }) }));
31
+ }
32
+ const PANEL_TRANSITION = 'transform 700ms cubic-bezier(0.2, 0.8, 0.2, 1), width 700ms cubic-bezier(0.2, 0.8, 0.2, 1), height 700ms cubic-bezier(0.2, 0.8, 0.2, 1)';
33
+ function SpatialStage({ children }) {
34
+ const { isDark, prefersReducedMotion } = useUI();
35
+ const viewport = useViewportSize();
36
+ const store = useMemo(() => new SpatialStageStore(), []);
37
+ const cameraRef = useRef(null);
38
+ const startRef = useRef(null);
39
+ const endRef = useRef(null);
40
+ const topRef = useRef(null);
41
+ const bottomRef = useRef(null);
42
+ const sizeRefs = useMemo(() => ({ start: startRef, end: endRef, top: topRef, bottom: bottomRef }), []);
43
+ const sizes = useNaturalSizes(sizeRefs);
44
+ const panels = useMemo(() => layoutSpatialPanels({ viewport, startWidth: sizes.start, endWidth: sizes.end, topHeight: sizes.top, bottomHeight: sizes.bottom }), [viewport, sizes.start, sizes.end, sizes.top, sizes.bottom]);
45
+ const shown = useMemo(() => {
46
+ const visible = { [SpatialPanelId.CENTRE]: panels[SpatialPanelId.CENTRE] };
47
+ if (sizes.start > 0)
48
+ visible[SpatialPanelId.START_COLUMN] = panels[SpatialPanelId.START_COLUMN];
49
+ if (sizes.end > 0)
50
+ visible[SpatialPanelId.END_COLUMN] = panels[SpatialPanelId.END_COLUMN];
51
+ if (sizes.top > 0)
52
+ visible[SpatialPanelId.TOP] = panels[SpatialPanelId.TOP];
53
+ if (sizes.bottom > 0)
54
+ visible[SpatialPanelId.BOTTOM] = panels[SpatialPanelId.BOTTOM];
55
+ return visible;
56
+ }, [panels, sizes.start, sizes.end, sizes.top, sizes.bottom]);
57
+ useLayoutEffect(() => {
58
+ store.set({ viewport, panels: shown, isDark });
59
+ }, [store, viewport, shown, isDark]);
60
+ const play = useCameraPlayer(cameraRef, store, prefersReducedMotion);
61
+ useSpatialCues(play, sizes.start, sizes.start + sizes.end + sizes.top + sizes.bottom > 0, viewport);
62
+ const panel = (id, ref, size, content) => {
63
+ const placement = panels[id];
64
+ const style = {
65
+ position: 'absolute',
66
+ left: 0,
67
+ top: 0,
68
+ transform: panelTransform(placement),
69
+ transition: prefersReducedMotion ? undefined : PANEL_TRANSITION,
70
+ backfaceVisibility: 'hidden',
71
+ visibility: shown[id] ? 'visible' : 'hidden',
72
+ ...(size !== 'natural-width' ? { width: placement.width } : {}),
73
+ ...(size !== 'natural-height' ? { height: placement.height } : {}),
74
+ ...GLASS_STYLE,
75
+ };
76
+ return (_jsx("div", { ref: ref ?? undefined, "data-spatial-panel": id, className: "flex overflow-hidden", style: style, children: content }));
77
+ };
78
+ return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.SHELL, policyOverride: NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE, children: _jsxs("div", { className: "relative h-screen w-screen overflow-hidden bg-background", "data-spatial-stage": "", children: [_jsx(SpatialEnvironmentDoor, { store: store }), _jsx("div", { className: "absolute inset-0", style: { perspective: `${SPATIAL_CAMERA_DISTANCE_PX}px`, perspectiveOrigin: '50% 50%' }, children: _jsxs("div", { ref: cameraRef, "data-spatial-camera": "", style: { position: 'absolute', left: '50%', top: '50%', width: 0, height: 0, transformStyle: 'preserve-3d', transform: cssCameraTransform(restPose()) }, children: [panel(SpatialPanelId.START_COLUMN, startRef, 'natural-width', (_jsxs(_Fragment, { children: [_jsx(AppShellRegionOutlet, { region: ShellRegion.ACTIVITY_BAR }), _jsx(AppShellRegionOutlet, { region: ShellRegion.SIDEBAR, placement: HorizontalPlacement.START }), _jsx(AppShellRegionOutlet, { region: ShellRegion.UTILITY_PANEL, placement: HorizontalPlacement.START })] }))), panel(SpatialPanelId.CENTRE, null, 'fixed', (_jsxs("div", { className: "flex-1 flex flex-col min-w-0 min-h-0", children: [_jsx(AppShellRegionOutlet, { region: ShellRegion.TOOLBAR }), _jsx(AppShellContentOutlet, { className: "flex-1 relative min-w-0 min-h-0", children: children })] }))), panel(SpatialPanelId.END_COLUMN, endRef, 'natural-width', (_jsxs(_Fragment, { children: [_jsx(AppShellRegionOutlet, { region: ShellRegion.SIDEBAR, placement: HorizontalPlacement.END }), _jsx(AppShellRegionOutlet, { region: ShellRegion.UTILITY_PANEL, placement: HorizontalPlacement.END })] }))), panel(SpatialPanelId.TOP, topRef, 'natural-height', (_jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [_jsx(AppShellRegionOutlet, { region: ShellRegion.STATUS_BAR, placement: VerticalPlacement.TOP }), _jsx(AppShellRegionOutlet, { region: ShellRegion.MENUBAR })] }))), panel(SpatialPanelId.BOTTOM, bottomRef, 'natural-height', (_jsx("div", { className: "flex-1 flex flex-col min-w-0", children: _jsx(AppShellRegionOutlet, { region: ShellRegion.STATUS_BAR, placement: VerticalPlacement.BOTTOM }) })))] }) }), _jsx(AppShellOverlaysOutlet, {}), _jsx(AppShellOverlayPortalLayer, {})] }) }));
79
+ }
80
+ /**
81
+ * The glass every panel is made of: a translucent card colour over a blurred backdrop, a hairline light edge and a
82
+ * deep soft shadow. Colours come from the theme's tokens, so light and dark modes follow the theme.
83
+ */
84
+ const GLASS_STYLE = {
85
+ borderRadius: 22,
86
+ background: 'color-mix(in oklab, var(--card, var(--background)) 74%, transparent)',
87
+ backdropFilter: 'blur(28px) saturate(1.3)',
88
+ border: '1px solid color-mix(in oklab, var(--border) 55%, white 45%)',
89
+ boxShadow: '0 40px 90px -30px rgb(15 23 42 / 0.35), 0 12px 30px -12px rgb(15 23 42 / 0.18), inset 0 1px 0 0 rgb(255 255 255 / 0.45)',
90
+ };
91
+ function useViewportSize() {
92
+ const read = () => ({ width: window.innerWidth, height: window.innerHeight });
93
+ const [size, setSize] = useState(read);
94
+ useEffect(() => {
95
+ const onResize = () => setSize(read());
96
+ window.addEventListener('resize', onResize);
97
+ return () => window.removeEventListener('resize', onResize);
98
+ }, []);
99
+ return size;
100
+ }
101
+ /**
102
+ * The natural (untransformed) sizes of the panels whose size comes from their content: the side columns' widths and
103
+ * the strips' heights. `offsetWidth`/`offsetHeight` ignore transforms, so a turned column reads its real width.
104
+ */
105
+ function useNaturalSizes(refs) {
106
+ const [sizes, setSizes] = useState({ start: 0, end: 0, top: 0, bottom: 0 });
107
+ useLayoutEffect(() => {
108
+ const measure = () => {
109
+ const width = (ref) => (ref.current && ref.current.childElementCount > 0 ? ref.current.offsetWidth : 0);
110
+ const height = (ref) => (ref.current && hasRenderedRegion(ref.current) ? ref.current.offsetHeight : 0);
111
+ const next = { start: width(refs.start), end: width(refs.end), top: height(refs.top), bottom: height(refs.bottom) };
112
+ setSizes((previous) => (previous.start === next.start && previous.end === next.end && previous.top === next.top && previous.bottom === next.bottom ? previous : next));
113
+ };
114
+ measure();
115
+ const observer = new ResizeObserver(measure);
116
+ for (const ref of Object.values(refs))
117
+ if (ref.current)
118
+ observer.observe(ref.current);
119
+ const mutations = new MutationObserver(measure);
120
+ for (const ref of Object.values(refs))
121
+ if (ref.current)
122
+ mutations.observe(ref.current, { childList: true, subtree: true });
123
+ return () => {
124
+ observer.disconnect();
125
+ mutations.disconnect();
126
+ };
127
+ }, [refs]);
128
+ return sizes;
129
+ }
130
+ function hasRenderedRegion(element) {
131
+ return element.querySelector('[data-component-area]') !== null;
132
+ }
133
+ /**
134
+ * Plays camera moves on the camera element (the stage's OWN element, so writing its inline transform touches nothing
135
+ * React renders) and publishes every pose to the store for the environment. Under reduced motion every move is a cut
136
+ * to its final pose. Returns `play(move)`; a new move replaces the one in progress, starting from where it stands.
137
+ */
138
+ function useCameraPlayer(cameraRef, store, reduced) {
139
+ const frame = useRef(0);
140
+ useEffect(() => () => cancelAnimationFrame(frame.current), []);
141
+ return useMemo(() => {
142
+ const apply = (pose) => {
143
+ if (cameraRef.current)
144
+ cameraRef.current.style.transform = cssCameraTransform(pose);
145
+ store.set({ pose });
146
+ };
147
+ return (move) => {
148
+ cancelAnimationFrame(frame.current);
149
+ if (reduced) {
150
+ apply(move.keyframes[move.keyframes.length - 1].pose);
151
+ return;
152
+ }
153
+ // Start from where the camera stands, so an interrupted move blends instead of jumping.
154
+ const from = store.get().pose;
155
+ const blended = { ...move, keyframes: [{ at: 0, pose: from }, ...move.keyframes.filter((keyframe) => keyframe.at > 0)] };
156
+ const start = performance.now();
157
+ const tick = () => {
158
+ const elapsed = performance.now() - start;
159
+ apply(sampleMove(blended, elapsed));
160
+ if (elapsed < blended.durationMs)
161
+ frame.current = requestAnimationFrame(tick);
162
+ };
163
+ frame.current = requestAnimationFrame(tick);
164
+ };
165
+ }, [cameraRef, store, reduced]);
166
+ }
167
+ /**
168
+ * What moves the camera: the shell arriving, the content changing (a structural zone's top entry is another place,
169
+ * by URL path — the same signature the flat frame uses), focus moving between side-by-side panes, and the start
170
+ * column resizing (the sidebar collapsing or expanding).
171
+ */
172
+ function useSpatialCues(play, startWidth, measured, viewport) {
173
+ const navigation = useNavigationState();
174
+ const zones = Object.keys(navigation.state.zones);
175
+ const places = zones.map((zone) => {
176
+ const top = navigation.getTopEntry(zone);
177
+ return top ? (top.urlPath?.split(/[?#]/)[0] ?? top.id) : '';
178
+ });
179
+ const signature = places.some((place) => place !== '') ? zones.map((zone, index) => `${zone}:${places[index]}`).join('|') : '';
180
+ const arrived = useRef(false);
181
+ useEffect(() => {
182
+ if (arrived.current || !measured)
183
+ return;
184
+ arrived.current = true;
185
+ play(cameraMoveFor(SpatialCameraCue.ARRIVAL));
186
+ }, [play, measured]);
187
+ const lastSignature = useRef(null);
188
+ useEffect(() => {
189
+ if (signature === '')
190
+ return;
191
+ const previous = lastSignature.current;
192
+ lastSignature.current = signature;
193
+ if (previous !== null && previous !== signature)
194
+ play(cameraMoveFor(SpatialCameraCue.NAVIGATION));
195
+ }, [play, signature]);
196
+ const lastFocus = useRef(null);
197
+ useEffect(() => {
198
+ const zone = navigation.focusedZone ?? null;
199
+ const previous = lastFocus.current;
200
+ lastFocus.current = zone;
201
+ if (previous === null || zone === null || previous === zone)
202
+ return;
203
+ const panes = [...document.querySelectorAll(`[data-component-area="${ShellRegion.CONTENT}"] [data-content-area]`)].filter((pane) => pane.offsetWidth > 0);
204
+ const focused = panes.find((pane) => pane.dataset.contentArea === zone);
205
+ if (panes.length < 2 || !focused)
206
+ return;
207
+ const rect = focused.getBoundingClientRect();
208
+ play(cameraMoveFor(SpatialCameraCue.ZONE_FOCUS, SPATIAL_CAMERA_DISTANCE_PX, rect.left + rect.width / 2 - viewport.width / 2));
209
+ }, [play, navigation.focusedZone, viewport.width]);
210
+ // A collapse animates the width over many frames: cue once per settled change, not once per frame.
211
+ const settledStart = useRef(0);
212
+ const lastResizeCue = useRef(0);
213
+ useEffect(() => {
214
+ if (startWidth === 0)
215
+ return;
216
+ const previous = settledStart.current;
217
+ if (previous === 0) {
218
+ settledStart.current = startWidth;
219
+ return;
220
+ }
221
+ if (Math.abs(previous - startWidth) <= 24)
222
+ return;
223
+ settledStart.current = startWidth;
224
+ const now = performance.now();
225
+ if (now - lastResizeCue.current < 900)
226
+ return;
227
+ lastResizeCue.current = now;
228
+ play(cameraMoveFor(SpatialCameraCue.COLUMN_RESIZE));
229
+ }, [play, startWidth]);
230
+ }
231
+ //# sourceMappingURL=spatial-shell-container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatial-shell-container.js","sourceRoot":"","sources":["../../../../src/spatial/spatial-shell-container.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC1H,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,2CAA2C,EAC3C,OAAO,EACP,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,GAEN,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,QAAQ,EACR,UAAU,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,cAAc,GAGf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAE,QAAQ,EAA8C;IAC5F,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC3E,IAAI,CAAC,UAAU,CAAC,aAAa,IAAI,CAAC,kBAAkB;QAAE,OAAO,KAAC,oBAAoB,KAAG,CAAC;IACtF,OAAO,CACL,KAAC,iBAAiB,IAAC,MAAM,EAAE,UAAU,YACnC,KAAC,YAAY,cAAE,QAAQ,GAAgB,GACrB,CACrB,CAAC;AACJ,CAAC;AAED,MAAM,gBAAgB,GAAG,yIAAyI,CAAC;AAEnK,SAAS,YAAY,CAAC,EAAE,QAAQ,EAAiC;IAC/D,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,GAAG,KAAK,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE,EAAE,EAAE,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACvG,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CAAC,mBAAmB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,EACvI,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAC5D,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE;QACzB,MAAM,OAAO,GAA2D,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;QACnI,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC;YAAE,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QAChG,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC;YAAE,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAC1F,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC;YAAE,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAC5E,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACrF,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAE9D,eAAe,CAAC,GAAG,EAAE;QACnB,KAAK,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAErC,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAAC;IACrE,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEpG,MAAM,KAAK,GAAG,CAAC,EAAkB,EAAE,GAAqC,EAAE,IAAkD,EAAE,OAAwB,EAAqB,EAAE;QAC3K,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAwB;YACjC,QAAQ,EAAE,UAAU;YACpB,IAAI,EAAE,CAAC;YACP,GAAG,EAAE,CAAC;YACN,SAAS,EAAE,cAAc,CAAC,SAAS,CAAC;YACpC,UAAU,EAAE,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB;YAC/D,kBAAkB,EAAE,QAAQ;YAC5B,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;YAC5C,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,WAAW;SACf,CAAC;QACF,OAAO,CACL,cAAK,GAAG,EAAE,GAAG,IAAI,SAAS,wBAAsB,EAAE,EAAE,SAAS,EAAC,sBAAsB,EAAC,KAAK,EAAE,KAAK,YAC9F,OAAO,GACJ,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,OAAO,IAAC,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,2CAA2C,YAChI,eAAK,SAAS,EAAC,0DAA0D,wBAAoB,EAAE,aAC7F,KAAC,sBAAsB,IAAC,KAAK,EAAE,KAAK,GAAI,EACxC,cAAK,SAAS,EAAC,kBAAkB,EAAC,KAAK,EAAE,EAAE,WAAW,EAAE,GAAG,0BAA0B,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,YACvH,eACE,GAAG,EAAE,SAAS,yBACM,EAAE,EACtB,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,EAAE,aAEtJ,KAAK,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,CAC7D,8BACE,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,YAAY,GAAI,EAC1D,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,mBAAmB,CAAC,KAAK,GAAI,EAC3F,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,aAAa,EAAE,SAAS,EAAE,mBAAmB,CAAC,KAAK,GAAI,IAChG,CACJ,CAAC,EACD,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAC3C,eAAK,SAAS,EAAC,sCAAsC,aACnD,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,OAAO,GAAI,EACrD,KAAC,qBAAqB,IAAC,SAAS,EAAC,iCAAiC,YAAE,QAAQ,GAAyB,IACjG,CACP,CAAC,EACD,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,CACzD,8BACE,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,mBAAmB,CAAC,GAAG,GAAI,EACzF,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,aAAa,EAAE,SAAS,EAAE,mBAAmB,CAAC,GAAG,GAAI,IAC9F,CACJ,CAAC,EACD,KAAK,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,EAAE,CACnD,eAAK,SAAS,EAAC,8BAA8B,aAC3C,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,iBAAiB,CAAC,GAAG,GAAI,EAC1F,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,OAAO,GAAI,IACjD,CACP,CAAC,EACD,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,CACzD,cAAK,SAAS,EAAC,8BAA8B,YAC3C,KAAC,oBAAoB,IAAC,MAAM,EAAE,WAAW,CAAC,UAAU,EAAE,SAAS,EAAE,iBAAiB,CAAC,MAAM,GAAI,GACzF,CACP,CAAC,IACE,GACF,EACN,KAAC,sBAAsB,KAAG,EAC1B,KAAC,0BAA0B,KAAG,IAC1B,GACE,CACX,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,WAAW,GAAwB;IACvC,YAAY,EAAE,EAAE;IAChB,UAAU,EAAE,sEAAsE;IAClF,cAAc,EAAE,0BAA0B;IAC1C,MAAM,EAAE,6DAA6D;IACrE,SAAS,EAAE,yHAAyH;CACrI,CAAC;AAEF,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG,GAAsC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACjH,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,QAAQ,GAAG,GAAS,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC5C,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,IAAwF;IAC/G,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5E,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,MAAM,KAAK,GAAG,CAAC,GAA2C,EAAU,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxJ,MAAM,MAAM,GAAG,CAAC,GAA2C,EAAU,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvJ,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACpH,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACzK,CAAC,CAAC;QACF,OAAO,EAAE,CAAC;QACV,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;QAC7C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,CAAC,OAAO;gBAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,IAAI,GAAG,CAAC,OAAO;gBAAE,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3H,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtB,SAAS,CAAC,UAAU,EAAE,CAAC;QACzB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACX,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAoB;IAC7C,OAAO,OAAO,CAAC,aAAa,CAAC,uBAAuB,CAAC,KAAK,IAAI,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,SAAiD,EAAE,KAAwB,EAAE,OAAgB;IACpH,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/D,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,KAAK,GAAG,CAAC,IAAiC,EAAQ,EAAE;YACxD,IAAI,SAAS,CAAC,OAAO;gBAAE,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YACpF,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACtB,CAAC,CAAC;QACF,OAAO,CAAC,IAAuB,EAAQ,EAAE;YACvC,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC;gBACvD,OAAO;YACT,CAAC;YACD,wFAAwF;YACxF,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;YAC9B,MAAM,OAAO,GAAsB,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5I,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,GAAS,EAAE;gBACtB,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;gBAC1C,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBACpC,IAAI,OAAO,GAAG,OAAO,CAAC,UAAU;oBAAE,KAAK,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAChF,CAAC,CAAC;YACF,KAAK,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,IAAuC,EAAE,UAAkB,EAAE,QAAiB,EAAE,QAA2C;IACjJ,MAAM,UAAU,GAAG,kBAAkB,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAA+C,CAAC;IAChG,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,CAAC,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/H,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,CAAC,OAAO,IAAI,CAAC,QAAQ;YAAE,OAAO;QACzC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAChD,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAErB,MAAM,aAAa,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAClD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,KAAK,EAAE;YAAE,OAAO;QAC7B,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC;QACvC,aAAa,CAAC,OAAO,GAAG,SAAS,CAAC;QAClC,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;IACpG,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAEtB,MAAM,SAAS,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC9C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,IAAI,IAAI,CAAC;QAC5C,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC;QACnC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO;QACpE,MAAM,KAAK,GAAG,CAAC,GAAG,QAAQ,CAAC,gBAAgB,CAAc,yBAAyB,WAAW,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QACvK,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC;QACxE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;QAC7C,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,UAAU,EAAE,0BAA0B,EAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;IAChI,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnD,mGAAmG;IACnG,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAChC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,KAAK,CAAC;YAAE,OAAO;QAC7B,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC;QACtC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnB,YAAY,CAAC,OAAO,GAAG,UAAU,CAAC;YAClC,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE;YAAE,OAAO;QAClD,YAAY,CAAC,OAAO,GAAG,UAAU,CAAC;QAClC,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,GAAG,GAAG,aAAa,CAAC,OAAO,GAAG,GAAG;YAAE,OAAO;QAC9C,aAAa,CAAC,OAAO,GAAG,GAAG,CAAC;QAC5B,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC;IACtD,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AACzB,CAAC","sourcesContent":["import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\n\nimport { HorizontalPlacement, ShellRegion, SurfaceVariant, VerticalPlacement } from '@wildo-ai/presets-components-models';\nimport {\n AppShellContentOutlet,\n AppShellLoadingState,\n AppShellOverlayPortalLayer,\n AppShellOverlaysOutlet,\n AppShellProviders,\n AppShellRegionOutlet,\n NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE,\n Surface,\n useAppShellFirstReady,\n useAppShellLayout,\n useNavigationState,\n useUI,\n type AppLayoutPreset_MainContainer_DefaultProps,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport {\n cameraMoveFor,\n cssCameraTransform,\n layoutSpatialPanels,\n panelTransform,\n restPose,\n sampleMove,\n SPATIAL_CAMERA_DISTANCE_PX,\n SpatialCameraCue,\n SpatialPanelId,\n type SpatialCameraMove,\n type SpatialPanelPlacement,\n} from './spatial-camera';\nimport { SpatialEnvironmentDoor } from './spatial-environment.lazy';\nimport { SpatialStageStore } from './spatial-stage-store';\n\n/**\n * The spatial layout's placement (PROTOTYPE, Paul 2026-09-30: \"something futurist, with a real camera aspect and\n * transitions\" — clean spatial, side panels angled, content frontal).\n *\n * The regions are the application's own, rendered by the standard outlets with every context; this container only\n * groups them into five glass panels and stands those panels in a CSS 3D stage:\n *\n * - a perspective root the size of the viewport;\n * - a CAMERA element at its centre, `preserve-3d`, whose transform is the inverse of the camera pose;\n * - the panels, each centred on that element and moved/turned to its place (`layoutSpatialPanels`).\n *\n * At rest the camera faces the centre panel from exactly the perspective distance, so the content is drawn at its CSS\n * size — crisp. The camera moves on the shell's transitions and always returns to rest.\n *\n * Overlays render in `AppShellOverlayPortalLayer`, OUTSIDE the stage: a dialog inside a transformed panel would be\n * confined to it, and a menu would be placed in the wrong coordinates.\n */\nexport function SpatialShellContainer({ children }: AppLayoutPreset_MainContainer_DefaultProps): React.JSX.Element {\n const layoutInfo = useAppShellLayout();\n const hasLayoutBeenReady = useAppShellFirstReady(layoutInfo.isLayoutReady);\n if (!layoutInfo.isLayoutReady && !hasLayoutBeenReady) return <AppShellLoadingState />;\n return (\n <AppShellProviders layout={layoutInfo}>\n <SpatialStage>{children}</SpatialStage>\n </AppShellProviders>\n );\n}\n\nconst PANEL_TRANSITION = 'transform 700ms cubic-bezier(0.2, 0.8, 0.2, 1), width 700ms cubic-bezier(0.2, 0.8, 0.2, 1), height 700ms cubic-bezier(0.2, 0.8, 0.2, 1)';\n\nfunction SpatialStage({ children }: { children: React.ReactNode }): React.JSX.Element {\n const { isDark, prefersReducedMotion } = useUI();\n const viewport = useViewportSize();\n const store = useMemo(() => new SpatialStageStore(), []);\n const cameraRef = useRef<HTMLDivElement>(null);\n const startRef = useRef<HTMLDivElement>(null);\n const endRef = useRef<HTMLDivElement>(null);\n const topRef = useRef<HTMLDivElement>(null);\n const bottomRef = useRef<HTMLDivElement>(null);\n const sizeRefs = useMemo(() => ({ start: startRef, end: endRef, top: topRef, bottom: bottomRef }), []);\n const sizes = useNaturalSizes(sizeRefs);\n const panels = useMemo(\n () => layoutSpatialPanels({ viewport, startWidth: sizes.start, endWidth: sizes.end, topHeight: sizes.top, bottomHeight: sizes.bottom }),\n [viewport, sizes.start, sizes.end, sizes.top, sizes.bottom],\n );\n const shown = useMemo(() => {\n const visible: Partial<Record<SpatialPanelId, SpatialPanelPlacement>> = { [SpatialPanelId.CENTRE]: panels[SpatialPanelId.CENTRE] };\n if (sizes.start > 0) visible[SpatialPanelId.START_COLUMN] = panels[SpatialPanelId.START_COLUMN];\n if (sizes.end > 0) visible[SpatialPanelId.END_COLUMN] = panels[SpatialPanelId.END_COLUMN];\n if (sizes.top > 0) visible[SpatialPanelId.TOP] = panels[SpatialPanelId.TOP];\n if (sizes.bottom > 0) visible[SpatialPanelId.BOTTOM] = panels[SpatialPanelId.BOTTOM];\n return visible;\n }, [panels, sizes.start, sizes.end, sizes.top, sizes.bottom]);\n\n useLayoutEffect(() => {\n store.set({ viewport, panels: shown, isDark });\n }, [store, viewport, shown, isDark]);\n\n const play = useCameraPlayer(cameraRef, store, prefersReducedMotion);\n useSpatialCues(play, sizes.start, sizes.start + sizes.end + sizes.top + sizes.bottom > 0, viewport);\n\n const panel = (id: SpatialPanelId, ref: React.Ref<HTMLDivElement> | null, size: 'fixed' | 'natural-width' | 'natural-height', content: React.ReactNode): React.JSX.Element => {\n const placement = panels[id];\n const style: React.CSSProperties = {\n position: 'absolute',\n left: 0,\n top: 0,\n transform: panelTransform(placement),\n transition: prefersReducedMotion ? undefined : PANEL_TRANSITION,\n backfaceVisibility: 'hidden',\n visibility: shown[id] ? 'visible' : 'hidden',\n ...(size !== 'natural-width' ? { width: placement.width } : {}),\n ...(size !== 'natural-height' ? { height: placement.height } : {}),\n ...GLASS_STYLE,\n };\n return (\n <div ref={ref ?? undefined} data-spatial-panel={id} className=\"flex overflow-hidden\" style={style}>\n {content}\n </div>\n );\n };\n\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.SHELL} policyOverride={NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE}>\n <div className=\"relative h-screen w-screen overflow-hidden bg-background\" data-spatial-stage=\"\">\n <SpatialEnvironmentDoor store={store} />\n <div className=\"absolute inset-0\" style={{ perspective: `${SPATIAL_CAMERA_DISTANCE_PX}px`, perspectiveOrigin: '50% 50%' }}>\n <div\n ref={cameraRef}\n data-spatial-camera=\"\"\n style={{ position: 'absolute', left: '50%', top: '50%', width: 0, height: 0, transformStyle: 'preserve-3d', transform: cssCameraTransform(restPose()) }}\n >\n {panel(SpatialPanelId.START_COLUMN, startRef, 'natural-width', (\n <>\n <AppShellRegionOutlet region={ShellRegion.ACTIVITY_BAR} />\n <AppShellRegionOutlet region={ShellRegion.SIDEBAR} placement={HorizontalPlacement.START} />\n <AppShellRegionOutlet region={ShellRegion.UTILITY_PANEL} placement={HorizontalPlacement.START} />\n </>\n ))}\n {panel(SpatialPanelId.CENTRE, null, 'fixed', (\n <div className=\"flex-1 flex flex-col min-w-0 min-h-0\">\n <AppShellRegionOutlet region={ShellRegion.TOOLBAR} />\n <AppShellContentOutlet className=\"flex-1 relative min-w-0 min-h-0\">{children}</AppShellContentOutlet>\n </div>\n ))}\n {panel(SpatialPanelId.END_COLUMN, endRef, 'natural-width', (\n <>\n <AppShellRegionOutlet region={ShellRegion.SIDEBAR} placement={HorizontalPlacement.END} />\n <AppShellRegionOutlet region={ShellRegion.UTILITY_PANEL} placement={HorizontalPlacement.END} />\n </>\n ))}\n {panel(SpatialPanelId.TOP, topRef, 'natural-height', (\n <div className=\"flex-1 flex flex-col min-w-0\">\n <AppShellRegionOutlet region={ShellRegion.STATUS_BAR} placement={VerticalPlacement.TOP} />\n <AppShellRegionOutlet region={ShellRegion.MENUBAR} />\n </div>\n ))}\n {panel(SpatialPanelId.BOTTOM, bottomRef, 'natural-height', (\n <div className=\"flex-1 flex flex-col min-w-0\">\n <AppShellRegionOutlet region={ShellRegion.STATUS_BAR} placement={VerticalPlacement.BOTTOM} />\n </div>\n ))}\n </div>\n </div>\n <AppShellOverlaysOutlet />\n <AppShellOverlayPortalLayer />\n </div>\n </Surface>\n );\n}\n\n/**\n * The glass every panel is made of: a translucent card colour over a blurred backdrop, a hairline light edge and a\n * deep soft shadow. Colours come from the theme's tokens, so light and dark modes follow the theme.\n */\nconst GLASS_STYLE: React.CSSProperties = {\n borderRadius: 22,\n background: 'color-mix(in oklab, var(--card, var(--background)) 74%, transparent)',\n backdropFilter: 'blur(28px) saturate(1.3)',\n border: '1px solid color-mix(in oklab, var(--border) 55%, white 45%)',\n boxShadow: '0 40px 90px -30px rgb(15 23 42 / 0.35), 0 12px 30px -12px rgb(15 23 42 / 0.18), inset 0 1px 0 0 rgb(255 255 255 / 0.45)',\n};\n\nfunction useViewportSize(): { width: number; height: number } {\n const read = (): { width: number; height: number } => ({ width: window.innerWidth, height: window.innerHeight });\n const [size, setSize] = useState(read);\n useEffect(() => {\n const onResize = (): void => setSize(read());\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n return size;\n}\n\n/**\n * The natural (untransformed) sizes of the panels whose size comes from their content: the side columns' widths and\n * the strips' heights. `offsetWidth`/`offsetHeight` ignore transforms, so a turned column reads its real width.\n */\nfunction useNaturalSizes(refs: Record<'start' | 'end' | 'top' | 'bottom', React.RefObject<HTMLDivElement | null>>): Record<'start' | 'end' | 'top' | 'bottom', number> {\n const [sizes, setSizes] = useState({ start: 0, end: 0, top: 0, bottom: 0 });\n useLayoutEffect(() => {\n const measure = (): void => {\n const width = (ref: React.RefObject<HTMLDivElement | null>): number => (ref.current && ref.current.childElementCount > 0 ? ref.current.offsetWidth : 0);\n const height = (ref: React.RefObject<HTMLDivElement | null>): number => (ref.current && hasRenderedRegion(ref.current) ? ref.current.offsetHeight : 0);\n const next = { start: width(refs.start), end: width(refs.end), top: height(refs.top), bottom: height(refs.bottom) };\n setSizes((previous) => (previous.start === next.start && previous.end === next.end && previous.top === next.top && previous.bottom === next.bottom ? previous : next));\n };\n measure();\n const observer = new ResizeObserver(measure);\n for (const ref of Object.values(refs)) if (ref.current) observer.observe(ref.current);\n const mutations = new MutationObserver(measure);\n for (const ref of Object.values(refs)) if (ref.current) mutations.observe(ref.current, { childList: true, subtree: true });\n return () => {\n observer.disconnect();\n mutations.disconnect();\n };\n }, [refs]);\n return sizes;\n}\n\nfunction hasRenderedRegion(element: HTMLElement): boolean {\n return element.querySelector('[data-component-area]') !== null;\n}\n\n/**\n * Plays camera moves on the camera element (the stage's OWN element, so writing its inline transform touches nothing\n * React renders) and publishes every pose to the store for the environment. Under reduced motion every move is a cut\n * to its final pose. Returns `play(move)`; a new move replaces the one in progress, starting from where it stands.\n */\nfunction useCameraPlayer(cameraRef: React.RefObject<HTMLDivElement | null>, store: SpatialStageStore, reduced: boolean): (move: SpatialCameraMove) => void {\n const frame = useRef(0);\n useEffect(() => () => cancelAnimationFrame(frame.current), []);\n return useMemo(() => {\n const apply = (pose: ReturnType<typeof restPose>): void => {\n if (cameraRef.current) cameraRef.current.style.transform = cssCameraTransform(pose);\n store.set({ pose });\n };\n return (move: SpatialCameraMove): void => {\n cancelAnimationFrame(frame.current);\n if (reduced) {\n apply(move.keyframes[move.keyframes.length - 1]!.pose);\n return;\n }\n // Start from where the camera stands, so an interrupted move blends instead of jumping.\n const from = store.get().pose;\n const blended: SpatialCameraMove = { ...move, keyframes: [{ at: 0, pose: from }, ...move.keyframes.filter((keyframe) => keyframe.at > 0)] };\n const start = performance.now();\n const tick = (): void => {\n const elapsed = performance.now() - start;\n apply(sampleMove(blended, elapsed));\n if (elapsed < blended.durationMs) frame.current = requestAnimationFrame(tick);\n };\n frame.current = requestAnimationFrame(tick);\n };\n }, [cameraRef, store, reduced]);\n}\n\n/**\n * What moves the camera: the shell arriving, the content changing (a structural zone's top entry is another place,\n * by URL path — the same signature the flat frame uses), focus moving between side-by-side panes, and the start\n * column resizing (the sidebar collapsing or expanding).\n */\nfunction useSpatialCues(play: (move: SpatialCameraMove) => void, startWidth: number, measured: boolean, viewport: { width: number; height: number }): void {\n const navigation = useNavigationState();\n const zones = Object.keys(navigation.state.zones) as Array<keyof typeof navigation.state.zones>;\n const places = zones.map((zone) => {\n const top = navigation.getTopEntry(zone);\n return top ? (top.urlPath?.split(/[?#]/)[0] ?? top.id) : '';\n });\n const signature = places.some((place) => place !== '') ? zones.map((zone, index) => `${zone}:${places[index]}`).join('|') : '';\n\n const arrived = useRef(false);\n useEffect(() => {\n if (arrived.current || !measured) return;\n arrived.current = true;\n play(cameraMoveFor(SpatialCameraCue.ARRIVAL));\n }, [play, measured]);\n\n const lastSignature = useRef<string | null>(null);\n useEffect(() => {\n if (signature === '') return;\n const previous = lastSignature.current;\n lastSignature.current = signature;\n if (previous !== null && previous !== signature) play(cameraMoveFor(SpatialCameraCue.NAVIGATION));\n }, [play, signature]);\n\n const lastFocus = useRef<string | null>(null);\n useEffect(() => {\n const zone = navigation.focusedZone ?? null;\n const previous = lastFocus.current;\n lastFocus.current = zone;\n if (previous === null || zone === null || previous === zone) return;\n const panes = [...document.querySelectorAll<HTMLElement>(`[data-component-area=\"${ShellRegion.CONTENT}\"] [data-content-area]`)].filter((pane) => pane.offsetWidth > 0);\n const focused = panes.find((pane) => pane.dataset.contentArea === zone);\n if (panes.length < 2 || !focused) return;\n const rect = focused.getBoundingClientRect();\n play(cameraMoveFor(SpatialCameraCue.ZONE_FOCUS, SPATIAL_CAMERA_DISTANCE_PX, rect.left + rect.width / 2 - viewport.width / 2));\n }, [play, navigation.focusedZone, viewport.width]);\n\n // A collapse animates the width over many frames: cue once per settled change, not once per frame.\n const settledStart = useRef(0);\n const lastResizeCue = useRef(0);\n useEffect(() => {\n if (startWidth === 0) return;\n const previous = settledStart.current;\n if (previous === 0) {\n settledStart.current = startWidth;\n return;\n }\n if (Math.abs(previous - startWidth) <= 24) return;\n settledStart.current = startWidth;\n const now = performance.now();\n if (now - lastResizeCue.current < 900) return;\n lastResizeCue.current = now;\n play(cameraMoveFor(SpatialCameraCue.COLUMN_RESIZE));\n }, [play, startWidth]);\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { type SpatialCameraPose, type SpatialPanelId, type SpatialPanelPlacement } from './spatial-camera';
2
+ /** What the WebGL environment needs to draw the same world the HTML stage shows. */
3
+ export interface SpatialStageSnapshot {
4
+ pose: SpatialCameraPose;
5
+ distance: number;
6
+ viewport: {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ /** Only the panels that show something (a column with no region is absent). */
11
+ panels: Partial<Record<SpatialPanelId, SpatialPanelPlacement>>;
12
+ isDark: boolean;
13
+ }
14
+ /**
15
+ * The one piece of state the HTML stage and the WebGL environment share (PROTOTYPE). The stage WRITES it — the camera
16
+ * player on every frame of a move, the layout when a panel is re-arranged — and the environment, in its lazily loaded
17
+ * chunk, SUBSCRIBES and renders. A plain store rather than React state, so a camera frame re-renders no component.
18
+ */
19
+ export declare class SpatialStageStore {
20
+ private snapshot;
21
+ private readonly listeners;
22
+ constructor(initial?: Partial<SpatialStageSnapshot>);
23
+ get(): SpatialStageSnapshot;
24
+ set(change: Partial<SpatialStageSnapshot>): void;
25
+ subscribe(listener: (snapshot: SpatialStageSnapshot) => void): () => void;
26
+ }
27
+ //# sourceMappingURL=spatial-stage-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatial-stage-store.d.ts","sourceRoot":"","sources":["../../../../src/spatial/spatial-stage-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEjJ,oFAAoF;AACpF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,+EAA+E;IAC/E,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAC/D,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuD;gBAErE,OAAO,GAAE,OAAO,CAAC,oBAAoB,CAAM;IAWvD,GAAG,IAAI,oBAAoB;IAI3B,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAKhD,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;CAI1E"}
@@ -0,0 +1,33 @@
1
+ import { restPose, SPATIAL_CAMERA_DISTANCE_PX } from './spatial-camera.js';
2
+ /**
3
+ * The one piece of state the HTML stage and the WebGL environment share (PROTOTYPE). The stage WRITES it — the camera
4
+ * player on every frame of a move, the layout when a panel is re-arranged — and the environment, in its lazily loaded
5
+ * chunk, SUBSCRIBES and renders. A plain store rather than React state, so a camera frame re-renders no component.
6
+ */
7
+ export class SpatialStageStore {
8
+ snapshot;
9
+ listeners = new Set();
10
+ constructor(initial = {}) {
11
+ this.snapshot = {
12
+ pose: restPose(),
13
+ distance: SPATIAL_CAMERA_DISTANCE_PX,
14
+ viewport: { width: 1440, height: 900 },
15
+ panels: {},
16
+ isDark: false,
17
+ ...initial,
18
+ };
19
+ }
20
+ get() {
21
+ return this.snapshot;
22
+ }
23
+ set(change) {
24
+ this.snapshot = { ...this.snapshot, ...change };
25
+ for (const listener of this.listeners)
26
+ listener(this.snapshot);
27
+ }
28
+ subscribe(listener) {
29
+ this.listeners.add(listener);
30
+ return () => this.listeners.delete(listener);
31
+ }
32
+ }
33
+ //# sourceMappingURL=spatial-stage-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatial-stage-store.js","sourceRoot":"","sources":["../../../../src/spatial/spatial-stage-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,0BAA0B,EAA2E,MAAM,kBAAkB,CAAC;AAYjJ;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACpB,QAAQ,CAAuB;IACtB,SAAS,GAAG,IAAI,GAAG,EAA4C,CAAC;IAEjF,YAAY,UAAyC,EAAE;QACrD,IAAI,CAAC,QAAQ,GAAG;YACd,IAAI,EAAE,QAAQ,EAAE;YAChB,QAAQ,EAAE,0BAA0B;YACpC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;YACtC,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,KAAK;YACb,GAAG,OAAO;SACX,CAAC;IACJ,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,GAAG,CAAC,MAAqC;QACvC,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;QAChD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,SAAS,CAAC,QAAkD;QAC1D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;CACF","sourcesContent":["import { restPose, SPATIAL_CAMERA_DISTANCE_PX, type SpatialCameraPose, type SpatialPanelId, type SpatialPanelPlacement } from './spatial-camera';\n\n/** What the WebGL environment needs to draw the same world the HTML stage shows. */\nexport interface SpatialStageSnapshot {\n pose: SpatialCameraPose;\n distance: number;\n viewport: { width: number; height: number };\n /** Only the panels that show something (a column with no region is absent). */\n panels: Partial<Record<SpatialPanelId, SpatialPanelPlacement>>;\n isDark: boolean;\n}\n\n/**\n * The one piece of state the HTML stage and the WebGL environment share (PROTOTYPE). The stage WRITES it — the camera\n * player on every frame of a move, the layout when a panel is re-arranged — and the environment, in its lazily loaded\n * chunk, SUBSCRIBES and renders. A plain store rather than React state, so a camera frame re-renders no component.\n */\nexport class SpatialStageStore {\n private snapshot: SpatialStageSnapshot;\n private readonly listeners = new Set<(snapshot: SpatialStageSnapshot) => void>();\n\n constructor(initial: Partial<SpatialStageSnapshot> = {}) {\n this.snapshot = {\n pose: restPose(),\n distance: SPATIAL_CAMERA_DISTANCE_PX,\n viewport: { width: 1440, height: 900 },\n panels: {},\n isDark: false,\n ...initial,\n };\n }\n\n get(): SpatialStageSnapshot {\n return this.snapshot;\n }\n\n set(change: Partial<SpatialStageSnapshot>): void {\n this.snapshot = { ...this.snapshot, ...change };\n for (const listener of this.listeners) listener(this.snapshot);\n }\n\n subscribe(listener: (snapshot: SpatialStageSnapshot) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n}\n"]}
@@ -0,0 +1,110 @@
1
+ import { DesignSystemToken } from '@wildo-ai/presets-components-models';
2
+ /**
3
+ * What a design-token value resolved to, in the units a WebGL frame uses (#1819).
4
+ *
5
+ * Token values are authored as CSS strings — `oklch(...)`, `color-mix(...)`, `150ms`, `cubic-bezier(...)`,
6
+ * `0.5rem` — because the DOM consumes them as CSS. The 3D frame draws with numbers, so each value is
7
+ * resolved once, per theme and per light/dark mode, into one of these kinds.
8
+ */
9
+ export declare enum ResolvedDesignTokenKind {
10
+ /** A colour, in linear-light sRGB (what three.js expects of a material colour) plus alpha. */
11
+ COLOR = "color",
12
+ /** A duration (`ms` / `s`), in seconds. */
13
+ DURATION = "duration",
14
+ /** An easing, as the four control points of a cubic Bézier. */
15
+ EASING = "easing",
16
+ /** A length (`px` / `rem`), in CSS pixels. */
17
+ SIZE = "size",
18
+ /** A plain number (an opacity). */
19
+ NUMBER = "number"
20
+ }
21
+ /**
22
+ * Why a value was NOT resolved. A value the frame cannot use is reported, never guessed: a wrong number in
23
+ * a WebGL scene is invisible until someone notices the frame looks off.
24
+ */
25
+ export declare enum UnresolvedDesignTokenReason {
26
+ /**
27
+ * The value depends on the viewport or the containing layout (`clamp()`, `calc()`, viewport units such as `vw`
28
+ * and `dvh`, container units such as `cqi`, `%`), so it has no single number.
29
+ */
30
+ VIEWPORT_RELATIVE = "viewport-relative",
31
+ /**
32
+ * A reference (`var()`, `color-mix()`) that neither the token graph nor the browser probe resolved — an
33
+ * unknown custom property, a mixing space this resolver does not model, or a percentage CSS rejects.
34
+ */
35
+ REFERENCE_UNRESOLVED = "reference-unresolved",
36
+ /** Not one of the forms the frame reads: a shadow list, a list of palette names, a stepped easing. */
37
+ UNSUPPORTED_FORM = "unsupported-form"
38
+ }
39
+ /** Where a resolved colour came from. The provenance travels through references and mixes. */
40
+ export declare enum DesignTokenColorSource {
41
+ /** The token's own value was a colour literal. */
42
+ VALUE = "value",
43
+ /** Resolved through other tokens (`var(--token)`, `color-mix()` of tokens) with no browser involved. */
44
+ TOKEN_GRAPH = "token-graph",
45
+ /**
46
+ * At least one input came from the browser probe, which answers against the document's custom properties at
47
+ * the moment of the call — see `useDesignTokenResolution` for why such a result is recomputed after a commit.
48
+ */
49
+ BROWSER_PROBE = "browser-probe"
50
+ }
51
+ /**
52
+ * A token value in the frame's units. The kind decides the unit: linear-light sRGB plus alpha for a colour,
53
+ * seconds for a duration, cubic-Bézier control points for an easing, CSS pixels for a size.
54
+ */
55
+ export type ResolvedDesignTokenValue = {
56
+ kind: ResolvedDesignTokenKind.COLOR;
57
+ linearRgb: readonly [number, number, number];
58
+ alpha: number;
59
+ source: DesignTokenColorSource;
60
+ } | {
61
+ kind: ResolvedDesignTokenKind.DURATION;
62
+ seconds: number;
63
+ } | {
64
+ kind: ResolvedDesignTokenKind.EASING;
65
+ controlPoints: readonly [number, number, number, number];
66
+ } | {
67
+ kind: ResolvedDesignTokenKind.SIZE;
68
+ px: number;
69
+ } | {
70
+ kind: ResolvedDesignTokenKind.NUMBER;
71
+ value: number;
72
+ };
73
+ /**
74
+ * One token's outcome: its authored CSS `value`, and either what it `resolved` to or why it is `unresolved`.
75
+ * There is no third state, so a consumer must handle both, and an unresolved token is never read as a default.
76
+ */
77
+ export type DesignTokenResolution = {
78
+ token: DesignSystemToken;
79
+ value: string;
80
+ resolved: ResolvedDesignTokenValue;
81
+ } | {
82
+ token: DesignSystemToken;
83
+ value: string;
84
+ unresolved: UnresolvedDesignTokenReason;
85
+ };
86
+ export interface DesignTokenResolutionOptions {
87
+ /** The root font size a `rem` is measured against. The framework's own is 16 px. */
88
+ rootFontSizePx?: number;
89
+ /**
90
+ * The browser's computed form of a colour reference the token graph cannot express: a `var()` naming a custom
91
+ * property that is not a token (the browser also applies its fallback, when the property is undefined), or a
92
+ * `color-mix()` this resolver does not model. `readComputedCssColorViaDom` from `@wildo-ai/saas-frontend-lib`
93
+ * in a browser. Omitted in a test, where there is no browser to ask; such a reference is then unresolved.
94
+ */
95
+ readComputedColor?: (value: string) => string | null;
96
+ }
97
+ /**
98
+ * Resolve every token's value into the frame's units, or say why not.
99
+ *
100
+ * `values` is the whole token set for ONE theme and ONE mode — what `useUI().getTokenValue` returns — and
101
+ * must be the whole set, because a formula refers to other tokens: `border-strong` is
102
+ * `color-mix(in oklab, var(--foreground) 45%, var(--background))`.
103
+ *
104
+ * References to other tokens are resolved THROUGH THE TOKEN GRAPH rather than by asking the browser: the
105
+ * browser answers against whatever custom properties the document holds at the moment, which lags a light/dark
106
+ * switch, while the graph is the mode's own values by construction. The browser probe is the fallback for a
107
+ * reference the graph cannot express, and a result that used it says so (`BROWSER_PROBE`).
108
+ */
109
+ export declare function resolveDesignTokens(values: Readonly<Partial<Record<DesignSystemToken, string>>>, options?: DesignTokenResolutionOptions): Map<DesignSystemToken, DesignTokenResolution>;
110
+ //# sourceMappingURL=design-token-resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-token-resolution.d.ts","sourceRoot":"","sources":["../../../../src/tokens/design-token-resolution.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAExE;;;;;;GAMG;AACH,oBAAY,uBAAuB;IACjC,8FAA8F;IAC9F,KAAK,UAAU;IACf,2CAA2C;IAC3C,QAAQ,aAAa;IACrB,+DAA+D;IAC/D,MAAM,WAAW;IACjB,8CAA8C;IAC9C,IAAI,SAAS;IACb,mCAAmC;IACnC,MAAM,WAAW;CAClB;AAED;;;GAGG;AACH,oBAAY,2BAA2B;IACrC;;;OAGG;IACH,iBAAiB,sBAAsB;IACvC;;;OAGG;IACH,oBAAoB,yBAAyB;IAC7C,sGAAsG;IACtG,gBAAgB,qBAAqB;CACtC;AAED,8FAA8F;AAC9F,oBAAY,sBAAsB;IAChC,kDAAkD;IAClD,KAAK,UAAU;IACf,wGAAwG;IACxG,WAAW,gBAAgB;IAC3B;;;OAGG;IACH,aAAa,kBAAkB;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,uBAAuB,CAAC,KAAK,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACpI;IAAE,IAAI,EAAE,uBAAuB,CAAC,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,uBAAuB,CAAC,MAAM,CAAC;IAAC,aAAa,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAClG;IAAE,IAAI,EAAE,uBAAuB,CAAC,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,uBAAuB,CAAC,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,wBAAwB,CAAA;CAAE,GAC/E;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,2BAA2B,CAAA;CAAE,CAAC;AAEzF,MAAM,WAAW,4BAA4B;IAC3C,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACtD;AAyDD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC,EAC5D,OAAO,GAAE,4BAAiC,GACzC,GAAG,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAyG/C"}