Complete production-ready guide for Motion Canvas with ESM/CommonJS workarounds, full setup templates, and troubleshooting for programmatic video creation using TypeScript
---
name: motion-canvas
description: Complete production-ready guide for Motion Canvas with ESM/CommonJS workarounds, full setup templates, and troubleshooting for programmatic video creation using TypeScript
version: 2.0.0
author: motion-canvas
repo: https://github.com/motion-canvas/motion-canvas
license: MIT
tags: [Video, TypeScript, Animation, Motion Canvas, Signals, Generators, Canvas API, Vector, Audio Sync, Vite, ESM]
dependencies: [@motion-canvas/core>=3.0.0, @motion-canvas/2d>=3.0.0, @motion-canvas/ui>=3.0.0, @motion-canvas/vite-plugin>=3.0.0]
---
# Motion Canvas - Production-Ready Video Creation with TypeScript
Complete production-ready skill for creating programmatic videos using Motion Canvas, including critical ESM/CommonJS workarounds, full configuration templates, and comprehensive troubleshooting.
## ⚠️ CRITICAL: ESM/CommonJS Interoperability Issue
**IMPORTANT**: The `@motion-canvas/vite-plugin` package is distributed as CommonJS, which causes import errors in modern ESM projects. The standard `import motionCanvas from '@motion-canvas/vite-plugin'` **WILL NOT WORK**.
You MUST use the `createRequire` workaround documented in the Setup section below.
## When to use
Use this skill whenever you are dealing with Motion Canvas code to obtain domain-specific knowledge about:
- Creating animated videos using TypeScript and generator functions
- Building animations with signals and reactive values
- Working with vector graphics and Canvas API
- Synchronizing animations with voice-overs and audio
- Using the real-time preview editor for instant feedback
- Implementing procedural animations with flow control
- Creating informative visualizations and diagrams
- Animating text, shapes, and custom components
- **Setting up Motion Canvas projects from scratch with correct configuration**
- **Troubleshooting common setup and build errors**
## Core Concepts
Motion Canvas allows you to create videos using:
- **Generator Functions**: Describe animations using JavaScript generators with `yield*` syntax
- **Signals**: Reactive values that automatically update dependent properties
- **Real-time Preview**: Live editor with instant preview powered by Vite
- **TypeScript-First**: Write animations in TypeScript with full IDE support
- **Canvas API**: Leverage 2D Canvas for high-performance vector rendering
- **Audio Synchronization**: Sync animations precisely with voice-overs
## Complete Setup Guide
### Step 1: Initialize Project
```bash
# Create project directory
mkdir my-motion-canvas-project
cd my-motion-canvas-project
# Initialize package.json
npm init -y
```
### Step 2: Configure package.json for ESM
**CRITICAL**: Add `"type": "module"` to enable ESM imports.
```json
{
"name": "my-motion-canvas-project",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
```
### Step 3: Install ALL Required Dependencies
**CRITICAL**: Must include `@motion-canvas/ui` - the plugin will fail without it.
```bash
npm install --save-dev @motion-canvas/core @motion-canvas/2d @motion-canvas/vite-plugin @motion-canvas/ui vite typescript
```
### Step 4: Create Project Structure
```
my-motion-canvas-project/
├── package.json # "type": "module" required
├── vite.config.js # Use .js NOT .ts (see Step 5)
├── tsconfig.json # TypeScript configuration
├── index.html # HTML entry point
└── src/
├── project.ts # Project configuration with scenes
└── scenes/
└── example.tsx # Animation scene
```
### Step 5: Create vite.config.js with ESM/CommonJS Workaround
**CRITICAL**: Use `vite.config.js` (NOT `.ts`) with the `createRequire` workaround.
**File: `vite.config.js`**
```javascript
import {defineConfig} from 'vite';
import {createRequire} from 'module';
// WORKAROUND: @motion-canvas/vite-plugin is CommonJS, must use require
const require = createRequire(import.meta.url);
const motionCanvasModule = require('@motion-canvas/vite-plugin');
const motionCanvas = motionCanvasModule.default || motionCanvasModule;
export default defineConfig({
plugins: [
motionCanvas({
project: './src/project.ts',
}),
],
});
```
**Why .js instead of .ts?**
- Vite config runs before TypeScript compilation
- The `createRequire` workaround works reliably in plain JavaScript
- Avoids additional type resolution complexity
### Step 6: Create tsconfig.json
**CRITICAL**: Include `esModuleInterop` and `allowSyntheticDefaultImports`.
**File: `tsconfig.json`**
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020", "DOM"],
"jsx": "react-jsx",
"jsxImportSource": "@motion-canvas/2d/lib",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
```
### Step 7: Create index.html
**File: `index.html`**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Motion Canvas Project</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/project.ts"></script>
</body>
</html>
```
### Step 8: Create src/project.ts
**File: `src/project.ts`**
```typescript
import {makeProject} from '@motion-canvas/core';
import example from './scenes/example?scene';
export default makeProject({
scenes: [example],
});
```
### Step 9: Create First Animation Scene
**File: `src/scenes/example.tsx`**
```typescript
import {makeScene2D} from '@motion-canvas/2d/lib/scenes';
import {Circle} from '@motion-canvas/2d/lib/components';
import {createRef} from '@motion-canvas/core/lib/utils';
import {all} from '@motion-canvas/core/lib/flow';
export default makeScene2D(function* (view) {
const circleRef = createRef<Circle>();
view.add(
<Circle
ref={circleRef}
size={70}
fill="#e13238"
/>,
);
// Animate circle size and position
yield* circleRef().size(140, 1);
yield* circleRef().position.x(300, 1);
yield* circleRef().fill('#e6a700', 1);
// Parallel animations
yield* all(
circleRef().scale(1.5, 0.5),
circleRef().rotation(360, 1)
);
});
```
### Step 10: Run Development Server
```bash
npm run dev
```
Open browser at `http://localhost:5173` to see the Motion Canvas editor.
## Troubleshooting
### Error: `TypeError: motionCanvas is not a function`
**Cause**: ESM/CommonJS interoperability issue with `@motion-canvas/vite-plugin`
**Solution**: Use the `createRequire` workaround in `vite.config.js` (see Step 5)
```javascript
// ❌ WRONG - Will not work
import motionCanvas from '@motion-canvas/vite-plugin';
// ✅ CORRECT - Use createRequire
import {createRequire} from 'module';
const require = createRequire(import.meta.url);
const motionCanvasModule = require('@motion-canvas/vite-plugin');
const motionCanvas = motionCanvasModule.default || motionCanvasModule;
```
### Error: `Cannot find module '@motion-canvas/ui'`
**Cause**: Missing required dependency
**Solution**: Install the UI package:
```bash
npm install --save-dev @motion-canvas/ui
```
### Error: `Property 'default' does not exist on type ...`
**Cause**: TypeScript configuration missing ESM interop settings
**Solution**: Add to `tsconfig.json`:
```json
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}
```
### Warning: `The CJS build of Vite's Node API is deprecated`
**Status**: This is a known warning and can be safely ignored. It appears because `@motion-canvas/vite-plugin` is CommonJS. The workaround ensures functionality despite the warning.
### Error: `Failed to resolve import "*.tsx?scene"`
**Cause**: Vite plugin not properly loaded or configured
**Solution**:
1. Verify `vite.config.js` has the correct workaround
2. Check `project` path points to correct file: `'./src/project.ts'`
3. Ensure scene imports use `?scene` suffix: `import example from './scenes/example?scene';`
### Build fails with TypeScript errors
**Solution**:
1. Verify `tsconfig.json` includes all required options (see Step 6)
2. Check `jsxImportSource` is set to `@motion-canvas/2d/lib`
3. Ensure all dependencies are installed
## How to use
Read individual rule files for detailed explanations and code examples:
### Core Animation Concepts
- **[references/generators.md](references/generators.md)** - Generator functions for describing animations
- **[references/signals.md](references/signals.md)** - Reactive signals for dynamic properties and dependencies
- **[references/animations.md](references/animations.md)** - Tweening properties and creating smooth animations
For additional topics like scenes, shapes, text rendering, audio synchronization, and advanced features, refer to the comprehensive [Motion Canvas official documentation](https://motioncanvas.io/docs).
## Complete Working Example
This is a complete, tested project structure that works out of the box:
```
my-motion-canvas-project/
├── package.json
│ {
│ "name": "my-motion-canvas-project",
│ "type": "module",
│ "scripts": {
│ "dev": "vite",
│ "build": "vite build"
│ },
│ "devDependencies": {
│ "@motion-canvas/core": "^3.0.0",
│ "@motion-canvas/2d": "^3.0.0",
│ "@motion-canvas/vite-plugin": "^3.0.0",
│ "@motion-canvas/ui": "^3.0.0",
│ "vite": "^5.0.0",
│ "typescript": "^5.0.0"
│ }
│ }
│
├── vite.config.js (with createRequire workaround)
├── tsconfig.json (with esModuleInterop)
├── index.html
└── src/
├── project.ts (makeProject with scenes array)
└── scenes/
└── example.tsx (makeScene2D with animations)
```
## Best Practices
1. **Always use the createRequire workaround** - Don't try standard ESM imports for the Vite plugin
2. **Use vite.config.js not .ts** - Avoids additional compilation complexity
3. **Include all dependencies** - Don't forget `@motion-canvas/ui`
4. **Use generator functions** - All scene animations should use `function*` and `yield*` syntax
5. **Leverage signals** - Create reactive dependencies between properties
6. **Think in durations** - Specify animation duration in seconds as the second parameter
7. **Use refs for control** - Create references to nodes for precise animation control
8. **Preview frequently** - Take advantage of the real-time editor for instant feedback
9. **Organize scenes** - Break complex animations into multiple scenes
10. **Type everything** - Use TypeScript for better IDE support and fewer errors
## Common Pitfalls to Avoid
1. ❌ Forgetting `"type": "module"` in package.json
2. ❌ Using standard import for `@motion-canvas/vite-plugin`
3. ❌ Not installing `@motion-canvas/ui`
4. ❌ Missing `esModuleInterop` in tsconfig.json
5. ❌ Using `vite.config.ts` instead of `vite.config.js`
6. ❌ Forgetting `?scene` suffix in scene imports
## Resources
- **Documentation**: https://motioncanvas.io/docs
- **Repository**: https://github.com/motion-canvas/motion-canvas
- **Examples**: https://motioncanvas.io/docs/quickstart
- **Community**: Discord and GitHub Discussions
- **License**: MIT
don't have the plugin yet? install it then click "run inline in claude" again.
by @clawhub
extracted critical ESM/CommonJS workaround and setup steps into explicit procedure section with inputs/outputs for each step, added comprehensive decision points for common errors, defined output contract with file paths and config requirements, and clarified outcome signal with specific editor behavior expectations and build success indicators.
Complete production-ready skill for creating programmatic videos using Motion Canvas, including critical ESM/CommonJS workarounds, full configuration templates, and comprehensive troubleshooting.
Use this skill to set up Motion Canvas projects from scratch and create programmatic animations using TypeScript, generator functions, and reactive signals. This skill covers the full project initialization, critical ESM/CommonJS interoperability fixes, and common troubleshooting. Apply it when you need to create animated videos with precise synchronization, build procedural graphics, or work with real-time preview workflows. The skill handles domain-specific knowledge about generator-based animation flows, signal reactivity, Canvas API integration, audio synchronization, and vector graphics rendering.
Environment & Dependencies:
@motion-canvas/core>=3.0.0 - Core animation engine@motion-canvas/2d>=3.0.0 - 2D rendering and components@motion-canvas/ui>=3.0.0 - Web UI editor (required, non-optional)@motion-canvas/vite-plugin>=3.0.0 - Vite plugin (CommonJS distribution, requires workaround)vite>=5.0.0 - Build tool and dev servertypescript>=5.0.0 - TypeScript compilerProject Context:
External Connections:
1. Initialize Project Directory
Input: Project name string. Action: Create project folder and initialize npm.
mkdir my-motion-canvas-project
cd my-motion-canvas-project
npm init -y
Output: Empty package.json file in project root.
2. Configure package.json for ESM
Input: Freshly initialized package.json.
Action: Add "type": "module" to top level and configure build scripts.
{
"name": "my-motion-canvas-project",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
Output: Updated package.json with ESM flag and npm scripts.
3. Install All Required Dependencies
Input: Updated package.json.
Action: Run npm install with all required packages. Must include @motion-canvas/ui or the plugin will fail silently.
npm install --save-dev @motion-canvas/core @motion-canvas/2d @motion-canvas/vite-plugin @motion-canvas/ui vite typescript
Output: node_modules/ directory and package-lock.json with all transitive dependencies resolved.
4. Create Project Directory Structure
Input: Project root directory. Action: Create subdirectories and placeholder files.
my-motion-canvas-project/
├── package.json
├── vite.config.js
├── tsconfig.json
├── index.html
└── src/
├── project.ts
└── scenes/
└── example.tsx
Output: Directory tree matching structure above (files created in steps 5-9).
5. Create vite.config.js with ESM/CommonJS Workaround
Input: Project root directory.
Action: Write Vite config in plain JavaScript (not TypeScript) using createRequire to load CommonJS plugin. Use .js extension, not .ts.
import {defineConfig} from 'vite';
import {createRequire} from 'module';
// WORKAROUND: @motion-canvas/vite-plugin is CommonJS, must use require
const require = createRequire(import.meta.url);
const motionCanvasModule = require('@motion-canvas/vite-plugin');
const motionCanvas = motionCanvasModule.default || motionCanvasModule;
export default defineConfig({
plugins: [
motionCanvas({
project: './src/project.ts',
}),
],
});
Output: vite.config.js file at project root. Must be .js not .ts to avoid type resolution overhead.
6. Create tsconfig.json
Input: Project root directory. Action: Write TypeScript configuration with ESM interop flags set.
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020", "DOM"],
"jsx": "react-jsx",
"jsxImportSource": "@motion-canvas/2d/lib",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Output: tsconfig.json at project root with all required compiler options.
7. Create index.html
Input: Project root directory. Action: Write HTML entry point that loads the Motion Canvas project module.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Motion Canvas Project</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/project.ts"></script>
</body>
</html>
Output: index.html at project root.
8. Create src/project.ts
Input: /src directory.
Action: Write project configuration that registers all scenes and exports to Motion Canvas runtime.
import {makeProject} from '@motion-canvas/core';
import example from './scenes/example?scene';
export default makeProject({
scenes: [example],
});
Output: src/project.ts file. Note the ?scene query parameter on scene imports (required by Vite plugin).
9. Create src/scenes/example.tsx
Input: /src/scenes directory.
Action: Write first animation scene using generator syntax and Signal API.
import {makeScene2D} from '@motion-canvas/2d/lib/scenes';
import {Circle} from '@motion-canvas/2d/lib/components';
import {createRef} from '@motion-canvas/core/lib/utils';
import {all} from '@motion-canvas/core/lib/flow';
export default makeScene2D(function* (view) {
const circleRef = createRef<Circle>();
view.add(
<Circle
ref={circleRef}
size={70}
fill="#e13238"
/>,
);
// Animate circle size
yield* circleRef().size(140, 1);
// Animate position
yield* circleRef().position.x(300, 1);
// Animate color
yield* circleRef().fill('#e6a700', 1);
// Parallel animations
yield* all(
circleRef().scale(1.5, 0.5),
circleRef().rotation(360, 1)
);
});
Output: src/scenes/example.tsx file with working animation.
10. Start Development Server
Input: Initialized project with all files from steps 1-9. Action: Run Vite dev server.
npm run dev
Output: Dev server running at http://localhost:5173. Browser opens Motion Canvas editor with live preview. Hot module reloading active.
11. Build for Production
Input: Completed animation project. Action: Run Vite build command to generate output.
npm run build
Output: Compiled video file(s) in /dist directory (format depends on Motion Canvas export configuration).
If using a TypeScript Vite config (vite.config.ts):
createRequire workaround to fail.vite.config.js (plain JavaScript). Vite Vite config runs before TypeScript compilation, so plain JS is more reliable.If you see TypeError: motionCanvas is not a function:
@motion-canvas/vite-plugin.createRequire workaround in vite.config.js. Standard import will not work.If you see Cannot find module '@motion-canvas/ui':
@motion-canvas/ui immediately with npm install --save-dev @motion-canvas/ui. The plugin fails silently without it.If you see Property 'default' does not exist on type ... during build:
"esModuleInterop": true and "allowSyntheticDefaultImports": true to tsconfig.json compilerOptions.If you see Failed to resolve import "*.tsx?scene":
?scene query suffix.project path in plugin config points to correct file (default './src/project.ts'), (3) all scene imports use ?scene suffix like import example from './scenes/example?scene'.If build fails with TypeScript errors:
jsxImportSource: "@motion-canvas/2d/lib", target ES2020, module ES2020, and all compiler flags set correctly.If you see The CJS build of Vite's Node API is deprecated warning:
@motion-canvas/vite-plugin is CommonJS while Vite and Motion Canvas are ESM. The createRequire workaround handles it.If you need multiple scenes:
.tsx files in /src/scenes/, import each with ?scene suffix, and add to scenes array in project.ts. Order in array determines playback order.If you need to sync with audio:
Successful project setup produces:
package.json with "type": "module" and all 6 required devDependencies listed.vite.config.js (not .ts) with working createRequire workaround that runs without errors.tsconfig.json with esModuleInterop: true, allowSyntheticDefaultImports: true, jsxImportSource: "@motion-canvas/2d/lib", and all other flags from step 6.index.html with module script tag pointing to /src/project.ts.src/project.ts exporting a valid makeProject() config with at least one scene imported via ?scene suffix..tsx scene file in /src/scenes/ using makeScene2D(function* ...) generator syntax.node_modules/ directory with all dependencies installed and resolvable.File paths must match exactly:
vite.config.js at root (not .ts).src/project.ts (path referenced in vite.config.js).tsconfig.json at root.index.html at root.src/scenes/ (recommended, not mandatory but expected).Dev server must start cleanly:
npm run dev launches without errors.http://localhost:5173.Build must complete:
npm run build completes without errors.dist/ directory (or configured output folder).The skill worked if:
Running npm run dev opens the Motion Canvas editor in your browser at http://localhost:5173 with zero errors in terminal or console.
The editor UI displays your project with a live preview pane showing the example red circle animation on the left and timeline/playback controls on the right.
The example scene (red circle growing, moving, changing color, rotating) plays in the preview without glitches or console errors.
Editing src/scenes/example.tsx and saving the file triggers hot module reloading (HMR). The preview updates in real-time without requiring a manual refresh.
Running npm run build completes in under 30 seconds and produces compiled artifacts in the dist/ folder.
TypeScript in your editor shows zero errors on all imports from @motion-canvas/* packages.
No warnings about missing @motion-canvas/ui or unresolved ?scene queries appear in the console.
The createRequire workaround in vite.config.js executes without warnings or deprecation notices related to the plugin loader itself (the "CJS build deprecated" Vite message is expected and safe).