├── .dockerignore
├── .eslintrc
├── src
├── HelloWorld
│ ├── config.ts
│ ├── Subtitle.tsx
│ ├── Atom.tsx
│ ├── Title.tsx
│ ├── Arc.tsx
│ └── Logo.tsx
├── index.tsx
├── LoveDeathReact
│ ├── Icons
│ │ ├── Cyclop.tsx
│ │ ├── X.tsx
│ │ ├── Robot.tsx
│ │ ├── Pyramid.tsx
│ │ ├── Mute.tsx
│ │ ├── Eye.tsx
│ │ ├── Skull.tsx
│ │ ├── Evil.tsx
│ │ ├── Sadomazofembotochist.tsx
│ │ ├── Box.tsx
│ │ ├── Cat.tsx
│ │ └── Heart.tsx
│ ├── Background.tsx
│ ├── Rotation.tsx
│ ├── Dots2.tsx
│ ├── Circle.tsx
│ ├── SignsDark.tsx
│ ├── LoveDeathReact.tsx
│ ├── Rect.tsx
│ ├── index.tsx
│ ├── Dots.tsx
│ ├── ReactLogo.tsx
│ ├── Roulette.tsx
│ ├── Focus.tsx
│ ├── LogoLight.tsx
│ ├── Icons.tsx
│ ├── SignsLight.tsx
│ ├── MainTitle.tsx
│ └── Title.tsx
├── Video.tsx
├── HelloWorld.tsx
└── components
│ └── Redash.tsx
├── remotion.config.ts
├── .gitignore
├── .prettierrc
├── .vscode
└── settings.json
├── tsconfig.json
├── .github
└── workflows
│ └── render-video.yml
├── package.json
├── Dockerfile
├── README.md
└── server.tsx
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@remotion"
3 | }
4 |
--------------------------------------------------------------------------------
/src/HelloWorld/config.ts:
--------------------------------------------------------------------------------
1 | export const COLOR_1 = '#86A8E7';
2 | export const COLOR_2 = '#91EAE4';
3 |
--------------------------------------------------------------------------------
/remotion.config.ts:
--------------------------------------------------------------------------------
1 | import {Config} from 'remotion';
2 |
3 | Config.Rendering.setImageFormat('jpeg');
4 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import {registerRoot} from 'remotion';
2 | import {RemotionVideo} from './Video';
3 |
4 | registerRoot(RemotionVideo);
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .DS_Store
4 |
5 | # Ignore the output video from Git but not videos you import into src/.
6 | *.mp4
7 | !src**/*.mp4
8 | *.mp3
9 | !src**/*.mp3
10 | *.webm
11 | !src**/*.webm
12 | *.aac
13 | !src**/*.aac
14 | *.wav
15 | !src**/*.wav
16 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "bracketSpacing": false,
4 | "jsxBracketSameLine": false,
5 | "useTabs": true,
6 | "overrides": [
7 | {
8 | "files": ["*.yml"],
9 | "options": {
10 | "singleQuote": false
11 | }
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.tabSize": 2,
3 | "java.configuration.updateBuildConfiguration": "disabled",
4 | "typescript.tsdk": "node_modules/typescript/lib",
5 | "editor.codeActionsOnSave": {
6 | "source.organizeImports": false,
7 | "source.fixAll": true
8 | },
9 | "typescript.enablePromptUseWorkspaceTsdk": true
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2018",
4 | "module": "commonjs",
5 | "jsx": "react-jsx",
6 | "outDir": "./dist",
7 | "strict": true,
8 | "noEmit": true,
9 | "lib": ["es2015", "DOM"],
10 | "esModuleInterop": true,
11 | "skipLibCheck": true,
12 | "forceConsistentCasingInFileNames": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Cyclop.tsx:
--------------------------------------------------------------------------------
1 | const Cyclop = () => {
2 | return (
3 |
17 | );
18 | };
19 |
20 | export default Cyclop;
21 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Background.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { StyleSheet, View } from "react-native";
3 |
4 | const styles = StyleSheet.create({
5 | container: {
6 | ...StyleSheet.absoluteFillObject,
7 | backgroundImage: "radial-gradient(#F0E6E0 61%, #8B918D);",
8 | filter: "blur(40px)",
9 | },
10 | });
11 |
12 | const Background = () => {
13 | return (
14 |
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default Background;
22 |
--------------------------------------------------------------------------------
/src/HelloWorld/Subtitle.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, useCurrentFrame} from 'remotion';
2 | import {COLOR_1} from './config';
3 |
4 | export const Subtitle: React.FC = () => {
5 | const frame = useCurrentFrame();
6 | const opacity = interpolate(frame, [0, 30], [0, 1]);
7 | return (
8 |
19 | Edit{' '}
20 |
25 | src/Video.tsx
26 | {' '}
27 | and save to reload.
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/src/HelloWorld/Atom.tsx:
--------------------------------------------------------------------------------
1 | import {useVideoConfig} from 'remotion';
2 | import {COLOR_1, COLOR_2} from './config';
3 |
4 | export const Atom: React.FC<{
5 | scale: number;
6 | }> = ({scale}) => {
7 | const config = useVideoConfig();
8 | return (
9 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/X.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const X = () => {
3 | return (
4 |
20 | );
21 | };
22 |
23 | export default X;
24 |
--------------------------------------------------------------------------------
/src/Video.tsx:
--------------------------------------------------------------------------------
1 | import { Composition } from "remotion";
2 |
3 | import LoveDeathReact from "./LoveDeathReact";
4 |
5 | export const RemotionVideo = () => {
6 | return (
7 | <>
8 |
16 | >
17 | );
18 | };
19 |
20 | /*
21 |
22 |
30 |
38 | */
39 |
--------------------------------------------------------------------------------
/.github/workflows/render-video.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch:
3 | inputs:
4 | titleText:
5 | description: "Which text should it say?"
6 | required: true
7 | default: "Welcome to Remotion"
8 | titleColor:
9 | description: "Which color should it be in?"
10 | required: true
11 | default: "black"
12 | name: Render video
13 | jobs:
14 | render:
15 | name: Render video
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@main
19 | - uses: actions/setup-node@main
20 | - run: sudo apt update
21 | - run: sudo apt install ffmpeg
22 | - run: npm i
23 | - run: npm run build -- --props="$WORKFLOW_INPUT"
24 | env:
25 | WORKFLOW_INPUT: ${{ toJson(github.event.inputs) }}
26 | - uses: actions/upload-artifact@v2
27 | with:
28 | name: out.mp4
29 | path: out.mp4
30 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Robot.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 |
3 | const Robot = () => {
4 | return (
5 |
18 | );
19 | };
20 |
21 | export default Robot;
22 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Pyramid.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const Pyramid = () => {
3 | return (
4 |
18 | );
19 | };
20 |
21 | export default Pyramid;
22 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Mute.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 |
3 | const Mute = () => {
4 | return (
5 |
18 | );
19 | };
20 |
21 | export default Mute;
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "remotion-template",
3 | "version": "1.0.0",
4 | "description": "My Remotion video",
5 | "scripts": {
6 | "start": "remotion preview src/index.tsx",
7 | "build": "remotion render src/index.tsx HelloWorld out.mp4",
8 | "upgrade": "remotion upgrade",
9 | "server": "ts-node server.tsx",
10 | "test": "eslint src --ext ts,tsx,js,jsx && tsc"
11 | },
12 | "repository": {},
13 | "license": "UNLICENSED",
14 | "dependencies": {
15 | "@remotion/bundler": "^2.0.0",
16 | "@remotion/cli": "^2.0.0",
17 | "@remotion/eslint-config": "^2.0.0",
18 | "@remotion/renderer": "^2.0.0",
19 | "@types/express": "^4.17.9",
20 | "@types/react": "^17.0.0",
21 | "eslint": "^7.15.0",
22 | "express": "^4.17.1",
23 | "prettier": "^2.2.1",
24 | "prettier-plugin-organize-imports": "^1.1.1",
25 | "react": "^17.0.2",
26 | "react-dom": "^17.0.2",
27 | "react-native-web": "^0.16.3",
28 | "remotion": "^2.0.0",
29 | "svg-path-properties": "^1.0.11",
30 | "ts-node": "^9.1.1",
31 | "typescript": "^4.2.3"
32 | },
33 | "devDependencies": {
34 | "@types/react-native": "^0.64.5"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # This is a dockerized version of a server that you can easily deploy somewhere.
2 | # If you don't want server rendering, you can safely delete this file.
3 |
4 | FROM node:alpine
5 |
6 | # Installs latest Chromium (85) package.
7 | RUN apk add --no-cache \
8 | chromium \
9 | nss \
10 | freetype \
11 | freetype-dev \
12 | harfbuzz \
13 | ca-certificates \
14 | ttf-freefont \
15 | ffmpeg
16 |
17 | # Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
18 | ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
19 | PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
20 |
21 | COPY package*.json ./
22 | COPY tsconfig.json ./
23 | COPY src src
24 | COPY *.ts .
25 | COPY *.tsx .
26 |
27 | RUN npm i
28 |
29 | # Add user so we don't need --no-sandbox.
30 | RUN addgroup -S pptruser && adduser -S -g pptruser pptruser \
31 | && mkdir -p /home/pptruser/Downloads /app \
32 | && chown -R pptruser:pptruser /home/pptruser \
33 | && chown -R pptruser:pptruser /app
34 | # Run everything after as non-privileged user.
35 | USER pptruser
36 |
37 | EXPOSE 8000
38 |
39 | CMD ["npm", "run", "server"]
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Remotion video
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Welcome to your Remotion project!
10 |
11 | ## Commands
12 |
13 | **Start Preview**
14 |
15 | ```console
16 | npm start
17 | ```
18 |
19 | **Render video**
20 |
21 | ```console
22 | npm run build
23 | ```
24 |
25 | **Server render demo**
26 |
27 | ```console
28 | npm run server
29 | ```
30 |
31 | See [docs for server-side rendering](https://www.remotion.dev/docs/ssr) here.
32 |
33 | **Upgrade Remotion**
34 |
35 | ```console
36 | npm run upgrade
37 | ```
38 |
39 | ## Docs
40 |
41 | Get started with Remotion by reading the [fundamentals page](https://www.remotion.dev/docs/the-fundamentals).
42 |
43 | ## Issues
44 |
45 | Found an issue with Remotion? [File an issue here](https://github.com/JonnyBurger/remotion/issues/new).
46 |
47 | ## License
48 |
49 | Notice that for some entities a company license is needed. Read [the terms here](https://github.com/JonnyBurger/remotion/blob/main/LICENSE.md).
50 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Eye.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const Eye = () => {
3 | return (
4 |
17 | );
18 | };
19 |
20 | export default Eye;
21 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Skull.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const Skull = () => {
3 | return (
4 |
17 | );
18 | };
19 |
20 | export default Skull;
21 |
--------------------------------------------------------------------------------
/src/HelloWorld/Title.tsx:
--------------------------------------------------------------------------------
1 | import {spring, useCurrentFrame, useVideoConfig} from 'remotion';
2 |
3 | export const Title: React.FC<{
4 | titleText: string;
5 | titleColor: string;
6 | }> = ({titleText, titleColor}) => {
7 | const videoConfig = useVideoConfig();
8 | const frame = useCurrentFrame();
9 | const text = titleText.split(' ').map((t) => ` ${t} `);
10 | return (
11 |
22 | {text.map((t, i) => {
23 | return (
24 |
42 | {t}
43 |
44 | );
45 | })}
46 |
47 | );
48 | };
49 |
--------------------------------------------------------------------------------
/src/HelloWorld.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, Sequence, useCurrentFrame, useVideoConfig} from 'remotion';
2 | import {Logo} from './HelloWorld/Logo';
3 | import {Subtitle} from './HelloWorld/Subtitle';
4 | import {Title} from './HelloWorld/Title';
5 |
6 | export const HelloWorld: React.FC<{
7 | titleText: string;
8 | titleColor: string;
9 | }> = ({titleText, titleColor}) => {
10 | const frame = useCurrentFrame();
11 | const videoConfig = useVideoConfig();
12 |
13 | const opacity = interpolate(
14 | frame,
15 | [videoConfig.durationInFrames - 25, videoConfig.durationInFrames - 15],
16 | [1, 0],
17 | {
18 | extrapolateLeft: 'clamp',
19 | extrapolateRight: 'clamp',
20 | }
21 | );
22 | const transitionStart = 25;
23 |
24 | return (
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | );
39 | };
40 |
--------------------------------------------------------------------------------
/src/HelloWorld/Arc.tsx:
--------------------------------------------------------------------------------
1 | import {useVideoConfig} from 'remotion';
2 | import {COLOR_1, COLOR_2} from './config';
3 |
4 | export const Arc: React.FC<{
5 | progress: number;
6 | rotation: number;
7 | rotateProgress: number;
8 | }> = ({progress, rotation, rotateProgress}) => {
9 | const config = useVideoConfig();
10 | const cx = config.width / 2;
11 | const cy = config.height / 2;
12 |
13 | const rx = config.height / 8;
14 | const ry = rx * 2.2;
15 | const arcLength = Math.PI * 2 * Math.sqrt((rx * rx + ry * ry) / 2);
16 | const strokeWidth = arcLength / 60;
17 |
18 | return (
19 |
45 | );
46 | };
47 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Evil.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const Evil = () => {
3 | return (
4 |
17 | );
18 | };
19 |
20 | export default Evil;
21 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Sadomazofembotochist.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 |
3 | const Sadomazofembotochist = () => {
4 | return (
5 |
18 | );
19 | };
20 |
21 | export default Sadomazofembotochist;
22 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Rotation.tsx:
--------------------------------------------------------------------------------
1 | import { View } from "react-native";
2 | import { interpolate, useCurrentFrame } from "remotion";
3 |
4 | import { Extrapolate } from "../components/Redash";
5 |
6 | import Heart from "./Icons/Heart";
7 | import Robot from "./Icons/Robot";
8 | import X from "./Icons/X";
9 |
10 | const Rotation = () => {
11 | const frame = useCurrentFrame();
12 | const rotate = interpolate(frame, [0, 10], [0, 45], Extrapolate.CLAMP);
13 | const translateY = interpolate(frame, [0, 10], [0, 350], Extrapolate.CLAMP);
14 | const scale = interpolate(frame, [10, 17], [1, 0.75], Extrapolate.CLAMP);
15 | return (
16 |
24 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | );
44 | };
45 |
46 | export default Rotation;
47 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Box.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const Box = () => {
3 | return (
4 |
24 | );
25 | };
26 |
27 | export default Box;
28 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Dots2.tsx:
--------------------------------------------------------------------------------
1 | import { View, StyleSheet } from "react-native";
2 |
3 | import Circle from "./Circle";
4 |
5 | const styles = StyleSheet.create({
6 | container: {
7 | ...StyleSheet.absoluteFillObject,
8 | backgroundImage: "radial-gradient(#F5E8E1 61%, #7A7F7A);",
9 | filter: "blur(40px)",
10 | },
11 | footer: {
12 | ...StyleSheet.absoluteFillObject,
13 | flexDirection: "row",
14 | alignItems: "center",
15 | justifyContent: "center",
16 | paddingVertical: 100,
17 | paddingHorizontal: 250,
18 | },
19 | });
20 |
21 | const Background = () => {
22 | return (
23 |
24 |
25 |
26 |
27 | );
28 | };
29 |
30 | const Dots = () => {
31 | return (
32 |
33 |
34 |
35 |
44 |
45 |
46 |
56 |
57 |
58 |
67 |
68 |
69 |
70 |
71 | );
72 | };
73 |
74 | export default Dots;
75 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Circle.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | interface CircleProps {
4 | darkMode: boolean;
5 | }
6 |
7 | const Circle = ({ darkMode }: CircleProps) => {
8 | return (
9 |
50 | );
51 | };
52 |
53 | export default Circle;
54 |
--------------------------------------------------------------------------------
/src/HelloWorld/Logo.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
2 | import {Arc} from './Arc';
3 | import {Atom} from './Atom';
4 |
5 | export const Logo: React.FC<{
6 | transitionStart: number;
7 | }> = ({transitionStart}) => {
8 | const videoConfig = useVideoConfig();
9 | const frame = useCurrentFrame();
10 |
11 | const development = spring({
12 | config: {
13 | damping: 100,
14 | mass: 0.5,
15 | },
16 | fps: videoConfig.fps,
17 | frame,
18 | });
19 |
20 | const rotationDevelopment = spring({
21 | config: {
22 | damping: 100,
23 | mass: 0.5,
24 | },
25 | fps: videoConfig.fps,
26 | frame,
27 | });
28 |
29 | const scaleIn = spring({
30 | frame,
31 | config: {
32 | mass: 0.5,
33 | },
34 | fps: videoConfig.fps,
35 | });
36 |
37 | const translation = interpolate(
38 | spring({
39 | frame: frame - transitionStart,
40 | fps: videoConfig.fps,
41 | config: {
42 | damping: 100,
43 | mass: 0.5,
44 | },
45 | }),
46 | [0, 1],
47 | [0, -150]
48 | );
49 |
50 | const scale = frame < 50 ? scaleIn : 1;
51 |
52 | const logoRotation = interpolate(
53 | frame,
54 | [0, videoConfig.durationInFrames],
55 | [0, 360]
56 | );
57 |
58 | return (
59 |
84 | );
85 | };
86 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Cat.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | const Cat = () => {
3 | return (
4 |
17 | );
18 | };
19 |
20 | export default Cat;
21 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/SignsDark.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import { View } from "react-native";
3 | import { interpolate, useCurrentFrame } from "remotion";
4 |
5 | import { Extrapolate } from "../components/Redash";
6 |
7 | import ReactLogo from "./ReactLogo";
8 |
9 | const SignsDark = () => {
10 | const frame = useCurrentFrame();
11 | const progress = interpolate(frame, [0, 18], [0, 1], Extrapolate.CLAMP);
12 | const stroke = interpolate(frame, [0, 6], [5, 40], Extrapolate.CLAMP);
13 | return (
14 |
23 |
39 |
40 |
56 |
57 | );
58 | };
59 |
60 | export default SignsDark;
61 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/LoveDeathReact.tsx:
--------------------------------------------------------------------------------
1 | import { View, StyleSheet } from "react-native";
2 | import { Easing, interpolate, useCurrentFrame } from "remotion";
3 |
4 | import Background from "./Background";
5 | import Circle from "./Circle";
6 | import Rect from "./Rect";
7 | import Title from "./Title";
8 |
9 | const styles = StyleSheet.create({
10 | footer: {
11 | ...StyleSheet.absoluteFillObject,
12 | flexDirection: "row",
13 | alignItems: "flex-end",
14 | justifyContent: "space-between",
15 | paddingVertical: 100,
16 | paddingHorizontal: 250,
17 | },
18 | });
19 |
20 | interface LoveDeathReactProps {
21 | still: boolean;
22 | darkMode: boolean;
23 | noTitle?: boolean;
24 | }
25 |
26 | const LoveDeathReact = ({ darkMode, still, noTitle }: LoveDeathReactProps) => {
27 | const currentFrame = useCurrentFrame();
28 | const opacity = darkMode
29 | ? interpolate(currentFrame, [0, 2 * 24], [1, 0], {
30 | easing: Easing.out(Easing.ease),
31 | extrapolateLeft: "clamp",
32 | extrapolateRight: "clamp",
33 | })
34 | : 0;
35 | return (
36 |
37 |
38 | {darkMode ? (
39 |
42 | ) : null}
43 |
44 |
45 |
46 |
47 |
48 |
55 | {!noTitle && }
56 |
57 |
64 |
65 | );
66 | };
67 |
68 | export default LoveDeathReact;
69 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Rect.tsx:
--------------------------------------------------------------------------------
1 | import { Easing, interpolate } from "remotion";
2 |
3 | import { Extrapolate } from "../components/Redash";
4 |
5 | interface RectProps {
6 | darkMode: boolean;
7 | progress?: number;
8 | }
9 |
10 | const Circle = ({ progress, darkMode }: RectProps) => {
11 | return (
12 |
62 | );
63 | };
64 |
65 | export default Circle;
66 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/index.tsx:
--------------------------------------------------------------------------------
1 | import { View } from "react-native";
2 | import { Sequence, useVideoConfig } from "remotion";
3 |
4 | import LoveDeathReact from "./LoveDeathReact";
5 | import Dots from "./Dots";
6 | import Dots2 from "./Dots2";
7 | import SignsLight from "./SignsLight";
8 | import SignsDark from "./SignsDark";
9 | import LogoLight from "./LogoLight";
10 | import Icons from "./Icons";
11 | import Roulette from "./Roulette";
12 | import Rotation from "./Rotation";
13 | import MainTitle from "./MainTitle";
14 |
15 | const Comp = () => {
16 | const { fps } = useVideoConfig();
17 | const cuts = [2 * fps, fps, fps + 4, 1, 19, 18, 19, 13, 40, 17, 102] as const;
18 | const from = (index: number) => cuts.slice(0, index).reduce((a, v) => a + v);
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | );
56 | };
57 |
58 | export default Comp;
59 |
--------------------------------------------------------------------------------
/src/components/Redash.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Easing,
3 | interpolate,
4 | spring,
5 | useCurrentFrame,
6 | useVideoConfig,
7 | } from "remotion";
8 |
9 | export const UHD = { width: 3840, height: 2160, aspectRatio: 16 / 9 };
10 | export const HD = { width: 1280, height: 720, aspectRatio: 16 / 9 };
11 |
12 | export const interpolateFontWeight = (
13 | progress: number,
14 | inputRange: number[],
15 | outputRange: string[]
16 | ) =>
17 | `${Math.round(
18 | interpolate(
19 | progress,
20 | inputRange,
21 | outputRange.map((w) => parseInt(w[0]!, 10))
22 | )
23 | )}00`;
24 |
25 | export interface UseSpringParams {
26 | startInMs: number;
27 | currentFrame?: number;
28 | }
29 |
30 | export const useSpring = ({ startInMs, currentFrame }: UseSpringParams) => {
31 | const { fps } = useVideoConfig();
32 | const realFrame = useCurrentFrame();
33 | const frame = currentFrame ?? realFrame;
34 | const startInFrames = (fps * startInMs) / 1000;
35 | return spring({
36 | frame: frame - startInFrames,
37 | from: 0,
38 | to: 1,
39 | fps,
40 | config: {
41 | stiffness: 100,
42 | damping: 200,
43 | },
44 | });
45 | };
46 |
47 | export interface UseTimingParams {
48 | startInMs: number;
49 | durationInMs: number;
50 | currentFrame?: number;
51 | }
52 |
53 | export const useTiming = ({
54 | durationInMs,
55 | startInMs,
56 | currentFrame,
57 | }: UseTimingParams) => {
58 | const { fps } = useVideoConfig();
59 | const realFrame = useCurrentFrame();
60 | const frame = currentFrame ?? realFrame;
61 | const startInFrames = (fps * startInMs) / 1000;
62 | const durationInFrames = (fps * durationInMs) / 1000;
63 | return interpolate(
64 | frame,
65 | [startInFrames, startInFrames + durationInFrames],
66 | [0, 1],
67 | { ...Extrapolate.CLAMP, easing: Easing.inOut(Easing.ease) }
68 | );
69 | };
70 |
71 | export interface UseLoopParams {
72 | durationInMs: number;
73 | }
74 |
75 | export const useLoop = ({ durationInMs }: UseLoopParams) => {
76 | const { fps } = useVideoConfig();
77 | const frame = useCurrentFrame();
78 | const durationInFrames = (fps * durationInMs) / 1000;
79 | const iteration = Math.floor(frame / durationInFrames);
80 | const progress = frame % durationInFrames;
81 | return interpolate(
82 | progress,
83 | [0, durationInFrames],
84 | iteration % 2 ? [0, 1] : [1, 0],
85 | { easing: Easing.inOut(Easing.ease) }
86 | );
87 | };
88 |
89 | export const Extrapolate = {
90 | CLAMP: {
91 | extrapolateLeft: "clamp",
92 | extrapolateRight: "clamp",
93 | },
94 | } as const;
95 |
--------------------------------------------------------------------------------
/server.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an example of a server that returns dynamic video.
3 | * Run `npm run server` to try it out!
4 | * If you don't want to render videos on a server, you can safely
5 | * delete this file.
6 | */
7 |
8 | import {bundle} from '@remotion/bundler';
9 | import {
10 | getCompositions,
11 | renderFrames,
12 | stitchFramesToVideo,
13 | } from '@remotion/renderer';
14 | import express from 'express';
15 | import fs from 'fs';
16 | import os from 'os';
17 | import path from 'path';
18 |
19 | const app = express();
20 | const port = process.env.PORT || 8000;
21 | const compositionId = 'HelloWorld';
22 |
23 | const cache = new Map();
24 |
25 | app.get('/', async (req, res) => {
26 | const sendFile = (file: string) => {
27 | fs.createReadStream(file)
28 | .pipe(res)
29 | .on('close', () => {
30 | res.end();
31 | });
32 | };
33 | try {
34 | if (cache.get(JSON.stringify(req.query))) {
35 | sendFile(cache.get(JSON.stringify(req.query)) as string);
36 | return;
37 | }
38 | const bundled = await bundle(path.join(__dirname, './src/index.tsx'));
39 | const comps = await getCompositions(bundled, {inputProps: req.query});
40 | const video = comps.find((c) => c.id === compositionId);
41 | if (!video) {
42 | throw new Error(`No video called ${compositionId}`);
43 | }
44 | res.set('content-type', 'video/mp4');
45 |
46 | const tmpDir = await fs.promises.mkdtemp(
47 | path.join(os.tmpdir(), 'remotion-')
48 | );
49 | const {assetsInfo} = await renderFrames({
50 | config: video,
51 | webpackBundle: bundled,
52 | onStart: () => console.log('Rendering frames...'),
53 | onFrameUpdate: (f) => {
54 | if (f % 10 === 0) {
55 | console.log(`Rendered frame ${f}`);
56 | }
57 | },
58 | parallelism: null,
59 | outputDir: tmpDir,
60 | inputProps: req.query,
61 | compositionId,
62 | imageFormat: 'jpeg',
63 | });
64 |
65 | const finalOutput = path.join(tmpDir, 'out.mp4');
66 | await stitchFramesToVideo({
67 | dir: tmpDir,
68 | force: true,
69 | fps: video.fps,
70 | height: video.height,
71 | width: video.width,
72 | outputLocation: finalOutput,
73 | imageFormat: 'jpeg',
74 | assetsInfo,
75 | });
76 | cache.set(JSON.stringify(req.query), finalOutput);
77 | sendFile(finalOutput);
78 | console.log('Video rendered and sent!');
79 | } catch (err) {
80 | console.error(err);
81 | res.json({
82 | error: err,
83 | });
84 | }
85 | });
86 |
87 | app.listen(port);
88 |
89 | console.log(
90 | [
91 | `The server has started on http://localhost:${port}!`,
92 | 'You can render a video by passing props as URL parameters.',
93 | '',
94 | 'If you are running Hello World, try this:',
95 | '',
96 | `http://localhost:${port}?titleText=Hello,+World!&titleColor=red`,
97 | '',
98 | ].join('\n')
99 | );
100 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Dots.tsx:
--------------------------------------------------------------------------------
1 | import { View, StyleSheet } from "react-native";
2 | import { Easing, interpolate, useCurrentFrame } from "remotion";
3 |
4 | import { Extrapolate } from "../components/Redash";
5 |
6 | import Rect from "./Rect";
7 | import Circle from "./Circle";
8 |
9 | const styles = StyleSheet.create({
10 | container: {
11 | ...StyleSheet.absoluteFillObject,
12 | backgroundImage: "radial-gradient(#F5E8E1 61%, #7A7F7A);",
13 | filter: "blur(40px)",
14 | },
15 | footer: {
16 | ...StyleSheet.absoluteFillObject,
17 | flexDirection: "row",
18 | alignItems: "flex-end",
19 | justifyContent: "space-between",
20 | paddingVertical: 100,
21 | paddingHorizontal: 250,
22 | },
23 | });
24 |
25 | const Background = () => {
26 | return (
27 |
28 |
29 |
30 |
31 | );
32 | };
33 |
34 | const Dots = () => {
35 | const frame = useCurrentFrame();
36 | const progress = interpolate(frame, [0, 22], [0, 1], {
37 | ...Extrapolate.CLAMP,
38 | easing: Easing.inOut(Easing.ease),
39 | });
40 |
41 | const progress2 = interpolate(frame, [22, 25], [0, 1], {
42 | ...Extrapolate.CLAMP,
43 | easing: Easing.inOut(Easing.ease),
44 | });
45 | const progress3 = interpolate(frame, [25, 28], [0, 1], {
46 | ...Extrapolate.CLAMP,
47 | easing: Easing.inOut(Easing.ease),
48 | });
49 | const translateX = interpolate(progress, [0, 1], [0, 600], Extrapolate.CLAMP);
50 | const translateX2 = interpolate(
51 | progress3,
52 | [0, 1],
53 | [0, 100],
54 | Extrapolate.CLAMP
55 | );
56 | return (
57 |
58 |
59 |
76 |
84 |
85 |
86 |
100 |
101 |
102 |
107 |
108 |
109 |
110 |
111 | );
112 | };
113 |
114 | export default Dots;
115 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons/Heart.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 |
3 | const Heart = () => {
4 | return (
5 |
39 | );
40 | };
41 |
42 | export default Heart;
43 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/ReactLogo.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import { useRef, useState } from "react";
3 | import { Dimensions, StyleSheet, View } from "react-native";
4 | import Svg, { Ellipse, Circle } from "react-native-svg";
5 | import { continueRender, delayRender, interpolate } from "remotion";
6 | import { svgPathProperties } from "svg-path-properties";
7 |
8 | import { Extrapolate } from "../components/Redash";
9 |
10 | interface AnimatedLogoProps {
11 | progress: number;
12 | stroke: number;
13 | }
14 |
15 | const AnimatedLogo = ({ progress, stroke }: AnimatedLogoProps) => {
16 | const properties = new svgPathProperties(
17 | "M178.007 283.429C204.041 328.521 234.394 365.93 262.736 389.882C276.873 401.829 290.94 410.795 304.097 415.48C317.203 420.146 330.756 420.983 342.251 414.347C353.745 407.71 359.797 395.555 362.309 381.871C364.831 368.135 364.099 351.469 360.821 333.252C354.249 296.731 337.028 251.741 310.994 206.649C284.96 161.557 254.608 124.147 226.266 100.195C212.129 88.2486 198.061 79.282 184.905 74.5979C171.798 69.9314 158.245 69.0944 146.751 75.7307C135.256 82.367 129.205 94.5228 126.693 108.207C124.171 121.942 124.903 138.609 128.181 156.825C134.752 193.346 151.974 238.337 178.007 283.429Z"
18 | );
19 | const length = properties.getTotalLength();
20 | const strokeDashoffset = interpolate(
21 | progress,
22 | [0, 0.5],
23 | [length, 0],
24 | Extrapolate.CLAMP
25 | );
26 | const rotate = interpolate(progress, [0.5, 1], [0, 60], Extrapolate.CLAMP);
27 | return (
28 |
63 | );
64 | };
65 | export default AnimatedLogo;
66 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Roulette.tsx:
--------------------------------------------------------------------------------
1 | import { View } from "react-native";
2 | import { Easing, interpolate, useCurrentFrame } from "remotion";
3 |
4 | import { Extrapolate } from "../components/Redash";
5 |
6 | import Heart from "./Icons/Heart";
7 | import Skull from "./Icons/Skull";
8 | import Robot from "./Icons/Robot";
9 | import Sadomazofembotochist from "./Icons/Sadomazofembotochist";
10 | import Mute from "./Icons/Mute";
11 | import Eye from "./Icons/Eye";
12 | import Cat from "./Icons/Cat";
13 | import Pyramid from "./Icons/Pyramid";
14 | import Evil from "./Icons/Evil";
15 | import Cyclop from "./Icons/Cyclop";
16 | import Box from "./Icons/Box";
17 | import X from "./Icons/X";
18 |
19 | const Roulette = () => {
20 | const frame = useCurrentFrame();
21 | const marginVertical = 50;
22 | const translateY = interpolate(frame, [0, 35], [0, 12 * 300], {
23 | ...Extrapolate.CLAMP,
24 | easing: Easing.in(Easing.ease),
25 | });
26 | const translateY1 = interpolate(frame, [0, 40], [0, 8 * 300], {
27 | ...Extrapolate.CLAMP,
28 | easing: Easing.in(Easing.ease),
29 | });
30 | return (
31 |
39 |
48 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | );
161 | };
162 |
163 | export default Roulette;
164 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Focus.tsx:
--------------------------------------------------------------------------------
1 | import { View, StyleSheet } from "react-native";
2 |
3 | const Focus = () => {
4 | return (
5 |
6 |
240 |
241 | );
242 | };
243 |
244 | export default Focus;
245 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/LogoLight.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import React from "react";
3 | import { View, StyleSheet } from "react-native";
4 | import { interpolate, useCurrentFrame } from "remotion";
5 |
6 | import { Extrapolate } from "../components/Redash";
7 |
8 | import Background from "./Background";
9 |
10 | const LogoLight = () => {
11 | const frame = useCurrentFrame();
12 | const rotate = interpolate(frame, [0, 10], [0, 45], Extrapolate.CLAMP);
13 | const width = 853.66;
14 | const height = interpolate(
15 | frame,
16 | [0, 10],
17 | [77.846, 177.846],
18 | Extrapolate.CLAMP
19 | );
20 | const r1 = {
21 | x: 1208 / 2 - width / 2,
22 | y: 1208 / 2 - height / 2,
23 | width,
24 | height,
25 | transform: `rotate(-${rotate}, ${1208 / 2}, ${1208 / 2})`,
26 | };
27 | const r2 = {
28 | x: 1208 / 2 - width / 2,
29 | y: 1208 / 2 - height / 2,
30 | width,
31 | height,
32 | transform: `rotate(-${90 + rotate}, ${1208 / 2}, ${1208 / 2})`,
33 | };
34 | return (
35 |
36 |
37 |
44 |
134 |
135 |
136 | );
137 | };
138 |
139 | export default LogoLight;
140 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Icons.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import { View, StyleSheet } from "react-native";
3 | import { interpolate, useCurrentFrame } from "remotion";
4 |
5 | import { Extrapolate } from "../components/Redash";
6 |
7 | import Background from "./Background";
8 |
9 | const Icons = () => {
10 | const frame = useCurrentFrame();
11 | const darkMode = frame >= 10;
12 | const fill = darkMode ? "white" : "black";
13 | const oppositeFill = !darkMode ? "#F0E6E0" : "black";
14 | const translate = interpolate(
15 | frame,
16 | [0, 9, 12],
17 | [0, 4, 0],
18 | Extrapolate.CLAMP
19 | );
20 | const rotate = 45;
21 | const width = 853.66;
22 | const height = interpolate(frame, [0, 10], [10, 10], Extrapolate.CLAMP);
23 | const r1 = {
24 | x: 1208 / 2 - width / 2,
25 | y: 1208 / 2 - height / 2,
26 | width,
27 | height,
28 | transform: `rotate(-${rotate}, ${1208 / 2}, ${1208 / 2})`,
29 | };
30 | const r2 = {
31 | x: 1208 / 2 - width / 2,
32 | y: 1208 / 2 - height / 2,
33 | width,
34 | height,
35 | transform: `rotate(-${90 + rotate}, ${1208 / 2}, ${1208 / 2})`,
36 | };
37 | return (
38 |
39 |
40 | {darkMode && (
41 |
48 | )}
49 |
56 |
80 |
81 |
89 |
131 |
144 |
157 |
158 |
159 | );
160 | };
161 |
162 | export default Icons;
163 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/SignsLight.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import React from "react";
3 | import { View, StyleSheet } from "react-native";
4 | import { interpolate, useCurrentFrame } from "remotion";
5 |
6 | import { Extrapolate } from "../components/Redash";
7 |
8 | const styles = StyleSheet.create({
9 | container: {
10 | ...StyleSheet.absoluteFillObject,
11 | filter: "blur(40px)",
12 | },
13 | });
14 |
15 | const Background = () => {
16 | const frame = useCurrentFrame();
17 | return (
18 |
19 |
20 |
30 |
31 | );
32 | };
33 |
34 | const SignLights = () => {
35 | const frame = useCurrentFrame();
36 | const translate = interpolate(frame, [0, 4], [40, 0], Extrapolate.CLAMP);
37 | return (
38 |
39 |
40 |
48 |
49 |
90 |
91 |
92 |
104 |
105 |
106 |
119 |
120 |
121 |
122 | );
123 | };
124 |
125 | export default SignLights;
126 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/MainTitle.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | import { View } from "react-native";
3 | import { interpolate, useCurrentFrame } from "remotion";
4 |
5 | import { Extrapolate } from "../components/Redash";
6 |
7 | import Focus from "./Focus";
8 |
9 | const MainTitle = () => {
10 | const frame = useCurrentFrame();
11 | const ov = frame >= 3;
12 | const scale = interpolate(frame, [1, 5], [1.5, 1], Extrapolate.CLAMP);
13 | const translateYL = interpolate(frame, [1, 4], [-500, 0], Extrapolate.CLAMP);
14 | const legLength = interpolate(
15 | frame,
16 | [1, 8],
17 | [2259.86 * 2, 2259.86],
18 | Extrapolate.CLAMP
19 | );
20 | const legLength3 = interpolate(
21 | frame,
22 | [1, 6],
23 | [2279.36 * 1.5, 2279.36],
24 | Extrapolate.CLAMP
25 | );
26 | const L = `M2184.36 707.5H${legLength}V757.5H2184.36V860H${legLength3}V910H2129.36V560H${legLength3}V610H2184.36V707.5Z`;
27 | const Plus = interpolate(
28 | frame,
29 | [1, 10],
30 | [1952.27 * 2, 1952.27],
31 | Extrapolate.CLAMP
32 | );
33 | const width = interpolate(
34 | frame,
35 | [0, 6],
36 | [1563.95 + 707.64, 0],
37 | Extrapolate.CLAMP
38 | );
39 | const x = interpolate(
40 | frame,
41 | [0, 6],
42 | [0, 1563.95 + 707.64],
43 | Extrapolate.CLAMP
44 | );
45 | const R = frame >= 12;
46 | const translateYA = interpolate(frame, [12, 15], [200, 0], Extrapolate.CLAMP);
47 | const translateYC = interpolate(frame, [12, 15], [100, 0], Extrapolate.CLAMP);
48 | const T = interpolate(
49 | frame,
50 | [13, 17],
51 | [2275.03 * 2, 2275.03],
52 | Extrapolate.CLAMP
53 | );
54 | const focus = frame >= 11 && frame <= 25;
55 | const blur = interpolate(frame, [26, 34, 40], [0, 20, 0], Extrapolate.CLAMP);
56 | return (
57 |
64 |
69 |
170 | {focus && }
171 |
172 |
173 | );
174 | };
175 |
176 | export default MainTitle;
177 |
--------------------------------------------------------------------------------
/src/LoveDeathReact/Title.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-nested-ternary */
2 | /* eslint-disable max-len */
3 |
4 | import { interpolate, useCurrentFrame } from "remotion";
5 |
6 | import { Extrapolate } from "../components/Redash";
7 |
8 | interface TitleProps {
9 | darkMode: boolean;
10 | still: boolean;
11 | }
12 |
13 | const Title = ({ darkMode, still }: TitleProps) => {
14 | const currentFrame = useCurrentFrame();
15 | const frame = still ? 0 : currentFrame;
16 | const everythingIsGone = frame >= 17;
17 | const fill = everythingIsGone ? "transparent" : darkMode ? "white" : "black";
18 | const nIsGone = frame >= 5;
19 | const oIsGone = frame >= 7;
20 | const eIsGone = frame >= 9;
21 | const tIsGone = frame >= 10;
22 | const reversedEisGone = frame >= 12;
23 | const isAreGone = frame >= 13;
24 | const xAndLAreGone = frame >= 14;
25 | const rAndLAreGone = frame >= 15;
26 | const showSquares = frame >= 16;
27 | const aIsGone = frame >= 17;
28 | const lIsGone = frame >= 18;
29 | const rectangleIsVisible = frame >= 20 && frame < 23;
30 | const XIsVisible = frame >= 22 && frame < 24;
31 | return (
32 |
259 | );
260 | };
261 |
262 | export default Title;
263 |
--------------------------------------------------------------------------------