mulmocast 1.2.29 → 1.2.31

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/README.md +46 -0
  2. package/lib/actions/html.d.ts +3 -0
  3. package/lib/actions/html.js +76 -0
  4. package/lib/actions/image_agents.d.ts +4 -1
  5. package/lib/actions/image_agents.js +10 -1
  6. package/lib/actions/images.d.ts +6 -1
  7. package/lib/actions/images.js +2 -0
  8. package/lib/actions/index.d.ts +1 -0
  9. package/lib/actions/index.js +1 -0
  10. package/lib/actions/markdown.js +1 -1
  11. package/lib/cli/bin.js +2 -0
  12. package/lib/cli/commands/html/builder.d.ts +16 -0
  13. package/lib/cli/commands/html/builder.js +5 -0
  14. package/lib/cli/commands/html/handler.d.ts +4 -0
  15. package/lib/cli/commands/html/handler.js +11 -0
  16. package/lib/cli/commands/html/index.d.ts +4 -0
  17. package/lib/cli/commands/html/index.js +4 -0
  18. package/lib/data/scriptTemplates.d.ts +79 -0
  19. package/lib/data/scriptTemplates.js +112 -0
  20. package/lib/methods/mulmo_beat.d.ts +1 -0
  21. package/lib/types/schema.d.ts +13 -0
  22. package/lib/types/schema.js +2 -0
  23. package/lib/types/type.d.ts +1 -1
  24. package/lib/utils/context.d.ts +3 -0
  25. package/lib/utils/context.js +1 -0
  26. package/lib/utils/image_plugins/html_tailwind.d.ts +1 -0
  27. package/lib/utils/image_plugins/html_tailwind.js +7 -0
  28. package/lib/utils/image_plugins/index.d.ts +1 -0
  29. package/lib/utils/image_plugins/markdown.d.ts +1 -0
  30. package/lib/utils/image_plugins/markdown.js +6 -0
  31. package/lib/utils/image_plugins/text_slide.d.ts +1 -0
  32. package/lib/utils/image_plugins/text_slide.js +6 -0
  33. package/lib/utils/image_plugins/vision.d.ts +1 -0
  34. package/lib/utils/image_plugins/vision.js +8 -0
  35. package/package.json +9 -8
  36. package/scripts/templates/html_sample.json +111 -0
  37. package/scripts/templates/html_sample.json~ +0 -0
package/README.md CHANGED
@@ -283,6 +283,8 @@ Commands:
283
283
  mulmo images <file> Generate image files
284
284
  mulmo movie <file> Generate movie file
285
285
  mulmo pdf <file> Generate PDF files
286
+ mulmo markdown <file> Generate markdown files
287
+ mulmo html <file> Generate html files
286
288
  mulmo tool <command> Generate Mulmo script and other tools
287
289
 
288
290
  Options:
@@ -396,6 +398,50 @@ Options:
396
398
  [choices: "letter", "a4"] [default: "letter"]
397
399
  ```
398
400
 
401
+ ```
402
+ mulmo markdown <file>
403
+
404
+ Generate markdown files
405
+
406
+ Positionals:
407
+ file Mulmo Script File [string] [required]
408
+
409
+ Options:
410
+ --version Show version number [boolean]
411
+ -v, --verbose verbose log [boolean] [required] [default: false]
412
+ -h, --help Show help [boolean]
413
+ -o, --outdir output dir [string]
414
+ -b, --basedir base dir [string]
415
+ -l, --lang target language
416
+ [string] [choices: "en", "ja", "fr", "es", "de", "zh-CN", "zh-TW", "ko", "it",
417
+ "pt", "ar", "hi"]
418
+ -f, --force Force regenerate [boolean] [default: false]
419
+ -p, --presentationStyle Presentation Style [string]
420
+ --image_width Image width (e.g., 400px, 50%, auto) [string]
421
+ ```
422
+
423
+ ```
424
+ mulmo html <file>
425
+
426
+ Generate html files
427
+
428
+ Positionals:
429
+ file Mulmo Script File [string] [required]
430
+
431
+ Options:
432
+ --version Show version number [boolean]
433
+ -v, --verbose verbose log [boolean] [required] [default: false]
434
+ -h, --help Show help [boolean]
435
+ -o, --outdir output dir [string]
436
+ -b, --basedir base dir [string]
437
+ -l, --lang target language
438
+ [string] [choices: "en", "ja", "fr", "es", "de", "zh-CN", "zh-TW", "ko", "it",
439
+ "pt", "ar", "hi"]
440
+ -f, --force Force regenerate [boolean] [default: false]
441
+ -p, --presentationStyle Presentation Style [string]
442
+ --image_width Image width (e.g., 400px, 50%, auto) [string]
443
+ ```
444
+
399
445
  ```
400
446
  mulmo tool <command>
401
447
 
