## Generate Consistent Walking-Style Locomotion
Generate consistent walking-style locomotion for a character in a **specified direction** with controllable style, speed, and stride count. Use locomotion when you need **predictable, repeatable, looptable** travel motion for gameplay, background NPCs, or any workflow where a text prompt is too open-ended to rely on the same path and style every time.

## Overview
Text-to-motion is ideal when you want creative motion from a natural language description. Locomotion is different: you choose **where** the character should travel, **how fast**, **how many stride pairs** to use, and which **style** to apply, so clips stay stable and well-suited for **looping and stitching** in your own pipeline. Results are returned immediately, like text-to-motion, with no job polling.

Call [`locomotion_styles`](/content/docs/api/graphql#list-locomotion-styles/index.html) to list the `style_id` values accepted by [`create_locomotion`](/content/docs/api/graphql#generate-locomotion/index.html) (for example `neutral_male_a`).

## Step-by-step tutorial
### Step 1: Set up the client
Install your client library and authenticate using your API key. See the [quickstart](/content/docs/api/#step-1-install-the-client/index.html) for setup instructions for each language.

### Step 2: Query locomotion styles (optional)
Uthana exposes a query that returns every `style_id` you can pass to `create_locomotion`, for example `neutral_male_a`, `aeroplane`.

#### Example Queries

- Shell
```shell
curl -sS -X POST "https://uthana.com/graphql" \
  -u "$API_KEY:" \
  -H "Content-Type: application/json" \
  -d '{"query":"query { locomotion_styles }"}'
```

- Python
```python
async def main():
    styles = await client.motions.list_locomotion_styles()
    print(styles)

asyncio.run(main())
```

- TypeScript
```typescript
const styles = await client.motions.listLocomotionStyles();
console.log(styles);
```

- React
```javascript
import { useUthanaLocomotionStyles } from "@uthana/react";

function StyleList() {
  const { styles } = useUthanaLocomotionStyles();
  return <ul>{styles?.map((s) => <li key={s}>{s}</li>)}</ul>;
}
```

- C#
```csharp
var styleBody = @"{"query":"query { locomotion_styles }"}";
var styleContent = new StringContent(styleBody, Encoding.UTF8, "application/json");
_httpClient.DefaultRequestHeaders.Authorization = new(
    "Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_apiKey}:"))
);
var styleResp = await _httpClient.PostAsync(ApiUrl, styleContent);
var styleJson = await styleResp.Content.ReadAsStringAsync();
// Parse locomotion_styles from `styleJson` as needed
```

### Step 3: Generate locomotion
Call `create_locomotion` with the character to retarget to (required `character_id`) and the motion parameters. If you omit optional fields, the API uses these defaults:

- **`strides`**: `4` (number of full stride pairs; allowed `1` to `5`)
- **`move_speed`**: `1.2` m/s, relative to the character's height and stride (valid range `0.25` to `8.0`)
- **`style_id`**: "neutral_male_a"
- **`travel_angle`**: `0` degrees — `0` is North (forward), `90` is East (right), `-90` is West (left), `180`/`-180` is South (backward); values beyond this range are reduced via modulo 360.

#### Example Queries

- Shell
```shell
curl -X POST "https://uthana.com/graphql" \
  -u "$API_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation CreateLocomotion($character_id: String!, $strides: Int, $move_speed: Float, $style_id: String, $travel_angle: Float) { create_locomotion(character_id: $character_id, strides: $strides, move_speed: $move_speed, style_id: $style_id, travel_angle: $travel_angle) { motion { id name } } } }",
    "variables": {
      "character_id": "'$CHARACTER_ID'",
      "strides": 2,
      "move_speed": 1.3,
      "style_id": "neutral_male_a",
      "travel_angle": 0
    }
  }'
```

- Python
```python
async def main():
    result = await client.motions.create_locomotion(
        CHARACTER_ID,
        strides=2,
        move_speed=1.3,
        style_id="neutral_male_a",
        travel_angle=0,
    )
    print(f"Created motion: {result.motion_id}")

asyncio.run(main())
```

- TypeScript
```typescript
const result = await client.motions.createLocomotion(CHARACTER_ID, {
  strides: 2,
  move_speed: 1.3,
  style_id: "neutral_male_a",
  travel_angle: 0,
});
console.log(`Created motion: ${result.motion_id}`);
```

- React
```javascript
import { useUthanaCreateLocomotion, useUthanaLocomotionStyles } from "@uthana/react";

function LocomotionPanel({ characterId }: { characterId: string }) {
  const { styles } = useUthanaLocomotionStyles();
  const createLoco = useUthanaCreateLocomotion();

return (
    <div>
      <p>Styles: {styles?.join(", ")}</p>
      <button
        onClick={() =>
          createLoco.mutate({
            character_id: characterId,
            strides: 2,
            move_speed: 1.3,
            style_id: "neutral_male_a",
            travel_angle: 0,
          })
        }
        disabled={createLoco.isPending}
      >
        {createLoco.isPending ? "Generating..." : "Generate locomotion"}
      </button>
      {createLoco.data && <p>Motion ID: {createLoco.data.motion_id}</p>}
    </div>
  );
}
```

### Step 4: Handle the response
The mutation returns a motion with `id` and `name` immediately, similar to text-to-motion. Use the motion id in retargeting and downloading flows. When listing motions, filter with `motions(methods: ["Locomotion"])` where supported.

### Step 5: Integrate with a motion controller
Locomotion clips are a good fit for **motion controllers** because each clip encodes a fixed **travel direction** (`travel_angle`), **speed** (`move_speed`), and **style** (`style_id`). You can build a small library of clips (cardinal directions, a few speeds, one or more styles) and select or blend between them from gameplay input instead of relying on a single open-ended prompt.

#### Controller checklist
1. **Generate or pick clips** — Create one motion per combination you need (same character `character_id`), varying `style_id`, `move_speed`, and `travel_angle` as needed.
2. **Export for your engine** — Download GLB or FBX from [Download a motion](/content/docs/api/capabilities/downloading-motion/index.html) using your motion id and character id.
3. **Choose root motion vs in-place** — Either let the clip move the skeleton root ( **root motion**), or download with `in_place=true` so the character stays under the origin while you **move the character transform in code** in the direction that matches `travel_angle`. See [In-place motion](/content/docs/api/capabilities/downloading-motion#in-place-motion/index.html).
4. **Loop and switch** — Play clips with seamless looping where possible; swap or cross-fade clips when input direction or speed changes.

### Parameters
- **`character_id`**: `String!` — The character the motion is generated and retargeted for.
- **`strides`**: `Int` — Count of full stride **pairs** (1 to 5). Default 4.
- **`move_speed`**: `Float` — Travel speed in m/s. Recommended roughly 0.25 to 6.0, allowed up to 8.0. Default 1.2.
- **`style_id`**: `String` — Locomotion style. Resolves case-insensitively to a known Uthana style. Default `neutral_male_a`.
- **`travel_angle`**: `Float` — **Travel direction in degrees** on the ground plane, normalized to -180 to 180. Default 0.

### Error handling
- Shell
```shell
if echo "$RESPONSE" | jq -e '.errors' > /dev/null; then
    echo "Error occurred:";
    echo "$RESPONSE" | jq '.errors';
fi
```

- Python
```python
from uthana import UthanaError

async def main():
    try:
        result = await client.motions.create_locomotion(CHARACTER_ID, strides=2)
    except UthanaError as e:
        print(e.status_code, e.api_message)

asyncio.run(main())
```

## Next steps
- See [Text to motion](/content/docs/api/capabilities/text-to-motion/index.html) for open-ended, prompt-driven generation.
- See [Download a motion](/content/docs/api/capabilities/downloading-motion/index.html) to export assets.
- Explore [Retargeting](/content/docs/api/capabilities/retargeting/index.html) for applying motions to other characters.
