mulmocast 2.12.1 → 2.13.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 (38) hide show
  1. package/assets/schemas/mulmo_script.json +231 -0
  2. package/lib/actions/avatar.d.ts +37 -0
  3. package/lib/actions/avatar.js +176 -0
  4. package/lib/actions/image_agents.js +9 -9
  5. package/lib/actions/index.d.ts +1 -0
  6. package/lib/actions/index.js +1 -0
  7. package/lib/actions/movie.d.ts +1 -0
  8. package/lib/actions/movie.js +40 -2
  9. package/lib/agents/combine_audio_files_agent.js +2 -2
  10. package/lib/cli/commands/movie/handler.js +2 -2
  11. package/lib/mcp/server.js +3 -3
  12. package/lib/methods/mulmo_beat.d.ts +1 -0
  13. package/lib/methods/mulmo_beat.js +3 -0
  14. package/lib/methods/mulmo_beat_node.d.ts +1 -0
  15. package/lib/methods/mulmo_presentation_style.d.ts +5 -1
  16. package/lib/methods/mulmo_presentation_style.js +8 -0
  17. package/lib/types/schema.d.ts +405 -0
  18. package/lib/types/schema.js +61 -0
  19. package/lib/types/type.d.ts +6 -1
  20. package/lib/utils/context.d.ts +158 -0
  21. package/lib/utils/image_plugins/index.js +2 -0
  22. package/lib/utils/image_plugins/remotion.d.ts +16 -0
  23. package/lib/utils/image_plugins/remotion.js +164 -0
  24. package/lib/utils/remotion/claude_prompt.d.ts +33 -0
  25. package/lib/utils/remotion/claude_prompt.js +111 -0
  26. package/lib/utils/remotion/claude_runner.d.ts +4 -0
  27. package/lib/utils/remotion/claude_runner.js +47 -0
  28. package/lib/utils/remotion/commit_files.d.ts +11 -0
  29. package/lib/utils/remotion/commit_files.js +37 -0
  30. package/lib/utils/remotion/packages.d.ts +5 -0
  31. package/lib/utils/remotion/packages.js +20 -0
  32. package/lib/utils/remotion/render.d.ts +19 -0
  33. package/lib/utils/remotion/render.js +63 -0
  34. package/lib/utils/remotion/system_prompt.d.ts +3 -0
  35. package/lib/utils/remotion/system_prompt.js +62 -0
  36. package/package.json +108 -20
  37. package/scripts/test/test_avatar.json +46 -0
  38. package/scripts/test/test_remotion.json +38 -0
package/lib/mcp/server.js CHANGED
@@ -7,7 +7,7 @@ import fs from "fs";
7
7
  import path from "path";
8
8
  import { fileURLToPath } from "url";
9
9
  import { GraphAILogger } from "graphai";
10
- import { audio, images, movie, captions, pdf } from "../actions/index.js";
10
+ import { audio, images, movie, captions, avatar, pdf } from "../actions/index.js";
11
11
  import { initializeContext, runTranslateIfNeeded } from "../cli/helpers.js";
12
12
  import { outDirName } from "../types/const.js";
13
13
  import { resolveDirPath, mkdir, generateTimestampedFileName } from "../utils/file.js";
@@ -111,8 +111,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
111
111
  // Execute the requested command
