@chuzi/shared 1.3.34 → 1.3.36
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/appearance-DFP3Ymge.d.ts +31 -0
- package/dist/index.d.ts +24 -1
- package/dist/index.js +53 -1
- package/dist/index.js.map +1 -1
- package/dist/realms/cosmos/components/index.d.ts +49 -14
- package/dist/realms/cosmos/components/index.js +212 -85
- package/dist/realms/cosmos/components/index.js.map +1 -1
- package/dist/realms/cosmos/index.d.ts +2 -0
- package/dist/realms/cosmos/index.js +24 -1
- package/dist/realms/cosmos/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { AtomVisualProps } from '../../index.js';
|
|
4
|
+
import { C as ConstellationAppearance } from '../../../appearance-DFP3Ymge.js';
|
|
5
|
+
export { D as DEFAULT_CONSTELLATION_APPEARANCE, m as mergeConstellationAppearance } from '../../../appearance-DFP3Ymge.js';
|
|
4
6
|
import { StoryListItem } from '../../../types/index.js';
|
|
5
7
|
|
|
6
8
|
interface WorldProps {
|
|
@@ -37,10 +39,18 @@ interface ConstellationSceneEntry {
|
|
|
37
39
|
id: string;
|
|
38
40
|
/** Visual with final position already computed by the consumer. */
|
|
39
41
|
visual: AtomVisualProps;
|
|
42
|
+
/** Scene label shown beneath the preview card. */
|
|
43
|
+
label?: string;
|
|
44
|
+
/** Static preview image (coverbox, poster frame, etc.). */
|
|
45
|
+
previewImageUrl?: string | null;
|
|
46
|
+
/** Custom preview when no image URL is available. */
|
|
47
|
+
previewContent?: ReactNode;
|
|
40
48
|
/** When true the star renders at reduced brightness/saturation. */
|
|
41
49
|
dimmed?: boolean;
|
|
42
50
|
/** When true the star is non-navigable (click suppressed). */
|
|
43
51
|
locked?: boolean;
|
|
52
|
+
/** Highlight this star's billboard (focused traversal). */
|
|
53
|
+
focused?: boolean;
|
|
44
54
|
}
|
|
45
55
|
interface ConstellationEdgeEntry {
|
|
46
56
|
source: string;
|
|
@@ -48,24 +58,21 @@ interface ConstellationEdgeEntry {
|
|
|
48
58
|
type: "choice" | "go_to_scene" | "sequential";
|
|
49
59
|
}
|
|
50
60
|
interface ConstellationProps {
|
|
51
|
-
/** Scene entries
|
|
61
|
+
/** Scene entries with positions already computed by the consumer. */
|
|
52
62
|
scenes: ConstellationSceneEntry[];
|
|
53
|
-
/**
|
|
63
|
+
/** Film title rendered as ghost typography across the group. */
|
|
64
|
+
storyTitle?: string;
|
|
65
|
+
/** Explicit story-flow edges (goto + choice). No implicit sequential links. */
|
|
54
66
|
edges?: ConstellationEdgeEntry[];
|
|
67
|
+
appearance?: Partial<ConstellationAppearance>;
|
|
55
68
|
onSceneSelect?: (index: number) => void;
|
|
56
69
|
}
|
|
57
70
|
/**
|
|
58
71
|
* A single story rendered as a constellation: scene-stars connected by
|
|
59
72
|
* luminous gradient edges. This is the cosmos realm's `Group` component —
|
|
60
73
|
* identical rendering for own and others' stories.
|
|
61
|
-
*
|
|
62
|
-
* The consumer provides scenes with positions already computed so that
|
|
63
|
-
* overlay logic (camera targeting, focus rings) can use the same positions.
|
|
64
|
-
*
|
|
65
|
-
* When `edges` is provided, the component renders from the explicit graph
|
|
66
|
-
* (supporting Y-forks for choices) instead of sequential order.
|
|
67
74
|
*/
|
|
68
|
-
declare function Constellation({ scenes, edges, onSceneSelect, }: ConstellationProps): react_jsx_runtime.JSX.Element;
|
|
75
|
+
declare function Constellation({ scenes, storyTitle, edges, appearance: appearanceOverrides, onSceneSelect, }: ConstellationProps): react_jsx_runtime.JSX.Element;
|
|
69
76
|
|
|
70
77
|
type ConstellationEdgeVariant = "solid" | "dotted";
|
|
71
78
|
interface ConstellationEdgeProps {
|
|
@@ -79,17 +86,15 @@ interface ConstellationEdgeProps {
|
|
|
79
86
|
intensityB?: number;
|
|
80
87
|
/** Reduce opacity to indicate an unwatched connection. */
|
|
81
88
|
dimmed?: boolean;
|
|
82
|
-
/**
|
|
89
|
+
/** @deprecated All edges render as soft solid glow; variant is ignored. */
|
|
83
90
|
variant?: ConstellationEdgeVariant;
|
|
84
91
|
}
|
|
85
92
|
/**
|
|
86
93
|
* A luminous line connecting two stars in a constellation. Endpoints are
|
|
87
94
|
* pulled inward so the line floats between the stars rather than touching
|
|
88
95
|
* them. Color interpolates from hueA to hueB via vertex colors.
|
|
89
|
-
*
|
|
90
|
-
* Goto paths render as animated dotted lines; choice paths render solid.
|
|
91
96
|
*/
|
|
92
|
-
declare function ConstellationEdge({ from, to, hueA, hueB, gap, intensityA, intensityB, dimmed,
|
|
97
|
+
declare function ConstellationEdge({ from, to, hueA, hueB, gap, intensityA, intensityB, dimmed, }: ConstellationEdgeProps): react_jsx_runtime.JSX.Element | null;
|
|
93
98
|
|
|
94
99
|
interface CosmosSandboxProps {
|
|
95
100
|
films: StoryListItem[];
|
|
@@ -127,4 +132,34 @@ interface DistributeOptions {
|
|
|
127
132
|
*/
|
|
128
133
|
declare function distributeStars(count: number, options?: DistributeOptions): Vec3[];
|
|
129
134
|
|
|
130
|
-
|
|
135
|
+
interface ConstellationBounds {
|
|
136
|
+
center: [number, number, number];
|
|
137
|
+
spanX: number;
|
|
138
|
+
spanZ: number;
|
|
139
|
+
}
|
|
140
|
+
declare function computeConstellationBounds(positions: [number, number, number][]): ConstellationBounds | null;
|
|
141
|
+
interface ConstellationTitleProps {
|
|
142
|
+
title: string;
|
|
143
|
+
bounds: ConstellationBounds;
|
|
144
|
+
appearance: ConstellationAppearance;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Large ghostly film title draped across the constellation footprint.
|
|
148
|
+
*/
|
|
149
|
+
declare function ConstellationTitle({ title, bounds, appearance, }: ConstellationTitleProps): react_jsx_runtime.JSX.Element | null;
|
|
150
|
+
|
|
151
|
+
interface StarBillboardProps {
|
|
152
|
+
label: string;
|
|
153
|
+
appearance: ConstellationAppearance;
|
|
154
|
+
previewImageUrl?: string | null;
|
|
155
|
+
previewContent?: ReactNode;
|
|
156
|
+
dimmed?: boolean;
|
|
157
|
+
focused?: boolean;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Floating preview card and scene label above a star. Label sits beneath
|
|
161
|
+
* the preview image, offset from the star sphere.
|
|
162
|
+
*/
|
|
163
|
+
declare function StarBillboard({ label, appearance, previewImageUrl, previewContent, dimmed, focused, }: StarBillboardProps): react_jsx_runtime.JSX.Element;
|
|
164
|
+
|
|
165
|
+
export { Constellation, ConstellationAppearance, type ConstellationBounds, ConstellationEdge, type ConstellationEdgeEntry, type ConstellationEdgeProps, type ConstellationProps, type ConstellationSceneEntry, ConstellationTitle, type ConstellationTitleProps, CosmosSandbox, type CosmosSandboxProps, type DistributeOptions, Star, StarBillboard, type StarBillboardProps, type StarProps, type Vec3, World, type WorldProps, computeConstellationBounds, distributeStars };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Canvas, useFrame } from '@react-three/fiber';
|
|
2
|
-
import { Stars, OrbitControls, Line } from '@react-three/drei';
|
|
2
|
+
import { Stars, OrbitControls, Line, Text, Html } from '@react-three/drei';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
4
|
import { useRef, useMemo } from 'react';
|
|
5
5
|
import * as THREE from 'three';
|
|
@@ -73,34 +73,28 @@ function Star({ visual, onSelect, dimmed, locked }) {
|
|
|
73
73
|
}
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
toneMapped: false,
|
|
99
|
-
dashed: true,
|
|
100
|
-
dashSize: 0.35,
|
|
101
|
-
gapSize: 0.3
|
|
102
|
-
}
|
|
103
|
-
);
|
|
76
|
+
|
|
77
|
+
// src/realms/cosmos/appearance.ts
|
|
78
|
+
var DEFAULT_CONSTELLATION_APPEARANCE = {
|
|
79
|
+
titleFontSize: 2.8,
|
|
80
|
+
titleOpacity: 0.14,
|
|
81
|
+
titleColor: "#e8f0ff",
|
|
82
|
+
titleLetterSpacing: 0.35,
|
|
83
|
+
titleYOffset: 1.2,
|
|
84
|
+
previewWidth: 148,
|
|
85
|
+
previewHeight: 96,
|
|
86
|
+
previewOffsetY: 2.4,
|
|
87
|
+
labelFontSize: 13,
|
|
88
|
+
labelLetterSpacing: 1.2,
|
|
89
|
+
labelGap: 14,
|
|
90
|
+
billboardDistanceFactor: 10,
|
|
91
|
+
cameraDefaultOffset: [0, 4, 12],
|
|
92
|
+
cameraTargetOffset: [0, 0, 0],
|
|
93
|
+
cameraSlideLerp: 0.035,
|
|
94
|
+
cameraArrivalThreshold: 0.08
|
|
95
|
+
};
|
|
96
|
+
function mergeConstellationAppearance(overrides) {
|
|
97
|
+
return { ...DEFAULT_CONSTELLATION_APPEARANCE, ...overrides };
|
|
104
98
|
}
|
|
105
99
|
function ConstellationEdge({
|
|
106
100
|
from,
|
|
@@ -110,8 +104,7 @@ function ConstellationEdge({
|
|
|
110
104
|
gap = 0.55,
|
|
111
105
|
intensityA = 0.5,
|
|
112
106
|
intensityB = 0.5,
|
|
113
|
-
dimmed
|
|
114
|
-
variant = "solid"
|
|
107
|
+
dimmed
|
|
115
108
|
}) {
|
|
116
109
|
const { points, colorA, colorB, glowA, glowB } = useMemo(() => {
|
|
117
110
|
const a = new THREE.Vector3(...from);
|
|
@@ -139,31 +132,8 @@ function ConstellationEdge({
|
|
|
139
132
|
};
|
|
140
133
|
}, [from, to, hueA, hueB, gap, intensityA, intensityB]);
|
|
141
134
|
if (!points || !colorA || !colorB || !glowA || !glowB) return null;
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
const coreOpacity = dimmed ? 0.15 : isDotted ? 0.45 : 0.6;
|
|
145
|
-
if (isDotted) {
|
|
146
|
-
return /* @__PURE__ */ jsxs("group", { children: [
|
|
147
|
-
/* @__PURE__ */ jsx(
|
|
148
|
-
AnimatedDashedLine,
|
|
149
|
-
{
|
|
150
|
-
points,
|
|
151
|
-
vertexColors: [glowA, glowB],
|
|
152
|
-
lineWidth: 4,
|
|
153
|
-
opacity: glowOpacity
|
|
154
|
-
}
|
|
155
|
-
),
|
|
156
|
-
/* @__PURE__ */ jsx(
|
|
157
|
-
AnimatedDashedLine,
|
|
158
|
-
{
|
|
159
|
-
points,
|
|
160
|
-
vertexColors: [colorA, colorB],
|
|
161
|
-
lineWidth: 1.5,
|
|
162
|
-
opacity: coreOpacity
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
] });
|
|
166
|
-
}
|
|
135
|
+
const glowOpacity = dimmed ? 0.04 : 0.12;
|
|
136
|
+
const coreOpacity = dimmed ? 0.15 : 0.6;
|
|
167
137
|
return /* @__PURE__ */ jsxs("group", { children: [
|
|
168
138
|
/* @__PURE__ */ jsx(
|
|
169
139
|
Line,
|
|
@@ -189,44 +159,202 @@ function ConstellationEdge({
|
|
|
189
159
|
)
|
|
190
160
|
] });
|
|
191
161
|
}
|
|
162
|
+
function computeConstellationBounds(positions) {
|
|
163
|
+
if (positions.length === 0) return null;
|
|
164
|
+
let minX = Infinity;
|
|
165
|
+
let maxX = -Infinity;
|
|
166
|
+
let minZ = Infinity;
|
|
167
|
+
let maxZ = -Infinity;
|
|
168
|
+
let sumY = 0;
|
|
169
|
+
for (const [x, y, z] of positions) {
|
|
170
|
+
minX = Math.min(minX, x);
|
|
171
|
+
maxX = Math.max(maxX, x);
|
|
172
|
+
minZ = Math.min(minZ, z);
|
|
173
|
+
maxZ = Math.max(maxZ, z);
|
|
174
|
+
sumY += y;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
center: [(minX + maxX) / 2, sumY / positions.length, (minZ + maxZ) / 2],
|
|
178
|
+
spanX: Math.max(6, maxX - minX + 4),
|
|
179
|
+
spanZ: Math.max(4, maxZ - minZ + 3)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function ConstellationTitle({
|
|
183
|
+
title,
|
|
184
|
+
bounds,
|
|
185
|
+
appearance
|
|
186
|
+
}) {
|
|
187
|
+
if (!title.trim()) return null;
|
|
188
|
+
return /* @__PURE__ */ jsx(
|
|
189
|
+
Text,
|
|
190
|
+
{
|
|
191
|
+
position: [
|
|
192
|
+
bounds.center[0],
|
|
193
|
+
bounds.center[1] + appearance.titleYOffset,
|
|
194
|
+
bounds.center[2]
|
|
195
|
+
],
|
|
196
|
+
rotation: [-Math.PI / 2, 0, 0],
|
|
197
|
+
fontSize: appearance.titleFontSize,
|
|
198
|
+
color: appearance.titleColor,
|
|
199
|
+
fillOpacity: appearance.titleOpacity,
|
|
200
|
+
anchorX: "center",
|
|
201
|
+
anchorY: "middle",
|
|
202
|
+
maxWidth: Math.max(bounds.spanX, bounds.spanZ) * 1.35,
|
|
203
|
+
letterSpacing: appearance.titleLetterSpacing,
|
|
204
|
+
textAlign: "center",
|
|
205
|
+
children: title.toUpperCase()
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
function StarBillboard({
|
|
210
|
+
label,
|
|
211
|
+
appearance,
|
|
212
|
+
previewImageUrl,
|
|
213
|
+
previewContent,
|
|
214
|
+
dimmed,
|
|
215
|
+
focused
|
|
216
|
+
}) {
|
|
217
|
+
const borderColor = focused ? "rgba(126,184,255,0.65)" : "rgba(126,184,255,0.28)";
|
|
218
|
+
const opacity = dimmed ? 0.45 : focused ? 1 : 0.88;
|
|
219
|
+
return /* @__PURE__ */ jsx(
|
|
220
|
+
Html,
|
|
221
|
+
{
|
|
222
|
+
position: [0, appearance.previewOffsetY, 0],
|
|
223
|
+
center: true,
|
|
224
|
+
distanceFactor: appearance.billboardDistanceFactor,
|
|
225
|
+
style: {
|
|
226
|
+
pointerEvents: "none",
|
|
227
|
+
userSelect: "none",
|
|
228
|
+
opacity,
|
|
229
|
+
transition: "opacity 0.35s ease"
|
|
230
|
+
},
|
|
231
|
+
children: /* @__PURE__ */ jsxs(
|
|
232
|
+
"div",
|
|
233
|
+
{
|
|
234
|
+
style: {
|
|
235
|
+
display: "flex",
|
|
236
|
+
flexDirection: "column",
|
|
237
|
+
alignItems: "center",
|
|
238
|
+
gap: appearance.labelGap
|
|
239
|
+
},
|
|
240
|
+
children: [
|
|
241
|
+
/* @__PURE__ */ jsx(
|
|
242
|
+
"div",
|
|
243
|
+
{
|
|
244
|
+
style: {
|
|
245
|
+
width: appearance.previewWidth,
|
|
246
|
+
height: appearance.previewHeight,
|
|
247
|
+
borderRadius: 8,
|
|
248
|
+
overflow: "hidden",
|
|
249
|
+
border: `1px solid ${borderColor}`,
|
|
250
|
+
background: "rgba(4,7,13,0.92)",
|
|
251
|
+
boxShadow: focused ? "0 0 24px rgba(126,184,255,0.35)" : "0 4px 20px rgba(0,0,0,0.55)",
|
|
252
|
+
display: "flex",
|
|
253
|
+
alignItems: "center",
|
|
254
|
+
justifyContent: "center"
|
|
255
|
+
},
|
|
256
|
+
children: previewImageUrl ? /* @__PURE__ */ jsx(
|
|
257
|
+
"img",
|
|
258
|
+
{
|
|
259
|
+
src: previewImageUrl,
|
|
260
|
+
alt: "",
|
|
261
|
+
style: {
|
|
262
|
+
width: "100%",
|
|
263
|
+
height: "100%",
|
|
264
|
+
objectFit: "cover",
|
|
265
|
+
display: "block"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
) : previewContent ?? /* @__PURE__ */ jsx(
|
|
269
|
+
"div",
|
|
270
|
+
{
|
|
271
|
+
style: {
|
|
272
|
+
width: "100%",
|
|
273
|
+
height: "100%",
|
|
274
|
+
background: "radial-gradient(ellipse at 30% 20%, rgba(80,120,200,0.2) 0%, rgba(10,14,30,0.95) 70%)"
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
),
|
|
280
|
+
/* @__PURE__ */ jsx(
|
|
281
|
+
"div",
|
|
282
|
+
{
|
|
283
|
+
style: {
|
|
284
|
+
fontSize: appearance.labelFontSize,
|
|
285
|
+
fontWeight: 700,
|
|
286
|
+
letterSpacing: appearance.labelLetterSpacing,
|
|
287
|
+
textTransform: "uppercase",
|
|
288
|
+
color: focused ? "rgba(232,240,255,0.95)" : "rgba(232,240,255,0.72)",
|
|
289
|
+
textAlign: "center",
|
|
290
|
+
textShadow: "0 2px 12px rgba(0,0,0,0.95)",
|
|
291
|
+
whiteSpace: "nowrap",
|
|
292
|
+
maxWidth: appearance.previewWidth + 40,
|
|
293
|
+
overflow: "hidden",
|
|
294
|
+
textOverflow: "ellipsis"
|
|
295
|
+
},
|
|
296
|
+
children: label
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
192
305
|
function Constellation({
|
|
193
306
|
scenes,
|
|
194
|
-
|
|
307
|
+
storyTitle,
|
|
308
|
+
edges = [],
|
|
309
|
+
appearance: appearanceOverrides,
|
|
195
310
|
onSceneSelect
|
|
196
311
|
}) {
|
|
312
|
+
const appearance = mergeConstellationAppearance(appearanceOverrides);
|
|
197
313
|
const sceneMap = new Map(scenes.map((s, i) => [s.id, { entry: s, index: i }]));
|
|
314
|
+
const bounds = computeConstellationBounds(
|
|
315
|
+
scenes.map((s) => s.visual.position)
|
|
316
|
+
);
|
|
198
317
|
const resolvedEdges = [];
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
resolvedEdges.push({ from: src.entry, to: tgt.entry, type: edge.type });
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
for (let i = 1; i < scenes.length; i++) {
|
|
209
|
-
resolvedEdges.push({
|
|
210
|
-
from: scenes[i - 1],
|
|
211
|
-
to: scenes[i],
|
|
212
|
-
type: "sequential"
|
|
213
|
-
});
|
|
318
|
+
for (const edge of edges) {
|
|
319
|
+
const src = sceneMap.get(edge.source);
|
|
320
|
+
const tgt = sceneMap.get(edge.target);
|
|
321
|
+
if (src && tgt) {
|
|
322
|
+
resolvedEdges.push({ from: src.entry, to: tgt.entry, type: edge.type });
|
|
214
323
|
}
|
|
215
324
|
}
|
|
216
325
|
return /* @__PURE__ */ jsxs("group", { children: [
|
|
217
|
-
|
|
218
|
-
|
|
326
|
+
storyTitle && bounds ? /* @__PURE__ */ jsx(
|
|
327
|
+
ConstellationTitle,
|
|
219
328
|
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
329
|
+
title: storyTitle,
|
|
330
|
+
bounds,
|
|
331
|
+
appearance
|
|
332
|
+
}
|
|
333
|
+
) : null,
|
|
334
|
+
scenes.map((entry, i) => /* @__PURE__ */ jsxs("group", { position: entry.visual.position, children: [
|
|
335
|
+
/* @__PURE__ */ jsx(
|
|
336
|
+
Star,
|
|
337
|
+
{
|
|
338
|
+
visual: { ...entry.visual, position: [0, 0, 0] },
|
|
339
|
+
dimmed: entry.dimmed,
|
|
340
|
+
locked: entry.locked,
|
|
341
|
+
onSelect: onSceneSelect ? () => onSceneSelect(i) : void 0
|
|
342
|
+
}
|
|
343
|
+
),
|
|
344
|
+
entry.label || entry.previewImageUrl || entry.previewContent ? /* @__PURE__ */ jsx(
|
|
345
|
+
StarBillboard,
|
|
346
|
+
{
|
|
347
|
+
label: entry.label ?? "",
|
|
348
|
+
appearance,
|
|
349
|
+
previewImageUrl: entry.previewImageUrl,
|
|
350
|
+
previewContent: entry.previewContent,
|
|
351
|
+
dimmed: entry.dimmed,
|
|
352
|
+
focused: entry.focused
|
|
353
|
+
}
|
|
354
|
+
) : null
|
|
355
|
+
] }, entry.id)),
|
|
227
356
|
resolvedEdges.map(({ from, to, type }) => {
|
|
228
357
|
const edgeDimmed = !!(from.dimmed || to.dimmed);
|
|
229
|
-
const variant = type === "go_to_scene" ? "dotted" : "solid";
|
|
230
358
|
return /* @__PURE__ */ jsx(
|
|
231
359
|
ConstellationEdge,
|
|
232
360
|
{
|
|
@@ -236,8 +364,7 @@ function Constellation({
|
|
|
236
364
|
hueB: to.visual.hue,
|
|
237
365
|
intensityA: from.visual.intensity,
|
|
238
366
|
intensityB: to.visual.intensity,
|
|
239
|
-
dimmed: edgeDimmed
|
|
240
|
-
variant
|
|
367
|
+
dimmed: edgeDimmed
|
|
241
368
|
},
|
|
242
369
|
`edge-${from.id}-${to.id}-${type}`
|
|
243
370
|
);
|
|
@@ -349,6 +476,6 @@ function CosmosSandbox({
|
|
|
349
476
|
)) });
|
|
350
477
|
}
|
|
351
478
|
|
|
352
|
-
export { Constellation, ConstellationEdge, CosmosSandbox, Star, World, distributeStars };
|
|
479
|
+
export { Constellation, ConstellationEdge, ConstellationTitle, CosmosSandbox, DEFAULT_CONSTELLATION_APPEARANCE, Star, StarBillboard, World, computeConstellationBounds, distributeStars, mergeConstellationAppearance };
|
|
353
480
|
//# sourceMappingURL=index.js.map
|
|
354
481
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/themes/index.ts","../../../../src/realms/cosmos/components/World.tsx","../../../../src/realms/cosmos/components/Star.tsx","../../../../src/realms/cosmos/components/ConstellationEdge.tsx","../../../../src/realms/cosmos/components/Constellation.tsx","../../../../src/realms/cosmos/index.ts","../../../../src/realms/cosmos/components/layout.ts","../../../../src/realms/cosmos/components/CosmosSandbox.tsx"],"names":["DreiStars","jsxs","jsx","useRef","useFrame","useMemo"],"mappings":"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","file":"index.js","sourcesContent":["import type { RealmId } from \"../types/index.js\";\n\n/**\n * CSS custom property tokens, mirroring public/css/chuzi-realms.css.\n * Use these for any non-DOM rendering (e.g. React Native, canvas).\n */\nexport interface RealmThemeTokens {\n bgDeep: string;\n bgMid: string;\n accent: string;\n accentSoft: string;\n text: string;\n muted: string;\n effectLine: string;\n}\n\nexport const THEME_TOKENS: Record<RealmId, RealmThemeTokens> = {\n cosmos: {\n bgDeep: \"#04070d\",\n bgMid: \"#0a1020\",\n accent: \"#7eb8ff\",\n accentSoft: \"rgba(126, 184, 255, 0.35)\",\n text: \"#e8f0ff\",\n muted: \"rgba(232, 240, 255, 0.65)\",\n effectLine: \"#ffb347\",\n },\n wilds: {\n bgDeep: \"#0d120c\",\n bgMid: \"#152018\",\n accent: \"#7bc96f\",\n accentSoft: \"rgba(123, 201, 111, 0.35)\",\n text: \"#eef6ea\",\n muted: \"rgba(238, 246, 234, 0.7)\",\n effectLine: \"#b78aff\",\n },\n};\n\n/**\n * Scene tree visualization theme, mirroring the THEMES object in\n * resources/js/scene-tree-viewer.js.\n */\nexport interface SceneTreeTheme {\n bg: string;\n edgeChoice: string;\n edgeGoto: string;\n nodeDefault: string;\n nodeActive: string;\n borderDefault: string;\n borderActive: string;\n labelDefault: string;\n labelActive: string;\n nodeLockedFill: string;\n nodeLockedBorder: string;\n labelLocked: string;\n nodeShape: \"star\" | \"rect\";\n rectRx: number;\n}\n\nexport const SCENE_TREE_THEMES: Record<RealmId, SceneTreeTheme> = {\n cosmos: {\n bg: \"#020408\",\n edgeChoice: \"#e8f0ff\",\n edgeGoto: \"#4a9fff\",\n nodeDefault: \"#ffffff\",\n nodeActive: \"#ffd47e\",\n borderDefault: \"#3a5080\",\n borderActive: \"#fff6d0\",\n labelDefault: \"rgba(220, 232, 255, 0.92)\",\n labelActive: \"rgba(255, 246, 220, 0.98)\",\n nodeLockedFill: \"#151a28\",\n nodeLockedBorder: \"#2a3348\",\n labelLocked: \"rgba(200, 210, 230, 0.35)\",\n nodeShape: \"star\",\n rectRx: 2,\n },\n wilds: {\n bg: \"#04070d\",\n edgeChoice: \"#ffffff\",\n edgeGoto: \"#6ecf7a\",\n nodeDefault: \"#e8f5e4\",\n nodeActive: \"#d31e2f\",\n borderDefault: \"#2d4a32\",\n borderActive: \"#ff9ea8\",\n labelDefault: \"rgba(232, 245, 228, 0.92)\",\n labelActive: \"rgba(255, 214, 219, 0.98)\",\n nodeLockedFill: \"#1a221c\",\n nodeLockedBorder: \"#2a3d30\",\n labelLocked: \"rgba(200, 220, 200, 0.38)\",\n nodeShape: \"rect\",\n rectRx: 3,\n },\n};\n\n/**\n * Get theme tokens for a realm, defaulting to wilds.\n */\nexport function getThemeTokens(realmId: RealmId | null | undefined): RealmThemeTokens {\n return THEME_TOKENS[realmId ?? \"wilds\"] ?? THEME_TOKENS.wilds;\n}\n\n/**\n * Get scene tree theme for a realm, defaulting to wilds.\n */\nexport function getSceneTreeTheme(realmId: RealmId | null | undefined): SceneTreeTheme {\n return SCENE_TREE_THEMES[realmId ?? \"wilds\"] ?? SCENE_TREE_THEMES.wilds;\n}\n","import { Canvas } from \"@react-three/fiber\";\nimport { OrbitControls, Stars as DreiStars } from \"@react-three/drei\";\nimport type { ReactNode } from \"react\";\nimport { THEME_TOKENS } from \"../../../themes/index.js\";\n\nexport interface WorldProps {\n children: ReactNode;\n /** Pixel device ratio cap. Default 2 — keeps perf bounded on retina laptops. */\n dpr?: number | [number, number];\n}\n\n/**\n * Cosmos environment shell. Wraps an r3f Canvas with deep-space background,\n * ambient starfield (drei <Stars> for the *backdrop* — distinct from our\n * film-stars), and a placeholder OrbitControls camera. The real NavRig\n * (consuming an IntentSource and doing focus-snap on dpad) replaces\n * OrbitControls in a follow-up package.\n */\nexport function World({ children, dpr = [1, 2] }: WorldProps) {\n return (\n <Canvas\n camera={{ position: [0, 6, 32], fov: 60, near: 0.1, far: 500 }}\n dpr={dpr}\n gl={{ antialias: true }}\n >\n <color attach=\"background\" args={[THEME_TOKENS.cosmos.bgDeep]} />\n <ambientLight intensity={0.15} />\n <DreiStars\n radius={120}\n depth={60}\n count={3000}\n factor={4}\n fade\n saturation={0.4}\n />\n <OrbitControls enablePan={false} maxDistance={80} minDistance={4} />\n {children}\n </Canvas>\n );\n}\n","import { useRef } from \"react\";\nimport { useFrame } from \"@react-three/fiber\";\nimport type { Mesh } from \"three\";\nimport type { AtomVisualProps } from \"../../index.js\";\n\nexport interface StarProps {\n visual: AtomVisualProps;\n onSelect?: () => void;\n /** Reduce brightness and saturation to indicate an unwatched scene. */\n dimmed?: boolean;\n /** Non-navigable — suppresses click and lowers brightness further. */\n locked?: boolean;\n}\n\n/**\n * One film as a star. Color is HSL-derived from the realm mapping's hue +\n * intensity. Each star pulses on its own phase so a thousand of them don't\n * breathe in lockstep — gives the field life without per-star animation\n * state.\n */\nexport function Star({ visual, onSelect, dimmed, locked }: StarProps) {\n const ref = useRef<Mesh>(null);\n\n useFrame(({ clock }) => {\n if (!ref.current) return;\n const phase = visual.position[0] * 0.7 + visual.position[2] * 0.3;\n const pulse = 1 + Math.sin(clock.elapsedTime * 0.8 + phase) * 0.05;\n ref.current.scale.setScalar(visual.scale * pulse);\n });\n\n const saturation = dimmed || locked ? 25 : 75;\n const lightness = dimmed || locked\n ? 25 + visual.intensity * 10\n : 50 + visual.intensity * 25;\n const color = `hsl(${visual.hue}, ${saturation}%, ${lightness}%)`;\n\n const handleClick = locked\n ? undefined\n : onSelect\n ? (e: any) => {\n e.stopPropagation();\n onSelect();\n }\n : undefined;\n\n return (\n <mesh\n ref={ref}\n position={visual.position}\n onClick={handleClick}\n >\n <sphereGeometry args={[0.5, 16, 16]} />\n <meshBasicMaterial\n color={color}\n toneMapped={false}\n transparent={!!(dimmed || locked)}\n opacity={dimmed ? 0.35 : locked ? 0.25 : 1}\n />\n </mesh>\n );\n}\n","import { useMemo, useRef } from \"react\";\nimport { useFrame } from \"@react-three/fiber\";\nimport { Line } from \"@react-three/drei\";\nimport type { Line2 } from \"three-stdlib\";\nimport * as THREE from \"three\";\n\nexport type ConstellationEdgeVariant = \"solid\" | \"dotted\";\n\nexport interface ConstellationEdgeProps {\n from: [number, number, number];\n to: [number, number, number];\n hueA: number;\n hueB: number;\n /** Inward gap so the line doesn't touch the star spheres. */\n gap?: number;\n intensityA?: number;\n intensityB?: number;\n /** Reduce opacity to indicate an unwatched connection. */\n dimmed?: boolean;\n /** Solid for player choices; dotted + animated for default goto paths. */\n variant?: ConstellationEdgeVariant;\n}\n\nfunction AnimatedDashedLine({\n points,\n vertexColors,\n lineWidth,\n opacity,\n}: {\n points: [THREE.Vector3, THREE.Vector3];\n vertexColors: [THREE.Color, THREE.Color];\n lineWidth: number;\n opacity: number;\n}) {\n const lineRef = useRef<Line2>(null);\n\n useFrame((_, delta) => {\n const material = lineRef.current?.material as THREE.Material & {\n dashOffset?: number;\n dashed?: boolean;\n } | undefined;\n if (material?.dashed && material.dashOffset != null) {\n material.dashOffset -= delta * 2.5;\n }\n });\n\n return (\n <Line\n ref={lineRef}\n points={points}\n vertexColors={vertexColors}\n lineWidth={lineWidth}\n transparent\n opacity={opacity}\n toneMapped={false}\n dashed\n dashSize={0.35}\n gapSize={0.3}\n />\n );\n}\n\n/**\n * A luminous line connecting two stars in a constellation. Endpoints are\n * pulled inward so the line floats between the stars rather than touching\n * them. Color interpolates from hueA to hueB via vertex colors.\n *\n * Goto paths render as animated dotted lines; choice paths render solid.\n */\nexport function ConstellationEdge({\n from,\n to,\n hueA,\n hueB,\n gap = 0.55,\n intensityA = 0.5,\n intensityB = 0.5,\n dimmed,\n variant = \"solid\",\n}: ConstellationEdgeProps) {\n const { points, colorA, colorB, glowA, glowB } = useMemo(() => {\n const a = new THREE.Vector3(...from);\n const b = new THREE.Vector3(...to);\n const dir = b.clone().sub(a);\n const len = dir.length();\n\n if (len < gap * 2.5) {\n return { points: null, colorA: null, colorB: null, glowA: null, glowB: null };\n }\n\n dir.normalize();\n const start = a.clone().add(dir.clone().multiplyScalar(gap));\n const end = b.clone().sub(dir.clone().multiplyScalar(gap));\n\n const lA = 55 + intensityA * 20;\n const lB = 55 + intensityB * 20;\n\n const cA = new THREE.Color(`hsl(${hueA}, 70%, ${lA}%)`);\n const cB = new THREE.Color(`hsl(${hueB}, 70%, ${lB}%)`);\n\n const gA = new THREE.Color(`hsl(${hueA}, 50%, ${lA + 10}%)`);\n const gB = new THREE.Color(`hsl(${hueB}, 50%, ${lB + 10}%)`);\n\n return {\n points: [start, end] as [THREE.Vector3, THREE.Vector3],\n colorA: cA,\n colorB: cB,\n glowA: gA,\n glowB: gB,\n };\n }, [from, to, hueA, hueB, gap, intensityA, intensityB]);\n\n if (!points || !colorA || !colorB || !glowA || !glowB) return null;\n\n const isDotted = variant === \"dotted\";\n const glowOpacity = dimmed ? 0.04 : isDotted ? 0.08 : 0.12;\n const coreOpacity = dimmed ? 0.15 : isDotted ? 0.45 : 0.6;\n\n if (isDotted) {\n return (\n <group>\n <AnimatedDashedLine\n points={points}\n vertexColors={[glowA, glowB]}\n lineWidth={4}\n opacity={glowOpacity}\n />\n <AnimatedDashedLine\n points={points}\n vertexColors={[colorA, colorB]}\n lineWidth={1.5}\n opacity={coreOpacity}\n />\n </group>\n );\n }\n\n return (\n <group>\n <Line\n points={points}\n vertexColors={[glowA, glowB]}\n lineWidth={4}\n transparent\n opacity={glowOpacity}\n toneMapped={false}\n />\n <Line\n points={points}\n vertexColors={[colorA, colorB]}\n lineWidth={1.5}\n transparent\n opacity={coreOpacity}\n toneMapped={false}\n />\n </group>\n );\n}\n","import type { AtomVisualProps } from \"../../index.js\";\nimport { Star } from \"./Star.js\";\nimport { ConstellationEdge } from \"./ConstellationEdge.js\";\n\nexport interface ConstellationSceneEntry {\n id: string;\n /** Visual with final position already computed by the consumer. */\n visual: AtomVisualProps;\n /** When true the star renders at reduced brightness/saturation. */\n dimmed?: boolean;\n /** When true the star is non-navigable (click suppressed). */\n locked?: boolean;\n}\n\nexport interface ConstellationEdgeEntry {\n source: string;\n target: string;\n type: \"choice\" | \"go_to_scene\" | \"sequential\";\n}\n\nexport interface ConstellationProps {\n /** Scene entries in order (title first, end last), already positioned. */\n scenes: ConstellationSceneEntry[];\n /** Optional explicit edges. When provided, replaces sequential rendering. */\n edges?: ConstellationEdgeEntry[];\n onSceneSelect?: (index: number) => void;\n}\n\n/**\n * A single story rendered as a constellation: scene-stars connected by\n * luminous gradient edges. This is the cosmos realm's `Group` component —\n * identical rendering for own and others' stories.\n *\n * The consumer provides scenes with positions already computed so that\n * overlay logic (camera targeting, focus rings) can use the same positions.\n *\n * When `edges` is provided, the component renders from the explicit graph\n * (supporting Y-forks for choices) instead of sequential order.\n */\nexport function Constellation({\n scenes,\n edges,\n onSceneSelect,\n}: ConstellationProps) {\n const sceneMap = new Map(scenes.map((s, i) => [s.id, { entry: s, index: i }]));\n\n const resolvedEdges: {\n from: ConstellationSceneEntry;\n to: ConstellationSceneEntry;\n type: ConstellationEdgeEntry[\"type\"];\n }[] = [];\n\n if (edges && edges.length > 0) {\n for (const edge of edges) {\n const src = sceneMap.get(edge.source);\n const tgt = sceneMap.get(edge.target);\n if (src && tgt) {\n resolvedEdges.push({ from: src.entry, to: tgt.entry, type: edge.type });\n }\n }\n } else {\n for (let i = 1; i < scenes.length; i++) {\n resolvedEdges.push({\n from: scenes[i - 1],\n to: scenes[i],\n type: \"sequential\",\n });\n }\n }\n\n return (\n <group>\n {scenes.map((entry, i) => (\n <Star\n key={entry.id}\n visual={entry.visual}\n dimmed={entry.dimmed}\n locked={entry.locked}\n onSelect={onSceneSelect ? () => onSceneSelect(i) : undefined}\n />\n ))}\n\n {resolvedEdges.map(({ from, to, type }) => {\n const edgeDimmed = !!(from.dimmed || to.dimmed);\n const variant = type === \"go_to_scene\" ? \"dotted\" : \"solid\";\n return (\n <ConstellationEdge\n key={`edge-${from.id}-${to.id}-${type}`}\n from={from.visual.position}\n to={to.visual.position}\n hueA={from.visual.hue}\n hueB={to.visual.hue}\n intensityA={from.visual.intensity}\n intensityB={to.visual.intensity}\n dimmed={edgeDimmed}\n variant={variant}\n />\n );\n })}\n </group>\n );\n}\n","import type { StoryListItem } from \"../../types/index.js\";\nimport type { AtomMapping, AtomState, AudioPalette, MotionTokens } from \"../index.js\";\n\n/**\n * COSMOS realm — pure-data layer. The 3D components (World, Star, NavRig,\n * EngageTransition) live in a follow-up package once the JSX build is\n * wired up; this file owns the realm's mapping and tuning constants so\n * they can be consumed today by any non-3D surface (catalog list, search,\n * preview cards, sound design tooling).\n *\n * Mapping rationale:\n * runtime → scale (longer film = bigger star)\n * popularity → intensity (more watches = brighter)\n * mood → hue (warm/cool palette by tone)\n * genre → spectral hint (small offset on top of mood, reads as\n * \"stellar class\" — drama is yellow-G,\n * thriller is blue-O, romance is red-M).\n * state → orbit-ring rendering (handled by Atom component).\n */\n\nconst GENRE_HUE_OFFSET: Record<string, number> = {\n drama: 50,\n thriller: 220,\n horror: 0,\n comedy: 35,\n romance: 340,\n scifi: 200,\n documentary: 180,\n animation: 280,\n};\n\nconst MOOD_HUE: Record<string, number> = {\n bright: 50,\n warm: 25,\n bittersweet: 290,\n somber: 230,\n tense: 210,\n playful: 110,\n melancholy: 250,\n};\n\nfunction clamp01(n: number): number {\n return Math.max(0, Math.min(1, n));\n}\n\nfunction popularityToIntensity(film: StoryListItem): number {\n // Log-compress: a 100x more-watched film should not be 100x brighter.\n const watches = Math.max(0, film.watch_starts_count);\n const log = Math.log10(1 + watches);\n // Rough cap at ~6 (1M watches saturates the scale).\n return clamp01(log / 6);\n}\n\nfunction deriveScale(film: StoryListItem): number {\n // We don't have runtime in StoryListItem yet; proxy with scenes_count.\n // Caps the starfield from going visually noisy.\n const scenes = film.scenes_count ?? 1;\n return clamp01(0.25 + Math.log10(1 + scenes) / 4);\n}\n\nfunction deriveHue(film: StoryListItem): number {\n const genreKey = (film.genre ?? \"\").toLowerCase().replace(/[^a-z]/g, \"\");\n const moodKey = \"\";\n const moodHue = MOOD_HUE[moodKey];\n const genreOffset = GENRE_HUE_OFFSET[genreKey];\n if (moodHue !== undefined) return moodHue;\n if (genreOffset !== undefined) return genreOffset;\n return 210;\n}\n\nfunction deriveState(film: StoryListItem): AtomState {\n // Without per-user progress threaded through, default; the consuming\n // app will overlay state from CatalogResponse.meta.progress.\n return film.published ? \"default\" : \"new\";\n}\n\nexport const cosmosMapping: AtomMapping = (film) => ({\n position: [0, 0, 0], // assigned by the realm's spatial layouter\n scale: deriveScale(film),\n hue: deriveHue(film),\n intensity: popularityToIntensity(film),\n state: deriveState(film),\n metadata: {\n title: film.title,\n popularity: film.watch_starts_count,\n genre: film.genre,\n },\n});\n\nexport const cosmosMotion: MotionTokens = {\n flightAcceleration: 14,\n flightDamping: 0.92,\n focusEaseMs: 380,\n engageDurationMs: 900,\n backDurationMs: 900,\n};\n\nexport const cosmosAudio: AudioPalette = {\n // Asset paths are resolved by the host app's asset bundler; chuzi-shared\n // only declares the contract. Replace with CDN URLs at integration time.\n ambientLoop: \"audio/cosmos/ambient-deep.ogg\",\n focusChime: \"audio/cosmos/focus-shimmer.ogg\",\n engageImpact: \"audio/cosmos/dolly-in.ogg\",\n backWhoosh: \"audio/cosmos/dolly-out.ogg\",\n};\n","/**\n * Spatial distribution helpers for the cosmos realm. Kept as a stand-alone\n * module so non-3D surfaces (search overlays, accessibility list view,\n * minimap) can compute and reuse positions without pulling in three.js.\n */\n\nexport type Vec3 = [number, number, number];\n\nexport interface DistributeOptions {\n /** Outer radius of the disk in world units. */\n radius?: number;\n /** Vertical jitter band (±). Larger values flatten the disk less. */\n thickness?: number;\n /** Deterministic seed; identical seeds produce identical layouts. */\n seed?: number;\n}\n\n/**\n * Galaxy-disk distribution: stars cluster denser toward the center\n * (sqrt-r weighting), with a vertical jitter band. Deterministic when a\n * seed is provided so the same catalog produces the same starfield across\n * sessions.\n */\nexport function distributeStars(\n count: number,\n options: DistributeOptions = {},\n): Vec3[] {\n const radius = options.radius ?? 25;\n const thickness = options.thickness ?? 4;\n const random = options.seed !== undefined ? mulberry32(options.seed) : Math.random;\n\n const positions: Vec3[] = [];\n for (let i = 0; i < count; i++) {\n const r = Math.sqrt(random()) * radius;\n const theta = random() * Math.PI * 2;\n const y = (random() - 0.5) * thickness;\n positions.push([Math.cos(theta) * r, y, Math.sin(theta) * r]);\n }\n return positions;\n}\n\nfunction mulberry32(seed: number): () => number {\n let s = seed >>> 0;\n return () => {\n s = (s + 0x6d2b79f5) >>> 0;\n let t = s;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n","import { useMemo } from \"react\";\nimport type { StoryListItem } from \"../../../types/index.js\";\nimport { cosmosMapping } from \"../index.js\";\nimport { Star } from \"./Star.js\";\nimport { World } from \"./World.js\";\nimport { distributeStars, type Vec3 } from \"./layout.js\";\n\nexport interface CosmosSandboxProps {\n films: StoryListItem[];\n onFilmSelect?: (film: StoryListItem) => void;\n /** Layout seed — same seed + same films = same layout. */\n seed?: number;\n}\n\n/**\n * Drop-in 3D sandbox. Hands a list of films, gets back a navigable\n * starfield where each star is a film. Useful for: integration tests, the\n * realm-picker preview thumbnail, the editor's \"preview as star\" mode, and\n * as the smoke-test entry while migrating chuzi-web off Laravel.\n */\nexport function CosmosSandbox({\n films,\n onFilmSelect,\n seed = 1,\n}: CosmosSandboxProps) {\n const placed = useMemo(() => {\n const positions: Vec3[] = distributeStars(films.length, { seed });\n return films.map((film, i) => ({\n film,\n visual: { ...cosmosMapping(film), position: positions[i] },\n }));\n }, [films, seed]);\n\n return (\n <World>\n {placed.map(({ film, visual }) => (\n <Star\n key={film.id}\n visual={visual}\n onSelect={onFilmSelect ? () => onFilmSelect(film) : undefined}\n />\n ))}\n </World>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/themes/index.ts","../../../../src/realms/cosmos/components/World.tsx","../../../../src/realms/cosmos/components/Star.tsx","../../../../src/realms/cosmos/appearance.ts","../../../../src/realms/cosmos/components/ConstellationEdge.tsx","../../../../src/realms/cosmos/components/ConstellationTitle.tsx","../../../../src/realms/cosmos/components/StarBillboard.tsx","../../../../src/realms/cosmos/components/Constellation.tsx","../../../../src/realms/cosmos/index.ts","../../../../src/realms/cosmos/components/layout.ts","../../../../src/realms/cosmos/components/CosmosSandbox.tsx"],"names":["DreiStars","jsxs","jsx","useMemo"],"mappings":"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","file":"index.js","sourcesContent":["import type { RealmId } from \"../types/index.js\";\n\n/**\n * CSS custom property tokens, mirroring public/css/chuzi-realms.css.\n * Use these for any non-DOM rendering (e.g. React Native, canvas).\n */\nexport interface RealmThemeTokens {\n bgDeep: string;\n bgMid: string;\n accent: string;\n accentSoft: string;\n text: string;\n muted: string;\n effectLine: string;\n}\n\nexport const THEME_TOKENS: Record<RealmId, RealmThemeTokens> = {\n cosmos: {\n bgDeep: \"#04070d\",\n bgMid: \"#0a1020\",\n accent: \"#7eb8ff\",\n accentSoft: \"rgba(126, 184, 255, 0.35)\",\n text: \"#e8f0ff\",\n muted: \"rgba(232, 240, 255, 0.65)\",\n effectLine: \"#ffb347\",\n },\n wilds: {\n bgDeep: \"#0d120c\",\n bgMid: \"#152018\",\n accent: \"#7bc96f\",\n accentSoft: \"rgba(123, 201, 111, 0.35)\",\n text: \"#eef6ea\",\n muted: \"rgba(238, 246, 234, 0.7)\",\n effectLine: \"#b78aff\",\n },\n};\n\n/**\n * Scene tree visualization theme, mirroring the THEMES object in\n * resources/js/scene-tree-viewer.js.\n */\nexport interface SceneTreeTheme {\n bg: string;\n edgeChoice: string;\n edgeGoto: string;\n nodeDefault: string;\n nodeActive: string;\n borderDefault: string;\n borderActive: string;\n labelDefault: string;\n labelActive: string;\n nodeLockedFill: string;\n nodeLockedBorder: string;\n labelLocked: string;\n nodeShape: \"star\" | \"rect\";\n rectRx: number;\n}\n\nexport const SCENE_TREE_THEMES: Record<RealmId, SceneTreeTheme> = {\n cosmos: {\n bg: \"#020408\",\n edgeChoice: \"#e8f0ff\",\n edgeGoto: \"#4a9fff\",\n nodeDefault: \"#ffffff\",\n nodeActive: \"#ffd47e\",\n borderDefault: \"#3a5080\",\n borderActive: \"#fff6d0\",\n labelDefault: \"rgba(220, 232, 255, 0.92)\",\n labelActive: \"rgba(255, 246, 220, 0.98)\",\n nodeLockedFill: \"#151a28\",\n nodeLockedBorder: \"#2a3348\",\n labelLocked: \"rgba(200, 210, 230, 0.35)\",\n nodeShape: \"star\",\n rectRx: 2,\n },\n wilds: {\n bg: \"#04070d\",\n edgeChoice: \"#ffffff\",\n edgeGoto: \"#6ecf7a\",\n nodeDefault: \"#e8f5e4\",\n nodeActive: \"#d31e2f\",\n borderDefault: \"#2d4a32\",\n borderActive: \"#ff9ea8\",\n labelDefault: \"rgba(232, 245, 228, 0.92)\",\n labelActive: \"rgba(255, 214, 219, 0.98)\",\n nodeLockedFill: \"#1a221c\",\n nodeLockedBorder: \"#2a3d30\",\n labelLocked: \"rgba(200, 220, 200, 0.38)\",\n nodeShape: \"rect\",\n rectRx: 3,\n },\n};\n\n/**\n * Get theme tokens for a realm, defaulting to wilds.\n */\nexport function getThemeTokens(realmId: RealmId | null | undefined): RealmThemeTokens {\n return THEME_TOKENS[realmId ?? \"wilds\"] ?? THEME_TOKENS.wilds;\n}\n\n/**\n * Get scene tree theme for a realm, defaulting to wilds.\n */\nexport function getSceneTreeTheme(realmId: RealmId | null | undefined): SceneTreeTheme {\n return SCENE_TREE_THEMES[realmId ?? \"wilds\"] ?? SCENE_TREE_THEMES.wilds;\n}\n","import { Canvas } from \"@react-three/fiber\";\nimport { OrbitControls, Stars as DreiStars } from \"@react-three/drei\";\nimport type { ReactNode } from \"react\";\nimport { THEME_TOKENS } from \"../../../themes/index.js\";\n\nexport interface WorldProps {\n children: ReactNode;\n /** Pixel device ratio cap. Default 2 — keeps perf bounded on retina laptops. */\n dpr?: number | [number, number];\n}\n\n/**\n * Cosmos environment shell. Wraps an r3f Canvas with deep-space background,\n * ambient starfield (drei <Stars> for the *backdrop* — distinct from our\n * film-stars), and a placeholder OrbitControls camera. The real NavRig\n * (consuming an IntentSource and doing focus-snap on dpad) replaces\n * OrbitControls in a follow-up package.\n */\nexport function World({ children, dpr = [1, 2] }: WorldProps) {\n return (\n <Canvas\n camera={{ position: [0, 6, 32], fov: 60, near: 0.1, far: 500 }}\n dpr={dpr}\n gl={{ antialias: true }}\n >\n <color attach=\"background\" args={[THEME_TOKENS.cosmos.bgDeep]} />\n <ambientLight intensity={0.15} />\n <DreiStars\n radius={120}\n depth={60}\n count={3000}\n factor={4}\n fade\n saturation={0.4}\n />\n <OrbitControls enablePan={false} maxDistance={80} minDistance={4} />\n {children}\n </Canvas>\n );\n}\n","import { useRef } from \"react\";\nimport { useFrame } from \"@react-three/fiber\";\nimport type { Mesh } from \"three\";\nimport type { AtomVisualProps } from \"../../index.js\";\n\nexport interface StarProps {\n visual: AtomVisualProps;\n onSelect?: () => void;\n /** Reduce brightness and saturation to indicate an unwatched scene. */\n dimmed?: boolean;\n /** Non-navigable — suppresses click and lowers brightness further. */\n locked?: boolean;\n}\n\n/**\n * One film as a star. Color is HSL-derived from the realm mapping's hue +\n * intensity. Each star pulses on its own phase so a thousand of them don't\n * breathe in lockstep — gives the field life without per-star animation\n * state.\n */\nexport function Star({ visual, onSelect, dimmed, locked }: StarProps) {\n const ref = useRef<Mesh>(null);\n\n useFrame(({ clock }) => {\n if (!ref.current) return;\n const phase = visual.position[0] * 0.7 + visual.position[2] * 0.3;\n const pulse = 1 + Math.sin(clock.elapsedTime * 0.8 + phase) * 0.05;\n ref.current.scale.setScalar(visual.scale * pulse);\n });\n\n const saturation = dimmed || locked ? 25 : 75;\n const lightness = dimmed || locked\n ? 25 + visual.intensity * 10\n : 50 + visual.intensity * 25;\n const color = `hsl(${visual.hue}, ${saturation}%, ${lightness}%)`;\n\n const handleClick = locked\n ? undefined\n : onSelect\n ? (e: any) => {\n e.stopPropagation();\n onSelect();\n }\n : undefined;\n\n return (\n <mesh\n ref={ref}\n position={visual.position}\n onClick={handleClick}\n >\n <sphereGeometry args={[0.5, 16, 16]} />\n <meshBasicMaterial\n color={color}\n toneMapped={false}\n transparent={!!(dimmed || locked)}\n opacity={dimmed ? 0.35 : locked ? 0.25 : 1}\n />\n </mesh>\n );\n}\n","/**\n * Constellation presentation tokens — consumed by the cosmos realm camera,\n * star billboards, and ghost title typography. Admins can override via\n * saved experience / appearance templates.\n */\nexport interface ConstellationAppearance {\n /** Ghost film title spanning the constellation. */\n titleFontSize: number;\n titleOpacity: number;\n titleColor: string;\n titleLetterSpacing: number;\n titleYOffset: number;\n\n /** Per-star preview card + label. */\n previewWidth: number;\n previewHeight: number;\n previewOffsetY: number;\n labelFontSize: number;\n labelLetterSpacing: number;\n labelGap: number;\n billboardDistanceFactor: number;\n\n /** Camera — floating-in-space slide between stars. */\n cameraDefaultOffset: [number, number, number];\n cameraTargetOffset: [number, number, number];\n /** 0–1 lerp factor per frame while gliding (lower = smoother / pressurized). */\n cameraSlideLerp: number;\n cameraArrivalThreshold: number;\n}\n\nexport const DEFAULT_CONSTELLATION_APPEARANCE: ConstellationAppearance = {\n titleFontSize: 2.8,\n titleOpacity: 0.14,\n titleColor: \"#e8f0ff\",\n titleLetterSpacing: 0.35,\n titleYOffset: 1.2,\n\n previewWidth: 148,\n previewHeight: 96,\n previewOffsetY: 2.4,\n labelFontSize: 13,\n labelLetterSpacing: 1.2,\n labelGap: 14,\n billboardDistanceFactor: 10,\n\n cameraDefaultOffset: [0, 4, 12],\n cameraTargetOffset: [0, 0, 0],\n cameraSlideLerp: 0.035,\n cameraArrivalThreshold: 0.08,\n};\n\nexport function mergeConstellationAppearance(\n overrides?: Partial<ConstellationAppearance>,\n): ConstellationAppearance {\n return { ...DEFAULT_CONSTELLATION_APPEARANCE, ...overrides };\n}\n","import { useMemo } from \"react\";\nimport { Line } from \"@react-three/drei\";\nimport * as THREE from \"three\";\n\nexport type ConstellationEdgeVariant = \"solid\" | \"dotted\";\n\nexport interface ConstellationEdgeProps {\n from: [number, number, number];\n to: [number, number, number];\n hueA: number;\n hueB: number;\n /** Inward gap so the line doesn't touch the star spheres. */\n gap?: number;\n intensityA?: number;\n intensityB?: number;\n /** Reduce opacity to indicate an unwatched connection. */\n dimmed?: boolean;\n /** @deprecated All edges render as soft solid glow; variant is ignored. */\n variant?: ConstellationEdgeVariant;\n}\n\n/**\n * A luminous line connecting two stars in a constellation. Endpoints are\n * pulled inward so the line floats between the stars rather than touching\n * them. Color interpolates from hueA to hueB via vertex colors.\n */\nexport function ConstellationEdge({\n from,\n to,\n hueA,\n hueB,\n gap = 0.55,\n intensityA = 0.5,\n intensityB = 0.5,\n dimmed,\n}: ConstellationEdgeProps) {\n const { points, colorA, colorB, glowA, glowB } = useMemo(() => {\n const a = new THREE.Vector3(...from);\n const b = new THREE.Vector3(...to);\n const dir = b.clone().sub(a);\n const len = dir.length();\n\n if (len < gap * 2.5) {\n return { points: null, colorA: null, colorB: null, glowA: null, glowB: null };\n }\n\n dir.normalize();\n const start = a.clone().add(dir.clone().multiplyScalar(gap));\n const end = b.clone().sub(dir.clone().multiplyScalar(gap));\n\n const lA = 55 + intensityA * 20;\n const lB = 55 + intensityB * 20;\n\n const cA = new THREE.Color(`hsl(${hueA}, 70%, ${lA}%)`);\n const cB = new THREE.Color(`hsl(${hueB}, 70%, ${lB}%)`);\n\n const gA = new THREE.Color(`hsl(${hueA}, 50%, ${lA + 10}%)`);\n const gB = new THREE.Color(`hsl(${hueB}, 50%, ${lB + 10}%)`);\n\n return {\n points: [start, end] as [THREE.Vector3, THREE.Vector3],\n colorA: cA,\n colorB: cB,\n glowA: gA,\n glowB: gB,\n };\n }, [from, to, hueA, hueB, gap, intensityA, intensityB]);\n\n if (!points || !colorA || !colorB || !glowA || !glowB) return null;\n\n const glowOpacity = dimmed ? 0.04 : 0.12;\n const coreOpacity = dimmed ? 0.15 : 0.6;\n\n return (\n <group>\n <Line\n points={points}\n vertexColors={[glowA, glowB]}\n lineWidth={4}\n transparent\n opacity={glowOpacity}\n toneMapped={false}\n />\n <Line\n points={points}\n vertexColors={[colorA, colorB]}\n lineWidth={1.5}\n transparent\n opacity={coreOpacity}\n toneMapped={false}\n />\n </group>\n );\n}\n","import { Text } from \"@react-three/drei\";\nimport type { ConstellationAppearance } from \"../appearance.js\";\n\nexport interface ConstellationBounds {\n center: [number, number, number];\n spanX: number;\n spanZ: number;\n}\n\nexport function computeConstellationBounds(\n positions: [number, number, number][],\n): ConstellationBounds | null {\n if (positions.length === 0) return null;\n\n let minX = Infinity;\n let maxX = -Infinity;\n let minZ = Infinity;\n let maxZ = -Infinity;\n let sumY = 0;\n\n for (const [x, y, z] of positions) {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n minZ = Math.min(minZ, z);\n maxZ = Math.max(maxZ, z);\n sumY += y;\n }\n\n return {\n center: [(minX + maxX) / 2, sumY / positions.length, (minZ + maxZ) / 2],\n spanX: Math.max(6, maxX - minX + 4),\n spanZ: Math.max(4, maxZ - minZ + 3),\n };\n}\n\nexport interface ConstellationTitleProps {\n title: string;\n bounds: ConstellationBounds;\n appearance: ConstellationAppearance;\n}\n\n/**\n * Large ghostly film title draped across the constellation footprint.\n */\nexport function ConstellationTitle({\n title,\n bounds,\n appearance,\n}: ConstellationTitleProps) {\n if (!title.trim()) return null;\n\n return (\n <Text\n position={[\n bounds.center[0],\n bounds.center[1] + appearance.titleYOffset,\n bounds.center[2],\n ]}\n rotation={[-Math.PI / 2, 0, 0]}\n fontSize={appearance.titleFontSize}\n color={appearance.titleColor}\n fillOpacity={appearance.titleOpacity}\n anchorX=\"center\"\n anchorY=\"middle\"\n maxWidth={Math.max(bounds.spanX, bounds.spanZ) * 1.35}\n letterSpacing={appearance.titleLetterSpacing}\n textAlign=\"center\"\n >\n {title.toUpperCase()}\n </Text>\n );\n}\n","import { Html } from \"@react-three/drei\";\nimport type { ReactNode } from \"react\";\nimport type { ConstellationAppearance } from \"../appearance.js\";\n\nexport interface StarBillboardProps {\n label: string;\n appearance: ConstellationAppearance;\n previewImageUrl?: string | null;\n previewContent?: ReactNode;\n dimmed?: boolean;\n focused?: boolean;\n}\n\n/**\n * Floating preview card and scene label above a star. Label sits beneath\n * the preview image, offset from the star sphere.\n */\nexport function StarBillboard({\n label,\n appearance,\n previewImageUrl,\n previewContent,\n dimmed,\n focused,\n}: StarBillboardProps) {\n const borderColor = focused\n ? \"rgba(126,184,255,0.65)\"\n : \"rgba(126,184,255,0.28)\";\n const opacity = dimmed ? 0.45 : focused ? 1 : 0.88;\n\n return (\n <Html\n position={[0, appearance.previewOffsetY, 0]}\n center\n distanceFactor={appearance.billboardDistanceFactor}\n style={{\n pointerEvents: \"none\",\n userSelect: \"none\",\n opacity,\n transition: \"opacity 0.35s ease\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: appearance.labelGap,\n }}\n >\n <div\n style={{\n width: appearance.previewWidth,\n height: appearance.previewHeight,\n borderRadius: 8,\n overflow: \"hidden\",\n border: `1px solid ${borderColor}`,\n background: \"rgba(4,7,13,0.92)\",\n boxShadow: focused\n ? \"0 0 24px rgba(126,184,255,0.35)\"\n : \"0 4px 20px rgba(0,0,0,0.55)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n {previewImageUrl ? (\n <img\n src={previewImageUrl}\n alt=\"\"\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n display: \"block\",\n }}\n />\n ) : (\n previewContent ?? (\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n background:\n \"radial-gradient(ellipse at 30% 20%, rgba(80,120,200,0.2) 0%, rgba(10,14,30,0.95) 70%)\",\n }}\n />\n )\n )}\n </div>\n\n <div\n style={{\n fontSize: appearance.labelFontSize,\n fontWeight: 700,\n letterSpacing: appearance.labelLetterSpacing,\n textTransform: \"uppercase\",\n color: focused ? \"rgba(232,240,255,0.95)\" : \"rgba(232,240,255,0.72)\",\n textAlign: \"center\",\n textShadow: \"0 2px 12px rgba(0,0,0,0.95)\",\n whiteSpace: \"nowrap\",\n maxWidth: appearance.previewWidth + 40,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {label}\n </div>\n </div>\n </Html>\n );\n}\n","import type { ReactNode } from \"react\";\nimport type { AtomVisualProps } from \"../../index.js\";\nimport {\n mergeConstellationAppearance,\n type ConstellationAppearance,\n} from \"../appearance.js\";\nimport { Star } from \"./Star.js\";\nimport { ConstellationEdge } from \"./ConstellationEdge.js\";\nimport {\n ConstellationTitle,\n computeConstellationBounds,\n} from \"./ConstellationTitle.js\";\nimport { StarBillboard } from \"./StarBillboard.js\";\n\nexport interface ConstellationSceneEntry {\n id: string;\n /** Visual with final position already computed by the consumer. */\n visual: AtomVisualProps;\n /** Scene label shown beneath the preview card. */\n label?: string;\n /** Static preview image (coverbox, poster frame, etc.). */\n previewImageUrl?: string | null;\n /** Custom preview when no image URL is available. */\n previewContent?: ReactNode;\n /** When true the star renders at reduced brightness/saturation. */\n dimmed?: boolean;\n /** When true the star is non-navigable (click suppressed). */\n locked?: boolean;\n /** Highlight this star's billboard (focused traversal). */\n focused?: boolean;\n}\n\nexport interface ConstellationEdgeEntry {\n source: string;\n target: string;\n type: \"choice\" | \"go_to_scene\" | \"sequential\";\n}\n\nexport interface ConstellationProps {\n /** Scene entries with positions already computed by the consumer. */\n scenes: ConstellationSceneEntry[];\n /** Film title rendered as ghost typography across the group. */\n storyTitle?: string;\n /** Explicit story-flow edges (goto + choice). No implicit sequential links. */\n edges?: ConstellationEdgeEntry[];\n appearance?: Partial<ConstellationAppearance>;\n onSceneSelect?: (index: number) => void;\n}\n\n/**\n * A single story rendered as a constellation: scene-stars connected by\n * luminous gradient edges. This is the cosmos realm's `Group` component —\n * identical rendering for own and others' stories.\n */\nexport function Constellation({\n scenes,\n storyTitle,\n edges = [],\n appearance: appearanceOverrides,\n onSceneSelect,\n}: ConstellationProps) {\n const appearance = mergeConstellationAppearance(appearanceOverrides);\n const sceneMap = new Map(scenes.map((s, i) => [s.id, { entry: s, index: i }]));\n const bounds = computeConstellationBounds(\n scenes.map((s) => s.visual.position),\n );\n\n const resolvedEdges: {\n from: ConstellationSceneEntry;\n to: ConstellationSceneEntry;\n type: ConstellationEdgeEntry[\"type\"];\n }[] = [];\n\n for (const edge of edges) {\n const src = sceneMap.get(edge.source);\n const tgt = sceneMap.get(edge.target);\n if (src && tgt) {\n resolvedEdges.push({ from: src.entry, to: tgt.entry, type: edge.type });\n }\n }\n\n return (\n <group>\n {storyTitle && bounds ? (\n <ConstellationTitle\n title={storyTitle}\n bounds={bounds}\n appearance={appearance}\n />\n ) : null}\n\n {scenes.map((entry, i) => (\n <group key={entry.id} position={entry.visual.position}>\n <Star\n visual={{ ...entry.visual, position: [0, 0, 0] }}\n dimmed={entry.dimmed}\n locked={entry.locked}\n onSelect={onSceneSelect ? () => onSceneSelect(i) : undefined}\n />\n\n {entry.label || entry.previewImageUrl || entry.previewContent ? (\n <StarBillboard\n label={entry.label ?? \"\"}\n appearance={appearance}\n previewImageUrl={entry.previewImageUrl}\n previewContent={entry.previewContent}\n dimmed={entry.dimmed}\n focused={entry.focused}\n />\n ) : null}\n </group>\n ))}\n\n {resolvedEdges.map(({ from, to, type }) => {\n const edgeDimmed = !!(from.dimmed || to.dimmed);\n return (\n <ConstellationEdge\n key={`edge-${from.id}-${to.id}-${type}`}\n from={from.visual.position}\n to={to.visual.position}\n hueA={from.visual.hue}\n hueB={to.visual.hue}\n intensityA={from.visual.intensity}\n intensityB={to.visual.intensity}\n dimmed={edgeDimmed}\n />\n );\n })}\n </group>\n );\n}\n\n","import type { StoryListItem } from \"../../types/index.js\";\nimport type { AtomMapping, AtomState, AudioPalette, MotionTokens } from \"../index.js\";\n\n/**\n * COSMOS realm — pure-data layer. The 3D components (World, Star, NavRig,\n * EngageTransition) live in a follow-up package once the JSX build is\n * wired up; this file owns the realm's mapping and tuning constants so\n * they can be consumed today by any non-3D surface (catalog list, search,\n * preview cards, sound design tooling).\n *\n * Mapping rationale:\n * runtime → scale (longer film = bigger star)\n * popularity → intensity (more watches = brighter)\n * mood → hue (warm/cool palette by tone)\n * genre → spectral hint (small offset on top of mood, reads as\n * \"stellar class\" — drama is yellow-G,\n * thriller is blue-O, romance is red-M).\n * state → orbit-ring rendering (handled by Atom component).\n */\n\nconst GENRE_HUE_OFFSET: Record<string, number> = {\n drama: 50,\n thriller: 220,\n horror: 0,\n comedy: 35,\n romance: 340,\n scifi: 200,\n documentary: 180,\n animation: 280,\n};\n\nconst MOOD_HUE: Record<string, number> = {\n bright: 50,\n warm: 25,\n bittersweet: 290,\n somber: 230,\n tense: 210,\n playful: 110,\n melancholy: 250,\n};\n\nfunction clamp01(n: number): number {\n return Math.max(0, Math.min(1, n));\n}\n\nfunction popularityToIntensity(film: StoryListItem): number {\n // Log-compress: a 100x more-watched film should not be 100x brighter.\n const watches = Math.max(0, film.watch_starts_count);\n const log = Math.log10(1 + watches);\n // Rough cap at ~6 (1M watches saturates the scale).\n return clamp01(log / 6);\n}\n\nfunction deriveScale(film: StoryListItem): number {\n // We don't have runtime in StoryListItem yet; proxy with scenes_count.\n // Caps the starfield from going visually noisy.\n const scenes = film.scenes_count ?? 1;\n return clamp01(0.25 + Math.log10(1 + scenes) / 4);\n}\n\nfunction deriveHue(film: StoryListItem): number {\n const genreKey = (film.genre ?? \"\").toLowerCase().replace(/[^a-z]/g, \"\");\n const moodKey = \"\";\n const moodHue = MOOD_HUE[moodKey];\n const genreOffset = GENRE_HUE_OFFSET[genreKey];\n if (moodHue !== undefined) return moodHue;\n if (genreOffset !== undefined) return genreOffset;\n return 210;\n}\n\nfunction deriveState(film: StoryListItem): AtomState {\n // Without per-user progress threaded through, default; the consuming\n // app will overlay state from CatalogResponse.meta.progress.\n return film.published ? \"default\" : \"new\";\n}\n\nexport const cosmosMapping: AtomMapping = (film) => ({\n position: [0, 0, 0], // assigned by the realm's spatial layouter\n scale: deriveScale(film),\n hue: deriveHue(film),\n intensity: popularityToIntensity(film),\n state: deriveState(film),\n metadata: {\n title: film.title,\n popularity: film.watch_starts_count,\n genre: film.genre,\n },\n});\n\nexport const cosmosMotion: MotionTokens = {\n flightAcceleration: 14,\n flightDamping: 0.92,\n focusEaseMs: 380,\n engageDurationMs: 900,\n backDurationMs: 900,\n};\n\nexport {\n DEFAULT_CONSTELLATION_APPEARANCE,\n mergeConstellationAppearance,\n} from \"./appearance.js\";\nexport type { ConstellationAppearance } from \"./appearance.js\";\n\nexport const cosmosAudio: AudioPalette = {\n // Asset paths are resolved by the host app's asset bundler; chuzi-shared\n // only declares the contract. Replace with CDN URLs at integration time.\n ambientLoop: \"audio/cosmos/ambient-deep.ogg\",\n focusChime: \"audio/cosmos/focus-shimmer.ogg\",\n engageImpact: \"audio/cosmos/dolly-in.ogg\",\n backWhoosh: \"audio/cosmos/dolly-out.ogg\",\n};\n","/**\n * Spatial distribution helpers for the cosmos realm. Kept as a stand-alone\n * module so non-3D surfaces (search overlays, accessibility list view,\n * minimap) can compute and reuse positions without pulling in three.js.\n */\n\nexport type Vec3 = [number, number, number];\n\nexport interface DistributeOptions {\n /** Outer radius of the disk in world units. */\n radius?: number;\n /** Vertical jitter band (±). Larger values flatten the disk less. */\n thickness?: number;\n /** Deterministic seed; identical seeds produce identical layouts. */\n seed?: number;\n}\n\n/**\n * Galaxy-disk distribution: stars cluster denser toward the center\n * (sqrt-r weighting), with a vertical jitter band. Deterministic when a\n * seed is provided so the same catalog produces the same starfield across\n * sessions.\n */\nexport function distributeStars(\n count: number,\n options: DistributeOptions = {},\n): Vec3[] {\n const radius = options.radius ?? 25;\n const thickness = options.thickness ?? 4;\n const random = options.seed !== undefined ? mulberry32(options.seed) : Math.random;\n\n const positions: Vec3[] = [];\n for (let i = 0; i < count; i++) {\n const r = Math.sqrt(random()) * radius;\n const theta = random() * Math.PI * 2;\n const y = (random() - 0.5) * thickness;\n positions.push([Math.cos(theta) * r, y, Math.sin(theta) * r]);\n }\n return positions;\n}\n\nfunction mulberry32(seed: number): () => number {\n let s = seed >>> 0;\n return () => {\n s = (s + 0x6d2b79f5) >>> 0;\n let t = s;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n","import { useMemo } from \"react\";\nimport type { StoryListItem } from \"../../../types/index.js\";\nimport { cosmosMapping } from \"../index.js\";\nimport { Star } from \"./Star.js\";\nimport { World } from \"./World.js\";\nimport { distributeStars, type Vec3 } from \"./layout.js\";\n\nexport interface CosmosSandboxProps {\n films: StoryListItem[];\n onFilmSelect?: (film: StoryListItem) => void;\n /** Layout seed — same seed + same films = same layout. */\n seed?: number;\n}\n\n/**\n * Drop-in 3D sandbox. Hands a list of films, gets back a navigable\n * starfield where each star is a film. Useful for: integration tests, the\n * realm-picker preview thumbnail, the editor's \"preview as star\" mode, and\n * as the smoke-test entry while migrating chuzi-web off Laravel.\n */\nexport function CosmosSandbox({\n films,\n onFilmSelect,\n seed = 1,\n}: CosmosSandboxProps) {\n const placed = useMemo(() => {\n const positions: Vec3[] = distributeStars(films.length, { seed });\n return films.map((film, i) => ({\n film,\n visual: { ...cosmosMapping(film), position: positions[i] },\n }));\n }, [films, seed]);\n\n return (\n <World>\n {placed.map(({ film, visual }) => (\n <Star\n key={film.id}\n visual={visual}\n onSelect={onFilmSelect ? () => onFilmSelect(film) : undefined}\n />\n ))}\n </World>\n );\n}\n"]}
|