mulmocast 2.6.5 → 2.6.6

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 (37) hide show
  1. package/lib/actions/graph_option.d.ts +3 -0
  2. package/lib/actions/graph_option.js +18 -0
  3. package/lib/actions/image_references.js +1 -1
  4. package/lib/actions/images.d.ts +2 -3
  5. package/lib/actions/images.js +4 -17
  6. package/lib/actions/movie.d.ts +3 -0
  7. package/lib/actions/movie.js +38 -5
  8. package/lib/agents/add_bgm_agent.d.ts +10 -0
  9. package/lib/agents/add_bgm_agent.js +26 -4
  10. package/lib/agents/movie_genai_agent.js +1 -1
  11. package/lib/agents/movie_replicate_agent.js +29 -5
  12. package/lib/types/provider2agent.d.ts +2 -0
  13. package/lib/types/provider2agent.js +78 -5
  14. package/lib/types/schema.d.ts +34 -4
  15. package/lib/types/schema.js +9 -1
  16. package/lib/utils/context.d.ts +17 -2
  17. package/lib/utils/image_plugins/html_tailwind.d.ts +5 -0
  18. package/lib/utils/image_plugins/html_tailwind.js +56 -5
  19. package/package.json +8 -7
  20. package/scripts/test/fixtures/movie_tone_high.mov +0 -0
  21. package/scripts/test/fixtures/movie_tone_low.mov +0 -0
  22. package/scripts/test/fixtures/movie_tone_mid.mov +0 -0
  23. package/scripts/test/glb/sample_2026-03-15T172907.296_compat.glb +0 -0
  24. package/scripts/test/test_audio_mix.json +91 -0
  25. package/scripts/test/test_audio_mix_beat_vol.json +100 -0
  26. package/scripts/test/test_audio_mix_ducking.json +91 -0
  27. package/scripts/test/test_audio_mix_legacy.json +90 -0
  28. package/scripts/test/test_grok.json +57 -0
  29. package/scripts/test/test_image_references.json +74 -0
  30. package/scripts/test/test_kling_v3.json +54 -0
  31. package/scripts/test/test_kling_v3_omni.json +54 -0
  32. package/scripts/test/test_lipsync2.json +48 -52
  33. package/scripts/test/test_lipsync5.json +66 -0
  34. package/scripts/test/test_runway.json +54 -0
  35. package/scripts/test/test_threejs.json +241 -0
  36. package/scripts/test/test_threejs_glb.json +154 -0
  37. package/scripts/test/test_veo31_lite.json +39 -0
@@ -303,6 +303,11 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
303
303
  kind: "path";
304
304
  path: string;
305
305
  } | undefined;
306
+ movieVolume?: number | undefined;
307
+ ttsVolume?: number | undefined;
308
+ ducking?: {
309
+ ratio?: number | undefined;
310
+ } | undefined;
306
311
  };
307
312
  lang: string;
308
313
  beats: {
@@ -1846,8 +1851,8 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
1846
1851
  vertexai_location?: string | undefined;
1847
1852
  } | undefined;
1848
1853
  audioParams?: {
1849
- movieVolume: number;
1850
1854
  padding?: number | undefined;
1855
+ movieVolume?: number | undefined;
1851
1856
  } | undefined;
1852
1857
  movieParams?: {
1853
1858
  provider?: string | undefined;
@@ -2530,6 +2535,11 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
2530
2535
  kind: "path";
2531
2536
  path: string;
2532
2537
  } | undefined;
2538
+ movieVolume?: number | undefined;
2539
+ ttsVolume?: number | undefined;
2540
+ ducking?: {
2541
+ ratio?: number | undefined;
2542
+ } | undefined;
2533
2543
  };
2534
2544
  lang: string;
2535
2545
  beats: {
@@ -4073,8 +4083,8 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
4073
4083
  vertexai_location?: string | undefined;
4074
4084
  } | undefined;
4075
4085
  audioParams?: {
4076
- movieVolume: number;
4077
4086
  padding?: number | undefined;
4087
+ movieVolume?: number | undefined;
4078
4088
  } | undefined;
4079
4089
  movieParams?: {
4080
4090
  provider?: string | undefined;
@@ -4764,6 +4774,11 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
4764
4774
  kind: "path";
4765
4775
  path: string;
4766
4776
  } | undefined;
4777
+ movieVolume?: number | undefined;
4778
+ ttsVolume?: number | undefined;
4779
+ ducking?: {
4780
+ ratio?: number | undefined;
4781
+ } | undefined;
4767
4782
  };
