Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/browser-studio/src/templates/blank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import { Config } from "@remotion/cli/config";
Config.setRspack(true);
Config.setVideoImageFormat("jpeg");
Config.setOverwriteOutput(true);
Config.setDefaultPremountInSeconds(2);
`,
} as const;

Expand Down
7 changes: 7 additions & 0 deletions packages/cli/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const {
darkModeOption,
defaultCodingAgentOption,
defaultEditorOption,
defaultPremountInSecondsOption,
askAIOption,
publicLicenseKeyOption,
interactivityOption,
Expand Down Expand Up @@ -676,6 +677,11 @@ type FlatConfig = RemotionConfigObject &
* Set the editor used when opening files from Remotion Studio.
*/
setDefaultEditor: (editor: DefaultEditor) => void;
/**
* Set the default premount duration in seconds in Remotion Studio.
* Default: 0 in v4, 2 in v5.
*/
setDefaultPremountInSeconds: (seconds: number) => void;
/**
* Set the coding agent used by Remotion Studio.
*/
Expand Down Expand Up @@ -903,6 +909,7 @@ export const Config: FlatConfig = {
setPublicLicenseKey: publicLicenseKeyOption.setConfig,
setDefaultCodingAgent: defaultCodingAgentOption.setConfig,
setDefaultEditor: defaultEditorOption.setConfig,
setDefaultPremountInSeconds: defaultPremountInSecondsOption.setConfig,
setForceNewStudioEnabled: forceNewStudioOption.setConfig,
setIPv4: ipv4Option.setConfig,
setBundleOutDir: outDirOption.setConfig,
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/parsed-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const {
darkModeOption,
defaultCodingAgentOption,
defaultEditorOption,
defaultPremountInSecondsOption,
publicLicenseKeyOption,
forceNewStudioOption,
experimentalKeepAudioContextAliveOption,
Expand Down Expand Up @@ -111,6 +112,9 @@ export type CommandLineOptions = {
typeof defaultCodingAgentOption
>;
[defaultEditorOption.cliFlag]: TypeOfOption<typeof defaultEditorOption>;
[defaultPremountInSecondsOption.cliFlag]: TypeOfOption<
typeof defaultPremountInSecondsOption
>;
[disableWebSecurityOption.cliFlag]: TypeOfOption<
typeof disableWebSecurityOption
> | null;
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/print-help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ const studioOptions = options(
'beep-on-finish',
'ipv4',
'number-of-shared-audio-tags',
'default-premount-in-seconds',
'experimental-keep-audio-context-alive',
'preview-sample-rate',
'cross-site-isolation',
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const {
previewSampleRateOption,
defaultCodingAgentOption,
defaultEditorOption,
defaultPremountInSecondsOption,
publicLicenseKeyOption,
beepOnFinishOption,
logLevelOption,
Expand Down Expand Up @@ -166,6 +167,9 @@ export const studioCommand = async (

return {
maxTimelineTracks: ConfigInternals.getMaxTimelineTracks(),
defaultPremountInSeconds: defaultPremountInSecondsOption.getValue({
commandLine: parsedCli,
}).value,
keyboardShortcuts: ConfigInternals.getKeyboardShortcuts(),
askAIEnabled: askAIOption.getValue({
commandLine: parsedCli,
Expand Down Expand Up @@ -194,6 +198,8 @@ export const studioCommand = async (
commandLine: parsedCli,
}).value,
configFileStudioSettings: {
defaultPremountInSeconds:
defaultPremountInSecondsOption.getConfigValue(),
askAIEnabled: askAIOption.getConfigValue(),
audioLatencyHint: audioLatencyHintOption.getConfigValue(),
beepOnFinish: beepOnFinishOption.getConfigValue(),
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/DefaultPremountContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {createContext} from 'react';
import {DEFAULT_PREMOUNT_IN_SECONDS} from './default-premount-in-seconds.js';

export const DefaultPremountContext = createContext(
DEFAULT_PREMOUNT_IN_SECONDS,
);
10 changes: 5 additions & 5 deletions packages/core/src/Sequence.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
SequenceRegistrationControls,
TSequence,
} from './CompositionManager.js';
import {DefaultPremountContext} from './DefaultPremountContext.js';
import type {EffectDefinition} from './effects/effect-types.js';
import {getStackForControls} from './enable-sequence-stack-traces.js';
import {Freeze, useIsInsideNonPremountFreeze} from './freeze.js';
Expand Down Expand Up @@ -54,7 +55,6 @@ import {usePremounting} from './use-premounting.js';
import {useRemotionEnvironment} from './use-remotion-environment.js';
import {useSequenceRegistration} from './use-sequence-registration.js';
import {useVideoConfig} from './use-video-config.js';
import {ENABLE_V5_BREAKING_CHANGES} from './v5-flag.js';
import {withInteractivitySchema} from './with-interactivity-schema.js';

const SeriesContentVisibilityContext = createContext(true);
Expand Down Expand Up @@ -973,7 +973,7 @@ const PremountedPostmountedSequenceRefForwardingFunction: React.ForwardRefRender
active={isPremountingOrPostmounting}
_remotionInternalIsPremounting={premountingActive}
>
<SequenceInner
<RegularSequence
ref={ref}
from={from}
durationInFrames={durationInFrames}
Expand All @@ -998,10 +998,10 @@ const SequenceRefForwardingFunction: React.ForwardRefRenderFunction<
> = (props, ref) => {
const env = useRemotionEnvironment();
const {fps} = useVideoConfig();
const defaultPremountInSeconds = useContext(DefaultPremountContext);
if (props.layout !== 'none' && !env.isRendering) {
const effectivePremountFor = ENABLE_V5_BREAKING_CHANGES
? (props.premountFor ?? fps)
: props.premountFor;
const effectivePremountFor =
props.premountFor ?? Math.round(defaultPremountInSeconds * fps);
if (effectivePremountFor || props.postmountFor) {
return (
<PremountedPostmountedSequence
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/default-premount-in-seconds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {ENABLE_V5_BREAKING_CHANGES} from './v5-flag.js';

export const DEFAULT_PREMOUNT_IN_SECONDS = ENABLE_V5_BREAKING_CHANGES ? 2 : 0;

export const validateDefaultPremountInSeconds = (value: unknown) => {
if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
throw new TypeError(
`defaultPremountInSeconds must be a finite, non-negative number, but got ${String(value)}.`,
);
}
};
2 changes: 2 additions & 0 deletions packages/core/src/internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
import {CompositionManagerProvider} from './CompositionManagerProvider.js';
import * as CSSUtils from './default-css.js';
import {OBJECTFIT_CONTAIN_CLASS_NAME} from './default-css.js';
import {DefaultPremountContext} from './DefaultPremountContext.js';
import {
EditorPropsContext,
EditorPropsProvider,
Expand Down Expand Up @@ -333,6 +334,7 @@ const compositionSelectorRef = createRef<{
// Mark them as Internals so use don't assume this is public
// API and are less likely to use it
export const Internals = {
DefaultPremountContext,
evaluateSourceNumericValue,
evaluateSourcePropStatuses,
AbsoluteFillElement,
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/no-react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export {random} from './random.js';
export type {RandomSeed} from './random.js';
export type {VideoConfig} from './video-config';

import {
DEFAULT_PREMOUNT_IN_SECONDS,
validateDefaultPremountInSeconds,
} from './default-premount-in-seconds';
import {
DELAY_RENDER_CALLSTACK_TOKEN,
DELAY_RENDER_CLEAR_TOKEN,
Expand Down Expand Up @@ -58,6 +62,8 @@ import {getExpectedMediaFrameUncorrected} from './video/get-current-time';
import {getOffthreadVideoSource} from './video/offthread-video-source';

export const NoReactInternals = {
DEFAULT_PREMOUNT_IN_SECONDS,
validateDefaultPremountInSeconds,
evaluateSourceNumericValue,
evaluateSourcePropStatuses,
processColor,
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/use-premounting.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {useContext, useMemo} from 'react';
import type React from 'react';
import {DefaultPremountContext} from './DefaultPremountContext.js';
import {getSequenceBoundaryTolerance} from './get-sequence-boundary-tolerance.js';
import {PremountContext} from './PremountContext.js';
import {SequenceContext} from './SequenceContext.js';
import {useTimelinePosition} from './timeline-position-state.js';
import {useCurrentFrame} from './use-current-frame.js';
import {useRemotionEnvironment} from './use-remotion-environment.js';
import {useVideoConfig} from './use-video-config.js';
import {ENABLE_V5_BREAKING_CHANGES} from './v5-flag.js';

export const usePremounting = ({
from,
Expand All @@ -33,9 +33,9 @@ export const usePremounting = ({
useCurrentFrame() - parentPremountContext.premountFramesRemaining;
const environment = useRemotionEnvironment();
const {fps} = useVideoConfig();
const effectivePremountFor = ENABLE_V5_BREAKING_CHANGES
? (premountFor ?? fps)
: (premountFor ?? 0);
const defaultPremountInSeconds = useContext(DefaultPremountContext);
const effectivePremountFor =
premountFor ?? Math.round(defaultPremountInSeconds * fps);
const effectivePostmountFor = postmountFor ?? 0;
const endExclusive = from + durationInFrames;
const sequenceContext = useContext(SequenceContext);
Expand Down
10 changes: 9 additions & 1 deletion packages/core/src/wrap-remotion-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React, {useMemo} from 'react';
import {BufferingContextReact} from './buffering.js';
import {CanUseRemotionHooks} from './CanUseRemotionHooks.js';
import {CompositionManager} from './CompositionManagerContext.js';
import {DefaultPremountContext} from './DefaultPremountContext.js';
import {LogLevelContext} from './log-level-context.js';
import {PreloadContext} from './prefetch-state.js';
import {RenderAssetManager} from './RenderAssetManager.js';
Expand All @@ -27,6 +28,7 @@ export function useRemotionContexts() {
const timelineContext = React.useContext(TimelineContext);
const setTimelineContext = React.useContext(SetTimelineContext);
const sequenceContext = React.useContext(SequenceContext);
const defaultPremountInSeconds = React.useContext(DefaultPremountContext);
const experimentalTracksEnabled = React.useContext(
ExperimentalTracksEnabledContext,
);
Expand All @@ -49,6 +51,7 @@ export function useRemotionContexts() {
timelineContext,
setTimelineContext,
sequenceContext,
defaultPremountInSeconds,
experimentalTracksEnabled,
timelineTrackContext,
canUseRemotionHooksContext,
Expand All @@ -64,6 +67,7 @@ export function useRemotionContexts() {
[
compositionManagerCtx,
sequenceContext,
defaultPremountInSeconds,
experimentalTracksEnabled,
timelineTrackContext,
setTimelineContext,
Expand Down Expand Up @@ -126,7 +130,11 @@ export const RemotionContextProvider = (
<TimelineTrackContext.Provider
value={contexts.timelineTrackContext}
>
{children}
<DefaultPremountContext.Provider
value={contexts.defaultPremountInSeconds}
>
{children}
</DefaultPremountContext.Provider>
</TimelineTrackContext.Provider>
</ExperimentalTracksEnabledContext.Provider>
</BufferingContextReact.Provider>
Expand Down
10 changes: 5 additions & 5 deletions packages/docs/docs/5-0-migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ If you use `@remotion/eslint-config`, the minimum ESLint version is now <MinEsli
## Telemetry is now mandatory for Company License customers

Previously, we had no idea how many renders our company license customers are making, leading to a lack of accountability.
If you upgrade to Remotion 5.0, you must [enable telemetry](/docs/telemetry) if you are a company license holder or contact Remotion to arrange a plausible delivery of render counts.
If you upgrade to Remotion 5.0, you must [enable telemetry](/docs/telemetry) if you are a company license holder or contact Remotion to arrange a plausible delivery of render counts.

**Required action**: Pass license key to rendering APIs and in the [Remotion config file](/docs/config). If you are eligible for the free license, pass `"free-license"` as the license key.

Expand Down Expand Up @@ -174,12 +174,12 @@ loadFont('normal', {

**Required action**: Ensure custom fonts are loaded before calling these APIs, or pass `validateFontIsLoaded: false` explicitly to keep the previous behavior. See [layout utils best practices](/docs/layout-utils/best-practices).

## Sequences are automatically premounted
## Default premount duration is now 2 seconds

[`<Sequence>`](/docs/sequence), [`<Series.Sequence>`](/docs/series) and [`<TransitionSeries.Sequence>`](/docs/transitions/transitionseries) components now automatically [premount](/docs/player/premounting) for 1 second (`fps` frames) before they appear.
This prevents black frames that were commonly seen when a `<Sequence>` containing heavy content (e.g. videos, images) appeared.
The default [premount duration](/docs/player/premounting) for timed components changes from `0` to `2` seconds in the Studio and Player.
This prepares assets before components appear. Explicit `premountFor` props continue to take precedence. Premounting does not affect rendering.

**Required action**: If you don't want this behavior for a specific Sequence, opt out by passing [`premountFor={0}`](/docs/sequence#premountfor).
**Required action**: To keep the v4 default, set [`Config.setDefaultPremountInSeconds(0)`](/docs/config#setdefaultpremountinseconds) for the Studio and [`defaultPremountInSeconds={0}`](/docs/player/player#defaultpremountinseconds) on the Player. You can also use [`--default-premount-in-seconds=0`](/docs/options/default-premount-in-seconds) or change the Studio settings. For an individual component, pass [`premountFor={0}`](/docs/sequence#premountfor).

## `<Player>` does not create shared audio tags by default

Expand Down
8 changes: 8 additions & 0 deletions packages/docs/docs/cli/studio.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ npx remotion studio --beep-on-finish
npx remotion studio --ipv4
```

