@chuzi/shared 1.3.31 → 1.3.33
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/config/index.js +15 -0
- package/dist/config/index.js.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/realms/cosmos/components/index.d.ts +5 -3
- package/dist/realms/cosmos/components/index.js +67 -8
- package/dist/realms/cosmos/components/index.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/ui/index.js +15 -0
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -67,6 +67,7 @@ interface ConstellationProps {
|
|
|
67
67
|
*/
|
|
68
68
|
declare function Constellation({ scenes, edges, onSceneSelect, }: ConstellationProps): react_jsx_runtime.JSX.Element;
|
|
69
69
|
|
|
70
|
+
type ConstellationEdgeVariant = "solid" | "dotted";
|
|
70
71
|
interface ConstellationEdgeProps {
|
|
71
72
|
from: [number, number, number];
|
|
72
73
|
to: [number, number, number];
|
|
@@ -78,16 +79,17 @@ interface ConstellationEdgeProps {
|
|
|
78
79
|
intensityB?: number;
|
|
79
80
|
/** Reduce opacity to indicate an unwatched connection. */
|
|
80
81
|
dimmed?: boolean;
|
|
82
|
+
/** Solid for player choices; dotted + animated for default goto paths. */
|
|
83
|
+
variant?: ConstellationEdgeVariant;
|
|
81
84
|
}
|
|
82
85
|
/**
|
|
83
86
|
* A luminous line connecting two stars in a constellation. Endpoints are
|
|
84
87
|
* pulled inward so the line floats between the stars rather than touching
|
|
85
88
|
* them. Color interpolates from hueA to hueB via vertex colors.
|
|
86
89
|
*
|
|
87
|
-
*
|
|
88
|
-
* soft bloom behind it.
|
|
90
|
+
* Goto paths render as animated dotted lines; choice paths render solid.
|
|
89
91
|
*/
|
|
90
|
-
declare function ConstellationEdge({ from, to, hueA, hueB, gap, intensityA, intensityB, dimmed, }: ConstellationEdgeProps): react_jsx_runtime.JSX.Element | null;
|
|
92
|
+
declare function ConstellationEdge({ from, to, hueA, hueB, gap, intensityA, intensityB, dimmed, variant, }: ConstellationEdgeProps): react_jsx_runtime.JSX.Element | null;
|
|
91
93
|
|
|
92
94
|
interface CosmosSandboxProps {
|
|
93
95
|
films: StoryListItem[];
|
|
@@ -73,6 +73,35 @@ function Star({ visual, onSelect, dimmed, locked }) {
|
|
|
73
73
|
}
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
|
+
function AnimatedDashedLine({
|
|
77
|
+
points,
|
|
78
|
+
vertexColors,
|
|
79
|
+
lineWidth,
|
|
80
|
+
opacity
|
|
81
|
+
}) {
|
|
82
|
+
const lineRef = useRef(null);
|
|
83
|
+
useFrame((_, delta) => {
|
|
84
|
+
const material = lineRef.current?.material;
|
|
85
|
+
if (material?.dashed && material.dashOffset != null) {
|
|
86
|
+
material.dashOffset -= delta * 2.5;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return /* @__PURE__ */ jsx(
|
|
90
|
+
Line,
|
|
91
|
+
{
|
|
92
|
+
ref: lineRef,
|
|
93
|
+
points,
|
|
94
|
+
vertexColors,
|
|
95
|
+
lineWidth,
|
|
96
|
+
transparent: true,
|
|
97
|
+
opacity,
|
|
98
|
+
toneMapped: false,
|
|
99
|
+
dashed: true,
|
|
100
|
+
dashSize: 0.35,
|
|
101
|
+
gapSize: 0.3
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
76
105
|
function ConstellationEdge({
|
|
77
106
|
from,
|
|
78
107
|
to,
|
|
@@ -81,7 +110,8 @@ function ConstellationEdge({
|
|
|
81
110
|
gap = 0.55,
|
|
82
111
|
intensityA = 0.5,
|
|
83
112
|
intensityB = 0.5,
|
|
84
|
-
dimmed
|
|
113
|
+
dimmed,
|
|
114
|
+
variant = "solid"
|
|
85
115
|
}) {
|
|
86
116
|
const { points, colorA, colorB, glowA, glowB } = useMemo(() => {
|
|
87
117
|
const a = new THREE.Vector3(...from);
|
|
@@ -109,8 +139,31 @@ function ConstellationEdge({
|
|
|
109
139
|
};
|
|
110
140
|
}, [from, to, hueA, hueB, gap, intensityA, intensityB]);
|
|
111
141
|
if (!points || !colorA || !colorB || !glowA || !glowB) return null;
|
|
112
|
-
const
|
|
113
|
-
const
|
|
142
|
+
const isDotted = variant === "dotted";
|
|
143
|
+
const glowOpacity = dimmed ? 0.04 : isDotted ? 0.08 : 0.12;
|
|
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
|
+
}
|
|
114
167
|
return /* @__PURE__ */ jsxs("group", { children: [
|
|
115
168
|
/* @__PURE__ */ jsx(
|
|
116
169
|
Line,
|
|
@@ -148,12 +201,16 @@ function Constellation({
|
|
|
148
201
|
const src = sceneMap.get(edge.source);
|
|
149
202
|
const tgt = sceneMap.get(edge.target);
|
|
150
203
|
if (src && tgt) {
|
|
151
|
-
resolvedEdges.push({ from: src.entry, to: tgt.entry });
|
|
204
|
+
resolvedEdges.push({ from: src.entry, to: tgt.entry, type: edge.type });
|
|
152
205
|
}
|
|
153
206
|
}
|
|
154
207
|
} else {
|
|
155
208
|
for (let i = 1; i < scenes.length; i++) {
|
|
156
|
-
resolvedEdges.push({
|
|
209
|
+
resolvedEdges.push({
|
|
210
|
+
from: scenes[i - 1],
|
|
211
|
+
to: scenes[i],
|
|
212
|
+
type: "sequential"
|
|
213
|
+
});
|
|
157
214
|
}
|
|
158
215
|
}
|
|
159
216
|
return /* @__PURE__ */ jsxs("group", { children: [
|
|
@@ -167,8 +224,9 @@ function Constellation({
|
|
|
167
224
|
},
|
|
168
225
|
entry.id
|
|
169
226
|
)),
|
|
170
|
-
resolvedEdges.map(({ from, to }) => {
|
|
227
|
+
resolvedEdges.map(({ from, to, type }) => {
|
|
171
228
|
const edgeDimmed = !!(from.dimmed || to.dimmed);
|
|
229
|
+
const variant = type === "go_to_scene" ? "dotted" : "solid";
|
|
172
230
|
return /* @__PURE__ */ jsx(
|
|
173
231
|
ConstellationEdge,
|
|
174
232
|
{
|
|
@@ -178,9 +236,10 @@ function Constellation({
|
|
|
178
236
|
hueB: to.visual.hue,
|
|
179
237
|
intensityA: from.visual.intensity,
|
|
180
238
|
intensityB: to.visual.intensity,
|
|
181
|
-
dimmed: edgeDimmed
|
|
239
|
+
dimmed: edgeDimmed,
|
|
240
|
+
variant
|
|
182
241
|
},
|
|
183
|
-
`edge-${from.id}-${to.id}`
|
|
242
|
+
`edge-${from.id}-${to.id}-${type}`
|
|
184
243
|
);
|
|
185
244
|
})
|
|
186
245
|
] });
|
|
@@ -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","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 } from \"react\";\nimport { Line } from \"@react-three/drei\";\nimport * as THREE from \"three\";\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}\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 * Two overlapping lines produce the glow: a thin bright core and a wider\n * soft bloom behind it.\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 {/* Outer glow pass */}\n <Line\n points={points}\n vertexColors={[glowA, glowB]}\n lineWidth={4}\n transparent\n opacity={glowOpacity}\n toneMapped={false}\n />\n {/* Inner core pass */}\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: { from: ConstellationSceneEntry; to: ConstellationSceneEntry }[] = [];\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 });\n }\n }\n } else {\n for (let i = 1; i < scenes.length; i++) {\n resolvedEdges.push({ from: scenes[i - 1], to: scenes[i] });\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 }) => {\n const edgeDimmed = !!(from.dimmed || to.dimmed);\n return (\n <ConstellationEdge\n key={`edge-${from.id}-${to.id}`}\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","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/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"]}
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/index.ts"],"names":[],"mappings":";AA4qBO,SAAS,sBAAA,CACd,WACA,IAAA,EACmB;AACnB,EAAA,IAAI,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,UAAA,EAAY;AACrC,IAAA,OAAO,SAAA,CAAU,IAAI,OAAO,EAAE,WAAW,IAAA,EAAM,MAAA,EAAQ,OAAM,CAAE,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,SAAA,CAAU,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,IAC/B,WAAW,KAAA,CAAM,QAAA;AAAA,IACjB,MAAA,EAAQ,CAAC,KAAA,CAAM;AAAA,GACjB,CAAE,CAAA;AACJ","file":"index.js","sourcesContent":["// ── Auth ──\n\nexport interface MagicLinkRequest {\n email: string;\n username?: string;\n device_name?: string;\n}\n\nexport interface MagicLinkRequestResponse {\n message: string;\n}\n\nexport interface MagicLinkVerifyRequest {\n email: string;\n token: string;\n device_name?: string;\n}\n\nexport interface MagicLinkVerifyResponse {\n token?: string;\n user: UserProfile;\n}\n\nexport interface OidcExchangeRequest {\n code: string;\n code_verifier: string;\n redirect_uri: string;\n device_name?: string;\n}\n\nexport interface OidcExchangeResponse {\n token?: string;\n user: UserProfile;\n}\n\nexport interface PasswordLoginRequest {\n email: string;\n password: string;\n device_name?: string;\n}\n\nexport interface PasswordLoginResponse {\n token?: string;\n user: UserProfile;\n}\n\n// ── User ──\n\nexport interface UserProfile {\n id: string;\n name: string;\n username: string;\n email: string;\n realm: RealmId | null;\n needs_realm_choice: boolean;\n locale: LocaleId | null;\n avatar_url: string | null;\n is_admin: boolean;\n created_at: string;\n}\n\nexport interface UpdateRealmRequest {\n realm: RealmId;\n}\n\nexport interface UpdateRealmResponse {\n realm: RealmId;\n user: UserProfile;\n}\n\nexport interface UpdateProfileRequest {\n name?: string;\n username?: string;\n}\n\nexport interface UpdateProfileResponse {\n user: UserProfile;\n}\n\nexport interface UsernameAvailabilityResponse {\n username: string;\n available: boolean;\n suggestion?: string;\n}\n\nexport interface PublicDirectorProfile {\n id: string;\n name: string;\n avatar_url: string | null;\n realm: RealmId | null;\n stories_count: number;\n}\n\n// ── Catalog ──\n\nexport interface StoryListItem {\n id: string;\n title: string;\n description: string | null;\n genre: string | null;\n content_rating: ContentRating | null;\n published: boolean;\n published_version: number;\n watch_starts_count: number;\n choice_clicks_count: number;\n scenes_count: number;\n choices_count: number;\n tags: string[];\n creator: {\n id: string;\n name: string;\n } | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface StoryPreview {\n source: \"trailer\" | \"title_scene\" | \"none\";\n title: string;\n preview_url: string | null;\n media_type: string | null;\n is_ready: boolean;\n}\n\nexport interface PopularChoice {\n label: string;\n click_count: number;\n}\n\nexport interface StoryProgress {\n last_scene_id: string | null;\n bookmark_code: string | null;\n playback_seconds: number;\n watched_version: number;\n last_watched_at: string | null;\n}\n\nexport interface CatalogResponse {\n data: StoryListItem[];\n meta: {\n previews: Record<string, StoryPreview>;\n popular_choices: Record<string, PopularChoice[]>;\n creator_avatars: Record<string, string>;\n coverboxes: Record<string, string | null>;\n progress: Record<string, StoryProgress>;\n };\n}\n\nexport interface MineResponse {\n stories: StoryListItem[];\n data?: StoryListItem[];\n progress?: Record<string, StoryProgress>;\n meta: {\n coverboxes: Record<string, string | null>;\n };\n}\n\n// ── Watch / Scene Map ──\n\nexport interface SceneChoice {\n id: string;\n label: string;\n choice_type: string;\n choice_icon: string | null;\n choice_icon_media_id: string | null;\n choice_icon_url: string | null;\n reveal_mode: string;\n start_time_seconds: number | null;\n pause_for_choice: boolean;\n end_time_seconds: number | null;\n target_scene_id: string;\n x: number;\n y: number;\n w: number;\n h: number;\n arrow_rotation: number;\n arrow_scale: number;\n fade_in_ms?: number | null;\n fade_out_ms?: number | null;\n duration_ms?: number | null;\n visibility_rules: VisibilityRules | null;\n state_updates: StateUpdate[];\n}\n\nexport interface VisibilityRules {\n mode: \"all\" | \"any\";\n conditions: VisibilityCondition[];\n}\n\nexport interface VisibilityCondition {\n variable?: string;\n key?: string;\n operator?: string;\n value?: string;\n}\n\nexport interface StateUpdate {\n variable?: string;\n key?: string;\n action?: string;\n value?: string;\n}\n\nexport interface SceneNode {\n type: string;\n properties?: Record<string, unknown>;\n children?: SceneNode[];\n}\n\nexport type SceneActionPayload = Record<string, unknown> | unknown[];\n\nexport interface SceneMapEntry {\n scene_id: string;\n scene_title: string;\n color: string | null;\n is_title: boolean;\n media_title: string | null;\n media_type: string | null;\n media_url: string | null;\n stream_status: string | null;\n choice_style: string;\n choice_overlay_mode: string;\n goto_scene_id: string | null;\n choices: SceneChoice[];\n nodes: SceneNode[];\n}\n\nexport interface TreeGraphNode {\n id: string;\n title: string;\n is_title: boolean;\n is_end: boolean;\n level: number;\n index: number;\n x: number;\n y: number;\n color: string | null;\n}\n\nexport interface TreeGraphEdge {\n id: string;\n source: string;\n target: string;\n type: \"choice\" | \"go_to_scene\";\n}\n\nexport interface TreeGraph {\n nodes: TreeGraphNode[];\n edges: TreeGraphEdge[];\n meta: {\n root_id: string | null;\n level_count: number;\n };\n}\n\nexport interface WatchSnapshot {\n scene_id: string | null;\n state: Record<string, string>;\n history: HistoryEntry[];\n path: string[];\n visited_scene_ids?: string[];\n playback_seconds: number;\n}\n\nexport interface HistoryEntry {\n choice_id: string;\n scene_id: string;\n target_scene_id: string | null;\n at: string | null;\n path_index: number | null;\n}\n\nexport interface SceneMapResponse {\n story: {\n id: string;\n title: string;\n description: string | null;\n genre: string | null;\n content_rating: ContentRating | null;\n published_version: number;\n watch_starts_count: number;\n choice_clicks_count: number;\n };\n start_scene_id: string;\n scene_map: Record<string, SceneMapEntry>;\n tree_graph: TreeGraph;\n initial_snapshot: WatchSnapshot;\n initial_bookmark_code: string | null;\n}\n\n// ── Engagement ──\n\nexport interface TrackEngagementRequest {\n event: \"play_start\" | \"choice_click\";\n choice_id?: string;\n}\n\nexport interface EngagementResponse {\n watch_starts_count: number;\n choice_clicks_count: number;\n}\n\n// ── Bookmarks ──\n\nexport interface SaveBookmarkRequest {\n snapshot: WatchSnapshot;\n}\n\nexport interface BookmarkResponse {\n code: string;\n snapshot: WatchSnapshot;\n}\n\nexport interface BookmarkListItem {\n code: string;\n snapshot: WatchSnapshot;\n updated_at: string;\n}\n\nexport interface BookmarkListResponse {\n bookmarks: BookmarkListItem[];\n}\n\n// ── Pagination ──\n\nexport interface PaginatedLink {\n url: string | null;\n label: string;\n active: boolean;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n current_page: number;\n first_page_url: string;\n from: number | null;\n last_page: number;\n last_page_url: string;\n links: PaginatedLink[];\n next_page_url: string | null;\n path: string;\n per_page: number;\n prev_page_url: string | null;\n to: number | null;\n total: number;\n}\n\n// ── Scenes ──\n\nexport type LineType = \"text\" | \"sound\" | \"image\";\n\nexport interface TextLine {\n id: string;\n type?: LineType;\n media_id?: string;\n html: string;\n appear_at_ms: number;\n fade_in_ms: number;\n fade_out_ms: number;\n duration_ms: number;\n position_x?: number;\n position_y?: number;\n width_pct?: number;\n height_pct?: number;\n persist?: boolean;\n}\n\nexport interface SceneTextContent {\n html: string;\n lines?: TextLine[];\n}\n\nexport interface SceneListItem {\n id: string;\n story_id: string;\n title: string;\n order: number;\n is_title: boolean;\n is_end: boolean;\n color: string | null;\n media_id: string | null;\n alt_media_id: string | null;\n media_mode: \"text\" | \"imagery\" | \"film\" | null;\n text_content: SceneTextContent | null;\n text_style: {\n font_family?: string | null;\n text_color?: string | null;\n background_color?: string | null;\n } | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface UpdateSceneRequest {\n title?: string;\n order?: number;\n media_id?: string | null;\n alt_media_id?: string | null;\n media_mode?: \"text\" | \"imagery\" | \"film\" | null;\n text_content?: SceneTextContent | null;\n text_style?: {\n font_family?: string | null;\n text_color?: string | null;\n background_color?: string | null;\n } | null;\n color?: string | null;\n is_title?: boolean;\n is_end?: boolean;\n goto_scene_id?: string | null;\n choice_style?: string | null;\n choice_overlay_mode?: string | null;\n choice_reveal_mode?: string | null;\n choice_start_time_seconds?: number | null;\n choice_pause_for_choice?: boolean;\n choice_end_time_seconds?: number | null;\n}\n\nexport interface CreateSceneRequest {\n story_id: string;\n title: string;\n order?: number;\n is_title?: boolean;\n is_end?: boolean;\n}\n\nexport interface SceneActionItem {\n id: string;\n scene_id: string;\n name: string;\n type: string | null;\n scene_choice_id: string | null;\n order: number;\n duration: number;\n properties: SceneActionPayload | null;\n subproperties: SceneActionPayload | null;\n created_at?: string;\n updated_at?: string;\n}\n\nexport interface CreateSceneActionRequest {\n scene_id: string;\n name: string;\n type?: string | null;\n order?: number;\n duration?: number;\n properties?: SceneActionPayload | null;\n subproperties?: SceneActionPayload | null;\n}\n\nexport interface UpdateSceneActionRequest {\n name?: string;\n type?: string | null;\n order?: number;\n duration?: number;\n properties?: SceneActionPayload;\n subproperties?: SceneActionPayload;\n}\n\n// ── AI Generation ──\n\nexport type AiGenerationStatus =\n | \"pending\"\n | \"generating\"\n | \"ready\"\n | \"failed\"\n | \"accepted\"\n | \"rejected\";\n\nexport interface GenerateImageRequest {\n story_id: string;\n scene_id?: string;\n prompt: string;\n mood?: string;\n visual_style?: string;\n rejection_feedback?: string;\n previous_generation_id?: string;\n}\n\nexport interface AiGeneration {\n id: string;\n story_id: string;\n scene_id: string | null;\n status: AiGenerationStatus;\n user_prompt: string;\n style_context: {\n mood?: string;\n visual_style?: string;\n subject_prompt: string;\n full_prompt: string;\n negative_prompt?: string;\n };\n preview_url?: string;\n rejection_feedback: string | null;\n media_id: string | null;\n attempt_number: number;\n credits_charged: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface GenerateImageResponse {\n generation: AiGeneration;\n balance: { watch: number; create: number };\n}\n\nexport interface AiGenerationShowResponse {\n generation: AiGeneration;\n}\n\nexport interface AcceptGenerationRequest {\n scene_id: string;\n}\n\nexport interface AcceptGenerationResponse {\n generation: AiGeneration;\n scene: SceneListItem;\n media: MediaItem;\n}\n\nexport interface RejectGenerationRequest {\n feedback: string;\n}\n\nexport interface RejectGenerationResponse {\n generation: AiGeneration;\n}\n\nexport interface StoryStyleResponse {\n has_style: boolean;\n style_context: AiGeneration[\"style_context\"] | null;\n}\n\n// ── Media ──\n\nexport interface MediaItem {\n id: string;\n user_id: string;\n s3_key: string;\n source_path: string;\n output_prefix: string | null;\n status: \"uploaded\" | \"processing\" | \"ready\" | \"error\";\n meta: Record<string, unknown>;\n order: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface UploadUrlRequest {\n filename: string;\n contentType: string;\n}\n\nexport interface UploadUrlResponse {\n key: string;\n uploadUrl: string;\n}\n\nexport interface RegisterMediaRequest {\n key: string;\n s3_key: string;\n filename: string;\n content_type?: string;\n title?: string;\n file_size?: number;\n}\n\nexport interface RegisterMediaResponse extends MediaItem {\n credits_charged: number;\n balance: number;\n}\n\nexport interface TranscodeRequest {\n media_id: string;\n}\n\nexport interface TranscodeResponse {\n message: string;\n job_id: string | null;\n manifest_path?: string;\n}\n\nexport interface PlayUrlResponse {\n play_url: string;\n status: string;\n}\n\nexport interface SourceUrlResponse {\n url: string;\n}\n\n// ── Story authoring ──\n\nexport interface CreateStoryRequest {\n title: string;\n description?: string | null;\n genre?: string | null;\n content_rating?: ContentRating | null;\n}\n\nexport interface UpdateStoryRequest {\n title?: string;\n description?: string | null;\n genre?: string | null;\n content_rating?: ContentRating | null;\n published?: boolean;\n tags?: string[];\n}\n\nexport interface TagListResponse {\n data: string[];\n}\n\n// ── Content Ratings ──\n\nexport type ContentRating = \"G\" | \"PG\" | \"PG-13\" | \"R\" | \"NC-17\";\n\nexport interface ContentRatingDefinition {\n id: ContentRating;\n label: string;\n description: string;\n}\n\n// ── Realm Config ──\n\nexport type RealmId = \"cosmos\" | \"wilds\";\n\n/** Supported UI locales — matches PHP `chuzi_realms.supported_locales`. */\nexport type LocaleId = \"en\" | \"es\" | \"fr\" | \"de\" | \"pt\";\n\nexport interface RealmDefinition {\n label: string;\n short_label: string;\n /** Canonical English lexicon (always present). */\n lexicon: Record<string, string>;\n /** Optional per-locale overrides; missing keys fall through to `lexicon`. */\n locales?: Partial<Record<LocaleId, Record<string, string>>>;\n}\n\nexport interface RealmConfigResponse {\n realms: Record<RealmId, RealmDefinition>;\n fallback_lexicon: Record<string, string>;\n fallback_locales?: Partial<Record<LocaleId, Record<string, string>>>;\n intro: {\n line1: string;\n line2: string;\n };\n intro_locales?: Partial<Record<LocaleId, { line1: string; line2: string }>>;\n profile: {\n title: string;\n current_prefix: string;\n switch_prompt: string;\n };\n profile_locales?: Partial<Record<LocaleId, { title: string; current_prefix: string; switch_prompt: string }>>;\n allowed_realm_ids: RealmId[];\n supported_locales: LocaleId[];\n locale_labels?: Partial<Record<LocaleId, string>>;\n}\n\nexport interface UpdateLocaleRequest {\n locale: LocaleId;\n}\n\nexport interface UpdateLocaleResponse {\n locale: LocaleId;\n}\n\n// ── Scene Visibility ──\n\nexport interface SceneVisibility {\n /** Whether the user can navigate to this scene-star. */\n navigable: boolean;\n /** Whether the star/edge should render at reduced opacity. */\n dimmed: boolean;\n}\n\n/**\n * Compute per-scene navigable/dimmed flags for a constellation.\n *\n * Rules:\n * - If `isCreator` is true, everything is navigable and bright.\n * - Title scenes are always navigable and bright.\n * - If the user has watched the ending (`endingSeen`), all scenes unlock.\n * - Otherwise non-title scenes are locked and dimmed.\n */\nexport function computeSceneVisibility(\n sceneList: Pick<SceneListItem, \"is_title\" | \"is_end\">[],\n opts: { isCreator: boolean; endingSeen: boolean },\n): SceneVisibility[] {\n if (opts.isCreator || opts.endingSeen) {\n return sceneList.map(() => ({ navigable: true, dimmed: false }));\n }\n return sceneList.map((scene) => ({\n navigable: scene.is_title,\n dimmed: !scene.is_title,\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/types/index.ts"],"names":[],"mappings":";AA8qBO,SAAS,sBAAA,CACd,WACA,IAAA,EACmB;AACnB,EAAA,IAAI,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,UAAA,EAAY;AACrC,IAAA,OAAO,SAAA,CAAU,IAAI,OAAO,EAAE,WAAW,IAAA,EAAM,MAAA,EAAQ,OAAM,CAAE,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,SAAA,CAAU,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,IAC/B,WAAW,KAAA,CAAM,QAAA;AAAA,IACjB,MAAA,EAAQ,CAAC,KAAA,CAAM;AAAA,GACjB,CAAE,CAAA;AACJ","file":"index.js","sourcesContent":["// ── Auth ──\n\nexport interface MagicLinkRequest {\n email: string;\n username?: string;\n device_name?: string;\n}\n\nexport interface MagicLinkRequestResponse {\n message: string;\n}\n\nexport interface MagicLinkVerifyRequest {\n email: string;\n token: string;\n device_name?: string;\n}\n\nexport interface MagicLinkVerifyResponse {\n token?: string;\n user: UserProfile;\n}\n\nexport interface OidcExchangeRequest {\n code: string;\n code_verifier: string;\n redirect_uri: string;\n device_name?: string;\n}\n\nexport interface OidcExchangeResponse {\n token?: string;\n user: UserProfile;\n}\n\nexport interface PasswordLoginRequest {\n email: string;\n password: string;\n device_name?: string;\n}\n\nexport interface PasswordLoginResponse {\n token?: string;\n user: UserProfile;\n}\n\n// ── User ──\n\nexport interface UserProfile {\n id: string;\n name: string;\n username: string;\n email: string;\n realm: RealmId | null;\n needs_realm_choice: boolean;\n locale: LocaleId | null;\n avatar_url: string | null;\n is_admin: boolean;\n created_at: string;\n}\n\nexport interface UpdateRealmRequest {\n realm: RealmId;\n}\n\nexport interface UpdateRealmResponse {\n realm: RealmId;\n user: UserProfile;\n}\n\nexport interface UpdateProfileRequest {\n name?: string;\n username?: string;\n}\n\nexport interface UpdateProfileResponse {\n user: UserProfile;\n}\n\nexport interface UsernameAvailabilityResponse {\n username: string;\n available: boolean;\n suggestion?: string;\n}\n\nexport interface PublicDirectorProfile {\n id: string;\n name: string;\n avatar_url: string | null;\n realm: RealmId | null;\n stories_count: number;\n}\n\n// ── Catalog ──\n\nexport interface StoryListItem {\n id: string;\n title: string;\n description: string | null;\n genre: string | null;\n content_rating: ContentRating | null;\n published: boolean;\n published_version: number;\n watch_starts_count: number;\n choice_clicks_count: number;\n scenes_count: number;\n choices_count: number;\n tags: string[];\n creator: {\n id: string;\n name: string;\n } | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface StoryPreview {\n source: \"trailer\" | \"title_scene\" | \"none\";\n title: string;\n preview_url: string | null;\n media_type: string | null;\n is_ready: boolean;\n}\n\nexport interface PopularChoice {\n label: string;\n click_count: number;\n}\n\nexport interface StoryProgress {\n last_scene_id: string | null;\n bookmark_code: string | null;\n playback_seconds: number;\n watched_version: number;\n last_watched_at: string | null;\n}\n\nexport interface CatalogResponse {\n data: StoryListItem[];\n meta: {\n previews: Record<string, StoryPreview>;\n popular_choices: Record<string, PopularChoice[]>;\n creator_avatars: Record<string, string>;\n coverboxes: Record<string, string | null>;\n progress: Record<string, StoryProgress>;\n };\n}\n\nexport interface MineResponse {\n stories: StoryListItem[];\n data?: StoryListItem[];\n progress?: Record<string, StoryProgress>;\n meta: {\n coverboxes: Record<string, string | null>;\n };\n}\n\n// ── Watch / Scene Map ──\n\nexport interface SceneChoice {\n id: string;\n label: string;\n choice_type: string;\n choice_icon: string | null;\n choice_icon_media_id: string | null;\n choice_icon_url: string | null;\n reveal_mode: string;\n start_time_seconds: number | null;\n pause_for_choice: boolean;\n end_time_seconds: number | null;\n target_scene_id: string;\n x: number;\n y: number;\n w: number;\n h: number;\n arrow_rotation: number;\n arrow_scale: number;\n fade_in_ms?: number | null;\n fade_out_ms?: number | null;\n duration_ms?: number | null;\n visibility_rules: VisibilityRules | null;\n state_updates: StateUpdate[];\n}\n\nexport interface VisibilityRules {\n mode: \"all\" | \"any\";\n conditions: VisibilityCondition[];\n}\n\nexport interface VisibilityCondition {\n variable?: string;\n key?: string;\n operator?: string;\n value?: string;\n}\n\nexport interface StateUpdate {\n variable?: string;\n key?: string;\n action?: string;\n value?: string;\n}\n\nexport interface SceneNode {\n type: string;\n properties?: Record<string, unknown>;\n children?: SceneNode[];\n}\n\nexport type SceneActionPayload = Record<string, unknown> | unknown[];\n\nexport interface SceneMapEntry {\n scene_id: string;\n scene_title: string;\n color: string | null;\n is_title: boolean;\n media_title: string | null;\n media_type: string | null;\n media_url: string | null;\n stream_status: string | null;\n choice_style: string;\n choice_overlay_mode: string;\n goto_scene_id: string | null;\n choices: SceneChoice[];\n nodes: SceneNode[];\n}\n\nexport interface TreeGraphNode {\n id: string;\n title: string;\n is_title: boolean;\n is_end: boolean;\n level: number;\n index: number;\n x: number;\n y: number;\n color: string | null;\n}\n\nexport interface TreeGraphEdge {\n id: string;\n source: string;\n target: string;\n type: \"choice\" | \"go_to_scene\";\n}\n\nexport interface TreeGraph {\n nodes: TreeGraphNode[];\n edges: TreeGraphEdge[];\n meta: {\n root_id: string | null;\n level_count: number;\n };\n}\n\nexport interface WatchSnapshot {\n scene_id: string | null;\n state: Record<string, string>;\n history: HistoryEntry[];\n path: string[];\n visited_scene_ids?: string[];\n playback_seconds: number;\n}\n\nexport interface HistoryEntry {\n choice_id: string;\n scene_id: string;\n target_scene_id: string | null;\n at: string | null;\n path_index: number | null;\n}\n\nexport interface SceneMapResponse {\n story: {\n id: string;\n title: string;\n description: string | null;\n genre: string | null;\n content_rating: ContentRating | null;\n published_version: number;\n watch_starts_count: number;\n choice_clicks_count: number;\n };\n start_scene_id: string;\n scene_map: Record<string, SceneMapEntry>;\n tree_graph: TreeGraph;\n initial_snapshot: WatchSnapshot;\n initial_bookmark_code: string | null;\n}\n\n// ── Engagement ──\n\nexport interface TrackEngagementRequest {\n event: \"play_start\" | \"choice_click\";\n choice_id?: string;\n}\n\nexport interface EngagementResponse {\n watch_starts_count: number;\n choice_clicks_count: number;\n}\n\n// ── Bookmarks ──\n\nexport interface SaveBookmarkRequest {\n snapshot: WatchSnapshot;\n}\n\nexport interface BookmarkResponse {\n code: string;\n snapshot: WatchSnapshot;\n}\n\nexport interface BookmarkListItem {\n code: string;\n snapshot: WatchSnapshot;\n updated_at: string;\n}\n\nexport interface BookmarkListResponse {\n bookmarks: BookmarkListItem[];\n}\n\n// ── Pagination ──\n\nexport interface PaginatedLink {\n url: string | null;\n label: string;\n active: boolean;\n}\n\nexport interface PaginatedResponse<T> {\n data: T[];\n current_page: number;\n first_page_url: string;\n from: number | null;\n last_page: number;\n last_page_url: string;\n links: PaginatedLink[];\n next_page_url: string | null;\n path: string;\n per_page: number;\n prev_page_url: string | null;\n to: number | null;\n total: number;\n}\n\n// ── Scenes ──\n\nexport type LineType = \"text\" | \"sound\" | \"image\";\n\nexport interface TextLine {\n id: string;\n type?: LineType;\n media_id?: string;\n html: string;\n appear_at_ms: number;\n fade_in_ms: number;\n fade_out_ms: number;\n duration_ms: number;\n position_x?: number;\n position_y?: number;\n width_pct?: number;\n height_pct?: number;\n persist?: boolean;\n}\n\nexport interface SceneTextContent {\n html: string;\n lines?: TextLine[];\n}\n\nexport interface SceneListItem {\n id: string;\n story_id: string;\n title: string;\n order: number;\n is_title: boolean;\n is_end: boolean;\n color: string | null;\n media_id: string | null;\n alt_media_id: string | null;\n media_mode: \"text\" | \"imagery\" | \"film\" | null;\n text_content: SceneTextContent | null;\n text_style: {\n font_family?: string | null;\n text_color?: string | null;\n background_color?: string | null;\n } | null;\n goto_scene_id?: string | null;\n choice_end_time_seconds?: number | null;\n created_at: string;\n updated_at: string;\n}\n\nexport interface UpdateSceneRequest {\n title?: string;\n order?: number;\n media_id?: string | null;\n alt_media_id?: string | null;\n media_mode?: \"text\" | \"imagery\" | \"film\" | null;\n text_content?: SceneTextContent | null;\n text_style?: {\n font_family?: string | null;\n text_color?: string | null;\n background_color?: string | null;\n } | null;\n color?: string | null;\n is_title?: boolean;\n is_end?: boolean;\n goto_scene_id?: string | null;\n choice_style?: string | null;\n choice_overlay_mode?: string | null;\n choice_reveal_mode?: string | null;\n choice_start_time_seconds?: number | null;\n choice_pause_for_choice?: boolean;\n choice_end_time_seconds?: number | null;\n}\n\nexport interface CreateSceneRequest {\n story_id: string;\n title: string;\n order?: number;\n is_title?: boolean;\n is_end?: boolean;\n}\n\nexport interface SceneActionItem {\n id: string;\n scene_id: string;\n name: string;\n type: string | null;\n scene_choice_id: string | null;\n order: number;\n duration: number;\n properties: SceneActionPayload | null;\n subproperties: SceneActionPayload | null;\n created_at?: string;\n updated_at?: string;\n}\n\nexport interface CreateSceneActionRequest {\n scene_id: string;\n name: string;\n type?: string | null;\n order?: number;\n duration?: number;\n properties?: SceneActionPayload | null;\n subproperties?: SceneActionPayload | null;\n}\n\nexport interface UpdateSceneActionRequest {\n name?: string;\n type?: string | null;\n order?: number;\n duration?: number;\n properties?: SceneActionPayload;\n subproperties?: SceneActionPayload;\n}\n\n// ── AI Generation ──\n\nexport type AiGenerationStatus =\n | \"pending\"\n | \"generating\"\n | \"ready\"\n | \"failed\"\n | \"accepted\"\n | \"rejected\";\n\nexport interface GenerateImageRequest {\n story_id: string;\n scene_id?: string;\n prompt: string;\n mood?: string;\n visual_style?: string;\n rejection_feedback?: string;\n previous_generation_id?: string;\n}\n\nexport interface AiGeneration {\n id: string;\n story_id: string;\n scene_id: string | null;\n status: AiGenerationStatus;\n user_prompt: string;\n style_context: {\n mood?: string;\n visual_style?: string;\n subject_prompt: string;\n full_prompt: string;\n negative_prompt?: string;\n };\n preview_url?: string;\n rejection_feedback: string | null;\n media_id: string | null;\n attempt_number: number;\n credits_charged: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface GenerateImageResponse {\n generation: AiGeneration;\n balance: { watch: number; create: number };\n}\n\nexport interface AiGenerationShowResponse {\n generation: AiGeneration;\n}\n\nexport interface AcceptGenerationRequest {\n scene_id: string;\n}\n\nexport interface AcceptGenerationResponse {\n generation: AiGeneration;\n scene: SceneListItem;\n media: MediaItem;\n}\n\nexport interface RejectGenerationRequest {\n feedback: string;\n}\n\nexport interface RejectGenerationResponse {\n generation: AiGeneration;\n}\n\nexport interface StoryStyleResponse {\n has_style: boolean;\n style_context: AiGeneration[\"style_context\"] | null;\n}\n\n// ── Media ──\n\nexport interface MediaItem {\n id: string;\n user_id: string;\n s3_key: string;\n source_path: string;\n output_prefix: string | null;\n status: \"uploaded\" | \"processing\" | \"ready\" | \"error\";\n meta: Record<string, unknown>;\n order: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface UploadUrlRequest {\n filename: string;\n contentType: string;\n}\n\nexport interface UploadUrlResponse {\n key: string;\n uploadUrl: string;\n}\n\nexport interface RegisterMediaRequest {\n key: string;\n s3_key: string;\n filename: string;\n content_type?: string;\n title?: string;\n file_size?: number;\n}\n\nexport interface RegisterMediaResponse extends MediaItem {\n credits_charged: number;\n balance: number;\n}\n\nexport interface TranscodeRequest {\n media_id: string;\n}\n\nexport interface TranscodeResponse {\n message: string;\n job_id: string | null;\n manifest_path?: string;\n}\n\nexport interface PlayUrlResponse {\n play_url: string;\n status: string;\n}\n\nexport interface SourceUrlResponse {\n url: string;\n}\n\n// ── Story authoring ──\n\nexport interface CreateStoryRequest {\n title: string;\n description?: string | null;\n genre?: string | null;\n content_rating?: ContentRating | null;\n}\n\nexport interface UpdateStoryRequest {\n title?: string;\n description?: string | null;\n genre?: string | null;\n content_rating?: ContentRating | null;\n published?: boolean;\n tags?: string[];\n}\n\nexport interface TagListResponse {\n data: string[];\n}\n\n// ── Content Ratings ──\n\nexport type ContentRating = \"G\" | \"PG\" | \"PG-13\" | \"R\" | \"NC-17\";\n\nexport interface ContentRatingDefinition {\n id: ContentRating;\n label: string;\n description: string;\n}\n\n// ── Realm Config ──\n\nexport type RealmId = \"cosmos\" | \"wilds\";\n\n/** Supported UI locales — matches PHP `chuzi_realms.supported_locales`. */\nexport type LocaleId = \"en\" | \"es\" | \"fr\" | \"de\" | \"pt\";\n\nexport interface RealmDefinition {\n label: string;\n short_label: string;\n /** Canonical English lexicon (always present). */\n lexicon: Record<string, string>;\n /** Optional per-locale overrides; missing keys fall through to `lexicon`. */\n locales?: Partial<Record<LocaleId, Record<string, string>>>;\n}\n\nexport interface RealmConfigResponse {\n realms: Record<RealmId, RealmDefinition>;\n fallback_lexicon: Record<string, string>;\n fallback_locales?: Partial<Record<LocaleId, Record<string, string>>>;\n intro: {\n line1: string;\n line2: string;\n };\n intro_locales?: Partial<Record<LocaleId, { line1: string; line2: string }>>;\n profile: {\n title: string;\n current_prefix: string;\n switch_prompt: string;\n };\n profile_locales?: Partial<Record<LocaleId, { title: string; current_prefix: string; switch_prompt: string }>>;\n allowed_realm_ids: RealmId[];\n supported_locales: LocaleId[];\n locale_labels?: Partial<Record<LocaleId, string>>;\n}\n\nexport interface UpdateLocaleRequest {\n locale: LocaleId;\n}\n\nexport interface UpdateLocaleResponse {\n locale: LocaleId;\n}\n\n// ── Scene Visibility ──\n\nexport interface SceneVisibility {\n /** Whether the user can navigate to this scene-star. */\n navigable: boolean;\n /** Whether the star/edge should render at reduced opacity. */\n dimmed: boolean;\n}\n\n/**\n * Compute per-scene navigable/dimmed flags for a constellation.\n *\n * Rules:\n * - If `isCreator` is true, everything is navigable and bright.\n * - Title scenes are always navigable and bright.\n * - If the user has watched the ending (`endingSeen`), all scenes unlock.\n * - Otherwise non-title scenes are locked and dimmed.\n */\nexport function computeSceneVisibility(\n sceneList: Pick<SceneListItem, \"is_title\" | \"is_end\">[],\n opts: { isCreator: boolean; endingSeen: boolean },\n): SceneVisibility[] {\n if (opts.isCreator || opts.endingSeen) {\n return sceneList.map(() => ({ navigable: true, dimmed: false }));\n }\n return sceneList.map((scene) => ({\n navigable: scene.is_title,\n dimmed: !scene.is_title,\n }));\n}\n"]}
|
package/dist/ui/index.js
CHANGED
|
@@ -138,6 +138,11 @@ var REALMS = {
|
|
|
138
138
|
editor_choices_empty_hint: "Set a goto star or add a trajectory to branch the story.",
|
|
139
139
|
editor_goto_none: "None",
|
|
140
140
|
editor_choice_label: "Trajectory",
|
|
141
|
+
editor_flow_timeline: "Story Flow",
|
|
142
|
+
editor_flow_goto_path: "Default Goto",
|
|
143
|
+
editor_flow_add_choice_here: "Add Trajectory Here",
|
|
144
|
+
editor_flow_choice_branch: "Branch",
|
|
145
|
+
editor_flow_content_ref: "Content",
|
|
141
146
|
editor_scene_duration_unit: "seconds",
|
|
142
147
|
editor_scene_duration_override_hint: "Overrides transmission length. Signal runtime: {duration}s",
|
|
143
148
|
editor_arrow_scale: "Span",
|
|
@@ -431,6 +436,11 @@ var REALMS = {
|
|
|
431
436
|
editor_choices_empty_hint: "Set a goto clearing or add a trail to branch the story.",
|
|
432
437
|
editor_goto_none: "None",
|
|
433
438
|
editor_choice_label: "Trail",
|
|
439
|
+
editor_flow_timeline: "Story Flow",
|
|
440
|
+
editor_flow_goto_path: "Default Goto",
|
|
441
|
+
editor_flow_add_choice_here: "Add Trail Here",
|
|
442
|
+
editor_flow_choice_branch: "Branch",
|
|
443
|
+
editor_flow_content_ref: "Content",
|
|
434
444
|
editor_scene_duration_unit: "seconds",
|
|
435
445
|
editor_scene_duration_override_hint: "Overrides bloom length. Content runtime: {duration}s",
|
|
436
446
|
editor_arrow_scale: "Span",
|
|
@@ -722,6 +732,11 @@ var FALLBACK_LEXICON = {
|
|
|
722
732
|
editor_choices_empty_hint: "Set a goto scene or add a choice to create branching paths.",
|
|
723
733
|
editor_goto_none: "None",
|
|
724
734
|
editor_choice_label: "Choice",
|
|
735
|
+
editor_flow_timeline: "Story Flow",
|
|
736
|
+
editor_flow_goto_path: "Default Goto",
|
|
737
|
+
editor_flow_add_choice_here: "Add Choice Here",
|
|
738
|
+
editor_flow_choice_branch: "Branch",
|
|
739
|
+
editor_flow_content_ref: "Content",
|
|
725
740
|
editor_scene_duration_unit: "seconds",
|
|
726
741
|
editor_scene_duration_override_hint: "Overrides preview playback length. Content: {duration}s",
|
|
727
742
|
editor_arrow_scale: "Scale",
|