4768
4783
  lipSyncParams?: {
4769
4784
  provider?: string | undefined;
@@ -15,6 +15,11 @@ export declare const resolveMovieRefs: (html: string, movieRefs: Record<string,
15
15
  * Paths starting with http://, https://, file://, data:, image:, or / are left unchanged.
16
16
  */
17
17
  export declare const resolveRelativeImagePaths: (html: string, baseDirPath: string) => string;
18
+ /**
19
+ * Resolve relative modelUrl assignment in user scripts to file:// absolute paths.
20
+ * e.g. const modelUrl = "models/a.glb" -> const modelUrl = "file:///abs/models/a.glb"
21
+ */
22
+ export declare const resolveRelativeModelPathsInScript: (html: string, baseDirPath: string) => string;
18
23
  export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
19
24
  export declare const path: (params: ImageProcessorParams) => string;
20
25
  export declare const html: (params: ImageProcessorParams) => Promise<string | undefined>;
@@ -38,8 +38,16 @@ export const resolveMovieRefs = (html, movieRefs) => {
38
38
  * Paths starting with http://, https://, file://, data:, image:, or / are left unchanged.
39
39
  */
40
40
  export const resolveRelativeImagePaths = (html, baseDirPath) => {
41
- return html.replace(/(\bsrc\s*=\s*)(["'])((?!https?:\/\/|file:\/\/|data:|image:|\/)[^"']+)\2/gi, (_, prefix, quote, relativePath) => {
42
- const absolutePath = nodePath.resolve(baseDirPath, relativePath);
41
+ return html.replace(/(\bsrc\s*=\s*)(["'])([^"']+)\2/gi, (_, prefix, quote, pathValue) => {
42
+ const isAbsoluteLike = pathValue.startsWith("http://") ||
43
+ pathValue.startsWith("https://") ||
44
+ pathValue.startsWith("file://") ||
45
+ pathValue.startsWith("data:") ||
46
+ pathValue.startsWith("image:") ||
47
+ pathValue.startsWith("/");
48
+ if (isAbsoluteLike)
49
+ return `${prefix}${quote}${pathValue}${quote}`;
50
+ const absolutePath = nodePath.resolve(baseDirPath, pathValue);
43
51
  return `${prefix}${quote}file://${absolutePath}${quote}`;
44
52
  });
45
53
  };
@@ -52,7 +60,48 @@ const buildUserScript = (script) => {
52
60
  if (!script)
53
61
  return "";
54
62
  const code = Array.isArray(script) ? script.join("\n") : script;
55
- return `<script>\n${code}\n</script>`;
63
+ // If user script contains ESM import/export, emit module script so imports work.
64
+ const isModule = code.split("\n").some((line) => {
65
+ const trimmed = line.trimStart();
66
+ return trimmed.startsWith("import ") || trimmed.startsWith("export ");
67
+ });
68
+ return isModule ? `<script type="module">\n${code}\n</script>` : `<script>\n${code}\n</script>`;
69
+ };
70
+ /**
71
+ * Resolve relative modelUrl assignment in user scripts to file:// absolute paths.
72
+ * e.g. const modelUrl = "models/a.glb" -> const modelUrl = "file:///abs/models/a.glb"
73
+ */
74
+ export const resolveRelativeModelPathsInScript = (html, baseDirPath) => {
75
+ const lines = html.split("\n");
76
+ return lines
77
+ .map((line) => {
78
+ const hasModelDeclaration = line.includes("modelUrl") && (line.includes("const ") || line.includes("let ") || line.includes("var "));
79
+ if (!hasModelDeclaration || !line.includes("="))
80
+ return line;
81
+ const eqIndex = line.indexOf("=");
82
+ const afterEq = line.slice(eqIndex + 1);
83
+ const singleQuoteIndex = afterEq.indexOf("'");
84
+ const doubleQuoteIndex = afterEq.indexOf('"');
85
+ const quoteIndex = singleQuoteIndex >= 0 && (doubleQuoteIndex < 0 || singleQuoteIndex < doubleQuoteIndex) ? singleQuoteIndex : doubleQuoteIndex;
86
+ if (quoteIndex < 0)
87
+ return line;
88
+ const quoteChar = afterEq[quoteIndex];
89
+ const start = eqIndex + 1 + quoteIndex;
90
+ const end = line.indexOf(quoteChar, start + 1);
91
+ if (end < 0)
92
+ return line;
93
+ const rawPath = line.slice(start + 1, end);
94
+ const isAbsoluteLike = rawPath.startsWith("http://") ||
95
+ rawPath.startsWith("https://") ||
96
+ rawPath.startsWith("file://") ||
97
+ rawPath.startsWith("data:") ||
98
+ rawPath.startsWith("/");
99
+ if (isAbsoluteLike)
100
+ return line;
101
+ const absolutePath = nodePath.resolve(baseDirPath, rawPath);
102
+ return `${line.slice(0, start + 1)}file://${absolutePath}${line.slice(end)}`;
103
+ })
104
+ .join("\n");
56
105
  };
57
106
  /**
58
107
  * Resolve HTML and script from beat image data.
@@ -106,7 +155,8 @@ const buildAnimatedHtml = (params, totalFrames, fps) => {
106
155
  });
107
156
  const resolvedImageRefs = resolveImageRefs(rawHtmlData, params.imageRefs ?? {});
108
157
  const resolvedAllRefs = resolveMovieRefs(resolvedImageRefs, params.movieRefs ?? {});
109
- return resolveRelativeImagePaths(resolvedAllRefs, context.fileDirs.mulmoFileDirPath);
158
+ const resolvedImages = resolveRelativeImagePaths(resolvedAllRefs, context.fileDirs.mulmoFileDirPath);
159
+ return resolveRelativeModelPathsInScript(resolvedImages, context.fileDirs.mulmoFileDirPath);
110
160
  };
111
161
  const processHtmlTailwindAnimated = async (params) => {
112
162
  const { beat, imagePath, canvasSize } = params;
@@ -163,7 +213,8 @@ const processHtmlTailwindStatic = async (params) => {
163
213
  });
164
214
  const resolvedImageRefs = resolveImageRefs(rawHtmlData, params.imageRefs ?? {});
165
215
  const resolvedAllRefs = resolveMovieRefs(resolvedImageRefs, params.movieRefs ?? {});
166
- const htmlData = resolveRelativeImagePaths(resolvedAllRefs, context.fileDirs.mulmoFileDirPath);
216
+ const resolvedImages = resolveRelativeImagePaths(resolvedAllRefs, context.fileDirs.mulmoFileDirPath);
217
+ const htmlData = resolveRelativeModelPathsInScript(resolvedImages, context.fileDirs.mulmoFileDirPath);
167
218
  await renderHTMLToImage(htmlData, imagePath, canvasSize.width, canvasSize.height);
168
219
  return imagePath;
169
220
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "2.6.5",
3
+ "version": "2.6.6",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",
@@ -88,7 +88,7 @@
88
88
  "homepage": "https://github.com/receptron/mulmocast-cli#readme",
89
89
  "dependencies": {
90
90
  "@google-cloud/text-to-speech": "^6.4.0",
91
- "@google/genai": "^1.46.0",
91
+ "@google/genai": "^1.48.0",
92
92
  "@graphai/anthropic_agent": "^2.0.12",
93
93
  "@graphai/browserless_agent": "^2.0.2",
94
94
  "@graphai/gemini_agent": "^2.0.5",
@@ -100,12 +100,12 @@
100
100
  "@graphai/vanilla_node_agents": "^2.0.4",
101
101
  "@inquirer/input": "^5.0.10",
102
102
  "@inquirer/select": "^5.1.2",
103
- "@modelcontextprotocol/sdk": "^1.27.1",
103
+ "@modelcontextprotocol/sdk": "^1.29.0",
104
104
  "@mozilla/readability": "^0.6.0",
105
105
  "@tavily/core": "^0.5.11",
106
106
  "archiver": "^7.0.1",
107
107
  "clipboardy": "^5.3.1",
108
- "dotenv": "^17.3.1",
108
+ "dotenv": "^17.4.0",
109
109
  "fluent-ffmpeg": "^2.1.3",
110
110
  "graphai": "^2.0.16",
111
111
  "jsdom": "^29.0.1",
@@ -114,7 +114,7 @@
114
114
  "ora": "^9.3.0",
115
115
  "puppeteer": "^24.40.0",
116
116
  "replicate": "^1.4.0",
117
- "yaml": "^2.8.2",
117
+ "yaml": "^2.8.3",
118
118
  "yargs": "^18.0.0",
119
119
  "zod": "^4.3.6"
120
120
  },
@@ -128,13 +128,14 @@
128
128
  "cross-env": "^10.1.0",
129
129
  "eslint": "^10.1.0",
130
130
  "eslint-config-prettier": "^10.1.8",
131
+ "eslint-plugin-import": "^2.32.0",
131
132
  "eslint-plugin-prettier": "^5.5.5",
132
133
  "eslint-plugin-sonarjs": "^4.0.2",
133
134
  "globals": "^17.4.0",
134
135
  "prettier": "^3.8.1",
135
136
  "tsx": "^4.21.0",
136
- "typescript": "6.0.1-rc",
137
- "typescript-eslint": "^8.57.1"
137
+ "typescript": "6.0.2",
138
+ "typescript-eslint": "^8.58.0"
138
139
  },
139
140
  "engines": {
140
141
  "node": ">=22.0.0"
@@ -0,0 +1,91 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.1"
4
+ },
5
+ "title": "Audio Mix Manual Test (fixtures)",
6
+ "lang": "en",
7
+ "canvasSize": {
8
+ "width": 320,
9
+ "height": 180
10
+ },
11
+ "speechParams": {
12
+ "speakers": {
13
+ "Presenter": {
14
+ "provider": "openai",
15
+ "voiceId": "shimmer"
16
+ }
17
+ }
18
+ },
19
+ "audioParams": {
20
+ "bgmVolume": 0,
21
+ "movieVolume": 0.3
22
+ },
23
+ "beats": [
24
+ {
25
+ "speaker": "Presenter",
26
+ "text": "Low tone with narration.",
27
+ "image": {
28
+ "type": "movie",
29
+ "source": {
30
+ "kind": "path",
31
+ "path": "fixtures/movie_tone_low.mov"
32
+ }
33
+ }
34
+ },
35
+ {
36
+ "speaker": "Presenter",
37
+ "duration": 3.0,
38
+ "image": {
39
+ "type": "movie",
40
+ "source": {
41
+ "kind": "path",
42
+ "path": "fixtures/movie_tone_low.mov"
43
+ }
44
+ }
45
+ },
46
+ {
47
+ "speaker": "Presenter",
48
+ "text": "Mid tone with narration.",
49
+ "image": {
50
+ "type": "movie",
51
+ "source": {
52
+ "kind": "path",
53
+ "path": "fixtures/movie_tone_mid.mov"
54
+ }
55
+ }
56
+ },
57
+ {
58
+ "speaker": "Presenter",
59
+ "duration": 3.0,
60
+ "image": {
61
+ "type": "movie",
62
+ "source": {
63
+ "kind": "path",
64
+ "path": "fixtures/movie_tone_mid.mov"
65
+ }
66
+ }
67
+ },
68
+ {
69
+ "speaker": "Presenter",
70
+ "text": "High tone with narration.",
71
+ "image": {
72
+ "type": "movie",
73
+ "source": {
74
+ "kind": "path",
75
+ "path": "fixtures/movie_tone_high.mov"
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "speaker": "Presenter",
81
+ "duration": 3.0,
82
+ "image": {
83
+ "type": "movie",
84
+ "source": {
85
+ "kind": "path",
86
+ "path": "fixtures/movie_tone_high.mov"
87
+ }
88
+ }
89
+ }
90
+ ]
91
+ }
@@ -0,0 +1,100 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.1"
4
+ },
5
+ "title": "Audio Mix Beat Volume Test (fixtures)",
6
+ "lang": "en",
7
+ "canvasSize": {
8
+ "width": 320,
9
+ "height": 180
10
+ },
11
+ "speechParams": {
12
+ "speakers": {
13
+ "Presenter": {
14
+ "provider": "openai",
15
+ "voiceId": "shimmer"
16
+ }
17
+ }
18
+ },
19
+ "audioParams": {
20
+ "bgmVolume": 0,
21
+ "movieVolume": 0.5
22
+ },
23
+ "beats": [
24
+ {
25
+ "speaker": "Presenter",
26
+ "text": "Low tone, beat movieVolume 0.1.",
27
+ "audioParams": {
28
+ "movieVolume": 0.1
29
+ },
30
+ "image": {
31
+ "type": "movie",
32
+ "source": {
33
+ "kind": "path",
34
+ "path": "fixtures/movie_tone_low.mov"
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "speaker": "Presenter",
40
+ "text": "Low tone, script default 0.5.",
41
+ "image": {
42
+ "type": "movie",
43
+ "source": {
44
+ "kind": "path",
45
+ "path": "fixtures/movie_tone_low.mov"
46
+ }
47
+ }
48
+ },
49
+ {
50
+ "speaker": "Presenter",
51
+ "text": "Mid tone, beat movieVolume 1.0.",
52
+ "audioParams": {
53
+ "movieVolume": 1.0
54
+ },
55
+ "image": {
56
+ "type": "movie",
57
+ "source": {
58
+ "kind": "path",
59
+ "path": "fixtures/movie_tone_mid.mov"
60
+ }
61
+ }
62
+ },
63
+ {
64
+ "speaker": "Presenter",
65
+ "text": "Mid tone, script default 0.5.",
66
+ "image": {
67
+ "type": "movie",
68
+ "source": {
69
+ "kind": "path",
70
+ "path": "fixtures/movie_tone_mid.mov"
71
+ }
72
+ }
73
+ },
74
+ {
75
+ "speaker": "Presenter",
76
+ "text": "High tone, beat movieVolume 0.0, should be silent.",
77
+ "audioParams": {
78
+ "movieVolume": 0.0
79
+ },
80
+ "image": {
81
+ "type": "movie",
82
+ "source": {
83
+ "kind": "path",
84
+ "path": "fixtures/movie_tone_high.mov"
85
+ }
86
+ }
87
+ },
88
+ {
89
+ "speaker": "Presenter",
90
+ "text": "High tone, script default 0.5.",
91
+ "image": {
92
+ "type": "movie",
93
+ "source": {
94
+ "kind": "path",
95
+ "path": "fixtures/movie_tone_high.mov"
96
+ }
97
+ }
98
+ }
99
+ ]
100
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.1"
4
+ },
5
+ "title": "Audio Mix Ducking Test (fixtures)",
6
+ "lang": "en",
7
+ "canvasSize": {
8
+ "width": 320,
9
+ "height": 180
10
+ },
11
+ "speechParams": {
12
+ "speakers": {
13
+ "Presenter": {
14
+ "provider": "openai",
15
+ "voiceId": "shimmer"
16
+ }
17
+ }
18
+ },
19
+ "audioParams": {
20
+ "bgmVolume": 0,
21
+ "ducking": { "ratio": 0.3 }
22
+ },
23
+ "beats": [
24
+ {
25
+ "speaker": "Presenter",
26
+ "text": "Low tone with narration.",
27
+ "image": {
28
+ "type": "movie",
29
+ "source": {
30
+ "kind": "path",
31
+ "path": "fixtures/movie_tone_low.mov"
32
+ }
33
+ }
34
+ },
35
+ {
36
+ "speaker": "Presenter",
37
+ "duration": 3.0,
38
+ "image": {
39
+ "type": "movie",
40
+ "source": {
41
+ "kind": "path",
42
+ "path": "fixtures/movie_tone_low.mov"
43
+ }
44
+ }
45
+ },
46
+ {
47
+ "speaker": "Presenter",
48
+ "text": "Mid tone with narration.",
49
+ "image": {
50
+ "type": "movie",
51
+ "source": {
52
+ "kind": "path",
53
+ "path": "fixtures/movie_tone_mid.mov"
54
+ }
55
+ }
56
+ },
57
+ {
58
+ "speaker": "Presenter",
59
+ "duration": 3.0,
60
+ "image": {
61
+ "type": "movie",
62
+ "source": {
63
+ "kind": "path",
64
+ "path": "fixtures/movie_tone_mid.mov"
65
+ }
66
+ }
67
+ },
68
+ {
69
+ "speaker": "Presenter",
70
+ "text": "High tone with narration.",
71
+ "image": {
72
+ "type": "movie",
73
+ "source": {
74
+ "kind": "path",
75
+ "path": "fixtures/movie_tone_high.mov"
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "speaker": "Presenter",
81
+ "duration": 3.0,
82
+ "image": {
83
+ "type": "movie",
84
+ "source": {
85
+ "kind": "path",
86
+ "path": "fixtures/movie_tone_high.mov"
87
+ }
88
+ }
89
+ }
90
+ ]
91
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.1"
4
+ },
5
+ "title": "Audio Mix Legacy Test (fixtures)",
6
+ "lang": "en",
7
+ "canvasSize": {
8
+ "width": 320,
9
+ "height": 180
10
+ },
11
+ "speechParams": {
12
+ "speakers": {
13
+ "Presenter": {
14
+ "provider": "openai",
15
+ "voiceId": "shimmer"
16
+ }
17
+ }
18
+ },
19
+ "audioParams": {
20
+ "bgmVolume": 0
21
+ },
22
+ "beats": [
23
+ {
24
+ "speaker": "Presenter",
25
+ "text": "Low tone with narration.",
26
+ "image": {
27
+ "type": "movie",
28
+ "source": {
29
+ "kind": "path",
30
+ "path": "fixtures/movie_tone_low.mov"
31
+ }
32
+ }
33
+ },
34
+ {
35
+ "speaker": "Presenter",
36
+ "duration": 3.0,
37
+ "image": {
38
+ "type": "movie",
39
+ "source": {
40
+ "kind": "path",
41
+ "path": "fixtures/movie_tone_low.mov"
42
+ }
43
+ }
44
+ },
45
+ {
46
+ "speaker": "Presenter",
47
+ "text": "Mid tone with narration.",
48
+ "image": {
49
+ "type": "movie",
50
+ "source": {
51
+ "kind": "path",
52
+ "path": "fixtures/movie_tone_mid.mov"
53
+ }
54
+ }
55
+ },
56
+ {
57
+ "speaker": "Presenter",
58
+ "duration": 3.0,
59
+ "image": {
60
+ "type": "movie",
61
+ "source": {
62
+ "kind": "path",
63
+ "path": "fixtures/movie_tone_mid.mov"
64
+ }
65
+ }
66
+ },
67
+ {
68
+ "speaker": "Presenter",
69
+ "text": "High tone with narration.",
70
+ "image": {
71
+ "type": "movie",
72
+ "source": {
73
+ "kind": "path",
74
+ "path": "fixtures/movie_tone_high.mov"
75
+ }
76
+ }
77
+ },
78
+ {
79
+ "speaker": "Presenter",
80
+ "duration": 3.0,
81
+ "image": {
82
+ "type": "movie",
83
+ "source": {
84
+ "kind": "path",
85
+ "path": "fixtures/movie_tone_high.mov"
86
+ }
87
+ }
88
+ }
89
+ ]
90
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "$mulmocast": { "version": "1.1" },
3
+ "movieParams": {
4
+ "provider": "replicate",
5
+ "model": "xai/grok-imagine-video"
6
+ },
7
+ "audioParams": {
8
+ "bgmVolume": 0
9
+ },
10
+ "captionParams": {
11
+ "lang": "en"
12
+ },
13
+ "lang": "en",
14
+ "beats": [
15
+ {
16
+ "text": "Testing xai/grok-imagine-video — text-to-video, image-to-video, and duration varieties.",
17
+ "image": {
18
+ "type": "textSlide",
19
+ "slide": {
20
+ "title": "xai/grok-imagine-video test"
21
+ }
22
+ }
23
+ },
24
+ {
25
+ "id": "grok-t2v-5s",
26
+ "text": "Text-to-video, 5 seconds: a red fox trots through a snowy forest at dawn, pawprints left behind",
27
+ "duration": 5,
28
+ "moviePrompt": "a red fox trots through a snowy forest at dawn, pawprints left behind, soft golden light filtering through pine trees"
29
+ },
30
+ {
31
+ "id": "grok-t2v-8s",
32
+ "text": "Text-to-video, 8 seconds: timelapse of storm clouds forming over a mountain range",
33
+ "duration": 8,
34
+ "moviePrompt": "timelapse of dark storm clouds rolling in over a rugged mountain range, lightning flashes in the distance, dramatic cinematic lighting"
35
+ },
36
+ {
37
+ "id": "grok-t2v-10s",
38
+ "text": "Text-to-video, 10 seconds: bustling Tokyo crossing at night",
39
+ "duration": 10,
40
+ "moviePrompt": "aerial dolly shot over Shibuya crossing at night, neon lights reflecting on wet pavement, crowds of people crossing in all directions"
41
+ },
42
+ {
43
+ "id": "grok-i2v-5s",
44
+ "text": "Image-to-video, 5 seconds: ocean waves animated from a still image",
45
+ "duration": 5,
46
+ "imagePrompt": "a calm tropical beach at sunset, crystal-clear turquoise water, golden sand, photorealistic",
47
+ "moviePrompt": "gentle waves lapping the shore, palm trees swaying softly in the breeze, camera slowly pushing forward"
48
+ },
49
+ {
50
+ "id": "grok-i2v-8s",
51
+ "text": "Image-to-video, 8 seconds: city skyline coming to life",
52
+ "duration": 8,
53
+ "imagePrompt": "futuristic city skyline at dusk, glass skyscrapers with glowing windows, photorealistic",
54
+ "moviePrompt": "lights in the skyscraper windows flicker on one by one as night falls, slow upward pan along the tallest tower"
55
+ }
56
+ ]
57
+ }