ugcinc-render 1.8.14 → 1.8.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +104 -258
  2. package/dist/index.mjs +104 -258
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2404,233 +2404,49 @@ function ScreenshotAnimationComposition({
2404
2404
  // src/compositions/ScreenshotAnimationV2.tsx
2405
2405
  var import_remotion8 = require("remotion");
2406
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
- ]
2407
+ var CONTAINER_ANIMATION_DURATION = 480;
2408
+ var CONTAINER_SETTLE_DURATION = 200;
2409
+ var START = {
2410
+ ssBorderTop: 0,
2411
+ ssBorderTopInner: 5e-3,
2412
+ // Small border width
2413
+ ssBorderRight: 1,
2414
+ ssBorderLeft: 0,
2415
+ ssBorderBottom: 1,
2416
+ imgTop: 0.5,
2417
+ // 50% down
2418
+ imgClipRight: 0.21,
2419
+ imgClipBottom: 0.72,
2420
+ whiteOpacity: 0.824
2614
2421
  };
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];
2422
+ var END = {
2423
+ ssBorderTop: 0.7455,
2424
+ ssBorderTopInner: 0.7508,
2425
+ ssBorderRight: 0.321,
2426
+ ssBorderLeft: 0.0901,
2427
+ ssBorderBottom: 0.9588,
2428
+ imgTop: 0.7508,
2429
+ // Matches container inner top
2430
+ imgClipRight: 0.321,
2431
+ // Matches container right (fills width)
2432
+ imgClipBottom: 0.9588,
2433
+ // Matches container bottom (fills height)
2434
+ whiteOpacity: 0
2435
+ };
2436
+ var CLIP_FILL_TIME = 480;
2437
+ var WHITE_FADE_DURATION = 880;
2438
+ var GRAY_START = { r: 255, g: 255, b: 255 };
2439
+ var GRAY_END = { r: 174, g: 169, b: 171 };
2440
+ var CORNER_RADIUS_START_TIME = 400;
2441
+ var CORNER_RADIUS_DURATION = 180;
2442
+ var easeOutQuart = (t) => 1 - Math.pow(1 - t, 4);
2443
+ var easeOutExpo = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
2444
+ function smoothInterpolate(timeMs, startTime, duration, startValue, endValue, easingFn = easeOutQuart) {
2445
+ if (timeMs <= startTime) return startValue;
2446
+ if (timeMs >= startTime + duration) return endValue;
2447
+ const progress = (timeMs - startTime) / duration;
2448
+ const easedProgress = easingFn(progress);
2449
+ return startValue + (endValue - startValue) * easedProgress;
2634
2450
  }
