mulmocast 2.4.9 → 2.5.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.
@@ -1,293 +1,40 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en" class="h-full">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <script src="https://cdn.tailwindcss.com"></script>
7
- <style>
8
- /* Disable all CSS animations/transitions for deterministic frame-based rendering */
9
- *, *::before, *::after {
10
- animation-play-state: paused !important;
11
- transition: none !important;
12
- }
13
- ${custom_style}
14
- </style>
15
- </head>
16
- <body class="bg-white text-gray-800 h-full flex flex-col">
17
- ${html_body}
18
-
19
- <script>
20
- // === MulmoCast Animation Helpers ===
21
-
22
- /**
23
- * Easing functions for non-linear interpolation.
24
- */
25
- const Easing = {
26
- linear: (t) => t,
27
- easeIn: (t) => t * t,
28
- easeOut: (t) => 1 - (1 - t) * (1 - t),
29
- easeInOut: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
30
- };
31
-
32
- /**
33
- * Interpolation with clamping and optional easing.
34
- *
35
- * @param {number} value - Current value (typically frame number)
36
- * @param {Object} opts - { input: { inMin, inMax }, output: { outMin, outMax }, easing?: string | function }
37
- * @returns {number} Interpolated and clamped value
38
- *
39
- * @example
40
- * interpolate(frame, { input: { inMin: 0, inMax: 30 }, output: { outMin: 0, outMax: 1 } })
41
- * interpolate(frame, { input: { inMin: 0, inMax: 30 }, output: { outMin: 0, outMax: 1 }, easing: 'easeOut' })
42
- */
43
- function interpolate(value, opts) {
44
- const { inMin, inMax } = opts.input;
45
- const { outMin, outMax } = opts.output;
46
- if (inMax === inMin) {
47
- return outMin;
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <script src="https://cdn.tailwindcss.com"></script>
7
+ <style>
8
+ /* Disable all CSS animations/transitions for deterministic frame-based rendering */
9
+ *, *::before, *::after {
10
+ animation-play-state: paused !important;
11
+ transition: none !important;
48
12
  }
49
- const easing = !opts.easing ? Easing.linear
50
- : typeof opts.easing === 'function' ? opts.easing
51
- : Easing[opts.easing] || Easing.linear;
52
- const progress = Math.max(0, Math.min(1, (value - inMin) / (inMax - inMin)));
53
- return outMin + easing(progress) * (outMax - outMin);
54
- }
55
-
56
- // === MulmoAnimation Helper Class ===
57
-
58
- const TRANSFORM_PROPS = { translateX: 'px', translateY: 'px', scale: '', rotate: 'deg', rotateX: 'deg', rotateY: 'deg', rotateZ: 'deg' };
59
- const SVG_PROPS = ['r', 'cx', 'cy', 'x', 'y', 'x1', 'y1', 'x2', 'y2', 'rx', 'ry',
60
- 'width', 'height', 'stroke-width', 'stroke-dashoffset', 'stroke-dasharray', 'opacity'];
61
-
62
- function MulmoAnimation() {
63
- this._entries = [];
64
- }
65
-
66
- /**
67
- * Register a property animation on a single element.
68
- * @param {string} selector - CSS selector (e.g. '#title')
69
- * @param {Object} props - { opacity: [0, 1], translateY: [30, 0], width: [0, 80, '%'] }
70
- * @param {Object} opts - { start, end, easing } (start/end in seconds)
71
- */
72
- MulmoAnimation.prototype.animate = function(selector, props, opts) {
73
- this._entries.push({ kind: 'animate', selector, props, opts: opts || {} });
74
- return this;
75
- };
76
-
77
- /**
78
- * Stagger animation across numbered elements.
79
- * Selector must contain {i} placeholder (e.g. '#item{i}').
80
- * @param {string} selector - e.g. '#item{i}'
81
- * @param {number} count - number of elements (0-indexed)
82
- * @param {Object} props - same as animate()
83
- * @param {Object} opts - { start, stagger, duration, easing }
84
- */
85
- MulmoAnimation.prototype.stagger = function(selector, count, props, opts) {
86
- this._entries.push({ kind: 'stagger', selector, count, props, opts: opts || {} });
87
- return this;
88
- };
89
-
90
- /**
91
- * Typewriter effect — reveal text character by character.
92
- * @param {string} selector - target element selector
93
- * @param {string} text - full text to reveal
94
- * @param {Object} opts - { start, end }
95
- */
96
- MulmoAnimation.prototype.typewriter = function(selector, text, opts) {
97
- this._entries.push({ kind: 'typewriter', selector, text, opts: opts || {} });
98
- return this;
99
- };
100
-
101
- /**
102
- * Animated counter — interpolate a number and display with optional prefix/suffix.
103
- * @param {string} selector - target element selector
104
- * @param {[number, number]} range - [from, to]
105
- * @param {Object} opts - { start, end, prefix, suffix, decimals }
106
- */
107
- MulmoAnimation.prototype.counter = function(selector, range, opts) {
108
- this._entries.push({ kind: 'counter', selector, range, opts: opts || {} });
109
- return this;
110
- };
111
-
112
- /**
113
- * Code reveal — show lines of code one by one (line-level typewriter).
114
- * @param {string} selector - target element selector
115
- * @param {string[]} lines - array of code lines
116
- * @param {Object} opts - { start, end }
117
- */
118
- MulmoAnimation.prototype.codeReveal = function(selector, lines, opts) {
119
- this._entries.push({ kind: 'codeReveal', selector, lines, opts: opts || {} });
120
- return this;
121
- };
122
-
123
- /**
124
- * Blink — periodic show/hide toggle (e.g. cursor blinking).
125
- * @param {string} selector - target element selector
126
- * @param {Object} opts - { interval } (half-cycle seconds, default 0.5)
127
- */
128
- MulmoAnimation.prototype.blink = function(selector, opts) {
129
- this._entries.push({ kind: 'blink', selector, opts: opts || {} });
130
- return this;
131
- };
132
-
133
- /** Resolve easing name string or function to an easing function */
134
- MulmoAnimation.prototype._resolveEasing = function(e) {
135
- if (!e) return Easing.linear;
136
- if (typeof e === 'function') return e;
137
- return Easing[e] || Easing.linear;
138
- };
139
-
140
- /** Apply props to element at a given progress (0-1) with easing */
141
- MulmoAnimation.prototype._applyProps = function(el, props, progress, easingFn) {
142
- if (!el) return;
143
- const transforms = [];
144
- Object.keys(props).forEach((prop) => {
145
- const spec = props[prop];
146
- const from = spec[0], to = spec[1];
147
- const unit = (spec.length > 2) ? spec[2] : null;
148
- const val = from + easingFn(progress) * (to - from);
149
-
150
- if (TRANSFORM_PROPS.hasOwnProperty(prop)) {
151
- const tUnit = unit || TRANSFORM_PROPS[prop];
152
- transforms.push(prop === 'scale' ? 'scale(' + val + ')' : prop + '(' + val + tUnit + ')');
153
- } else if (el instanceof SVGElement && SVG_PROPS.indexOf(prop) !== -1) {
154
- el.setAttribute(prop, val);
155
- } else if (prop === 'opacity') {
156
- el.style.opacity = val;
157
- } else {
158
- const cssUnit = unit || 'px';
159
- el.style[prop] = val + cssUnit;
160
- }
161
- });
162
- if (transforms.length > 0) {
163
- el.style.transform = transforms.join(' ');
164
- }
165
- };
166
-
167
- /**
168
- * Update all registered animations for the given frame.
169
- * @param {number} frame - current frame number
170
- * @param {number} fps - frames per second
171
- */
172
- MulmoAnimation.prototype.update = function(frame, fps) {
173
- this._entries.forEach((entry) => {
174
- const opts = entry.opts;
175
- const easingFn = this._resolveEasing(opts.easing);
176
-
177
- if (entry.kind === 'animate') {
178
- const startFrame = (opts.start || 0) * fps;
179
- const endFrame = (opts.end === 'auto' ? window.__MULMO.totalFrames / fps : (opts.end || 0)) * fps;
180
- const progress = Math.max(0, Math.min(1, endFrame === startFrame ? 1 : (frame - startFrame) / (endFrame - startFrame)));
181
- const el = document.querySelector(entry.selector);
182
- this._applyProps(el, entry.props, progress, easingFn);
183
-
184
- } else if (entry.kind === 'stagger') {
185
- const baseStart = (opts.start || 0) * fps;
186
- const staggerDelay = (opts.stagger || 0.2) * fps;
187
- const dur = (opts.duration || 0.5) * fps;
188
- for (let j = 0; j < entry.count; j++) {
189
- const sel = entry.selector.replace(/\{i\}/g, j);
190
- const sEl = document.querySelector(sel);
191
- const sStart = baseStart + j * staggerDelay;
192
- const sEnd = sStart + dur;
193
- const sProgress = Math.max(0, Math.min(1, sEnd === sStart ? 1 : (frame - sStart) / (sEnd - sStart)));
194
- this._applyProps(sEl, entry.props, sProgress, easingFn);
195
- }
196
-
197
- } else if (entry.kind === 'typewriter') {
198
- const twStart = (opts.start || 0) * fps;
199
- const twEnd = (opts.end === 'auto' ? window.__MULMO.totalFrames / fps : (opts.end || 0)) * fps;
200
- const twProgress = Math.max(0, Math.min(1, twEnd === twStart ? 1 : (frame - twStart) / (twEnd - twStart)));
201
- const charCount = Math.floor(twProgress * entry.text.length);
202
- const twEl = document.querySelector(entry.selector);
203
- if (twEl) twEl.textContent = entry.text.substring(0, charCount);
204
-
205
- } else if (entry.kind === 'counter') {
206
- const cStart = (opts.start || 0) * fps;
207
- const cEnd = (opts.end === 'auto' ? window.__MULMO.totalFrames / fps : (opts.end || 0)) * fps;
208
- const cProgress = Math.max(0, Math.min(1, cEnd === cStart ? 1 : (frame - cStart) / (cEnd - cStart)));
209
- const cVal = entry.range[0] + easingFn(cProgress) * (entry.range[1] - entry.range[0]);
210
- const decimals = opts.decimals || 0;
211
- const display = (opts.prefix || '') + cVal.toFixed(decimals) + (opts.suffix || '');
212
- const cEl = document.querySelector(entry.selector);
213
- if (cEl) cEl.textContent = display;
214
-
215
- } else if (entry.kind === 'codeReveal') {
216
- const crStart = (opts.start || 0) * fps;
217
- const crEnd = (opts.end === 'auto' ? window.__MULMO.totalFrames / fps : (opts.end || 0)) * fps;
218
- const crProgress = Math.max(0, Math.min(1, crEnd === crStart ? 1 : (frame - crStart) / (crEnd - crStart)));
219
- const lineCount = Math.floor(crProgress * entry.lines.length);
220
- const crEl = document.querySelector(entry.selector);
221
- if (crEl) crEl.textContent = entry.lines.slice(0, lineCount).join('\n');
222
-
223
- } else if (entry.kind === 'blink') {
224
- const interval_s = opts.interval || 0.5;
225
- const blinkEl = document.querySelector(entry.selector);
226
- if (blinkEl) {
227
- const cycle = (frame / fps) / interval_s;
228
- blinkEl.style.opacity = (Math.floor(cycle) % 2 === 0) ? 1 : 0;
229
- }
230
- }
231
- });
232
- };
233
-
234
- // === MulmoCast Frame State (updated by Puppeteer per frame) ===
235
- window.__MULMO = {
236
- frame: 0,
237
- totalFrames: ${totalFrames},
238
- fps: ${fps},
239
- };
240
- </script>
241
-
242
- ${user_script}
243
-
244
- <script>
245
- // Auto-render: if MulmoAnimation is used but render() is not defined, generate it
246
- if (typeof render !== 'function' && typeof animation !== 'undefined' && animation instanceof MulmoAnimation) {
247
- window.render = function(frame, totalFrames, fps) { animation.update(frame, fps); };
248
- }
249
-
250
- // Initial render (frame 0)
251
- if (typeof render === 'function') {
252
- const result = render(0, window.__MULMO.totalFrames, window.__MULMO.fps);
253
- if (result && typeof result.then === 'function') {
254
- result.catch(console.error);
255
- }
256
- }
257
-
258
- /**
259
- * Play animation in real-time using requestAnimationFrame.
260
- * Returns a Promise that resolves when all frames have been rendered.
261
- * Called by Puppeteer's page.evaluate() during screencast recording.
262
- */
263
- window.playAnimation = function() {
264
- return new Promise(function(resolve) {
265
- var mulmo = window.__MULMO;
266
- var fps = mulmo.fps;
267
- var totalFrames = mulmo.totalFrames;
268
- var frameDuration = 1000 / fps;
269
- var startTime = null;
270
-
271
- function tick(timestamp) {
272
- if (startTime === null) startTime = timestamp;
273
- var elapsed = timestamp - startTime;
274
- var frame = Math.min(Math.floor(elapsed / frameDuration), totalFrames - 1);
275
-
276
- mulmo.frame = frame;
277
- if (typeof render === 'function') {
278
- render(frame, totalFrames, fps);
279
- }
280
-
281
- if (frame < totalFrames - 1) {
282
- requestAnimationFrame(tick);
283
- } else {
284
- resolve();
285
- }
286
- }
287
-
288
- requestAnimationFrame(tick);
289
- });
290
- };
291
- </script>
292
- </body>
13
+ ${custom_style}
14
+ </style>
15
+ </head>
16
+ <body class="bg-white text-gray-800 h-full flex flex-col">
17
+ ${html_body}
18
+
19
+ <script>
20
+ ${animation_runtime}
21
+
22
+ // === MulmoCast Frame State (updated by Puppeteer per frame) ===
23
+ window.__MULMO = {
24
+ frame: 0,
25
+ totalFrames: ${totalFrames},
26
+ fps: ${fps},
27
+ };
28
+ </script>
29
+
30
+ ${user_script}
31
+
32
+ <script>
33
+ ${data_attribute_registration}
34
+ </script>
35
+
36
+ <script>
37
+ ${auto_render}
38
+ </script>
39
+ </body>
293
40
  </html>
@@ -33,7 +33,7 @@ export const generateReferenceImage = async (inputs) => {
33
33
  },
34
34
  params: {
35
35
  model: imageAgentInfo.imageParams.model,
36
- canvasSize: context.presentationStyle.canvasSize,
36
+ canvasSize: image.canvasSize ?? context.presentationStyle.canvasSize,
37
37
  },
38
38
  },
