Convert screenshots into cinematic animated videos — Production-ready Next.js application powered by Remotion.
OpenMotion transforms your product screenshots, landing pages, or brand assets into professional animated videos using pre-built templates. This is Milestone 1: Template Mode — 12 carefully crafted templates optimized for different use cases.
[DONE] 12 Pre-built Templates across 4 categories
[DONE] Drag-and-drop asset management with deduplication
[DONE] Real-time preview with Remotion Player
[DONE] Customizable properties (aspect ratio, duration, FPS, colors)
[DONE] Background rendering with progress tracking
[DONE] Local file storage (no cloud dependencies)
[DONE] Type-safe with TypeScript strict mode
[DONE] Production-ready build (verified)
- Bun (>= 1.0) — Install Bun
- PostgreSQL (>= 14) — Install PostgreSQL
- Node.js (>= 18) — Only needed for certain Remotion operations
# Clone the repository
git clone https://github.com/yourusername/openmotion.git
cd openmotion
# Install dependencies
bun install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your database credentials
# Create database
createdb openmotion
# Push schema and seed templates
DATABASE_URL="postgresql://user@localhost:5432/openmotion" bun run db:push
DATABASE_URL="postgresql://user@localhost:5432/openmotion" bun run db:seed
# Start development server
DATABASE_URL="postgresql://user@localhost:5432/openmotion" bun run devOpen http://localhost:3000 in your browser.
# Development
bun run dev # Start dev server with Turbopack
bun run build # Production build
bun run start # Start production server
bun run lint # Run ESLint
# Database
bun run db:generate # Generate migrations
bun run db:migrate # Run migrations
bun run db:push # Push schema to database (quick)
bun run db:studio # Open Drizzle Studio
bun run db:seed # Seed 12 templates
# Type Checking
bunx tsc --noEmit # Check TypeScript errorsOpenMotion includes 12 templates across 4 categories:
Best for: Hero sections, single-screen highlights
Assets needed: 1-2 images
Duration: 3-5 seconds
- Hero Drift — Subtle pan with elegant fade
- Hero Copy — Dynamic text reveal with image
- Hero ZoomCut — Cinematic zoom with cut transition
Best for: Multi-screen flows, landing pages
Assets needed: 3-6 images
Duration: 8-12 seconds
- Smooth Carousel — Seamless horizontal carousel
- Stack Reveal — Layered card reveal effect
- Split Showcase — Side-by-side split transitions
Best for: Product launches, brand identity
Assets needed: Logo + 2-5 screenshots
Duration: 10-15 seconds
- Logo → Hero — Logo intro to product showcase
- Brand Carousel — Branded carousel with logo overlay
- Clean End Card — Professional ending with logo
Best for: Social media (Instagram, TikTok)
Assets needed: 3-6 images
Duration: 7-15 seconds
Optimized for: 9:16 (vertical)
- 7-Second Reel — Quick-cut vertical carousel
- Feature Beats — Rhythmic feature highlights
- Dark Premium — Premium dark theme with gold accents
openmotion/
├── app/ # Next.js App Router
│ ├── actions/ # Server actions (projects, assets, drafts, export)
│ ├── projects/ # Main application routes
│ │ ├── page.tsx # Projects list
│ │ └── [id]/
│ │ ├── page.tsx # Project detail (upload, templates)
│ │ ├── editor/ # Timeline editor
│ │ └── render/ # Render status
│ ├── layout.tsx # Root layout
│ └── globals.css # Tailwind v4 styles
│
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives
│ ├── video-editor.tsx # Remotion Player + controls
│ ├── render-status-client.tsx # Progress polling
│ ├── asset-gallery.tsx # Image grid
│ ├── asset-upload.tsx # File upload
│ └── template-selector.tsx # Template picker
│
├── lib/
│ ├── db/
│ │ ├── schema.ts # Drizzle schema (5 tables)
│ │ ├── seed/ # Template seeds
│ │ └── index.ts # DB connection
│ ├── rendering/
│ │ ├── render-engine.ts # Main render function
│ │ ├── browser-manager.ts # Chromium helpers
│ │ └── logger.ts # Structured logging
│ └── storage/
│ ├── local.ts # File operations
│ └── image-processor.ts # Sharp processing
│
├── remotion/
│ ├── scenes/ # 6 scene primitives
│ │ ├── carousel.tsx
│ │ ├── drift.tsx
│ │ ├── logo-intro.tsx
│ │ ├── split-screen.tsx
│ │ ├── stack-reveal.tsx
│ │ └── zoom-cut.tsx
│ ├── utils/
│ │ └── motion.ts # Constrained animations
│ ├── DynamicVideo.tsx # Main composition
│ └── Root.tsx # Remotion root
│
├── workflows/
│ ├── render-video.ts # Main workflow
│ └── render-steps.ts # 7 step functions
│
└── public/uploads/ # Local storage
├── original/
├── processed/
└── renders/
- Next.js 15.1.6 — App Router, Server Actions, RSC
- React 19 — Latest React features
- Remotion 4.0.407 — Video rendering and preview
- Tailwind CSS v4 — Utility-first styling
- shadcn/ui — High-quality component library
- TypeScript 5.9 — Strict type checking
- Drizzle ORM — Type-safe database queries
- PostgreSQL — Primary database
- Sharp — Image processing (resize, optimize)
- Vercel Workflow — Durable background jobs (beta)
- Bun — Fast JavaScript runtime and package manager
- Turbopack — Next.js dev server (faster than Webpack)
- ESLint — Code linting
- PostCSS — CSS processing
// 5 tables: projects, assets, templates, videoDrafts, renderJobs
projects
id: uuid (PK)
name: string
userId: string (future: auth)
createdAt, updatedAt
assets
id: uuid (PK)
projectId: uuid (FK → projects)
originalS3Key: string (local path)
processedS3Key: string (local path)
hash: string (deduplication)
aspectRatio: decimal
width, height: integer
createdAt
templates
id: string (PK, e.g., "t1-hero-drift")
name: string
category: enum (4 categories)
aspectRatio: enum (16:9, 9:16, 1:1, 4:5)
durationSeconds: integer
fps: integer (30 or 60)
minAssets, maxAssets: integer
propsSchema: json (Zod schema)
videoDrafts
id: uuid (PK)
projectId: uuid (FK → projects)
templateId: string (FK → templates)
propsJson: json (Remotion props)
status: enum (draft, rendering, complete, failed)
ratio: enum
fps: integer
createdAt, updatedAt
renderJobs
id: uuid (PK)
videoDraftId: uuid (FK → videoDrafts)
workflowRunId: string (Vercel workflow)
status: enum (pending, bundling, rendering, complete, failed)
progress: decimal (0-100)
stage: string (current step)
logsJson: json (structured logs)
outputS3Key: string (when complete)
sizeInBytes: bigint
createdAt, updatedAtUser creates a project → stored in projects table.
- User uploads screenshots (JPG/PNG/WebP)
- Sharp processes images (resize, optimize, hash)
- Deduplicated by hash → stored in
assetstable - Files saved to
public/uploads/original/andpublic/uploads/processed/
- User selects from 12 templates
- System validates: min/max asset requirements
- Creates
videoDraftwith initial props
- Remotion Player previews video in real-time
- User adjusts properties (colors, duration, fps)
- Changes saved to
videoDraft.propsJson
- User clicks "Export Video"
- Creates
renderJobwith uniqueworkflowRunId - Triggers Vercel workflow (background)
// workflows/render-video.ts
"use workflow"; // Vercel durable workflow
1. Load draft + assets from DB
2. Bundle Remotion project (webpack)
3. Select composition (template)
4. Render video (Chromium headless)
5. Save result to public/uploads/renders/
6. Update job status → complete
7. Cleanup temp files- User redirected to
/projects/[id]/render/[runId] - Page polls every 2 seconds for updates
- Displays: progress bar, current stage, logs
- When complete: download button appears
// projects.ts
createProject(name: string) → { id, name, userId }
getProjects() → Project[]
getProject(id: string) → Project
// assets.ts
uploadAssets(projectId: string, files: File[]) → Asset[]
getAssets(projectId: string) → Asset[]
// video-drafts.ts
createVideoDraft(data: CreateDraftInput) → VideoDraft
updateVideoDraft(id: string, propsJson: object) → VideoDraft
getVideoDraft(id: string) → VideoDraft
// export.ts
startExport(videoDraftId: string) → { success, runId, jobId }
getRenderStatus(runId: string) → RenderJob
cancelRender(runId: string) → { success }- Create scene primitive in
remotion/scenes/ - Define props schema with Zod
- Add template seed to
lib/db/seed/templates.ts - Test with Remotion Player
- Seed database:
bun run db:seed
Example:
// lib/db/seed/templates.ts
{
id: 't13-custom',
name: 'Custom Template',
category: 'minimal-hero',
aspectRatio: '16:9',
durationSeconds: 5,
fps: 30,
minAssets: 1,
maxAssets: 1,
propsSchema: {
type: 'object',
properties: {
primaryColor: { type: 'string', default: '#FF0000' },
// ...
},
},
}All animations use constrained motion (remotion/utils/motion.ts):
import { drift, easeInOut } from '@/remotion/utils/motion';
// Horizontal drift (constrained to 5% of width)
const x = drift(frame, fps, durationInFrames, 0.05);
// Smooth easing
const opacity = easeInOut(frame, 0, 30, 0, 1);- 7/7 flows passed (100% pass rate)
- 0 critical bugs found
- Full report:
docs/openmotion/E2E_Test_Report_20260122.md
# Unit tests (future)
bun test
# Integration tests (future)
bun test:integration# .env.local
DATABASE_URL=postgresql://user:password@localhost:5432/openmotion
NODE_ENV=production# Build and verify
bun run build
bun run start # Test production build locally
# Deploy to Vercel (recommended)
vercel --prod// vercel.json
{
"buildCommand": "bun run build",
"env": {
"DATABASE_URL": "@database-url"
}
}- No authentication in Milestone 1 (single-user mode)
- Local file storage (no AWS S3 credentials needed)
- SQL injection protected by Drizzle ORM parameterization
- File upload validation (type, size, hash)
For production:
- Add authentication (Clerk, NextAuth, etc.)
- Move to cloud storage (S3, R2)
- Add rate limiting
- Implement CSRF protection
- 12 pre-built templates
- Asset management
- Timeline editor
- Background rendering
- E2E testing
- Natural language → video generation
- AI template selection
- Smart asset cropping
- Voice-over integration
- Multi-user authentication
- Team collaboration
- Custom fonts and branding
- Audio track support
- Batch rendering
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License — See LICENSE for details.
- Remotion — Incredible video rendering library
- Next.js — Best React framework
- shadcn/ui — Beautiful component library
- Drizzle — Developer-friendly ORM
- Documentation: docs/
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Built with by [Your Name]