├── .gitignore
├── .prettierrc
├── README.md
├── eslint.config.mjs
├── package.json
├── remotion.config.js
└── src
├── HelloWorld
├── Arc.jsx
├── Atom.jsx
├── Logo.jsx
├── Subtitle.jsx
├── Title.jsx
├── constants.js
└── index.jsx
├── Root.jsx
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .DS_Store
4 | .env
5 |
6 | out
7 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "bracketSpacing": true,
4 | "tabWidth": 2
5 | }
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Remotion video
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Welcome to your Remotion project!
13 |
14 | ## Commands
15 |
16 | **Install Dependencies**
17 |
18 | ```console
19 | npm install
20 | ```
21 |
22 | **Start Preview**
23 |
24 | ```console
25 | npm run dev
26 | ```
27 |
28 | **Render video**
29 |
30 | ```console
31 | npx remotion render
32 | ```
33 |
34 | **Upgrade Remotion**
35 |
36 | ```console
37 | npx remotion upgrade
38 | ```
39 |
40 | ## Docs
41 |
42 | Get started with Remotion by reading the [fundamentals page](https://www.remotion.dev/docs/the-fundamentals).
43 |
44 | ## Help
45 |
46 | We provide help on our [Discord server](https://discord.gg/6VzzNDwUwV).
47 |
48 | ## Issues
49 |
50 | Found an issue with Remotion? [File an issue here](https://github.com/JonnyBurger/remotion/issues/new).
51 |
52 | ## License
53 |
54 | Note that for some entities a company license is needed. [Read the terms here](https://github.com/JonnyBurger/remotion/blob/main/LICENSE.md).
55 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { config } from "@remotion/eslint-config-flat";
2 |
3 | export default config;
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "template-javascript",
3 | "version": "1.0.0",
4 | "description": "My Remotion video",
5 | "scripts": {
6 | "dev": "remotion studio",
7 | "build": "remotion bundle",
8 | "upgrade": "remotion upgrade",
9 | "lint": "eslint src"
10 | },
11 | "repository": {},
12 | "license": "UNLICENSED",
13 | "dependencies": {
14 | "@remotion/cli": "^4.0.0",
15 | "react": "19.0.0",
16 | "react-dom": "19.0.0",
17 | "remotion": "^4.0.0",
18 | "zod": "3.22.3"
19 | },
20 | "devDependencies": {
21 | "@remotion/eslint-config-flat": "^4.0.0",
22 | "prettier": "3.3.3",
23 | "eslint": "9.19.0"
24 | },
25 | "private": true
26 | }
27 |
--------------------------------------------------------------------------------
/remotion.config.js:
--------------------------------------------------------------------------------
1 | // All configuration options: https://remotion.dev/docs/config
2 | // Each option also is available as a CLI flag: https://remotion.dev/docs/cli
3 |
4 | // Note: When using the Node.JS APIs, the config file doesn't apply. Instead, pass options directly to the APIs
5 |
6 | import { Config } from "@remotion/cli/config";
7 |
8 | Config.setVideoImageFormat("jpeg");
9 |
--------------------------------------------------------------------------------
/src/HelloWorld/Arc.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { random, useVideoConfig } from "remotion";
3 | import { COLOR_1, COLOR_2 } from "./constants";
4 |
5 | const getCircumferenceOfArc = (rx, ry) => {
6 | return Math.PI * 2 * Math.sqrt((rx * rx + ry * ry) / 2);
7 | };
8 |
9 | const rx = 135;
10 | const ry = 300;
11 | const cx = 960;
12 | const cy = 540;
13 | const arcLength = getCircumferenceOfArc(rx, ry);
14 | const strokeWidth = 30;
15 |
16 | export const Arc = ({ progress, rotation, rotateProgress }) => {
17 | const { width, height } = useVideoConfig();
18 |
19 | // Each svg Id must be unique to not conflict with each other
20 | const [gradientId] = useState(() => String(random(null)));
21 |
22 | return (
23 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/src/HelloWorld/Atom.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { random, useVideoConfig } from "remotion";
3 | import { COLOR_1, COLOR_2 } from "./constants";
4 |
5 | export const Atom = ({ scale }) => {
6 | const config = useVideoConfig();
7 |
8 | // Each SVG ID must be unique to not conflict with each other
9 | const [gradientId] = useState(() => String(random(null)));
10 |
11 | return (
12 |
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/src/HelloWorld/Logo.jsx:
--------------------------------------------------------------------------------
1 | import {
2 | AbsoluteFill,
3 | interpolate,
4 | spring,
5 | useCurrentFrame,
6 | useVideoConfig,
7 | } from "remotion";
8 | import { Arc } from "./Arc";
9 | import { Atom } from "./Atom";
10 |
11 | export const Logo = () => {
12 | const videoConfig = useVideoConfig();
13 | const frame = useCurrentFrame();
14 |
15 | const development = spring({
16 | config: {
17 | damping: 100,
18 | mass: 0.5,
19 | },
20 | fps: videoConfig.fps,
21 | frame,
22 | });
23 |
24 | const rotationDevelopment = spring({
25 | config: {
26 | damping: 100,
27 | mass: 0.5,
28 | },
29 | fps: videoConfig.fps,
30 | frame,
31 | });
32 |
33 | const scale = spring({
34 | frame,
35 | config: {
36 | mass: 0.5,
37 | },
38 | fps: videoConfig.fps,
39 | });
40 |
41 | const logoRotation = interpolate(
42 | frame,
43 | [0, videoConfig.durationInFrames],
44 | [0, 360],
45 | );
46 |
47 | return (
48 |
53 |
58 |
63 |
68 |
69 |
70 | );
71 | };
72 |
--------------------------------------------------------------------------------
/src/HelloWorld/Subtitle.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { interpolate, useCurrentFrame } from "remotion";
3 | import { COLOR_1, FONT_FAMILY } from "./constants";
4 |
5 | const subtitle = {
6 | fontFamily: FONT_FAMILY,
7 | fontSize: 40,
8 | textAlign: "center",
9 | position: "absolute",
10 | bottom: 140,
11 | width: "100%",
12 | };
13 |
14 | const codeStyle = {
15 | color: COLOR_1,
16 | };
17 |
18 | export const Subtitle = () => {
19 | const frame = useCurrentFrame();
20 | const opacity = interpolate(frame, [0, 30], [0, 1]);
21 | return (
22 |
23 | Edit src/Root.jsx
and save to reload.
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/HelloWorld/Title.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { spring, useCurrentFrame, useVideoConfig } from "remotion";
3 | import { FONT_FAMILY } from "./constants";
4 |
5 | const title = {
6 | fontFamily: FONT_FAMILY,
7 | fontWeight: "bold",
8 | fontSize: 100,
9 | textAlign: "center",
10 | position: "absolute",
11 | bottom: 160,
12 | width: "100%",
13 | };
14 |
15 | const word = {
16 | marginLeft: 10,
17 | marginRight: 10,
18 | display: "inline-block",
19 | };
20 |
21 | export const Title = ({ titleText, titleColor }) => {
22 | const videoConfig = useVideoConfig();
23 | const frame = useCurrentFrame();
24 |
25 | const words = titleText.split(" ");
26 |
27 | return (
28 |
29 | {words.map((t, i) => {
30 | const delay = i * 5;
31 |
32 | const scale = spring({
33 | fps: videoConfig.fps,
34 | frame: frame - delay,
35 | config: {
36 | damping: 200,
37 | },
38 | });
39 |
40 | return (
41 |
49 | {t}
50 |
51 | );
52 | })}
53 |
54 | );
55 | };
56 |
--------------------------------------------------------------------------------
/src/HelloWorld/constants.js:
--------------------------------------------------------------------------------
1 | // Change any of these to update your video live.
2 |
3 | export const COLOR_1 = "#86A8E7";
4 | export const COLOR_2 = "#91EAE4";
5 |
6 | export const FONT_FAMILY = "SF Pro Text, Helvetica, Arial, sans-serif";
7 |
--------------------------------------------------------------------------------
/src/HelloWorld/index.jsx:
--------------------------------------------------------------------------------
1 | import { spring } from "remotion";
2 | import {
3 | AbsoluteFill,
4 | interpolate,
5 | Sequence,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | } from "remotion";
9 | import { Logo } from "./Logo";
10 | import { Subtitle } from "./Subtitle";
11 | import { Title } from "./Title";
12 |
13 | export const HelloWorld = ({ titleText, titleColor }) => {
14 | const frame = useCurrentFrame();
15 | const { durationInFrames, fps } = useVideoConfig();
16 |
17 | // Animate from 0 to 1 after 25 frames
18 | const logoTranslationProgress = spring({
19 | frame: frame - 25,
20 | fps,
21 | config: {
22 | damping: 100,
23 | },
24 | });
25 |
26 | // Move the logo up by 150 pixels once the transition starts
27 | const logoTranslation = interpolate(
28 | logoTranslationProgress,
29 | [0, 1],
30 | [0, -150],
31 | );
32 |
33 | // Fade out the animation at the end
34 | const opacity = interpolate(
35 | frame,
36 | [durationInFrames - 25, durationInFrames - 15],
37 | [1, 0],
38 | {
39 | extrapolateLeft: "clamp",
40 | extrapolateRight: "clamp",
41 | },
42 | );
43 |
44 | // A is just a absolutely positioned !
45 | return (
46 |
47 |
48 |
49 |
50 |
51 | {/* Sequences can shift the time for its children! */}
52 |
53 |
54 |
55 | {/* The subtitle will only enter on the 75th frame. */}
56 |
57 |
58 |
59 |
60 |
61 | );
62 | };
63 |
--------------------------------------------------------------------------------
/src/Root.jsx:
--------------------------------------------------------------------------------
1 | import { Composition } from "remotion";
2 | import { HelloWorld } from "./HelloWorld";
3 | import { Logo } from "./HelloWorld/Logo";
4 |
5 | // Each
is an entry in the sidebar!
6 |
7 | export const RemotionRoot = () => {
8 | return (
9 | <>
10 | out/video.mp4
13 | id="HelloWorld"
14 | component={HelloWorld}
15 | durationInFrames={150}
16 | fps={30}
17 | width={1920}
18 | height={1080}
19 | // You can override these props for each render:
20 | // https://www.remotion.dev/docs/parametrized-rendering
21 | defaultProps={{
22 | titleText: "Welcome to Remotion",
23 | titleColor: "black",
24 | }}
25 | />
26 | {/* Mount any React component to make it show up in the sidebar and work on it individually! */}
27 |
35 | >
36 | );
37 | };
38 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // This is your entry file! Refer to it when you render:
2 | // npx remotion render HelloWorld out/video.mp4
3 |
4 | import { registerRoot } from "remotion";
5 | import { RemotionRoot } from "./Root";
6 |
7 | registerRoot(RemotionRoot);
8 |
--------------------------------------------------------------------------------