39
39
  },
@@ -2957,6 +2957,10 @@ export declare const mulmoAudioAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
2957
2957
  export declare const mulmoImagePromptMediaSchema: z.ZodObject<{
2958
2958
  type: z.ZodLiteral<"imagePrompt">;
2959
2959
  prompt: z.ZodString;
2960
+ canvasSize: z.ZodOptional<z.ZodObject<{
2961
+ width: z.ZodNumber;
2962
+ height: z.ZodNumber;
2963
+ }, z.core.$strict>>;
2960
2964
  }, z.core.$strict>;
2961
2965
  export declare const mulmoImageParamsImagesValueSchema: z.ZodUnion<readonly [z.ZodObject<{
2962
2966
  type: z.ZodLiteral<"image">;
@@ -2973,6 +2977,10 @@ export declare const mulmoImageParamsImagesValueSchema: z.ZodUnion<readonly [z.Z
2973
2977
  }, z.core.$strict>, z.ZodObject<{
2974
2978
  type: z.ZodLiteral<"imagePrompt">;
2975
2979
  prompt: z.ZodString;
2980
+ canvasSize: z.ZodOptional<z.ZodObject<{
2981
+ width: z.ZodNumber;
2982
+ height: z.ZodNumber;
2983
+ }, z.core.$strict>>;
2976
2984
  }, z.core.$strict>]>;
2977
2985
  export declare const mulmoImageParamsImagesSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
2978
2986
  type: z.ZodLiteral<"image">;
@@ -2989,6 +2997,10 @@ export declare const mulmoImageParamsImagesSchema: z.ZodRecord<z.ZodString, z.Zo
2989
2997
  }, z.core.$strict>, z.ZodObject<{
2990
2998
  type: z.ZodLiteral<"imagePrompt">;
2991
2999
  prompt: z.ZodString;
3000
+ canvasSize: z.ZodOptional<z.ZodObject<{
3001
+ width: z.ZodNumber;
3002
+ height: z.ZodNumber;
3003
+ }, z.core.$strict>>;
2992
3004
  }, z.core.$strict>]>>;
