How to use from
Docker Model Runner
docker model run hf.co/fernandotonon/QtMeshEditor-t2m:Q8_0
Quick Links

QtMesh T2M โ€” Lightweight Text-to-3D-Motion Generation

QtMesh T2M turns a sentence such as "a person waves with the right hand" into a skeletal animation for a rigged 3D character. The QtMeshEditor project trained it from scratch. It is not a quantized or distilled copy of NVIDIA Kimodo.

  • Two models, loaded separately. The motion generator is a custom 22.6 M-parameter flow-matching transformer, run with ONNX Runtime. The prompt is read by Qwen3-Embedding-0.6B (0.6 B parameters, Q8_0 GGUF), run with llama.cpp.
  • No Python at inference. Inside QtMeshEditor everything runs natively in C++.
  • Small enough for modest hardware. It is about a 740 MB download and peaks at under 1 GB of memory. It runs on the CPU: ONNX Runtime's CPU provider, and llama.cpp on Apple Silicon.
  • Integrated with the editor. QtMeshEditor maps the output onto your character's rig, can add root travel, and exports the result as glTF/GLB or FBX.
  • Experimental. Its motion quality is clearly below NVIDIA Kimodo, which stays QtMeshEditor's default. QtMesh T2M is the option for machines that cannot run Kimodo comfortably.

Contents

Benchmark: QtMesh T2M vs NVIDIA Kimodo

These are the QtMeshEditor project's own measurements, not an independent benchmark. Each run generated one 3-second clip for the same character.

QtMesh T2M NVIDIA Kimodo (native runtime)
Download ~740 MB ~9.2 GB
Text encoder Qwen3-Embedding-0.6B (Q8_0) Llama-3-LLM2Vec-8B (Q8_0)
Text encoding ~0.2โ€“0.4 s ~1.1 s, plus loading the 8 B encoder
Motion sampling ~2.7 s (24 flow steps) ~14 s (100 diffusion steps)
Whole CLI run (import, generate, export) ~5 s ~18โ€“21 s
Peak resident memory ~0.87 GB ~7.6โ€“8.2 GB

How it was measured

  • Hardware: Apple M5, 24 GB unified memory, macOS.
  • Runtime: QtMeshEditor 3.60 with ONNX Runtime 1.31.1 on the CPU execution provider. Both text encoders run as Q8_0 GGUFs through the bundled llama.cpp. Kimodo used QtMeshEditor's native (Python-free) port of Kimodo-SOMA-RP-v1.2, with its post-processing on.
  • Method:
    • The command was qtmesh anim char.fbx --generate "<prompt>" --backend <kimodo|qtmesh_t2m> --duration 3 --seed 1 --json -o out.fbx.
    • Each backend ran once per prompt, for four prompts: walk, run, wave with the right hand, jump.
    • Wall time and maximum resident set size come from /usr/bin/time -l.
    • The text-encoding and sampling times are the ones the CLI reports in --json.
    • The "whole CLI run" covers process start, importing the character, generating, retargeting and exporting the FBX.
    • The models were already downloaded.
  • Not controlled or not recorded:
    • File-cache warmth.
    • Background load.
    • Repeated trials. Each figure is one run per prompt; the ranges span the four prompts.
  • Root motion differed: Kimodo ran with --no-root-motion, while QtMesh T2M used its default foot-driven root motion.

Smaller and faster does not mean equivalent. Kimodo's motions are clearly more detailed and reliable; compare the clips below.

Visual results โ€” QtMesh T2M vs NVIDIA Kimodo

The same generated character and prompt are used on both sides. Each clip is 3 seconds, rendered in place (root motion off), with one sample per model. Left: NVIDIA Kimodo. Right: QtMesh T2M. The caption in each GIF gives the seed.

Prompt Seeds (Kimodo / QtMesh T2M) Comparison What to look for
"a person walks forward" 1 / 1 walk Both read as a walk cycle. QtMesh T2M's arms swing less.
"a person runs forward" 1 / 1 run Both read as a run. Kimodo keeps the elbows bent in a running position; QtMesh T2M's arms hang straighter.
"a person waves with the right hand" 1 / 1 wave with the right hand Both raise the character's right hand, the side named in the prompt; the text embedding carries left/right. QtMesh T2M waves with a large overhead arm, Kimodo with a smaller wave near the head.
"a person jumps" 1 / 2 jump Cherry-picked: the QtMesh T2M clip uses seed 2, not seed 1. See the failure case below.