@@ -0,0 +1,3 @@
1
+ import { MulmoStudioContext } from "../types/index.js";
2
+ export declare const htmlFilePath: (context: MulmoStudioContext) => string;
3
+ export declare const html: (context: MulmoStudioContext, imageWidth?: string) => Promise<void>;
@@ -0,0 +1,76 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { isNull } from "graphai";
4
+ import { localizedText } from "../utils/utils.js";
5
+ import { writingMessage } from "../utils/file.js";
6
+ import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
7
+ const generateHtmlContent = (context, imageWidth) => {
8
+ const { studio, multiLingual, lang = "en" } = context;
9
+ const title = studio.script.title || "MulmoCast Content";
10
+ const description = studio.script.description || "";
11
+ let html = "";
12
+ if (description) {
13
+ html += `${description}\n\n`;
14
+ }
15
+ studio.script.beats.forEach((beat, index) => {
16
+ const text = localizedText(beat, multiLingual?.[index], lang);
17
+ const studioBeat = studio.beats[index];
18
+ if (text.trim() || studioBeat?.html || studioBeat?.imageFile) {
19
+ if (studioBeat?.html) {
20
+ html += `${studioBeat.html}\n\n`;
21
+ }
22
+ else if (studioBeat?.imageFile && isNull(studioBeat.html)) {
23
+ const imagePath = path.relative(context.fileDirs.outDirPath, studioBeat.imageFile);
24
+ const altText = `Beat ${index + 1}`;
25
+ if (imageWidth) {
26
+ // Use HTML img tag for width control
27
+ html += `<img src="${imagePath}" alt="${altText}" width="${imageWidth}" />\n\n`;
28
+ }
29
+ else {
30
+ // Use standard html image syntax
31
+ html += `<img src="${imagePath}" alt="${altText}" />\n\n`;
32
+ }
33
+ }
34
+ if (text.trim()) {
35
+ html += `${text}\n\n`;
36
+ }
37
+ }
38
+ });
39
+ return `
40
+ <!doctype html>
41
+ <html lang="en">
42
+ <head>
43
+ <meta charset="UTF-8" />
44
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
45
+ <title>${title}</title>
46
+ <!-- Tailwind CSS CDN -->
47
+ <script src="https://cdn.tailwindcss.com"></script>
48
+ </head>
49
+ <body class="min-h-screen flex flex-col">
50
+ ${html}
51
+ </body>
52
+ </html>
53
+ `;
54
+ };
55
+ export const htmlFilePath = (context) => {
56
+ const { studio, fileDirs, lang = "en" } = context;
57
+ // Add language suffix only when target language is different from script's original language
58
+ const langSuffix = studio.script.lang !== lang ? `_${lang}` : "";
59
+ const filename = `${studio.filename}${langSuffix}.html`;
60
+ return path.join(fileDirs.outDirPath, filename);
61
+ };
62
+ const generateHtml = async (context, imageWidth) => {
63
+ const outputHtmlPath = htmlFilePath(context);
64
+ const htmlContent = generateHtmlContent(context, imageWidth);
65
+ fs.writeFileSync(outputHtmlPath, htmlContent, "utf8");
66
+ writingMessage(outputHtmlPath);
67
+ };
68
+ export const html = async (context, imageWidth) => {
69
+ try {
70
+ MulmoStudioContextMethods.setSessionState(context, "html", true);
71
+ await generateHtml(context, imageWidth);
72
+ }
73
+ finally {
74
+ MulmoStudioContextMethods.setSessionState(context, "html", false);
75
+ }
76
+ };
@@ -12,9 +12,9 @@ export declare const imagePreprocessAgent: (namedInputs: {
12
12
  htmlImageSystemPrompt: string;
13
13
  } | {
14
14
  imagePath: string | undefined;
15
+ movieFile: string | undefined;
15
16
  referenceImageForMovie: string | undefined;
16
17
  imageParams: MulmoImageParams;
17
- movieFile: string | undefined;
18
18
  soundEffectFile?: string;
19
19
  soundEffectPrompt?: string;
20
20
  soundEffectModel?: string;
@@ -36,6 +36,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
36
36
  movieParams: MulmoMovieParams;
37
37
  };
38
38
  markdown?: string;
39
+ html?: string;
39
40
  htmlPrompt?: undefined;
40
41
  htmlImageFile?: undefined;
41
42
  htmlPath?: undefined;
@@ -66,6 +67,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
66
67
  movieParams: MulmoMovieParams;
67
68
  };
68
69
  markdown?: string;
70
+ html?: string;
69
71
  htmlPrompt?: undefined;
70
72
  htmlImageFile?: undefined;
71
73
  htmlPath?: undefined;
@@ -99,6 +101,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
99
101
  movieParams: MulmoMovieParams;
100
102
  };
101
103
  markdown?: string;
104
+ html?: string;
102
105
  htmlPrompt?: undefined;
103
106
  htmlImageFile?: undefined;
104
107
  htmlPath?: undefined;
@@ -63,8 +63,17 @@ export const imagePreprocessAgent = async (namedInputs) => {
63
63
  if (plugin.markdown) {
64
64
  returnValue.markdown = plugin.markdown({ beat, context, imagePath, ...htmlStyle(context, beat) });
65
65
  }
66
+ if (plugin.html) {
67
+ returnValue.html = await plugin.html({ beat, context, imagePath, ...htmlStyle(context, beat) });
68
+ }
69
+ const isTypeMovie = beat.image.type === "movie";
66
70
  // undefined prompt indicates that image generation is not needed
67
- return { ...returnValue, imagePath: pluginPath, referenceImageForMovie: pluginPath };
71
+ return {
72
+ ...returnValue,
73
+ imagePath: isTypeMovie ? undefined : pluginPath,
74
+ movieFile: isTypeMovie ? pluginPath : undefined,
75
+ referenceImageForMovie: pluginPath,
76
+ };
68
77
  }
