Clueso
Qué hace este MCP
Creates and edits video projects, screen recordings, articles, audio tracks, visual elements, AI-generated media, reusable templates, and exports.
Herramientas
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['kind', 'project_id'], 'properties': {'kind': {'enum': ['image', 'gif'], 'type': 'string', 'description': "'image' or 'gif'."}, 'duration': {'type': 'number', 'description': "kind='gif' only: GIF duration in seconds.", 'exclusiveMinimum': 0}, 'timestamp': {'type': 'number', 'minimum': 0, 'description': "kind='image': capture frame at this timestamp (seconds). kind='gif': GIF start time."}, 'project_id': {'type': 'string', 'description': 'Project ID.'}, 'mcp_upload_id': {'type': 'string', 'description': "kind='image' only: attach an uploaded image (mcp_upload_id from the upload tool) instead of capturing from video."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'type'], 'properties': {'src': {'type': 'string', 'description': "Audio source. For type='music' (required) or a stock type='sfx': the `src` from a find(type='music'|'sfx') result (may be an opaque Freesound handle — pass as-is), or an mcp_upload_id (prefixed 'mup_') from upload_file. Not needed for legacy fixed-library sfx (use sfx_key)."}, 'loop': {'type': 'boolean', 'description': 'Loop the track if project is longer than the source. Music only. (default: false)'}, 'name': {'type': 'string', 'description': "Track/effect name. From the find result, or any descriptive label when using mcp_upload_id. Required for type='music' and for stock type='sfx' (passed via src)."}, 'type': {'enum': ['music', 'sfx'], 'type': 'string', 'description': "Audio type: 'music' or 'sfx'"}, 'volume': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'Volume as percent (0–100). Default: 50 for music, 80 for sfx.'}, 'fade_in': {'type': 'number', 'minimum': 0, 'description': 'Fade-in duration in seconds. Music only. (default: 0.5)'}, 'sfx_key': {'type': 'string', 'description': "LEGACY fixed-library SFX key (e.g. 'whoosh', 'pop', 'click'). Optional alternative to src for type='sfx'. Prefer the src/name/source_duration from a find(type='sfx') result."}, 'fade_out': {'type': 'number', 'minimum': 0, 'description': 'Fade-out duration in seconds. Music only. (default: 0.5)'}, 'project_id': {'type': 'string', 'description': 'The project ID'}, 'guide_end_time': {'type': 'number', 'description': 'When to stop playing (seconds). Music only. Default = end of project AT CALL TIME — captured once at insert and NOT recomputed when clips are later added or resized. Pass an explicit value (e.g. the intended final project duration) when adding audio before clips are sized.', 'exclusiveMinimum': 0}, 'music_end_time': {'type': 'number', 'description': 'Out-point within the SOURCE track (seconds) — trims where playback ends in the music file. Music only. Default = source_duration.', 'exclusiveMinimum': 0}, 'source_duration': {'type': 'number', 'description': "Source duration in seconds. From the find result, or analyze_audio mode='features' (data.duration_ms / 1000). Required for type='music' and for stock type='sfx' (passed via src).", 'exclusiveMinimum': 0}, 'guide_start_time': {'type': 'number', 'minimum': 0, 'description': "When to start playing in the guide timeline (seconds). Required for type='sfx', optional for music (default 0)."}, 'music_start_time': {'type': 'number', 'minimum': 0, 'description': 'In-point within the SOURCE track (seconds) — trims where playback begins in the music file. Music only. Default 0 (start of source).'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['kind', 'project_id'], 'properties': {'cuts': {'type': 'array', 'items': {'type': 'object', 'required': ['start_seconds', 'end_seconds'], 'properties': {'heading': {'type': 'string', 'description': 'Optional clip title for this cut.'}, 'end_seconds': {'type': 'number', 'description': 'Cut end in original-source seconds (exclusive).', 'exclusiveMinimum': 0}, 'start_seconds': {'type': 'number', 'minimum': 0, 'description': 'Cut start in original-source seconds (inclusive).'}}}, 'description': "kind='video' only: per-clip cuts. Each entry becomes one inserted clip. Omit to insert the full upload as a single clip."}, 'kind': {'enum': ['blank', 'pptx', 'video'], 'type': 'string', 'description': "Source for the new clips: 'blank' | 'pptx' | 'video'."}, 'clips': {'type': 'array', 'items': {'type': 'object', 'properties': {'title': {'type': 'string', 'description': 'Clip title shown in the timeline.'}, 'duration': {'type': 'number', 'description': 'Clip length in seconds. Defaults to a short blank-clip duration.', 'exclusiveMinimum': 0}, 'background': {'type': 'object', 'description': "Full background object from find(type='backgrounds'), set at creation.", 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'transition': {'type': 'object', 'required': ['type', 'duration'], 'properties': {'type': {'enum': ['circleWipe', 'rainbowWipe', 'cornerWipe', 'stack', 'colorWipe', 'dissolve', 'pushPull', 'fadeToColor'], 'type': 'string', 'description': "Transition style. NOTE: a clip's transition plays at the END of that clip, into the next one — to put a transition between clips 2 and 3, set it on clip 2."}, 'color': {'type': 'string', 'description': 'Hex color, honoured by fadeToColor (default #000000), colorWipe (default #073cad) and rainbowWipe (default #D43F8C).'}, 'duration': {'type': 'number', 'description': 'Transition length in seconds.', 'exclusiveMinimum': 0}, 'direction': {'type': 'string', 'description': 'Direction, honoured only by some types: rainbowWipe and cornerWipe take topLeft/topRight/bottomLeft/bottomRight (default topRight); colorWipe takes left or right (default right); stack and pushPull take left/right/top/bottom (default right). Ignored by dissolve, circleWipe and fadeToColor.'}}, 'description': 'Transition at the END of this clip, into the next one.'}, 'background_color': {'type': 'string', 'description': "Hex background set at creation, e.g. '#0B0E1A'."}}}, 'description': "kind='blank' only: one entry per blank clip. Optionally set background_color/background + transition per clip at creation — no follow-up update_clips needed."}, 'title': {'type': 'string', 'description': "kind='video' only: clip title (default 'Video')."}, 'mime_type': {'type': 'string', 'description': "kind='video' only: MIME type (default 'video/mp4'). Audio MIME types insert the file as a sequential clip with auto-TTS; for background music, use add_audio instead."}, 'project_id': {'type': 'string', 'description': 'Project (guide) ID.'}, 'after_clip_id': {'type': 'string', 'description': 'Insert after this clip ID; appends at end if omitted.'}, 'auto_elements': {'type': 'boolean', 'description': "kind='video' only: when true, run auto-element detection (zooms, spotlights, blurs). Default false. Only meaningful on cache miss; cache hits clone the originating run's auto-elements."}, 'mcp_upload_id': {'type': 'string', 'description': "kind='pptx' or 'video': mcp_upload_id from the upload_file tool."}, 'slide_indices': {'type': 'array', 'items': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0}, 'description': "kind='pptx' only: 0-based slide indices to insert. Omit to insert all slides."}, 'voiceover_text': {'type': 'string', 'description': "kind='video' only: post-AI voiceover script (saved as v2). Original audio is always retained as the base transcript."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'comment_text'], 'properties': {'clip_id': {'type': 'string', 'description': 'Optional clip ID to pin the comment to. Omit for a project-level comment.'}, 'project_id': {'type': 'string', 'description': 'The project (guide) ID'}, 'comment_text': {'type': 'string', 'minLength': 1, 'description': 'Comment text to post'}, 'clip_timestamp': {'type': 'number', 'minimum': 0, 'description': 'Optional timestamp within the clip (seconds). Only used when clip_id is provided.'}, 'parent_comment_id': {'type': 'string', 'description': 'Reply to this comment instead of starting a new thread. Take the id from get_comments. Replying is how you answer feedback you have acted on — the clip pin and timestamp come from the parent, so leave clip_id/clip_timestamp off.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'elements'], 'properties': {'defaults': {'type': 'object', 'properties': {'x': {'type': 'number'}, 'y': {'type': 'number'}, 'group': {'type': 'string', 'minLength': 1}, 'width': {'type': 'number', 'minimum': 0}, 'height': {'type': 'number', 'minimum': 0}, 'clip_id': {'type': 'string'}, 'end_time': {'type': 'number', 'minimum': 0}, 'rotation': {'type': 'number'}, 'insert_at': {'enum': ['front', 'back'], 'type': 'string'}, 'keyframes': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['timestamp'], 'properties': {'blur': {'type': 'number', 'description': 'Layer blur'}, 'cropX': {'type': 'number', 'description': 'cropX (native unit)'}, 'cropY': {'type': 'number', 'description': 'cropY (native unit)'}, 'width': {'type': 'number', 'minimum': 0, 'description': 'Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)'}, 'bezier': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4, 'description': "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'."}, 'height': {'type': 'number', 'minimum': 0, 'description': 'Height in canvas pixels (0 allowed)'}, 'scaleX': {'type': 'number', 'description': 'Horizontal scale multiplier (1 = 100%)'}, 'scaleY': {'type': 'number', 'description': 'Vertical scale multiplier (1 = 100%)'}, 'opacity': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'Opacity 0-100'}, 'rotateX': {'type': 'number', 'description': 'rotateX (native unit)'}, 'rotateY': {'type': 'number', 'description': 'rotateY (native unit)'}, 'fontSize': {'type': 'number', 'description': 'Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).'}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees'}, 'cropWidth': {'type': 'number', 'description': 'cropWidth (native unit)'}, 'fillColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'fillColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'positionX': {'type': 'number', 'description': "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right."}, 'positionY': {'type': 'number', 'description': "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y."}, 'strokeGap': {'type': 'number', 'description': 'strokeGap in canvas pixels'}, 'textColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'timestamp': {'type': 'number', 'minimum': 0, 'description': 'Clip-relative time in seconds'}, 'cropHeight': {'type': 'number', 'description': 'cropHeight (native unit)'}, 'lineHeight': {'type': 'number', 'description': 'lineHeight (native unit)'}, 'paddingTop': {'type': 'number', 'description': 'paddingTop in canvas pixels'}, 'shadowBlur': {'type': 'number', 'description': 'shadowBlur in canvas pixels'}, 'strokeDash': {'type': 'number', 'description': 'strokeDash in canvas pixels'}, 'paddingLeft': {'type': 'number', 'description': 'paddingLeft in canvas pixels'}, 'shadowColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeWidth': {'type': 'number', 'description': 'strokeWidth in canvas pixels'}, 'paddingRight': {'type': 'number', 'description': 'paddingRight in canvas pixels'}, 'shadowSpread': {'type': 'number', 'description': 'shadowSpread in canvas pixels'}, 'interpolation': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string', 'description': 'Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.'}, 'letterSpacing': {'type': 'number', 'description': 'Letter spacing in canvas pixels.'}, 'paddingBottom': {'type': 'number', 'description': 'paddingBottom in canvas pixels'}, 'shadowOffsetX': {'type': 'number', 'description': 'shadowOffsetX in canvas pixels'}, 'shadowOffsetY': {'type': 'number', 'description': 'shadowOffsetY in canvas pixels'}, 'strokeTrimEnd': {'type': 'number', 'description': 'strokeTrimEnd (native unit)'}, 'textStrokeGap': {'type': 'number', 'description': 'textStrokeGap in canvas pixels'}, 'backgroundBlur': {'type': 'number', 'description': 'Backdrop blur behind the element'}, 'textStrokeDash': {'type': 'number', 'description': 'textStrokeDash in canvas pixels'}, 'strokeTrimStart': {'type': 'number', 'description': 'strokeTrimStart (native unit)'}, 'textStrokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textStrokeWidth': {'type': 'number', 'description': 'textStrokeWidth in canvas pixels'}, 'bezier_overrides': {'type': 'object', 'description': 'Per-property cubic-bezier override, e.g. {"opacity":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4}}, 'imageBorderColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'imageBorderWidth': {'type': 'number', 'description': 'imageBorderWidth in canvas pixels'}, 'strokeTrimOffset': {'type': 'number', 'description': 'strokeTrimOffset (native unit)'}, 'borderRadiusTopLeft': {'type': 'number', 'description': 'borderRadiusTopLeft in canvas pixels'}, 'textBackgroundColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textBgRadiusTopLeft': {'type': 'number', 'description': 'textBgRadiusTopLeft in canvas pixels'}, 'borderRadiusTopRight': {'type': 'number', 'description': 'borderRadiusTopRight in canvas pixels'}, 'textBgRadiusTopRight': {'type': 'number', 'description': 'textBgRadiusTopRight in canvas pixels'}, 'borderRadiusBottomLeft': {'type': 'number', 'description': 'borderRadiusBottomLeft in canvas pixels'}, 'textBgRadiusBottomLeft': {'type': 'number', 'description': 'textBgRadiusBottomLeft in canvas pixels'}, 'borderRadiusBottomRight': {'type': 'number', 'description': 'borderRadiusBottomRight in canvas pixels'}, 'interpolation_overrides': {'type': 'object', 'description': 'Per-property easing override, e.g. {"opacity":"linear"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string'}}, 'textBgRadiusBottomRight': {'type': 'number', 'description': 'textBgRadiusBottomRight in canvas pixels'}, 'imageCornerRadiusTopLeft': {'type': 'number', 'description': 'imageCornerRadiusTopLeft in canvas pixels'}, 'videoCornerRadiusTopLeft': {'type': 'number', 'description': 'videoCornerRadiusTopLeft in canvas pixels'}, 'imageCornerRadiusTopRight': {'type': 'number', 'description': 'imageCornerRadiusTopRight in canvas pixels'}, 'videoCornerRadiusTopRight': {'type': 'number', 'description': 'videoCornerRadiusTopRight in canvas pixels'}, 'imageCornerRadiusBottomLeft': {'type': 'number', 'description': 'imageCornerRadiusBottomLeft in canvas pixels'}, 'videoCornerRadiusBottomLeft': {'type': 'number', 'description': 'videoCornerRadiusBottomLeft in canvas pixels'}, 'imageCornerRadiusBottomRight': {'type': 'number', 'description': 'imageCornerRadiusBottomRight in canvas pixels'}, 'videoCornerRadiusBottomRight': {'type': 'number', 'description': 'videoCornerRadiusBottomRight in canvas pixels'}}, 'additionalProperties': False}}, {'type': 'null'}]}, 'type_data': {'type': 'object', 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0}, 'start_time': {'type': 'number', 'minimum': 0}, 'element_type': {'enum': ['text', 'callout', 'rectangle', 'arrow', 'blur', 'spotlight', 'zoom', 'image', 'video', 'animation'], 'type': 'string'}}, 'description': "Values shared by every item, sent once rather than repeated. Items win per key; type_data merges one level. E.g. defaults:{clip_index:1, element_type:'text', type_data:{font_setting:{font:'Inter',weight:'600'}, alignment:'center'}} then items carry only what differs.", 'additionalProperties': False}, 'elements': {'type': 'array', 'items': {'type': 'object', 'properties': {'x': {'type': 'number', 'description': 'X position in canvas pixels. `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right (callout, rectangle, arrow, blur, spotlight, image and animation all use the left edge). For zoom, use type_data.centerX instead.'}, 'y': {'type': 'number', 'description': 'Y position in canvas pixels — for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. Pair it with y_anchor (below), always.'}, 'name': {'type': 'string', 'description': 'Label'}, 'group': {'type': 'string', 'minLength': 1, 'description': 'Put this element in a named group. The name is the handle: items in ONE call sharing the same name land in the SAME group, and a later call with that name adds to it. Use it to keep a unit together (a card and its label, a stat and its caption) so the user can move or hide it as one thing. Grouping never moves anything — coordinates stay absolute. Animations and AI-generated images are created in the background and cannot be grouped as they are added; add them first, then set `group` via update_elements.'}, 'width': {'type': 'number', 'minimum': 0, 'description': "Width, pixels (0 allowed — e.g. a bar that draws in from 0). For text this is the WRAP width and it is kept as sent: the text wraps to it and the box stays this wide. (Height differs — the box's height follows the measured text.)"}, 'height': {'type': 'number', 'minimum': 0, 'description': "Height, pixels (0 allowed). For text the box's height always follows the measured text, so this reads as the space you are giving it: the text is centred in that space and layout.fits_height says whether it fit. Use type_data.fit to shrink the font into it."}, 'clip_id': {'type': 'string', 'description': 'Clip ID — accepted but unused; the clip is located by clip_index for all element types.'}, 'end_time': {'type': 'number', 'minimum': 0, 'description': 'Disappear at (seconds)'}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees'}, 'y_anchor': {'enum': ['top', 'center', 'bottom'], 'type': 'string', 'description': "TEXT only. ALWAYS send `y_anchor` ('top'|'center'|'bottom') when you set `y` on text, so the position states what you meant instead of inheriting the alignment origin. To centre in a row, pill, chip, card or button: pass the container's centre line as `y` with y_anchor:'center'. The server centres the MEASURED box — you cannot compute that height, since wrapping and `fit` change it. A write-time DIRECTIVE: never stored, never returned by a read, so send it on every call whose `y` means the same thing. (Also accepted inside type_data — older spelling; this one wins.)"}, 'insert_at': {'anyOf': [{'enum': ['front', 'back'], 'type': 'string'}, {'type': 'object', 'required': ['before'], 'properties': {'before': {'type': 'string', 'minLength': 1}}, 'additionalProperties': False}, {'type': 'object', 'required': ['after'], 'properties': {'after': {'type': 'string', 'minLength': 1}}, 'additionalProperties': False}], 'description': "Where the element lands in z-order, so you don't need a follow-up reorder_elements. `front` (default) puts it on top of what's already on the clip; `back` puts it behind everything — what a backdrop panel or a wash needs. `{before: element_id}` / `{after: element_id}` place it next to a specific element or group and put it in THAT node's group, which is the only way to position inside a group. Passing `group` as well changes what `front`/`back` address — see the Z-order notes in this tool's description. Placement is relative to the clip AS IT STANDS when the item is applied, so several `back` items in one call end up in REVERSE input order: send one backdrop per call, or list them back-to-front."}, 'keyframes': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['timestamp'], 'properties': {'blur': {'type': 'number', 'description': 'Layer blur'}, 'cropX': {'type': 'number', 'description': 'cropX (native unit)'}, 'cropY': {'type': 'number', 'description': 'cropY (native unit)'}, 'width': {'type': 'number', 'minimum': 0, 'description': 'Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)'}, 'bezier': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4, 'description': "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'."}, 'height': {'type': 'number', 'minimum': 0, 'description': 'Height in canvas pixels (0 allowed)'}, 'scaleX': {'type': 'number', 'description': 'Horizontal scale multiplier (1 = 100%)'}, 'scaleY': {'type': 'number', 'description': 'Vertical scale multiplier (1 = 100%)'}, 'opacity': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'Opacity 0-100'}, 'rotateX': {'type': 'number', 'description': 'rotateX (native unit)'}, 'rotateY': {'type': 'number', 'description': 'rotateY (native unit)'}, 'fontSize': {'type': 'number', 'description': 'Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).'}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees'}, 'cropWidth': {'type': 'number', 'description': 'cropWidth (native unit)'}, 'fillColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'fillColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'positionX': {'type': 'number', 'description': "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right."}, 'positionY': {'type': 'number', 'description': "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y."}, 'strokeGap': {'type': 'number', 'description': 'strokeGap in canvas pixels'}, 'textColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'timestamp': {'type': 'number', 'minimum': 0, 'description': 'Clip-relative time in seconds'}, 'cropHeight': {'type': 'number', 'description': 'cropHeight (native unit)'}, 'lineHeight': {'type': 'number', 'description': 'lineHeight (native unit)'}, 'paddingTop': {'type': 'number', 'description': 'paddingTop in canvas pixels'}, 'shadowBlur': {'type': 'number', 'description': 'shadowBlur in canvas pixels'}, 'strokeDash': {'type': 'number', 'description': 'strokeDash in canvas pixels'}, 'paddingLeft': {'type': 'number', 'description': 'paddingLeft in canvas pixels'}, 'shadowColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeWidth': {'type': 'number', 'description': 'strokeWidth in canvas pixels'}, 'paddingRight': {'type': 'number', 'description': 'paddingRight in canvas pixels'}, 'shadowSpread': {'type': 'number', 'description': 'shadowSpread in canvas pixels'}, 'interpolation': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string', 'description': 'Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.'}, 'letterSpacing': {'type': 'number', 'description': 'Letter spacing in canvas pixels.'}, 'paddingBottom': {'type': 'number', 'description': 'paddingBottom in canvas pixels'}, 'shadowOffsetX': {'type': 'number', 'description': 'shadowOffsetX in canvas pixels'}, 'shadowOffsetY': {'type': 'number', 'description': 'shadowOffsetY in canvas pixels'}, 'strokeTrimEnd': {'type': 'number', 'description': 'strokeTrimEnd (native unit)'}, 'textStrokeGap': {'type': 'number', 'description': 'textStrokeGap in canvas pixels'}, 'backgroundBlur': {'type': 'number', 'description': 'Backdrop blur behind the element'}, 'textStrokeDash': {'type': 'number', 'description': 'textStrokeDash in canvas pixels'}, 'strokeTrimStart': {'type': 'number', 'description': 'strokeTrimStart (native unit)'}, 'textStrokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textStrokeWidth': {'type': 'number', 'description': 'textStrokeWidth in canvas pixels'}, 'bezier_overrides': {'type': 'object', 'description': 'Per-property cubic-bezier override, e.g. {"opacity":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4}}, 'imageBorderColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'imageBorderWidth': {'type': 'number', 'description': 'imageBorderWidth in canvas pixels'}, 'strokeTrimOffset': {'type': 'number', 'description': 'strokeTrimOffset (native unit)'}, 'borderRadiusTopLeft': {'type': 'number', 'description': 'borderRadiusTopLeft in canvas pixels'}, 'textBackgroundColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textBgRadiusTopLeft': {'type': 'number', 'description': 'textBgRadiusTopLeft in canvas pixels'}, 'borderRadiusTopRight': {'type': 'number', 'description': 'borderRadiusTopRight in canvas pixels'}, 'textBgRadiusTopRight': {'type': 'number', 'description': 'textBgRadiusTopRight in canvas pixels'}, 'borderRadiusBottomLeft': {'type': 'number', 'description': 'borderRadiusBottomLeft in canvas pixels'}, 'textBgRadiusBottomLeft': {'type': 'number', 'description': 'textBgRadiusBottomLeft in canvas pixels'}, 'borderRadiusBottomRight': {'type': 'number', 'description': 'borderRadiusBottomRight in canvas pixels'}, 'interpolation_overrides': {'type': 'object', 'description': 'Per-property easing override, e.g. {"opacity":"linear"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string'}}, 'textBgRadiusBottomRight': {'type': 'number', 'description': 'textBgRadiusBottomRight in canvas pixels'}, 'imageCornerRadiusTopLeft': {'type': 'number', 'description': 'imageCornerRadiusTopLeft in canvas pixels'}, 'videoCornerRadiusTopLeft': {'type': 'number', 'description': 'videoCornerRadiusTopLeft in canvas pixels'}, 'imageCornerRadiusTopRight': {'type': 'number', 'description': 'imageCornerRadiusTopRight in canvas pixels'}, 'videoCornerRadiusTopRight': {'type': 'number', 'description': 'videoCornerRadiusTopRight in canvas pixels'}, 'imageCornerRadiusBottomLeft': {'type': 'number', 'description': 'imageCornerRadiusBottomLeft in canvas pixels'}, 'videoCornerRadiusBottomLeft': {'type': 'number', 'description': 'videoCornerRadiusBottomLeft in canvas pixels'}, 'imageCornerRadiusBottomRight': {'type': 'number', 'description': 'imageCornerRadiusBottomRight in canvas pixels'}, 'videoCornerRadiusBottomRight': {'type': 'number', 'description': 'videoCornerRadiusBottomRight in canvas pixels'}}, 'additionalProperties': False}}, {'type': 'null'}], 'description': 'Animation keyframes (≥2 entries). Each entry has a timestamp plus one or more keyframable properties (position/size in canvas pixels; rotation°, opacity 0-100, scale, colors as #rrggbb[aa], etc. in native units). Easing: per-entry `interpolation` + optional per-property `interpolation_overrides`. Call get_element_schema to see which properties this element_type can keyframe. null is accepted and means none.'}, 'type_data': {'type': 'object', 'description': 'Type-specific fields. Use the get_element_schema tool first to discover the shape for a given element_type. Omit when using component_id.', 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index. Required unless hoisted into `defaults`.'}, 'start_time': {'type': 'number', 'minimum': 0, 'description': 'Appear at (seconds)'}, 'component_id': {'type': 'string', 'minLength': 1, 'description': "Insert a SAVED COMPONENT exactly as stored — no AI generation, no restyling. This is how you reuse a component from your workspace verbatim (find one with find(type='element_components')). Components are workspace-scoped — there is no community library for them. A component is a fragment of a clip — one or more elements, possibly grouped — so this inserts ALL of them and returns every new element_id plus the animation's parameter_schema. Customise afterwards with update_elements(type_data.parameter_values). Mutually exclusive with element_type/type_data. To instead GENERATE a new animation using a component as a style reference, use element_type='animation' with type_data.base_component_id."}, 'element_type': {'enum': ['text', 'callout', 'rectangle', 'arrow', 'blur', 'spotlight', 'zoom', 'image', 'video', 'animation'], 'type': 'string', 'description': 'One of: text, callout, rectangle, arrow, blur, spotlight, zoom, image, video, animation. Omit when using component_id.'}, 'keyframes_repeat': {'type': 'object', 'required': ['count'], 'properties': {'mode': {'enum': ['loop', 'pingpong'], 'type': 'string', 'description': "'loop' (default) replays the cycle forwards every time — seamless only if your first and last values match. 'pingpong' alternates forwards/backwards, so the value always returns to where it started without a jump; use it for a breathe/pulse written as a one-way ramp."}, 'count': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 1, 'description': 'TOTAL number of cycles, INCLUDING the one you wrote. 1 is a no-op. Expansion stops at the clip end rather than piling the overflow onto the last frame, and the generated total is capped at 600 keyframes (it errors rather than silently truncating).'}, 'every': {'type': 'number', 'description': "Seconds between cycle STARTS. Defaults to the cycle's own span (back-to-back). A LARGER value holds the last value in the gap — that is how you get a pulse every 2s instead of a constant wobble. Shorter than the cycle is rejected, because the cycles would overlap and collide on the same frames.", 'exclusiveMinimum': 0}}, 'description': 'Repeat `keyframes` as a cycle — { count, mode?, every? }. Requires `keyframes` in the same call.', 'additionalProperties': False}}, 'additionalProperties': False}, 'minItems': 1, 'description': 'Elements to add — at least one entry.'}, 'returning': {'type': 'array', 'items': {'enum': ['ids', 'layout', 'qa', 'qa.codes'], 'type': 'string'}, 'description': "Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."}, 'project_id': {'type': 'string', 'description': 'Project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'word', 'timestamp_seconds'], 'properties': {'word': {'type': 'string', 'minLength': 1, 'description': 'Target word (case-insensitive; trailing punctuation is stripped).'}, 'clip_id': {'type': 'string', 'description': 'Clip ID (preferred). If omitted, clip_index is used.'}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index. Ignored if clip_id is provided.'}, 'occurrence': {'type': 'integer', 'default': 1, 'maximum': 9007199254740991, 'minimum': 1, 'description': '1-indexed match number when the word repeats. Defaults to 1 (first occurrence).'}, 'project_id': {'type': 'string', 'description': 'Project ID.'}, 'sync_point_name': {'type': 'string', 'description': "Optional label (e.g. 'Click submit'). Defaults to 'Sync point N' using the next order number."}, 'timestamp_seconds': {'type': 'number', 'minimum': 0, 'description': 'Clip-relative timestamp in seconds. Auto-mapped to original-recording seconds when the clip has generated_timestamps.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['mode'], 'properties': {'mode': {'enum': ['transcript', 'silences', 'beats', 'features'], 'type': 'string', 'description': 'Which analysis to run.'}, 'file_url': {'type': 'string', 'description': "Public http(s) URL to the audio. Use when the file is already accessible (e.g. find(type='music') result, Clueso CDN). Validated against private/loopback ranges."}, 'range_end_ms': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'End of analysis window in milliseconds. Default: whole file.'}, 'mcp_upload_id': {'type': 'string', 'description': 'MCP upload ID from the upload_file tool. Use this OR file_url, not both.'}, 'range_start_ms': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Start of analysis window in milliseconds. Default 0 (beginning).'}, 'silences_options': {'type': 'object', 'properties': {'min_pause_ms': {'type': 'integer', 'maximum': 9007199254740991, 'description': 'Minimum pause length to report. Default 250ms.', 'exclusiveMinimum': 0}, 'threshold_db': {'type': 'number', 'description': 'Silence threshold in dBFS. Default -40.'}}, 'description': "Options for mode='silences'."}, 'transcript_options': {'type': 'object', 'properties': {'language': {'type': 'string', 'description': "Language code hint (e.g. 'en', 'es'). Auto-detected if omitted."}}, 'description': "Options for mode='transcript'."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'clip_id'], 'properties': {'clip_id': {'type': 'string', 'description': 'Clip ID to auto-sync.'}, 'project_id': {'type': 'string', 'description': 'Project ID.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'action'], 'properties': {'text': {'type': 'string', 'description': 'edit / manual_add / manual_edit — the caption text.'}, 'action': {'enum': ['list', 'edit', 'reset', 'split', 'merge', 'timing', 'timing_reset', 'manual_add', 'manual_edit', 'manual_remove', 'translate', 'language'], 'type': 'string', 'description': 'What to do — see the tool description'}, 'end_time': {'type': 'number', 'minimum': 0, 'description': 'timing / manual_add / manual_edit — seconds from the start of the clip.'}, 'language': {'type': 'string', 'description': 'translate — language id ("fr") or name ("French"). language — a translated id, or "original".'}, 'caption_id': {'type': 'string', 'description': "manual_edit / manual_remove — from list's manual_captions."}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'The clip. Required for every action except translate/language, where omitting it means every clip.'}, 'project_id': {'type': 'string', 'description': 'The project ID'}, 'start_time': {'type': 'number', 'minimum': 0, 'description': 'timing / manual_add / manual_edit — seconds from the start of the clip.'}, 'split_word_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 1, 'description': 'split — the word that starts the new second caption.'}, 'start_word_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'edit/reset/split/merge/timing/timing_reset — the caption, exactly as list returned it.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['upload_token'], 'properties': {'upload_token': {'type': 'string', 'description': 'The upload_token returned by upload_file(request_hosted_upload: true)'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['name', 'visibility'], 'properties': {'name': {'type': 'string', 'description': 'Name of the clueprint'}, 'visibility': {'enum': ['private', 'workspace'], 'type': 'string', 'description': "'private' = only you, 'workspace' = everyone in your workspace"}, 'description': {'type': 'string', 'description': 'Description of what this clueprint does'}, 'source_guide_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'IDs of existing projects to extract template data from'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'properties': {'title': {'type': 'string', 'description': 'Project title'}, 'folder_id': {'type': 'string', 'description': "Optional folder ID to nest the project under. Use find(type='folders') to discover IDs. Omit to create at workspace root."}, 'description': {'type': 'string', 'description': 'Optional project description (max ~500 chars)'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['target_project_id', 'source_clip_id'], 'properties': {'after_clip_id': {'type': 'string', 'description': 'Insert after this clip ID in the target. Appends at end if omitted.'}, 'source_clip_id': {'type': 'string', 'description': 'ID of the clip to duplicate.'}, 'source_project_id': {'type': 'string', 'description': 'Cross-project mode: ID of the project the source clip lives in. Omit for same-project duplication.'}, 'target_project_id': {'type': 'string', 'description': 'Project (guide) ID to insert the duplicate into.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['source_project_id'], 'properties': {'folder_id': {'type': 'string', 'description': "Place the duplicate in this folder. Omit to keep the same folder as the source. Pass '' (empty string) to move to workspace root."}, 'new_title': {'type': 'string', 'description': 'Override the title of the duplicate.'}, 'source_project_id': {'type': 'string', 'description': 'Project (guide) ID to duplicate.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['texts'], 'properties': {'texts': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1, 'description': 'Array of voiceover texts to estimate — one string per clip.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id'], 'properties': {'fps': {'anyOf': [{'type': 'number', 'const': 24}, {'type': 'number', 'const': 30}, {'type': 'number', 'const': 60}], 'description': 'Frames per second (default 30)'}, 'captions': {'type': 'boolean', 'description': 'Burn subtitles into the video (default false)'}, 'project_id': {'type': 'string', 'description': 'The project ID to export'}, 'resolution': {'enum': ['720p', '1080p', '2k', '4k'], 'type': 'string', 'description': 'Output resolution (default 1080p)'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['type'], 'properties': {'id': {'type': 'string', 'description': 'Exact id — returns just that record.'}, 'page': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 1, 'description': 'Page (default 1) — projects/element_components/clueprints.'}, 'size': {'enum': ['large', 'medium', 'small'], 'type': 'string', 'description': 'stock videos only: minimum resolution bucket.'}, 'type': {'enum': ['projects', 'folders', 'clueprints', 'workspaces', 'backgrounds', 'voices', 'fonts', 'image_gen_style_packs', 'element_components', 'images', 'videos', 'music', 'sfx'], 'type': 'string', 'description': 'Resource type to find.'}, 'color': {'type': 'string', 'description': "stock images only: color name or hex, e.g. 'blue'."}, 'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1, 'description': "Page size (default 50; voices default 5 — a '_more' item flags further pages)."}, 'query': {'type': 'string', 'description': 'Case-insensitive substring match on name.'}, 'engine': {'type': 'string', 'description': "voices only: 'eleven' | 'cartesia' | 'google'."}, 'source': {'enum': ['org', 'stock', 'all'], 'type': 'string', 'description': "media types (images/videos/music/sfx) only: where to search — 'org' (your saved workspace media), 'stock' (stock library — images/videos via Pexels, music from Clueso's catalog), 'all' (both; default). sfx is stock-only."}, 'language': {'type': 'string', 'description': "voices only: e.g. 'en'."}, 'provider': {'enum': ['pexels', 'pixabay', 'clueso', 'freesound'], 'type': 'string', 'description': "stock media: which library to search (exactly one). images/videos: 'pexels' (default — polished real-world photos & footage) | 'pixabay' (illustrations, vectors, clip-art, icons + more variety; pair with image_type/video_type). music/sfx: 'clueso' (default for music — our curated, brand-safe, well-described library, best semantic search) | 'freesound' (huge community library; best for niche music and sound effects — default for sfx)."}, 'folder_id': {'type': 'string', 'description': 'projects/images/videos/music only: restrict to a folder.'}, 'mine_only': {'type': 'boolean', 'description': 'clueprints only: only ones I created.'}, 'creator_id': {'type': 'string', 'description': 'clueprints only: filter by creator id.'}, 'image_type': {'enum': ['photo', 'illustration', 'vector'], 'type': 'string', 'description': "stock images + provider='pixabay' only: 'photo' | 'illustration' | 'vector' (flat/drawn graphics, icons, clip-art). Use illustration/vector for graphic looks; photo (or Pexels) for realism."}, 'video_type': {'enum': ['film', 'animation'], 'type': 'string', 'description': "stock videos + provider='pixabay' only: 'film' (live footage) | 'animation' (motion graphics)."}, 'orientation': {'enum': ['landscape', 'portrait', 'square'], 'type': 'string', 'description': 'stock images/videos only: result orientation.'}, 'max_duration': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'stock videos + freesound audio: maximum clip length in seconds.'}, 'min_duration': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'stock videos only: minimum clip length in seconds.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['kind', 'project_id', 'clip_id', 'prompt', 'x', 'y', 'width', 'height'], 'properties': {'x': {'type': 'number', 'description': 'Top-left X in canvas pixels.'}, 'y': {'type': 'number', 'description': 'Top-left Y in canvas pixels.'}, 'kind': {'enum': ['image', 'animation'], 'type': 'string', 'description': "'image' = AI text-to-image; 'animation' = canvas-code-based motion graphic."}, 'model': {'enum': ['gemini-3-pro-image-preview', 'gemini-3.1-flash-image-preview', 'gemini-2.5-flash-image', 'gpt-image-2.5-flare', 'gpt-image-2.5-sunburst', 'gpt-image-2', 'gpt-image-1.5', 'gpt-image-1'], 'type': 'string', 'description': "Image only. Which image model renders it. Default `gemini-3-pro-image-preview` (Nano Banana Pro), a strong general choice — leave it off unless you want one of the specifics below. `gemini-3.1-flash-image-preview` (Nano Banana 2) and `gemini-2.5-flash-image` are faster and cheaper. `gpt-image-2.5-flare` is OpenAI's fast one, `gpt-image-2.5-sunburst` its most precise editor, and `gpt-image-2` is the one to reach for when the image must carry legible text or follow several reference images. `gpt-image-1` / `gpt-image-1.5` are the older pair and only accept square-ish framing — a wide box is snapped to 4:3 rather than honoured, so do not pick them for a banner. An unlisted value is rejected here rather than silently swapped for the default, which is what the backend does with one."}, 'width': {'type': 'number', 'description': 'Width in pixels.', 'exclusiveMinimum': 0}, 'height': {'type': 'number', 'description': 'Height in pixels.', 'exclusiveMinimum': 0}, 'prompt': {'type': 'string', 'minLength': 1, 'description': 'Generation prompt. For animations, be SPECIFIC: name the UI elements, interaction sequence, timing feel, and visual style. Vague prompts produce bad output.'}, 'clip_id': {'type': 'string', 'description': 'Clip ID to place the generated element into.'}, 'end_time': {'type': 'number', 'minimum': 0, 'description': 'Disappear at (seconds).'}, 'style_id': {'type': 'string', 'description': "Image only. Style preset ID from find(type='image_gen_style_packs'). See resource clueso://docs/generation-styles."}, 'background': {'anyOf': [{'type': 'boolean'}, {'enum': ['0', '1', 'true', 'false', 'yes', 'no'], 'type': 'string'}], 'description': 'Image only, and only honoured by `gpt-image-2.5-flare`, `gpt-image-2.5-sunburst`, `gpt-image-1` and `gpt-image-1.5` — every other model is always opaque and ignores this. Pass `false` for a cut-out with no background: icons, logos, stickers, anything meant to sit ON the composition rather than behind it. You MUST set `model` to one of those four in the same call; `gpt-image-2.5-flare` is the one to default to, since the older pair cannot frame wide. Asking for transparency in the PROMPT instead does not work — the model paints a grey-and-white checkerboard as real pixels.'}, 'project_id': {'type': 'string', 'description': 'Project ID.'}, 'start_time': {'type': 'number', 'minimum': 0, 'description': 'Appear at (seconds).'}, 'aspect_ratio': {'enum': ['1:1', '4:3', '3:4', '16:9', '9:16', '3:2', '2:3'], 'type': 'string', 'description': 'Image only. Overrides the ratio inferred from width/height. Leave it off and the box decides, which is usually what you want — set it when the box is a placeholder and you know the shape you need. Still clamped to what the model accepts: gpt-image-1/1.5 only do 1:1, 4:3 and 3:4; the gpt-image-2.5 pair adds 16:9 and 9:16; gpt-image-2 has no 3:2 or 2:3, so those become 4:3 and 3:4. The response does not report the ratio used.'}, 'mcp_upload_id': {'type': 'string', 'description': 'mcp_upload_id from the upload flow. Resolved server-side to a presigned URL before generation.'}, 'voiceover_text': {'type': 'string', 'description': "Animation only. Paces the motion to the spoken script — and as a side effect sets this clip's voiceover text and triggers speech generation for the clip. If the clip's current voiceover_text (get_clip) has <SYNC_MARKER N> tokens, this text must carry each of them once, in order, or the animation is refused."}, 'animation_setting': {'type': 'object', 'properties': {'exit': {'type': 'object', 'properties': {'preset': {'enum': ['slide', 'fade', 'pop', 'scale', 'masked_reveal', 'typewriter', 'none'], 'type': 'string', 'description': "Preset for this phase. 'typewriter' is char-only and has no direction."}, 'direction': {'enum': ['left', 'right', 'top', 'bottom', 'center_all', 'center_vertically', 'center_horizontally', 'none'], 'type': 'string', 'description': "Slide direction for this phase. Ignored by fade/scale/pop/typewriter; pass 'none' when the preset has no direction."}, 'apply_to_unit': {'enum': ['char', 'word', 'line', 'box'], 'type': 'string', 'description': "Granularity. 'typewriter' is restricted to 'char'."}, 'duration_per_unit_ms': {'type': 'number', 'minimum': 0, 'description': "NAME IS MISLEADING — this is the TOTAL duration of the phase in ms (NOT per unit). The renderer splits it across all N units with ~50% overlap. For a perceptible per-unit rhythm scale UP with the unit count (e.g. typewriter on N chars ≈ N × 100–200 ms). For applyToUnit='box' it's just the phase duration. Omit it and you get 400ms, the same default the editor creates with."}}, 'description': 'Exit (disappear) animation phase.'}, 'entry': {'type': 'object', 'properties': {'preset': {'enum': ['slide', 'fade', 'pop', 'scale', 'masked_reveal', 'typewriter', 'none'], 'type': 'string', 'description': "Preset for this phase. 'typewriter' is char-only and has no direction."}, 'direction': {'enum': ['left', 'right', 'top', 'bottom', 'center_all', 'center_vertically', 'center_horizontally', 'none'], 'type': 'string', 'description': "Slide direction for this phase. Ignored by fade/scale/pop/typewriter; pass 'none' when the preset has no direction."}, 'apply_to_unit': {'enum': ['char', 'word', 'line', 'box'], 'type': 'string', 'description': "Granularity. 'typewriter' is restricted to 'char'."}, 'duration_per_unit_ms': {'type': 'number', 'minimum': 0, 'description': "NAME IS MISLEADING — this is the TOTAL duration of the phase in ms (NOT per unit). The renderer splits it across all N units with ~50% overlap. For a perceptible per-unit rhythm scale UP with the unit count (e.g. typewriter on N chars ≈ N × 100–200 ms). For applyToUnit='box' it's just the phase duration. Omit it and you get 400ms, the same default the editor creates with."}}, 'description': 'Entry (appear) animation phase.'}}, 'description': "Image only. Entry/exit animation, same shape as add_elements' type_data.animation_setting. The design guide asks AI images to enter with `masked_reveal` or a slow fade, so set it here rather than following up with update_elements — that follow-up targets the element while it is still generating. Ignored for kind='animation', which animates through its generated code."}, 'base_component_id': {'type': 'string', 'description': "Animation only. Reuse a saved animation component as the starting point (from find(type='element_components')). To re-skin its tunable parameters, set parameter_values via update_elements after it renders."}, 'reference_image_url': {'type': 'string', 'description': 'Public URL of a reference image. Mutually exclusive with mcp_upload_id.'}}, 'additionalProperties': {}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id'], 'properties': {'project_id': {'type': 'string', 'description': 'Project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'clip_index'], 'properties': {'render': {'type': 'object', 'properties': {'save': {'type': 'boolean', 'description': "Also upload the rendered image to S3 and return presigned_url, which you can pass as source_url to update_clueprint (files=[{path, source_url}]). Uploads ONE image, so it works with a single frame or a grid but not with layout:'separate' — there is one URL and several frames."}, 'layout': {'enum': ['sheet', 'separate'], 'type': 'string', 'description': "Only meaningful when `timestamps` holds several. 'sheet' (default) tiles them into one image; 'separate' returns them full-size, which costs ~4x more — use it only when a grid cell is too small to judge."}, 'max_width': {'type': 'integer', 'maximum': 1568, 'minimum': 320, 'description': "Width in px of the IMAGE you get back — for a grid that is the whole grid, not each cell, so a cell is roughly a third of it. Default 960 for a single frame, 1280 for a grid. An image costs roughly (w×h)/750 tokens, so 1280 is ~1229 and 960 ~691; above 1568 nothing is gained because the model downscales to that anyway. The default is legible for this design system's type scale — a 40px canvas caption lands at ~20px. Raise it only to read genuinely small print, such as UI text inside a pasted screenshot."}, 'animations': {'type': 'boolean', 'description': 'Whether entry/exit animations play at this timestamp. Default true — the frame as the video will show it, which is what you want to judge motion. Pass false to draw every element settled at its final position and full opacity: use that to check COMPOSITION, because with staggered starts and short windows there may be no single timestamp at which nothing is mid-flight, and an element part-way through a slide reads as mis-positioned when it is fine.'}, 'timestamps': {'anyOf': [{'type': 'number', 'minimum': 0}, {'type': 'array', 'items': {'type': 'number', 'minimum': 0}, 'maxItems': 15, 'minItems': 1}], 'description': 'Which moment(s) of the clip to render, in seconds (default 0). Pass several — [0.5, 2, 4] — and they come back as one labelled grid costing about a quarter of what those frames cost individually. Prefer several whenever you are checking rather than reading: entry animations mean no single moment shows everything, so one frame is usually the wrong question. A grid cell is a third of the width, so for small print pass a single number. Max 15; duplicates dropped, sorted into time order.'}}, 'description': "Render the clip as an image. Presence of this object IS the request to render — omit it and nothing is rendered. `{}` renders at t=0. Independent of `select`, which only shapes the JSON: pair `select: []` with `render: {}` for the PNG alone (smallest read). CHECKING YOUR WORK: pass `timestamps` with SEVERAL mid-clip moments, not the t=0 default — text and image elements have entry animations (a ~0.4s slide/fade by default), so at t=0 they have not arrived yet and a correct edit renders as an empty frame, while shapes have no entry animation and do show at t=0. That mix is what makes a single t=0 render actively misleading: some elements appear and others don't. A list comes back as one grid for about a quarter of the tokens of the same frames separately, so checking several moments is the cheap option, not the expensive one. `animations: false` draws everything settled if you would rather not pick moments at all.", 'additionalProperties': False}, 'select': {'type': 'array', 'items': {'enum': ['elements', 'voiceover_words', 'groups', 'busy', 'elements.name', 'elements.element_type', 'elements.x', 'elements.y', 'elements.width', 'elements.height', 'elements.start_time', 'elements.end_time', 'elements.rotation', 'elements.keyframes', 'elements.textdata', 'elements.shapedata', 'elements.imagedata', 'elements.videodata', 'elements.zoomdata', 'elements.codedata', 'elements.parent_id', 'elements.dropShadows'], 'type': 'string'}, 'description': "Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes), 'busy' (generations still writing to this clip, as `[{entity_path, job_type}]` — EMPTY means nothing is pending, which is how you know a voiceover or AI image has landed; it is the same lock that would refuse your write, so a non-empty list also tells you what not to touch yet). Each section returns the key it is named after. Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id, dropShadows. y_top is text-only and present ONLY when alignment is 'center' — the unambiguous TOP edge, which is exactly the case where `y` is NOT the top but the vertical CENTRE. To put that position back, send it as `y` with y_anchor:'top'.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this."}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index'}, 'project_id': {'type': 'string', 'description': 'The project ID'}, 'element_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': "WHICH element rows to return — all others are dropped. Independent of `select`, which chooses the sections/keys. Use it to re-inspect just what you added or updated; most add_elements/update_elements already echo the element's resolved layout, so often you don't need this at all."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['clueprint_id'], 'properties': {'include': {'enum': ['metadata', 'tree', 'files', 'all'], 'type': 'string', 'default': 'tree', 'description': "What to return: 'metadata' | 'tree' | 'files' | 'all'. Defaults to 'tree'."}, 'file_paths': {'type': 'array', 'items': {'type': 'string', 'minLength': 1}, 'description': "include='files' only: relative paths to read (e.g. ['design/colors.md', 'rules/voice.md']). Ignored for other modes."}, 'clueprint_id': {'type': 'string', 'description': 'ID of the clueprint.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id'], 'properties': {'clip_id': {'type': 'string', 'description': 'Only comments pinned to this clip. Omit for every comment on the project, project-level ones included.'}, 'project_id': {'type': 'string', 'description': 'The project (guide) ID'}, 'include_resolved': {'type': 'boolean', 'description': 'Include threads already marked resolved (default false). Turn it on to see history; leave it off to see the work outstanding.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'properties': {}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['element_type'], 'properties': {'mode': {'enum': ['add', 'update'], 'type': 'string', 'default': 'add', 'description': "'add' returns required + optional fields; 'update' returns all-optional."}, 'fields': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Return only these fields, with their prose — text is 15KB whole, ~300 bytes for two. Omit while learning the type: only the full schema carries the keyframable list and the keyframe rules.'}, 'format': {'enum': ['declarations', 'json'], 'type': 'string', 'description': "Defaults to 'declarations' — TypeScript-style, which is the better READ. Inside run_script it defaults to 'json' instead, because a script indexes into the structure and the declaration text would arrive newline-escaped. Set it explicitly to override either default."}, 'element_type': {'enum': ['text', 'callout', 'rectangle', 'arrow', 'blur', 'spotlight', 'zoom', 'image', 'video', 'animation', 'group'], 'type': 'string', 'description': 'One of: text, callout, rectangle, arrow, blur, spotlight, zoom, image, video, animation, group'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'properties': {'export_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$', 'description': 'The export_id export_project returned. Omit when passing project_id.'}, 'project_id': {'type': 'string', 'description': "Check this project's most recently requested export instead. Omit when passing export_id."}, 'wait_seconds': {'type': 'integer', 'maximum': 55, 'minimum': 0, 'description': 'How long to wait for the export to complete or fail before answering, default 45s. Pass 0 for an immediate status check.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id'], 'properties': {'project_id': {'type': 'string', 'description': 'The project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['job_id'], 'properties': {'job_id': {'type': 'string', 'format': 'uuid', 'pattern': '^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$', 'description': 'From the run_script reply.'}, 'wait_seconds': {'type': 'integer', 'maximum': 55, 'minimum': 0, 'description': 'How long to wait for completion before answering, default 45s. Pass 0 for an immediate status check.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['guide_id', 'chat_id', 'preceding_clip_id', 'scenes'], 'properties': {'scenes': {'type': 'array', 'items': {'type': 'object', 'properties': {'exit': {'type': 'object', 'required': ['mode'], 'properties': {'mode': {'enum': ['hard', 'hold', 'freeze'], 'type': 'string', 'description': "'hard' (default), 'hold' or 'freeze' — how this scene ends. Consumed by AVS (contract: MULTI_VIDEO_MODE_CONTRACT.md in gigauser-backend-prod)."}}, 'description': 'How this scene ends.'}, 'pace': {'enum': ['quick', 'normal', 'hold'], 'type': 'string', 'description': "b-roll scenes ONLY — set to null on narrated scenes by the normalizer, so it has no effect there. Controls how long the scene dwells ('quick' | 'normal' | 'hold'); absent means unset, not 'normal'."}, 'type': {'enum': ['narrated', 'b-roll'], 'type': 'string', 'description': "Scene kind. 'narrated' carries a voiceover and requires narration_script; 'b-roll' is silent footage with no narration or article."}, 'entry': {'type': 'object', 'required': ['mode'], 'properties': {'mode': {'enum': ['fresh', 'continue'], 'type': 'string', 'description': "'fresh' (default) or 'continue' — how this scene begins relative to the previous one. Consumed by AVS (contract: MULTI_VIDEO_MODE_CONTRACT.md in gigauser-backend-prod)."}}, 'description': 'How this scene begins relative to the preceding one.'}, 'clip_name': {'type': 'string', 'description': 'Title for the clip this scene produces.'}, 'voice_name': {'type': 'string', 'description': "Voice to narrate this scene, from find(type='voices')."}, 'description': {'type': 'string', 'description': 'What should happen on screen during this scene.'}, 'voice_engine': {'type': 'string', 'description': "Speech engine used to render this scene's voice."}, 'article_script': {'type': 'string', 'description': 'Article text written into the written guide for this scene.'}, 'narration_script': {'type': 'string', 'description': 'Voiceover text spoken over this scene. Required for a narrated scene, omitted for b-roll.'}, 'video_script_mode': {'enum': ['rewrite', 'near_exact', 'exact'], 'type': 'string', 'description': 'How the narration is treated for this scene. Overrides the top-level setting for this scene.'}, 'exact_video_script': {'type': 'boolean', 'description': 'Legacy flag — prefer video_script_mode instead. When true, narration_script for this scene is used verbatim and left unreworded. Overrides the top-level setting for this scene.'}, 'article_script_mode': {'enum': ['rewrite', 'exact'], 'type': 'string', 'description': 'How the article is treated for this scene. Overrides the top-level setting for this scene.'}, 'custom_instructions': {'type': 'string', 'description': "Extra guidance for recording this scene only, e.g. 'select project X' or 'scroll to the pricing table'."}, 'exact_article_script': {'type': 'boolean', 'description': 'Legacy flag — prefer article_script_mode instead. When true, article_script for this scene is used verbatim and left unreworded. Overrides the top-level setting for this scene.'}}}, 'minItems': 1, 'description': 'REQUIRED — the recording to make, as a list of scenes. This is the ONLY way to specify what to record. A normal single recording is exactly ONE scene; a code-wizard multi-scene / marketing video is N scenes (one clip per scene, and ALL cuts of one video go in a SINGLE record_screen call). A narrated scene REQUIRES a non-empty narration_script; a b-roll scene is silent (no narration, no article). A cut that starts somewhere disconnected is just a scene with entry.mode "fresh". Cleopatra orgs accept exactly ONE narrated scene. Do not set scene_id — it is assigned server-side.'}, 'chat_id': {'type': 'string', 'description': 'Conversation context ID'}, 'guide_id': {'type': 'string', 'description': 'Target guide ID'}, 'language': {'type': 'string', 'default': 'en', 'description': 'Language code for the recording (default: en)'}, 'edit_scene_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'The clip id(s) this edit replaces. Only used when recording_session_id is set; scenes you do not name are not re-filmed. Set preceding_clip_id to the clip you are replacing — an edit naming a clip that is not in the guide is refused rather than appended to the end.'}, 'video_intention': {'type': 'string', 'default': '', 'description': 'One-line intent shared across all scenes of a multi-scene recording (e.g. "punchy 30s launch teaser for feature X"). Ignored for single-scene recordings.'}, 'preceding_clip_id': {'type': 'string', 'description': 'Clip ID after which to insert the new clip'}, 'video_script_mode': {'enum': ['rewrite', 'near_exact', 'exact'], 'type': 'string', 'description': "How the narration is treated. 'exact': the user's narration is final and is read word for word; steps the script does not mention play silently. 'near_exact': keep the user's narration word for word, but briefly narrate steps the recording must take that the script does not mention (for example opening a settings dialog to reach something) — use this when the user gives a finished script and did not ask for strictly exact wording. 'rewrite': the narration is a draft and may be reworded to match what was recorded — use this when there is no user script or it is rough. Overrides exact_video_script when both are set."}, 'exact_video_script': {'type': 'boolean', 'default': False, 'description': 'Legacy flag — prefer video_script_mode instead. Set to true when the video narration must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite video_script at all. Default false.'}, 'article_script_mode': {'enum': ['rewrite', 'exact'], 'type': 'string', 'description': "'exact': the article is used word for word. 'rewrite': the article may be reworded to match the recording. Overrides exact_article_script when both are set."}, 'custom_instructions': {'type': 'string', 'default': '', 'description': 'Optional per-recording instructions (e.g. "select project X", "add rectangle 200x100"). Not related to mocking.'}, 'exact_article_script': {'type': 'boolean', 'default': False, 'description': 'Legacy flag — prefer article_script_mode instead. Set to true when the article must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite article_script at all. Default false.'}, 'recording_session_id': {'type': 'string', 'description': "EDIT an existing recording instead of shooting a new one. Pass the recording_session_id from the record_screen that made it, or read it off get_clip. The recorder restores that take's code, notes and click script and changes only what you ask for, which is far faster and cheaper than re-recording. Omit for a fresh recording. Only code-wizard recordings are editable; get_clip omits the field for any clip that is not."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'clip_index'], 'properties': {'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index to remove'}, 'project_id': {'type': 'string', 'description': 'The project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'removals'], 'properties': {'removals': {'type': 'array', 'items': {'type': 'object', 'required': ['clip_index', 'element_id'], 'properties': {'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index'}, 'element_id': {'type': 'string', 'description': 'Element ID (from get_clip)'}}, 'additionalProperties': False}, 'minItems': 1, 'description': 'Elements to remove — at least one entry.'}, 'project_id': {'type': 'string', 'description': 'Project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'target'], 'properties': {'target': {'enum': ['element', 'group', 'audio'], 'type': 'string', 'description': "What to remove: 'element', 'group' or 'audio'"}, 'group_id': {'type': 'string', 'description': "Group ID to remove (required for target='group')"}, 'music_id': {'type': 'string', 'description': "Music/SFX track ID to remove (required for target='audio')"}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': "Zero-based clip index. Required for target='group'; for target='element' an optional hint — the element is found by id either way"}, 'element_id': {'type': 'string', 'description': "Element ID to remove (target='element'; or use element_ids)"}, 'project_id': {'type': 'string', 'description': 'The project ID'}, 'element_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': "Several element IDs to remove (target='element'). Removed one at a time, so a failure part-way leaves the earlier ones removed; retrying the same list is safe — ids already gone come back as already_absent. For a large batch prefer remove_elements, which lands in one save"}, 'keep_children': {'type': 'boolean', 'description': "target='group' only. Omit/true ungroups: children rise to the removed group's own parent. false deletes the whole subtree."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'clip_index', 'ordered_element_ids'], 'properties': {'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index.'}, 'project_id': {'type': 'string', 'description': 'Project ID.'}, 'ordered_element_ids': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1, 'description': 'All element IDs currently in the clip, in the new order. Position N = z-index N (later = on top).'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['code'], 'properties': {'code': {'type': 'string', 'maxLength': 40000, 'minLength': 1, 'description': 'JavaScript. Tools are globals called synchronously — no async/await, no imports, no network or filesystem. `return` a value to hand it back.'}, 'dry_run': {'type': 'boolean', 'description': 'Read-only tools still run; anything that writes is recorded and skipped. Use it to check what a script would do before it does it.'}, 'wait_seconds': {'type': 'integer', 'maximum': 55, 'minimum': 1, 'description': 'How long to hold this call open waiting for the script, default 45s. If it finishes in time you get the result here; if not you get a job_id to poll with get_script_job, and the script keeps running either way.'}, 'idempotency_key': {'type': 'string', 'maxLength': 200, 'minLength': 8, 'description': 'Pass a unique string so a retry cannot run the same build twice. If a script with this key already ran in this workspace, its job is returned and nothing executes again — including when that run FAILED, because a script is not a transaction and the writes it made before failing are still there. To act after a failure, read the project, repair what landed, and use a NEW key. Worth setting for anything that builds.'}, 'timeout_seconds': {'type': 'integer', 'maximum': 900, 'minimum': 5, 'description': "Wall-clock budget for the SCRIPT — separate from wait_seconds, which is only how long this call stays open. By default a script gets 45s while you are waiting on it, and is raised to 5 minutes the moment it outlives the wait and becomes a job you poll with get_script_job. Set this only to override BOTH with one fixed budget. Watch the slow tools: analyze_audio in 'transcript' or 'beats' mode, export_project and auto_sync take tens of seconds each and will eat a budget fast, and get_export holds for its wait_seconds (pass 0 inside a script). analyze_audio in 'features' mode is ~1s and is fine to loop over."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'voice_name', 'voice_engine'], 'properties': {'project_id': {'type': 'string', 'description': 'The project (guide) ID'}, 'voice_name': {'type': 'string', 'minLength': 1, 'description': "Voice name as stored in the voices table (e.g. 'Alex', 'Sofia')"}, 'voice_engine': {'type': 'string', 'minLength': 1, 'description': "Voice engine — 'eleven', 'cartesia', 'google', etc."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'clip_index', 'split_time'], 'properties': {'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Index of the clip to split'}, 'project_id': {'type': 'string', 'description': 'The project ID'}, 'split_time': {'type': 'number', 'description': 'Time in seconds within the clip where to split (clip-relative, not timeline-relative). Must be > 0.1s and < clip_duration − 0.1s; values outside this range are rejected.', 'exclusiveMinimum': 0.1}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['workspaceId'], 'properties': {'workspaceId': {'type': 'string', 'description': 'Workspace ID to switch to'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'markdown'], 'properties': {'markdown': {'type': 'string', 'description': 'Updated article content as markdown with <SCREENSHOT {id}> placeholders'}, 'project_id': {'type': 'string', 'description': 'Project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'screenshot_id'], 'properties': {'crop': {'type': 'object', 'description': 'Crop data: { position: [x,y], size: [w,h] } in fractional coords.', 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'render': {'type': 'boolean', 'description': 'If true (and no other updates supplied), returns current details and a PNG preview without mutating.'}, 'shapes': {'type': 'array', 'items': {'type': 'object', 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'description': 'Array of shape objects for annotations.'}, 'project_id': {'type': 'string', 'description': 'Project ID.'}, 'zoom_factor': {'type': 'number', 'minimum': 1, 'description': 'Zoom magnification (1.0 = no zoom).'}, 'screenshot_id': {'type': 'string', 'description': 'Screenshot ID (from get_article).'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'music_id'], 'properties': {'loop': {'anyOf': [{'type': 'boolean'}, {'enum': ['0', '1', 'true', 'false', 'yes', 'no'], 'type': 'string'}], 'description': 'Whether the track loops'}, 'volume': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'New playback volume 0-100'}, 'fade_in': {'type': 'number', 'minimum': 0, 'description': 'Fade-in duration (seconds)'}, 'fade_out': {'type': 'number', 'minimum': 0, 'description': 'Fade-out duration (seconds)'}, 'music_id': {'type': 'string', 'description': 'ID of the audio track (from get_project.audio_tracks[].id)'}, 'project_id': {'type': 'string', 'description': 'The project ID'}, 'guide_end_time': {'type': 'number', 'minimum': 0, 'description': 'New end time on the project timeline (seconds)'}, 'music_end_time': {'type': 'number', 'minimum': 0, 'description': 'New end offset within the source file (seconds)'}, 'guide_start_time': {'type': 'number', 'minimum': 0, 'description': 'New start time on the project timeline (seconds)'}, 'music_start_time': {'type': 'number', 'minimum': 0, 'description': 'New start offset within the source file (seconds)'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'updates'], 'properties': {'updates': {'type': 'array', 'items': {'type': 'object', 'required': ['clip_index'], 'properties': {'title': {'type': 'string', 'description': 'New clip title'}, 'hidden': {'anyOf': [{'type': 'boolean'}, {'enum': ['0', '1', 'true', 'false', 'yes', 'no'], 'type': 'string'}], 'description': 'Whether the clip is hidden'}, 'duration': {'type': 'number', 'description': 'New duration (seconds)', 'exclusiveMinimum': 0}, 'position': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Move clip to this zero-based index'}, 'background': {'type': 'object', 'description': "Full background object from find(type='backgrounds')", 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index'}, 'transition': {'anyOf': [{'type': 'object', 'required': ['type', 'duration'], 'properties': {'type': {'enum': ['circleWipe', 'rainbowWipe', 'cornerWipe', 'stack', 'colorWipe', 'dissolve', 'pushPull', 'fadeToColor'], 'type': 'string', 'description': "Transition style. NOTE: a clip's transition plays at the END of that clip, into the next one — to put a transition between clips 2 and 3, set it on clip 2."}, 'color': {'type': 'string', 'description': 'Hex color, honoured by fadeToColor (default #000000), colorWipe (default #073cad) and rainbowWipe (default #D43F8C).'}, 'duration': {'type': 'number', 'description': 'Transition length in seconds.', 'exclusiveMinimum': 0}, 'direction': {'type': 'string', 'description': 'Direction, honoured only by some types: rainbowWipe and cornerWipe take topLeft/topRight/bottomLeft/bottomRight (default topRight); colorWipe takes left or right (default right); stack and pushPull take left/right/top/bottom (default right). Ignored by dissolve, circleWipe and fadeToColor.'}}}, {'type': 'null'}], 'description': 'Transition at the END of this clip, into the next one; null to remove'}, 'video_styling': {'type': 'object', 'properties': {'crop': {'anyOf': [{'type': 'object', 'required': ['position', 'size'], 'properties': {'size': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 2, 'minItems': 2, 'description': '[width, height] as fractions of natural size (0–1).'}, 'position': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 2, 'minItems': 2, 'description': '[left, top] as fractions of natural size (0–1).'}}}, {'type': 'null'}], 'description': 'Footage crop rect in fractional coords (0–1), or null to clear.'}, 'size': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 2, 'minItems': 2, 'description': 'Footage [width,height] as canvas fractions 0–1 ([1,1] = full-bleed).'}, 'border': {'anyOf': [{'type': 'object', 'required': ['type'], 'properties': {'type': {'enum': ['none', 'solid', 'glass', 'animated', 'browser'], 'type': 'string', 'description': "Border style. 'none' = no border."}, 'color': {'type': 'string', 'description': 'Border color hex (defaults to brand color).'}, 'borderWidth': {'type': 'number', 'minimum': 0, 'description': 'Border width in pixels.'}, 'border_width': {'type': 'number', 'minimum': 0, 'description': 'Snake-case alias for borderWidth. Border width in pixels.'}}}, {'type': 'null'}], 'description': 'Frame around the footage ({type, color?, borderWidth?} — border_width also accepted), or null to clear.'}, 'position': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 2, 'minItems': 2, 'description': 'Footage center [x,y] as canvas fractions 0–1 (0.5,0.5 = centered).'}}, 'description': "VIDEO CLIPS ONLY: reposition/resize the screen recording on the canvas (e.g. into a designed window slot). position/size are canvas fractions 0–1; [1,1] = full-bleed. Fields merge onto the clip's existing video_styling. Ignored for slide clips."}, 'background_color': {'type': 'string', 'description': 'Hex background color (keeps pattern, changes color)'}, 'voiceover_volume': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'Narration loudness for this clip, 0-100 (default 100). Set 0 for a silent cut — this MUTES the voiceover without deleting it, so the text and its word timings survive and you can restore it by setting the volume back. No-op on a clip that has no voiceover.'}}}, 'minItems': 1, 'description': 'One entry per clip to update.'}, 'project_id': {'type': 'string', 'description': 'Project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['clueprint_id'], 'properties': {'name': {'type': 'string', 'description': 'New name.'}, 'tags': {'type': 'array', 'items': {'type': 'string'}, 'description': 'New tags (replaces existing).'}, 'files': {'type': 'array', 'items': {'type': 'object', 'required': ['path'], 'properties': {'path': {'type': 'string', 'description': "Relative file path (e.g. 'design/colors.md', 'screenshots/intro.png')."}, 'content': {'type': ['string', 'null'], 'description': "Text content, or base64-encoded binary if encoding='base64'. Set to null to DELETE this path. Omit (with source_url) when writing from a URL."}, 'encoding': {'enum': ['base64'], 'type': 'string', 'description': "Set to 'base64' for binary files like images."}, 'source_url': {'type': 'string', 'description': 'Presigned URL to download the file from. Server fetches and saves it. Use this instead of inline content for large/binary files.'}}}, 'description': 'File mutations — writes and deletes. Empty/omitted for metadata-only updates.'}, 'visibility': {'enum': ['private', 'workspace'], 'type': 'string', 'description': 'New visibility.'}, 'description': {'type': 'string', 'description': 'New description.'}, 'clueprint_id': {'type': 'string', 'description': 'ID of the clueprint to update.'}, 'thumbnail_path': {'type': 'string', 'description': "Relative path of a screenshot in the clueprint to use as thumbnail (e.g. 'screenshots/title-slide.png')."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'updates'], 'properties': {'updates': {'type': 'array', 'items': {'type': 'object', 'required': ['element_id'], 'properties': {'x': {'type': 'number', 'description': 'New X (canvas pixels). Same origin as add_elements: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right. Changing alignment in the same call re-anchors x to the new edge.'}, 'y': {'type': 'number', 'description': 'New Y (canvas pixels) — for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. See y_anchor.'}, 'name': {'type': 'string', 'description': 'New label for the element.'}, 'group': {'type': 'string', 'description': 'Move this element into a named group, creating it if this clip has none by that name. Pass an empty string to pull it back out to the clip root. Omit to leave grouping unchanged. Grouping never moves anything — coordinates stay absolute.'}, 'width': {'type': 'number', 'minimum': 0, 'description': 'New width, pixels (0 allowed — e.g. a bar that draws in from 0). For text this is the wrap width and re-wraps the text.'}, 'height': {'type': 'number', 'minimum': 0, 'description': 'New height, pixels (0 allowed). For text, the space you are giving it — the box resizes to the measured text. See layout.fits_height in the response.'}, 'end_time': {'type': 'number', 'minimum': 0, 'description': 'New time the element disappears, in seconds from the start of the clip.'}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees'}, 'y_anchor': {'enum': ['top', 'center', 'bottom'], 'type': 'string', 'description': "TEXT only. ALWAYS send `y_anchor` ('top'|'center'|'bottom') when you set `y` on text, so the position states what you meant instead of inheriting the alignment origin. Omit `y` and it anchors to the element's CURRENT box, holding a centred label centred across a re-measure. Not stored — state it on every call. (Also accepted inside type_data; this one wins.)"}, 'insert_at': {'anyOf': [{'enum': ['front', 'back'], 'type': 'string'}, {'type': 'object', 'required': ['before'], 'properties': {'before': {'type': 'string', 'minLength': 1}}, 'additionalProperties': False}, {'type': 'object', 'required': ['after'], 'properties': {'after': {'type': 'string', 'minLength': 1}}, 'additionalProperties': False}], 'description': "Move this element in z-order, without rebuilding it. `front`/`back` are the ends of the group it is already in (the clip itself for an ungrouped element), so they never change what it belongs to — with one exception: for an element that is ALONE in its group they move the GROUP within its parent scope, because positioning a sole member inside its own group would be a no-op. `{before: element_id}` / `{after: element_id}` sit it next to that element or group and put it in THAT node's group — which is how you move something into or out of a group and position it in one call. Applied after `group` when both are passed."}, 'keyframes': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['timestamp'], 'properties': {'blur': {'type': 'number', 'description': 'Layer blur'}, 'cropX': {'type': 'number', 'description': 'cropX (native unit)'}, 'cropY': {'type': 'number', 'description': 'cropY (native unit)'}, 'width': {'type': 'number', 'minimum': 0, 'description': 'Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)'}, 'bezier': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4, 'description': "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'."}, 'height': {'type': 'number', 'minimum': 0, 'description': 'Height in canvas pixels (0 allowed)'}, 'scaleX': {'type': 'number', 'description': 'Horizontal scale multiplier (1 = 100%)'}, 'scaleY': {'type': 'number', 'description': 'Vertical scale multiplier (1 = 100%)'}, 'opacity': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'Opacity 0-100'}, 'rotateX': {'type': 'number', 'description': 'rotateX (native unit)'}, 'rotateY': {'type': 'number', 'description': 'rotateY (native unit)'}, 'fontSize': {'type': 'number', 'description': 'Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).'}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees'}, 'cropWidth': {'type': 'number', 'description': 'cropWidth (native unit)'}, 'fillColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'fillColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'positionX': {'type': 'number', 'description': "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right."}, 'positionY': {'type': 'number', 'description': "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y."}, 'strokeGap': {'type': 'number', 'description': 'strokeGap in canvas pixels'}, 'textColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'timestamp': {'type': 'number', 'minimum': 0, 'description': 'Clip-relative time in seconds'}, 'cropHeight': {'type': 'number', 'description': 'cropHeight (native unit)'}, 'lineHeight': {'type': 'number', 'description': 'lineHeight (native unit)'}, 'paddingTop': {'type': 'number', 'description': 'paddingTop in canvas pixels'}, 'shadowBlur': {'type': 'number', 'description': 'shadowBlur in canvas pixels'}, 'strokeDash': {'type': 'number', 'description': 'strokeDash in canvas pixels'}, 'paddingLeft': {'type': 'number', 'description': 'paddingLeft in canvas pixels'}, 'shadowColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeWidth': {'type': 'number', 'description': 'strokeWidth in canvas pixels'}, 'paddingRight': {'type': 'number', 'description': 'paddingRight in canvas pixels'}, 'shadowSpread': {'type': 'number', 'description': 'shadowSpread in canvas pixels'}, 'interpolation': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string', 'description': 'Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.'}, 'letterSpacing': {'type': 'number', 'description': 'Letter spacing in canvas pixels.'}, 'paddingBottom': {'type': 'number', 'description': 'paddingBottom in canvas pixels'}, 'shadowOffsetX': {'type': 'number', 'description': 'shadowOffsetX in canvas pixels'}, 'shadowOffsetY': {'type': 'number', 'description': 'shadowOffsetY in canvas pixels'}, 'strokeTrimEnd': {'type': 'number', 'description': 'strokeTrimEnd (native unit)'}, 'textStrokeGap': {'type': 'number', 'description': 'textStrokeGap in canvas pixels'}, 'backgroundBlur': {'type': 'number', 'description': 'Backdrop blur behind the element'}, 'textStrokeDash': {'type': 'number', 'description': 'textStrokeDash in canvas pixels'}, 'strokeTrimStart': {'type': 'number', 'description': 'strokeTrimStart (native unit)'}, 'textStrokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textStrokeWidth': {'type': 'number', 'description': 'textStrokeWidth in canvas pixels'}, 'bezier_overrides': {'type': 'object', 'description': 'Per-property cubic-bezier override, e.g. {"opacity":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4}}, 'imageBorderColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'imageBorderWidth': {'type': 'number', 'description': 'imageBorderWidth in canvas pixels'}, 'strokeTrimOffset': {'type': 'number', 'description': 'strokeTrimOffset (native unit)'}, 'borderRadiusTopLeft': {'type': 'number', 'description': 'borderRadiusTopLeft in canvas pixels'}, 'textBackgroundColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textBgRadiusTopLeft': {'type': 'number', 'description': 'textBgRadiusTopLeft in canvas pixels'}, 'borderRadiusTopRight': {'type': 'number', 'description': 'borderRadiusTopRight in canvas pixels'}, 'textBgRadiusTopRight': {'type': 'number', 'description': 'textBgRadiusTopRight in canvas pixels'}, 'borderRadiusBottomLeft': {'type': 'number', 'description': 'borderRadiusBottomLeft in canvas pixels'}, 'textBgRadiusBottomLeft': {'type': 'number', 'description': 'textBgRadiusBottomLeft in canvas pixels'}, 'borderRadiusBottomRight': {'type': 'number', 'description': 'borderRadiusBottomRight in canvas pixels'}, 'interpolation_overrides': {'type': 'object', 'description': 'Per-property easing override, e.g. {"opacity":"linear"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string'}}, 'textBgRadiusBottomRight': {'type': 'number', 'description': 'textBgRadiusBottomRight in canvas pixels'}, 'imageCornerRadiusTopLeft': {'type': 'number', 'description': 'imageCornerRadiusTopLeft in canvas pixels'}, 'videoCornerRadiusTopLeft': {'type': 'number', 'description': 'videoCornerRadiusTopLeft in canvas pixels'}, 'imageCornerRadiusTopRight': {'type': 'number', 'description': 'imageCornerRadiusTopRight in canvas pixels'}, 'videoCornerRadiusTopRight': {'type': 'number', 'description': 'videoCornerRadiusTopRight in canvas pixels'}, 'imageCornerRadiusBottomLeft': {'type': 'number', 'description': 'imageCornerRadiusBottomLeft in canvas pixels'}, 'videoCornerRadiusBottomLeft': {'type': 'number', 'description': 'videoCornerRadiusBottomLeft in canvas pixels'}, 'imageCornerRadiusBottomRight': {'type': 'number', 'description': 'imageCornerRadiusBottomRight in canvas pixels'}, 'videoCornerRadiusBottomRight': {'type': 'number', 'description': 'videoCornerRadiusBottomRight in canvas pixels'}}, 'additionalProperties': False}}, {'type': 'null'}], 'description': 'Set keyframes for this element. Only the property tracks present in your entries are replaced — other tracks (color/rotation/typography/…) are preserved. Pass null OR an empty array to clear ALL keyframes. Same per-entry shape as add_elements; see get_element_schema for the keyframable properties of this element_type.'}, 'parent_id': {'type': ['string', 'null'], 'description': "The parent `get_clip` reports on this element: a group id, or the clip id for an ungrouped element. Accepted so a read round-trips unedited — the element's current parent is a no-op and leaves z-order alone. A different group id on this element's clip moves it there (the group must have a name); the clip id or null moves it to the root. Use `group` when you are choosing a group — the name is the handle. `group` wins if both are sent."}, 'type_data': {'type': 'object', 'description': 'Type-specific updates. When provided, element_type is required. Get the schema via get_element_schema.', 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index. OPTIONAL — `element_id` is unique within the project, so the server finds the clip itself. Pass it only as a fast-path hint; a wrong one is corrected rather than rejected.'}, 'element_id': {'type': 'string', 'description': 'Element ID (from get_clip)'}, 'start_time': {'type': 'number', 'minimum': 0, 'description': 'New time the element appears, in seconds from the start of the clip.'}, 'element_type': {'enum': ['text', 'callout', 'rectangle', 'arrow', 'blur', 'spotlight', 'zoom', 'image', 'video', 'animation'], 'type': 'string', 'description': "Required only when providing type_data. Use get_element_schema in 'update' mode to see fields."}, 'fit_to_lines': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 1, 'description': "Text elements only. Target line count for the element. After this entry's regular updates land, the server widens (then font-shrinks if widen can't fit) the element so the rendered text wraps to at most N lines without overlapping its neighbours. Uses the same compute path as director's fit_text_layout."}, 'keyframes_repeat': {'type': 'object', 'required': ['count'], 'properties': {'mode': {'enum': ['loop', 'pingpong'], 'type': 'string', 'description': "'loop' (default) replays the cycle forwards every time — seamless only if your first and last values match. 'pingpong' alternates forwards/backwards, so the value always returns to where it started without a jump; use it for a breathe/pulse written as a one-way ramp."}, 'count': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 1, 'description': 'TOTAL number of cycles, INCLUDING the one you wrote. 1 is a no-op. Expansion stops at the clip end rather than piling the overflow onto the last frame, and the generated total is capped at 600 keyframes (it errors rather than silently truncating).'}, 'every': {'type': 'number', 'description': "Seconds between cycle STARTS. Defaults to the cycle's own span (back-to-back). A LARGER value holds the last value in the gap — that is how you get a pulse every 2s instead of a constant wobble. Shorter than the cycle is rejected, because the cycles would overlap and collide on the same frames.", 'exclusiveMinimum': 0}}, 'description': 'Repeat `keyframes` as a cycle — { count, mode?, every? }. Requires `keyframes` in the same call.', 'additionalProperties': False}, 'save_as_component': {'type': ['boolean', 'string'], 'description': 'Animation elements only. Set true to save the current state as a reusable animation component (auto-named from the animation title), or pass a string to name it explicitly. Save runs AFTER any position/type_data updates land. Returns the component_id alongside the per-update result.'}}, 'additionalProperties': False}, 'minItems': 1, 'description': 'Element updates — at least one entry.'}, 'defaults': {'type': 'object', 'properties': {'x': {'type': 'number'}, 'y': {'type': 'number'}, 'group': {'type': 'string', 'minLength': 1}, 'width': {'type': 'number', 'minimum': 0}, 'height': {'type': 'number', 'minimum': 0}, 'clip_id': {'type': 'string'}, 'end_time': {'type': 'number', 'minimum': 0}, 'rotation': {'type': 'number'}, 'insert_at': {'enum': ['front', 'back'], 'type': 'string'}, 'keyframes': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['timestamp'], 'properties': {'blur': {'type': 'number', 'description': 'Layer blur'}, 'cropX': {'type': 'number', 'description': 'cropX (native unit)'}, 'cropY': {'type': 'number', 'description': 'cropY (native unit)'}, 'width': {'type': 'number', 'minimum': 0, 'description': 'Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)'}, 'bezier': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4, 'description': "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'."}, 'height': {'type': 'number', 'minimum': 0, 'description': 'Height in canvas pixels (0 allowed)'}, 'scaleX': {'type': 'number', 'description': 'Horizontal scale multiplier (1 = 100%)'}, 'scaleY': {'type': 'number', 'description': 'Vertical scale multiplier (1 = 100%)'}, 'opacity': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': 'Opacity 0-100'}, 'rotateX': {'type': 'number', 'description': 'rotateX (native unit)'}, 'rotateY': {'type': 'number', 'description': 'rotateY (native unit)'}, 'fontSize': {'type': 'number', 'description': 'Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).'}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees'}, 'cropWidth': {'type': 'number', 'description': 'cropWidth (native unit)'}, 'fillColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'fillColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'positionX': {'type': 'number', 'description': "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right."}, 'positionY': {'type': 'number', 'description': "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y."}, 'strokeGap': {'type': 'number', 'description': 'strokeGap in canvas pixels'}, 'textColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'timestamp': {'type': 'number', 'minimum': 0, 'description': 'Clip-relative time in seconds'}, 'cropHeight': {'type': 'number', 'description': 'cropHeight (native unit)'}, 'lineHeight': {'type': 'number', 'description': 'lineHeight (native unit)'}, 'paddingTop': {'type': 'number', 'description': 'paddingTop in canvas pixels'}, 'shadowBlur': {'type': 'number', 'description': 'shadowBlur in canvas pixels'}, 'strokeDash': {'type': 'number', 'description': 'strokeDash in canvas pixels'}, 'paddingLeft': {'type': 'number', 'description': 'paddingLeft in canvas pixels'}, 'shadowColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'strokeWidth': {'type': 'number', 'description': 'strokeWidth in canvas pixels'}, 'paddingRight': {'type': 'number', 'description': 'paddingRight in canvas pixels'}, 'shadowSpread': {'type': 'number', 'description': 'shadowSpread in canvas pixels'}, 'interpolation': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string', 'description': 'Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.'}, 'letterSpacing': {'type': 'number', 'description': 'Letter spacing in canvas pixels.'}, 'paddingBottom': {'type': 'number', 'description': 'paddingBottom in canvas pixels'}, 'shadowOffsetX': {'type': 'number', 'description': 'shadowOffsetX in canvas pixels'}, 'shadowOffsetY': {'type': 'number', 'description': 'shadowOffsetY in canvas pixels'}, 'strokeTrimEnd': {'type': 'number', 'description': 'strokeTrimEnd (native unit)'}, 'textStrokeGap': {'type': 'number', 'description': 'textStrokeGap in canvas pixels'}, 'backgroundBlur': {'type': 'number', 'description': 'Backdrop blur behind the element'}, 'textStrokeDash': {'type': 'number', 'description': 'textStrokeDash in canvas pixels'}, 'strokeTrimStart': {'type': 'number', 'description': 'strokeTrimStart (native unit)'}, 'textStrokeColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textStrokeWidth': {'type': 'number', 'description': 'textStrokeWidth in canvas pixels'}, 'bezier_overrides': {'type': 'object', 'description': 'Per-property cubic-bezier override, e.g. {"opacity":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4}}, 'imageBorderColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'imageBorderWidth': {'type': 'number', 'description': 'imageBorderWidth in canvas pixels'}, 'strokeTrimOffset': {'type': 'number', 'description': 'strokeTrimOffset (native unit)'}, 'borderRadiusTopLeft': {'type': 'number', 'description': 'borderRadiusTopLeft in canvas pixels'}, 'textBackgroundColor': {'type': 'string', 'pattern': '^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$', 'description': 'textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)'}, 'textBgRadiusTopLeft': {'type': 'number', 'description': 'textBgRadiusTopLeft in canvas pixels'}, 'borderRadiusTopRight': {'type': 'number', 'description': 'borderRadiusTopRight in canvas pixels'}, 'textBgRadiusTopRight': {'type': 'number', 'description': 'textBgRadiusTopRight in canvas pixels'}, 'borderRadiusBottomLeft': {'type': 'number', 'description': 'borderRadiusBottomLeft in canvas pixels'}, 'textBgRadiusBottomLeft': {'type': 'number', 'description': 'textBgRadiusBottomLeft in canvas pixels'}, 'borderRadiusBottomRight': {'type': 'number', 'description': 'borderRadiusBottomRight in canvas pixels'}, 'interpolation_overrides': {'type': 'object', 'description': 'Per-property easing override, e.g. {"opacity":"linear"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.', 'propertyNames': {'enum': ['positionX', 'positionY', 'width', 'height', 'rotation', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'cropX', 'cropY', 'cropWidth', 'cropHeight', 'opacity', 'blur', 'backgroundBlur', 'strokeWidth', 'strokeDash', 'strokeGap', 'strokeTrimStart', 'strokeTrimEnd', 'strokeTrimOffset', 'textStrokeWidth', 'textStrokeDash', 'textStrokeGap', 'imageBorderWidth', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowSpread', 'borderRadiusTopLeft', 'borderRadiusTopRight', 'borderRadiusBottomRight', 'borderRadiusBottomLeft', 'imageCornerRadiusTopLeft', 'imageCornerRadiusTopRight', 'imageCornerRadiusBottomRight', 'imageCornerRadiusBottomLeft', 'videoCornerRadiusTopLeft', 'videoCornerRadiusTopRight', 'videoCornerRadiusBottomRight', 'videoCornerRadiusBottomLeft', 'fontSize', 'lineHeight', 'letterSpacing', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'textBgRadiusTopLeft', 'textBgRadiusTopRight', 'textBgRadiusBottomRight', 'textBgRadiusBottomLeft', 'fillColor', 'strokeColor', 'textStrokeColor', 'imageBorderColor', 'textColor', 'textBackgroundColor', 'shadowColor'], 'type': 'string'}, 'additionalProperties': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string'}}, 'textBgRadiusBottomRight': {'type': 'number', 'description': 'textBgRadiusBottomRight in canvas pixels'}, 'imageCornerRadiusTopLeft': {'type': 'number', 'description': 'imageCornerRadiusTopLeft in canvas pixels'}, 'videoCornerRadiusTopLeft': {'type': 'number', 'description': 'videoCornerRadiusTopLeft in canvas pixels'}, 'imageCornerRadiusTopRight': {'type': 'number', 'description': 'imageCornerRadiusTopRight in canvas pixels'}, 'videoCornerRadiusTopRight': {'type': 'number', 'description': 'videoCornerRadiusTopRight in canvas pixels'}, 'imageCornerRadiusBottomLeft': {'type': 'number', 'description': 'imageCornerRadiusBottomLeft in canvas pixels'}, 'videoCornerRadiusBottomLeft': {'type': 'number', 'description': 'videoCornerRadiusBottomLeft in canvas pixels'}, 'imageCornerRadiusBottomRight': {'type': 'number', 'description': 'imageCornerRadiusBottomRight in canvas pixels'}, 'videoCornerRadiusBottomRight': {'type': 'number', 'description': 'videoCornerRadiusBottomRight in canvas pixels'}}, 'additionalProperties': False}}, {'type': 'null'}]}, 'type_data': {'type': 'object', 'propertyNames': {'type': 'string'}, 'additionalProperties': {}}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0}, 'start_time': {'type': 'number', 'minimum': 0}, 'element_type': {'enum': ['text', 'callout', 'rectangle', 'arrow', 'blur', 'spotlight', 'zoom', 'image', 'video', 'animation'], 'type': 'string'}}, 'description': "Values shared by every item, sent once rather than repeated. Items win per key; type_data merges one level. E.g. defaults:{clip_index:1, element_type:'text', type_data:{font_setting:{font:'Inter',weight:'600'}, alignment:'center'}} then items carry only what differs.", 'additionalProperties': False}, 'returning': {'type': 'array', 'items': {'enum': ['ids', 'layout', 'qa', 'qa.codes'], 'type': 'string'}, 'description': "Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."}, 'project_id': {'type': 'string', 'description': 'Project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'items'], 'properties': {'items': {'type': 'array', 'items': {'type': 'object', 'required': ['clip_index', 'group_id'], 'properties': {'name': {'type': 'string', 'minLength': 1, 'description': 'Rename the group. Names stay unique per clip, so a collision is rejected.'}, 'scale': {'type': 'array', 'items': False, 'maxItems': 2, 'minItems': 2, 'description': 'Scale [x, y] as a multiplier about the anchor (1 = unscaled)', 'prefixItems': [{'type': 'number'}, {'type': 'number'}]}, 'locked': {'type': 'boolean', 'description': 'Lock the group in the editor'}, 'rotate': {'type': 'array', 'items': False, 'maxItems': 2, 'minItems': 2, 'description': '3D tilt [x, y] in degrees', 'prefixItems': [{'type': 'number'}, {'type': 'number'}]}, 'blur_px': {'type': 'number', 'minimum': 0, 'description': 'Blur in pixels, applied over every child'}, 'opacity': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': "0-100, multiplied over each child's own opacity"}, 'group_id': {'type': 'string', 'minLength': 1, 'description': "The group's id (from get_clip, or returned by add_elements when you pass `group`)"}, 'rotation': {'type': 'number', 'description': 'Rotation in degrees about the anchor'}, 'anchor_px': {'type': 'array', 'items': False, 'maxItems': 2, 'minItems': 2, 'description': "The pivot, as a canvas-pixel point. Defaults to the centre of the group's child bounding box.", 'prefixItems': [{'type': 'number'}, {'type': 'number'}]}, 'collapsed': {'type': 'boolean', 'description': "Collapse the group in the editor's layer tree"}, 'keyframes': {'type': 'array', 'items': {'type': 'object', 'required': ['timestamp'], 'properties': {'blur': {'type': 'number', 'description': 'blur in pixels, applied over every child'}, 'bezier': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4, 'description': "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'."}, 'scaleX': {'type': 'number', 'description': "scaleX multiplier (1 = unscaled), about the group's anchor"}, 'scaleY': {'type': 'number', 'description': "scaleY multiplier (1 = unscaled), about the group's anchor"}, 'offsetX': {'type': 'number', 'description': 'offsetX in canvas pixels — how far to move the whole group'}, 'offsetY': {'type': 'number', 'description': 'offsetY in canvas pixels — how far to move the whole group'}, 'opacity': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': "0-100, multiplied over each child's own opacity"}, 'rotateX': {'type': 'number', 'description': 'rotateX in degrees'}, 'rotateY': {'type': 'number', 'description': 'rotateY in degrees'}, 'rotation': {'type': 'number', 'description': 'rotation in degrees'}, 'timestamp': {'type': 'number', 'minimum': 0, 'description': 'Clip-relative time in seconds'}, 'interpolation': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string', 'description': 'Easing for THIS entry, applied to every property in it (default easeInOut).'}, 'bezier_overrides': {'type': 'object', 'description': 'Per-property cubic-bezier override.', 'propertyNames': {'enum': ['offsetX', 'offsetY', 'scaleX', 'scaleY', 'rotation', 'rotateX', 'rotateY', 'opacity', 'blur'], 'type': 'string'}, 'additionalProperties': {'type': 'array', 'items': {'type': 'number'}, 'maxItems': 4, 'minItems': 4}}, 'interpolation_overrides': {'type': 'object', 'description': 'Per-property easing override, e.g. {"opacity":"linear"}.', 'propertyNames': {'enum': ['offsetX', 'offsetY', 'scaleX', 'scaleY', 'rotation', 'rotateX', 'rotateY', 'opacity', 'blur'], 'type': 'string'}, 'additionalProperties': {'enum': ['linear', 'easeInOut', 'easeIn', 'easeOut', 'sigmoid', 'smootherstep', 'smoothstep', 'hold', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'custom'], 'type': 'string'}}}, 'additionalProperties': False}, 'description': 'Animate the group over time. [] clears every track; omit to leave tracks alone.'}, 'offset_px': {'type': 'array', 'items': False, 'maxItems': 2, 'minItems': 2, 'description': "Move the whole group by [dx, dy] canvas pixels. Children's stored positions are untouched.", 'prefixItems': [{'type': 'number'}, {'type': 'number'}]}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index'}, 'parent_group_id': {'type': 'string', 'description': 'Nest this group under another by id. "" moves it to the clip root. Omit to leave the parent alone.'}}, 'additionalProperties': False}, 'minItems': 1, 'description': 'One entry per group to update'}, 'returning': {'type': 'array', 'items': {'enum': ['ids', 'layout', 'qa', 'qa.codes'], 'type': 'string'}, 'description': "Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."}, 'project_id': {'type': 'string', 'description': 'The project ID'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id'], 'properties': {'title': {'type': 'string', 'description': 'New project title'}, 'folder_id': {'type': 'string', 'description': "New folder ID. Pass '' (empty string) to move to workspace root."}, 'project_id': {'type': 'string', 'description': 'The project ID to update'}, 'description': {'type': 'string', 'description': 'New description'}, 'aspect_ratio': {'type': 'string', 'pattern': '^[1-9]\\d*:[1-9]\\d*$', 'description': "New aspect ratio as 'W:H' (positive integers). Common: '16:9' landscape, '9:16'/'4:5'/'3:4' portrait, '1:1' square."}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'properties': {'files': {'type': 'array', 'items': {'type': 'object', 'required': ['download_url', 'file_id'], 'properties': {'file_id': {'type': 'string', 'description': 'ChatGPT file id'}, 'file_name': {'type': 'string'}, 'mime_type': {'type': 'string'}, 'download_url': {'type': 'string', 'description': 'Temporary download URL supplied by ChatGPT'}}}, 'description': 'ChatGPT file attachments, one entry per file (filled by ChatGPT).'}, 'file_url': {'type': 'string', 'description': 'Public URL to fetch the file from'}, 'file_name': {'type': 'string', 'description': 'File name with extension. Returns a Clueso upload URL + curl command that streams this single local file to us (single file).'}, 'file_names': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of file names the user will upload (for hosted mode). Shown on the upload page as guidance.'}, 'request_hosted_upload': {'type': 'boolean', 'description': 'If true, returns a hosted upload page. Call once for all files — the page accepts multiple uploads under one token.'}}}
Esquema de entrada
{'type': 'object', '$schema': 'https://json-schema.org/draft/2020-12/schema', 'required': ['project_id', 'entries'], 'properties': {'entries': {'type': 'array', 'items': {'oneOf': [{'type': 'object', 'required': ['action', 'clip_index', 'text'], 'properties': {'text': {'type': 'string', 'minLength': 1, 'description': 'Voiceover transcript'}, 'action': {'type': 'string', 'const': 'set_text', 'description': 'Write the voiceover transcript onto the clip without generating audio.'}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index'}}}, {'type': 'object', 'required': ['action'], 'properties': {'action': {'type': 'string', 'const': 'generate_speech', 'description': 'Generate speech audio from the transcript already set on the clip.'}, 'clip_id': {'type': 'string', 'minLength': 1, 'description': 'Clip ID. Give this or clip_index.'}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index. Give this or clip_id.'}}}, {'type': 'object', 'required': ['action', 'text'], 'properties': {'text': {'type': 'string', 'minLength': 1, 'description': 'Voiceover transcript'}, 'action': {'type': 'string', 'const': 'set_and_generate', 'description': 'Write the transcript and generate its speech audio in one step.'}, 'clip_id': {'type': 'string', 'minLength': 1, 'description': 'Clip ID. Give this or clip_index.'}, 'clip_index': {'type': 'integer', 'maximum': 9007199254740991, 'minimum': 0, 'description': 'Zero-based clip index. Give this or clip_id.'}}}]}, 'minItems': 1, 'description': 'Voiceover entries — at least one.'}, 'project_id': {'type': 'string', 'description': 'Project ID'}}}
Cambios recientes en herramientas
Servidores MCP similares
MiOffice — AI-Powered Workspace Studio
Provides browser-based tools for processing PDFs, images, video, and audio, including generation, enhancement, conversion, transc…
BlitzReels Video Editor
Creates and edits short-form videos, including timelines, captions, transitions, AI-generated visuals, music, voiceovers, sound e…
Morpha
Enables creating, animating, and exporting layered short-form video projects.
switch
Enables management and exploration of an account-scoped library of AI-generated images and videos.
framesail
Creates long-form YouTube videos through script generation, storyboarding, visual assets, voiceover, music, scene composition, an…
Magnific
Provides image enhancement and design tools, AI image and audio generation, text-to-speech, creation management, and reusable cre…
Uwear
Supports AI fashion photoshoot production with garments, outfits, avatars, locations, art direction, image generation, backdrops,…
Creative Claw
Generates and edits branded images, video, audio, speech, and 3D-related creative assets, with media processing and reusable them…