---
title: "Directional Sprites: render a 3D model into one spritesheet per direction, in a style. Pass the GLB in `model` (URL or base64; rigged, to animate it - see create3DModel with rig, or rigModel) and at most one animation: `animation_url` (the `glb_url` of an animation from animate3DModel or animate3DModelPreset, made for this model), `preset_id` (a preset from listAnimationPresets, retargeted onto the model; any rig type can take one, though retargeting does not succeed on every model, and when it does not the call returns an error) or `model_animation` (the name of an animation the GLB itself carries). With no animation each sheet is a single frame. `directions` are where the camera stands around a character facing S (up to 8); every direction is rendered together, on the same frame size, scale and floor, so the sheets line up. Pick the style with listDirectionalSpriteStyles (style_id, and style_params for its settings) and check it with previewDirectionalSprites first. The job result is one sheet per direction, in the order asked, each with its `spritesheet_url`, grid fields, fps and `render_3d`. Credits are held for every direction when the job is accepted and charged for the sheets that come back; a failed or cancelled job is refunded. Pass an optional request_id to tag the sheets for later retrieval via listGenerations (type spritesheet). Requires an API key (user scope). The call returns 202 with a job id - poll getApiJob (pass wait 30 to long-poll) honouring poll_after_ms, until status is succeeded; its result field is exactly the response documented for this operation. Synchronous responses are deprecated but still supported: pass `async: false` to block until the result is ready and receive it as the response body. Synchronous calls run on the same queue: the response carries an X-Ludo-Job-Id header, and a job still running after 15 minutes comes back as 202 with the job instead of an error. Each account may have up to 50 generations queued or running at once via the API; a request beyond that returns 429 (code PENDING_JOBS_LIMIT)."
method: POST
path: "/assets/sprite/directional"
tags: ["Spritesheets"]
---

# Directional Sprites: render a 3D model into one spritesheet per direction, in a style. Pass the GLB in \`model\` (URL or base64; rigged, to animate it - see create3DModel with rig, or rigModel) and at most one animation: \`animation_url\` (the \`glb_url\` of an animation from animate3DModel or animate3DModelPreset, made for this model), \`preset_id\` (a preset from listAnimationPresets, retargeted onto the model; any rig type can take one, though retargeting does not succeed on every model, and when it does not the call returns an error) or \`model_animation\` (the name of an animation the GLB itself carries). With no animation each sheet is a single frame. \`directions\` are where the camera stands around a character facing S (up to 8); every direction is rendered together, on the same frame size, scale and floor, so the sheets line up. Pick the style with listDirectionalSpriteStyles (style_id, and style_params for its settings) and check it with previewDirectionalSprites first. The job result is one sheet per direction, in the order asked, each with its \`spritesheet_url\`, grid fields, fps and \`render_3d\`. Credits are held for every direction when the job is accepted and charged for the sheets that come back; a failed or cancelled job is refunded. Pass an optional request_id to tag the sheets for later retrieval via listGenerations (type spritesheet). Requires an API key (user scope). The call returns 202 with a job id - poll getApiJob (pass wait 30 to long-poll) honouring poll_after_ms, until status is succeeded; its result field is exactly the response documented for this operation. Synchronous responses are deprecated but still supported: pass \`async: false\` to block until the result is ready and receive it as the response body. Synchronous calls run on the same queue: the response carries an X-Ludo-Job-Id header, and a job still running after 15 minutes comes back as 202 with the job instead of an error. Each account may have up to 50 generations queued or running at once via the API; a request beyond that returns 429 (code PENDING_JOBS_LIMIT).

`POST /assets/sprite/directional`

## Request

- Base URL: `https://api.ludo.ai/api`
- URL: `https://api.ludo.ai/api/assets/sprite/directional`
- Auth: API key in header `Authorization`

## Request body

