maxmotion-edit
Maxmotion Video Editor Skill
The user's message contains an <editor /> tag with project path and selected element.
Context Format
<editor project="<path>" type="<type>" id="<id>" name="<name>" frame="<from>-<end>" />
Core Rule: Code First, JSON for Simple Edits
| Task | Approach |
|---|---|
| Create new content (new video segment, composition, animation) | Write Remotion code in <project>/src/*.tsx |
| Modify existing clip properties (color, text, animation) | Edit <project>/maxmotion.json |
| Modify existing sequence content/logic | Edit <project>/src/*.tsx source code |
Never hand-write large maxmotion.json from scratch. JSON clips are for simple overlay elements (solid rects, text labels). Creative content should be Remotion components in code.
Routing (for existing elements)
| Selected Type | How to Operate |
|---|---|
solid, text, image, video, audio, component |
Edit <project>/maxmotion.json |
sequence |
Edit <project>/src/*.tsx source code |
Operations
| Operation | Clip (JSON) | Sequence (Code) |
|---|---|---|
| Add | Create clip, append to tracks[].clips[] |
Add <Sequence> in .tsx |
| Update | Find by id, modify fields |
Find <Sequence name="">, modify code |
| Delete | Remove from tracks[].clips[] |
Remove <Sequence> block |
AI vs UI Boundary
AI handles — content, color, animation, code logic, batch operations, add/delete elements, create new compositions
User handles in Editor UI — timing (drag timeline), position (drag canvas), resize, opacity
If the user asks to move/resize/adjust timing, reply suggesting they do it in the Editor UI. Match the user's language (Chinese/English).
JSON Schema (maxmotion.json)
{
"schemaVersion": 4,
"timelines": {
"<compositionId>": {
"tracks": [{
"id": "track_xxx",
"name": "Text",
"visible": true, "locked": false, "muted": false,
"clips": [{
"id": "clip_xxx",
"timing": { "from": 0, "duration": 150 },
"content": { "type": "solid", "color": "#3b82f6" },
"style": { "x": 100, "y": 100, "width": 200, "height": 200 },
"animation": { "fadeIn": 15, "fadeOut": 15 }
}]
}],
"sequenceOverrides": []
}
},
"assets": {
"<assetId>": {
"id": "<assetId>",
"type": "image",
"filename": "original-name.png",
"url": "stored-filename-in-public.png"
}
}
}
Clip Fields
| field | type | required | description |
|---|---|---|---|
id |
string | yes | Unique ID: clip_<base36-timestamp>_<random6> |
timing |
object | yes | { from: number, duration: number } (frames, NOT flat) |
content |
object | yes | See Content Types below |
style |
object | yes | See Clip Style below |
animation |
object | no | See Clip Animation below |
Important:
fromanddurationmust be nested insidetiming, not flat on the clip object. Flatfrom/durationwill crash the renderer.
Clip Content Types
| type | fields |
|---|---|
solid |
color |
text |
text, fontSize, color, fontFamily?, align? |
image |
assetId |
video |
assetId, playbackRate?, volume? |
audio |
assetId, volume? |
component |
componentId, props |
Clip Style
| field | type | required | description |
|---|---|---|---|
x |
number | yes | X position (px) |
y |
number | yes | Y position (px) |
width |
number | yes | Width (px) |
height |
number | yes | Height (px) |
opacity |
number | no | 0-1, default 1 |
rotation |
number | no | Degrees |
borderRadius |
number | no | Pixels |
transform3d |
object | no | { perspective?, rotateX?, rotateY?, rotateZ?, translateZ? } |
Clip Animation
| field | type | description |
|---|---|---|
fadeIn |
number | Fade-in frames |
fadeOut |
number | Fade-out frames |
springConfig |
object | { mass?, damping?, stiffness? } |
Sequence Overrides
timelines.<compositionId>.sequenceOverrides can override properties of code-defined <Sequence> elements:
| field | type | description |
|---|---|---|
id |
string | Sequence ID (required) |
name |
string | Sequence name (for matching) |
from |
number | Override start frame |
duration |
number | Override duration frames |
visible |
boolean | Show/hide (default true) |
style |
object | { x?, y?, width?, height?, opacity? } |
Asset Schema
Clips with assetId (image/video/audio) reference entries in assets. Each asset key is the asset ID.
| field | type | description |
|---|---|---|
id |
string | Same as the key in assets object |
type |
string | image | video | audio |
filename |
string | Original display name (e.g. photo.png) |
url |
string | Filename in public/ directory or full HTTP URL |
Important: Use url (not src) and filename (not name). Wrong field names will crash the renderer.
Timing
All values are frames. Get fps from <project>/src/Root.tsx:
<Composition id="Main" fps={30} width={1920} height={1080} ... />
Convert: seconds * fps = frames
Remotion Code Pattern
import { AbsoluteFill, Sequence, useCurrentFrame, interpolate } from 'remotion';
export const MyComp = () => (
<AbsoluteFill>
<Sequence from={0} durationInFrames={90} name="intro">
<h1 style={{ fontSize: 60 }}>Title</h1>
</Sequence>
</AbsoluteFill>
);
When creating new content, write proper Remotion components using Sequence, AbsoluteFill, useCurrentFrame, interpolate, spring, etc. Register in Root.tsx via <Composition>.
Remotion Quick Reference
Project Structure
video/
├── src/
│ ├── index.ts # registerRoot(RemotionRoot)
│ ├── Root.tsx # <Composition> registration
│ └── MyComp.tsx # Component implementation
├── public/ # Static assets (images, fonts, videos)
├── remotion.config.ts # Remotion config
└── maxmotion.json # Editor timeline data
Core Components
| Component | Purpose | Example |
|---|---|---|
<Composition> |
Register a video (in Root.tsx) | <Composition id="Main" component={MyComp} fps={30} width={1920} height={1080} durationInFrames={300} /> |
<AbsoluteFill> |
Full-screen container (position: absolute, inset: 0) | <AbsoluteFill style={{ backgroundColor: '#000' }}> |
<Sequence> |
Time-scoped section | <Sequence from={30} durationInFrames={60} name="intro"> |
<Video> |
Video playback | <Video src={staticFile('clip.mp4')} /> |
<Audio> |
Audio playback | <Audio src={staticFile('music.mp3')} volume={0.5} /> |
<Img> |
Image (preloaded) | <Img src={staticFile('logo.png')} /> |
<Series> |
Sequential sequences (auto-calculates from) |
<Series><Series.Sequence durationInFrames={60}>...</Series.Sequence></Series> |
Core Hooks
| Hook | Returns | Usage |
|---|---|---|
useCurrentFrame() |
number |
Current frame (0-based, resets inside each <Sequence>) |
useVideoConfig() |
{ fps, width, height, durationInFrames } |
Composition config |
Animation Utilities
import { interpolate, spring, Easing } from 'remotion';
// Linear interpolation
const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: 'clamp' });
// Spring animation
const scale = spring({ frame, fps, config: { damping: 12, stiffness: 200 } });
// With easing
const x = interpolate(frame, [0, 60], [0, 500], { easing: Easing.bezier(0.25, 0.1, 0.25, 1) });
Static Assets
import { staticFile } from 'remotion';
// References files in public/ directory
<Img src={staticFile('logo.png')} />
<Video src={staticFile('intro.mp4')} />
Validation
After editing maxmotion.json, always run validation to catch schema errors:
cd <project> && npx maxmotion validate
If validation fails, fix the errors before telling the user the edit is done.
Notes
- After editing JSON: user needs to refresh Editor. After editing .tsx: HMR auto-updates.
- New clip IDs:
clip_<base36-timestamp>_<random6>. Keep 2-space JSON indent. - The first
<Composition>in Root.tsx is selected by default in the Editor. After creating a new composition, remove empty/unused ones (e.g. components returningnull) to avoid a black screen.
More from maxgent-ai/maxgent-plugin
audio-transcribe
Speech-to-text transcription using Whisper with word-level timestamps. Use when users ask to transcribe audio or video to text, generate subtitles, or recognize speech.
51memory
Read long-term memory files to get historical context, code references, and error fix records. Use when user wants to read memory, get context, check history, avoid repeating errors.
12video-gen
AI video generation with text-to-video, image-to-video, and first/last frame control. Use when users ask to generate or create videos from text prompts or images.
10youtube-download
Download videos, audio, or subtitles from YouTube, Bilibili, and other sites using yt-dlp. Use when users ask to download online videos or extract audio from video URLs.
9image-gen
AI image generation and editing. Use when users ask to generate, create, or draw images with AI, or edit and modify existing images.
6browser
Browser automation with persistent page state. Use when users ask to navigate websites, fill forms, take screenshots, extract web data, test web apps, or automate browser workflows. Trigger phrases include "go to [url]", "click on", "fill out the form", "take a screenshot", "scrape", "automate", "test the website", "log into", or any browser interaction request.
5