├── .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 | Animated Remotion Logo 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 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 48 | 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 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 31 | 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 | </Sequence> 55 | {/* The subtitle will only enter on the 75th frame. */} 56 | <Sequence from={75}> 57 | <Subtitle /> 58 | </Sequence> 59 | </AbsoluteFill> 60 | </AbsoluteFill> 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 <Composition> is an entry in the sidebar! 6 | 7 | export const RemotionRoot = () => { 8 | return ( 9 | <> 10 | <Composition 11 | // You can take the "id" to render a video: 12 | // npx remotion render src/index.jsx <id> 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 | <Composition 28 | id="OnlyLogo" 29 | component={Logo} 30 | durationInFrames={150} 31 | fps={30} 32 | width={1920} 33 | height={1080} 34 | /> 35 | </> 36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // This is your entry file! Refer to it when you render: 2 | // npx remotion render <entry-file> HelloWorld out/video.mp4 3 | 4 | import { registerRoot } from "remotion"; 5 | import { RemotionRoot } from "./Root"; 6 | 7 | registerRoot(RemotionRoot); 8 | --------------------------------------------------------------------------------