- DirectionalSpritesPayload: Payload for rendering a 3D model as directional sprite sheets
  - `model` string, required: The 3D model, as a URL or base64-encoded GLB file (not an AI model name). Rigged, to animate it. Up to 30MB; a larger file is rejected with HTTP 400.
  - `animation_url` string: An animation for the model, as a URL or base64-encoded GLB file - the glb_url of an animation from animate3DModel or animate3DModelPreset, made for this model's skeleton. At most one of animation_url, preset_id and model_animation. Up to 30MB; a larger file is rejected with HTTP 400.
  - `preset_id` string: An animation preset id from listAnimationPresets, retargeted onto the model. Any rig type can take one; when the preset cannot be retargeted onto the model, the call returns an error. At most one of animation_url, preset_id and model_animation.
  - `crop_loop` boolean: With preset_id, trim the preset to the span that loops seamlessly. Omit to follow the preset's own loop flag.
  - `model_animation` string: The name of an animation the GLB itself carries. At most one of animation_url, preset_id and model_animation; with none, each sheet is a single frame.
  - `perspective` 'horizon' | 'low' | 'isometric' | 'high' | 'top': Camera height, from the side (horizon) to straight down (top).
  - `directions` string[]: Where the camera stands around a character facing S, each direction at most once. One sheet per direction, in this order, rendered together on the same frame size, scale and floor so they line up.
  - `style_id` string: A style id from listDirectionalSpriteStyles.
  - `style_version` integer: Version of the style; omit for its current one. A render_3d from an earlier result names the version it was rendered with.
  - `style_params` object: The style's settings to change, by name, each one of its listed option values (true/false for a bool setting, or any colour for a color one). Omit a setting to keep its default.
  - `keep_horizontal_travel` boolean: Keep the animation's ground travel (the character moves across the frame). Off keeps it in place.
  - `keep_vertical_travel` boolean: Keep the animation's vertical root motion (jumps, bobbing).
  - `target_frame_size` integer: Sprite size in pixels - the longer side of the frame, which every direction shares.
  - `num_frames` integer: Frames per sheet, sampled over the animation; moved to the nearest count that fills the sheet grid, and never more than the animation's keyframes. A still model gives one.
  - `loop` boolean: Sample the animation as a seamless loop. Omit to follow the animation's own loop flag.
  - `gif` boolean: Also return each sheet as an animated GIF (gif_url).
  - `individual_frames` boolean: Also return each sheet's frames as separate images (individual_frame_urls).
  - `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.

## Response `200`

Success

- DirectionalSpritesResult
  - `sheets` DirectionalSpriteSheet[]: One sheet per direction, in the order asked.
    - `direction` string: The direction this sheet is seen from.
    - `spritesheet_url` string
    - `video_url` string
    - `gif_url` string
    - `individual_frame_urls` string[]
    - `num_frames` integer: Number of frames in the spritesheet.
    - `num_cols` integer: Columns in the frame grid. Frames run left-to-right, top-to-bottom.
    - `num_rows` integer: Rows in the frame grid. The last row may be only partly filled.
    - `fps` number, float: The frame rate the sheet plays at.
    - `render_3d` DirectionalSpriteRender
      - `style_id` string
      - `style_version` integer
      - `style_params` object: The style's settings as rendered, by name.
      - `perspective` string
      - `direction` string
      - `animation_name` string
      - `fps` number, float
      - `keep_horizontal_travel` boolean
      - `keep_vertical_travel` boolean
    - `loop` boolean: Whether the animation loops: the loop you asked for, else the animation's own. false is a one-shot (a jump, a death) that should play once in an engine.

## Other responses

- `202`: Accepted - the generation was queued; poll GET /assets/jobs/{id}. A synchronous (async: false) call still running after 15 minutes also receives this.
- `400`: Error

## Changes

- **2026-10-15** `5386c8cd3d81`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/ludo/apis/ludo-ai-api/changes/assets/sprite/directional/post.md)

---

[API](https://skmtc.dev/ludo/apis/ludo-ai-api.md) - [All operations](https://skmtc.dev/ludo/apis/ludo-ai-api/llms.txt) - [OpenAPI document](https://skmtc.dev/ludo/apis/ludo-ai-api/revisions/4efeb12a23c9?raw)
