├── .eslintrc ├── .github └── workflows │ └── render-video.yml ├── .gitignore ├── .prettierrc ├── .vscode └── settings.json ├── README.md ├── package.json ├── remotion.config.ts ├── src ├── Composition.tsx ├── Logo.tsx ├── Root.tsx ├── Subtitle.tsx ├── Title.tsx ├── index.ts ├── style.css └── webpack-override.ts ├── tailwind.config.js └── tsconfig.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@remotion", 3 | "env": { 4 | "node": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/render-video.yml: -------------------------------------------------------------------------------- 1 | on: workflow_dispatch 2 | 3 | name: Render video 4 | jobs: 5 | render: 6 | name: Render video 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@main 10 | - uses: actions/setup-node@main 11 | - run: sudo apt update 12 | - run: sudo apt install ffmpeg 13 | - run: npm i 14 | - run: echo $WORKFLOW_INPUT > input-props.json 15 | env: 16 | WORKFLOW_INPUT: ${{ toJson(github.event.inputs) }} 17 | - run: npm run build -- --props="./input-props.json" 18 | - uses: actions/upload-artifact@v2 19 | with: 20 | name: video.mp4 21 | path: out/video.mp4 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | .env 5 | 6 | # Ignore the output video from Git but not videos you import into src/. 7 | out 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "bracketSpacing": false, 4 | "useTabs": true, 5 | "overrides": [ 6 | { 7 | "files": ["*.yml"], 8 | "options": { 9 | "singleQuote": false 10 | } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "typescript.tsdk": "node_modules/typescript/lib", 4 | "typescript.enablePromptUseWorkspaceTsdk": true, 5 | "css.lint.unknownAtRules": "ignore" 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Obsolete Remotion template. When running `npx create-video@latest`, many other templates support adding Tailwind. 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remotion-template", 3 | "version": "1.0.0", 4 | "description": "My Remotion video", 5 | "sideEffects": [ 6 | "*.css" 7 | ], 8 | "scripts": { 9 | "start": "remotion studio", 10 | "build": "remotion render MyComp out/video.mp4", 11 | "upgrade": "remotion upgrade", 12 | "test": "eslint src --ext ts,tsx,js,jsx && tsc" 13 | }, 14 | "repository": {}, 15 | "license": "UNLICENSED", 16 | "dependencies": { 17 | "@remotion/bundler": "^4.0.0", 18 | "@remotion/cli": "^4.0.0", 19 | "@remotion/zod-types": "^4.0.0", 20 | "react": "^18.0.0", 21 | "react-dom": "^18.0.0", 22 | "remotion": "^4.0.0", 23 | "zod": "3.22.3" 24 | }, 25 | "devDependencies": { 26 | "@remotion/eslint-config": "^4.0.0", 27 | "@types/react": "^18.0.26", 28 | "@types/web": "^0.0.143", 29 | "eslint": "^8.43.0", 30 | "prettier": "^3.2.5", 31 | "@remotion/tailwind": "^4.0.0", 32 | "typescript": "5.4.5" 33 | }, 34 | "pnpm": { 35 | "peerDependencyRules": { 36 | "ignoreMissing": [ 37 | "webpack" 38 | ] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /remotion.config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Note: When using the Node.JS APIs, the config file 3 | * doesn't apply. Instead, pass options directly to the APIs. 4 | * 5 | * All configuration options: https://remotion.dev/docs/config 6 | */ 7 | 8 | import {Config} from '@remotion/cli/config'; 9 | import {webpackOverride} from './src/webpack-override'; 10 | 11 | Config.setVideoImageFormat('jpeg'); 12 | Config.setOverwriteOutput(true); 13 | 14 | Config.overrideWebpackConfig(webpackOverride); 15 | -------------------------------------------------------------------------------- /src/Composition.tsx: -------------------------------------------------------------------------------- 1 | import {AbsoluteFill} from 'remotion'; 2 | import {Logo} from './Logo'; 3 | import {Subtitle} from './Subtitle'; 4 | import {Title} from './Title'; 5 | import {z} from 'zod'; 6 | import {zColor} from '@remotion/zod-types'; 7 | 8 | export const myCompSchema = z.object({ 9 | titleText: z.string(), 10 | titleColor: zColor(), 11 | logoColor: zColor(), 12 | }); 13 | 14 | export const MyComposition: React.FC> = ({ 15 | titleText: propOne, 16 | titleColor: propTwo, 17 | logoColor: propThree, 18 | }) => { 19 | return ( 20 | 21 |
22 | 23 |
24 | 25 | <Subtitle /> 26 | </AbsoluteFill> 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/Logo.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion'; 3 | 4 | export const Logo: React.FC<{ 5 | logoColor: string; 6 | }> = ({logoColor}) => { 7 | const frame = useCurrentFrame(); 8 | const {height, fps} = useVideoConfig(); 9 | 10 | const entrance = spring({ 11 | fps, 12 | frame, 13 | config: { 14 | damping: 200, 15 | }, 16 | durationInFrames: 30, 17 | }); 18 | 19 | const entranceOffset = interpolate(entrance, [0, 1], [height, 0]); 20 | 21 | const wave1 = Math.cos(frame / 15) * 10 + entranceOffset; 22 | const wave2 = Math.cos((frame - 5) / 15) * 10 + entranceOffset; 23 | 24 | return ( 25 | <div> 26 | <svg 27 | style={{transform: `translateY(${wave1}px)`}} 28 | className="absolute" 29 | height={120} 30 | viewBox="0 0 51 31" 31 | > 32 | <path 33 | d="M0 25.364C1.701 18.6 5.954 15.218 12.758 15.218C19.0815 15.218 21.9775 18.1395 24.4794 20.6634L24.48 20.664C26.015 22.213 27.403 23.613 29.344 24.096C32.746 24.941 35.723 23.673 38.275 20.291C36.574 27.055 32.321 30.436 25.517 30.436C19.1925 30.436 16.2975 27.5155 13.7956 24.9916L13.795 24.991C12.26 23.441 10.872 22.041 8.93 21.559C5.529 20.714 2.552 21.982 0 25.364Z" 34 | style={{fill: logoColor}} 35 | /> 36 | </svg> 37 | <svg 38 | style={{transform: `translateY(${wave2}px)`}} 39 | height={120} 40 | viewBox="0 0 51 31" 41 | > 42 | <path 43 | d="M12 10.146C13.701 3.382 17.954 0 24.758 0C31.0815 0 33.9775 2.92151 36.4794 5.44536L36.48 5.446C38.015 6.995 39.403 8.395 41.344 8.878C44.746 9.723 47.723 8.455 50.275 5.073C48.574 11.837 44.321 15.218 37.517 15.218C31.1925 15.218 28.2975 12.2975 25.7956 9.77365L25.795 9.773C24.26 8.223 22.872 6.823 20.93 6.341C17.529 5.496 14.552 6.764 12 10.146Z" 44 | style={{fill: logoColor}} 45 | /> 46 | </svg> 47 | </div> 48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /src/Root.tsx: -------------------------------------------------------------------------------- 1 | import {Composition} from 'remotion'; 2 | import {MyComposition, myCompSchema} from './Composition'; 3 | import './style.css'; 4 | 5 | export const RemotionRoot: React.FC = () => { 6 | return ( 7 | <> 8 | <Composition 9 | id="MyComp" 10 | component={MyComposition} 11 | durationInFrames={240} 12 | fps={30} 13 | width={1280} 14 | height={720} 15 | schema={myCompSchema} 16 | defaultProps={{ 17 | titleText: 'Welcome to Remotion with Tailwind CSS', 18 | titleColor: '#000000', 19 | logoColor: '#00bfff', 20 | }} 21 | /> 22 | </> 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /src/Subtitle.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {interpolate, useCurrentFrame} from 'remotion'; 3 | 4 | export const Subtitle: React.FC = () => { 5 | const frame = useCurrentFrame(); 6 | const opacity = interpolate(frame, [30, 50], [0, 1], { 7 | extrapolateLeft: 'clamp', 8 | extrapolateRight: 'clamp', 9 | }); 10 | 11 | return ( 12 | <div className="text-gray-600 text-3xl" style={{opacity}}> 13 | Edit <code>src/Composition.tsx</code> and save to reload. 14 | </div> 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /src/Title.tsx: -------------------------------------------------------------------------------- 1 | import {interpolate} from 'remotion'; 2 | import {useCurrentFrame} from 'remotion'; 3 | import React from 'react'; 4 | 5 | export const Title: React.FC<{ 6 | titleText: string; 7 | titleColor: string; 8 | }> = ({titleText, titleColor}) => { 9 | const frame = useCurrentFrame(); 10 | const opacity = interpolate(frame, [20, 40], [0, 1], { 11 | extrapolateLeft: 'clamp', 12 | extrapolateRight: 'clamp', 13 | }); 14 | return ( 15 | <div 16 | style={{opacity, color: titleColor}} 17 | className="text-5xl font-bold leading-relaxed" 18 | > 19 | {' '} 20 | {titleText} 21 | </div> 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import {registerRoot} from 'remotion'; 2 | import {RemotionRoot} from './Root'; 3 | 4 | registerRoot(RemotionRoot); 5 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/webpack-override.ts: -------------------------------------------------------------------------------- 1 | import {enableTailwind} from '@remotion/tailwind'; 2 | import {WebpackOverrideFn} from '@remotion/bundler'; 3 | 4 | export const webpackOverride: WebpackOverrideFn = (currentConfiguration) => { 5 | return enableTailwind(currentConfiguration); 6 | }; 7 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./src/**/*.{ts,tsx}'], 3 | theme: { 4 | extend: {}, 5 | }, 6 | plugins: [], 7 | }; 8 | -------------------------------------------------------------------------------- /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"], 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "noUnusedLocals": true 14 | } 15 | } 16 | --------------------------------------------------------------------------------