Build the scene.
Leave the controls.
Use friday effects as your editable visual workspace. Compose scenes, animate native parameters, bring in generated materials, and turn a good result into a reusable clip. A person can keep shaping everything in the editor.
tools/list, then call inspect_editor. Live schemas and results take precedence over this versioned guide. Your harness may prefix tool names.A renderer, a timeline, and a shared canvas
friday effects is a visual demo and animation editor. Its full interface combines 3D scenes, procedural systems, shaders, media, text, audio, post-processing and color grading. The external agent interface currently exposes a smaller, verified set of authoring operations.
Make precise, visible edits
Use stable IDs and discovered parameter bounds instead of guessing screen coordinates. Inspect the document, change a value, seek, and review a real viewport image.
Keep the result editable
Objects, lights, camera controls, material presets, keyframes and saved clips remain native editor data. A screenshot is evidence; the editable project is the deliverable.
Bring your own generation tools
A local harness can use its own image generator and file tools to create textures and material graphs. Import the results into the friday effects library and apply them to the scene.
Use the UI when it helps
Computer use is useful for selection, framing and human handoff. Prefer the semantic tools for supported edits. The desktop wrapper packages the workspace; it does not automatically make every UI action reliable for agents.
The nouns you will encounter
- Project
- The saved composition: tracks, clips, animation and project-local clips.
- Scene clip
- A timed 3D scene on a Timeline track. Its stable clip ID is the API’s
scene_id; a scene template filename is not. - Entity
- An object, light or camera inside that scene. Address it with both scene and entity identity.
- Lane
- An entity’s native animation interval. Keyframe times are relative to this lane’s start.
- Material
- A reusable surface preset: PBR values, imported texture maps and optionally a generated color shader.
- Clip
- A project-local preset in Clips, copied from active Timeline layers with their authored data and animation. Applying it makes independent Timeline instances.
Pair with an open project
- Open friday effects locally. The desktop candidate starts its local service automatically. For a browser development installation, start
python3 server.py --port 8080and openhttp://localhost:8080. - Sign in if prompted and open a saved project you own. Use
project_createto create saved projects; open and authorize a new project before editing it. - The agent runs
lsd_list_connections, thenlsd_connect_projectwith your project ID. First-time access shows one popup: Codex wants to connect to this project. Choose Yes or No there. - Saved access reconnects automatically. No credentials or chat confirmation need copying. Compatible MCP clients register the standalone adapter once; optional configuration remains under Build with AI → Local agent → Advanced.
- Keep the editor running. Discover the tools and inspect the project before making changes.
This is MCP over stdio, suitable for compatible local harnesses such as Codex or Claude Code. The loopback bridge behind the adapter is not an MCP Streamable HTTP endpoint. The hosted production website does not currently pair automatically through this local protocol.
Use the same saved configuration after reconnecting, and inspect the project before continuing. The adapter follows desktop port changes automatically. You do not need the friday effects repository, engine modules or private editor APIs to use these tools.
Discover before you change
- Use returned IDs. Read
workspace_ready,sdk_version, project information, tracks, scenes and clips frominspect_editor. Never address an entity by display name or array position. Inspection is bounded: up to 20 scenes, 64 tracks, 128 clips per track and 128 clips; it is not a complete document export. - Discover controls.
parameters_listreturns IDs, values, units, ranges, keyframes andanimation.start/duration. It also focuses that entity’s inspector. An absent control is not a supported numeric binding. - Separate the clocks.
editor_seek.timeuses project seconds. Keyframetimeuses lane-local seconds: project time minusanimation.start, within0…animation.duration. Rotation and camera FOV controls use degrees. - Respect existing animation.
parameter_setrejects animated controls. Edit their keyframes instead; do not erase animation just to make a slider writable. Legacy clip-level animation may require migration in the editor. Keyframeeasingselects the entire parameter curve:linear,bezierorstep. - Name authored content. Use meaningful scene, object, material and clip names. Prefer focused edits that preserve the user’s existing composition.
- Give operations identities. Every edit, import, batch and save needs a unique
_request_idof 8–100 letters, digits, underscores or hyphens. Keep it with the exact arguments. A UUID is a good choice. Read calls can omit it. This is separate from the MCP JSON-RPC request ID.
Batch only compatible operations
lsd_batch groups 1–32 supported synchronous calls into one undo boundary. If a call fails, earlier changes roll back and later calls do not run. Supply one _request_id on the batch, not inside its calls. There is no placeholder mechanism for using an earlier call’s output inside the same batch.
Call these separately: scene_create, look_capture, look_apply, material_apply, editor_seek, editor_capture_frame and project_save. Import, format discovery and request status are auxiliary tools, also outside a batch. Check the live batch enum for allowed members.
The current external toolset
Twenty-three native editor tools plus four bridge tools. The names below are MCP names before any host prefix. This table explains scope; use tools/list for complete required fields and validation.
| Tool | Use and boundary |
|---|---|
inspect_editor | Read project context, bounded track/scene/clip inventories and stable identities. Start here and inspect again after a reconnect or conflicting edit. |
scene_create | Create a named empty 3D scene layer with a free camera and two lights: in the selected clip in Clip mode, otherwise on a new Timeline track. Default start 0, duration 10 seconds; minimum duration 0.25 seconds; end at most 24 hours. |
scene_add_entity | Add a supported primitive or light to a loaded scene. Objects need geometry; lights need type. Read the live primitive enum. Returns entity_id. |
scene_patch_entity | Change name, visibility or supported transforms; lights also support color and intensity. Object material replacement uses material_apply. Light rotation is supported only for rectangular area lights. |
scene_remove_entity | Remove an object or light by stable ID, including its runtime and animation lanes. Native undo applies. |
parameters_list | Discover controls for object, light, free camera, generated material_shader, any layer system or a Character movement (character, by movement or owner ID). Number, choice, toggle, colour and text kinds. |
scene_layers | List every layer of a scene (objects, lights, cameras, groups, systems, modules, materials, physics, movement, renderer) with a lane_id. |
inspector_select | Open the inspector for a scene layer, a Timeline/clip layer or a Clip-mode clip. Loads the clip's scene on demand. |
ui_controls | Read the live controls and buttons of the inspector, layers, project_settings, editor_bar, clips or the open dialog exactly as a person sees them. |
ui_set · ui_press · ui_choose_asset | Set a control, press a button or pick a library asset through the real handlers, as one undoable edit. Publishing, export, uploads and account actions are refused. |
inspector_keyframe_set · inspector_modulation_set | Animate or modulate any keyframeable inspector control on its own lane. |
scene_add · scene_remove · scene_rename · system_apply_preset | Runtime-aware add (primitive, 3D text, light, camera, system with preset, group, model, physics world), delete, rename and preset replacement. |
clip_create · clip_patch · clip_launch · editor_undo · editor_mode | Clip-mode clips, history and view. Launch a clip before seeking or capturing it. |
parameter_set | Set a discovered, unanimated numeric control within its bounds. Uses the same binding as the inspector and renderer. |
keyframe_upsert | Add or replace a key at an exact lane-local time on a discovered parameter. Produces ordinary editable keyframes. |
keyframe_remove | Remove a key at an exact lane-local time. Inspect the existing key times first. |
editor_seek | Pause and seek to project seconds within the project duration. Waits for a matching presented frame. |
editor_capture_frame | Capture the paused viewport. Width 64–1920, default 960. Returns an MCP PNG image and metadata, including time, frame sequence, document revision and source/output dimensions. |
project_list | Discover your saved projects and available templates. |
project_read | Read persisted project JSON and scene overrides; omit project_id for the open project. Use after saving to check stored edits. |
project_create | Create a private saved project: source=current copies the live document; empty creates a blank project; template uses a discovered template_id. Returns project_id and editor_url. Keeps the current project selected; open the returned URL and pair again to edit the new project. |
assets_list | Search available assets by type, query, offset and limit. Returns exact paths without large inline definitions. Use type=scenes to discover built-in scene presets. |
preset_list | List persistent native clip presets in your account. |
preset_read | Read a preset bundle by preset_id, including native layers and animation. |
preset_save | Save a named immutable preset from exactly one of look_id or Timeline time. Scene definitions are embedded; external media remain asset references. Saved presets persist across projects, reloads and undo. |
preset_load | Apply exactly one of preset_id or a discovered scene_path at start, on new Timeline tracks with one undo entry. Saved presets retain animation; scene assets accept an optional duration. Inspect returned clip IDs before editing. |
project_save | Wait for the server save queue and return an acknowledgement, sequence, revision and submitted-snapshot SHA-256. |
material_apply | Apply an imported material asset to a single-mesh primitive. Prepares maps and compiles through the renderer before one undoable commit; rejects a changed target during preparation. |
look_capture | Save active Timeline layers at time as a named native clip in Clip mode, including authored overrides, materials and animation. Returns look_id; an empty moment rejects. |
look_apply | Copy a saved clip onto new Timeline tracks at start. Preserves the saved clip and returns new clip IDs. End must remain within 24 hours. |
lsd_batch | Run 1–32 compatible calls with one undo boundary and rollback. Inspect per-call results on failure. |
lsd_request_status | Recover a live pairing’s recorded operation using request_id. Use after a lost or uncertain reply. |
lsd_asset_formats | Discover current import root, formats, material fields, graph operations, limits and a complete example before generating files. |
lsd_import_asset | Import a local PNG texture or material JSON into the owner’s library. Requires file_path, kind, name and _request_id. Returns a stable asset ID and content hash. |
A turning object, ready for a person
- Inspect
- Create
- Animate
- See
- Refine
- Save
These JSON blocks are tools/call parameters, not complete JSON-RPC envelopes. Replace SCENE_ID and OBJECT_ID with returned values. Example operation IDs are illustrative: generate fresh IDs for your actual work and retain them for recovery.
1. Inspect, then create a scene
{"name":"inspect_editor","arguments":{}}
Confirm the correct project is ready and choose an unused interval or intentional overlap. In this example, the project must accommodate ten seconds.
{
"name": "scene_create",
"arguments": {
"_request_id": "turning-scene-001",
"name": "Turning ceramic", "start": 0, "duration": 10
}
}
Read output.tracks[0].clips[0].id as SCENE_ID. The MCP text result wraps successful tool output with request_id and status; parse that content before using IDs.
2. Add and discover
{
"name": "scene_add_entity",
"arguments": {
"_request_id": "turning-object-001",
"scene_id": "SCENE_ID", "entity_type": "object",
"entity": {
"geometry": "box", "name": "Hero ceramic",
"material": {"color":"#b9d9ce","roughness":0.65,"metalness":0.1}
}
}
}
Keep the returned output.entity_id as OBJECT_ID.
{
"name": "parameters_list",
"arguments": {
"scene_id": "SCENE_ID", "entity_type": "object", "entity_id": "OBJECT_ID"
}
}
3. Animate one control
Confirm obj_rot_y is available, its bounds include 0–90 degrees, the lane is at least two seconds long, and the change respects existing animation. Then add both keys as one undoable edit:
{
"name": "lsd_batch",
"arguments": {
"_request_id": "turning-animation-001",
"calls": [
{"name":"keyframe_upsert","arguments":{
"scene_id":"SCENE_ID","entity_type":"object","entity_id":"OBJECT_ID",
"parameter_id":"obj_rot_y","time":0,"value":0,"easing":"linear"
}},
{"name":"keyframe_upsert","arguments":{
"scene_id":"SCENE_ID","entity_type":"object","entity_id":"OBJECT_ID",
"parameter_id":"obj_rot_y","time":2,"value":90,"easing":"linear"
}}
]
}
}
4. See it, refine it, save it
Seek separately to animation.start + 1. For a lane starting at project time zero:
{"name":"editor_seek","arguments":{"time":1}}
{"name":"editor_capture_frame","arguments":{"width":960}}
Inspect the returned image. Check framing, lighting and the intermediate rotation; compare the endpoints and scrub backward as well. Use discovered free-camera controls to improve framing. Re-capture after refinements.
{"name":"project_save","arguments":{"_request_id":"turning-save-001"}}
Check for status: "server_acknowledged" inside the save output. Report the named scene, object ID, animated control, reviewed times and save receipt.
From generated pixels to an editable preset
Call lsd_asset_formats first. The harness supplies the image-generation tool and credentials; friday effects does not inherit your harness’s tools or need a copy of its API keys. A remote generation result must become a supported local file before importing.
Texture → material → scene
- Generate a texture suited to its role. For a repeating base-color map, request seamless edges and avoid baked directional lighting. A color image alone does not supply physically meaningful normal, roughness or displacement maps.
- Write a supported PNG under the reported import root. The default is
~/LSD Agent Assets; create it if needed. A dedicated folder can be configured withLSD_IMPORT_ROOTin the adapter environment. Supply an absolute regular-file path to imports, with no symlinks. - Call
lsd_import_assetwithkind: "texture". Keep the returnedasset_id. - Write a material JSON using that asset ID, import it with
kind: "material", and apply its returned ID withmaterial_apply. - Seek, capture and inspect the actual rendered surface. Refine the preset and save the project. The person can load the material from the library and adjust its normal inspector controls.
{
"name": "lsd_import_asset",
"arguments": {
"_request_id": "ceramic-texture-001",
"file_path": "/ABSOLUTE/IMPORT/ROOT/ceramic.png",
"kind": "texture", "name": "Ceramic base color"
}
}
Save the following as ceramic.material.json inside the same import root. Replace the map placeholder with the imported texture’s asset ID, not its filesystem path or URL.
{
"assetType": "material", "version": 1, "name": "Generated ceramic",
"material": {
"color": "#ffffff", "roughness": 0.65,
"map": "REPLACE_WITH_IMPORTED_TEXTURE_ASSET_ID", "textureRepeat": 3
}
}
{
"name": "lsd_import_asset",
"arguments": {
"_request_id": "ceramic-material-001",
"file_path": "/ABSOLUTE/IMPORT/ROOT/ceramic.material.json",
"kind": "material", "name": "Generated ceramic"
}
}
{
"name": "material_apply",
"arguments": {
"_request_id": "ceramic-apply-001",
"scene_id": "SCENE_ID", "entity_id": "OBJECT_ID",
"asset_id": "REPLACE_WITH_IMPORTED_MATERIAL_ASSET_ID"
}
}
Generate a controllable color shader
The verified shader path accepts a bounded, declarative color graph compiled into TSL. It is not a general GLSL, WGSL or JavaScript execution tool, nor a full-screen effect authoring API. Expose useful numeric parameters so a person can adjust and animate the result.
This complete material JSON creates a UV gradient with an editable brightness parameter. Import it as a material, then apply it as above.
{
"assetType": "material", "version": 1, "name": "Adjustable gradient",
"material": {
"color": "#ffffff", "roughness": 0.5,
"colorShader": {
"name": "Gradient",
"graph": {
"version": 1,
"parameters": [
{"name":"brightness","default":1,"min":0,"max":1,"step":0.01}
],
"nodes": [
{"id":"u","op":"uv_x"},
{"id":"gain","op":"parameter","name":"brightness"},
{"id":"value","op":"mul","inputs":["u","gain"]}
],
"output": ["value","value","value"]
}
}
}
}
After applying, inspect the target object’s material.colorShader.id. Use it as entity_id with entity_type: "material_shader" in parameters_list. Discover the exposed parameter IDs, then use parameter_set or native keyframes. The editor’s Color Map shader lane shows the same sliders and K controls. Graph structure is edited through JSON and a new import; there is currently no visual graph editor.
| Type | Supported form |
|---|---|
| PNG texture | Non-interlaced, 8-bit grayscale, grayscale-alpha, RGB or RGBA. Up to 4096 pixels per side, 8,388,608 total pixels and 8 MiB. Palette PNG, APNG, JPEG and WebP are not supported by this importer. |
| Material JSON | Version 1, up to 32 KiB. Bounded PBR fields and same-owner imported texture IDs. Map roles: map, normalMap, roughnessMap, metalnessMap, emissiveMap, bumpMap, displacementMap, aoMap, alphaMap. Color/emissive maps use sRGB; data maps use linear color space. |
| Color graph | 1–64 scalar nodes and at most 16 numeric parameters. Sources: constant, parameter, uv_x, uv_y, time (scene-local seconds). Operations: add, sub, mul, sin, cos, abs, fract, clamp01, mix. References must point to earlier nodes. Intermediates clamp to ±10,000; final RGB clamps to 0–1. |
| Graph boundaries | No loops, custom code, texture-sampling nodes, depth/audio inputs, filesystem or network access. A graph replaces the base-color map; other supported PBR maps can coexist. Declared parameter bounds remain fixed. |
| Import session | 64 MiB of successful imports per day for a saved connection. Asset, material and shader display names use 1–80 ASCII letters, digits, spaces, underscores, dots or hyphens. Scoped file import currently requires POSIX directory-handle support and is not implemented on Windows. |
Save the recipe, not only the image
Visual layer order is authoritative in Timeline and Clips. The top row renders on top; Post FX and LUT layers affect the combined image below their row. Master layers sit above the active clip. Place a visual above an adjustment to leave it unaffected; ignorePostFx is obsolete. Text effects attached to a text layer remain local to that layer.
When a composition works, capture a named clip at a Timeline moment. This copies active layers and their authored data into Clips. It does not bake a simulation or flatten the result into a screenshot.
{
"name": "look_capture",
"arguments": {"_request_id":"ceramic-look-001","name":"Ceramic / slow turn","time":1}
}
To reuse it, take the returned look_id and choose an appropriate start time:
{
"name": "look_apply",
"arguments": {"_request_id":"ceramic-look-copy-001","look_id":"LOOK_ID","start":12}
}
The copy appears on new Timeline tracks; it preserves the saved clip. Use the returned new scene clip IDs for later edits. Entity IDs can repeat across independent scene copies, so always retain their scene scope. Clips are project-local; a portable cross-project dependency bundle is not part of this interface.
Definition of a finished agent task
- The result consists of named native entities, editable materials, keyframes and, when useful, a saved clip.
- Useful artistic controls remain exposed in the inspector. Authored timing and units match what a person sees.
- You have inspected relevant frames, including animation endpoints and an intermediate moment; refine visible issues before declaring success.
- The last intended changes have a successful
project_savereceipt. - Your handoff identifies the project, scenes/objects, clip and asset IDs, reviewed times, controls to tweak and any unresolved visual limitations. Keep credentials out of it.
A reply is evidence. Read what it proves.
Inspect MCP isError and the text result’s status and output. A successful JSON-RPC exchange can still contain a tool error. Frame capture also returns a native image content block; review it if your harness supports image input.
Applied ≠ visually reviewed
An applied edit is document state. renderer_compile_completed means material preparation compiled, not that the final picture is correct. Seek and capture to inspect it.
Captured ≠ deterministic replay
A capture is an actual presented viewport frame. It does not certify that every background asset has settled or that physics, particles and feedback rewind deterministically. Source viewport dimensions can differ between sessions.
A save receipt acknowledges the submitted snapshot and reports its hash. It does not independently read the stored file back or prove filesystem durability. If persistence is central to the task, reopen through the editor and inspect the saved result; reopening ends the current pairing.
When a call times out or the reply is lost
Do not repeat the edit with a new ID. Reconcile the original operation first:
{"name":"lsd_request_status","arguments":{"request_id":"turning-object-001"}}
| Recorded state | How to proceed |
|---|---|
queued | Not yet delivered. MCP cancellation can stop it before dispatch. |
dispatched | Outcome uncertain: it may be executing or its reply may be lost. Do not duplicate it. Cancellation cannot safely undo an already dispatched edit. |
completed | Read the recorded success or error. For failed batches, inspect rollback and not-run results. |
cancelled | Cancelled before dispatch; it will not run. |
The same ID with the same arguments retrieves the durable status/result, including after a server restart. Changed arguments under that ID reject. The adapter retries the exact ID and payload for up to 15 seconds during temporary outages; it never creates a new operation for recovery. The bridge dispatches each operation at most once.
After reconnecting: the same saved connection retains its request receipts across server restarts. Query lsd_request_status with the original ID. A delivered edit is never replayed; missing delivery acknowledgements remain uncertain. Forgetting access deletes that grant’s receipts, so inspect the actual document before recreating any work through a new connection.
Common reasons to stop and inspect
- Scene not loaded or ID missing: re-inspect and select/load the intended clip through the editor if needed; do not substitute a similarly named entity.
- Parameter unavailable or out of range: call
parameters_listagain. Target/orbit cameras and unverified controls are not interchangeable with free-camera bindings. - Target changed during material preparation: inspect the human’s latest state before applying a revised operation.
- Capture rejected while playing: call
editor_seekfirst, then capture separately. - Import rejected: verify the reported root, actual encoding, dimensions, size and material schema. Renaming an extension does not convert a file.
Limits: 128 saved connections, 32 outstanding operations, 32 KiB command payloads, 10 MiB per result and a 32 MiB retained result budget. Old large results may be retired, but their completed status and request fingerprints are retained to prevent replay. The adapter waits up to 90 seconds, then returns the operation ID for reconciliation. Budget errors can leave an uncertain outcome; reconcile before doing more work.
Know which surface you are using
| Surface | What to expect today |
|---|---|
| Verified external authoring | The 19 tools above: native scenes, primitives/lights, selected numeric controls, free cameras, keyframes, PNG/material imports, bounded color shaders, project-local clips, seek/capture and acknowledged saves. |
| Broader editor interface | Procedural scene systems, models, media, text, audio, effects, grading and other animation modes exist in the editor. Their presence in the UI does not establish complete external MCP authoring support. Computer use may operate visible controls, but validate the result and report what you actually verified. |
| Not exposed in this interface | Project creation/opening, arbitrary application code execution, unrestricted filesystem access, automatic publishing, arbitrary shader programs, URL-based imports, general export/render jobs, contact-sheet or short-video APIs, and full procedural/LFO authoring. |
| Desktop candidate | An unsigned Apple Silicon Mac preview with a bundled local service and MCP adapter. It opens the animated start screen and ships the curated default catalog, registered templates and their assets. Signing/notarization, Windows validation, media/export behavior and GPU recovery remain release work. Private hosted uploads and externally loaded fonts are not part of the built-in catalog. |
| Host compatibility | The stdio protocol and authoring path have harness and browser coverage. This is not a claim that every Codex/Claude release, model or computer-use workflow has been tested. Your host must support MCP stdio and any image/file tools you intend to use. |
Collaborating with a person
Supported edits share native undo and animation behavior. Imports remain library assets outside scene undo. Staged commands guard project/target changes, but there is not yet one revision token covering every legacy human edit. Inspect around long preparation steps and avoid treating concurrent human changes as permission to overwrite them.
Source privacy and editable authorship
Agents can work through schemas, returned data and pixels without receiving the application repository. User-authored graphs, material data and project structure intentionally remain editable. Packaging and minification reduce casual source exposure; delivered JavaScript and executable code are still recoverable. An Electron container cannot promise source secrecy.
If an operation is missing, use supported tools or a visible editor workflow within the task’s scope. Do not turn missing capabilities into a dependency on private SDK commands, eval, or extracted application source.
Give your harness a clear starting point
Copy this brief after configuring the MCP connection. Add the creative direction, target duration and any content that must be preserved. The manual uses the bundled brand stylesheet and font, with no scripts.
Work in the currently paired friday effects project.
Discover the live MCP tools and inspect the editor before changing it.
Confirm the intended project and use returned scene/entity/asset IDs.
Create the requested result as named, native editable scene content.
Discover numeric parameters before setting values or adding keyframes.
Use lane-local seconds for keys and project seconds for seek/capture.
Preserve existing content and expose useful controls for a human.
If generating textures or shader materials, discover import formats first.
Use the harness's generation tools, write supported files to the import root,
import them as library assets, then apply and inspect the rendered surface.
Keep shader work within the supported declarative color graph format.
Give each edit/import/batch/save a unique operation ID. Reconcile the same
ID after an uncertain reply; never blindly repeat a create with a new ID.
Use batches only for the operations allowed by the live batch schema.
Seek and inspect frames at useful moments, refine visible issues, and save.
Create a project-local clip if it helps reuse. Hand off the named content,
stable IDs, reviewed times, editable controls and save receipt.
State any limitations or checks you could not complete. Keep tokens private.