@chuzi/shared 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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}\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 },\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 },\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}\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 }: 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 lightness = 50 + visual.intensity * 25;\n const color = `hsl(${visual.hue}, 75%, ${lightness}%)`;\n\n return (\n <mesh\n ref={ref}\n position={visual.position}\n onClick={\n onSelect\n ? (e) => {\n e.stopPropagation();\n onSelect();\n }\n : undefined\n }\n >\n <sphereGeometry args={[0.5, 16, 16]} />\n <meshBasicMaterial color={color} toneMapped={false} />\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}\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}: 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 return (\n <group>\n {/* Outer glow pass */}\n <Line\n points={points}\n vertexColors={[glowA, glowB]}\n lineWidth={4}\n transparent\n opacity={0.12}\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={0.6}\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}\n\nexport interface ConstellationProps {\n /** Scene entries in order (title first, end last), already positioned. */\n scenes: ConstellationSceneEntry[];\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 */\nexport function Constellation({\n scenes,\n onSceneSelect,\n}: ConstellationProps) {\n return (\n <group>\n {scenes.map((entry, i) => (\n <Star\n key={entry.id}\n visual={entry.visual}\n onSelect={onSceneSelect ? () => onSceneSelect(i) : undefined}\n />\n ))}\n\n {scenes.map((entry, i) => {\n if (i === 0) return null;\n const prev = scenes[i - 1];\n return (\n <ConstellationEdge\n key={`edge-${prev.id}-${entry.id}`}\n from={prev.visual.position}\n to={entry.visual.position}\n hueA={prev.visual.hue}\n hueB={entry.visual.hue}\n intensityA={prev.visual.intensity}\n intensityB={entry.visual.intensity}\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","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}\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 },\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 },\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 ConstellationProps {\n /** Scene entries in order (title first, end last), already positioned. */\n scenes: ConstellationSceneEntry[];\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 */\nexport function Constellation({\n scenes,\n onSceneSelect,\n}: ConstellationProps) {\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 {scenes.map((entry, i) => {\n if (i === 0) return null;\n const prev = scenes[i - 1];\n const edgeDimmed = !!(entry.dimmed || prev.dimmed);\n return (\n <ConstellationEdge\n key={`edge-${prev.id}-${entry.id}`}\n from={prev.visual.position}\n to={entry.visual.position}\n hueA={prev.visual.hue}\n hueB={entry.visual.hue}\n intensityA={prev.visual.intensity}\n intensityB={entry.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"]}
@@ -43,6 +43,7 @@ interface StoryListItem {
43
43
  choice_clicks_count: number;
44
44
  scenes_count: number;
45
45
  choices_count: number;
46
+ tags: string[];
46
47
  creator: {
47
48
  id: string;
48
49
  name: string;
@@ -384,6 +385,17 @@ interface CreateStoryRequest {
384
385
  genre?: string | null;
385
386
  content_rating?: ContentRating | null;
386
387
  }
388
+ interface UpdateStoryRequest {
389
+ title?: string;
390
+ description?: string | null;
391
+ genre?: string | null;
392
+ content_rating?: ContentRating | null;
393
+ published?: boolean;
394
+ tags?: string[];
395
+ }
396
+ interface TagListResponse {
397
+ data: string[];
398
+ }
387
399
  type ContentRating = "G" | "PG" | "PG-13" | "R" | "NC-17";
388
400
  interface ContentRatingDefinition {
389
401
  id: ContentRating;
@@ -433,5 +445,24 @@ interface UpdateLocaleRequest {
433
445
  interface UpdateLocaleResponse {
434
446
  locale: LocaleId;
435
447
  }
448
+ interface SceneVisibility {
449
+ /** Whether the user can navigate to this scene-star. */
450
+ navigable: boolean;
451
+ /** Whether the star/edge should render at reduced opacity. */
452
+ dimmed: boolean;
453
+ }
454
+ /**
455
+ * Compute per-scene navigable/dimmed flags for a constellation.
456
+ *
457
+ * Rules:
458
+ * - If `isCreator` is true, everything is navigable and bright.
459
+ * - Title scenes are always navigable and bright.
460
+ * - If the user has watched the ending (`endingSeen`), all scenes unlock.
461
+ * - Otherwise non-title scenes are locked and dimmed.
462
+ */
463
+ declare function computeSceneVisibility(sceneList: Pick<SceneListItem, "is_title" | "is_end">[], opts: {
464
+ isCreator: boolean;
465
+ endingSeen: boolean;
466
+ }): SceneVisibility[];
436
467
 
437
- export type { AcceptGenerationRequest, AcceptGenerationResponse, AiGeneration, AiGenerationShowResponse, AiGenerationStatus, BookmarkListItem, BookmarkListResponse, BookmarkResponse, CatalogResponse, ContentRating, ContentRatingDefinition, CreateSceneRequest, CreateStoryRequest, EngagementResponse, GenerateImageRequest, GenerateImageResponse, HistoryEntry, LocaleId, LoginRequest, LoginResponse, MediaItem, MineResponse, PaginatedLink, PaginatedResponse, PlayUrlResponse, PopularChoice, RealmConfigResponse, RealmDefinition, RealmId, RegisterMediaRequest, RegisterMediaResponse, RejectGenerationRequest, RejectGenerationResponse, SaveBookmarkRequest, SceneChoice, SceneListItem, SceneMapEntry, SceneMapResponse, SceneNode, SourceUrlResponse, StateUpdate, StoryListItem, StoryPreview, StoryProgress, StoryStyleResponse, TrackEngagementRequest, TranscodeRequest, TranscodeResponse, TreeGraph, TreeGraphEdge, TreeGraphNode, UpdateLocaleRequest, UpdateLocaleResponse, UpdateProfileRequest, UpdateProfileResponse, UpdateRealmRequest, UpdateRealmResponse, UpdateSceneRequest, UploadUrlRequest, UploadUrlResponse, UserProfile, VisibilityCondition, VisibilityRules, WatchSnapshot };
468
+ export { type AcceptGenerationRequest, type AcceptGenerationResponse, type AiGeneration, type AiGenerationShowResponse, type AiGenerationStatus, type BookmarkListItem, type BookmarkListResponse, type BookmarkResponse, type CatalogResponse, type ContentRating, type ContentRatingDefinition, type CreateSceneRequest, type CreateStoryRequest, type EngagementResponse, type GenerateImageRequest, type GenerateImageResponse, type HistoryEntry, type LocaleId, type LoginRequest, type LoginResponse, type MediaItem, type MineResponse, type PaginatedLink, type PaginatedResponse, type PlayUrlResponse, type PopularChoice, type RealmConfigResponse, type RealmDefinition, type RealmId, type RegisterMediaRequest, type RegisterMediaResponse, type RejectGenerationRequest, type RejectGenerationResponse, type SaveBookmarkRequest, type SceneChoice, type SceneListItem, type SceneMapEntry, type SceneMapResponse, type SceneNode, type SceneVisibility, type SourceUrlResponse, type StateUpdate, type StoryListItem, type StoryPreview, type StoryProgress, type StoryStyleResponse, type TagListResponse, type TrackEngagementRequest, type TranscodeRequest, type TranscodeResponse, type TreeGraph, type TreeGraphEdge, type TreeGraphNode, type UpdateLocaleRequest, type UpdateLocaleResponse, type UpdateProfileRequest, type UpdateProfileResponse, type UpdateRealmRequest, type UpdateRealmResponse, type UpdateSceneRequest, type UpdateStoryRequest, type UploadUrlRequest, type UploadUrlResponse, type UserProfile, type VisibilityCondition, type VisibilityRules, type WatchSnapshot, computeSceneVisibility };
@@ -1,3 +1,14 @@
1
+ // src/types/index.ts
2
+ function computeSceneVisibility(sceneList, opts) {
3
+ if (opts.isCreator || opts.endingSeen) {
4
+ return sceneList.map(() => ({ navigable: true, dimmed: false }));
5
+ }
6
+ return sceneList.map((scene) => ({
7
+ navigable: scene.is_title,
8
+ dimmed: !scene.is_title
9
+ }));
10
+ }
1
11
 
12
+ export { computeSceneVisibility };
2
13
  //# sourceMappingURL=index.js.map
3
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
1
+ {"version":3,"sources":["../../src/types/index.ts"],"names":[],"mappings":";AAyiBO,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 LoginRequest {\n email: string;\n password: string;\n device_name: string;\n}\n\nexport interface LoginResponse {\n token: string;\n user: UserProfile;\n}\n\n// ── User ──\n\nexport interface UserProfile {\n id: string;\n name: 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}\n\nexport interface UpdateProfileResponse {\n user: UserProfile;\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 data: StoryListItem[];\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 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 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 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 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 color?: string | null;\n is_title?: boolean;\n is_end?: boolean;\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}\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
@@ -89,7 +89,14 @@ var REALMS = {
89
89
  editor_remove_media: "Remove Transmission",
90
90
  constellation_no_coverbox: "Uncharted",
91
91
  hud_edit_control: "Engage",
92
- hud_delete_control: "Jettison"
92
+ hud_delete_control: "Jettison",
93
+ hud_publish_control: "Launch",
94
+ create_button: "CREATE",
95
+ publish_form_heading: "Launch readiness",
96
+ tags_label: "Signal Tags",
97
+ tags_placeholder: "Search signal tags\u2026",
98
+ tags_empty: "No signal tags yet",
99
+ story_picker_label: "Constellations"
93
100
  },
94
101
  locales: {
95
102
  es: {
@@ -221,7 +228,14 @@ var REALMS = {
221
228
  editor_remove_media: "Uproot Bloom",
222
229
  constellation_no_coverbox: "Unseen",
223
230
  hud_edit_control: "Tend",
224
- hud_delete_control: "Uproot"
231
+ hud_delete_control: "Uproot",
232
+ hud_publish_control: "Plant",
233
+ create_button: "CREATE",
234
+ publish_form_heading: "Planting check",
235
+ tags_label: "Root Tags",
236
+ tags_placeholder: "Search root tags\u2026",
237
+ tags_empty: "No root tags yet",
238
+ story_picker_label: "Groves"
225
239
  },
226
240
  locales: {
227
241
  es: {
@@ -351,7 +365,14 @@ var FALLBACK_LEXICON = {
351
365
  editor_remove_media: "Remove Media",
352
366
  constellation_no_coverbox: "No cover",
353
367
  hud_edit_control: "Edit",
354
- hud_delete_control: "Delete"
368
+ hud_delete_control: "Delete",
369
+ hud_publish_control: "Publish",
370
+ create_button: "CREATE",
371
+ publish_form_heading: "Publish checklist",
372
+ tags_label: "Tags",
373
+ tags_placeholder: "Search tags\u2026",
374
+ tags_empty: "No tags yet",
375
+ story_picker_label: "Stories"
355
376
  };
356
377
  var FALLBACK_LOCALES = {
357
378
  es: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/index.ts","../../src/themes/index.ts","../../src/ui/theme/RealmThemeProvider.tsx","../../src/ui/Button.tsx","../../src/ui/FilmCard.tsx","../../src/ui/CreditBadge.tsx"],"names":["jsx","t","Text","styles","Pressable","StyleSheet","jsxs","View"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n RealmId,\n RealmDefinition,\n ContentRating,\n ContentRatingDefinition,\n LocaleId,\n} from \"../types/index.js\";\n\nexport const REALM_IDS: readonly RealmId[] = [\"cosmos\", \"wilds\"] as const;\n\nexport const SUPPORTED_LOCALES: readonly LocaleId[] = [\n \"en\",\n \"es\",\n \"fr\",\n \"de\",\n \"pt\",\n] as const;\n\nexport const LOCALE_LABELS: Record<LocaleId, string> = {\n en: \"English\",\n es: \"Español\",\n fr: \"Français\",\n de: \"Deutsch\",\n pt: \"Português\",\n};\n\nexport const DEFAULT_LOCALE: LocaleId = \"en\";\n\nexport function isSupportedLocale(value: unknown): value is LocaleId {\n return (\n typeof value === \"string\" &&\n SUPPORTED_LOCALES.includes(value as LocaleId)\n );\n}\n\n/**\n * Normalize a raw locale tag (e.g. \"en-US\", \"pt_BR\") to a supported LocaleId,\n * matching the PHP `LocaleResolver::normalize` behavior.\n */\nexport function normalizeLocale(value: string | null | undefined): LocaleId | null {\n if (!value) return null;\n const lower = value.toLowerCase().trim();\n if (isSupportedLocale(lower)) return lower;\n const base = lower.split(/[-_]/, 1)[0];\n return isSupportedLocale(base) ? base : null;\n}\n\n/**\n * Pick the best supported locale from a browser Accept-Language string.\n * Mirrors PHP `LocaleResolver::matchAcceptLanguage` (q-value aware).\n */\nexport function matchAcceptLanguage(\n accept: string | null | undefined\n): LocaleId | null {\n if (!accept) return null;\n const tags = accept\n .split(\",\")\n .map((part) => {\n const [tag, ...params] = part.trim().split(\";\");\n const qParam = params.find((p) => p.trim().startsWith(\"q=\"));\n const q = qParam ? parseFloat(qParam.split(\"=\")[1]) || 0 : 1;\n return { tag: tag.trim(), q };\n })\n .filter((c) => c.tag && c.tag !== \"*\")\n .sort((a, b) => b.q - a.q);\n\n for (const c of tags) {\n const normalized = normalizeLocale(c.tag);\n if (normalized) return normalized;\n }\n return null;\n}\n\nexport const CONTENT_RATING_IDS: readonly ContentRating[] = [\n \"G\",\n \"PG\",\n \"PG-13\",\n \"R\",\n \"NC-17\",\n] as const;\n\nexport const CONTENT_RATINGS: Record<ContentRating, ContentRatingDefinition> = {\n G: {\n id: \"G\",\n label: \"G\",\n description: \"General Audiences — all ages admitted.\",\n },\n PG: {\n id: \"PG\",\n label: \"PG\",\n description: \"Parental Guidance Suggested — some material may not be suitable for children.\",\n },\n \"PG-13\": {\n id: \"PG-13\",\n label: \"PG-13\",\n description: \"Parents Strongly Cautioned — some material may be inappropriate for children under 13.\",\n },\n R: {\n id: \"R\",\n label: \"R\",\n description: \"Restricted — under 17 requires accompanying parent or adult guardian.\",\n },\n \"NC-17\": {\n id: \"NC-17\",\n label: \"NC-17\",\n description: \"Adults Only — no one 17 and under admitted.\",\n },\n};\n\nexport function isContentRating(value: unknown): value is ContentRating {\n return typeof value === \"string\" && CONTENT_RATING_IDS.includes(value as ContentRating);\n}\n\nexport const REALMS: Record<RealmId, RealmDefinition> = {\n cosmos: {\n label: \"CHUZI COSMOS\",\n short_label: \"Cosmos\",\n lexicon: {\n genre: \"Galaxy\",\n story: \"Star System\",\n scene: \"Planet\",\n scene_choice: \"Trajectory\",\n node: \"Signal\",\n node_type_choice: \"Trajectory\",\n node_type_media: \"Transmission\",\n node_type_go_to_scene: \"Warp\",\n player: \"Voyager\",\n library: \"Star Chart\",\n library_open: \"Open Star Chart\",\n library_close: \"Close Star Chart\",\n editor: \"Mission Control\",\n publish: \"Launch\",\n the_end: \"Final Orbit\",\n media_pool: \"Cargo Bay\",\n scene_graph: \"Star Chart\",\n watch_path: \"Your trajectory\",\n untitled_story: \"Untitled Star System\",\n unknown_genre: \"Unknown Galaxy\",\n scenes_count: \"planets\",\n choices_count: \"trajectories\",\n drafts_published: \"Drafts + Launched\",\n published_ver: \"Launched ver.\",\n draft: \"Draft\",\n no_scenes_yet: \"No planets in this chart yet.\",\n no_path_yet: \"No trajectory to show yet.\",\n menu_empty_drafts: \"No star systems yet. Chart one to begin.\",\n menu_empty_published: \"No launched systems in the chart.\",\n menu_published_heading: \"Launched constellations\",\n menu_create_story: \"New star system\",\n menu_create_film: \"Create film\",\n film_title_placeholder: \"Star system title\",\n select_genre: \"Select galaxy\",\n genre_field_aria: \"Galaxy\",\n delete_story_verb: \"Delete star system\",\n title_scene_default: \"Title planet\",\n choices_made_stat: \"trajectories taken\",\n content_rating: \"Audience Class\",\n content_rating_field_aria: \"Audience class\",\n select_content_rating: \"Select audience class\",\n unrated: \"Unclassified\",\n viewer_credits: \"Fuel Cells\",\n creator_credits: \"Stardust\",\n editor_media_upload: \"Upload Transmission\",\n editor_media_preview: \"Transmission Preview\",\n editor_alt_media: \"Additional Transmission\",\n editor_choices: \"Trajectories\",\n editor_scene_settings: \"Star Settings\",\n editor_title_scene: \"Title Star\",\n editor_ending_scene: \"Final Star\",\n editor_play: \"Engage\",\n editor_pause: \"Hold\",\n editor_prev_frame: \"Previous Frame\",\n editor_next_frame: \"Next Frame\",\n editor_seek: \"Seek\",\n editor_no_media: \"No transmission assigned\",\n editor_uploading: \"Transmitting\\u2026\",\n editor_drop_media: \"Drop transmission here\",\n editor_scene_type: \"Star Type\",\n editor_save: \"Lock In\",\n editor_scene_color: \"Star Hue\",\n editor_ai_generate: \"Generate Transmission\",\n editor_ai_generating: \"Transmitting Signal\\u2026\",\n editor_ai_mood_question: \"What energy should this planet radiate?\",\n editor_ai_style_question: \"What vision style for this transmission?\",\n editor_ai_prompt_question: \"Describe this planet\\u2019s landscape\",\n editor_ai_accept: \"Lock Transmission\",\n editor_ai_reject: \"Reject Signal\",\n editor_ai_retry: \"Retransmit\",\n editor_ai_feedback_prompt: \"How should we adjust the signal?\",\n editor_ai_credit_cost: \"1 Stardust per signal\",\n editor_ai_generating_scene: \"Planet forming\\u2026\",\n editor_ai_style_badge: \"Signal Style\",\n editor_ai_failed: \"Signal lost. Try retransmitting.\",\n editor_media_attached: \"This star already has a transmission locked in.\",\n editor_remove_media: \"Remove Transmission\",\n constellation_no_coverbox: \"Uncharted\",\n hud_edit_control: \"Engage\",\n hud_delete_control: \"Jettison\",\n },\n locales: {\n es: {\n genre: \"Galaxia\",\n story: \"Sistema Estelar\",\n scene: \"Planeta\",\n scene_choice: \"Trayectoria\",\n player: \"Viajero\",\n library: \"Carta Estelar\",\n editor: \"Control de Misión\",\n publish: \"Lanzar\",\n the_end: \"Órbita Final\",\n untitled_story: \"Sistema Estelar sin título\",\n menu_create_story: \"Nuevo sistema estelar\",\n film_title_placeholder: \"Título del sistema estelar\",\n select_genre: \"Seleccionar galaxia\",\n },\n fr: {\n genre: \"Galaxie\",\n story: \"Système Stellaire\",\n scene: \"Planète\",\n scene_choice: \"Trajectoire\",\n player: \"Voyageur\",\n library: \"Carte Stellaire\",\n editor: \"Contrôle de Mission\",\n publish: \"Lancer\",\n the_end: \"Orbite Finale\",\n untitled_story: \"Système stellaire sans titre\",\n menu_create_story: \"Nouveau système stellaire\",\n film_title_placeholder: \"Titre du système stellaire\",\n select_genre: \"Sélectionner une galaxie\",\n },\n de: {\n genre: \"Galaxie\",\n story: \"Sternsystem\",\n scene: \"Planet\",\n player: \"Reisender\",\n publish: \"Starten\",\n },\n pt: {\n genre: \"Galáxia\",\n story: \"Sistema Estelar\",\n scene: \"Planeta\",\n player: \"Viajante\",\n publish: \"Lançar\",\n },\n },\n },\n wilds: {\n label: \"CHUZI WILDS\",\n short_label: \"Wilds\",\n lexicon: {\n genre: \"Biome\",\n story: \"Grove\",\n scene: \"Clearing\",\n scene_choice: \"Trail\",\n node: \"Seed\",\n node_type_choice: \"Trail\",\n node_type_media: \"Bloom\",\n node_type_go_to_scene: \"Crossing\",\n player: \"Wanderer\",\n library: \"Canopy\",\n library_open: \"Open Canopy\",\n library_close: \"Close Canopy\",\n editor: \"Heartwood\",\n publish: \"Plant\",\n the_end: \"Roots\",\n media_pool: \"Undergrowth\",\n scene_graph: \"Canopy\",\n watch_path: \"Your trail\",\n untitled_story: \"Untitled Grove\",\n unknown_genre: \"Unknown Biome\",\n scenes_count: \"clearings\",\n choices_count: \"trails\",\n drafts_published: \"Drafts + Planted\",\n published_ver: \"Planted ver.\",\n draft: \"Draft\",\n no_scenes_yet: \"No clearings in this canopy yet.\",\n no_path_yet: \"No trail to show yet.\",\n menu_empty_drafts: \"No groves yet. Plant one to begin.\",\n menu_empty_published: \"No planted groves in the canopy.\",\n menu_published_heading: \"Planted groves\",\n menu_create_story: \"New grove\",\n menu_create_film: \"Create film\",\n film_title_placeholder: \"Grove title\",\n select_genre: \"Select biome\",\n genre_field_aria: \"Biome\",\n delete_story_verb: \"Delete grove\",\n title_scene_default: \"Title clearing\",\n choices_made_stat: \"trails taken\",\n content_rating: \"Field Guide\",\n content_rating_field_aria: \"Field guide\",\n select_content_rating: \"Select field guide\",\n unrated: \"Unmarked\",\n viewer_credits: \"Sap\",\n creator_credits: \"Pollen\",\n editor_media_upload: \"Upload Bloom\",\n editor_media_preview: \"Bloom Preview\",\n editor_alt_media: \"Additional Bloom\",\n editor_choices: \"Trails\",\n editor_scene_settings: \"Clearing Settings\",\n editor_title_scene: \"Title Clearing\",\n editor_ending_scene: \"Roots\",\n editor_play: \"Unfurl\",\n editor_pause: \"Rest\",\n editor_prev_frame: \"Previous Frame\",\n editor_next_frame: \"Next Frame\",\n editor_seek: \"Seek\",\n editor_no_media: \"No bloom assigned\",\n editor_uploading: \"Blooming\\u2026\",\n editor_drop_media: \"Drop bloom here\",\n editor_scene_type: \"Clearing Type\",\n editor_save: \"Engrave\",\n editor_scene_color: \"Clearing Tint\",\n editor_ai_generate: \"Grow Bloom\",\n editor_ai_generating: \"Seed Sprouting\\u2026\",\n editor_ai_mood_question: \"What feeling should this clearing evoke?\",\n editor_ai_style_question: \"What growth pattern for this bloom?\",\n editor_ai_prompt_question: \"Describe this clearing\",\n editor_ai_accept: \"Root Bloom\",\n editor_ai_reject: \"Prune Bloom\",\n editor_ai_retry: \"Regrow\",\n editor_ai_feedback_prompt: \"How should we reshape the growth?\",\n editor_ai_credit_cost: \"1 Pollen per bloom\",\n editor_ai_generating_scene: \"Clearing emerging\\u2026\",\n editor_ai_style_badge: \"Growth Style\",\n editor_ai_failed: \"Growth withered. Try regrowing.\",\n editor_media_attached: \"This clearing already has a bloom rooted.\",\n editor_remove_media: \"Uproot Bloom\",\n constellation_no_coverbox: \"Unseen\",\n hud_edit_control: \"Tend\",\n hud_delete_control: \"Uproot\",\n },\n locales: {\n es: {\n genre: \"Bioma\",\n story: \"Arboleda\",\n scene: \"Claro\",\n scene_choice: \"Sendero\",\n player: \"Errante\",\n library: \"Dosel\",\n editor: \"Duramen\",\n publish: \"Plantar\",\n the_end: \"Raíces\",\n untitled_story: \"Arboleda sin título\",\n menu_create_story: \"Nueva arboleda\",\n film_title_placeholder: \"Título de la arboleda\",\n select_genre: \"Seleccionar bioma\",\n },\n fr: {\n genre: \"Biome\",\n story: \"Bosquet\",\n scene: \"Clairière\",\n scene_choice: \"Sentier\",\n player: \"Vagabond\",\n library: \"Canopée\",\n editor: \"Cœur de bois\",\n publish: \"Planter\",\n the_end: \"Racines\",\n untitled_story: \"Bosquet sans titre\",\n menu_create_story: \"Nouveau bosquet\",\n film_title_placeholder: \"Titre du bosquet\",\n select_genre: \"Sélectionner un biome\",\n },\n de: {\n genre: \"Biom\",\n story: \"Hain\",\n scene: \"Lichtung\",\n player: \"Wanderer\",\n publish: \"Pflanzen\",\n },\n pt: {\n genre: \"Bioma\",\n story: \"Bosque\",\n scene: \"Clareira\",\n player: \"Andarilho\",\n publish: \"Plantar\",\n },\n },\n },\n};\n\nexport const FALLBACK_LEXICON: Record<string, string> = {\n genre: \"Genre\",\n story: \"Story\",\n scene: \"Scene\",\n scene_choice: \"Choice\",\n node: \"Node\",\n node_type_choice: \"Choice\",\n node_type_media: \"Media\",\n node_type_go_to_scene: \"Go to scene\",\n player: \"Player\",\n library: \"Library\",\n library_open: \"Open scene tree\",\n library_close: \"Close scene tree\",\n editor: \"Editor\",\n publish: \"Publish\",\n the_end: \"The End\",\n media_pool: \"Media Pool\",\n scene_graph: \"Scene tree\",\n watch_path: \"Your path\",\n untitled_story: \"Untitled Story\",\n unknown_genre: \"Unknown Genre\",\n scenes_count: \"scenes\",\n choices_count: \"choices\",\n drafts_published: \"Drafts + Published\",\n published_ver: \"Published ver.\",\n draft: \"Draft\",\n no_scenes_yet: \"No scenes available yet.\",\n no_path_yet: \"No path to show yet.\",\n menu_empty_drafts: \"No films yet. Create one to get started.\",\n menu_empty_published: \"No published films found.\",\n menu_published_heading: \"Published Films\",\n menu_create_story: \"Create Story\",\n menu_create_film: \"Create Film\",\n film_title_placeholder: \"Film title\",\n select_genre: \"Select genre\",\n genre_field_aria: \"Film genre\",\n delete_story_verb: \"Delete film\",\n title_scene_default: \"Title Scene\",\n choices_made_stat: \"choices made\",\n content_rating: \"Rating\",\n content_rating_field_aria: \"Content rating\",\n select_content_rating: \"Select rating\",\n unrated: \"Not Rated\",\n viewer_credits: \"Viewer Credits\",\n creator_credits: \"Creator Credits\",\n editor_media_upload: \"Upload Media\",\n editor_media_preview: \"Media Preview\",\n editor_alt_media: \"Additional Media\",\n editor_choices: \"Choices\",\n editor_scene_settings: \"Scene Settings\",\n editor_title_scene: \"Title Scene\",\n editor_ending_scene: \"Ending Scene\",\n editor_play: \"Play\",\n editor_pause: \"Pause\",\n editor_prev_frame: \"Previous Frame\",\n editor_next_frame: \"Next Frame\",\n editor_seek: \"Seek\",\n editor_no_media: \"No media assigned\",\n editor_uploading: \"Uploading\\u2026\",\n editor_drop_media: \"Drop media here\",\n editor_scene_type: \"Scene Type\",\n editor_save: \"Save\",\n editor_scene_color: \"Scene Color\",\n editor_ai_generate: \"Generate with AI\",\n editor_ai_generating: \"Generating\\u2026\",\n editor_ai_mood_question: \"What mood should this scene convey?\",\n editor_ai_style_question: \"What visual style do you want?\",\n editor_ai_prompt_question: \"Describe this scene\",\n editor_ai_accept: \"Accept\",\n editor_ai_reject: \"Reject\",\n editor_ai_retry: \"Try Again\",\n editor_ai_feedback_prompt: \"What should we change?\",\n editor_ai_credit_cost: \"1 credit per generation\",\n editor_ai_generating_scene: \"Scene generating\\u2026\",\n editor_ai_style_badge: \"Style\",\n editor_ai_failed: \"Generation failed. Please try again.\",\n editor_media_attached: \"This scene already has media attached.\",\n editor_remove_media: \"Remove Media\",\n constellation_no_coverbox: \"No cover\",\n hud_edit_control: \"Edit\",\n hud_delete_control: \"Delete\",\n};\n\n/**\n * Per-locale overrides for FALLBACK_LEXICON. Missing keys fall through to\n * the English fallback. Mirrors PHP `chuzi_realms.fallback_locales`.\n */\nexport const FALLBACK_LOCALES: Partial<\n Record<LocaleId, Record<string, string>>\n> = {\n es: {\n genre: \"Género\",\n story: \"Historia\",\n scene: \"Escena\",\n scene_choice: \"Elección\",\n player: \"Reproductor\",\n library: \"Biblioteca\",\n editor: \"Editor\",\n publish: \"Publicar\",\n the_end: \"Fin\",\n untitled_story: \"Historia sin título\",\n menu_create_story: \"Crear historia\",\n menu_create_film: \"Crear película\",\n film_title_placeholder: \"Título de la película\",\n select_genre: \"Seleccionar género\",\n delete_story_verb: \"Eliminar película\",\n },\n fr: {\n genre: \"Genre\",\n story: \"Histoire\",\n scene: \"Scène\",\n scene_choice: \"Choix\",\n player: \"Lecteur\",\n library: \"Bibliothèque\",\n editor: \"Éditeur\",\n publish: \"Publier\",\n the_end: \"Fin\",\n untitled_story: \"Histoire sans titre\",\n menu_create_story: \"Créer une histoire\",\n menu_create_film: \"Créer un film\",\n film_title_placeholder: \"Titre du film\",\n select_genre: \"Sélectionner un genre\",\n delete_story_verb: \"Supprimer le film\",\n },\n de: {\n genre: \"Genre\",\n story: \"Geschichte\",\n scene: \"Szene\",\n publish: \"Veröffentlichen\",\n the_end: \"Ende\",\n untitled_story: \"Unbenannte Geschichte\",\n menu_create_story: \"Geschichte erstellen\",\n film_title_placeholder: \"Filmtitel\",\n select_genre: \"Genre auswählen\",\n },\n pt: {\n genre: \"Gênero\",\n story: \"História\",\n scene: \"Cena\",\n publish: \"Publicar\",\n the_end: \"Fim\",\n untitled_story: \"História sem título\",\n menu_create_story: \"Criar história\",\n film_title_placeholder: \"Título do filme\",\n select_genre: \"Selecionar gênero\",\n },\n};\n\nfunction resolveFallback(locale: LocaleId | null | undefined): Record<string, string> {\n const overrides = locale && FALLBACK_LOCALES[locale];\n return overrides ? { ...FALLBACK_LEXICON, ...overrides } : { ...FALLBACK_LEXICON };\n}\n\nfunction resolveRealm(\n realmId: RealmId,\n locale: LocaleId | null | undefined\n): Record<string, string> {\n const realm = REALMS[realmId];\n const overrides = locale && realm.locales ? realm.locales[locale] : undefined;\n return overrides ? { ...realm.lexicon, ...overrides } : { ...realm.lexicon };\n}\n\n/**\n * Get a lexicon value for a realm + locale, falling back to the neutral\n * lexicon (which itself respects locale).\n */\nexport function t(\n realmId: RealmId | null | undefined,\n key: string,\n fallback = \"\",\n locale: LocaleId | null | undefined = null\n): string {\n if (realmId && REALMS[realmId]) {\n const realmLex = resolveRealm(realmId, locale);\n if (realmLex[key] !== undefined) return realmLex[key];\n }\n const fb = resolveFallback(locale);\n return fb[key] ?? fallback;\n}\n\n/**\n * Get the full merged lexicon for a realm + locale (realm lexicon on top of\n * locale-aware fallback).\n */\nexport function lexiconForRealm(\n realmId: RealmId | null | undefined,\n locale: LocaleId | null | undefined = null\n): Record<string, string> {\n const fb = resolveFallback(locale);\n if (!realmId || !REALMS[realmId]) {\n return fb;\n }\n return { ...fb, ...resolveRealm(realmId, locale) };\n}\n","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}\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 },\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 },\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 { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport { lexiconForRealm, t as translateRealm } from \"../../config/index.js\";\nimport { getThemeTokens, type RealmThemeTokens } from \"../../themes/index.js\";\nimport type { LocaleId, RealmId } from \"../../types/index.js\";\n\n/**\n * Realm-aware theme + lexicon context. Every chuzi-shared/ui primitive reads\n * from this; consuming apps wrap their tree once at the top level. Switching\n * realms or locales re-renders all consumers without prop drilling.\n */\n\nexport interface RealmTheme {\n realmId: RealmId | null;\n locale: LocaleId | null;\n tokens: RealmThemeTokens;\n /** Realm + locale aware lexicon lookup. */\n t: (key: string, fallback?: string) => string;\n /** Full merged lexicon for the current realm + locale. */\n lexicon: Record<string, string>;\n}\n\nconst RealmThemeContext = createContext<RealmTheme | null>(null);\n\nexport interface RealmThemeProviderProps {\n realmId: RealmId | null;\n locale?: LocaleId | null;\n children: ReactNode;\n}\n\nexport function RealmThemeProvider({\n realmId,\n locale = null,\n children,\n}: RealmThemeProviderProps) {\n const value = useMemo<RealmTheme>(() => {\n return {\n realmId,\n locale,\n tokens: getThemeTokens(realmId),\n lexicon: lexiconForRealm(realmId, locale),\n t: (key, fallback = \"\") => translateRealm(realmId, key, fallback, locale),\n };\n }, [realmId, locale]);\n\n return (\n <RealmThemeContext.Provider value={value}>\n {children}\n </RealmThemeContext.Provider>\n );\n}\n\nexport function useRealmTheme(): RealmTheme {\n const ctx = useContext(RealmThemeContext);\n if (!ctx) {\n throw new Error(\n \"useRealmTheme: no RealmThemeProvider in tree. Wrap your app root with <RealmThemeProvider realmId={...} />.\",\n );\n }\n return ctx;\n}\n","import {\n Pressable,\n StyleSheet,\n Text,\n type PressableProps,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\nimport { useRealmTheme } from \"./theme/RealmThemeProvider.js\";\n\nexport type ButtonVariant = \"primary\" | \"ghost\";\n\nexport interface ButtonProps\n extends Omit<PressableProps, \"style\" | \"children\"> {\n label: string;\n variant?: ButtonVariant;\n style?: StyleProp<ViewStyle>;\n}\n\n/**\n * Realm-themed button. Primitives come from react-native so the same\n * component renders on web (via react-native-web) and native. Colors come\n * from the active realm's theme tokens — primary fills with accent, ghost\n * draws an accent outline.\n */\nexport function Button({\n label,\n variant = \"primary\",\n style,\n ...rest\n}: ButtonProps) {\n const { tokens } = useRealmTheme();\n return (\n <Pressable\n accessibilityRole=\"button\"\n style={({ pressed }) => [\n styles.base,\n variant === \"primary\"\n ? { backgroundColor: tokens.accent }\n : {\n backgroundColor: \"transparent\",\n borderColor: tokens.accent,\n borderWidth: 1,\n },\n pressed && { opacity: 0.85 },\n style,\n ]}\n {...rest}\n >\n <Text\n style={[\n styles.label,\n {\n color: variant === \"primary\" ? tokens.bgDeep : tokens.accent,\n },\n ]}\n >\n {label}\n </Text>\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n paddingHorizontal: 18,\n paddingVertical: 10,\n borderRadius: 8,\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n label: {\n fontSize: 14,\n fontWeight: \"600\",\n letterSpacing: 0.5,\n },\n});\n","import {\n Pressable,\n StyleSheet,\n Text,\n View,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\nimport type { StoryListItem } from \"../types/index.js\";\nimport { useRealmTheme } from \"./theme/RealmThemeProvider.js\";\n\nexport interface FilmCardProps {\n film: StoryListItem;\n /** Tap/click handler. Without one, the card is a static block. */\n onPress?: () => void;\n style?: StyleProp<ViewStyle>;\n}\n\n/**\n * Realm-themed film card. Title falls back to the realm's \"untitled\" lexicon\n * (Untitled Star System / Untitled Grove). Genre falls back to the realm's\n * \"unknown genre\" string. Pressable when an onPress is provided; otherwise\n * renders a non-interactive View — important for list contexts that want\n * the press handled at the row level instead.\n */\nexport function FilmCard({ film, onPress, style }: FilmCardProps) {\n const { tokens, t } = useRealmTheme();\n\n const title = film.title?.trim() || t(\"untitled_story\", \"Untitled\");\n const genre = film.genre?.trim() || t(\"unknown_genre\", \"Unknown\");\n const sceneLabel = t(\"scenes_count\", \"scenes\");\n const choiceLabel = t(\"choices_count\", \"choices\");\n\n const inner = (\n <>\n <Text\n style={[styles.title, { color: tokens.text }]}\n numberOfLines={2}\n >\n {title}\n </Text>\n <Text style={[styles.meta, { color: tokens.muted }]}>\n {genre} · {film.scenes_count} {sceneLabel} · {film.choices_count}{\" \"}\n {choiceLabel}\n </Text>\n {film.creator?.name ? (\n <Text style={[styles.creator, { color: tokens.accent }]}>\n {film.creator.name}\n </Text>\n ) : null}\n </>\n );\n\n if (onPress) {\n return (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onPress}\n style={({ pressed }) => [\n styles.base,\n { backgroundColor: tokens.bgMid, borderColor: tokens.accentSoft },\n pressed && { opacity: 0.92 },\n style,\n ]}\n >\n {inner}\n </Pressable>\n );\n }\n\n return (\n <View\n style={[\n styles.base,\n { backgroundColor: tokens.bgMid, borderColor: tokens.accentSoft },\n style,\n ]}\n >\n {inner}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n padding: 16,\n borderRadius: 12,\n borderWidth: 1,\n gap: 6,\n minWidth: 240,\n },\n title: {\n fontSize: 16,\n fontWeight: \"700\",\n },\n meta: {\n fontSize: 12,\n },\n creator: {\n fontSize: 12,\n fontWeight: \"600\",\n },\n});\n","import {\n StyleSheet,\n Text,\n View,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\nimport { useRealmTheme } from \"./theme/RealmThemeProvider.js\";\n\nexport type CreditRole = \"viewer\" | \"creator\";\n\nexport interface CreditBadgeProps {\n role: CreditRole;\n value: number;\n style?: StyleProp<ViewStyle>;\n}\n\n/**\n * Realm-themed credit badge — a bordered label showing a viewer or creator\n * credit balance. The label text adapts to the active realm's lexicon and\n * colors pull from the realm's theme tokens.\n */\nexport function CreditBadge({ role, value, style }: CreditBadgeProps) {\n const { tokens } = useRealmTheme();\n\n const label = role === \"viewer\" ? \"Viewer Credits\" : \"Creator Credits\";\n\n return (\n <View\n style={[\n styles.container,\n {\n borderColor: tokens.accent,\n backgroundColor: tokens.bgMid,\n },\n style,\n ]}\n >\n <Text style={[styles.label, { color: tokens.muted }]}>{label}</Text>\n <Text style={[styles.value, { color: tokens.accent }]}>\n {value.toLocaleString()}\n </Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 8,\n paddingHorizontal: 14,\n paddingVertical: 8,\n borderRadius: 8,\n borderWidth: 1,\n },\n label: {\n fontSize: 12,\n fontWeight: \"600\",\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n },\n value: {\n fontSize: 16,\n fontWeight: \"700\",\n },\n});\n"]}
1
+ {"version":3,"sources":["../../src/config/index.ts","../../src/themes/index.ts","../../src/ui/theme/RealmThemeProvider.tsx","../../src/ui/Button.tsx","../../src/ui/FilmCard.tsx","../../src/ui/CreditBadge.tsx"],"names":["jsx","t","Text","styles","Pressable","StyleSheet","jsxs","View"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n RealmId,\n RealmDefinition,\n ContentRating,\n ContentRatingDefinition,\n LocaleId,\n} from \"../types/index.js\";\n\nexport const REALM_IDS: readonly RealmId[] = [\"cosmos\", \"wilds\"] as const;\n\nexport const SUPPORTED_LOCALES: readonly LocaleId[] = [\n \"en\",\n \"es\",\n \"fr\",\n \"de\",\n \"pt\",\n] as const;\n\nexport const LOCALE_LABELS: Record<LocaleId, string> = {\n en: \"English\",\n es: \"Español\",\n fr: \"Français\",\n de: \"Deutsch\",\n pt: \"Português\",\n};\n\nexport const DEFAULT_LOCALE: LocaleId = \"en\";\n\nexport function isSupportedLocale(value: unknown): value is LocaleId {\n return (\n typeof value === \"string\" &&\n SUPPORTED_LOCALES.includes(value as LocaleId)\n );\n}\n\n/**\n * Normalize a raw locale tag (e.g. \"en-US\", \"pt_BR\") to a supported LocaleId,\n * matching the PHP `LocaleResolver::normalize` behavior.\n */\nexport function normalizeLocale(value: string | null | undefined): LocaleId | null {\n if (!value) return null;\n const lower = value.toLowerCase().trim();\n if (isSupportedLocale(lower)) return lower;\n const base = lower.split(/[-_]/, 1)[0];\n return isSupportedLocale(base) ? base : null;\n}\n\n/**\n * Pick the best supported locale from a browser Accept-Language string.\n * Mirrors PHP `LocaleResolver::matchAcceptLanguage` (q-value aware).\n */\nexport function matchAcceptLanguage(\n accept: string | null | undefined\n): LocaleId | null {\n if (!accept) return null;\n const tags = accept\n .split(\",\")\n .map((part) => {\n const [tag, ...params] = part.trim().split(\";\");\n const qParam = params.find((p) => p.trim().startsWith(\"q=\"));\n const q = qParam ? parseFloat(qParam.split(\"=\")[1]) || 0 : 1;\n return { tag: tag.trim(), q };\n })\n .filter((c) => c.tag && c.tag !== \"*\")\n .sort((a, b) => b.q - a.q);\n\n for (const c of tags) {\n const normalized = normalizeLocale(c.tag);\n if (normalized) return normalized;\n }\n return null;\n}\n\nexport const CONTENT_RATING_IDS: readonly ContentRating[] = [\n \"G\",\n \"PG\",\n \"PG-13\",\n \"R\",\n \"NC-17\",\n] as const;\n\nexport const CONTENT_RATINGS: Record<ContentRating, ContentRatingDefinition> = {\n G: {\n id: \"G\",\n label: \"G\",\n description: \"General Audiences — all ages admitted.\",\n },\n PG: {\n id: \"PG\",\n label: \"PG\",\n description: \"Parental Guidance Suggested — some material may not be suitable for children.\",\n },\n \"PG-13\": {\n id: \"PG-13\",\n label: \"PG-13\",\n description: \"Parents Strongly Cautioned — some material may be inappropriate for children under 13.\",\n },\n R: {\n id: \"R\",\n label: \"R\",\n description: \"Restricted — under 17 requires accompanying parent or adult guardian.\",\n },\n \"NC-17\": {\n id: \"NC-17\",\n label: \"NC-17\",\n description: \"Adults Only — no one 17 and under admitted.\",\n },\n};\n\nexport function isContentRating(value: unknown): value is ContentRating {\n return typeof value === \"string\" && CONTENT_RATING_IDS.includes(value as ContentRating);\n}\n\nexport const REALMS: Record<RealmId, RealmDefinition> = {\n cosmos: {\n label: \"CHUZI COSMOS\",\n short_label: \"Cosmos\",\n lexicon: {\n genre: \"Galaxy\",\n story: \"Star System\",\n scene: \"Planet\",\n scene_choice: \"Trajectory\",\n node: \"Signal\",\n node_type_choice: \"Trajectory\",\n node_type_media: \"Transmission\",\n node_type_go_to_scene: \"Warp\",\n player: \"Voyager\",\n library: \"Star Chart\",\n library_open: \"Open Star Chart\",\n library_close: \"Close Star Chart\",\n editor: \"Mission Control\",\n publish: \"Launch\",\n the_end: \"Final Orbit\",\n media_pool: \"Cargo Bay\",\n scene_graph: \"Star Chart\",\n watch_path: \"Your trajectory\",\n untitled_story: \"Untitled Star System\",\n unknown_genre: \"Unknown Galaxy\",\n scenes_count: \"planets\",\n choices_count: \"trajectories\",\n drafts_published: \"Drafts + Launched\",\n published_ver: \"Launched ver.\",\n draft: \"Draft\",\n no_scenes_yet: \"No planets in this chart yet.\",\n no_path_yet: \"No trajectory to show yet.\",\n menu_empty_drafts: \"No star systems yet. Chart one to begin.\",\n menu_empty_published: \"No launched systems in the chart.\",\n menu_published_heading: \"Launched constellations\",\n menu_create_story: \"New star system\",\n menu_create_film: \"Create film\",\n film_title_placeholder: \"Star system title\",\n select_genre: \"Select galaxy\",\n genre_field_aria: \"Galaxy\",\n delete_story_verb: \"Delete star system\",\n title_scene_default: \"Title planet\",\n choices_made_stat: \"trajectories taken\",\n content_rating: \"Audience Class\",\n content_rating_field_aria: \"Audience class\",\n select_content_rating: \"Select audience class\",\n unrated: \"Unclassified\",\n viewer_credits: \"Fuel Cells\",\n creator_credits: \"Stardust\",\n editor_media_upload: \"Upload Transmission\",\n editor_media_preview: \"Transmission Preview\",\n editor_alt_media: \"Additional Transmission\",\n editor_choices: \"Trajectories\",\n editor_scene_settings: \"Star Settings\",\n editor_title_scene: \"Title Star\",\n editor_ending_scene: \"Final Star\",\n editor_play: \"Engage\",\n editor_pause: \"Hold\",\n editor_prev_frame: \"Previous Frame\",\n editor_next_frame: \"Next Frame\",\n editor_seek: \"Seek\",\n editor_no_media: \"No transmission assigned\",\n editor_uploading: \"Transmitting\\u2026\",\n editor_drop_media: \"Drop transmission here\",\n editor_scene_type: \"Star Type\",\n editor_save: \"Lock In\",\n editor_scene_color: \"Star Hue\",\n editor_ai_generate: \"Generate Transmission\",\n editor_ai_generating: \"Transmitting Signal\\u2026\",\n editor_ai_mood_question: \"What energy should this planet radiate?\",\n editor_ai_style_question: \"What vision style for this transmission?\",\n editor_ai_prompt_question: \"Describe this planet\\u2019s landscape\",\n editor_ai_accept: \"Lock Transmission\",\n editor_ai_reject: \"Reject Signal\",\n editor_ai_retry: \"Retransmit\",\n editor_ai_feedback_prompt: \"How should we adjust the signal?\",\n editor_ai_credit_cost: \"1 Stardust per signal\",\n editor_ai_generating_scene: \"Planet forming\\u2026\",\n editor_ai_style_badge: \"Signal Style\",\n editor_ai_failed: \"Signal lost. Try retransmitting.\",\n editor_media_attached: \"This star already has a transmission locked in.\",\n editor_remove_media: \"Remove Transmission\",\n constellation_no_coverbox: \"Uncharted\",\n hud_edit_control: \"Engage\",\n hud_delete_control: \"Jettison\",\n hud_publish_control: \"Launch\",\n create_button: \"CREATE\",\n publish_form_heading: \"Launch readiness\",\n tags_label: \"Signal Tags\",\n tags_placeholder: \"Search signal tags\\u2026\",\n tags_empty: \"No signal tags yet\",\n story_picker_label: \"Constellations\",\n },\n locales: {\n es: {\n genre: \"Galaxia\",\n story: \"Sistema Estelar\",\n scene: \"Planeta\",\n scene_choice: \"Trayectoria\",\n player: \"Viajero\",\n library: \"Carta Estelar\",\n editor: \"Control de Misión\",\n publish: \"Lanzar\",\n the_end: \"Órbita Final\",\n untitled_story: \"Sistema Estelar sin título\",\n menu_create_story: \"Nuevo sistema estelar\",\n film_title_placeholder: \"Título del sistema estelar\",\n select_genre: \"Seleccionar galaxia\",\n },\n fr: {\n genre: \"Galaxie\",\n story: \"Système Stellaire\",\n scene: \"Planète\",\n scene_choice: \"Trajectoire\",\n player: \"Voyageur\",\n library: \"Carte Stellaire\",\n editor: \"Contrôle de Mission\",\n publish: \"Lancer\",\n the_end: \"Orbite Finale\",\n untitled_story: \"Système stellaire sans titre\",\n menu_create_story: \"Nouveau système stellaire\",\n film_title_placeholder: \"Titre du système stellaire\",\n select_genre: \"Sélectionner une galaxie\",\n },\n de: {\n genre: \"Galaxie\",\n story: \"Sternsystem\",\n scene: \"Planet\",\n player: \"Reisender\",\n publish: \"Starten\",\n },\n pt: {\n genre: \"Galáxia\",\n story: \"Sistema Estelar\",\n scene: \"Planeta\",\n player: \"Viajante\",\n publish: \"Lançar\",\n },\n },\n },\n wilds: {\n label: \"CHUZI WILDS\",\n short_label: \"Wilds\",\n lexicon: {\n genre: \"Biome\",\n story: \"Grove\",\n scene: \"Clearing\",\n scene_choice: \"Trail\",\n node: \"Seed\",\n node_type_choice: \"Trail\",\n node_type_media: \"Bloom\",\n node_type_go_to_scene: \"Crossing\",\n player: \"Wanderer\",\n library: \"Canopy\",\n library_open: \"Open Canopy\",\n library_close: \"Close Canopy\",\n editor: \"Heartwood\",\n publish: \"Plant\",\n the_end: \"Roots\",\n media_pool: \"Undergrowth\",\n scene_graph: \"Canopy\",\n watch_path: \"Your trail\",\n untitled_story: \"Untitled Grove\",\n unknown_genre: \"Unknown Biome\",\n scenes_count: \"clearings\",\n choices_count: \"trails\",\n drafts_published: \"Drafts + Planted\",\n published_ver: \"Planted ver.\",\n draft: \"Draft\",\n no_scenes_yet: \"No clearings in this canopy yet.\",\n no_path_yet: \"No trail to show yet.\",\n menu_empty_drafts: \"No groves yet. Plant one to begin.\",\n menu_empty_published: \"No planted groves in the canopy.\",\n menu_published_heading: \"Planted groves\",\n menu_create_story: \"New grove\",\n menu_create_film: \"Create film\",\n film_title_placeholder: \"Grove title\",\n select_genre: \"Select biome\",\n genre_field_aria: \"Biome\",\n delete_story_verb: \"Delete grove\",\n title_scene_default: \"Title clearing\",\n choices_made_stat: \"trails taken\",\n content_rating: \"Field Guide\",\n content_rating_field_aria: \"Field guide\",\n select_content_rating: \"Select field guide\",\n unrated: \"Unmarked\",\n viewer_credits: \"Sap\",\n creator_credits: \"Pollen\",\n editor_media_upload: \"Upload Bloom\",\n editor_media_preview: \"Bloom Preview\",\n editor_alt_media: \"Additional Bloom\",\n editor_choices: \"Trails\",\n editor_scene_settings: \"Clearing Settings\",\n editor_title_scene: \"Title Clearing\",\n editor_ending_scene: \"Roots\",\n editor_play: \"Unfurl\",\n editor_pause: \"Rest\",\n editor_prev_frame: \"Previous Frame\",\n editor_next_frame: \"Next Frame\",\n editor_seek: \"Seek\",\n editor_no_media: \"No bloom assigned\",\n editor_uploading: \"Blooming\\u2026\",\n editor_drop_media: \"Drop bloom here\",\n editor_scene_type: \"Clearing Type\",\n editor_save: \"Engrave\",\n editor_scene_color: \"Clearing Tint\",\n editor_ai_generate: \"Grow Bloom\",\n editor_ai_generating: \"Seed Sprouting\\u2026\",\n editor_ai_mood_question: \"What feeling should this clearing evoke?\",\n editor_ai_style_question: \"What growth pattern for this bloom?\",\n editor_ai_prompt_question: \"Describe this clearing\",\n editor_ai_accept: \"Root Bloom\",\n editor_ai_reject: \"Prune Bloom\",\n editor_ai_retry: \"Regrow\",\n editor_ai_feedback_prompt: \"How should we reshape the growth?\",\n editor_ai_credit_cost: \"1 Pollen per bloom\",\n editor_ai_generating_scene: \"Clearing emerging\\u2026\",\n editor_ai_style_badge: \"Growth Style\",\n editor_ai_failed: \"Growth withered. Try regrowing.\",\n editor_media_attached: \"This clearing already has a bloom rooted.\",\n editor_remove_media: \"Uproot Bloom\",\n constellation_no_coverbox: \"Unseen\",\n hud_edit_control: \"Tend\",\n hud_delete_control: \"Uproot\",\n hud_publish_control: \"Plant\",\n create_button: \"CREATE\",\n publish_form_heading: \"Planting check\",\n tags_label: \"Root Tags\",\n tags_placeholder: \"Search root tags\\u2026\",\n tags_empty: \"No root tags yet\",\n story_picker_label: \"Groves\",\n },\n locales: {\n es: {\n genre: \"Bioma\",\n story: \"Arboleda\",\n scene: \"Claro\",\n scene_choice: \"Sendero\",\n player: \"Errante\",\n library: \"Dosel\",\n editor: \"Duramen\",\n publish: \"Plantar\",\n the_end: \"Raíces\",\n untitled_story: \"Arboleda sin título\",\n menu_create_story: \"Nueva arboleda\",\n film_title_placeholder: \"Título de la arboleda\",\n select_genre: \"Seleccionar bioma\",\n },\n fr: {\n genre: \"Biome\",\n story: \"Bosquet\",\n scene: \"Clairière\",\n scene_choice: \"Sentier\",\n player: \"Vagabond\",\n library: \"Canopée\",\n editor: \"Cœur de bois\",\n publish: \"Planter\",\n the_end: \"Racines\",\n untitled_story: \"Bosquet sans titre\",\n menu_create_story: \"Nouveau bosquet\",\n film_title_placeholder: \"Titre du bosquet\",\n select_genre: \"Sélectionner un biome\",\n },\n de: {\n genre: \"Biom\",\n story: \"Hain\",\n scene: \"Lichtung\",\n player: \"Wanderer\",\n publish: \"Pflanzen\",\n },\n pt: {\n genre: \"Bioma\",\n story: \"Bosque\",\n scene: \"Clareira\",\n player: \"Andarilho\",\n publish: \"Plantar\",\n },\n },\n },\n};\n\nexport const FALLBACK_LEXICON: Record<string, string> = {\n genre: \"Genre\",\n story: \"Story\",\n scene: \"Scene\",\n scene_choice: \"Choice\",\n node: \"Node\",\n node_type_choice: \"Choice\",\n node_type_media: \"Media\",\n node_type_go_to_scene: \"Go to scene\",\n player: \"Player\",\n library: \"Library\",\n library_open: \"Open scene tree\",\n library_close: \"Close scene tree\",\n editor: \"Editor\",\n publish: \"Publish\",\n the_end: \"The End\",\n media_pool: \"Media Pool\",\n scene_graph: \"Scene tree\",\n watch_path: \"Your path\",\n untitled_story: \"Untitled Story\",\n unknown_genre: \"Unknown Genre\",\n scenes_count: \"scenes\",\n choices_count: \"choices\",\n drafts_published: \"Drafts + Published\",\n published_ver: \"Published ver.\",\n draft: \"Draft\",\n no_scenes_yet: \"No scenes available yet.\",\n no_path_yet: \"No path to show yet.\",\n menu_empty_drafts: \"No films yet. Create one to get started.\",\n menu_empty_published: \"No published films found.\",\n menu_published_heading: \"Published Films\",\n menu_create_story: \"Create Story\",\n menu_create_film: \"Create Film\",\n film_title_placeholder: \"Film title\",\n select_genre: \"Select genre\",\n genre_field_aria: \"Film genre\",\n delete_story_verb: \"Delete film\",\n title_scene_default: \"Title Scene\",\n choices_made_stat: \"choices made\",\n content_rating: \"Rating\",\n content_rating_field_aria: \"Content rating\",\n select_content_rating: \"Select rating\",\n unrated: \"Not Rated\",\n viewer_credits: \"Viewer Credits\",\n creator_credits: \"Creator Credits\",\n editor_media_upload: \"Upload Media\",\n editor_media_preview: \"Media Preview\",\n editor_alt_media: \"Additional Media\",\n editor_choices: \"Choices\",\n editor_scene_settings: \"Scene Settings\",\n editor_title_scene: \"Title Scene\",\n editor_ending_scene: \"Ending Scene\",\n editor_play: \"Play\",\n editor_pause: \"Pause\",\n editor_prev_frame: \"Previous Frame\",\n editor_next_frame: \"Next Frame\",\n editor_seek: \"Seek\",\n editor_no_media: \"No media assigned\",\n editor_uploading: \"Uploading\\u2026\",\n editor_drop_media: \"Drop media here\",\n editor_scene_type: \"Scene Type\",\n editor_save: \"Save\",\n editor_scene_color: \"Scene Color\",\n editor_ai_generate: \"Generate with AI\",\n editor_ai_generating: \"Generating\\u2026\",\n editor_ai_mood_question: \"What mood should this scene convey?\",\n editor_ai_style_question: \"What visual style do you want?\",\n editor_ai_prompt_question: \"Describe this scene\",\n editor_ai_accept: \"Accept\",\n editor_ai_reject: \"Reject\",\n editor_ai_retry: \"Try Again\",\n editor_ai_feedback_prompt: \"What should we change?\",\n editor_ai_credit_cost: \"1 credit per generation\",\n editor_ai_generating_scene: \"Scene generating\\u2026\",\n editor_ai_style_badge: \"Style\",\n editor_ai_failed: \"Generation failed. Please try again.\",\n editor_media_attached: \"This scene already has media attached.\",\n editor_remove_media: \"Remove Media\",\n constellation_no_coverbox: \"No cover\",\n hud_edit_control: \"Edit\",\n hud_delete_control: \"Delete\",\n hud_publish_control: \"Publish\",\n create_button: \"CREATE\",\n publish_form_heading: \"Publish checklist\",\n tags_label: \"Tags\",\n tags_placeholder: \"Search tags\\u2026\",\n tags_empty: \"No tags yet\",\n story_picker_label: \"Stories\",\n};\n\n/**\n * Per-locale overrides for FALLBACK_LEXICON. Missing keys fall through to\n * the English fallback. Mirrors PHP `chuzi_realms.fallback_locales`.\n */\nexport const FALLBACK_LOCALES: Partial<\n Record<LocaleId, Record<string, string>>\n> = {\n es: {\n genre: \"Género\",\n story: \"Historia\",\n scene: \"Escena\",\n scene_choice: \"Elección\",\n player: \"Reproductor\",\n library: \"Biblioteca\",\n editor: \"Editor\",\n publish: \"Publicar\",\n the_end: \"Fin\",\n untitled_story: \"Historia sin título\",\n menu_create_story: \"Crear historia\",\n menu_create_film: \"Crear película\",\n film_title_placeholder: \"Título de la película\",\n select_genre: \"Seleccionar género\",\n delete_story_verb: \"Eliminar película\",\n },\n fr: {\n genre: \"Genre\",\n story: \"Histoire\",\n scene: \"Scène\",\n scene_choice: \"Choix\",\n player: \"Lecteur\",\n library: \"Bibliothèque\",\n editor: \"Éditeur\",\n publish: \"Publier\",\n the_end: \"Fin\",\n untitled_story: \"Histoire sans titre\",\n menu_create_story: \"Créer une histoire\",\n menu_create_film: \"Créer un film\",\n film_title_placeholder: \"Titre du film\",\n select_genre: \"Sélectionner un genre\",\n delete_story_verb: \"Supprimer le film\",\n },\n de: {\n genre: \"Genre\",\n story: \"Geschichte\",\n scene: \"Szene\",\n publish: \"Veröffentlichen\",\n the_end: \"Ende\",\n untitled_story: \"Unbenannte Geschichte\",\n menu_create_story: \"Geschichte erstellen\",\n film_title_placeholder: \"Filmtitel\",\n select_genre: \"Genre auswählen\",\n },\n pt: {\n genre: \"Gênero\",\n story: \"História\",\n scene: \"Cena\",\n publish: \"Publicar\",\n the_end: \"Fim\",\n untitled_story: \"História sem título\",\n menu_create_story: \"Criar história\",\n film_title_placeholder: \"Título do filme\",\n select_genre: \"Selecionar gênero\",\n },\n};\n\nfunction resolveFallback(locale: LocaleId | null | undefined): Record<string, string> {\n const overrides = locale && FALLBACK_LOCALES[locale];\n return overrides ? { ...FALLBACK_LEXICON, ...overrides } : { ...FALLBACK_LEXICON };\n}\n\nfunction resolveRealm(\n realmId: RealmId,\n locale: LocaleId | null | undefined\n): Record<string, string> {\n const realm = REALMS[realmId];\n const overrides = locale && realm.locales ? realm.locales[locale] : undefined;\n return overrides ? { ...realm.lexicon, ...overrides } : { ...realm.lexicon };\n}\n\n/**\n * Get a lexicon value for a realm + locale, falling back to the neutral\n * lexicon (which itself respects locale).\n */\nexport function t(\n realmId: RealmId | null | undefined,\n key: string,\n fallback = \"\",\n locale: LocaleId | null | undefined = null\n): string {\n if (realmId && REALMS[realmId]) {\n const realmLex = resolveRealm(realmId, locale);\n if (realmLex[key] !== undefined) return realmLex[key];\n }\n const fb = resolveFallback(locale);\n return fb[key] ?? fallback;\n}\n\n/**\n * Get the full merged lexicon for a realm + locale (realm lexicon on top of\n * locale-aware fallback).\n */\nexport function lexiconForRealm(\n realmId: RealmId | null | undefined,\n locale: LocaleId | null | undefined = null\n): Record<string, string> {\n const fb = resolveFallback(locale);\n if (!realmId || !REALMS[realmId]) {\n return fb;\n }\n return { ...fb, ...resolveRealm(realmId, locale) };\n}\n","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}\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 },\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 },\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 { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport { lexiconForRealm, t as translateRealm } from \"../../config/index.js\";\nimport { getThemeTokens, type RealmThemeTokens } from \"../../themes/index.js\";\nimport type { LocaleId, RealmId } from \"../../types/index.js\";\n\n/**\n * Realm-aware theme + lexicon context. Every chuzi-shared/ui primitive reads\n * from this; consuming apps wrap their tree once at the top level. Switching\n * realms or locales re-renders all consumers without prop drilling.\n */\n\nexport interface RealmTheme {\n realmId: RealmId | null;\n locale: LocaleId | null;\n tokens: RealmThemeTokens;\n /** Realm + locale aware lexicon lookup. */\n t: (key: string, fallback?: string) => string;\n /** Full merged lexicon for the current realm + locale. */\n lexicon: Record<string, string>;\n}\n\nconst RealmThemeContext = createContext<RealmTheme | null>(null);\n\nexport interface RealmThemeProviderProps {\n realmId: RealmId | null;\n locale?: LocaleId | null;\n children: ReactNode;\n}\n\nexport function RealmThemeProvider({\n realmId,\n locale = null,\n children,\n}: RealmThemeProviderProps) {\n const value = useMemo<RealmTheme>(() => {\n return {\n realmId,\n locale,\n tokens: getThemeTokens(realmId),\n lexicon: lexiconForRealm(realmId, locale),\n t: (key, fallback = \"\") => translateRealm(realmId, key, fallback, locale),\n };\n }, [realmId, locale]);\n\n return (\n <RealmThemeContext.Provider value={value}>\n {children}\n </RealmThemeContext.Provider>\n );\n}\n\nexport function useRealmTheme(): RealmTheme {\n const ctx = useContext(RealmThemeContext);\n if (!ctx) {\n throw new Error(\n \"useRealmTheme: no RealmThemeProvider in tree. Wrap your app root with <RealmThemeProvider realmId={...} />.\",\n );\n }\n return ctx;\n}\n","import {\n Pressable,\n StyleSheet,\n Text,\n type PressableProps,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\nimport { useRealmTheme } from \"./theme/RealmThemeProvider.js\";\n\nexport type ButtonVariant = \"primary\" | \"ghost\";\n\nexport interface ButtonProps\n extends Omit<PressableProps, \"style\" | \"children\"> {\n label: string;\n variant?: ButtonVariant;\n style?: StyleProp<ViewStyle>;\n}\n\n/**\n * Realm-themed button. Primitives come from react-native so the same\n * component renders on web (via react-native-web) and native. Colors come\n * from the active realm's theme tokens — primary fills with accent, ghost\n * draws an accent outline.\n */\nexport function Button({\n label,\n variant = \"primary\",\n style,\n ...rest\n}: ButtonProps) {\n const { tokens } = useRealmTheme();\n return (\n <Pressable\n accessibilityRole=\"button\"\n style={({ pressed }) => [\n styles.base,\n variant === \"primary\"\n ? { backgroundColor: tokens.accent }\n : {\n backgroundColor: \"transparent\",\n borderColor: tokens.accent,\n borderWidth: 1,\n },\n pressed && { opacity: 0.85 },\n style,\n ]}\n {...rest}\n >\n <Text\n style={[\n styles.label,\n {\n color: variant === \"primary\" ? tokens.bgDeep : tokens.accent,\n },\n ]}\n >\n {label}\n </Text>\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n paddingHorizontal: 18,\n paddingVertical: 10,\n borderRadius: 8,\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n label: {\n fontSize: 14,\n fontWeight: \"600\",\n letterSpacing: 0.5,\n },\n});\n","import {\n Pressable,\n StyleSheet,\n Text,\n View,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\nimport type { StoryListItem } from \"../types/index.js\";\nimport { useRealmTheme } from \"./theme/RealmThemeProvider.js\";\n\nexport interface FilmCardProps {\n film: StoryListItem;\n /** Tap/click handler. Without one, the card is a static block. */\n onPress?: () => void;\n style?: StyleProp<ViewStyle>;\n}\n\n/**\n * Realm-themed film card. Title falls back to the realm's \"untitled\" lexicon\n * (Untitled Star System / Untitled Grove). Genre falls back to the realm's\n * \"unknown genre\" string. Pressable when an onPress is provided; otherwise\n * renders a non-interactive View — important for list contexts that want\n * the press handled at the row level instead.\n */\nexport function FilmCard({ film, onPress, style }: FilmCardProps) {\n const { tokens, t } = useRealmTheme();\n\n const title = film.title?.trim() || t(\"untitled_story\", \"Untitled\");\n const genre = film.genre?.trim() || t(\"unknown_genre\", \"Unknown\");\n const sceneLabel = t(\"scenes_count\", \"scenes\");\n const choiceLabel = t(\"choices_count\", \"choices\");\n\n const inner = (\n <>\n <Text\n style={[styles.title, { color: tokens.text }]}\n numberOfLines={2}\n >\n {title}\n </Text>\n <Text style={[styles.meta, { color: tokens.muted }]}>\n {genre} · {film.scenes_count} {sceneLabel} · {film.choices_count}{\" \"}\n {choiceLabel}\n </Text>\n {film.creator?.name ? (\n <Text style={[styles.creator, { color: tokens.accent }]}>\n {film.creator.name}\n </Text>\n ) : null}\n </>\n );\n\n if (onPress) {\n return (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onPress}\n style={({ pressed }) => [\n styles.base,\n { backgroundColor: tokens.bgMid, borderColor: tokens.accentSoft },\n pressed && { opacity: 0.92 },\n style,\n ]}\n >\n {inner}\n </Pressable>\n );\n }\n\n return (\n <View\n style={[\n styles.base,\n { backgroundColor: tokens.bgMid, borderColor: tokens.accentSoft },\n style,\n ]}\n >\n {inner}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n padding: 16,\n borderRadius: 12,\n borderWidth: 1,\n gap: 6,\n minWidth: 240,\n },\n title: {\n fontSize: 16,\n fontWeight: \"700\",\n },\n meta: {\n fontSize: 12,\n },\n creator: {\n fontSize: 12,\n fontWeight: \"600\",\n },\n});\n","import {\n StyleSheet,\n Text,\n View,\n type StyleProp,\n type ViewStyle,\n} from \"react-native\";\nimport { useRealmTheme } from \"./theme/RealmThemeProvider.js\";\n\nexport type CreditRole = \"viewer\" | \"creator\";\n\nexport interface CreditBadgeProps {\n role: CreditRole;\n value: number;\n style?: StyleProp<ViewStyle>;\n}\n\n/**\n * Realm-themed credit badge — a bordered label showing a viewer or creator\n * credit balance. The label text adapts to the active realm's lexicon and\n * colors pull from the realm's theme tokens.\n */\nexport function CreditBadge({ role, value, style }: CreditBadgeProps) {\n const { tokens } = useRealmTheme();\n\n const label = role === \"viewer\" ? \"Viewer Credits\" : \"Creator Credits\";\n\n return (\n <View\n style={[\n styles.container,\n {\n borderColor: tokens.accent,\n backgroundColor: tokens.bgMid,\n },\n style,\n ]}\n >\n <Text style={[styles.label, { color: tokens.muted }]}>{label}</Text>\n <Text style={[styles.value, { color: tokens.accent }]}>\n {value.toLocaleString()}\n </Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 8,\n paddingHorizontal: 14,\n paddingVertical: 8,\n borderRadius: 8,\n borderWidth: 1,\n },\n label: {\n fontSize: 12,\n fontWeight: \"600\",\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n },\n value: {\n fontSize: 16,\n fontWeight: \"700\",\n },\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chuzi/shared",
3
- "version": "1.2.2",
3
+ "version": "1.3.1",
4
4
  "description": "Shared types, realm config, theme tokens, API client, input layer, and realm rendering primitives for CHUZI apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,