@wildo-ai/presets-components-3d 1.1.6 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/focal-plane/focal-plane-settings.d.ts +35 -0
- package/dist/esm/focal-plane/focal-plane-settings.d.ts.map +1 -0
- package/dist/esm/focal-plane/focal-plane-settings.js +68 -0
- package/dist/esm/focal-plane/focal-plane-settings.js.map +1 -0
- package/dist/esm/focal-plane/focal-plane-shell-container.d.ts +13 -0
- package/dist/esm/focal-plane/focal-plane-shell-container.d.ts.map +1 -0
- package/dist/esm/focal-plane/focal-plane-shell-container.js +147 -0
- package/dist/esm/focal-plane/focal-plane-shell-container.js.map +1 -0
- package/dist/esm/focal-plane/focal-plane-stylesheet.d.ts +14 -0
- package/dist/esm/focal-plane/focal-plane-stylesheet.d.ts.map +1 -0
- package/dist/esm/focal-plane/focal-plane-stylesheet.js +236 -0
- package/dist/esm/focal-plane/focal-plane-stylesheet.js.map +1 -0
- package/dist/esm/focal-plane/use-pane-depth.d.ts +20 -0
- package/dist/esm/focal-plane/use-pane-depth.d.ts.map +1 -0
- package/dist/esm/focal-plane/use-pane-depth.js +162 -0
- package/dist/esm/focal-plane/use-pane-depth.js.map +1 -0
- package/dist/esm/focal-plane/use-shared-vanishing-point.d.ts +35 -0
- package/dist/esm/focal-plane/use-shared-vanishing-point.d.ts.map +1 -0
- package/dist/esm/focal-plane/use-shared-vanishing-point.js +86 -0
- package/dist/esm/focal-plane/use-shared-vanishing-point.js.map +1 -0
- package/dist/esm/frame/frame-3d-style.d.ts.map +1 -1
- package/dist/esm/frame/frame-3d-style.js.map +1 -1
- package/dist/esm/frame/frame-appearance.d.ts.map +1 -1
- package/dist/esm/frame/frame-appearance.js.map +1 -1
- package/dist/esm/frame/frame-canvas.d.ts.map +1 -1
- package/dist/esm/frame/frame-canvas.js +3 -3
- package/dist/esm/frame/frame-canvas.js.map +1 -1
- package/dist/esm/frame/frame-canvas.lazy.d.ts.map +1 -1
- package/dist/esm/frame/frame-canvas.lazy.js.map +1 -1
- package/dist/esm/frame/frame-color.d.ts.map +1 -1
- package/dist/esm/frame/frame-color.js.map +1 -1
- package/dist/esm/frame/frame-driver.d.ts.map +1 -1
- package/dist/esm/frame/frame-driver.js.map +1 -1
- package/dist/esm/frame/frame-renderer.d.ts.map +1 -1
- package/dist/esm/frame/frame-renderer.js.map +1 -1
- package/dist/esm/frame/frame-shaders.d.ts.map +1 -1
- package/dist/esm/frame/frame-shaders.js.map +1 -1
- package/dist/esm/frame/use-frame-appearance.d.ts.map +1 -1
- package/dist/esm/frame/use-frame-appearance.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/layout/header-first-shell-container.d.ts.map +1 -1
- package/dist/esm/layout/header-first-shell-container.js.map +1 -1
- package/dist/esm/layout/layout-3d-definition.d.ts +5 -6
- package/dist/esm/layout/layout-3d-definition.d.ts.map +1 -1
- package/dist/esm/layout/layout-3d-definition.js +13 -14
- package/dist/esm/layout/layout-3d-definition.js.map +1 -1
- package/dist/esm/layout/layout-3d-transition-choreography.d.ts.map +1 -1
- package/dist/esm/layout/layout-3d-transition-choreography.js.map +1 -1
- package/dist/esm/layout/layout-3d-vocabulary.d.ts +13 -8
- package/dist/esm/layout/layout-3d-vocabulary.d.ts.map +1 -1
- package/dist/esm/layout/layout-3d-vocabulary.js +12 -7
- package/dist/esm/layout/layout-3d-vocabulary.js.map +1 -1
- package/dist/esm/layout/shell-layout-placement.d.ts.map +1 -1
- package/dist/esm/layout/shell-layout-placement.js.map +1 -1
- package/dist/esm/layout-3d-main-container.d.ts +6 -0
- package/dist/esm/layout-3d-main-container.d.ts.map +1 -1
- package/dist/esm/layout-3d-main-container.js +8 -1
- package/dist/esm/layout-3d-main-container.js.map +1 -1
- package/dist/esm/register-3d-layout.d.ts.map +1 -1
- package/dist/esm/register-3d-layout.js.map +1 -1
- package/dist/esm/shell-region-measurement.d.ts.map +1 -1
- package/dist/esm/shell-region-measurement.js.map +1 -1
- package/dist/esm/tokens/design-token-resolution.d.ts.map +1 -1
- package/dist/esm/tokens/design-token-resolution.js.map +1 -1
- package/dist/esm/tokens/use-design-token-resolution.d.ts.map +1 -1
- package/dist/esm/tokens/use-design-token-resolution.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +3 -3
- package/dist/esm/spatial/spatial-camera.d.ts +0 -106
- package/dist/esm/spatial/spatial-camera.d.ts.map +0 -1
- package/dist/esm/spatial/spatial-camera.js +0 -151
- package/dist/esm/spatial/spatial-camera.js.map +0 -1
- package/dist/esm/spatial/spatial-environment.d.ts +0 -6
- package/dist/esm/spatial/spatial-environment.d.ts.map +0 -1
- package/dist/esm/spatial/spatial-environment.js +0 -166
- package/dist/esm/spatial/spatial-environment.js.map +0 -1
- package/dist/esm/spatial/spatial-environment.lazy.d.ts +0 -10
- package/dist/esm/spatial/spatial-environment.lazy.d.ts.map +0 -1
- package/dist/esm/spatial/spatial-environment.lazy.js +0 -13
- package/dist/esm/spatial/spatial-environment.lazy.js.map +0 -1
- package/dist/esm/spatial/spatial-shell-container.d.ts +0 -21
- package/dist/esm/spatial/spatial-shell-container.d.ts.map +0 -1
- package/dist/esm/spatial/spatial-shell-container.js +0 -231
- package/dist/esm/spatial/spatial-shell-container.js.map +0 -1
- package/dist/esm/spatial/spatial-stage-store.d.ts +0 -27
- package/dist/esm/spatial/spatial-stage-store.d.ts.map +0 -1
- package/dist/esm/spatial/spatial-stage-store.js +0 -33
- package/dist/esm/spatial/spatial-stage-store.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wildo-ai/presets-components-3d",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "Optional 3D layouts for the Wildo AI application shell: its regions, unchanged HTML, arranged by a 3D layout over a decorative WebGL frame",
|
|
6
6
|
"author": "Wildo AI",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"test:watch": "vitest"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@wildo-ai/presets-components-models": "1.1.
|
|
33
|
-
"@wildo-ai/saas-frontend-lib": "1.1.
|
|
32
|
+
"@wildo-ai/presets-components-models": "1.1.7",
|
|
33
|
+
"@wildo-ai/saas-frontend-lib": "1.1.7",
|
|
34
34
|
"culori": "^4.0.2"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The spatial layout's camera and panel geometry (PROTOTYPE, 2026-09-30): plain math, no three.js, so the placement
|
|
3
|
-
* container can import it without pulling the WebGL chunk in (`check:lazy-boundaries`).
|
|
4
|
-
*
|
|
5
|
-
* ## One world, two renderers
|
|
6
|
-
*
|
|
7
|
-
* The world is in CSS pixels, with its origin at the middle of the viewport, x to the right, y DOWN, z toward the
|
|
8
|
-
* viewer — CSS's own axes, so the HTML stage needs no conversion. A CSS `perspective: d` root with the camera element
|
|
9
|
-
* at its centre shows an element at z = 0 at exactly its CSS size when the camera rests at (0, 0, d): that is the rest
|
|
10
|
-
* pose, and it is why the content panel is crisp at rest. The WebGL environment renders the same world through a
|
|
11
|
-
* three.js perspective camera built from the same pose (y flipped, see `spatial-environment.tsx`).
|
|
12
|
-
*/
|
|
13
|
-
/** Where the camera is and where it looks. Angles in degrees, in CSS rotation terms (`rotateY`, `rotateX`). */
|
|
14
|
-
export interface SpatialCameraPose {
|
|
15
|
-
x: number;
|
|
16
|
-
y: number;
|
|
17
|
-
z: number;
|
|
18
|
-
yawDeg: number;
|
|
19
|
-
pitchDeg: number;
|
|
20
|
-
}
|
|
21
|
-
/** The CSS perspective distance: the viewer's distance from the z = 0 plane at rest. Short enough to feel spatial. */
|
|
22
|
-
export declare const SPATIAL_CAMERA_DISTANCE_PX = 1100;
|
|
23
|
-
export declare function restPose(distance?: number): SpatialCameraPose;
|
|
24
|
-
/**
|
|
25
|
-
* The transform of the stage's camera element for a pose: the inverse of the camera (a camera moving right is the
|
|
26
|
-
* world moving left), then pushed to the perspective plane. `translateZ(d) · Rᵀ · T(−P)`, where the camera's rotation is
|
|
27
|
-
* `rotateY(yaw) · rotateX(pitch)`; at rest it is the identity.
|
|
28
|
-
*/
|
|
29
|
-
export declare function cssCameraTransform(pose: SpatialCameraPose, distance?: number): string;
|
|
30
|
-
export declare function lerpPose(from: SpatialCameraPose, to: SpatialCameraPose, t: number): SpatialCameraPose;
|
|
31
|
-
/** A camera move: poses at points of its duration (0 to 1), eased between. The last pose is where it comes to rest. */
|
|
32
|
-
export interface SpatialCameraMove {
|
|
33
|
-
durationMs: number;
|
|
34
|
-
keyframes: ReadonlyArray<{
|
|
35
|
-
at: number;
|
|
36
|
-
pose: SpatialCameraPose;
|
|
37
|
-
}>;
|
|
38
|
-
}
|
|
39
|
-
/** A smooth in-out easing: the camera starts and stops without a jolt. */
|
|
40
|
-
export declare function easeInOutCubic(t: number): number;
|
|
41
|
-
/** The camera's pose `elapsedMs` into a move. Past its end, the move's final pose. */
|
|
42
|
-
export declare function sampleMove(move: SpatialCameraMove, elapsedMs: number): SpatialCameraPose;
|
|
43
|
-
/** The moves the prototype plays. Each leaves the camera at rest, so the content is always crisp when nothing moves. */
|
|
44
|
-
export declare enum SpatialCameraCue {
|
|
45
|
-
/** The shell appears: the camera glides in from far back. */
|
|
46
|
-
ARRIVAL = "arrival",
|
|
47
|
-
/** The content changed: the camera steps back to take in the space, then returns. */
|
|
48
|
-
NAVIGATION = "navigation",
|
|
49
|
-
/** Focus moved to a pane beside another: the camera leans toward it, then returns. */
|
|
50
|
-
ZONE_FOCUS = "zone-focus",
|
|
51
|
-
/** The side column resized: the camera breathes out while the panels re-arrange. */
|
|
52
|
-
COLUMN_RESIZE = "column-resize"
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* The move for a cue. `towardX` is, for a zone focus, the focused pane's centre in world x (the camera leans toward
|
|
56
|
-
* it); ignored otherwise.
|
|
57
|
-
*/
|
|
58
|
-
export declare function cameraMoveFor(cue: SpatialCameraCue, distance?: number, towardX?: number): SpatialCameraMove;
|
|
59
|
-
/** The panels the spatial placement arranges the shell regions into. */
|
|
60
|
-
export declare enum SpatialPanelId {
|
|
61
|
-
/** Activity bar, start sidebar, start utility panel: one column standing angled on the start side. */
|
|
62
|
-
START_COLUMN = "start-column",
|
|
63
|
-
/** Toolbar and content: facing the camera. */
|
|
64
|
-
CENTRE = "centre",
|
|
65
|
-
/** End sidebar and end utility panel, angled on the end side. */
|
|
66
|
-
END_COLUMN = "end-column",
|
|
67
|
-
/** Top status bar and menubar, floating above the centre. */
|
|
68
|
-
TOP = "top",
|
|
69
|
-
/** Bottom status bar, below the centre. */
|
|
70
|
-
BOTTOM = "bottom"
|
|
71
|
-
}
|
|
72
|
-
/** A panel's size (its CSS box, measured untransformed) and where its centre stands in the world. */
|
|
73
|
-
export interface SpatialPanelPlacement {
|
|
74
|
-
x: number;
|
|
75
|
-
y: number;
|
|
76
|
-
z: number;
|
|
77
|
-
width: number;
|
|
78
|
-
height: number;
|
|
79
|
-
yawDeg: number;
|
|
80
|
-
}
|
|
81
|
-
export interface SpatialLayoutInput {
|
|
82
|
-
viewport: {
|
|
83
|
-
width: number;
|
|
84
|
-
height: number;
|
|
85
|
-
};
|
|
86
|
-
/** Natural widths of the side columns (0 when empty). */
|
|
87
|
-
startWidth: number;
|
|
88
|
-
endWidth: number;
|
|
89
|
-
/** Natural heights of the top and bottom strips (0 when empty). */
|
|
90
|
-
topHeight: number;
|
|
91
|
-
bottomHeight: number;
|
|
92
|
-
}
|
|
93
|
-
/** Margin around the arrangement and gap between panels, in CSS pixels. */
|
|
94
|
-
export declare const SPATIAL_MARGIN_PX = 28;
|
|
95
|
-
export declare const SPATIAL_GAP_PX = 18;
|
|
96
|
-
/** How far the side columns turn toward the viewer, like screens beside a desk. */
|
|
97
|
-
export declare const SPATIAL_SIDE_ANGLE_DEG = 26;
|
|
98
|
-
/**
|
|
99
|
-
* Where each panel stands. The centre keeps the footprint it would have in 2D and faces the camera at z = 0, so at
|
|
100
|
-
* rest it is shown at exactly its CSS size. Each side column is hinged at its inner edge, a gap from the centre, and
|
|
101
|
-
* turned so its outer edge comes toward the viewer. The top strip floats slightly forward, above the centre.
|
|
102
|
-
*/
|
|
103
|
-
export declare function layoutSpatialPanels(input: SpatialLayoutInput): Record<SpatialPanelId, SpatialPanelPlacement>;
|
|
104
|
-
/** The CSS transform standing a panel at its placement: centred on the stage origin, moved, then turned. */
|
|
105
|
-
export declare function panelTransform(panel: SpatialPanelPlacement): string;
|
|
106
|
-
//# sourceMappingURL=spatial-camera.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-camera.d.ts","sourceRoot":"","sources":["../../../../src/spatial/spatial-camera.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+GAA+G;AAC/G,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,sHAAsH;AACtH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,wBAAgB,QAAQ,CAAC,QAAQ,GAAE,MAAmC,GAAG,iBAAiB,CAEzF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,EAAE,QAAQ,GAAE,MAAmC,GAAG,MAAM,CAEjH;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAGrG;AAED,uHAAuH;AACvH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAAC;CACnE;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,GAAG,iBAAiB,CAaxF;AAED,wHAAwH;AACxH,oBAAY,gBAAgB;IAC1B,6DAA6D;IAC7D,OAAO,YAAY;IACnB,qFAAqF;IACrF,UAAU,eAAe;IACzB,sFAAsF;IACtF,UAAU,eAAe;IACzB,oFAAoF;IACpF,aAAa,kBAAkB;CAChC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,QAAQ,GAAE,MAAmC,EAAE,OAAO,SAAI,GAAG,iBAAiB,CAwBlI;AAED,wEAAwE;AACxE,oBAAY,cAAc;IACxB,sGAAsG;IACtG,YAAY,iBAAiB;IAC7B,8CAA8C;IAC9C,MAAM,WAAW;IACjB,iEAAiE;IACjE,UAAU,eAAe;IACzB,6DAA6D;IAC7D,GAAG,QAAQ;IACX,2CAA2C;IAC3C,MAAM,WAAW;CAClB;AAED,qGAAqG;AACrG,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAAC,CA6B5G;AAED,4GAA4G;AAC5G,wBAAgB,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAEnE"}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The spatial layout's camera and panel geometry (PROTOTYPE, 2026-09-30): plain math, no three.js, so the placement
|
|
3
|
-
* container can import it without pulling the WebGL chunk in (`check:lazy-boundaries`).
|
|
4
|
-
*
|
|
5
|
-
* ## One world, two renderers
|
|
6
|
-
*
|
|
7
|
-
* The world is in CSS pixels, with its origin at the middle of the viewport, x to the right, y DOWN, z toward the
|
|
8
|
-
* viewer — CSS's own axes, so the HTML stage needs no conversion. A CSS `perspective: d` root with the camera element
|
|
9
|
-
* at its centre shows an element at z = 0 at exactly its CSS size when the camera rests at (0, 0, d): that is the rest
|
|
10
|
-
* pose, and it is why the content panel is crisp at rest. The WebGL environment renders the same world through a
|
|
11
|
-
* three.js perspective camera built from the same pose (y flipped, see `spatial-environment.tsx`).
|
|
12
|
-
*/
|
|
13
|
-
/** The CSS perspective distance: the viewer's distance from the z = 0 plane at rest. Short enough to feel spatial. */
|
|
14
|
-
export const SPATIAL_CAMERA_DISTANCE_PX = 1100;
|
|
15
|
-
export function restPose(distance = SPATIAL_CAMERA_DISTANCE_PX) {
|
|
16
|
-
return { x: 0, y: 0, z: distance, yawDeg: 0, pitchDeg: 0 };
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* The transform of the stage's camera element for a pose: the inverse of the camera (a camera moving right is the
|
|
20
|
-
* world moving left), then pushed to the perspective plane. `translateZ(d) · Rᵀ · T(−P)`, where the camera's rotation is
|
|
21
|
-
* `rotateY(yaw) · rotateX(pitch)`; at rest it is the identity.
|
|
22
|
-
*/
|
|
23
|
-
export function cssCameraTransform(pose, distance = SPATIAL_CAMERA_DISTANCE_PX) {
|
|
24
|
-
return `translateZ(${distance}px) rotateX(${-pose.pitchDeg}deg) rotateY(${-pose.yawDeg}deg) translate3d(${-pose.x}px, ${-pose.y}px, ${-pose.z}px)`;
|
|
25
|
-
}
|
|
26
|
-
export function lerpPose(from, to, t) {
|
|
27
|
-
const at = (a, b) => a + (b - a) * t;
|
|
28
|
-
return { x: at(from.x, to.x), y: at(from.y, to.y), z: at(from.z, to.z), yawDeg: at(from.yawDeg, to.yawDeg), pitchDeg: at(from.pitchDeg, to.pitchDeg) };
|
|
29
|
-
}
|
|
30
|
-
/** A smooth in-out easing: the camera starts and stops without a jolt. */
|
|
31
|
-
export function easeInOutCubic(t) {
|
|
32
|
-
return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
33
|
-
}
|
|
34
|
-
/** The camera's pose `elapsedMs` into a move. Past its end, the move's final pose. */
|
|
35
|
-
export function sampleMove(move, elapsedMs) {
|
|
36
|
-
const frames = move.keyframes;
|
|
37
|
-
const first = frames[0];
|
|
38
|
-
const last = frames[frames.length - 1];
|
|
39
|
-
if (!first || !last)
|
|
40
|
-
throw new Error('A spatial camera move needs at least one keyframe.');
|
|
41
|
-
const t = move.durationMs <= 0 ? 1 : Math.min(1, Math.max(0, elapsedMs / move.durationMs));
|
|
42
|
-
if (t <= first.at)
|
|
43
|
-
return first.pose;
|
|
44
|
-
for (let index = 1; index < frames.length; index += 1) {
|
|
45
|
-
const previous = frames[index - 1];
|
|
46
|
-
const next = frames[index];
|
|
47
|
-
if (t <= next.at)
|
|
48
|
-
return lerpPose(previous.pose, next.pose, easeInOutCubic((t - previous.at) / Math.max(1e-6, next.at - previous.at)));
|
|
49
|
-
}
|
|
50
|
-
return last.pose;
|
|
51
|
-
}
|
|
52
|
-
/** The moves the prototype plays. Each leaves the camera at rest, so the content is always crisp when nothing moves. */
|
|
53
|
-
export var SpatialCameraCue;
|
|
54
|
-
(function (SpatialCameraCue) {
|
|
55
|
-
/** The shell appears: the camera glides in from far back. */
|
|
56
|
-
SpatialCameraCue["ARRIVAL"] = "arrival";
|
|
57
|
-
/** The content changed: the camera steps back to take in the space, then returns. */
|
|
58
|
-
SpatialCameraCue["NAVIGATION"] = "navigation";
|
|
59
|
-
/** Focus moved to a pane beside another: the camera leans toward it, then returns. */
|
|
60
|
-
SpatialCameraCue["ZONE_FOCUS"] = "zone-focus";
|
|
61
|
-
/** The side column resized: the camera breathes out while the panels re-arrange. */
|
|
62
|
-
SpatialCameraCue["COLUMN_RESIZE"] = "column-resize";
|
|
63
|
-
})(SpatialCameraCue || (SpatialCameraCue = {}));
|
|
64
|
-
/**
|
|
65
|
-
* The move for a cue. `towardX` is, for a zone focus, the focused pane's centre in world x (the camera leans toward
|
|
66
|
-
* it); ignored otherwise.
|
|
67
|
-
*/
|
|
68
|
-
export function cameraMoveFor(cue, distance = SPATIAL_CAMERA_DISTANCE_PX, towardX = 0) {
|
|
69
|
-
const rest = restPose(distance);
|
|
70
|
-
switch (cue) {
|
|
71
|
-
case SpatialCameraCue.ARRIVAL:
|
|
72
|
-
return { durationMs: 1700, keyframes: [{ at: 0, pose: { ...rest, y: -140, z: distance + 1400, pitchDeg: 9 } }, { at: 1, pose: rest }] };
|
|
73
|
-
case SpatialCameraCue.NAVIGATION:
|
|
74
|
-
return {
|
|
75
|
-
durationMs: 1200,
|
|
76
|
-
keyframes: [{ at: 0, pose: rest }, { at: 0.42, pose: { ...rest, y: -60, z: distance + 520, pitchDeg: 4 } }, { at: 1, pose: rest }],
|
|
77
|
-
};
|
|
78
|
-
case SpatialCameraCue.ZONE_FOCUS: {
|
|
79
|
-
const lean = Math.sign(towardX);
|
|
80
|
-
return {
|
|
81
|
-
durationMs: 1100,
|
|
82
|
-
keyframes: [{ at: 0, pose: rest }, { at: 0.45, pose: { ...rest, x: towardX * 0.3, z: distance + 220, yawDeg: -lean * 6 } }, { at: 1, pose: rest }],
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
case SpatialCameraCue.COLUMN_RESIZE:
|
|
86
|
-
return { durationMs: 900, keyframes: [{ at: 0, pose: rest }, { at: 0.5, pose: { ...rest, z: distance + 260 } }, { at: 1, pose: rest }] };
|
|
87
|
-
default: {
|
|
88
|
-
const unsupported = cue;
|
|
89
|
-
throw new Error(`The spatial camera has no move for '${String(unsupported)}'.`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/** The panels the spatial placement arranges the shell regions into. */
|
|
94
|
-
export var SpatialPanelId;
|
|
95
|
-
(function (SpatialPanelId) {
|
|
96
|
-
/** Activity bar, start sidebar, start utility panel: one column standing angled on the start side. */
|
|
97
|
-
SpatialPanelId["START_COLUMN"] = "start-column";
|
|
98
|
-
/** Toolbar and content: facing the camera. */
|
|
99
|
-
SpatialPanelId["CENTRE"] = "centre";
|
|
100
|
-
/** End sidebar and end utility panel, angled on the end side. */
|
|
101
|
-
SpatialPanelId["END_COLUMN"] = "end-column";
|
|
102
|
-
/** Top status bar and menubar, floating above the centre. */
|
|
103
|
-
SpatialPanelId["TOP"] = "top";
|
|
104
|
-
/** Bottom status bar, below the centre. */
|
|
105
|
-
SpatialPanelId["BOTTOM"] = "bottom";
|
|
106
|
-
})(SpatialPanelId || (SpatialPanelId = {}));
|
|
107
|
-
/** Margin around the arrangement and gap between panels, in CSS pixels. */
|
|
108
|
-
export const SPATIAL_MARGIN_PX = 28;
|
|
109
|
-
export const SPATIAL_GAP_PX = 18;
|
|
110
|
-
/** How far the side columns turn toward the viewer, like screens beside a desk. */
|
|
111
|
-
export const SPATIAL_SIDE_ANGLE_DEG = 26;
|
|
112
|
-
/**
|
|
113
|
-
* Where each panel stands. The centre keeps the footprint it would have in 2D and faces the camera at z = 0, so at
|
|
114
|
-
* rest it is shown at exactly its CSS size. Each side column is hinged at its inner edge, a gap from the centre, and
|
|
115
|
-
* turned so its outer edge comes toward the viewer. The top strip floats slightly forward, above the centre.
|
|
116
|
-
*/
|
|
117
|
-
export function layoutSpatialPanels(input) {
|
|
118
|
-
const { width: W, height: H } = input.viewport;
|
|
119
|
-
const M = SPATIAL_MARGIN_PX;
|
|
120
|
-
const G = SPATIAL_GAP_PX;
|
|
121
|
-
const left = -W / 2 + M + (input.startWidth > 0 ? input.startWidth + G : 0);
|
|
122
|
-
const right = W / 2 - M - (input.endWidth > 0 ? input.endWidth + G : 0);
|
|
123
|
-
const top = -H / 2 + M + (input.topHeight > 0 ? input.topHeight + G : 0);
|
|
124
|
-
const bottom = H / 2 - M - (input.bottomHeight > 0 ? input.bottomHeight + G : 0);
|
|
125
|
-
const centreWidth = Math.max(0, right - left);
|
|
126
|
-
const centreHeight = Math.max(0, bottom - top);
|
|
127
|
-
const columnHeight = H - 2 * M;
|
|
128
|
-
const theta = (SPATIAL_SIDE_ANGLE_DEG * Math.PI) / 180;
|
|
129
|
-
// A column turned by θ about its centre moves its inner edge by (w/2)(1 − cos θ) and w/2·sin θ in depth: place the
|
|
130
|
-
// centre so the inner edge stands exactly on the hinge line, a gap from the centre panel, at depth 0.
|
|
131
|
-
const hinged = (width, hingeX, side) => ({
|
|
132
|
-
x: hingeX - side * (width / 2) * Math.cos(theta),
|
|
133
|
-
y: 0,
|
|
134
|
-
z: (width / 2) * Math.sin(theta),
|
|
135
|
-
width,
|
|
136
|
-
height: columnHeight,
|
|
137
|
-
yawDeg: side * SPATIAL_SIDE_ANGLE_DEG,
|
|
138
|
-
});
|
|
139
|
-
return {
|
|
140
|
-
[SpatialPanelId.CENTRE]: { x: (left + right) / 2, y: (top + bottom) / 2, z: 0, width: centreWidth, height: centreHeight, yawDeg: 0 },
|
|
141
|
-
[SpatialPanelId.START_COLUMN]: hinged(input.startWidth, left - G, 1),
|
|
142
|
-
[SpatialPanelId.END_COLUMN]: hinged(input.endWidth, right + G, -1),
|
|
143
|
-
[SpatialPanelId.TOP]: { x: (left + right) / 2, y: -H / 2 + M + input.topHeight / 2, z: 24, width: centreWidth, height: input.topHeight, yawDeg: 0 },
|
|
144
|
-
[SpatialPanelId.BOTTOM]: { x: (left + right) / 2, y: H / 2 - M - input.bottomHeight / 2, z: 12, width: centreWidth, height: input.bottomHeight, yawDeg: 0 },
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
/** The CSS transform standing a panel at its placement: centred on the stage origin, moved, then turned. */
|
|
148
|
-
export function panelTransform(panel) {
|
|
149
|
-
return `translate(-50%, -50%) translate3d(${panel.x}px, ${panel.y}px, ${panel.z}px) rotateY(${panel.yawDeg}deg)`;
|
|
150
|
-
}
|
|
151
|
-
//# sourceMappingURL=spatial-camera.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-camera.js","sourceRoot":"","sources":["../../../../src/spatial/spatial-camera.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The spatial layout's camera and panel geometry (PROTOTYPE, 2026-09-30): plain math, no three.js, so the placement\n * container can import it without pulling the WebGL chunk in (`check:lazy-boundaries`).\n *\n * ## One world, two renderers\n *\n * The world is in CSS pixels, with its origin at the middle of the viewport, x to the right, y DOWN, z toward the\n * viewer — CSS's own axes, so the HTML stage needs no conversion. A CSS `perspective: d` root with the camera element\n * at its centre shows an element at z = 0 at exactly its CSS size when the camera rests at (0, 0, d): that is the rest\n * pose, and it is why the content panel is crisp at rest. The WebGL environment renders the same world through a\n * three.js perspective camera built from the same pose (y flipped, see `spatial-environment.tsx`).\n */\n\n/** Where the camera is and where it looks. Angles in degrees, in CSS rotation terms (`rotateY`, `rotateX`). */\nexport interface SpatialCameraPose {\n x: number;\n y: number;\n z: number;\n yawDeg: number;\n pitchDeg: number;\n}\n\n/** The CSS perspective distance: the viewer's distance from the z = 0 plane at rest. Short enough to feel spatial. */\nexport const SPATIAL_CAMERA_DISTANCE_PX = 1100;\n\nexport function restPose(distance: number = SPATIAL_CAMERA_DISTANCE_PX): SpatialCameraPose {\n return { x: 0, y: 0, z: distance, yawDeg: 0, pitchDeg: 0 };\n}\n\n/**\n * The transform of the stage's camera element for a pose: the inverse of the camera (a camera moving right is the\n * world moving left), then pushed to the perspective plane. `translateZ(d) · Rᵀ · T(−P)`, where the camera's rotation is\n * `rotateY(yaw) · rotateX(pitch)`; at rest it is the identity.\n */\nexport function cssCameraTransform(pose: SpatialCameraPose, distance: number = SPATIAL_CAMERA_DISTANCE_PX): string {\n return `translateZ(${distance}px) rotateX(${-pose.pitchDeg}deg) rotateY(${-pose.yawDeg}deg) translate3d(${-pose.x}px, ${-pose.y}px, ${-pose.z}px)`;\n}\n\nexport function lerpPose(from: SpatialCameraPose, to: SpatialCameraPose, t: number): SpatialCameraPose {\n const at = (a: number, b: number): number => a + (b - a) * t;\n return { x: at(from.x, to.x), y: at(from.y, to.y), z: at(from.z, to.z), yawDeg: at(from.yawDeg, to.yawDeg), pitchDeg: at(from.pitchDeg, to.pitchDeg) };\n}\n\n/** A camera move: poses at points of its duration (0 to 1), eased between. The last pose is where it comes to rest. */\nexport interface SpatialCameraMove {\n durationMs: number;\n keyframes: ReadonlyArray<{ at: number; pose: SpatialCameraPose }>;\n}\n\n/** A smooth in-out easing: the camera starts and stops without a jolt. */\nexport function easeInOutCubic(t: number): number {\n return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;\n}\n\n/** The camera's pose `elapsedMs` into a move. Past its end, the move's final pose. */\nexport function sampleMove(move: SpatialCameraMove, elapsedMs: number): SpatialCameraPose {\n const frames = move.keyframes;\n const first = frames[0];\n const last = frames[frames.length - 1];\n if (!first || !last) throw new Error('A spatial camera move needs at least one keyframe.');\n const t = move.durationMs <= 0 ? 1 : Math.min(1, Math.max(0, elapsedMs / move.durationMs));\n if (t <= first.at) return first.pose;\n for (let index = 1; index < frames.length; index += 1) {\n const previous = frames[index - 1]!;\n const next = frames[index]!;\n if (t <= next.at) return lerpPose(previous.pose, next.pose, easeInOutCubic((t - previous.at) / Math.max(1e-6, next.at - previous.at)));\n }\n return last.pose;\n}\n\n/** The moves the prototype plays. Each leaves the camera at rest, so the content is always crisp when nothing moves. */\nexport enum SpatialCameraCue {\n /** The shell appears: the camera glides in from far back. */\n ARRIVAL = 'arrival',\n /** The content changed: the camera steps back to take in the space, then returns. */\n NAVIGATION = 'navigation',\n /** Focus moved to a pane beside another: the camera leans toward it, then returns. */\n ZONE_FOCUS = 'zone-focus',\n /** The side column resized: the camera breathes out while the panels re-arrange. */\n COLUMN_RESIZE = 'column-resize',\n}\n\n/**\n * The move for a cue. `towardX` is, for a zone focus, the focused pane's centre in world x (the camera leans toward\n * it); ignored otherwise.\n */\nexport function cameraMoveFor(cue: SpatialCameraCue, distance: number = SPATIAL_CAMERA_DISTANCE_PX, towardX = 0): SpatialCameraMove {\n const rest = restPose(distance);\n switch (cue) {\n case SpatialCameraCue.ARRIVAL:\n return { durationMs: 1700, keyframes: [{ at: 0, pose: { ...rest, y: -140, z: distance + 1400, pitchDeg: 9 } }, { at: 1, pose: rest }] };\n case SpatialCameraCue.NAVIGATION:\n return {\n durationMs: 1200,\n keyframes: [{ at: 0, pose: rest }, { at: 0.42, pose: { ...rest, y: -60, z: distance + 520, pitchDeg: 4 } }, { at: 1, pose: rest }],\n };\n case SpatialCameraCue.ZONE_FOCUS: {\n const lean = Math.sign(towardX);\n return {\n durationMs: 1100,\n keyframes: [{ at: 0, pose: rest }, { at: 0.45, pose: { ...rest, x: towardX * 0.3, z: distance + 220, yawDeg: -lean * 6 } }, { at: 1, pose: rest }],\n };\n }\n case SpatialCameraCue.COLUMN_RESIZE:\n return { durationMs: 900, keyframes: [{ at: 0, pose: rest }, { at: 0.5, pose: { ...rest, z: distance + 260 } }, { at: 1, pose: rest }] };\n default: {\n const unsupported: never = cue;\n throw new Error(`The spatial camera has no move for '${String(unsupported)}'.`);\n }\n }\n}\n\n/** The panels the spatial placement arranges the shell regions into. */\nexport enum SpatialPanelId {\n /** Activity bar, start sidebar, start utility panel: one column standing angled on the start side. */\n START_COLUMN = 'start-column',\n /** Toolbar and content: facing the camera. */\n CENTRE = 'centre',\n /** End sidebar and end utility panel, angled on the end side. */\n END_COLUMN = 'end-column',\n /** Top status bar and menubar, floating above the centre. */\n TOP = 'top',\n /** Bottom status bar, below the centre. */\n BOTTOM = 'bottom',\n}\n\n/** A panel's size (its CSS box, measured untransformed) and where its centre stands in the world. */\nexport interface SpatialPanelPlacement {\n x: number;\n y: number;\n z: number;\n width: number;\n height: number;\n yawDeg: number;\n}\n\nexport interface SpatialLayoutInput {\n viewport: { width: number; height: number };\n /** Natural widths of the side columns (0 when empty). */\n startWidth: number;\n endWidth: number;\n /** Natural heights of the top and bottom strips (0 when empty). */\n topHeight: number;\n bottomHeight: number;\n}\n\n/** Margin around the arrangement and gap between panels, in CSS pixels. */\nexport const SPATIAL_MARGIN_PX = 28;\nexport const SPATIAL_GAP_PX = 18;\n/** How far the side columns turn toward the viewer, like screens beside a desk. */\nexport const SPATIAL_SIDE_ANGLE_DEG = 26;\n\n/**\n * Where each panel stands. The centre keeps the footprint it would have in 2D and faces the camera at z = 0, so at\n * rest it is shown at exactly its CSS size. Each side column is hinged at its inner edge, a gap from the centre, and\n * turned so its outer edge comes toward the viewer. The top strip floats slightly forward, above the centre.\n */\nexport function layoutSpatialPanels(input: SpatialLayoutInput): Record<SpatialPanelId, SpatialPanelPlacement> {\n const { width: W, height: H } = input.viewport;\n const M = SPATIAL_MARGIN_PX;\n const G = SPATIAL_GAP_PX;\n const left = -W / 2 + M + (input.startWidth > 0 ? input.startWidth + G : 0);\n const right = W / 2 - M - (input.endWidth > 0 ? input.endWidth + G : 0);\n const top = -H / 2 + M + (input.topHeight > 0 ? input.topHeight + G : 0);\n const bottom = H / 2 - M - (input.bottomHeight > 0 ? input.bottomHeight + G : 0);\n const centreWidth = Math.max(0, right - left);\n const centreHeight = Math.max(0, bottom - top);\n const columnHeight = H - 2 * M;\n const theta = (SPATIAL_SIDE_ANGLE_DEG * Math.PI) / 180;\n // A column turned by θ about its centre moves its inner edge by (w/2)(1 − cos θ) and w/2·sin θ in depth: place the\n // centre so the inner edge stands exactly on the hinge line, a gap from the centre panel, at depth 0.\n const hinged = (width: number, hingeX: number, side: 1 | -1): SpatialPanelPlacement => ({\n x: hingeX - side * (width / 2) * Math.cos(theta),\n y: 0,\n z: (width / 2) * Math.sin(theta),\n width,\n height: columnHeight,\n yawDeg: side * SPATIAL_SIDE_ANGLE_DEG,\n });\n return {\n [SpatialPanelId.CENTRE]: { x: (left + right) / 2, y: (top + bottom) / 2, z: 0, width: centreWidth, height: centreHeight, yawDeg: 0 },\n [SpatialPanelId.START_COLUMN]: hinged(input.startWidth, left - G, 1),\n [SpatialPanelId.END_COLUMN]: hinged(input.endWidth, right + G, -1),\n [SpatialPanelId.TOP]: { x: (left + right) / 2, y: -H / 2 + M + input.topHeight / 2, z: 24, width: centreWidth, height: input.topHeight, yawDeg: 0 },\n [SpatialPanelId.BOTTOM]: { x: (left + right) / 2, y: H / 2 - M - input.bottomHeight / 2, z: 12, width: centreWidth, height: input.bottomHeight, yawDeg: 0 },\n };\n}\n\n/** The CSS transform standing a panel at its placement: centred on the stage origin, moved, then turned. */\nexport function panelTransform(panel: SpatialPanelPlacement): string {\n return `translate(-50%, -50%) translate3d(${panel.x}px, ${panel.y}px, ${panel.z}px) rotateY(${panel.yawDeg}deg)`;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-environment.d.ts","sourceRoot":"","sources":["../../../../src/spatial/spatial-environment.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmC,MAAM,OAAO,CAAC;AAkBxD,OAAO,KAAK,EAAwB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAmBrF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAQrG"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useLayoutEffect, useMemo } from 'react';
|
|
3
|
-
import { Canvas, useThree } from '@react-three/fiber';
|
|
4
|
-
import { AdditiveBlending, BackSide, CanvasTexture, Color, Group, Mesh, MeshBasicMaterial, PlaneGeometry, ShaderMaterial, SphereGeometry, SRGBColorSpace, } from 'three';
|
|
5
|
-
import { SpatialPanelId } from './spatial-camera.js';
|
|
6
|
-
/**
|
|
7
|
-
* The spatial layout's environment (PROTOTYPE, clean spatial — "visionOS-like"): an airy backdrop that falls to a
|
|
8
|
-
* soft horizon, a pool of light behind the centre panel, and a soft contact shadow under every panel on a floor far
|
|
9
|
-
* below. Drawn through a three.js perspective camera built from the SAME pose as the HTML stage, so the shadows sit
|
|
10
|
-
* exactly under the panels while the camera moves.
|
|
11
|
-
*
|
|
12
|
-
* ## Matching the CSS camera
|
|
13
|
-
*
|
|
14
|
-
* The stage's world has y DOWN (CSS); three.js has y up. A point (x, y, z) of the stage is (x, −y, z) here. The CSS
|
|
15
|
-
* camera rotates by `rotateY(yaw) · rotateX(pitch)`; flipping y leaves the yaw and negates the pitch, so the three.js
|
|
16
|
-
* camera takes Euler (−pitch, yaw, 0) in 'YXZ' order. Its vertical field of view is the one a CSS perspective of
|
|
17
|
-
* `distance` gives a viewport `height` tall: 2·atan(height / 2 / distance).
|
|
18
|
-
*
|
|
19
|
-
* Rendering is on demand: the store notifies on every camera frame and every re-arrangement, and nothing else draws.
|
|
20
|
-
*/
|
|
21
|
-
const NO_POINTER_EVENTS = () => ({ enabled: false, priority: 0 });
|
|
22
|
-
export default function SpatialEnvironment({ store }) {
|
|
23
|
-
return (_jsx("div", { "aria-hidden": "true", "data-spatial-environment": "", className: "absolute inset-0 pointer-events-none", children: _jsx(Canvas, { frameloop: "never", events: NO_POINTER_EVENTS, gl: { antialias: true, alpha: false, powerPreference: 'high-performance' }, camera: { near: 10, far: 40000 }, children: _jsx(SpatialScene, { store: store }) }) }));
|
|
24
|
-
}
|
|
25
|
-
/** Where the floor lies below the stage's centre, in world pixels. */
|
|
26
|
-
const FLOOR_DROP_PX = 260;
|
|
27
|
-
function environmentColours(isDark, primary) {
|
|
28
|
-
const srgb = (hex) => new Color().setStyle(hex, SRGBColorSpace);
|
|
29
|
-
return isDark
|
|
30
|
-
? { zenith: srgb('#0f1219'), horizon: srgb('#1f2433'), ground: srgb('#0b0d13'), glow: primary.clone().multiplyScalar(0.5), shadowOpacity: 0.55 }
|
|
31
|
-
: { zenith: srgb('#dfe6f1'), horizon: srgb('#f8f9fc'), ground: srgb('#e6ebf2'), glow: primary.clone().lerp(new Color(1, 1, 1), 0.55), shadowOpacity: 0.2 };
|
|
32
|
-
}
|
|
33
|
-
/** The theme's `--primary`, whatever CSS colour syntax it uses (oklch included), read through a 2D canvas. */
|
|
34
|
-
function resolveCssColour(value, fallback) {
|
|
35
|
-
const canvas = document.createElement('canvas');
|
|
36
|
-
canvas.width = 1;
|
|
37
|
-
canvas.height = 1;
|
|
38
|
-
const context = canvas.getContext('2d');
|
|
39
|
-
if (!context)
|
|
40
|
-
return new Color().setStyle(fallback, SRGBColorSpace);
|
|
41
|
-
context.fillStyle = fallback;
|
|
42
|
-
context.fillStyle = value || fallback;
|
|
43
|
-
context.fillRect(0, 0, 1, 1);
|
|
44
|
-
const [r, g, b] = context.getImageData(0, 0, 1, 1).data;
|
|
45
|
-
return new Color().setRGB((r ?? 0) / 255, (g ?? 0) / 255, (b ?? 0) / 255, SRGBColorSpace);
|
|
46
|
-
}
|
|
47
|
-
function radialTexture(inner, outer) {
|
|
48
|
-
const size = 256;
|
|
49
|
-
const canvas = document.createElement('canvas');
|
|
50
|
-
canvas.width = size;
|
|
51
|
-
canvas.height = size;
|
|
52
|
-
const context = canvas.getContext('2d');
|
|
53
|
-
const gradient = context.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);
|
|
54
|
-
gradient.addColorStop(0, inner);
|
|
55
|
-
gradient.addColorStop(1, outer);
|
|
56
|
-
context.fillStyle = gradient;
|
|
57
|
-
context.fillRect(0, 0, size, size);
|
|
58
|
-
const texture = new CanvasTexture(canvas);
|
|
59
|
-
texture.colorSpace = SRGBColorSpace;
|
|
60
|
-
return texture;
|
|
61
|
-
}
|
|
62
|
-
/** A soft rounded-rectangle shadow: black, blurred, fading to transparent at its edges. */
|
|
63
|
-
function shadowTexture() {
|
|
64
|
-
const canvas = document.createElement('canvas');
|
|
65
|
-
canvas.width = 256;
|
|
66
|
-
canvas.height = 128;
|
|
67
|
-
const context = canvas.getContext('2d');
|
|
68
|
-
context.filter = 'blur(18px)';
|
|
69
|
-
context.fillStyle = 'rgba(0,0,0,1)';
|
|
70
|
-
context.beginPath();
|
|
71
|
-
context.roundRect(40, 34, 176, 60, 30);
|
|
72
|
-
context.fill();
|
|
73
|
-
return new CanvasTexture(canvas);
|
|
74
|
-
}
|
|
75
|
-
function SpatialScene({ store }) {
|
|
76
|
-
const gl = useThree((state) => state.gl);
|
|
77
|
-
const scene = useThree((state) => state.scene);
|
|
78
|
-
const camera = useThree((state) => state.camera);
|
|
79
|
-
const size = useThree((state) => state.size);
|
|
80
|
-
const world = useMemo(() => {
|
|
81
|
-
const sky = new ShaderMaterial({
|
|
82
|
-
side: BackSide,
|
|
83
|
-
depthWrite: false,
|
|
84
|
-
uniforms: { zenith: { value: new Color() }, horizon: { value: new Color() }, ground: { value: new Color() } },
|
|
85
|
-
vertexShader: 'varying vec3 vDir; void main() { vDir = normalize(position); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }',
|
|
86
|
-
fragmentShader: [
|
|
87
|
-
'uniform vec3 zenith; uniform vec3 horizon; uniform vec3 ground; varying vec3 vDir;',
|
|
88
|
-
'void main() {',
|
|
89
|
-
' float h = vDir.y;',
|
|
90
|
-
' vec3 colour = h > 0.0 ? mix(horizon, zenith, pow(smoothstep(0.0, 0.6, h), 0.8)) : mix(horizon, ground, smoothstep(0.0, 0.25, -h));',
|
|
91
|
-
' gl_FragColor = vec4(colour, 1.0);',
|
|
92
|
-
'}',
|
|
93
|
-
].join('\n'),
|
|
94
|
-
});
|
|
95
|
-
const skyMesh = new Mesh(new SphereGeometry(20000, 48, 24), sky);
|
|
96
|
-
const glow = new MeshBasicMaterial({ map: radialTexture('rgba(255,255,255,0.9)', 'rgba(255,255,255,0)'), transparent: true, depthWrite: false, blending: AdditiveBlending });
|
|
97
|
-
const glowMesh = new Mesh(new PlaneGeometry(1, 1), glow);
|
|
98
|
-
const floorMaterial = new MeshBasicMaterial({ map: radialTexture('rgba(0,0,0,0.10)', 'rgba(0,0,0,0)'), transparent: true, depthWrite: false });
|
|
99
|
-
const floor = new Mesh(new PlaneGeometry(1, 1), floorMaterial);
|
|
100
|
-
floor.rotation.x = -Math.PI / 2;
|
|
101
|
-
const shadowMap = shadowTexture();
|
|
102
|
-
const shadows = new Map();
|
|
103
|
-
for (const id of Object.values(SpatialPanelId)) {
|
|
104
|
-
const mesh = new Mesh(new PlaneGeometry(1, 1), new MeshBasicMaterial({ map: shadowMap, transparent: true, depthWrite: false, color: 0x000000 }));
|
|
105
|
-
mesh.rotation.x = -Math.PI / 2;
|
|
106
|
-
const group = new Group();
|
|
107
|
-
group.add(mesh);
|
|
108
|
-
shadows.set(id, { group, mesh });
|
|
109
|
-
}
|
|
110
|
-
return { sky, skyMesh, glow, glowMesh, floor, shadows };
|
|
111
|
-
}, []);
|
|
112
|
-
useLayoutEffect(() => {
|
|
113
|
-
scene.add(world.skyMesh, world.glowMesh, world.floor);
|
|
114
|
-
for (const { group } of world.shadows.values())
|
|
115
|
-
scene.add(group);
|
|
116
|
-
return () => {
|
|
117
|
-
scene.remove(world.skyMesh, world.glowMesh, world.floor);
|
|
118
|
-
for (const { group } of world.shadows.values())
|
|
119
|
-
scene.remove(group);
|
|
120
|
-
};
|
|
121
|
-
}, [scene, world]);
|
|
122
|
-
useLayoutEffect(() => {
|
|
123
|
-
let colourKey = '';
|
|
124
|
-
const draw = (snapshot) => {
|
|
125
|
-
const { pose, distance, viewport, panels, isDark } = snapshot;
|
|
126
|
-
// Colours follow the mode; re-read the theme's primary only when the mode changes.
|
|
127
|
-
const key = isDark ? 'dark' : 'light';
|
|
128
|
-
if (key !== colourKey) {
|
|
129
|
-
colourKey = key;
|
|
130
|
-
const primary = resolveCssColour(getComputedStyle(document.documentElement).getPropertyValue('--primary').trim(), '#3b82f6');
|
|
131
|
-
const colours = environmentColours(isDark, primary);
|
|
132
|
-
world.sky.uniforms.zenith.value = colours.zenith;
|
|
133
|
-
world.sky.uniforms.horizon.value = colours.horizon;
|
|
134
|
-
world.sky.uniforms.ground.value = colours.ground;
|
|
135
|
-
world.glow.color = colours.glow;
|
|
136
|
-
world.glow.opacity = isDark ? 0.35 : 0.5;
|
|
137
|
-
for (const { mesh } of world.shadows.values())
|
|
138
|
-
mesh.material.opacity = colours.shadowOpacity;
|
|
139
|
-
}
|
|
140
|
-
camera.fov = (2 * Math.atan(viewport.height / 2 / distance) * 180) / Math.PI;
|
|
141
|
-
camera.aspect = viewport.width / viewport.height;
|
|
142
|
-
camera.position.set(pose.x, -pose.y, pose.z);
|
|
143
|
-
camera.rotation.set((-pose.pitchDeg * Math.PI) / 180, (pose.yawDeg * Math.PI) / 180, 0, 'YXZ');
|
|
144
|
-
camera.updateProjectionMatrix();
|
|
145
|
-
const floorY = -(viewport.height / 2 + FLOOR_DROP_PX);
|
|
146
|
-
world.floor.position.set(0, floorY, -200);
|
|
147
|
-
world.floor.scale.set(viewport.width * 3.2, viewport.width * 2.4, 1);
|
|
148
|
-
world.glowMesh.position.set(0, viewport.height * 0.05, -1400);
|
|
149
|
-
world.glowMesh.scale.set(viewport.width * 2.6, viewport.height * 2.2, 1);
|
|
150
|
-
for (const [id, { group, mesh }] of world.shadows) {
|
|
151
|
-
const panel = panels[id];
|
|
152
|
-
group.visible = panel !== undefined && id !== SpatialPanelId.TOP && id !== SpatialPanelId.BOTTOM;
|
|
153
|
-
if (!panel)
|
|
154
|
-
continue;
|
|
155
|
-
group.position.set(panel.x, floorY + 1, panel.z);
|
|
156
|
-
group.rotation.y = (panel.yawDeg * Math.PI) / 180;
|
|
157
|
-
mesh.scale.set(panel.width * 1.25, 320, 1);
|
|
158
|
-
}
|
|
159
|
-
gl.render(scene, camera);
|
|
160
|
-
};
|
|
161
|
-
draw(store.get());
|
|
162
|
-
return store.subscribe(draw);
|
|
163
|
-
}, [gl, scene, camera, store, world, size.width, size.height]);
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
//# sourceMappingURL=spatial-environment.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-environment.js","sourceRoot":"","sources":["../../../../src/spatial/spatial-environment.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useLayoutEffect, useMemo } from 'react';\nimport { Canvas, useThree, type EventManager } from '@react-three/fiber';\nimport {\n AdditiveBlending,\n BackSide,\n CanvasTexture,\n Color,\n Group,\n Mesh,\n MeshBasicMaterial,\n PerspectiveCamera,\n PlaneGeometry,\n ShaderMaterial,\n SphereGeometry,\n SRGBColorSpace,\n} from 'three';\n\nimport { SpatialPanelId, type SpatialPanelPlacement } from './spatial-camera';\nimport type { SpatialStageSnapshot, SpatialStageStore } from './spatial-stage-store';\n\n/**\n * The spatial layout's environment (PROTOTYPE, clean spatial — \"visionOS-like\"): an airy backdrop that falls to a\n * soft horizon, a pool of light behind the centre panel, and a soft contact shadow under every panel on a floor far\n * below. Drawn through a three.js perspective camera built from the SAME pose as the HTML stage, so the shadows sit\n * exactly under the panels while the camera moves.\n *\n * ## Matching the CSS camera\n *\n * The stage's world has y DOWN (CSS); three.js has y up. A point (x, y, z) of the stage is (x, −y, z) here. The CSS\n * camera rotates by `rotateY(yaw) · rotateX(pitch)`; flipping y leaves the yaw and negates the pitch, so the three.js\n * camera takes Euler (−pitch, yaw, 0) in 'YXZ' order. Its vertical field of view is the one a CSS perspective of\n * `distance` gives a viewport `height` tall: 2·atan(height / 2 / distance).\n *\n * Rendering is on demand: the store notifies on every camera frame and every re-arrangement, and nothing else draws.\n */\nconst NO_POINTER_EVENTS = (): EventManager<HTMLElement> => ({ enabled: false, priority: 0 });\n\nexport default function SpatialEnvironment({ store }: { store: SpatialStageStore }): React.JSX.Element {\n return (\n <div aria-hidden=\"true\" data-spatial-environment=\"\" className=\"absolute inset-0 pointer-events-none\">\n <Canvas frameloop=\"never\" events={NO_POINTER_EVENTS} gl={{ antialias: true, alpha: false, powerPreference: 'high-performance' }} camera={{ near: 10, far: 40000 }}>\n <SpatialScene store={store} />\n </Canvas>\n </div>\n );\n}\n\n/** Where the floor lies below the stage's centre, in world pixels. */\nconst FLOOR_DROP_PX = 260;\n\ninterface EnvironmentColours {\n zenith: Color;\n horizon: Color;\n ground: Color;\n glow: Color;\n shadowOpacity: number;\n}\n\nfunction environmentColours(isDark: boolean, primary: Color): EnvironmentColours {\n const srgb = (hex: string): Color => new Color().setStyle(hex, SRGBColorSpace);\n return isDark\n ? { zenith: srgb('#0f1219'), horizon: srgb('#1f2433'), ground: srgb('#0b0d13'), glow: primary.clone().multiplyScalar(0.5), shadowOpacity: 0.55 }\n : { zenith: srgb('#dfe6f1'), horizon: srgb('#f8f9fc'), ground: srgb('#e6ebf2'), glow: primary.clone().lerp(new Color(1, 1, 1), 0.55), shadowOpacity: 0.2 };\n}\n\n/** The theme's `--primary`, whatever CSS colour syntax it uses (oklch included), read through a 2D canvas. */\nfunction resolveCssColour(value: string, fallback: string): Color {\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n const context = canvas.getContext('2d');\n if (!context) return new Color().setStyle(fallback, SRGBColorSpace);\n context.fillStyle = fallback;\n context.fillStyle = value || fallback;\n context.fillRect(0, 0, 1, 1);\n const [r, g, b] = context.getImageData(0, 0, 1, 1).data;\n return new Color().setRGB((r ?? 0) / 255, (g ?? 0) / 255, (b ?? 0) / 255, SRGBColorSpace);\n}\n\nfunction radialTexture(inner: string, outer: string): CanvasTexture {\n const size = 256;\n const canvas = document.createElement('canvas');\n canvas.width = size;\n canvas.height = size;\n const context = canvas.getContext('2d')!;\n const gradient = context.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);\n gradient.addColorStop(0, inner);\n gradient.addColorStop(1, outer);\n context.fillStyle = gradient;\n context.fillRect(0, 0, size, size);\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\n/** A soft rounded-rectangle shadow: black, blurred, fading to transparent at its edges. */\nfunction shadowTexture(): CanvasTexture {\n const canvas = document.createElement('canvas');\n canvas.width = 256;\n canvas.height = 128;\n const context = canvas.getContext('2d')!;\n context.filter = 'blur(18px)';\n context.fillStyle = 'rgba(0,0,0,1)';\n context.beginPath();\n context.roundRect(40, 34, 176, 60, 30);\n context.fill();\n return new CanvasTexture(canvas);\n}\n\nfunction SpatialScene({ store }: { store: SpatialStageStore }): React.JSX.Element | null {\n const gl = useThree((state) => state.gl);\n const scene = useThree((state) => state.scene);\n const camera = useThree((state) => state.camera) as PerspectiveCamera;\n const size = useThree((state) => state.size);\n\n const world = useMemo(() => {\n const sky = new ShaderMaterial({\n side: BackSide,\n depthWrite: false,\n uniforms: { zenith: { value: new Color() }, horizon: { value: new Color() }, ground: { value: new Color() } },\n vertexShader: 'varying vec3 vDir; void main() { vDir = normalize(position); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }',\n fragmentShader: [\n 'uniform vec3 zenith; uniform vec3 horizon; uniform vec3 ground; varying vec3 vDir;',\n 'void main() {',\n ' float h = vDir.y;',\n ' vec3 colour = h > 0.0 ? mix(horizon, zenith, pow(smoothstep(0.0, 0.6, h), 0.8)) : mix(horizon, ground, smoothstep(0.0, 0.25, -h));',\n ' gl_FragColor = vec4(colour, 1.0);',\n '}',\n ].join('\\n'),\n });\n const skyMesh = new Mesh(new SphereGeometry(20000, 48, 24), sky);\n\n const glow = new MeshBasicMaterial({ map: radialTexture('rgba(255,255,255,0.9)', 'rgba(255,255,255,0)'), transparent: true, depthWrite: false, blending: AdditiveBlending });\n const glowMesh = new Mesh(new PlaneGeometry(1, 1), glow);\n\n const floorMaterial = new MeshBasicMaterial({ map: radialTexture('rgba(0,0,0,0.10)', 'rgba(0,0,0,0)'), transparent: true, depthWrite: false });\n const floor = new Mesh(new PlaneGeometry(1, 1), floorMaterial);\n floor.rotation.x = -Math.PI / 2;\n\n const shadowMap = shadowTexture();\n const shadows = new Map<SpatialPanelId, { group: Group; mesh: Mesh<PlaneGeometry, MeshBasicMaterial> }>();\n for (const id of Object.values(SpatialPanelId)) {\n const mesh = new Mesh(new PlaneGeometry(1, 1), new MeshBasicMaterial({ map: shadowMap, transparent: true, depthWrite: false, color: 0x000000 }));\n mesh.rotation.x = -Math.PI / 2;\n const group = new Group();\n group.add(mesh);\n shadows.set(id, { group, mesh });\n }\n return { sky, skyMesh, glow, glowMesh, floor, shadows };\n }, []);\n\n useLayoutEffect(() => {\n scene.add(world.skyMesh, world.glowMesh, world.floor);\n for (const { group } of world.shadows.values()) scene.add(group);\n return () => {\n scene.remove(world.skyMesh, world.glowMesh, world.floor);\n for (const { group } of world.shadows.values()) scene.remove(group);\n };\n }, [scene, world]);\n\n useLayoutEffect(() => {\n let colourKey = '';\n const draw = (snapshot: SpatialStageSnapshot): void => {\n const { pose, distance, viewport, panels, isDark } = snapshot;\n // Colours follow the mode; re-read the theme's primary only when the mode changes.\n const key = isDark ? 'dark' : 'light';\n if (key !== colourKey) {\n colourKey = key;\n const primary = resolveCssColour(getComputedStyle(document.documentElement).getPropertyValue('--primary').trim(), '#3b82f6');\n const colours = environmentColours(isDark, primary);\n world.sky.uniforms.zenith!.value = colours.zenith;\n world.sky.uniforms.horizon!.value = colours.horizon;\n world.sky.uniforms.ground!.value = colours.ground;\n world.glow.color = colours.glow;\n world.glow.opacity = isDark ? 0.35 : 0.5;\n for (const { mesh } of world.shadows.values()) mesh.material.opacity = colours.shadowOpacity;\n }\n camera.fov = (2 * Math.atan(viewport.height / 2 / distance) * 180) / Math.PI;\n camera.aspect = viewport.width / viewport.height;\n camera.position.set(pose.x, -pose.y, pose.z);\n camera.rotation.set((-pose.pitchDeg * Math.PI) / 180, (pose.yawDeg * Math.PI) / 180, 0, 'YXZ');\n camera.updateProjectionMatrix();\n\n const floorY = -(viewport.height / 2 + FLOOR_DROP_PX);\n world.floor.position.set(0, floorY, -200);\n world.floor.scale.set(viewport.width * 3.2, viewport.width * 2.4, 1);\n world.glowMesh.position.set(0, viewport.height * 0.05, -1400);\n world.glowMesh.scale.set(viewport.width * 2.6, viewport.height * 2.2, 1);\n\n for (const [id, { group, mesh }] of world.shadows) {\n const panel: SpatialPanelPlacement | undefined = panels[id];\n group.visible = panel !== undefined && id !== SpatialPanelId.TOP && id !== SpatialPanelId.BOTTOM;\n if (!panel) continue;\n group.position.set(panel.x, floorY + 1, panel.z);\n group.rotation.y = (panel.yawDeg * Math.PI) / 180;\n mesh.scale.set(panel.width * 1.25, 320, 1);\n }\n gl.render(scene, camera);\n };\n draw(store.get());\n return store.subscribe(draw);\n }, [gl, scene, camera, store, world, size.width, size.height]);\n\n return null;\n}\n"]}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { SpatialStageStore } from './spatial-stage-store';
|
|
3
|
-
/**
|
|
4
|
-
* Where the WebGL environment appears. Without WebGL (or while it loads) nothing is drawn: the HTML stage stands on
|
|
5
|
-
* the page background and still works — the panels, their placement in space and the camera are all CSS.
|
|
6
|
-
*/
|
|
7
|
-
export declare const SpatialEnvironmentDoor: React.NamedExoticComponent<{
|
|
8
|
-
store: SpatialStageStore;
|
|
9
|
-
}>;
|
|
10
|
-
//# sourceMappingURL=spatial-environment.lazy.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-environment.lazy.d.ts","sourceRoot":"","sources":["../../../../src/spatial/spatial-environment.lazy.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAI9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAK/D;;;GAGG;AACH,eAAO,MAAM,sBAAsB;WAAkE,iBAAiB;EAQpH,CAAC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React, { Suspense, lazy } from 'react';
|
|
3
|
-
import { LazyDoorErrorBoundary } from '@wildo-ai/saas-frontend-lib';
|
|
4
|
-
/** The spatial environment's WebGL renderer (three.js) loads only when a spatial layout is on screen. */
|
|
5
|
-
const LazySpatialEnvironment = lazy(() => import('./spatial-environment.js'));
|
|
6
|
-
/**
|
|
7
|
-
* Where the WebGL environment appears. Without WebGL (or while it loads) nothing is drawn: the HTML stage stands on
|
|
8
|
-
* the page background and still works — the panels, their placement in space and the camera are all CSS.
|
|
9
|
-
*/
|
|
10
|
-
export const SpatialEnvironmentDoor = React.memo(function SpatialEnvironmentDoor({ store }) {
|
|
11
|
-
return (_jsx(LazyDoorErrorBoundary, { doorName: "presets-components-3d/spatial-environment", fallback: null, children: _jsx(Suspense, { fallback: null, children: _jsx(LazySpatialEnvironment, { store: store }) }) }));
|
|
12
|
-
});
|
|
13
|
-
//# sourceMappingURL=spatial-environment.lazy.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-environment.lazy.js","sourceRoot":"","sources":["../../../../src/spatial/spatial-environment.lazy.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAIpE,yGAAyG;AACzG,MAAM,sBAAsB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,sBAAsB,CAAC,EAAE,KAAK,EAAgC;IACtH,OAAO,CACL,KAAC,qBAAqB,IAAC,QAAQ,EAAC,2CAA2C,EAAC,QAAQ,EAAE,IAAI,YACxF,KAAC,QAAQ,IAAC,QAAQ,EAAE,IAAI,YACtB,KAAC,sBAAsB,IAAC,KAAK,EAAE,KAAK,GAAI,GAC/B,GACW,CACzB,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import React, { Suspense, lazy } from 'react';\n\nimport { LazyDoorErrorBoundary } from '@wildo-ai/saas-frontend-lib';\n\nimport type { SpatialStageStore } from './spatial-stage-store';\n\n/** The spatial environment's WebGL renderer (three.js) loads only when a spatial layout is on screen. */\nconst LazySpatialEnvironment = lazy(() => import('./spatial-environment'));\n\n/**\n * Where the WebGL environment appears. Without WebGL (or while it loads) nothing is drawn: the HTML stage stands on\n * the page background and still works — the panels, their placement in space and the camera are all CSS.\n */\nexport const SpatialEnvironmentDoor = React.memo(function SpatialEnvironmentDoor({ store }: { store: SpatialStageStore }): React.JSX.Element {\n return (\n <LazyDoorErrorBoundary doorName=\"presets-components-3d/spatial-environment\" fallback={null}>\n <Suspense fallback={null}>\n <LazySpatialEnvironment store={store} />\n </Suspense>\n </LazyDoorErrorBoundary>\n );\n});\n"]}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { type AppLayoutPreset_MainContainer_DefaultProps } from '@wildo-ai/saas-frontend-lib';
|
|
3
|
-
/**
|
|
4
|
-
* The spatial layout's placement (PROTOTYPE, Paul 2026-09-30: "something futurist, with a real camera aspect and
|
|
5
|
-
* transitions" — clean spatial, side panels angled, content frontal).
|
|
6
|
-
*
|
|
7
|
-
* The regions are the application's own, rendered by the standard outlets with every context; this container only
|
|
8
|
-
* groups them into five glass panels and stands those panels in a CSS 3D stage:
|
|
9
|
-
*
|
|
10
|
-
* - a perspective root the size of the viewport;
|
|
11
|
-
* - a CAMERA element at its centre, `preserve-3d`, whose transform is the inverse of the camera pose;
|
|
12
|
-
* - the panels, each centred on that element and moved/turned to its place (`layoutSpatialPanels`).
|
|
13
|
-
*
|
|
14
|
-
* At rest the camera faces the centre panel from exactly the perspective distance, so the content is drawn at its CSS
|
|
15
|
-
* size — crisp. The camera moves on the shell's transitions and always returns to rest.
|
|
16
|
-
*
|
|
17
|
-
* Overlays render in `AppShellOverlayPortalLayer`, OUTSIDE the stage: a dialog inside a transformed panel would be
|
|
18
|
-
* confined to it, and a menu would be placed in the wrong coordinates.
|
|
19
|
-
*/
|
|
20
|
-
export declare function SpatialShellContainer({ children }: AppLayoutPreset_MainContainer_DefaultProps): React.JSX.Element;
|
|
21
|
-
//# sourceMappingURL=spatial-shell-container.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-shell-container.d.ts","sourceRoot":"","sources":["../../../../src/spatial/spatial-shell-container.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgE,MAAM,OAAO,CAAC;AAGrF,OAAO,EAaL,KAAK,0CAA0C,EAChD,MAAM,6BAA6B,CAAC;AAkBrC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,EAAE,0CAA0C,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CASjH"}
|