@synthetic-ai/ae-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,35 @@
1
+ PROPRIETARY SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2025 Synthetic (synthetic.com.ar). All rights reserved.
4
+
5
+ NOTICE: This software and its source code are proprietary and confidential
6
+ intellectual property of Synthetic. Access to this software is granted
7
+ exclusively through a valid commercial license purchased at synthetic.com.ar.
8
+
9
+ PERMITTED USE:
10
+ - You may use this software solely for your own internal business purposes
11
+ while you maintain an active, paid license subscription.
12
+ - You may install this software on the number of machines permitted by your
13
+ license tier.
14
+
15
+ PROHIBITED:
16
+ - Copying, reproducing, or distributing this software or any portion thereof
17
+ without prior written consent from Synthetic.
18
+ - Sublicensing, selling, reselling, renting, lending, or transferring this
19
+ software to any third party.
20
+ - Reverse engineering, decompiling, or disassembling this software.
21
+ - Removing or altering any copyright, trademark, or proprietary notices.
22
+ - Using this software after your license subscription has expired or been
23
+ terminated.
24
+
25
+ TERMINATION:
26
+ This license is effective until terminated. It will terminate automatically
27
+ if you fail to comply with any term of this agreement. Upon termination, you
28
+ must destroy all copies of this software in your possession.
29
+
30
+ DISCLAIMER:
31
+ THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. SYNTHETIC
32
+ SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING FROM USE OF THIS SOFTWARE.
33
+
34
+ For licensing inquiries: hello@synthetic.com.ar
35
+ Website: https://synthetic.com.ar
package/README.md ADDED
@@ -0,0 +1,441 @@
1
+ # Synthetic After Effects MCP
2
+
3
+ > A product by **[Synthetic](https://synthetic.com.ar)** — AI tools for motion designers.
4
+
5
+ Local MCP server for controlling Adobe After Effects from any MCP-compatible tool. **220+ tools.** No external npm packages required — communicates via JSON-RPC over `stdio`, using `AfterFX.exe` and `aerender.exe`.
6
+
7
+ **Get a license:** https://synthetic.com.ar/pricing
8
+ **Dashboard:** https://synthetic.com.ar/dashboard
9
+ **Docs:** https://docs.synthetic.com.ar
10
+
11
+ ## Quick start
12
+
13
+ ### 1. Register the server
14
+
15
+ Add to your MCP client config (e.g. `claude_desktop_config.json`):
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "after-effects": {
21
+ "command": "node",
22
+ "args": ["C:\\path\\to\\after-effects-mcp\\src\\server.mjs"]
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ ### 2. Enable script file access in After Effects
29
+
30
+ `Edit > Preferences > Scripting & Expressions > Allow Scripts to Write Files and Access Network`
31
+
32
+ Without this, JSX cannot write the temporary result files the MCP uses.
33
+
34
+ ### 3. Verify
35
+
36
+ ```powershell
37
+ node --check src\server.mjs
38
+ node scripts\inspect-tools.mjs
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Requirements
44
+
45
+ - **Node.js** ≥ 18
46
+ - **Adobe After Effects** CS6 through 2026 (desktop app must be running for most tools)
47
+ - **Windows** (uses `AfterFX.exe` and `aerender.exe`)
48
+
49
+ ---
50
+
51
+ ## Installation detection
52
+
53
+ The server auto-detects After Effects from these default install roots (CS6 through 2026):
54
+
55
+ ```
56
+ C:\Program Files\Adobe\Adobe After Effects 2026
57
+ C:\Program Files\Adobe\Adobe After Effects 2025
58
+ C:\Program Files\Adobe\Adobe After Effects 2024
59
+ ...
60
+ C:\Program Files\Adobe\Adobe After Effects CS6
61
+ C:\Program Files\Adobe\Adobe After Effects (Beta)
62
+ ```
63
+
64
+ To override, set environment variables before starting the MCP server:
65
+
66
+ ```powershell
67
+ $env:AE_AFTERFX_PATH = "C:\Program Files\Adobe\Adobe After Effects 2025\Support Files\AfterFX.exe"
68
+ $env:AE_AERENDER_PATH = "C:\Program Files\Adobe\Adobe After Effects 2025\Support Files\aerender.exe"
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Tools (220)
74
+
75
+ ### Diagnostics
76
+
77
+ | Tool | Description |
78
+ |------|-------------|
79
+ | `ae_info` | Detect installed After Effects executables. |
80
+ | `ae_healthcheck` | Validate binaries, temp write access, and aerender version. |
81
+ | `ae_dialogs` | List or close visible After Effects modal dialogs (Windows UI Automation). |
82
+ | `get_recent_errors` | Return the last tool error captured by the server. |
83
+ | `get_ae_version` | Detect the running AE version, build number, and feature availability. |
84
+
85
+ ---
86
+
87
+ ### Project management
88
+
89
+ | Tool | Description |
90
+ |------|-------------|
91
+ | `project_info` | Summary of the current project (items, comps, render queue). |
92
+ | `new_project` | Create a new project, optionally save it. |
93
+ | `open_project` | Open an `.aep` file. |
94
+ | `save_project` | Save the current project in place. |
95
+ | `save_project_as` | Save to an explicit path. |
96
+ | `close_project` | Close with explicit save policy (`save`, `do_not_save`, `prompt`). |
97
+ | `set_project_color_settings` | Set bits per channel (8/16/32) and working color space. |
98
+ | `purge_caches` | Purge AE memory and/or disk image caches. |
99
+ | `get_project_settings` | Read project-level settings: color depth, time display, audio sample rate, and expression engine. |
100
+ | `set_project_settings` | Set project-level settings: color depth, time display, and expression engine. |
101
+ | `reduce_project` | Remove unused footage items and comps (File > Reduce Project). |
102
+ | `consolidate_footage` | Remove duplicate footage items (consolidate to a single instance). |
103
+ | `collect_files` | Collect the project and all footage into a folder (File > Collect Files). |
104
+ | `undo` | Undo the last operation in After Effects. |
105
+ | `redo` | Redo the last undone operation. |
106
+ | `get_preferences` | Read After Effects preferences (section + key). |
107
+ | `set_preference` | Write an After Effects preference value (section + key). |
108
+
109
+ ---
110
+
111
+ ### Project panel
112
+
113
+ | Tool | Description |
114
+ |------|-------------|
115
+ | `list_project_items` | List all items with metadata. |
116
+ | `find_project_items` | Search by name, type, parent folder, or missing state. |
117
+ | `create_folder` | Create a folder in the project panel. |
118
+ | `rename_item` | Rename any item by id or name. |
119
+ | `move_items_to_folder` | Move items into a folder. |
120
+ | `duplicate_item` | Duplicate comps and footage items. |
121
+ | `delete_items` | Delete items (requires `confirm: true`). |
122
+ | `set_item_label` | Set the label color of a project item. |
123
+ | `set_item_comment` | Set the comment string on a project item (footage, comp, or folder). |
124
+
125
+ ---
126
+
127
+ ### Compositions
128
+
129
+ | Tool | Description |
130
+ |------|-------------|
131
+ | `list_comps` | List all compositions. |
132
+ | `create_comp` | Create a composition. |
133
+ | `get_comp_info` | Detailed comp settings, renderers, markers, and layer summaries. |
134
+ | `update_comp_settings` | Change dimensions, duration, frame rate, background, work area. |
135
+ | `duplicate_comp` | Duplicate a composition. |
136
+ | `delete_comp` | Delete a composition. |
137
+ | `set_comp_renderer` | Set the renderer (Classic 3D, CINEMA 4D, or GPU Accelerated). |
138
+ | `set_comp_bg_color` | Set the background color of a composition. |
139
+ | `set_comp_work_area` | Set the work area in/out points without recreating the comp. |
140
+ | `trim_comp_to_work_area` | Trim a composition to its work area. |
141
+ | `list_comp_markers` | List all markers on a composition. |
142
+ | `add_comp_marker` | Add a marker to a composition timeline. |
143
+ | `remove_comp_marker` | Remove a composition marker by index or time. |
144
+ | `update_comp_marker` | Edit an existing composition marker (comment, duration, chapter, url). |
145
+ | `add_guide` | Add a guide to a composition (horizontal or vertical). |
146
+ | `list_guides` | List all guides in a composition. |
147
+ | `remove_guide` | Remove a specific guide by its 0-based index. |
148
+ | `clear_guides` | Remove all guides from a composition. |
149
+
150
+ ---
151
+
152
+ ### Layers
153
+
154
+ | Tool | Description |
155
+ |------|-------------|
156
+ | `list_layers` | List layers in a composition. |
157
+ | `get_layer_info` | Extended info: transforms, switches, blend mode, parent, in/out points. |
158
+ | `add_solid_layer` | Add a solid layer. |
159
+ | `add_null_layer` | Add a null object. |
160
+ | `add_camera_layer` | Add a camera. |
161
+ | `add_light_layer` | Add a light. |
162
+ | `add_adjustment_layer` | Add an adjustment layer. |
163
+ | `add_text_layer` | Add a text layer. |
164
+ | `add_shape_layer` | Add a shape layer (rect, ellipse, polygon, star, path). |
165
+ | `add_footage_layer` | Add imported footage as a layer. |
166
+ | `duplicate_layer` | Duplicate a layer. |
167
+ | `delete_layers` | Delete one or more layers. |
168
+ | `rename_layer` | Rename a layer. |
169
+ | `reorder_layer` | Move a layer to before/after/beginning/end/index. |
170
+ | `parent_layer` | Set or clear a layer parent. |
171
+ | `clone_layer_to_comp` | Copy a layer from a source comp into a different target comp. |
172
+ | `split_layer` | Split a layer at a given time (like Ctrl+Shift+D). |
173
+ | `sequence_layers` | Sequence layers in time so each starts after the previous ends (with optional overlap). |
174
+ | `set_layer_timing` | Set start/in/out/stretch. |
175
+ | `set_layer_switches` | enabled, shy, solo, locked, guide, 3D, motionBlur, adjustment. |
176
+ | `set_blending_mode` | Set blending mode by name (NORMAL, ADD, SCREEN, MULTIPLY, …). |
177
+ | `get_layer_blend_mode` | Return the current blending mode of a layer as a string. |
178
+ | `set_frame_blend_mode` | Set frame blending mode (none, frame_mix, pixel_motion). |
179
+ | `set_track_matte` | Set track matte type and mode on a layer. |
180
+ | `get_layer_track_matte` | Read track matte type and mode from a layer. |
181
+ | `set_layer_label` | Set the label color of a layer. |
182
+ | `precompose_layers` | Precompose selected layers into a new composition. |
183
+ | `auto_orient_layer` | Set auto-orientation mode (off, along path, camera, or characters). |
184
+ | `set_layer_quality` | Set render quality (best, draft, or wireframe). |
185
+ | `set_layer_sampling` | Set sampling quality (bilinear or bicubic). AE 2022+ only. |
186
+ | `set_layer_collapse` | Enable/disable Collapse Transformations / Continuously Rasterize. |
187
+ | `set_environment_layer` | Toggle the environment layer flag on a 3D layer. |
188
+ | `list_layer_markers` | List all markers on a layer. |
189
+ | `add_layer_marker` | Add a marker to a layer. |
190
+ | `remove_layer_marker` | Remove a layer marker by index or time. |
191
+ | `update_layer_marker` | Edit an existing layer marker (comment, duration, chapter, url). |
192
+ | `add_layer_style` | Add a layer style (drop shadow, outer glow, bevel, stroke, etc.). |
193
+ | `set_layer_style_property` | Set a property value inside a layer style (e.g. shadow distance, opacity, color). |
194
+ | `list_layer_styles` | List all layer styles applied to a layer. |
195
+ | `enable_layer_style` | Enable or disable a specific layer style. |
196
+ | `get_layer_audio` | Read audio levels and mute state of a layer. |
197
+ | `set_layer_audio` | Set audio levels and mute state of a layer. |
198
+
199
+ ---
200
+
201
+ ### Transform & 3D
202
+
203
+ | Tool | Description |
204
+ |------|-------------|
205
+ | `set_transform` | Position, scale, rotation, opacity, anchor point. |
206
+ | `get_transform` | Read current transform values at a given time. |
207
+ | `set_3d_transform` | 3D position, orientation, X/Y/Z rotation, scale. |
208
+ | `set_camera_options` | Zoom, depth of field, focus distance, aperture, blur level. |
209
+ | `set_camera_dof` | Enable/disable depth-of-field and set focus distance, aperture, blur level. |
210
+ | `list_lights_cameras` | List all camera and light layers in a comp with their settings. |
211
+ | `set_light_options` | Intensity, color, cone angle/feather, shadow darkness/diffusion. |
212
+ | `set_material_options` | Cast/accept shadows, accept lights, ambient, diffuse, specular. |
213
+ | `get_spatial_tangents` | Get spatial bezier in/out tangent handles for all keys of a position property. |
214
+ | `set_spatial_tangents` | Set spatial bezier in/out tangent handles for a specific keyframe. |
215
+
216
+ ---
217
+
218
+ ### Text
219
+
220
+ | Tool | Description |
221
+ |------|-------------|
222
+ | `set_text_layer` | Change text content. |
223
+ | `set_text_style` | Set font, size, color, tracking, leading, stroke, justification. |
224
+ | `set_text_style_range` | Apply style to a specific character range (AE CC 2019+). |
225
+ | `get_text_document` | Read full TextDocument details. |
226
+ | `set_text_box` | Set box text dimensions and position, or convert point text to box text. |
227
+ | `set_text_justification` | Set paragraph justification (left, center, right, full). |
228
+ | `add_text_animator` | Add a text animator with a range selector to a text layer. |
229
+ | `list_text_animators` | List all text animators on a text layer. |
230
+ | `set_text_selector` | Configure the range selector on a text animator (start, end, offset). |
231
+ | `remove_text_animator` | Remove a text animator by name or 1-based index. |
232
+ | `set_text_animator_property` | Set the animated value on an existing text animator (color, tracking, scale, opacity, …). |
233
+
234
+ ---
235
+
236
+ ### Shapes & masks
237
+
238
+ | Tool | Description |
239
+ |------|-------------|
240
+ | `list_shape_groups` | List shape groups inside a shape layer. |
241
+ | `add_shape_group` | Add a new shape group (rect, ellipse, polygon, star, or path) to a shape layer. |
242
+ | `remove_shape_group` | Remove a shape group by name or index. |
243
+ | `set_shape_fill` | Set or add the first fill in a shape layer. |
244
+ | `set_shape_stroke` | Set or add the first stroke in a shape layer. |
245
+ | `set_gradient_fill` | Add or update a gradient fill on a shape group. |
246
+ | `set_trim_paths` | Set Trim Paths (start, end, offset) on a shape group. |
247
+ | `set_repeater` | Add or update a Repeater operator on a shape group (copies, offset, transform). |
248
+ | `set_merge_paths` | Add or set a Merge Paths operator on a shape group. |
249
+ | `get_shape_vertices` | Read vertices, inTangents, outTangents, and closed state of a shape path. |
250
+ | `set_shape_vertices` | Set vertices, inTangents, outTangents and closed state of a shape path. |
251
+ | `add_shape_operator` | Add trim_paths, repeater, merge_paths, offset_paths, or wiggle_paths. |
252
+ | `list_masks` | List all masks on a layer. |
253
+ | `add_mask` | Add a mask to a layer. |
254
+ | `set_mask_mode` | Set mask mode (add, subtract, intersect, etc.). |
255
+ | `set_mask_feather_opacity_expansion` | Set mask feather, opacity, and expansion. |
256
+ | `set_mask_path` | Set mask shape vertices by index. |
257
+ | `add_mask_path_keyframe` | Add a keyframe to a mask path property. |
258
+ | `delete_mask` | Delete a mask by name or index. |
259
+ | `set_mask_name` | Rename a mask on a layer. |
260
+ | `lock_mask` | Lock or unlock a mask. |
261
+
262
+ ---
263
+
264
+ ### Properties, keyframes & expressions
265
+
266
+ | Tool | Description |
267
+ |------|-------------|
268
+ | `get_property_tree` | Inspect a layer's full property tree. |
269
+ | `get_property_value` | Read a property value by path. |
270
+ | `set_property_value` | Set a property value by path. |
271
+ | `get_all_property_values` | Read values of multiple properties in a single call. |
272
+ | `set_keyframes` | Write multiple keyframes to a property. |
273
+ | `list_keyframes` | List keyframes with time, value, and interpolation. |
274
+ | `remove_keyframes` | Remove keyframes by index, time range, or all. |
275
+ | `set_keyframe_interpolation` | Set temporal interpolation (linear, bezier, hold). |
276
+ | `set_keyframe_ease` | Set ease speed/influence on keyframes. |
277
+ | `set_keyframe_hold` | Convert keyframes to hold (step) interpolation. |
278
+ | `set_keyframe_roving` | Enable or disable roving-through-space on spatial keyframes. |
279
+ | `copy_keyframes` | Copy keyframes from one property to another, with optional time offset. |
280
+ | `reverse_keyframes` | Reverse the temporal order of all keyframes on a property. |
281
+ | `batch_keyframe_offset` | Shift all keyframes on specified layers by a time offset. |
282
+ | `set_expression` | Set an expression on a property. |
283
+ | `get_expression` | Read the expression string on a property. |
284
+ | `toggle_expression` | Enable or disable an expression on a property. |
285
+ | `bake_expression` | Sample and bake expression values to keyframes. |
286
+ | `get_expression_globals` | Extract all expressions from all layers in a comp. |
287
+ | `list_expression_errors` | List all layers and properties that have expression errors. |
288
+ | `enable_time_remap` | Enable time remapping on a layer (with keyframes). |
289
+ | `link_property_expression` | Link a layer property to another layer's property via expression. |
290
+
291
+ ---
292
+
293
+ ### Effects
294
+
295
+ | Tool | Description |
296
+ |------|-------------|
297
+ | `list_layer_effects` | List effects on a layer. |
298
+ | `add_effect` | Add an effect by match name. |
299
+ | `set_effect_property` | Set an effect parameter. |
300
+ | `remove_effect` | Remove an effect by name, match name, or index. |
301
+ | `reorder_effect` | Move an effect up or down in the effect stack. |
302
+ | `enable_effect` | Enable or disable (mute) an effect without removing it. |
303
+ | `copy_effect` | Duplicate an effect on the same layer. |
304
+ | `copy_effect_to_layer` | Copy an effect from a source layer to a destination layer, optionally in a different comp. |
305
+ | `batch_add_effect` | Add the same effect to multiple layers in a single call. |
306
+ | `batch_apply_ffx` | Apply an animation preset (`.ffx` file) to multiple layers. |
307
+
308
+ ---
309
+
310
+ ### Footage & import
311
+
312
+ | Tool | Description |
313
+ |------|-------------|
314
+ | `import_file` | Import a file or image sequence. |
315
+ | `import_sequence` | Import a numbered image sequence. |
316
+ | `import_folder` | Import files from a folder with optional extension filter. |
317
+ | `import_placeholder` | Create a placeholder footage item. |
318
+ | `import_solid` | Create a native solid footage item. |
319
+ | `list_missing_footage` | Report missing footage. |
320
+ | `relink_missing_footage` | Relink missing footage by filename search. |
321
+ | `set_proxy` | Set a proxy on a footage item. |
322
+ | `clear_proxy` | Clear the proxy from a footage item. |
323
+ | `interpret_footage` | Set alpha mode, conform frame rate, loop count. |
324
+ | `collect_asset_report` | JSON report of assets, missing items, proxies, and comp usage. |
325
+ | `replace_footage` | Replace a footage item's source file. |
326
+ | `batch_replace_footage` | Replace multiple footage items by mapping filename patterns to new paths. |
327
+ | `set_alpha_mode` | Set the alpha interpretation (ignore, straight, premultiplied). |
328
+ | `set_footage_fields` | Set field order for interlaced footage. |
329
+ | `set_footage_color_profile` | Assign a color profile / ICC profile to a footage item. |
330
+ | `set_footage_loop` | Set how many times a footage item loops. |
331
+ | `set_footage_pixel_aspect` | Override the pixel aspect ratio of a footage item. |
332
+
333
+ ---
334
+
335
+ ### Render & output
336
+
337
+ | Tool | Description |
338
+ |------|-------------|
339
+ | `add_to_render_queue` | Add a composition to the render queue. |
340
+ | `add_comps_to_render_queue` | Add multiple compositions to the render queue in a single call. |
341
+ | `list_render_queue` | List render queue items. |
342
+ | `set_render_queue_output` | Set output module template and/or path on a render queue item. |
343
+ | `set_render_settings` | Set render settings (quality, resolution, frame blending, motion blur). |
344
+ | `set_output_module` | Configure the output module (format, channels, depth, color). |
345
+ | `remove_render_queue_item` | Remove an item from the render queue. |
346
+ | `clear_render_queue` | Remove all items from the render queue. |
347
+ | `duplicate_render_item` | Duplicate a render queue item. |
348
+ | `set_rq_item_enabled` | Enable or disable (queue/dequeue) a render queue item. |
349
+ | `list_render_templates` | List available render settings and output module templates. |
350
+ | `apply_render_template` | Apply a named render settings and/or output module template to a queue item. |
351
+ | `list_output_modules` | List the output modules configured on a render queue item. |
352
+ | `render_project_queue` | Render the existing queue with `aerender.exe`. |
353
+ | `render_comp` | Render a composition with `aerender.exe`. |
354
+ | `render_comp_range` | Render a frame range with `aerender.exe`. |
355
+ | `validate_render_output` | Check that a render file exists and has minimum size. |
356
+ | `export_frame` | Export a single frame from a composition as PNG/JPEG/TIFF. |
357
+ | `get_render_status` | Get the current status and progress of all items in the render queue. |
358
+ | `cancel_render` | Stop/cancel any currently running render. |
359
+
360
+ ---
361
+
362
+ ### Essential Graphics (MOGRT)
363
+
364
+ | Tool | Description |
365
+ |------|-------------|
366
+ | `set_mogrt_name` | Set a composition Motion Graphics Template name. |
367
+ | `set_mogrt_comment` | Set the comment/description on the Essential Graphics template. |
368
+ | `set_mogrt_property_range` | Set the min/max range (slider bounds) for a numeric MOGRT controller. |
369
+ | `list_mogrt_controllers` | List Essential Graphics controllers. |
370
+ | `add_property_to_mogrt` | Add a property to Essential Graphics. |
371
+ | `remove_property_from_mogrt` | Remove a property from the Essential Graphics panel. |
372
+ | `rename_mogrt_controller` | Rename a controller by index. |
373
+ | `set_mogrt_controller_value` | Set the value of a property exposed in the Essential Graphics panel. |
374
+ | `export_mogrt` | Export a composition as a MOGRT file. |
375
+
376
+ ---
377
+
378
+ ### Batch operations
379
+
380
+ | Tool | Description |
381
+ |------|-------------|
382
+ | `batch_replace_text` | Find and replace text across all text layers in one or more comps. |
383
+ | `batch_rename_layers` | Rename multiple layers using a pattern, find-and-replace, or numeric sequence. |
384
+ | `batch_set_expression` | Set the same expression on a property across multiple layers. |
385
+ | `batch_set_layer_property` | Set the same property value on multiple layers in a single call. |
386
+ | `batch_add_effect` | Add the same effect to multiple layers in a single call. |
387
+ | `batch_apply_ffx` | Apply an animation preset (`.ffx`) to multiple layers. |
388
+ | `batch_set_transform` | Set transform properties across multiple layers, optionally filtered by name pattern. |
389
+ | `batch_replace_footage` | Replace multiple footage items by mapping filename patterns to new paths. |
390
+ | `batch_keyframe_offset` | Shift all keyframes on specified layers by a time offset. |
391
+
392
+ ---
393
+
394
+ ### Utilities
395
+
396
+ | Tool | Description |
397
+ |------|-------------|
398
+ | `run_jsx` | Run raw ExtendScript/JSX in After Effects. |
399
+ | `run_jsx_json` | Run JSX inside the shared JSON wrapper and return parsed JSON. |
400
+
401
+ ---
402
+
403
+ ## Smoke tests
404
+
405
+ Run the full suite (After Effects cannot handle parallel script invocations, so run in series):
406
+
407
+ ```powershell
408
+ node scripts\smoke-suite.mjs
409
+ ```
410
+
411
+ Individual test modules:
412
+
413
+ | Module | Coverage |
414
+ |--------|----------|
415
+ | `smoke-core-tools.mjs` | Diagnostics and project basics |
416
+ | `smoke-project-items.mjs` | Project panel operations |
417
+ | `smoke-comp-layer-advanced.mjs` | Compositions and layers |
418
+ | `smoke-property-keyframes-pro.mjs` | Properties, keyframes, expressions |
419
+ | `smoke-shapes-masks.mjs` | Shapes and masks |
420
+ | `smoke-effects-expressions.mjs` | Effects and expressions |
421
+ | `smoke-footage-tools.mjs` | Footage import and management |
422
+ | `smoke-media-render-queue.mjs` | Render queue and output |
423
+ | `smoke-mogrt-tools.mjs` | Essential Graphics |
424
+
425
+ ---
426
+
427
+ ## Architecture notes
428
+
429
+ - `run_jsx` and most tools control the desktop app via `AfterFX.exe -r script.jsx`.
430
+ - `render_comp` and `render_project_queue` use `aerender.exe` — the most reliable path for headless rendering.
431
+ - The server serializes all JSX executions with a global lock — no concurrent script conflicts.
432
+ - All JSX is ES3/ES5-compatible (ExtendScript engine): no arrow functions, no template literals, no destructuring.
433
+ - If the dialog `"A second script attempted to execute..."` appears, the previous script is still running. The lock prevents this in normal use.
434
+ - To inspect or close AE dialogs without screenshots: `ae_dialogs { mode: "list" }` or `{ mode: "close" }`.
435
+ - `render_comp_range` returns `actualOutputPath` because After Effects may change the file extension based on the active output module.
436
+
437
+ ---
438
+
439
+ ## License
440
+
441
+ MIT — see [LICENSE](LICENSE).