@effectnode/media 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.
Files changed (133) hide show
  1. package/bin/effectnode-media +2 -0
  2. package/dist/backend/index.d.ts +8 -0
  3. package/dist/backend/index.js +13 -0
  4. package/dist/backend/movie-backend/agent/agent-backend.d.ts +16 -0
  5. package/dist/backend/movie-backend/agent/agent-backend.js +703 -0
  6. package/dist/backend/movie-backend/agent/storyprompt.d.ts +1 -0
  7. package/dist/backend/movie-backend/agent/storyprompt.js +90 -0
  8. package/dist/backend/movie-backend/agent/tools/edit-image.d.ts +3 -0
  9. package/dist/backend/movie-backend/agent/tools/edit-image.js +192 -0
  10. package/dist/backend/movie-backend/agent/tools/get-time.d.ts +3 -0
  11. package/dist/backend/movie-backend/agent/tools/get-time.js +7 -0
  12. package/dist/backend/movie-backend/agent/tools/grep-files.d.ts +3 -0
  13. package/dist/backend/movie-backend/agent/tools/grep-files.js +59 -0
  14. package/dist/backend/movie-backend/agent/tools/image-to-video-generation.d.ts +3 -0
  15. package/dist/backend/movie-backend/agent/tools/image-to-video-generation.js +160 -0
  16. package/dist/backend/movie-backend/agent/tools/index.d.ts +7 -0
  17. package/dist/backend/movie-backend/agent/tools/index.js +59 -0
  18. package/dist/backend/movie-backend/agent/tools/list-files.d.ts +3 -0
  19. package/dist/backend/movie-backend/agent/tools/list-files.js +17 -0
  20. package/dist/backend/movie-backend/agent/tools/read-file.d.ts +3 -0
  21. package/dist/backend/movie-backend/agent/tools/read-file.js +28 -0
  22. package/dist/backend/movie-backend/agent/tools/remove-file.d.ts +3 -0
  23. package/dist/backend/movie-backend/agent/tools/remove-file.js +22 -0
  24. package/dist/backend/movie-backend/agent/tools/rename-file.d.ts +3 -0
  25. package/dist/backend/movie-backend/agent/tools/rename-file.js +37 -0
  26. package/dist/backend/movie-backend/agent/tools/show-image.d.ts +3 -0
  27. package/dist/backend/movie-backend/agent/tools/show-image.js +28 -0
  28. package/dist/backend/movie-backend/agent/tools/stitch-videos.d.ts +3 -0
  29. package/dist/backend/movie-backend/agent/tools/stitch-videos.js +96 -0
  30. package/dist/backend/movie-backend/agent/tools/text-to-video-generation.d.ts +3 -0
  31. package/dist/backend/movie-backend/agent/tools/text-to-video-generation.js +125 -0
  32. package/dist/backend/movie-backend/agent/tools/types.d.ts +15 -0
  33. package/dist/backend/movie-backend/agent/tools/types.js +1 -0
  34. package/dist/backend/movie-backend/agent/tools/update-file.d.ts +3 -0
  35. package/dist/backend/movie-backend/agent/tools/update-file.js +27 -0
  36. package/dist/backend/movie-backend/agent/tools/write-file.d.ts +3 -0
  37. package/dist/backend/movie-backend/agent/tools/write-file.js +26 -0
  38. package/dist/backend/movie-backend/agent/workspace.d.ts +25 -0
  39. package/dist/backend/movie-backend/agent/workspace.js +124 -0
  40. package/dist/backend/movie-backend/core.d.ts +4 -0
  41. package/dist/backend/movie-backend/core.js +1167 -0
  42. package/dist/backend/movie-backend/generation-queue.d.ts +24 -0
  43. package/dist/backend/movie-backend/generation-queue.js +766 -0
  44. package/dist/backend/movie-backend/process.d.ts +21 -0
  45. package/dist/backend/movie-backend/process.js +98 -0
  46. package/dist/backend/movie-backend/render-media.d.ts +48 -0
  47. package/dist/backend/movie-backend/render-media.js +3311 -0
  48. package/dist/backend/routes/health.d.ts +1 -0
  49. package/dist/backend/routes/health.js +9 -0
  50. package/dist/backend/routes/index.d.ts +1 -0
  51. package/dist/backend/routes/index.js +11 -0
  52. package/dist/backend/routes/media.d.ts +1 -0
  53. package/dist/backend/routes/media.js +13 -0
  54. package/dist/backend/routes/projects.d.ts +8 -0
  55. package/dist/backend/routes/projects.js +68 -0
  56. package/dist/backend/routes/voice.d.ts +1 -0
  57. package/dist/backend/routes/voice.js +39 -0
  58. package/dist/backend/routes.d.ts +1 -0
  59. package/dist/backend/routes.js +20 -0
  60. package/dist/backend/server.d.ts +1 -0
  61. package/dist/backend/server.js +23 -0
  62. package/dist/backend/workspace.d.ts +5 -0
  63. package/dist/backend/workspace.js +27 -0
  64. package/dist/backend/ws/index.d.ts +3 -0
  65. package/dist/backend/ws/index.js +27 -0
  66. package/dist/backend/ws/messages.d.ts +8 -0
  67. package/dist/backend/ws/messages.js +21 -0
  68. package/dist/backend/ws.d.ts +3 -0
  69. package/dist/backend/ws.js +29 -0
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.js +80 -0
  72. package/frontend/index.html +22 -0
  73. package/frontend/public/ffmpeg/ffmpeg-core.js +16 -0
  74. package/frontend/public/ffmpeg/ffmpeg-core.wasm +0 -0
  75. package/frontend/src/index.css +46 -0
  76. package/frontend/src/main.tsx +13 -0
  77. package/frontend/src/movie-app/AppRouter.tsx +14 -0
  78. package/frontend/src/movie-app/MediaStudio.tsx +9 -0
  79. package/frontend/src/movie-app/SetupPage.tsx +293 -0
  80. package/frontend/src/movie-app/components/AgentWorkspace.tsx +574 -0
  81. package/frontend/src/movie-app/components/ChatUI/ChatUI.tsx +655 -0
  82. package/frontend/src/movie-app/components/ChatUI/MarkdownMessage.tsx +267 -0
  83. package/frontend/src/movie-app/components/EditorTabs/AgentTab.tsx +61 -0
  84. package/frontend/src/movie-app/components/EditorTabs/BatchImageToVideoTab.tsx +927 -0
  85. package/frontend/src/movie-app/components/EditorTabs/BatchVideoTab.tsx +777 -0
  86. package/frontend/src/movie-app/components/EditorTabs/BatchVoiceVideoTab.tsx +913 -0
  87. package/frontend/src/movie-app/components/EditorTabs/CharacterSheet.tsx +234 -0
  88. package/frontend/src/movie-app/components/EditorTabs/CharactersTab.tsx +664 -0
  89. package/frontend/src/movie-app/components/EditorTabs/CropTool.tsx +251 -0
  90. package/frontend/src/movie-app/components/EditorTabs/ExtendVideoTab.tsx +305 -0
  91. package/frontend/src/movie-app/components/EditorTabs/ExtractImageTab.tsx +249 -0
  92. package/frontend/src/movie-app/components/EditorTabs/FastImageEditTab.tsx +555 -0
  93. package/frontend/src/movie-app/components/EditorTabs/GenerateVideoTab.tsx +722 -0
  94. package/frontend/src/movie-app/components/EditorTabs/LlmServerTab.tsx +40 -0
  95. package/frontend/src/movie-app/components/EditorTabs/MlxVlmServerPanel.tsx +490 -0
  96. package/frontend/src/movie-app/components/EditorTabs/MovieStudioTab.tsx +938 -0
  97. package/frontend/src/movie-app/components/EditorTabs/ReferencesToVideoTab.tsx +881 -0
  98. package/frontend/src/movie-app/components/EditorTabs/SceneVisualTab.tsx +267 -0
  99. package/frontend/src/movie-app/components/EditorTabs/StoryWriterTab.tsx +51 -0
  100. package/frontend/src/movie-app/components/EditorTabs/TaskQueuePanel.tsx +246 -0
  101. package/frontend/src/movie-app/components/EditorTabs/TerminalLogPanel.tsx +49 -0
  102. package/frontend/src/movie-app/components/EditorTabs/TextToImageTab.tsx +574 -0
  103. package/frontend/src/movie-app/components/EditorTabs/VoiceChatPanel.tsx +320 -0
  104. package/frontend/src/movie-app/components/ProjectEditorPage.tsx +636 -0
  105. package/frontend/src/movie-app/components/ProjectManager.tsx +381 -0
  106. package/frontend/src/movie-app/index.css +46 -0
  107. package/frontend/src/movie-app/index.html +16 -0
  108. package/frontend/src/movie-app/lambobo.png +0 -0
  109. package/frontend/src/movie-app/lib/batchImageToVideoStorage.ts +69 -0
  110. package/frontend/src/movie-app/lib/batchVideoStorage.ts +68 -0
  111. package/frontend/src/movie-app/lib/batchVoiceStorage.ts +75 -0
  112. package/frontend/src/movie-app/lib/ffmpeg.ts +42 -0
  113. package/frontend/src/movie-app/lib/referencesToVideoStorage.ts +64 -0
  114. package/frontend/src/movie-app/lib/textToImageStorage.ts +61 -0
  115. package/frontend/src/movie-app/public/ffmpeg/ffmpeg-core.js +16 -0
  116. package/frontend/src/movie-app/public/ffmpeg/ffmpeg-core.wasm +0 -0
  117. package/frontend/src/movie-app/stores/batchImageToVideoStore.ts +736 -0
  118. package/frontend/src/movie-app/stores/batchVideoStore.ts +670 -0
  119. package/frontend/src/movie-app/stores/batchVoiceStore.ts +990 -0
  120. package/frontend/src/movie-app/stores/characterStore.ts +109 -0
  121. package/frontend/src/movie-app/stores/chatStore.ts +459 -0
  122. package/frontend/src/movie-app/stores/generationStore.ts +2140 -0
  123. package/frontend/src/movie-app/stores/logStore.ts +25 -0
  124. package/frontend/src/movie-app/stores/movieStudioStore.ts +709 -0
  125. package/frontend/src/movie-app/stores/projectStore.ts +124 -0
  126. package/frontend/src/movie-app/stores/queueStore.ts +214 -0
  127. package/frontend/src/movie-app/stores/referencesToVideoStore.ts +467 -0
  128. package/frontend/src/movie-app/stores/sceneVisualStore.ts +251 -0
  129. package/frontend/src/movie-app/stores/voiceChatStore.ts +170 -0
  130. package/frontend/src/movie-app/stores/workspaceStore.ts +158 -0
  131. package/frontend/src/vite-env.d.ts +1 -0
  132. package/frontend/tsconfig.json +19 -0
  133. package/package.json +65 -0
