@rig-c/parts 1.19.0 → 1.20.0
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.
- package/README.md +10 -2
- package/cli.ts +24 -6
- package/docs/AUTHORING.md +136 -6
- package/docs/MIGRATION.md +20 -0
- package/docs/STABILITY.md +7 -3
- package/package.json +2 -2
- package/skills/rig-parts/SKILL.md +17 -3
- package/src/build.ts +2 -2
- package/src/check.ts +10 -2
- package/src/cloth.ts +378 -0
- package/src/config.ts +139 -2
- package/src/propose.ts +187 -15
- package/src/scene.ts +1 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ config beside the values it replaced: the two outer skirt chains were moved out
|
|
|
37
37
|
against 1.4725; moved, 2.425). One input-stage edit: <code>hair_back</code> is taken
|
|
38
38
|
from the full run, because the twin tails leave the head crop sideways (a plan edit).
|
|
39
39
|
<code>check</code> printed, verbatim:<br/>
|
|
40
|
-
<code>
|
|
40
|
+
<code>50 assertions: 24 measured (24 passed, 0 failed), 26 skipped, 0 not in profile "rig-play"</code><br/>
|
|
41
41
|
<code>loop: idle 41 frame(s) at 12 fps, f0000 vs f0040 (t = 3.333333333333333s) with the rig's 29 physics constraint(s) left out (named on the `loop physics:` line; rendered with them, the ends need not meet — `build --loop --lead-in <n>`): max |d| 0 (0 required)</code><br/>
|
|
42
42
|
<code>seam: setup pose at 654x1216, scale 0.9438: mean |d| 0.147 (<= 1.0), 0 px over 40, 0.00 rig px (the count / s²; <= 50), 0 px over 80 (reported)</code><br/>
|
|
43
43
|
<code>pack: skeleton.png 1051x972, 23 region(s), 96.9% covered, padding 2, page edges free, shape polygon</code><br/>
|
|
@@ -250,7 +250,9 @@ rig-parts assemble --source painting.png --full layers/full --head layers/head -
|
|
|
250
250
|
# -> a large red hole neither run holds? add an assemble.patches entry (cut from the painting) and assemble again
|
|
251
251
|
rig-parts propose --parts work/rig --source painting.png --out work
|
|
252
252
|
# -> proposal.json, basis.json (what each bone rests on) and render/landmarks.png; per-bone coverage lines;
|
|
253
|
-
# correct it, copy bones/meshes/regions/motion into config.json
|
|
253
|
+
# correct it, copy bones/meshes/regions/limbs/motion/constraints/turn into config.json, each it wrote
|
|
254
|
+
# (limbs only with --keypoints, constraints only with --cloth, turn only with --full/--head;
|
|
255
|
+
# a limbs block left out is refused next)
|
|
254
256
|
rig-parts propose --parts work/rig --source painting.png --out work --from-config config.json
|
|
255
257
|
# -> LINT lines; exit 1 while any remain
|
|
256
258
|
rig-parts build --config config.json --source painting.png --full layers/full --head layers/head --out out --loop
|
|
@@ -265,6 +267,12 @@ proposal pasted uncorrected stops at the last step, naming its `bottomwear` on
|
|
|
265
267
|
`CHECK_TIP_OVER_ROOT` — the correction its tracked config records there, the two outer
|
|
266
268
|
skirt chains moved (issue #227, [its README](examples/demo/README.md)); on `scarf`,
|
|
267
269
|
since issue #262, it builds green.
|
|
270
|
+
On `demo`, which tracks the pose file it was painted on, the block runs again with
|
|
271
|
+
`--keypoints` on both `propose --parts` lines (`RL03`): the proposal then also drafts
|
|
272
|
+
`limbs`, the step's list carries them, and the run ends where `RL01` ends. The joints
|
|
273
|
+
are that pose file scaled to the painting, not read off it, so this shows what the
|
|
274
|
+
loop carries, not where the joints are. The list as it stood before issue #375, four
|
|
275
|
+
sections, stops at `--from-config` naming every limb part (`RL04`).
|
|
268
276
|
|
|
269
277
|
`propose` is deliberately not a step of `build`: the proposal is a draft to correct
|
|
270
278
|
against its overlay, and a config with bones is `build`'s input. `rig`, `check` and
|
package/cli.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { DEFAULT_PROJECT_RULE, DEFAULT_SEAM_RULE, HOLES_LISTED, PROJECT_RULES, t
|
|
|
19
19
|
import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns, readSource, rigStage, suppliedCheckFlag } from './src/build.ts';
|
|
20
20
|
import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, rigcRunnerAt, type PackShape, PAGE_EDGES, type PageEdges, PARTS_HOME_SENTENCE, RIGC_GEOMETRY_VERSION, type RigcRunner, NO_PARTS_SENTENCE, SEAM_MEAN_BAR, SOURCE_SENTENCE, SEAM_PX_BAR, SEAM_PX_LEVEL, SPINEBOY_YARDSTICK, TEXTURE_STRETCH_CEILING } from './src/check.ts';
|
|
21
21
|
import { ComfyClient, resolveHost, runPainting, runSeeThrough } from './src/comfy/index.ts';
|
|
22
|
-
import { type CharacterConfig, loadConfig, loadEarlyConfig, loadPaintConfig } from './src/config.ts';
|
|
22
|
+
import { type CharacterConfig, loadClothConfig, loadConfig, loadEarlyConfig, loadPaintConfig } from './src/config.ts';
|
|
23
23
|
import { failLine, guidePointer, PartsError } from './src/errors.ts';
|
|
24
24
|
import { GUIDE_DOC, type GuideAnswer, guideRule, guideSection } from './src/guide.ts';
|
|
25
25
|
import { proposeHeadBox } from './src/headbox.ts';
|
|
@@ -197,6 +197,20 @@ usage:
|
|
|
197
197
|
reference's rule, a tenth of the part's short side clamped to 5..36.
|
|
198
198
|
r is the part rule's under both.
|
|
199
199
|
|
|
200
|
+
rig-parts propose … [--cloth <config.json>]
|
|
201
|
+
Draft cloth and hair as trees that answer the world (issue #364), from
|
|
202
|
+
the config's "cloth" block — a recipe per tag, bottomwear, back hair
|
|
203
|
+
and front hair (AUTHORING §3, *Recipe: cloth and hair*). Each tagged
|
|
204
|
+
piece hangs "chains" trees of "links" links from its attachment bone
|
|
205
|
+
(hip, or head), forked by "split", the links shortening toward the tip;
|
|
206
|
+
proposal.json's "constraints" puts a physics constraint on every link,
|
|
207
|
+
its strength by trunk, branch or edge, its wind and gravity response
|
|
208
|
+
on a ramp from the declared root value to the tip value (multipliers
|
|
209
|
+
of the consumer's environment — no direction is drafted), and drafts no
|
|
210
|
+
idle key on them. A bottomwear recipe's "swing" drives each tree's
|
|
211
|
+
first link from one shared pendulum. A recipe that drafts nothing is
|
|
212
|
+
refused (PROPOSE_CLOTH_DRAFTED). Without --cloth nothing changes.
|
|
213
|
+
|
|
200
214
|
rig-parts propose --parts <dir> --source <painting.png> --out <dir> --from-config <config.json>
|
|
201
215
|
Draw the config's CURRENT bones instead (<out>/render/landmarks_config.png
|
|
202
216
|
and _head) and LINT them (by the joints too, given --keypoints), with the
|
|
@@ -262,7 +276,7 @@ usage:
|
|
|
262
276
|
written into motion.json as read, for rigc's gate to judge (AUTHORING
|
|
263
277
|
§3). --parts is the
|
|
264
278
|
directory holding parts.json and parts/<name>.png. The result is built
|
|
265
|
-
through rig-c (profile
|
|
279
|
+
through rig-c (profile rig-play, packed with --page-edges and
|
|
266
280
|
--pack-shape as for check; rigc's build gates the compile and the packed pages on disk) in a
|
|
267
281
|
scratch directory first, and --out receives images/*.png, rig.json,
|
|
268
282
|
motion.json and mesh_report.json only when it is green. Prints one line
|
|
@@ -323,7 +337,7 @@ usage:
|
|
|
323
337
|
builds); an "idle" in it is not.
|
|
324
338
|
${PARTS_HOME_SENTENCE}; ${NO_PARTS_SENTENCE}.
|
|
325
339
|
Both are only read. Into --out:
|
|
326
|
-
build/ (rigc build --profile
|
|
340
|
+
build/ (rigc build --profile rig-play --pack --page-edges <value>
|
|
327
341
|
--pack-shape <value>: the packed atlas is the artifact), gate_spine-html.txt (the gate lines
|
|
328
342
|
verbatim), idle_frames/ (rigc render --animation idle --fps 12 --max 640
|
|
329
343
|
--geometry: the frames and geometry.json, the skinned vertices and
|
|
@@ -617,7 +631,7 @@ usage:
|
|
|
617
631
|
another character without its prefix (SCENE_NAME_PREFIXED); a plate not
|
|
618
632
|
of the canvas size; idles of different durations; a key in a build's
|
|
619
633
|
rig or motion compose does not know. The result is gated through
|
|
620
|
-
rig-c as rig gates its own (build --profile
|
|
634
|
+
rig-c as rig gates its own (build --profile rig-play --pack, the
|
|
621
635
|
compile and the packed pages on disk); --out receives rig/ (rig.json,
|
|
622
636
|
motion.json, images/) and ${SCENE_REPORT_FILE} (spec "${SCENE_REPORT_SPEC}":
|
|
623
637
|
every setting, each character's offset, scale, bounds and shift (and what it
|
|
@@ -763,7 +777,7 @@ const TAKES = {
|
|
|
763
777
|
layers: { valued: ['--export', '--template', '--canvas'], switches: [] },
|
|
764
778
|
sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
|
|
765
779
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
766
|
-
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule'], switches: ['--head-box'] },
|
|
780
|
+
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule', '--cloth'], switches: ['--head-box'] },
|
|
767
781
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
768
782
|
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements'], switches: ['--seam-pairs', '--keep-stills'] },
|
|
769
783
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
@@ -1124,6 +1138,10 @@ function cmdPropose(args: string[]): number {
|
|
|
1124
1138
|
if (ruleArg !== undefined && flags.has('--from-config')) return usage('--grid-rule chooses the drafted spacing; --from-config proposes nothing');
|
|
1125
1139
|
if (ruleArg !== undefined && !(GRID_RULES as readonly string[]).includes(ruleArg)) return usage(`--grid-rule ${ruleArg}; one of ${GRID_RULES.join(', ')} is required`);
|
|
1126
1140
|
const gridRule = (ruleArg ?? DEFAULT_GRID_RULE) as GridRule;
|
|
1141
|
+
// Issue #364: the cloth and hair recipe, read from a config's cloth block; without it nothing changes.
|
|
1142
|
+
const clothArg = flags.get('--cloth');
|
|
1143
|
+
if (clothArg !== undefined && flags.has('--from-config')) return usage('--cloth drafts trees while proposing; --from-config proposes nothing');
|
|
1144
|
+
const cloth = clothArg === undefined ? null : loadClothConfig(clothArg).cloth;
|
|
1127
1145
|
const partsDir = existsSync(partsArg) && statSync(partsArg).isFile() ? dirname(partsArg) : partsArg;
|
|
1128
1146
|
if (!existsSync(source)) {
|
|
1129
1147
|
throw new PartsError([{ code: 'PROPOSE_SOURCE_PRESENT', object: source, detail: 'no such file; the painting is drawn under the overlay' }]);
|
|
@@ -1151,7 +1169,7 @@ function cmdPropose(args: string[]): number {
|
|
|
1151
1169
|
}
|
|
1152
1170
|
const cmpPath = flags.get('--compare');
|
|
1153
1171
|
const cfg = cmpPath === undefined ? null : loadConfig(cmpPath);
|
|
1154
|
-
const { proposal: drafted, basis } = proposeWithBasis(P, joints, wristSnap, gridRule);
|
|
1172
|
+
const { proposal: drafted, basis } = proposeWithBasis(P, joints, wristSnap, gridRule, cloth);
|
|
1155
1173
|
const fullRun = flags.get('--full');
|
|
1156
1174
|
const headRun = flags.get('--head');
|
|
1157
1175
|
const prop =
|
package/docs/AUTHORING.md
CHANGED
|
@@ -114,9 +114,10 @@ read by no CPU stage).
|
|
|
114
114
|
| `motion.blink` | rig | **proposed**: `{t, eyes, brows, squash, brow_drop}`; the whole blink, `t` to `t + 0.364` s (`t + 0.314` s without brows: the brows' keys are the ones that end last), must fit inside the idle (`RIG_BLINK_INSIDE_IDLE`). The `eyes` group's `scaley` squashes every part on the eye bones about the bone's origin, the eyewhite's centre. Optional: a figure with no `eyewhite-r`/`-l` part has no eye bone, so `propose` writes no `blink` and notes `no blink: no eyewhite part (looked for: eyewhite-r, eyewhite-l), …`; with eyes and no `eyebrow-r`/`-l` part it writes the blink without `brows` and `brow_drop` and notes `blink without brows: …`. `brows` and `brow_drop` are stated together or not at all (`CONFIG_BLINK_BROWS_PAIRED`), and a group that names no bone is refused (`CONFIG_BLINK_GROUP_MEMBERS`) — rigc would refuse it one stage later, `group "eyes" declares no members` — as is a group that names one bone twice (`CONFIG_BLINK_GROUP_UNIQUE`; rigc: `group "eyes" names member "eye" twice`). An `irides-*` or `eyelash-*` part on a side with no eyewhite has no eye bone to ride: `propose` places it on `head` as a region, which the blink does not move, and notes `no eyewhite part for eye_r (looked for: eyewhite-r): iris (head:irides-r) is placed on head as a region, …`. The timing is fixed, not a field (table below) |
|
|
115
115
|
| `motion.blink.still` | rig | **proposed** only for a lash `propose` notes (below), then checked: `{<part>: {row, bone}}` — the rows of that region part above `row` (rig px, y down) are drawn by a second slot `<part>_still` on `bone` and do not blink; rows from `row` down keep the part's slot and blink. The part must be a region on a bone `eyes` names, `bone` one it does not (`CONFIG_STILL_OFF_THE_BLINK`), and `row` a row of the part with no art across its whole width (`RIG_STILL_ROW_CLEAR`) |
|
|
116
116
|
| `motion.animations_from` | rig; check (named; read for folds) | optional, never proposed (issue #183): a path, relative to the config file's directory, to a file in rig-c's motion-spec shape, `{"spec": "rigc-motion/1", "animations": {"<name>": {"duration": …, "tracks": [...]}, …}}` — an expression, a gesture, anything beside the idle. On every `rig` and `build` each of its animations is written into `rig/motion.json` after `idle`, as read: nothing added, re-keyed or judged here, and each is rigc's to accept or refuse at the rig stage's gate, in rigc's words. It may name what `motion.json` already holds — the bones `bones` declares, the easings `shut` and `open`, the groups `eyes` and `brows` when the blink writes them — and nothing else from the file reaches it. The loader refuses, every problem at once: no such file or one that cannot be read (`CONFIG_FILE_PRESENT`), text that is not JSON (`CONFIG_IS_JSON`), a file that is not an object, a `spec` other than `"rigc-motion/1"`, an `animations` that is not a table of objects (`CONFIG_FIELD_TYPE`), any other key — rig-c's `easings`, `groups`, `setup`, `physics`, `mix`, `archetype` and `cut` included, which would be read and not written (`CONFIG_KEY_KNOWN`), an animation named `idle` (`CONFIG_ANIMATION_NAME_FREE`), and a key written twice in one object of the file, which JSON would fold into its last value without a word (`CONFIG_KEY_UNIQUE`). `check` names the others on one line (`beside the idle: …`) and reads each for folds, with the idle — `ANIMATIONS_DO_NOT_FOLD` (§7, issues #320, #333); every other bar reads the idle. Absent, `motion.json` holds the idle alone, byte for byte as before, and `check` reads that idle for folds |
|
|
117
|
-
| `constraints` | rig (handed to rig-c as `rig.json`'s `constraints`); `compare` and the coverage lines (roles) | **authored**, optional; `propose` writes none. A list of constraints in **rig-c's own rig-spec shape** (`RigConstraint`: `ik`, `transform`, `path`, `physics`, `slider` — rig-c's `src/rig.ts` documents every field), in the order rigc applies them. The loader checks only what this package owns: each entry is an object with a `type` rigc names (`CONFIG_CONSTRAINT_TYPE_KNOWN`) and a non-empty `name`, unique within its kind as rigc finds constraints (`CONFIG_CONSTRAINT_NAME_UNIQUE`; an ik and a transform may share one); every bone it names — `bones`, an ik's `target`, a transform's `source`, a physics or slider constraint's `bone` — is a bone `bones` declares, a chain link as `<chain><i>` (`CONFIG_NAME_RESOLVES`); the bone a constraint follows does not sit under a bone it drives (`CONFIG_CONSTRAINT_TARGET_DETACHED`). Every other field (`mix`, `softness`, `properties`, a path's `slot`, a slider's `animation`) and every value is rigc's to accept or refuse at the rig stage's gate, in rigc's words (`RIG_RIGC_GREEN`) — an ik's `bones` as a shape too: from rig-c 2.15.0 rigc refuses an ik over more than two bones, or over a pair whose second bone is not the first's child (issue #103; this loader refused both itself until then). A note and an `x-` record may ride on an entry; the rig stage leaves them out of what it hands rigc. Under the default `--idle-keys ctl` a two-bone ik whose child link the idle keys is split by that link's control, and rigc refuses the pair: run `rig --idle-keys direct` or `build --idle-keys direct` (the rig stage adds that sentence, naming the flag on the command that ran, to rigc's line; `build` forwards it to its rig stage, issue #95). Each bone a constraint follows is declared to rigc as `invariants.detached` from every bone it drives, which rigc's gate rule `A25` checks |
|
|
117
|
+
| `constraints` | rig (handed to rig-c as `rig.json`'s `constraints`); `compare` and the coverage lines (roles) | **authored**, optional; `propose` writes none, but with `--cloth` (issue #364), where it writes the recipe's physics and swing transforms (*Recipe: cloth and hair that answer the world*, below). A list of constraints in **rig-c's own rig-spec shape** (`RigConstraint`: `ik`, `transform`, `path`, `physics`, `slider` — rig-c's `src/rig.ts` documents every field), in the order rigc applies them. The loader checks only what this package owns: each entry is an object with a `type` rigc names (`CONFIG_CONSTRAINT_TYPE_KNOWN`) and a non-empty `name`, unique within its kind as rigc finds constraints (`CONFIG_CONSTRAINT_NAME_UNIQUE`; an ik and a transform may share one); every bone it names — `bones`, an ik's `target`, a transform's `source`, a physics or slider constraint's `bone` — is a bone `bones` declares, a chain link as `<chain><i>` (`CONFIG_NAME_RESOLVES`); the bone a constraint follows does not sit under a bone it drives (`CONFIG_CONSTRAINT_TARGET_DETACHED`). Every other field (`mix`, `softness`, `properties`, a path's `slot`, a slider's `animation`) and every value is rigc's to accept or refuse at the rig stage's gate, in rigc's words (`RIG_RIGC_GREEN`) — an ik's `bones` as a shape too: from rig-c 2.15.0 rigc refuses an ik over more than two bones, or over a pair whose second bone is not the first's child (issue #103; this loader refused both itself until then). A note and an `x-` record may ride on an entry; the rig stage leaves them out of what it hands rigc. Under the default `--idle-keys ctl` a two-bone ik whose child link the idle keys is split by that link's control, and rigc refuses the pair: run `rig --idle-keys direct` or `build --idle-keys direct` (the rig stage adds that sentence, naming the flag on the command that ran, to rigc's line; `build` forwards it to its rig stage, issue #95). Each bone a constraint follows is declared to rigc as `invariants.detached` from every bone it drives, which rigc's gate rule `A25` checks |
|
|
118
118
|
| `turn` | rig (adds the turn control) | **proposed** only with `propose --full`/`--head` (issue #251), then corrected: `{pivot, depths}`. `depths` holds, per part, the See-through layer's `depth_median` the part came from (larger = further back), read from the run the part was assembled from; a `painting:` patch has none and is not carried. A rider (issue #271) — a part from an `eyewhite`, `irides`, `eyelash`, `eyebrow`, `nose` or `mouth` layer — is drafted at the `face` part's depth, 0.001 nearer when parts.json draws it after the face and 0.001 further when before: See-through makes no depth of its own for the eye group (it cuts them from one depth map of the combined eyes) and clamps nose and mouth to the face's median − 0.001, and the two runs' own medians for these layers disagreed by up to 0.47 and swapped their order against the face. Every other layer — ears, headwear and earwear included — keeps its own median. With no `face` part, or more than one, the riders keep their own and a note says so. One note lists each part's depth and where it came from; a carrier the other run places more than 10 % of `pivot − nearest` away gets a note naming both values and the run read — the two runs are not reconciled. `pivot` is the depth that stays put; `propose` drafts the mean of the parts' depths weighted by `opaque_px`, the one depth at which the painted pixels' centroid does not slide under the dial. The rig stage adds a bone `turn` under `root` at its origin that nothing keys — its local x is the dial, in rig px — and carries each part by `(pivot − depth) / (pivot − nearest depth)` of it: the nearest part all of it, a part behind the pivot the other way, a part at the pivot not at all. Each part rides leaf twins (`turn_<part>_<bone>`, an identity child of every bone its slot and weights bind) moved by one `transform` constraint (`turn_<part>`, after the config's own); the idle's keys, the `<bone>_ctl` controls and a physics constraint stay on the bones, and the dial moves none of them. At rest: with `turn` declared, no pixel differs by more than 1 level at dial 0 (not byte-identical; the cause is float noise in the identity child bones, and the constraints add nothing); without `turn`, byte-identical. Neither field has a default (`CONFIG_FIELD_PRESENT`); the pivot must lie behind the nearest part (`CONFIG_TURN_PIVOT_BEHIND_NEAREST`). Absent, no control is added and no byte of any output moves |
|
|
119
119
|
| `scene` | assemble (the recomposite, its holes and the figure's mask); check, through `parts.json`'s `scene` block (`RECOMPOSITE_HOLES`, the seam) | **authored**, optional; `propose` writes none (issue #242). `{}` declares the painting a scene: the figure and its surroundings in one image, See-through's full run holding only the figure. With it, `assemble` reads the recomposite figures, the hole list and the `uncovered:` lines inside the figure — the rig pixels where any full-run layer's alpha is above 8 (`OPAQUE_ALPHA_ABOVE`, the cut every layer's painted pixels are read by) — each line starting `inside the figure (config.scene: …, <n> of <m> rig px)`; writes that figure as `figure_rig.png` (white on black) beside the recomposite, and a `scene` block in `parts.json`; flags error pixels on the error map inside it only (outside, the painting grey); and `check` leaves out of the seam every frame pixel whose composite sample reaches the painting's outermost row or column, saying how many (`seam_border` in `check.json`, and on the seam line). It takes no field: the figure and its threshold are derived. A key in it other than a record or an annotation is `CONFIG_KEY_KNOWN`. Absent, no byte of any output moves |
|
|
120
|
+
| `cloth` | `propose --cloth` only; no other stage reads it, so it moves no byte of any build | **authored**, optional (issue #364): one recipe per tag, `{"bottomwear": {…}, "back hair": {…}, "front hair": {…}}`, each `{chains, links, wind, gravity, split?, length_ratio?, strength?, damping?, alternate_damping?, translate?, swing?}`. `chains` — trees across the piece (for `back hair`, per side of the eye axis), a whole number, 1 or more; `links` — links from root to tip on every path, 1 or more; `split` — `{at, into}`: the first `at` links are the trunk, which forks into `into` (2 or more) branches; `at` below `links` (`CONFIG_CLOTH_SPLIT_BEFORE_TIP`); `length_ratio` — a path's last link over its first, above 0, default 0.5; `strength` — `{trunk, branch, edge}`, each above 0 and below the spring's stability bound (`CONFIG_CLOTH_SPRING_STABLE`), default 100 / 100 / 50; `damping` — in [0, 1], absent: rig-c's default; `alternate_damping` — the odd trees' damping, in [0, 1], beside `damping` and different from it (`CONFIG_CLOTH_ALTERNATE_DIFFERS`); `wind`, `gravity` — `[root, tip]`, each 0 or more, tip at or above root (`CONFIG_CLOTH_RESPONSE_GROWS_TO_TIP`); `translate` — the x and y mix of a dangling end's flutter, above 0 and at most 1; `swing` — `bottomwear` only, `{scales}`, one positive scale per tree (`CONFIG_CLOTH_SWING_SCALE_PER_TREE`). The two defaults are the recipe's own, measured on its synthetic fixture (the recipe below). The recipe below says what each field drafts |
|
|
120
121
|
|
|
121
122
|
**A scene target is an ordinary bone.** A target the scene places — a point a hand
|
|
122
123
|
reaches for, a face something turns toward — is a single bone parented to `root`,
|
|
@@ -822,7 +823,7 @@ unreduced source on the rig's idle and passes the author's bounds (step 4). The
|
|
|
822
823
|
4. **Motion** — the rig stage builds the rig twice through rigc's gate: as written (the
|
|
823
824
|
**candidate**, the reduced mesh, packed as `--out` receives it) and with that one attachment
|
|
824
825
|
swapped for the unreduced source — its UVs, triangles and hull as `reduceMesh` was handed them,
|
|
825
|
-
its own weights bound the same way (the **reference**, `build --profile
|
|
826
|
+
its own weights bound the same way (the **reference**, `build --profile rig-play` without
|
|
826
827
|
`--pack`: the same gate over the compile, and nothing reads a reference's pages). rig-c's
|
|
827
828
|
`compareMeshesInMotion` (`rig-c/meshcompare`) poses both model documents on the idle
|
|
828
829
|
exactly as `check` renders it — `idle` at 12 fps over its duration, physics reset at 0 and
|
|
@@ -991,7 +992,7 @@ wall time goes to standard error, not into the table).
|
|
|
991
992
|
| `boundaryRuns` | optional, `{ maxVertices }`, a whole number 2 or more, no default: each removal pass first tries to replace a run of 2 to `maxVertices` consecutive source-hull vertices with one chord, as one step held to every declared row (below) |
|
|
992
993
|
| `retriangulate` | optional, `"delaunay"`: once the reduction ends, the kept vertices are re-triangulated by Delaunay flips, taken whole only when every declared row still passes (below) |
|
|
993
994
|
| `removalOrder` | optional, `"deformation-load"`: the single removals are tried in ascending predicted load instead of ascending source index (below) |
|
|
994
|
-
| `stimulus` | optional (issue #196), `{ "chain", "degrees" }` or a non-empty list of them: a bend the motion gate measures the part against, for a part no idle key deforms (*A part only physics moves*, after the physics recipe). `chain` is a chain this mesh's `segments` name, each named once; `degrees` a number above 0. Each link of the chain is turned by +`degrees` and by −`degrees` about its joint — a `rotate` key on the link, so the chain curls — in two animations of duration 0 (`stimulus <chain> +<degrees>`, `stimulus <chain> -<degrees>`) that only the comparison's builds carry: the reference and a candidate built from the written rig with them added (`build --profile
|
|
995
|
+
| `stimulus` | optional (issue #196), `{ "chain", "degrees" }` or a non-empty list of them: a bend the motion gate measures the part against, for a part no idle key deforms (*A part only physics moves*, after the physics recipe). `chain` is a chain this mesh's `segments` name, each named once; `degrees` a number above 0. Each link of the chain is turned by +`degrees` and by −`degrees` about its joint — a `rotate` key on the link, so the chain curls — in two animations of duration 0 (`stimulus <chain> +<degrees>`, `stimulus <chain> -<degrees>`) that only the comparison's builds carry: the reference and a candidate built from the written rig with them added (`build --profile rig-play` without `--pack`, one more gated build per part); `rig/motion.json` never holds them. Each is walked at time 0, right after the physics reset, so the pose is the declared bend and no constraint has moved it; the idle is walked as before, so where idle keys also move the part both are measured, against the one `motion` bound. The acceptance loop's probes walk them too, as `selection` beside the grid frames. The row echoes `stimulus` (chain, degrees, links, the two animation names); absent, nothing is added and every byte is the same. A chain the segments do not name is `CONFIG_NAME_RESOLVES`, `degrees` that is not a number above 0 `CONFIG_FIELD_TYPE`, both at the field; an animation of `motion.animations_from` already called by one of the two names is `AUTO_MESH_MOTION_INPUT`. The amplitude (*The allocation rows*) is still derived from the idle alone |
|
|
995
996
|
|
|
996
997
|
**A bound declared absent.** `maxOvershoot` and `maxUndercut`, in `sourceBounds` and in
|
|
997
998
|
`targets.artFit`, each take a number of px 0 or more or `null`. `null` means *measured and
|
|
@@ -1500,6 +1501,122 @@ is the fix.
|
|
|
1500
1501
|
201 to 198 px wide and moved `check.json`'s `BREATH_VISIBLE` `torso_heat_mean` from 7.8 to
|
|
1501
1502
|
7.705, every status unchanged, although `check` reads the idle alone.
|
|
1502
1503
|
|
|
1504
|
+
### Recipe: cloth and hair that answer the world
|
|
1505
|
+
|
|
1506
|
+
Issue #364. Cloth and hair move **by physics, not by keyed animation** (the owner's
|
|
1507
|
+
direction, 2026-10-13), so that a rig in a scene answers the scene — the body under
|
|
1508
|
+
it moving, a gust from the side. The config's `cloth` block declares the recipe per
|
|
1509
|
+
tag, and `propose --cloth <config.json>` drafts it; the proposal is copied into the
|
|
1510
|
+
config as always, `constraints` with the rest. Without `--cloth` nothing the proposer
|
|
1511
|
+
writes changes. The recipe makes the rig **respond**; driving it — a hip key, a walk,
|
|
1512
|
+
the wind — is the consumer's, and the recipe drafts no key and no stimulus.
|
|
1513
|
+
|
|
1514
|
+
```jsonc
|
|
1515
|
+
"cloth": {
|
|
1516
|
+
"bottomwear": { "chains": 4, "links": 3, "split": { "at": 1, "into": 2 },
|
|
1517
|
+
"damping": 0.85, "alternate_damping": 0.7,
|
|
1518
|
+
"wind": [2, 10], "gravity": [5, 30], "translate": 0.2,
|
|
1519
|
+
"swing": { "scales": [1.3, 1, 1, 1.3] } },
|
|
1520
|
+
"back hair": { "chains": 2, "links": 3, "split": { "at": 1, "into": 2 }, "wind": [1, 8], "gravity": [4, 24] },
|
|
1521
|
+
"front hair": { "chains": 1, "links": 3, "wind": [1, 6], "gravity": [2, 12], "translate": 0.2 }
|
|
1522
|
+
}
|
|
1523
|
+
```
|
|
1524
|
+
|
|
1525
|
+
(The selftest's fixture recipe, `fixtures/cloth.ts`: values chosen to exercise every
|
|
1526
|
+
rule, not advice. It leaves `length_ratio` and `strength` out, so the recipe's own
|
|
1527
|
+
defaults are what is built and measured below.)
|
|
1528
|
+
|
|
1529
|
+
What each rule drafts (`src/cloth.ts` holds them):
|
|
1530
|
+
|
|
1531
|
+
| rule | drafts | from |
|
|
1532
|
+
| --- | --- | --- |
|
|
1533
|
+
| where | `bottomwear`: from `hip`, the root row 20 px below hip's y (the keyed chains' row), the tip row 4 px above the part's bottom. `back hair` that reaches below the shoulders: from `head`, per side of the eye axis (twin tails are a side each), the eye line to 4 px above its bottom. `front hair`: each strand that hangs below the chin (the lock rule's), from `head`, 0.22 face heights above the eye line to 5 px below the strand; the fringe's three columns keep their two links and their places | the keyed chains' own rows, which these replace |
|
|
1534
|
+
| trees | tree k of `chains` owns the cell k/N .. (k+1)/N of the art's width in every row, and its links sit at the cell's centre in the 24-row band there, so a piece that widens fans its trees. With `split`, the trunk's tip is the fork, and branch b of `into` follows the centre of its share of the cell. Chains are named `<prefix><k>_` (trunk) and `<prefix><k><a, b, …>_` (branches): `skirt`, `hairback_r`/`hairback_l`, `lockt` | `chains`, `links`, `split` |
|
|
1535
|
+
| lengths | link j's length is the first's times q^j, q = `length_ratio`^(1/(links − 1)), the whole spanning root row to tip row: the links shorten toward the tip | `length_ratio` (default 0.5, below) |
|
|
1536
|
+
| stiffness | a trunk link takes `strength.trunk`, a branch link `strength.branch`, and the edge — the outermost branch on each outer side of the piece (both sides of a skirt or a strand; the outer side of each back-hair side), or without `split` the outermost tree — `strength.edge`; a fringe column is a trunk, its outer two the edge. **Strength does not fall along a chain**: a tip reads soft because each link turns on top of every link above it, so the motion accumulates down the chain at one strength. Only the edge is declared softer | `strength` (default trunk 100, branch 100, edge 50, below) |
|
|
1537
|
+
| response | link j of an n-link path takes `wind` and `gravity` at j/(n − 1) of the way from the root value to the tip value; a single-link path takes the tip value. Each is a scalar **multiplier** of the environment the consumer sets (spine-core's skeleton `windX, windY`, `gravityX, gravityY`; rig-c 2.52.0's live track `setEnvironment`, rig-play 1.10.0's `environment()`): no direction is drafted | `wind`, `gravity` |
|
|
1538
|
+
| out of phase | the odd trees take `alternate_damping`, the even ones `damping` | `damping`, `alternate_damping` |
|
|
1539
|
+
| flutter | the last link of every path gets a second physics constraint, `<bone>_translate`, moving x and y by `translate`, with the link's stiffness and damping and **no** wind or gravity response. spine-core scales a translate spring's response by the skeleton's reference scale (100) and a rotation's by the link's length over it, so one response on both pushes an end about 100/length times further than it turns it (the table below) | `translate` |
|
|
1540
|
+
| swing | `bottomwear` only: a bone `<prefix>_swing` under `hip` at the centre of the root row, one link long, straight down, with physics (the trunk's stiffness, the root's response); each tree's first link takes the swing's rotation times its scale — a transform `<swing>_<k>`, local source and target, additive, the swing's setup rotation in hip's frame (−90: hip is drafted unturned) subtracted — and no physics of its own | `swing.scales` |
|
|
1541
|
+
|
|
1542
|
+
Every link but a swing-driven first link gets `<bone>_physics` (`rotate` 1), and no
|
|
1543
|
+
idle key: the drafted idle keys none of the trees. A recipe that drafts nothing —
|
|
1544
|
+
its tag on no part, or `back hair` that ends above the shoulders (a bun) — is refused,
|
|
1545
|
+
`PROPOSE_CLOTH_DRAFTED`.
|
|
1546
|
+
|
|
1547
|
+
**Every spring is stable at its step (A23's inequality).** Per step spine-core does
|
|
1548
|
+
`v += −strength·x·step·massInverse`, `x += v·step`, `v *= d` with d = damping^(60·step);
|
|
1549
|
+
in (x, v·step) that is the matrix [[1 − k, 1], [−d·k, d]] with
|
|
1550
|
+
k = strength·massInverse·step², and both eigenvalues are inside the unit circle exactly
|
|
1551
|
+
when **0 < k < 2(1 + damping^(60·step))**. The recipe sets no `fps` or `mass`, so step is
|
|
1552
|
+
1/60 and massInverse 1 (rig-c's defaults), and a damping left out is rig-c's 0.85. The
|
|
1553
|
+
loader refuses a strength, declared or default, at or past the bound at any damping the
|
|
1554
|
+
recipe runs at (`CONFIG_CLOTH_SPRING_STABLE`). The defaults against it:
|
|
1555
|
+
|
|
1556
|
+
| strength | k = strength/3600 | bound at damping 0.85 (rig-c's default) | at 0.7 | at 0 (the lowest) | at 1 |
|
|
1557
|
+
| --- | --- | --- | --- | --- | --- |
|
|
1558
|
+
| 100 (trunk, branch) | 0.027778 | 3.7 | 3.4 | 2 | 4 |
|
|
1559
|
+
| 50 (edge) | 0.013889 | 3.7 | 3.4 | 2 | 4 |
|
|
1560
|
+
|
|
1561
|
+
**The defaults are the recipe's own, measured here** on the cloth fixture
|
|
1562
|
+
(`fixtures/cloth.ts`: a skirt of four trees on a swing, twin-tail back hair of two trees
|
|
1563
|
+
a side, a lock and the fringe; its recipe above; rig-c 2.47.1's build and `check`, and
|
|
1564
|
+
for the environment rig-c's live track, `setEnvironment`, which rig-c has from 2.52.0,
|
|
1565
|
+
read with 2.53.0). Candidates, each with the others at the
|
|
1566
|
+
default (`TEXTURE_STRETCH` severity, ceiling 1.927; then, under wind (1, 0) against
|
|
1567
|
+
calm (0, 0), gravity (0, 1) throughout, each held three idle cycles, the largest vertex
|
|
1568
|
+
displacement of `hair_back`, `skirt` and `hair_front`, and how far the origin of the last
|
|
1569
|
+
link of the right side's outer edge branch, `hairback_r0a_1`, moves against that of the
|
|
1570
|
+
inner branch beside it, `hairback_r0b_1`, in rig px):
|
|
1571
|
+
|
|
1572
|
+
| candidate | TEXTURE_STRETCH | wind (1, 0) vs calm: hair_back / skirt / hair_front | edge / inner branch |
|
|
1573
|
+
| --- | --- | --- | --- |
|
|
1574
|
+
| **default: strength 100 / 100 / 50, length_ratio 0.5** | **1.382** | **10.299 / 3.390 / 2.119** | **5.608 / 3.846** |
|
|
1575
|
+
| edge 100 (no softer edge) | 1.125 | 8.126 / 2.480 / 1.091 | 3.857 / 3.846 |
|
|
1576
|
+
| edge 25 | 2.062, **FAIL** | 14.355 / 4.931 / 4.014 | 8.333 / 3.846 |
|
|
1577
|
+
| length_ratio 1 (equal links) | 1.516 | 13.677 / 4.133 / 2.721 | 5.208 / 3.348 |
|
|
1578
|
+
| length_ratio 0.25 | 1.217 | 7.841 / 2.762 / 1.731 | 5.513 / 4.083 |
|
|
1579
|
+
|
|
1580
|
+
The rule the defaults were chosen by: the edge visibly softer than the branch beside it
|
|
1581
|
+
(edge 100 makes them one), every bar green (edge 25 stretches the texture past the
|
|
1582
|
+
ceiling), and among the ratios that do shorten the links toward the tip (1 does not) the
|
|
1583
|
+
one that answers the wind most. The figures are this fixture's; on other art the same
|
|
1584
|
+
reading, `check` and a gust, is how to tune them.
|
|
1585
|
+
|
|
1586
|
+
The flutter's split, measured on the same fixture (`TEXTURE_STRETCH` severity, the
|
|
1587
|
+
translate mix at 0.2 / 0.5 / 1): as drafted, no response on the translate, 1.382 /
|
|
1588
|
+
1.388 / 1.398; given the link's own wind and gravity, 1.65 / 3.233 (**FAIL**) /
|
|
1589
|
+
3.814 (**FAIL**).
|
|
1590
|
+
|
|
1591
|
+
**What moves them.** Physics answers motion of the bones above it and the environment.
|
|
1592
|
+
The drafted idle keys `chest` (the breath) and the head chain, never `hip`, and the
|
|
1593
|
+
recipe adds no key: under the idle alone a skirt's trees move only by the environment.
|
|
1594
|
+
`rigc render` and `check` pose under spine-core's default, wind (1, 0) and gravity
|
|
1595
|
+
(0, 1), so on the fixture `check` reads `check: PASS`, `TEXTURE_STRETCH` 1.382,
|
|
1596
|
+
`TIP_OVER_ROOT` ratio 15.06 (root 0.095, tip 1.438 rig px), `CHAIN_LAG` PASS,
|
|
1597
|
+
`ANIMATIONS_DO_NOT_FOLD` 0 folding meshes (that bar leaves physics out), and
|
|
1598
|
+
`rigc render --folds` on the same build **with** all of its physics constraints reads 0 of 3
|
|
1599
|
+
meshes folding at 12, 24 and 60 fps. Under an explicit environment set through the live
|
|
1600
|
+
track's `setEnvironment` — wind (1, 0) for one idle cycle, then (−1, 0) for one, then
|
|
1601
|
+
calm (0, 0) for one, gravity (0, 1) throughout, on one looping track — the frame at the
|
|
1602
|
+
end of each wind phase, against the calm frame at the same idle time, moves `hair_back`
|
|
1603
|
+
by up to 10.396 and 10.188, `skirt` 3.390 and 3.382, and `hair_front` 2.131 and 2.104 rig
|
|
1604
|
+
px, either way alike; held three cycles each from a fresh track, 10.299 / 10.277,
|
|
1605
|
+
3.390 / 3.382 and 2.119 / 2.115.
|
|
1606
|
+
|
|
1607
|
+
**Not in this recipe.**
|
|
1608
|
+
|
|
1609
|
+
- **Weights across neighbouring chains** (rig-c/core#1415's per-vertex weights, a vertex
|
|
1610
|
+
following the links of several trees): issue #378.
|
|
1611
|
+
- **A stop at the legs** is not needed for this recipe. On a copy of the fixture with two
|
|
1612
|
+
thighs drawn behind the skirt, under the environment alone (wind (1, 0), then (−1, 0),
|
|
1613
|
+
then calm) no skirt link that clears the thighs at rest crosses into one: 0 crossings.
|
|
1614
|
+
A consumer's hip motion can make the hem cross: on the same copy, under a hip sway
|
|
1615
|
+
applied to it through the live track (±8 degrees and ±12 px, a 2 s period), skirt links
|
|
1616
|
+
cross on 224 (calm) and 228 (wind (1, 0)) of 360 steps. That case is rig-c/core#1413's; until it lands, a stop is the
|
|
1617
|
+
author's own constraint network in `constraints`. When `--keypoints` drafts leg chains,
|
|
1618
|
+
a note says so.
|
|
1619
|
+
|
|
1503
1620
|
## 4. The command order
|
|
1504
1621
|
|
|
1505
1622
|
Two steps are external: the See-through runs (by any route; the optional `comfy seethrough` adapter is only a client for a ComfyUI box). Everything else is this tool.
|
|
@@ -1518,6 +1635,7 @@ early loader does not read it.
|
|
|
1518
1635
|
| `layers` | 1 and 4 `inputs`, 6 `assemble --propose-plan` | `key`, `seethrough`, `assemble.rig_scale` | `seethrough.head_box`, for `--propose-plan` only (`ASSEMBLE_FIELD_PRESENT`) |
|
|
1519
1636
|
| `assemble` | 7 `assemble` | `key`, `seethrough`, `assemble.rig_scale`, `assemble.plan` | `seethrough.head_box` (`ASSEMBLE_FIELD_PRESENT`) |
|
|
1520
1637
|
| `full` | 8 `propose --from-config`, `propose --compare`, `compare` (a side that states a `key`), `rig`, 9 `build` | `key`, `assemble.rig_scale`, `assemble.plan`, `bones`, `meshes`, `regions`, `motion` | for `build`, the `assemble` row's too: its assemble stage reads through that loader after this one |
|
|
1638
|
+
| `cloth` | 8 `propose --cloth` (issue #364) | `key`, `cloth` | every other key must still be one a config knows; only `cloth` is vouched for. Every other loader vouches for `cloth` too when it is present |
|
|
1521
1639
|
|
|
1522
1640
|
A missing field is `CONFIG_FIELD_PRESENT` naming it; a missing `generation` names
|
|
1523
1641
|
the fields the block holds, and a missing `assemble.plan` names
|
|
@@ -1582,7 +1700,13 @@ full loader before its assemble stage writes anything.
|
|
|
1582
1700
|
no later stage can see — then
|
|
1583
1701
|
`rig-parts propose --parts work/rig --source inputs/painting.png --out work` →
|
|
1584
1702
|
`work/proposal.json` and `work/render/landmarks.png` (+ `_head`). Copy
|
|
1585
|
-
`bones`, `meshes`, `regions`
|
|
1703
|
+
each of `bones`, `meshes`, `regions`, `limbs`, `motion`, `constraints` and `turn` it
|
|
1704
|
+
wrote into the config: `limbs` is written only with `--keypoints`, `constraints`
|
|
1705
|
+
only with `--cloth` and `turn` only with `--full`/`--head` (`PROPOSAL_CONFIG_SECTIONS` in `src/propose.ts` is the list,
|
|
1706
|
+
and the selftest's `TY18` holds this sentence to it). A `limbs` block left out
|
|
1707
|
+
is refused at step 8 by the name of every part it cuts: `CONFIG_NAME_RESOLVES`
|
|
1708
|
+
on each limb part the meshes or regions attach, `CONFIG_PART_ATTACHED` on the
|
|
1709
|
+
layer it would have cut (`RL04`). Then read what
|
|
1586
1710
|
was looked at. After the LINT summary, one `coverage <bone> [<role>]:` line
|
|
1587
1711
|
per bone says `checked, clean` (and which checks read it), `checked, LINT`,
|
|
1588
1712
|
or `not checked` and why — its role (a `control` binds nothing and may sit
|
|
@@ -2086,7 +2210,7 @@ skip); the pose costs 14.8 against 15.3 us per frame (reference-demo) and 8.3 ag
|
|
|
2086
2210
|
(reference-sample), the difference all in `updateWorldTransform`; the rendered idle frames
|
|
2087
2211
|
differ by at most one level in a channel. The default stays `ctl`: the examples'
|
|
2088
2212
|
`expected/rig.json` and `motion.json` are the reference's output, and the
|
|
2089
|
-
declaration is in the rig spec only, so `rigc validate <build> --profile
|
|
2213
|
+
declaration is in the rig spec only, so `rigc validate <build> --profile rig-play`
|
|
2090
2214
|
run on a `direct` build (it has no rig spec to read) refuses A15 once per keyed
|
|
2091
2215
|
bone. No stage runs `validate`: the gate is `rigc build`, which reads the rig spec
|
|
2092
2216
|
and its declaration, and is green on both (`RG19`).
|
|
@@ -2369,6 +2493,11 @@ See-through with another seed.
|
|
|
2369
2493
|
| <a id="CONFIG_CONSTRAINT_NAME_UNIQUE"></a>`CONFIG_CONSTRAINT_NAME_UNIQUE` | two `constraints` entries of one kind share a `name`; rigc finds a constraint by its kind and its name, so an ik and a transform may share one | rename one |
|
|
2370
2494
|
| <a id="CONFIG_CONSTRAINT_TARGET_DETACHED"></a>`CONFIG_CONSTRAINT_TARGET_DETACHED` | the bone an ik follows (`target`) or a transform reads (`source`) is one of the bones that constraint drives, or sits under one (the detail gives the line of parents) — driving them would move what they follow. This package's refusal: rig-c 2.15.0 gates such a rig green when nothing declares the parentage (measured on the selftest's rig fixture, issue #103) | a bone beside the chain; a scene target is a single bone parented to `root` (§3) |
|
|
2371
2495
|
| <a id="CONFIG_TURN_PIVOT_BEHIND_NEAREST"></a>`CONFIG_TURN_PIVOT_BEHIND_NEAREST` | `turn.pivot` is at or in front of the nearest part's depth: the law `(pivot − depth) / (pivot − nearest)` has no value there, and in front of it every part travels against the dial | a pivot above the smallest depth in `turn.depths` |
|
|
2496
|
+
| <a id="CONFIG_CLOTH_SPLIT_BEFORE_TIP"></a>`CONFIG_CLOTH_SPLIT_BEFORE_TIP` | a `cloth` recipe's `split.at` is at or past its `links`: the trunk would leave no link for the branches (issue #364) | `split.at` below `links`, or leave `split` out |
|
|
2497
|
+
| <a id="CONFIG_CLOTH_RESPONSE_GROWS_TO_TIP"></a>`CONFIG_CLOTH_RESPONSE_GROWS_TO_TIP` | a `cloth` recipe's `wind` or `gravity` is `[root, tip]` with tip below root: the response grows from the root to the tip, where the motion accumulates down the chain | that pair |
|
|
2498
|
+
| <a id="CONFIG_CLOTH_ALTERNATE_DIFFERS"></a>`CONFIG_CLOTH_ALTERNATE_DIFFERS` | a `cloth` recipe's `alternate_damping` without `damping`, or equal to it: neighbouring trees are declared out of phase, and an alternate that alternates nothing declares nothing | `damping` beside it, a different value, or leave `alternate_damping` out |
|
|
2499
|
+
| <a id="CONFIG_CLOTH_SWING_SCALE_PER_TREE"></a>`CONFIG_CLOTH_SWING_SCALE_PER_TREE` | `swing` on a tag other than `bottomwear`, or `swing.scales` not one scale per tree (`chains`) | one scale per tree, in tree order across the skirt |
|
|
2500
|
+
| <a id="CONFIG_CLOTH_SPRING_STABLE"></a>`CONFIG_CLOTH_SPRING_STABLE` | a `cloth` recipe's strength — declared, or the default 100 / 100 / 50 — whose spring is unstable at a damping the recipe runs at (`damping`, `alternate_damping`, or rig-c's 0.85 when `damping` is left out): k = strength·massInverse·step² at or past 2(1 + damping^(60·step)), step 1/60 and mass 1 (rig-c's defaults; the recipe sets neither). The detail gives k and the bound | a lower strength, or a higher damping |
|
|
2372
2501
|
| <a id="CONFIG_TURN_BONE_FREE"></a>`CONFIG_TURN_BONE_FREE` | the config has `turn` and `bones` declares a bone named `turn`, the control the rig stage adds | rename that bone |
|
|
2373
2502
|
|
|
2374
2503
|
### inputs
|
|
@@ -2447,6 +2576,7 @@ says why each requirement exists and what breaks without it.
|
|
|
2447
2576
|
| <a id="PROPOSE_FACE_PRESENT"></a>`PROPOSE_FACE_PRESENT` | no part comes from a `face` layer, and the face-less fallback cannot derive a face box either: it needs the head run's `neck` and at least one head-run `front hair`/`back hair` part whose top is above the neck's, and the message names the half that is missing. With both, `propose` does not refuse — it derives the box and says so in its first note (§5) | `assemble.plan`: take the face, or the head run's hair and neck |
|
|
2448
2577
|
| <a id="PROPOSE_CUT_FROM_RECORDED"></a>`PROPOSE_CUT_FROM_RECORDED` | two parts share one layer and none of them records `cut_from`: a `parts.json` an `assemble` before 1.6.0 wrote with `assemble.cuts`. The records are in draw order, so which is the plan part and which the piece cannot be read off the file; the message names the parts and the layer. Every other reader still takes the file | `--parts`: re-run assemble (1.6.0+) to record `cut_from` |
|
|
2449
2578
|
| <a id="PROPOSE_LIMB_PARTS"></a>`PROPOSE_LIMB_PARTS` | `parts.json` holds parts `config.limbs` cut at their joints (issue #349); the limbs are drafted from the parts before the cut, which the rules read by layer | `--parts` a build assembled with the config's `limbs` left out; keep the block the config holds (its caps and ranges are the author's). `propose --from-config` reads the config's bones on either build |
|
|
2579
|
+
| <a id="PROPOSE_CLOTH_DRAFTED"></a>`PROPOSE_CLOTH_DRAFTED` | with `--cloth` (issue #364): the config's `cloth` block holds a recipe for a tag the proposer drafts no chain on — no part has that tag, or every `back hair` part ends above the shoulders (a bun bone, no chain) | leave that recipe out, or assemble the layer it is for |
|
|
2450
2580
|
| <a id="PROPOSE_ACCESSORY_BODY"></a>`PROPOSE_ACCESSORY_BODY` | an accessory has nothing above its pendant rows to hang its bone on | that part's plan entry, or author its bones by hand |
|
|
2451
2581
|
| <a id="PROPOSE_TURN_RUN_GIVEN"></a><a id="PROPOSE_TURN_LAYER_PRESENT"></a><a id="PROPOSE_TURN_DEPTH_PRESENT"></a>`PROPOSE_TURN_RUN_GIVEN`, `PROPOSE_TURN_LAYER_PRESENT`, `PROPOSE_TURN_DEPTH_PRESENT` | with `--full`/`--head` (issue #251): a part came from a run whose layers were not given, the run given holds no layer of the part's tag, or its layer carries no `depth_median` while another part's layer carries one; a run with no depth on any part's layer (a PSD, or an export of one) is not refused — the turn is skipped, and the note says `turn: SKIP` and names the run (issue #359) | give the run the parts were assembled from, as the wrapper's `layers.json` |
|
|
2452
2582
|
| <a id="BASIS_RECORDS_EVERY_BONE"></a><a id="BASIS_NAMES_RESOLVE"></a><a id="BASIS_KIND_KNOWN"></a><a id="BASIS_KIND_HOLDS"></a>`BASIS_RECORDS_EVERY_BONE`, `BASIS_NAMES_RESOLVE`, `BASIS_KIND_KNOWN`, `BASIS_KIND_HOLDS` | `propose --keypoints`'s record of how it placed each bone, `basis.json`, does not hold to the proposal it was written with: a proposed bone with no record, one recorded twice or out of the proposal's order; a part, bone or frame quantity it names that is not there; a placement kind outside the known ones; or a placement that does not hold what its kind says (a joint placement with no joint, a non-joint one with a joint, a derived one with no bone, a constant that is not finite). Nothing is written | a proposer bug, not an input problem: report it with the line |
|
|
@@ -3152,7 +3282,7 @@ What is composed:
|
|
|
3152
3282
|
play. Each is read with the idle's own key lists, so a key compose does not know
|
|
3153
3283
|
how to prefix is `SCENE_BUILD_FIELD_KNOWN`, as it is on the idle, and a track of
|
|
3154
3284
|
one that keys `root` is `SCENE_ROOT_SHARED` (issue #183).
|
|
3155
|
-
- **Gated as `rig` gates its own:** `rigc build --profile
|
|
3285
|
+
- **Gated as `rig` gates its own:** `rigc build --profile rig-play --pack`, the
|
|
3156
3286
|
compile and the packed pages on disk, in a scratch directory; `--out` receives
|
|
3157
3287
|
`rig/` (`rig.json`, `motion.json`, `images/`) and `scene.json` only when it is
|
|
3158
3288
|
green. Then `check` runs over `rig/` into `check/`, as on any rig it did not
|
package/docs/MIGRATION.md
CHANGED
|
@@ -283,3 +283,23 @@ hip*). No other command changed, and no byte any build writes moves.
|
|
|
283
283
|
|
|
284
284
|
What to do: write a hip a skirt hides as `occluded` with its estimate. A file that
|
|
285
285
|
wrote it `observed` reads the same gaps as before.
|
|
286
|
+
|
|
287
|
+
### And cloth and hair that answer the world (`propose --cloth`, issue #364)
|
|
288
|
+
|
|
289
|
+
A config may hold a `cloth` block — one recipe per tag, `bottomwear`, `back hair` and
|
|
290
|
+
`front hair` (AUTHORING §3, *Recipe: cloth and hair that answer the world*) — and
|
|
291
|
+
`propose --cloth <config.json>` drafts that tag's pieces as trees of physics links
|
|
292
|
+
in place of the keyed chains. Without `--cloth` nothing the proposer writes moves;
|
|
293
|
+
`rig` and `build` do not read `cloth` at all, so no byte any build writes moves
|
|
294
|
+
either (the examples' `expected/` and every existing control are unchanged).
|
|
295
|
+
|
|
296
|
+
| change | before | after |
|
|
297
|
+
| --- | --- | --- |
|
|
298
|
+
| `cloth` in a config | refused, `CONFIG_KEY_KNOWN` | vouched by every loader (`CONFIG_FIELD_*`, and the `CONFIG_CLOTH_*` rules of AUTHORING §6), read by `propose --cloth` only |
|
|
299
|
+
| `propose --cloth <config.json>` | a usage error, flag not taken (exit 2) | the recipe's trees, their `constraints` in proposal.json, one note per piece; a recipe that drafts nothing, `PROPOSE_CLOTH_DRAFTED` (exit 1) |
|
|
300
|
+
| `proposal.json` | no `constraints` | `constraints` after `motion`, with `--cloth` only |
|
|
301
|
+
|
|
302
|
+
What to do: nothing. To draft a skirt or hair that the consumer's wind and gravity move,
|
|
303
|
+
add a `cloth` block and propose with `--cloth`; copy each of `bones`, `meshes`, `regions`,
|
|
304
|
+
`limbs`, `motion`, `constraints` and `turn` the proposal wrote into the config, as before
|
|
305
|
+
(`constraints` is the one `--cloth` adds).
|
package/docs/STABILITY.md
CHANGED
|
@@ -53,7 +53,7 @@ defaults are the help's too, and none is guessed from the art.
|
|
|
53
53
|
| `comfy` | `seethrough`: `--image`, `--out`; optional `--resolution`, `--steps`, `--seed`, `--prefix`, `--offload`, `--lama`, `--nf4`, `--host`, `--wait`, `--timeout`, `--poll` |
|
|
54
54
|
| `assemble` | `--propose-plan` with `--source`, `--full`, `--config`, optional `--head`; or `--source`, `--full`, `--config`, `--out`, optional `--head` (without it, one run: issue #359), `--seam` (near-white, silhouette), `--project` (core, visible) |
|
|
55
55
|
| `propose` | `--head-box` with `--full`, `--canvas` |
|
|
56
|
-
| `propose` | `--parts`, `--source`, `--out`; optional `--compare` or `--from-config` (one of them), `--keypoints`, `--person` and `--wrist-snap` (each with `--keypoints`), `--full`, `--head` (the turn control's depths; not with `--from-config`), `--grid-rule` (`figure` or `part`, the drafted lattice's spacing; not with `--from-config`) |
|
|
56
|
+
| `propose` | `--parts`, `--source`, `--out`; optional `--compare` or `--from-config` (one of them), `--keypoints`, `--person` and `--wrist-snap` (each with `--keypoints`), `--full`, `--head` (the turn control's depths; not with `--from-config`), `--grid-rule` (`figure` or `part`, the drafted lattice's spacing; not with `--from-config`), `--cloth` (a config whose `cloth` block is the recipe, issue #364; not with `--from-config`) |
|
|
57
57
|
| `compare` | `--left`, `--right`; optional `--map` |
|
|
58
58
|
| `rig` | `--config`, `--parts`, `--out`; optional `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
|
|
59
59
|
| `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills` |
|
|
@@ -112,7 +112,7 @@ The fields, object by object (a bold path is where the object sits; `<part>` is
|
|
|
112
112
|
part name, `[i]` an entry of a list):
|
|
113
113
|
|
|
114
114
|
<!-- stable:config -->
|
|
115
|
-
- **config** — required by the full loader, in front of rig and build: `key`, `assemble`, `bones`, `meshes`, `regions`, `motion`; optional: `generation`, `seethrough`, `limbs`, `constraints`, `turn`, `scene`
|
|
115
|
+
- **config** — required by the full loader, in front of rig and build: `key`, `assemble`, `bones`, `meshes`, `regions`, `motion`; optional: `generation`, `seethrough`, `limbs`, `constraints`, `turn`, `scene`, `cloth`
|
|
116
116
|
- **generation** — required: `checkpoint`, `loras`, `trigger`, `identity`, `sampler`, `costume`, `negative_extra`, `style`, `negative_pose`, `latent`, `seed`; optional: `pose`, `control`
|
|
117
117
|
- **generation.loras[i]** — required: `name`, `strength`; optional: `strength_clip`
|
|
118
118
|
- **generation.sampler** — required: `steps`, `cfg`, `sampler`, `scheduler`
|
|
@@ -147,6 +147,10 @@ part name, `[i]` an entry of a list):
|
|
|
147
147
|
- **meshes.<part>.auto.regions[i]** — required: `name`, `shape`, `maxEdgeLength`, `transition`, `grade`, `minArtSamples`, and `cx`, `cy`, `r` for a circle or `points` for a polygon; optional: `bone`, `band` (both or neither; with neither the region is density only)
|
|
148
148
|
- **meshes.<part>.auto.boundaryRuns** — required: `maxVertices`
|
|
149
149
|
- **meshes.<part>.auto.stimulus**, or each entry of it when a list — required: `chain`, `degrees`
|
|
150
|
+
- **cloth.<tag>**, the tag bottomwear, back hair or front hair (issue #364; read by propose --cloth only) — required: `chains`, `links`, `wind`, `gravity`; optional: `split`, `length_ratio`, `strength`, `damping`, `alternate_damping`, `translate`, `swing` (on bottomwear only)
|
|
151
|
+
- **cloth.<tag>.split** — required: `at`, `into`
|
|
152
|
+
- **cloth.<tag>.strength** — required: `trunk`, `branch`, `edge`
|
|
153
|
+
- **cloth.<tag>.swing** — required: `scales`
|
|
150
154
|
- **regions.<part>** — a bone name
|
|
151
155
|
- **motion** — required: `duration`, `tracks`; optional: `blink`, `animations_from`
|
|
152
156
|
- **motion.tracks[i]**, a single track — required: `bone`, `prop`, `amp`, `period`, `phase`; optional: `base`
|
|
@@ -180,7 +184,7 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
|
|
|
180
184
|
| `check/check.json` and the rest of `check/` | `check`, `build`, `compose` | the reference's fields in its order (`gate_spine_html_green`, `rigc_entry`, `pack_mode`, `loop_max_diff`, the seam figures — `seam_mean`, `seam_px_over_40`, `seam_px_over_80` and, from issue #216, `seam_frame_scale`, the frame scale the bar divides the count by), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `seam_border` after the seam figures when `parts.json` declares a scene (issue #242), `seam_pairs` after the seam figures when the seam bar fails or `--seam-pairs` asks (each row's picture under `check/seam/`; `--keep-stills` leaves the setup-pose still and its `frames.json` under `check/setup_still/`), then the judgement lines (`BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`), `ANIMATIONS_DO_NOT_FOLD` after them when `motion.json` holds an animation, the idle included — on every rig with an idle since issue #333 (issue #320: `status`, `animations`, `fps`, `physics_left_out`, `folding`, `folding_undeclared`, `declared_not_folding`, `bar`), `FEET_STAY_LEVEL` after it when a `footwear` part rides a bone that hangs from another and `motion.json` holds an animation (issue #348: `status`, `reason` on a SKIP only, `animations`, `fps`, `physics_left_out`, `bar_degrees`, `bar`, `feet` — each `part`, `bone`, `hangs_from`, `status`, `frames_posed`, `worst`), `LIMB_ONE_BONE` after it (and after `STRESS_OFF_CHAIN` where that is written) when `parts.json` holds a limb segment's part (issue #349: `status`, `parts` — each `part`, `limb`, `bone`, `status`, `others`), `RECOMPOSITE_HOLES` (its first figure `declared_scene` when `parts.json` declares a scene), `SETUP_POSE_VS_SOURCE`, `skipped`, a `requirements` block under `--requirements`, and `PASS`; `check/build/skeleton.json`, `.atlas` and `.png` are the packed artifact rig-c writes |
|
|
181
185
|
| `layers.json`, `<index>_<name>.png` | `layers --export` | the wrapper form `layers` reads (issue #359): `width`, `height`, then `layers` — each `name`, `filename`, `left`, `top`, `right`, `bottom`, `depth_median` (the input's own; `null` for a PSD, the manifest's order then being the draw order) — drawn layers in draw order, then the hidden-art layers; a PNG's name is its index and its layer's name, and the manifest, not the file name, says which layer it is |
|
|
182
186
|
| the template `.psd` | `layers --template` | one empty layer per name `templateLayerNames` (`src/layers.ts`) holds, bottom first; the same canvas writes the same bytes |
|
|
183
|
-
| `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `turn` with `--full`/`--head`, and `notes` |
|
|
187
|
+
| `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `constraints` with `--cloth` (issue #364: a physics constraint per tree link named `<bone>_physics`, a dangling end's `<bone>_translate`, and a skirt swing's transforms `<swing>_<tree>`), `turn` with `--full`/`--head`, and `notes` |
|
|
184
188
|
| `basis.json` | `propose` | spec `spine-parts-basis/1` |
|
|
185
189
|
| `config.json`, `mesh_draft.json` | `mesh-draft` | `config.json` is the config read, byte for byte, but for each drafted part's `meshes` entry; `mesh_draft.json` is spec `rig-parts-mesh-draft/1`: `rules`, `lattice_check`, `draft_check`, `figure_overdraw`, and per lattice part `part`, `mode`, `lattice`, `candidate` (with `bridges` — `units`, `joins` of `span` and `area_px2`, `area_px2`, `overdraw`, and `faint` only when an island was left out as faint — only when the candidate is a bridged one, issue #326), `delta` (under `--more-triangles` only), `readings`, `gate` (each line's `reading`, `pass`, `text`, `margin`), `note`; and `not_compared` (issue #307), only when the config holds an `auto` or `contour` entry: per such entry, in config order, `part`, `mode` and `note` — the part was neither drafted nor compared, and a config of lattices alone writes no such key |
|
|
186
190
|
| the scene report | `compose` | spec `spine-parts-scene-report/1` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rig-c/parts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "AI-authored 2D character parts from one anime painting and its See-through layer decomposition: measured parts, weighted-mesh rig specs, verified through rig-c before anything is written. A CLI for agents that cannot see the image.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"ag-psd": "^31.0.2",
|
|
64
|
-
"rig-c": "^2.
|
|
64
|
+
"rig-c": "^2.54.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@esotericsoftware/spine-core": "4.3.13",
|
|
@@ -84,9 +84,11 @@ under that.
|
|
|
84
84
|
`work/render/recomposite_error_rig.png`; a large red hole between two parts is a
|
|
85
85
|
gap See-through left (a skirt split into two legs), fixed in the plan or the layers,
|
|
86
86
|
not in the rig. Then `rig-parts propose --parts work/rig
|
|
87
|
-
--source <painting> --out work` → copy `bones`, `meshes`, `regions`, `
|
|
88
|
-
from `proposal.json` into the config
|
|
89
|
-
|
|
87
|
+
--source <painting> --out work` → copy `bones`, `meshes`, `regions`, `limbs`,
|
|
88
|
+
`motion`, `constraints`, `turn` from `proposal.json` into the config, each it
|
|
89
|
+
wrote (`limbs` only with `--keypoints`, `constraints` only with `--cloth`, `turn`
|
|
90
|
+
only with `--full`/`--head`; a `limbs` block left out is refused at the next step). `assemble` needs the plan and none of
|
|
91
|
+
those sections; do not stub them to get past it (AUTHORING §4 says what each step
|
|
90
92
|
requires). If an `uncovered hole` stays large with the plan right — a piece
|
|
91
93
|
of the figure neither run holds, red in `recomposite_error_rig.png` — add an
|
|
92
94
|
`assemble.patches` entry (a rig-pixel box, `alpha: "silhouette"`, drawn
|
|
@@ -108,6 +110,18 @@ under that.
|
|
|
108
110
|
again, and read each `limb cap:` line for the pixels a cap is missing. A clean
|
|
109
111
|
LINT does not show a seated hip is right; the overlay does. Never write a joint you did not get from an
|
|
110
112
|
estimator or the painting: say `missing` and let the rule stand in.
|
|
113
|
+
A skirt or hair that must answer the scene (wind, the body moving) rather than
|
|
114
|
+
loop a keyed swing: add a `cloth` block to the config — one recipe per tag,
|
|
115
|
+
`bottomwear`, `back hair`, `front hair`: `chains`, `links`, `wind` and `gravity`
|
|
116
|
+
as `[root, tip]` (multipliers of the consumer's environment, tip >= root), and
|
|
117
|
+
optionally `split`, `strength`, `damping`/`alternate_damping`, `translate`,
|
|
118
|
+
and on the skirt `swing.scales` (AUTHORING §3, *Recipe: cloth and hair*) —
|
|
119
|
+
and propose with `--cloth config.json`; copy its `constraints` too. Every
|
|
120
|
+
number is yours but `length_ratio` and `strength`, whose defaults the note
|
|
121
|
+
names. Weights across neighbouring trees are not drafted (issue #378). No
|
|
122
|
+
stop at the legs is drafted: on the recipe's fixture the environment alone
|
|
123
|
+
pushed no hem through a thigh, but the consumer's hip motion can
|
|
124
|
+
(rig-c/core#1413).
|
|
111
125
|
6. Correct against `render/landmarks.png` and `note:` lines; a
|
|
112
126
|
`coverage … not checked` line is a bone no check read (the line says why),
|
|
113
127
|
and `basis.json` beside the proposal says what each bone rests on — check
|
package/src/build.ts
CHANGED
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
splitSchedule,
|
|
71
71
|
untestedIntervals,
|
|
72
72
|
} from './autoreplay.ts';
|
|
73
|
-
import { besideIdleLine, FOLD_LINE, type FoldsLine, LEVEL_LINE, type LevelLine, LIMB_LINE, type LimbLine, STRESS_LINE, buildGateLines, causeLines, IDLE_FPS, IDLE_MAX_PX, maxRgbDiff, REQUIREMENTS_DIR, type CheckReport, type PackLine, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, JUDGEMENT_LINES, type JudgementLine, packedBuildArgs, packedBuildLabel, type PackMode, type PackShape, type PageEdges, readFrameSet, rigcFailed, rigcIdentity, rigcRanClause, REPORTED_LINES, type ReportedLine, type RigcRunner, runCheck, SEAM_DIR, SEAM_MEAN_BAR, seamPairText, seamRigPxText, SOURCE_LINE, SEAM_PX_BAR, SEAM_PX_LEVEL, SEAM_PX_LEVEL_HIGH, SPINEBOY_YARDSTICK, STILL_DIR } from './check.ts';
|
|
73
|
+
import { besideIdleLine, FOLD_LINE, type FoldsLine, LEVEL_LINE, type LevelLine, LIMB_LINE, type LimbLine, STRESS_LINE, buildGateLines, causeLines, IDLE_FPS, IDLE_MAX_PX, maxRgbDiff, REQUIREMENTS_DIR, type CheckReport, type PackLine, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, GATE_PROFILE, JUDGEMENT_LINES, type JudgementLine, packedBuildArgs, packedBuildLabel, type PackMode, type PackShape, type PageEdges, readFrameSet, rigcFailed, rigcIdentity, rigcRanClause, REPORTED_LINES, type ReportedLine, type RigcRunner, runCheck, SEAM_DIR, SEAM_MEAN_BAR, seamPairText, seamRigPxText, SOURCE_LINE, SEAM_PX_BAR, SEAM_PX_LEVEL, SEAM_PX_LEVEL_HIGH, SPINEBOY_YARDSTICK, STILL_DIR } from './check.ts';
|
|
74
74
|
import { type Cut, type Limb, loadConfig, loadConfigAndAnimations, loadEarlyConfig } from './config.ts';
|
|
75
75
|
import { failLine, PartsError, type Problem, refuseIfAny } from './errors.ts';
|
|
76
76
|
import type { MeshQualityReport, MotionSchedule } from 'rig-c/mesh';
|
|
@@ -365,7 +365,7 @@ function gateRun(label: string, rigc: RigcRunner, args: string[]): GateRun {
|
|
|
365
365
|
* written anywhere, so packing them was work nobody read. No render is asked
|
|
366
366
|
* of rigc by either build.
|
|
367
367
|
*/
|
|
368
|
-
export const REFERENCE_BUILD_ARGS: readonly string[] = ['--profile',
|
|
368
|
+
export const REFERENCE_BUILD_ARGS: readonly string[] = ['--profile', GATE_PROFILE];
|
|
369
369
|
|
|
370
370
|
/** The reference build's label, as the rig stage prints it. */
|
|
371
371
|
export const REFERENCE_BUILD_LABEL = `build ${REFERENCE_BUILD_ARGS.join(' ')}`;
|
package/src/check.ts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*
|
|
31
31
|
* | output | what |
|
|
32
32
|
* | --- | --- |
|
|
33
|
-
* | `build/` | `rigc build --profile
|
|
33
|
+
* | `build/` | `rigc build --profile rig-play --pack --page-edges free --pack-shape polygon` (or `pot`, `rect`, when the caller names them; {@link PAGE_EDGES}, {@link PACK_SHAPES}) — the packed atlas is the final artifact |
|
|
34
34
|
* | `gate_spine-html.txt` | that build's gate lines, verbatim — the one gate: rigc's `build` runs it once over the compile and once over the packed pages on disk, and `spine-html` holds every rule `spine` measures (selftest `CH09`) |
|
|
35
35
|
* | `idle_frames/` | `rigc render --animation idle --fps 12 --max 640 --geometry`: `frames.json` + `idle/f*.png` + `idle/geometry.json` (each mesh's skinned vertices, which `TEXTURE_STRETCH` reads, every attachment's posed triangles, which `TIP_OVER_ROOT` and both halves of `STILL_REGIONS_DARK` read since issues #118 and #123, and every bone's world transform, which the face half reads its head bone from) |
|
|
36
36
|
* | `contact.png` | rigc's own contact sheet of that render, copied out |
|
|
@@ -304,9 +304,17 @@ export interface PackMode {
|
|
|
304
304
|
/** Both defaults, {@link DEFAULT_PAGE_EDGES} and {@link DEFAULT_PACK_SHAPE}. */
|
|
305
305
|
export const DEFAULT_PACK_MODE: PackMode = { pageEdges: DEFAULT_PAGE_EDGES, packShape: DEFAULT_PACK_SHAPE };
|
|
306
306
|
|
|
307
|
+
/**
|
|
308
|
+
* The profile every rigc build this package runs is gated under. rig-c 2.50.0
|
|
309
|
+
* renamed `spine-html` to `rig-play` and runs the same rules under it; the old
|
|
310
|
+
* name is accepted only until a later minor release and prints a deprecation
|
|
311
|
+
* line on stderr (selftest `CK20` holds every stage's build to the new name).
|
|
312
|
+
*/
|
|
313
|
+
export const GATE_PROFILE = 'rig-play';
|
|
314
|
+
|
|
307
315
|
/** The packed build's rigc arguments after `--out <dir>`, as every stage that packs passes them. */
|
|
308
316
|
export function packedBuildArgs(mode: PackMode): string[] {
|
|
309
|
-
return ['--profile',
|
|
317
|
+
return ['--profile', GATE_PROFILE, '--pack', '--page-edges', mode.pageEdges, '--pack-shape', mode.packShape];
|
|
310
318
|
}
|
|
311
319
|
|
|
312
320
|
/** The packed build as a label: the rigc command line that was run, after `rigc`. */
|