├── .dockerignore
├── .eslintrc
├── .gitattributes
├── .github
└── workflows
│ └── render-video.yml
├── .gitignore
├── .prettierrc
├── .vscode
└── settings.json
├── Dockerfile
├── README.md
├── package-lock.json
├── package.json
├── remotion.config.ts
├── server.tsx
├── src
├── Apple.tsx
├── Arc.tsx
├── AudioSupport.tsx
├── Blue.tsx
├── Both.tsx
├── CodeFrame.tsx
├── Coding.tsx
├── Crash.tsx
├── DefiningComposition.tsx
├── Docs.tsx
├── Editing.tsx
├── EndCard.tsx
├── EndCardRepo.tsx
├── EndCardWebsite.tsx
├── EndCardYarn.tsx
├── Face.tsx
├── FadeOut.tsx
├── GlowingStroke.tsx
├── How.tsx
├── HowRemotionWorks.tsx
├── Intro.tsx
├── Logo
│ ├── Logo.tsx
│ ├── LogoMask.tsx
│ └── Triangle.tsx
├── OpenSource.tsx
├── Outro.tsx
├── Outside.tsx
├── Remotion.tsx
├── Reusability.tsx
├── SSR.tsx
├── Screen.tsx
├── Sequences.tsx
├── Slide.tsx
├── Slide1.tsx
├── SlideTitle.tsx
├── Stairs.tsx
├── Step.tsx
├── Step3.tsx
├── SynchronizedCode.tsx
├── Traditional.tsx
├── TraditionalPrograms.tsx
├── UseFrame.tsx
├── VersionControl.tsx
├── Video.tsx
├── WhatToLearnNext.tsx
├── Why.tsx
├── WrittenInReact.tsx
├── crash.mp3
├── footage
│ ├── P1000318.MP4
│ ├── P1000320.MP4
│ ├── apple-long.mp4
│ ├── codep1-1.mp4
│ ├── codep1-2.mp4
│ ├── codep1-3.mp4
│ ├── codep1-4.mp4
│ ├── codep1-5.mp4
│ ├── codep1-6.mp4
│ ├── codep1-7.mp4
│ ├── codep1-8.mp4
│ ├── codep1-9.mp4
│ ├── editing.mp4
│ ├── how.MP4
│ ├── intro.mp4
│ ├── outro.MP4
│ ├── outside.mp4
│ ├── screen.mp4
│ ├── screen3.mp4
│ ├── split-video.sh
│ ├── stairs.mp4
│ ├── traditional.mp4
│ ├── traditional2.mp4
│ └── why.MP4
├── index.tsx
├── prism.css
└── variables.ts
└── tsconfig.json
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@remotion"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | src/footage/split-video.sh filter=lfs diff=lfs merge=lfs -text
2 | src/footage/traditional2.mp4 filter=lfs diff=lfs merge=lfs -text
3 | src/footage/codep1-1.mp4 filter=lfs diff=lfs merge=lfs -text
4 | src/footage/how.MP4 filter=lfs diff=lfs merge=lfs -text
5 | src/footage/intro.mp4 filter=lfs diff=lfs merge=lfs -text
6 | src/footage/outro.MP4 filter=lfs diff=lfs merge=lfs -text
7 | src/footage/screen.mp4 filter=lfs diff=lfs merge=lfs -text
8 | src/footage/why.MP4 filter=lfs diff=lfs merge=lfs -text
9 | src/footage/codep1-4.mp4 filter=lfs diff=lfs merge=lfs -text
10 | src/footage/codep1-8.mp4 filter=lfs diff=lfs merge=lfs -text
11 | src/footage/traditional.mp4 filter=lfs diff=lfs merge=lfs -text
12 | src/footage/codep1-6.mp4 filter=lfs diff=lfs merge=lfs -text
13 | src/footage/outside.mp4 filter=lfs diff=lfs merge=lfs -text
14 | src/footage/screen3.mp4 filter=lfs diff=lfs merge=lfs -text
15 | src/footage/codep1-9.mp4 filter=lfs diff=lfs merge=lfs -text
16 | src/footage/P1000318.MP4 filter=lfs diff=lfs merge=lfs -text
17 | src/footage/P1000320.MP4 filter=lfs diff=lfs merge=lfs -text
18 | src/footage/codep1-2.mp4 filter=lfs diff=lfs merge=lfs -text
19 | src/footage/codep1-3.mp4 filter=lfs diff=lfs merge=lfs -text
20 | src/footage/codep1-5.mp4 filter=lfs diff=lfs merge=lfs -text
21 | src/footage/codep1-7.mp4 filter=lfs diff=lfs merge=lfs -text
22 | src/footage/stairs.mp4 filter=lfs diff=lfs merge=lfs -text
23 | src/footage/apple-long.mp4 filter=lfs diff=lfs merge=lfs -text
24 | src/footage/editing.mp4 filter=lfs diff=lfs merge=lfs -text
25 | src/footage/codep1.MP4 filter=lfs diff=lfs merge=lfs -text
26 | src/footage/codep2.MP4 filter=lfs diff=lfs merge=lfs -text
27 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .DS_Store
4 | src/footage/codep1.MP4
5 | src/footage/codep2.MP4
6 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 | RUN addgroup -S pptruser && adduser -S -g pptruser pptruser \
30 | && mkdir -p /home/pptruser/Downloads /app \
31 | && chown -R pptruser:pptruser /home/pptruser \
32 | && chown -R pptruser:pptruser /app
33 | # Run everything after as non-privileged user.
34 | USER pptruser
35 |
36 | EXPOSE 8000
37 |
38 | CMD ["npm", "run", "server"]
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | My React summit presentation, edited in Remotion!
2 |
3 | Note that because I took the footage directly from the camera, this repo is about 10GB big and will take a long time to clone (need Git LFS).
4 |
5 | I will add a link once the video has been published by React Summit.
6 |
7 | # Remotion video
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Welcome to your Remotion project!
16 |
17 | ## Commands
18 |
19 | **Start Preview**
20 |
21 | ```console
22 | npm start
23 | ```
24 |
25 | **Render video**
26 |
27 | ```console
28 | npm run build
29 | ```
30 |
31 | **Server render demo**
32 |
33 | ```console
34 | npm run server
35 | ```
36 |
37 | See [docs for server-side rendering](https://www.remotion.dev/docs/ssr) here.
38 |
39 | **Upgrade Remotion**
40 |
41 | ```console
42 | npm run upgrade
43 | ```
44 |
45 | ## Docs
46 |
47 | Get started with Remotion by reading the [fundamentals page](https://www.remotion.dev/docs/the-fundamentals).
48 |
49 | ## Issues
50 |
51 | Found an issue with Remotion? [File an issue here](https://github.com/JonnyBurger/remotion/issues/new).
52 |
53 | ## License
54 |
55 | Notice that a company license is needed. Read [the terms here](https://github.com/JonnyBurger/remotion/blob/main/LICENSE.md).
56 |
--------------------------------------------------------------------------------
/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 Both both.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/babel-loader": "^2.0.0",
16 | "@remotion/bundler": "^2.0.0",
17 | "@remotion/cli": "^2.0.0",
18 | "@remotion/eslint-config": "^2.0.0",
19 | "@remotion/renderer": "^2.0.0",
20 | "@types/express": "^4.17.9",
21 | "@types/react": "^17.0.0",
22 | "@types/styled-components": "^5.1.9",
23 | "eslint": "^7.15.0",
24 | "express": "^4.17.1",
25 | "hack-font": "^3.3.0",
26 | "prettier": "^2.2.1",
27 | "prettier-plugin-organize-imports": "^1.1.1",
28 | "prism-react-renderer": "^1.2.0",
29 | "react": "^17.0.1",
30 | "react-dom": "^17.0.2",
31 | "remotion": "^2.0.0",
32 | "styled-components": "^5.2.1",
33 | "ts-node": "^9.1.1",
34 | "typescript": "^4.1.3"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/remotion.config.ts:
--------------------------------------------------------------------------------
1 | import {Config} from 'remotion';
2 |
3 | Config.Output.setCodec('h264');
4 | Config.Output.setImageSequence(false);
5 | Config.Rendering.setImageFormat('jpeg');
6 |
--------------------------------------------------------------------------------
/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 = 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);
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 | 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 | userProps: 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 | });
75 | cache.set(JSON.stringify(req.query), finalOutput);
76 | sendFile(finalOutput);
77 | console.log('Video rendered and sent!');
78 | } catch (err) {
79 | console.error(err);
80 | res.json({
81 | error: err,
82 | });
83 | }
84 | });
85 |
86 | app.listen(port);
87 |
88 | console.log(
89 | [
90 | `The server has started on http://localhost:${port}!`,
91 | 'You can render a video by passing props as URL parameters.',
92 | '',
93 | 'If you are running Hello World, try this:',
94 | '',
95 | `http://localhost:${port}?titleText=Hello,+World!&titleColor=red`,
96 | '',
97 | ].join('\n')
98 | );
99 |
--------------------------------------------------------------------------------
/src/Apple.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | interpolate,
4 | spring,
5 | useCurrentFrame,
6 | useVideoConfig,
7 | Video,
8 | } from 'remotion';
9 | import apple from './footage/apple-long.mp4';
10 |
11 | export const Apple: React.FC = () => {
12 | const frame = useCurrentFrame();
13 | const {durationInFrames, fps} = useVideoConfig();
14 | const opacity = interpolate(
15 | frame,
16 | [durationInFrames - 10, durationInFrames],
17 | [1, 0]
18 | );
19 | const scale = spring({
20 | frame,
21 | fps,
22 | config: {
23 | damping: 400,
24 | mass: 2,
25 | },
26 | });
27 | return (
28 |
37 |
42 |
43 | );
44 | };
45 |
--------------------------------------------------------------------------------
/src/Arc.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
2 |
3 | export const Arc: React.FC<{
4 | rotation: number;
5 | delay: number;
6 | }> = ({delay, rotation}) => {
7 | const frame = useCurrentFrame();
8 | const {height, width, fps} = useVideoConfig();
9 | const rx = 180;
10 | const ry = 400;
11 | const arcLength = Math.PI * 2 * Math.sqrt((rx * rx + ry * ry) / 2);
12 |
13 | const progress = spring({
14 | frame: frame - delay,
15 | fps,
16 | config: {
17 | damping: 100,
18 | mass: 10,
19 | },
20 | });
21 |
22 | const opacity = interpolate(progress, [0, 0.2], [0, 0.7], {
23 | extrapolateRight: 'clamp',
24 | extrapolateLeft: 'clamp',
25 | });
26 |
27 | const strokeWidth = interpolate(progress, [0, 1], [200, 60]);
28 |
29 | return (
30 |
37 |
51 |
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/src/AudioSupport.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | export const AudioSupport: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const {fps, durationInFrames} = useVideoConfig();
9 | const pos = spring({
10 | fps,
11 | frame,
12 | config: {
13 | damping: 200,
14 | },
15 | });
16 | const posout = spring({
17 | fps,
18 | frame: durationInFrames - frame - 10,
19 | config: {
20 | damping: 200,
21 | },
22 | });
23 | const actualpos =
24 | interpolate(pos, [0, 1], [1200, 0]) +
25 | interpolate(posout, [0, 1], [-1200, 0]);
26 | return (
27 |
28 |
29 |
<Audio/>
30 |
31 |
32 | - Include audio in your video
33 | - Use multiple tracks, cut and trim, control volume
34 | - Remotion will place and mix the audio for you
35 |
36 |
37 |
38 |
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/src/Blue.tsx:
--------------------------------------------------------------------------------
1 | import {AbsoluteFill} from 'remotion';
2 |
3 | export const Blue: React.FC = () => {
4 | return (
5 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/src/Both.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Face} from './Face';
3 | import {ScreenRecording} from './Screen';
4 |
5 | export const Both: React.FC = () => {
6 | return (
7 |
8 |
17 |
18 |
19 |
27 |
28 |
29 |
30 | );
31 | };
32 |
--------------------------------------------------------------------------------
/src/CodeFrame.tsx:
--------------------------------------------------------------------------------
1 | import 'hack-font/build/web/hack.css';
2 | import Highlight, {defaultProps} from 'prism-react-renderer';
3 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
4 | import styled from 'styled-components';
5 | import './prism.css';
6 |
7 | const Pre = styled.pre<{
8 | width: number;
9 | }>`
10 | text-align: left;
11 | margin: 1em 0;
12 | font-size: 40px;
13 | width: ${(props) => props.width}px;
14 | `;
15 |
16 | const Line = styled.div`
17 | display: table-row;
18 | `;
19 |
20 | const LineContent = styled.span`
21 | display: table-cell;
22 | `;
23 |
24 | const Container = styled.div`
25 | flex: 1;
26 | justify-content: center;
27 | align-items: center;
28 | display: flex;
29 | `;
30 |
31 | const Frame = styled.div`
32 | border: 2px solid rgba(0, 0, 0, 0.14);
33 | border-radius: 20px;
34 | background-color: white;
35 |
36 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
37 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
38 | `;
39 |
40 | const Title = styled.div`
41 | padding: 20px;
42 | text-align: center;
43 | font-size: 28px;
44 | `;
45 |
46 | const getProgressOfLine = ({
47 | line,
48 | frame,
49 | fps,
50 | timing,
51 | }: {
52 | line: number;
53 | frame: number;
54 | fps: number;
55 | timing: Timing[];
56 | }) => {
57 | const segment = timing.find((t) => t.line === line);
58 | if (!segment) {
59 | return 1;
60 | }
61 | return spring({
62 | fps,
63 | frame: frame - segment.from,
64 | config: {
65 | stiffness: 200,
66 | damping: 100,
67 | mass: 0.5,
68 | overshootClamping: true,
69 | },
70 | });
71 | };
72 |
73 | type Timing = {
74 | line: number;
75 | from: number;
76 | };
77 |
78 | export const CodeFrame: React.FC<{
79 | code: string;
80 | timing: Timing[];
81 | title: string;
82 | width: number;
83 | }> = ({code, timing, title, width}) => {
84 | const frame = useCurrentFrame();
85 | const {fps} = useVideoConfig();
86 |
87 | return (
88 |
89 |
90 | {title}
91 |
92 |
98 | {({className, style, tokens, getLineProps, getTokenProps}) => (
99 |
100 | {tokens.map((line, i) => {
101 | return (
102 |
132 |
133 | {line.map((token, key) => {
134 | const props = getTokenProps({token, key});
135 | return (
136 |
145 | );
146 | })}
147 |
148 |
149 | );
150 | })}
151 |
152 | )}
153 |
154 |
155 |
156 |
157 | );
158 | };
159 |
--------------------------------------------------------------------------------
/src/Coding.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | AbsoluteFill,
3 | interpolate,
4 | Sequence,
5 | spring,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | } from 'remotion';
9 | import {SynchronizedCode} from './SynchronizedCode';
10 | const topick = [
11 | [-22250, 22736],
12 | [-25005, 27426],
13 | [-46740, 52920],
14 | [-53503, 69746],
15 | [-72858, 75706],
16 | [-87294, 96643],
17 | [-98325, 100068],
18 | [-105244, 108610],
19 | ];
20 |
21 | export const CODING_DURATION = topick.reduce((a, b) => {
22 | return a + b[0] + b[1];
23 | }, 0);
24 |
25 | export const Coding: React.FC<{
26 | type: 'both' | 'face' | 'screen';
27 | }> = ({type}) => {
28 | let durationSum = 0;
29 | const {fps, durationInFrames} = useVideoConfig();
30 | const frame = useCurrentFrame();
31 | const progress = spring({
32 | fps,
33 | frame,
34 | config: {
35 | damping: 200,
36 | },
37 | });
38 | const translateX =
39 | type === 'screen' ? interpolate(progress, [0, 1], [2000, 0]) : 0;
40 |
41 | const opacity = interpolate(
42 | frame,
43 | [durationInFrames - 20, durationInFrames],
44 | [1, 0]
45 | );
46 |
47 | return (
48 |
54 | {topick.map((pick) => {
55 | const duration = pick[0] + pick[1];
56 | durationSum += duration;
57 | return (
58 |
59 |
60 |
61 |
62 |
63 | );
64 | })}
65 |
66 | );
67 | };
68 |
--------------------------------------------------------------------------------
/src/Crash.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Img,
4 | interpolate,
5 | spring,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | } from 'remotion';
9 | import {Slide} from './Slide';
10 |
11 | export const Crash: React.FC = () => {
12 | const frame = useCurrentFrame();
13 | const {fps} = useVideoConfig();
14 | const scale = spring({
15 | frame,
16 | fps,
17 | });
18 |
19 | const hang = interpolate(
20 | spring({
21 | frame: frame - 100,
22 | fps,
23 | config: {
24 | mass: 10,
25 | damping: 20,
26 | },
27 | }),
28 | [0, 1],
29 | [0, -90]
30 | );
31 |
32 | const fallDown = spring({
33 | fps,
34 | frame: frame - 200,
35 | config: {
36 | damping: 200,
37 | },
38 | });
39 |
40 | return (
41 |
42 |
48 |

52 |
53 |
54 | );
55 | };
56 |
--------------------------------------------------------------------------------
/src/DefiningComposition.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {CodeFrame} from './CodeFrame';
3 | import {Slide} from './Slide';
4 |
5 | export const DefiningComposition: React.FC = () => {
6 | return (
7 |
8 | {
13 | return (
14 |
22 | );
23 | }
24 |
25 | `.trim()}
26 | timing={[
27 | {
28 | line: 4,
29 | from: 800,
30 | },
31 | {
32 | line: 5,
33 | from: 850,
34 | },
35 | {
36 | line: 6,
37 | from: 900,
38 | },
39 | {
40 | line: 7,
41 | from: 950,
42 | },
43 | {
44 | line: 8,
45 | from: 1100,
46 | },
47 | ]}
48 | />
49 |
50 | );
51 | };
52 |
--------------------------------------------------------------------------------
/src/Docs.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | export const Docs: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const {fps, durationInFrames} = useVideoConfig();
9 | const pos = spring({
10 | fps,
11 | frame,
12 | config: {
13 | damping: 200,
14 | },
15 | });
16 | const posout = spring({
17 | fps,
18 | frame: durationInFrames - frame - 10,
19 | config: {
20 | damping: 200,
21 | },
22 | });
23 | const actualpos =
24 | interpolate(pos, [0, 1], [1200, 0]) +
25 | interpolate(posout, [0, 1], [-1200, 0]);
26 | return (
27 |
28 |
29 |
Docs: remotion.dev
30 |
31 |
32 | - Documentation of all Remotion APIs
33 | - Tips for common use cases
34 | - Video tutorials
35 |
36 |
37 |
38 |
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/src/Editing.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | AbsoluteFill,
4 | interpolate,
5 | spring,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | Video,
9 | } from 'remotion';
10 | import styled from 'styled-components';
11 | import editing from './footage/editing.mp4';
12 | import {Slide} from './Slide';
13 |
14 | const Banner = styled.div`
15 | background-color: white;
16 | left: 60px;
17 | font-size: 60px;
18 | font-weight: 500;
19 | font-family: --apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
20 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
21 | padding: 20px 40px;
22 | display: inline-block;
23 | margin-left: 100px;
24 | `;
25 |
26 | export const Editing: React.FC = () => {
27 | const frame = useCurrentFrame();
28 | const {fps} = useVideoConfig();
29 | const translation = spring({
30 | fps,
31 | frame: frame - 20,
32 | config: {
33 | damping: 200,
34 | },
35 | });
36 |
37 | return (
38 |
39 |
40 |
41 |
42 |
51 | This is what it looks like editing this video!
52 |
53 |
54 |
55 |
56 |
57 | );
58 | };
59 |
--------------------------------------------------------------------------------
/src/EndCard.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | AbsoluteFill,
3 | interpolate,
4 | Sequence,
5 | spring,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | } from 'remotion';
9 | import styled from 'styled-components';
10 | import {EndCardRepo} from './EndCardRepo';
11 | import {EndCardWebsite} from './EndCardWebsite';
12 | import {EndCardYarn} from './EndCardYarn';
13 | import {GlowingStroke} from './GlowingStroke';
14 | import {LogoMask} from './Logo/LogoMask';
15 |
16 | const Outer = styled(AbsoluteFill)`
17 | background-color: white;
18 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
19 | `;
20 |
21 | const Container = styled.div`
22 | display: flex;
23 | flex: 1;
24 | flex-direction: row;
25 | padding: 40px;
26 | `;
27 |
28 | const Left = styled.div`
29 | flex: 1;
30 | display: flex;
31 | `;
32 |
33 | const Right = styled.div`
34 | flex: 1;
35 | display: flex;
36 | flex-direction: column;
37 | `;
38 |
39 | const RADIUS = 30;
40 |
41 | const Panel = styled.div`
42 | position: absolute;
43 | background-color: white;
44 | border-radius: ${RADIUS}px;
45 | display: flex;
46 | justify-content: center;
47 | align-items: center;
48 | box-shadow: 0 15px 20px rgba(0, 0, 0, 0.07);
49 | `;
50 |
51 | const Centered = styled(AbsoluteFill)`
52 | justify-content: center;
53 | align-items: center;
54 | `;
55 |
56 | export const EndCard: React.FC = () => {
57 | const width = 1792;
58 | const height = 1120;
59 | const {fps, durationInFrames} = useVideoConfig();
60 |
61 | const PADDING = 40;
62 | const SPACING = 30;
63 | const PANEL_WIDTH = (width - PADDING * 2 - SPACING) / 2;
64 | const BIG_PANEL_HEIGHT = height - PADDING * 2;
65 | const SMALL_PANEL_HEIGHT = (height - PADDING * 2 - SPACING) / 2;
66 | const frame = useCurrentFrame();
67 | const progress = (i: number) =>
68 | spring({
69 | fps,
70 | frame: frame - i * 10 - 15,
71 | config: {
72 | damping: 100,
73 | mass: 2,
74 | },
75 | });
76 |
77 | const opacity = interpolate(frame, [0, 50], [0, 1]);
78 |
79 | return (
80 |
81 |
82 |
83 |
84 |
91 |
92 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
113 |
114 |
122 |
123 |
124 |
125 |
126 |
134 |
135 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | );
155 | };
156 |
--------------------------------------------------------------------------------
/src/EndCardRepo.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | const Container = styled.div`
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | flex-direction: column;
8 | `;
9 |
10 | const Title = styled.div`
11 | font-weight: 700;
12 | font-family: -apple-system, BlinkMacSystemFont;
13 | font-size: 30px;
14 | margin-bottom: 7px;
15 | `;
16 |
17 | const Link = styled.div`
18 | font-weight: 700;
19 | font-size: 40px;
20 | font-family: -apple-system, BlinkMacSystemFont;
21 | background: linear-gradient(to right, #f5ad43, #fd764a);
22 | -webkit-background-clip: text;
23 | -moz-background-clip: text;
24 | background-clip: text;
25 | -webkit-text-fill-color: transparent;
26 | -moz-text-fill-color: transparent;
27 | text-fill-color: transparent;
28 | `;
29 |
30 | export const EndCardRepo: React.FC = () => {
31 | return (
32 |
33 | This talk is on Github:
34 |
39 | JonnyBurger/react-summit-talk
40 |
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/src/EndCardWebsite.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | const Container = styled.div`
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | flex-direction: column;
8 | `;
9 |
10 | const Title = styled.div`
11 | font-weight: 700;
12 | font-family: -apple-system, BlinkMacSystemFont;
13 | font-size: 30px;
14 | margin-bottom: 5px;
15 | `;
16 |
17 | const Link = styled.div`
18 | font-weight: 700;
19 | font-size: 60px;
20 | font-family: -apple-system, BlinkMacSystemFont;
21 | background: linear-gradient(to right, #e01d67, #79367a);
22 | -webkit-background-clip: text;
23 | -moz-background-clip: text;
24 | background-clip: text;
25 | -webkit-text-fill-color: transparent;
26 | -moz-text-fill-color: transparent;
27 | text-fill-color: transparent;
28 | `;
29 |
30 | export const EndCardWebsite: React.FC = () => {
31 | return (
32 |
33 | Read the documentation:
34 |
41 | remotion.dev
42 |
43 |
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/src/EndCardYarn.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import {Triangle} from './Logo/Triangle';
3 |
4 | const Container = styled.div`
5 | justify-content: center;
6 | align-items: center;
7 | display: flex;
8 | flex-direction: column;
9 | `;
10 |
11 | const Title = styled.div`
12 | font-weight: 700;
13 | font-family: -apple-system, BlinkMacSystemFont;
14 | font-size: 30px;
15 | margin-bottom: 5px;
16 | `;
17 |
18 | const YarnCreateVideo = styled.div`
19 | font-weight: 700;
20 | font-size: 60px;
21 | font-family: -apple-system, BlinkMacSystemFont;
22 | background: linear-gradient(to right, #4290f5, #42e9f5);
23 | -webkit-background-clip: text;
24 | -moz-background-clip: text;
25 | background-clip: text;
26 | -webkit-text-fill-color: transparent;
27 | -moz-text-fill-color: transparent;
28 | text-fill-color: transparent;
29 | `;
30 |
31 | export const EndCardYarn: React.FC = () => {
32 | return (
33 |
34 |
35 |
36 |
37 |
38 |
39 | Create your first video:
40 | yarn create video
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/src/Face.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {AbsoluteFill, Audio, Sequence, useVideoConfig} from 'remotion';
3 | import {Coding, CODING_DURATION} from './Coding';
4 | import crash from './crash.mp3';
5 | import {How, howlength} from './How';
6 | import {Intro} from './Intro';
7 | import {LogoMask} from './Logo/LogoMask';
8 | import {Outro, outrolength} from './Outro';
9 | import {Outside} from './Outside';
10 | import {Stairs} from './Stairs';
11 | import {Traditional} from './Traditional';
12 | import {
13 | introlength,
14 | introoffset,
15 | outsidelength,
16 | stairslength,
17 | traditionallength,
18 | } from './variables';
19 | import {ENABLE_WHY, Why, whylength} from './Why';
20 |
21 | export const Face: React.FC = () => {
22 | const {durationInFrames} = useVideoConfig();
23 | return (
24 | <>
25 |
26 |
27 |
28 |
32 |
33 |
34 |
38 |
39 |
40 |
44 |
45 |
46 |
56 |
57 |
58 | {ENABLE_WHY ? (
59 |
71 |
72 |
73 | ) : (
74 | 0
75 | )}
76 |
88 |
89 |
90 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | >
114 | );
115 | };
116 |
--------------------------------------------------------------------------------
/src/FadeOut.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | AbsoluteFill,
4 | interpolate,
5 | spring,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | } from 'remotion';
9 | import {Triangle} from './Logo/Triangle';
10 |
11 | export const FadeOut: React.FC = () => {
12 | const frame = useCurrentFrame();
13 | const {fps} = useVideoConfig();
14 | const spring1 = spring({
15 | fps,
16 | frame,
17 | config: {damping: 200, mass: 1.5},
18 | });
19 | const size1 = interpolate(spring1, [0, 1], [0, 10]);
20 | const spring2 = spring({
21 | fps,
22 | frame: frame - 15,
23 | config: {damping: 200, mass: 1.5},
24 | });
25 | const size2 = interpolate(spring2, [0, 1], [0, 10]);
26 | return (
27 |
32 |
33 |
40 |
41 |
42 |
43 |
44 |
51 |
52 |
53 |
54 |
55 | );
56 | };
57 |
--------------------------------------------------------------------------------
/src/GlowingStroke.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
2 | import styled from 'styled-components';
3 |
4 | const Container = styled.div<{
5 | width: number;
6 | height: number;
7 | }>`
8 | position: absolute;
9 | width: ${(props) => props.width}px;
10 | height: ${(props) => props.height}px;
11 | `;
12 |
13 | export const GlowingStroke: React.FC<{
14 | width: number;
15 | height: number;
16 | radius: number;
17 | color1: string;
18 | color2: string;
19 | offset: number;
20 | }> = ({width, height, radius, color1, color2, offset}) => {
21 | const frame = useCurrentFrame();
22 | const {fps} = useVideoConfig();
23 | const start = 40 + offset;
24 | const progress = spring({
25 | frame: frame - start,
26 | fps,
27 | config: {
28 | damping: 200,
29 | stiffness: 50,
30 | mass: 6,
31 | },
32 | });
33 | const circumference = width * 2 + height * 2;
34 | const strokeDashoffset = interpolate(
35 | progress,
36 | [0, 1],
37 | [0, -circumference + 250]
38 | );
39 | const opacity = (() => {
40 | if (frame < start + 10) {
41 | return interpolate(frame, [start, start + 10], [0, 1], {
42 | extrapolateLeft: 'clamp',
43 | extrapolateRight: 'clamp',
44 | });
45 | }
46 | return interpolate(progress, [0.9, 0.95], [1, 0]);
47 | })();
48 | const gId = `g-${color1}-${color2}`;
49 | return (
50 |
51 |
76 |
77 | );
78 | };
79 |
--------------------------------------------------------------------------------
/src/How.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, Sequence, useCurrentFrame, Video} from 'remotion';
2 | import how from './footage/how.mp4';
3 | export const howlength = 241.5 * 50;
4 | const howoffset = -400;
5 |
6 | export const How: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const opacity = interpolate(frame, [0, 50], [0, 1]);
9 | return (
10 |
15 |
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/src/HowRemotionWorks.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, useCurrentFrame} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideTitle} from './SlideTitle';
5 |
6 | export const HowRemotionWorks: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const opacity = interpolate(frame, [0, 50], [0, 1]);
9 | return (
10 |
11 |
12 | Understanding Remotion
13 |
14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/src/Intro.tsx:
--------------------------------------------------------------------------------
1 | import {Video} from 'remotion';
2 | import intro from './footage/intro.mp4';
3 |
4 | export const Intro: React.FC = () => {
5 | return ;
6 | };
7 |
--------------------------------------------------------------------------------
/src/Logo/Logo.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
2 | import styled from 'styled-components';
3 | import {Triangle} from './Triangle';
4 |
5 | const Outer = styled.div`
6 | display: flex;
7 | justify-content: center;
8 | flex: 1;
9 | align-items: center;
10 | background-color: white;
11 | `;
12 |
13 | const Introducing = styled.div`
14 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
15 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
16 | color: white;
17 | font-size: 120px;
18 | font-weight: 700;
19 | `;
20 |
21 | const Title = styled.div`
22 | font-size: 210px;
23 | font-family: 'SF Pro Text';
24 | font-weight: 700;
25 | `;
26 |
27 | const scaleStart = 45;
28 |
29 | export const Logo: React.FC<{
30 | showText: boolean;
31 | offset: number;
32 | textStartOffset: number;
33 | }> = ({showText, offset, textStartOffset}) => {
34 | const textStart = 85 + textStartOffset;
35 | const {fps, width, height} = useVideoConfig();
36 | const currentFrame = useCurrentFrame();
37 | const frame = currentFrame - offset;
38 | const blueOpacity = interpolate(frame, [0, 5], [0, 1], {
39 | extrapolateRight: 'clamp',
40 | });
41 | const textOpacity = interpolate(
42 | frame,
43 | [scaleStart - 10, scaleStart - 0],
44 | [1, 0]
45 | );
46 |
47 | const scale = (index: number) => {
48 | const progress = spring({
49 | fps,
50 | frame: frame - index * 10 - scaleStart,
51 | config: {
52 | damping: 200,
53 | mass: 0.7,
54 | },
55 | });
56 | return interpolate(progress, [0, 1], [20, 1]);
57 | };
58 |
59 | const textAnimated = spring({
60 | fps,
61 | frame: frame - textStart,
62 | config: {
63 | damping: 100,
64 | mass: 2,
65 | stiffness: 200,
66 | },
67 | });
68 |
69 | return (
70 |
71 |
85 |
Remotion
86 |
87 |
102 |
107 |
108 |
109 |
110 | {showText ? (
111 |
120 | Introducing
121 |
122 | ) : null}
123 |
124 | );
125 | };
126 |
--------------------------------------------------------------------------------
/src/Logo/LogoMask.tsx:
--------------------------------------------------------------------------------
1 | import {Easing, interpolate, useCurrentFrame} from 'remotion';
2 | import styled from 'styled-components';
3 |
4 | const Container = styled.svg`
5 | position: absolute;
6 | `;
7 |
8 | const triangleWidth = 195;
9 | const triangleHeight = 185.63699340820312;
10 |
11 | export const LogoMask: React.FC<{
12 | width: number;
13 | height: number;
14 | inverse: boolean;
15 | offset: number;
16 | }> = ({width, height, inverse, offset}) => {
17 | const frame = useCurrentFrame();
18 | const spr = interpolate(frame - offset, [0, 50], [0, 1], {
19 | extrapolateLeft: 'clamp',
20 | extrapolateRight: 'clamp',
21 | easing: Easing.in(Easing.ease),
22 | });
23 |
24 | const progress = inverse ? 1 - spr : spr;
25 | const scale = interpolate(progress, [0, 1], [10, 0]);
26 | const s = scale;
27 | return (
28 |
36 |
37 |
43 |
44 |
51 |
61 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 | );
81 | };
82 |
--------------------------------------------------------------------------------
/src/Logo/Triangle.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | const Container = styled.svg`
4 | position: absolute;
5 | `;
6 |
7 | export const Triangle: React.FC<{
8 | size: number;
9 | opacity: number;
10 | scale: number;
11 | color?: string;
12 | }> = ({size, opacity, scale, color}) => {
13 | return (
14 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
35 |
36 |
37 | );
38 | };
39 |
--------------------------------------------------------------------------------
/src/OpenSource.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, useCurrentFrame, useVideoConfig} from 'remotion';
2 | import styled from 'styled-components';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | const GithubIcon: React.FC = () => {
7 | return (
8 |
14 | );
15 | };
16 |
17 | const Title = styled(SlideTitle)`
18 | background: linear-gradient(to right, #000, #444);
19 | -webkit-background-clip: text;
20 | -moz-background-clip: text;
21 | background-clip: text;
22 | -webkit-text-fill-color: transparent;
23 | -moz-text-fill-color: transparent;
24 | text-fill-color: transparent;
25 | color: black;
26 | `;
27 |
28 | export const OpenSource: React.FC = () => {
29 | const frame = useCurrentFrame();
30 | const {durationInFrames} = useVideoConfig();
31 | const opacity1 = interpolate(frame, [0, 50], [0, 1], {
32 | extrapolateLeft: 'clamp',
33 | extrapolateRight: 'clamp',
34 | });
35 | const opacity =
36 | interpolate(frame, [durationInFrames - 50, durationInFrames], [1, 0], {
37 | extrapolateLeft: 'clamp',
38 | extrapolateRight: 'clamp',
39 | }) * opacity1;
40 | return (
41 |
42 |
43 | This talk is
44 |
Open source
45 |
46 |
47 |
48 | JonnyBurger/react-summit-talk
49 |
50 |
51 |
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/src/Outro.tsx:
--------------------------------------------------------------------------------
1 | import {Sequence, Video} from 'remotion';
2 | import outro from './footage/outro.mp4';
3 |
4 | export const outrolength = 113 * 50;
5 | const outrooffset = -530;
6 |
7 | export const Outro: React.FC = () => {
8 | return (
9 |
14 |
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/Outside.tsx:
--------------------------------------------------------------------------------
1 | import {Video} from 'remotion';
2 | import outside from './footage/outside.mp4';
3 |
4 | export const Outside: React.FC = () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/src/Remotion.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | AbsoluteFill,
4 | Img,
5 | interpolate,
6 | spring,
7 | useCurrentFrame,
8 | useVideoConfig,
9 | } from 'remotion';
10 | import {LogoMask} from './Logo/LogoMask';
11 | import {Slide} from './Slide';
12 | import {SlideTitle} from './SlideTitle';
13 |
14 | export const Remotion: React.FC = () => {
15 | const frame = useCurrentFrame();
16 | const {fps} = useVideoConfig();
17 | const transition = spring({
18 | frame,
19 | fps,
20 | config: {
21 | damping: 200,
22 | },
23 | });
24 | const opacity = interpolate(frame, [49, 50], [0, 1]);
25 | return (
26 |
27 |
28 |
29 |
33 |
34 | Remotion
35 |
36 |
37 |
38 |
47 |
48 |
49 |
50 | );
51 | };
52 |
--------------------------------------------------------------------------------
/src/Reusability.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle} from './SlideTitle';
5 |
6 | export const Reusability: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const {fps} = useVideoConfig();
9 | const scale = spring({
10 | frame,
11 | fps,
12 | from: 0,
13 | to: 1,
14 | config: {
15 | damping: 200,
16 | },
17 | });
18 | return (
19 |
20 |
25 | Is there a better way to reuse elements than copy-paste?
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/SSR.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | export const Ssr: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const {fps, durationInFrames} = useVideoConfig();
9 | const pos = spring({
10 | fps,
11 | frame,
12 | config: {
13 | damping: 200,
14 | },
15 | });
16 | const posout = spring({
17 | fps,
18 | frame: durationInFrames - frame - 10,
19 | config: {
20 | damping: 200,
21 | },
22 | });
23 | const actualpos =
24 | interpolate(pos, [0, 1], [1200, 0]) +
25 | interpolate(posout, [0, 1], [-1200, 0]);
26 | return (
27 |
28 |
29 |
SSR
30 |
31 |
32 | - Render videos in the cloud
33 | -
34 | Use the APIs for bundling, rendering and stitching
35 | programmatically
36 |
37 |
38 |
39 |
40 |
41 | );
42 | };
43 |
--------------------------------------------------------------------------------
/src/Screen.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {AbsoluteFill, Sequence, useVideoConfig} from 'remotion';
3 | import {Apple} from './Apple';
4 | import {AudioSupport} from './AudioSupport';
5 | import {Coding, CODING_DURATION} from './Coding';
6 | import {Crash} from './Crash';
7 | import {DefiningComposition} from './DefiningComposition';
8 | import {Docs} from './Docs';
9 | import {Editing} from './Editing';
10 | import {EndCard} from './EndCard';
11 | import {howlength} from './How';
12 | import {HowRemotionWorks} from './HowRemotionWorks';
13 | import {OpenSource} from './OpenSource';
14 | import {Remotion} from './Remotion';
15 | import {Reusability} from './Reusability';
16 | import {Sequences} from './Sequences';
17 | import {Slide1} from './Slide1';
18 | import {Ssr} from './SSR';
19 | import {Step} from './Step';
20 | import {TraditionalPrograms} from './TraditionalPrograms';
21 | import {UseFrame} from './UseFrame';
22 | import {
23 | introlength,
24 | introoffset,
25 | outsidelength,
26 | stairslength,
27 | traditionallength,
28 | } from './variables';
29 | import {VersionControl} from './VersionControl';
30 | import {whylength} from './Why';
31 | import {WrittenInReact} from './WrittenInReact';
32 |
33 | const whattolearnnext = 400;
34 | const sequences = 1600;
35 | const audiosupport = 1000;
36 | const ssr = 500;
37 | const docs = 600;
38 | const opensource = 800;
39 |
40 | export const ScreenRecording: React.FC = () => {
41 | const {durationInFrames} = useVideoConfig();
42 | return (
43 |
48 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
114 |
115 |
116 |
128 |
129 |
130 |
143 |
144 |
145 |
159 |
160 |
161 |
162 |
177 |
178 |
179 |
195 |
196 |
197 |
214 |
215 |
216 |
234 |
235 |
236 |
271 |
272 |
273 |
274 |
275 |
276 | );
277 | };
278 |
--------------------------------------------------------------------------------
/src/Sequences.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | export const Sequences: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const {fps, durationInFrames} = useVideoConfig();
9 | const pos = spring({
10 | fps,
11 | frame,
12 | config: {
13 | damping: 200,
14 | },
15 | });
16 | const posout = spring({
17 | fps,
18 | frame: durationInFrames - frame - 10,
19 | config: {
20 | damping: 200,
21 | },
22 | });
23 | const actualpos =
24 | interpolate(pos, [0, 1], [1200, 0]) +
25 | interpolate(posout, [0, 1], [-1200, 0]);
26 | return (
27 |
28 |
29 |
<Sequence/>
30 |
31 |
32 | -
33 | Takes 2 parameters:
from and{' '}
34 | durationInFrames{' '}
35 |
36 | - Allows you to shift content in your timeline
37 | - All children of sequence will still start at frame 0
38 |
39 |
40 |
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/src/Slide.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | export const Slide = styled.div`
4 | background-color: white;
5 | flex: 1;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | `;
10 |
--------------------------------------------------------------------------------
/src/Slide1.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import styled from 'styled-components';
4 | import {Slide} from './Slide';
5 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
6 |
7 | const Title = styled(SlideTitle)`
8 | background: linear-gradient(to right, #000, #444);
9 | -webkit-background-clip: text;
10 | -moz-background-clip: text;
11 | background-clip: text;
12 | -webkit-text-fill-color: transparent;
13 | -moz-text-fill-color: transparent;
14 | text-fill-color: transparent;
15 | color: black;
16 | `;
17 |
18 | export const Slide1: React.FC = () => {
19 | const frame = useCurrentFrame();
20 | const {durationInFrames} = useVideoConfig();
21 | const opacity = interpolate(
22 | frame,
23 | [durationInFrames - 10, durationInFrames],
24 | [1, 0]
25 | );
26 | return (
27 |
28 |
34 |
Creating Videos Programmatically in React
35 |
36 |
37 |
38 | Jonny Burger
@JNYBGR
39 |
40 |
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/src/SlideTitle.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | export const SlideTitle = styled.div`
4 | font-family: --apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
5 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
6 | font-weight: 700;
7 | font-size: 150px;
8 | `;
9 |
10 | export const SlideSubtitle = styled.div`
11 | font-family: --apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
12 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
13 | font-weight: 500;
14 | font-size: 60px;
15 | ul {
16 | li {
17 | line-height: 1.4;
18 | margin-bottom: 40px;
19 | }
20 | }
21 | `;
22 |
--------------------------------------------------------------------------------
/src/Stairs.tsx:
--------------------------------------------------------------------------------
1 | import {Video} from 'remotion';
2 | import stair from './footage/stairs.mp4';
3 |
4 | export const Stairs: React.FC = () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/src/Step.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | export const Step: React.FC<{
7 | title: string;
8 | subtitle: string;
9 | }> = ({title, subtitle}) => {
10 | const frame = useCurrentFrame();
11 | const {fps, durationInFrames} = useVideoConfig();
12 | const pos = spring({
13 | fps,
14 | frame,
15 | config: {
16 | damping: 200,
17 | },
18 | });
19 | const posout = spring({
20 | fps,
21 | frame: durationInFrames - frame - 10,
22 | config: {
23 | damping: 200,
24 | },
25 | });
26 | const actualpos = posout * pos;
27 | return (
28 |
29 |
38 | {subtitle}
39 | {title}
40 |
41 |
42 | );
43 | };
44 |
--------------------------------------------------------------------------------
/src/Step3.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Slide} from './Slide';
3 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
4 |
5 | export const Step3: React.FC = () => {
6 | return (
7 |
8 |
9 | Step 3
10 | Stitch frames together
11 |
12 |
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/src/SynchronizedCode.tsx:
--------------------------------------------------------------------------------
1 | import {Sequence, Video} from 'remotion';
2 | import screen3 from './footage/screen3.mp4';
3 |
4 | const lengths = [
5 | 4 * 50 * 60,
6 | 4 * 50 * 60,
7 | 4 * 50 * 60,
8 | 4 * 50 * 60,
9 | 4 * 50 * 60 + 57 * 50 + Math.floor(0.12 / 50),
10 | 4 * 50 * 60,
11 | 4 * 50 * 60,
12 | 4 * 50 * 60,
13 | 3 * 50 * 60 + 30 * 60 + Math.floor(0.72 * 50),
14 | ];
15 |
16 | export const SynchronizedCode: React.FC<{
17 | type: 'both' | 'screen' | 'face';
18 | }> = ({type}) => {
19 | let totalDurations = 0;
20 | return (
21 | <>
22 | {type === 'both' || type === 'face'
23 | ? lengths.map((l, i) => {
24 | totalDurations += lengths[i];
25 | return (
26 |
30 |
37 | ;
38 |
39 | );
40 | })
41 | : null}
42 | {type === 'both' || type === 'screen' ? (
43 |
48 |
61 |
62 | ) : null}
63 | >
64 | );
65 | };
66 |
--------------------------------------------------------------------------------
/src/Traditional.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, useCurrentFrame, useVideoConfig, Video} from 'remotion';
2 | import traditional2 from './footage/traditional2.mp4';
3 |
4 | export const Traditional: React.FC = () => {
5 | const frame = useCurrentFrame();
6 | const {durationInFrames} = useVideoConfig();
7 |
8 | const opacity = interpolate(
9 | frame,
10 | [durationInFrames - 50, durationInFrames],
11 | [1, 0]
12 | );
13 | return (
14 |
15 |
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/src/TraditionalPrograms.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Img,
4 | interpolate,
5 | spring,
6 | useCurrentFrame,
7 | useVideoConfig,
8 | } from 'remotion';
9 | import {Slide} from './Slide';
10 | import {SlideSubtitle} from './SlideTitle';
11 |
12 | export const TraditionalPrograms: React.FC = () => {
13 | const frame = useCurrentFrame();
14 | const {fps, durationInFrames} = useVideoConfig();
15 |
16 | const scale = (i: number) =>
17 | spring({
18 | frame: frame - 5 * i - 240,
19 | fps,
20 | config: {
21 | damping: 60,
22 | },
23 | });
24 |
25 | const opacity = interpolate(frame, [180, 200], [0, 1]);
26 |
27 | const out = spring({
28 | frame: durationInFrames - 10 - frame,
29 | fps,
30 | from: 0,
31 | to: 1,
32 | config: {
33 | damping: 200,
34 | },
35 | });
36 |
37 | return (
38 |
39 |
40 |
41 | Your household video editing programs
42 |
43 |
44 |
45 |
83 |
84 |
85 | );
86 | };
87 |
--------------------------------------------------------------------------------
/src/UseFrame.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
3 | import {CodeFrame} from './CodeFrame';
4 | import {Slide} from './Slide';
5 |
6 | export const UseFrame: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const {fps, durationInFrames} = useVideoConfig();
9 | const posout = spring({
10 | fps,
11 | frame: durationInFrames - frame - 10,
12 | config: {
13 | damping: 200,
14 | },
15 | });
16 | return (
17 |
18 |
23 | {
28 | const frame = useCurrentFrame() // ${frame}
29 | }
30 | `.trim()}
31 | timing={[
32 | {
33 | line: 1,
34 | from: 50,
35 | },
36 | ]}
37 | />
38 |
39 |
40 | );
41 | };
42 |
--------------------------------------------------------------------------------
/src/VersionControl.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, useCurrentFrame} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle} from './SlideTitle';
5 |
6 | export const VersionControl: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const opacity = interpolate(frame, [30, 50], [0, 1]);
9 | const opacity2 = interpolate(frame, [350, 400], [0, 1]);
10 | return (
11 |
12 |
13 |
14 | Developer workflow:
commit, merge, rebase,
15 | cherry-pick, revert, ...
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Video editor workflow:
24 | undo, redo, save as project_FINAL_V2.aep
25 |
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/Video.tsx:
--------------------------------------------------------------------------------
1 | import {Composition} from 'remotion';
2 | import {Both} from './Both';
3 | import {Coding, CODING_DURATION} from './Coding';
4 | import {EndCard} from './EndCard';
5 | import {Face} from './Face';
6 | import {FadeOut} from './FadeOut';
7 | import {LogoMask} from './Logo/LogoMask';
8 | import {Remotion} from './Remotion';
9 | import {ScreenRecording} from './Screen';
10 | import {SynchronizedCode} from './SynchronizedCode';
11 | import {TraditionalPrograms} from './TraditionalPrograms';
12 |
13 | export const RemotionVideo: React.FC = () => {
14 | return (
15 | <>
16 |
24 |
32 |
40 |
51 |
62 |
70 |
78 |
86 |
98 |
106 | >
107 | );
108 | };
109 |
--------------------------------------------------------------------------------
/src/WhatToLearnNext.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {interpolate, useCurrentFrame} from 'remotion';
3 | import {Slide} from './Slide';
4 | import {SlideSubtitle, SlideTitle} from './SlideTitle';
5 |
6 | export const WhatToLearnNext: React.FC = () => {
7 | const frame = useCurrentFrame();
8 | const opacity = interpolate(frame, [0, 20], [0, 1]);
9 | return (
10 |
11 |
16 | What to
17 | learn next?
18 |
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/src/Why.tsx:
--------------------------------------------------------------------------------
1 | import {Sequence, Video} from 'remotion';
2 | import why from './footage/why.mp4';
3 |
4 | export const ENABLE_WHY = false;
5 |
6 | export const whylength = ENABLE_WHY ? 251 * 50 : 0;
7 | const whyoffset = -450;
8 |
9 | export const Why: React.FC = () => {
10 | return (
11 |
12 |
13 |
14 | );
15 | };
16 |
--------------------------------------------------------------------------------
/src/WrittenInReact.tsx:
--------------------------------------------------------------------------------
1 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
2 | import styled from 'styled-components';
3 | import {Arc} from './Arc';
4 |
5 | const Container = styled.div`
6 | background-color: white;
7 |
8 | flex: 1;
9 | display: flex;
10 | justify-content: center;
11 | align-items: center;
12 | flex-direction: column;
13 | overflow: hidden;
14 | `;
15 |
16 | const ZIndex1 = styled.div`
17 | flex: 1;
18 | display: flex;
19 | justify-content: center;
20 | align-items: center;
21 | flex-direction: column;
22 | z-index: 1;
23 | position: absolute;
24 | width: 100%;
25 | height: 100%;
26 | `;
27 |
28 | const Text = styled.span`
29 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
30 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
31 | font-size: 180px;
32 | font-weight: 700;
33 | `;
34 |
35 | export const WrittenInReact: React.FC<{offset: number; showText: boolean}> = ({
36 | offset,
37 | showText,
38 | }) => {
39 | const frame = useCurrentFrame();
40 | const {fps, width, height, durationInFrames} = useVideoConfig();
41 | const scaleProgress = spring({
42 | fps,
43 | frame: frame - offset,
44 | config: {
45 | mass: 10,
46 | damping: 200,
47 | },
48 | });
49 | const scale = interpolate(scaleProgress, [0, 1], [1.5, 1]);
50 | const spring1 = spring({
51 | fps,
52 | frame: frame - 30 - offset,
53 | config: {
54 | stiffness: 100,
55 | damping: 200,
56 | },
57 | });
58 | const spring2 = spring({
59 | fps,
60 | frame: frame - 60 - offset,
61 | config: {
62 | stiffness: 100,
63 | damping: 200,
64 | },
65 | });
66 | const offset1 = interpolate(spring1, [0, 1], [800, 0]);
67 | const offset2 = interpolate(spring2, [0, 1], [800, 0]);
68 |
69 | const text = showText ? (
70 | <>
71 |
72 | Write
73 | videos
74 |
75 |
76 | programmatically
77 |
78 | >
79 | ) : null;
80 |
81 | const arcs = (
82 | <>
83 |
84 |
85 |
86 | >
87 | );
88 |
89 | return (
90 |
91 | {text}
92 |
126 |
127 | );
128 | };
129 |
--------------------------------------------------------------------------------
/src/crash.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonnyBurger/react-summit-talk/acb6f92244ec160412011d34dafbe7f7dcf2a6be/src/crash.mp3
--------------------------------------------------------------------------------
/src/footage/P1000318.MP4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:22e608ecd1bae7508f0d91a7be99d241969cba6785d7236d447c67e2f8b3b4ef
3 | size 74557615
4 |
--------------------------------------------------------------------------------
/src/footage/P1000320.MP4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:06a142f95817f9e2a3fe87b89e8f94000a46ad8c62756439082c07f57f90835e
3 | size 427341624
4 |
--------------------------------------------------------------------------------
/src/footage/apple-long.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fe191384c4eae1ab44dc8e16e1f8e2c20da41765f54972234946f3d2a33d6daa
3 | size 2079545
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:1bdd078fbeb07838dcbe087eb90b77ff341a8fbba49c3603311a17527dedf88c
3 | size 814156876
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-2.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b871db5a536281420091c05a12965a676afcd1df407f96427ba93c6e1780e854
3 | size 812444623
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-3.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:644f133810cd216ac4dc6d48fafda5ab48f81f25f6a615afcfa7d00754051b1b
3 | size 812516286
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-4.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:1408bd13746cd38cdb5a3635b51a8834398ffd2e84e0a6d930fe446fd2ebd31f
3 | size 813172169
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-5.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:d44a42a2fe2c0bc58d286de3f85f390b0180cf658e139632eaa4b6d550e2865d
3 | size 1005384216
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-6.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fef1c2d08b1ad5f99eebb76c8f1f5d3da335fd17ea68261daccda8802db178c1
3 | size 813313370
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-7.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:84e90f1ff25c17c9263915982df91afc67b8697bb85aa31761a4a919b3f76912
3 | size 812518972
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-8.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:9f1f5dfc453828b710825ecac2a7ed86de65d5947318ed77cdae0f8cda36bf54
3 | size 812320899
4 |
--------------------------------------------------------------------------------
/src/footage/codep1-9.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:5d5811e77aba4e451346f0d3190fd1473b7ea8fe4e7179614b436695a8dd62b5
3 | size 712984149
4 |
--------------------------------------------------------------------------------
/src/footage/editing.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:1517822d334717b56c98bf52245d85f27a6e5435334be3241cf0c15862b05fc6
3 | size 1016681
4 |
--------------------------------------------------------------------------------
/src/footage/how.MP4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:148a28ee1c407e1c62f4ffa779f74f91140fcf258f22617f09e3b2d3aa389bce
3 | size 874538878
4 |
--------------------------------------------------------------------------------
/src/footage/intro.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:70b6fb4efe26b8b959f1a9e8f2505bdbda2710b497ce57c0687b3b4b5e89e941
3 | size 78202647
4 |
--------------------------------------------------------------------------------
/src/footage/outro.MP4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:767972bee84286d95ac1e86e383857907052719a0cbeb46fdf4fda8f26a705bb
3 | size 447081645
4 |
--------------------------------------------------------------------------------
/src/footage/outside.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:58cfdb990148e8e9151171fb4dc52ff6e484d9b2830ac0bc1d95202180d7012f
3 | size 38496049
4 |
--------------------------------------------------------------------------------
/src/footage/screen.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:1e72617549b3401577bcf4bdfc1cf396a0db63ffc4733f5b50104f69fe335ea5
3 | size 365142566
4 |
--------------------------------------------------------------------------------
/src/footage/screen3.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:8ea614cafe01da7f28c38a77c6c2400024665797661f8ceaf5a4c34d1c7d892a
3 | size 154028100
4 |
--------------------------------------------------------------------------------
/src/footage/split-video.sh:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:3e858c4871db9c56e92cb89ff85424290638eb4964000cc06438467999c8cbd3
3 | size 724
4 |
--------------------------------------------------------------------------------
/src/footage/stairs.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b76a475cc6f5aef28a1e42da8235749b1e9b8e184438cd7683f197a8e1ad9b84
3 | size 36266710
4 |
--------------------------------------------------------------------------------
/src/footage/traditional.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e6bc018959fb5b96124a5eaa04d9a092561b5701104e1cd93c487fc761257e0a
3 | size 386031408
4 |
--------------------------------------------------------------------------------
/src/footage/traditional2.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2f38da3320b0cc0bc97ea9e2c62e7e32a6f4306db8f681d8ef63d339578f1c55
3 | size 388133634
4 |
--------------------------------------------------------------------------------
/src/footage/why.MP4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:41a7d685c84b0d4f220c60f2359a0dcda468007113e0c5dfd6dfdd0309c8fe7f
3 | size 907731231
4 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import {registerRoot} from 'remotion';
2 | import {RemotionVideo} from './Video';
3 |
4 | registerRoot(RemotionVideo);
5 |
--------------------------------------------------------------------------------
/src/prism.css:
--------------------------------------------------------------------------------
1 | code[class*='language-'],
2 | pre[class*='language-'] {
3 | color: #383a42;
4 | background: none;
5 | font-family: Hack;
6 | text-align: left;
7 | white-space: pre;
8 | word-spacing: normal;
9 | word-break: normal;
10 | word-wrap: normal;
11 | line-height: 1.5;
12 | -moz-tab-size: 4;
13 | -o-tab-size: 4;
14 | tab-size: 4;
15 | -webkit-hyphens: none;
16 | -moz-hyphens: none;
17 | -ms-hyphens: none;
18 | hyphens: none;
19 | }
20 | pre[class*='language-']::selection,
21 | pre[class*='language-'] ::selection,
22 | code[class*='language-']::selection,
23 | code[class*='language-'] ::selection,
24 | pre[class*='language-']::-moz-selection,
25 | pre[class*='language-'] ::-moz-selection,
26 | code[class*='language-']::-moz-selection,
27 | code[class*='language-'] ::-moz-selection {
28 | text-shadow: none;
29 | background: #e5e6e7;
30 | }
31 | @media print {
32 | code[class*='language-'],
33 | pre[class*='language-'] {
34 | text-shadow: none;
35 | }
36 | }
37 | pre[class*='language-'] {
38 | padding: 1em;
39 | margin: 0.5em 0;
40 | overflow: auto;
41 | }
42 | :not(pre) > code[class*='language-'],
43 | pre[class*='language-'] {
44 | background: #fff;
45 | }
46 | :not(pre) > code[class*='language-'] {
47 | padding: 0.1em;
48 | border-radius: 0.3em;
49 | white-space: normal;
50 | }
51 | .token.comment,
52 | .token.prolog,
53 | .token.doctype,
54 | .token.cdata {
55 | color: #a0a1a7;
56 | }
57 | .token.punctuation {
58 | color: #383a42;
59 | }
60 | .token.selector,
61 | .token.tag {
62 | color: #f07c85;
63 | }
64 | .token.property,
65 | .token.boolean,
66 | .token.number,
67 | .token.constant,
68 | .token.symbol,
69 | .token.attr-name,
70 | .token.deleted {
71 | color: #e1aa76;
72 | }
73 | .token.string,
74 | .token.char,
75 | .token.attr-value,
76 | .token.builtin,
77 | .token.inserted {
78 | color: #88b369;
79 | }
80 | .token.operator,
81 | .token.entity,
82 | .token.url,
83 | .language-css .token.string,
84 | .style .token.string {
85 | color: #46a6b2;
86 | }
87 | .token.function {
88 | color: #519fdf;
89 | }
90 | .token.atrule,
91 | .token.keyword,
92 | .token.regex,
93 | .token.important,
94 | .token.variable {
95 | color: #b668cd;
96 | }
97 | .token.important,
98 | .token.bold {
99 | font-weight: bold;
100 | }
101 | .token.italic {
102 | font-style: italic;
103 | }
104 | .token.entity {
105 | cursor: help;
106 | }
107 | pre.line-numbers {
108 | position: relative;
109 | padding-left: 3.8em;
110 | counter-reset: linenumber;
111 | }
112 | pre.line-numbers > code {
113 | position: relative;
114 | }
115 | .line-numbers .line-numbers-rows {
116 | position: absolute;
117 | pointer-events: none;
118 | top: 0;
119 | font-size: 100%;
120 | left: -3.8em;
121 | width: 3em;
122 | letter-spacing: -1px;
123 | border-right: 0;
124 | -webkit-user-select: none;
125 | -moz-user-select: none;
126 | -ms-user-select: none;
127 | user-select: none;
128 | }
129 | .line-numbers-rows > span {
130 | pointer-events: none;
131 | display: block;
132 | counter-increment: linenumber;
133 | }
134 | .line-numbers-rows > span:before {
135 | content: counter(linenumber);
136 | color: #b5b9c2;
137 | display: block;
138 | padding-right: 0.8em;
139 | text-align: right;
140 | }
141 | code.language-css,
142 | pre.languagecss {
143 | color: #ca1243;
144 | }
145 | code.language-javascript,
146 | pre.languagejavascript {
147 | color: #ca1243;
148 | }
149 | code.language-js,
150 | pre.languagejs {
151 | color: #ca1243;
152 | }
153 | code.language-jsx,
154 | pre.languagejsx {
155 | color: #ca1243;
156 | }
157 | code.language-sass,
158 | pre.languagesass {
159 | color: #ca1243;
160 | }
161 | code.language-scss,
162 | pre.languagescss {
163 | color: #ca1243;
164 | }
165 | code.language-ts,
166 | pre.languagets {
167 | color: #ca1243;
168 | }
169 | code.language-tsx,
170 | pre.languagetsx {
171 | color: #ca1243;
172 | }
173 | code.language-typescript,
174 | pre.languagetypescript {
175 | color: #ca1243;
176 | }
177 |
--------------------------------------------------------------------------------
/src/variables.ts:
--------------------------------------------------------------------------------
1 | export const introlength = 22.5 * 50;
2 | export const introoffset = -50;
3 | export const stairslength = 10.5 * 50;
4 | export const outsidelength = 10.5 * 50;
5 | export const traditionallength = 113.5 * 50;
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------