Endpoints: 28,729MCP servers: 18,413Payout addresses: 2,071Paid calls: 1,549Letters: 14Defects: 1,324counted 1 min ago
teppi

Server definition

Hash
sha256:a9a033744276d844ac6bc0c14244f1d31963b947f2abdf10ee9aa8165d07b2a6
What it is
What a remote MCP server returned when asked what it offers: 37 tools

The blob, as servednamed by its sha256

{ "instructions": "IMPORTANT: Asset URLs returned by these tools point to Google Cloud Storage links that EXPIRE AFTER 7 DAYS. Any generated asset that needs to outlive that window — especially assets destined for production use — must be downloaded and saved locally (or re-uploaded to permanent storage) right away. Never store or hard-code the returned URLs as permanent references. Before generating with a feature you have not used here before, call searchDocs with a plain-language question to read Ludo's own guidance for it — how to pick a sprite animation mode or model, when to use Generate Before / Generate After, how margins behave, and each generator's known limitations. It returns only the few documentation sections that answer the question. Use getDocs when you need to browse what documentation exists (no arguments gives a table of contents) or to read a whole document or named sections; a whole document can run to tens of thousands of characters. If searchDocs returns no results or an error, fall back to getDocs. JOBS: every generation tool returns {id, status} immediately. Poll getApiJob with that id (pass wait: 30 to long-poll; up to 60) until status is succeeded (read result - exactly the response documented for the tool) or failed (read error: {code, subcode, message, retriable}); canceled is the third terminal status. Non-terminal responses carry poll_after_ms - wait at least that long between polls. Each account may have up to 50 generations queued or running at once; beyond that a call returns 429 (PENDING_JOBS_LIMIT) - wait for jobs to finish. cancelApiJob cancels a job that is still queued. CREDITS: each tool states its price. Credits are held when a job is accepted; for duration-priced tools the final charge is max(rate x produced seconds, the model's minimum charge), never more than for the duration requested, and the difference - or everything, if the job fails or is cancelled - is refunded. Every tool requires the API key the session was opened with. FEEDBACK: when you hit a limitation you cannot work around, a bug, or a capability the user needed that Ludo lacks, send one short report with submitApiFeedback (free, capped at a few a day) and tell the user you did. Current models: hydra (Hydra) - Most capable all-around model, generates audio. forge (Forge) - Sharper detail, simpler motion. Best for simple body shapes and short actions; may need a few tries. forge-pixel (Forge Pixel) - Best for low-res pixel art animations. griffin (Griffin) - Fast cinematic videos in any style, with audio, 480p. griffin-hd (Griffin HD) - Same as Griffin, but in 720p. Per action - sprite animation: hydra, forge, forge-pixel; motion transfer: hydra, forge, forge-pixel; spritesheet editing: hydra, forge, forge-pixel; new view: hydra; video generation: griffin, griffin-hd; references to video: griffin, griffin-hd; video editing: griffin-hd. LEGACY models, still accepted but scheduled for removal - do not use them for new work: blitz, eagle, eagle-audio, tango.", "tools": [ { "description": "Generate text-driven skeletal animations for an already-rigged 3D model. Pass the rigged GLB in `model` (URL or base64; the 3D asset file, not an AI model name) and a motion `prompt` (e.g. \"walking\", \"swinging its axe\"). The model must already have a skeleton - rig it first with rigModel if not. The job result is num_variants candidate animations (default 4), each a standalone animation-only GLB (skeleton + one clip, no mesh) in `glb_url` plus an mp4 `preview_url`, so you can pick the best one and fuse it with your model in a game engine or three.js. mode selects the representation - rot_trans (default, rotation plus translation per bone, most faithful) or rot_only (rotation only, easier to retarget onto another skeleton in an engine). Animation quality is hit-or-miss, which is why multiple candidates are returned. Credits are held once per call regardless of variant count and refunded if the job fails or is cancelled. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.2 credits per call.", "inputSchema": { "properties": { "requestBody": { "properties": { "augment_prompt": { "description": "Rewrites the prompt into a detailed motion caption with an LLM. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "loop": { "description": "Return to the initial pose: each clip plays forward then mirrors back to the rest pose for a seamless loop. Best for one-way motions (crouch, punch, wave); reads oddly for cyclic gaits like walking. Default: true.", "example": true, "type": "boolean" }, "mode": { "description": "Animation representation: rot_trans (per-bone rotation+translation, most faithful) or rot_only (rotation + root translation only, for retargeting). Default: \"rot_trans\".", "enum": [ "rot_trans", "rot_only" ], "example": "rot_trans", "type": "string" }, "model": { "description": "The already-rigged 3D asset to animate, as a URL or base64-encoded GLB file (not an AI model name). Rig it first with rigModel if it has no skeleton.", "example": "<url> OR data:model/gltf-binary;base64,...", "type": "string" }, "num_variants": { "description": "Number of candidate animations to generate; each returned as a standalone animation-only GLB with an mp4 preview. Default: 4.", "example": 4, "maximum": 8, "minimum": 1, "type": "integer" }, "prompt": { "description": "Desired motion, e.g. \"walking\" or \"swinging its axe\".", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "model", "prompt" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "animate3DModel", "outputSchema": null }, { "description": "Apply a curated animation preset to an already-rigged 3D model (retargeting). Pass the rigged GLB in `model` (URL or base64; the 3D asset file, not an AI model name) and a `preset_id` from the animation presets list (from listAnimationPresets) - only presets that expose a `clip_url` can be applied to a 3D model. The model must have a humanoid-template rig (rig it with rig_type humanoid_template or humanoid_template_hands). The job result is one retargeted animation - a standalone animation-only GLB in `glb_url` plus an mp4 `preview_url` - in the same `animations` envelope as the animate endpoint. crop_loop trims the clip to its seamlessly-looping span (omit to follow the preset's own loop flag); in_place removes net travel so the character moves on the spot, as game-engine locomotion expects (omit to keep the preset's own travel). Credits are held when the job is accepted and refunded if it fails or is cancelled. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.2 credits per call.", "inputSchema": { "properties": { "requestBody": { "properties": { "crop_loop": { "description": "Trim the animation to the span that loops seamlessly. Omit to follow the preset's own loop flag. Ignored when no clean loop exists.", "type": "boolean" }, "in_place": { "description": "Remove the animation's net travel so the character moves on the spot (engine-driven locomotion). Omit to keep the preset's own travel.", "type": "boolean" }, "model": { "description": "The already-rigged 3D asset, as a URL or base64-encoded GLB file (not an AI model name). Rig it with rigModel using rig_type humanoid_template or humanoid_template_hands first.", "example": "<url> OR data:model/gltf-binary;base64,...", "type": "string" }, "preset_id": { "description": "id of an animation preset from the presets list. Only presets that expose a clip_url can be applied to a 3D model.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "model", "preset_id" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "animate3DModelPreset", "outputSchema": null }, { "description": "Animate a static sprite into a spritesheet driven by a motion text prompt (image-to-spritesheet): supply an initial_image (URL or base64) plus a motion_prompt like \"walking\" or \"attack slash\", and optionally a final_image to interpolate between a start and end frame. Describe the motion exactly and unambiguously, but do not over-describe it: an action the model already knows is one phrase, not a sequence of steps, and the character, art style, background and camera come from the image, not the prompt. For animations driven by up to three keyframes (including a middle frame), use animateSpriteKeyframes instead. The job result is a single sprite result: `spritesheet_url` (the sheet image), `video_url` (an mp4 of the animation - pass it as `video` to transferMotion or as `spritesheet_video_url` to createSpriteAudio; editSpritesheet takes `spritesheet_url`), `num_frames`/`num_cols`/`num_rows` (the grid layout), and, when requested, `gif_url`, `individual_frame_urls` and `spritesheet_with_background_url`. The hydra model also returns `audio_url`, a sound effect for the animation - there is no need to call createSpriteAudio afterwards; forge and forge-pixel produce no audio. The chosen model must support sprite animation and the duration must be valid for it; incompatible model/duration combinations return HTTP 400. Credits are held for the duration you requested when the job is accepted; the final charge is max(rate × seconds of video generated, the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. The returned sheet is then trimmed to its best loop and can run slightly shorter than the video; that trim is not deducted. Choosing a tool: animateSprite (this one) when you can describe the motion in text; transferMotion when you want an exact motion copied from a reference video or one of the named presets from listAnimationPresets (e.g. a standard walk or attack cycle); generatePose first when the source image is not yet in the pose the animation should start from. Omit `model` to run on hydra (the default) - see the `model` field for the per-model rates and the 4-credit minimum charge on forge/forge-pixel. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: credits/s × seconds, per model: Hydra 3/s (min charge 9 credits), Forge 1.5/s (min charge 4 credits), Forge Pixel 1.5/s (min charge 4 credits), Blitz 1.9/s (min charge 4 credits) [LEGACY], Eagle 2.6/s (min charge 4 credits) [LEGACY], Eagle with Audio 3.1/s (min charge 4 credits) [LEGACY]; [LEGACY] models are scheduled for removal - do not use them for new work; see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating an animated spritesheet from a static image. Input images can either be provided in base64 or URL. If the image was generated using Ludo, ideally it should be generated using the \"sprite\", \"sprite-vfx\" or \"ui_asset\" type.", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "crop": { "description": "Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations. Default: true.", "example": true, "type": "boolean" }, "duration": { "description": "Duration in seconds. Available values depend on the model:\n- hydra: 3, 3.5, 4, 4.5, 5\n- forge: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5\n- forge-pixel: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5\n- blitz: 1.2, 1.5, 2, 2.5, 3, 3.5, 4\n- eagle: 1, 2, 3, 4\n- eagle-audio: 1, 2, 3, 4 Default: 3.", "example": 3, "format": "float", "type": "number" }, "final_image": { "description": "The url OR base64 of ending frame image. When provided, the animation will interpolate between the initial and final frames.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "frame_size": { "description": "Size of each frame in pixels (width and height). It sizes the exported frames only - it does not change how the sprite is generated. 0 is maximum resolution. -1 is AI 1.5x upscaling. -9 is True Size: frames keep the size and position of the input frame, untrimmed, so the spritesheet lines up exactly with the input image - use it (not margin_ratio_mode \"none\") whenever the output must align with your input; it works with any margin mode. Exporting larger than the input image adds no detail: do not pick a size above the input's own resolution, and 0 or -1 gain nothing on inputs under 512 px. Accepted values: 32, 64, 96, 128, 192, 256, 384, 0, -1, -9. Default: 0.", "example": 0, "format": "integer", "type": "number" }, "frames": { "description": "Maximum number of frames in the output spritesheet. Allow about one second of duration per 16 frames - above that the model may not be able to produce them all (64 frames needs a duration of at least 4). The result can have fewer frames when the duration is short or bad frames were removed. Accepted values: 4, 9, 16, 25, 36, 49, 64. Default: 36.", "example": 36, "format": "integer", "type": "number" }, "gif": { "description": "When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time. Default: false.", "example": false, "type": "boolean" }, "image_type": { "description": "Type of sprite being animated. Affects generation parameters and styling. Tiling types (horizontal / vertical tiles, scrolling backgrounds, parallax layers, textures) stay seamless only on forge and forge-pixel, and only if the input image itself already wraps seamlessly on that axis; otherwise the animation shows a visible seam when tiled. Default: \"sprite\".", "enum": [ "sprite", "sprite-vfx", "item-icon", "ui_asset", "logo", "sprite-tiling-horizontal", "sprite-tiling-vertical", "parallax_layer", "tile", "texture", "portrait", "card-art" ], "example": "sprite", "type": "string" }, "individual_frames": { "description": "When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls. Default: false.", "example": false, "type": "boolean" }, "initial_image": { "description": "The url OR base64 of the starting frame image to animate. This is the base sprite that will be brought to life.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "loop": { "description": "Trim the animation at the beginning or end to create a seamless loop. Not guaranteed to produce a perfect loop. Default: true.", "example": true, "type": "boolean" }, "margin_ratio": { "deprecated": true, "description": "Deprecated: prefer margin_ratio_horizontal / margin_ratio_vertical. Amount of padding around the sprite as a ratio (0.0 to 1.0). Sets both axes to this value. A per-axis value, when also given, overrides this for that axis. Supplying any margin value selects margin_ratio_mode \"manual\" unless margin_ratio_mode is set explicitly.", "format": "float", "type": "number" }, "margin_ratio_horizontal": { "description": "Horizontal padding around the sprite as a ratio (0.0 to 1.0). Every bit of margin is resolution taken from the sprite, so keep it as tight as the motion allows - about 0.15 - and go higher only for motion that extends sideways (sword slashes, punches) or if the sprite gets cut off. Supplying a value selects margin_ratio_mode \"manual\" unless margin_ratio_mode is set explicitly; overrides the legacy margin_ratio on this axis.", "format": "float", "type": "number" }, "margin_ratio_mode": { "description": "How the sprite is framed for generation. The model always generates on a canvas of the same size, so any margin is canvas the sprite does not fill: the more margin, the lower the resolution and detail of the sprite. \"auto\" (default, recommended) trims and centers the sprite and picks a margin suited to the motion. \"manual\" uses margin_ratio_horizontal / margin_ratio_vertical; keep them as tight as the motion allows (about 0.15) and raise only the axis the motion needs. \"none\" animates the input exactly as framed, with no trimming and no margin added, so the input must already have suitable margins: a sprite touching the edges gets its limbs, weapons and effects cut off as soon as it moves, and an image that is mostly empty space yields a small, low-detail sprite. \"none\" is the way to keep a deliberately off-center sprite (e.g. a character at the left edge firing a beam to the right), but results can be unpredictable. Do not use \"none\" to make the spritesheet line up with the input image - use frame_size -9 (True Size) for that; it works with any margin mode. Rules: omit margin_ratio_mode and send margin_ratio_horizontal / margin_ratio_vertical to get \"manual\" automatically; \"manual\" with no margin value fails with HTTP 400; \"auto\" or \"none\" sent together with a margin value fails with HTTP 400 (the value would be ignored). Default: \"auto\".", "enum": [ "auto", "manual", "none" ], "example": "auto", "type": "string" }, "margin_ratio_vertical": { "description": "Vertical padding around the sprite as a ratio (0.0 to 1.0). Every bit of margin is resolution taken from the sprite, so keep it as tight as the motion allows - about 0.15 - and go higher only for motion that extends up or down (jumps) or if the sprite gets cut off. Supplying a value selects margin_ratio_mode \"manual\" unless margin_ratio_mode is set explicitly; overrides the legacy margin_ratio on this axis.", "format": "float", "type": "number" }, "model": { "description": "Model to use. Available models:\n- \"hydra\" (Hydra): 3 credits/s, min charge 9 credits · Most capable all-around model, generates audio\n- \"forge\" (Forge): 1.5 credits/s, min charge 4 credits · Sharper detail, simpler motion. Best for simple body shapes and short actions; may need a few tries\n- \"forge-pixel\" (Forge Pixel): 1.5 credits/s, min charge 4 credits · Best for low-res pixel art animations\n- \"blitz\" (Blitz): 1.9 credits/s, min charge 4 credits · LEGACY - scheduled for removal, do not use for new work\n- \"eagle\" (Eagle): 2.6 credits/s, min charge 4 credits · LEGACY - scheduled for removal, do not use for new work\n- \"eagle-audio\" (Eagle with Audio): 3.1 credits/s, min charge 4 credits · LEGACY - scheduled for removal, do not use for new work\nLegacy aliases: \"standard\" → blitz.\nModels marked LEGACY still work for existing integrations but will be removed; pick a current model for anything new.\nforge-pixel expects real pixel art - a perfect pixel grid at its natural resolution; for other art use hydra or forge. Tiling image types stay seamless only on forge and forge-pixel. Default: \"hydra\".", "enum": [ "hydra", "forge", "forge-pixel", "blitz", "standard", "eagle", "eagle-audio" ], "example": "hydra", "type": "string" }, "motion_prompt": { "description": "Text description of the desired animation, e.g. \"walking\", \"idle breathing\", \"attack slash\", \"casting a fireball with both hands\". Describe exactly and unambiguously what the character should do. Specific or complex actions are fine; there is no need to simplify them. Do not over-describe, though: too much detail can harm the animation, and an action the model already knows should be named, not decomposed into its steps (\"walking\", never \"move the left foot forward, then the right foot\"). Do not restate what initial_image already shows (the character, its appearance and equipment, the art style, the background, the lighting, the camera), and leave frame count and timing to the frames and duration fields. Negative phrasing (\"no background\", \"do not move the camera\", \"without a weapon\") works only on hydra. On forge, forge-pixel and the legacy models it backfires: naming something you do not want makes it more likely to appear, so \"without a weapon\" tends to produce a weapon. On those models never phrase anything negatively; state only what should happen, and control everything else through the image and the other fields. Keep it well under 100 words: in longer prompts details start competing and some get dropped.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "spritesheet_with_background": { "description": "When true, also returns the spritesheet with background intact (before background removal). Useful for manually fixing background removal issues. The with-background spritesheet URL will be in spritesheet_with_background_url. Default: false.", "example": false, "type": "boolean" } }, "required": [ "motion_prompt", "initial_image" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "animateSprite", "outputSchema": null }, { "description": "Animate a sprite through up to three fixed keyframes - initial_image, middle_image and final_image (each a URL or base64) - producing a spritesheet that interpolates through the provided frames in order. At least one of initial_image or middle_image is required (a final_image alone has nothing to anchor the animation); any keyframe may be omitted. The motion_prompt is optional here - when omitted, the motion is derived purely from the keyframes. Runs on hydra (default; also returns `audio_url`), forge, or forge-pixel for pixel-art sprites - the models that support a middle keyframe; any other model returns HTTP 400. For just a start and end frame, animateSprite with `final_image` does the same job. The job result is the same sprite result as animateSprite (`spritesheet_url`, `video_url`, grid fields, optional GIF and frame URLs, `audio_url` on hydra). Credits are held for the duration you requested when the job is accepted; the final charge is max(rate × seconds of video generated, the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. The returned sheet is then trimmed to its best loop and can run slightly shorter than the video; that trim is not deducted. Use animateSprite instead for the classic single-image + text-prompt animation. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: credits/s × seconds, per model: Hydra 3/s (min charge 9 credits), Forge 1.5/s (min charge 4 credits), Forge Pixel 1.5/s (min charge 4 credits); see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating an animated spritesheet that interpolates through up to three fixed keyframes (initial / middle / final). Runs on hydra (default), forge or forge-pixel - the models supporting a middle keyframe. Input images can be provided in base64 or URL. At least one of initial_image or middle_image must be provided.", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "crop": { "description": "Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations. Default: true.", "example": true, "type": "boolean" }, "duration": { "description": "Duration in seconds. Available values depend on the model:\n- hydra: 3, 3.5, 4, 4.5, 5\n- forge: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5\n- forge-pixel: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5 Default: 3.", "example": 3, "format": "float", "type": "number" }, "final_image": { "description": "The url OR base64 of the final keyframe. Requires an initial_image or middle_image to anchor the animation.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "frame_size": { "description": "Size of each frame in pixels (width and height). It sizes the exported frames only - it does not change how the sprite is generated. 0 is maximum resolution. -1 is AI 1.5x upscaling. -9 is True Size: frames keep the size and position of the input frame, untrimmed, so the spritesheet lines up exactly with the input image - use it (not margin_ratio_mode \"none\") whenever the output must align with your input; it works with any margin mode. Exporting larger than the input image adds no detail: do not pick a size above the input's own resolution, and 0 or -1 gain nothing on inputs under 512 px. Accepted values: 32, 64, 96, 128, 192, 256, 384, 0, -1, -9. Default: 0.", "example": 0, "format": "integer", "type": "number" }, "frames": { "description": "Maximum number of frames in the output spritesheet. Allow about one second of duration per 16 frames - above that the model may not be able to produce them all (64 frames needs a duration of at least 4). The result can have fewer frames when the duration is short or bad frames were removed. Accepted values: 4, 9, 16, 25, 36, 49, 64. Default: 36.", "example": 36, "format": "integer", "type": "number" }, "gif": { "description": "When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time. Default: false.", "example": false, "type": "boolean" }, "image_type": { "description": "Type of sprite being animated. Affects generation parameters and styling. Tiling types (horizontal / vertical tiles, scrolling backgrounds, parallax layers, textures) stay seamless only on forge and forge-pixel, and only if the input image itself already wraps seamlessly on that axis; otherwise the animation shows a visible seam when tiled. Default: \"sprite\".", "enum": [ "sprite", "sprite-vfx", "item-icon", "ui_asset", "logo", "sprite-tiling-horizontal", "sprite-tiling-vertical", "parallax_layer", "tile", "texture", "portrait", "card-art" ], "example": "sprite", "type": "string" }, "individual_frames": { "description": "When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls. Default: false.", "example": false, "type": "boolean" }, "initial_image": { "description": "The url OR base64 of the first keyframe. Optional when a middle_image is provided.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "loop": { "description": "Trim the animation at the beginning or end to create a seamless loop. Not guaranteed to produce a perfect loop. Default: true.", "example": true, "type": "boolean" }, "margin_ratio": { "deprecated": true, "description": "Deprecated: prefer margin_ratio_horizontal / margin_ratio_vertical. Amount of padding around the sprite as a ratio (0.0 to 1.0). Sets both axes to this value. A per-axis value, when also given, overrides this for that axis. Supplying any margin value selects margin_ratio_mode \"manual\" unless margin_ratio_mode is set explicitly.", "format": "float", "type": "number" }, "margin_ratio_horizontal": { "description": "Horizontal padding around the sprite as a ratio (0.0 to 1.0). Every bit of margin is resolution taken from the sprite, so keep it as tight as the motion allows - about 0.15 - and go higher only for motion that extends sideways (sword slashes, punches) or if the sprite gets cut off. Supplying a value selects margin_ratio_mode \"manual\" unless margin_ratio_mode is set explicitly; overrides the legacy margin_ratio on this axis.", "format": "float", "type": "number" }, "margin_ratio_mode": { "description": "How the sprite is framed for generation. The model always generates on a canvas of the same size, so any margin is canvas the sprite does not fill: the more margin, the lower the resolution and detail of the sprite. \"auto\" (default, recommended) trims and centers the sprite and picks a margin suited to the motion. \"manual\" uses margin_ratio_horizontal / margin_ratio_vertical; keep them as tight as the motion allows (about 0.15) and raise only the axis the motion needs. \"none\" animates the input exactly as framed, with no trimming and no margin added, so the input must already have suitable margins: a sprite touching the edges gets its limbs, weapons and effects cut off as soon as it moves, and an image that is mostly empty space yields a small, low-detail sprite. \"none\" is the way to keep a deliberately off-center sprite (e.g. a character at the left edge firing a beam to the right), but results can be unpredictable. Do not use \"none\" to make the spritesheet line up with the input image - use frame_size -9 (True Size) for that; it works with any margin mode. Rules: omit margin_ratio_mode and send margin_ratio_horizontal / margin_ratio_vertical to get \"manual\" automatically; \"manual\" with no margin value fails with HTTP 400; \"auto\" or \"none\" sent together with a margin value fails with HTTP 400 (the value would be ignored). Default: \"auto\".", "enum": [ "auto", "manual", "none" ], "example": "auto", "type": "string" }, "margin_ratio_vertical": { "description": "Vertical padding around the sprite as a ratio (0.0 to 1.0). Every bit of margin is resolution taken from the sprite, so keep it as tight as the motion allows - about 0.15 - and go higher only for motion that extends up or down (jumps) or if the sprite gets cut off. Supplying a value selects margin_ratio_mode \"manual\" unless margin_ratio_mode is set explicitly; overrides the legacy margin_ratio on this axis.", "format": "float", "type": "number" }, "middle_image": { "description": "The url OR base64 of the middle keyframe the animation passes through between the initial and final frames. Consecutive keyframes must differ - two identical keyframes in a row produce no motion across that span.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "model": { "description": "Model to use. Available models:\n- \"hydra\" (Hydra): 3 credits/s, min charge 9 credits · Most capable all-around model, generates audio\n- \"forge\" (Forge): 1.5 credits/s, min charge 4 credits · Sharper detail, simpler motion. Best for simple body shapes and short actions; may need a few tries\n- \"forge-pixel\" (Forge Pixel): 1.5 credits/s, min charge 4 credits · Best for low-res pixel art animations\nforge-pixel expects real pixel art - a perfect pixel grid at its natural resolution; for other art use hydra or forge. Tiling image types stay seamless only on forge and forge-pixel. Default: \"hydra\".", "enum": [ "hydra", "forge", "forge-pixel" ], "example": "hydra", "type": "string" }, "motion_prompt": { "description": "Optional text description of the desired animation, e.g. \"walking\", \"attack slash\". When omitted, the motion is derived purely from the keyframes. When provided, describe exactly and unambiguously what the character should do. Specific or complex actions are fine; there is no need to simplify them. Do not over-describe, though: too much detail can harm the animation, and an action the model already knows should be named, not decomposed into its steps (\"walking\", never \"move the left foot forward, then the right foot\"). Do not restate what the keyframes already show (the character, its appearance and equipment, the art style, the background, the lighting, the camera), and leave frame count and timing to the frames and duration fields. Negative phrasing (\"no background\", \"do not move the camera\", \"without a weapon\") works only on hydra. On forge and forge-pixel it backfires: naming something you do not want makes it more likely to appear, so \"without a weapon\" tends to produce a weapon. On those models never phrase anything negatively; state only what should happen, and control everything else through the keyframes and the other fields. Keep it well under 100 words: in longer prompts details start competing and some get dropped.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "spritesheet_with_background": { "description": "When true, also returns the spritesheet with background intact (before background removal). Useful for manually fixing background removal issues. The with-background spritesheet URL will be in spritesheet_with_background_url. Default: false.", "example": false, "type": "boolean" } }, "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "animateSpriteKeyframes", "outputSchema": null }, { "description": "Cancel a queued job you started through the API or MCP; the credits held for it are refunded. Jobs that are already running cannot be canceled (409). Returns the canceled job. This is free (no credits).", "inputSchema": { "properties": { "id": { "type": "string" } }, "required": [ "id" ], "type": "object" }, "name": "cancelApiJob", "outputSchema": null }, { "description": "Convert a source image into a textured 3D model (image-to-3D). The job result is a downloadable GLB model_url plus an array of snapshot image URLs rendered from different angles (handy for previews). image is the front view; pass an optional back_image (the same subject seen from behind) so the back of the model follows it instead of being invented. Accepts optional mesh controls: target_num_faces (max triangle count, 1000-200000, default 50000), texture_size (1024 or 2048, default 2048), and texture_type (\"pbr\", \"simple\", or \"none\", default \"pbr\"). Credits are held when the job is accepted and refunded if it fails or is cancelled. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type 3d). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 3 credits per call.", "inputSchema": { "properties": { "requestBody": { "properties": { "back_image": { "description": "Optional URL or base64-encoded image of the SAME subject seen from behind (rotated 180 degrees from image). The model's back then follows it instead of being invented from the front view alone. It must show the same subject, at the same scale and in the same pose and style as image. Only a back view is supported: a side or three-quarter view here produces a distorted model. No extra cost.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "image": { "description": "URL or base64-encoded image to convert to 3D, taken as the front view of the subject", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "target_num_faces": { "description": "Maximum triangle count for the mesh (1000-200000) Default: 50000.", "example": 50000, "maximum": 200000, "minimum": 1000, "type": "integer" }, "texture_size": { "description": "Texture resolution in pixels Accepted values: 1024, 2048. Default: 2048.", "example": 2048, "type": "integer" }, "texture_type": { "description": "Texture type Default: \"pbr\".", "enum": [ "pbr", "simple", "none" ], "example": "pbr", "type": "string" } }, "required": [ "image" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "create3DModel", "outputSchema": null }, { "description": "Produce a looping background ambiance soundscape from a text description, such as \"windy forest at dusk\" or \"busy tavern interior\". The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). The description field is required and duration is capped at 10 seconds (0 means auto-pick based on the description). Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this for continuous, atmospheric background loops; use createSoundEffect for short discrete sound effects, createMusic for musical pieces, and createAudioTransform to remix an existing audio sample. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 2 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating a seamless looping ambiance soundscape from a text description", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "description": { "description": "Text description of the ambiance to generate (e.g., \"windy forest at dusk\", \"busy tavern interior\").", "type": "string" }, "duration": { "description": "Duration in seconds. Use 0 for automatic duration based on the description. Default: 0.", "example": 0, "format": "float", "maximum": 10, "minimum": 0, "type": "number" }, "loop": { "description": "Generate an ambiance that loops seamlessly. Default: true.", "example": true, "type": "boolean" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "description" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createAmbiance", "outputSchema": null }, { "description": "Remix an existing audio sample (a sound effect, ambiance, or music clip) into a variation guided by a text prompt, for example turning a track into an 80s synthwave or metal version. Both the sample and the prompt are required; the sample is uploaded as a URL or base64 audio and must be at most 15MB or the call returns HTTP 400, and duration must be one of the allowed values (0 means match the source, otherwise multiples of 10 up to 180 seconds). The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). The optional modification_strength (0 to 1, default 0.6) controls how far the result departs from the original. Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this to transform existing audio you already have; use createSoundEffect, createAmbiance, or createMusic to generate audio from scratch. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 3 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for remixing an audio sample (sound effect, ambiance or music) into a variation guided by a text prompt", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "duration": { "description": "Duration in seconds. Use 0 for automatic duration matching the source sample. Accepted values: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180. Default: 0.", "example": 0, "type": "integer" }, "modification_strength": { "description": "Controls how strongly the source sample is modified. 0 keeps it close to the original, 1 transforms it fully. Default: 0.6.", "example": 0.6, "format": "float", "maximum": 1, "minimum": 0, "type": "number" }, "prompt": { "description": "Text description guiding the remix (e.g., \"make it sound like an 80s synthwave track\", \"turn this into a metal version\").", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "sample": { "description": "URL or base64-encoded source audio sample to remix (15MB max).", "example": "<url> OR data:audio/mp3;base64,...", "type": "string" } }, "required": [ "sample", "prompt" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createAudioTransform", "outputSchema": null }, { "description": "Generate game-art images from a text prompt alone, selecting an image_type (e.g. sprite) and optionally art_style, perspective, and aspect_ratio. The job result is an array of image results, each with a url; request n (1-8) to control how many variations come back. Because it generates purely from text it takes no source image, so there is no upload size limit to trip. Credits are held when the job is accepted and refunded if it fails or is cancelled; the charge scales with the number of images produced. Use createImage to make new images from scratch; use generateWithStyle to match a reference image's art style, editImage to modify an existing image, and removeBackground to cut out a subject. Pass an optional request_id to tag the results so you can retrieve them later via listGenerations (type image). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.5 credits per result.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating an image from text prompt", "properties": { "art_style": { "description": "Visual art style for the sprite (e.g., \"Pixel Art\", \"Cartoonish\", \"Realistic\").", "enum": [ "Any style", "Cel-Shaded", "Inked Painterly", "Illustration", "Western Cartoon", "Anime/Manga", "Chibi", "8-Bit", "16-Bit", "32-Bit", "Hi-Bit", "Retro 2D", "Hand-Painted", "Digital Painting", "Comic Book", "Block Print", "Sketch", "Watercolor", "Stylized 3D", "Pixar Style", "Low Poly", "Photorealistic 3D", "Voxel Art", "Retro 3D", "Flat Design", "Minimalist", "Silhouette", "Noir", "Neon", "Glitch Art", "Claymation", "Paper Craft", "Textile" ], "example": "Any style", "type": "string" }, "aspect_ratio": { "description": "Aspect ratio of the output image.", "enum": [ "default", "ar_1_1", "ar_4_3", "ar_16_9", "ar_19_9", "ar_3_4", "ar_9_16", "ar_9_19" ], "example": "default", "type": "string" }, "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "image_type": { "description": "What kind of image to generate.", "enum": [ "generic", "screenshot", "art", "asset", "sprite", "sprite-vfx", "sprite-tiling-horizontal", "sprite-tiling-vertical", "icon", "logo", "ui_asset", "fixed_background", "side_scrolling_background", "vertical_scrolling_background", "parallax_layer", "texture", "tile", "item-icon", "portrait", "card-art", "splash", "3d" ], "example": "generic", "type": "string" }, "n": { "description": "Number of image variations to generate Default: 1.", "example": 1, "format": "integer", "maximum": 8, "minimum": 1, "type": "integer" }, "perspective": { "description": "Camera angle/view for the sprite (e.g., \"Side view\", \"Front view\", \"Isometric\").", "enum": [ "Any perspective", "Side-Scroll", "Isometric", "High Angle", "Top-Down", "2.5D", "First-Person", "Third-Person", "Over-the-Shoulder", "Free Camera" ], "example": "Any perspective", "type": "string" }, "prompt": { "description": "Text description of the image to generate. The more detailed the prompt, the more accurate the image will be.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "image_type", "prompt" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createImage", "outputSchema": null }, { "description": "Produce a piece of music from a text description, such as \"epic orchestral battle theme\" or \"calm piano melody\", with optional lyrics. The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). The description field is required; duration must be one of the allowed values (0 means auto, otherwise multiples of 10 up to 180 seconds) and out-of-range values return HTTP 400. Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this for songs and musical scores; use createSoundEffect for short sound effects, createAmbiance for looping background soundscapes, and createAudioTransform to remix an existing audio sample. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 3 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating music from a text description", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "description": { "description": "Text description of the music to generate (e.g., \"epic orchestral battle theme\", \"calm piano melody\").", "type": "string" }, "duration": { "description": "Duration in seconds. Use 0 for automatic duration based on the description. Accepted values: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180. Default: 0.", "example": 0, "type": "integer" }, "lyrics": { "description": "Optional lyrics to include in the generated music.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "description" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createMusic", "outputSchema": null }, { "description": "Produce a short sound effect (SFX) from a text description, such as \"laser gun firing\" or \"footsteps on gravel\". The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). The description field is required, duration is capped at 10 seconds (0 means auto-pick based on the description), and you may set loop to true for a seamlessly looping effect. Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this for short, discrete sounds; use createAmbiance for a continuous looping background soundscape, createMusic for musical pieces, and createAudioTransform to remix an existing audio sample. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 2 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating a sound effect from a text description", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "description": { "description": "Text description of the sound effect to generate (e.g., \"laser gun firing\", \"footsteps on gravel\").", "type": "string" }, "duration": { "description": "Duration in seconds. Use 0 for automatic duration based on the description. Default: 0.", "example": 0, "format": "float", "maximum": 10, "minimum": 0, "type": "number" }, "loop": { "description": "Generate a sound effect that loops seamlessly. Default: false.", "example": false, "type": "boolean" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "description" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createSoundEffect", "outputSchema": null }, { "description": "Convert text to speech by cloning the voice from an audio sample you provide (voice-cloning text-to-speech). Both text and sample are required; the text is limited to 1000 characters and the sample is supplied as a URL or base64 audio that must be at most 15MB, with violations returning HTTP 400. The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this when you have a reference voice sample to clone; use createSpeechPreset to speak with a built-in named preset voice instead, and createVoice to design a brand-new voice from a text description rather than cloning one. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 1 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for text-to-speech generation using voice cloning", "properties": { "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "sample": { "description": "URL or base64-encoded audio sample for voice cloning.", "example": "<url> OR data:audio/mp3;base64,...", "type": "string" }, "text": { "description": "Text to convert to speech (max 1000 characters).", "maxLength": 1000, "minLength": 1, "type": "string" } }, "required": [ "text", "sample" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createSpeech", "outputSchema": null }, { "description": "Convert text to speech using a named built-in preset voice, with optional emotion and language settings. Both text and voice_preset_id are required and the text is limited to 1000 characters; invalid input returns HTTP 400. The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this when you want a ready-made catalog voice and do not need to supply your own sample; use createSpeech to clone a voice from an audio sample instead, and createVoice to design a new voice from a text description. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 1 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for text-to-speech generation using a voice preset", "properties": { "emotion": { "description": "Emotion to apply to the speech.", "enum": [ "Default", "Happy", "Sad", "Angry", "Fearful", "Disgusted", "Surprised", "Neutral" ], "example": "Default", "type": "string" }, "language": { "description": "Language code for the speech.", "enum": [ "auto", "English", "Afrikaans", "Arabic", "Bulgarian", "Catalan", "Chinese", "Chinese,Yue", "Croatian", "Czech", "Danish", "English", "Filipino", "Finnish", "French", "German", "Greek", "Hebrew", "Hindi", "Hungarian", "Indonesian", "Italian", "Japanese", "Korean", "Malay", "Norwegian", "Nynorsk", "Persian", "Polish", "Portuguese", "Romanian", "Russian", "Slovak", "Slovenian", "Spanish", "Swedish", "Tamil", "Thai", "Turkish", "Ukrainian", "Vietnamese" ], "example": "auto", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "text": { "description": "Text to convert to speech (max 1000 characters).", "maxLength": 1000, "type": "string" }, "voice_preset_id": { "description": "Voice preset identifier.", "enum": [ "Serious woman", "Wise woman", "Calm woman", "Fast-paced woman", "Calm young girl", "Expressive teen girl", "Calm teen girl", "Sweet girl", "Patient man", "Determined man", "Young elegant man", "Teen boy", "Friendly man", "Deep voice man" ], "example": "Serious woman", "type": "string" } }, "required": [ "text", "voice_preset_id" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createSpeechPreset", "outputSchema": null }, { "description": "Generate a sound effect for a previously generated spritesheet animation. Pass, as `spritesheet_video_url`, the `video_url` you received from `animateSprite`, `animateSpriteKeyframes`, `transferMotion`, or `editSpritesheet` - it must belong to a spritesheet you generated within the last 7 days; arbitrary external videos are not accepted. Spritesheets generated with the hydra model already come with `audio_url`, so only call this for forge / forge-pixel output or to replace hydra's sound. Optionally add a `prompt` describing the sound you want. The job result is only the URL of the generated audio file, an MP3 or WAV (the URL's extension, .mp3 or .wav, says which); no video is returned. The audio is also attached to the spritesheet, so it appears as `audio_url` in listGenerations (type spritesheet), where the spritesheet keeps the `request_id` it was generated with. Pass an optional `request_id` to make this call idempotent and to find its job again; it must not be one you already used for another generation. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 3 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating audio for a previously generated spritesheet animation.", "properties": { "prompt": { "description": "Optional description of the sound to generate.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. It does not re-tag the spritesheet, which keeps the request_id it was generated with.", "type": "string" }, "spritesheet_video_url": { "description": "The video_url of a spritesheet you generated in the last 7 days (returned by animateSprite, animateSpriteKeyframes, transferMotion, or editSpritesheet). External URLs are not accepted.", "example": "<url>", "type": "string" } }, "required": [ "spritesheet_video_url" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createSpriteAudio", "outputSchema": null }, { "description": "Generate a short video clip from a source image and a motion text prompt (image-to-video); a source `image` is required - to make a video from text alone, first createImage and animate that, or use createVideoFromReferences with reference images. Griffin (default, 480p) and Griffin HD (720p) both generate a soundtrack; no separate audio step is needed. The job result is the video URL and its actual duration in seconds. Optionally pass `final_image` to interpolate between a start and end frame. The chosen `model` and `duration` must be compatible (incompatible combinations return HTTP 400); see the `model` and `duration` fields for the values each model accepts. Credits are held when the job is accepted; the final charge is max(rate × produced seconds, the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. Pass an optional `request_id` to tag the result so you can locate it later via listGenerations (type video). Related tools: use `createImage` for static images, `animateSprite` for sprite-sheet animation, and listGenerations (type video) to list videos you generated earlier. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: credits/s × seconds, per model: Griffin 1.5/s (shortest duration 5s, so 7.5 credits minimum), Griffin HD 2/s (shortest duration 5s, so 10 credits minimum), Blitz 1/s (shortest duration 2s, so 2 credits minimum) [LEGACY], Eagle 1.3/s [LEGACY], Eagle with Audio 1.8/s [LEGACY]; [LEGACY] models are scheduled for removal - do not use them for new work; see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating a video from a source image and motion prompt", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "duration": { "description": "Duration in seconds. Available values depend on the model:\n- griffin: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- griffin-hd: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- blitz: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12\n- eagle: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- eagle-audio: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 Default: 5.", "example": 5, "format": "float", "type": "number" }, "final_image": { "description": "URL or base64-encoded end frame image. When provided, the video will interpolate between the initial and final frames.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "image": { "description": "URL or base64-encoded source image (the starting frame for the video)", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "model": { "description": "Model to use. Available models:\n- \"griffin\" (Griffin): 1.5 credits/s, shortest duration 5s, so 7.5 credits minimum · Fast cinematic videos in any style, with audio, 480p\n- \"griffin-hd\" (Griffin HD): 2 credits/s, shortest duration 5s, so 10 credits minimum · Same as Griffin, but in 720p\n- \"blitz\" (Blitz): 1 credits/s, shortest duration 2s, so 2 credits minimum · LEGACY - scheduled for removal, do not use for new work\n- \"eagle\" (Eagle): 1.3 credits/s · LEGACY - scheduled for removal, do not use for new work\n- \"eagle-audio\" (Eagle with Audio): 1.8 credits/s · LEGACY - scheduled for removal, do not use for new work\nLegacy aliases: \"standard\" → blitz.\nModels marked LEGACY still work for existing integrations but will be removed; pick a current model for anything new. Default: \"griffin\".", "enum": [ "griffin", "griffin-hd", "blitz", "standard", "eagle", "eagle-audio" ], "example": "griffin", "type": "string" }, "prompt": { "description": "Text description of the motion or action for the video (e.g., \"walking forward\", \"waving hand\", \"camera zoom in\")", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "image", "prompt" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createVideo", "outputSchema": null }, { "description": "Generate a video from 1-5 reference images and a text prompt (references-to-video). Unlike createVideo, which animates a single source image, this composes a new scene that borrows characters, objects, and style from the reference images. Each image can be a URL or base64. Griffin (default, 480p) and Griffin HD (720p) generate a soundtrack; note the per-second rate here is higher than createVideo's for the same model. The job result is the video URL and its actual duration in seconds. Choose the output shape with `aspect_ratio` (\"default\" lets the model decide). The chosen `model` and `duration` must be compatible (incompatible combinations return HTTP 400). Credits are held when the job is accepted; the final charge is max(rate × produced seconds, the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. Pass an optional `request_id` to tag the result so you can locate it later via listGenerations (type video). Related tools: `createVideo` for image-to-video, `editVideo` to modify a generated video. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: credits/s × seconds, per model: Griffin 2.5/s (shortest duration 5s, so 12.5 credits minimum), Griffin HD 4/s (shortest duration 5s, so 20 credits minimum), Eagle 1.5/s [LEGACY], Eagle with Audio 2/s [LEGACY]; [LEGACY] models are scheduled for removal - do not use them for new work; see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating a video from 1-5 reference images and a text prompt.", "properties": { "aspect_ratio": { "description": "Output aspect ratio. \"default\" lets the model choose. Default: \"default\".", "enum": [ "default", "ar_1_1", "ar_16_9", "ar_9_16", "ar_4_3", "ar_3_4", "ar_21_9" ], "example": "default", "type": "string" }, "duration": { "description": "Duration in seconds. Available values depend on the model:\n- griffin: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- griffin-hd: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- eagle: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- eagle-audio: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 Default: 5.", "example": 5, "format": "float", "type": "number" }, "images": { "description": "Reference images (1 to 5), each a URL or base64. The generated video borrows characters, objects, and style from them.", "items": { "type": "string" }, "maxItems": 5, "minItems": 1, "type": "array" }, "model": { "description": "Model to use. Available models:\n- \"griffin\" (Griffin): 2.5 credits/s, shortest duration 5s, so 12.5 credits minimum · Fast cinematic videos in any style, with audio, 480p\n- \"griffin-hd\" (Griffin HD): 4 credits/s, shortest duration 5s, so 20 credits minimum · Same as Griffin, but in 720p\n- \"eagle\" (Eagle): 1.5 credits/s · LEGACY - scheduled for removal, do not use for new work\n- \"eagle-audio\" (Eagle with Audio): 2 credits/s · LEGACY - scheduled for removal, do not use for new work\nModels marked LEGACY still work for existing integrations but will be removed; pick a current model for anything new. Default: \"griffin\".", "enum": [ "griffin", "griffin-hd", "eagle", "eagle-audio" ], "example": "griffin", "type": "string" }, "prompt": { "description": "Text description of the video to generate.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "prompt", "images" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createVideoFromReferences", "outputSchema": null }, { "description": "Design a new voice from a character description (such as \"deep-voiced warrior\" or \"cheerful young girl\") and have it speak a short line of text, returning a sample of that newly created voice. Both voice_description and text are required, the spoken text is limited to 200 characters or the call returns HTTP 400, and type selects \"human\" or \"non-human\" voices. The job result is a single audio result containing the URL of an MP3 or WAV file (the URL's extension, .mp3 or .wav, says which). Credits are held when the job is accepted and refunded if it fails or is cancelled. Use this to invent and audition a voice from a description; use createSpeech for text-to-speech that clones a specific voice from an audio sample, and createSpeechPreset for text-to-speech using a named preset voice. Pass an optional request_id to tag the result so you can locate it later via listGenerations (type audio). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 1 credits per call.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating a voice sample from a character description", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "text": { "description": "Text for the voice to speak (max 200 characters).", "maxLength": 200, "minLength": 1, "type": "string" }, "type": { "description": "Type of voice to generate. Default: \"human\".", "enum": [ "human", "non-human" ], "example": "human", "type": "string" }, "voice_description": { "description": "Text description of the voice character (e.g., \"deep-voiced warrior\", \"cheerful young girl\").", "type": "string" } }, "required": [ "voice_description", "text" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "createVoice", "outputSchema": null }, { "description": "Modify an existing image according to text instructions: supply a source image (URL or base64) and a prompt describing the changes (e.g. \"add clouds\", \"warmer color scheme\"), with an optional reference_image for extra style or content guidance. The job result is an array of image results, each with a url; request n (1-4) to control the number of edited variations. Provided images are uploaded and validated, and any image larger than 15MB is rejected with HTTP 400. Credits are held when the job is accepted and refunded if it fails or is cancelled; the charge scales with the number of images produced. Use editImage to transform a specific existing image; use createImage to generate from text alone, generateWithStyle to borrow a reference's art style, and removeBackground for the dedicated background-removal case. Pass an optional request_id to tag the results so you can retrieve them later via listGenerations (type image). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.5 credits per result.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for editing an existing image based on text instructions", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "image": { "description": "URL or base64-encoded source image to edit.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "image_type": { "description": "What kind of image the source is (e.g. \"sprite\"). Not needed when `image` is the URL of an image you generated on Ludo in the last 30 days, which keeps its own type. Set it when the image is an upload or a link from elsewhere, so a sprite is edited as a sprite and keeps its transparent background.", "enum": [ "generic", "screenshot", "art", "asset", "sprite", "sprite-vfx", "sprite-tiling-horizontal", "sprite-tiling-vertical", "icon", "logo", "ui_asset", "fixed_background", "side_scrolling_background", "vertical_scrolling_background", "parallax_layer", "texture", "tile", "item-icon", "portrait", "card-art", "splash", "3d" ], "example": "sprite", "type": "string" }, "n": { "description": "Number of edited variations to generate (1-4). Default: 1.", "example": 1, "format": "integer", "maximum": 4, "minimum": 1, "type": "number" }, "prompt": { "description": "Text description of the changes to make (e.g., \"remove the background\", \"add clouds to the sky\", \"make it darker\", \"change the color scheme to warmer tones\").", "type": "string" }, "reference_image": { "description": "Optional URL or base64-encoded reference image for style or content guidance.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "image", "prompt" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "editImage", "outputSchema": null }, { "description": "Edit a previously generated spritesheet: re-prompt its underlying animation (edit_mode \"prompt\"), extend the frame beyond its borders (\"outpaint\"), or repair a bad loop (\"fix_loop\"). Pass the `spritesheet_url` you received from `animateSprite`, `animateSpriteKeyframes`, `transferMotion`, or an earlier edit - it must be a spritesheet you generated within the last 7 days; arbitrary external images are not accepted. Omit `duration`, `frames`, `frame_size`, `crop` and `model` to keep the source spritesheet's values. A `prompt` is required for edit_mode \"prompt\", optional for \"outpaint\", and not accepted for \"fix_loop\"; optionally add up to 5 reference `images` (URL or base64) to guide the edit. The job result is the same result shape as animateSprite (spritesheet URL, frame layout, optional GIF or individual frames). Credits are held for the duration you requested when the job is accepted; the final charge is max(rate × seconds of video generated, the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. The returned sheet is then trimmed to its best loop and can run slightly shorter than the video; that trim is not deducted. Prompt edits are priced per model (credits/second × duration); \"outpaint\" and \"fix_loop\" run a lighter pipeline in which `model` is ignored and are billed at a flat 1 credit per second of the output duration (the source spritesheet's duration unless you pass one). Outpaint decides the extra margin itself - there is no amount parameter. The result carries the same fields as animateSprite (`spritesheet_url`, `video_url`, grid fields); audio is generated only by prompt edits on hydra, so a fix on a hydra sheet comes back without `audio_url`. Pass an optional `request_id` to tag the result for later retrieval via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: edit_mode \"fix_loop\" / \"outpaint\": flat 1 credit per second of output, no minimum, model ignored; edit_mode \"prompt\": per model as listed - credits/s × seconds, per model: Hydra 3/s (min charge 9 credits), Forge 2/s (min charge 4 credits), Forge Pixel 2/s (min charge 4 credits); see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for editing a previously generated spritesheet. edit_mode selects the operation - prompt-driven edit (default), outpaint, or loop fixing.", "properties": { "crop": { "description": "Crop sprite frames to fit content (omit to keep the source spritesheet's setting). Results in smaller spritesheets but inconsistent frame sizes across different animations.", "type": "boolean" }, "duration": { "description": "Duration in seconds. Available values depend on the model:\n- hydra: 3, 3.5, 4, 4.5, 5\n- forge: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5\n- forge-pixel: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5", "format": "float", "type": "number" }, "edit_mode": { "description": "Edit operation to perform. Default: \"prompt\".", "enum": [ "prompt", "outpaint", "fix_loop" ], "example": "prompt", "type": "string" }, "frame_size": { "description": "Size of each frame in pixels (width and height). 0 is for maximum resolution. Omit to keep the source spritesheet's frame size. Accepted values: 32, 64, 96, 128, 192, 256, 384, 0.", "format": "integer", "type": "number" }, "frames": { "description": "Number of frames in the output spritesheet. Omit to keep the source spritesheet's frame count. Allow about one second of duration per 16 frames - above that the model may not be able to produce them all. Accepted values: 4, 9, 16, 25, 36, 49, 64.", "format": "integer", "type": "number" }, "gif": { "description": "When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time. Default: false.", "example": false, "type": "boolean" }, "images": { "description": "Optional reference images (up to 5), each a URL or base64, to guide the edit. Two, at most three, work best: more references reduce the model's ability to use any of them correctly.", "items": { "type": "string" }, "maxItems": 5, "type": "array" }, "individual_frames": { "description": "When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls. Default: false.", "example": false, "type": "boolean" }, "loop": { "description": "Trim the animation at the beginning or end to create a seamless loop. Default: true.", "type": "boolean" }, "model": { "description": "Model to use. Available models:\n- \"hydra\" (Hydra): 3 credits/s, min charge 9 credits · Most capable all-around model, generates audio\n- \"forge\" (Forge): 2 credits/s, min charge 4 credits · Sharper detail, simpler motion. Best for simple body shapes and short actions; may need a few tries\n- \"forge-pixel\" (Forge Pixel): 2 credits/s, min charge 4 credits · Best for low-res pixel art animations Default: \"hydra\".", "enum": [ "hydra", "forge", "forge-pixel" ], "type": "string" }, "prompt": { "description": "Edit instruction. Required for edit_mode \"prompt\", optional for \"outpaint\", not accepted for \"fix_loop\". Focus it on a single change and keep it short (under about 50 words); run a second edit for more.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "spritesheet_url": { "description": "URL of a spritesheet you generated in the last 7 days (returned by animateSprite, transferMotion, or a previous edit as spritesheet_url). External URLs are not accepted. Edit the original animation rather than a previous edit's result: every edit re-renders the whole animation, so colors and detail drift further with each pass. If an edit did not work, retry from the original instead of editing on top.", "example": "<url>", "type": "string" }, "spritesheet_with_background": { "description": "When true, also returns the spritesheet with background intact (before background removal). The with-background spritesheet URL will be in spritesheet_with_background_url. Default: false.", "example": false, "type": "boolean" } }, "required": [ "spritesheet_url" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "editSpritesheet", "outputSchema": null }, { "description": "Edit a previously generated video with a text prompt and optional reference images (video-to-video); runs on griffin-hd (720p, with soundtrack) and the output keeps the source video's duration unless you pass one. Pass the video `url` you received from `createVideo`, `createVideoFromReferences`, or an earlier edit - it must be a video you generated within the last 7 days; arbitrary external videos are not accepted. Optionally add up to 5 reference `images` (URL or base64) to guide the edit. The job result is the new video URL and its actual duration in seconds. Credits are held when the job is accepted; the final charge is max(rate × produced seconds, the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. Pass an optional `request_id` to tag the result so you can locate it later via listGenerations (type video). Related tools: `createVideo` to generate the source clip, `createVideoFromReferences` for reference-driven generation. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: credits/s × seconds, per model: Griffin HD 2/s (shortest duration 5s, so 10 credits minimum), Eagle 2/s [LEGACY]; [LEGACY] models are scheduled for removal - do not use them for new work; see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for editing a previously generated video with a text prompt and optional reference images.", "properties": { "duration": { "description": "Duration in seconds. Available values depend on the model:\n- griffin-hd: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15\n- eagle: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15", "format": "float", "type": "number" }, "images": { "description": "Optional reference images (up to 5), each a URL or base64, to guide the edit.", "items": { "type": "string" }, "maxItems": 5, "type": "array" }, "model": { "description": "Model to use. Available models:\n- \"griffin-hd\" (Griffin HD): 2 credits/s, shortest duration 5s, so 10 credits minimum · Same as Griffin, but in 720p\n- \"eagle\" (Eagle): 2 credits/s · LEGACY - scheduled for removal, do not use for new work\nModels marked LEGACY still work for existing integrations but will be removed; pick a current model for anything new. Default: \"griffin-hd\".", "enum": [ "griffin-hd", "eagle" ], "example": "griffin-hd", "type": "string" }, "prompt": { "description": "Edit instruction describing the desired change.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "video": { "description": "URL of a video you generated in the last 7 days (returned by createVideo, createVideoFromReferences, or a previous edit). External URLs are not accepted.", "type": "string" } }, "required": [ "prompt", "video" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "editVideo", "outputSchema": null }, { "description": "Re-pose an existing sprite into a new target pose while preserving the character, taking a source image (URL or base64), a pose name (or \"Other\" with a free-text description), and an optional n (1-4) for how many variations to produce. Only works with sprite image types (not icons, screenshots, etc.). The job result is an array of pose results, each containing the generated image url, the pose and description used, and a suggested motion_prompt tuned for that pose. Credits are held when the job is accepted and refunded if it fails or is cancelled; the charge scales with the number of images generated. This is typically the first step before animating: call generatePose to set the character's pose, then feed the result (and its suggested motion_prompt) into animateSprite for the best animation quality; use rotateSprite instead when you want to change the camera angle rather than the pose. Pass an optional request_id to tag the results so you can locate them later via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.5 credits per result.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating a new pose for an existing sprite", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "description": { "description": "Optional additional instructions or description to guide the pose generation.", "type": "string" }, "image": { "description": "URL or base64-encoded source sprite image to generate a new pose from.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "n": { "description": "Number of pose variations to generate (1-4). Default: 1.", "example": 1, "format": "integer", "maximum": 4, "minimum": 1, "type": "number" }, "pose": { "description": "Target pose for the sprite. Use the value \"Other\" to generate other poses not listed in the accepted values, and fill the field description accordingly.", "enum": [ "Idle (Front)", "Idle (Back)", "Idle (Left Facing)", "Idle (Right Facing)", "Walk (Left)", "Walk (Right)", "Walk (Towards the camera)", "Walk (Away from the camera)", "Run (Left)", "Run (Right)", "Run (Towards the camera)", "Run (Away from the camera)", "Crouching", "Crawling", "Sitting", "Defending / Blocking", "Attack Ready", "Jump Preparation", "Sleeping", "Flying", "Other" ], "example": "Idle (Front)", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "image", "pose" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "generatePose", "outputSchema": null }, { "description": "Generate new images that match the visual style of a reference image: supply a style_image (URL or base64) plus a text prompt describing what to create and an optional image_type (defaults to sprite). The job result is an array of image results, each with a url; request n (1-4) to control the number of variations. The style_image is uploaded and validated, and an image larger than 15MB is rejected with HTTP 400. Credits are held when the job is accepted and refunded if it fails or is cancelled; the charge scales with the number of images produced. Use this instead of createImage when style consistency with an existing asset matters; use editImage to alter the content of a specific image rather than borrow its style, and removeBackground to isolate a subject. Pass an optional request_id to tag the results so you can retrieve them later via listGenerations (type image). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.5 credits per result.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for generating new content while maintaining the visual style of a reference image", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "image_type": { "description": "What kind of image to generate. Default: \"sprite\".", "enum": [ "generic", "screenshot", "art", "asset", "sprite", "sprite-vfx", "sprite-tiling-horizontal", "sprite-tiling-vertical", "icon", "logo", "ui_asset", "fixed_background", "side_scrolling_background", "vertical_scrolling_background", "parallax_layer", "texture", "tile", "item-icon", "portrait", "card-art", "splash", "3d" ], "example": "sprite", "type": "string" }, "n": { "description": "Number of variations to generate (1-4). Default: 1.", "example": 1, "format": "integer", "maximum": 4, "minimum": 1, "type": "number" }, "prompt": { "description": "Text description of what to generate (e.g., \"a warrior character\", \"a forest background\", \"a treasure chest\").", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "style_image": { "description": "URL or base64-encoded reference image whose visual style should be matched.", "example": "<url> OR data:image/png;base64,...", "type": "string" } }, "required": [ "style_image", "prompt" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "generateWithStyle", "outputSchema": null }, { "description": "Show your account's credit balance, plan and auto top-up settings. `credits.available` is what generations can spend right now (plan_credits + extra - used); `resets_at` is when the plan's monthly credits refill (unix seconds). When `team_pool` is true the balance is your team's shared pool, and `auto_topup` is null because the team owner manages it. Check this before an expensive generation instead of waiting for a 402. Buying credits and changing auto top-up happen in the web app at `billing_url`. This is a free read-only lookup (no credits, no generation).", "inputSchema": { "properties": {}, "required": [], "type": "object" }, "name": "getAccount", "outputSchema": null }, { "description": "Poll the status of a generation job started by any tool. Every generation tool returns `{id, status}`; call getApiJob with that id until status is `succeeded` (then read `result`, shaped exactly like the tool's documented output) or `failed` (read `error`). Poll every few seconds, or pass `wait: 30` to long-poll - the call is held up to 30 seconds (max 60) and returns as soon as the job finishes.", "inputSchema": { "properties": { "id": { "description": "The job id returned by a generation call (its `id` in the 202 response).", "type": "string" }, "wait": { "description": "Seconds to long-poll for a terminal state (0-60). Defaults to 0 (return immediately).", "format": "int32", "type": "integer" } }, "required": [ "id" ], "type": "object" }, "name": "getApiJob", "outputSchema": null }, { "description": "Browse or read Ludo's own documentation in full - how to choose a sprite animation mode, when to use Generate Before / Generate After, how margins behave, which model suits a job, and each generator's known limitations. To answer a specific question, call searchDocs first: it returns just the sections that match. Use getDocs to see what documentation exists, or to read a whole document or named sections. This is the same documentation the Ludo web app shows its users, so it occasionally describes buttons rather than parameters; the substance applies to the API and MCP surfaces just the same. To browse, call it with NO parameters to get a table of contents - every document with its id, label and section titles, and no bodies - then call it again with `doc` (and optionally `sections`) to read only what you need. Fetching a whole document can return tens of thousands of characters, so prefer naming the sections, using titles copied from the table of contents. Section titles match ignoring case, spacing and punctuation: when only some requested titles exist you receive those sections plus `unmatched_sections` and `available_sections`, and when none exist (or `doc` is unknown) the call returns 400 listing the valid values so you can retry once. This is a free discovery endpoint: it does not charge credits and does not queue a job.", "inputSchema": { "properties": { "doc": { "description": "Which document to read, by id (the table of contents returned by the no-parameter call lists them). Omit to receive the table of contents.", "enum": [ "assistant", "game-ideator", "image-generator", "project", "account", "faq", "3d-generator", "video-generator", "sprite-generator", "audio-generator", "api-mcp", "game-asset-generation" ], "type": "string" }, "sections": { "description": "Section titles to return from `doc`, copied from the table of contents (an array of titles; over plain REST, a comma-separated string, where a title that itself contains a comma is still matched whole). Matching ignores case, spacing and punctuation; titles that match nothing are reported back in `unmatched_sections` rather than guessed at. Only valid together with `doc`. Omit to return every section of the document.", "items": { "type": "string" }, "type": "array" } }, "required": [], "type": "object" }, "name": "getDocs", "outputSchema": null }, { "description": "List the available animation presets along with their perspectives and the eight supported compass directions (N, NE, E, SE, S, SW, W, NW). Synchronous GET with no request body: it returns an animations array (each with id, name, category, description, duration, preview_url, and - when the preset can be retargeted onto a rigged 3D model - clip_url), a deduplicated perspectives array, and the directions list. This is a free discovery endpoint and does not charge credits. Use it to obtain the preset_id, perspective, and direction values that transferMotion needs, and to find motion preset names you can reference when animating; pair it with transferMotion (to apply a preset onto a sprite), animateSprite (text-prompt animation), or animate3DModelPreset (apply a clip_url-backed preset to a rigged 3D model).", "inputSchema": { "properties": {}, "required": [], "type": "object" }, "name": "listAnimationPresets", "outputSchema": null }, { "description": "List the generation jobs you started through the API or MCP, most recent first. Web-app jobs are not included. This is a free read-only lookup (no credits, no generation). Filter with a comma-separated status list; limit defaults to 50 and is capped at 100.", "inputSchema": { "properties": { "limit": { "description": "Maximum number of jobs to return. Defaults to 50, capped at 100.", "format": "int32", "type": "integer" }, "status": { "description": "Comma-separated statuses to include (queued, running, succeeded, failed, canceled). Defaults to all.", "type": "string" } }, "required": [], "type": "object" }, "name": "listApiJobs", "outputSchema": null }, { "description": "List your generation history across the API and the web app - filter by type, source (api|web|all), text search, and date range. Returns {items, page, page_size, has_more}; keep paging while has_more is true. API-originated results expire after 7 days - download anything you want to retain. For an in-flight job's status use getApiJob instead.", "inputSchema": { "properties": { "date_from": { "description": "Only return items generated at or after this time (unix seconds)", "type": "integer" }, "date_to": { "description": "Only return items generated at or before this time (unix seconds)", "type": "integer" }, "page_number": { "description": "1-based page number Default: 1.", "type": "integer" }, "page_size": { "description": "Items per page (1-100) Default: 20.", "type": "integer" }, "request_id": { "description": "Only return items tagged with this request_id when you generated them", "type": "string" }, "search": { "description": "Free-text search. Every whitespace-separated term must match (case-insensitive substring) the item's tags or one of its text fields (prompt, hints, style, label, ...), so \"dwarf axe\" narrows to items matching both.", "type": "string" }, "source": { "description": "Which surface the items were generated from: api (your API/MCP generations, last 7 days only), web (your Ludo web studio generations, no time limit), or all (default, both) Default: \"all\".", "enum": [ "api", "web", "all" ], "type": "string" }, "type": { "description": "Which kind of generation to list", "enum": [ "image", "spritesheet", "video", "audio", "3d" ], "type": "string" } }, "required": [ "type" ], "type": "object" }, "name": "listGenerations", "outputSchema": null }, { "description": "Remove the background from a single image, returning the subject isolated on a transparent background. Supply the source image (URL or base64); optionally set crop to trim the result to the content, and creative_edit (default true) for higher-quality output that may not match the input pixel-for-pixel - set it false when the subject must stay pixel-identical, e.g. an existing sprite you will animate. The job result is a single image result with a url (not an array). The image is uploaded and validated, and an image larger than 15MB is rejected with HTTP 400. Credits are held when the job is accepted and refunded if it fails or is cancelled. Use removeBackground for this dedicated cutout task; editImage can also remove backgrounds via a prompt but is better for broader edits, while createImage and generateWithStyle produce new images rather than process an existing one. Pass an optional request_id to tag the result so you can retrieve it later via listGenerations (type image). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.5 credits per result.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for removing the background of an image", "properties": { "creative_edit": { "description": "Higher quality results but the image will not be exactly the same as the input. Default: true.", "example": true, "type": "boolean" }, "crop": { "description": "Whether to crop/trim the result to fit the content. Default: false.", "example": false, "type": "boolean" }, "image": { "description": "URL or base64-encoded image to remove the background from.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "image" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "removeBackground", "outputSchema": null }, { "description": "Rig a 3D model: generate a skeleton and skin weights for an existing GLB so it can be animated. Accepts a URL or base64-encoded GLB in `model` (here `model` is the 3D asset file, not an AI model name - there is no model choice on the 3D tools). The job result is a downloadable `model_url` for the rigged GLB. rig_type selects the skeleton prior - general (default, any asset), humanoid (anime-style characters), game (classic game-character rigs), or the pinned humanoid templates for two-armed, two-legged characters: humanoid_template (standard 22-joint skeleton with named joints, required for animating from the preset library) and humanoid_template_hands (52 joints, five fingers per hand). joint_naming relabels the identified joints to a convention - smpl (default), mixamo, humanik, unreal, godot, rigify, or vroid - without changing the skeleton. Credits are held when the job is accepted and refunded if it fails or is cancelled. Rigging is non-destructive to geometry but replaces any prior skeleton, so animations made against an old rig no longer apply. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 1 credits per call.", "inputSchema": { "properties": { "requestBody": { "properties": { "joint_naming": { "description": "Bone naming convention for the identified joints: smpl (default), mixamo (Unity's humanoid auto-mapper), humanik (same names unprefixed - Maya/MotionBuilder/FBX), unreal (UE mannequin), godot (SkeletonProfileHumanoid), rigify (Blender) or vroid (VRM). Purely a relabel - the skeleton is identical. Default: \"smpl\".", "enum": [ "smpl", "mixamo", "humanik", "unreal", "godot", "rigify", "vroid" ], "example": "smpl", "type": "string" }, "model": { "description": "The 3D asset to rig, as a URL or base64-encoded GLB file (not an AI model name).", "example": "<url> OR data:model/gltf-binary;base64,...", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "rig_type": { "description": "Which skeleton to build. Pick humanoid_template (or humanoid_template_hands) if you intend to use animate3DModelPreset later - the default general rig cannot take presets. general (any asset), humanoid (anime-style characters), game (classic game-character rigs), or the pinned humanoid templates with named joints required for the animation preset library - humanoid_template (22 joints) / humanoid_template_hands (52, five fingers per hand). Templates only suit two-armed, two-legged characters. Default: \"general\".", "enum": [ "general", "humanoid", "game", "humanoid_template", "humanoid_template_hands" ], "example": "general", "type": "string" } }, "required": [ "model" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "rigModel", "outputSchema": null }, { "description": "Re-render an existing sprite from a different camera viewpoint while keeping the same character and pose, taking a source image (URL or base64), a required camera_rotation azimuth (one of 0, 45, 90, 135, 180, -135, -90, -45 degrees), an optional camera_elevation (0, 30, or 60 degrees; omit to keep the current elevation), and an optional n (1-4) for the number of variations. Only works with sprite image types (not icons, screenshots, etc.). The job result is an array of rotate-sprite results, each with the generated image url and the camera_rotation and camera_elevation that were applied. Credits are held when the job is accepted and refunded if it fails or is cancelled; the charge scales with the number of images generated. Use this to produce alternate view angles of a character; use generatePose instead to change the character's pose rather than the camera, and animateSprite or transferMotion to bring a sprite to life. Pass an optional request_id to tag the results so you can retrieve them later via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: This endpoint consumes 0.5 credits per result.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for rotating the camera view of an existing sprite", "properties": { "augment_prompt": { "description": "Rewrites your prompt behind the scenes into the form the model works best with. Leave it on (the default). Turning it off does not give you more control - it usually gives worse results. Do not disable it unless you really know what you are doing and have tested your prompts extensively. Default: true.", "example": true, "type": "boolean" }, "camera_elevation": { "description": "Optional camera elevation/tilt in degrees. 0 = eye-level, 30 = elevated, 60 = high-angle. Omit to keep the sprite's current elevation. Accepted values: 0, 30, 60.", "example": 0, "type": "integer" }, "camera_rotation": { "description": "Camera azimuth angle in degrees. 0 = front, 45 = front-right, 90 = right side, 135 = back-right, 180 = back, -135 = back-left, -90 = left side, -45 = front-left. Accepted values: 0, 45, 90, 135, 180, -135, -90, -45.", "example": 0, "type": "integer" }, "image": { "description": "URL or base64-encoded source sprite image to rotate.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "n": { "description": "Number of variations to generate (1-4). Default: 1.", "example": 1, "format": "integer", "maximum": 4, "minimum": 1, "type": "number" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" } }, "required": [ "image", "camera_rotation" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "rotateSprite", "outputSchema": null }, { "description": "Re-render a previously generated sprite animation from a new view: the same motion and timing, seen from a different angle (e.g. a front-facing walk cycle turned into the same walk seen from the back). Pass the `spritesheet_url` you received from `animateSprite`, `animateSpriteKeyframes`, `transferMotion`, `editSpritesheet` or an earlier call - it must be a spritesheet you generated within the last 7 days; arbitrary external images are not accepted - and, as `image` (URL or base64), the character exactly as it must appear in the new view: it becomes the first frame of the animation. To produce that image, call rotateSprite on the animation's first frame (or any image of the character) and pick the view you want. An optional `final_image` fixes the last frame (it defaults to the first frame, for cyclic or returning animations), and an optional `prompt` steers the result: the character's facing in the new view (\"its back to the camera\"), where the action goes (\"the kick goes to the left of the frame\"), or anything else about the motion. Runs on hydra only. The job result is the same sprite result as animateSprite (`spritesheet_url`, `video_url`, grid fields, optional GIF and frame URLs). The animation covers the source's own length (up to 5 seconds; a longer source is sped up to fit), so omit `duration` unless you need to change that. Credits are held for that length when the job is accepted, and never less than the model's minimum charge (hydra generates at least 3 seconds, so 9 credits); the final charge is the model's rate × seconds of video generated, never more than was held, and the difference (or everything, if the job fails or is cancelled) is refunded. Pass an optional request_id to tag the result for later retrieval via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: Cost varies by model and duration (credits/second × duration).", "inputSchema": { "properties": { "requestBody": { "description": "Payload for re-rendering a previously generated sprite animation from a new view.", "properties": { "crop": { "description": "Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations. Default: true.", "type": "boolean" }, "duration": { "description": "Duration in seconds. Available values depend on the model:\n- hydra: 3, 3.5, 4, 4.5, 5", "format": "float", "maximum": 5, "minimum": 1, "type": "number" }, "final_image": { "description": "Optional exact last frame (URL or base64). Defaults to the first frame, for cyclic or returning animations.", "type": "string" }, "frame_size": { "description": "Size of each frame in pixels (width and height). 0 is for maximum resolution. Omit to keep the source spritesheet's frame size. Accepted values: 32, 64, 96, 128, 192, 256, 384, 0.", "format": "integer", "type": "number" }, "frames": { "description": "Number of frames in the output spritesheet. Omit to keep the source spritesheet's frame count. Allow about one second of duration per 16 frames - above that the model may not be able to produce them all. Accepted values: 4, 9, 16, 25, 36, 49, 64.", "format": "integer", "type": "number" }, "gif": { "description": "When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time. Default: false.", "example": false, "type": "boolean" }, "image": { "description": "The character exactly as it must appear in the new view, as a URL or base64. It becomes the first frame of the animation. rotateSprite produces one from the animation's first frame.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "individual_frames": { "description": "When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls. Default: false.", "example": false, "type": "boolean" }, "loop": { "description": "Trim the animation at the beginning or end to create a seamless loop. Omit to keep the source spritesheet's setting.", "type": "boolean" }, "model": { "description": "Model to use. Available models:\n- \"hydra\" (Hydra): 3 credits/s, min charge 9 credits · Most capable all-around model, generates audio Default: \"hydra\".", "enum": [ "hydra" ], "type": "string" }, "prompt": { "description": "Optional instructions - the character's facing in the new view (\"its back to the camera\"), where the action goes (\"the kick goes to the left of the frame\"), or anything else about the motion.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "spritesheet_url": { "description": "URL of a spritesheet you generated in the last 7 days (returned by animateSprite, animateSpriteKeyframes, transferMotion or editSpritesheet as spritesheet_url). External URLs are not accepted.", "example": "<url>", "type": "string" }, "spritesheet_with_background": { "description": "When true, also returns the spritesheet with background intact (before background removal). The with-background spritesheet URL will be in spritesheet_with_background_url. Default: false.", "example": false, "type": "boolean" } }, "required": [ "spritesheet_url", "image" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "rotateSpritesheet", "outputSchema": null }, { "description": "Search Ludo's own documentation with a plain-language question and get back only the few sections that answer it - the fastest way to learn how a feature is meant to be used before you generate with it (how to pick a sprite animation mode or model, how margins behave, what something costs, known limitations). Start here rather than reading whole documents. Each result carries `doc` and `section`, which you can pass straight to getDocs to re-read that section, and the section's full markdown `content`. Results are best first; weak matches are left out, so an empty `results` list means the documentation does not cover the question - rephrase it, or call getDocs with no parameters to browse the table of contents. This is the same documentation the Ludo web app shows its users, so it occasionally describes buttons rather than parameters; the substance applies to the API and MCP surfaces just the same. Returns up to `n` sections (default 3, max 10). If it answers 503 the search backend is briefly unavailable: call getDocs instead rather than retrying in a loop. This is a free discovery endpoint: it does not charge credits and does not queue a job.", "inputSchema": { "properties": { "n": { "description": "Maximum number of sections to return. Defaults to 3.", "format": "int32", "maximum": 10, "minimum": 1, "type": "integer" }, "query": { "description": "What you want to know, in plain language, e.g. \"how do I keep a sprite animation's colors consistent\" or \"what does a 3D model cost\".", "maxLength": 500, "minLength": 1, "type": "string" } }, "required": [ "query" ], "type": "object" }, "name": "searchDocs", "outputSchema": null }, { "description": "Report a problem with the Ludo API itself to the Ludo team. Use it ONLY for API bugs (an error, a failed or stuck job, a crash, a response that does not match this documentation) and API limitations (a parameter, operation or format you needed that the API does not support, and that you could not work around). NEVER use it to report model limitations or the quality of a result: an image, sprite, animation, 3D model, video or sound that looks wrong, ignores part of the prompt, has artifacts or is not what you wanted is not an API bug. Do not report those; retry with a different prompt, model or settings instead. Describe what you were trying to do and what went wrong, and name the operation (and job_id, when there is one) it relates to. Do not include personal data, secrets or file contents. Send one report per issue, and if you are an agent, tell the user what you sent. Free (no credits).", "inputSchema": { "properties": { "requestBody": { "properties": { "agent": { "description": "The agent or app sending it, e.g. Claude Code.", "maxLength": 100, "type": "string" }, "category": { "description": "bug - the API errored, a job failed or got stuck, or a response did not match the documentation; limitation - the API does not support a parameter, operation or format you needed; feature_request - a new API capability you would like; praise - something that worked well; other - any other API issue. Generated content that looks wrong or does not match the prompt is a model limitation, not a bug: do not report it.", "enum": [ "limitation", "bug", "feature_request", "praise", "other" ], "example": "limitation", "type": "string" }, "job_id": { "description": "The job the feedback is about, when there is one.", "maxLength": 64, "type": "string" }, "message": { "description": "What you were trying to do, what happened, and what would have helped.", "maxLength": 4000, "minLength": 1, "type": "string" }, "operation": { "description": "The operation the feedback is about, e.g. animateSprite.", "maxLength": 100, "type": "string" } }, "required": [ "category", "message" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "submitApiFeedback", "outputSchema": null }, { "description": "Transfer motion from a reference video or a named animation preset onto a static sprite image, producing an animated spritesheet that mimics the reference movement. Provide the sprite as image (URL or base64) plus either a video URL or a preset_id together with perspective and direction (all three from listAnimationPresets; if both video and preset_id are sent the video wins). The job result is the same sprite result as animateSprite: `spritesheet_url`, `video_url`, grid fields, optional GIF / frame / with-background URLs, and `audio_url` when the model is hydra. `duration` defaults to 1.5s where the chosen model offers it, otherwise to that model's shortest (hydra, the default, starts at 3s) - and a longer reference clip or preset is compressed to fit, so pass the preset's own `duration` (returned by listAnimationPresets) to keep its timing. It returns HTTP 400 if neither a video nor a complete preset_id/perspective/direction triple is supplied, if the named preset, perspective, or direction cannot be resolved, or if the model/duration combination is invalid. Credits are held for the duration you requested when the job is accepted; the final charge is max(rate × seconds of video generated (which follows the reference clip or preset), the model's minimum charge), never more than for the duration you requested, and the difference (or everything, if the job fails or is cancelled) is refunded. The returned sheet is then trimmed to its best loop and can run slightly shorter than the video; that trim is not deducted. Use this when you have an existing motion clip or preset to copy; prefer animateSprite to generate animation purely from a text prompt. Omit `model` to run on hydra (the default - most capable, and returns audio); pick forge for a cheaper run on simple motion, presets and matching poses; the `model` field lists rates. Pass an optional request_id to tag the result so you can retrieve it later via listGenerations (type spritesheet). Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: credits/s × seconds, per model: Hydra 3/s (min charge 9 credits), Forge 2/s (min charge 4 credits), Forge Pixel 2/s (min charge 4 credits), Tango 4/s (min charge 4 credits) [LEGACY]; [LEGACY] models are scheduled for removal - do not use them for new work; see this endpoint's full pricing table in the API docs.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for transferring motion from a video onto a static sprite image, producing an animated spritesheet.", "properties": { "crop": { "description": "Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations. Default: true.", "example": true, "type": "boolean" }, "direction": { "description": "Direction for the animation preset. When using a preset, `direction` is required.", "enum": [ "N", "NE", "E", "SE", "S", "SW", "W", "NW" ], "example": "N", "type": "string" }, "duration": { "description": "Duration in seconds. If the reference video is longer, it will be compressed to this duration. Available values depend on the model:\n- hydra: 3, 3.5, 4, 4.5, 5\n- forge: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5\n- forge-pixel: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5\n- tango: 1, 1.5, 2, 2.5, 3, 3.5, 4 Default: 1.5.", "example": 1.5, "format": "float", "type": "number" }, "frame_size": { "description": "Size of each frame in pixels (width and height). 0 is maximum resolution. Exporting larger than the input image adds no detail: do not pick a size above the input's own resolution, and 0 gains nothing on inputs under 512 px. True Size is not available here: the image is not the first frame of the result, so there is nothing to align to. Accepted values: 32, 64, 96, 128, 192, 256, 384, 0. Default: 0.", "example": 0, "format": "integer", "type": "number" }, "frames": { "description": "Maximum number of frames in the output spritesheet. Allow about one second of duration per 16 frames - above that the model may not be able to produce them all (64 frames needs a duration of at least 4). The result can have fewer frames when the duration is short or bad frames were removed. Accepted values: 4, 9, 16, 25, 36, 49, 64. Default: 36.", "example": 36, "format": "integer", "type": "number" }, "gif": { "description": "When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time. Default: false.", "example": false, "type": "boolean" }, "image": { "description": "The static sprite to animate, as a URL or base64 image. Ideally an image generated with the \"sprite\", \"sprite-vfx\" or \"ui_asset\" image type.", "example": "<url> OR data:image/png;base64,...", "type": "string" }, "individual_frames": { "description": "When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls. Default: false.", "example": false, "type": "boolean" }, "loop": { "description": "Trim the animation at the beginning or end to create a seamless loop. Default: true.", "example": true, "type": "boolean" }, "margin_ratio": { "deprecated": true, "description": "Deprecated: prefer margin_ratio_horizontal / margin_ratio_vertical. Amount of padding around the sprite as a ratio (0.0 to 1.0). Sets both axes to this value. A per-axis value, when also given, overrides this for that axis. Defaults to 0.15 when no margin value is given at all.", "format": "float", "type": "number" }, "margin_ratio_horizontal": { "description": "Horizontal padding around the sprite as a ratio (0.0 to 1.0). Every bit of margin is resolution taken from the sprite, so keep it as tight as the motion allows - about 0.15 - and go higher only for motion that extends sideways (sword slashes, punches) or if the sprite gets cut off. Overrides the legacy margin_ratio on this axis.", "format": "float", "type": "number" }, "margin_ratio_mode": { "description": "How the sprite is framed for generation. Defaults to \"manual\" (0.15 on each axis when no margin value is given); transfer motion has no \"auto\". The model always generates on a canvas of the same size, so any margin is canvas the sprite does not fill: the more margin, the lower the resolution and detail of the sprite. Keep the margins tight - about 0.15 - and raise only the axis the motion needs. \"none\" animates the image exactly as framed, so it must already have suitable margins (not touching the edges, not mostly empty space); an off-center sprite can give unpredictable results. Sending \"none\" together with a margin value fails with HTTP 400 (the value would be ignored). Default: \"manual\".", "enum": [ "manual", "none" ], "example": "manual", "type": "string" }, "margin_ratio_vertical": { "description": "Vertical padding around the sprite as a ratio (0.0 to 1.0). Every bit of margin is resolution taken from the sprite, so keep it as tight as the motion allows - about 0.15 - and go higher only for motion that extends up or down (jumps) or if the sprite gets cut off. Overrides the legacy margin_ratio on this axis.", "format": "float", "type": "number" }, "model": { "description": "Model to use. Available models:\n- \"hydra\" (Hydra): 3 credits/s, min charge 9 credits · Most capable all-around model, generates audio\n- \"forge\" (Forge): 2 credits/s, min charge 4 credits · Sharper detail, simpler motion. Best for simple body shapes and short actions; may need a few tries\n- \"forge-pixel\" (Forge Pixel): 2 credits/s, min charge 4 credits · Best for low-res pixel art animations\n- \"tango\" (Tango): 4 credits/s, min charge 4 credits · LEGACY - scheduled for removal, do not use for new work\nModels marked LEGACY still work for existing integrations but will be removed; pick a current model for anything new.\nforge is tuned for the motion presets (preset_id) and often fails to follow your own video - use hydra for custom footage. forge-pixel expects real pixel art - a perfect pixel grid at its natural resolution. Default: \"hydra\".", "enum": [ "hydra", "forge", "forge-pixel", "tango" ], "example": "hydra", "type": "string" }, "perspective": { "description": "Camera perspective of the preset clip, by id (the `perspectives` list of listAnimationPresets, the same set for every preset): high = tactical steep top-down, horizon = side view at eye level, isometric = diagonal top-down with depth, low = hero low angle, top = directly overhead. Required when using a preset. Unrelated to the `perspective` of createImage, which is a free-text art direction.", "enum": [ "high", "horizon", "isometric", "low", "top" ], "example": "high", "type": "string" }, "preset_id": { "description": "ID of an animation preset to use instead of a video URL. Use listAnimationPresets to list available presets. When using a preset, `perspective` and `direction` are required.", "type": "string" }, "prompt": { "description": "Optional extra instructions for the motion transfer (e.g. \"keep the cape still\"), added to the model's own prompt.", "type": "string" }, "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "spritesheet_with_background": { "description": "When true, also returns the spritesheet with background intact (before background removal). Useful for manually fixing background removal issues. The with-background spritesheet URL will be in spritesheet_with_background_url. Default: false.", "example": false, "type": "boolean" }, "video": { "description": "URL of the video to use as motion source - the `video_url` of a spritesheet from animateSprite, or your own clip. Videos up to 4 seconds work best. Either `video` or `preset_id` + `perspective` + `direction` must be provided; when both are sent the video is used. A video more than twice as long as `duration` gets heavily compressed and the motion turns rushed - trim it to the part you want, or raise `duration`.", "type": "string" } }, "required": [ "image" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "transferMotion", "outputSchema": null }, { "description": "Upscale a previously generated video to twice its resolution (2x). Pass the video `url` you received from `createVideo`, `createVideoFromReferences`, or `editVideo` - it must be a video you generated within the last 7 days; arbitrary external videos are not accepted. Both dimensions of the source must be under 960 pixels: griffin (480p) output qualifies; griffin-hd (720p) output does not, landscape or portrait (only a square 720x720 would) - generate on griffin if you intend to upscale. A too-large source fails the job and the held credits are refunded. The job result is the new video URL (2x width and height, same duration) and its duration in seconds. Billed per second of video, independent of model; held when the job is accepted and refunded if it fails or is cancelled. Pass an optional `request_id` to tag the result so you can locate it later via listGenerations (type video). Related tools: `createVideo` for image-to-video, `editVideo` to modify a generated video. Async generation job: returns `{id, status}` - poll `getApiJob` (job and credit contract: see the server instructions).\n\nCredits: 0.2 credits per second of video.", "inputSchema": { "properties": { "requestBody": { "description": "Payload for upscaling a previously generated video to twice its resolution.", "properties": { "request_id": { "description": "Optional client-provided identifier, unique per request. Re-sending the same request_id returns the existing job instead of generating again. Also usable as the request_id filter of listGenerations.", "type": "string" }, "video": { "description": "URL of a video you generated in the last 7 days (returned by createVideo, createVideoFromReferences, or editVideo). External URLs are not accepted. Both dimensions must be under 960 pixels (griffin 480p output qualifies; griffin-hd 720p output does not, except square).", "type": "string" } }, "required": [ "video" ], "type": "object" } }, "required": [ "requestBody" ], "type": "object" }, "name": "upscaleVideo", "outputSchema": null }, { "description": "Validates an API key. Returns 200 if valid, 403 if invalid.", "inputSchema": { "properties": {}, "required": [], "type": "object" }, "name": "validateApiKeyEndpoint", "outputSchema": null } ] }
Verify it yourselfcurl -s https://api.teppi.xyz/v1/evidence/sha256:a9a033744276d844ac6bc0c14244f1d31963b947f2abdf10ee9aa8165d07b2a6 | sha256sum