2635
2451
  function ScreenshotAnimationV2({
2636
2452
  imageUrl,
@@ -2648,7 +2464,7 @@ function ScreenshotAnimationV2({
2648
2464
  const flashStartMs = pauseDurationMs;
2649
2465
  const flashEndMs = flashStartMs + flashDurationMs;
2650
2466
  const phase2StartMs = flashEndMs;
2651
- const animationTimeMs = Math.max(0, timeMs - flashStartMs);
2467
+ const phase2TimeMs = Math.max(0, timeMs - phase2StartMs);
2652
2468
  const isPause = timeMs < flashStartMs;
2653
2469
  const isFlashPhase = timeMs >= flashStartMs && timeMs < flashEndMs;
2654
2470
  const isPhase2 = timeMs >= phase2StartMs;
@@ -2658,48 +2474,79 @@ function ScreenshotAnimationV2({
2658
2474
  whiteOpacity = 0;
2659
2475
  } else if (isFlashPhase) {
2660
2476
  const flashProgress = (timeMs - flashStartMs) / flashDurationMs;
2661
- whiteOpacity = (0, import_remotion8.interpolate)(flashProgress, [0, 0.1, 1], [1, 1, 0.824], {
2477
+ whiteOpacity = (0, import_remotion8.interpolate)(flashProgress, [0, 0.1, 1], [1, 1, START.whiteOpacity], {
2662
2478
  extrapolateRight: "clamp"
2663
2479
  });
2664
2480
  } else if (isPhase2) {
2665
- whiteOpacity = interpolateKeyframes(KEYFRAMES.whiteOpacity, animationTimeMs);
2481
+ whiteOpacity = smoothInterpolate(
2482
+ phase2TimeMs,
2483
+ 0,
2484
+ WHITE_FADE_DURATION,
2485
+ START.whiteOpacity,
2486
+ END.whiteOpacity,
2487
+ easeOutExpo
2488
+ );
2489
+ }
2490
+ let containerTop;
2491
+ let containerTopInner;
2492
+ let containerLeft;
2493
+ let containerRight;
2494
+ let containerBottom;
2495
+ if (isFlashPhase) {
2496
+ containerTop = 0;
2497
+ containerTopInner = 5e-3;
2498
+ containerLeft = 0;
2499
+ containerRight = 1;
2500
+ containerBottom = 1;
2501
+ } else {
2502
+ const totalDuration = CONTAINER_ANIMATION_DURATION + CONTAINER_SETTLE_DURATION;
2503
+ containerTop = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderTop, END.ssBorderTop, easeOutQuart);
2504
+ containerTopInner = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderTopInner, END.ssBorderTopInner, easeOutQuart);
2505
+ containerLeft = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderLeft, END.ssBorderLeft, easeOutQuart);
2506
+ containerRight = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderRight, END.ssBorderRight, easeOutQuart);
2507
+ containerBottom = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderBottom, END.ssBorderBottom, easeOutQuart);
2666
2508
  }
2667
- const containerTop = isFlashPhase ? 0 : interpolateKeyframes(KEYFRAMES.ssBorderTop, animationTimeMs);
2668
- const containerTopInner = isFlashPhase ? 5e-3 : interpolateKeyframes(KEYFRAMES.ssBorderTopInner, animationTimeMs);
2669
- const containerLeft = isFlashPhase ? 0 : interpolateKeyframes(KEYFRAMES.ssBorderLeft, animationTimeMs);
2670
- const containerRight = isFlashPhase ? 1 : interpolateKeyframes(KEYFRAMES.ssBorderRight, animationTimeMs);
2671
- const containerBottom = isFlashPhase ? 1 : interpolateKeyframes(KEYFRAMES.ssBorderBottom, animationTimeMs);
2672
2509
  const borderWidth = (containerTopInner - containerTop) * height;
2673
2510
  const containerX = containerLeft * width;
2674
2511
  const containerY = containerTop * height;
2675
2512
  const containerW = (containerRight - containerLeft) * width;
2676
2513
  const containerH = (containerBottom - containerTop) * height;
2677
- const contentX = containerX + borderWidth;
2678
- const contentY = containerY + borderWidth;
2679
2514
  const contentW = containerW - borderWidth * 2;
2680
2515
  const contentH = containerH - borderWidth * 2;
2681
- const imgTopPercent = isFlashPhase ? 0.5 : interpolateKeyframes(KEYFRAMES.imgTop, animationTimeMs);
2682
- const imgClipRightPercent = interpolateKeyframes(KEYFRAMES.imgClipRight, animationTimeMs);
2683
- const imgClipBottomPercent = interpolateKeyframes(KEYFRAMES.imgClipBottom, animationTimeMs);
2516
+ let imgTopPercent;
2517
+ let imgClipRightPercent;
2518
+ let imgClipBottomPercent;
2519
+ if (isFlashPhase) {
2520
+ imgTopPercent = 0.5;
2521
+ imgClipRightPercent = START.imgClipRight;
2522
+ imgClipBottomPercent = START.imgClipBottom;
2523
+ } else {
2524
+ imgTopPercent = smoothInterpolate(phase2TimeMs, 0, CLIP_FILL_TIME, START.imgTop, END.imgTop, easeOutQuart);
2525
+ imgClipRightPercent = smoothInterpolate(phase2TimeMs, 0, CLIP_FILL_TIME, START.imgClipRight, END.imgClipRight, easeOutQuart);
2526
+ imgClipBottomPercent = smoothInterpolate(phase2TimeMs, 0, CLIP_FILL_TIME, START.imgClipBottom, END.imgClipBottom, easeOutQuart);
2527
+ }
2684
2528
  const showSmallClip = isPhase2;
2685
- const thumbnailFilled = animationTimeMs >= 735;
2686
- const grayR = interpolateKeyframes(KEYFRAMES.grayFillR, animationTimeMs);
2687
- const grayG = interpolateKeyframes(KEYFRAMES.grayFillG, animationTimeMs);
2688
- const grayB = interpolateKeyframes(KEYFRAMES.grayFillB, animationTimeMs);
2529
+ const thumbnailFilled = phase2TimeMs >= CLIP_FILL_TIME;
2530
+ const grayProgress = Math.min(1, phase2TimeMs / CLIP_FILL_TIME);
2531
+ const easedGrayProgress = easeOutQuart(grayProgress);
2532
+ const grayR = GRAY_START.r + (GRAY_END.r - GRAY_START.r) * easedGrayProgress;
2533
+ const grayG = GRAY_START.g + (GRAY_END.g - GRAY_START.g) * easedGrayProgress;
2534
+ const grayB = GRAY_START.b + (GRAY_END.b - GRAY_START.b) * easedGrayProgress;
2689
2535
  const grayColor = `rgb(${Math.round(grayR)}, ${Math.round(grayG)}, ${Math.round(grayB)})`;
2690
- const innerCornerProgress = interpolateKeyframes(KEYFRAMES.innerCornerRadius, animationTimeMs);
2691
- const innerBorderRadius = borderRadius * innerCornerProgress;
2692
- const grayGapTop = contentY;
2693
- const grayGapBottom = imgTopPercent * height;
2694
- const grayGapHeight = Math.max(0, grayGapBottom - grayGapTop);
2695
- const largeImgTop = imgTopPercent * height;
2696
- const largeImgLeft = contentX;
2697
- const largeImgWidth = contentW;
2698
- const largeImgHeight = height;
2536
+ const cornerProgress = smoothInterpolate(
2537
+ phase2TimeMs,
2538
+ CORNER_RADIUS_START_TIME,
2539
+ CORNER_RADIUS_DURATION,
2540
+ 0,
2541
+ 1,
2542
+ easeOutQuart
2543
+ );
2544
+ const innerBorderRadius = (borderRadius - borderWidth) * cornerProgress;
2545
+ const grayGapHeight = Math.max(0, (imgTopPercent - containerTopInner) * height);
2699
2546
  const smallClipTop = imgTopPercent * height;
2700
- const smallClipLeft = contentX;
2701
2547
  const smallClipRight = imgClipRightPercent * width;
2702
2548
  const smallClipBottom = imgClipBottomPercent * height;
2549
+ const smallClipLeft = containerLeft * width + borderWidth;
2703
2550
  const smallClipWidth = smallClipRight - smallClipLeft;
2704
2551
  const smallClipHeight = smallClipBottom - smallClipTop;
2705
2552
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_remotion8.AbsoluteFill, { style: { backgroundColor }, children: [
@@ -2754,7 +2601,7 @@ function ScreenshotAnimationV2({
2754
2601
  left: 0,
2755
2602
  top: 0,
2756
2603
  width: contentW,
2757
- height: grayGapBottom - containerTopInner * height,
2604
+ height: Math.max(0, (imgTopPercent - containerTopInner) * height),
2758
2605
  backgroundColor: grayColor
2759
2606
  }
2760
2607
  }
@@ -2765,9 +2612,9 @@ function ScreenshotAnimationV2({
2765
2612
  style: {
2766
2613
  position: "absolute",
2767
2614
  left: 0,
2768
- top: largeImgTop - containerTopInner * height,
2615
+ top: (imgTopPercent - containerTopInner) * height,
2769
2616
  width: contentW,
2770
- height: largeImgHeight,
2617
+ height,
2771
2618
  overflow: "hidden"
2772
2619
  },
2773
2620
  children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -2777,7 +2624,6 @@ function ScreenshotAnimationV2({
2777
2624
  style: {
2778
2625
  width: contentW,
2779
2626
  height: contentW * (height / width),
2780
- // Maintain aspect ratio
2781
2627
  objectFit: "cover"
2782
2628
  }
2783
2629
  }
@@ -2790,7 +2636,7 @@ function ScreenshotAnimationV2({
2790
2636
  style: {
2791
2637
  position: "absolute",
2792
2638
  left: 0,
2793
- top: thumbnailFilled ? 0 : smallClipTop - containerTopInner * height,
2639
+ top: thumbnailFilled ? 0 : (imgTopPercent - containerTopInner) * height,
2794
2640
  width: thumbnailFilled ? contentW : smallClipWidth,
2795
2641
  height: thumbnailFilled ? contentH : smallClipHeight,
2796
2642
  overflow: "hidden"
package/dist/index.mjs CHANGED
@@ -1540,233 +1540,49 @@ function ScreenshotAnimationComposition({
1540
1540
  // src/compositions/ScreenshotAnimationV2.tsx
1541
1541
  import { AbsoluteFill as AbsoluteFill5, Img as Img4, interpolate as interpolate3, useCurrentFrame as useCurrentFrame6, useVideoConfig as useVideoConfig6 } from "remotion";
1542
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
- ]
1543
+ var CONTAINER_ANIMATION_DURATION = 480;
1544
+ var CONTAINER_SETTLE_DURATION = 200;
1545
+ var START = {
1546
+ ssBorderTop: 0,
1547
+ ssBorderTopInner: 5e-3,
1548
+ // Small border width
1549
+ ssBorderRight: 1,
1550
+ ssBorderLeft: 0,
1551
+ ssBorderBottom: 1,
1552
+ imgTop: 0.5,
1553
+ // 50% down
1554
+ imgClipRight: 0.21,
1555
+ imgClipBottom: 0.72,
1556
+ whiteOpacity: 0.824
1750
1557
  };
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];
1558
+ var END = {
1559
+ ssBorderTop: 0.7455,
1560
+ ssBorderTopInner: 0.7508,
1561
+ ssBorderRight: 0.321,
1562
+ ssBorderLeft: 0.0901,
1563
+ ssBorderBottom: 0.9588,
1564
+ imgTop: 0.7508,
1565
+ // Matches container inner top
1566
+ imgClipRight: 0.321,
1567
+ // Matches container right (fills width)
1568
+ imgClipBottom: 0.9588,
1569
+ // Matches container bottom (fills height)
1570
+ whiteOpacity: 0
1571
+ };
1572
+ var CLIP_FILL_TIME = 480;
1573
+ var WHITE_FADE_DURATION = 880;
1574
+ var GRAY_START = { r: 255, g: 255, b: 255 };
1575
+ var GRAY_END = { r: 174, g: 169, b: 171 };
1576
+ var CORNER_RADIUS_START_TIME = 400;
1577
+ var CORNER_RADIUS_DURATION = 180;
1578
+ var easeOutQuart = (t) => 1 - Math.pow(1 - t, 4);
1579
+ var easeOutExpo = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
1580
+ function smoothInterpolate(timeMs, startTime, duration, startValue, endValue, easingFn = easeOutQuart) {
1581
+ if (timeMs <= startTime) return startValue;
1582
+ if (timeMs >= startTime + duration) return endValue;
1583
+ const progress = (timeMs - startTime) / duration;
1584
+ const easedProgress = easingFn(progress);
1585
+ return startValue + (endValue - startValue) * easedProgress;
1770
1586
  }
1771
1587
  function ScreenshotAnimationV2({
1772
1588
  imageUrl,
@@ -1784,7 +1600,7 @@ function ScreenshotAnimationV2({
1784
1600
  const flashStartMs = pauseDurationMs;
1785
1601
  const flashEndMs = flashStartMs + flashDurationMs;
1786
1602
  const phase2StartMs = flashEndMs;
1787
- const animationTimeMs = Math.max(0, timeMs - flashStartMs);
1603
+ const phase2TimeMs = Math.max(0, timeMs - phase2StartMs);
1788
1604
  const isPause = timeMs < flashStartMs;
1789
1605
  const isFlashPhase = timeMs >= flashStartMs && timeMs < flashEndMs;
1790
1606
  const isPhase2 = timeMs >= phase2StartMs;
@@ -1794,48 +1610,79 @@ function ScreenshotAnimationV2({
1794
1610
  whiteOpacity = 0;
1795
1611
  } else if (isFlashPhase) {
1796
1612
  const flashProgress = (timeMs - flashStartMs) / flashDurationMs;
1797
- whiteOpacity = interpolate3(flashProgress, [0, 0.1, 1], [1, 1, 0.824], {
1613
+ whiteOpacity = interpolate3(flashProgress, [0, 0.1, 1], [1, 1, START.whiteOpacity], {
1798
1614
  extrapolateRight: "clamp"
1799
1615
  });
1800
1616
  } else if (isPhase2) {
1801
- whiteOpacity = interpolateKeyframes(KEYFRAMES.whiteOpacity, animationTimeMs);
1617
+ whiteOpacity = smoothInterpolate(
1618
+ phase2TimeMs,
1619
+ 0,
1620
+ WHITE_FADE_DURATION,
1621
+ START.whiteOpacity,
1622
+ END.whiteOpacity,
1623
+ easeOutExpo
1624
+ );
1625
+ }
1626
+ let containerTop;
1627
+ let containerTopInner;
1628
+ let containerLeft;
1629
+ let containerRight;
1630
+ let containerBottom;
1631
+ if (isFlashPhase) {
1632
+ containerTop = 0;
1633
+ containerTopInner = 5e-3;
1634
+ containerLeft = 0;
1635
+ containerRight = 1;
1636
+ containerBottom = 1;
1637
+ } else {
1638
+ const totalDuration = CONTAINER_ANIMATION_DURATION + CONTAINER_SETTLE_DURATION;
1639
+ containerTop = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderTop, END.ssBorderTop, easeOutQuart);
1640
+ containerTopInner = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderTopInner, END.ssBorderTopInner, easeOutQuart);
1641
+ containerLeft = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderLeft, END.ssBorderLeft, easeOutQuart);
1642
+ containerRight = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderRight, END.ssBorderRight, easeOutQuart);
1643
+ containerBottom = smoothInterpolate(phase2TimeMs, 0, totalDuration, START.ssBorderBottom, END.ssBorderBottom, easeOutQuart);
1802
1644
  }
1803
- const containerTop = isFlashPhase ? 0 : interpolateKeyframes(KEYFRAMES.ssBorderTop, animationTimeMs);
1804
- const containerTopInner = isFlashPhase ? 5e-3 : interpolateKeyframes(KEYFRAMES.ssBorderTopInner, animationTimeMs);
1805
- const containerLeft = isFlashPhase ? 0 : interpolateKeyframes(KEYFRAMES.ssBorderLeft, animationTimeMs);
1806
- const containerRight = isFlashPhase ? 1 : interpolateKeyframes(KEYFRAMES.ssBorderRight, animationTimeMs);
1807
- const containerBottom = isFlashPhase ? 1 : interpolateKeyframes(KEYFRAMES.ssBorderBottom, animationTimeMs);
1808
1645
  const borderWidth = (containerTopInner - containerTop) * height;
1809
1646
  const containerX = containerLeft * width;
1810
1647
  const containerY = containerTop * height;
1811
1648
  const containerW = (containerRight - containerLeft) * width;
1812
1649
  const containerH = (containerBottom - containerTop) * height;
1813
- const contentX = containerX + borderWidth;
1814
- const contentY = containerY + borderWidth;
1815
1650
  const contentW = containerW - borderWidth * 2;
1816
1651
  const contentH = containerH - borderWidth * 2;
1817
- const imgTopPercent = isFlashPhase ? 0.5 : interpolateKeyframes(KEYFRAMES.imgTop, animationTimeMs);
1818
- const imgClipRightPercent = interpolateKeyframes(KEYFRAMES.imgClipRight, animationTimeMs);
1819
- const imgClipBottomPercent = interpolateKeyframes(KEYFRAMES.imgClipBottom, animationTimeMs);
1652
+ let imgTopPercent;
1653
+ let imgClipRightPercent;
1654
+ let imgClipBottomPercent;
1655
+ if (isFlashPhase) {
1656
+ imgTopPercent = 0.5;
1657
+ imgClipRightPercent = START.imgClipRight;
1658
+ imgClipBottomPercent = START.imgClipBottom;
1659
+ } else {
1660
+ imgTopPercent = smoothInterpolate(phase2TimeMs, 0, CLIP_FILL_TIME, START.imgTop, END.imgTop, easeOutQuart);
1661
+ imgClipRightPercent = smoothInterpolate(phase2TimeMs, 0, CLIP_FILL_TIME, START.imgClipRight, END.imgClipRight, easeOutQuart);
1662
+ imgClipBottomPercent = smoothInterpolate(phase2TimeMs, 0, CLIP_FILL_TIME, START.imgClipBottom, END.imgClipBottom, easeOutQuart);
1663
+ }
1820
1664
  const showSmallClip = isPhase2;
1821
- const thumbnailFilled = animationTimeMs >= 735;
1822
- const grayR = interpolateKeyframes(KEYFRAMES.grayFillR, animationTimeMs);
1823
- const grayG = interpolateKeyframes(KEYFRAMES.grayFillG, animationTimeMs);
1824
- const grayB = interpolateKeyframes(KEYFRAMES.grayFillB, animationTimeMs);
1665
+ const thumbnailFilled = phase2TimeMs >= CLIP_FILL_TIME;
1666
+ const grayProgress = Math.min(1, phase2TimeMs / CLIP_FILL_TIME);
1667
+ const easedGrayProgress = easeOutQuart(grayProgress);
1668
+ const grayR = GRAY_START.r + (GRAY_END.r - GRAY_START.r) * easedGrayProgress;
1669
+ const grayG = GRAY_START.g + (GRAY_END.g - GRAY_START.g) * easedGrayProgress;
1670
+ const grayB = GRAY_START.b + (GRAY_END.b - GRAY_START.b) * easedGrayProgress;
1825
1671
  const grayColor = `rgb(${Math.round(grayR)}, ${Math.round(grayG)}, ${Math.round(grayB)})`;
1826
- const innerCornerProgress = interpolateKeyframes(KEYFRAMES.innerCornerRadius, animationTimeMs);
1827
- const innerBorderRadius = borderRadius * innerCornerProgress;
1828
- const grayGapTop = contentY;
1829
- const grayGapBottom = imgTopPercent * height;
1830
- const grayGapHeight = Math.max(0, grayGapBottom - grayGapTop);
1831
- const largeImgTop = imgTopPercent * height;
1832
- const largeImgLeft = contentX;
1833
- const largeImgWidth = contentW;
1834
- const largeImgHeight = height;
1672
+ const cornerProgress = smoothInterpolate(
1673
+ phase2TimeMs,
1674
+ CORNER_RADIUS_START_TIME,
1675
+ CORNER_RADIUS_DURATION,
1676
+ 0,
1677
+ 1,
1678
+ easeOutQuart
1679
+ );
1680
+ const innerBorderRadius = (borderRadius - borderWidth) * cornerProgress;
1681
+ const grayGapHeight = Math.max(0, (imgTopPercent - containerTopInner) * height);
1835
1682
  const smallClipTop = imgTopPercent * height;
1836
- const smallClipLeft = contentX;
1837
1683
  const smallClipRight = imgClipRightPercent * width;
1838
1684
  const smallClipBottom = imgClipBottomPercent * height;
1685
+ const smallClipLeft = containerLeft * width + borderWidth;
1839
1686
  const smallClipWidth = smallClipRight - smallClipLeft;
1840
1687
  const smallClipHeight = smallClipBottom - smallClipTop;
1841
1688
  return /* @__PURE__ */ jsxs7(AbsoluteFill5, { style: { backgroundColor }, children: [
@@ -1890,7 +1737,7 @@ function ScreenshotAnimationV2({
1890
1737
  left: 0,
1891
1738
  top: 0,
1892
1739
  width: contentW,
1893
- height: grayGapBottom - containerTopInner * height,
1740
+ height: Math.max(0, (imgTopPercent - containerTopInner) * height),
1894
1741
  backgroundColor: grayColor
1895
1742
  }
1896
1743
  }
@@ -1901,9 +1748,9 @@ function ScreenshotAnimationV2({
1901
1748
  style: {
1902
1749
  position: "absolute",
1903
1750
  left: 0,
1904
- top: largeImgTop - containerTopInner * height,
1751
+ top: (imgTopPercent - containerTopInner) * height,
1905
1752
  width: contentW,
1906
- height: largeImgHeight,
1753
+ height,
1907
1754
  overflow: "hidden"
1908
1755
  },
1909
1756
  children: /* @__PURE__ */ jsx9(
@@ -1913,7 +1760,6 @@ function ScreenshotAnimationV2({
1913
1760
  style: {
1914
1761
  width: contentW,
1915
1762
  height: contentW * (height / width),
1916
- // Maintain aspect ratio
1917
1763
  objectFit: "cover"
1918
1764
  }
1919
1765
  }
@@ -1926,7 +1772,7 @@ function ScreenshotAnimationV2({
1926
1772
  style: {
1927
1773
  position: "absolute",
1928
1774
  left: 0,
1929
- top: thumbnailFilled ? 0 : smallClipTop - containerTopInner * height,
1775
+ top: thumbnailFilled ? 0 : (imgTopPercent - containerTopInner) * height,
1930
1776
  width: thumbnailFilled ? contentW : smallClipWidth,
1931
1777
  height: thumbnailFilled ? contentH : smallClipHeight,
1932
1778
  overflow: "hidden"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugcinc-render",
3
- "version": "1.8.14",
3
+ "version": "1.8.15",
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",