@remotion/promo-pages 4.0.434 → 4.0.436

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/Homepage.js CHANGED
@@ -547,29 +547,80 @@ var experts = [
547
547
  x: null,
548
548
  github: "sambowenhughes",
549
549
  linkedin: "in/sambowenhughes/",
550
- email: "sambowenhughes@icloud.com",
551
- videocall: "https://calendly.com/hello-reactvideoeditor/30min",
550
+ email: "sam@reactvideoeditor.com",
551
+ videocall: "https://calendly.com/reactvideoeditor/30min",
552
552
  since: new Date("2025-06-03").getTime(),
553
553
  description: /* @__PURE__ */ jsxs("div", {
554
554
  children: [
555
- "Full-stack engineer with 10+ years experience. I built",
556
- " ",
557
- /* @__PURE__ */ jsx("a", {
558
- target: "_blank",
559
- href: "https://reactvideoeditor.com?utm_source=remotion",
560
- children: "React Video Editor"
555
+ /* @__PURE__ */ jsxs("p", {
556
+ children: [
557
+ "Experienced engineer with 10+ years building advanced software products. Creator of",
558
+ " ",
559
+ /* @__PURE__ */ jsx("a", {
560
+ target: "_blank",
561
+ href: "https://reactvideoeditor.com",
562
+ children: "React Video Editor"
563
+ }),
564
+ "and",
565
+ " ",
566
+ /* @__PURE__ */ jsx("a", {
567
+ target: "_blank",
568
+ href: "https://clippkit.com",
569
+ children: "Clippkit"
570
+ }),
571
+ "."
572
+ ]
561
573
  }),
562
- " ",
563
- "and",
564
- " ",
565
- /* @__PURE__ */ jsx("a", {
566
- target: "_blank",
567
- href: "https://clippkit.com?utm_source=remotion",
568
- children: "Clippkit"
574
+ /* @__PURE__ */ jsxs("p", {
575
+ children: [
576
+ "I work with companies building products with",
577
+ " ",
578
+ /* @__PURE__ */ jsx("strong", {
579
+ children: "Remotion at their core"
580
+ }),
581
+ ". Custom video editors, automated video generation tools, and scalable rendering pipelines."
582
+ ]
569
583
  }),
570
- ".",
571
- /* @__PURE__ */ jsx("br", {}),
572
- "I can help with anything Remotion-related, or just be a reliable engineering partner if you need someone who moves fast and builds things right – SaaS, design, backend, whatever's needed."
584
+ /* @__PURE__ */ jsxs("ul", {
585
+ children: [
586
+ /* @__PURE__ */ jsxs("li", {
587
+ children: [
588
+ /* @__PURE__ */ jsx("strong", {
589
+ children: "Custom video editors"
590
+ }),
591
+ " built with Remotion"
592
+ ]
593
+ }),
594
+ /* @__PURE__ */ jsxs("li", {
595
+ children: [
596
+ /* @__PURE__ */ jsx("strong", {
597
+ children: "Automated video generation"
598
+ }),
599
+ " systems"
600
+ ]
601
+ }),
602
+ /* @__PURE__ */ jsxs("li", {
603
+ children: [
604
+ /* @__PURE__ */ jsx("strong", {
605
+ children: "Rendering infrastructure"
606
+ }),
607
+ " and media pipelines"
608
+ ]
609
+ }),
610
+ /* @__PURE__ */ jsx("li", {
611
+ children: /* @__PURE__ */ jsx("strong", {
612
+ children: "UI/UX and full-stack product development"
613
+ })
614
+ })
615
+ ]
616
+ }),
617
+ /* @__PURE__ */ jsxs("p", {
618
+ children: [
619
+ "If you",
620
+ "'",
621
+ "re building software around video, or just need a reliable engineering partner who moves fast and builds things right, feel free to reach out."
622
+ ]
623
+ })
573
624
  ]
574
625
  })
575
626
  },
@@ -952,7 +1003,7 @@ var useIsPlayer = () => {
952
1003
  function truthy(value) {
953
1004
  return Boolean(value);
954
1005
  }
955
- var VERSION = "4.0.434";
1006
+ var VERSION = "4.0.436";
956
1007
  var checkMultipleRemotionVersions = () => {
957
1008
  if (typeof globalThis === "undefined") {
958
1009
  return;
@@ -23181,7 +23232,7 @@ var GitHubStars = () => {
23181
23232
  width: "45px"
23182
23233
  }),
23183
23234
  /* @__PURE__ */ jsx50(StatItemContent, {
23184
- content: "38k",
23235
+ content: "39k",
23185
23236
  width: "80px",
23186
23237
  fontSize: "2.5rem",
23187
23238
  fontWeight: "bold"
@@ -26553,7 +26604,7 @@ var PlayerUI = ({
26553
26604
  throw new TypeError(`setVolume() got a number that is NaN. Volume must be between 0 and 1.`);
26554
26605
  }
26555
26606
  if (vol < 0 || vol > 1) {
26556
- throw new TypeError(`setVolume() got a number that is out of range. Must be between 0 and 1, got ${typeof vol}`);
26607
+ throw new TypeError(`setVolume() got a number that is out of range. Must be between 0 and 1, got ${vol}`);
26557
26608
  }
26558
26609
  setMediaVolume(vol);
26559
26610
  },
@@ -28408,7 +28459,12 @@ var setGlobalTimeAnchor = ({
28408
28459
  }
28409
28460
  audioSyncAnchor.value = newAnchor;
28410
28461
  };
28411
- var makeAudioIterator = (startFromSecond, maximumTimestamp, cache2, debugAudioScheduling) => {
28462
+ var makeAudioIterator = ({
28463
+ startFromSecond,
28464
+ maximumTimestamp,
28465
+ cache: cache2,
28466
+ debugAudioScheduling
28467
+ }) => {
28412
28468
  let destroyed = false;
28413
28469
  const iterator = cache2.makeIteratorOrUsePrewarmed(startFromSecond, maximumTimestamp);
28414
28470
  const queuedAudioNodes = [];
@@ -28418,15 +28474,15 @@ var makeAudioIterator = (startFromSecond, maximumTimestamp, cache2, debugAudioSc
28418
28474
  const cleanupAudioQueue = (audioContext) => {
28419
28475
  for (const node of queuedAudioNodes) {
28420
28476
  try {
28421
- const currentlyHearing = audioContext.getOutputTimestamp().contextTime;
28422
- const nodeEndTime = node.scheduledTime + node.buffer.duration / node.playbackRate;
28423
- const isAlreadyPlaying = node.scheduledTime - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT < audioContext.currentTime;
28424
- const shouldKeep = isAlreadyPlaying;
28425
- if (shouldKeep) {
28477
+ const isAlreadyPlaying = node.scheduledTime - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT < audioContext.audioContext.currentTime;
28478
+ const wasScheduledForThisAnchor = node.scheduledAtAnchor === audioContext.audioSyncAnchor.value;
28479
+ if (isAlreadyPlaying && wasScheduledForThisAnchor) {
28426
28480
  continue;
28427
28481
  }
28428
28482
  if (debugAudioScheduling) {
28429
- Internals.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, `Stopping node ${node.timestamp.toFixed(3)}, currently hearing = ${currentlyHearing.toFixed(3)} currentTime = ${audioContext.currentTime.toFixed(3)} nodeEndTime = ${nodeEndTime.toFixed(3)} scheduledTime = ${node.scheduledTime.toFixed(3)}`);
28483
+ const currentlyHearing = audioContext.audioContext.getOutputTimestamp().contextTime;
28484
+ const nodeEndTime = node.scheduledTime + node.buffer.duration / node.playbackRate;
28485
+ Internals.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, `Stopping node ${node.timestamp.toFixed(3)}, currently hearing = ${currentlyHearing.toFixed(3)} currentTime = ${audioContext.audioContext.currentTime.toFixed(3)} nodeEndTime = ${nodeEndTime.toFixed(3)} scheduledTime = ${node.scheduledTime.toFixed(3)}`);
28430
28486
  }
28431
28487
  node.node.stop();
28432
28488
  } catch {}
@@ -28587,14 +28643,16 @@ var makeAudioIterator = (startFromSecond, maximumTimestamp, cache2, debugAudioSc
28587
28643
  timestamp,
28588
28644
  buffer,
28589
28645
  scheduledTime,
28590
- playbackRate
28646
+ playbackRate,
28647
+ scheduledAtAnchor
28591
28648
  }) => {
28592
28649
  queuedAudioNodes.push({
28593
28650
  node,
28594
28651
  timestamp,
28595
28652
  buffer,
28596
28653
  scheduledTime,
28597
- playbackRate
28654
+ playbackRate,
28655
+ scheduledAtAnchor
28598
28656
  });
28599
28657
  },
28600
28658
  removeQueuedAudioNode: (node) => {
@@ -28833,8 +28891,8 @@ var audioIteratorManager = ({
28833
28891
  }) => {
28834
28892
  let muted = initialMuted;
28835
28893
  let currentVolume = 1;
28836
- const gainNode = sharedAudioContext.createGain();
28837
- gainNode.connect(sharedAudioContext.destination);
28894
+ const gainNode = sharedAudioContext.audioContext.createGain();
28895
+ gainNode.connect(sharedAudioContext.audioContext.destination);
28838
28896
  const audioSink = new AudioBufferSink(audioTrack);
28839
28897
  const prewarmedAudioIteratorCache = makePrewarmedAudioIteratorCache(audioSink);
28840
28898
  let audioBufferIterator = null;
@@ -28850,13 +28908,13 @@ var audioIteratorManager = ({
28850
28908
  if (!audioBufferIterator) {
28851
28909
  throw new Error("Audio buffer iterator not found");
28852
28910
  }
28853
- if (sharedAudioContext.state !== "running") {
28911
+ if (sharedAudioContext.audioContext.state !== "running") {
28854
28912
  throw new Error("Tried to schedule node while audio context is not running");
28855
28913
  }
28856
28914
  if (muted) {
28857
28915
  return;
28858
28916
  }
28859
- const node = sharedAudioContext.createBufferSource();
28917
+ const node = sharedAudioContext.audioContext.createBufferSource();
28860
28918
  node.buffer = buffer;
28861
28919
  node.playbackRate.value = playbackRate;
28862
28920
  node.connect(gainNode);
@@ -28874,7 +28932,8 @@ var audioIteratorManager = ({
28874
28932
  timestamp: mediaTimestamp,
28875
28933
  buffer,
28876
28934
  scheduledTime: started.scheduledTime,
28877
- playbackRate
28935
+ playbackRate,
28936
+ scheduledAtAnchor: sharedAudioContext.audioSyncAnchor.value
28878
28937
  });
28879
28938
  node.onended = () => {
28880
28939
  setTimeout(() => {
@@ -28921,7 +28980,7 @@ var audioIteratorManager = ({
28921
28980
  if (buffer.timestamp >= endTime) {
28922
28981
  return;
28923
28982
  }
28924
- if (getIsPlaying() && sharedAudioContext.state === "running" && (sharedAudioContext.getOutputTimestamp().contextTime ?? 0) > 0) {
28983
+ if (getIsPlaying() && sharedAudioContext.audioContext.state === "running" && (sharedAudioContext.audioContext.getOutputTimestamp().contextTime ?? 0) > 0) {
28925
28984
  resumeScheduledAudioChunks({
28926
28985
  playbackRate,
28927
28986
  scheduleAudioNode,
@@ -28961,7 +29020,12 @@ var audioIteratorManager = ({
28961
29020
  audioBufferIterator?.destroy(sharedAudioContext);
28962
29021
  const delayHandle = __using(__stack, delayPlaybackHandleIfNotPremounting(), 0);
28963
29022
  currentDelayHandle = delayHandle;
28964
- const iterator = makeAudioIterator(startFromSecond, getEndTime(), prewarmedAudioIteratorCache, debugAudioScheduling);
29023
+ const iterator = makeAudioIterator({
29024
+ startFromSecond,
29025
+ maximumTimestamp: getEndTime(),
29026
+ cache: prewarmedAudioIteratorCache,
29027
+ debugAudioScheduling
29028
+ });
28965
29029
  audioIteratorsCreated++;
28966
29030
  audioBufferIterator = iterator;
28967
29031
  try {
@@ -29045,7 +29109,7 @@ var audioIteratorManager = ({
29045
29109
  }
29046
29110
  const queuedPeriod = audioBufferIterator.getQueuedPeriod();
29047
29111
  const queuedPeriodMinusLatency = queuedPeriod ? {
29048
- from: queuedPeriod.from - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT - sharedAudioContext.baseLatency - sharedAudioContext.outputLatency,
29112
+ from: queuedPeriod.from - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT - sharedAudioContext.audioContext.baseLatency - sharedAudioContext.audioContext.outputLatency,
29049
29113
  until: queuedPeriod.until
29050
29114
  } : null;
29051
29115
  const currentTimeIsAlreadyQueued = isAlreadyQueued(newTime, queuedPeriodMinusLatency);
@@ -29608,7 +29672,7 @@ class MediaPlayer {
29608
29672
  this.audioIteratorManager = audioIteratorManager({
29609
29673
  audioTrack,
29610
29674
  delayPlaybackHandleIfNotPremounting: this.delayPlaybackHandleIfNotPremounting,
29611
- sharedAudioContext: this.sharedAudioContext.audioContext,
29675
+ sharedAudioContext: this.sharedAudioContext,
29612
29676
  getIsLooping: () => this.loop,
29613
29677
  getEndTime: () => this.getEndTime(),
29614
29678
  getStartTime: () => this.getStartTime(),
@@ -34721,7 +34785,7 @@ import {
34721
34785
  import { BufferTarget, StreamTarget } from "mediabunny";
34722
34786
 
34723
34787
  // ../core/dist/esm/version.mjs
34724
- var VERSION2 = "4.0.434";
34788
+ var VERSION2 = "4.0.436";
34725
34789
 
34726
34790
  // ../web-renderer/dist/esm/index.mjs
34727
34791
  import { AudioSample, VideoSample } from "mediabunny";
@@ -38406,6 +38470,7 @@ var createWebFsTarget = async () => {
38406
38470
  const close = () => writable.close();
38407
38471
  return { stream, getBlob, close };
38408
38472
  };
38473
+ var MAX_RECENT_FRAME_TIMINGS = 150;
38409
38474
  var internalRenderMediaOnWeb = async ({
38410
38475
  composition,
38411
38476
  inputProps,
@@ -38541,6 +38606,10 @@ var internalRenderMediaOnWeb = async ({
38541
38606
  }) : null, 0);
38542
38607
  const totalFrames = realFrameRange[1] - realFrameRange[0] + 1;
38543
38608
  const durationInSeconds = totalFrames / resolved.fps;
38609
+ const renderStart = Date.now();
38610
+ let doneIn = null;
38611
+ let renderEstimatedTime = 0;
38612
+ const recentFrameTimings = [];
38544
38613
  if (videoSampleSource) {
38545
38614
  outputWithCleanup.output.addVideoTrack(videoSampleSource.videoSampleSource, {
38546
38615
  maximumPacketCount: Math.ceil(totalFrames * 1.33)
@@ -38560,10 +38629,21 @@ var internalRenderMediaOnWeb = async ({
38560
38629
  if (signal?.aborted) {
38561
38630
  throw new Error("renderMediaOnWeb() was cancelled");
38562
38631
  }
38632
+ let timeOfLastFrame = Date.now();
38563
38633
  const progress = {
38564
38634
  renderedFrames: 0,
38565
38635
  encodedFrames: 0
38566
38636
  };
38637
+ const getProgressPayload = () => {
38638
+ const overallProgress = Math.round((70 * progress.renderedFrames + 30 * progress.encodedFrames) / totalFrames) / 100;
38639
+ return {
38640
+ renderedFrames: progress.renderedFrames,
38641
+ encodedFrames: progress.encodedFrames,
38642
+ doneIn,
38643
+ renderEstimatedTime,
38644
+ progress: overallProgress
38645
+ };
38646
+ };
38567
38647
  for (let frame = realFrameRange[0];frame <= realFrameRange[1]; frame++) {
38568
38648
  if (signal?.aborted) {
38569
38649
  throw new Error("renderMediaOnWeb() was cancelled");
@@ -38617,8 +38697,19 @@ var internalRenderMediaOnWeb = async ({
38617
38697
  });
38618
38698
  }
38619
38699
  }
38700
+ const now = Date.now();
38701
+ const timeToRenderInMilliseconds = now - timeOfLastFrame;
38702
+ timeOfLastFrame = now;
38620
38703
  progress.renderedFrames++;
38621
- throttledOnProgress?.({ ...progress });
38704
+ recentFrameTimings.push(timeToRenderInMilliseconds);
38705
+ if (recentFrameTimings.length > MAX_RECENT_FRAME_TIMINGS) {
38706
+ recentFrameTimings.shift();
38707
+ }
38708
+ const recentTimingsSum = recentFrameTimings.reduce((sum, time) => sum + time, 0);
38709
+ const newAverage = recentTimingsSum / recentFrameTimings.length;
38710
+ const remainingFrames = totalFrames - progress.renderedFrames;
38711
+ renderEstimatedTime = Math.round(remainingFrames * newAverage);
38712
+ throttledOnProgress?.(getProgressPayload());
38622
38713
  const audioCombineStart = performance.now();
38623
38714
  const assets = collectAssets.current.collectAssets();
38624
38715
  if (onArtifact) {
@@ -38645,12 +38736,15 @@ var internalRenderMediaOnWeb = async ({
38645
38736
  await Promise.all(encodingPromises);
38646
38737
  internalState.addAddSampleTime(performance.now() - addSampleStart);
38647
38738
  progress.encodedFrames++;
38648
- throttledOnProgress?.({ ...progress });
38739
+ if (progress.encodedFrames === totalFrames) {
38740
+ doneIn = Date.now() - renderStart;
38741
+ }
38742
+ throttledOnProgress?.(getProgressPayload());
38649
38743
  if (signal?.aborted) {
38650
38744
  throw new Error("renderMediaOnWeb() was cancelled");
38651
38745
  }
38652
38746
  }
38653
- onProgress?.({ ...progress });
38747
+ onProgress?.(getProgressPayload());
38654
38748
  videoSampleSource?.videoSampleSource.close();
38655
38749
  audioSampleSource?.audioSampleSource.close();
38656
38750
  await outputWithCleanup.output.finalize();
@@ -38977,10 +39071,10 @@ var RenderButton = ({ renderData, onError, playerRef }) => {
38977
39071
  muted: typeof AudioEncoder === "undefined",
38978
39072
  scale: 1,
38979
39073
  inputProps,
38980
- onProgress: ({ renderedFrames }) => {
39074
+ onProgress: ({ progress }) => {
38981
39075
  setState({
38982
39076
  type: "progress",
38983
- progress: renderedFrames / durationInFrames
39077
+ progress
38984
39078
  });
38985
39079
  }
38986
39080
  });
@@ -41042,6 +41136,7 @@ var listOfRemotionPackages = [
41042
41136
  "@remotion/astro-example",
41043
41137
  "@remotion/babel-loader",
41044
41138
  "@remotion/bugs",
41139
+ "@remotion/brand",
41045
41140
  "@remotion/bundler",
41046
41141
  "@remotion/cli",
41047
41142
  "@remotion/cloudrun",
@@ -41120,6 +41215,7 @@ var listOfRemotionPackages = [
41120
41215
  "@remotion/web-renderer",
41121
41216
  "@remotion/design",
41122
41217
  "@remotion/light-leaks",
41218
+ "@remotion/starburst",
41123
41219
  "@remotion/vercel",
41124
41220
  "@remotion/sfx"
41125
41221
  ];
@@ -41293,7 +41389,7 @@ var FEATURED_TEMPLATES = [
41293
41389
  shortName: "Prompt to Motion Graphics SaaS Starter Kit",
41294
41390
  org: "remotion-dev",
41295
41391
  repoName: "template-prompt-to-motion-graphics-saas",
41296
- description: "SaaS template for AI-powered code generation with Remotion",
41392
+ description: "SaaS template for AI-powered animation generation",
41297
41393
  longerDescription: 'A SaaS template for "Prompt to Motion Graphics" products. Generates Remotion code, streams it to the frontend, and compiles and previews it in the browser. See the <a href="/docs/ai/ai-saas-template">documentation page</a> for more details.',
41298
41394
  promoBanner: {
41299
41395
  width: 2880,
@@ -42334,7 +42430,7 @@ var GithubButton = () => {
42334
42430
  " ",
42335
42431
  /* @__PURE__ */ jsx161("div", {
42336
42432
  className: "text-xs inline-block ml-2 leading-none mt-[3px] self-center",
42337
- children: "38k"
42433
+ children: "39k"
42338
42434
  })
42339
42435
  ]
42340
42436
  });