Deterministic, code-only vertical video engine built with Next.js + TypeScript + Remotion. No AI image generation is used. All visuals are generated via code (typography, geometry, particles, comic panels, and data visuals).
GitHub inline preview uses a lightweight web version:
- JSON-driven project input:
meta,theme,audio,scenes[] - 9:16 MP4 rendering pipeline via Remotion
- In-app preview with Remotion Player
- 5 reusable scene templates:
kinetic-textgeometric-motionparticle-flowcomic-paneldata-pulse
- Theme engine tokens:
- palette, font, background mode, motion preset, line thickness, glow intensity
- Timing engine:
- frame-safe start/duration handling + transitions
- Motion presets:
snappy,cinematic,elastic
- Subtitle + voiceover + BGM support
- Dynamic visual layer:
- keyword-to-SVG/icon mapping
- stick-figure choreography
- custom SVG upload and scene-level reuse
- auto-crawl SVG library from public icon sources
- Auto generation library:
- auto-save project/storyboard/transcript after agent pipeline
- auto-attach rendered MP4 after export
- keeps newest 100 items (older items are pruned automatically)
- download-ready URLs for project JSON, transcript, and final video
- Cloud concurrency guard:
- in cloud mode, heavy endpoints are capped to 5 concurrent jobs by default
- overflow requests are queued briefly, then return
429withRetry-After
- Audio-duration alignment:
- scene timeline is stretched/compressed to match input audio duration
- each scene remains capped at 5 seconds
- optional transition mode:
smoothornone
- Minimal editor UI:
- JSON panel, script compiler panel, preview player, preset selector, render trigger
After researching devforth/scriptimate, two patterns were applied:
- Script-to-timeline workflow
- Added a lightweight scene DSL compiler (
compileSceneScriptToProject) inspired by Scriptimate’s script-first animation flow. - You can write scene lines and compile directly into project JSON.
- Deterministic render cache
- Added project-hash based render caching (
hashProject) so repeated renders of identical input reuse existing MP4 output.
src/
data/
demo-project.json
lib/
schema/
index.ts
project-schema.ts
remotion/
index.ts
Root.tsx
compositions/
AnimationEngineComposition.tsx
AnimationVideo.tsx
RemotionRoot.tsx
scenes/
KineticTextScene.tsx
GeometricMotionScene.tsx
ParticleFlowScene.tsx
ComicPanelScene.tsx
DataPulseScene.tsx
components/
AnimationEditor.tsx
AudioLayers.tsx
BackgroundLayer.tsx
SceneContainer.tsx
SceneTitleBlock.tsx
SubtitlesLayer.tsx
engine/
constants.ts
motion-presets.ts
project-hash.ts
render-video.ts
scene-factory.tsx
script-compiler.ts
theme-engine.ts
timing.ts
types.ts
styles/
backgrounds.ts
theme-presets.ts
app/
page.tsx
animation-engine/page.tsx
api/render/route.ts
api/animation-engine/render/route.ts
npm install
npm run devOpen:
http://localhost:3000(main editor)http://localhost:3000/animation-engine(legacy-compatible editor path)
npm run build -- --webpackRecommended for this app: Railway or Render using Docker (stable for Remotion MP4 rendering).
git add .
git commit -m "prepare cloud deployment"
git push- Railway: New Project -> Deploy from GitHub repo
- Render: New Web Service -> Connect GitHub repo -> choose
Docker
Required:
OPENAI_API_KEY
Optional:
OPENAI_MODEL(default:gpt-4o-mini)OPENAI_TRANSCRIBE_MODEL(default:gpt-4o-mini-transcribe)SVG_AUTO_SYNC_ON_LIST(1by default; set0to disable auto-crawl on library refresh)SVG_AUTO_SYNC_MINUTES(default180, minimum5)ANIMATION_ENGINE_MAX_CONCURRENT_USERS(default5)ANIMATION_ENGINE_MAX_QUEUE_SIZE(default20)ANIMATION_ENGINE_QUEUE_TIMEOUT_MS(default25000)ANIMATION_ENGINE_CONCURRENCY_LIMIT_FORCE(1to enforce limit on localhost too)
- Port: platform default (
$PORT) is already supported - Memory: use at least
2 GB(recommended4 GB) for smoother video rendering - Instance: keep at least 1 instance always on (avoid cold starts for mobile usage)
- To keep a strict shared cap of 5 active users, run a single app instance with
ANIMATION_ENGINE_MAX_CONCURRENT_USERS=5
- Open the generated HTTPS URL from Railway/Render
- Go to
/animation-engine - Add to Home Screen on iOS/Android for app-like access
- Edit script or JSON in the editor.
- Click
Compile Script(optional) thenValidate + Apply. - Preview updates in Remotion Player.
- Click
Render MP4.
Routes:
POST /api/render(JSON response with output URL)POST /api/animation-engine/render(returns MP4 file stream)GET/POST /api/animation-engine/svg-assets(list/upload custom SVG assets)POST /api/animation-engine/svg-assets/sync(manual crawler sync)POST /api/animation-engine/agent-pipelinesupports:audioDurationMsfor duration matchingtransitionMode(smooth/none)- audio upload saved to
/public/uploadsand injected as voiceover source
GET/POST /api/animation-engine/library- list and save generation library entries
- auto-prunes old entries beyond 100 newest items
- storage path:
/public/generation-library/<item-id>/...
npm run remotion:studio
npm run render:demo- Add scene component in
src/remotion/compositions/scenes. - Extend
sceneTypeSchemainsrc/lib/schema/project-schema.ts. - Register in
src/remotion/engine/scene-factory.tsx. - Add optional scene data fields in
sceneDataSchema. - Add sample usage in
src/data/demo-project.json.
- Add preset to
src/remotion/styles/theme-presets.ts. - Update
ThemePresetIdunion there. - Preset selector auto-loads from
THEME_PRESET_IDS.
- Motion state is frame-based and deterministic.
- Render cache key is computed from stable project JSON hash.
- Same project input yields consistent output.
- Local JSON + script workflow
- No database
- No authentication
- Single-job render trigger from UI/API
- Never commit API keys into source code.
- If an API key was shared in chat/logs, rotate it immediately in OpenAI dashboard.