2993
3005
  export declare const mulmoFillOptionSchema: z.ZodObject<{
2994
3006
  style: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
@@ -3057,6 +3069,10 @@ export declare const mulmoImageParamsSchema: z.ZodObject<{
3057
3069
  }, z.core.$strict>, z.ZodObject<{
3058
3070
  type: z.ZodLiteral<"imagePrompt">;
3059
3071
  prompt: z.ZodString;
3072
+ canvasSize: z.ZodOptional<z.ZodObject<{
3073
+ width: z.ZodNumber;
3074
+ height: z.ZodNumber;
3075
+ }, z.core.$strict>>;
3060
3076
  }, z.core.$strict>]>>>;
3061
3077
  backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
3062
3078
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -6405,6 +6421,10 @@ export declare const mulmoPresentationStyleSchema: z.ZodObject<{
6405
6421
  }, z.core.$strict>, z.ZodObject<{
6406
6422
  type: z.ZodLiteral<"imagePrompt">;
6407
6423
  prompt: z.ZodString;
6424
+ canvasSize: z.ZodOptional<z.ZodObject<{
6425
+ width: z.ZodNumber;
6426
+ height: z.ZodNumber;
6427
+ }, z.core.$strict>>;
6408
6428
  }, z.core.$strict>]>>>;
