@studiomeyer/mcp-video 1.0.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 (184) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  3. package/.github/workflows/ci.yml +34 -0
  4. package/CHANGELOG.md +24 -0
  5. package/CONTRIBUTING.md +75 -0
  6. package/LICENSE +21 -0
  7. package/README.md +198 -0
  8. package/USAGE.md +144 -0
  9. package/dist/handlers/capcut.d.ts +6 -0
  10. package/dist/handlers/capcut.js +229 -0
  11. package/dist/handlers/capcut.js.map +1 -0
  12. package/dist/handlers/editing.d.ts +6 -0
  13. package/dist/handlers/editing.js +242 -0
  14. package/dist/handlers/editing.js.map +1 -0
  15. package/dist/handlers/index.d.ts +2 -0
  16. package/dist/handlers/index.js +33 -0
  17. package/dist/handlers/index.js.map +1 -0
  18. package/dist/handlers/post-production.d.ts +5 -0
  19. package/dist/handlers/post-production.js +109 -0
  20. package/dist/handlers/post-production.js.map +1 -0
  21. package/dist/handlers/smart-screenshot.d.ts +5 -0
  22. package/dist/handlers/smart-screenshot.js +83 -0
  23. package/dist/handlers/smart-screenshot.js.map +1 -0
  24. package/dist/handlers/tts.d.ts +5 -0
  25. package/dist/handlers/tts.js +83 -0
  26. package/dist/handlers/tts.js.map +1 -0
  27. package/dist/handlers/video.d.ts +5 -0
  28. package/dist/handlers/video.js +127 -0
  29. package/dist/handlers/video.js.map +1 -0
  30. package/dist/lib/dual-transport.d.ts +42 -0
  31. package/dist/lib/dual-transport.js +208 -0
  32. package/dist/lib/dual-transport.js.map +1 -0
  33. package/dist/lib/logger.d.ts +12 -0
  34. package/dist/lib/logger.js +42 -0
  35. package/dist/lib/logger.js.map +1 -0
  36. package/dist/lib/types.d.ts +16 -0
  37. package/dist/lib/types.js +15 -0
  38. package/dist/lib/types.js.map +1 -0
  39. package/dist/schemas/capcut.d.ts +608 -0
  40. package/dist/schemas/capcut.js +411 -0
  41. package/dist/schemas/capcut.js.map +1 -0
  42. package/dist/schemas/editing.d.ts +822 -0
  43. package/dist/schemas/editing.js +466 -0
  44. package/dist/schemas/editing.js.map +1 -0
  45. package/dist/schemas/index.d.ts +2366 -0
  46. package/dist/schemas/index.js +15 -0
  47. package/dist/schemas/index.js.map +1 -0
  48. package/dist/schemas/post-production.d.ts +379 -0
  49. package/dist/schemas/post-production.js +268 -0
  50. package/dist/schemas/post-production.js.map +1 -0
  51. package/dist/schemas/smart-screenshot.d.ts +127 -0
  52. package/dist/schemas/smart-screenshot.js +122 -0
  53. package/dist/schemas/smart-screenshot.js.map +1 -0
  54. package/dist/schemas/tts.d.ts +220 -0
  55. package/dist/schemas/tts.js +194 -0
  56. package/dist/schemas/tts.js.map +1 -0
  57. package/dist/schemas/video.d.ts +236 -0
  58. package/dist/schemas/video.js +210 -0
  59. package/dist/schemas/video.js.map +1 -0
  60. package/dist/server.d.ts +11 -0
  61. package/dist/server.js +239 -0
  62. package/dist/server.js.map +1 -0
  63. package/dist/server.test.d.ts +1 -0
  64. package/dist/server.test.js +87 -0
  65. package/dist/server.test.js.map +1 -0
  66. package/dist/tools/engine/audio-mixer.d.ts +40 -0
  67. package/dist/tools/engine/audio-mixer.js +169 -0
  68. package/dist/tools/engine/audio-mixer.js.map +1 -0
  69. package/dist/tools/engine/audio.d.ts +22 -0
  70. package/dist/tools/engine/audio.js +73 -0
  71. package/dist/tools/engine/audio.js.map +1 -0
  72. package/dist/tools/engine/beat-sync.d.ts +31 -0
  73. package/dist/tools/engine/beat-sync.js +270 -0
  74. package/dist/tools/engine/beat-sync.js.map +1 -0
  75. package/dist/tools/engine/capture.d.ts +12 -0
  76. package/dist/tools/engine/capture.js +290 -0
  77. package/dist/tools/engine/capture.js.map +1 -0
  78. package/dist/tools/engine/chroma-key.d.ts +27 -0
  79. package/dist/tools/engine/chroma-key.js +154 -0
  80. package/dist/tools/engine/chroma-key.js.map +1 -0
  81. package/dist/tools/engine/concat.d.ts +49 -0
  82. package/dist/tools/engine/concat.js +149 -0
  83. package/dist/tools/engine/concat.js.map +1 -0
  84. package/dist/tools/engine/cursor.d.ts +26 -0
  85. package/dist/tools/engine/cursor.js +185 -0
  86. package/dist/tools/engine/cursor.js.map +1 -0
  87. package/dist/tools/engine/easing.d.ts +15 -0
  88. package/dist/tools/engine/easing.js +100 -0
  89. package/dist/tools/engine/easing.js.map +1 -0
  90. package/dist/tools/engine/editing.d.ts +158 -0
  91. package/dist/tools/engine/editing.js +541 -0
  92. package/dist/tools/engine/editing.js.map +1 -0
  93. package/dist/tools/engine/encoder.d.ts +31 -0
  94. package/dist/tools/engine/encoder.js +154 -0
  95. package/dist/tools/engine/encoder.js.map +1 -0
  96. package/dist/tools/engine/index.d.ts +30 -0
  97. package/dist/tools/engine/index.js +23 -0
  98. package/dist/tools/engine/index.js.map +1 -0
  99. package/dist/tools/engine/lut-presets.d.ts +25 -0
  100. package/dist/tools/engine/lut-presets.js +141 -0
  101. package/dist/tools/engine/lut-presets.js.map +1 -0
  102. package/dist/tools/engine/narrated-video.d.ts +63 -0
  103. package/dist/tools/engine/narrated-video.js +163 -0
  104. package/dist/tools/engine/narrated-video.js.map +1 -0
  105. package/dist/tools/engine/scenes.d.ts +17 -0
  106. package/dist/tools/engine/scenes.js +223 -0
  107. package/dist/tools/engine/scenes.js.map +1 -0
  108. package/dist/tools/engine/smart-screenshot.d.ts +80 -0
  109. package/dist/tools/engine/smart-screenshot.js +744 -0
  110. package/dist/tools/engine/smart-screenshot.js.map +1 -0
  111. package/dist/tools/engine/social-format.d.ts +66 -0
  112. package/dist/tools/engine/social-format.js +107 -0
  113. package/dist/tools/engine/social-format.js.map +1 -0
  114. package/dist/tools/engine/template-renderer.d.ts +45 -0
  115. package/dist/tools/engine/template-renderer.js +233 -0
  116. package/dist/tools/engine/template-renderer.js.map +1 -0
  117. package/dist/tools/engine/templates.d.ts +87 -0
  118. package/dist/tools/engine/templates.js +272 -0
  119. package/dist/tools/engine/templates.js.map +1 -0
  120. package/dist/tools/engine/text-animations.d.ts +33 -0
  121. package/dist/tools/engine/text-animations.js +192 -0
  122. package/dist/tools/engine/text-animations.js.map +1 -0
  123. package/dist/tools/engine/text-overlay.d.ts +27 -0
  124. package/dist/tools/engine/text-overlay.js +84 -0
  125. package/dist/tools/engine/text-overlay.js.map +1 -0
  126. package/dist/tools/engine/tts.d.ts +54 -0
  127. package/dist/tools/engine/tts.js +186 -0
  128. package/dist/tools/engine/tts.js.map +1 -0
  129. package/dist/tools/engine/types.d.ts +166 -0
  130. package/dist/tools/engine/types.js +13 -0
  131. package/dist/tools/engine/types.js.map +1 -0
  132. package/dist/tools/engine/voice-effects.d.ts +18 -0
  133. package/dist/tools/engine/voice-effects.js +215 -0
  134. package/dist/tools/engine/voice-effects.js.map +1 -0
  135. package/dist/tools/index.d.ts +32 -0
  136. package/dist/tools/index.js +23 -0
  137. package/dist/tools/index.js.map +1 -0
  138. package/package.json +56 -0
  139. package/scripts/check-deps.js +39 -0
  140. package/src/handlers/capcut.ts +245 -0
  141. package/src/handlers/editing.ts +260 -0
  142. package/src/handlers/index.ts +34 -0
  143. package/src/handlers/post-production.ts +136 -0
  144. package/src/handlers/smart-screenshot.ts +86 -0
  145. package/src/handlers/tts.ts +103 -0
  146. package/src/handlers/video.ts +137 -0
  147. package/src/lib/dual-transport.ts +272 -0
  148. package/src/lib/logger.ts +59 -0
  149. package/src/lib/types.ts +25 -0
  150. package/src/schemas/capcut.ts +418 -0
  151. package/src/schemas/editing.ts +476 -0
  152. package/src/schemas/index.ts +15 -0
  153. package/src/schemas/post-production.ts +273 -0
  154. package/src/schemas/smart-screenshot.ts +122 -0
  155. package/src/schemas/tts.ts +197 -0
  156. package/src/schemas/video.ts +211 -0
  157. package/src/server.test.ts +99 -0
  158. package/src/server.ts +289 -0
  159. package/src/tools/engine/audio-mixer.ts +244 -0
  160. package/src/tools/engine/audio.ts +115 -0
  161. package/src/tools/engine/beat-sync.ts +356 -0
  162. package/src/tools/engine/capture.ts +360 -0
  163. package/src/tools/engine/chroma-key.ts +202 -0
  164. package/src/tools/engine/concat.ts +242 -0
  165. package/src/tools/engine/cursor.ts +222 -0
  166. package/src/tools/engine/easing.ts +120 -0
  167. package/src/tools/engine/editing.ts +809 -0
  168. package/src/tools/engine/encoder.ts +208 -0
  169. package/src/tools/engine/index.ts +33 -0
  170. package/src/tools/engine/lut-presets.ts +235 -0
  171. package/src/tools/engine/narrated-video.ts +267 -0
  172. package/src/tools/engine/scenes.ts +309 -0
  173. package/src/tools/engine/smart-screenshot.ts +923 -0
  174. package/src/tools/engine/social-format.ts +146 -0
  175. package/src/tools/engine/template-renderer.ts +294 -0
  176. package/src/tools/engine/templates.ts +370 -0
  177. package/src/tools/engine/text-animations.ts +282 -0
  178. package/src/tools/engine/text-overlay.ts +143 -0
  179. package/src/tools/engine/tts.ts +284 -0
  180. package/src/tools/engine/types.ts +191 -0
  181. package/src/tools/engine/voice-effects.ts +258 -0
  182. package/src/tools/index.ts +67 -0
  183. package/tsconfig.json +19 -0
  184. package/vitest.config.ts +7 -0
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Voice Effects Engine — 9 audio effects via FFmpeg filter chains.
3
+ *
4
+ * Effects: echo, reverb, deep, chipmunk, robot, whisper, radio, megaphone, underwater.
5
+ * Works on both audio files and video files (preserves video stream).
6
+ */
7
+
8
+ import { execFile } from 'child_process';
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import { logger } from '../../lib/logger.js';
12
+
13
+ // ─── Types ──────────────────────────────────────────────────────────
14
+
15
+ export type VoiceEffect =
16
+ | 'echo'
17
+ | 'reverb'
18
+ | 'deep'
19
+ | 'chipmunk'
20
+ | 'robot'
21
+ | 'whisper'
22
+ | 'radio'
23
+ | 'megaphone'
24
+ | 'underwater';
25
+
26
+ export interface VoiceEffectConfig {
27
+ inputPath: string;
28
+ outputPath: string;
29
+ /** Voice effect to apply */
30
+ effect: VoiceEffect;
31
+ /** Intensity 0.0-1.0 (default: 0.5). Controls how strong the effect is. */
32
+ intensity?: number;
33
+ }
34
+
35
+ export const ALL_VOICE_EFFECTS: VoiceEffect[] = [
36
+ 'echo', 'reverb', 'deep', 'chipmunk', 'robot',
37
+ 'whisper', 'radio', 'megaphone', 'underwater',
38
+ ];
39
+
40
+ export const VOICE_EFFECT_DESCRIPTIONS: Record<VoiceEffect, string> = {
41
+ echo: 'Indoor/outdoor echo with configurable delay',
42
+ reverb: 'Dense multi-tap reverb (hall-like)',
43
+ deep: 'Lower pitch — deep/bass voice',
44
+ chipmunk: 'Higher pitch — chipmunk/squeaky voice',
45
+ robot: 'Metallic robotic voice (phase zeroing)',
46
+ whisper: 'Breathy whisper effect with randomized phase',
47
+ radio: 'AM radio / telephone quality (bandpass)',
48
+ megaphone: 'Distorted megaphone with resonance',
49
+ underwater: 'Muffled underwater sound (heavy lowpass)',
50
+ };
51
+
52
+ // ─── Effect Filter Builders ─────────────────────────────────────────
53
+
54
+ function getEffectFilter(effect: VoiceEffect, intensity: number): { filter: string; needsComplexPitch?: boolean; pitchFactor?: number } {
55
+ const i = Math.max(0, Math.min(1, intensity));
56
+
57
+ switch (effect) {
58
+ case 'echo': {
59
+ // Scale delay and decay with intensity
60
+ const delay1 = Math.round(30 + i * 470); // 30-500ms
61
+ const delay2 = Math.round(60 + i * 940); // 60-1000ms
62
+ const decay1 = (0.2 + i * 0.3).toFixed(2); // 0.2-0.5
63
+ const decay2 = (0.1 + i * 0.2).toFixed(2); // 0.1-0.3
64
+ return { filter: `aecho=0.8:0.9:${delay1}|${delay2}:${decay1}|${decay2}` };
65
+ }
66
+
67
+ case 'reverb': {
68
+ // Dense multi-tap approximation of reverb
69
+ const taps = Math.round(3 + i * 7); // 3-10 taps
70
+ const delays: string[] = [];
71
+ const decays: string[] = [];
72
+ for (let t = 1; t <= taps; t++) {
73
+ delays.push(String(Math.round(t * 20)));
74
+ decays.push((0.6 - t * (0.5 / taps)).toFixed(2));
75
+ }
76
+ return { filter: `aecho=0.8:0.9:${delays.join('|')}:${decays.join('|')}` };
77
+ }
78
+
79
+ case 'deep': {
80
+ // Lower pitch: factor < 1.0 lowers pitch
81
+ // Intensity 0.0 → factor 0.95 (subtle), 1.0 → factor 0.5 (very deep)
82
+ const factor = 0.95 - i * 0.45; // 0.95 → 0.5
83
+ return { filter: '', needsComplexPitch: true, pitchFactor: factor };
84
+ }
85
+
86
+ case 'chipmunk': {
87
+ // Higher pitch: factor > 1.0 raises pitch
88
+ // Intensity 0.0 → factor 1.1 (subtle), 1.0 → factor 2.0 (extreme)
89
+ const factor = 1.1 + i * 0.9; // 1.1 → 2.0
90
+ return { filter: '', needsComplexPitch: true, pitchFactor: factor };
91
+ }
92
+
93
+ case 'robot': {
94
+ // Phase zeroing creates metallic robot effect
95
+ // At lower intensity, mix with short echo for metallic quality
96
+ if (i > 0.5) {
97
+ return { filter: "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=512:overlap=0.75" };
98
+ }
99
+ // Lighter robot via very short echo
100
+ const delay = Math.round(3 + i * 10);
101
+ return { filter: `aecho=0.8:0.88:${delay}:${(0.3 + i * 0.3).toFixed(2)}` };
102
+ }
103
+
104
+ case 'whisper': {
105
+ if (i > 0.5) {
106
+ // Full whisper via phase randomization
107
+ return { filter: "afftfilt=real='hypot(re,im)*cos((random(0)*2-1)*2*3.14)':imag='hypot(re,im)*sin((random(1)*2-1)*2*3.14)':win_size=128:overlap=0.8" };
108
+ }
109
+ // Lighter whisper via filtering
110
+ const vol = (0.6 - i * 0.3).toFixed(2);
111
+ return { filter: `highpass=f=1000,lowpass=f=4000,volume=${vol}` };
112
+ }
113
+
114
+ case 'radio': {
115
+ // Bandpass gets narrower with intensity
116
+ const lowCut = Math.round(200 + i * 400); // 200-600 Hz
117
+ const highCut = Math.round(4000 - i * 2000); // 4000-2000 Hz
118
+ const crush = i > 0.5 ? `,acrusher=bits=${Math.round(12 - i * 6)}:mode=log:aa=1` : '';
119
+ return { filter: `highpass=f=${lowCut},lowpass=f=${highCut}${crush}` };
120
+ }
121
+
122
+ case 'megaphone': {
123
+ const bits = Math.round(12 - i * 6); // 12→6 bits
124
+ const vol = (1.5 + i * 1.0).toFixed(1);
125
+ return { filter: `highpass=f=500,lowpass=f=4000,acrusher=bits=${bits}:mode=log:aa=1:samples=1,aecho=0.8:0.88:10:${(0.3 + i * 0.3).toFixed(2)},volume=${vol}` };
126
+ }
127
+
128
+ case 'underwater': {
129
+ // Lowpass gets more extreme with intensity
130
+ const cutoff = Math.round(500 - i * 350); // 500→150 Hz
131
+ const vol = (0.9 - i * 0.3).toFixed(2);
132
+ const wobble = i > 0.3 ? `,flanger=delay=5:depth=${Math.round(1 + i * 4)}:speed=0.3` : '';
133
+ return { filter: `lowpass=f=${cutoff}${wobble},volume=${vol}` };
134
+ }
135
+
136
+ default:
137
+ throw new Error(`Unknown voice effect: ${effect}`);
138
+ }
139
+ }
140
+
141
+ // ─── Helpers ────────────────────────────────────────────────────────
142
+
143
+ function runFfmpeg(args: string[], timeoutMs = 300_000): Promise<string> {
144
+ return new Promise((resolve, reject) => {
145
+ execFile('ffmpeg', args, { maxBuffer: 100 * 1024 * 1024, timeout: timeoutMs }, (error, stdout, stderr) => {
146
+ if (error) {
147
+ logger.error(`ffmpeg failed: ${stderr}`);
148
+ reject(new Error(`ffmpeg failed: ${stderr || error.message}`));
149
+ return;
150
+ }
151
+ resolve(stdout);
152
+ });
153
+ });
154
+ }
155
+
156
+ function runFfprobe(args: string[]): Promise<string> {
157
+ return new Promise((resolve, reject) => {
158
+ execFile('ffprobe', args, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout) => {
159
+ if (error) { reject(new Error(`ffprobe failed: ${error.message}`)); return; }
160
+ resolve(stdout.trim());
161
+ });
162
+ });
163
+ }
164
+
165
+ function ensureDir(filePath: string): void {
166
+ const dir = path.dirname(filePath);
167
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
168
+ }
169
+
170
+ function assertExists(filePath: string, label = 'File'): void {
171
+ if (!fs.existsSync(filePath)) throw new Error(`${label} not found: ${filePath}`);
172
+ }
173
+
174
+ function fileInfo(filePath: string): string {
175
+ const stats = fs.statSync(filePath);
176
+ return `${(stats.size / 1024 / 1024).toFixed(2)} MB`;
177
+ }
178
+
179
+ async function hasVideoStream(filePath: string): Promise<boolean> {
180
+ try {
181
+ const result = await runFfprobe(['-v', 'quiet', '-select_streams', 'v', '-show_entries', 'stream=codec_type', '-of', 'csv=p=0', filePath]);
182
+ return result.length > 0;
183
+ } catch { return false; }
184
+ }
185
+
186
+ async function getSampleRate(filePath: string): Promise<number> {
187
+ try {
188
+ const result = await runFfprobe(['-v', 'quiet', '-select_streams', 'a:0', '-show_entries', 'stream=sample_rate', '-of', 'csv=p=0', filePath]);
189
+ const rate = parseInt(result, 10);
190
+ return isNaN(rate) ? 44100 : rate;
191
+ } catch { return 44100; }
192
+ }
193
+
194
+ /** Build chained atempo filters (each must be 0.5-100.0 range) */
195
+ function buildAtempoChain(speed: number): string {
196
+ const filters: string[] = [];
197
+ let remaining = speed;
198
+
199
+ while (remaining > 2.0) {
200
+ filters.push('atempo=2.0');
201
+ remaining /= 2.0;
202
+ }
203
+ while (remaining < 0.5) {
204
+ filters.push('atempo=0.5');
205
+ remaining /= 0.5;
206
+ }
207
+ filters.push(`atempo=${remaining.toFixed(4)}`);
208
+ return filters.join(',');
209
+ }
210
+
211
+ // ─── Main Function ──────────────────────────────────────────────────
212
+
213
+ export async function applyVoiceEffect(config: VoiceEffectConfig): Promise<string> {
214
+ const { inputPath, outputPath, effect, intensity = 0.5 } = config;
215
+
216
+ assertExists(inputPath, 'Input file');
217
+ ensureDir(outputPath);
218
+
219
+ const clampedIntensity = Math.max(0, Math.min(1, intensity));
220
+ logger.info(`Applying voice effect: ${effect} (intensity: ${clampedIntensity})`);
221
+
222
+ const effectData = getEffectFilter(effect, clampedIntensity);
223
+ const hasVideo = await hasVideoStream(inputPath);
224
+
225
+ if (effectData.needsComplexPitch && effectData.pitchFactor) {
226
+ // Pitch shifting requires asetrate + atempo combination
227
+ const sampleRate = await getSampleRate(inputPath);
228
+ const factor = effectData.pitchFactor;
229
+ const newRate = Math.round(sampleRate * factor);
230
+ const tempoCompensation = 1 / factor;
231
+
232
+ const audioFilter = `asetrate=${newRate},${buildAtempoChain(tempoCompensation)},aresample=${sampleRate}`;
233
+
234
+ const args = ['-y', '-i', inputPath];
235
+ if (hasVideo) {
236
+ args.push('-af', audioFilter, '-c:v', 'copy', '-movflags', '+faststart');
237
+ } else {
238
+ args.push('-af', audioFilter);
239
+ }
240
+ args.push(outputPath);
241
+
242
+ await runFfmpeg(args);
243
+ } else {
244
+ // Standard filter-based effects
245
+ const args = ['-y', '-i', inputPath];
246
+ if (hasVideo) {
247
+ args.push('-af', effectData.filter, '-c:v', 'copy', '-movflags', '+faststart');
248
+ } else {
249
+ args.push('-af', effectData.filter);
250
+ }
251
+ args.push(outputPath);
252
+
253
+ await runFfmpeg(args);
254
+ }
255
+
256
+ logger.info(`Voice effect applied: ${effect} → ${outputPath} (${fileInfo(outputPath)})`);
257
+ return outputPath;
258
+ }
@@ -0,0 +1,67 @@
1
+ // Core recording
2
+ export { recordWebsite } from './engine/index.js';
3
+ export type { RecordingConfig, RecordingResult, Scene, ViewportPreset, EasingName } from './engine/index.js';
4
+
5
+ // Post-production
6
+ export { addBackgroundMusic } from './engine/audio.js';
7
+ export type { AddMusicConfig } from './engine/audio.js';
8
+ export { concatenateVideos, generateIntro } from './engine/concat.js';
9
+ export type { ConcatConfig, ConcatClip, IntroConfig, TransitionType } from './engine/concat.js';
10
+ export { convertToSocialFormat, convertToAllFormats, SOCIAL_FORMATS } from './engine/social-format.js';
11
+ export type { SocialFormat, CropStrategy, FormatConvertConfig } from './engine/social-format.js';
12
+ export { addTextOverlays } from './engine/text-overlay.js';
13
+ export type { TextOverlay, TextPosition } from './engine/text-overlay.js';
14
+
15
+ // TTS & Narration
16
+ export { generateSpeech, listElevenLabsVoices } from './engine/tts.js';
17
+ export type { TTSConfig, TTSResult, TTSProvider, ElevenLabsVoice, OpenAIVoice } from './engine/tts.js';
18
+ export { createNarratedVideo } from './engine/narrated-video.js';
19
+ export type { NarratedVideoConfig, NarratedVideoResult, NarrationSegment } from './engine/narrated-video.js';
20
+
21
+ // Editing (NEW — CapCut-tier features)
22
+ export {
23
+ adjustVideoSpeed,
24
+ applyColorGrade,
25
+ applyVideoEffect,
26
+ cropVideo,
27
+ reverseClip,
28
+ extractAudio,
29
+ burnSubtitles,
30
+ autoCaption,
31
+ addKeyframeAnimation,
32
+ composePip,
33
+ addAudioDucking,
34
+ } from './engine/editing.js';
35
+ export type {
36
+ SpeedConfig,
37
+ ColorGradeConfig,
38
+ VideoEffect, EffectConfig,
39
+ CropConfig,
40
+ ReverseConfig,
41
+ ExtractAudioConfig,
42
+ BurnSubtitlesConfig,
43
+ AutoCaptionConfig, AutoCaptionResult,
44
+ Keyframe, KeyframeAnimationConfig,
45
+ PipPosition, PipConfig,
46
+ AudioDuckingConfig,
47
+ } from './engine/editing.js';
48
+
49
+ // CapCut-tier engines
50
+ export { applyLutPreset, listLutPresets, ALL_LUT_PRESETS, PRESET_DESCRIPTIONS } from './engine/lut-presets.js';
51
+ export type { LutPreset, LutPresetConfig } from './engine/lut-presets.js';
52
+ export { applyVoiceEffect, ALL_VOICE_EFFECTS, VOICE_EFFECT_DESCRIPTIONS } from './engine/voice-effects.js';
53
+ export type { VoiceEffect, VoiceEffectConfig } from './engine/voice-effects.js';
54
+ export { applyChromaKey } from './engine/chroma-key.js';
55
+ export type { ChromaKeyConfig } from './engine/chroma-key.js';
56
+ export { syncToBeats } from './engine/beat-sync.js';
57
+ export type { BeatSyncConfig, BeatSyncResult } from './engine/beat-sync.js';
58
+ export { animateText, ALL_TEXT_ANIMATIONS, TEXT_ANIMATION_DESCRIPTIONS } from './engine/text-animations.js';
59
+ export type { TextAnimation, TextAnimationConfig } from './engine/text-animations.js';
60
+ export { mixAudioTracks } from './engine/audio-mixer.js';
61
+ export type { AudioTrack, AudioMixConfig, AudioMixResult } from './engine/audio-mixer.js';
62
+
63
+ // Template engine
64
+ export { listTemplates, getTemplate, getTemplateSummaries, getTemplateCategories } from './engine/templates.js';
65
+ export type { VideoTemplate, TemplateCategory, TemplateSlot } from './engine/templates.js';
66
+ export { renderTemplate } from './engine/template-renderer.js';
67
+ export type { RenderTemplateConfig, RenderResult, TemplateAssets } from './engine/template-renderer.js';
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022", "DOM"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['src/**/*.test.ts'],
6
+ },
7
+ });