ugcinc-render 1.8.10 → 1.8.11

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.d.mts CHANGED
@@ -670,6 +670,36 @@ interface ScreenshotAnimationCompositionProps {
670
670
  }
671
671
  declare function ScreenshotAnimationComposition({ imageUrl, width, height, flashDurationMs, shrinkDurationMs, pauseDurationMs, dismissDurationMs, imageCornerRadius, thumbnailCornerRadius, borderWidth, borderColor, thumbnailScale, thumbnailPadding, bottomOffset, springDamping, springStiffness, springMass, backgroundColor, }: ScreenshotAnimationCompositionProps): react_jsx_runtime.JSX.Element;
672
672
 
673
+ /**
674
+ * ScreenshotAnimationV2
675
+ *
676
+ * Accurate iPhone screenshot animation based on real device measurements.
677
+ *
678
+ * Timeline:
679
+ * - 0-1000ms: Pause (show image)
680
+ * - 1000-1255ms: Phase 1 (flash & reveal, content shifts down 50%)
681
+ * - 1255ms+: Phase 2 (container shrinks, content morphs to thumbnail)
682
+ */
683
+ interface ScreenshotAnimationV2Props {
684
+ /** The image URL being "screenshotted" */
685
+ imageUrl: string;
686
+ /** Canvas width in pixels */
687
+ width?: number;
688
+ /** Canvas height in pixels */
689
+ height?: number;
690
+ /** Duration of pause before flash (ms) */
691
+ pauseDurationMs?: number;
692
+ /** Duration of flash phase (ms) */
693
+ flashDurationMs?: number;
694
+ /** Border corner radius (px) */
695
+ borderRadius?: number;
696
+ /** Border color */
697
+ borderColor?: string;
698
+ /** Background color (behind everything) */
699
+ backgroundColor?: string;
700
+ }
701
+ declare function ScreenshotAnimationV2({ imageUrl, width, height, pauseDurationMs, flashDurationMs, borderRadius, borderColor, backgroundColor, }: ScreenshotAnimationV2Props): react_jsx_runtime.JSX.Element;
702
+
673
703
  interface TextElementProps {
674
704
  segment: TextSegment;
675
705
  /** Optional scale for high-DPI rendering */
@@ -802,4 +832,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
802
832
 
803
833
  declare const RenderRoot: React.FC;
804
834
 
805
- export { type Acceleration, type AudioConfig, type AudioSegment, AutoCaptionComposition, AutoCaptionCompositionProps, AutoCaptionCompositionWithVideo, type BaseEditorConfig, type BaseSegment, type BlendMode, BorderRadiusConfig, CaptionOverlay, CaptionOverlayProps, type Channel, type ColorFilterConfig, type ColorShiftConfig, type CropConfig, type CuttingConfig, DEDUPLICATION_LEVELS, type DeduplicationConfig, type DeduplicationInput, type DeduplicationLevel, type DiagonalFilterConfig, type DiagonalFilterType, DynamicCropConfig, type EditorConfig, type EditorSegment, type EnhanceLevel, type EnhancementConfig, FitMode, type FrameManipulationConfig, type GifOverlayConfig, type GifSource, type GradientOverlayConfig, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, ImageEditorElement, ImageElement, type ImageElementProps, type ImageSegment, LEVEL_1_CONFIG, LEVEL_2_CONFIG, LEVEL_3_CONFIG, LEVEL_4_CONFIG, LEVEL_5_CONFIG, type LensCorrectionConfig, type MobileEncodingConfig, type ParticleOverlayConfig, type PhoneConfig, type PhoneModel, type PhoneType, type PictureSegment, PositionResolutionResult, RelativePositionConfigX, RelativePositionConfigY, RenderRoot, ScreenshotAnimationComposition, type ScreenshotAnimationCompositionProps, type Segment, SegmentType, type SpeedConfig, type StaticSegment, TextElement, type TextElementProps, type TextSegment, TextStyleProperties, TimeValue, type TraceRemovalConfig, type VideoCodec, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, VideoElement, type VideoElementProps, type VideoExtension, type VideoSegment, type VisualAdjustmentsConfig, type VisualSegment, type VisualSegmentUnion, isDeduplicationLevel, resolveDeduplicationConfig, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions };
835
+ export { type Acceleration, type AudioConfig, type AudioSegment, AutoCaptionComposition, AutoCaptionCompositionProps, AutoCaptionCompositionWithVideo, type BaseEditorConfig, type BaseSegment, type BlendMode, BorderRadiusConfig, CaptionOverlay, CaptionOverlayProps, type Channel, type ColorFilterConfig, type ColorShiftConfig, type CropConfig, type CuttingConfig, DEDUPLICATION_LEVELS, type DeduplicationConfig, type DeduplicationInput, type DeduplicationLevel, type DiagonalFilterConfig, type DiagonalFilterType, DynamicCropConfig, type EditorConfig, type EditorSegment, type EnhanceLevel, type EnhancementConfig, FitMode, type FrameManipulationConfig, type GifOverlayConfig, type GifSource, type GradientOverlayConfig, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, ImageEditorElement, ImageElement, type ImageElementProps, type ImageSegment, LEVEL_1_CONFIG, LEVEL_2_CONFIG, LEVEL_3_CONFIG, LEVEL_4_CONFIG, LEVEL_5_CONFIG, type LensCorrectionConfig, type MobileEncodingConfig, type ParticleOverlayConfig, type PhoneConfig, type PhoneModel, type PhoneType, type PictureSegment, PositionResolutionResult, RelativePositionConfigX, RelativePositionConfigY, RenderRoot, ScreenshotAnimationComposition, type ScreenshotAnimationCompositionProps, ScreenshotAnimationV2, type ScreenshotAnimationV2Props, type Segment, SegmentType, type SpeedConfig, type StaticSegment, TextElement, type TextElementProps, type TextSegment, TextStyleProperties, TimeValue, type TraceRemovalConfig, type VideoCodec, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, VideoElement, type VideoElementProps, type VideoExtension, type VideoSegment, type VisualAdjustmentsConfig, type VisualSegment, type VisualSegmentUnion, isDeduplicationLevel, resolveDeduplicationConfig, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions };
package/dist/index.d.ts CHANGED
@@ -670,6 +670,36 @@ interface ScreenshotAnimationCompositionProps {
670
670
  }
671
671
  declare function ScreenshotAnimationComposition({ imageUrl, width, height, flashDurationMs, shrinkDurationMs, pauseDurationMs, dismissDurationMs, imageCornerRadius, thumbnailCornerRadius, borderWidth, borderColor, thumbnailScale, thumbnailPadding, bottomOffset, springDamping, springStiffness, springMass, backgroundColor, }: ScreenshotAnimationCompositionProps): react_jsx_runtime.JSX.Element;
672
672
 
673
+ /**
674
+ * ScreenshotAnimationV2
675
+ *
676
+ * Accurate iPhone screenshot animation based on real device measurements.
677
+ *
678
+ * Timeline:
679
+ * - 0-1000ms: Pause (show image)
680
+ * - 1000-1255ms: Phase 1 (flash & reveal, content shifts down 50%)
681
+ * - 1255ms+: Phase 2 (container shrinks, content morphs to thumbnail)
682
+ */
683
+ interface ScreenshotAnimationV2Props {
684
+ /** The image URL being "screenshotted" */
685
+ imageUrl: string;
686
+ /** Canvas width in pixels */
687
+ width?: number;
688
+ /** Canvas height in pixels */
689
+ height?: number;
690
+ /** Duration of pause before flash (ms) */
691
+ pauseDurationMs?: number;
692
+ /** Duration of flash phase (ms) */
693
+ flashDurationMs?: number;
694
+ /** Border corner radius (px) */
695
+ borderRadius?: number;
696
+ /** Border color */
697
+ borderColor?: string;
698
+ /** Background color (behind everything) */
699
+ backgroundColor?: string;
700
+ }
701
+ declare function ScreenshotAnimationV2({ imageUrl, width, height, pauseDurationMs, flashDurationMs, borderRadius, borderColor, backgroundColor, }: ScreenshotAnimationV2Props): react_jsx_runtime.JSX.Element;
702
+
673
703
  interface TextElementProps {
674
704
  segment: TextSegment;
675
705
  /** Optional scale for high-DPI rendering */
@@ -802,4 +832,4 @@ declare function useResolvedPositions(elements: ImageEditorElement[], textValues
802
832
 
803
833
  declare const RenderRoot: React.FC;
804
834
 
805
- export { type Acceleration, type AudioConfig, type AudioSegment, AutoCaptionComposition, AutoCaptionCompositionProps, AutoCaptionCompositionWithVideo, type BaseEditorConfig, type BaseSegment, type BlendMode, BorderRadiusConfig, CaptionOverlay, CaptionOverlayProps, type Channel, type ColorFilterConfig, type ColorShiftConfig, type CropConfig, type CuttingConfig, DEDUPLICATION_LEVELS, type DeduplicationConfig, type DeduplicationInput, type DeduplicationLevel, type DiagonalFilterConfig, type DiagonalFilterType, DynamicCropConfig, type EditorConfig, type EditorSegment, type EnhanceLevel, type EnhancementConfig, FitMode, type FrameManipulationConfig, type GifOverlayConfig, type GifSource, type GradientOverlayConfig, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, ImageEditorElement, ImageElement, type ImageElementProps, type ImageSegment, LEVEL_1_CONFIG, LEVEL_2_CONFIG, LEVEL_3_CONFIG, LEVEL_4_CONFIG, LEVEL_5_CONFIG, type LensCorrectionConfig, type MobileEncodingConfig, type ParticleOverlayConfig, type PhoneConfig, type PhoneModel, type PhoneType, type PictureSegment, PositionResolutionResult, RelativePositionConfigX, RelativePositionConfigY, RenderRoot, ScreenshotAnimationComposition, type ScreenshotAnimationCompositionProps, type Segment, SegmentType, type SpeedConfig, type StaticSegment, TextElement, type TextElementProps, type TextSegment, TextStyleProperties, TimeValue, type TraceRemovalConfig, type VideoCodec, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, VideoElement, type VideoElementProps, type VideoExtension, type VideoSegment, type VisualAdjustmentsConfig, type VisualSegment, type VisualSegmentUnion, isDeduplicationLevel, resolveDeduplicationConfig, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions };
835
+ export { type Acceleration, type AudioConfig, type AudioSegment, AutoCaptionComposition, AutoCaptionCompositionProps, AutoCaptionCompositionWithVideo, type BaseEditorConfig, type BaseSegment, type BlendMode, BorderRadiusConfig, CaptionOverlay, CaptionOverlayProps, type Channel, type ColorFilterConfig, type ColorShiftConfig, type CropConfig, type CuttingConfig, DEDUPLICATION_LEVELS, type DeduplicationConfig, type DeduplicationInput, type DeduplicationLevel, type DiagonalFilterConfig, type DiagonalFilterType, DynamicCropConfig, type EditorConfig, type EditorSegment, type EnhanceLevel, type EnhancementConfig, FitMode, type FrameManipulationConfig, type GifOverlayConfig, type GifSource, type GradientOverlayConfig, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, ImageEditorElement, ImageElement, type ImageElementProps, type ImageSegment, LEVEL_1_CONFIG, LEVEL_2_CONFIG, LEVEL_3_CONFIG, LEVEL_4_CONFIG, LEVEL_5_CONFIG, type LensCorrectionConfig, type MobileEncodingConfig, type ParticleOverlayConfig, type PhoneConfig, type PhoneModel, type PhoneType, type PictureSegment, PositionResolutionResult, RelativePositionConfigX, RelativePositionConfigY, RenderRoot, ScreenshotAnimationComposition, type ScreenshotAnimationCompositionProps, ScreenshotAnimationV2, type ScreenshotAnimationV2Props, type Segment, SegmentType, type SpeedConfig, type StaticSegment, TextElement, type TextElementProps, type TextSegment, TextStyleProperties, TimeValue, type TraceRemovalConfig, type VideoCodec, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, VideoElement, type VideoElementProps, type VideoExtension, type VideoSegment, type VisualAdjustmentsConfig, type VisualSegment, type VisualSegmentUnion, isDeduplicationLevel, resolveDeduplicationConfig, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions };
package/dist/index.js CHANGED
@@ -50,6 +50,7 @@ __export(index_exports, {
50
50
  LEVEL_5_CONFIG: () => LEVEL_5_CONFIG,
51
51
  RenderRoot: () => RenderRoot,
52
52
  ScreenshotAnimationComposition: () => ScreenshotAnimationComposition,
53
+ ScreenshotAnimationV2: () => ScreenshotAnimationV2,
53
54
  TEXT_DEFAULTS: () => TEXT_DEFAULTS,
54
55
  TextElement: () => TextElement,
55
56
  VIDEO_DEFAULTS: () => VIDEO_DEFAULTS,
@@ -2400,6 +2401,425 @@ function ScreenshotAnimationComposition({
2400
2401
  ] });
2401
2402
  }
2402
2403
 
2404
+ // src/compositions/ScreenshotAnimationV2.tsx
2405
+ var import_remotion8 = require("remotion");
2406
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2407
+ var KEYFRAMES = {
2408
+ // Screenshot container outer bounds (including border)
2409
+ ssBorderTop: [
2410
+ [255, 0.0623],
2411
+ [295, 0.2017],
2412
+ [335, 0.3443],
2413
+ [375, 0.508],
2414
+ [415, 0.584],
2415
+ [455, 0.6367],
2416
+ [495, 0.7023],
2417
+ [535, 0.7065],
2418
+ [575, 0.7255],
2419
+ [615, 0.7329],
2420
+ [655, 0.7371],
2421
+ [695, 0.7413],
2422
+ [735, 0.7434],
2423
+ [835, 0.7434],
2424
+ [935, 0.7455],
2425
+ [1135, 0.7455]
2426
+ ],
2427
+ ssBorderTopInner: [
2428
+ [255, 0.0697],
2429
+ [295, 0.208],
2430
+ [335, 0.3517],
2431
+ [375, 0.5132],
2432
+ [415, 0.5882],
2433
+ [455, 0.642],
2434
+ [495, 0.7076],
2435
+ [535, 0.7138],
2436
+ [575, 0.7308],
2437
+ [615, 0.7381],
2438
+ [655, 0.7423],
2439
+ [695, 0.7466],
2440
+ [735, 0.7487],
2441
+ [835, 0.7497],
2442
+ [935, 0.7497],
2443
+ [1135, 0.7508]
2444
+ ],
2445
+ ssBorderRight: [
2446
+ [255, 0.9584],
2447
+ [295, 0.8245],
2448
+ [335, 0.6951],
2449
+ [375, 0.5404],
2450
+ [415, 0.4734],
2451
+ [455, 0.4226],
2452
+ [495, 0.3742],
2453
+ [535, 0.3557],
2454
+ [575, 0.3418],
2455
+ [615, 0.3349],
2456
+ [655, 0.3279],
2457
+ [695, 0.3257],
2458
+ [735, 0.3257],
2459
+ [835, 0.321],
2460
+ [935, 0.321],
2461
+ [1135, 0.321]
2462
+ ],
2463
+ ssBorderLeft: [
2464
+ [255, 0],
2465
+ [295, 0.0115],
2466
+ [335, 0.0323],
2467
+ [375, 0.0554],
2468
+ [415, 0.067],
2469
+ [455, 0.0739],
2470
+ [495, 0.0808],
2471
+ [535, 0.0831],
2472
+ [575, 0.0877],
2473
+ [615, 0.0877],
2474
+ [655, 0.0901],
2475
+ [695, 0.0901],
2476
+ [735, 0.0901],
2477
+ [835, 0.0901],
2478
+ [935, 0.0901],
2479
+ [1135, 0.0901]
2480
+ ],
2481
+ ssBorderBottom: [
2482
+ [255, 1],
2483
+ [295, 0.9947],
2484
+ [335, 0.9842],
2485
+ [375, 0.9747],
2486
+ [415, 0.9683],
2487
+ [455, 0.9662],
2488
+ [495, 0.9757],
2489
+ [535, 0.962],
2490
+ [575, 0.9599],
2491
+ [615, 0.9588],
2492
+ [655, 0.9588],
2493
+ [695, 0.9588],
2494
+ [735, 0.9588],
2495
+ [835, 0.9588],
2496
+ [935, 0.9588],
2497
+ [1135, 0.9588]
2498
+ ],
2499
+ // Inner content positions
2500
+ imgTop: [
2501
+ [255, 0.5248],
2502
+ [295, 0.5702],
2503
+ [335, 0.6178],
2504
+ [375, 0.6726],
2505
+ [415, 0.6969],
2506
+ [455, 0.7138],
2507
+ [495, 0.7455],
2508
+ [535, 0.7381],
2509
+ [575, 0.7434],
2510
+ [615, 0.7466],
2511
+ [655, 0.7487],
2512
+ [695, 0.7508]
2513
+ // After 735ms, imgTop matches container inner top (content fills container)
2514
+ ],
2515
+ imgClipRight: [
2516
+ [255, 0.2125],
2517
+ [295, 0.2286],
2518
+ [335, 0.2494],
2519
+ [375, 0.2725],
2520
+ [415, 0.2817],
2521
+ [455, 0.291],
2522
+ [495, 0.2979],
2523
+ [535, 0.3002],
2524
+ [575, 0.3025],
2525
+ [615, 0.3025],
2526
+ [655, 0.3002],
2527
+ [695, 0.3095]
2528
+ // After 735ms, clip fills container width
2529
+ ],
2530
+ imgClipBottom: [
2531
+ [255, 0.7233],
2532
+ [295, 0.7698],
2533
+ [335, 0.8184],
2534
+ [375, 0.8722],
2535
+ [415, 0.8975],
2536
+ [455, 0.9145],
2537
+ [495, 0.9504],
2538
+ [535, 0.9472],
2539
+ [575, 0.944],
2540
+ [615, 0.9472],
2541
+ [655, 0.9483],
2542
+ [695, 0.9504]
2543
+ // After 735ms, clip fills container height
2544
+ ],
2545
+ // White overlay opacity (derived from black RGBA: value/255)
2546
+ whiteOpacity: [
2547
+ [255, 0.824],
2548
+ [295, 0.773],
2549
+ [335, 0.722],
2550
+ [375, 0.639],
2551
+ [415, 0.58],
2552
+ [455, 0.522],
2553
+ [495, 0.427],
2554
+ [535, 0.376],
2555
+ [575, 0.345],
2556
+ [615, 0.267],
2557
+ [655, 0.245],
2558
+ [695, 0.165],
2559
+ [735, 0.106],
2560
+ [835, 0.065],
2561
+ [935, 0.039],
2562
+ [1135, 0.014]
2563
+ ],
2564
+ // Gray fill color (RGB values for gap above shifted content)
2565
+ grayFillR: [
2566
+ [255, 241],
2567
+ [295, 237],
2568
+ [335, 231],
2569
+ [375, 224],
2570
+ [415, 219],
2571
+ [455, 213],
2572
+ [495, 205],
2573
+ [535, 200],
2574
+ [575, 191],
2575
+ [615, 188],
2576
+ [655, 188],
2577
+ [695, 174]
2578
+ ],
2579
+ grayFillG: [
2580
+ [255, 239],
2581
+ [295, 234],
2582
+ [335, 228],
2583
+ [375, 221],
2584
+ [415, 217],
2585
+ [455, 210],
2586
+ [495, 203],
2587
+ [535, 197],
2588
+ [575, 189],
2589
+ [615, 187],
2590
+ [655, 187],
2591
+ [695, 169]
2592
+ ],
2593
+ grayFillB: [
2594
+ [255, 242],
2595
+ [295, 237],
2596
+ [335, 231],
2597
+ [375, 224],
2598
+ [415, 220],
2599
+ [455, 216],
2600
+ [495, 206],
2601
+ [535, 200],
2602
+ [575, 192],
2603
+ [615, 190],
2604
+ [655, 190],
2605
+ [695, 171]
2606
+ ],
2607
+ // Inner content bottom corner radius (0 = square, 1 = fully rounded)
2608
+ innerCornerRadius: [
2609
+ [655, 0],
2610
+ [695, 0.15],
2611
+ [735, 0.5],
2612
+ [835, 1]
2613
+ ]
2614
+ };
2615
+ function interpolateKeyframes(keyframes, timeMs, defaultValue) {
2616
+ if (keyframes.length === 0) {
2617
+ return defaultValue ?? 0;
2618
+ }
2619
+ if (timeMs <= keyframes[0][0]) {
2620
+ return keyframes[0][1];
2621
+ }
2622
+ if (timeMs >= keyframes[keyframes.length - 1][0]) {
2623
+ return keyframes[keyframes.length - 1][1];
2624
+ }
2625
+ for (let i = 0; i < keyframes.length - 1; i++) {
2626
+ const [t1, v1] = keyframes[i];
2627
+ const [t2, v2] = keyframes[i + 1];
2628
+ if (timeMs >= t1 && timeMs <= t2) {
2629
+ const progress = (timeMs - t1) / (t2 - t1);
2630
+ return v1 + (v2 - v1) * progress;
2631
+ }
2632
+ }
2633
+ return keyframes[keyframes.length - 1][1];
2634
+ }
2635
+ function ScreenshotAnimationV2({
2636
+ imageUrl,
2637
+ width = 1080,
2638
+ height = 1920,
2639
+ pauseDurationMs = 1e3,
2640
+ flashDurationMs = 255,
2641
+ borderRadius = 16,
2642
+ borderColor = "rgba(80, 80, 80, 0.8)",
2643
+ backgroundColor = "#000000"
2644
+ }) {
2645
+ const frame = (0, import_remotion8.useCurrentFrame)();
2646
+ const { fps } = (0, import_remotion8.useVideoConfig)();
2647
+ const timeMs = frame / fps * 1e3;
2648
+ const flashStartMs = pauseDurationMs;
2649
+ const flashEndMs = flashStartMs + flashDurationMs;
2650
+ const phase2StartMs = flashEndMs;
2651
+ const animationTimeMs = Math.max(0, timeMs - flashStartMs);
2652
+ const isPause = timeMs < flashStartMs;
2653
+ const isFlashPhase = timeMs >= flashStartMs && timeMs < flashEndMs;
2654
+ const isPhase2 = timeMs >= phase2StartMs;
2655
+ let whiteOpacity = 0;
2656
+ if (isPause) {
2657
+ whiteOpacity = 0;
2658
+ } else if (isFlashPhase) {
2659
+ const flashProgress = (timeMs - flashStartMs) / flashDurationMs;
2660
+ whiteOpacity = (0, import_remotion8.interpolate)(flashProgress, [0, 0.1, 1], [1, 1, 0.824], {
2661
+ extrapolateRight: "clamp"
2662
+ });
2663
+ } else if (isPhase2) {
2664
+ whiteOpacity = interpolateKeyframes(KEYFRAMES.whiteOpacity, animationTimeMs);
2665
+ }
2666
+ const containerTop = interpolateKeyframes(KEYFRAMES.ssBorderTop, animationTimeMs);
2667
+ const containerTopInner = interpolateKeyframes(KEYFRAMES.ssBorderTopInner, animationTimeMs);
2668
+ const containerLeft = interpolateKeyframes(KEYFRAMES.ssBorderLeft, animationTimeMs);
2669
+ const containerRight = interpolateKeyframes(KEYFRAMES.ssBorderRight, animationTimeMs);
2670
+ const containerBottom = interpolateKeyframes(KEYFRAMES.ssBorderBottom, animationTimeMs);
2671
+ const borderWidth = (containerTopInner - containerTop) * height;
2672
+ const containerX = containerLeft * width;
2673
+ const containerY = containerTop * height;
2674
+ const containerW = (containerRight - containerLeft) * width;
2675
+ const containerH = (containerBottom - containerTop) * height;
2676
+ const contentX = containerX + borderWidth;
2677
+ const contentY = containerY + borderWidth;
2678
+ const contentW = containerW - borderWidth * 2;
2679
+ const contentH = containerH - borderWidth * 2;
2680
+ const imgTopPercent = interpolateKeyframes(KEYFRAMES.imgTop, animationTimeMs);
2681
+ const imgClipRightPercent = interpolateKeyframes(KEYFRAMES.imgClipRight, animationTimeMs);
2682
+ const imgClipBottomPercent = interpolateKeyframes(KEYFRAMES.imgClipBottom, animationTimeMs);
2683
+ const thumbnailFilled = animationTimeMs >= 735;
2684
+ const grayR = interpolateKeyframes(KEYFRAMES.grayFillR, animationTimeMs);
2685
+ const grayG = interpolateKeyframes(KEYFRAMES.grayFillG, animationTimeMs);
2686
+ const grayB = interpolateKeyframes(KEYFRAMES.grayFillB, animationTimeMs);
2687
+ const grayColor = `rgb(${Math.round(grayR)}, ${Math.round(grayG)}, ${Math.round(grayB)})`;
2688
+ const innerCornerProgress = interpolateKeyframes(KEYFRAMES.innerCornerRadius, animationTimeMs);
2689
+ const innerBorderRadius = borderRadius * innerCornerProgress;
2690
+ const grayGapTop = contentY;
2691
+ const grayGapBottom = imgTopPercent * height;
2692
+ const grayGapHeight = Math.max(0, grayGapBottom - grayGapTop);
2693
+ const largeImgTop = imgTopPercent * height;
2694
+ const largeImgLeft = contentX;
2695
+ const largeImgWidth = contentW;
2696
+ const largeImgHeight = height;
2697
+ const smallClipTop = imgTopPercent * height;
2698
+ const smallClipLeft = contentX;
2699
+ const smallClipRight = imgClipRightPercent * width;
2700
+ const smallClipBottom = imgClipBottomPercent * height;
2701
+ const smallClipWidth = smallClipRight - smallClipLeft;
2702
+ const smallClipHeight = smallClipBottom - smallClipTop;
2703
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_remotion8.AbsoluteFill, { style: { backgroundColor }, children: [
2704
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2705
+ import_remotion8.Img,
2706
+ {
2707
+ src: imageUrl,
2708
+ style: {
2709
+ position: "absolute",
2710
+ top: 0,
2711
+ left: 0,
2712
+ width,
2713
+ height,
2714
+ objectFit: "cover"
2715
+ }
2716
+ }
2717
+ ),
2718
+ isPhase2 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2719
+ "div",
2720
+ {
2721
+ style: {
2722
+ position: "absolute",
2723
+ left: containerX,
2724
+ top: containerY,
2725
+ width: containerW,
2726
+ height: containerH,
2727
+ borderRadius,
2728
+ border: `${borderWidth}px solid ${borderColor}`,
2729
+ boxSizing: "border-box",
2730
+ overflow: "hidden"
2731
+ },
2732
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2733
+ "div",
2734
+ {
2735
+ style: {
2736
+ position: "absolute",
2737
+ left: 0,
2738
+ top: 0,
2739
+ width: contentW,
2740
+ height: contentH,
2741
+ overflow: "hidden",
2742
+ borderRadius: `${borderRadius - borderWidth}px ${borderRadius - borderWidth}px ${innerBorderRadius}px ${innerBorderRadius}px`
2743
+ },
2744
+ children: [
2745
+ !thumbnailFilled && grayGapHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2746
+ "div",
2747
+ {
2748
+ style: {
2749
+ position: "absolute",
2750
+ left: 0,
2751
+ top: 0,
2752
+ width: contentW,
2753
+ height: grayGapBottom - containerTopInner * height,
2754
+ backgroundColor: grayColor
2755
+ }
2756
+ }
2757
+ ),
2758
+ !thumbnailFilled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2759
+ "div",
2760
+ {
2761
+ style: {
2762
+ position: "absolute",
2763
+ left: 0,
2764
+ top: largeImgTop - containerTopInner * height,
2765
+ width: contentW,
2766
+ height: largeImgHeight,
2767
+ overflow: "hidden"
2768
+ },
2769
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2770
+ import_remotion8.Img,
2771
+ {
2772
+ src: imageUrl,
2773
+ style: {
2774
+ width: contentW,
2775
+ height: contentW * (height / width),
2776
+ // Maintain aspect ratio
2777
+ objectFit: "cover"
2778
+ }
2779
+ }
2780
+ )
2781
+ }
2782
+ ),
2783
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2784
+ "div",
2785
+ {
2786
+ style: {
2787
+ position: "absolute",
2788
+ left: 0,
2789
+ top: thumbnailFilled ? 0 : smallClipTop - containerTopInner * height,
2790
+ width: thumbnailFilled ? contentW : smallClipWidth,
2791
+ height: thumbnailFilled ? contentH : smallClipHeight,
2792
+ overflow: "hidden"
2793
+ },
2794
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2795
+ import_remotion8.Img,
2796
+ {
2797
+ src: imageUrl,
2798
+ style: {
2799
+ width: thumbnailFilled ? contentW : smallClipWidth,
2800
+ height: thumbnailFilled ? contentH : smallClipWidth * (height / width),
2801
+ objectFit: "cover"
2802
+ }
2803
+ }
2804
+ )
2805
+ }
2806
+ )
2807
+ ]
2808
+ }
2809
+ )
2810
+ }
2811
+ ),
2812
+ whiteOpacity > 1e-3 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2813
+ import_remotion8.AbsoluteFill,
2814
+ {
2815
+ style: {
2816
+ backgroundColor: `rgba(255, 254, 255, ${whiteOpacity})`
2817
+ }
2818
+ }
2819
+ )
2820
+ ] });
2821
+ }
2822
+
2403
2823
  // src/utils/fit.ts
