# Downloading Motion Files

Download generated motions in **FBX**, **GLB**, or **BVH** using the motion download endpoints. (For integrating Uthana motions with a Unitree G1 robot, see [Unitree G1](/content/docs/api/capabilities/unitree-g1/index.html)).

## Step 1: Identify your character and motion IDs

You need both the `characterId` and `motionId` to download files.

**Note:** The filename in the URL is customizable for `/motion/file/` and `/motion/animation/` endpoints. You can use any filename you want (e.g., `motion.fbx`, `walking-animation.glb`). The `/motion/bundle/` endpoint requires the fixed filename `character.glb` or `character.fbx`.

**Retargeting:** When you download a motion with a specific character ID, [retargeting](/content/docs/api/capabilities/retargeting/index.html) happens automatically—the motion is adapted to work with that character's skeleton and proportions. This applies to **FBX, GLB, and BVH** character-animated exports (the [Unitree G1](/content/docs/api/capabilities/unitree-g1/index.html) **CSV** format does not include model meshes, so retargeting is not applicable).

## Step 2: Download the motion file

### Shell
```bash
API_KEY="your-api-key"
CHARACTER_ID="cXi2eAP19XwQ"
MOTION_ID="your-motion-id"

# FBX (includes character mesh)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx" \
  -u $API_KEY: \
  -o motion.fbx

# GLB (includes character mesh)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/motion.glb" \
  -u $API_KEY: \
  -o motion.glb
```

### Python
```python
import asyncio
from uthana import Uthana

client = Uthana("your-api-key")
CHARACTER_ID = "cXi2eAP19XwQ"
MOTION_ID = "your-motion-id"

async def main():
    # GLB (includes character mesh)
    glb_data = await client.motions.download(CHARACTER_ID, MOTION_ID, output_format="glb")
    with open("motion.glb", "wb") as f:
        f.write(glb_data)

# FBX
    fbx_data = await client.motions.download(CHARACTER_ID, MOTION_ID, output_format="fbx")
    with open("motion.fbx", "wb") as f:
        f.write(fbx_data)

asyncio.run(main())
```

### TypeScript
```typescript
import { UthanaClient } from "@uthana/client";

const client = new UthanaClient(process.env.UTHANA_API_KEY!);
const CHARACTER_ID = "cXi2eAP19XwQ";
const MOTION_ID = "your-motion-id";

// GLB (includes character mesh)
const glbBuffer = await client.motions.download(CHARACTER_ID, MOTION_ID, { output_format: "glb" });

// FBX
const fbxBuffer = await client.motions.download(CHARACTER_ID, MOTION_ID, { output_format: "fbx" });
```

### Download options

#### Frame rate (FPS)

You can specify the frame rate for downloaded motions using the `fps` query parameter. Supported values are `24`, `30`, and `60`.

### Download at 30 FPS
```bash
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx?fps=30" \
  -u $API_KEY: \
  -o motion-30fps.fbx
```

### Exclude character mesh

Use the `no_mesh` query parameter to download animation data without the character mesh. Set `no_mesh=true` to exclude the mesh, or `no_mesh=false` to include it (default). For `.glb` downloads only, there is an additional option `no_mesh=minimal`, which creates a skeleton-like mesh for easier viewing.

### Download FBX without character mesh
```bash
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx?no_mesh=true" \
  -u $API_KEY: \
  -o motion-no-mesh.fbx
```

### In-place motion

Use the `in_place` query parameter to remove horizontal root motion from the animation. Set `in_place=true` to keep the character in place with no horizontal translation (default: `false`). This applies to FBX, GLB, and BVH retargeted exports.

### Download motion with character in place
```bash
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx?in_place=true" \
  -u $API_KEY: \
  -o motion-in-place.fbx
```

### Speed multiplier

Use the `speed_multiplier` query parameter to scale the playback speed of the downloaded motion. Accepts a float value greater than `0` and at most `2.0`. The default is `1.0` (no change).

### Download at half speed
```bash
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx?speed_multiplier=0.5" \
  -u $API_KEY: \
  -o motion-half-speed.fbx
```

### Combining options

You can combine `fps`, `no_mesh`, `in_place`, `torso_only`, `roblox_compatible`, and `speed_multiplier` parameters (some parameters are not supported for certain formats).

### Download at 30 FPS without character mesh
```bash
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx?fps=30&no_mesh=true" \
  -u $API_KEY: \
  -o motion-30fps-no-mesh.fbx
```

## Motion-only GLB

To download only animation data without the character mesh, you can use the motion-only endpoint or the `no_mesh=true` parameter:

### Using the motion-only endpoint
```bash
curl -L "https://uthana.com/motion/animation/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/motion.glb" \
  -u $API_KEY: \
  -o motion-only.glb
```

### Preview WebM

Download a short preview video (WebM) for a motion. Preview downloads do not count against your download quota.

### Error handling

These endpoints return binary file data on success. On error, they return an HTTP error status. Check `response.status` (or `response.status_code`) in your code—the response body may contain error details, but for file downloads the status code is the primary signal.

| Condition | Status code |
| --- | --- |
| Invalid `fps` (not 24, 30, or 60) | 400 |
| Invalid `no_mesh` (not `true`, `false`, or `minimal`) | 400 |
| Invalid `in_place` (not `true` or `false`) | 400 |
| Invalid `torso_only` (not `true` or `false`) | 400 |
| Invalid `roblox_compatible` (not `true` or `false`) | 400 |
| Invalid motion or character ID, or no access | 404 |
| Permission denied (quota, etc.) | 403 |
| Not logged in | 401 |
