---
title: "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. Always runs on the Forge model (there is no model parameter; Forge is the only model supporting middle keyframes), so durations follow Forge's pricing. Synchronous: the call blocks until the spritesheet is rendered and returns a single sprite result directly (spritesheet URL, frame layout, and optionally a GIF or individual frame URLs when requested) with no separate polling step. Credits are charged only on success, based on the produced duration and never more than the duration you requested. Use animateSprite instead for the classic single-image + text-prompt animation with model choice. Pass an optional request_id to tag the result so you can locate it later via getSpriteResults. Requires an API key (user scope)."
method: POST
path: "/assets/sprite/animate-keyframes"
tags: ["Spritesheets"]
---

# 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. Always runs on the Forge model (there is no model parameter; Forge is the only model supporting middle keyframes), so durations follow Forge's pricing. Synchronous: the call blocks until the spritesheet is rendered and returns a single sprite result directly (spritesheet URL, frame layout, and optionally a GIF or individual frame URLs when requested) with no separate polling step. Credits are charged only on success, based on the produced duration and never more than the duration you requested. Use animateSprite instead for the classic single-image + text-prompt animation with model choice. Pass an optional request_id to tag the result so you can locate it later via getSpriteResults. Requires an API key (user scope).

`POST /assets/sprite/animate-keyframes`

## Request body

- AnimateSpriteKeyframesPayload — Payload for generating an animated spritesheet that interpolates through up to three fixed keyframes (initial / middle / final). Runs exclusively on the Forge model. Input images can be provided in base64 or URL. At least one of initial_image or middle_image must be provided.
  - `motion_prompt` string — Optional text description of the desired animation (e.g., "walking", "attack slash"). When omitted, the motion is derived purely from the keyframes.
  - `initial_image` string — The url OR base64 of the first keyframe. Optional when a middle_image is provided.
  - `middle_image` string — The url OR base64 of the middle keyframe the animation passes through between the initial and final frames.
  - `final_image` string — The url OR base64 of the final keyframe. Requires an initial_image or middle_image to anchor the animation.
  - `loop` boolean — Trim the animation at the beginning or end to create a seamless loop. Not guaranteed to produce a perfect loop.
  - `crop` boolean — Crop sprite frames to fit content. Results in smaller spritesheets but inconsistent frame sizes across different animations.
  - `frames` 4 | 9 | 16 | 25 | 36 | 49 | 64 — Number of frames in the output spritesheet.
  - `frame_size` 32 | 64 | 96 | 128 | 192 | 256 | 384 | 0 | -1 | -9 — Size of each frame in pixels (width and height). 0 is for maximum resolution. -1 is for AI 1.5x upscaling. -9 is for matching the size and position of the input frame.
  - `margin_ratio` number, float — Deprecated — prefer margin_ratio_horizontal / margin_ratio_vertical. Amount of padding around the sprite as a ratio (0.0 to 1.0), applied to both axes (equivalent to setting both per-axis params to this value). Only used when margin_ratio_mode is "manual". Cannot be combined with the per-axis params: providing both fails with HTTP 400.
  - `margin_ratio_horizontal` number, float — Horizontal padding around the sprite as a ratio (0.0 to 1.0). Only used when margin_ratio_mode is "manual". Useful for animations that extend sideways (e.g., sword slashes, punches). Cannot be combined with the legacy margin_ratio param.
  - `margin_ratio_vertical` number, float — Vertical padding around the sprite as a ratio (0.0 to 1.0). Only used when margin_ratio_mode is "manual". Useful for animations that extend up or down (e.g., jumps). Cannot be combined with the legacy margin_ratio param.
  - `margin_ratio_mode` 'auto' | 'manual' | 'none' — Controls how margins are applied around the sprite.
  - `image_type` 'sprite' | 'sprite-vfx' | 'ui_asset' — Type of sprite being animated. Affects generation parameters and styling.
  - `duration` number, float — Animation length in seconds. This endpoint always runs on the Forge model, so only Forge's durations apply — the source of truth is MODEL_PRICING (credits.js), surfaced via /credits/costs.
  - `augment_prompt` boolean — Augment the prompt behind the scenes. Disable to have more control.
  - `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 spritesheet_with_background_url.
  - `request_id` string — Optional client-provided identifier for this request. Use this to retrieve results later via the results endpoint.

## Response `200`

Success

- SpriteResult
  - `spritesheet_url` string
  - `video_url` string
  - `audio_b64` string
  - `gif_url` string
  - `individual_frame_urls` string[]
  - `num_frames` integer
  - `num_cols` integer
  - `num_rows` integer
  - `spritesheet_with_background_url` string
  - `individual_frame_with_background_urls` string[]
  - `duration` number, float
  - `request_id` string
  - `created_at` integer

## Other responses

- `400` — Error

---

[API](https://skmtc.net/ludo/apis/ludo-ai-api.md) · [All operations](https://skmtc.net/ludo/apis/ludo-ai-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/ludo/ludo-ai-api/revisions/3af866d68651/schema)