6409
6429
  backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
6410
6430
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -6861,6 +6881,10 @@ export declare const mulmoScriptSchema: z.ZodObject<{
6861
6881
  }, z.core.$strict>, z.ZodObject<{
6862
6882
  type: z.ZodLiteral<"imagePrompt">;
6863
6883
  prompt: z.ZodString;
6884
+ canvasSize: z.ZodOptional<z.ZodObject<{
6885
+ width: z.ZodNumber;
6886
+ height: z.ZodNumber;
6887
+ }, z.core.$strict>>;
6864
6888
  }, z.core.$strict>]>>>;
6865
6889
  backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
6866
6890
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -10279,6 +10303,10 @@ export declare const mulmoStudioSchema: z.ZodObject<{
10279
10303
  }, z.core.$strict>, z.ZodObject<{
10280
10304
  type: z.ZodLiteral<"imagePrompt">;
10281
10305
  prompt: z.ZodString;
10306
+ canvasSize: z.ZodOptional<z.ZodObject<{
10307
+ width: z.ZodNumber;
10308
+ height: z.ZodNumber;
10309
+ }, z.core.$strict>>;
10282
10310
  }, z.core.$strict>]>>>;
10283
10311
  backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
10284
10312
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -13633,6 +13661,10 @@ export declare const mulmoPromptTemplateSchema: z.ZodObject<{
13633
13661
  }, z.core.$strict>, z.ZodObject<{
13634
13662
  type: z.ZodLiteral<"imagePrompt">;
13635
13663
  prompt: z.ZodString;
13664
+ canvasSize: z.ZodOptional<z.ZodObject<{
13665
+ width: z.ZodNumber;
13666
+ height: z.ZodNumber;
13667
+ }, z.core.$strict>>;
13636
13668
  }, z.core.$strict>]>>>;
