Repository navigation
Releases: dha-aa/ae-motion
Release list
2.24.0
Added
-
The installers (
scripts/install.sh,scripts/install.ps1) register ae-motion with Claude Desktop and Claude Code themselves (scripts/register.ts), so there is no command left to copy. Claude Desktop gets an absolutenodepath (it starts with a minimal PATH that misses Homebrew and nvm); Claude Code gets the server at user scope, so it works in every project instead of only the folder the old printed command was run in. Other servers, app settings and anenvyou added are kept; an entry that is already right is left alone (the panel's Update button re-runs the installer); a config file that isn't valid JSON is never overwritten.AE_MCP_REGISTER=0skips it. -
Install with an agent: paste "Install the After Effects MCP server from https://github.com/dha-aa/ae-motion. Follow its INSTALL.md." into Claude Code (or any agent that can run commands) and it clones, installs and registers the server, then lists the two After Effects settings only you can change.
INSTALL.mdholds the agent's steps; the README's Installation section offers both ways. -
The installers stop at once with a clear message when Node.js is missing or older than 22.18, instead of failing partway through the build.
-
node scripts/check.ts --aesays what is still missing after an install: it checks the server starts, reads Allow Scripts to Write Files and Access Network from After Effects' own prefs file (read only) and asks the panel for the project, and names the step for each part that fails. The installers run the server part after building, so a build that does not start fails the install instead of the first tool call. INSTALL.md ends with it instead of looking forbridge.json, which a crashed After Effects can leave behind. -
Install with an agent installs a missing Node.js or git for you, after asking: Homebrew, or Apple's own installers, on macOS, and
wingeton Windows. It checks After Effects is installed too. The README's Requirements say how to check and install each one by hand. -
AGENTS.mdpoints AI agents other than Claude Code (Codex, Cursor and others) to INSTALL.md for installing and to CLAUDE.md and CONTRIBUTING.md for changes. CONTRIBUTING.md now says which doc gets what (README for people, INSTALL.md for agents, docs/setup.md for everything else), and a test keeps the docs' links and sections working and every setting documented.
Fixed
AE_MCP_FFMPEG(where ffmpeg is, for render checks anddeliver) andAE_MCP_UPDATE_URLwere read by the server but not documented; both are in the Configuration table now.- Installing by following INSTALL.md or the README put you on
main, and the panel's Update button, which installs the newest release, then moved you back to that older release (dropping changes not released yet, such as the Claude Desktop / Claude Code registration). Both now install withnode scripts/update.ts, which checks out the newest release and runs the installer for your OS, so installing and updating agree. - The installer's
Claude Code:line and INSTALL.md say how to load the server in a running Claude Code session (/mcp, ae-motion, Reconnect) instead of only "start a new session".
Changed
- The After Effects quirks (about 40 behaviours found in live testing) are in one place,
host/CLAUDE.md, instead of two lists that had drifted apart:CLAUDE.mdanddocs/development.mdeach held facts the other lacked. Claude Code now loads them only when working inhost/, so theCLAUDE.mdread at the start of every session is about a third smaller (26 KB to 17 KB). - The README is rewritten in plain words for people who just want to use ae-motion: what it does, how it works, what you need, how to install it with Claude or by hand, and the two steps in After Effects. The details (what the installer changes, other MCP clients, configuration, security, troubleshooting, updating and uninstalling) moved, unchanged, to docs/setup.md; the tool list and example prompts are in docs/tools.md.
- The server instructions are rewritten to fit in the 4,096 characters Claude Code shows (5,599 before, 4,083 now). The last rules (editing footage, framing, text over video, sound, counting, before finishing, run_jsx) used to be cut off, so Claude only saw them after the motion-guide prompt was run; now every rule reaches the model in every session. Same rules and numbers in fewer words; about 380 tokens less per session, and Claude Code's motion-guide is about 570 tokens (was about 1,090) since nothing is left over for it. A test fails if the instructions grow past the cut.
- The README ends with every tool, grouped by area with an example of what to ask for, and how to contribute (bug reports, CONTRIBUTING.md, AGENTS.md). A test keeps the tool table equal to the tools the server offers.
2.23.0
Changed
- The
motion-guideprompt no longer repeats what Claude Code already shows from the server instructions. Claude Code cuts the instructions at 4,096 characters, so the conventions and the first design rules (format, copy, type, layout, timing, holds, polish) were in the model's context twice. The rules past the cut (editing footage, footage framing, text over video, sound, counting, before finishing, and the run_jsx rule) stay in the guide. Claude Code's guide is about 1,090 tokens instead of 1,680. Other clients, which may not show the server instructions to the model, get the whole guide as before. - Tool definitions use shorter forms that mean the same in JSON Schema: plain-type
anyOfmembers become one type list ("type": ["integer", "null"]), no"type"beside a stringconst, no emptyadditionalProperties. That is about 100 tokens less, on every request in clients that send the definitions with each message; descriptions are unchanged and zod checks every value as before. - The server is built on the MCP TypeScript SDK v2 (
@modelcontextprotocol/server2.3) instead of v1 (@modelcontextprotocol/sdk, which now gets only bug and security fixes). Clients see the same tool list, instructions, prompt and results as before. Bad-argument errors are now explained from the schema's own issues instead of the SDK's wording, so they keep theirBAD_ARGSformat and "did you mean" hints whatever the SDK says.
Fixed
- Calling a tool that does not exist returns a
NOT_FOUNDerror with the closest tool name as a hint, in the usual{error: {code, message, hint}}format (it was the SDK's raw text).
2.22.0
Changed
- Clients that send every tool definition with every message (Claude Desktop, most others) are shown the core tools only: about 11k tokens of definitions per message instead of 18k. The other 32 tools are named in the server instructions, and a
batchstep that uses one shows its group first (the result listsloaded_groups);load_toolsstill works. Claude Code is shown every tool, as before, because it loads definitions only when a tool is used.AE_MCP_TOOLSETSstill chooses the groups (allfor everything); every tool is registered either way. batchreturnsresults: "auto"by default: each step's result whole up to 600 characters (ids, timing, values read back), larger ones cut to ids and names with anote(results: "all"keeps the old behaviour). Batch results were 43% of the result tokens in a 3-minute video build, mostly keyframe lists nobody re-read.render_statusincludes the aerender log tail only when a job fails or logged errors; while running, every poll repeated the same ten progress lines.find_fontsgroups its result as{family: {style: PostScript name}}(pluslistedwhenlimitcut it): the same information in about 40% of the size.- Tool definitions: an enum of strings no longer repeats
"type": "string"(about 1k characters less on every request; zod still checks every value).
2.21.0
Added
batchnamed steps: give a stepas: "title"and refer to it as"$title.id"instead of counting steps, the most common reference mistake in long builds. A"$word"that is not a declared name stays literal text, so"$TSLA"in a caption still works; a repeated name, or a name used before its step, is reported before anything runs.batchdefaults: {tool: args}: shared arguments merged under every step of that tool (nested objects merge, the step's own values win). Repeated layers such as captions send theircomp_idand style once instead of in every step, which cut a 48-caption build to about a third of its size.add_layerfit: "cover" | "contain"scales footage, precomps and solids to fill the comp frame or fit inside it (pixel aspect included) and returns thescaleused, instead of working out a percentage per clip.add_layersource_inandstretch: place a clip by the source time it shows atin({in: 1, source_in: 9.3}) and its speed, with no start-time maths. Hand-computed start times put the wrong part of a clip on screen twice while building a 3-minute edit.
Verified
- Live in After Effects 26.3:
fitcover / contain scales,source_inwithstretch, named steps,defaultsand a literal$wordinbatch; both are now part of the live tests (27/27 pass).
2.20.1
Fixed
preview_frameimages show the comp's background in its own colour. After Effects writes the background as transparent pixels, which clients drew white, so light text on a dark comp looked invisible or washed out and a model could "fix" a design that was fine. The returned image is now opaque and matches the comp exactly (the edges were already blended).set_layerreads back every field it sets:adjustment,guide,effects,audio,quality,sampling,collapse,time_remap,frame_blending,auto_orient,separate_dimensions,preserve_transparency,solid_colorandsolid_sizewere left out of its result.import_footageas: sequencerefuses a file whose name has no frame number. After Effects took every image in that folder as one sequence named after the folder.- A layered PSD or Illustrator comp import says its duration comes from After Effects' still-footage preference (it was 102.9 s), and its
<name> Layersfolder moves intofolderwith the comp. - About 50 errors now say what to do next (a missing file names the allowed folders, a move starting before 0 s says to start later, stagger on a property with no keys says to animate it first, and so on).
Verified
- Blend modes and adjustment layers, from preview pixels in After Effects 26.3, now part of the live tests.
2.20.0
Added
set_textrangesstyle part of a text in the same call (After Effects 24.3+): a word in the accent colour, a bold name, one outlined line. Each range ismatch(every occurrence of a string) orstart/endcharacter indexes, with font, size, color, stroke, faux styles, caps, tracking, scale or baseline shift. This used to take a text animator built through severaladd_propertycalls. Every range is checked against the text before anything changes.get_textlists the parts styled differently from the first character (ranges, only the fields that differ), so a model sees part styling before it changes the text.import_footageimports several files at once (paths), a layered PSD or Illustrator file as a comp of its layers (as: comp/comp_cropped), and sets the footage's interpretation as it imports:fps(image sequences come in at 30 fps whatever they were rendered at, so a 24 fps render played too fast),loopandalpha.folderfiles the imports in a project folder (made if missing). Every file is checked before any is imported.set_item, a new tool: rename a project item, set its comment or label, move it into a folder or back to the top level, change a footage item'sfps/loop/alpha, or swap its file (or image sequence) for every layer that uses it.- Footage in
get_projectshows itsfps, and items inside a folder showfolder_id. save_projectclean: trueremoves footage no comp uses before saving (imports never placed, sources left behind byreplace_source), and says how many (removed_footage).- A wrong argument name now says which one was meant:
Unrecognized key: "stagger" (did you mean stagger -> stagger_seconds?). The suggestion is a known synonym (the timing tools name the same ideastagger,stagger_secondsandoffset_seconds) or a near spelling, so a model fixes the call on the first retry. It costs nothing in the tool definitions. find_sound_cuesevents: the model says what moments mean (importance 0-1, a label, optionally the sound) and the tool keeps the timing: the nearest motion cue takes the importance and keeps its frame-exact time; an event with no motion becomes its own cue; importance 0 keeps a moment quiet. The meaning comes from the model and the timing from the rules, which a music and sound-effects planner needs.duck_musicdips: stretches of near-silence, e.g. 0.35 s before a reveal (measured live: -100 dB through the pause, then the impact). A dips-only call keeps the ducks as they are.set_layeraudio_fade(in / out seconds) andsequence_layersaudio_crossfade: equal-power fades, so one music cue crossfades into the next without a dip in level (measured live: within 0.4 dB through a 2 s crossfade).
Changed
staggerandshift_layerssay which one moves keys and which moves whole layers, and point tosequence_layers.duck_musicducks by -6 dB by default (was -10): the usual range under narration is 4-8 dB.find_sound_cuesranks cuts low on their own, so a hit on every cut is no longer the default; story events raise the cuts that matter.- Volume keys can be set under the ducking expression (
set_keyframesrefused them, and its hint said to clear the expression, which removed the ducking). Springs are still refused there, since they would replace it.
Fixed
set_textwith new text now says when it removed part styling (ranges_cleared: true): After Effects gives every character the first one's style when the text changes. Passing the same text no longer reassigns it, so part styling survives.find_sound_cuescues a scale pop when the layer arrives (97% of the way), not at its last key: with a spring or snappy ease the last key is where it only settles, up to 15 frames after the hit. An entrance that pops and fades in is now one cue instead of two competing ones. Found by building a 12-second documentary reveal and checking where the impact belongs.- The after-render check no longer calls a dark title card with a line of text a black picture (and no longer suggests a GPU failure for it): a frame now counts as black only when 99.9% of it is dark.
2.18.0
Added
set_propertytakeslayer_ids: the same value on many layers in one call (13 coins, 10 ingots), every layer checked before any changes.save_projectsnapshot: true(with an optionalnote) keeps a numbered copy insnapshots/next to the project, so going back to an earlier version isopen_projecton that copy instead of rebuilding it from memory.render_startstart/end(seconds) render part of a comp, anddraft: trueuses the Draft Settings template: a quick moving preview of a few seconds, wherepreview_frameonly shows stills.preview_framenames the scene each frame shows in an edit (scene, orscenesfor a contact sheet): the top precomp playing at that time.add_layer_styleaccepts the Layer Style panel's labels where the match name differs:size(blur),spread/choke,angle,altitude,blend_mode,range,technique.
Fixed
render_startalways passes the comp's frame range toaerender, and a finished file shorter than that fails the job. A render once stopped at 54 of 2,422 frames, exited 0 and was reported as done with a clean check.- A new text layer no longer inherits the last text's character settings (After Effects takes the Character panel's current ones):
add_layerstarts text from tracking 0, no faux styles or caps, auto leading, 100% scale, before anytext_style. set_track_matteandadd_layer_stylewarn when a 3D layer has layer styles: After Effects then ignores its track matte and draws it in stacking order instead of by depth (verified live; even a style switched off does it).review_motionchecks text against the title-safe margin on its last frame too, not only mid-way: camera pushes carried titles out of frame by the end, where the check never looked.batch: a"$N.path"reference inside an array (e.g.layer_ids: ["$1.id", "$2.id"]) was rejected by the pre-check ("expected number, received string") although it resolves to a number when the step runs. Zod reports array positions as numbers and the comparison only matched strings.
2.17.0
Added
animatemoves for holds:push(a slow scale-up, default 4%) anddrift(a slow float), from where a layer's animation lands to its out point, keeping the landing's ease (a spring still lands exactly). In review, frozen holds after the build were the most common flaw.- Design rules for the model in the server instructions and
motion-guide, as a senior motion designer and video editor would work: sizes relative to the comp's short side so they fit landscape, vertical (9:16 social) and square; the safe areas social apps cover; copy kept exactly as given; timing (move within 0.2 s, finish the build by 40%), keeping holds alive, polish (soft-edged glows, depth, one accent colour); and for footage: cutting on action or the beat, shot lengths, hooks, trimming dead air, b-roll over jump cuts, framing and reframing for vertical, text over video and captions, sound levels and delivery loudness. review_motionchecks: a late first move (after 0.3 s); changes too small to see no longer count as motion, so a wobbling layer still shows as a hold; text crossing the 5% title-safe margin, or in vertical comps the top 10% and bottom 20% that social apps cover; small text judged against 3% of the comp's short side (was 2.2% of its height).
Changed
preview_frameis 5-7 times faster: about 0.1 s per frame instead of 0.6 s, 0.2 s for a six-frame sheet instead of about 3 s. It returns as soon as the PNG is complete (its IEND chunk) instead of polling the size in 150 ms steps, and renders at the coarsest resolution that still covers the returned image instead of always at full resolution.get_projectlists each comp's layers (unless the project has over 300), andset_keyframesreturns the keys as set, so a model needs fewer calls; the server instructions ask it to make independent calls together and not to re-read what a result already shows.
Fixed
get_projectworks on big projects: it used to stop at 500 items and, past roughly 300 items with real file names, went over the size limit and failed with no way to ask for less. It now takesname(substring) andtypefilters and pages withlimit(default 200) /offset, reportingmatchedandnext_offsetlikeget_comp(thetruncatedfield is gone). The 300-layer limit for listing each comp's layers now counts the comps on the returned page, so paging also brings layers back on big projects.list_markerspages withlimit(default 100) /offsetand returnsnext_offset, instead of stopping at 500 markers.set_playheadandset_3d_vieware no longer marked destructive: they only change the viewer.- The update instructions
get_projectandcheck_for_updatesgive for updating by hand saidgit pull, which fails in the state the panel's Update button leaves the repo in (a release tag, not a branch). They now saynode scripts/update.ts, which checks out the newest release and runs the installer. set_light'spoint_of_interestwas described as where a camera looks.- Errors that left the model guessing now say what to do: an unknown
blend_modelists the valid names, an unknown render job explains that jobs are forgotten when the MCP server restarts, a marker property points to the marker tools (notrun_jsx), and "not keyframable", "does not support expressions", a missing preset and failed menu commands (text_to_shapes,add_layer_style) have hints. - The
ae://projectandae://selectionresources return compact JSON, and a failed read is now a resources/read error (with the code and hint) instead of the error body returned as if it were the resource.
Removed
- The evaluations (
evals/): the question and build-task runs through headless Claude Code. The live tests (test/live/run.ts) stay. - The hard limit on the size of the tool definitions (
npm testprints the size instead).
2.16.0
Changed
- Back to the 2.13.0 code: everything from 2.14.0 and 2.15.0 is undone (the compact schemas,
run_jsxhidden when disabled, the core-toolset default and its reversal, the six extra build evaluations, the splitreview.ts/sound.tshost files, the constant-time token check, and the removed tool-list budget). Reopen the panel after updating. The undone work is kept in the git history and on thebackup-speed-qualitybranch.
2.15.0
Changed
- All tools are loaded by default again (
AE_MCP_TOOLSETS=coreis still there to opt in). With core as the default (2.14.0) the evals kept their scores on about 40% fewer input tokens, but cost only 2-8% less, because most of the input is cached and cached tokens are cheap, and ran 12-20% slower; and the model rebuilt camera moves, alignment and 3D settings from keyframes instead of loadingcamera_move,align_layersandset_3d. The smaller schemas and the hiddenrun_jsxfrom 2.14.0 stay: they cut 5-7% of the tokens with no such side effect. - No hard limit on the size of the tool definitions any more (
npm testprints it).