Skip to main content

GenerateRequest

The body of POST /generate.

Top-level shape​

FieldTypeRequiredNotes
protocol_versionstring matching ^\d+\.\d+$yesWire version. A v1.x server MUST accept any value matching ^1\.\d+$ and MAY refuse other majors with version_unsupported
modelstringyesOne of Capabilities.models[].id
skeletonSkeletonyesThe character's skeleton; must be sent every time
segmentsSegment[]no, default []Discriminated union of TextSegment, UnconditionedSegment, PoseSegment and (1.2) MotionReferenceSegment and VideoReferenceSegment. A pose stands alone; a motion or video reference composes exactly like a text segment. At least one of segments or constraints must be non-empty
constraintsConstraint[]no, default []See constraint primitives
duration_framesint (> 0)conditionalRequired when segments is empty (constraints-only); forbidden when segments is non-empty
timing{ "fps": number }noIf set, frames are interpreted in this fps and the response is resampled. See Timing →
optionsOptionsno, default objectGeneration hyperparameters

The skeleton is required in every request. A backbone with supports_retargeting=false MUST be sent its canonical_skeleton verbatim; otherwise the server returns 400. A backbone with retargeting accepts any skeleton.

Options​

{
"diffusion_steps": 100,
"num_samples": 1,
"seed": 42,
"post_processing": true,
"transition_frames": 5,
"guidance": {
"type": "separated",
"weight": [2.0, 2.0]
}
}
FieldTypeDefaultNotes
diffusion_stepsint (1–500)100Backbone-specific; ignored by non-diffusion models
num_samplesint (1–model.limits.max_num_samples)1Independent samples per request. Samples differ only in stochastic backbone choices (e.g. distinct initial noise drawn from the shared RNG stream)
seedint | nullnullRNG seed for reproducibility. Fixes the RNG state before generation, making the full (seed, num_samples) tuple deterministic
post_processingbooltrueFoot-skate cleanup, root correction (backbone-specific)
transition_framesint (0–60)5Blend window between segments. Rotations blend via slerp; root translation blends linearly
guidance.type"nocfg" | "regular" | "separated"backbone defaultClassifier-free guidance mode
guidance.weightfloat[]backbone defaultLength 1 for regular, length 2 for separated, length 0 (or omitted) for nocfg

Backbones that don't implement an option MAY ignore it; they MUST NOT fail.

Reproducibility caveat

Re-sending an identical request with the same seed and num_samples yields an identical response. Clients that need to reproduce an individual sample from a multi-sample response should re-request with the same seed and sample count, then pick the same index — servers do not guarantee that sample i is reproducible via a separate num_samples: 1 request with a derived seed.

Examples​

Minimal — text-only​

{
"protocol_version": "1.0",
"model": "kimodo-soma-rp",
"skeleton": { "joints": [ /* model's canonical skeleton */ ] },
"segments": [{ "type": "text", "prompt": "a person walks forward", "duration_frames": 90 }]
}

Multi-segment with unconditioned bridge​

{
"protocol_version": "1.0",
"model": "kimodo-soma-rp",
"skeleton": { "joints": [ /* … */ ] },
"segments": [
{ "type": "text", "prompt": "person walks forward", "duration_frames": 90 },
{ "type": "unconditioned", "duration_frames": 30 },
{ "type": "text", "prompt": "then sits down", "duration_frames": 60 }
],
"options": { "seed": 42, "transition_frames": 8 }
}

Constraints + custom skeleton​

{
"protocol_version": "1.0",
"model": "kimodo-soma-rp",
"skeleton": {
"joints": [
{ "name": "Hips", "parent": null, "rest_translation": [0, 0.95, 0], "rest_rotation": [0, 0, 0, 1] },
{ "name": "Spine", "parent": "Hips", "rest_translation": [0, 0.10, 0], "rest_rotation": [0, 0, 0, 1] },
{ "name": "LeftArm", "parent": "Spine", "rest_translation": [0.18, 0.30, 0], "rest_rotation": [0, 0, 0, 1] }
],
"coordinate_system": "right_handed_y_up",
"units": "meters"
},
"segments": [{ "type": "text", "prompt": "wave hello", "duration_frames": 60 }],
"constraints": [
{
"type": "root_path",
"frames": [0, 30, 60],
"positions_xz": [[0,0], [0.5,0], [1,0]]
},
{
"type": "effector_target",
"joint": "LeftArm",
"frames": [0, 30, 59],
"positions": [[0.5, 1.4, 0.2], [0.6, 1.6, 0.3], [0.5, 1.4, 0.2]]
}
]
}