13637
13669
  backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
13638
13670
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -14083,6 +14115,10 @@ export declare const mulmoPromptTemplateFileSchema: z.ZodObject<{
14083
14115
  }, z.core.$strict>, z.ZodObject<{
14084
14116
  type: z.ZodLiteral<"imagePrompt">;
14085
14117
  prompt: z.ZodString;
14118
+ canvasSize: z.ZodOptional<z.ZodObject<{
14119
+ width: z.ZodNumber;
14120
+ height: z.ZodNumber;
14121
+ }, z.core.$strict>>;
14086
14122
  }, z.core.$strict>]>>>;
14087
14123
  backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
14088
14124
  source: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -264,6 +264,7 @@ export const mulmoImagePromptMediaSchema = z
264
264
  .object({
265
265
  type: z.literal("imagePrompt"),
266
266
  prompt: z.string().min(1),
267
+ canvasSize: z.object({ width: z.number(), height: z.number() }).strict().optional(),
267
268
  })
268
269
  .strict();
269
270
  export const mulmoImageParamsImagesValueSchema = z.union([mulmoImageMediaSchema, mulmoImagePromptMediaSchema]);
@@ -69,6 +69,10 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
69
69
  } | {
70
70
  type: "imagePrompt";
71
71
  prompt: string;
72
+ canvasSize?: {
73
+ width: number;
74
+ height: number;
75
+ } | undefined;
72
76
  }> | undefined;