69
78
  if (beat.moviePrompt && !beat.imagePrompt) {
70
79
  return { ...returnValue, imagePath, imageFromMovie: true }; // no image prompt, only movie prompt
@@ -35,9 +35,9 @@ export declare const beat_graph_data: {
35
35
  htmlImageSystemPrompt: string;
36
36
  } | {
37
37
  imagePath: string | undefined;
38
+ movieFile: string | undefined;
38
39
  referenceImageForMovie: string | undefined;
39
40
  imageParams: MulmoImageParams;
40
- movieFile: string | undefined;
41
41
  soundEffectFile?: string;
42
42
  soundEffectPrompt?: string;
43
43
  soundEffectModel?: string;
@@ -59,6 +59,7 @@ export declare const beat_graph_data: {
59
59
  movieParams: import("../types/type.js").MulmoMovieParams;
60
60
  };
61
61
  markdown?: string;
62
+ html?: string;
62
63
  htmlPrompt?: undefined;
63
64
  htmlImageFile?: undefined;
64
65
  htmlPath?: undefined;
@@ -89,6 +90,7 @@ export declare const beat_graph_data: {
89
90
  movieParams: import("../types/type.js").MulmoMovieParams;
90
91
  };
91
92
  markdown?: string;
93
+ html?: string;
92
94
  htmlPrompt?: undefined;
93
95
  htmlImageFile?: undefined;
94
96
  htmlPath?: undefined;
@@ -122,6 +124,7 @@ export declare const beat_graph_data: {
122
124
  movieParams: import("../types/type.js").MulmoMovieParams;
123
125
  };
124
126
  markdown?: string;
127
+ html?: string;
125
128
  htmlPrompt?: undefined;
126
129
  htmlImageFile?: undefined;
127
130
  htmlPath?: undefined;
@@ -363,6 +366,7 @@ export declare const beat_graph_data: {
363
366
  hasMovieAudio: string;
364
367
  htmlImageFile: string;
365
368
  markdown: string;
369
+ html: string;
366
370
  };
367
371
  output: {
368
372
  imageFile: string;
@@ -372,6 +376,7 @@ export declare const beat_graph_data: {
372
376
  hasMovieAudio: string;
373
377
  htmlImageFile: string;
374
378
  markdown: string;
379
+ html: string;
375
380
  };
376
381
  isResult: boolean;
377
382
  };
@@ -286,6 +286,7 @@ export const beat_graph_data = {
286
286
  hasMovieAudio: ":audioChecker.hasMovieAudio",
287
287
  htmlImageFile: ":preprocessor.htmlImageFile",
288
288
  markdown: ":preprocessor.markdown",
289
+ html: ":preprocessor.html",
289
290
  },
290
291
  output: {
291
292
  imageFile: ".imageFile",
@@ -295,6 +296,7 @@ export const beat_graph_data = {
295
296
  hasMovieAudio: ".hasMovieAudio",
296
297
  htmlImageFile: ".htmlImageFile",
297
298
  markdown: ".markdown",
299
+ html: ".html",
298
300
  },
299
301
  isResult: true,
300
302
  },
@@ -7,3 +7,4 @@ export * from "./movie.js";
7
7
  export * from "./pdf.js";
8
8
  export * from "./translate.js";
9
9
  export * from "./markdown.js";
10
+ export * from "./html.js";
@@ -7,3 +7,4 @@ export * from "./movie.js";
7
7
  export * from "./pdf.js";
8
8
  export * from "./translate.js";
9
9
  export * from "./markdown.js";
10
+ export * from "./html.js";
@@ -18,7 +18,7 @@ const generateMarkdownContent = (context, imageWidth) => {
18
18
  if (studioBeat?.markdown) {
19
19
  markdown += `${studioBeat.markdown}\n\n`;
20
20
  }
21
- else if (studioBeat?.imageFile && studioBeat.markdown !== "") {
21
+ else if (studioBeat?.imageFile) {
22
22
  const imagePath = path.relative(context.fileDirs.outDirPath, studioBeat.imageFile);
23
23
  if (imageWidth) {
24
24
  // Use HTML img tag for width control
package/lib/cli/bin.js CHANGED
@@ -11,6 +11,7 @@ import * as imagesCmd from "./commands/image/index.js";
11
11
  import * as movieCmd from "./commands/movie/index.js";
12
12
  import * as pdfCmd from "./commands/pdf/index.js";
13
13
  import * as markdownCmd from "./commands/markdown/index.js";
14
+ import * as htmlCmd from "./commands/html/index.js";
14
15
  import * as toolCmd from "./commands/tool/index.js";
15
16
  import { GraphAILogger } from "graphai";
16
17
  const __filename = fileURLToPath(import.meta.url);
@@ -34,6 +35,7 @@ export const main = async () => {
34
35
  .command(movieCmd)
35
36
  .command(pdfCmd)
36
37
  .command(markdownCmd)
38
+ .command(htmlCmd)
37
39
  .command(toolCmd)
38
40
  .demandCommand()
39
41
  .strict()
@@ -0,0 +1,16 @@
1
+ import type { Argv } from "yargs";
2
+ export declare const builder: (yargs: Argv) => Argv<{
3
+ o: string | undefined;
4
+ } & {
5
+ b: string | undefined;
6
+ } & {
7
+ l: string | undefined;
8
+ } & {
9
+ f: boolean;
10
+ } & {
11
+ p: string | undefined;
12
+ } & {
13
+ file: string | undefined;
14
+ } & {
15
+ image_width: string | undefined;
16
+ }>;
@@ -0,0 +1,5 @@
1
+ import { commonOptions } from "../../common.js";
2
+ export const builder = (yargs) => commonOptions(yargs).option("image_width", {
3
+ describe: "Image width (e.g., 400px, 50%, auto)",
4
+ type: "string",
5
+ });
@@ -0,0 +1,4 @@
1
+ import { CliArgs } from "../../../types/cli_types.js";
2
+ export declare const handler: (argv: CliArgs<{
3
+ image_width?: string;
4
+ }>) => Promise<void>;
@@ -0,0 +1,11 @@
1
+ import { images, html } from "../../../actions/index.js";
2
+ import { initializeContext, runTranslateIfNeeded } from "../../helpers.js";
3
+ export const handler = async (argv) => {
4
+ const context = await initializeContext(argv);
5
+ if (!context) {
6
+ process.exit(1);
7
+ }
8
+ await runTranslateIfNeeded(context);
9
+ await images(context);
10
+ await html(context, argv.image_width);
11
+ };
@@ -0,0 +1,4 @@
1
+ export declare const command = "html <file>";
2
+ export declare const desc = "Generate html files";
3
+ export { builder } from "./builder.js";
4
+ export { handler } from "./handler.js";
@@ -0,0 +1,4 @@
1
+ export const command = "html <file>";
2
+ export const desc = "Generate html files";
3
+ export { builder } from "./builder.js";
4
+ export { handler } from "./handler.js";
@@ -381,6 +381,85 @@ export declare const scriptTemplates: ({
381
381
  description?: undefined;
382
382
  canvasSize?: undefined;
383
383
  captionParams?: undefined;
384
+ } | {
385
+ $mulmocast: {
386
+ credit: string;
387
+ version: string;
388
+ };
389
+ beats: ({
390
+ image: {
391
+ html: string[];
392
+ type: string;
393
+ markdown?: undefined;
394
+ slide?: undefined;
395
+ data?: undefined;
396
+ style?: undefined;
397
+ };
398
+ text: string;
399
+ } | {
400
+ image: {
401
+ markdown: string[];
402
+ type: string;
403
+ html?: undefined;
404
+ slide?: undefined;
405
+ data?: undefined;
406
+ style?: undefined;
407
+ };
408
+ text: string;
409
+ } | {
410
+ image: {
411
+ slide: {
412
+ subtitle: string;
413
+ title: string;
414
+ };
415
+ type: string;
416
+ html?: undefined;
417
+ markdown?: undefined;
418
+ data?: undefined;
419
+ style?: undefined;
420
+ };
421
+ text: string;
422
+ } | {
423
+ image: {
424
+ data: {
425
+ heading: string;
426
+ subheading: string;
427
+ items?: undefined;
428
+ title?: undefined;
429
+ };
430
+ style: string;
431
+ type: string;
432
+ html?: undefined;
433
+ markdown?: undefined;
434
+ slide?: undefined;
435
+ };
436
+ text: string;
437
+ } | {
438
+ image: {
439
+ data: {
440
+ items: string[];
441
+ title: string;
442
+ heading?: undefined;
443
+ subheading?: undefined;
444
+ };
445
+ style: string;
446
+ type: string;
447
+ html?: undefined;
448
+ markdown?: undefined;
449
+ slide?: undefined;
450
+ };
451
+ text: string;
452
+ })[];
453
+ filename: string;
454
+ lang: string;
455
+ title: string;
456
+ references?: undefined;
457
+ htmlImageParams?: undefined;
458
+ imageParams?: undefined;
459
+ movieParams?: undefined;
460
+ description?: undefined;
461
+ canvasSize?: undefined;
462
+ captionParams?: undefined;
384
463
  } | {
385
464
  $mulmocast: {
386
465
  credit: string;
@@ -497,6 +497,118 @@ export const scriptTemplates = [
497
497
  ],
498
498
  title: "[TITLE: Brief, engaging title for the topic]",
499
499
  },
500
+ {
501
+ $mulmocast: {
502
+ credit: "closing",
503
+ version: "1.1",
504
+ },
505
+ beats: [
506
+ {
507
+ image: {
508
+ html: [
509
+ '<main class="flex-grow">',
510
+ " <!-- Hero Section -->",
511
+ ' <section class="bg-blue-600 text-white py-20">',
512
+ ' <div class="container mx-auto px-6 text-center">',
513
+ ' <h1 class="text-4xl md:text-5xl font-bold mb-4">Welcome to Mulmocast</h1>',
514
+ ' <p class="text-lg md:text-xl mb-8">A modern web experience powered by Tailwind CSS</p>',
515
+ ' <a href="#features" class="bg-white text-blue-600 px-6 py-3 rounded-lg font-semibold shadow hover:bg-gray-100 transition">',
516
+ " Learn More",
517
+ " </a>",
518
+ " </div>",
519
+ " </section>",
520
+ "",
521
+ " <!-- Features Section -->",
522
+ ' <section id="features" class="py-16 bg-gray-100">',
523
+ ' <div class="container mx-auto px-6">',
524
+ ' <div class="grid grid-cols-1 md:grid-cols-3 gap-8 text-center">',
525
+ " <div>",
526
+ ' <div class="text-blue-600 text-4xl mb-2">⚡</div>',
527
+ ' <h3 class="text-xl font-semibold mb-2">Fast</h3>',
528
+ ' <p class="text-gray-600">Built with performance in mind using modern tools.</p>',
529
+ " </div>",
530
+ " <div>",
531
+ ' <div class="text-blue-600 text-4xl mb-2">🎨</div>',
532
+ ' <h3 class="text-xl font-semibold mb-2">Beautiful</h3>',
533
+ ' <p class="text-gray-600">Styled with Tailwind CSS for clean, responsive design.</p>',
534
+ " </div>",
535
+ " <div>",
536
+ ' <div class="text-blue-600 text-4xl mb-2">🚀</div>',
537
+ ' <h3 class="text-xl font-semibold mb-2">Launch Ready</h3>',
538
+ ' <p class="text-gray-600">Easy to deploy and extend for your next big idea.</p>',
539
+ " </div>",
540
+ " </div>",
541
+ " </div>",
542
+ " </section>",
543
+ "</main>",
544
+ "",
545
+ "<!-- Footer -->",
546
+ '<footer class="bg-white text-gray-500 text-center py-6 border-t">',
547
+ " 2025 Mulmocast.",
548
+ "</footer>",
549
+ ],
550
+ type: "html_tailwind",
551
+ },
552
+ text: "This is a tailwind html format.",
553
+ },
554
+ {
555
+ image: {
556
+ markdown: [
557
+ "# Markdown Table Example",
558
+ "| Item | In Stock | Price |",
559
+ "| :---------------- | :------: | ----: |",
560
+ "| Python Hat | True | 23.99 |",
561
+ "| SQL Hat | True | 23.99 |",
562
+ "| Codecademy Tee | False | 19.99 |",
563
+ "| Codecademy Hoodie | False | 42.99 |",
564
+ ],
565
+ type: "markdown",
566
+ },
567
+ text: "This is a table of items in the store.",
568
+ },
569
+ {
570
+ image: {
571
+ slide: {
572
+ subtitle: "Tom Johnson",
573
+ title: "This is the title of the presentation",
574
+ },
575
+ type: "textSlide",
576
+ },
577
+ text: "This is a sample slide, which just displays the title and the presenter's name of this presentation.",
578
+ },
579
+ {
580
+ image: {
581
+ data: {
582
+ heading: "How AI Is Reshaping Referencing",
583
+ subheading: "From sources to systems: reliability, traceability, and credit in the age of models",
584
+ },
585
+ style: "sectionDividerSlide",
586
+ type: "vision",
587
+ },
588
+ text: "sectionDividerSlide",
589
+ },
590
+ {
591
+ image: {
592
+ data: {
593
+ items: [
594
+ "Executive summary",
595
+ "Reference reliability and hallucinations",
596
+ "Attribution and credit in AI workflows",
597
+ "Standards & compliance (academia, journalism, law)",
598
+ "Roadmap & recommendations",
599
+ ],
600
+ title: "Agenda",
601
+ },
602
+ style: "agendaSlide",
603
+ type: "vision",
604
+ },
605
+ text: "agendaSlide",
606
+ },
607
+ ],
608
+ filename: "html_sample",
609
+ lang: "en",
610
+ title: "[TITLE: Brief, engaging title for the topic]",
611
+ },
500
612
  {
501
613
  $mulmocast: {
502
614
  credit: "closing",
@@ -6,6 +6,7 @@ export declare const MulmoBeatMethods: {
6
6
  process: (params: import("../types/type.js").ImageProcessorParams) => Promise<string | undefined> | void;
7
7
  path: (params: import("../types/type.js").ImageProcessorParams) => string | undefined;
8
8
  markdown?: (params: import("../types/type.js").ImageProcessorParams) => string | undefined;
9
+ html?: (params: import("../types/type.js").ImageProcessorParams) => Promise<string | undefined>;
9
10
  };
10
11
  getImageReferenceForImageGenerator(beat: MulmoBeat, imageRefs: Record<string, string>): string[];
11
12
  };
@@ -5778,9 +5778,11 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
5778
5778
  captionFile: z.ZodOptional<z.ZodString>;
5779
5779
  htmlImageFile: z.ZodOptional<z.ZodString>;
5780
5780
  markdown: z.ZodOptional<z.ZodString>;
5781
+ html: z.ZodOptional<z.ZodString>;
5781
5782
  }, "strict", z.ZodTypeAny, {
5782
5783
  duration?: number | undefined;
5783
5784
  markdown?: string | undefined;
5785
+ html?: string | undefined;
5784
5786
  id?: string | undefined;
5785
5787
  startAt?: number | undefined;
5786
5788
  hash?: string | undefined;
@@ -5798,6 +5800,7 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
5798
5800
  }, {
5799
5801
  duration?: number | undefined;
5800
5802
  markdown?: string | undefined;
5803
+ html?: string | undefined;
5801
5804
  id?: string | undefined;
5802
5805
  startAt?: number | undefined;
5803
5806
  hash?: string | undefined;
@@ -6031,12 +6034,14 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
6031
6034
  caption: z.ZodBoolean;
6032
6035
  pdf: z.ZodBoolean;
6033
6036
  markdown: z.ZodBoolean;
6037
+ html: z.ZodBoolean;
6034
6038
  }, "strip", z.ZodTypeAny, {
6035
6039
  image: boolean;
6036
6040
  video: boolean;
6037
6041
  audio: boolean;
6038
6042
  markdown: boolean;
6039
6043
  pdf: boolean;
6044
+ html: boolean;
6040
6045
  multiLingual: boolean;
6041
6046
  caption: boolean;
6042
6047
  }, {
@@ -6045,6 +6050,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
6045
6050
  audio: boolean;
6046
6051
  markdown: boolean;
6047
6052
  pdf: boolean;
6053
+ html: boolean;
6048
6054
  multiLingual: boolean;
6049
6055
  caption: boolean;
6050
6056
  }>;
@@ -6086,6 +6092,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
6086
6092
  audio: boolean;
6087
6093
  markdown: boolean;
6088
6094
  pdf: boolean;
6095
+ html: boolean;
6089
6096
  multiLingual: boolean;
6090
6097
  caption: boolean;
6091
6098
  };
@@ -6107,6 +6114,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
6107
6114
  audio: boolean;
6108
6115
  markdown: boolean;
6109
6116
  pdf: boolean;
6117
+ html: boolean;
6110
6118
  multiLingual: boolean;
6111
6119
  caption: boolean;
6112
6120
  };
@@ -8488,9 +8496,11 @@ export declare const mulmoStudioSchema: z.ZodObject<{
8488
8496
  captionFile: z.ZodOptional<z.ZodString>;
8489
8497
  htmlImageFile: z.ZodOptional<z.ZodString>;
8490
8498
  markdown: z.ZodOptional<z.ZodString>;
8499
+ html: z.ZodOptional<z.ZodString>;
8491
8500
  }, "strict", z.ZodTypeAny, {
8492
8501
  duration?: number | undefined;
8493
8502
  markdown?: string | undefined;
8503
+ html?: string | undefined;
8494
8504
  id?: string | undefined;
8495
8505
  startAt?: number | undefined;
8496
8506
  hash?: string | undefined;
@@ -8508,6 +8518,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
8508
8518
  }, {
8509
8519
  duration?: number | undefined;
8510
8520
  markdown?: string | undefined;
8521
+ html?: string | undefined;
8511
8522
  id?: string | undefined;
8512
8523
  startAt?: number | undefined;
8513
8524
  hash?: string | undefined;
@@ -8527,6 +8538,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
8527
8538
  beats: {
8528
8539
  duration?: number | undefined;
8529
8540
  markdown?: string | undefined;
8541
+ html?: string | undefined;
8530
8542
  id?: string | undefined;
8531
8543
  startAt?: number | undefined;
8532
8544
  hash?: string | undefined;
@@ -8875,6 +8887,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
8875
8887
  beats: {
8876
8888
  duration?: number | undefined;
8877
8889
  markdown?: string | undefined;
8890
+ html?: string | undefined;
8878
8891
  id?: string | undefined;
8879
8892
  startAt?: number | undefined;
8880
8893
  hash?: string | undefined;
@@ -405,6 +405,7 @@ export const mulmoStudioBeatSchema = z
405
405
  captionFile: z.string().optional(), // path to the caption image
406
406
  htmlImageFile: z.string().optional(), // path to the html image
407
407
  markdown: z.string().optional(), // markdown string (alternative to image)
408
+ html: z.string().optional(), // html string (alternative to image)
408
409
  })
409
410
  .strict();
410
411
  export const mulmoStudioMultiLingualDataSchema = z.object({
@@ -426,6 +427,7 @@ export const mulmoSessionStateSchema = z.object({
426
427
  caption: z.boolean(),
427
428
  pdf: z.boolean(),
428
429
  markdown: z.boolean(),
430
+ html: z.boolean(),
429
431
  }),
430
432
  inBeatSession: z.object({
431
433
  audio: z.record(z.string(), z.boolean()),
@@ -85,7 +85,7 @@ export type Text2HtmlAgentInfo = {
85
85
  };
86
86
  export type BeatMediaType = "movie" | "image";
87
87
  export type StoryToScriptGenerateMode = (typeof storyToScriptGenerateMode)[keyof typeof storyToScriptGenerateMode];
88
- export type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf" | "markdown";
88
+ export type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf" | "markdown" | "html";
89
89
  export type BeatSessionType = "audio" | "image" | "multiLingual" | "caption" | "movie" | "html" | "imageReference" | "soundEffect" | "lipSync";
90
90
  export type SessionProgressEvent = {
91
91
  kind: "session";
@@ -3,6 +3,7 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
3
3
  beats: {
4
4
  duration?: number | undefined;
5
5
  markdown?: string | undefined;
6
+ html?: string | undefined;
6
7
  id?: string | undefined;
7
8
  startAt?: number | undefined;
8
9
  hash?: string | undefined;
@@ -356,6 +357,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
356
357
  beats: {
357
358
  duration?: number | undefined;
358
359
  markdown?: string | undefined;
360
+ html?: string | undefined;
359
361
  id?: string | undefined;
360
362
  startAt?: number | undefined;
361
363
  hash?: string | undefined;
@@ -834,6 +836,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
834
836
  caption: boolean;
835
837
  pdf: boolean;
836
838
  markdown: boolean;
839
+ html: boolean;
837
840
  };
838
841
  inBeatSession: {
839
842
  audio: {};
@@ -35,6 +35,7 @@ const initSessionState = () => {
35
35
  caption: false,
36
36
  pdf: false,
37
37
  markdown: false,
38
+ html: false,
38
39
  },
39
40
  inBeatSession: {
40
41
  audio: {},
@@ -2,3 +2,4 @@ import { ImageProcessorParams } from "../../types/index.js";
2
2
  export declare const imageType = "html_tailwind";
3
3
  export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
4
4
  export declare const path: (params: ImageProcessorParams) => string;
5
+ export declare const html: (params: ImageProcessorParams) => Promise<string | undefined>;
@@ -16,5 +16,12 @@ const processHtmlTailwind = async (params) => {
16
16
  await renderHTMLToImage(htmlData, imagePath, canvasSize.width, canvasSize.height);
17
17
  return imagePath;
18
18
  };
19
+ const dumpHtml = async (params) => {
20
+ const { beat } = params;
21
+ if (!beat.image || beat.image.type !== imageType)
22
+ return;
23
+ return Array.isArray(beat.image.html) ? beat.image.html.join("\n") : beat.image.html;
24
+ };
19
25
  export const process = processHtmlTailwind;
20
26
  export const path = parrotingImagePath;
27
+ export const html = dumpHtml;
@@ -4,4 +4,5 @@ export declare const findImagePlugin: (imageType?: string) => {
4
4
  process: (params: ImageProcessorParams) => Promise<string | undefined> | void;
5
5
  path: (params: ImageProcessorParams) => string | undefined;
6
6
  markdown?: (params: ImageProcessorParams) => string | undefined;
7
+ html?: (params: ImageProcessorParams) => Promise<string | undefined>;
7
8
  } | undefined;
@@ -3,3 +3,4 @@ export declare const imageType = "markdown";
3
3
  export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
4
4
  export declare const path: (params: ImageProcessorParams) => string;
5
5
  export declare const markdown: (params: ImageProcessorParams) => string | undefined;
6
+ export declare const html: (params: ImageProcessorParams) => Promise<string>;
@@ -1,5 +1,6 @@
1
1
  import { renderMarkdownToImage } from "../markdown.js";
2
2
  import { parrotingImagePath } from "./utils.js";
3
+ import { marked } from "marked";
3
4
  export const imageType = "markdown";
4
5
  const processMarkdown = async (params) => {
5
6
  const { beat, imagePath, textSlideStyle, canvasSize } = params;
@@ -15,6 +16,11 @@ const dumpMarkdown = (params) => {
15
16
  return;
16
17
  return Array.isArray(beat.image.markdown) ? beat.image.markdown.join("\n") : beat.image.markdown;
17
18
  };
19
+ const dumpHtml = async (params) => {
20
+ const markdown = dumpMarkdown(params);
21
+ return await marked.parse(markdown ?? "");
22
+ };
18
23
  export const process = processMarkdown;
19
24
  export const path = parrotingImagePath;
20
25
  export const markdown = dumpMarkdown;
26
+ export const html = dumpHtml;
@@ -3,3 +3,4 @@ export declare const imageType = "textSlide";
3
3
  export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
4
4
  export declare const path: (params: ImageProcessorParams) => string;
5
5
  export declare const markdown: (params: ImageProcessorParams) => string | undefined;
6
+ export declare const html: (params: ImageProcessorParams) => Promise<string>;
@@ -1,5 +1,6 @@
1
1
  import { renderMarkdownToImage } from "../markdown.js";
2
2
  import { parrotingImagePath } from "./utils.js";
3
+ import { marked } from "marked";
3
4
  export const imageType = "textSlide";
4
5
  const processTextSlide = async (params) => {
5
6
  const { beat, imagePath, textSlideStyle, canvasSize } = params;
@@ -27,6 +28,11 @@ const dumpMarkdown = (params) => {
27
28
  const bulletsString = (slide.bullets ?? []).map((text) => `- ${text}`).join("\n");
28
29
  return `${titleString}${subtitleString}${bulletsString}`;
29
30
  };
31
+ const dumpHtml = async (params) => {
32
+ const markdown = dumpMarkdown(params);
33
+ return await marked.parse(markdown ?? "");
34
+ };
30
35
  export const process = processTextSlide;
31
36
  export const path = parrotingImagePath;
32
37
  export const markdown = dumpMarkdown;
38
+ export const html = dumpHtml;
@@ -2,3 +2,4 @@ import { ImageProcessorParams } from "../../types/index.js";
2
2
  export declare const imageType = "vision";
3
3
  export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
4
4
  export declare const path: (params: ImageProcessorParams) => string;
5
+ export declare const html: (params: ImageProcessorParams) => Promise<string | undefined>;
@@ -15,5 +15,13 @@ const processVision = async (params) => {
15
15
  });
16
16
  return imagePath;
17
17
  };
18
+ const dumpHtml = async (params) => {
19
+ const { beat } = params;
20
+ if (!beat.image || beat.image.type !== imageType)
21
+ return;
22
+ const handler = new htmlPlugin({});
23
+ return handler.getHtml(templateNameTofunctionName(beat.image.style), beat.image.data);
24
+ };
18
25
  export const process = processVision;
19
26
  export const path = parrotingImagePath;
27
+ export const html = dumpHtml;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "1.2.29",
3
+ "version": "1.2.31",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",
@@ -50,6 +50,7 @@
50
50
  "prompt": "npx tsx ./src/cli/bin.ts tool prompt",
51
51
  "schema": "npx tsx ./src/cli/bin.ts tool schema",
52
52
  "markdown": "npx tsx ./src/cli/bin.ts markdown",
53
+ "html": "npx tsx ./src/cli/bin.ts html",
53
54
  "story_to_script": "npx tsx ./src/cli/bin.ts tool story_to_script",
54
55
  "whisper": "npx tsx ./src/cli/bin.ts tool whisper",
55
56
  "latest": "yarn upgrade-interactive --latest",
@@ -68,7 +69,7 @@
68
69
  "homepage": "https://github.com/receptron/mulmocast-cli#readme",
69
70
  "dependencies": {
70
71
  "@google-cloud/text-to-speech": "^6.3.0",
71
- "@google/genai": "^1.17.0",
72
+ "@google/genai": "^1.19.0",
72
73
  "@graphai/anthropic_agent": "^2.0.11",
73
74
  "@graphai/browserless_agent": "^2.0.1",
74
75
  "@graphai/gemini_agent": "^2.0.1",
@@ -78,18 +79,18 @@
78
79
  "@graphai/stream_agent_filter": "^2.0.2",
79
80
  "@graphai/vanilla": "^2.0.12",
80
81
  "@graphai/vanilla_node_agents": "^2.0.4",
81
- "@inquirer/input": "^4.2.2",
82
- "@inquirer/select": "^4.3.2",
83
- "@modelcontextprotocol/sdk": "^1.17.5",
82
+ "@inquirer/input": "^4.2.4",
83
+ "@inquirer/select": "^4.3.4",
84
+ "@modelcontextprotocol/sdk": "^1.18.0",
84
85
  "@mozilla/readability": "^0.6.0",
85
86
  "@tavily/core": "^0.5.11",
86
87
  "clipboardy": "^4.0.0",
87
88
  "dotenv": "^17.2.2",
88
89
  "fluent-ffmpeg": "^2.1.3",
89
90
  "graphai": "^2.0.14",
90
- "jsdom": "^26.1.0",
91
- "marked": "^16.2.1",
92
- "mulmocast-vision": "^0.1.4",
91
+ "jsdom": "^27.0.0",
92
+ "marked": "^16.3.0",
93
+ "mulmocast-vision": "^1.0.3",
93
94
  "ora": "^8.2.0",
94
95
  "puppeteer": "^24.20.0",
95
96
  "replicate": "^1.1.0",
@@ -0,0 +1,111 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.1",
4
+ "credit": "closing"
5
+ },
6
+ "title": "[TITLE: Brief, engaging title for the topic]",
7
+ "lang": "en",
8
+ "beats": [
9
+ {
10
+ "text": "This is a tailwind html format.",
11
+ "image": {
12
+ "type": "html_tailwind",
13
+ "html": [
14
+ "<main class=\"flex-grow\">",
15
+ " <!-- Hero Section -->",
16
+ " <section class=\"bg-blue-600 text-white py-20\">",
17
+ " <div class=\"container mx-auto px-6 text-center\">",
18
+ " <h1 class=\"text-4xl md:text-5xl font-bold mb-4\">Welcome to Mulmocast</h1>",
19
+ " <p class=\"text-lg md:text-xl mb-8\">A modern web experience powered by Tailwind CSS</p>",
20
+ " <a href=\"#features\" class=\"bg-white text-blue-600 px-6 py-3 rounded-lg font-semibold shadow hover:bg-gray-100 transition\">",
21
+ " Learn More",
22
+ " </a>",
23
+ " </div>",
24
+ " </section>",
25
+ "",
26
+ " <!-- Features Section -->",
27
+ " <section id=\"features\" class=\"py-16 bg-gray-100\">",
28
+ " <div class=\"container mx-auto px-6\">",
29
+ " <div class=\"grid grid-cols-1 md:grid-cols-3 gap-8 text-center\">",
30
+ " <div>",
31
+ " <div class=\"text-blue-600 text-4xl mb-2\">⚡</div>",
32
+ " <h3 class=\"text-xl font-semibold mb-2\">Fast</h3>",
33
+ " <p class=\"text-gray-600\">Built with performance in mind using modern tools.</p>",
34
+ " </div>",
35
+ " <div>",
36
+ " <div class=\"text-blue-600 text-4xl mb-2\">🎨</div>",
37
+ " <h3 class=\"text-xl font-semibold mb-2\">Beautiful</h3>",
38
+ " <p class=\"text-gray-600\">Styled with Tailwind CSS for clean, responsive design.</p>",
39
+ " </div>",
40
+ " <div>",
41
+ " <div class=\"text-blue-600 text-4xl mb-2\">🚀</div>",
42
+ " <h3 class=\"text-xl font-semibold mb-2\">Launch Ready</h3>",
43
+ " <p class=\"text-gray-600\">Easy to deploy and extend for your next big idea.</p>",
44
+ " </div>",
45
+ " </div>",
46
+ " </div>",
47
+ " </section>",
48
+ "</main>",
49
+ "",
50
+ "<!-- Footer -->",
51
+ "<footer class=\"bg-white text-gray-500 text-center py-6 border-t\">",
52
+ " 2025 Mulmocast.",
53
+ "</footer>"
54
+ ]
55
+ }
56
+ },
57
+ {
58
+ "text": "This is a table of items in the store.",
59
+ "image": {
60
+ "type": "markdown",
61
+ "markdown": [
62
+ "# Markdown Table Example",
63
+ "| Item | In Stock | Price |",
64
+ "| :---------------- | :------: | ----: |",
65
+ "| Python Hat | True | 23.99 |",
66
+ "| SQL Hat | True | 23.99 |",
67
+ "| Codecademy Tee | False | 19.99 |",
68
+ "| Codecademy Hoodie | False | 42.99 |"
69
+ ]
70
+ }
71
+ },
72
+ {
73
+ "text": "This is a sample slide, which just displays the title and the presenter's name of this presentation.",
74
+ "image": {
75
+ "type": "textSlide",
76
+ "slide": {
77
+ "title": "This is the title of the presentation",
78
+ "subtitle": "Tom Johnson"
79
+ }
80
+ }
81
+ },
82
+ {
83
+ "text": "sectionDividerSlide",
84
+ "image": {
85
+ "type": "vision",
86
+ "style": "sectionDividerSlide",
87
+ "data": {
88
+ "heading": "How AI Is Reshaping Referencing",
89
+ "subheading": "From sources to systems: reliability, traceability, and credit in the age of models"
90
+ }
91
+ }
92
+ },
93
+ {
94
+ "text": "agendaSlide",
95
+ "image": {
96
+ "type": "vision",
97
+ "style": "agendaSlide",
98
+ "data": {
99
+ "title": "Agenda",
100
+ "items": [
101
+ "Executive summary",
102
+ "Reference reliability and hallucinations",
103
+ "Attribution and credit in AI workflows",
104
+ "Standards & compliance (academia, journalism, law)",
105
+ "Roadmap & recommendations"
106
+ ]
107
+ }
108
+ }
109
+ }
110
+ ]
111
+ }
File without changes