2404
2824
  function calculateFitDimensions({
2405
2825
  sourceWidth,
@@ -2765,9 +3185,9 @@ function useResolvedPositions(elements, textValues) {
2765
3185
  }
2766
3186
 
2767
3187
  // src/Root.tsx
2768
- var import_remotion8 = require("remotion");
3188
+ var import_remotion9 = require("remotion");
2769
3189
  var import_zod = require("zod");
2770
- var import_jsx_runtime9 = require("react/jsx-runtime");
3190
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2771
3191
  var defaultImageProps = {
2772
3192
  config: {
2773
3193
  width: 1080,
@@ -2835,6 +3255,26 @@ var defaultScreenshotAnimationProps = {
2835
3255
  // Background
2836
3256
  backgroundColor: "#000000"
2837
3257
  };
3258
+ var defaultScreenshotAnimationV2Props = {
3259
+ imageUrl: "https://images.unsplash.com/photo-1611162617474-5b21e879e113?w=1080&h=1920&fit=crop",
3260
+ width: 1080,
3261
+ height: 1920,
3262
+ pauseDurationMs: 1e3,
3263
+ flashDurationMs: 255,
3264
+ borderRadius: 16,
3265
+ borderColor: "rgba(80, 80, 80, 0.8)",
3266
+ backgroundColor: "#000000"
3267
+ };
3268
+ var screenshotAnimationV2Schema = import_zod.z.object({
3269
+ imageUrl: import_zod.z.string().describe("URL of the image being screenshotted"),
3270
+ width: import_zod.z.number().optional().default(1080).describe("Canvas width (px)"),
3271
+ height: import_zod.z.number().optional().default(1920).describe("Canvas height (px)"),
3272
+ pauseDurationMs: import_zod.z.number().optional().default(1e3).describe("Pause before flash (ms)"),
3273
+ flashDurationMs: import_zod.z.number().optional().default(255).describe("Flash phase duration (ms)"),
3274
+ borderRadius: import_zod.z.number().optional().default(16).describe("Border corner radius (px)"),
3275
+ borderColor: import_zod.z.string().optional().default("rgba(80, 80, 80, 0.8)").describe("Border color"),
3276
+ backgroundColor: import_zod.z.string().optional().default("#000000").describe("Background color")
3277
+ });
2838
3278
  var screenshotAnimationSchema = import_zod.z.object({
2839
3279
  // Core
2840
3280
  imageUrl: import_zod.z.string().describe("URL of the image to screenshot"),
@@ -2866,6 +3306,7 @@ var ImageComp = ImageEditorComposition;
2866
3306
  var VideoComp = VideoEditorComposition;
2867
3307
  var AutoCaptionComp = AutoCaptionComposition;
2868
3308
  var ScreenshotAnimationComp = ScreenshotAnimationComposition;
3309
+ var ScreenshotAnimationV2Comp = ScreenshotAnimationV2;
2869
3310
  var calculateImageMetadata = async ({ props }) => {
2870
3311
  console.log("[calculateMetadata] Starting metadata calculation...");
2871
3312
  const canvasWidth = props.width ?? props.config?.width ?? 1080;
@@ -2916,9 +3357,9 @@ var calculateImageMetadata = async ({ props }) => {
2916
3357
  };
2917
3358
  };
2918
3359
  var RenderRoot = () => {
2919
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2920
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2921
- import_remotion8.Composition,
3360
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3361
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3362
+ import_remotion9.Composition,
2922
3363
  {
2923
3364
  id: "ImageEditorComposition",
2924
3365
  component: ImageComp,
@@ -2930,8 +3371,8 @@ var RenderRoot = () => {
2930
3371
  defaultProps: defaultImageProps
2931
3372
  }
2932
3373
  ),
2933
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2934
- import_remotion8.Composition,
3374
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3375
+ import_remotion9.Composition,
2935
3376
  {
2936
3377
  id: "VideoEditorComposition",
2937
3378
  component: VideoComp,
@@ -2942,8 +3383,8 @@ var RenderRoot = () => {
2942
3383
  defaultProps: defaultVideoProps
2943
3384
  }
2944
3385
  ),
2945
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2946
- import_remotion8.Composition,
3386
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3387
+ import_remotion9.Composition,
2947
3388
  {
2948
3389
  id: "AutoCaptionComposition",
2949
3390
  component: AutoCaptionComp,
@@ -2954,8 +3395,8 @@ var RenderRoot = () => {
2954
3395
  defaultProps: defaultAutoCaptionProps
2955
3396
  }
2956
3397
  ),
2957
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2958
- import_remotion8.Composition,
3398
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3399
+ import_remotion9.Composition,
2959
3400
  {
2960
3401
  id: "ScreenshotAnimationComposition",
2961
3402
  component: ScreenshotAnimationComp,
@@ -2966,6 +3407,19 @@ var RenderRoot = () => {
2966
3407
  height: 1920,
2967
3408
  defaultProps: defaultScreenshotAnimationProps
2968
3409
  }
3410
+ ),
3411
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3412
+ import_remotion9.Composition,
3413
+ {
3414
+ id: "ScreenshotAnimationV2",
3415
+ component: ScreenshotAnimationV2Comp,
3416
+ schema: screenshotAnimationV2Schema,
3417
+ durationInFrames: 90,
3418
+ fps: 30,
3419
+ width: 1080,
3420
+ height: 1920,
3421
+ defaultProps: defaultScreenshotAnimationV2Props
3422
+ }
2969
3423
  )
2970
3424
  ] });
2971
3425
  };
@@ -2991,6 +3445,7 @@ var RenderRoot = () => {
2991
3445
  LEVEL_5_CONFIG,
2992
3446
  RenderRoot,
2993
3447
  ScreenshotAnimationComposition,
3448
+ ScreenshotAnimationV2,
2994
3449
  TEXT_DEFAULTS,
2995
3450
  TextElement,
2996
3451
  VIDEO_DEFAULTS,
package/dist/index.mjs CHANGED
@@ -1537,6 +1537,425 @@ function ScreenshotAnimationComposition({
1537
1537
  ] });
1538
1538
  }
1539
1539
 
1540
+ // src/compositions/ScreenshotAnimationV2.tsx
1541
+ import { AbsoluteFill as AbsoluteFill5, Img as Img4, interpolate as interpolate3, useCurrentFrame as useCurrentFrame6, useVideoConfig as useVideoConfig6 } from "remotion";
1542
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1543
+ var KEYFRAMES = {
1544
+ // Screenshot container outer bounds (including border)
1545
+ ssBorderTop: [
1546
+ [255, 0.0623],
1547
+ [295, 0.2017],
1548
+ [335, 0.3443],
1549
+ [375, 0.508],
1550
+ [415, 0.584],
1551
+ [455, 0.6367],
1552
+ [495, 0.7023],
1553
+ [535, 0.7065],
1554
+ [575, 0.7255],
1555
+ [615, 0.7329],
1556
+ [655, 0.7371],
1557
+ [695, 0.7413],
1558
+ [735, 0.7434],
1559
+ [835, 0.7434],
1560
+ [935, 0.7455],
1561
+ [1135, 0.7455]
1562
+ ],
1563
+ ssBorderTopInner: [
1564
+ [255, 0.0697],
1565
+ [295, 0.208],
1566
+ [335, 0.3517],
1567
+ [375, 0.5132],
1568
+ [415, 0.5882],
1569
+ [455, 0.642],
1570
+ [495, 0.7076],
1571
+ [535, 0.7138],
1572
+ [575, 0.7308],
1573
+ [615, 0.7381],
1574
+ [655, 0.7423],
1575
+ [695, 0.7466],
1576
+ [735, 0.7487],
1577
+ [835, 0.7497],
1578
+ [935, 0.7497],
1579
+ [1135, 0.7508]
1580
+ ],
1581
+ ssBorderRight: [
1582
+ [255, 0.9584],
1583
+ [295, 0.8245],
1584
+ [335, 0.6951],
1585
+ [375, 0.5404],
1586
+ [415, 0.4734],
1587
+ [455, 0.4226],
1588
+ [495, 0.3742],
1589
+ [535, 0.3557],
1590
+ [575, 0.3418],
1591
+ [615, 0.3349],
1592
+ [655, 0.3279],
1593
+ [695, 0.3257],
1594
+ [735, 0.3257],
1595
+ [835, 0.321],
1596
+ [935, 0.321],
1597
+ [1135, 0.321]
1598
+ ],
1599
+ ssBorderLeft: [
1600
+ [255, 0],
1601
+ [295, 0.0115],
1602
+ [335, 0.0323],
1603
+ [375, 0.0554],
1604
+ [415, 0.067],
1605
+ [455, 0.0739],
1606
+ [495, 0.0808],
1607
+ [535, 0.0831],
1608
+ [575, 0.0877],
1609
+ [615, 0.0877],
1610
+ [655, 0.0901],
1611
+ [695, 0.0901],
1612
+ [735, 0.0901],
1613
+ [835, 0.0901],
1614
+ [935, 0.0901],
1615
+ [1135, 0.0901]
1616
+ ],
1617
+ ssBorderBottom: [
1618
+ [255, 1],
1619
+ [295, 0.9947],
1620
+ [335, 0.9842],
1621
+ [375, 0.9747],
1622
+ [415, 0.9683],
1623
+ [455, 0.9662],
1624
+ [495, 0.9757],
1625
+ [535, 0.962],
1626
+ [575, 0.9599],
1627
+ [615, 0.9588],
1628
+ [655, 0.9588],
1629
+ [695, 0.9588],
1630
+ [735, 0.9588],
1631
+ [835, 0.9588],
1632
+ [935, 0.9588],
1633
+ [1135, 0.9588]
1634
+ ],
1635
+ // Inner content positions
1636
+ imgTop: [
1637
+ [255, 0.5248],
1638
+ [295, 0.5702],
1639
+ [335, 0.6178],
1640
+ [375, 0.6726],
1641
+ [415, 0.6969],
1642
+ [455, 0.7138],
1643
+ [495, 0.7455],
1644
+ [535, 0.7381],
1645
+ [575, 0.7434],
1646
+ [615, 0.7466],
1647
+ [655, 0.7487],
1648
+ [695, 0.7508]
1649
+ // After 735ms, imgTop matches container inner top (content fills container)
1650
+ ],
1651
+ imgClipRight: [
1652
+ [255, 0.2125],
1653
+ [295, 0.2286],
1654
+ [335, 0.2494],
1655
+ [375, 0.2725],
1656
+ [415, 0.2817],
1657
+ [455, 0.291],
1658
+ [495, 0.2979],
1659
+ [535, 0.3002],
1660
+ [575, 0.3025],
1661
+ [615, 0.3025],
1662
+ [655, 0.3002],
1663
+ [695, 0.3095]
1664
+ // After 735ms, clip fills container width
1665
+ ],
1666
+ imgClipBottom: [
1667
+ [255, 0.7233],
1668
+ [295, 0.7698],
1669
+ [335, 0.8184],
1670
+ [375, 0.8722],
1671
+ [415, 0.8975],
1672
+ [455, 0.9145],
1673
+ [495, 0.9504],
1674
+ [535, 0.9472],
1675
+ [575, 0.944],
1676
+ [615, 0.9472],
1677
+ [655, 0.9483],
1678
+ [695, 0.9504]
1679
+ // After 735ms, clip fills container height
1680
+ ],
1681
+ // White overlay opacity (derived from black RGBA: value/255)
1682
+ whiteOpacity: [
1683
+ [255, 0.824],
1684
+ [295, 0.773],
1685
+ [335, 0.722],
1686
+ [375, 0.639],
1687
+ [415, 0.58],
1688
+ [455, 0.522],
1689
+ [495, 0.427],
1690
+ [535, 0.376],
1691
+ [575, 0.345],
1692
+ [615, 0.267],
1693
+ [655, 0.245],
1694
+ [695, 0.165],
1695
+ [735, 0.106],
1696
+ [835, 0.065],
1697
+ [935, 0.039],
1698
+ [1135, 0.014]
1699
+ ],
1700
+ // Gray fill color (RGB values for gap above shifted content)
1701
+ grayFillR: [
1702
+ [255, 241],
1703
+ [295, 237],
1704
+ [335, 231],
1705
+ [375, 224],
1706
+ [415, 219],
1707
+ [455, 213],
1708
+ [495, 205],
1709
+ [535, 200],
1710
+ [575, 191],
1711
+ [615, 188],
1712
+ [655, 188],
1713
+ [695, 174]
1714
+ ],
1715
+ grayFillG: [
1716
+ [255, 239],
1717
+ [295, 234],
1718
+ [335, 228],
1719
+ [375, 221],
1720
+ [415, 217],
1721
+ [455, 210],
1722
+ [495, 203],
1723
+ [535, 197],
1724
+ [575, 189],
1725
+ [615, 187],
1726
+ [655, 187],
1727
+ [695, 169]
1728
+ ],
1729
+ grayFillB: [
1730
+ [255, 242],
1731
+ [295, 237],
1732
+ [335, 231],
1733
+ [375, 224],
1734
+ [415, 220],
1735
+ [455, 216],
1736
+ [495, 206],
1737
+ [535, 200],
1738
+ [575, 192],
1739
+ [615, 190],
1740
+ [655, 190],
1741
+ [695, 171]
1742
+ ],
1743
+ // Inner content bottom corner radius (0 = square, 1 = fully rounded)
1744
+ innerCornerRadius: [
1745
+ [655, 0],
1746
+ [695, 0.15],
1747
+ [735, 0.5],
1748
+ [835, 1]
1749
+ ]
1750
+ };
1751
+ function interpolateKeyframes(keyframes, timeMs, defaultValue) {
1752
+ if (keyframes.length === 0) {
1753
+ return defaultValue ?? 0;
1754
+ }
1755
+ if (timeMs <= keyframes[0][0]) {
1756
+ return keyframes[0][1];
1757
+ }
1758
+ if (timeMs >= keyframes[keyframes.length - 1][0]) {
1759
+ return keyframes[keyframes.length - 1][1];
1760
+ }
1761
+ for (let i = 0; i < keyframes.length - 1; i++) {
1762
+ const [t1, v1] = keyframes[i];
1763
+ const [t2, v2] = keyframes[i + 1];
1764
+ if (timeMs >= t1 && timeMs <= t2) {
1765
+ const progress = (timeMs - t1) / (t2 - t1);
1766
+ return v1 + (v2 - v1) * progress;
1767
+ }
1768
+ }
1769
+ return keyframes[keyframes.length - 1][1];
1770
+ }
1771
+ function ScreenshotAnimationV2({
1772
+ imageUrl,
1773
+ width = 1080,
1774
+ height = 1920,
1775
+ pauseDurationMs = 1e3,
1776
+ flashDurationMs = 255,
1777
+ borderRadius = 16,
1778
+ borderColor = "rgba(80, 80, 80, 0.8)",
1779
+ backgroundColor = "#000000"
1780
+ }) {
1781
+ const frame = useCurrentFrame6();
1782
+ const { fps } = useVideoConfig6();
1783
+ const timeMs = frame / fps * 1e3;
1784
+ const flashStartMs = pauseDurationMs;
1785
+ const flashEndMs = flashStartMs + flashDurationMs;
1786
+ const phase2StartMs = flashEndMs;
1787
+ const animationTimeMs = Math.max(0, timeMs - flashStartMs);
1788
+ const isPause = timeMs < flashStartMs;
1789
+ const isFlashPhase = timeMs >= flashStartMs && timeMs < flashEndMs;
1790
+ const isPhase2 = timeMs >= phase2StartMs;
1791
+ let whiteOpacity = 0;
1792
+ if (isPause) {
1793
+ whiteOpacity = 0;
1794
+ } else if (isFlashPhase) {
1795
+ const flashProgress = (timeMs - flashStartMs) / flashDurationMs;
1796
+ whiteOpacity = interpolate3(flashProgress, [0, 0.1, 1], [1, 1, 0.824], {
1797
+ extrapolateRight: "clamp"
1798
+ });
1799
+ } else if (isPhase2) {
1800
+ whiteOpacity = interpolateKeyframes(KEYFRAMES.whiteOpacity, animationTimeMs);
1801
+ }
1802
+ const containerTop = interpolateKeyframes(KEYFRAMES.ssBorderTop, animationTimeMs);
1803
+ const containerTopInner = interpolateKeyframes(KEYFRAMES.ssBorderTopInner, animationTimeMs);
1804
+ const containerLeft = interpolateKeyframes(KEYFRAMES.ssBorderLeft, animationTimeMs);
1805
+ const containerRight = interpolateKeyframes(KEYFRAMES.ssBorderRight, animationTimeMs);
1806
+ const containerBottom = interpolateKeyframes(KEYFRAMES.ssBorderBottom, animationTimeMs);
1807
+ const borderWidth = (containerTopInner - containerTop) * height;
1808
+ const containerX = containerLeft * width;
1809
+ const containerY = containerTop * height;
1810
+ const containerW = (containerRight - containerLeft) * width;
1811
+ const containerH = (containerBottom - containerTop) * height;
1812
+ const contentX = containerX + borderWidth;
1813
+ const contentY = containerY + borderWidth;
1814
+ const contentW = containerW - borderWidth * 2;
1815
+ const contentH = containerH - borderWidth * 2;
1816
+ const imgTopPercent = interpolateKeyframes(KEYFRAMES.imgTop, animationTimeMs);
1817
+ const imgClipRightPercent = interpolateKeyframes(KEYFRAMES.imgClipRight, animationTimeMs);
1818
+ const imgClipBottomPercent = interpolateKeyframes(KEYFRAMES.imgClipBottom, animationTimeMs);
1819
+ const thumbnailFilled = animationTimeMs >= 735;
1820
+ const grayR = interpolateKeyframes(KEYFRAMES.grayFillR, animationTimeMs);
1821
+ const grayG = interpolateKeyframes(KEYFRAMES.grayFillG, animationTimeMs);
1822
+ const grayB = interpolateKeyframes(KEYFRAMES.grayFillB, animationTimeMs);
1823
+ const grayColor = `rgb(${Math.round(grayR)}, ${Math.round(grayG)}, ${Math.round(grayB)})`;
1824
+ const innerCornerProgress = interpolateKeyframes(KEYFRAMES.innerCornerRadius, animationTimeMs);
1825
+ const innerBorderRadius = borderRadius * innerCornerProgress;
1826
+ const grayGapTop = contentY;
1827
+ const grayGapBottom = imgTopPercent * height;
1828
+ const grayGapHeight = Math.max(0, grayGapBottom - grayGapTop);
1829
+ const largeImgTop = imgTopPercent * height;
1830
+ const largeImgLeft = contentX;
1831
+ const largeImgWidth = contentW;
1832
+ const largeImgHeight = height;
1833
+ const smallClipTop = imgTopPercent * height;
1834
+ const smallClipLeft = contentX;
1835
+ const smallClipRight = imgClipRightPercent * width;
1836
+ const smallClipBottom = imgClipBottomPercent * height;
1837
+ const smallClipWidth = smallClipRight - smallClipLeft;
1838
+ const smallClipHeight = smallClipBottom - smallClipTop;
1839
+ return /* @__PURE__ */ jsxs7(AbsoluteFill5, { style: { backgroundColor }, children: [
1840
+ /* @__PURE__ */ jsx9(
1841
+ Img4,
1842
+ {
1843
+ src: imageUrl,
1844
+ style: {
1845
+ position: "absolute",
1846
+ top: 0,
1847
+ left: 0,
1848
+ width,
1849
+ height,
1850
+ objectFit: "cover"
1851
+ }
1852
+ }
1853
+ ),
1854
+ isPhase2 && /* @__PURE__ */ jsx9(
1855
+ "div",
1856
+ {
1857
+ style: {
1858
+ position: "absolute",
1859
+ left: containerX,
1860
+ top: containerY,
1861
+ width: containerW,
1862
+ height: containerH,
1863
+ borderRadius,
1864
+ border: `${borderWidth}px solid ${borderColor}`,
1865
+ boxSizing: "border-box",
1866
+ overflow: "hidden"
1867
+ },
1868
+ children: /* @__PURE__ */ jsxs7(
1869
+ "div",
1870
+ {
1871
+ style: {
1872
+ position: "absolute",
1873
+ left: 0,
1874
+ top: 0,
1875
+ width: contentW,
1876
+ height: contentH,
1877
+ overflow: "hidden",
1878
+ borderRadius: `${borderRadius - borderWidth}px ${borderRadius - borderWidth}px ${innerBorderRadius}px ${innerBorderRadius}px`
1879
+ },
1880
+ children: [
1881
+ !thumbnailFilled && grayGapHeight > 0 && /* @__PURE__ */ jsx9(
1882
+ "div",
1883
+ {
1884
+ style: {
1885
+ position: "absolute",
1886
+ left: 0,
1887
+ top: 0,
1888
+ width: contentW,
1889
+ height: grayGapBottom - containerTopInner * height,
1890
+ backgroundColor: grayColor
1891
+ }
1892
+ }
1893
+ ),
1894
+ !thumbnailFilled && /* @__PURE__ */ jsx9(
1895
+ "div",
1896
+ {
1897
+ style: {
1898
+ position: "absolute",
1899
+ left: 0,
1900
+ top: largeImgTop - containerTopInner * height,
1901
+ width: contentW,
1902
+ height: largeImgHeight,
1903
+ overflow: "hidden"
1904
+ },
1905
+ children: /* @__PURE__ */ jsx9(
1906
+ Img4,
1907
+ {
1908
+ src: imageUrl,
1909
+ style: {
1910
+ width: contentW,
1911
+ height: contentW * (height / width),
1912
+ // Maintain aspect ratio
1913
+ objectFit: "cover"
1914
+ }
1915
+ }
1916
+ )
1917
+ }
1918
+ ),
1919
+ /* @__PURE__ */ jsx9(
1920
+ "div",
1921
+ {
1922
+ style: {
1923
+ position: "absolute",
1924
+ left: 0,
1925
+ top: thumbnailFilled ? 0 : smallClipTop - containerTopInner * height,
1926
+ width: thumbnailFilled ? contentW : smallClipWidth,
1927
+ height: thumbnailFilled ? contentH : smallClipHeight,
1928
+ overflow: "hidden"
1929
+ },
1930
+ children: /* @__PURE__ */ jsx9(
1931
+ Img4,
1932
+ {
1933
+ src: imageUrl,
1934
+ style: {
1935
+ width: thumbnailFilled ? contentW : smallClipWidth,
1936
+ height: thumbnailFilled ? contentH : smallClipWidth * (height / width),
1937
+ objectFit: "cover"
1938
+ }
1939
+ }
1940
+ )
1941
+ }
1942
+ )
1943
+ ]
1944
+ }
1945
+ )
1946
+ }
1947
+ ),
1948
+ whiteOpacity > 1e-3 && /* @__PURE__ */ jsx9(
1949
+ AbsoluteFill5,
1950
+ {
1951
+ style: {
1952
+ backgroundColor: `rgba(255, 254, 255, ${whiteOpacity})`
1953
+ }
1954
+ }
1955
+ )
1956
+ ] });
1957
+ }
1958
+
1540
1959
  // src/hooks/index.ts
1541
1960
  import { useEffect as useEffect2, useState as useState2, useMemo as useMemo7 } from "react";
1542
1961
  function useFontsLoaded() {
@@ -1621,7 +2040,7 @@ function useResolvedPositions(elements, textValues) {
1621
2040
  // src/Root.tsx
1622
2041
  import { Composition } from "remotion";
1623
2042
  import { z } from "zod";
1624
- import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2043
+ import { Fragment, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1625
2044
  var defaultImageProps = {
1626
2045
  config: {
1627
2046
  width: 1080,
@@ -1689,6 +2108,26 @@ var defaultScreenshotAnimationProps = {
1689
2108
  // Background
1690
2109
  backgroundColor: "#000000"
1691
2110
  };
2111
+ var defaultScreenshotAnimationV2Props = {
2112
+ imageUrl: "https://images.unsplash.com/photo-1611162617474-5b21e879e113?w=1080&h=1920&fit=crop",
2113
+ width: 1080,
2114
+ height: 1920,
2115
+ pauseDurationMs: 1e3,
2116
+ flashDurationMs: 255,
2117
+ borderRadius: 16,
2118
+ borderColor: "rgba(80, 80, 80, 0.8)",
2119
+ backgroundColor: "#000000"
2120
+ };
2121
+ var screenshotAnimationV2Schema = z.object({
2122
+ imageUrl: z.string().describe("URL of the image being screenshotted"),
2123
+ width: z.number().optional().default(1080).describe("Canvas width (px)"),
2124
+ height: z.number().optional().default(1920).describe("Canvas height (px)"),
2125
+ pauseDurationMs: z.number().optional().default(1e3).describe("Pause before flash (ms)"),
2126
+ flashDurationMs: z.number().optional().default(255).describe("Flash phase duration (ms)"),
2127
+ borderRadius: z.number().optional().default(16).describe("Border corner radius (px)"),
2128
+ borderColor: z.string().optional().default("rgba(80, 80, 80, 0.8)").describe("Border color"),
2129
+ backgroundColor: z.string().optional().default("#000000").describe("Background color")
2130
+ });
1692
2131
  var screenshotAnimationSchema = z.object({
1693
2132
  // Core
1694
2133
  imageUrl: z.string().describe("URL of the image to screenshot"),
@@ -1720,6 +2159,7 @@ var ImageComp = ImageEditorComposition;
1720
2159
  var VideoComp = VideoEditorComposition;
1721
2160
  var AutoCaptionComp = AutoCaptionComposition;
1722
2161
  var ScreenshotAnimationComp = ScreenshotAnimationComposition;
2162
+ var ScreenshotAnimationV2Comp = ScreenshotAnimationV2;
1723
2163
  var calculateImageMetadata = async ({ props }) => {
1724
2164
  console.log("[calculateMetadata] Starting metadata calculation...");
1725
2165
  const canvasWidth = props.width ?? props.config?.width ?? 1080;
@@ -1770,8 +2210,8 @@ var calculateImageMetadata = async ({ props }) => {
1770
2210
  };
1771
2211
  };
1772
2212
  var RenderRoot = () => {
1773
- return /* @__PURE__ */ jsxs7(Fragment, { children: [
1774
- /* @__PURE__ */ jsx9(
2213
+ return /* @__PURE__ */ jsxs8(Fragment, { children: [
2214
+ /* @__PURE__ */ jsx10(
1775
2215
  Composition,
1776
2216
  {
1777
2217
  id: "ImageEditorComposition",
@@ -1784,7 +2224,7 @@ var RenderRoot = () => {
1784
2224
  defaultProps: defaultImageProps
1785
2225
  }
1786
2226
  ),
1787
- /* @__PURE__ */ jsx9(
2227
+ /* @__PURE__ */ jsx10(
1788
2228
  Composition,
1789
2229
  {
1790
2230
  id: "VideoEditorComposition",
@@ -1796,7 +2236,7 @@ var RenderRoot = () => {
1796
2236
  defaultProps: defaultVideoProps
1797
2237
  }
1798
2238
  ),
1799
- /* @__PURE__ */ jsx9(
2239
+ /* @__PURE__ */ jsx10(
1800
2240
  Composition,
1801
2241
  {
1802
2242
  id: "AutoCaptionComposition",
@@ -1808,7 +2248,7 @@ var RenderRoot = () => {
1808
2248
  defaultProps: defaultAutoCaptionProps
1809
2249
  }
1810
2250
  ),
1811
- /* @__PURE__ */ jsx9(
2251
+ /* @__PURE__ */ jsx10(
1812
2252
  Composition,
1813
2253
  {
1814
2254
  id: "ScreenshotAnimationComposition",
@@ -1820,6 +2260,19 @@ var RenderRoot = () => {
1820
2260
  height: 1920,
1821
2261
  defaultProps: defaultScreenshotAnimationProps
1822
2262
  }
2263
+ ),
2264
+ /* @__PURE__ */ jsx10(
2265
+ Composition,
2266
+ {
2267
+ id: "ScreenshotAnimationV2",
2268
+ component: ScreenshotAnimationV2Comp,
2269
+ schema: screenshotAnimationV2Schema,
2270
+ durationInFrames: 90,
2271
+ fps: 30,
2272
+ width: 1080,
2273
+ height: 1920,
2274
+ defaultProps: defaultScreenshotAnimationV2Props
2275
+ }
1823
2276
  )
1824
2277
  ] });
1825
2278
  };
@@ -1844,6 +2297,7 @@ export {
1844
2297
  LEVEL_5_CONFIG,
1845
2298
  RenderRoot,
1846
2299
  ScreenshotAnimationComposition,
2300
+ ScreenshotAnimationV2,
1847
2301
  TEXT_DEFAULTS,
1848
2302
  TextElement,
1849
2303
  VIDEO_DEFAULTS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.8.10",
3
+ "version": "1.8.11",
4
4
  "description": "Unified rendering package for UGC Inc - shared types, components, and compositions for pixel-perfect client/server rendering",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",