Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Complete production-ready guide for Motion Canvas with ESM/CommonJS workarounds, full setup templates, and troubleshooting for programmatic video creation using TypeScript
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 222% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 99% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 236% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 173% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 95% | 0% |
Complete production-ready skill for creating programmatic videos using Motion Canvas, including critical ESM/CommonJS workarounds, full configuration templates, and comprehensive troubleshooting.
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.
Use this skill whenever you are dealing with Motion Canvas code to obtain domain-specific knowledge about:
Motion Canvas allows you to create videos using:
yield* syntaxbash# Create project directory mkdir my-motion-canvas-project cd my-motion-canvas-project # Initialize package.json npm init -y
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" } }
CRITICAL: Must include @motion-canvas/ui - the plugin will fail without it.
bashnpm install --save-dev @motion-canvas/core @motion-canvas/2d @motion-canvas/vite-plugin @motion-canvas/ui vite typescript
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 sceneCRITICAL: Use vite.config.js (NOT .ts) with the createRequire workaround.
File: vite.config.js
javascriptimport {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?
createRequire workaround works reliably in plain JavaScriptCRITICAL: 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"] }
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>
File: src/project.ts
typescriptimport {makeProject} from '@motion-canvas/core'; import example from './scenes/example?scene'; export default makeProject({ scenes: [example], });
File: src/scenes/example.tsx
typescriptimport {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) ); });
bashnpm run dev
Open browser at http://localhost:5173 to see the Motion Canvas editor.
TypeError: motionCanvas is not a functionCause: 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;
Cannot find module '@motion-canvas/ui'Cause: Missing required dependency
Solution: Install the UI package:
bashnpm install --save-dev @motion-canvas/ui
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 } }
The CJS build of Vite's Node API is deprecatedStatus: 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.
Failed to resolve import "*.tsx?scene"Cause: Vite plugin not properly loaded or configured
Solution:
vite.config.js has the correct workaroundproject path points to correct file: './src/project.ts'?scene suffix: import example from './scenes/example?scene';Solution:
tsconfig.json includes all required options (see Step 6)jsxImportSource is set to @motion-canvas/2d/libRead individual rule files for detailed explanations and code examples:
For additional topics like scenes, shapes, text rendering, audio synchronization, and advanced features, refer to the comprehensive Motion Canvas official documentation.
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)@motion-canvas/uifunction* and yield* syntax"type": "module" in package.json@motion-canvas/vite-plugin@motion-canvas/uiesModuleInterop in tsconfig.jsonvite.config.ts instead of vite.config.js?scene suffix in scene importsOther measured skills in the registry, with their headline benchmark lift.