Failure case: seed sensitivity

The two clips below come from the same model and prompt with different seeds. The left one is what you get with seed 1, the seed used for the other comparisons.

QtMesh T2M jump, seed 1 vs seed 2

Across ten seeds of "a person jumps", four bent the knees 70โ€“86ยฐ into a clear jump, and four barely moved. The showcased clips are therefore not a statistically representative sample. Treat them as examples of what the model can produce. In practice, generate a few variations and keep the best one.

How it works

Text prompt
  โ†’ Qwen3-Embedding-0.6B (llama.cpp)       1024-d, L2-normalised sentence embedding
  โ†’ Flow-matching transformer (ONNX)        22.6 M params, 24 Euler steps, classifier-free guidance
  โ†’ Canonical 22-joint motion               joint rotations, 30 fps, up to 150 frames (5 s)
  โ†’ QtMeshEditor retargeting                mapped onto your character's skeleton
  โ†’ glTF/GLB or FBX animation
  • Text conditioning.
    • The prompt is prefixed with a fixed instruction: Instruct: Given a description of a human body motion, retrieve motions that match it\nQuery:.
    • Qwen3-Embedding then encodes it with last-token pooling, and the vector is L2-normalised.
    • Because the model sees a sentence embedding rather than an action label, wording, body side ("with the right hand"), speed and style all reach it.
  • Motion model.
    • A transformer of width 384 and 8 layers, conditioned on the text and the flow time through AdaLN-Zero.
    • It is trained with rectified flow (flow matching): it learns a velocity field that carries random noise to a motion.
    • The ONNX graph contains the whole sampler, unrolled: 24 Euler steps with classifier-free guidance (scale 2.0).
    • The model generates rotations for 22 canonical joints (pelvis, spine, neck, head, arms and legs), in the world frame, at 30 fps.
    • Clips are up to 150 frames (5 s). The length is an input, and frames past it are padding.
  • What the model does not generate.
    • It produces no root translation and no vertical root displacement. A jump therefore stays on the spot.
    • When Root motion is on, QtMeshEditor estimates horizontal travel from the planted foot. Measured: walk ~1.4 m/s, run ~1.9 m/s. The character never rises.
  • Editor post-processing.
    • Long clips in the training data start from rest, so the editor generates up to 1 s of extra motion and trims a still start.
    • The canonical motion is then retargeted onto the character with QtMeshEditor's incompatible-skeleton retargeter, the same one used for Kimodo output. Humanoid rigs are mapped automatically from their bone names (for example Mixamo-style rigs and the characters QtMeshEditor generates).

Training

The training is best described as synthetic-data-assisted: part of the motion data was generated by a stronger teacher model (Kimodo). It is not formal knowledge distillation. QtMesh T2M never sees Kimodo's weights, logits or text features; it only sees the finished clips.

  • Data: 30,488 training samples and 8,028 distinct text descriptions, including paraphrases. These figures were checked against the training cache. The samples come from:
    • 3,400 clips generated with NVIDIA Kimodo from 3,470 prompts. The prompts were written with make-kimodo-t2m-prompts.py, combining gaits, directions, styles, gestures, combat, sports, dance, reactions and body-side variants.
    • Every clip was mirrored leftโ†”right, with "left" and "right" swapped in its text. That gives 6,800 samples.
    • 23,688 windows from QtMeshEditor's earlier v8 data, captioned per action: the curated template clip library (motion-library-v2.json) and the CC0 / CC-BY-4.0 motion corpus.
    • Every text gets paraphrases: the person word varies ("a person" / "someone" / "the character" / none), and the action words are kept.
  • Quality control.
    • Kimodo clips pass automatic gates (check-kimodo-t2m-corpus.py): finite values, foot sliding during contact, feet below the floor, implausible hip height, and joint-acceleration spikes. 3,400 of the 3,470 generated clips passed.
    • Samples that resolve fewer than 16 of the 22 joints are dropped.
    • The v8 data had already been filtered with an anatomical ankle gate and a minimum-joints gate, and non-humanoid characters were excluded.
  • Text features.
    • The Qwen3 embeddings were computed separately for this model with embed-t2m-text.py, through the same llama.cpp build the editor uses. On the reference prompts, the app's embeddings match the training ones with cosine 1.000000.
    • Kimodo's Llama 3 text embeddings were never stored or used as training inputs.
  • Recipe (train-t2m-text.py):
    • 200 epochs of 20,000 samples each, batch 128.
    • AdamW at 2e-4 (weight decay 1e-4) with a cosine schedule.
    • 70% of each batch is drawn from the Kimodo clips, balanced per base prompt.
    • 10% of the texts are dropped (zero vector) to train classifier-free guidance.
    • Clips are padded to 150 frames with a length mask.
    • The final flow-matching loss is 0.0478, and the ONNX export matches PyTorch to 2.4e-6.
    • The export pins two canonical joints the data never supervises (the left and right buttock roles) to identity.
  • Scripts (offline development tools; the editor never runs Python):