@@ -0,0 +1,234 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+
3
+ export interface SheetItem {
4
+ id: string;
5
+ name: string;
6
+ url: string;
7
+ }
8
+
9
+ interface Props {
10
+ items: SheetItem[];
11
+ projectId: string;
12
+ }
13
+
14
+ const API_BASE = `http://localhost:${(window as any).PORT}`;
15
+
16
+ // Base layout in "cell units"; scaled up so the sheet's longest edge is TARGET px.
17
+ const CELL_W = 160;
18
+ const CELL_H = 160;
19
+ const LABEL_H = 18;
20
+ const GAP = 12;
21
+ const PADDING = 12;
22
+ const COLUMNS = 5;
23
+ const TARGET = 4096;
24
+
25
+ function loadImage(src: string): Promise<HTMLImageElement> {
26
+ return new Promise((resolve, reject) => {
27
+ const img = new Image();
28
+ img.crossOrigin = "anonymous";
29
+ img.onload = () => resolve(img);
30
+ img.onerror = () => reject(new Error("Failed to load image"));
31
+ img.src = src;
32
+ });
33
+ }
34
+
35
+ /** Draw a contain-fit image into a cell, centered. */
36
+ function drawContain(
37
+ ctx: CanvasRenderingContext2D,
38
+ img: HTMLImageElement,
39
+ x: number,
40
+ y: number,
41
+ cellW: number,
42
+ cellH: number,
43
+ ) {
44
+ const scale = Math.min(cellW / img.width, cellH / img.height);
45
+ const dw = img.width * scale;
46
+ const dh = img.height * scale;
47
+ ctx.drawImage(img, x + (cellW - dw) / 2, y + (cellH - dh) / 2, dw, dh);
48
+ }
49
+
50
+ export default function CharacterSheet({ items, projectId }: Props) {
51
+ const canvasRef = useRef<HTMLCanvasElement>(null);
52
+ const [saving, setSaving] = useState(false);
53
+ const [saveError, setSaveError] = useState<string | null>(null);
54
+ const [saveInfo, setSaveInfo] = useState<string | null>(null);
55
+
56
+ useEffect(() => {
57
+ const canvas = canvasRef.current;
58
+ if (!canvas) return;
59
+ const ctx = canvas.getContext("2d");
60
+ if (!ctx) return;
61
+
62
+ const cols = Math.max(1, COLUMNS);
63
+ const rows = Math.ceil(items.length / cols) || 1;
64
+
65
+ const baseWidth = cols * CELL_W + (cols - 1) * GAP + PADDING * 2;
66
+ const baseHeight =
67
+ rows * (CELL_H + LABEL_H) + (rows - 1) * GAP + PADDING * 2;
68
+ const scale = TARGET / Math.max(baseWidth, baseHeight);
69
+
70
+ const cellW = CELL_W * scale;
71
+ const cellH = CELL_H * scale;
72
+ const labelH = LABEL_H * scale;
73
+ const gap = GAP * scale;
74
+ const pad = PADDING * scale;
75
+ const width = Math.round(baseWidth * scale);
76
+ const height = Math.round(baseHeight * scale);
77
+
78
+ canvas.width = width;
79
+ canvas.height = height;
80
+
81
+ ctx.fillStyle = "#ffffff";
82
+ ctx.fillRect(0, 0, width, height);
83
+
84
+ if (items.length === 0) {
85
+ ctx.fillStyle = "#94a3b8";
86
+ ctx.font = `${Math.round(12 * scale)}px sans-serif`;
87
+ ctx.textAlign = "center";
88
+ ctx.textBaseline = "middle";
89
+ ctx.fillText("No characters yet", width / 2, height / 2);
90
+ return;
91
+ }
92
+
93
+ // Guard against stale async draws if `items` changes mid-load.
94
+ let cancelled = false;
95
+
96
+ items.forEach(async (item, i) => {
97
+ const col = i % cols;
98
+ const row = Math.floor(i / cols);
99
+ const x = pad + col * (cellW + gap);
100
+ const y = pad + row * (cellH + labelH + gap);
101
+
102
+ // Cell background
103
+ ctx.fillStyle = "#f0fdfa";
104
+ ctx.fillRect(x, y, cellW, cellH + labelH);
105
+
106
+ let img: HTMLImageElement | null = null;
107
+ try {
108
+ img = await loadImage(item.url);
109
+ } catch {
110
+ img = null;
111
+ }
112
+ if (cancelled) return;
113
+
114
+ if (img) drawContain(ctx, img, x, y, cellW, cellH);
115
+
116
+ // Label bar
117
+ ctx.fillStyle = "rgba(0,0,0,0.65)";
118
+ ctx.fillRect(x, y + cellH, cellW, labelH);
119
+ ctx.fillStyle = "#ffffff";
120
+ ctx.font = `${Math.round(11 * scale)}px sans-serif`;
121
+ ctx.textAlign = "center";
122
+ ctx.textBaseline = "middle";
123
+ ctx.fillText(item.name, x + cellW / 2, y + cellH + labelH / 2);
124
+ });
125
+
126
+ return () => {
127
+ cancelled = true;
128
+ };
129
+ }, [items]);
130
+
131
+ const downloadSheet = () => {
132
+ const canvas = canvasRef.current;
133
+ if (!canvas) return;
134
+ const a = document.createElement("a");
135
+ a.href = canvas.toDataURL("image/png");
136
+ a.download = "character-sheet.png";
137
+ a.click();
138
+ };
139
+
140
+ const saveSheet = async () => {
141
+ const canvas = canvasRef.current;
142
+ if (!canvas || items.length === 0) return;
143
+ setSaving(true);
144
+ setSaveError(null);
145
+ setSaveInfo(null);
146
+ try {
147
+ const dataUrl = canvas.toDataURL("image/png");
148
+ const res = await fetch(`${API_BASE}/api/character-sheet`, {
149
+ method: "POST",
150
+ headers: { "Content-Type": "application/json" },
151
+ body: JSON.stringify({ image: dataUrl, projectId }),
152
+ });
153
+ if (!res.ok) throw new Error(await res.text());
154
+ const data = await res.json();
155
+ setSaveInfo(`Saved current.png (+ backup ${data.backupFilename})`);
156
+ } catch (e) {
157
+ setSaveError(String(e));
158
+ } finally {
159
+ setSaving(false);
160
+ }
161
+ };
162
+
163
+ const SaveIcon = (
164
+ <svg
165
+ width="14"
166
+ height="14"
167
+ viewBox="0 0 24 24"
168
+ fill="none"
169
+ stroke="currentColor"
170
+ strokeWidth="2"
171
+ strokeLinecap="round"
172
+ strokeLinejoin="round"
173
+ >
174
+ <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
175
+ <polyline points="17 21 17 13 7 13 7 21" />
176
+ <polyline points="7 3 7 8 15 8" />
177
+ </svg>
178
+ );
179
+
180
+ const DownloadIcon = (
181
+ <svg
182
+ width="14"
183
+ height="14"
184
+ viewBox="0 0 24 24"
185
+ fill="none"
186
+ stroke="currentColor"
187
+ strokeWidth="2"
188
+ strokeLinecap="round"
189
+ strokeLinejoin="round"
190
+ >
191
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
192
+ <polyline points="7 10 12 15 17 10" />
193
+ <line x1="12" y1="15" x2="12" y2="3" />
194
+ </svg>
195
+ );
196
+
197
+ return (
198
+ <div className="flex flex-col gap-3">
199
+ <div className="flex items-center justify-between">
200
+ <p className="text-xs text-ink-600/60">
201
+ {items.length} character{items.length === 1 ? "" : "s"}
202
+ </p>
203
+ <div className="flex items-center gap-2">
204
+ <button
205
+ onClick={saveSheet}
206
+ disabled={saving || items.length === 0}
207
+ className="flex items-center gap-1.5 px-3 py-2 text-xs font-medium rounded-xl bg-tiffany-500 hover:bg-tiffany-600 disabled:bg-ink-200 disabled:text-ink-500 text-ink-950 transition-colors"
208
+ >
209
+ {SaveIcon}
210
+ {saving ? "Saving..." : "Save Sheet"}
211
+ </button>
212
+ <button
213
+ onClick={downloadSheet}
214
+ disabled={items.length === 0}
215
+ className="flex items-center gap-1.5 px-3 py-2 text-xs font-medium rounded-xl border border-ink-200 bg-white text-ink-600 hover:border-ink-300 disabled:opacity-50 transition-colors"
216
+ >
217
+ {DownloadIcon}
218
+ Download Sheet
219
+ </button>
220
+ </div>
221
+ </div>
222
+
223
+ {saveInfo && (
224
+ <p className="text-xs text-emerald-600">{saveInfo}</p>
225
+ )}
226
+ {saveError && <p className="text-xs text-red-600">{saveError}</p>}
227
+
228
+ <canvas
229
+ ref={canvasRef}
230
+ className="rounded-2xl border border-ink-200 max-w-full h-auto"
231
+ />
232
+ </div>
233
+ );
234
+ }