Nodes/Melite Kimodo Nodes/Kimodo Text to Pose
ComfyUI Node

Kimodo Text to Pose

Type a sentence, get a .npz of human motion

By JayDataEngineer·Created 2 months ago·Updated 4 days ago· 1
Kimodo Text to Pose
  • model
  • npz_path
  • result
◄prompt►
◄seed42►
◄duration_sec6.00►
◄diffusion_steps100►
◄num_samples1►
◄num_transition_frames30►
◄cfg_typeseparated►
◄cfg_weight_a2.00►
◄cfg_weight_b2.00►
◄prev_motion_npz►
◄motion_constraints►
◄motion_prompts►

This is the payoff node. A prompt goes in, a compressed .npz of 3D joint motion comes out - 30fps, 77 joints on the SOMA skeleton, plus per-joint rotation matrices. Wire KimodoLoader's model in, type "a person walks forward and then waves", hit run.

What it is not: a video generator, or a rig. There's no mesh here and no render. You get numbers that describe a moving skeleton, and something downstream has to drive a body with them.

How the motion gets made

Under the hood the node calls the Kimodo model's __call__ with a list of prompts and a frame count per prompt, and Kimodo runs its own diffusion loop - that's where the diffusion_steps number goes. Frame count is derived, not guessed: the model's fps is 30, and the node rounds duration_sec × 30. So duration_sec 6.0 gives you 180 frames of motion.

Before sampling it seeds python, numpy and torch from your seed, which is why a fixed seed gives you reproducible output instead of a coin flip. And ComfyUI's memory manager loads the model onto the GPU first, which is the thing that stops the device-mismatch crash the pack was rewritten to fix.

There's a nice detail buried in the source: the node wraps the model's internal progress loop with its own interrupt check, so the Cancel button kills a run partway through instead of appearing dead until generation finishes. Diffusion over 100 steps at 30fps of motion takes a while, so you'll appreciate that.

One upstream quirk worth knowing: models with g1 in the resolved name skip post-processing entirely. If a G1 variant produces visibly rawer motion than another variant, that's why.

The inputs you'll actually touch

Required: model (from KimodoLoader), prompt (multiline, hard-capped at 2000 characters - over that it raises, empty raises), and seed.

Then the optional ones, in the order you'll care about them.

  • duration_sec defaults to 6 and maxes at 10. That ceiling is upstream's, not the pack's: 10 seconds is the most Kimodo will generate for a single prompt. Want a longer clip? That's what motion_prompts is for.
  • diffusion_steps defaults to 100. This is your quality-versus-time dial and it's the honest one - sampling steps, nothing exotic.
  • num_samples (1–8) generates several candidates. Note that only the first is written to the file; the rest exist during the run.
  • cfg_type (separated, regular, nocfg) with cfg_weight_a and cfg_weight_b at 2.0 each. Leave these alone until you have a reason.
  • num_transition_frames (default 30) is how long the model takes to blend between prompt segments. It only matters once you use segments.
  • motion_prompts is the interesting one: a JSON list of {"text": "...", "duration_sec": 2.0} segments. Feed it two or more valid entries and it overrides your single prompt - Kimodo composes a multi-segment performance with transitions between them. Malformed JSON raises loudly; entries that are individually broken get dropped rather than crashing the run.
  • prev_motion_npz is chain mode. Give it the bare filename of a previous motion stored in ComfyUI's input directory, and the new clip is generated conditioned on where the old one ended - the motion equivalent of a first-frame constraint. The transition frames get dropped and the two clips are merged into one output.
  • motion_constraints takes hand-authored timeline constraints as JSON. If you're not generating that JSON from a UI, you're not going to want to write it by hand.

Outputs

npz_path is a real filesystem path: the file lands in ComfyUI's output directory as kimodo_pose_<timestamp>_<seed>.npz, and the node logs the frame count and motion duration when it's done. result is a KIMODO_RESULT - a metadata dict carrying motion_shape, fps, the prompt, the seed and how many seconds inference took. Useful if you're logging runs; it is not what you feed the next node.

The .npz is the thing you carry forward, into whatever retargets motion onto a character.

Install

Same pack as everything else here:

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/JayDataEngineer/melite-kimodo-nodes.git
cd melite-kimodo-nodes
pip install -r requirements.txt

Restart, then load the model from KimodoLoader before you run this. The single most common failure in the whole pack belongs to that loader - if your run dies with No module named 'kimodo', it's a missing dependency, not a bad prompt.

Watch out for

Prompts over 2000 characters raise rather than truncate - that's deliberate, but it bites people pasting a whole shot description. Wire a batch of anything into duration_sec and remember the 10-second ceiling, because the clamp isn't where you'd look for it. And a 6-second clip at 100 steps is not fast on a card that's also holding a 17GB text encoder. Budget the run, not the prompt.

CategoryMelite/Kimodo

Inputs (13)

NameTypeDefaultDescription
modelKIMODO_MODEL—
promptSTRING—
seedINT420–4294967295—
duration_secoptFLOAT6.000.1–10—
diffusion_stepsoptINT1001–1000—
num_samplesoptINT11–8—
num_transition_framesoptINT300–300—
cfg_typeoptCOMBOseparated3 options: separated, regular, nocfg
cfg_weight_aoptFLOAT2.000–20—
cfg_weight_boptFLOAT2.000–20—
prev_motion_npzoptSTRING—
motion_constraintsoptSTRING—
motion_promptsoptSTRING—

Outputs (2)

NameTypeDescription
npz_pathSTRING—
resultKIMODO_RESULT—