The Kimodo-generated training clips and the training cache are not published.

Usage

Recommended: the QtMeshEditor GUI

  1. Install QtMeshEditor.

    Platform Command
    Windows winget install FernandoTonon.QtMeshEditor
    macOS brew tap fernandotonon/qtmesheditor && brew trust fernandotonon/qtmesheditor && brew install qtmesheditor
    Linux sudo snap install qtmesheditor

    Installers are also on the GitHub releases page. QtMesh T2M needs version 3.60.0 or later.

  2. Import a rigged humanoid character (FBX, glTF/GLB and other formats). You can also make one with the built-in character generator.

  3. Switch to Animation mode and find Generate from text in the Inspector's Animations section.

  4. Pick a model: set Model to QtMesh T2M (experimental, small).

  5. Download the model: press Download QtMesh T2M. This happens once, about 740 MB. Nothing downloads until you ask.

  6. Write a prompt, for example "a person waves with the right hand". Set the duration (up to 5 s) and the number of variations. Optionally turn on Root motion or set a Fixed seed.

  7. Generate. The clips appear as generated_qtmesh_t2m, generated_qtmesh_t2m_v2, โ€ฆ All variations are added in one undo step. Preview them on the timeline.

  8. Export the character with its animations (for example to .glb or .fbx).

Advanced: the command line

qtmesh anim rigged.glb \
  --generate "a person waves with the right hand" \
  --backend qtmesh_t2m \
  --duration 3 \
  --download \
  -o animated.glb

--download fetches the model files the first time. Other options:

Option What it does
--variations N Generates N clips, 1โ€“16.
--seed N Makes the result reproducible.
--no-root-motion Keeps the clip in place.
--name NAME Names the clip.
--json Prints a machine-readable report, including the timings.

MCP (AI agents)

QtMeshEditor's MCP server exposes the same thing through the generate_motion tool:

{"backend": "qtmesh_t2m", "prompt": "a person jumps", "duration": 3, "variations": 2, "seed": 2, "download": true}

Using the files directly

You can run the ONNX model in your own pipeline with ONNX Runtime and any llama.cpp build that supports Qwen3 embeddings. See Files and tensor contract. You then need your own retargeting from the 22-joint canonical skeleton, which is described in t2m-text.json.

About the GGUF file. Qwen3-Embedding-0.6B-Q8_0.gguf is a text-embedding model. It is not a chat model and not the animation generator. Hugging Face may show "Use this model with llama.cpp / Ollama" buttons because of it. Those apply only to the embedding model, not to the text-to-motion pipeline, and chatting with it will not produce anything useful.

Files and tensor contract

The current model lives in qtmesh_t2m/:

File Size What it is
t2m-text.onnx 98 MB The motion model (22.6 M parameters), with the 24-step Euler + CFG sampler unrolled in the graph.
t2m-text.json small The contract: shapes, fps, the embedding instruction and pooling, canonical rest directions.
Qwen3-Embedding-0.6B-Q8_0.gguf ~640 MB The text encoder. It is byte-identical to Qwen's official Q8_0 GGUF (SHA-256 06507c7bโ€ฆe439).
LICENSE-Qwen3-Embedding.txt The Apache-2.0 licence for the encoder.
ATTRIBUTION.md The required credits for the CC-BY-4.0 motion data the model was trained on.

t2m-text.onnx I/O (checked against the graph):

