mulmocast 2.13.0 → 2.14.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/assets/schemas/mulmo_script.json +87 -21
- package/lib/index.remotion.d.ts +3 -0
- package/lib/index.remotion.js +4 -0
- package/lib/types/schema.d.ts +68 -11
- package/lib/types/schema.js +21 -5
- package/lib/types/type.d.ts +2 -1
- package/lib/utils/context.d.ts +22 -2
- package/lib/utils/image_plugins/remotion.d.ts +2 -1
- package/lib/utils/image_plugins/remotion.js +50 -12
- package/lib/utils/remotion/render.d.ts +1 -0
- package/lib/utils/remotion/render.js +3 -1
- package/lib/utils/remotion/system_prompt.d.ts +1 -0
- package/lib/utils/remotion/system_prompt.js +9 -5
- package/package.json +5 -1
|
@@ -13517,29 +13517,95 @@
|
|
|
13517
13517
|
"additionalProperties": false
|
|
13518
13518
|
},
|
|
13519
13519
|
{
|
|
13520
|
-
"
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
"
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13520
|
+
"anyOf": [
|
|
13521
|
+
{
|
|
13522
|
+
"type": "object",
|
|
13523
|
+
"properties": {
|
|
13524
|
+
"type": {
|
|
13525
|
+
"type": "string",
|
|
13526
|
+
"const": "remotion"
|
|
13527
|
+
},
|
|
13528
|
+
"fps": {
|
|
13529
|
+
"description": "Frame rate of the rendered video. Default: 30.",
|
|
13530
|
+
"type": "number",
|
|
13531
|
+
"minimum": 1,
|
|
13532
|
+
"maximum": 60
|
|
13533
|
+
},
|
|
13534
|
+
"prompt": {
|
|
13535
|
+
"type": "string",
|
|
13536
|
+
"minLength": 1,
|
|
13537
|
+
"description": "What the scene shows. Claude Code (claude -p) writes a Remotion component from it."
|
|
13538
|
+
}
|
|
13539
|
+
},
|
|
13540
|
+
"required": [
|
|
13541
|
+
"type",
|
|
13542
|
+
"prompt"
|
|
13543
|
+
],
|
|
13544
|
+
"additionalProperties": false
|
|
13530
13545
|
},
|
|
13531
|
-
|
|
13532
|
-
"
|
|
13533
|
-
"
|
|
13534
|
-
|
|
13535
|
-
|
|
13546
|
+
{
|
|
13547
|
+
"type": "object",
|
|
13548
|
+
"properties": {
|
|
13549
|
+
"type": {
|
|
13550
|
+
"type": "string",
|
|
13551
|
+
"const": "remotion"
|
|
13552
|
+
},
|
|
13553
|
+
"fps": {
|
|
13554
|
+
"description": "Frame rate of the rendered video. Default: 30.",
|
|
13555
|
+
"type": "number",
|
|
13556
|
+
"minimum": 1,
|
|
13557
|
+
"maximum": 60
|
|
13558
|
+
},
|
|
13559
|
+
"code": {
|
|
13560
|
+
"oneOf": [
|
|
13561
|
+
{
|
|
13562
|
+
"type": "object",
|
|
13563
|
+
"properties": {
|
|
13564
|
+
"kind": {
|
|
13565
|
+
"type": "string",
|
|
13566
|
+
"const": "text"
|
|
13567
|
+
},
|
|
13568
|
+
"text": {
|
|
13569
|
+
"type": "string",
|
|
13570
|
+
"minLength": 1
|
|
13571
|
+
}
|
|
13572
|
+
},
|
|
13573
|
+
"required": [
|
|
13574
|
+
"kind",
|
|
13575
|
+
"text"
|
|
13576
|
+
],
|
|
13577
|
+
"additionalProperties": false
|
|
13578
|
+
},
|
|
13579
|
+
{
|
|
13580
|
+
"type": "object",
|
|
13581
|
+
"properties": {
|
|
13582
|
+
"kind": {
|
|
13583
|
+
"type": "string",
|
|
13584
|
+
"const": "path"
|
|
13585
|
+
},
|
|
13586
|
+
"path": {
|
|
13587
|
+
"type": "string",
|
|
13588
|
+
"minLength": 1,
|
|
13589
|
+
"description": "Relative to the script"
|
|
13590
|
+
}
|
|
13591
|
+
},
|
|
13592
|
+
"required": [
|
|
13593
|
+
"kind",
|
|
13594
|
+
"path"
|
|
13595
|
+
],
|
|
13596
|
+
"additionalProperties": false
|
|
13597
|
+
}
|
|
13598
|
+
],
|
|
13599
|
+
"description": "A finished Remotion component (TSX that default-exports the scene). It is rendered as is, without claude -p."
|
|
13600
|
+
}
|
|
13601
|
+
},
|
|
13602
|
+
"required": [
|
|
13603
|
+
"type",
|
|
13604
|
+
"code"
|
|
13605
|
+
],
|
|
13606
|
+
"additionalProperties": false
|
|
13536
13607
|
}
|
|
13537
|
-
|
|
13538
|
-
"required": [
|
|
13539
|
-
"type",
|
|
13540
|
-
"prompt"
|
|
13541
|
-
],
|
|
13542
|
-
"additionalProperties": false
|
|
13608
|
+
]
|
|
13543
13609
|
}
|
|
13544
13610
|
]
|
|
13545
13611
|
},
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { REMOTION_COMPONENT_GUIDE } from "./utils/remotion/system_prompt.js";
|
|
2
|
+
export { REMOTION_PACKAGES, REMOTION_RENDER_PACKAGES, REMOTION_SCENE_PACKAGES, remotionInstallCommand } from "./utils/remotion/packages.js";
|
|
3
|
+
export { ensureRemotionPackages, missingInstalledRemotionPackages } from "./utils/remotion/render.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Entry point for hosts whose own agent writes the remotion beat's component and passes it as `code`.
|
|
2
|
+
export { REMOTION_COMPONENT_GUIDE } from "./utils/remotion/system_prompt.js";
|
|
3
|
+
export { REMOTION_PACKAGES, REMOTION_RENDER_PACKAGES, REMOTION_SCENE_PACKAGES, remotionInstallCommand } from "./utils/remotion/packages.js";
|
|
4
|
+
export { ensureRemotionPackages, missingInstalledRemotionPackages } from "./utils/remotion/render.js";
|
package/lib/types/schema.d.ts
CHANGED
|
@@ -545,11 +545,28 @@ export declare const mulmoVisionMediaSchema: z.ZodObject<{
|
|
|
545
545
|
style: z.ZodString;
|
|
546
546
|
data: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
547
547
|
}, z.core.$strict>;
|
|
548
|
-
export declare const
|
|
549
|
-
|
|
548
|
+
export declare const remotionCodeSourceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
549
|
+
kind: z.ZodLiteral<"text">;
|
|
550
|
+
text: z.ZodString;
|
|
551
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
552
|
+
kind: z.ZodLiteral<"path">;
|
|
553
|
+
path: z.ZodString;
|
|
554
|
+
}, z.core.$strict>], "kind">;
|
|
555
|
+
export declare const mulmoRemotionMediaSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
550
556
|
prompt: z.ZodString;
|
|
557
|
+
type: z.ZodLiteral<"remotion">;
|
|
551
558
|
fps: z.ZodOptional<z.ZodNumber>;
|
|
552
|
-
}, z.core.$strict
|
|
559
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
560
|
+
code: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
561
|
+
kind: z.ZodLiteral<"text">;
|
|
562
|
+
text: z.ZodString;
|
|
563
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
564
|
+
kind: z.ZodLiteral<"path">;
|
|
565
|
+
path: z.ZodString;
|
|
566
|
+
}, z.core.$strict>], "kind">;
|
|
567
|
+
type: z.ZodLiteral<"remotion">;
|
|
568
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
569
|
+
}, z.core.$strict>]>;
|
|
553
570
|
export declare const mulmoRemotionParamsSchema: z.ZodObject<{
|
|
554
571
|
brief: z.ZodOptional<z.ZodString>;
|
|
555
572
|
}, z.core.$strict>;
|
|
@@ -4233,11 +4250,21 @@ export declare const mulmoImageAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
4233
4250
|
bgOpacity: z.ZodOptional<z.ZodNumber>;
|
|
4234
4251
|
}, z.core.$strip>>;
|
|
4235
4252
|
}, z.core.$strict>>>;
|
|
4253
|
+
}, z.core.$strict>, z.ZodUnion<readonly [z.ZodObject<{
|
|
4254
|
+
prompt: z.ZodString;
|
|
4255
|
+
type: z.ZodLiteral<"remotion">;
|
|
4256
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
4236
4257
|
}, z.core.$strict>, z.ZodObject<{
|
|
4258
|
+
code: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4259
|
+
kind: z.ZodLiteral<"text">;
|
|
4260
|
+
text: z.ZodString;
|
|
4261
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
4262
|
+
kind: z.ZodLiteral<"path">;
|
|
4263
|
+
path: z.ZodString;
|
|
4264
|
+
}, z.core.$strict>], "kind">;
|
|
4237
4265
|
type: z.ZodLiteral<"remotion">;
|
|
4238
|
-
prompt: z.ZodString;
|
|
4239
4266
|
fps: z.ZodOptional<z.ZodNumber>;
|
|
4240
|
-
}, z.core.$strict>]>;
|
|
4267
|
+
}, z.core.$strict>]>]>;
|
|
4241
4268
|
export declare const mulmoAudioAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
4242
4269
|
type: z.ZodLiteral<"audio">;
|
|
4243
4270
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -8644,11 +8671,21 @@ export declare const mulmoBeatSchema: z.ZodObject<{
|
|
|
8644
8671
|
bgOpacity: z.ZodOptional<z.ZodNumber>;
|
|
8645
8672
|
}, z.core.$strip>>;
|
|
8646
8673
|
}, z.core.$strict>>>;
|
|
8674
|
+
}, z.core.$strict>, z.ZodUnion<readonly [z.ZodObject<{
|
|
8675
|
+
prompt: z.ZodString;
|
|
8676
|
+
type: z.ZodLiteral<"remotion">;
|
|
8677
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
8647
8678
|
}, z.core.$strict>, z.ZodObject<{
|
|
8679
|
+
code: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
8680
|
+
kind: z.ZodLiteral<"text">;
|
|
8681
|
+
text: z.ZodString;
|
|
8682
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
8683
|
+
kind: z.ZodLiteral<"path">;
|
|
8684
|
+
path: z.ZodString;
|
|
8685
|
+
}, z.core.$strict>], "kind">;
|
|
8648
8686
|
type: z.ZodLiteral<"remotion">;
|
|
8649
|
-
prompt: z.ZodString;
|
|
8650
8687
|
fps: z.ZodOptional<z.ZodNumber>;
|
|
8651
|
-
}, z.core.$strict>]>>;
|
|
8688
|
+
}, z.core.$strict>]>]>>;
|
|
8652
8689
|
audio: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
8653
8690
|
type: z.ZodLiteral<"audio">;
|
|
8654
8691
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -13901,11 +13938,21 @@ export declare const mulmoScriptSchema: z.ZodObject<{
|
|
|
13901
13938
|
bgOpacity: z.ZodOptional<z.ZodNumber>;
|
|
13902
13939
|
}, z.core.$strip>>;
|
|
13903
13940
|
}, z.core.$strict>>>;
|
|
13941
|
+
}, z.core.$strict>, z.ZodUnion<readonly [z.ZodObject<{
|
|
13942
|
+
prompt: z.ZodString;
|
|
13943
|
+
type: z.ZodLiteral<"remotion">;
|
|
13944
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
13904
13945
|
}, z.core.$strict>, z.ZodObject<{
|
|
13946
|
+
code: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13947
|
+
kind: z.ZodLiteral<"text">;
|
|
13948
|
+
text: z.ZodString;
|
|
13949
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13950
|
+
kind: z.ZodLiteral<"path">;
|
|
13951
|
+
path: z.ZodString;
|
|
13952
|
+
}, z.core.$strict>], "kind">;
|
|
13905
13953
|
type: z.ZodLiteral<"remotion">;
|
|
13906
|
-
prompt: z.ZodString;
|
|
13907
13954
|
fps: z.ZodOptional<z.ZodNumber>;
|
|
13908
|
-
}, z.core.$strict>]>>;
|
|
13955
|
+
}, z.core.$strict>]>]>>;
|
|
13909
13956
|
audio: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
13910
13957
|
type: z.ZodLiteral<"audio">;
|
|
13911
13958
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -18682,11 +18729,21 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
18682
18729
|
bgOpacity: z.ZodOptional<z.ZodNumber>;
|
|
18683
18730
|
}, z.core.$strip>>;
|
|
18684
18731
|
}, z.core.$strict>>>;
|
|
18732
|
+
}, z.core.$strict>, z.ZodUnion<readonly [z.ZodObject<{
|
|
18733
|
+
prompt: z.ZodString;
|
|
18734
|
+
type: z.ZodLiteral<"remotion">;
|
|
18735
|
+
fps: z.ZodOptional<z.ZodNumber>;
|
|
18685
18736
|
}, z.core.$strict>, z.ZodObject<{
|
|
18737
|
+
code: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
18738
|
+
kind: z.ZodLiteral<"text">;
|
|
18739
|
+
text: z.ZodString;
|
|
18740
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
18741
|
+
kind: z.ZodLiteral<"path">;
|
|
18742
|
+
path: z.ZodString;
|
|
18743
|
+
}, z.core.$strict>], "kind">;
|
|
18686
18744
|
type: z.ZodLiteral<"remotion">;
|
|
18687
|
-
prompt: z.ZodString;
|
|
18688
18745
|
fps: z.ZodOptional<z.ZodNumber>;
|
|
18689
|
-
}, z.core.$strict>]>>;
|
|
18746
|
+
}, z.core.$strict>]>]>>;
|
|
18690
18747
|
audio: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
18691
18748
|
type: z.ZodLiteral<"audio">;
|
|
18692
18749
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
package/lib/types/schema.js
CHANGED
|
@@ -359,13 +359,29 @@ export const mulmoVisionMediaSchema = z
|
|
|
359
359
|
data: z.record(z.string(), z.any()),
|
|
360
360
|
})
|
|
361
361
|
.strict();
|
|
362
|
-
export const
|
|
363
|
-
.object({
|
|
362
|
+
export const remotionCodeSourceSchema = z.discriminatedUnion("kind", [
|
|
363
|
+
z.object({ kind: z.literal("text"), text: z.string().min(1) }).strict(),
|
|
364
|
+
z.object({ kind: z.literal("path"), path: z.string().min(1).describe("Relative to the script") }).strict(),
|
|
365
|
+
]);
|
|
366
|
+
const remotionMediaShape = {
|
|
364
367
|
type: z.literal(ImageMediaType.Remotion),
|
|
365
|
-
prompt: z.string().min(1).describe("What the scene shows. Claude Code (claude -p) writes a Remotion component from it."),
|
|
366
368
|
fps: z.number().min(1).max(60).optional().describe("Frame rate of the rendered video. Default: 30."),
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
+
};
|
|
370
|
+
// Two strict shapes rather than one object with a refine, so the bundled JSON schema states "prompt or code, not both" too.
|
|
371
|
+
export const mulmoRemotionMediaSchema = z.union([
|
|
372
|
+
z
|
|
373
|
+
.object({
|
|
374
|
+
...remotionMediaShape,
|
|
375
|
+
prompt: z.string().min(1).describe("What the scene shows. Claude Code (claude -p) writes a Remotion component from it."),
|
|
376
|
+
})
|
|
377
|
+
.strict(),
|
|
378
|
+
z
|
|
379
|
+
.object({
|
|
380
|
+
...remotionMediaShape,
|
|
381
|
+
code: remotionCodeSourceSchema.describe("A finished Remotion component (TSX that default-exports the scene). It is rendered as is, without claude -p."),
|
|
382
|
+
})
|
|
383
|
+
.strict(),
|
|
384
|
+
]);
|
|
369
385
|
export const mulmoRemotionParamsSchema = z
|
|
370
386
|
.object({
|
|
371
387
|
brief: z.string().optional().describe("Whole-video art direction shared by every remotion beat (palette, type, mood), so all scenes look like one film."),
|
package/lib/types/type.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CallbackFunction } from "graphai";
|
|
2
2
|
import type { UsageCollectorAPI } from "./usage.js";
|
|
3
|
-
import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualArraySchema, mulmoStudioMultiLingualDataSchema, mulmoStudioMultiLingualFileSchema, speakerDictionarySchema, speakerSchema, mulmoSpeechParamsSchema, mulmoImageParamsSchema, mulmoImageParamsImagesValueSchema, mulmoImageParamsImagesSchema, mulmoFillOptionSchema, mulmoTransitionSchema, mulmoVideoFilterSchema, mulmoMovieParamsSchema, mulmoSoundEffectParamsSchema, mulmoLipSyncParamsSchema, textSlideParamsSchema, speechOptionsSchema, speakerDataSchema, mulmoCanvasDimensionSchema, mulmoPromptTemplateSchema, mulmoPromptTemplateFileSchema, text2ImageProviderSchema, text2HtmlImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoImageAssetSchema, mulmoMermaidMediaSchema, mulmoRemotionMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mediaSourceMermaidSchema, backgroundImageSchema, backgroundImageSourceSchema, mulmoSessionStateSchema, mulmoOpenAIImageModelSchema, mulmoGoogleImageModelSchema, mulmoGoogleMovieModelSchema, mulmoReplicateMovieModelSchema, mulmoImagePromptMediaSchema, mulmoImageReferenceSchema, mulmoMovieMediaSchema, mulmoMoviePromptMediaSchema, markdownLayoutSchema, row2Schema, grid2x2Schema, mulmoAvatarParamsSchema, avatarPositionSchema, speakerAvatarSchema, mulmoAvatarTrackSchema } from "./schema.js";
|
|
3
|
+
import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualArraySchema, mulmoStudioMultiLingualDataSchema, mulmoStudioMultiLingualFileSchema, speakerDictionarySchema, speakerSchema, mulmoSpeechParamsSchema, mulmoImageParamsSchema, mulmoImageParamsImagesValueSchema, mulmoImageParamsImagesSchema, mulmoFillOptionSchema, mulmoTransitionSchema, mulmoVideoFilterSchema, mulmoMovieParamsSchema, mulmoSoundEffectParamsSchema, mulmoLipSyncParamsSchema, textSlideParamsSchema, speechOptionsSchema, speakerDataSchema, mulmoCanvasDimensionSchema, mulmoPromptTemplateSchema, mulmoPromptTemplateFileSchema, text2ImageProviderSchema, text2HtmlImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoImageAssetSchema, mulmoMermaidMediaSchema, mulmoRemotionMediaSchema, remotionCodeSourceSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mediaSourceMermaidSchema, backgroundImageSchema, backgroundImageSourceSchema, mulmoSessionStateSchema, mulmoOpenAIImageModelSchema, mulmoGoogleImageModelSchema, mulmoGoogleMovieModelSchema, mulmoReplicateMovieModelSchema, mulmoImagePromptMediaSchema, mulmoImageReferenceSchema, mulmoMovieMediaSchema, mulmoMoviePromptMediaSchema, markdownLayoutSchema, row2Schema, grid2x2Schema, mulmoAvatarParamsSchema, avatarPositionSchema, speakerAvatarSchema, mulmoAvatarTrackSchema } from "./schema.js";
|
|
4
4
|
import { pdf_modes, pdf_sizes, storyToScriptGenerateMode } from "./const.js";
|
|
5
5
|
import type { LLM } from "./provider2agent.js";
|
|
6
6
|
import { z } from "zod";
|
|
@@ -66,6 +66,7 @@ export type MulmoMovieMedia = z.infer<typeof mulmoMovieMediaSchema>;
|
|
|
66
66
|
export type MulmoChartMedia = z.infer<typeof mulmoChartMediaSchema>;
|
|
67
67
|
export type MulmoMermaidMedia = z.infer<typeof mulmoMermaidMediaSchema>;
|
|
68
68
|
export type MulmoRemotionMedia = z.infer<typeof mulmoRemotionMediaSchema>;
|
|
69
|
+
export type MulmoRemotionCodeSource = z.infer<typeof remotionCodeSourceSchema>;
|
|
69
70
|
export type MulmoSessionState = z.infer<typeof mulmoSessionStateSchema>;
|
|
70
71
|
export type MulmoStudioContext = {
|
|
71
72
|
fileDirs: FileObject;
|
package/lib/utils/context.d.ts
CHANGED
|
@@ -549,8 +549,18 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
|
|
|
549
549
|
style: string;
|
|
550
550
|
data: Record<string, any>;
|
|
551
551
|
} | {
|
|
552
|
-
type: "remotion";
|
|
553
552
|
prompt: string;
|
|
553
|
+
type: "remotion";
|
|
554
|
+
fps?: number | undefined;
|
|
555
|
+
} | {
|
|
556
|
+
code: {
|
|
557
|
+
kind: "text";
|
|
558
|
+
text: string;
|
|
559
|
+
} | {
|
|
560
|
+
kind: "path";
|
|
561
|
+
path: string;
|
|
562
|
+
};
|
|
563
|
+
type: "remotion";
|
|
554
564
|
fps?: number | undefined;
|
|
555
565
|
} | {
|
|
556
566
|
type: "slide";
|
|
@@ -3178,8 +3188,18 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
3178
3188
|
style: string;
|
|
3179
3189
|
data: Record<string, any>;
|
|
3180
3190
|
} | {
|
|
3181
|
-
type: "remotion";
|
|
3182
3191
|
prompt: string;
|
|
3192
|
+
type: "remotion";
|
|
3193
|
+
fps?: number | undefined;
|
|
3194
|
+
} | {
|
|
3195
|
+
code: {
|
|
3196
|
+
kind: "text";
|
|
3197
|
+
text: string;
|
|
3198
|
+
} | {
|
|
3199
|
+
kind: "path";
|
|
3200
|
+
path: string;
|
|
3201
|
+
};
|
|
3202
|
+
type: "remotion";
|
|
3183
3203
|
fps?: number | undefined;
|
|
3184
3204
|
} | {
|
|
3185
3205
|
type: "slide";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ImageProcessorParams } from "../../types/index.js";
|
|
1
|
+
import { ImageProcessorParams, MulmoRemotionCodeSource, MulmoStudioContext } from "../../types/index.js";
|
|
2
2
|
import { ComponentReviewer, ComponentWriter } from "../remotion/claude_runner.js";
|
|
3
3
|
import { SceneRenderer } from "../remotion/render.js";
|
|
4
4
|
export declare const imageType: "remotion";
|
|
@@ -11,6 +11,7 @@ export type RemotionDeps = {
|
|
|
11
11
|
export declare const remotionWorkDir: (imagePath: string) => string;
|
|
12
12
|
export declare const remotionStillPath: (imagePath: string) => string;
|
|
13
13
|
export declare const reviewCandidatePath: (filePath: string) => string;
|
|
14
|
+
export declare const remotionCodeLocation: (code: MulmoRemotionCodeSource, context: MulmoStudioContext, beatIndex: number) => string;
|
|
14
15
|
export declare const createRemotionProcess: (deps: RemotionDeps) => (params: ImageProcessorParams) => Promise<string | undefined>;
|
|
15
16
|
export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
|
|
16
17
|
export declare const path: (params: import("../../types/type.js").BeatPathParams) => string;
|
|
@@ -3,6 +3,7 @@ import nodePath from "node:path";
|
|
|
3
3
|
import { GraphAILogger } from "graphai";
|
|
4
4
|
import { ImageMediaType } from "../../types/index.js";
|
|
5
5
|
import { localizedText } from "../utils.js";
|
|
6
|
+
import { getFullPath } from "../file.js";
|
|
6
7
|
import { REMOTION_COMPONENT_FILE, buildRepairPrompt, buildReviewPrompt, buildScenePrompt, remotionCacheKey, } from "../remotion/claude_prompt.js";
|
|
7
8
|
import { reviewComponentWithClaude, writeComponentWithClaude } from "../remotion/claude_runner.js";
|
|
8
9
|
import { ensureRemotionPackages, renderRemotionScene } from "../remotion/render.js";
|
|
@@ -114,9 +115,18 @@ const toFrameCount = (durationSec, fps) => {
|
|
|
114
115
|
const scenePosition = (beats, index) => (index < 0 ? undefined : { index, count: beats.length });
|
|
115
116
|
// The words actually spoken over the scene: the translation when the video is rendered in another language.
|
|
116
117
|
const spokenNarration = (context, beat, index) => (index < 0 ? beat.text : localizedText(beat, context.multiLingual?.[index], context.lang, context.studio.script.lang)) || undefined;
|
|
117
|
-
const
|
|
118
|
-
const { beat,
|
|
118
|
+
const buildSceneOutput = (params, fps) => {
|
|
119
|
+
const { beat, imagePath, canvasSize } = params;
|
|
119
120
|
const duration = params.beatDuration ?? beat.duration;
|
|
121
|
+
return {
|
|
122
|
+
workDir: remotionWorkDir(imagePath),
|
|
123
|
+
props: { durationInFrames: toFrameCount(duration ?? STILL_ONLY_DURATION_SEC, fps), fps, width: canvasSize.width, height: canvasSize.height },
|
|
124
|
+
videoPath: duration !== undefined ? imagePath : undefined,
|
|
125
|
+
stillPath: remotionStillPath(imagePath),
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
const buildJob = (params, prompt, fps) => {
|
|
129
|
+
const { beat, context, canvasSize } = params;
|
|
120
130
|
const index = context.studio.script.beats.indexOf(beat);
|
|
121
131
|
const spec = {
|
|
122
132
|
prompt,
|
|
@@ -127,21 +137,49 @@ const buildJob = (params, prompt, fps) => {
|
|
|
127
137
|
width: canvasSize.width,
|
|
128
138
|
height: canvasSize.height,
|
|
129
139
|
};
|
|
130
|
-
const
|
|
131
|
-
return {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
140
|
+
const output = buildSceneOutput(params, fps);
|
|
141
|
+
return { ...output, spec, codePath: nodePath.join(output.workDir, `${remotionCacheKey(spec)}.tsx`) };
|
|
142
|
+
};
|
|
143
|
+
// Named in errors, so whoever wrote the component (usually the host's agent) knows what to fix.
|
|
144
|
+
export const remotionCodeLocation = (code, context, beatIndex) => {
|
|
145
|
+
if (code.kind === "path")
|
|
146
|
+
return getFullPath(context.fileDirs.mulmoFileDirPath, code.path);
|
|
147
|
+
return beatIndex < 0 ? "inline code" : `inline code of beat ${beatIndex + 1}`;
|
|
148
|
+
};
|
|
149
|
+
const readGivenComponent = (code, location) => {
|
|
150
|
+
if (code.kind === "text")
|
|
151
|
+
return code.text;
|
|
152
|
+
try {
|
|
153
|
+
return fs.readFileSync(location, "utf8");
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
throw new Error(`remotion: cannot read the component file ${location}`, { cause: error });
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
// A given component is the caller's to fix, so a failed render stops here instead of asking claude -p to repair it.
|
|
160
|
+
const renderGivenComponent = async (params, code, fps, deps) => {
|
|
161
|
+
const output = buildSceneOutput(params, fps);
|
|
162
|
+
const location = remotionCodeLocation(code, params.context, params.context.studio.script.beats.indexOf(params.beat));
|
|
163
|
+
deps.ensurePackages();
|
|
164
|
+
const source = readGivenComponent(code, location);
|
|
165
|
+
fs.mkdirSync(output.workDir, { recursive: true });
|
|
166
|
+
fs.writeFileSync(nodePath.join(output.workDir, REMOTION_COMPONENT_FILE), source);
|
|
167
|
+
try {
|
|
168
|
+
await deps.renderScene({ workDir: output.workDir, props: output.props, videoPath: output.videoPath, stillPath: output.stillPath });
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw new Error(`remotion beat failed to render the given component (code: ${location}): ${errorMessage(error)}`, { cause: error });
|
|
172
|
+
}
|
|
173
|
+
return output.videoPath ?? output.stillPath;
|
|
139
174
|
};
|
|
140
175
|
export const createRemotionProcess = (deps) => async (params) => {
|
|
141
176
|
const { beat, context } = params;
|
|
142
177
|
if (!beat.image || beat.image.type !== imageType)
|
|
143
178
|
return;
|
|
144
|
-
const
|
|
179
|
+
const fps = beat.image.fps ?? DEFAULT_FPS;
|
|
180
|
+
if ("code" in beat.image)
|
|
181
|
+
return await renderGivenComponent(params, beat.image.code, fps, deps);
|
|
182
|
+
const job = buildJob(params, beat.image.prompt, fps);
|
|
145
183
|
deps.ensurePackages();
|
|
146
184
|
fs.mkdirSync(job.workDir, { recursive: true });
|
|
147
185
|
const { code, isNew } = await loadOrWriteComponent(job, context.force, deps);
|
|
@@ -15,5 +15,6 @@ export type RemotionRenderRequest = {
|
|
|
15
15
|
}[];
|
|
16
16
|
};
|
|
17
17
|
export type SceneRenderer = (request: RemotionRenderRequest) => Promise<void>;
|
|
18
|
+
export declare const missingInstalledRemotionPackages: () => string[];
|
|
18
19
|
export declare const ensureRemotionPackages: () => void;
|
|
19
20
|
export declare const renderRemotionScene: SceneRenderer;
|
|
@@ -24,10 +24,12 @@ const isPackageInstalled = (name) => {
|
|
|
24
24
|
return !(error instanceof Error && "code" in error && error.code === "MODULE_NOT_FOUND");
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
+
// Resolved from mulmocast's own location, which is where the renderer looks for them.
|
|
28
|
+
export const missingInstalledRemotionPackages = () => missingRemotionPackages(isPackageInstalled);
|
|
27
29
|
// Checked before asking claude -p for a component: a generated import of a missing optional peer
|
|
28
30
|
// would otherwise surface as an opaque bundling error after the generation was already paid for.
|
|
29
31
|
export const ensureRemotionPackages = () => {
|
|
30
|
-
const missing =
|
|
32
|
+
const missing = missingInstalledRemotionPackages();
|
|
31
33
|
if (missing.length > 0) {
|
|
32
34
|
throw new Error(`The remotion beat needs packages that are not installed (${missing.join(", ")}). Install them with: ${remotionInstallCommand()}`);
|
|
33
35
|
}
|
|
@@ -2,13 +2,13 @@ import { REMOTION_SCENE_PACKAGES } from "./packages.js";
|
|
|
2
2
|
const ALLOWED_IMPORTS = ["react", "remotion", ...REMOTION_SCENE_PACKAGES].map((name) => `"${name}"`).join(", ");
|
|
3
3
|
// The contract and the house style for the component `claude -p` writes for one remotion beat.
|
|
4
4
|
// Every snippet in the toolkit section was rendered with this repository's renderer settings.
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- \`export default\` the scene component. It receives props \`{ durationInFrames: number; fps: number; width: number; height: number }\`; read them with \`useVideoConfig()\`.
|
|
5
|
+
const ROLE = `You are a senior motion designer and Remotion (v4.0.533) engineer. You write ONE React component in TypeScript (TSX) that renders one scene of a commercial-quality video.`;
|
|
6
|
+
const REPLY_FORMAT = `- Reply with ONLY the TSX source in one \`\`\`tsx code block. No explanation before or after.`;
|
|
7
|
+
const COMPONENT_RULES = `- One self-contained file: no relative imports, since it is rendered on its own.`;
|
|
8
|
+
const CONTRACT_BODY = `- \`export default\` the scene component. It receives props \`{ durationInFrames: number; fps: number; width: number; height: number }\`; read them with \`useVideoConfig()\`.
|
|
10
9
|
- Allowed imports, nothing else: ${ALLOWED_IMPORTS}. Subpaths of these packages are allowed too, e.g. "@remotion/transitions/fade" (also "/slide", "/wipe", "/iris", "/cross-zoom", "/film-burn", "/dissolve", "/clock-wipe") and "@remotion/effects/<name>".
|
|
11
10
|
- No network, no external URLs, no image/video/audio files, no web fonts. Draw everything with DOM, SVG, canvas or three.js.`;
|
|
11
|
+
const OUTPUT_CONTRACT = [ROLE, "", "# Output contract", REPLY_FORMAT, CONTRACT_BODY].join("\n");
|
|
12
12
|
const TIMING_RULES = `# Timing (hard rules — breaking them causes flicker or broken renders)
|
|
13
13
|
- Everything is a pure function of \`useCurrentFrame()\`. NEVER use CSS animations/transitions, \`setTimeout\`, \`requestAnimationFrame\`, \`Date\`, or three.js \`useFrame\`.
|
|
14
14
|
- NEVER use \`Math.random()\`; use \`random("seed-" + i)\` from "remotion" or \`noise2D/noise3D\` from "@remotion/noise".
|
|
@@ -51,6 +51,10 @@ const SELF_CHECK = `# Before you answer, check silently
|
|
|
51
51
|
- At 30%, 60% and 100% of the duration the frame is fully composed, readable, balanced, and nothing overflows the safe margins or overlaps.
|
|
52
52
|
- The scene matches the brief and the narration, and looks like a frame from a premium brand film.`;
|
|
53
53
|
export const REMOTION_SYSTEM_PROMPT = [OUTPUT_CONTRACT, TIMING_RULES, DESIGN_SYSTEM, MOTION_LANGUAGE, TOOLKIT, SELF_CHECK].join("\n\n");
|
|
54
|
+
// The same contract for a host's agent that writes the component file itself and passes it as \`code\`.
|
|
55
|
+
// The system prompt stays byte-identical, since it is part of every cached component's key.
|
|
56
|
+
const COMPONENT_CONTRACT = ["# Component contract", COMPONENT_RULES, CONTRACT_BODY].join("\n");
|
|
57
|
+
export const REMOTION_COMPONENT_GUIDE = [COMPONENT_CONTRACT, TIMING_RULES, DESIGN_SYSTEM, MOTION_LANGUAGE, TOOLKIT, SELF_CHECK].join("\n\n");
|
|
54
58
|
export const REMOTION_REVIEW_MARKER = "LGTM";
|
|
55
59
|
export const REMOTION_REVIEW_SYSTEM_PROMPT = [
|
|
56
60
|
REMOTION_SYSTEM_PROMPT,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mulmocast",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.node.js",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
"./data": {
|
|
17
17
|
"default": "./lib/data/index.js"
|
|
18
18
|
},
|
|
19
|
+
"./remotion": {
|
|
20
|
+
"types": "./lib/index.remotion.d.ts",
|
|
21
|
+
"default": "./lib/index.remotion.js"
|
|
22
|
+
},
|
|
19
23
|
"./assets/*": "./assets/*",
|
|
20
24
|
"./scripts/*": "./scripts/*",
|
|
21
25
|
"./tools/complete_script": {
|