@microfox/remotion 1.0.1 → 1.1.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/dist/index.js DELETED
@@ -1,3320 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // src/index.ts
30
- var index_exports = {};
31
- __export(index_exports, {
32
- AudioAtom: () => Atom5,
33
- AudioAtomConfig: () => config6,
34
- BaseLayout: () => Layout,
35
- BaseLayoutConfig: () => config,
36
- BlurEffect: () => BlurEffect,
37
- BlurEffectConfig: () => config8,
38
- ComponentRenderer: () => ComponentRenderer,
39
- Composition: () => Composition,
40
- CompositionLayout: () => CompositionLayout,
41
- CompositionProvider: () => CompositionProvider,
42
- Frame: () => Frame,
43
- ImageAtom: () => Atom2,
44
- ImageAtomConfig: () => config3,
45
- LoopEffect: () => LoopEffect,
46
- LoopEffectConfig: () => config9,
47
- NextjsLogo: () => NextjsLogo,
48
- PanEffect: () => PanEffect,
49
- PanEffectConfig: () => config10,
50
- Rings: () => Rings,
51
- RippleOutLayout: () => RippleOutLayout,
52
- SceneFrame: () => SceneFrame,
53
- ShapeAtom: () => Atom,
54
- ShapeAtomConfig: () => config2,
55
- TextAtom: () => Atom3,
56
- TextAtomConfig: () => config4,
57
- TextAtomWithFonts: () => Atom6,
58
- TextAtomWithFontsConfig: () => config7,
59
- TextFade: () => TextFade,
60
- VideoAtom: () => Atom4,
61
- VideoAtomConfig: () => config5,
62
- Waveform: () => Waveform,
63
- WaveformCircle: () => WaveformCircle,
64
- WaveformHistogram: () => WaveformHistogram,
65
- WaveformHistogramRanged: () => WaveformHistogramRanged,
66
- WaveformLine: () => WaveformLine,
67
- WaveformPresets: () => WaveformPresets,
68
- ZoomEffect: () => ZoomEffect,
69
- ZoomEffectConfig: () => config11,
70
- buildLayoutHook: () => buildLayoutHook,
71
- calculateCircularPosition: () => calculateCircularPosition,
72
- calculateCompositionLayoutMetadata: () => calculateCompositionLayoutMetadata,
73
- calculateGridPosition: () => calculateGridPosition,
74
- calculateHierarchy: () => calculateHierarchy,
75
- calculateTimingWithInheritance: () => calculateTimingWithInheritance,
76
- clearFontCache: () => clearFontCache,
77
- componentRegistry: () => componentRegistry,
78
- createRootContext: () => createRootContext,
79
- findComponentById: () => findComponentById,
80
- findParentComponent: () => findParentComponent,
81
- getComponent: () => getComponent,
82
- getComponentConfig: () => getComponentConfig,
83
- getComponentWithConfig: () => getComponentWithConfig,
84
- getLoadedFontFamily: () => getLoadedFontFamily,
85
- getLoadedFonts: () => getLoadedFonts,
86
- getNormalizedFontName: () => getNormalizedFontName,
87
- isFontAvailable: () => isFontAvailable,
88
- isFontLoaded: () => isFontLoaded,
89
- loadGoogleFont: () => loadGoogleFont,
90
- loadMultipleFonts: () => loadMultipleFonts,
91
- mergeContexts: () => mergeContexts,
92
- nextjsLogoConfig: () => nextjsLogoConfig,
93
- preloadCommonFonts: () => preloadCommonFonts,
94
- registerComponent: () => registerComponent,
95
- registerEffect: () => registerEffect,
96
- registerPackage: () => registerPackage,
97
- ringsConfig: () => ringsConfig,
98
- rippleOutLayoutConfig: () => rippleOutLayoutConfig,
99
- textFadeConfig: () => textFadeConfig,
100
- useBoundaryCalculation: () => useBoundaryCalculation,
101
- useComponentRegistry: () => useComponentRegistry,
102
- useComposition: () => useComposition,
103
- useFont: () => useFont,
104
- useFontLoader: () => useFontLoader,
105
- useRenderContext: () => useRenderContext,
106
- useRippleOutLayout: () => useRippleOutLayout,
107
- useWaveformContext: () => useWaveformContext,
108
- useWaveformData: () => useWaveformData
109
- });
110
- module.exports = __toCommonJS(index_exports);
111
-
112
- // src/core/registry/componentRegistry.ts
113
- var ComponentRegistryManager = class {
114
- constructor() {
115
- this.registry = {};
116
- this.packageRegistry = {};
117
- }
118
- registerComponent(name, component, type, config12 = { displayName: "" }, packageName) {
119
- this.registry[name] = { component, config: config12 };
120
- if (packageName) {
121
- if (!this.packageRegistry[packageName]) {
122
- this.packageRegistry[packageName] = {};
123
- }
124
- this.packageRegistry[packageName][name] = { component, config: config12 };
125
- }
126
- }
127
- registerEffect(name, component, config12 = { displayName: "" }, packageName) {
128
- this.registerComponent(
129
- name?.includes("effect-") ? name : `effect-${name}`,
130
- component,
131
- "layout",
132
- config12,
133
- packageName
134
- );
135
- }
136
- getComponent(name) {
137
- return this.registry[name]?.component;
138
- }
139
- getComponentConfig(name) {
140
- return this.registry[name]?.config;
141
- }
142
- getComponentWithConfig(name) {
143
- return this.registry[name];
144
- }
145
- registerPackage(packageName, components) {
146
- this.packageRegistry[packageName] = components;
147
- Object.entries(components).forEach(([name, { component, config: config12 }]) => {
148
- this.registry[`${packageName}:${name}`] = { component, config: config12 };
149
- });
150
- }
151
- getPackageComponents(packageName) {
152
- return this.packageRegistry[packageName];
153
- }
154
- getAllComponents() {
155
- return { ...this.registry };
156
- }
157
- clear() {
158
- this.registry = {};
159
- this.packageRegistry = {};
160
- }
161
- };
162
- var componentRegistry = new ComponentRegistryManager();
163
- var registerComponent = (name, component, type, config12 = { displayName: "" }, packageName) => {
164
- componentRegistry.registerComponent(
165
- name,
166
- component,
167
- type,
168
- config12,
169
- packageName
170
- );
171
- };
172
- var registerEffect = (name, component, config12 = { displayName: "" }, packageName) => {
173
- componentRegistry.registerEffect(name, component, config12, packageName);
174
- };
175
- var registerPackage = (packageName, components) => {
176
- componentRegistry.registerPackage(packageName, components);
177
- };
178
- var getComponent = (name) => componentRegistry.getComponent(name);
179
- var getComponentConfig = (name) => componentRegistry.getComponentConfig(name);
180
- var getComponentWithConfig = (name) => componentRegistry.getComponentWithConfig(name);
181
-
182
- // src/core/context/CompositionContext.tsx
183
- var import_react = __toESM(require("react"));
184
- var CompositionContext = (0, import_react.createContext)(null);
185
- var CompositionProvider = ({ children, value }) => {
186
- return /* @__PURE__ */ import_react.default.createElement(CompositionContext.Provider, { value }, children);
187
- };
188
- var useComposition = () => {
189
- const context = (0, import_react.useContext)(CompositionContext);
190
- if (!context) {
191
- throw new Error("useComposition must be used within a CompositionProvider");
192
- }
193
- return context;
194
- };
195
-
196
- // src/components/base/ComponentRenderer.tsx
197
- var import_react3 = __toESM(require("react"));
198
- var import_remotion = require("remotion");
199
-
200
- // src/core/utils/timing.ts
201
- var calculateTiming = (type, context, videoConfig) => {
202
- let newTiming;
203
- if (type !== "atom" && context?.timing) {
204
- const { start = 0, duration = 0 } = context.timing;
205
- newTiming = {
206
- startInFrames: Math.round(
207
- context.timing?.startInFrames ? context.timing.startInFrames : type === "scene" ? start * videoConfig.fps : start * videoConfig.fps
208
- ),
209
- durationInFrames: Math.round(
210
- context.timing?.durationInFrames ? context.timing.durationInFrames : type === "scene" ? duration * videoConfig.fps : duration * videoConfig.fps
211
- ),
212
- duration,
213
- start
214
- };
215
- } else {
216
- newTiming = {
217
- startInFrames: context.timing?.startInFrames ? context.timing.startInFrames : context.timing?.start ? Math.round(videoConfig.fps * (context.timing.start || 0)) : 0,
218
- durationInFrames: Math.round(
219
- context.timing?.durationInFrames ? context.timing.durationInFrames : context.timing?.duration ? Math.round(videoConfig.fps * (context.timing.duration || 0)) : 0
220
- ),
221
- duration: context.timing?.duration,
222
- start: context.timing?.start
223
- };
224
- }
225
- return newTiming;
226
- };
227
-
228
- // src/core/utils/hierarchyUtils.ts
229
- var findComponentById = (root, targetId) => {
230
- if (!root) return null;
231
- const search = (components) => {
232
- for (const component of components) {
233
- if (component.id === targetId) {
234
- return component;
235
- }
236
- if (component.childrenData && component.childrenData.length > 0) {
237
- const found = search(component.childrenData);
238
- if (found) return found;
239
- }
240
- }
241
- return null;
242
- };
243
- return search(root);
244
- };
245
- var findParentComponent = (root, targetId) => {
246
- if (!root) return null;
247
- const search = (components, parent) => {
248
- for (const component of components) {
249
- if (component.childrenData && component.childrenData.length > 0) {
250
- const hasTargetChild = component.childrenData.some(
251
- (child) => child.id === targetId
252
- );
253
- if (hasTargetChild) {
254
- return component;
255
- }
256
- const found = search(component.childrenData, component);
257
- if (found) return found;
258
- }
259
- }
260
- return null;
261
- };
262
- return search(root, null);
263
- };
264
- var calculateHierarchy = (root, componentId, currentContext) => {
265
- if (!root) {
266
- return {
267
- depth: (currentContext?.hierarchy?.depth || 0) + 1,
268
- parentIds: [...currentContext?.hierarchy?.parentIds || [], componentId]
269
- };
270
- }
271
- const parentIds = [];
272
- let depth = 0;
273
- const traverse = (components, currentDepth) => {
274
- for (const component of components) {
275
- if (component.id === componentId) {
276
- depth = currentDepth;
277
- return true;
278
- }
279
- if (component.childrenData && component.childrenData.length > 0) {
280
- parentIds.push(component.id);
281
- const found = traverse(component.childrenData, currentDepth + 1);
282
- if (found) return true;
283
- parentIds.pop();
284
- }
285
- }
286
- return false;
287
- };
288
- traverse(root, 0);
289
- return {
290
- depth,
291
- parentIds: [...parentIds]
292
- };
293
- };
294
- var calculateTimingWithInheritance = (component, root, videoConfig) => {
295
- const currentContext = component.context || {};
296
- const baseTiming = calculateTiming(
297
- component.type,
298
- currentContext,
299
- videoConfig
300
- );
301
- if (!baseTiming.durationInFrames || baseTiming.durationInFrames <= 0) {
302
- const findParentWithTiming = (targetId) => {
303
- const parent = findParentComponent(root, targetId);
304
- if (!parent) return null;
305
- const parentContext = parent.context || {};
306
- const parentTiming = calculateTiming(
307
- parent.type,
308
- parentContext,
309
- videoConfig
310
- );
311
- if (parentTiming.durationInFrames && parentTiming.durationInFrames > 0) {
312
- return parentTiming;
313
- }
314
- return findParentWithTiming(parent.id);
315
- };
316
- const inheritedTiming = findParentWithTiming(component.id);
317
- if (inheritedTiming) {
318
- return {
319
- ...baseTiming,
320
- durationInFrames: inheritedTiming.durationInFrames ? inheritedTiming.durationInFrames : inheritedTiming.duration ? inheritedTiming.duration * videoConfig.fps : 0,
321
- duration: inheritedTiming.duration
322
- };
323
- }
324
- }
325
- return baseTiming;
326
- };
327
-
328
- // src/components/base/EffectWrapper.tsx
329
- var import_react2 = __toESM(require("react"));
330
- var EffectWrapper = ({
331
- effects,
332
- children,
333
- context
334
- }) => {
335
- if (!effects || effects.length === 0) {
336
- return children;
337
- }
338
- let wrappedContent = children;
339
- effects.forEach((effect, index) => {
340
- const effectId = typeof effect === "string" ? `effect-${effect}` : `effect-${effect.componentId}`;
341
- const EffectComponent = getComponent(effectId);
342
- if (!EffectComponent) {
343
- console.warn(`Effect component ${effectId} not found in registry`);
344
- return;
345
- }
346
- const effectData = typeof effect === "string" ? {} : effect.data || {};
347
- const effectContext = typeof effect === "string" ? context : effect.context || context;
348
- const effectProps = {
349
- id: typeof effect === "string" ? `effect-${index}` : effect.id,
350
- componentId: effectId,
351
- type: "layout",
352
- // Effects use the same rendering logic as layout
353
- data: effectData,
354
- context: effectContext,
355
- children: wrappedContent
356
- };
357
- wrappedContent = /* @__PURE__ */ import_react2.default.createElement(EffectComponent, { ...effectProps });
358
- });
359
- return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, wrappedContent);
360
- };
361
-
362
- // src/components/base/ComponentRenderer.tsx
363
- var RenderContext = (0, import_react3.createContext)(null);
364
- var useRenderContext = () => {
365
- const context = (0, import_react3.useContext)(RenderContext);
366
- if (!context) {
367
- throw new Error("useRenderContext must be used within a ComponentRenderer");
368
- }
369
- return context;
370
- };
371
- var ComponentRenderer = ({
372
- id,
373
- componentId,
374
- type,
375
- data,
376
- childrenData,
377
- context,
378
- effects
379
- }) => {
380
- const videoConfig = (0, import_remotion.useVideoConfig)();
381
- const { root } = useComposition();
382
- const defaultContext = {
383
- boundaries: {
384
- left: 0,
385
- top: 0,
386
- width: videoConfig.width,
387
- height: videoConfig.height,
388
- zIndex: 0
389
- },
390
- timing: {
391
- startInFrames: 0,
392
- durationInFrames: videoConfig.durationInFrames
393
- },
394
- hierarchy: {
395
- depth: 0,
396
- parentIds: []
397
- }
398
- };
399
- if (!context) {
400
- context = {};
401
- }
402
- const newHierarchy = calculateHierarchy(root, id, context ?? defaultContext);
403
- const componentData = {
404
- id,
405
- componentId,
406
- type,
407
- data,
408
- childrenData,
409
- context,
410
- effects
411
- };
412
- let newTiming = calculateTimingWithInheritance(componentData, root, videoConfig);
413
- const newContext = {
414
- ...context,
415
- boundaries: context?.boundaries,
416
- hierarchy: newHierarchy,
417
- timing: newTiming
418
- };
419
- const ComponentClass = getComponent(componentId);
420
- if (type === "scene") {
421
- return /* @__PURE__ */ import_react3.default.createElement(RenderContext.Provider, { value: newContext }, /* @__PURE__ */ import_react3.default.createElement(import_remotion.Series, null, childrenData?.map((child) => {
422
- const childTiming = calculateTimingWithInheritance(child, root, videoConfig);
423
- return /* @__PURE__ */ import_react3.default.createElement(
424
- import_remotion.Series.Sequence,
425
- {
426
- key: child.id,
427
- name: child.componentId + " - " + child.id,
428
- offset: childTiming.startInFrames ?? 0,
429
- durationInFrames: childTiming.durationInFrames ?? 0
430
- },
431
- child.effects && child.effects.length > 0 ? /* @__PURE__ */ import_react3.default.createElement(EffectWrapper, { effects: child.effects, context: newContext }, /* @__PURE__ */ import_react3.default.createElement(ComponentRenderer, { key: child.id, ...child })) : /* @__PURE__ */ import_react3.default.createElement(ComponentRenderer, { key: child.id, ...child })
432
- );
433
- })));
434
- }
435
- if (!ComponentClass) {
436
- console.warn(`Component type ${id} not found in registry`);
437
- return null;
438
- }
439
- const props = {
440
- id,
441
- componentId,
442
- data,
443
- context
444
- };
445
- if (type === "layout") {
446
- const config12 = getComponentConfig(componentId);
447
- const isInnerSequence = config12?.isInnerSequence;
448
- if (isInnerSequence) {
449
- return /* @__PURE__ */ import_react3.default.createElement(RenderContext.Provider, { value: newContext }, /* @__PURE__ */ import_react3.default.createElement(ComponentClass, { ...props }, effects && effects.length > 0 ? /* @__PURE__ */ import_react3.default.createElement(EffectWrapper, { effects, context: newContext }, childrenData?.map((child) => /* @__PURE__ */ import_react3.default.createElement(ComponentRenderer, { key: child.id, ...child }))) : childrenData?.map((child) => /* @__PURE__ */ import_react3.default.createElement(ComponentRenderer, { key: child.id, ...child }))));
450
- }
451
- return /* @__PURE__ */ import_react3.default.createElement(RenderContext.Provider, { value: newContext }, /* @__PURE__ */ import_react3.default.createElement(import_remotion.Sequence, { layout: "none", name: componentId + " - " + id, from: newTiming.startInFrames, durationInFrames: newTiming.durationInFrames }, /* @__PURE__ */ import_react3.default.createElement(ComponentClass, { ...props }, effects && effects.length > 0 ? /* @__PURE__ */ import_react3.default.createElement(EffectWrapper, { effects, context: newContext }, childrenData?.map((child) => /* @__PURE__ */ import_react3.default.createElement(ComponentRenderer, { key: child.id, ...child }))) : childrenData?.map((child) => /* @__PURE__ */ import_react3.default.createElement(ComponentRenderer, { key: child.id, ...child })))));
452
- }
453
- if (type === "atom") {
454
- if (newTiming.durationInFrames && newTiming.durationInFrames > 0) {
455
- return /* @__PURE__ */ import_react3.default.createElement(RenderContext.Provider, { value: newContext }, /* @__PURE__ */ import_react3.default.createElement(import_remotion.Sequence, { layout: "none", name: componentId + " - " + id, from: newTiming.startInFrames, durationInFrames: newTiming.durationInFrames }, effects && effects.length > 0 ? /* @__PURE__ */ import_react3.default.createElement(EffectWrapper, { effects, context: newContext }, /* @__PURE__ */ import_react3.default.createElement(ComponentClass, { ...props })) : /* @__PURE__ */ import_react3.default.createElement(ComponentClass, { ...props })));
456
- }
457
- return /* @__PURE__ */ import_react3.default.createElement(RenderContext.Provider, { value: newContext }, effects && effects.length > 0 ? /* @__PURE__ */ import_react3.default.createElement(EffectWrapper, { effects, context: newContext }, /* @__PURE__ */ import_react3.default.createElement(ComponentClass, { ...props })) : /* @__PURE__ */ import_react3.default.createElement(ComponentClass, { ...props }));
458
- }
459
- };
460
-
461
- // src/components/frames/Frame.tsx
462
- var import_react4 = __toESM(require("react"));
463
- var import_remotion2 = require("remotion");
464
- var Frame = ({ children, data }) => {
465
- return /* @__PURE__ */ import_react4.default.createElement(import_remotion2.AbsoluteFill, { style: data?.style }, children);
466
- };
467
-
468
- // src/components/frames/SceneFrame.tsx
469
- var import_react5 = __toESM(require("react"));
470
- var import_remotion3 = require("remotion");
471
- var SceneFrame = ({ children }) => {
472
- return /* @__PURE__ */ import_react5.default.createElement(import_remotion3.AbsoluteFill, null, children);
473
- };
474
-
475
- // src/components/layouts/BaseLayout.tsx
476
- var import_react6 = __toESM(require("react"));
477
- var import_remotion4 = require("remotion");
478
- var Layout = ({ id, children, data, context }) => {
479
- const { containerProps, childrenProps } = data || {
480
- containerProps: {},
481
- childrenProps: []
482
- };
483
- const childrenArray = import_react6.Children.toArray(children);
484
- return (
485
- // @ts-ignore
486
- /* @__PURE__ */ import_react6.default.createElement(
487
- import_remotion4.AbsoluteFill,
488
- {
489
- ...containerProps,
490
- style: {
491
- ...context?.boundaries,
492
- ...containerProps.style
493
- }
494
- },
495
- childrenArray.map((child, index) => /* @__PURE__ */ import_react6.default.createElement(
496
- "div",
497
- {
498
- key: index,
499
- ...index < childrenProps.length && childrenProps[index]
500
- },
501
- child
502
- ))
503
- )
504
- );
505
- };
506
- var config = {
507
- displayName: "BaseLayout",
508
- type: "layout",
509
- isInnerSequence: false
510
- };
511
-
512
- // src/components/layouts/index.ts
513
- registerComponent(
514
- config.displayName,
515
- Layout,
516
- "layout",
517
- config
518
- );
519
-
520
- // src/components/atoms/ShapeAtom.tsx
521
- var import_react7 = __toESM(require("react"));
522
- var import_remotion5 = require("remotion");
523
- var Atom = ({ data }) => {
524
- const frame = (0, import_remotion5.useCurrentFrame)();
525
- const { shape, color, rotation, style } = data;
526
- const rotationStyle = rotation ? {
527
- transform: `rotate(${(0, import_remotion5.interpolate)(
528
- frame % rotation.duration,
529
- [0, rotation.duration],
530
- [0, 360],
531
- {
532
- extrapolateLeft: "clamp",
533
- extrapolateRight: "clamp",
534
- easing: import_remotion5.Easing.linear
535
- }
536
- )}deg)`
537
- } : {};
538
- const baseStyle = {
539
- width: "100%",
540
- height: "100%",
541
- ...style,
542
- ...rotationStyle
543
- };
544
- switch (shape) {
545
- case "circle":
546
- return /* @__PURE__ */ import_react7.default.createElement("div", { style: { ...baseStyle, backgroundColor: color, borderRadius: "50%" } });
547
- case "rectangle":
548
- return /* @__PURE__ */ import_react7.default.createElement("div", { style: { ...baseStyle, backgroundColor: color } });
549
- default:
550
- return null;
551
- }
552
- };
553
- var config2 = {
554
- displayName: "ShapeAtom",
555
- type: "atom",
556
- isInnerSequence: false
557
- };
558
-
559
- // src/components/atoms/ImageAtom.tsx
560
- var import_react8 = __toESM(require("react"));
561
- var import_remotion6 = require("remotion");
562
- var Atom2 = ({ data }) => {
563
- const source = (0, import_react8.useMemo)(() => {
564
- if (data.src.startsWith("http")) {
565
- return data.src;
566
- }
567
- return (0, import_remotion6.staticFile)(data.src);
568
- }, [data.src]);
569
- return /* @__PURE__ */ import_react8.default.createElement(import_remotion6.Img, { className: data.className, src: source, style: data.style, crossOrigin: "anonymous" });
570
- };
571
- var config3 = {
572
- displayName: "ImageAtom",
573
- type: "atom",
574
- isInnerSequence: false
575
- };
576
-
577
- // src/components/atoms/TextAtom.tsx
578
- var import_react10 = __toESM(require("react"));
579
-
580
- // src/hooks/useFontLoader.ts
581
- var import_react9 = require("react");
582
-
583
- // src/utils/fontUtils.ts
584
- var import_google_fonts = require("@remotion/google-fonts");
585
- var availableFonts = (0, import_google_fonts.getAvailableFonts)();
586
- var loadedFonts = /* @__PURE__ */ new Map();
587
- var loadGoogleFont = async (fontFamily2, options = {}) => {
588
- if (!fontFamily2 || typeof fontFamily2 !== "string" || fontFamily2 === "") {
589
- console.warn("Invalid fontFamily provided:", fontFamily2);
590
- return "sans-serif";
591
- }
592
- const fontKey = `${fontFamily2}-${JSON.stringify(options)}`;
593
- if (loadedFonts.has(fontKey)) {
594
- return loadedFonts.get(fontKey);
595
- }
596
- try {
597
- console.log("availableFonts", availableFonts);
598
- const thisFont = availableFonts.find(
599
- (font) => font.importName === fontFamily2
600
- );
601
- console.log("thisFont", thisFont);
602
- if (thisFont?.load) {
603
- const fontPackage = await thisFont.load();
604
- const allFontStuff = fontPackage.loadFont("normal", {
605
- subsets: options.subsets || ["latin"],
606
- weights: options.weights || ["400"]
607
- });
608
- console.log("loadedFontFamily", allFontStuff.fontFamily);
609
- await allFontStuff.waitUntilDone();
610
- loadedFonts.set(fontKey, allFontStuff.fontFamily);
611
- return allFontStuff.fontFamily;
612
- } else {
613
- throw new Error(
614
- `Font Package @remotion/google-fonts/${fontFamily2} does not have loadFont method`
615
- );
616
- }
617
- } catch (error) {
618
- console.warn(`Failed to load font ${fontFamily2}:`, error);
619
- try {
620
- const alternativeNames = [
621
- fontFamily2.toLowerCase().replace(/\s+/g, ""),
622
- fontFamily2.toLowerCase().replace(/\s+/g, "-"),
623
- fontFamily2.toLowerCase().replace(/\s+/g, "_")
624
- ];
625
- for (const altName of alternativeNames) {
626
- if (altName === fontFamily2.toLowerCase().replace(/\s+/g, "-")) {
627
- continue;
628
- }
629
- try {
630
- const altFontPackage = await import(`@remotion/google-fonts/${altName}`);
631
- if (altFontPackage.loadFont) {
632
- const { fontFamily: loadedFontFamily } = await altFontPackage.loadFont("normal", {
633
- subsets: options.subsets || ["latin"],
634
- weights: options.weights || ["400"],
635
- display: options.display || "swap",
636
- preload: options.preload !== false
637
- });
638
- loadedFonts.set(fontKey, loadedFontFamily);
639
- return loadedFontFamily;
640
- }
641
- } catch (altError) {
642
- continue;
643
- }
644
- }
645
- } catch (altError) {
646
- }
647
- const fallbackFontFamily = `"${fontFamily2}"`;
648
- loadedFonts.set(fontKey, fallbackFontFamily);
649
- return fallbackFontFamily;
650
- }
651
- };
652
- var loadMultipleFonts = async (fonts) => {
653
- const loadPromises = fonts.map(async ({ family, options }) => {
654
- const fontFamily2 = await loadGoogleFont(family, options);
655
- return { family, fontFamily: fontFamily2 };
656
- });
657
- const results = await Promise.all(loadPromises);
658
- const fontMap = /* @__PURE__ */ new Map();
659
- results.forEach(({ family, fontFamily: fontFamily2 }) => {
660
- fontMap.set(family, fontFamily2);
661
- });
662
- return fontMap;
663
- };
664
- var getLoadedFontFamily = (fontFamily2, options = {}) => {
665
- const fontKey = `${fontFamily2}-${JSON.stringify(options)}`;
666
- return loadedFonts.get(fontKey);
667
- };
668
- var preloadCommonFonts = async () => {
669
- const commonFonts = [
670
- { family: "Inter", options: { weights: ["400", "500", "600", "700"] } },
671
- { family: "Roboto", options: { weights: ["400", "500", "700"] } },
672
- { family: "Open Sans", options: { weights: ["400", "600", "700"] } },
673
- { family: "Lato", options: { weights: ["400", "700"] } }
674
- ];
675
- return await loadMultipleFonts(commonFonts);
676
- };
677
- var isFontLoaded = (fontFamily2, options = {}) => {
678
- const fontKey = `${fontFamily2}-${JSON.stringify(options)}`;
679
- return loadedFonts.has(fontKey);
680
- };
681
- var clearFontCache = () => {
682
- loadedFonts.clear();
683
- };
684
- var getLoadedFonts = () => {
685
- return new Map(loadedFonts);
686
- };
687
- var isFontAvailable = async (fontFamily2) => {
688
- if (!fontFamily2 || typeof fontFamily2 !== "string") {
689
- return false;
690
- }
691
- try {
692
- const normalizedFontName = fontFamily2.trim().replace(/\s+/g, "-").toLowerCase();
693
- const fontPackage = await import(`@remotion/google-fonts/${normalizedFontName}`);
694
- return !!fontPackage.loadFont;
695
- } catch (error) {
696
- return false;
697
- }
698
- };
699
- var getNormalizedFontName = (fontFamily2) => {
700
- if (!fontFamily2 || typeof fontFamily2 !== "string") {
701
- return "";
702
- }
703
- return fontFamily2.trim().replace(/\s+/g, "-").toLowerCase();
704
- };
705
-
706
- // src/hooks/useFontLoader.ts
707
- var useFontLoader = (options = {}) => {
708
- const [state, setState] = (0, import_react9.useState)({
709
- loadedFonts: /* @__PURE__ */ new Map(),
710
- loadingFonts: /* @__PURE__ */ new Set(),
711
- errorFonts: /* @__PURE__ */ new Map()
712
- });
713
- const loadFont2 = (0, import_react9.useCallback)(
714
- async (fontFamily2, fontOptions = {}) => {
715
- const fontKey = `${fontFamily2}-${JSON.stringify(fontOptions)}`;
716
- if (state.loadedFonts.has(fontKey) || state.loadingFonts.has(fontFamily2)) {
717
- return state.loadedFonts.get(fontKey) || `"${fontFamily2}", sans-serif`;
718
- }
719
- setState((prev) => ({
720
- ...prev,
721
- loadingFonts: new Set(prev.loadingFonts).add(fontFamily2)
722
- }));
723
- try {
724
- const cssValue = await loadGoogleFont(fontFamily2, fontOptions);
725
- if (cssValue !== null) {
726
- setState((prev) => ({
727
- ...prev,
728
- loadedFonts: new Map(prev.loadedFonts).set(fontKey, cssValue),
729
- loadingFonts: new Set(
730
- [...prev.loadingFonts].filter((f) => f !== fontFamily2)
731
- )
732
- }));
733
- options.onLoad?.(fontFamily2, cssValue);
734
- return cssValue;
735
- } else {
736
- throw new Error(
737
- `Font Package @remotion/google-fonts/${fontFamily2} not found`
738
- );
739
- }
740
- } catch (error) {
741
- const errorObj = error instanceof Error ? error : new Error(String(error));
742
- setState((prev) => ({
743
- ...prev,
744
- errorFonts: new Map(prev.errorFonts).set(fontFamily2, errorObj),
745
- loadingFonts: new Set(
746
- [...prev.loadingFonts].filter((f) => f !== fontFamily2)
747
- )
748
- }));
749
- options.onError?.(fontFamily2, errorObj);
750
- const fallbackValue = `"${fontFamily2}", sans-serif`;
751
- return fallbackValue;
752
- }
753
- },
754
- [state.loadedFonts, state.loadingFonts, options]
755
- );
756
- const loadMultipleFonts2 = (0, import_react9.useCallback)(
757
- async (fonts) => {
758
- const fontsToLoad = fonts.filter(({ family, options: options2 = {} }) => {
759
- const fontKey = `${family}-${JSON.stringify(options2)}`;
760
- return !state.loadedFonts.has(fontKey) && !state.loadingFonts.has(family);
761
- });
762
- if (fontsToLoad.length === 0) {
763
- return state.loadedFonts;
764
- }
765
- setState((prev) => ({
766
- ...prev,
767
- loadingFonts: /* @__PURE__ */ new Set([
768
- ...prev.loadingFonts,
769
- ...fontsToLoad.map((f) => f.family)
770
- ])
771
- }));
772
- try {
773
- const fontMap = await loadMultipleFonts(fontsToLoad);
774
- const newFontsMap = /* @__PURE__ */ new Map();
775
- fontsToLoad.forEach(({ family, options: options2 = {} }) => {
776
- const fontKey = `${family}-${JSON.stringify(options2)}`;
777
- const cssValue = fontMap.get(family);
778
- if (cssValue) {
779
- newFontsMap.set(fontKey, cssValue);
780
- }
781
- });
782
- setState((prev) => ({
783
- ...prev,
784
- loadedFonts: new Map([...prev.loadedFonts, ...newFontsMap]),
785
- loadingFonts: new Set(
786
- [...prev.loadingFonts].filter(
787
- (f) => !fontsToLoad.some((ftl) => ftl.family === f)
788
- )
789
- )
790
- }));
791
- fontsToLoad.forEach(({ family }) => {
792
- const cssValue = fontMap.get(family);
793
- if (cssValue) {
794
- options.onLoad?.(family, cssValue);
795
- }
796
- });
797
- return fontMap;
798
- } catch (error) {
799
- const errorObj = error instanceof Error ? error : new Error(String(error));
800
- setState((prev) => ({
801
- ...prev,
802
- errorFonts: new Map(prev.errorFonts).set("multiple", errorObj),
803
- loadingFonts: new Set(
804
- [...prev.loadingFonts].filter(
805
- (f) => !fontsToLoad.some((ftl) => ftl.family === f)
806
- )
807
- )
808
- }));
809
- options.onError?.("multiple", errorObj);
810
- return state.loadedFonts;
811
- }
812
- },
813
- [state.loadedFonts, state.loadingFonts, options]
814
- );
815
- const isFontReady = (0, import_react9.useCallback)(
816
- (fontFamily2, options2 = {}) => {
817
- const fontKey = `${fontFamily2}-${JSON.stringify(options2)}`;
818
- return state.loadedFonts.has(fontKey);
819
- },
820
- [state.loadedFonts]
821
- );
822
- const areFontsReady = (0, import_react9.useCallback)(
823
- (fontFamilies) => {
824
- return fontFamilies.every(({ family, options: options2 = {} }) => {
825
- const fontKey = `${family}-${JSON.stringify(options2)}`;
826
- return state.loadedFonts.has(fontKey);
827
- });
828
- },
829
- [state.loadedFonts]
830
- );
831
- const getFontFamily = (0, import_react9.useCallback)(
832
- (fontFamily2, options2 = {}) => {
833
- const fontKey = `${fontFamily2}-${JSON.stringify(options2)}`;
834
- return state.loadedFonts.get(fontKey);
835
- },
836
- [state.loadedFonts]
837
- );
838
- const getFontError = (0, import_react9.useCallback)(
839
- (fontFamily2) => {
840
- return state.errorFonts.get(fontFamily2);
841
- },
842
- [state.errorFonts]
843
- );
844
- const clearErrors = (0, import_react9.useCallback)(() => {
845
- setState((prev) => ({
846
- ...prev,
847
- errorFonts: /* @__PURE__ */ new Map()
848
- }));
849
- }, []);
850
- return {
851
- // State
852
- loadedFonts: state.loadedFonts,
853
- loadingFonts: state.loadingFonts,
854
- errorFonts: state.errorFonts,
855
- // Actions
856
- loadFont: loadFont2,
857
- loadMultipleFonts: loadMultipleFonts2,
858
- isFontReady,
859
- areFontsReady,
860
- getFontFamily,
861
- getFontError,
862
- clearErrors
863
- };
864
- };
865
- var useFont = (fontFamily2, options = {}) => {
866
- const { loadFont: loadFont2, isFontReady, getFontFamily, getFontError, ...rest } = useFontLoader(options);
867
- const [isLoaded, setIsLoaded] = (0, import_react9.useState)(false);
868
- const [error, setError] = (0, import_react9.useState)(null);
869
- const initialFontFamily = getFontFamily(fontFamily2, options) || `"${fontFamily2}", sans-serif`;
870
- const [fontFamilyValue, setFontFamilyValue] = (0, import_react9.useState)(initialFontFamily);
871
- (0, import_react9.useEffect)(() => {
872
- const loadFontAsync = async () => {
873
- try {
874
- const cssValue = await loadFont2(fontFamily2, options);
875
- setFontFamilyValue(cssValue);
876
- setIsLoaded(true);
877
- setError(null);
878
- } catch (err) {
879
- setError(err instanceof Error ? err : new Error(String(err)));
880
- setIsLoaded(false);
881
- }
882
- };
883
- if (!isFontReady(fontFamily2, options)) {
884
- loadFontAsync();
885
- } else {
886
- const cachedValue = getFontFamily(fontFamily2, options);
887
- if (cachedValue) {
888
- setFontFamilyValue(cachedValue);
889
- }
890
- setIsLoaded(true);
891
- }
892
- }, [fontFamily2, loadFont2, isFontReady, getFontFamily, options]);
893
- return {
894
- isLoaded,
895
- error,
896
- isReady: isFontReady(fontFamily2, options),
897
- fontFamily: fontFamilyValue,
898
- ...rest
899
- };
900
- };
901
-
902
- // src/components/atoms/TextAtom.tsx
903
- var Atom3 = ({ data }) => {
904
- const [isFontLoading, setIsFontLoading] = (0, import_react10.useState)(false);
905
- const { isLoaded, error, isReady, fontFamily: fontFamily2 } = useFont(
906
- data.font?.family || "Inter",
907
- {
908
- weights: data.font?.weights || ["400"],
909
- subsets: data.font?.subsets || ["latin"],
910
- display: data.font?.display || "swap",
911
- preload: data.font?.preload !== false
912
- }
913
- );
914
- (0, import_react10.useEffect)(() => {
915
- if (data.font?.family) {
916
- setIsFontLoading(true);
917
- if (isReady || isLoaded) {
918
- setIsFontLoading(false);
919
- }
920
- }
921
- }, [data.font, isReady, isLoaded]);
922
- const enhancedStyle = {
923
- fontFamily: fontFamily2,
924
- opacity: isFontLoading ? 0.8 : 1,
925
- // Slight opacity during loading
926
- transition: "opacity 0.2s ease-in-out",
927
- ...data.style
928
- };
929
- if (error) {
930
- console.warn(`Font loading error for ${data.font?.family}:`, error);
931
- }
932
- return /* @__PURE__ */ import_react10.default.createElement(
933
- "div",
934
- {
935
- style: enhancedStyle,
936
- className: data.className,
937
- "data-font-loading": isFontLoading,
938
- "data-font-loaded": isReady || isLoaded
939
- },
940
- data.text
941
- );
942
- };
943
- var config4 = {
944
- displayName: "TextAtom",
945
- type: "atom",
946
- isInnerSequence: false
947
- };
948
-
949
- // src/components/atoms/VideoAtom.tsx
950
- var import_react11 = __toESM(require("react"));
951
- var import_remotion7 = require("remotion");
952
- var import_zod = require("zod");
953
- var VideoAtomDataProps = import_zod.z.object({
954
- src: import_zod.z.string(),
955
- // Video source URL
956
- style: import_zod.z.record(import_zod.z.any()).optional(),
957
- // CSS styles object
958
- className: import_zod.z.string().optional(),
959
- // CSS class names
960
- startFrom: import_zod.z.number().optional(),
961
- // Start playback from this time (seconds)
962
- endAt: import_zod.z.number().optional(),
963
- // End playback at this time (seconds)
964
- playbackRate: import_zod.z.number().optional(),
965
- // Playback speed multiplier
966
- volume: import_zod.z.number().optional(),
967
- // Volume level (0-1)
968
- muted: import_zod.z.boolean().optional(),
969
- // Mute video audio
970
- loop: import_zod.z.boolean().optional(),
971
- // Whether to loop the video
972
- fit: import_zod.z.enum(["contain", "cover", "fill", "none", "scale-down"]).optional()
973
- // Object fit style
974
- });
975
- var Atom4 = ({ data }) => {
976
- const { fps } = (0, import_remotion7.useVideoConfig)();
977
- const frame = (0, import_remotion7.useCurrentFrame)();
978
- const source = (0, import_react11.useMemo)(() => {
979
- if (data.src.startsWith("http")) {
980
- return data.src;
981
- }
982
- return (0, import_remotion7.staticFile)(data.src);
983
- }, [data.src]);
984
- const trimBefore = (0, import_react11.useMemo)(() => {
985
- return data.startFrom ? data.startFrom * fps : void 0;
986
- }, [data.startFrom, fps]);
987
- const trimAfter = (0, import_react11.useMemo)(() => {
988
- return data.endAt ? data.endAt * fps : void 0;
989
- }, [data.endAt, fps]);
990
- const combinedStyle = (0, import_react11.useMemo)(() => {
991
- const baseStyle = data.style || {};
992
- const objectFit = data.fit ? { objectFit: data.fit } : {};
993
- return { ...baseStyle, ...objectFit };
994
- }, [data.style, data.fit]);
995
- return (
996
- // @ts-ignore
997
- /* @__PURE__ */ import_react11.default.createElement(
998
- import_remotion7.Video,
999
- {
1000
- className: data.className,
1001
- src: source,
1002
- style: combinedStyle,
1003
- trimBefore,
1004
- trimAfter,
1005
- playbackRate: data.playbackRate,
1006
- volume: data.volume,
1007
- muted: data.muted,
1008
- loop: data.loop
1009
- }
1010
- )
1011
- );
1012
- };
1013
- var config5 = {
1014
- displayName: "VideoAtom",
1015
- type: "atom",
1016
- isInnerSequence: false
1017
- };
1018
-
1019
- // src/components/atoms/AudioAtom.tsx
1020
- var import_react12 = __toESM(require("react"));
1021
- var import_remotion8 = require("remotion");
1022
- var import_zod2 = require("zod");
1023
- var AudioAtomMutedRangeProps = import_zod2.z.object({
1024
- type: import_zod2.z.literal("range"),
1025
- values: import_zod2.z.array(import_zod2.z.object({
1026
- start: import_zod2.z.number(),
1027
- // Start time in seconds
1028
- end: import_zod2.z.number()
1029
- // End time in seconds
1030
- }))
1031
- });
1032
- var AudioAtomMutedFullProps = import_zod2.z.object({
1033
- type: import_zod2.z.literal("full"),
1034
- value: import_zod2.z.boolean()
1035
- // true = muted, false = unmuted
1036
- });
1037
- var AudioAtomDataProps = import_zod2.z.object({
1038
- src: import_zod2.z.string(),
1039
- // Audio source URL
1040
- startFrom: import_zod2.z.number().optional(),
1041
- // Start playback from this time (seconds)
1042
- endAt: import_zod2.z.number().optional(),
1043
- // End playback at this time (seconds)
1044
- volume: import_zod2.z.number().optional(),
1045
- // Volume level (0-1)
1046
- playbackRate: import_zod2.z.number().optional(),
1047
- // Playback speed multiplier
1048
- muted: import_zod2.z.union([AudioAtomMutedFullProps, AudioAtomMutedRangeProps]).optional()
1049
- // Mute configuration
1050
- });
1051
- var Atom5 = ({ data }) => {
1052
- const { fps } = (0, import_remotion8.useVideoConfig)();
1053
- const { muted } = data;
1054
- const frame = (0, import_remotion8.useCurrentFrame)();
1055
- const isMuted = (0, import_react12.useMemo)(() => {
1056
- if (muted?.type === "full") {
1057
- return muted.value;
1058
- }
1059
- if (muted?.type === "range") {
1060
- return muted?.values.some(
1061
- (value) => frame >= value.start * fps && frame <= value.end * fps
1062
- );
1063
- }
1064
- return false;
1065
- }, [muted, frame, fps]);
1066
- const source = (0, import_react12.useMemo)(() => {
1067
- if (data.src.startsWith("http")) {
1068
- return data.src;
1069
- }
1070
- return (0, import_remotion8.staticFile)(data.src);
1071
- }, [data.src]);
1072
- return (
1073
- // @ts-ignore
1074
- /* @__PURE__ */ import_react12.default.createElement(
1075
- import_remotion8.Audio,
1076
- {
1077
- src: source,
1078
- trimBefore: data.startFrom ? data.startFrom * fps : void 0,
1079
- trimAfter: data.endAt ? data.endAt * fps : void 0,
1080
- volume: data.volume,
1081
- playbackRate: data.playbackRate,
1082
- muted: isMuted
1083
- }
1084
- )
1085
- );
1086
- };
1087
- var config6 = {
1088
- displayName: "AudioAtom",
1089
- type: "atom",
1090
- isInnerSequence: false
1091
- };
1092
-
1093
- // src/components/atoms/TextAtomWithFonts.tsx
1094
- var import_react13 = __toESM(require("react"));
1095
- var Atom6 = ({ data }) => {
1096
- const [isFontLoading, setIsFontLoading] = (0, import_react13.useState)(false);
1097
- const { isLoaded, error, isReady, fontFamily: fontFamily2 } = useFont(
1098
- data.font?.family || "Inter",
1099
- {
1100
- weights: data.font?.weights || ["400"],
1101
- subsets: data.font?.subsets || ["latin"],
1102
- display: data.font?.display || "swap",
1103
- preload: data.font?.preload !== false,
1104
- onLoad: (family, cssValue) => {
1105
- console.log(`Font ${family} loaded successfully with CSS value: ${cssValue}`);
1106
- setIsFontLoading(false);
1107
- },
1108
- onError: (family, error2) => {
1109
- console.warn(`Font ${family} failed to load:`, error2);
1110
- setIsFontLoading(false);
1111
- }
1112
- }
1113
- );
1114
- (0, import_react13.useEffect)(() => {
1115
- if (data.font?.family) {
1116
- if (isReady || isLoaded) {
1117
- setIsFontLoading(false);
1118
- } else if (!isReady && !isLoaded && !error) {
1119
- setIsFontLoading(true);
1120
- }
1121
- }
1122
- }, [data.font, isReady, isLoaded, error]);
1123
- const enhancedStyle = {
1124
- fontFamily: fontFamily2,
1125
- opacity: isFontLoading ? 0.8 : 1,
1126
- transition: "opacity 0.3s ease-in-out, font-family 0.2s ease-in-out",
1127
- ...data.style
1128
- };
1129
- if (isFontLoading && data.loadingState?.showLoadingIndicator) {
1130
- return /* @__PURE__ */ import_react13.default.createElement("div", { style: enhancedStyle, className: data.className }, /* @__PURE__ */ import_react13.default.createElement("span", { style: data.loadingState.loadingStyle }, data.loadingState.loadingText || "Loading..."));
1131
- }
1132
- if (error && data.errorState?.showErrorIndicator) {
1133
- return /* @__PURE__ */ import_react13.default.createElement("div", { style: enhancedStyle, className: data.className }, /* @__PURE__ */ import_react13.default.createElement("span", { style: data.errorState.errorStyle }, data.errorState.errorText || data.text));
1134
- }
1135
- return /* @__PURE__ */ import_react13.default.createElement(
1136
- "div",
1137
- {
1138
- style: enhancedStyle,
1139
- className: data.className,
1140
- "data-font-loading": isFontLoading,
1141
- "data-font-loaded": isReady || isLoaded,
1142
- "data-font-error": !!error,
1143
- "data-font-family": data.font?.family || "system"
1144
- },
1145
- data.text
1146
- );
1147
- };
1148
- var config7 = {
1149
- displayName: "TextAtomWithFonts",
1150
- type: "atom",
1151
- isInnerSequence: false
1152
- };
1153
-
1154
- // src/components/atoms/index.ts
1155
- registerComponent(
1156
- config2.displayName,
1157
- Atom,
1158
- "atom",
1159
- config2
1160
- );
1161
- registerComponent(
1162
- config3.displayName,
1163
- Atom2,
1164
- "atom",
1165
- config3
1166
- );
1167
- registerComponent(config4.displayName, Atom3, "atom", config4);
1168
- registerComponent(
1169
- config5.displayName,
1170
- Atom4,
1171
- "atom",
1172
- config5
1173
- );
1174
- registerComponent(
1175
- config6.displayName,
1176
- Atom5,
1177
- "atom",
1178
- config6
1179
- );
1180
- registerComponent(
1181
- config7.displayName,
1182
- Atom6,
1183
- "atom",
1184
- config7
1185
- );
1186
-
1187
- // src/components/effects/BlurEffect.tsx
1188
- var import_react14 = __toESM(require("react"));
1189
- var BlurEffect = ({
1190
- data,
1191
- children
1192
- }) => {
1193
- const blurAmount = data?.blur || 5;
1194
- return /* @__PURE__ */ import_react14.default.createElement("div", { style: {
1195
- filter: `blur(${blurAmount}px)`,
1196
- width: "100%",
1197
- height: "100%"
1198
- } }, children);
1199
- };
1200
- var config8 = {
1201
- displayName: "blur",
1202
- description: "Applies a blur effect to its children",
1203
- category: "effects",
1204
- props: {
1205
- blur: {
1206
- type: "number",
1207
- description: "Blur amount in pixels",
1208
- default: 5
1209
- }
1210
- }
1211
- };
1212
-
1213
- // src/components/effects/Loop.tsx
1214
- var import_react15 = __toESM(require("react"));
1215
- var import_remotion9 = require("remotion");
1216
- var LoopEffect = ({
1217
- data,
1218
- children,
1219
- context
1220
- }) => {
1221
- const { timing } = context ?? {};
1222
- const loopData = data;
1223
- const durationInFrames = loopData?.durationInFrames || timing?.durationInFrames || 50;
1224
- const times = loopData?.times ?? Infinity;
1225
- const layout = loopData?.layout || "absolute-fill";
1226
- return (
1227
- // @ts-ignore
1228
- /* @__PURE__ */ import_react15.default.createElement(
1229
- import_remotion9.Loop,
1230
- {
1231
- durationInFrames,
1232
- times,
1233
- layout
1234
- },
1235
- /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, children)
1236
- )
1237
- );
1238
- };
1239
- var config9 = {
1240
- displayName: "loop",
1241
- type: "layout",
1242
- isInnerSequence: false,
1243
- props: {
1244
- durationInFrames: {
1245
- type: "number",
1246
- description: "How many frames one iteration of the loop should be long",
1247
- default: 50
1248
- },
1249
- times: {
1250
- type: "number",
1251
- description: "How many times to loop the content (defaults to Infinity)",
1252
- default: void 0
1253
- },
1254
- layout: {
1255
- type: "string",
1256
- description: 'Either "absolute-fill" (default) or "none"',
1257
- default: "absolute-fill"
1258
- }
1259
- }
1260
- };
1261
-
1262
- // src/components/effects/Pan.tsx
1263
- var import_react16 = __toESM(require("react"));
1264
- var import_remotion10 = require("remotion");
1265
- var parseDuration = (duration, contextDuration, fps) => {
1266
- if (!duration) return contextDuration;
1267
- if (typeof duration === "number") {
1268
- return duration * fps;
1269
- }
1270
- if (typeof duration === "string" && duration.endsWith("%")) {
1271
- const percentage = parseFloat(duration.replace("%", "")) / 100;
1272
- return Math.floor(contextDuration * percentage);
1273
- }
1274
- return contextDuration;
1275
- };
1276
- var parseDelay = (delay, contextDuration, fps) => {
1277
- if (!delay) return 0;
1278
- if (typeof delay === "number") {
1279
- return delay * fps;
1280
- }
1281
- if (typeof delay === "string" && delay.endsWith("%")) {
1282
- const percentage = parseFloat(delay) / 100;
1283
- return Math.floor(contextDuration * percentage);
1284
- }
1285
- return 0;
1286
- };
1287
- var getPanDistance = (progress, panDistance) => {
1288
- if (typeof panDistance === "number") {
1289
- return panDistance;
1290
- }
1291
- if (Array.isArray(panDistance)) {
1292
- if (panDistance.length === 0) return 0;
1293
- if (panDistance.length === 1) return panDistance[0][1];
1294
- for (let i = 0; i < panDistance.length - 1; i++) {
1295
- const [currentProgress, currentDistance] = panDistance[i];
1296
- const [nextProgress, nextDistance] = panDistance[i + 1];
1297
- if (progress >= currentProgress && progress <= nextProgress) {
1298
- const localProgress = (progress - currentProgress) / (nextProgress - currentProgress);
1299
- return (0, import_remotion10.interpolate)(localProgress, [0, 1], [currentDistance, nextDistance]);
1300
- }
1301
- }
1302
- return panDistance[panDistance.length - 1][1];
1303
- }
1304
- return 0;
1305
- };
1306
- var getPosition = (position) => {
1307
- if (!position) return [0.5, 0.5];
1308
- if (Array.isArray(position)) {
1309
- return position;
1310
- }
1311
- const positions = {
1312
- "top-left": [0, 0],
1313
- "top": [0.5, 0],
1314
- "top-right": [1, 0],
1315
- "left": [0, 0.5],
1316
- "center": [0.5, 0.5],
1317
- "right": [1, 0.5],
1318
- "bottom-left": [0, 1],
1319
- "bottom": [0.5, 1],
1320
- "bottom-right": [1, 1]
1321
- };
1322
- return positions[position] || [0.5, 0.5];
1323
- };
1324
- var getEasingFunction = (animationType) => {
1325
- switch (animationType) {
1326
- case "linear":
1327
- return import_remotion10.Easing.linear;
1328
- case "ease-in":
1329
- return import_remotion10.Easing.in(import_remotion10.Easing.ease);
1330
- case "ease-out":
1331
- return import_remotion10.Easing.out(import_remotion10.Easing.ease);
1332
- case "ease-in-out":
1333
- return import_remotion10.Easing.inOut(import_remotion10.Easing.ease);
1334
- default:
1335
- return import_remotion10.Easing.linear;
1336
- }
1337
- };
1338
- var getPanVector = (direction, distance) => {
1339
- switch (direction) {
1340
- case "left":
1341
- return [-distance, 0];
1342
- case "right":
1343
- return [distance, 0];
1344
- case "up":
1345
- return [0, -distance];
1346
- case "down":
1347
- return [0, distance];
1348
- case "diagonal":
1349
- return [distance * 0.707, distance * 0.707];
1350
- // 45-degree diagonal
1351
- default:
1352
- return [0, 0];
1353
- }
1354
- };
1355
- var PanEffect = ({
1356
- data,
1357
- children,
1358
- context
1359
- }) => {
1360
- const frame = (0, import_remotion10.useCurrentFrame)();
1361
- const { fps } = (0, import_remotion10.useVideoConfig)();
1362
- const panData = data;
1363
- const { timing } = context ?? {};
1364
- const contextDuration = timing?.durationInFrames || 50;
1365
- const effectTiming = panData?.effectTiming || "start";
1366
- const panDuration = parseDuration(panData?.panDuration, contextDuration, fps);
1367
- const panStartDelay = parseDelay(panData?.panStartDelay, contextDuration, fps);
1368
- const panEndDelay = parseDelay(panData?.panEndDelay, contextDuration, fps);
1369
- const panDirection = panData?.panDirection || "right";
1370
- let panDistance = panData?.panDistance || 100;
1371
- const loopTimes = panData?.loopTimes || 0;
1372
- const panStartPosition = getPosition(panData?.panStartPosition);
1373
- const panEndPosition = getPosition(panData?.panEndPosition);
1374
- const animationType = panData?.animationType || "linear";
1375
- if (loopTimes > 0 && typeof panDistance === "number") {
1376
- const loopedPanDistance = [];
1377
- for (let i = 0; i < loopTimes; i++) {
1378
- const loopProgress = i / loopTimes;
1379
- const nextLoopProgress = (i + 1) / loopTimes;
1380
- loopedPanDistance.push([loopProgress, 0]);
1381
- loopedPanDistance.push([loopProgress + (nextLoopProgress - loopProgress) * 0.5, panDistance]);
1382
- loopedPanDistance.push([nextLoopProgress, 0]);
1383
- }
1384
- panDistance = loopedPanDistance;
1385
- }
1386
- let progress;
1387
- if (animationType === "spring") {
1388
- progress = (0, import_remotion10.spring)({
1389
- frame,
1390
- fps,
1391
- config: {
1392
- stiffness: 100,
1393
- damping: 10,
1394
- mass: 1
1395
- },
1396
- durationInFrames: panDuration,
1397
- delay: effectTiming === "start" ? panStartDelay : contextDuration - panEndDelay - panDuration
1398
- });
1399
- } else {
1400
- let animationFrame;
1401
- if (effectTiming === "start") {
1402
- animationFrame = frame - panStartDelay;
1403
- } else {
1404
- animationFrame = frame - (contextDuration - panEndDelay - panDuration);
1405
- }
1406
- const easing = getEasingFunction(animationType);
1407
- progress = (0, import_remotion10.interpolate)(
1408
- animationFrame,
1409
- [0, panDuration],
1410
- [0, 1],
1411
- {
1412
- easing,
1413
- extrapolateLeft: "clamp",
1414
- extrapolateRight: "clamp"
1415
- }
1416
- );
1417
- }
1418
- let panOffset;
1419
- if (panDirection === "custom") {
1420
- const [startX, startY] = panStartPosition;
1421
- const [endX, endY] = panEndPosition;
1422
- const offsetX = (endX - startX) * 100;
1423
- const offsetY = (endY - startY) * 100;
1424
- panOffset = [
1425
- (0, import_remotion10.interpolate)(progress, [0, 1], [0, offsetX]),
1426
- (0, import_remotion10.interpolate)(progress, [0, 1], [0, offsetY])
1427
- ];
1428
- } else {
1429
- const distance = getPanDistance(progress, panDistance);
1430
- const [vectorX, vectorY] = getPanVector(panDirection, distance);
1431
- panOffset = [vectorX, vectorY];
1432
- }
1433
- const style = (0, import_react16.useMemo)(() => {
1434
- return {
1435
- width: "100%",
1436
- height: "100%",
1437
- transform: `translate(${panOffset[0]}px, ${panOffset[1]}px)`
1438
- };
1439
- }, [panOffset]);
1440
- return /* @__PURE__ */ import_react16.default.createElement("div", { style }, children);
1441
- };
1442
- var config10 = {
1443
- displayName: "pan",
1444
- type: "layout",
1445
- isInnerSequence: false,
1446
- props: {
1447
- effectTiming: {
1448
- type: "string",
1449
- description: 'When the pan effect should occur: "start" or "end"',
1450
- default: "start"
1451
- },
1452
- panDuration: {
1453
- type: "string",
1454
- description: 'Duration of the pan animation in seconds or percentage (e.g., "2" or "50%")',
1455
- default: void 0
1456
- },
1457
- panStart: {
1458
- type: "number",
1459
- description: "Start time of pan in seconds",
1460
- default: 0
1461
- },
1462
- panEnd: {
1463
- type: "number",
1464
- description: "End time of pan in seconds",
1465
- default: void 0
1466
- },
1467
- panStartDelay: {
1468
- type: "string",
1469
- description: "Delay before pan starts in seconds or percentage",
1470
- default: 0
1471
- },
1472
- panEndDelay: {
1473
- type: "string",
1474
- description: "Delay before video ends in seconds or percentage",
1475
- default: 0
1476
- },
1477
- panDirection: {
1478
- type: "string",
1479
- description: 'Direction of pan: "left", "right", "up", "down", "diagonal", or "custom"',
1480
- default: "right"
1481
- },
1482
- panDistance: {
1483
- type: "string",
1484
- description: "Pan distance in pixels or array of [progress, distance] pairs",
1485
- default: 100
1486
- },
1487
- panStartPosition: {
1488
- type: "string",
1489
- description: "Starting position: [x, y] coordinates or position string (top-left, center, etc.)",
1490
- default: "center"
1491
- },
1492
- panEndPosition: {
1493
- type: "string",
1494
- description: "Ending position: [x, y] coordinates or position string (top-left, center, etc.)",
1495
- default: "center"
1496
- },
1497
- animationType: {
1498
- type: "string",
1499
- description: 'Animation curve: "linear", "spring", "ease-in", "ease-out", "ease-in-out"',
1500
- default: "linear"
1501
- }
1502
- }
1503
- };
1504
-
1505
- // src/components/effects/Zoom.tsx
1506
- var import_react17 = __toESM(require("react"));
1507
- var import_remotion11 = require("remotion");
1508
- var parseDuration2 = (duration, contextDuration, fps) => {
1509
- if (!duration) return contextDuration;
1510
- if (typeof duration === "number") {
1511
- return duration * fps;
1512
- }
1513
- if (typeof duration === "string" && duration.endsWith("%")) {
1514
- const percentage = parseFloat(duration.replace("%", "")) / 100;
1515
- return Math.floor(contextDuration * percentage);
1516
- }
1517
- return contextDuration;
1518
- };
1519
- var parseDelay2 = (delay, contextDuration, fps) => {
1520
- if (!delay) return 0;
1521
- if (typeof delay === "number") {
1522
- return delay * fps;
1523
- }
1524
- if (typeof delay === "string" && delay.endsWith("%")) {
1525
- const percentage = parseFloat(delay) / 100;
1526
- return Math.floor(contextDuration * percentage);
1527
- }
1528
- return 0;
1529
- };
1530
- var getZoomScale = (progress, zoomDepth) => {
1531
- if (typeof zoomDepth === "number") {
1532
- return zoomDepth;
1533
- }
1534
- if (Array.isArray(zoomDepth)) {
1535
- if (zoomDepth.length === 0) return 1;
1536
- if (zoomDepth.length === 1) return zoomDepth[0][1];
1537
- for (let i = 0; i < zoomDepth.length - 1; i++) {
1538
- const [currentProgress, currentScale] = zoomDepth[i];
1539
- const [nextProgress, nextScale] = zoomDepth[i + 1];
1540
- if (progress >= currentProgress && progress <= nextProgress) {
1541
- const localProgress = (progress - currentProgress) / (nextProgress - currentProgress);
1542
- return (0, import_remotion11.interpolate)(localProgress, [0, 1], [currentScale, nextScale]);
1543
- }
1544
- }
1545
- return zoomDepth[zoomDepth.length - 1][1];
1546
- }
1547
- return 1;
1548
- };
1549
- var getZoomPosition = (position) => {
1550
- if (!position) return [0.5, 0.5];
1551
- if (Array.isArray(position)) {
1552
- return position;
1553
- }
1554
- const positions = {
1555
- "top-left": [0, 0],
1556
- "top": [0.5, 0],
1557
- "top-right": [1, 0],
1558
- "left": [0, 0.5],
1559
- "center": [0.5, 0.5],
1560
- "right": [1, 0.5],
1561
- "bottom-left": [0, 1],
1562
- "bottom": [0.5, 1],
1563
- "bottom-right": [1, 1]
1564
- };
1565
- return positions[position] || [0.5, 0.5];
1566
- };
1567
- var getEasingFunction2 = (animationType) => {
1568
- switch (animationType) {
1569
- case "linear":
1570
- return import_remotion11.Easing.linear;
1571
- case "ease-in":
1572
- return import_remotion11.Easing.in(import_remotion11.Easing.ease);
1573
- case "ease-out":
1574
- return import_remotion11.Easing.out(import_remotion11.Easing.ease);
1575
- case "ease-in-out":
1576
- return import_remotion11.Easing.inOut(import_remotion11.Easing.ease);
1577
- default:
1578
- return import_remotion11.Easing.linear;
1579
- }
1580
- };
1581
- var ZoomEffect = ({
1582
- data,
1583
- children,
1584
- context
1585
- }) => {
1586
- const frame = (0, import_remotion11.useCurrentFrame)();
1587
- const { fps } = (0, import_remotion11.useVideoConfig)();
1588
- const zoomData = data;
1589
- const { timing } = context ?? {};
1590
- const contextDuration = timing?.durationInFrames || 50;
1591
- console.log(contextDuration);
1592
- const effectTiming = zoomData?.effectTiming || "start";
1593
- const zoomDuration = parseDuration2(zoomData?.zoomDuration, contextDuration, fps);
1594
- const zoomStartDelay = parseDelay2(zoomData?.zoomStartDelay, contextDuration, fps);
1595
- const zoomEndDelay = parseDelay2(zoomData?.zoomEndDelay, contextDuration, fps);
1596
- const zoomDirection = zoomData?.zoomDirection || "in";
1597
- let zoomDepth = zoomData?.zoomDepth || 1.5;
1598
- const loopTimes = zoomData?.loopTimes || 0;
1599
- if (loopTimes > 1 && Array.isArray(zoomDepth)) {
1600
- const loopedZoomDepth = [];
1601
- for (let i = 0; i < loopTimes; i++) {
1602
- const loopProgress = i / loopTimes;
1603
- const nextLoopProgress = (i + 1) / loopTimes;
1604
- zoomDepth.forEach(([x, y]) => {
1605
- const mappedX = loopProgress + x * (nextLoopProgress - loopProgress);
1606
- loopedZoomDepth.push([mappedX, y]);
1607
- });
1608
- }
1609
- zoomDepth = loopedZoomDepth;
1610
- } else if (loopTimes > 0 && typeof zoomDepth === "number") {
1611
- const loopedZoomDepth = [];
1612
- for (let i = 0; i < loopTimes; i++) {
1613
- const loopProgress = i / loopTimes;
1614
- const nextLoopProgress = (i + 1) / loopTimes;
1615
- loopedZoomDepth.push([loopProgress, 1]);
1616
- loopedZoomDepth.push([loopProgress + (nextLoopProgress - loopProgress) * 0.5, zoomDepth]);
1617
- loopedZoomDepth.push([nextLoopProgress, 1]);
1618
- }
1619
- zoomDepth = loopedZoomDepth;
1620
- }
1621
- const zoomPosition = getZoomPosition(zoomData?.zoomPosition);
1622
- const animationType = zoomData?.animationType || "linear";
1623
- let progress;
1624
- if (animationType === "spring") {
1625
- progress = (0, import_remotion11.spring)({
1626
- frame,
1627
- fps,
1628
- config: {
1629
- stiffness: 100,
1630
- damping: 10,
1631
- mass: 1
1632
- },
1633
- durationInFrames: zoomDuration,
1634
- delay: effectTiming === "start" ? zoomStartDelay : contextDuration - zoomEndDelay - zoomDuration
1635
- });
1636
- } else {
1637
- let animationFrame;
1638
- if (effectTiming === "start") {
1639
- animationFrame = frame - zoomStartDelay;
1640
- } else {
1641
- animationFrame = frame - (contextDuration - zoomEndDelay - zoomDuration);
1642
- }
1643
- const easing = getEasingFunction2(animationType);
1644
- progress = (0, import_remotion11.interpolate)(
1645
- animationFrame,
1646
- [0, zoomDuration],
1647
- [0, 1],
1648
- {
1649
- easing,
1650
- extrapolateLeft: "clamp",
1651
- extrapolateRight: "clamp"
1652
- }
1653
- );
1654
- }
1655
- let scale;
1656
- if (typeof zoomDepth === "number") {
1657
- const baseScale = zoomDirection === "in" ? 1 : zoomDepth;
1658
- const targetScale = zoomDirection === "in" ? zoomDepth : 1;
1659
- scale = (0, import_remotion11.interpolate)(progress, [0, 1], [baseScale, targetScale]);
1660
- } else if (Array.isArray(zoomDepth)) {
1661
- scale = getZoomScale(progress, zoomDepth);
1662
- } else {
1663
- const baseScale = zoomDirection === "in" ? 1 : 1.5;
1664
- const targetScale = zoomDirection === "in" ? 1.5 : 1;
1665
- scale = (0, import_remotion11.interpolate)(progress, [0, 1], [baseScale, targetScale]);
1666
- }
1667
- const [originX, originY] = zoomPosition;
1668
- const transformOrigin = `${originX * 100}% ${originY * 100}%`;
1669
- const style = (0, import_react17.useMemo)(() => {
1670
- return {
1671
- width: "100%",
1672
- height: "100%",
1673
- transform: `scale(${scale})`,
1674
- transformOrigin
1675
- };
1676
- }, [scale, transformOrigin]);
1677
- return /* @__PURE__ */ import_react17.default.createElement("div", { style }, children);
1678
- };
1679
- var config11 = {
1680
- displayName: "zoom",
1681
- type: "layout",
1682
- isInnerSequence: false,
1683
- props: {
1684
- effectTiming: {
1685
- type: "string",
1686
- description: 'When the zoom effect should occur: "start" or "end"',
1687
- default: "start"
1688
- },
1689
- zoomDuration: {
1690
- type: "string",
1691
- description: 'Duration of the zoom animation in seconds or percentage (e.g., "2" or "50%")',
1692
- default: void 0
1693
- },
1694
- zoomStart: {
1695
- type: "number",
1696
- description: "Start time of zoom in seconds",
1697
- default: 0
1698
- },
1699
- zoomEnd: {
1700
- type: "number",
1701
- description: "End time of zoom in seconds",
1702
- default: void 0
1703
- },
1704
- zoomStartDelay: {
1705
- type: "string",
1706
- description: "Delay before zoom starts in seconds or percentage",
1707
- default: 0
1708
- },
1709
- zoomEndDelay: {
1710
- type: "string",
1711
- description: "Delay before video ends in seconds or percentage",
1712
- default: 0
1713
- },
1714
- zoomDirection: {
1715
- type: "string",
1716
- description: 'Direction of zoom: "in" or "out"',
1717
- default: "in"
1718
- },
1719
- zoomDepth: {
1720
- type: "string",
1721
- description: "Zoom scale factor or array of [progress, scale] pairs",
1722
- default: 1.5
1723
- },
1724
- zoomPosition: {
1725
- type: "string",
1726
- description: "Zoom anchor point: [x, y] coordinates or position string (top-left, center, etc.)",
1727
- default: "center"
1728
- },
1729
- animationType: {
1730
- type: "string",
1731
- description: 'Animation curve: "linear", "spring", "ease-in", "ease-out", "ease-in-out"',
1732
- default: "linear"
1733
- }
1734
- }
1735
- };
1736
-
1737
- // src/components/effects/index.ts
1738
- registerEffect(config8.displayName, BlurEffect, config8);
1739
- registerEffect(config9.displayName, LoopEffect, config9);
1740
- registerEffect(config10.displayName, PanEffect, config10);
1741
- registerEffect(config11.displayName, ZoomEffect, config11);
1742
-
1743
- // src/hooks/useComponentRegistry.ts
1744
- var import_react18 = require("react");
1745
- var useComponentRegistry = () => {
1746
- return (0, import_react18.useMemo)(() => {
1747
- return {
1748
- registerComponent: componentRegistry.registerComponent.bind(componentRegistry),
1749
- registerPackage: componentRegistry.registerPackage.bind(componentRegistry),
1750
- getComponent: componentRegistry.getComponent.bind(componentRegistry),
1751
- getAllComponents: componentRegistry.getAllComponents.bind(componentRegistry)
1752
- };
1753
- }, []);
1754
- };
1755
-
1756
- // src/hooks/useBoundaryCalculation.ts
1757
- var import_react19 = require("react");
1758
- var useBoundaryCalculation = ({
1759
- parentBoundaries,
1760
- constraints,
1761
- layout
1762
- }) => {
1763
- return (0, import_react19.useMemo)(() => {
1764
- const { x, y, width, height } = parentBoundaries;
1765
- const calculatedX = typeof constraints.x === "number" ? constraints.x : x;
1766
- const calculatedY = typeof constraints.y === "number" ? constraints.y : y;
1767
- const calculatedWidth = typeof constraints.width === "number" ? constraints.width : width;
1768
- const calculatedHeight = typeof constraints.height === "number" ? constraints.height : height;
1769
- return {
1770
- x: calculatedX,
1771
- y: calculatedY,
1772
- width: calculatedWidth,
1773
- height: calculatedHeight,
1774
- zIndex: constraints.zIndex || 0
1775
- };
1776
- }, [parentBoundaries, constraints, layout]);
1777
- };
1778
-
1779
- // src/hooks/buildTransitionHook.ts
1780
- var import_react21 = require("react");
1781
-
1782
- // src/core/types/transition.types.ts
1783
- var import_react20 = require("react");
1784
- var LayoutContext = (0, import_react20.createContext)(null);
1785
-
1786
- // src/hooks/buildTransitionHook.ts
1787
- function buildLayoutHook(schema, defaultValue) {
1788
- return () => {
1789
- const context = (0, import_react21.useContext)(LayoutContext);
1790
- if (!context) {
1791
- return defaultValue;
1792
- }
1793
- try {
1794
- const validatedData = schema.parse(context);
1795
- return validatedData;
1796
- } catch (error) {
1797
- console.warn("Transition data validation failed, using defaults:", error);
1798
- return defaultValue;
1799
- }
1800
- };
1801
- }
1802
-
1803
- // src/utils/contextUtils.ts
1804
- var createRootContext = (width, height, duration, fps) => {
1805
- return {
1806
- boundaries: {
1807
- left: 0,
1808
- top: 0,
1809
- width,
1810
- height,
1811
- zIndex: 0
1812
- },
1813
- timing: {
1814
- startInFrames: 0,
1815
- durationInFrames: duration
1816
- },
1817
- hierarchy: {
1818
- depth: 0,
1819
- parentIds: []
1820
- }
1821
- };
1822
- };
1823
- var mergeContexts = (parent, child) => {
1824
- return {
1825
- boundaries: {
1826
- ...parent.boundaries,
1827
- ...child.boundaries
1828
- },
1829
- timing: { ...parent.timing, ...child.timing },
1830
- hierarchy: {
1831
- depth: (parent.hierarchy?.depth || 0) + 1,
1832
- parentIds: [...parent.hierarchy?.parentIds || [], "root"]
1833
- }
1834
- };
1835
- };
1836
-
1837
- // src/utils/boundaryUtils.ts
1838
- var calculateGridPosition = (index, columns, cellWidth, cellHeight, spacing) => {
1839
- const row = Math.floor(index / columns);
1840
- const col = index % columns;
1841
- return {
1842
- x: col * (cellWidth + spacing),
1843
- y: row * (cellHeight + spacing),
1844
- width: cellWidth,
1845
- height: cellHeight
1846
- };
1847
- };
1848
- var calculateCircularPosition = (index, total, radius, centerX, centerY) => {
1849
- const angle = index / total * 2 * Math.PI;
1850
- return {
1851
- x: centerX + radius * Math.cos(angle),
1852
- y: centerY + radius * Math.sin(angle)
1853
- };
1854
- };
1855
-
1856
- // src/templates/rings/NextjsLogo.tsx
1857
- var import_paths = require("@remotion/paths");
1858
- var import_react23 = __toESM(require("react"));
1859
- var import_remotion13 = require("remotion");
1860
-
1861
- // src/templates/rings/RippleOutLayout.tsx
1862
- var import_react22 = __toESM(require("react"));
1863
- var import_remotion12 = require("remotion");
1864
- var import_zod3 = require("zod");
1865
- var import_Inter = require("@remotion/google-fonts/Inter");
1866
- (0, import_Inter.loadFont)("normal", {
1867
- subsets: ["latin"],
1868
- weights: ["400", "700"]
1869
- });
1870
- var RippleOutTransitionSchema = import_zod3.z.object({
1871
- progress: import_zod3.z.number().min(0).max(1),
1872
- logoOut: import_zod3.z.number().min(0).max(1)
1873
- });
1874
- var defaultRippleOutData = {
1875
- progress: 0,
1876
- logoOut: 0
1877
- };
1878
- var useRippleOutLayout = buildLayoutHook(
1879
- RippleOutTransitionSchema,
1880
- defaultRippleOutData
1881
- );
1882
- var container = {
1883
- backgroundColor: "white"
1884
- };
1885
- var RippleOutLayout = ({ data, context, children }) => {
1886
- const {
1887
- transitionStart,
1888
- transitionDuration
1889
- } = data || { transitionStart: 2, transitionDuration: 1 };
1890
- const frame = (0, import_remotion12.useCurrentFrame)();
1891
- const { fps } = (0, import_remotion12.useVideoConfig)();
1892
- const { hierarchy } = useRenderContext();
1893
- const transitionStartFrame = transitionStart * fps;
1894
- const transitionDurationFrames = transitionDuration * fps;
1895
- const logoOut = (0, import_remotion12.spring)({
1896
- fps,
1897
- frame,
1898
- config: {
1899
- damping: 200
1900
- },
1901
- durationInFrames: transitionDurationFrames,
1902
- delay: transitionStartFrame
1903
- });
1904
- const transitionData = {
1905
- progress: logoOut,
1906
- logoOut
1907
- };
1908
- const childrenArray = import_react22.default.Children.toArray(children).filter(
1909
- (child) => import_react22.default.isValidElement(child)
1910
- );
1911
- const [from, to] = childrenArray;
1912
- return /* @__PURE__ */ import_react22.default.createElement(LayoutContext.Provider, { value: transitionData }, /* @__PURE__ */ import_react22.default.createElement(import_remotion12.AbsoluteFill, { style: {
1913
- ...container,
1914
- ...context?.boundaries
1915
- } }, /* @__PURE__ */ import_react22.default.createElement(import_remotion12.Sequence, { name: from.props.componentId + " - " + from.props.id, from: 0, durationInFrames: transitionStartFrame + transitionDurationFrames }, from), /* @__PURE__ */ import_react22.default.createElement(import_remotion12.Sequence, { name: to.props.componentId + " - " + to.props.id, from: transitionStartFrame + transitionDurationFrames / 2 }, to)));
1916
- };
1917
- var rippleOutLayoutConfig = {
1918
- displayName: "RippleOutLayout",
1919
- type: "layout",
1920
- isInnerSequence: true
1921
- };
1922
-
1923
- // src/templates/rings/NextjsLogo.tsx
1924
- var mask = {
1925
- maskType: "alpha"
1926
- };
1927
- var nStroke = "M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z";
1928
- var NextjsLogo = () => {
1929
- const { logoOut } = useRippleOutLayout();
1930
- const outProgress = logoOut;
1931
- const { fps } = (0, import_remotion13.useVideoConfig)();
1932
- const frame = (0, import_remotion13.useCurrentFrame)();
1933
- const evolve1 = (0, import_remotion13.spring)({
1934
- fps,
1935
- frame,
1936
- config: {
1937
- damping: 200
1938
- }
1939
- });
1940
- const evolve2 = (0, import_remotion13.spring)({
1941
- fps,
1942
- frame: frame - 15,
1943
- config: {
1944
- damping: 200
1945
- }
1946
- });
1947
- const evolve3 = (0, import_remotion13.spring)({
1948
- fps,
1949
- frame: frame - 30,
1950
- config: {
1951
- damping: 200,
1952
- mass: 3
1953
- },
1954
- durationInFrames: 30
1955
- });
1956
- const style = (0, import_react23.useMemo)(() => {
1957
- return {
1958
- height: 140,
1959
- borderRadius: 70,
1960
- scale: String(1 - outProgress)
1961
- };
1962
- }, [outProgress]);
1963
- const firstPath = `M 60.0568 54 v 71.97`;
1964
- const secondPath = `M 63.47956 56.17496 L 144.7535 161.1825`;
1965
- const thirdPath = `M 121 54 L 121 126`;
1966
- const evolution1 = (0, import_paths.evolvePath)(evolve1, firstPath);
1967
- const evolution2 = (0, import_paths.evolvePath)(evolve2, secondPath);
1968
- const evolution3 = (0, import_paths.evolvePath)(
1969
- (0, import_remotion13.interpolate)(evolve3, [0, 1], [0, 0.7]),
1970
- thirdPath
1971
- );
1972
- return /* @__PURE__ */ import_react23.default.createElement("svg", { style, fill: "none", viewBox: "0 0 180 180" }, /* @__PURE__ */ import_react23.default.createElement("mask", { height: "180", id: "mask", style: mask, width: "180", x: "0", y: "0" }, /* @__PURE__ */ import_react23.default.createElement("circle", { cx: "90", cy: "90", fill: "black", r: "90" })), /* @__PURE__ */ import_react23.default.createElement("mask", { id: "n-mask", style: mask }, /* @__PURE__ */ import_react23.default.createElement("path", { d: nStroke, fill: "black" })), /* @__PURE__ */ import_react23.default.createElement("g", { mask: "url(#mask)" }, /* @__PURE__ */ import_react23.default.createElement("circle", { cx: "90", cy: "90", fill: "black", r: "90" }), /* @__PURE__ */ import_react23.default.createElement("g", { stroke: "url(#gradient0)", mask: "url(#n-mask)" }, /* @__PURE__ */ import_react23.default.createElement(
1973
- "path",
1974
- {
1975
- strokeWidth: "12.1136",
1976
- d: firstPath,
1977
- strokeDasharray: evolution1.strokeDasharray,
1978
- strokeDashoffset: evolution1.strokeDashoffset
1979
- }
1980
- ), /* @__PURE__ */ import_react23.default.createElement(
1981
- "path",
1982
- {
1983
- strokeWidth: 12.1136,
1984
- d: secondPath,
1985
- strokeDasharray: evolution2.strokeDasharray,
1986
- strokeDashoffset: evolution2.strokeDashoffset
1987
- }
1988
- )), /* @__PURE__ */ import_react23.default.createElement(
1989
- "path",
1990
- {
1991
- stroke: "url(#gradient1)",
1992
- d: thirdPath,
1993
- strokeDasharray: evolution3.strokeDasharray,
1994
- strokeDashoffset: evolution3.strokeDashoffset,
1995
- strokeWidth: "12"
1996
- }
1997
- )), /* @__PURE__ */ import_react23.default.createElement("defs", null, /* @__PURE__ */ import_react23.default.createElement(
1998
- "linearGradient",
1999
- {
2000
- gradientUnits: "userSpaceOnUse",
2001
- id: "gradient0",
2002
- x1: "109",
2003
- x2: "144.5",
2004
- y1: "116.5",
2005
- y2: "160.5"
2006
- },
2007
- /* @__PURE__ */ import_react23.default.createElement("stop", { stopColor: "white" }),
2008
- /* @__PURE__ */ import_react23.default.createElement("stop", { offset: "1", stopColor: "white", stopOpacity: "0" })
2009
- ), /* @__PURE__ */ import_react23.default.createElement(
2010
- "linearGradient",
2011
- {
2012
- gradientUnits: "userSpaceOnUse",
2013
- id: "gradient1",
2014
- x1: "121",
2015
- x2: "120.799",
2016
- y1: "54",
2017
- y2: "106.875"
2018
- },
2019
- /* @__PURE__ */ import_react23.default.createElement("stop", { stopColor: "white" }),
2020
- /* @__PURE__ */ import_react23.default.createElement("stop", { offset: "1", stopColor: "white", stopOpacity: "0" })
2021
- )));
2022
- };
2023
- var nextjsLogoConfig = {
2024
- displayName: "NextjsLogo",
2025
- type: "atom",
2026
- isInnerSequence: false
2027
- };
2028
-
2029
- // src/templates/rings/Rings.tsx
2030
- var import_react24 = __toESM(require("react"));
2031
- var import_remotion14 = require("remotion");
2032
- var RadialGradient = ({ radius, color }) => {
2033
- const height = radius * 2;
2034
- const width = radius * 2;
2035
- return (
2036
- // @ts-ignore
2037
- /* @__PURE__ */ import_react24.default.createElement(
2038
- import_remotion14.AbsoluteFill,
2039
- {
2040
- style: {
2041
- justifyContent: "center",
2042
- alignItems: "center"
2043
- }
2044
- },
2045
- /* @__PURE__ */ import_react24.default.createElement(
2046
- "div",
2047
- {
2048
- style: {
2049
- height,
2050
- width,
2051
- borderRadius: "50%",
2052
- backgroundColor: color,
2053
- position: "absolute",
2054
- boxShadow: "0 0 100px rgba(0, 0, 0, 0.05)"
2055
- }
2056
- }
2057
- )
2058
- )
2059
- );
2060
- };
2061
- var Rings = ({ context, data }) => {
2062
- const { logoOut } = useRippleOutLayout();
2063
- const outProgress = logoOut;
2064
- const scale = 1 / (1 - outProgress);
2065
- const { height } = (0, import_remotion14.useVideoConfig)();
2066
- return (
2067
- // @ts-ignore
2068
- /* @__PURE__ */ import_react24.default.createElement(
2069
- import_remotion14.AbsoluteFill,
2070
- {
2071
- style: {
2072
- transform: `scale(${scale})`,
2073
- ...context?.boundaries
2074
- }
2075
- },
2076
- new Array(5).fill(true).map((_, i) => {
2077
- return /* @__PURE__ */ import_react24.default.createElement(
2078
- RadialGradient,
2079
- {
2080
- key: i,
2081
- radius: height * 0.3 * i,
2082
- color: (0, import_remotion14.interpolateColors)(i, [0, 4], ["#fff", "#fff"])
2083
- }
2084
- );
2085
- }).reverse()
2086
- )
2087
- );
2088
- };
2089
- var ringsConfig = {
2090
- displayName: "Rings",
2091
- type: "atom",
2092
- isInnerSequence: false
2093
- };
2094
-
2095
- // src/templates/rings/TextFade.tsx
2096
- var import_react25 = __toESM(require("react"));
2097
- var import_remotion15 = require("remotion");
2098
- var TextFade = (props) => {
2099
- const { children, context, data } = props;
2100
- const { animation } = data || {
2101
- animation: {
2102
- duration: 1
2103
- }
2104
- };
2105
- const { fps } = (0, import_remotion15.useVideoConfig)();
2106
- const frame = (0, import_remotion15.useCurrentFrame)();
2107
- const progress = (0, import_remotion15.spring)({
2108
- fps,
2109
- frame,
2110
- config: {
2111
- damping: 200
2112
- },
2113
- durationInFrames: animation.duration * fps
2114
- });
2115
- const rightStop = (0, import_remotion15.interpolate)(progress, [0, 1], [200, 0]);
2116
- const leftStop = Math.max(0, rightStop - 60);
2117
- const maskImage = `linear-gradient(-45deg, transparent ${leftStop}%, black ${rightStop}%)`;
2118
- const container2 = (0, import_react25.useMemo)(() => {
2119
- return {
2120
- width: "100%",
2121
- height: "100%",
2122
- justifyContent: "center",
2123
- alignItems: "center"
2124
- };
2125
- }, []);
2126
- const content = (0, import_react25.useMemo)(() => {
2127
- return {
2128
- ...context?.boundaries,
2129
- maskImage,
2130
- WebkitMaskImage: maskImage,
2131
- justifyContent: "center",
2132
- alignItems: "center",
2133
- display: "flex"
2134
- };
2135
- }, [maskImage]);
2136
- return (
2137
- // @ts-ignore
2138
- /* @__PURE__ */ import_react25.default.createElement(import_remotion15.AbsoluteFill, { style: container2 }, /* @__PURE__ */ import_react25.default.createElement("div", { style: content }, children))
2139
- );
2140
- };
2141
- var textFadeConfig = {
2142
- displayName: "TextFade",
2143
- type: "layout",
2144
- isInnerSequence: false
2145
- };
2146
-
2147
- // src/templates/rings/index.ts
2148
- registerComponent(
2149
- nextjsLogoConfig.displayName,
2150
- NextjsLogo,
2151
- "atom",
2152
- nextjsLogoConfig
2153
- );
2154
- registerComponent(
2155
- textFadeConfig.displayName,
2156
- TextFade,
2157
- "layout",
2158
- textFadeConfig
2159
- );
2160
- registerComponent(ringsConfig.displayName, Rings, "atom", ringsConfig);
2161
- registerComponent(
2162
- rippleOutLayoutConfig.displayName,
2163
- RippleOutLayout,
2164
- "layout",
2165
- rippleOutLayoutConfig
2166
- );
2167
-
2168
- // src/templates/waveform/components/WaveformCircle.tsx
2169
- var import_react28 = __toESM(require("react"));
2170
-
2171
- // src/templates/waveform/Waveform.tsx
2172
- var import_react27 = __toESM(require("react"));
2173
- var import_remotion17 = require("remotion");
2174
-
2175
- // src/templates/waveform/hooks/useWaveformData.ts
2176
- var import_react26 = require("react");
2177
- var import_media_utils = require("@remotion/media-utils");
2178
- var import_remotion16 = require("remotion");
2179
- var isValidPowerOfTwo = (num) => {
2180
- return num > 0 && (num & num - 1) === 0;
2181
- };
2182
- var getClosestPowerOfTwo = (num) => {
2183
- if (num <= 0) return 32;
2184
- let power = 1;
2185
- while (power < num) {
2186
- power *= 2;
2187
- }
2188
- const lower = power / 2;
2189
- const upper = power;
2190
- return Math.abs(num - lower) < Math.abs(num - upper) ? lower : upper;
2191
- };
2192
- var useWaveformData = (config12) => {
2193
- const {
2194
- audioSrc,
2195
- numberOfSamples,
2196
- windowInSeconds,
2197
- dataOffsetInSeconds = 0,
2198
- normalize = false,
2199
- frame,
2200
- fps,
2201
- posterize,
2202
- includeFrequencyData = false,
2203
- minDb = -100,
2204
- maxDb = -30
2205
- } = config12;
2206
- const validatedNumberOfSamples = (0, import_react26.useMemo)(() => {
2207
- if (!isValidPowerOfTwo(numberOfSamples)) {
2208
- console.warn(
2209
- `numberOfSamples must be a power of 2. Adjusting ${numberOfSamples} to ${getClosestPowerOfTwo(numberOfSamples)}`
2210
- );
2211
- return getClosestPowerOfTwo(numberOfSamples);
2212
- }
2213
- return numberOfSamples;
2214
- }, [numberOfSamples]);
2215
- const source = (0, import_react26.useMemo)(() => {
2216
- if (audioSrc.startsWith("http")) {
2217
- return audioSrc;
2218
- }
2219
- return (0, import_remotion16.staticFile)(audioSrc);
2220
- }, [audioSrc]);
2221
- const audioData = (0, import_media_utils.useAudioData)(source);
2222
- const adjustedFrame = (0, import_react26.useMemo)(() => {
2223
- if (posterize && posterize > 1) {
2224
- return Math.round(frame / posterize) * posterize;
2225
- }
2226
- return frame;
2227
- }, [frame, posterize]);
2228
- const waveformData = (0, import_react26.useMemo)(() => {
2229
- if (!audioData) return null;
2230
- try {
2231
- const waveform = (0, import_media_utils.visualizeAudioWaveform)({
2232
- fps,
2233
- frame: adjustedFrame,
2234
- audioData,
2235
- numberOfSamples: validatedNumberOfSamples,
2236
- windowInSeconds,
2237
- dataOffsetInSeconds,
2238
- normalize
2239
- });
2240
- return waveform;
2241
- } catch (error2) {
2242
- console.error("Error generating waveform:", error2);
2243
- return null;
2244
- }
2245
- }, [
2246
- audioData,
2247
- adjustedFrame,
2248
- fps,
2249
- validatedNumberOfSamples,
2250
- windowInSeconds,
2251
- dataOffsetInSeconds,
2252
- normalize
2253
- ]);
2254
- const {
2255
- frequencyData,
2256
- amplitudes,
2257
- bass,
2258
- mid,
2259
- treble,
2260
- bassValues,
2261
- midValues,
2262
- trebleValues
2263
- } = (0, import_react26.useMemo)(() => {
2264
- if (!audioData || !includeFrequencyData) {
2265
- return {
2266
- frequencyData: null,
2267
- amplitudes: null,
2268
- bass: null,
2269
- mid: null,
2270
- treble: null,
2271
- bassValues: null,
2272
- midValues: null,
2273
- trebleValues: null
2274
- };
2275
- }
2276
- try {
2277
- const frequencyData2 = (0, import_media_utils.visualizeAudio)({
2278
- fps,
2279
- frame: adjustedFrame,
2280
- audioData,
2281
- numberOfSamples: validatedNumberOfSamples
2282
- });
2283
- const { sampleRate } = audioData;
2284
- const bassValues2 = [];
2285
- const midValues2 = [];
2286
- const trebleValues2 = [];
2287
- for (let i = 0; i < frequencyData2.length; i++) {
2288
- const freq = i * sampleRate / (2 * frequencyData2.length);
2289
- const value = frequencyData2[i];
2290
- if (freq >= 0 && freq < 250) {
2291
- bassValues2.push(value * 2.5);
2292
- } else if (freq >= 250 && freq < 4e3) {
2293
- midValues2.push(value * 3);
2294
- midValues2.push(value * 4.5);
2295
- midValues2.push(value * 5);
2296
- } else if (freq >= 4e3 && freq < sampleRate / 2) {
2297
- trebleValues2.push(value * 30);
2298
- }
2299
- }
2300
- const getAverage = (arr) => arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;
2301
- const bass2 = getAverage(bassValues2);
2302
- const mid2 = getAverage(midValues2);
2303
- const treble2 = getAverage(trebleValues2);
2304
- const amplitudes2 = frequencyData2.map((value) => {
2305
- const db = 20 * Math.log10(value);
2306
- const scaled = (db - minDb) / (maxDb - minDb);
2307
- return Math.max(0, Math.min(1, scaled));
2308
- });
2309
- return {
2310
- frequencyData: frequencyData2,
2311
- amplitudes: amplitudes2,
2312
- bass: bass2,
2313
- mid: mid2,
2314
- treble: treble2,
2315
- bassValues: bassValues2,
2316
- midValues: midValues2,
2317
- trebleValues: trebleValues2.reverse()
2318
- };
2319
- } catch (error2) {
2320
- console.error("Error generating frequency data:", error2);
2321
- return {
2322
- frequencyData: null,
2323
- amplitudes: null,
2324
- bass: null,
2325
- mid: null,
2326
- treble: null
2327
- };
2328
- }
2329
- }, [
2330
- audioData,
2331
- includeFrequencyData,
2332
- adjustedFrame,
2333
- fps,
2334
- validatedNumberOfSamples,
2335
- windowInSeconds,
2336
- dataOffsetInSeconds,
2337
- minDb,
2338
- maxDb
2339
- ]);
2340
- const isLoading = !audioData;
2341
- const error = audioData === null && !isLoading ? "Failed to load audio data" : null;
2342
- return {
2343
- waveformData,
2344
- frequencyData,
2345
- amplitudes,
2346
- audioData,
2347
- isLoading,
2348
- error,
2349
- bass,
2350
- bassValues,
2351
- mid,
2352
- midValues,
2353
- treble,
2354
- trebleValues
2355
- };
2356
- };
2357
-
2358
- // src/templates/waveform/Waveform.tsx
2359
- var WaveformContext = (0, import_react27.createContext)(null);
2360
- var useWaveformContext = () => {
2361
- const context = (0, import_react27.useContext)(WaveformContext);
2362
- if (!context) {
2363
- throw new Error("useWaveformContext must be used within a Waveform component");
2364
- }
2365
- return context;
2366
- };
2367
- var Waveform = ({
2368
- config: config12,
2369
- children,
2370
- className = "",
2371
- style = {}
2372
- }) => {
2373
- const frame = (0, import_remotion17.useCurrentFrame)();
2374
- const { width: videoWidth, height: videoHeight, fps } = (0, import_remotion17.useVideoConfig)();
2375
- const { waveformData, frequencyData, amplitudes, audioData, bass, mid, treble, bassValues, midValues, trebleValues } = useWaveformData({
2376
- audioSrc: config12.audioSrc,
2377
- numberOfSamples: config12.numberOfSamples || 128,
2378
- windowInSeconds: config12.windowInSeconds || 1 / fps,
2379
- dataOffsetInSeconds: config12.dataOffsetInSeconds || 0,
2380
- normalize: config12.normalize || false,
2381
- frame,
2382
- fps,
2383
- posterize: config12.posterize,
2384
- includeFrequencyData: config12.useFrequencyData || false
2385
- });
2386
- const width = config12.width || videoWidth;
2387
- const height = config12.height || videoHeight;
2388
- const contextValue = {
2389
- waveformData,
2390
- frequencyData,
2391
- amplitudes,
2392
- audioData,
2393
- frame,
2394
- fps,
2395
- config: config12,
2396
- width,
2397
- height,
2398
- bass,
2399
- mid,
2400
- treble,
2401
- bassValues,
2402
- midValues,
2403
- trebleValues
2404
- };
2405
- return /* @__PURE__ */ import_react27.default.createElement(WaveformContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react27.default.createElement(
2406
- "div",
2407
- {
2408
- className: `relative ${className}`,
2409
- style: {
2410
- width,
2411
- height,
2412
- position: "relative",
2413
- backgroundColor: config12.backgroundColor || "transparent",
2414
- ...style
2415
- }
2416
- },
2417
- children
2418
- ));
2419
- };
2420
-
2421
- // src/templates/waveform/components/WaveformCircle.tsx
2422
- var WaveformCircle = ({ data }) => {
2423
- const {
2424
- config: config12,
2425
- className = "",
2426
- style = {},
2427
- strokeColor = "#FF6B6B",
2428
- strokeWidth = 3,
2429
- fill = "none",
2430
- opacity = 1,
2431
- radius = 80,
2432
- centerX = 50,
2433
- centerY = 50,
2434
- startAngle = 0,
2435
- endAngle = 360,
2436
- amplitude = 1,
2437
- rotationSpeed = 0,
2438
- gradientStartColor,
2439
- gradientEndColor
2440
- } = data;
2441
- return /* @__PURE__ */ import_react28.default.createElement(Waveform, { config: config12, className, style }, /* @__PURE__ */ import_react28.default.createElement(
2442
- WaveformCircleContent,
2443
- {
2444
- strokeColor,
2445
- strokeWidth,
2446
- fill,
2447
- opacity,
2448
- radius,
2449
- centerX,
2450
- centerY,
2451
- startAngle,
2452
- endAngle,
2453
- amplitude,
2454
- rotationSpeed,
2455
- gradientStartColor,
2456
- gradientEndColor
2457
- }
2458
- ));
2459
- };
2460
- var WaveformCircleContent = ({
2461
- strokeColor,
2462
- strokeWidth,
2463
- fill,
2464
- opacity,
2465
- radius,
2466
- centerX,
2467
- centerY,
2468
- startAngle,
2469
- endAngle,
2470
- amplitude,
2471
- rotationSpeed,
2472
- gradientStartColor,
2473
- gradientEndColor
2474
- }) => {
2475
- const { waveformData, width, height, frame } = useWaveformContext();
2476
- const circleRadius = Math.min(width, height) * (radius || 80) / 100;
2477
- const circleCenterX = width * (centerX || 50) / 100;
2478
- const circleCenterY = height * (centerY || 50) / 100;
2479
- const rotation = frame * (rotationSpeed || 0) % 360;
2480
- const circularPath = (0, import_react28.useMemo)(() => {
2481
- if (!waveformData) return "";
2482
- const totalAngle = (endAngle || 360) - (startAngle || 0);
2483
- const angleStep = totalAngle / waveformData.length;
2484
- let path = "";
2485
- waveformData.forEach((value, index) => {
2486
- const angle = ((startAngle || 0) + index * angleStep + rotation) * (Math.PI / 180);
2487
- const waveRadius = circleRadius + value * (amplitude || 1) * circleRadius * 0.3;
2488
- const x = circleCenterX + waveRadius * Math.cos(angle);
2489
- const y = circleCenterY + waveRadius * Math.sin(angle);
2490
- if (index === 0) {
2491
- path += `M ${x} ${y}`;
2492
- } else {
2493
- path += ` L ${x} ${y}`;
2494
- }
2495
- });
2496
- if (Math.abs((endAngle || 360) - (startAngle || 0)) >= 360) {
2497
- path += " Z";
2498
- }
2499
- return path;
2500
- }, [waveformData, circleRadius, circleCenterX, circleCenterY, startAngle, endAngle, rotation, amplitude]);
2501
- if (!waveformData) {
2502
- return /* @__PURE__ */ import_react28.default.createElement("div", { className: "flex items-center justify-center w-full h-full text-gray-500" }, "Loading circular waveform...");
2503
- }
2504
- const gradientId = "circle-waveform-gradient";
2505
- const hasGradient = gradientStartColor && gradientEndColor;
2506
- return /* @__PURE__ */ import_react28.default.createElement(
2507
- "svg",
2508
- {
2509
- width,
2510
- height,
2511
- className: "absolute inset-0",
2512
- style: { pointerEvents: "none" }
2513
- },
2514
- hasGradient && /* @__PURE__ */ import_react28.default.createElement("defs", null, /* @__PURE__ */ import_react28.default.createElement("linearGradient", { id: gradientId, x1: "0%", y1: "0%", x2: "100%", y2: "0%" }, /* @__PURE__ */ import_react28.default.createElement("stop", { offset: "0%", stopColor: gradientStartColor }), /* @__PURE__ */ import_react28.default.createElement("stop", { offset: "100%", stopColor: gradientEndColor }))),
2515
- /* @__PURE__ */ import_react28.default.createElement(
2516
- "path",
2517
- {
2518
- d: circularPath,
2519
- stroke: hasGradient ? `url(#${gradientId})` : strokeColor,
2520
- strokeWidth,
2521
- fill,
2522
- opacity,
2523
- strokeLinecap: "round",
2524
- strokeLinejoin: "round"
2525
- }
2526
- )
2527
- );
2528
- };
2529
-
2530
- // src/templates/waveform/components/WaveformHistogram.tsx
2531
- var import_react29 = __toESM(require("react"));
2532
- var WaveformHistogram = ({ data }) => {
2533
- const {
2534
- config: config12,
2535
- className = "",
2536
- style = {},
2537
- barColor = "#FF6B6B",
2538
- barWidth = 4,
2539
- barSpacing = 2,
2540
- barBorderRadius = 2,
2541
- opacity = 1,
2542
- horizontalSymmetry = true,
2543
- verticalMirror = false,
2544
- histogramStyle = "centered",
2545
- amplitude = 1,
2546
- multiplier = 1,
2547
- gradientStartColor,
2548
- gradientEndColor,
2549
- gradientDirection = "vertical",
2550
- gradientStyle = "normal",
2551
- waveDirection = "right-to-left"
2552
- } = data;
2553
- return /* @__PURE__ */ import_react29.default.createElement(Waveform, { config: config12, className, style }, /* @__PURE__ */ import_react29.default.createElement(
2554
- WaveformHistogramContent,
2555
- {
2556
- barColor,
2557
- barWidth,
2558
- barSpacing,
2559
- barBorderRadius,
2560
- opacity,
2561
- horizontalSymmetry,
2562
- verticalMirror,
2563
- histogramStyle,
2564
- amplitude,
2565
- gradientStartColor,
2566
- gradientEndColor,
2567
- gradientDirection,
2568
- multiplier,
2569
- gradientStyle,
2570
- waveDirection
2571
- }
2572
- ));
2573
- };
2574
- var WaveformHistogramContent = ({
2575
- barColor,
2576
- barWidth,
2577
- barSpacing,
2578
- barBorderRadius,
2579
- opacity,
2580
- horizontalSymmetry,
2581
- verticalMirror,
2582
- histogramStyle,
2583
- amplitude,
2584
- gradientStartColor,
2585
- gradientEndColor,
2586
- gradientDirection,
2587
- multiplier,
2588
- gradientStyle,
2589
- waveDirection
2590
- }) => {
2591
- const { waveformData, frequencyData, amplitudes, width, height } = useWaveformContext();
2592
- const dataToUse = amplitudes || waveformData;
2593
- if (!dataToUse) {
2594
- return /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center justify-center w-full h-full text-gray-500" }, "Loading histogram...");
2595
- }
2596
- let directedData = waveDirection === "left-to-right" ? dataToUse.slice(1).reverse() : dataToUse;
2597
- const frequencies = horizontalSymmetry ? [...directedData, ...directedData.slice(1).reverse()] : Array(multiplier).fill(directedData).flat();
2598
- const Bars = ({ growUpwards }) => {
2599
- const styleGradientProp = gradientStartColor && gradientEndColor ? {
2600
- background: `linear-gradient(${gradientDirection === "horizontal" ? gradientStyle === "mirrored" ? "to right" : growUpwards ? "to right" : "to left" : gradientStyle === "normal" ? growUpwards ? "to top" : "to bottom" : "to bottom"}, ${gradientStartColor}, ${gradientEndColor})`
2601
- } : { backgroundColor: barColor };
2602
- const containerStyle2 = {
2603
- display: "flex",
2604
- flexDirection: "row",
2605
- alignItems: growUpwards ? "flex-end" : "flex-start",
2606
- height: "100%",
2607
- width: "100%",
2608
- ...histogramStyle === "centered" && {
2609
- justifyContent: "center",
2610
- gap: `${barSpacing}px`
2611
- },
2612
- ...histogramStyle === "full-width" && {
2613
- gap: `${barSpacing}px`,
2614
- justifyContent: "space-between"
2615
- },
2616
- opacity: gradientStyle === "mirrored" && !growUpwards ? 0.25 : 1
2617
- };
2618
- return /* @__PURE__ */ import_react29.default.createElement("div", { style: containerStyle2 }, frequencies.map((value, index) => /* @__PURE__ */ import_react29.default.createElement(
2619
- "div",
2620
- {
2621
- key: index,
2622
- style: {
2623
- ...histogramStyle === "full-width" ? { width: `${barWidth}px` } : { width: `${barWidth}px` },
2624
- ...styleGradientProp,
2625
- height: `${Math.min(
2626
- height / 2,
2627
- Math.abs(value) * (height / 2) * (amplitude || 1)
2628
- )}px`,
2629
- borderRadius: growUpwards ? `${barBorderRadius}px ${barBorderRadius}px 0 0` : `0 0 ${barBorderRadius}px ${barBorderRadius}px`,
2630
- opacity
2631
- }
2632
- }
2633
- )));
2634
- };
2635
- if (verticalMirror) {
2636
- const topHalfStyle = {
2637
- position: "absolute",
2638
- bottom: `calc(100% - ${height / 2}px)`,
2639
- height: `${height / 2}px`,
2640
- width: "100%",
2641
- left: 0
2642
- };
2643
- const bottomHalfStyle = {
2644
- position: "absolute",
2645
- top: `${height / 2}px`,
2646
- height: `${height / 2}px`,
2647
- width: "100%",
2648
- left: 0
2649
- };
2650
- return /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement("div", { style: topHalfStyle }, /* @__PURE__ */ import_react29.default.createElement(Bars, { growUpwards: true })), /* @__PURE__ */ import_react29.default.createElement("div", { style: bottomHalfStyle }, /* @__PURE__ */ import_react29.default.createElement(Bars, { growUpwards: false })));
2651
- }
2652
- const containerStyle = {
2653
- width: "100%",
2654
- position: "absolute",
2655
- top: `${height / 2 - height / 4}px`,
2656
- height: `${height / 2}px`,
2657
- left: 0
2658
- };
2659
- return /* @__PURE__ */ import_react29.default.createElement("div", { style: containerStyle }, /* @__PURE__ */ import_react29.default.createElement(Bars, { growUpwards: true }));
2660
- };
2661
-
2662
- // src/templates/waveform/components/WaveformHistogramRanged.tsx
2663
- var import_react30 = __toESM(require("react"));
2664
- var WaveformHistogramRanged = ({ data }) => {
2665
- const {
2666
- config: config12,
2667
- className = "",
2668
- style = {},
2669
- barColor = "#FF6B6B",
2670
- barWidth = 4,
2671
- barSpacing = 2,
2672
- barBorderRadius = 2,
2673
- opacity = 1,
2674
- verticalMirror = false,
2675
- histogramStyle = "centered",
2676
- amplitude = 1,
2677
- showFrequencyRanges = true,
2678
- rangeDividerColor = "#666",
2679
- rangeLabels = false,
2680
- bassBarColor = "#5DADE2",
2681
- midBarColor = "#58D68D",
2682
- trebleBarColor = "#F5B041",
2683
- gradientStartColor,
2684
- gradientEndColor,
2685
- gradientDirection = "vertical",
2686
- gradientStyle = "normal",
2687
- horizontalSymmetry = false,
2688
- waveDirection = "right-to-left"
2689
- } = data;
2690
- return /* @__PURE__ */ import_react30.default.createElement(Waveform, { config: config12, className, style }, /* @__PURE__ */ import_react30.default.createElement(
2691
- WaveformHistogramRangedContent,
2692
- {
2693
- barColor,
2694
- barWidth,
2695
- barSpacing,
2696
- barBorderRadius,
2697
- opacity,
2698
- verticalMirror,
2699
- histogramStyle,
2700
- amplitude,
2701
- showFrequencyRanges,
2702
- rangeDividerColor,
2703
- rangeLabels,
2704
- bassBarColor,
2705
- midBarColor,
2706
- trebleBarColor,
2707
- gradientStartColor,
2708
- gradientEndColor,
2709
- gradientDirection,
2710
- gradientStyle,
2711
- horizontalSymmetry,
2712
- waveDirection
2713
- }
2714
- ));
2715
- };
2716
- var WaveformHistogramRangedContent = ({
2717
- barColor,
2718
- barWidth,
2719
- barSpacing,
2720
- barBorderRadius,
2721
- opacity,
2722
- verticalMirror,
2723
- histogramStyle,
2724
- amplitude,
2725
- showFrequencyRanges,
2726
- rangeDividerColor,
2727
- rangeLabels,
2728
- bassBarColor,
2729
- midBarColor,
2730
- trebleBarColor,
2731
- gradientStartColor,
2732
- gradientEndColor,
2733
- gradientDirection,
2734
- gradientStyle,
2735
- horizontalSymmetry,
2736
- waveDirection
2737
- }) => {
2738
- const { amplitudes, bassValues, midValues, trebleValues, height } = useWaveformContext();
2739
- if (!amplitudes || !bassValues || !midValues || !trebleValues) {
2740
- return /* @__PURE__ */ import_react30.default.createElement("div", { className: "flex items-center justify-center w-full h-full text-gray-500" }, "Loading frequency data...");
2741
- }
2742
- const bassFrequencies = bassValues;
2743
- const midFrequencies = midValues;
2744
- const trebleFrequencies = trebleValues;
2745
- const allFrequencies = waveDirection === "right-to-left" ? [bassFrequencies, midFrequencies, trebleFrequencies].flat() : [trebleFrequencies, midFrequencies, bassFrequencies].flat();
2746
- const unifiedWaveform = horizontalSymmetry ? [...allFrequencies.slice(1).reverse(), ...allFrequencies] : allFrequencies;
2747
- const Bars = ({ growUpwards }) => {
2748
- const containerStyle2 = {
2749
- display: "flex",
2750
- flexDirection: "row",
2751
- alignItems: growUpwards ? "flex-end" : "flex-start",
2752
- height: "100%",
2753
- width: "100%",
2754
- ...histogramStyle === "centered" && {
2755
- justifyContent: "center",
2756
- gap: `${barSpacing}px`
2757
- },
2758
- ...histogramStyle === "full-width" && {
2759
- gap: `${barSpacing}px`,
2760
- justifyContent: "space-between"
2761
- },
2762
- opacity: gradientStyle === "mirrored" && !growUpwards ? 0.25 : 1
2763
- };
2764
- return /* @__PURE__ */ import_react30.default.createElement("div", { style: containerStyle2 }, unifiedWaveform.map((value, index) => {
2765
- const rangeName = index === 0 ? "Bass" : index === 1 ? "Mid" : "Treble";
2766
- const styleGradientProp = gradientStartColor && gradientEndColor ? {
2767
- background: `linear-gradient(${gradientDirection === "horizontal" ? gradientStyle === "mirrored" ? "to right" : growUpwards ? "to right" : "to left" : gradientStyle === "normal" ? growUpwards ? "to top" : "to bottom" : "to bottom"}, ${gradientStartColor}, ${gradientEndColor})`
2768
- } : { backgroundColor: barColor };
2769
- return /* @__PURE__ */ import_react30.default.createElement(
2770
- "div",
2771
- {
2772
- key: index,
2773
- style: {
2774
- width: `${barWidth || 4}px`,
2775
- // Wider bars for the three ranges
2776
- ...styleGradientProp,
2777
- height: `${Math.min(
2778
- height / 2,
2779
- Math.abs(value) * (height / 2) * (amplitude || 1)
2780
- )}px`,
2781
- borderRadius: growUpwards ? `${barBorderRadius}px ${barBorderRadius}px 0 0` : `0 0 ${barBorderRadius}px ${barBorderRadius}px`,
2782
- opacity,
2783
- position: "relative"
2784
- },
2785
- title: `${rangeName}: ${(value * 100).toFixed(1)}%`
2786
- },
2787
- rangeLabels && /* @__PURE__ */ import_react30.default.createElement("div", { style: {
2788
- position: "absolute",
2789
- bottom: growUpwards ? "-20px" : "auto",
2790
- top: growUpwards ? "auto" : "-20px",
2791
- left: "50%",
2792
- transform: "translateX(-50%)",
2793
- fontSize: "10px",
2794
- color: rangeDividerColor,
2795
- whiteSpace: "nowrap"
2796
- } }, rangeName)
2797
- );
2798
- }));
2799
- };
2800
- if (verticalMirror) {
2801
- const topHalfStyle = {
2802
- position: "absolute",
2803
- bottom: `calc(100% - ${height / 2}px)`,
2804
- height: `${height / 2}px`,
2805
- width: "100%",
2806
- left: 0
2807
- };
2808
- const bottomHalfStyle = {
2809
- position: "absolute",
2810
- top: `${height / 2}px`,
2811
- height: `${height / 2}px`,
2812
- width: "100%",
2813
- left: 0
2814
- };
2815
- return /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, /* @__PURE__ */ import_react30.default.createElement("div", { style: topHalfStyle }, /* @__PURE__ */ import_react30.default.createElement(Bars, { growUpwards: true })), /* @__PURE__ */ import_react30.default.createElement("div", { style: bottomHalfStyle }, /* @__PURE__ */ import_react30.default.createElement(Bars, { growUpwards: false })));
2816
- }
2817
- const containerStyle = {
2818
- width: "100%",
2819
- position: "absolute",
2820
- top: `${height / 2 - height / 4}px`,
2821
- height: `${height / 2}px`,
2822
- left: 0
2823
- };
2824
- return /* @__PURE__ */ import_react30.default.createElement("div", { style: containerStyle }, /* @__PURE__ */ import_react30.default.createElement(Bars, { growUpwards: true }));
2825
- };
2826
-
2827
- // src/templates/waveform/components/WaveformLine.tsx
2828
- var import_react31 = __toESM(require("react"));
2829
- var import_media_utils2 = require("@remotion/media-utils");
2830
- var import_remotion18 = require("remotion");
2831
- var detectBeat = (frequencyData, amplitudes, threshold = 0.7, bpm, frame = 0, fps = 30) => {
2832
- if (!frequencyData || !amplitudes || frequencyData.length === 0) return false;
2833
- if (bpm) {
2834
- const beatInterval = 60 / bpm * fps;
2835
- const beatFrame = Math.round(frame / beatInterval) * beatInterval;
2836
- return Math.abs(frame - beatFrame) < 2;
2837
- }
2838
- const bassFrequencies = amplitudes.slice(0, Math.floor(amplitudes.length * 0.15));
2839
- const midFrequencies = amplitudes.slice(Math.floor(amplitudes.length * 0.15), Math.floor(amplitudes.length * 0.4));
2840
- const bassEnergy = Math.sqrt(bassFrequencies.reduce((sum, val) => sum + val * val, 0) / bassFrequencies.length);
2841
- const midEnergy = Math.sqrt(midFrequencies.reduce((sum, val) => sum + val * val, 0) / midFrequencies.length);
2842
- const bassPeak = Math.max(...bassFrequencies);
2843
- const midPeak = Math.max(...midFrequencies);
2844
- const totalEnergy = bassEnergy * 0.6 + midEnergy * 0.2 + bassPeak * 0.15 + midPeak * 0.05;
2845
- const normalizedEnergy = Math.min(totalEnergy, 1);
2846
- return normalizedEnergy > threshold;
2847
- };
2848
- var easingFunctions = {
2849
- linear: (t) => t,
2850
- "ease-in": (t) => t * t,
2851
- "ease-out": (t) => 1 - (1 - t) * (1 - t),
2852
- "ease-in-out": (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
2853
- bounce: (t) => {
2854
- if (t < 1 / 2.75) return 7.5625 * t * t;
2855
- if (t < 2 / 2.75) return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
2856
- if (t < 2.5 / 2.75) return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
2857
- return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
2858
- }
2859
- };
2860
- var WaveformLine = ({ data }) => {
2861
- const {
2862
- config: config12,
2863
- className = "",
2864
- style = {},
2865
- strokeColor = "#FF6B6B",
2866
- strokeWidth = 3,
2867
- strokeLinecap = "round",
2868
- strokeLinejoin = "round",
2869
- fill = "none",
2870
- opacity = 1,
2871
- centerLine = false,
2872
- centerLineColor = "#666",
2873
- centerLineWidth = 1,
2874
- beatSync = false,
2875
- bpm,
2876
- beatThreshold = 0.7,
2877
- beatAmplitudeMultiplier = 1.2,
2878
- beatAnimationDuration = 30,
2879
- smoothAnimation = true,
2880
- waveSpacing = 0.1,
2881
- waveSegments = 1,
2882
- waveOffset = 0,
2883
- waveDirection = "horizontal",
2884
- amplitudeCurve = "ease-out",
2885
- animationSpeed = 0.5,
2886
- pulseOnBeat = false,
2887
- pulseColor = "#FFD700",
2888
- pulseScale = 1.2
2889
- } = data;
2890
- return /* @__PURE__ */ import_react31.default.createElement(Waveform, { config: config12, className, style }, /* @__PURE__ */ import_react31.default.createElement(
2891
- WaveformLineContent,
2892
- {
2893
- strokeColor,
2894
- strokeWidth,
2895
- strokeLinecap,
2896
- strokeLinejoin,
2897
- fill,
2898
- opacity,
2899
- centerLine,
2900
- centerLineColor,
2901
- centerLineWidth,
2902
- beatSync,
2903
- bpm,
2904
- beatThreshold,
2905
- beatAmplitudeMultiplier,
2906
- beatAnimationDuration,
2907
- smoothAnimation,
2908
- waveSpacing,
2909
- waveSegments,
2910
- waveOffset,
2911
- waveDirection,
2912
- amplitudeCurve,
2913
- animationSpeed,
2914
- pulseOnBeat,
2915
- pulseColor,
2916
- pulseScale
2917
- }
2918
- ));
2919
- };
2920
- var WaveformLineContent = ({
2921
- strokeColor,
2922
- strokeWidth,
2923
- strokeLinecap,
2924
- strokeLinejoin,
2925
- fill,
2926
- opacity,
2927
- centerLine,
2928
- centerLineColor,
2929
- centerLineWidth,
2930
- beatSync,
2931
- bpm,
2932
- beatThreshold,
2933
- beatAmplitudeMultiplier,
2934
- beatAnimationDuration,
2935
- smoothAnimation,
2936
- waveSpacing,
2937
- waveSegments,
2938
- waveOffset,
2939
- waveDirection,
2940
- amplitudeCurve,
2941
- animationSpeed,
2942
- pulseOnBeat,
2943
- pulseColor,
2944
- pulseScale
2945
- }) => {
2946
- const { waveformData, frequencyData, amplitudes, width, height, config: config12, frame, fps } = useWaveformContext();
2947
- const currentFrame = (0, import_remotion18.useCurrentFrame)();
2948
- const videoConfig = (0, import_remotion18.useVideoConfig)();
2949
- const isBeat = (0, import_react31.useMemo)(() => {
2950
- if (!beatSync || !frequencyData || !amplitudes) return false;
2951
- return detectBeat(frequencyData, amplitudes, beatThreshold, bpm, currentFrame, fps);
2952
- }, [beatSync, frequencyData, amplitudes, beatThreshold, bpm, currentFrame, fps]);
2953
- const beatProgress = (0, import_react31.useMemo)(() => {
2954
- if (!isBeat || !beatAnimationDuration) return 0;
2955
- const beatStartFrame = Math.floor(currentFrame / beatAnimationDuration) * beatAnimationDuration;
2956
- const progress = (currentFrame - beatStartFrame) / beatAnimationDuration;
2957
- const clampedProgress = Math.max(0, Math.min(1, progress));
2958
- if (smoothAnimation) {
2959
- return 1 - Math.pow(1 - clampedProgress, 3);
2960
- }
2961
- return clampedProgress;
2962
- }, [isBeat, currentFrame, beatAnimationDuration, smoothAnimation]);
2963
- const currentBeatMultiplier = (0, import_react31.useMemo)(() => {
2964
- if (!beatSync || !isBeat || !beatAmplitudeMultiplier || !amplitudeCurve) return 1;
2965
- const easing = easingFunctions[amplitudeCurve];
2966
- const easedProgress = easing(beatProgress);
2967
- return 1 + (beatAmplitudeMultiplier - 1) * (1 - easedProgress);
2968
- }, [beatSync, isBeat, beatProgress, beatAmplitudeMultiplier, amplitudeCurve]);
2969
- const smoothFactor = (0, import_react31.useMemo)(() => {
2970
- if (!beatSync) {
2971
- return 0.3;
2972
- }
2973
- return smoothAnimation ? 0.7 : 1;
2974
- }, [beatSync, smoothAnimation]);
2975
- const waveformPaths = (0, import_react31.useMemo)(() => {
2976
- if (!waveformData) return [];
2977
- const paths = [];
2978
- const segments = waveSegments || 1;
2979
- const spacing = waveSpacing || 0.1;
2980
- const offset = waveOffset || 0;
2981
- const speed = animationSpeed || 1;
2982
- const segmentWidth = width / segments;
2983
- const segmentSpacing = segmentWidth * spacing;
2984
- for (let i = 0; i < segments; i++) {
2985
- const segmentStart = i * segmentWidth;
2986
- const segmentEnd = (i + 1) * segmentWidth;
2987
- const segmentDataWidth = segmentEnd - segmentStart;
2988
- const points = waveformData.map((y, index) => {
2989
- const progress = index / (waveformData.length - 1);
2990
- const x = segmentStart + progress * segmentDataWidth + offset;
2991
- let animatedAmplitude = y * (config12.amplitude || 1) * currentBeatMultiplier * speed;
2992
- const baseAmplitude = y * (config12.amplitude || 1) * speed;
2993
- const beatAmplitude = animatedAmplitude - baseAmplitude;
2994
- animatedAmplitude = baseAmplitude + beatAmplitude * smoothFactor;
2995
- const yPos = waveDirection === "horizontal" ? animatedAmplitude * height / 2 + height / 2 : animatedAmplitude * width / 2 + width / 2;
2996
- return waveDirection === "horizontal" ? { x, y: yPos } : { x: yPos, y: x };
2997
- });
2998
- const path = (0, import_media_utils2.createSmoothSvgPath)({ points });
2999
- paths.push({ path, segmentIndex: i });
3000
- }
3001
- return paths;
3002
- }, [waveformData, width, height, config12.amplitude, currentBeatMultiplier, animationSpeed, waveSegments, waveSpacing, waveOffset, waveDirection, smoothFactor]);
3003
- if (!waveformData) {
3004
- return /* @__PURE__ */ import_react31.default.createElement("div", { className: "flex items-center justify-center w-full h-full text-gray-500" }, "Loading waveform...");
3005
- }
3006
- return /* @__PURE__ */ import_react31.default.createElement(
3007
- "svg",
3008
- {
3009
- width,
3010
- height,
3011
- className: "absolute inset-0",
3012
- style: { pointerEvents: "none" }
3013
- },
3014
- centerLine && /* @__PURE__ */ import_react31.default.createElement(
3015
- "line",
3016
- {
3017
- x1: waveDirection === "horizontal" ? 0 : width / 2,
3018
- y1: waveDirection === "horizontal" ? height / 2 : 0,
3019
- x2: waveDirection === "horizontal" ? width : width / 2,
3020
- y2: waveDirection === "horizontal" ? height / 2 : height,
3021
- stroke: centerLineColor,
3022
- strokeWidth: centerLineWidth,
3023
- opacity: 0.3
3024
- }
3025
- ),
3026
- waveformPaths.map(({ path, segmentIndex }) => /* @__PURE__ */ import_react31.default.createElement("g", { key: segmentIndex }, pulseOnBeat && isBeat && /* @__PURE__ */ import_react31.default.createElement(
3027
- "path",
3028
- {
3029
- d: path,
3030
- stroke: pulseColor,
3031
- strokeWidth: (strokeWidth || 3) * (pulseScale || 1.2),
3032
- strokeLinecap,
3033
- strokeLinejoin,
3034
- fill: "none",
3035
- opacity: (opacity || 1) * (1 - beatProgress)
3036
- }
3037
- ), /* @__PURE__ */ import_react31.default.createElement(
3038
- "path",
3039
- {
3040
- d: path,
3041
- stroke: strokeColor,
3042
- strokeWidth,
3043
- strokeLinecap,
3044
- strokeLinejoin,
3045
- fill,
3046
- opacity
3047
- }
3048
- )))
3049
- );
3050
- };
3051
-
3052
- // src/templates/waveform/utils.ts
3053
- var WaveformPresets = {
3054
- stopgapLine: (props) => {
3055
- return {
3056
- componentId: "WaveformLine",
3057
- type: "atom",
3058
- data: {
3059
- strokeColor: "#58C4DC",
3060
- strokeWidth: 8,
3061
- strokeLinecap: "round",
3062
- opacity: 1,
3063
- amplitudeCurve: "ease-in-out",
3064
- animationSpeed: 0.15,
3065
- smoothAnimation: true,
3066
- ...props,
3067
- config: {
3068
- numberOfSamples: 64,
3069
- // Increased for better frequency resolution
3070
- windowInSeconds: 1 / 30,
3071
- amplitude: 4,
3072
- height: 300,
3073
- width: 1920 * 3,
3074
- posterize: 4,
3075
- ...props.config
3076
- }
3077
- }
3078
- };
3079
- }
3080
- };
3081
-
3082
- // src/templates/waveform/index.ts
3083
- registerComponent("WaveformLine", WaveformLine, "atom", {
3084
- displayName: "WaveformLine"
3085
- });
3086
- registerComponent("WaveformHistogram", WaveformHistogram, "atom", {
3087
- displayName: "WaveformHistogram"
3088
- });
3089
- registerComponent("WaveformHistogramRanged", WaveformHistogramRanged, "atom", {
3090
- displayName: "WaveformHistogramRanged"
3091
- });
3092
- registerComponent("WaveformCircle", WaveformCircle, "atom", {
3093
- displayName: "WaveformCircle"
3094
- });
3095
-
3096
- // src/components/Composition.tsx
3097
- var import_react32 = __toESM(require("react"));
3098
- var import_remotion19 = require("remotion");
3099
-
3100
- // src/core/context/timing.ts
3101
- var import_mediabunny = require("mediabunny");
3102
- var findMatchingComponents = (childrenData, targetIds) => {
3103
- const matches = [];
3104
- const searchRecursively = (components) => {
3105
- for (const component of components) {
3106
- if (targetIds.includes(component.id)) {
3107
- matches.push(component);
3108
- }
3109
- if (component.childrenData && component.childrenData.length > 0) {
3110
- searchRecursively(component.childrenData);
3111
- }
3112
- }
3113
- };
3114
- searchRecursively(childrenData);
3115
- return matches;
3116
- };
3117
- var calculateDuration = async (childrenData, config12) => {
3118
- let calculatedDuration = void 0;
3119
- const targetIds = Array.isArray(config12.fitDurationTo) ? config12.fitDurationTo : [config12.fitDurationTo];
3120
- const matchingComponents = findMatchingComponents(
3121
- childrenData || [],
3122
- targetIds
3123
- );
3124
- if (matchingComponents.length === 1) {
3125
- if (matchingComponents[0].type === "atom" && (matchingComponents[0].componentId === "AudioAtom" || matchingComponents[0].componentId === "VideoAtom")) {
3126
- const src = matchingComponents[0].data.src;
3127
- if (src.startsWith("http")) {
3128
- const audioInput = new import_mediabunny.Input({
3129
- formats: import_mediabunny.ALL_FORMATS,
3130
- source: new import_mediabunny.UrlSource(src)
3131
- });
3132
- calculatedDuration = await audioInput.computeDuration();
3133
- } else {
3134
- }
3135
- }
3136
- }
3137
- return calculatedDuration;
3138
- };
3139
- var setDurationsInContext = async (root) => {
3140
- const iterateRecursively = async (components) => {
3141
- const updatedComponents = [];
3142
- for (const component of components) {
3143
- let updatedComponent = { ...component };
3144
- if (component.context?.timing?.fitDurationTo?.length > 0) {
3145
- const duration = await calculateDuration(component.childrenData, {
3146
- fitDurationTo: component.context?.timing?.fitDurationTo
3147
- });
3148
- updatedComponent = {
3149
- ...component,
3150
- context: {
3151
- ...component.context,
3152
- timing: {
3153
- ...component.context.timing,
3154
- duration
3155
- }
3156
- }
3157
- };
3158
- }
3159
- if (component.childrenData && component.childrenData.length > 0) {
3160
- updatedComponent.childrenData = await iterateRecursively(
3161
- component.childrenData
3162
- );
3163
- }
3164
- updatedComponents.push(updatedComponent);
3165
- }
3166
- return updatedComponents;
3167
- };
3168
- const updatedChildrenData = await iterateRecursively(root.childrenData);
3169
- return {
3170
- ...root,
3171
- childrenData: updatedChildrenData
3172
- };
3173
- };
3174
-
3175
- // src/components/Composition.tsx
3176
- var CompositionLayout = ({ childrenData, style, config: config12 }) => {
3177
- return /* @__PURE__ */ import_react32.default.createElement(
3178
- CompositionProvider,
3179
- {
3180
- value: {
3181
- root: childrenData,
3182
- duration: config12.duration
3183
- }
3184
- },
3185
- /* @__PURE__ */ import_react32.default.createElement(import_remotion19.AbsoluteFill, { style }, childrenData?.map((component) => /* @__PURE__ */ import_react32.default.createElement(
3186
- ComponentRenderer,
3187
- {
3188
- key: component.id,
3189
- ...component
3190
- }
3191
- )))
3192
- );
3193
- };
3194
- var calculateCompositionLayoutMetadata = async ({ props, defaultProps, abortSignal, isRendering }) => {
3195
- let calculatedDuration = void 0;
3196
- if (props.config?.fitDurationTo?.length > 0) {
3197
- calculatedDuration = await calculateDuration(props.childrenData, {
3198
- fitDurationTo: props.config.fitDurationTo
3199
- });
3200
- }
3201
- const duration = calculatedDuration ?? props.config.duration ?? defaultProps.config.duration;
3202
- const fps = props.config.fps ?? defaultProps.config.fps;
3203
- const durationInFrames = Math.round(duration * fps);
3204
- const updatedProps = await setDurationsInContext(props);
3205
- return {
3206
- // Change the metadata
3207
- durationInFrames,
3208
- // or transform some props
3209
- props: updatedProps,
3210
- // // or add per-composition default codec
3211
- // defaultCodec: 'h264',
3212
- // // or add per-composition default video image format
3213
- // defaultVideoImageFormat: 'png',
3214
- // // or add per-composition default pixel format
3215
- // defaultPixelFormat: 'yuv420p',
3216
- width: props.config?.width || defaultProps.config.width,
3217
- height: props.config?.height || defaultProps.config.height,
3218
- fps,
3219
- duration
3220
- };
3221
- };
3222
- var Composition = ({
3223
- id,
3224
- childrenData,
3225
- config: config12,
3226
- style
3227
- }) => {
3228
- return /* @__PURE__ */ import_react32.default.createElement(
3229
- import_remotion19.Composition,
3230
- {
3231
- id,
3232
- component: CompositionLayout,
3233
- durationInFrames: Math.round(config12.duration * config12.fps),
3234
- fps: config12.fps,
3235
- defaultProps: { childrenData, style, config: config12 },
3236
- calculateMetadata: calculateCompositionLayoutMetadata
3237
- }
3238
- );
3239
- };
3240
- // Annotate the CommonJS export names for ESM import in node:
3241
- 0 && (module.exports = {
3242
- AudioAtom,
3243
- AudioAtomConfig,
3244
- BaseLayout,
3245
- BaseLayoutConfig,
3246
- BlurEffect,
3247
- BlurEffectConfig,
3248
- ComponentRenderer,
3249
- Composition,
3250
- CompositionLayout,
3251
- CompositionProvider,
3252
- Frame,
3253
- ImageAtom,
3254
- ImageAtomConfig,
3255
- LoopEffect,
3256
- LoopEffectConfig,
3257
- NextjsLogo,
3258
- PanEffect,
3259
- PanEffectConfig,
3260
- Rings,
3261
- RippleOutLayout,
3262
- SceneFrame,
3263
- ShapeAtom,
3264
- ShapeAtomConfig,
3265
- TextAtom,
3266
- TextAtomConfig,
3267
- TextAtomWithFonts,
3268
- TextAtomWithFontsConfig,
3269
- TextFade,
3270
- VideoAtom,
3271
- VideoAtomConfig,
3272
- Waveform,
3273
- WaveformCircle,
3274
- WaveformHistogram,
3275
- WaveformHistogramRanged,
3276
- WaveformLine,
3277
- WaveformPresets,
3278
- ZoomEffect,
3279
- ZoomEffectConfig,
3280
- buildLayoutHook,
3281
- calculateCircularPosition,
3282
- calculateCompositionLayoutMetadata,
3283
- calculateGridPosition,
3284
- calculateHierarchy,
3285
- calculateTimingWithInheritance,
3286
- clearFontCache,
3287
- componentRegistry,
3288
- createRootContext,
3289
- findComponentById,
3290
- findParentComponent,
3291
- getComponent,
3292
- getComponentConfig,
3293
- getComponentWithConfig,
3294
- getLoadedFontFamily,
3295
- getLoadedFonts,
3296
- getNormalizedFontName,
3297
- isFontAvailable,
3298
- isFontLoaded,
3299
- loadGoogleFont,
3300
- loadMultipleFonts,
3301
- mergeContexts,
3302
- nextjsLogoConfig,
3303
- preloadCommonFonts,
3304
- registerComponent,
3305
- registerEffect,
3306
- registerPackage,
3307
- ringsConfig,
3308
- rippleOutLayoutConfig,
3309
- textFadeConfig,
3310
- useBoundaryCalculation,
3311
- useComponentRegistry,
3312
- useComposition,
3313
- useFont,
3314
- useFontLoader,
3315
- useRenderContext,
3316
- useRippleOutLayout,
3317
- useWaveformContext,
3318
- useWaveformData
3319
- });
3320
- //# sourceMappingURL=index.js.map