mulmocast 2.4.9 → 2.6.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/html/js/animation_runtime.js +371 -0
- package/assets/html/js/auto_render.js +64 -0
- package/assets/html/js/data_attribute_registration.js +178 -0
- package/assets/html/tailwind_animated.html +37 -290
- package/lib/actions/image_references.js +1 -1
- package/lib/types/schema.d.ts +47 -5
- package/lib/types/schema.js +72 -1
- package/lib/utils/context.d.ts +16 -2
- package/lib/utils/file.d.ts +1 -0
- package/lib/utils/file.js +4 -0
- package/lib/utils/image_plugins/html_tailwind.js +33 -6
- package/lib/utils/swipe_to_html.d.ts +55 -0
- package/lib/utils/swipe_to_html.js +240 -0
- package/package.json +7 -6
- package/scripts/test/images/qa_landscape.jpg +0 -0
- package/scripts/test/images/qa_portrait.png +0 -0
- package/scripts/test/macoro_anime_proto.json +120 -0
- package/scripts/test/macoro_swipe_proto.json +104 -0
- package/scripts/test/macoro_swipe_rich.json +820 -0
- package/scripts/test/test_animated.json +592 -0
- package/scripts/test/test_data_animation.json +149 -0
- package/scripts/test/test_html_cover_pan_zoom_landscape_canvas.json +245 -0
- package/scripts/test/test_html_cover_pan_zoom_portrait_canvas.json +207 -0
- package/scripts/test/test_reference_canvas_size.json +83 -0
|
@@ -1,293 +1,40 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en" class="h-full">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
},
|
package/lib/types/schema.d.ts
CHANGED
|
@@ -372,14 +372,16 @@ export declare const mulmoMermaidMediaSchema: z.ZodObject<{
|
|
|
372
372
|
opacity: z.ZodOptional<z.ZodNumber>;
|
|
373
373
|
}, z.core.$strip>]>>>;
|
|
374
374
|
}, z.core.$strict>;
|
|
375
|
+
export declare const swipeElementSchema: z.ZodType;
|
|
375
376
|
export declare const htmlTailwindAnimationSchema: z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
376
377
|
fps: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
377
378
|
movie: z.ZodOptional<z.ZodBoolean>;
|
|
378
379
|
}, z.core.$strip>]>;
|
|
379
380
|
export declare const mulmoHtmlTailwindMediaSchema: z.ZodObject<{
|
|
380
381
|
type: z.ZodLiteral<"html_tailwind">;
|
|
381
|
-
html: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
382
|
+
html: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
382
383
|
script: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
384
|
+
elements: z.ZodOptional<z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
383
385
|
animation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
384
386
|
fps: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
385
387
|
movie: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -551,8 +553,9 @@ export declare const mulmoImageAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
551
553
|
}, z.core.$strip>]>>>;
|
|
552
554
|
}, z.core.$strict>, z.ZodObject<{
|
|
553
555
|
type: z.ZodLiteral<"html_tailwind">;
|
|
554
|
-
html: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
556
|
+
html: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
555
557
|
script: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
558
|
+
elements: z.ZodOptional<z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
556
559
|
animation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
557
560
|
fps: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
558
561
|
movie: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -2957,6 +2960,10 @@ export declare const mulmoAudioAssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
2957
2960
|
export declare const mulmoImagePromptMediaSchema: z.ZodObject<{
|
|
2958
2961
|
type: z.ZodLiteral<"imagePrompt">;
|
|
2959
2962
|
prompt: z.ZodString;
|
|
2963
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
2964
|
+
width: z.ZodNumber;
|
|
2965
|
+
height: z.ZodNumber;
|
|
2966
|
+
}, z.core.$strict>>;
|
|
2960
2967
|
}, z.core.$strict>;
|
|
2961
2968
|
export declare const mulmoImageParamsImagesValueSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
2962
2969
|
type: z.ZodLiteral<"image">;
|
|
@@ -2973,6 +2980,10 @@ export declare const mulmoImageParamsImagesValueSchema: z.ZodUnion<readonly [z.Z
|
|
|
2973
2980
|
}, z.core.$strict>, z.ZodObject<{
|
|
2974
2981
|
type: z.ZodLiteral<"imagePrompt">;
|
|
2975
2982
|
prompt: z.ZodString;
|
|
2983
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
2984
|
+
width: z.ZodNumber;
|
|
2985
|
+
height: z.ZodNumber;
|
|
2986
|
+
}, z.core.$strict>>;
|
|
2976
2987
|
}, z.core.$strict>]>;
|
|
2977
2988
|
export declare const mulmoImageParamsImagesSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
2978
2989
|
type: z.ZodLiteral<"image">;
|
|
@@ -2989,6 +3000,10 @@ export declare const mulmoImageParamsImagesSchema: z.ZodRecord<z.ZodString, z.Zo
|
|
|
2989
3000
|
}, z.core.$strict>, z.ZodObject<{
|
|
2990
3001
|
type: z.ZodLiteral<"imagePrompt">;
|
|
2991
3002
|
prompt: z.ZodString;
|
|
3003
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
3004
|
+
width: z.ZodNumber;
|
|
3005
|
+
height: z.ZodNumber;
|
|
3006
|
+
}, z.core.$strict>>;
|
|
2992
3007
|
}, z.core.$strict>]>>;
|
|
2993
3008
|
export declare const mulmoFillOptionSchema: z.ZodObject<{
|
|
2994
3009
|
style: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
@@ -3057,6 +3072,10 @@ export declare const mulmoImageParamsSchema: z.ZodObject<{
|
|
|
3057
3072
|
}, z.core.$strict>, z.ZodObject<{
|
|
3058
3073
|
type: z.ZodLiteral<"imagePrompt">;
|
|
3059
3074
|
prompt: z.ZodString;
|
|
3075
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
3076
|
+
width: z.ZodNumber;
|
|
3077
|
+
height: z.ZodNumber;
|
|
3078
|
+
}, z.core.$strict>>;
|
|
3060
3079
|
}, z.core.$strict>]>>>;
|
|
3061
3080
|
backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
3062
3081
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -3605,8 +3624,9 @@ export declare const mulmoBeatSchema: z.ZodObject<{
|
|
|
3605
3624
|
}, z.core.$strip>]>>>;
|
|
3606
3625
|
}, z.core.$strict>, z.ZodObject<{
|
|
3607
3626
|
type: z.ZodLiteral<"html_tailwind">;
|
|
3608
|
-
html: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
3627
|
+
html: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
3609
3628
|
script: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
3629
|
+
elements: z.ZodOptional<z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
3610
3630
|
animation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
3611
3631
|
fps: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
3612
3632
|
movie: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -6405,6 +6425,10 @@ export declare const mulmoPresentationStyleSchema: z.ZodObject<{
|
|
|
6405
6425
|
}, z.core.$strict>, z.ZodObject<{
|
|
6406
6426
|
type: z.ZodLiteral<"imagePrompt">;
|
|
6407
6427
|
prompt: z.ZodString;
|
|
6428
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
6429
|
+
width: z.ZodNumber;
|
|
6430
|
+
height: z.ZodNumber;
|
|
6431
|
+
}, z.core.$strict>>;
|
|
6408
6432
|
}, z.core.$strict>]>>>;
|
|
6409
6433
|
backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
6410
6434
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -6861,6 +6885,10 @@ export declare const mulmoScriptSchema: z.ZodObject<{
|
|
|
6861
6885
|
}, z.core.$strict>, z.ZodObject<{
|
|
6862
6886
|
type: z.ZodLiteral<"imagePrompt">;
|
|
6863
6887
|
prompt: z.ZodString;
|
|
6888
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
6889
|
+
width: z.ZodNumber;
|
|
6890
|
+
height: z.ZodNumber;
|
|
6891
|
+
}, z.core.$strict>>;
|
|
6864
6892
|
}, z.core.$strict>]>>>;
|
|
6865
6893
|
backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
6866
6894
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -7404,8 +7432,9 @@ export declare const mulmoScriptSchema: z.ZodObject<{
|
|
|
7404
7432
|
}, z.core.$strip>]>>>;
|
|
7405
7433
|
}, z.core.$strict>, z.ZodObject<{
|
|
7406
7434
|
type: z.ZodLiteral<"html_tailwind">;
|
|
7407
|
-
html: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
7435
|
+
html: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
7408
7436
|
script: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
7437
|
+
elements: z.ZodOptional<z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
7409
7438
|
animation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
7410
7439
|
fps: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
7411
7440
|
movie: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -10279,6 +10308,10 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
10279
10308
|
}, z.core.$strict>, z.ZodObject<{
|
|
10280
10309
|
type: z.ZodLiteral<"imagePrompt">;
|
|
10281
10310
|
prompt: z.ZodString;
|
|
10311
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
10312
|
+
width: z.ZodNumber;
|
|
10313
|
+
height: z.ZodNumber;
|
|
10314
|
+
}, z.core.$strict>>;
|
|
10282
10315
|
}, z.core.$strict>]>>>;
|
|
10283
10316
|
backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
10284
10317
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -10822,8 +10855,9 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
10822
10855
|
}, z.core.$strip>]>>>;
|
|
10823
10856
|
}, z.core.$strict>, z.ZodObject<{
|
|
10824
10857
|
type: z.ZodLiteral<"html_tailwind">;
|
|
10825
|
-
html: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
10858
|
+
html: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
10826
10859
|
script: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
10860
|
+
elements: z.ZodOptional<z.ZodArray<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
10827
10861
|
animation: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodObject<{
|
|
10828
10862
|
fps: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
10829
10863
|
movie: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -13633,6 +13667,10 @@ export declare const mulmoPromptTemplateSchema: z.ZodObject<{
|
|
|
13633
13667
|
}, z.core.$strict>, z.ZodObject<{
|
|
13634
13668
|
type: z.ZodLiteral<"imagePrompt">;
|
|
13635
13669
|
prompt: z.ZodString;
|
|
13670
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
13671
|
+
width: z.ZodNumber;
|
|
13672
|
+
height: z.ZodNumber;
|
|
13673
|
+
}, z.core.$strict>>;
|
|
13636
13674
|
}, z.core.$strict>]>>>;
|
|
13637
13675
|
backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
13638
13676
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -14083,6 +14121,10 @@ export declare const mulmoPromptTemplateFileSchema: z.ZodObject<{
|
|
|
14083
14121
|
}, z.core.$strict>, z.ZodObject<{
|
|
14084
14122
|
type: z.ZodLiteral<"imagePrompt">;
|
|
14085
14123
|
prompt: z.ZodString;
|
|
14124
|
+
canvasSize: z.ZodOptional<z.ZodObject<{
|
|
14125
|
+
width: z.ZodNumber;
|
|
14126
|
+
height: z.ZodNumber;
|
|
14127
|
+
}, z.core.$strict>>;
|
|
14086
14128
|
}, z.core.$strict>]>>>;
|
|
14087
14129
|
backgroundImage: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
14088
14130
|
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
package/lib/types/schema.js
CHANGED
|
@@ -194,6 +194,72 @@ export const mulmoMermaidMediaSchema = z
|
|
|
194
194
|
backgroundImage: backgroundImageSchema,
|
|
195
195
|
})
|
|
196
196
|
.strict();
|
|
197
|
+
// Swipe-inspired element animation schemas
|
|
198
|
+
const swipePositionValue = z.union([z.number(), z.string()]);
|
|
199
|
+
const swipeTransitionSchema = z
|
|
200
|
+
.object({
|
|
201
|
+
opacity: z.number().min(0).max(1).optional(),
|
|
202
|
+
rotate: z.number().optional(),
|
|
203
|
+
scale: z.union([z.number(), z.tuple([z.number(), z.number()])]).optional(),
|
|
204
|
+
translate: z.tuple([z.number(), z.number()]).optional(),
|
|
205
|
+
bc: z.string().optional(),
|
|
206
|
+
timing: z.tuple([z.number(), z.number()]).default([0, 1]).optional().describe("Animation timing [start, end] as ratio 0.0-1.0 of beat duration"),
|
|
207
|
+
})
|
|
208
|
+
.strict();
|
|
209
|
+
const swipeLoopSchema = z
|
|
210
|
+
.object({
|
|
211
|
+
style: z.enum(["vibrate", "blink", "wiggle", "spin", "shift", "bounce", "pulse"]),
|
|
212
|
+
count: z.number().optional().describe("Number of loop iterations. 0 = infinite"),
|
|
213
|
+
delta: z.number().optional().describe("Distance for vibrate / angle for wiggle"),
|
|
214
|
+
duration: z.number().optional().describe("Duration of one cycle in seconds"),
|
|
215
|
+
direction: z.enum(["n", "s", "e", "w"]).optional().describe("Direction for shift animation"),
|
|
216
|
+
clockwise: z.boolean().optional().describe("Spin direction. Default: true"),
|
|
217
|
+
})
|
|
218
|
+
.strict();
|
|
219
|
+
const swipeShadowSchema = z
|
|
220
|
+
.object({
|
|
221
|
+
color: z.string().optional().default("black"),
|
|
222
|
+
offset: z.tuple([z.number(), z.number()]).optional().default([1, 1]),
|
|
223
|
+
opacity: z.number().optional().default(0.5),
|
|
224
|
+
radius: z.number().optional().default(1),
|
|
225
|
+
})
|
|
226
|
+
.strict();
|
|
227
|
+
export const swipeElementSchema = z.lazy(() => z
|
|
228
|
+
.object({
|
|
229
|
+
id: z.string().optional(),
|
|
230
|
+
// Position & size
|
|
231
|
+
x: swipePositionValue.optional(),
|
|
232
|
+
y: swipePositionValue.optional(),
|
|
233
|
+
w: swipePositionValue.optional(),
|
|
234
|
+
h: swipePositionValue.optional(),
|
|
235
|
+
pos: z.tuple([swipePositionValue, swipePositionValue]).optional().describe("Position by anchor point [x, y]"),
|
|
236
|
+
// Visual
|
|
237
|
+
bc: z.string().optional().describe("Background color"),
|
|
238
|
+
opacity: z.number().min(0).max(1).optional(),
|
|
239
|
+
rotate: z.number().optional(),
|
|
240
|
+
scale: z.union([z.number(), z.tuple([z.number(), z.number()])]).optional(),
|
|
241
|
+
translate: z.tuple([z.number(), z.number()]).optional(),
|
|
242
|
+
cornerRadius: z.number().optional(),
|
|
243
|
+
borderWidth: z.number().optional(),
|
|
244
|
+
borderColor: z.string().optional(),
|
|
245
|
+
shadow: swipeShadowSchema.optional(),
|
|
246
|
+
clip: z.boolean().optional(),
|
|
247
|
+
// Content
|
|
248
|
+
text: z.string().optional(),
|
|
249
|
+
fontSize: z.union([z.number(), z.string()]).optional(),
|
|
250
|
+
fontWeight: z.string().optional(),
|
|
251
|
+
textColor: z.string().optional(),
|
|
252
|
+
textAlign: z.enum(["center", "left", "right"]).optional(),
|
|
253
|
+
lineHeight: z.union([z.number(), z.string()]).optional(),
|
|
254
|
+
img: z.string().optional().describe("Image URL or image:ref"),
|
|
255
|
+
imgFit: z.enum(["contain", "cover", "fill"]).optional().default("contain"),
|
|
256
|
+
// Animation
|
|
257
|
+
to: swipeTransitionSchema.optional().describe("Transition animation"),
|
|
258
|
+
loop: swipeLoopSchema.optional().describe("Loop animation"),
|
|
259
|
+
// Children
|
|
260
|
+
elements: z.array(z.lazy(() => swipeElementSchema)).optional(),
|
|
261
|
+
})
|
|
262
|
+
.strict());
|
|
197
263
|
export const htmlTailwindAnimationSchema = z.union([
|
|
198
264
|
z.literal(true),
|
|
199
265
|
z.object({
|
|
@@ -204,8 +270,12 @@ export const htmlTailwindAnimationSchema = z.union([
|
|
|
204
270
|
export const mulmoHtmlTailwindMediaSchema = z
|
|
205
271
|
.object({
|
|
206
272
|
type: z.literal("html_tailwind"),
|
|
207
|
-
html: stringOrStringArray,
|
|
273
|
+
html: stringOrStringArray.optional(),
|
|
208
274
|
script: stringOrStringArray.optional().describe("JavaScript code for the beat. Injected as a <script> tag after html. Use for render() function etc."),
|
|
275
|
+
elements: z
|
|
276
|
+
.array(swipeElementSchema)
|
|
277
|
+
.optional()
|
|
278
|
+
.describe("Swipe-style declarative animation elements. Converted to HTML + render() automatically. Use this OR html, not both."),
|
|
209
279
|
animation: htmlTailwindAnimationSchema
|
|
210
280
|
.optional()
|
|
211
281
|
.describe("Enable frame-based animation (Remotion-style). true for defaults (30fps), or { fps: N } for custom frame rate."),
|
|
@@ -264,6 +334,7 @@ export const mulmoImagePromptMediaSchema = z
|
|
|
264
334
|
.object({
|
|
265
335
|
type: z.literal("imagePrompt"),
|
|
266
336
|
prompt: z.string().min(1),
|
|
337
|
+
canvasSize: z.object({ width: z.number(), height: z.number() }).strict().optional(),
|
|
267
338
|
})
|
|
268
339
|
.strict();
|
|
269
340
|
export const mulmoImageParamsImagesValueSchema = z.union([mulmoImageMediaSchema, mulmoImagePromptMediaSchema]);
|
package/lib/utils/context.d.ts
CHANGED
|
@@ -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: {
|
|
@@ -1721,8 +1725,9 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
|
|
|
1721
1725
|
} | null | undefined;
|
|
1722
1726
|
} | {
|
|
1723
1727
|
type: "html_tailwind";
|
|
1724
|
-
html
|
|
1728
|
+
html?: string | string[] | undefined;
|
|
1725
1729
|
script?: string | string[] | undefined;
|
|
1730
|
+
elements?: unknown[] | undefined;
|
|
1726
1731
|
animation?: true | {
|
|
1727
1732
|
fps: number;
|
|
1728
1733
|
movie?: boolean | undefined;
|
|
@@ -2164,6 +2169,10 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
2164
2169
|
} | {
|
|
2165
2170
|
type: "imagePrompt";
|
|
2166
2171
|
prompt: string;
|
|
2172
|
+
canvasSize?: {
|
|
2173
|
+
width: number;
|
|
2174
|
+
height: number;
|
|
2175
|
+
} | undefined;
|
|
2167
2176
|
}> | undefined;
|
|
2168
2177
|
backgroundImage?: string | {
|
|
2169
2178
|
source: {
|
|
@@ -3816,8 +3825,9 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
3816
3825
|
} | null | undefined;
|
|
3817
3826
|
} | {
|
|
3818
3827
|
type: "html_tailwind";
|
|
3819
|
-
html
|
|
3828
|
+
html?: string | string[] | undefined;
|
|
3820
3829
|
script?: string | string[] | undefined;
|
|
3830
|
+
elements?: unknown[] | undefined;
|
|
3821
3831
|
animation?: true | {
|
|
3822
3832
|
fps: number;
|
|
3823
3833
|
movie?: boolean | undefined;
|
|
@@ -4266,6 +4276,10 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
4266
4276
|
} | {
|
|
4267
4277
|
type: "imagePrompt";
|
|
4268
4278
|
prompt: string;
|
|
4279
|
+
canvasSize?: {
|
|
4280
|
+
width: number;
|
|
4281
|
+
height: number;
|
|
4282
|
+
} | undefined;
|
|
4269
4283
|
}> | undefined;
|
|
4270
4284
|
backgroundImage?: string | {
|
|
4271
4285
|
source: {
|
package/lib/utils/file.d.ts
CHANGED
|
@@ -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) {
|