@genex-ai/cli-demo 0.90.0-dev.227 → 0.92.0-dev.229

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,145 +0,0 @@
1
- # Custom animations with `genex motion` — the full procedure
2
-
3
- Text → raw motion takes on the platform GPU service → objective verify →
4
- YOUR pick → local compile → a rig-independent set the vendored runtime plays
5
- on any humanoid. The skeleton is a 27-joint humanoid core at 20 fps; takes
6
- arrive as `.npz` files plus a machine verify report. Everything after `gen`
7
- runs locally and free — regenerate compiled sets as often as you like.
8
-
9
- **Rig limits (say them to the user before promising a move):** biped,
10
- human-proportioned characters only. Rigs without finger bones (many Meshy
11
- characters) cannot curl fingers around a grip — prefer weapon-carry looks
12
- that read well with flat hands there, or use a rig with fingers for hero
13
- characters. Takes are 2–10 seconds.
14
-
15
- ## The loop
16
-
17
- ```bash
18
- # 1. Generate (bills per take, default 4; ALWAYS --no-wait — jobs run minutes)
19
- npx genex motion gen "soldier rifle low-ready idle, fully upright, head held high" --takes 4 --no-wait
20
- npx genex wait <id> # prints one URL per take + the report
21
-
22
- # 2. Download the takes it printed and RENAME them — filenames drive everything
23
- mkdir -p takes && curl -o takes/rifle-idle.npz "<take-url>"
24
-
25
- # 3. Verify locally (same math the service ran; free, reproducible)
26
- npx genex motion verify takes/
27
-
28
- # 4. Pick the takes whose MOTION reads right (the report is data, not taste),
29
- # then compile the set
30
- npx genex motion compile takes/ --out src/motion/rifle.json
31
-
32
- # 5. Vendor the runtime once per game (+ the proven rifle starter set)
33
- npx genex motion install --set rifle
34
- ```
35
-
36
- ## Take naming — the routing contract
37
-
38
- `verify` and `compile` classify each take by its FILENAME stem. Rename
39
- downloaded takes before running them:
40
-
41
- | Stem pattern | Compiles into |
42
- |---|---|
43
- | `<set>-run-forward` / `-back` | `forward` / `back` gait |
44
- | `<set>-strafe-left` / `-strafe-right` | `strafeLeft` / `strafeRight` |
45
- | `<set>-run-fl` / `-fr` / `-bl` / `-br` | the four diagonal gaits |
46
- | `<set>-idle` or `…stance…` | the `idle` loop |
47
- | `…jump…` (`jump-stand`, `jump-run`) | `jumpStand` / `jumpRun` one-shots |
48
- | anything else | a named freeform loop |
49
-
50
- A stem containing `aim`, `rifle`, or `pistol` marks the take as a WEAPON
51
- HOLD: verify adds the hold-shape gates, and compile grip-line-normalizes the
52
- idle (the whole body blades as one) and plucks `aim0`/`aim0Up`/`aim0Dn`
53
- upper-body mask poses from the hold takes.
54
-
55
- ## The prompt wording ladder (hard-won — wrong words cost paid takes)
56
-
57
- - **Never ask for "sights" or a "cheek weld"** — you get a hunched
58
- face-height hold that reads absurd on game rigs. Ask for the third-person
59
- hold: *"weapon at chest height, arms extended"*, *"low-ready"* as the
60
- fallback.
61
- - **Always add "fully upright, head held high"** — the model's prior slouches.
62
- - **Describe hand geometry literally** (*"left hand forward on the handguard,
63
- right hand at the grip"*), not by weapon jargon.
64
- - The model NEVER squares a two-handed hold to the pelvis — real marksmen
65
- blade, and compile normalizes the heading by the grip line. Do not fight
66
- it with prompt words; it is not a defect.
67
- - **Gaits need constraints, not prose.** Direction words alone drift; pin
68
- the trajectory:
69
-
70
- ```bash
71
- npx genex motion constraints --dir strafe-left --speed 2.5 --duration 5 --out strafe-left.json
72
- npx genex motion gen "soldier strafing with a rifle at low-ready" --constraints strafe-left.json --no-wait
73
- ```
74
-
75
- The constraint pins the root path AND the heading (facing stays +Z) — that
76
- pin is what makes a strafe a strafe. One direction per request; a full
77
- 8-direction set is 8 requests + one idle (run them in parallel with
78
- `--no-wait`, like any batch).
79
-
80
- ## Verify semantics
81
-
82
- `PASS` (≥70) / `WARN` (≥50) / `FAIL`, with a hard-zero cap: a zero on any
83
- load-bearing gate fails the take no matter the average. The reasons column
84
- names the defect in plain words (feet skate, grip line wanders, cheek weld…).
85
- The report is DATA — freeform verbs have no semantic gate, so watch the take
86
- on the rig before shipping it. Tune bands via `--gates gates.json` (partial
87
- JSON, deep-merged: `{"aim": {"hunch": {"bad": 25}}}`).
88
-
89
- ## Compile semantics + tunables
90
-
91
- Compile cuts loop cycles at left-foot strikes (gaits) or the best seam window
92
- (idles), removes the linear trajectory (residual sway + full Y bob stay),
93
- normalizes heading to +Z, phase-aligns gaits (frame 0 = left strike), and for
94
- weapon holds levels the arm assembly, raises the gaze, clamps tall stances,
95
- and yaws mask poses in the SPINE. All rigid whole-body/assembly operations —
96
- no joint ever moves relative to another (the no-bake law; it is why compiled
97
- sets survive retargeting). Every threshold lives in
98
- `src/motion/motion.config.json` after install — pass `--config` to use it.
99
-
100
- ## Wiring the runtime
101
-
102
- `genex motion install` puts the runtime IN YOUR GAME — `src/motion/rigs.js`
103
- (both retarget formulas + the load-time normalizations), `anim-runtime.js`
104
- (ClipSet/Animator/dir8Weights/aimMaskStep), `ik.js`, and the config. They are
105
- yours: read them, tune them, the comments explain every formula. Load order
106
- matters:
107
-
108
- ```js
109
- import { loadRig, captureRestAnkle, reanchorFeet, groundCalibrate, curlFingers } from "./motion/rigs.js";
110
- import { ClipSet, Animator, dir8Weights, aimMaskStep } from "./motion/anim-runtime.js";
111
-
112
- const set = await (await fetch("./motion-sets/rifle.json")).json(); // copy sets where your bundler serves them
113
- const rig = await loadRig("./assets/character.glb", set, modelFrame); // GLB or VRM — auto-detected
114
- rig.computeCorrection();
115
- const restAnkle = captureRestAnkle(rig, scene); // BIND pose, before any clip
116
- reanchorFeet(rig, set, scene); // steep-boot fix — BEFORE ClipSet
117
- const clipSet = new ClipSet(rig, set, set.gaits);
118
- groundCalibrate(rig, clipSet, scene, restAnkle); // short-leg fix — AFTER ClipSet
119
- curlFingers(rig, scene); // grips (no-op on finger-less rigs)
120
- const anim = new Animator(clipSet);
121
-
122
- // per frame: your input → blend weights; the mask follows the COMMAND magnitude
123
- anim.setLoops({ idle: 1 - mag, ...dir8Weights(x, z, mag) }, dt);
124
- maskW = aimMaskStep(maskW, { mag, grounded, pitch, dt });
125
- anim.setMask("aim0", maskW, pitch / 0.6); // ±40° at pitch extremes
126
- anim.update(dt);
127
- ```
128
-
129
- - Physics owns the world transform: hips play LOCAL values only (residual
130
- x/z + absolute y); your character root carries position + yaw.
131
- - Jumps: `anim.playOneShot("jumpRun", { yCap: 0.1 })` — cap hips Y when the
132
- physics capsule owns the jump, and gate the impulse on the clip's own
133
- takeoff frame. The `--set rifle` install includes the shared jumps set;
134
- merge it: `Object.assign(clipSet.tracks, new ClipSet(rig, jumps, jumps.gaits).tracks)`.
135
- - The aim mask WINS over one-shots on masked bones — a jump keeps aiming.
136
- - Standing aim = the UNMASKED bladed idle; the spine-yawed mask pose is only
137
- for moving/airborne/pitched states. `aimMaskStep` already encodes this.
138
-
139
- ## Cost + discipline
140
-
141
- Per-take billing (a 4-take request ≈ one model generation). One regenerate
142
- per verb is a fair budget when takes fail the gates — reword with the ladder
143
- above before spending again, and compare candidates from ONE batch first
144
- (that is what `--takes 4` is for). Never re-run `motion gen` to "pick up" a
145
- result — `genex wait <id>` re-attaches free.