diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 4c2c5724..603cf1d6 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -31,6 +31,7 @@ jobs:
with:
fetch-depth: 0
token: ${{secrets.PUBLISH_TOKEN}}
+ submodules: true
- uses: actions/setup-node@v3
with:
node-version: 18
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..a8c87a9e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "packages/create/examples"]
+ path = packages/create/examples
+ url = https://github.com/redotvideo/examples
diff --git a/packages/create/examples b/packages/create/examples
new file mode 160000
index 00000000..ca265692
--- /dev/null
+++ b/packages/create/examples
@@ -0,0 +1 @@
+Subproject commit ca265692c230b64705c88a999b2361c90e569021
diff --git a/packages/create/index.js b/packages/create/index.js
index df3cd5ce..febf6f10 100755
--- a/packages/create/index.js
+++ b/packages/create/index.js
@@ -7,53 +7,21 @@ import {fileURLToPath} from 'node:url';
import path from 'path';
import prompts from 'prompts';
-const FILES_TO_MODIFY = {
- gitignore: '.gitignore',
- '.gitkeep': false,
-};
-
-const MANIFEST = JSON.parse(
- fs.readFileSync(
- path.resolve(fileURLToPath(import.meta.url), '../package.json'),
- 'utf-8',
- ),
-);
-
-const PLUGINS = {
- core: {
- package: '@revideo/vite-plugin',
- variable: 'motionCanvas',
- options: response =>
- response.language === 'js' ? `{project: './src/project.js'}` : '',
- },
-};
-
-(async () => {
+const templates = [
+ 'default',
+ 'avatar-with-background',
+ 'google-cloud-run',
+ 'google-cloud-run-parallelized',
+ 'stitching-videos',
+ 'youtube-shorts',
+];
+
+async function run() {
const options = minimist(process.argv.slice(2));
- if (options.plugins !== undefined) {
- if (typeof options.plugins === 'string') {
- options.plugins = options.plugins.split(',');
- }
-
- if (!Array.isArray(options.plugins)) {
- options.plugins = [options.plugins];
- }
-
- const plugins = ['core'];
- for (const plugin of options.plugins) {
- if (plugin === 'core') continue;
- if (!(plugin in PLUGINS)) {
- console.log(kleur.yellow(`! Unknown plugin "${plugin}".\n`));
- continue;
- }
- plugins.push(plugin);
- }
-
- options.plugins = plugins;
- }
prompts.override(options);
const response = await prompts([
+ // Prompt for project name
{
type: 'text',
name: 'name',
@@ -64,6 +32,7 @@ const PLUGINS = {
? true
: 'Project name must be a valid npm package name.',
},
+ // Prompt for project path
{
type: 'text',
name: 'path',
@@ -90,42 +59,48 @@ const PLUGINS = {
},
format: value => path.resolve(value),
},
+ // Prompt for which example to scaffold
+ {
+ type: 'select',
+ name: 'starter',
+ message: 'Choose a starter template',
+
+ choices: [
+ ...templates.map(template => ({title: template, value: template})),
+ ],
+ },
]);
+ // Abort if the user didn't provide a project name
if (!response.path) {
console.log(kleur.red('× Scaffolding aborted by the user.\n'));
return;
}
- const plugins = [PLUGINS.core];
+ // Clone files
const templateDir = path.resolve(
fileURLToPath(import.meta.url),
'..',
- `template-2d-ts`,
+ `examples/${response.starter}`,
);
copyDirectory(templateDir, response.path);
- createConfig(response, plugins);
+ createConfig(response);
- const manifest = JSON.parse(
- fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8'),
- );
- manifest.name = response.name;
- manifest.dependencies ??= {};
- for (const data of plugins) {
- if (data.version) {
- manifest.dependencies[data.package] = data.version;
- }
- }
- cloneVersions(manifest.dependencies);
-
- if (manifest.devDependencies) {
- cloneVersions(manifest.devDependencies);
+ // Read package.json and modify name
+ try {
+ const manifest = JSON.parse(
+ fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8'),
+ );
+ manifest.name = response.name;
+ fs.writeFileSync(
+ path.join(response.path, 'package.json'),
+ JSON.stringify(manifest, undefined, 2),
+ );
+ } catch (e) {
+ // Example doesn't have a package.json file
}
- fs.writeFileSync(
- path.join(response.path, 'package.json'),
- JSON.stringify(manifest, undefined, 2),
- );
+ // Tell user that the process is complete
const manager = getPackageManager();
console.log(kleur.green('\n√ Scaffolding complete. You can now run:'));
if (response.path !== process.cwd()) {
@@ -142,7 +117,7 @@ const PLUGINS = {
console.log(` ${boldManager} start`);
}
console.log();
-})();
+}
function isValidPackageName(projectName) {
return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(
@@ -153,13 +128,8 @@ function isValidPackageName(projectName) {
function copyDirectory(src, dest) {
fs.mkdirSync(dest, {recursive: true});
for (const file of fs.readdirSync(src)) {
- let target = file;
- if (file in FILES_TO_MODIFY) {
- if (FILES_TO_MODIFY[file] === false) continue;
- target = FILES_TO_MODIFY[file];
- }
const srcFile = path.resolve(src, file);
- const destFile = path.resolve(dest, target);
+ const destFile = path.resolve(dest, file);
copy(srcFile, destFile);
}
}
@@ -173,27 +143,17 @@ function copy(src, dest) {
}
}
-function createConfig(response, selectedPlugins) {
- const imports = [];
- const plugins = [];
- for (const data of selectedPlugins) {
- imports.push(`import ${data.variable} from '${data.package}';\n`);
- plugins.push(`${data.variable}(${data.options?.(response) ?? ''}),`);
- }
-
+function createConfig(response) {
const configFile = path.resolve(response.path, `vite.config.ts`);
fs.writeFileSync(
configFile,
- `import {defineConfig} from 'vite';
-${imports.join('')}
-
-export default defineConfig({
- plugins: [
- ${plugins.join('\n ')}
- ],
-});
-`,
+ `import motionCanvas from '@revideo/vite-plugin';
+ import {defineConfig} from 'vite';
+
+ export default defineConfig({
+ plugins: [motionCanvas()],
+ });`,
);
}
@@ -202,13 +162,4 @@ function getPackageManager() {
return ua?.split(' ')[0].split('/')[0] ?? 'npm';
}
-function cloneVersions(versions) {
- for (const dependency in versions) {
- if (
- dependency.startsWith('@revideo') &&
- MANIFEST.devDependencies[dependency]
- ) {
- versions[dependency] = MANIFEST.devDependencies[dependency];
- }
- }
-}
+void run();
diff --git a/packages/create/package.json b/packages/create/package.json
index 4d9cb736..7c3ad084 100644
--- a/packages/create/package.json
+++ b/packages/create/package.json
@@ -13,7 +13,7 @@
},
"files": [
"index.js",
- "template-*"
+ "examples"
],
"repository": {
"type": "git",
diff --git a/packages/create/template-2d-ts/package.json b/packages/create/template-2d-ts/package.json
deleted file mode 100644
index 3a91a731..00000000
--- a/packages/create/template-2d-ts/package.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "2d-starter",
- "private": true,
- "version": "0.0.0",
- "scripts": {
- "start": "vite",
- "serve": "vite",
- "build": "tsc && vite build",
- "render": "tsc && node dist/render.js"
- },
- "dependencies": {
- "@revideo/core": "^0.3.4",
- "@revideo/2d": "^0.3.4",
- "@revideo/renderer": "^0.3.4",
- "@revideo/vite-plugin": "^0.3.4",
- "@revideo/ffmpeg": "^0.3.4"
- },
- "devDependencies": {
- "@revideo/ui": "^0.3.4",
- "@revideo/cli": "^0.3.4",
- "typescript": "^5.2.2",
- "vite": "^4.5"
- }
-}
diff --git a/packages/create/template-2d-ts/public/.gitkeep b/packages/create/template-2d-ts/public/.gitkeep
deleted file mode 100644
index e69de29b..00000000
diff --git a/packages/create/template-2d-ts/src/project.meta b/packages/create/template-2d-ts/src/project.meta
deleted file mode 100644
index 18e0a42e..00000000
--- a/packages/create/template-2d-ts/src/project.meta
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "version": 0,
- "shared": {
- "background": null,
- "range": [
- 0,
- null
- ],
- "size": {
- "x": 1920,
- "y": 1080
- },
- "audioOffset": 0
- },
- "preview": {
- "fps": 30,
- "resolutionScale": 1
- },
- "rendering": {
- "fps": 30,
- "resolutionScale": 1,
- "colorSpace": "srgb",
- "exporter": {
- "name": "@revideo/ffmpeg",
- "options": {
- "fastStart": true,
- "includeAudio": true
- }
- }
- }
-}
\ No newline at end of file
diff --git a/packages/create/template-2d-ts/src/project.ts b/packages/create/template-2d-ts/src/project.ts
deleted file mode 100644
index ab05fd7e..00000000
--- a/packages/create/template-2d-ts/src/project.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {makeProject} from '@revideo/core';
-
-import example from './scenes/example?scene';
-
-export default makeProject({
- scenes: [example],
-});
diff --git a/packages/create/template-2d-ts/src/render.ts b/packages/create/template-2d-ts/src/render.ts
deleted file mode 100644
index 2769fab8..00000000
--- a/packages/create/template-2d-ts/src/render.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import {renderVideo} from '@revideo/renderer';
-
-async function render() {
- console.log('Rendering video...');
-
- // This is the main function that renders the video
- const file = await renderVideo(
- './vite.config.ts',
- {fill: 'orange'},
- () => {},
- {logProgress: true},
- );
-
- console.log(`Rendered video to ${file}`);
-}
-
-render();
diff --git a/packages/create/template-2d-ts/src/revideo.d.ts b/packages/create/template-2d-ts/src/revideo.d.ts
deleted file mode 100644
index 7ec2e111..00000000
--- a/packages/create/template-2d-ts/src/revideo.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/packages/create/template-2d-ts/src/scenes/example.tsx b/packages/create/template-2d-ts/src/scenes/example.tsx
deleted file mode 100644
index 95f3c71e..00000000
--- a/packages/create/template-2d-ts/src/scenes/example.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import {Audio, Img, Video, makeScene2D} from '@revideo/2d';
-import {all, chain, createRef, waitFor} from '@revideo/core';
-
-export default makeScene2D(function* (view) {
- const logoRef = createRef
();
-
- yield view.add(
- <>
-
-
- >,
- );
-
- yield* waitFor(1);
-
- view.add(
-
,
- );
-
- yield* chain(
- all(logoRef().scale(40, 2), logoRef().rotation(360, 2)),
- logoRef().scale(60, 1),
- );
-});
diff --git a/packages/create/template-2d-ts/tsconfig.json b/packages/create/template-2d-ts/tsconfig.json
deleted file mode 100644
index cf964848..00000000
--- a/packages/create/template-2d-ts/tsconfig.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "extends": "@revideo/2d/tsconfig.project.json",
- "include": ["src"],
- "compilerOptions": {
- "noEmit": false,
- "outDir": "dist",
- "module": "CommonJS"
- }
-}