Tensor Shape / type Meaning
input text float32 [1, 1024] The L2-normalised Qwen3 embedding of instruct + prompt. A zero vector means unconditional.
input seed float32 [1, 19800] Starting noise, sampled from N(0, 0.5). 19800 = 150 frames ร— 132.
input length float32 [1] The number of frames wanted, up to 150.
output motion float32 [1, 150, 220] Per frame, 22 joints ร— 10 values [tx, ty, tz, qx, qy, qz, qw, sx, sy, sz]: world-frame rotation quaternions, with t = 0 and s = 1. Frames from length onward are padding.

From t2m-text.json:

version v9-text   T 150   J 22   C 220   Z 19800   fps 30   frame world
flowSteps 24   guidance 2.0   embedDim 1024   pooling last

The joint order and the canonical rest pose (restWorld, restDir) are listed in the JSON.

Limitations

  • Lower motion fidelity than Kimodo. Motions are simpler, less expressive and less physically convincing.
  • Occasionally wrong or too subtle. Some prompts give a weak or only partly correct motion.
  • Sensitive to the seed. Quality varies a lot between seeds (see the jump example), so generate several variations and pick the best one.
  • One action prompt per clip. There are no multi-segment timelines; QtMeshEditor rejects a multi-line prompt for this model. Kimodo supports timelines.
  • At most 5 seconds per clip (150 frames at 30 fps).
  • No root height or root translation. Jumps stay on the ground plane. Horizontal travel is only an estimate made by the editor.
  • Weaker on uncommon movements. Actions that are rare in the training data come out worse.
  • Body only. There are no fingers, face or props; the model drives 22 body joints. In QtMeshEditor, Kimodo drives the fingers.
  • English prompts. The training text was English only.
  • Experimental and under active development. Expect the model to change.

License and attribution

This repository contains files under different licences, so its metadata says license: other (mixed, per file) instead of claiming a single licence. The full per-file breakdown is in LICENSES.md. In short:

Files Licence
QtMesh T2M weights and contracts (qtmesh_t2m/t2m-text.onnx, t2m-text.json), the v8 model (t2m.onnx, t2m-vocab.json), the GIFs in media/ CC0-1.0, released by the QtMeshEditor project. The models were trained on CC-BY-4.0 data, so please keep the attribution files with them.
qtmesh_t2m/Qwen3-Embedding-0.6B-Q8_0.gguf Apache-2.0, ยฉ Qwen team, Alibaba Cloud (LICENSE-Qwen3-Embedding.txt).
motion-library.json, motion-library-v2.json Mixed CC0-1.0 and CC-BY-4.0, per clip. Credits are in ATTRIBUTION-v2.md and ATTRIBUTION.md.
ATTRIBUTION.md, ATTRIBUTION-v2.md, qtmesh_t2m/ATTRIBUTION.md The credits for the CC-BY-4.0 works. Ship them with the models or the data.

About the Kimodo-generated training clips:

  • Kimodo's outputs are not "Derivative Models" under the NVIDIA Open Model License (ยง1.1), and NVIDIA claims no ownership of outputs (ยง2.4).
  • The QtMeshEditor project therefore used Kimodo outputs as training data.
  • No Kimodo weights, code, generated clips or Llama 3 embeddings are distributed in this repository. Kimodo itself is a separate download inside QtMeshEditor, under its own licences.

QtMeshEditor itself is MIT-licensed.

Previous versions

QtMesh T2M (v9, in qtmesh_t2m/) is the current model. The files at the repository root belong to earlier releases and are kept for compatibility and reproducibility:

  • t2m.onnx + t2m-vocab.json is the v8.0 action-label model: a 21.7 M-parameter flow-matching transformer conditioned on one of 30 action words. It is QtMeshEditor's opt-in --model path.
  • motion-library-v2.json (150 clips) is the curated template clip library. It is also the v8 training source.
  • motion-library.json is the older v1 template library.

The full v8 model card (dataset, measurements, architecture, I/O contract, reproduction) is in PREVIOUS_VERSIONS.md. Earlier checkpoints remain in this repository's commit history.

Links

Downloads last month
-
GGUF
Model size
0.6B params
Architecture
qwen3
Hardware compatibility
Log In to add your hardware

8-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ 1 Ask for provider support

Dataset used to train fernandotonon/QtMeshEditor-t2m