73
77
  backgroundImage?: string | {
74
78
  source: {
@@ -2164,6 +2168,10 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
2164
2168
  } | {
2165
2169
  type: "imagePrompt";
2166
2170
  prompt: string;
2171
+ canvasSize?: {
2172
+ width: number;
2173
+ height: number;
2174
+ } | undefined;
2167
2175
  }> | undefined;
2168
2176
  backgroundImage?: string | {
2169
2177
  source: {
@@ -4266,6 +4274,10 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
4266
4274
  } | {
4267
4275
  type: "imagePrompt";
4268
4276
  prompt: string;
4277
+ canvasSize?: {
4278
+ width: number;
4279
+ height: number;
4280
+ } | undefined;
4269
4281
  }> | undefined;
4270
4282
  backgroundImage?: string | {
4271
4283
  source: {
@@ -49,6 +49,7 @@ export declare const blankImagePath: () => string;
49
49
  export declare const blankVerticalImagePath: () => string;
50
50
  export declare const blankSquareImagePath: () => string;
51
51
  export declare const getHTMLFile: (filename: string) => string;
52
+ export declare const getJSFile: (filename: string) => string;
52
53
  export declare const getBaseDirPath: (basedir?: string) => string;
53
54
  export declare const getFullPath: (baseDirPath: string | undefined, file: string) => string;
54
55
  export declare const readScriptTemplateFile: (scriptTemplateFileName: string) => MulmoScript;
package/lib/utils/file.js CHANGED
@@ -158,6 +158,10 @@ export const getHTMLFile = (filename) => {
158
158
  const htmlPath = resolveAssetFile(`./assets/html/${filename}.html`, npmRoot);
159
159
  return fs.readFileSync(htmlPath, "utf-8");
160
160
  };
161
+ export const getJSFile = (filename) => {
162
+ const jsPath = resolveAssetFile(`./assets/html/js/${filename}.js`, npmRoot);
163
+ return fs.readFileSync(jsPath, "utf-8");
164
+ };
161
165
  // for cli
162
166
  export const getBaseDirPath = (basedir) => {
163
167
  if (!basedir) {
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import nodePath from "node:path";
3
3
  import { MulmoBeatMethods } from "../../methods/mulmo_beat.js";
4
- import { getHTMLFile } from "../file.js";
4
+ import { getHTMLFile, getJSFile } from "../file.js";
5
5
  import { renderHTMLToImage, interpolate, renderHTMLToFrames, renderHTMLToVideo } from "../html_render.js";
6
6
  import { framesToVideo } from "../ffmpeg_utils.js";
7
7
  import { parrotingImagePath } from "./utils.js";
@@ -72,6 +72,9 @@ const processHtmlTailwindAnimated = async (params) => {
72
72
  const script = "script" in beat.image ? beat.image.script : undefined;
73
73
  const rawHtmlData = interpolate(template, {
74
74
  html_body: html,
75
+ animation_runtime: getJSFile("animation_runtime"),
76
+ data_attribute_registration: getJSFile("data_attribute_registration"),
77
+ auto_render: getJSFile("auto_render"),
75
78
  user_script: buildUserScript(script),
76
79
  totalFrames: String(totalFrames),
77
80
  fps: String(fps),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "2.4.9",
3
+ "version": "2.5.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",
@@ -24,7 +24,8 @@
24
24
  }
25
25
  },
26
26
  "resolutions": {
27
- "minimatch": "^10.2.4"
27
+ "minimatch": "^10.2.4",
28
+ "yauzl": "^3.2.1"
28
29
  },
29
30
  "bin": {
30
31
  "mulmo": "lib/cli/bin.js",
@@ -56,7 +57,7 @@
56
57
  "pdf": "npx tsx ./src/cli/bin.ts pdf",
57
58
  "test": "rm -f scratchpad/test*.* && npx tsx ./src/audio.ts scripts/test/test.json && npx tsx ./src/images.ts scripts/test/test.json && npx tsx ./src/movie.ts scripts/test/test.json",
58
59
  "ci_test": "cross-env NODE_ENV=test tsx --test --experimental-test-coverage ./test/*/test_*.ts",
59
- "lint": "eslint src test",
60
+ "lint": "eslint src test assets/html/js",
60
61
  "build": "tsc",
61
62
  "build_test": "tsc && git checkout -- lib/*",
62
63
  "cli": "npx tsx ./src/cli/bin.ts",
@@ -68,7 +69,7 @@
68
69
  "story_to_script": "npx tsx ./src/cli/bin.ts tool story_to_script",
69
70
  "whisper": "npx tsx ./src/cli/bin.ts tool whisper",
70
71
  "latest": "yarn upgrade-interactive --latest",
71
- "format": "prettier --write '{src,scripts,assets/templates,assets/styles,draft,ideason,scripts_mag2,proto,test,batch,graphai,output,docs/scripts}/**/*.{ts,json,yaml}'",
72
+ "format": "prettier --write '{src,scripts,assets/templates,assets/styles,assets/html/js,draft,ideason,scripts_mag2,proto,test,batch,graphai,output,docs/scripts}/**/*.{ts,js,json,yaml}'",
72
73
  "deep_research": "npx tsx ./src/tools/deep_research.ts",
73
74
  "template": "npx tsx batch/template2tsobject.ts && yarn run format",
74
75
  "mcp_server": "npx tsx ./src/mcp/server.ts",
@@ -109,9 +110,9 @@
109
110
  "graphai": "^2.0.16",
110
111
  "jsdom": "^28.1.0",
111
112
  "marked": "^17.0.4",
112
- "mulmocast-vision": "^1.0.8",
113
+ "mulmocast-vision": "^1.0.9",
113
114
  "ora": "^9.3.0",
114
- "puppeteer": "^24.39.0",
115
+ "puppeteer": "^24.39.1",
115
116
  "replicate": "^1.4.0",
116
117
  "yaml": "^2.8.2",
117
118
  "yargs": "^18.0.0",