Ludo.ai · Schema

TransferMotionPayload

Payload for transferring motion from a video onto a static sprite image, producing an animated spritesheet.

Artificial IntelligenceAsset GenerationGame DesignGame DevelopmentGame Asset GenerationAI ArtSprite Sheets

Properties

Name Type Description
image string 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.
video string 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` + `dir
preset_id string 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.
direction string Direction for the animation preset. When using a preset, `direction` is required.
perspective string 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, isometr
frames number 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
frame_size number 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
loop boolean Trim the animation at the beginning or end to create a seamless loop.
crop boolean Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations.
margin_ratio number 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, overri
margin_ratio_horizontal number 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 mo
margin_ratio_vertical number 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 moti
margin_ratio_mode string 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,
gif boolean When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time.
individual_frames boolean When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls.
spritesheet_with_background boolean 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 sprites
model string Model to use. Available models: - "hydra" (Hydra): 3 credits/s, min charge 9 credits · Most capable all-around model, generates audio - "forge" (Forge): 2 credits/s, min charge 4 credits · Sharper det
prompt string Optional extra instructions for the motion transfer (e.g. "keep the cape still"), added to the model's own prompt.
duration number Duration in seconds. If the reference video is longer, it will be compressed to this duration. Available values depend on the model: - hydra: 3, 3.5, 4, 4.5, 5 - forge: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5,
request_id string 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.
async boolean Defaults to true: the call returns 202 immediately with a job id to poll with getApiJob. Set false for a synchronous response (deprecated but supported): the call then blocks until the result is ready
View JSON Schema on GitHub

JSON Schema

ludo-ai-transfer-motion-payload-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/api-evangelist/ludo-ai/main/json-schema/ludo-ai-transfer-motion-payload-schema.json",
  "title": "TransferMotionPayload",
  "description": "Payload for transferring motion from a video onto a static sprite image, producing an animated spritesheet.",
  "x-generated": "2026-10-02",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/ludo-ai-openapi.json#/components/schemas/TransferMotionPayload",
  "type": "object",
  "required": [
    "image"
  ],
  "properties": {
    "image": {
      "type": "string",
      "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."
    },
    "video": {
      "type": "string",
      "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`."
    },
    "preset_id": {
      "type": "string",
      "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."
    },
    "direction": {
      "type": "string",
      "description": "Direction for the animation preset. When using a preset, `direction` is required.",
      "enum": [
        "N",
        "NE",
        "E",
        "SE",
        "S",
        "SW",
        "W",
        "NW"
      ]
    },
    "perspective": {
      "type": "string",
      "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"
      ]
    },
    "frames": {
      "type": "number",
      "format": "integer",
      "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.",
      "default": 36,
      "enum": [
        4,
        9,
        16,
        25,
        36,
        49,
        64
      ]
    },
    "frame_size": {
      "type": "number",
      "format": "integer",
      "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.",
      "default": 0,
      "enum": [
        32,
        64,
        96,
        128,
        192,
        256,
        384,
        0
      ]
    },
    "loop": {
      "type": "boolean",
      "default": true,
      "description": "Trim the animation at the beginning or end to create a seamless loop."
    },
    "crop": {
      "type": "boolean",
      "default": true,
      "description": "Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations."
    },
    "margin_ratio": {
      "type": "number",
      "format": "float",
      "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.",
      "deprecated": true
    },
    "margin_ratio_horizontal": {
      "type": "number",
      "format": "float",
      "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."
    },
    "margin_ratio_vertical": {
      "type": "number",
      "format": "float",
      "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."
    },
    "margin_ratio_mode": {
      "type": "string",
      "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).",
      "enum": [
        "manual",
        "none"
      ],
      "default": "manual"
    },
    "gif": {
      "type": "boolean",
      "default": false,
      "description": "When true, generates an animated GIF from the spritesheet and returns it in gif_url. Disabled by default to reduce response time."
    },
    "individual_frames": {
      "type": "boolean",
      "default": false,
      "description": "When true, extracts each frame from the spritesheet as an individual image and returns the URLs in individual_frame_urls."
    },
    "spritesheet_with_background": {
      "type": "boolean",
      "default": false,
      "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."
    },
    "model": {
      "type": "string",
      "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.",
      "enum": [
        "hydra",
        "forge",
        "forge-pixel",
        "tango"
      ],
      "default": "hydra"
    },
    "prompt": {
      "type": "string",
      "description": "Optional extra instructions for the motion transfer (e.g. \"keep the cape still\"), added to the model's own prompt."
    },
    "duration": {
      "type": "number",
      "format": "float",
      "default": 1.5,
      "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"
    },
    "request_id": {
      "type": "string",
      "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."
    },
    "async": {
      "type": "boolean",
      "default": true,
      "description": "Defaults to true: the call returns 202 immediately with a job id to poll with getApiJob. Set false for a synchronous response (deprecated but supported): the call then blocks until the result is ready."
    }
  }
}

Work with this as data

Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for schemas

4 MCP tools reach this
  • find_json_schemasBrowse and filter every JSON Schema in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/ludo-ai-transfer-motion-payload"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.