A clip as the prompt (1.2)​

Four new performances of the kind of motion in a 2-second reference, 3 seconds long, to a model that lists "motion_reference" in supported_segments — the request a text prompt would make, with the clip where the prompt was:

{
"protocol_version": "1.2",
"model": "kimodo-soma-rp",
"skeleton": { "joints": [ /* … */ ] },
"segments": [{
"type": "motion_reference",
"duration_frames": 90,
"joint_names": ["Hips", "Spine1", "..."],
"rotations": [ /* 60 frames × one [x, y, z, w] per joint */ ],
"root_positions": [ /* 60 × [x, y, z] */ ],
"fps": 30
}],
"options": { "num_samples": 4 }
}

A clip from another rig carries that rig as the segment's skeleton (same schema as the request skeleton); its joint_names are then that rig's, and the server retargets the clip from it:

{ "type": "motion_reference", "duration_frames": 120,
"skeleton": { "joints": [ { "name": "mixamorig:Hips", "parent": null, /* … */ }, /* … */ ] },
"joint_names": ["mixamorig:Hips", "mixamorig:Spine", "..."],
"rotations": [ /* … */ ], "root_positions": [ /* … */ ], "fps": 30 }

Two clips in one take (1.2)​

References are prompts like text segments, so they mix with them: here a walk like one clip, a text prompt, then a sit like another clip (sampled on a Mixamo rig), stitched with the usual transitions.

{
"protocol_version": "1.2",
"model": "kimodo-soma-rp",
"skeleton": { "joints": [ /* the character */ ] },
"segments": [
{ "type": "motion_reference", "duration_frames": 90,
"joint_names": ["Hips", "Spine1", "..."],
"rotations": [ /* walk: T × J × [x, y, z, w] */ ], "root_positions": [ /* T × 3 */ ], "fps": 30 },
{ "type": "text", "prompt": "a person stops and looks around", "duration_frames": 45 },
{ "type": "motion_reference", "duration_frames": 75,
"skeleton": { "joints": [ /* the sit clip's rig */ ] },
"joint_names": ["mixamorig:Hips", "..."],
"rotations": [ /* sit */ ], "root_positions": [ /* … */ ], "fps": 30 }
],
"options": { "num_samples": 2, "transition_frames": 5 }
}

See Segments → for the rules, and Building reference segments → for how to sample rotations and root_positions from a rig.

A video as the prompt (1.2)​

The dance in seconds 2–6 of a video, as a 4-second take on the character, to a model that lists "video_reference" in supported_segments. The server fetches the URL and follows the most prominent dancer in it:

{
"protocol_version": "1.2",
"model": "my-video-model",
"skeleton": { "joints": [ /* … */ ] },
"segments": [{
"type": "video_reference",
"duration_frames": 120,
"video": { "url": "https://cdn.example.com/dance.mp4" },
"start_s": 2.0,
"end_s": 6.0
}]
}

A video from disk goes inline as base64, with its container's media type (motionmcp.client.video_source("clip.mov") builds this object):

{ "type": "video_reference", "duration_frames": 90,
"video": { "data": "AAAAFGZ0eXBxdCAg…", "media_type": "video/quicktime" } }

Text, a clip and a video in one take (1.2)​

All three kinds of prompt mix in any order: a walk from words, a stop like a reference clip, then a turn like the one in a video, stitched with the usual transitions. Each segment can take its own seed.

{
"protocol_version": "1.2",
"model": "my-video-model",
"skeleton": { "joints": [ /* the character */ ] },
"segments": [
{ "type": "text", "prompt": "a person walks forward", "duration_frames": 90, "seed": 7 },
{ "type": "motion_reference", "duration_frames": 45,
"joint_names": ["Hips", "Spine1", "..."],
"rotations": [ /* stop: T × J × [x, y, z, w] */ ], "root_positions": [ /* T × 3 */ ],
"fps": 30 },
{ "type": "video_reference", "duration_frames": 60,
"video": { "url": "https://cdn.example.com/turn.mp4" }, "end_s": 2.5 }
],
"options": { "num_samples": 2, "transition_frames": 5 }
}

See Segments → for the rules, and Building reference segments → for how to build each one.