@servantcdh/ez-planet-cosmos 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # @servantcdh/ez-planet-cosmos
2
+
3
+ ReactFlow + Three.js 기반의 코스모스(우주) 스타일 플랫폼 시각화 라이브러리.
4
+
5
+ 행성(Planet), 궤도(Orbit), 위성(Satellite) 메타포로 MLOps 파이프라인을 시각화합니다.
6
+
7
+ [![StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/servantcdh/ez-planet/tree/master/examples/cosmos-demo?file=src/App.tsx)
8
+
9
+ ## 설치
10
+
11
+ ```bash
12
+ npm install @servantcdh/ez-planet-cosmos
13
+ ```
14
+
15
+ ## Dependencies
16
+
17
+ ### Peer Dependencies (호스트 앱에서 설치)
18
+
19
+ | Package | Version | 용도 |
20
+ |---------|---------|------|
21
+ | `react` | `^18.0.0` | UI 런타임 |
22
+ | `react-dom` | `^18.0.0` | DOM 렌더링 |
23
+ | `@xyflow/react` | `^12.0.0` | 그래프 시각화 |
24
+ | `@react-three/fiber` | `^8.0.0` | Three.js React 바인딩 |
25
+ | `@react-three/drei` | `^9.0.0` | Three.js 유틸리티 |
26
+ | `three` | `>=0.160.0` | 3D 렌더링 (StarField) |
27
+ | `framer-motion` | `^11.0.0` | 애니메이션 |
28
+
29
+ ### Bundled Dependencies (라이브러리에 포함)
30
+
31
+ | Package | 용도 |
32
+ |---------|------|
33
+ | `zustand` | 내부 상태 관리 |
34
+
35
+ ## Quick Start
36
+
37
+ ```tsx
38
+ import { CosmosCanvas } from '@servantcdh/ez-planet-cosmos'
39
+ import type { PlanetConfig, OrbitConfig } from '@servantcdh/ez-planet-cosmos'
40
+ import '@servantcdh/ez-planet-cosmos/dist/style.css'
41
+ import '@xyflow/react/dist/style.css'
42
+
43
+ const planets: PlanetConfig[] = [
44
+ {
45
+ id: 'terra',
46
+ label: 'Terra',
47
+ subtitle: 'Dataset',
48
+ color: '#3498db',
49
+ x: 200, y: 300,
50
+ satellites: [
51
+ { id: 'upload', label: 'Upload', icon: '📤', route: '/data/upload' },
52
+ { id: 'browse', label: 'Browse', icon: '🔍', route: '/data/browse' },
53
+ ],
54
+ },
55
+ {
56
+ id: 'nova',
57
+ label: 'Nova',
58
+ subtitle: 'Model',
59
+ color: '#e74c3c',
60
+ x: 650, y: 310,
61
+ satellites: [
62
+ { id: 'train', label: 'Training', icon: '🧠', route: '/model/train' },
63
+ ],
64
+ },
65
+ ]
66
+
67
+ const orbits: OrbitConfig[] = [
68
+ { source: 'terra', target: 'nova', label: 'Dataset → Model' },
69
+ ]
70
+
71
+ function App() {
72
+ return (
73
+ <CosmosCanvas
74
+ planets={planets}
75
+ orbits={orbits}
76
+ topBar={<MyTopBar />}
77
+ onPlanetClick={(planet) => console.log('Click:', planet.id)}
78
+ onPlanetEnter={(planet) => console.log('Enter:', planet.id)}
79
+ onSatelliteClick={({ satellite }) => {
80
+ if (satellite?.route) router.push(satellite.route)
81
+ }}
82
+ />
83
+ )
84
+ }
85
+ ```
86
+
87
+ ## Props Reference
88
+
89
+ ### CosmosCanvasProps
90
+
91
+ | Prop | Type | Required | Description |
92
+ |------|------|----------|-------------|
93
+ | `planets` | `PlanetConfig[]` | Yes | 행성 목록 |
94
+ | `orbits` | `OrbitConfig[]` | Yes | 궤도(연결선) 목록 |
95
+ | `onPlanetClick` | `(planet: PlanetConfig) => void` | No | 행성 클릭 (사이드패널 열기) |
96
+ | `onPlanetEnter` | `(planet: PlanetConfig) => void` | No | 행성 더블클릭 (내부 진입) |
97
+ | `onPlanetExit` | `() => void` | No | 행성 내부에서 나가기 |
98
+ | `onSatelliteClick` | `(event: CosmosNavigateEvent) => void` | No | 위성 클릭 (라우팅) |
99
+ | `topBar` | `ReactNode` | No | 상단 슬롯 (호스트 앱 네비게이션 바) |
100
+ | `starField` | `boolean \| StarFieldConfig` | No | Three.js 별 배경 (기본: `true`) |
101
+ | `theme` | `Partial<CosmosTheme>` | No | 테마 커스터마이징 |
102
+ | `tutorialSteps` | `TutorialStep[]` | No | 온보딩 튜토리얼 단계 |
103
+ | `showTutorial` | `boolean` | No | 튜토리얼 표시 여부 |
104
+ | `onTutorialComplete` | `() => void` | No | 튜토리얼 완료 콜백 |
105
+ | `initialView` | `CosmosView` | No | 초기 뷰 상태 |
106
+ | `onViewChange` | `(view: CosmosView) => void` | No | 뷰 상태 변경 콜백 |
107
+ | `renderPlanetInterior` | `(planet, onExit) => ReactNode` | No | 행성 내부 커스텀 렌더 |
108
+ | `nodeTypes` | `Record<string, ComponentType>` | No | 커스텀 ReactFlow 노드 타입 |
109
+ | `edgeTypes` | `Record<string, ComponentType>` | No | 커스텀 ReactFlow 엣지 타입 |
110
+
111
+ ### PlanetConfig
112
+
113
+ ```ts
114
+ interface PlanetConfig {
115
+ id: string
116
+ label: string
117
+ subtitle: string
118
+ color: string // 행성 색상 (radial gradient, glow)
119
+ x: number // ReactFlow 위치
120
+ y: number
121
+ satellites: Satellite[] // 위성 (서브메뉴)
122
+ status?: PlanetStatus // 'idle' | 'running' | 'error' | 'success' | 'disabled'
123
+ icon?: ReactNode
124
+ meta?: Record<string, unknown>
125
+ }
126
+ ```
127
+
128
+ ### Satellite
129
+
130
+ ```ts
131
+ interface Satellite {
132
+ id: string
133
+ label: string
134
+ route?: string // 클릭 시 라우팅 경로
135
+ icon?: string | ReactNode
136
+ summary?: { total?: number; running?: number; failed?: number }
137
+ quickActions?: Array<{ label: string; action: string }>
138
+ }
139
+ ```
140
+
141
+ ## 주요 기능
142
+
143
+ ### StarField
144
+
145
+ Three.js 기반 우주 배경. 2000개 별 + 500개 성운 파티클.
146
+
147
+ ```tsx
148
+ <CosmosCanvas
149
+ starField={{ starCount: 3000, nebulaCount: 800, rotationSpeed: 0.0005 }}
150
+ ...
151
+ />
152
+ ```
153
+
154
+ ### PlanetNode
155
+
156
+ 상태별 시각 효과:
157
+ - `idle` — 기본 글로우
158
+ - `running` — 펄스 애니메이션
159
+ - `error` — 빨간 글로우
160
+ - `success` — 초록 글로우
161
+ - `disabled` — 회색 디밍
162
+
163
+ ### SidePanel
164
+
165
+ 행성 클릭 시 슬라이드-인 패널. 위성 목록, 요약 통계, Enter 버튼.
166
+
167
+ ### PlanetInterior
168
+
169
+ 행성 더블클릭 시 줌인 + 내부 뷰. 원형 위성 배치. `renderPlanetInterior`로 커스터마이징 가능.
170
+
171
+ ### Tutorial System
172
+
173
+ 3단계 온보딩: Welcome → Stepping (키보드/클릭) → Complete.
174
+
175
+ ```tsx
176
+ const tutorialSteps: TutorialStep[] = [
177
+ { planetId: 'terra', title: 'Dataset', description: '데이터를 관리합니다.' },
178
+ { planetId: 'nova', title: 'Model', description: '모델을 학습합니다.' },
179
+ ]
180
+
181
+ <CosmosCanvas
182
+ tutorialSteps={tutorialSteps}
183
+ showTutorial={isFirstVisit}
184
+ onTutorialComplete={() => markTutorialDone()}
185
+ ...
186
+ />
187
+ ```
188
+
189
+ ### TopBar Slot
190
+
191
+ 호스트 앱의 네비게이션 바를 주입합니다.
192
+
193
+ ```tsx
194
+ <CosmosCanvas topBar={<MyAppTopBar user={user} onLogout={logout} />} ... />
195
+ ```
196
+
197
+ ## Theming
198
+
199
+ ```tsx
200
+ <CosmosCanvas
201
+ theme={{
202
+ background: '#0a0a1a',
203
+ textColor: '#e2e8f0',
204
+ panelBackground: 'rgba(20, 20, 40, 0.9)',
205
+ panelBorder: 'rgba(255, 255, 255, 0.1)',
206
+ controlsBackground: 'rgba(20, 20, 40, 0.8)',
207
+ fontFamily: 'Pretendard, sans-serif',
208
+ }}
209
+ ...
210
+ />
211
+ ```
212
+
213
+ ## 개별 컴포넌트 사용
214
+
215
+ 모든 하위 컴포넌트를 개별적으로 import할 수 있습니다.
216
+
217
+ ```tsx
218
+ import {
219
+ CosmosCanvas,
220
+ PlanetNode,
221
+ OrbitEdge,
222
+ StarField,
223
+ SidePanel,
224
+ ZoomTransition,
225
+ PlanetInterior,
226
+ CosmosTutorial,
227
+ } from '@servantcdh/ez-planet-cosmos'
228
+ ```
229
+
230
+ ## License
231
+
232
+ MIT
@@ -0,0 +1,175 @@
1
+ import { EdgeProps } from '@xyflow/react';
2
+ import { JSX as JSX_2 } from 'react/jsx-runtime';
3
+ import { MemoExoticComponent } from 'react';
4
+ import { NodeProps } from '@xyflow/react';
5
+ import { ReactNode } from 'react';
6
+
7
+ /**
8
+ * CosmosCanvas — ReactFlowProvider wrapper for the cosmic visualization.
9
+ *
10
+ * Renders: StarField + ReactFlow graph + SidePanel + PlanetInterior + Tutorial
11
+ * All data via props, no API dependencies.
12
+ */
13
+ export declare function CosmosCanvas(props: CosmosCanvasProps): JSX_2.Element;
14
+
15
+ export declare interface CosmosCanvasProps {
16
+ planets: PlanetConfig[];
17
+ orbits: OrbitConfig[];
18
+ onPlanetClick?: (planet: PlanetConfig) => void;
19
+ onPlanetEnter?: (planet: PlanetConfig) => void;
20
+ onPlanetExit?: () => void;
21
+ onSatelliteClick?: (event: CosmosNavigateEvent) => void;
22
+ tutorialSteps?: TutorialStep[];
23
+ showTutorial?: boolean;
24
+ onTutorialComplete?: () => void;
25
+ initialView?: CosmosView;
26
+ onViewChange?: (view: CosmosView) => void;
27
+ renderPlanetInterior?: (planet: PlanetConfig, onExit: () => void) => ReactNode;
28
+ topBar?: ReactNode;
29
+ theme?: Partial<CosmosTheme>;
30
+ starField?: boolean | StarFieldConfig;
31
+ nodeTypes?: Record<string, React.ComponentType<any>>;
32
+ edgeTypes?: Record<string, React.ComponentType<any>>;
33
+ className?: string;
34
+ style?: React.CSSProperties;
35
+ }
36
+
37
+ export declare interface CosmosNavigateEvent {
38
+ planetId: string;
39
+ satelliteId?: string;
40
+ satellite?: Satellite;
41
+ }
42
+
43
+ export declare interface CosmosTheme {
44
+ background: string;
45
+ starColor: string;
46
+ nebulaColor: string;
47
+ textColor: string;
48
+ panelBackground: string;
49
+ panelBorder: string;
50
+ controlsBackground: string;
51
+ fontFamily: string;
52
+ }
53
+
54
+ export declare function CosmosTutorial({ steps, onHighlightPlanet, onStepChange, onFinish, flyTo: _flyTo, }: CosmosTutorialProps): JSX_2.Element;
55
+
56
+ declare interface CosmosTutorialProps {
57
+ steps: TutorialStep[];
58
+ onHighlightPlanet: (planetId: string | null) => void;
59
+ onStepChange: (stepIdx: number) => void;
60
+ onFinish: () => void;
61
+ /** Camera flyover function — called with (x, y, zoom, duration) */
62
+ flyTo?: (x: number, y: number, zoom: number, duration: number) => void;
63
+ }
64
+
65
+ export declare type CosmosView = {
66
+ mode: 'universe';
67
+ } | {
68
+ mode: 'inspecting';
69
+ planetId: string;
70
+ } | {
71
+ mode: 'entering';
72
+ planetId: string;
73
+ } | {
74
+ mode: 'planet';
75
+ planetId: string;
76
+ };
77
+
78
+ export declare type CosmosWorkspaceProps = CosmosCanvasProps;
79
+
80
+ export declare interface OrbitConfig {
81
+ source: string;
82
+ target: string;
83
+ label?: string;
84
+ }
85
+
86
+ export declare const OrbitEdge: MemoExoticComponent<typeof OrbitEdgeComponent>;
87
+
88
+ declare function OrbitEdgeComponent({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, style, }: EdgeProps): JSX_2.Element;
89
+
90
+ export declare interface PlanetConfig {
91
+ id: string;
92
+ label: string;
93
+ subtitle: string;
94
+ color: string;
95
+ x: number;
96
+ y: number;
97
+ satellites: Satellite[];
98
+ status?: PlanetStatus;
99
+ icon?: ReactNode;
100
+ meta?: Record<string, unknown>;
101
+ }
102
+
103
+ export declare function PlanetInterior({ planet, onExit, onSatelliteClick, renderCustom, }: PlanetInteriorProps): JSX_2.Element;
104
+
105
+ declare interface PlanetInteriorProps {
106
+ planet: PlanetConfig;
107
+ onExit: () => void;
108
+ onSatelliteClick?: (event: CosmosNavigateEvent) => void;
109
+ renderCustom?: (planet: PlanetConfig, onExit: () => void) => ReactNode;
110
+ }
111
+
112
+ export declare const PlanetNode: MemoExoticComponent<typeof PlanetNodeComponent>;
113
+
114
+ declare function PlanetNodeComponent({ data }: NodeProps): JSX_2.Element;
115
+
116
+ export declare type PlanetStatus = 'idle' | 'running' | 'error' | 'success' | 'disabled';
117
+
118
+ export declare interface Satellite {
119
+ id: string;
120
+ label: string;
121
+ route?: string;
122
+ icon?: string | ReactNode;
123
+ summary?: {
124
+ total?: number;
125
+ running?: number;
126
+ failed?: number;
127
+ };
128
+ quickActions?: Array<{
129
+ label: string;
130
+ action: string;
131
+ }>;
132
+ meta?: Record<string, unknown>;
133
+ }
134
+
135
+ export declare function SidePanel({ planet, onClose, onEnterPlanet, onSatelliteClick, }: SidePanelProps): JSX_2.Element;
136
+
137
+ declare interface SidePanelProps {
138
+ planet: PlanetConfig;
139
+ onClose: () => void;
140
+ onEnterPlanet: () => void;
141
+ onSatelliteClick?: (event: CosmosNavigateEvent) => void;
142
+ }
143
+
144
+ export declare function StarField({ config, background }: StarFieldProps): JSX_2.Element;
145
+
146
+ export declare interface StarFieldConfig {
147
+ starCount?: number;
148
+ nebulaCount?: number;
149
+ starColor?: string;
150
+ nebulaColor?: string;
151
+ starSize?: number;
152
+ nebulaSize?: number;
153
+ rotationSpeed?: number;
154
+ }
155
+
156
+ declare interface StarFieldProps {
157
+ config?: StarFieldConfig;
158
+ background?: string;
159
+ }
160
+
161
+ export declare interface TutorialStep {
162
+ planetId: string;
163
+ title: string;
164
+ description: string;
165
+ chipText?: string;
166
+ chipColor?: string;
167
+ }
168
+
169
+ export declare function ZoomTransition({ planet }: ZoomTransitionProps): JSX_2.Element;
170
+
171
+ declare interface ZoomTransitionProps {
172
+ planet: PlanetConfig;
173
+ }
174
+
175
+ export { }