112
112
  switch (cmd) {
113
113
  case "movie":
114
- // Generate movie (audio + images + captions + movie)
115
- await audio(context).then(images).then(captions).then(movie);
114
+ // Generate movie (audio + images + captions + avatar + movie)
115
+ await audio(context).then(images).then(captions).then(avatar).then(movie);
116
116
  return {
117
117
  content: [
118
118
  {
@@ -7,6 +7,7 @@ export declare const MulmoBeatMethods: {
7
7
  isAnimationEnabled: (animation: unknown) => animation is true | AnimationConfig;
8
8
  isAnimationObject: (animation: unknown) => animation is AnimationConfig;
9
9
  isAnimatedHtmlTailwind: (beat: MulmoBeat) => boolean;
10
+ isPluginVideo: (beat: MulmoBeat) => boolean;
10
11
  isMovieMode: (animation: unknown) => boolean;
11
12
  isVoiceOver: (beat?: MulmoBeat) => boolean;
12
13
  getPrevRenderedBeatIndex(beats: MulmoBeat[], index: number): number;
@@ -18,12 +18,15 @@ const isAnimatedHtmlTailwind = (beat) => {
18
18
  const animation = beat.image.animation;
19
19
  return isAnimationEnabled(animation);
20
20
  };
21
+ // Beats whose image plugin writes the beat's .mp4 itself, at the length the audio gives it.
22
+ const isPluginVideo = (beat) => isAnimatedHtmlTailwind(beat) || beat.image?.type === ImageMediaType.Remotion;
21
23
  // voice_over beats share the preceding beat's shot, and contribute no video segment of their own.
22
24
  const isVoiceOver = (beat) => beat?.image?.type === ImageMediaType.VoiceOver;
23
25
  export const MulmoBeatMethods = {
24
26
  isAnimationEnabled,
25
27
  isAnimationObject,
26
28
  isAnimatedHtmlTailwind,
29
+ isPluginVideo,
27
30
  isMovieMode,
28
31
  isVoiceOver,
29
32
  // Index of the closest preceding beat which is actually rendered as a video segment (-1 if none).
@@ -16,6 +16,7 @@ export declare const MulmoBeatMethods: {
16
16
  movie?: boolean;
17
17
  };
18
18
  isAnimatedHtmlTailwind: (beat: MulmoBeat) => boolean;
19
+ isPluginVideo: (beat: MulmoBeat) => boolean;
19
20
  isMovieMode: (animation: unknown) => boolean;
20
21
  isVoiceOver: (beat?: MulmoBeat) => boolean;
21
22
  getPrevRenderedBeatIndex(beats: MulmoBeat[], index: number): number;
@@ -4,7 +4,7 @@
4
4
  * Works in both Node.js and modern browsers.
5
5
  */
6
6
  import type { SlideTheme } from "@mulmocast/deck";
7
- import { MulmoCanvasDimension, MulmoBeat, Text2SpeechProvider, Text2ImageAgentInfo, Text2HtmlAgentInfo, BeatMediaType, MulmoPresentationStyle, SpeakerData, Text2ImageProvider, MulmoStudioContext, MulmoTransition, MulmoFillOption } from "../types/index.js";
7
+ import { MulmoCanvasDimension, MulmoBeat, Text2SpeechProvider, Text2ImageAgentInfo, Text2HtmlAgentInfo, BeatMediaType, MulmoPresentationStyle, SpeakerData, MulmoSpeakerAvatar, Text2ImageProvider, MulmoStudioContext, MulmoTransition, MulmoFillOption } from "../types/index.js";
8
8
  export declare const MulmoPresentationStyleMethods: {
9
9
  getCanvasSize(presentationStyle: MulmoPresentationStyle): MulmoCanvasDimension;
10
10
  getAllSpeechProviders(presentationStyle: MulmoPresentationStyle): Set<Text2SpeechProvider>;
@@ -28,6 +28,10 @@ export declare const MulmoPresentationStyleMethods: {
28
28
  getResolvedSlideTheme(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): SlideTheme;
29
29
  getDefaultSpeaker(presentationStyle: MulmoPresentationStyle): string;
30
30
  getSpeakerData(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat, lang: string | undefined): SpeakerData;
31
+ getSpeakerAvatar(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat, lang: string | undefined): {
32
+ speakerId: string;
33
+ avatar: MulmoSpeakerAvatar;
34
+ } | null;
31
35
  getSpeaker(context: MulmoStudioContext, beat: MulmoBeat, targetLang: string | undefined): SpeakerData;
32
36
  getMovieTransition(context: MulmoStudioContext, beat: MulmoBeat): MulmoTransition | null;
33
37
  getNeedFirstFrame(context: MulmoStudioContext): boolean[];
@@ -92,6 +92,14 @@ export const MulmoPresentationStyleMethods = {
92
92
  }
93
93
  return speaker;
94
94
  },
95
+ // The speaker of a beat and the avatar it speaks with, if any. A language-specific speaker
96
+ // replaces the whole speaker, so its avatar falls back to the base speaker's.
97
+ getSpeakerAvatar(presentationStyle, beat, lang) {
98
+ const speakerId = beat?.speaker ?? MulmoPresentationStyleMethods.getDefaultSpeaker(presentationStyle);
99
+ const speaker = presentationStyle.speechParams?.speakers?.[speakerId];
100
+ const avatar = (lang ? speaker?.lang?.[lang]?.avatar : undefined) ?? speaker?.avatar;
101
+ return avatar ? { speakerId, avatar } : null;
102
+ },
95
103
  getSpeaker(context, beat, targetLang) {
96
104
  // Normally, lang is determined by the context, but lang may be specified when using the API.
97
105
  const lang = targetLang ?? context.lang ?? context?.studio?.script?.lang;