### `--default-premount-in-seconds`<AvailableFrom v="4.0.534" />

<Options id="default-premount-in-seconds" />

```bash title="Terminal"
npx remotion studio --default-premount-in-seconds=2
```

### `--number-of-shared-audio-tags`<AvailableFrom v="3.3.2" />

<Options id="number-of-shared-audio-tags" />
Expand Down
13 changes: 13 additions & 0 deletions packages/docs/docs/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,19 @@ Changes apply immediately in the Studio without reloading the page.

The [`--experimental-tracks`](/docs/options/experimental-tracks) flag takes precedence over this option.

## `setDefaultPremountInSeconds()`<AvailableFrom v="4.0.534" />

<Options id="default-premount-in-seconds" />

```ts twoslash title="remotion.config.ts"
import {Config} from '@remotion/cli/config';
// ---cut---
Config.setDefaultPremountInSeconds(2);
```

You can also change this value in the Studio settings. Changes apply immediately after saving.
The [`--default-premount-in-seconds`](/docs/options/default-premount-in-seconds) flag takes precedence over this option.

## `setDefaultEditor()`<AvailableFrom v="4.0.503" />

<Options id="editor" />
Expand Down
32 changes: 32 additions & 0 deletions packages/docs/docs/options/default-premount-in-seconds.mdx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/docs/docs/options/index.mdx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/docs/docs/player/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,12 @@ Either `player-size` (default) or `composition-size`:
- `player-size`: The poster will be rendered in the size of the player. This is useful if you want to render for example a Play button with constant size.
- `composition-size`: The poster will be rendered in the size of the composition and scaled to the size of the Player. This is useful if you want to render a freeze frame of the video as a poster.

### `defaultPremountInSeconds?`<AvailableFrom v="4.0.534" />

The default [premount duration](/docs/player/premounting) in seconds for timed components inside the Player. Defaults to `0` in v4 and `2` in v5.
Must be a finite, non-negative number. The duration is converted to frames using `fps` and rounded to the nearest frame.
An explicit [`premountFor`](/docs/sequence#premountfor) prop takes precedence, including `premountFor={0}` to disable premounting for a component.

### `bufferStateDelayInMilliseconds`<AvailableFrom v="4.0.111"/>

After the Player has entered a [buffer state](/docs/player/buffer-state), it will wait for this amount of time before showing the buffering UI.
Expand Down
Loading
Loading