rig-parts 1.4.0 → 1.5.1
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 +1 -1
- package/cli.ts +47 -19
- package/docs/AUTHORING.md +88 -15
- package/docs/STABILITY.md +7 -5
- package/package.json +1 -1
- package/src/automotion.ts +119 -8
- package/src/build.ts +74 -13
- package/src/check.ts +122 -26
- package/src/comfy/painting.ts +25 -10
- package/src/config.ts +203 -9
- package/src/graphs.ts +5 -4
- package/src/instruments.ts +6 -0
- package/src/propose.ts +94 -13
- package/src/rig.ts +14 -1
- package/src/scene.ts +94 -14
- package/src/skeleton.ts +22 -8
package/README.md
CHANGED
|
@@ -288,7 +288,7 @@ agent skill.
|
|
|
288
288
|
| `check --rig --out [--parts] [--source] [--requirements]` | build packed, gated under `spine-html`, render the idle, measure seam, loop and the six judgement lines (mesh texture stretch among them, from the idle's `render --geometry`), and report the recomposite's holes from `parts.json`; on a rig spec with no `parts.json` or no `idle` (a merged rig, issue #77) the gate still runs and every line that needs the missing input says SKIP by name; `--source <painting.png>` adds `SETUP_POSE_VS_SOURCE`, the setup pose against the painting by assemble's recomposite figures; `--requirements <scene.json>` measures what a scene declares of the motion — a contact, a follow fraction, an aim, a joint range, a mesh's stretch, the seam between two parts over the motion — each against the author's own bar, from rig-c's posed frames, one line each, PASS, FAIL or NOT MEASURABLE (AUTHORING §7, *Declared requirements*) |
|
|
289
289
|
| `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
|
|
290
290
|
| `build --config --source --full --head --out [--seam] [--project] [--loop] [--requirements] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements` is forwarded to check, `--idle-keys` to rig |
|
|
291
|
-
| `compose --scene <scene.json> --out [--requirements]` | bind several characters' green builds into one rig: every name prefixed `<id>:` under one shared root, each character's offset added at its first-level bones, an optional background plate (its provenance recorded, judged by nothing) drawn first, and the draw order between the characters' slots as the scene file declares it — nothing inferred, nothing scaled; gated through rig-c as `rig` is, then checked ([AUTHORING §7](docs/AUTHORING.md), *Composing several characters*) |
|
|
291
|
+
| `compose --scene <scene.json> --out [--requirements] [--accept]` | bind several characters' green builds into one rig (or, under `--accept`, builds failing only the bars named — for looking, not shipping): every name prefixed `<id>:` under one shared root, each character's offset added at its first-level bones, an optional background plate (its provenance recorded, judged by nothing) drawn first, and the draw order between the characters' slots as the scene file declares it — nothing inferred, nothing scaled; gated through rig-c as `rig` is, then checked ([AUTHORING §7](docs/AUTHORING.md), *Composing several characters*) |
|
|
292
292
|
|
|
293
293
|
`rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
|
|
294
294
|
reason is a FAIL line), 2 a usage error or a command this version does not implement.
|
package/cli.ts
CHANGED
|
@@ -17,16 +17,16 @@ import { tmpdir } from 'node:os';
|
|
|
17
17
|
import { basename, dirname, extname, join } from 'node:path';
|
|
18
18
|
import { DEFAULT_PROJECT_RULE, DEFAULT_SEAM_RULE, HOLES_LISTED, PROJECT_RULES, type ProjectRule, proposeFields, proposePlan, SEAM_RULES, type SeamRule } from './src/assemble.ts';
|
|
19
19
|
import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns, readSource, rigStage } from './src/build.ts';
|
|
20
|
-
import { DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, 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';
|
|
20
|
+
import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, 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 } from './src/config.ts';
|
|
22
|
+
import { type CharacterConfig, loadConfig, loadEarlyConfig, loadPaintConfig } from './src/config.ts';
|
|
23
23
|
import { PartsError, problemLine } from './src/errors.ts';
|
|
24
24
|
import { proposeHeadBox } from './src/headbox.ts';
|
|
25
25
|
import { makeInputs } from './src/inputs.ts';
|
|
26
26
|
import { idleKeysOf, isIdleKeys } from './src/rig.ts';
|
|
27
27
|
import { figuresPhrase, implausibleRules, layerFigures, type LayerSet, pct, readLayers, ruleSummary, times } from './src/layers.ts';
|
|
28
28
|
import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJoints, toRigJoints } from './src/keypoints.ts';
|
|
29
|
-
import { basisLines, checkProposal, compare, compareLines, drawLandmarks, HIP_MIN_FRACTION, lint, lintLine, type PartSet, proposeWithBasis, readPartSet, serializeProposal } from './src/propose.ts';
|
|
29
|
+
import { basisLines, checkProposal, compare, compareLines, drawLandmarks, HIP_MIN_FRACTION, lint, lintLine, type PartSet, proposeWithBasis, readPartSet, serializeProposal, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
30
30
|
import { BASIS_FILE, BASIS_SPEC, basisFile, basisLine, coverageLines, serializeBasis } from './src/diagnostics.ts';
|
|
31
31
|
import { readPng, writePng } from './src/raster/png.ts';
|
|
32
32
|
import { REQUIREMENTS_SENTENCE } from './src/requirements.ts';
|
|
@@ -108,7 +108,7 @@ usage:
|
|
|
108
108
|
bone differs (origin, tip, parent; how far, in px). No confidence is
|
|
109
109
|
computed. It prints "wrote ${BASIS_FILE} (…)" after the coverage lines.
|
|
110
110
|
|
|
111
|
-
rig-parts propose … [--keypoints <keypoints.json> [--person <id>]]
|
|
111
|
+
rig-parts propose … [--keypoints <keypoints.json> [--person <id>] [--wrist-snap <px>]]
|
|
112
112
|
Read the figure's pose from one explicit file (spec "${KEYPOINTS_SPEC}"):
|
|
113
113
|
its space (painting-px, origin top-left, y down — another is refused),
|
|
114
114
|
the image's width and height (held to --source's, KEYPOINTS_IMAGE_SIZE),
|
|
@@ -124,7 +124,11 @@ usage:
|
|
|
124
124
|
the rule. One note per joint says which. LINT then reads the torso along
|
|
125
125
|
the neck -> hips line and each sleeve chain along shoulder -> wrist
|
|
126
126
|
instead of by screen y, and prints the rule set it used first. Without
|
|
127
|
-
--keypoints nothing changes.
|
|
127
|
+
--keypoints nothing changes. A wrist holds a part when it lies within
|
|
128
|
+
${WRIST_ON_PART_PX} px of its art (the larger of the x and y gaps);
|
|
129
|
+
--wrist-snap <px>, an integer above ${WRIST_ON_PART_PX}, binds a wrist on no
|
|
130
|
+
part to the one nearest part within <px>, said in a "wrist snap:" note
|
|
131
|
+
(with --keypoints, not with --from-config). Without it nothing changes.
|
|
128
132
|
|
|
129
133
|
rig-parts propose --parts <dir> --source <painting.png> --out <dir> --from-config <config.json>
|
|
130
134
|
Draw the config's CURRENT bones instead (<out>/render/landmarks_config.png
|
|
@@ -205,7 +209,7 @@ usage:
|
|
|
205
209
|
rounding, and so is the per-frame mesh work (AUTHORING §5).
|
|
206
210
|
rig-parts check --rig <dir> --out <dir> [--parts <dir>] [--source <painting.png>]
|
|
207
211
|
[--page-edges pot|free] [--pack-shape rect|polygon]
|
|
208
|
-
[--requirements <file.json>] [--seam-pairs]
|
|
212
|
+
[--requirements <file.json>] [--seam-pairs] [--keep-stills]
|
|
209
213
|
Build, gate, render and measure a rig through rig-c's CLI (the rigc at
|
|
210
214
|
node_modules/.bin/rigc, or on PATH). --rig holds rig.json and motion.json:
|
|
211
215
|
a rig spec, which rigc build compiles, not a compiled skeleton.json.
|
|
@@ -226,7 +230,9 @@ usage:
|
|
|
226
230
|
--seam-pairs, is split by the pair of parts each counted pixel lies
|
|
227
231
|
between: one "seam pair" line each, worst first, with its count, frame
|
|
228
232
|
and rig boxes and a picture under seam/, and check.json's seam_pairs
|
|
229
|
-
(AUTHORING §7).
|
|
233
|
+
(AUTHORING §7). --keep-stills leaves the setup-pose still the seam reads,
|
|
234
|
+
rigc's render directory with its frames.json (viewport and background),
|
|
235
|
+
under setup_still/. Then six judgement lines, each in
|
|
230
236
|
check.json and on the console as NAME: PASS|FAIL|SKIP with its figures and
|
|
231
237
|
bars (AUTHORING §7): BREATH_VISIBLE (the topwear moves, the footwear does
|
|
232
238
|
not, each rendered alone), BLINK_NO_HOLE (the setup pose with the blink
|
|
@@ -425,7 +431,7 @@ usage:
|
|
|
425
431
|
rigc refuses the pair a control splits, and the RIG_RIGC_GREEN line
|
|
426
432
|
names the flag on the command that ran.
|
|
427
433
|
|
|
428
|
-
rig-parts compose --scene <scene.json> --out <dir> [--requirements <file.json>]
|
|
434
|
+
rig-parts compose --scene <scene.json> --out <dir> [--requirements <file.json>] [--accept <bar>[,<bar>...]]
|
|
429
435
|
Bind several finished characters into one rig. The scene file (spec
|
|
430
436
|
"${SCENE_SPEC}") states the canvas {width, height}, an optional plate
|
|
431
437
|
{image, provenance: ${PROVENANCES.join(' | ')}, note?}, the characters
|
|
@@ -470,8 +476,14 @@ usage:
|
|
|
470
476
|
TIP_OVER_ROOT, STILL_REGIONS_DARK and RECOMPOSITE_HOLES say SKIP and
|
|
471
477
|
why), --requirements forwarded. Nothing is inferred: not the order, not
|
|
472
478
|
an overlap, not a scale, not a person; the plate's provenance and the
|
|
473
|
-
order are the author's and judged by nothing.
|
|
474
|
-
|
|
479
|
+
order are the author's and judged by nothing. --accept (or a
|
|
480
|
+
character's "accept": [...] in the scene file; the two lists are
|
|
481
|
+
joined, the command line's applying to every character) takes a build
|
|
482
|
+
whose own check failed only the bars named — ${ACCEPTABLE_BARS.join(', ')};
|
|
483
|
+
the gate, a declared requirement and an unknown name are refused
|
|
484
|
+
(SCENE_ACCEPT_KNOWN). It is for looking, not shipping: the [compose]
|
|
485
|
+
line and ${SCENE_REPORT_FILE} name what was accepted, and the run exits 1.
|
|
486
|
+
Exit 0 when the check is PASS and nothing was accepted, 1 otherwise.
|
|
475
487
|
|
|
476
488
|
rig-parts --version
|
|
477
489
|
rig-parts --help
|
|
@@ -697,11 +709,13 @@ function flags(args: string[], known: readonly string[], command: string, option
|
|
|
697
709
|
}
|
|
698
710
|
|
|
699
711
|
function cmdCheck(args: string[]): number {
|
|
700
|
-
// The
|
|
712
|
+
// The two switches check takes (issues #202, #209): they carry no value, so they are taken out before the valued flags are read.
|
|
701
713
|
const seamPairs = args.filter((a) => a === '--seam-pairs').length;
|
|
702
714
|
if (seamPairs > 1) return usage('--seam-pairs is given twice');
|
|
715
|
+
const keepStills = args.filter((a) => a === '--keep-stills').length;
|
|
716
|
+
if (keepStills > 1) return usage('--keep-stills is given twice');
|
|
703
717
|
const f = flags(
|
|
704
|
-
args.filter((a) => a !== '--seam-pairs'),
|
|
718
|
+
args.filter((a) => a !== '--seam-pairs' && a !== '--keep-stills'),
|
|
705
719
|
['--rig', '--out'],
|
|
706
720
|
'check',
|
|
707
721
|
['--parts', '--source', '--page-edges', '--pack-shape', '--requirements'],
|
|
@@ -716,7 +730,7 @@ function cmdCheck(args: string[]): number {
|
|
|
716
730
|
try {
|
|
717
731
|
const bin = findRigc(import.meta.dir, process.env.PATH ?? '');
|
|
718
732
|
const r = checkStage(
|
|
719
|
-
{ rig, parts: f.get('--parts'), source: f.get('--source'), out, pageEdges: edges, packShape: shape, requirements: f.get('--requirements'), seamPairs: seamPairs === 1 },
|
|
733
|
+
{ rig, parts: f.get('--parts'), source: f.get('--source'), out, pageEdges: edges, packShape: shape, requirements: f.get('--requirements'), seamPairs: seamPairs === 1, keepStills: keepStills === 1 },
|
|
720
734
|
rigcRunner(bin),
|
|
721
735
|
bin,
|
|
722
736
|
console.log,
|
|
@@ -754,7 +768,7 @@ function printLint(P: PartSet, spec: { bones: CharacterConfig['bones']; meshes:
|
|
|
754
768
|
function cmdPropose(args: string[]): number {
|
|
755
769
|
const flags = new Map<string, string>();
|
|
756
770
|
let headBox = false;
|
|
757
|
-
const valued = ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--canvas', '--keypoints', '--person'];
|
|
771
|
+
const valued = ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--canvas', '--keypoints', '--person', '--wrist-snap'];
|
|
758
772
|
for (let i = 0; i < args.length; i++) {
|
|
759
773
|
const flag = args[i];
|
|
760
774
|
if (flag === '--head-box') {
|
|
@@ -797,6 +811,18 @@ function cmdPropose(args: string[]): number {
|
|
|
797
811
|
if (out === undefined) return usage('propose needs --out <dir>');
|
|
798
812
|
if (flags.has('--from-config') && flags.has('--compare')) return usage('--from-config and --compare are two modes; give one');
|
|
799
813
|
if (flags.has('--person') && !flags.has('--keypoints')) return usage('--person names a person in the --keypoints file; give --keypoints <file>');
|
|
814
|
+
// Issue #199: a declared tolerance for a wrist on no handwear part. Whole px above the built-in one: the distance is
|
|
815
|
+
// counted in whole px, so a fraction would bind what its floor binds, and a value at or under the built-in binds nothing.
|
|
816
|
+
const snapArg = flags.get('--wrist-snap');
|
|
817
|
+
let wristSnap: number | null = null;
|
|
818
|
+
if (snapArg !== undefined) {
|
|
819
|
+
if (!flags.has('--keypoints')) return usage('--wrist-snap binds a wrist joint to a handwear part; give --keypoints <file>');
|
|
820
|
+
if (flags.has('--from-config')) return usage('--wrist-snap binds a wrist while proposing; --from-config proposes nothing');
|
|
821
|
+
if (!/^[0-9]+$/.test(snapArg) || Number(snapArg) <= WRIST_ON_PART_PX) {
|
|
822
|
+
return usage(`--wrist-snap ${snapArg} is not an integer above ${WRIST_ON_PART_PX}, the px within which a wrist already holds a part`);
|
|
823
|
+
}
|
|
824
|
+
wristSnap = Number(snapArg);
|
|
825
|
+
}
|
|
800
826
|
const partsDir = existsSync(partsArg) && statSync(partsArg).isFile() ? dirname(partsArg) : partsArg;
|
|
801
827
|
if (!existsSync(source)) {
|
|
802
828
|
throw new PartsError([{ code: 'PROPOSE_SOURCE_PRESENT', object: source, detail: 'no such file; the painting is drawn under the overlay' }]);
|
|
@@ -824,7 +850,7 @@ function cmdPropose(args: string[]): number {
|
|
|
824
850
|
}
|
|
825
851
|
const cmpPath = flags.get('--compare');
|
|
826
852
|
const cfg = cmpPath === undefined ? null : loadConfig(cmpPath);
|
|
827
|
-
const { proposal: prop, basis } = proposeWithBasis(P, joints);
|
|
853
|
+
const { proposal: prop, basis } = proposeWithBasis(P, joints, wristSnap);
|
|
828
854
|
// Emit only after green: a proposal the config loader would refuse is not written, nor a basis record that does not hold to it.
|
|
829
855
|
checkProposal(P, prop);
|
|
830
856
|
const bfile = basisFile(P, prop, basis, cfg === null || cmpPath === undefined ? null : { where: cmpPath, config: cfg });
|
|
@@ -1000,7 +1026,8 @@ async function cmdComfy(args: string[]): Promise<number> {
|
|
|
1000
1026
|
try {
|
|
1001
1027
|
// The config is a local file, so it is answered before any host is: a
|
|
1002
1028
|
// config comfy paint cannot paint from is refused with no box named.
|
|
1003
|
-
const
|
|
1029
|
+
const paint = sub === 'paint' ? loadPaintConfig(configPath as string) : null;
|
|
1030
|
+
const cfg = paint === null ? null : paint.config;
|
|
1004
1031
|
const host = resolveHost(v.get('--host'), process.env.COMFY_HOST);
|
|
1005
1032
|
const client = new ComfyClient(host, { poll: poll as number, request: 30 });
|
|
1006
1033
|
if (sub === 'seethrough') {
|
|
@@ -1039,7 +1066,7 @@ async function cmdComfy(args: string[]): Promise<number> {
|
|
|
1039
1066
|
if (typeof seed0 === 'string') return usage(seed0);
|
|
1040
1067
|
console.log(`rig-parts comfy paint: ${cfg.key} -> ${out}`);
|
|
1041
1068
|
console.log(` ${seeds} seed(s) from ${seed0}${v.has('--seed0') ? '' : ' (generation.seed)'}; wait <= ${wait} s per seed, timeout ${timeout} s`);
|
|
1042
|
-
const done = await runPainting(client, { config: cfg, out, seeds, seed0, wait: wait as number, timeout: timeout as number }, (l) => console.log(l));
|
|
1069
|
+
const done = await runPainting(client, { config: cfg, pose: paint === null ? null : paint.pose, out, seeds, seed0, wait: wait as number, timeout: timeout as number }, (l) => console.log(l));
|
|
1043
1070
|
console.log(` wrote ${done.length} painting(s): ${done.map((d) => `${d.file} ${d.size[0]}x${d.size[1]} in ${d.elapsed.toFixed(1)} s`).join(', ')}; GPU job(s) ended`);
|
|
1044
1071
|
return EXIT_OK;
|
|
1045
1072
|
} catch (err) {
|
|
@@ -1127,7 +1154,7 @@ function cmdBuild(args: string[]): number {
|
|
|
1127
1154
|
}
|
|
1128
1155
|
|
|
1129
1156
|
function cmdCompose(args: string[]): number {
|
|
1130
|
-
const f = flags(args, ['--scene', '--out'], 'compose', ['--requirements']);
|
|
1157
|
+
const f = flags(args, ['--scene', '--out'], 'compose', ['--requirements', '--accept']);
|
|
1131
1158
|
if (typeof f === 'string') return usage(f);
|
|
1132
1159
|
let bin: string;
|
|
1133
1160
|
try {
|
|
@@ -1138,8 +1165,9 @@ function cmdCompose(args: string[]): number {
|
|
|
1138
1165
|
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-compose-'));
|
|
1139
1166
|
try {
|
|
1140
1167
|
const req = f.get('--requirements');
|
|
1168
|
+
const accept = f.get('--accept');
|
|
1141
1169
|
const r = composeStage(
|
|
1142
|
-
{ scene: f.get('--scene') as string, out: f.get('--out') as string, ...(req === undefined ? {} : { requirements: req }) },
|
|
1170
|
+
{ scene: f.get('--scene') as string, out: f.get('--out') as string, ...(req === undefined ? {} : { requirements: req }), ...(accept === undefined ? {} : { accept: accept.split(',') }) },
|
|
1143
1171
|
{ rig: rigcRunner(bin), check: rigcRunner(bin), checkBin: bin, scratch: join(scratch, 'gate') },
|
|
1144
1172
|
console.log,
|
|
1145
1173
|
);
|
package/docs/AUTHORING.md
CHANGED
|
@@ -75,6 +75,7 @@ read by no CPU stage).
|
|
|
75
75
|
| --- | --- | --- |
|
|
76
76
|
| `key` | every stage's report | authored; the examples use the directory name |
|
|
77
77
|
| `generation.*` | the optional `comfy` adapter only; no CPU stage | recorded: checkpoint, LoRAs, sampler, prompt parts, `latent`, `seed`, `control` |
|
|
78
|
+
| `generation.control.skeleton` | `comfy paint` — the OpenPose control image, drawn at `latent` | **authored**: a built-in standing pose, `"stand_sides"` or `"stand_clasp"`, or (issue #198) any other string, read as a path relative to the config file's directory to a pose file `{"width": W, "height": H, "points": {"nose": [x, y], "neck": [x, y], …}}` — `width` x `height` is the canvas and must be `generation.latent` (the points are not scaled; `CONFIG_POSE_CANVAS`), and `points` holds the 18 body-18 keypoints of `src/skeleton.ts` by name (`nose`, `neck`, `r_shoulder`, `r_elbow`, `r_wrist`, `l_shoulder`, `l_elbow`, `l_wrist`, `r_hip`, `r_knee`, `r_ankle`, `l_hip`, `l_knee`, `l_ankle`, `r_eye`, `l_eye`, `r_ear`, `l_ear`; `r`/`l` the subject's sides), each `[x, y]` in canvas px, x right, y down, `0 <= x <= W`, `0 <= y <= H`. The image is drawn from the file exactly as from a built-in (same renderer, same size), written as `control_pose-<first 12 hex of its sha256>.png`. A pose file carries no words, so `generation.pose` is required beside it (`CONFIG_FIELD_PRESENT`). The file is read wherever the config is read from a path, every problem at once: no such file — a misspelt built-in lands here too — or one that cannot be read (`CONFIG_FILE_PRESENT`), not JSON (`CONFIG_IS_JSON`), not an object, a size that is not a whole positive px count, a point that is not two numbers (`CONFIG_FIELD_TYPE`), a key besides the three (`CONFIG_KEY_KNOWN`) or written twice (`CONFIG_KEY_UNIQUE`), `points` holding other than the 18 names (`CONFIG_POSE_KEYPOINTS`, with the count found and required), a point off the canvas (`CONFIG_POSE_IN_CANVAS`, naming the point and the canvas size) |
|
|
78
79
|
| `seethrough.resolution` | assemble — each run's canvas must be `resolution` square (`ASSEMBLE_RUN_CANVAS`) | recorded from the See-through runs; 1024 in both examples |
|
|
79
80
|
| `seethrough.steps`, `.seed`, `.offload` | no CPU stage | recorded from the runs |
|
|
80
81
|
| `seethrough.head_box` | inputs (cuts the head image there; optional at the first call); assemble — where the head run sits on the painting | **proposed** by `propose --head-box` from the full run, square, source pixels, shifted inside the painting when needed; the head run must then be fed exactly that crop |
|
|
@@ -86,7 +87,7 @@ read by no CPU stage).
|
|
|
86
87
|
| `bones` | rig; `propose --from-config` | **proposed** by `propose`, then corrected. A single bone `{name, parent, at, tip?}` or a chain `{chain, parent, points, tip}` whose links are named `<chain>0 … <chain>n`. Parents come before children. In `rig.json` each link is **turned along its chain** — `rotation` is the direction from its origin to the next link's (the last link's to `tip`) and `length` that distance (issue #73), so a physics constraint added downstream finds a lever; under `--idle-keys ctl` the link's `<link>_ctl` carries the turn and the length and the link sits at local rotation 0 beneath it. A single bone is never turned; one whose parent is a link is turned back upright |
|
|
87
88
|
| `meshes.<part>` | rig | **proposed**, then corrected. Exactly one of `grid` (the lattice: cell size, px — what `propose` writes), `contour` (the outline mode, authored; the next row and "A contour mesh" below) or `auto` (the automatic mode, authored; "An automatic mesh" below) — two, or none, is `CONFIG_MESH_MODE`. In every mode: `r` (added to every distance before weighting: `w = 1/(d + r)²`), `segments` (a chain name, a bone name with a `tip`, or `[bone, [x0,y0], [x1,y1]]`), and, **authored**, optional, `exponent` (issue #161): a number above 0 that replaces the 2 in that rule, `w = 1/(d + r)^exponent` — a larger one hands each vertex more fully to its nearest bone; absent is 2 and changes no byte, a value that is not a number above 0 is `CONFIG_FIELD_TYPE` at `meshes.<part>.exponent`, and a declared one is echoed as `exponent` in the mesh's `mesh_report.json` row; the exponent is the distance rule's, so declared beside `rule: "heat"` it is refused (`CONFIG_FIELD_TYPE` at `meshes.<part>.exponent`). The segment list is the one authored decision about a layer: which bones may pull it. The slot's bone is the first segment's. Optional `rule` (issue #161): `"distance"` — the rule above, and what an absent `rule` means (every byte is the same) — or `"heat"`, bone heat over the part's own silhouette, in every mode: the lattice's art (alpha above 8) with holes filled, or for `contour` and `auto` the silhouette their outline is traced from (that mode's art — alpha above 8 for `contour`, alpha 1 and above for `auto` — less any island a declared `stray` left out, holes filled, grown by its `margin`); each bound bone's sources are the silhouette pixels whose centre lies within 0.75 px of its segment (a pixel two bones reach goes to the nearer, a tie to the first listed), held at 1 for that bone and 0 for the others; the field is solved by row-major Gauss–Seidel over-relaxation to a sweep change under 1e-7 within 20000 sweeps; a vertex reads the nearest silhouette pixel and takes the same cap and floor (and `regions`) as the distance rule; `r` is not read. The mesh's `mesh_report.json` row gains `heat` (the constants, each bone's sources and sweeps, the residual). Any other value is `CONFIG_FIELD_TYPE`; a bound bone with no source pixel is `RIG_HEAT_BONE_SOURCE`, an island no bone has a source in `RIG_HEAT_ISLAND_SOURCE`, a solve past its sweep bound `RIG_HEAT_CONVERGED` — none is weighted 0 |
|
|
88
89
|
| `meshes.<part>.contour` | rig | **authored**, optional (issue #84): `{tolerance, margin, spacing, budget?, stray?, regions?}`. `tolerance` — rig-c's Douglas–Peucker tolerance on the traced outline, px, 0 or more; `margin` — how far the silhouette grows before it is traced, px: 0, or 1 or more (a pixel joins when its centre lies within `margin` of an art pixel's centre; a value above 0 and below 1 adds nothing and is refused, `CONFIG_FIELD_TYPE`); `spacing` — the background interior spacing, px, above 0; `budget` — the most vertices the mesh may have (refused above it, nothing thinned); `stray` — the largest island, in art pixels, that may be left out of the mesh (absent: none is); `regions` — local deformation regions, each `{name, shape, bone, spacing, band}` with `shape` `"circle"` (`cx, cy, r`) or `"polygon"` (`points`, 3 or more): `bone` is the region's control bone (any bone `bones` declares), `spacing` the interior spacing inside the region and its band, `band` the width the bone's weight falls across. Every length and position is **rig px**, like every other in the config; the part image is the rig less `(x − 4, y − 4)` (its box less the pad), a translation, so a length is the same number in both. A region's `cx`, `cy`, `r`, `band` and `points` are multiples of 1/256 px (`CONFIG_FIELD_TYPE` otherwise); region names are unique per mesh (`CONFIG_REGION_NAME_UNIQUE`). The alpha threshold is not a field: art is alpha above 8, the lattice's and `check`'s |
|
|
89
|
-
| `meshes.<part>.ribs` | rig | **authored**, optional (issue #188), in the `contour` and `auto` modes: `{<chain>: {stations}, …}`, each key a chain this mesh's `segments` name. Each link of the chain gets a row of vertices across the part at its origin and at `stations` points evenly between its origin and its end (`stations`, a whole number, 0 or more, required; a chain of L links carries L × (stations + 1) ribs)
|
|
90
|
+
| `meshes.<part>.ribs` | rig | **authored**, optional (issue #188), in the `contour` and `auto` modes: `{<chain>: {stations}, …}`, each key a chain this mesh's `segments` name. Each link of the chain gets a row of vertices across the part at its origin and at `stations` points evenly between its origin and its end (`stations`, a whole number, 0 or more, required; a chain of L links carries L × (stations + 1) ribs), each rib a row of vertices across the part, kept as a row of locked edges; the rule is "Ribs along a chain" under "A contour mesh". Absent places none and changes no byte. Refused: a lattice mesh with ribs (`CONFIG_RIBS_MODE` — its vertices are its grid's corners), a key that is not one of the mesh's chains (`CONFIG_NAME_RESOLVES`), an object naming no chain or a `stations` that is not a whole number from 0 (`CONFIG_FIELD_TYPE`); at the rig stage `CONTOUR_RIB_ART`, `CONTOUR_RIB_LINK`, `CONTOUR_RIB_CROSSING`, `CONTOUR_RIB_EDGE` (the contour refusals). The mesh's `mesh_report.json` row gains `ribs` — the declaration, the ribs placed and the vertices they hold — and its contour report (the source's, in `auto`) lists each rib's vertices |
|
|
90
91
|
| `regions.<part>` | rig | **proposed**: the bone a rigid part rides. Every plan part is exactly one of a mesh or a region (`CONFIG_PART_ATTACHED`) |
|
|
91
92
|
| `motion.duration` | rig; check (the loop is measured at this time) | proposed as 4 s; a whole number of 1/12 s ticks, because `check` renders at 12 fps |
|
|
92
93
|
| `motion.tracks` | rig | **proposed**, then tuned. Single `{bone, prop, amp, period, phase, base?}` or chain `{chain, amps, period, phase, lag}` — one amplitude per link, link `i` at phase `phase + lag·i`. Every `period` must divide `duration` (`CONFIG_PERIOD_DIVIDES_DURATION`). A bone property is keyed by one track (`CONFIG_BONE_PROPERTY_KEYED_ONCE`): a chain keys `rotate` on every link, the blink's `eyes` group `scaley` and its `brows` group `translatey` on every member, so a single track on any of those is a second track on it — rigc would refuse it one stage later, `animation "idle" has two tracks on eye.scaley`. A chain link is turned along its chain (the `bones` row), so a `translatex`/`translatey` key on a bone whose parent is a turned link, or a `scale`/`shear` key on a turned link, would move or stretch along the link and not along the picture's axis: the rig stage refuses it (`RIG_KEY_FRAME_UNTURNED`); `rotate` is keyed on any bone |
|
|
@@ -151,7 +152,11 @@ swing, hair of another shape, whether an accessory swings — is yours to add, a
|
|
|
151
152
|
**A posed figure: `propose --keypoints`.** The proposer's ratios assume a
|
|
152
153
|
standing figure: the hip below the chest, sleeves hanging from the shoulders. A
|
|
153
154
|
seated, reclining or otherwise posed figure is told where its joints are with one
|
|
154
|
-
explicit file (issue #75, `src/keypoints.ts`)
|
|
155
|
+
explicit file (issue #75, `src/keypoints.ts`). A pose file named by
|
|
156
|
+
`generation.control.skeleton` is not that file and is not offered as its default:
|
|
157
|
+
the control skeleton is what was asked of the model, not where the joints ended up
|
|
158
|
+
(a consumer measured a generated picture not following the control's raised hand),
|
|
159
|
+
so `keypoints.json` is read off the generated picture:
|
|
155
160
|
|
|
156
161
|
```json
|
|
157
162
|
{
|
|
@@ -186,9 +191,37 @@ What a joint with a position places, as given — no ratio is applied over it:
|
|
|
186
191
|
| `neck` | `neck` | the rule: half way from the chin to the neck part's bottom (or 0.12 face heights below the chin), on the eye axis |
|
|
187
192
|
| `hip` | the midpoint of `r_hip` and `l_hip` — a point between two joints, said as that | the hip rule (bottomwear top, the waist, or 0.32 of the figure); one hip alone is said to be unused |
|
|
188
193
|
| `chest` | its rule, half way from neck to hip, taken along the line between the placed ends | the rule as before when neither end is a joint |
|
|
189
|
-
| `sleeve_<s>` | `<s>_shoulder` → `<s>_elbow` (two links), tip at `<s>_wrist`, with the two-blob rule's first two amplitudes and its chest stub laid along the upper arm — when every handwear part over 500 px holds one such wrist within 15 px of its art | the sleeve rule places every sleeve chain, and each arm joint's note says why |
|
|
194
|
+
| `sleeve_<s>` | `<s>_shoulder` → `<s>_elbow` (two links), tip at `<s>_wrist`, with the two-blob rule's first two amplitudes and its chest stub laid along the upper arm — when every handwear part over 500 px holds one such wrist within 15 px of its art (the larger of the x and y gaps, the LINT's own tolerance), or is bound one by `--wrist-snap` (below) | the sleeve rule places every sleeve chain, and each arm joint's note says why: for a wrist on no part, `… lies on the art of no handwear part within 15 px, so it does not say which sleeve it ends; the nearest is <part>, <d> px from its art by the larger of the x and y gaps (--wrist-snap <d> would bind it)` — `(beyond --wrist-snap <px>)` when the flag was given and fell short, and `the nearest are <a> and <b>, each <d> px …, so no tolerance says which` when two parts tie |
|
|
190
195
|
| `eye_<s>`, `head`, the face box | not moved: they are measured off the parts | the note prints the eye joint's distance from the eye bone, with no bar |
|
|
191
196
|
|
|
197
|
+
**`--wrist-snap <px>`** (issue #199), with `--keypoints` only, declares a tolerance
|
|
198
|
+
for a wrist that lies on no handwear part within the built-in 15 px — hands folded
|
|
199
|
+
together, or a sleeve painted over the hand. `<px>` is an integer above 15 (the
|
|
200
|
+
distance is counted in whole px, so a fraction would bind exactly what its floor
|
|
201
|
+
binds, and 15 or less binds nothing the built-in does not); anything else is refused
|
|
202
|
+
as a usage error naming the value, as is the flag without `--keypoints` or with
|
|
203
|
+
`--from-config`, which proposes nothing. Such a wrist is measured to every handwear
|
|
204
|
+
part's art by the larger of the x and y gaps — the measure of the built-in 15 px —
|
|
205
|
+
and bound to the one nearest part when it is at most `<px>` away; two parts tied
|
|
206
|
+
nearest bind neither. A bound wrist's joint lines say `(the wrist is bound to <part>
|
|
207
|
+
by --wrist-snap)`, and a note says which wrist went to which part and how far:
|
|
208
|
+
|
|
209
|
+
wrist snap: r_wrist at [x, y] lies on no handwear part within 15 px; --wrist-snap <px> bound it to <part>, the nearest, <d> px from its art by the larger of the x and y gaps
|
|
210
|
+
|
|
211
|
+
A wrist already on a part is not moved by the flag, and without the flag nothing
|
|
212
|
+
changes, byte for byte. Choosing the tolerance automatically is not done: the note
|
|
213
|
+
for an unbound wrist prints the distance that would have bound it.
|
|
214
|
+
|
|
215
|
+
**One handwear part holding both wrists** — two sleeves and the hands decomposed as
|
|
216
|
+
one piece, not clasped at the midline — gets both sleeve chains on its one mesh, as
|
|
217
|
+
before, and a note says so rather than leaving two chains to share the part
|
|
218
|
+
silently:
|
|
219
|
+
|
|
220
|
+
one handwear part holds both wrists: r_wrist and l_wrist both end on <part>, so chains sleeve_r and sleeve_l share its mesh and its art bends with both arms; to separate them, cut one sleeve out of <part> with an assemble.cuts entry (a polygon round it) and propose again
|
|
221
|
+
|
|
222
|
+
The `assemble.cuts` entry (§3; §5, *Cutting a piece out of a layer*) splits the part; the
|
|
223
|
+
proposer does not.
|
|
224
|
+
|
|
192
225
|
Every other joint (`nose`, knees, ankles, ears; the eyes with no eyewhite) is named
|
|
193
226
|
with its state in one note: no bone is authored from it. Every joint the proposer
|
|
194
227
|
could use gets its own note — `used as given for bone X`, `used as the producer's
|
|
@@ -371,11 +404,10 @@ contour refusal in a run is listed together; nothing falls back to the lattice:
|
|
|
371
404
|
| `CONTOUR_RIB_CROSSING` | two ribs cross, touch or share an end (both named, with their ends) | fewer `stations`, or a chain that bends less sharply inside a wide part |
|
|
372
405
|
| `CONTOUR_RIB_EDGE` | a rib's consecutive vertices could not be joined by an edge (no edge across them could be flipped) — a guard: the rule keeps every other point off a rib | report it |
|
|
373
406
|
|
|
374
|
-
**Ribs along a chain** (`meshes.<part>.ribs`, issue #188). A
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
(`placeRibs`) places, in part-image px:
|
|
407
|
+
**Ribs along a chain** (`meshes.<part>.ribs`, issue #188). A rib is a row of vertices across
|
|
408
|
+
the part at a joint of a chain the mesh is bound to, or at a station along one of its links;
|
|
409
|
+
what a rib does to how the part deforms is not claimed. For each chain `ribs` names,
|
|
410
|
+
`src/contour.ts` (`placeRibs`) places, in part-image px:
|
|
379
411
|
|
|
380
412
|
- **where**: on each link k (from `points[k]` to `points[k + 1]`, the last to the tip) a rib at
|
|
381
413
|
its origin and at `points[k] + m/(stations + 1) · (end − origin)`, m = 1..`stations`; the tip
|
|
@@ -525,7 +557,11 @@ unreduced source on the rig's idle and passes the author's bounds (step 4). The
|
|
|
525
557
|
moves some of the bones the part is weighted to and not all of them (a key on their shared
|
|
526
558
|
ancestor, or on the one bone a single-bone part binds, moves every vertex by one affine map and
|
|
527
559
|
would read 0 over nothing). Constraints are not read for this: a part only a constraint moves
|
|
528
|
-
is refused, never passed
|
|
560
|
+
is refused, never passed — unless its author declares the motion, `stimulus` (issue #196,
|
|
561
|
+
the field table below and *A part only physics moves* after the physics recipe): each
|
|
562
|
+
declared bend is two more frames, every link of the chain turned by +`degrees` and by
|
|
563
|
+
−`degrees`, walked in both builds at time 0 beside the idle's, and its links count as keys
|
|
564
|
+
by the rule above.
|
|
529
565
|
5. **The acceptance loop** (rig-c 2.24.0, rigc#1266 mechanism 2; `src/autoreplay.ts`) — only
|
|
530
566
|
when step 4 refuses the full reduction on motion (`AUTO_MESH_MOTION`). rig-c reports every
|
|
531
567
|
accepted **operation** of the call (`acceptedAt`: N entries `{ step, kind, count,
|
|
@@ -676,6 +712,7 @@ wall time goes to standard error, not into the table).
|
|
|
676
712
|
| `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) |
|
|
677
713
|
| `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) |
|
|
678
714
|
| `removalOrder` | optional, `"deformation-load"`: the single removals are tried in ascending predicted load instead of ascending source index (below) |
|
|
715
|
+
| `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 spine-html` 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 |
|
|
679
716
|
|
|
680
717
|
**A bound declared absent.** `maxOvershoot` and `maxUndercut`, in `sourceBounds` and in
|
|
681
718
|
`targets.artFit`, each take a number of px 0 or more or `null`. `null` means *measured and
|
|
@@ -868,7 +905,7 @@ safe is the author's to choose here.
|
|
|
868
905
|
| `AUTO_MESH_INPUT` | rig-c refused the call's input by throwing (a protected vertex the source does not have), in its words and code |
|
|
869
906
|
| `AUTO_MESH_TERMINATION` | rig-c returned no mesh: `invalid-input` (the source fails its own `sourceBounds`, a region it refuses, protected influences over the cap), `unsupported-topology`, or `budget-exhausted` with `none-met-the-targets`; or, in the acceptance loop, a replay that does not end as rig-c's contract promises (`replayed-to-accepted-step` at the step asked, `candidatesTried` the full run's `acceptedAt[n − 1].step`, its `acceptedAt` the full run's first n operations, each the same `step`, `kind`, `count` and `sourceVertices`) |
|
|
870
907
|
| `AUTO_MESH_ACCEPTED` | rig-c returned a mesh that is not accepted; the detail names every declared row not passing and the constraint that stopped it |
|
|
871
|
-
| `AUTO_MESH_NO_STIMULUS` | the idle
|
|
908
|
+
| `AUTO_MESH_NO_STIMULUS` | neither the idle nor a declared `stimulus` moves some of the part's bound bones against the others, so no frame deforms it — the detail names the bones with no motion against each other and the field to declare; missing stimulus is not a pass; declare `meshes.<part>.auto.stimulus`, put the part in `contour` or `grid` mode, or key a bone it binds |
|
|
872
909
|
| `AUTO_MESH_MOTION` | the reduced mesh against its source on the idle is not accepted and the acceptance loop wrote no step in its place: "no reduction passes the motion bound" (the full result's failing rows and every probe named; under `motion.selection`, "… among the tested candidates", with `maxProbes` and the termination), or the chosen step passes on the grid frames and not on the whole idle (its selection and held-out values and worst frames named); when the source itself is not accepted against itself, the full result's rows as before |
|
|
873
910
|
| `AUTO_MESH_SELECTION_BUDGET` | `motion.selection.maxProbes` is below ⌈log₂(N − I)⌉, the bisection the multi-interval search runs whole first; N, I and the number required named; nothing replayed |
|
|
874
911
|
| `AUTO_MESH_SELECTION_ROLES` | a multi-interval choice whose probes read a frame the final comparison holds out, or one it does not declare `selection`; the frames named, the held-out claim withdrawn |
|
|
@@ -993,6 +1030,33 @@ into the landing), and both overshoot after it, 3.38 and 1.38 rig px (frames 21
|
|
|
993
1030
|
`CHECK_TEXTURE_STRETCH: mesh "bottomwear" triangle 13 (vertices 5 183 6), edge 6-5, idle frame 13 — the edge is 0.233 times its rest length (max(ratio, 1/ratio) 4.29); <= 1.926544 is required`
|
|
994
1031
|
and `topwear` 2.597; with the values tracked now it reads 1.697 (`topwear`) and 1.566
|
|
995
1032
|
(`bottomwear`). Tune the constraint against the animation that drives it, not the idle.
|
|
1033
|
+
|
|
1034
|
+
#### A part only physics moves, in the automatic mode
|
|
1035
|
+
|
|
1036
|
+
A tie, a strand or a hem whose chain only a `physics` constraint turns has no idle key that
|
|
1037
|
+
deforms it, so `auto` refuses it, `AUTO_MESH_NO_STIMULUS`, naming the bones with no motion and
|
|
1038
|
+
the field: the motion gate measures against motion, and the package derives none from a
|
|
1039
|
+
constraint. Declare the bend in `meshes.<part>.auto.stimulus` (issue #196, the field table in
|
|
1040
|
+
*An automatic mesh*):
|
|
1041
|
+
|
|
1042
|
+
```jsonc
|
|
1043
|
+
"scarf": { "auto": { …, "motion": { "maxLocalDeformation": 1 },
|
|
1044
|
+
"stimulus": { "chain": "robe_r", "degrees": 9 } },
|
|
1045
|
+
"r": 6, "segments": [ "robe_r" ] }
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
Choose `degrees` as the largest bend, per link, that the physics is expected to reach in the
|
|
1049
|
+
animations that drive it: the mesh is held only to what was declared, so a smaller bend passes a
|
|
1050
|
+
mesh that tears at the real one, and nothing here checks the declaration against the
|
|
1051
|
+
constraint. The recipe for a thin strand only physics moves is therefore two steps: put its
|
|
1052
|
+
chain on the strand's own art, and declare the stimulus. The chain's position decides whether
|
|
1053
|
+
the motion bound can be held at all: on the scarf strap cut out of the sweater, with the chain
|
|
1054
|
+
on the strap (the tracked example's), the automatic mesh passes at the default
|
|
1055
|
+
`maxLocalDeformation` 1 with 68 vertices (the contour mesh's 133); with the chain beside the
|
|
1056
|
+
strap, as the proposal first placed it, the same part is refused `AUTO_MESH_MOTION` at 1 and
|
|
1057
|
+
passes only at 3, with its hull alone (31 vertices) — a hull cannot hold a bend the chain does
|
|
1058
|
+
not run through. Raising the bound is the author's choice, not the package's; moving the chain
|
|
1059
|
+
is the fix.
|
|
996
1060
|
- **An added animation can move the idle's figures.** The render's viewport is fitted over
|
|
997
1061
|
every animation, and the idle frames share it, so an animation that travels further than the
|
|
998
1062
|
idle redraws the idle at another size: adding `hop` to `sample` narrowed the idle render from
|
|
@@ -1134,7 +1198,7 @@ proposal in as the steps above say (`RL01`); every step must exit 0.
|
|
|
1134
1198
|
| `layers` | the table, then the `WARN` lines | every tag the plan will need has opaque pixels; one `face` in the head run; `0 WARN line(s)` | a run whose layer PNG is not its box's size (`LAYERS_PNG_MATCHES_BBOX`); a `WARN PLAN_LAYER_…` line (§6, *Plausibility*) |
|
|
1135
1199
|
| `sheet` of both runs | the tile list (and the sheet, if you can see) | eyes, irises, lashes and brows as left/right pairs in the head run | a head box that cut off an ornament: move `head_box`, re-run the head crop |
|
|
1136
1200
|
| `assemble` | one line per part, the `pixels:` totals (opaque = visible + occluded; taken; visible but not projected), then `recomposite vs source: mean \|d\|, within 8, error px > 40, uncovered error px`, then `uncovered holes (8-connected): N` and the largest five as `uncovered hole K: <px> px at x,y wxh (between "<part>" <px> px, …)`; and look at `render/recomposite_error_rig.png`. Between the part lines and the totals, one `cut: "<part>" opaque <n> = "<part>" <kept> + "<piece>" <taken> …` line per part an `assemble.cuts` entry cut (below; it ends `; under <n> px filled, <m> px left empty` when a cut of that part has `under`), then one `fringe pushed back: "<part>" <px> px, where the painting shows "<holder>" <px> px, …` line per part whose fringe was cleared (below) | on the examples: `sample` 0.83 / 98.0 % / 4,359 / 1,185, 259 holes, the largest 94 px; `demo` 2.34 / 95.8 % / 10,340 / 1,564, 453 holes, the largest 70 px (default rule) — many slivers along part edges, no hole a region could hide | one large hole: part of the figure is in no layer — a plan entry is missing, hair left the head crop sideways (the demo's `hair_back` is taken from the full run for that reason), or See-through split one garment into two and left the space between them in neither (a skirt as two trouser legs); the `between` parts say where. When neither run holds it at all, an `assemble.patches` entry cuts it from the painting (below) |
|
|
1137
|
-
| `propose` | `note:` lines, `LINT` lines, the `coverage` lines, `landmarks.png`, `basis.json` | no LINT line: every chain link lies on its mesh's art, and the hip is below the chest and the figure's top quarter; the `coverage:` summary says how many bones that verdict covers — a `not checked` bone was read by no check (its line says why), and a `ratio` or `fallback` bone in `basis.json` is a guess | a link off the art (a bone on the background) — move it onto the layer; `LINT hip at [x, y] is not below chest at [x, y]: …` or `LINT hip at [x, y] is above 0.25 of the figure height (figure y T..B, so hip y must be at least L): a hip at the shoulders` — move `hip` down to the waist (and `chest` between it and the neck); a `hanging strand … -- no chain proposed` note — that strand hangs stiff until you add a chain down the x and rows it names (§3); a `no blink: …` or `blink without brows: …` note — the idle will not blink (or its brows will not drop), because no part came from an `eyewhite` (or `eyebrow`) layer; the note names the tags looked for; a `no eyewhite part for eye_<s> …` note — the iris and lash parts it names ride `head` and do not blink, because no `eyewhite-<s>` part made that side's eye bone: take the eyewhite from the other run, or keep them on `head`; a `no face part: face box derived from …` note (always the first) — `head`, `neck` and every face-height scale come from a box guessed off the hair and neck (§3): check `head` and `neck` on `landmarks_head.png` and move them; when it adds `the blink shuts the eyes over no face part`, read `BLINK_NO_HOLE` after `check` — an eye with no face under it can open a hole (the `sample` with only its face removed: 587 px). Under `--keypoints`: the `lint rule set:` line first (joints, or screen and why), then the joint notes — `missing: the rule "…" placed bone X instead` is a bone still guessed; `not used — …` names why an arm's joints did not place its sleeve; `LINT chest at … is not between the neck joint …`, `LINT hip at … is not past chest …`, `LINT hip at … is nearer the neck joint …` and `LINT <chain><i> at … does not advance from <s>_shoulder toward <s>_wrist` are the joint-frame lines: move that bone between, past or along the joints they name |
|
|
1201
|
+
| `propose` | `note:` lines, `LINT` lines, the `coverage` lines, `landmarks.png`, `basis.json` | no LINT line: every chain link lies on its mesh's art, and the hip is below the chest and the figure's top quarter; the `coverage:` summary says how many bones that verdict covers — a `not checked` bone was read by no check (its line says why), and a `ratio` or `fallback` bone in `basis.json` is a guess | a link off the art (a bone on the background) — move it onto the layer; `LINT hip at [x, y] is not below chest at [x, y]: …` or `LINT hip at [x, y] is above 0.25 of the figure height (figure y T..B, so hip y must be at least L): a hip at the shoulders` — move `hip` down to the waist (and `chest` between it and the neck); a `hanging strand … -- no chain proposed` note — that strand hangs stiff until you add a chain down the x and rows it names (§3); a `no blink: …` or `blink without brows: …` note — the idle will not blink (or its brows will not drop), because no part came from an `eyewhite` (or `eyebrow`) layer; the note names the tags looked for; a `no eyewhite part for eye_<s> …` note — the iris and lash parts it names ride `head` and do not blink, because no `eyewhite-<s>` part made that side's eye bone: take the eyewhite from the other run, or keep them on `head`; a `no face part: face box derived from …` note (always the first) — `head`, `neck` and every face-height scale come from a box guessed off the hair and neck (§3): check `head` and `neck` on `landmarks_head.png` and move them; when it adds `the blink shuts the eyes over no face part`, read `BLINK_NO_HOLE` after `check` — an eye with no face under it can open a hole (the `sample` with only its face removed: 587 px). Under `--keypoints`: the `lint rule set:` line first (joints, or screen and why), then the joint notes — `missing: the rule "…" placed bone X instead` is a bone still guessed; `not used — …` names why an arm's joints did not place its sleeve (for a wrist on no part, the nearest part and the `--wrist-snap` that would bind it); a `wrist snap: …` note is a wrist bound past 15 px by the flag — check that chain's tip on `landmarks.png`; a `one handwear part holds both wrists` note is two chains on one mesh — cut the part with `assemble.cuts` to separate them; `LINT chest at … is not between the neck joint …`, `LINT hip at … is not past chest …`, `LINT hip at … is nearer the neck joint …` and `LINT <chain><i> at … does not advance from <s>_shoulder toward <s>_wrist` are the joint-frame lines: move that bone between, past or along the joints they name |
|
|
1138
1202
|
| `compare` | one line per pair (origin, parent, tip, length, direction — or SKIP and why), then the per-row summary, the unmapped bones of each side, `required:`, each side's roles and the `controls:` line | proposal against the config you corrected: the rows you changed and no others. Config against the `rig.json` `build` writes for it: measured on both examples, every origin within 6.19e-7 px (the rig's offsets are written to 6 places) and every chain link's tip and length within 4.99e-4 px (`length` is written to 3), printed to three places as `0.000` (a signed figure as `+0.000` or `-0.000`); `parent … is the right's ancestor at depth 2, <bone>_ctl between` for every keyed mesh bone, no `DIFFERENT` and no `NOT MAPPED` | `parent DIFFERENT: left a, right b` — a bone hangs from another parent than the other side's; `frames not related` — a rig with no stage (`skeleton.width`/`height`), two configs at different `rig_scale`: the distance rows SKIP, so declare the frame in a `--map` file if the author knows it; `FAIL STRUCTURE_REQUIRED_PRESENT` — a bone the map requires is missing through its pairs |
|
|
1139
1203
|
| `rig` (inside `build`) | one line per mesh: vertices, triangles, bones, influences, `cover`; the `bones` line; the `idle keys` line; then rigc's gate lines (with A15's declared SKIP under `--idle-keys direct`); in `rig.json`, each chain link's (or its `_ctl`'s) `length` and `rotation` | `cover 1.00000` on every mesh, both gate summaries `0 failed` (the compile and the packed pages); every link's `length` the distance to the next link and `rotation` its direction (Spine degrees, counter-clockwise, y up, local to the parent), every offset under it — a child bone's `x, y`, a weight's bind `x, y`, a region's `x, y` — in that turned frame, and a region on a link carrying `rotation` that turns it back upright. Nothing moved: `flattenRig` (`src/rig.ts`) turns every offset back and gives the unturned numbers | `RIG_LATTICE_ONE_LOOP`: change that mesh's `grid` |
|
|
1140
1204
|
| `check` (inside `build`) | the gate lines verbatim, the pack line, `loop:` (and `loop physics:` when the rig declares a physics constraint, §7), `seam:`, the six judgement lines, `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the nine bars measured and names the ones that said SKIP | `check: PASS; 9 of 9 bar(s) measured, 0 skipped` on the examples, and a judgement line SKIP only where the character lacks what it reads; on a rig spec with no `parts.json` or no `idle` (a merged rig, §7 *Measuring a rig rig-parts did not assemble*), PASS with the skipped bars named | `CHECK_SEAM_WITHIN_BAR` or `CHECK_LOOP_CLOSES` (§6) |
|
|
@@ -1553,6 +1617,7 @@ See-through with another seed.
|
|
|
1553
1617
|
| `COMFY_HISTORY_OUTPUTS`, `COMFY_VIEW_PRESENT`, `COMFY_MANIFEST_NAMED`, `COMFY_MANIFEST_IS_THIS_RUN`, `COMFY_LAYER_NAME` | the job's outputs are missing, unreadable, belong to another run, or name a layer that is not a plain file name | the wrapper's version on the box; report it |
|
|
1554
1618
|
| `COMFY_IMAGE_PRESENT`, `COMFY_OUT_EMPTY`, `COMFY_OUT_FREE` | no `--image`, an `--out` that already holds files, or a seed whose painting is already on disk | `--image`, `--out`, `--seed0` |
|
|
1555
1619
|
| `CONFIG_FIELD_PRESENT` on `config.generation`, `COMFY_PAINTING_SIZE` | `comfy paint` was given a config with no `generation` block (the line names the fields it holds), or the painting that came back is not twice the latent | `config.generation` |
|
|
1620
|
+
| `CONFIG_POSE_CANVAS`, `CONFIG_POSE_KEYPOINTS`, `CONFIG_POSE_IN_CANVAS` | the pose file `generation.control.skeleton` names states another canvas than `generation.latent`, holds other than the 18 body-18 keypoints, or puts one off its canvas | the pose file (§3, the `generation.control.skeleton` row) |
|
|
1556
1621
|
|
|
1557
1622
|
### assemble
|
|
1558
1623
|
|
|
@@ -1656,7 +1721,8 @@ and stay absent).
|
|
|
1656
1721
|
| `SCENE_ID_UNIQUE`, `SCENE_ID_FORM` | an `id` repeated, empty, or holding `:` — the separator of a prefixed name — or `/`, `\` or a leading `.`, because an id begins every image file of its character | another id |
|
|
1657
1722
|
| `SCENE_PLATE_PROVENANCE`, `SCENE_PLATE_PRESENT`, `SCENE_PLATE_SIZE` | the plate's `provenance` is not `observed`, `generated` or `unknown`; its image is missing or not a PNG; it is not the canvas's size (it is drawn at canvas (0, 0) and never scaled) | the plate |
|
|
1658
1723
|
| `SCENE_BUILD_PRESENT` | a build directory, or a file `build` writes in it (`parts.json`, `rig/rig.json`, `rig/motion.json` with an `idle`, an image its skin names, `check/check.json`), is missing | run `build` for that character |
|
|
1659
|
-
| `SCENE_BUILD_GREEN` | the build's own `check/check.json` does not say `PASS` and `gate_spine_html_green` | finish that character first: compose binds finished characters |
|
|
1724
|
+
| `SCENE_BUILD_GREEN` | the build's own `check/check.json` does not say `PASS` and `gate_spine_html_green`; under an accept list (`--accept`, `characters[].accept`), it failed a bar the list does not name, its gate is red, a declared requirement is not PASS, or it names no failing bar — the bars not met and the ones accepted are listed | finish that character first: compose binds finished characters. To look at the scene meanwhile, name the failing bars (§7, *Composing several characters*) |
|
|
1725
|
+
| `SCENE_ACCEPT_KNOWN` | an `--accept` name, or one in a character's `accept`, is not a bar `check` holds a build to: a problem code (`CHECK_LOOP_CLOSES`) where the bar's name (`loop`) belongs, a misspelling, or `gate`, which is rig-c's and never accepted | one of the names the message lists |
|
|
1660
1726
|
| `SCENE_BUILD_FIELD_KNOWN` | a build's `rig.json` or `motion.json` carries a key compose does not know how to prefix or place, or a root with a transform of its own | a rig `build` wrote; a rig written by something else is `check`'s to measure (§7, *Measuring a rig rig-parts did not assemble*), not compose's to merge |
|
|
1661
1727
|
| `SCENE_RIG_SCALE_AGREES` | the characters' `parts.json` `scale_rig_per_source` differ (each named) | one `assemble.rig_scale` for every character; `characters[].scale` sizes a placed character, it does not make two `rig_scale`s one |
|
|
1662
1728
|
| `SCENE_SCALE_EXACT` | a character at a `scale` other than 1 carries something no per-character value can scale: a physics constraint with a nonzero `wind` or `gravity` (Spine applies both through the skeleton's `referenceScale`, which the composed skeleton holds once for every character), a track whose `property` compose does not know to be a length or not, or a translate key whose `v` is neither a list of numbers nor a map of them | `scale` 1 for that character, or rebuild it at another `assemble.rig_scale` |
|
|
@@ -1719,7 +1785,12 @@ assemble*, at the end of this section):
|
|
|
1719
1785
|
line runs along the scarf's red edge [observed, issue #202]. A wider band moves
|
|
1720
1786
|
neither; the polygon's edge does — run it through art of one colour on both
|
|
1721
1787
|
sides, in both copies, which `rig/parts/<from>.png` and `rig/parts/<into>.png`
|
|
1722
|
-
show pixel for pixel
|
|
1788
|
+
show pixel for pixel. The composite meets the frame pixel centre to pixel
|
|
1789
|
+
centre: rig pixel index u lands on frame index s·u + t + 0.5·(s − 1), `s` the
|
|
1790
|
+
scale the `seam:` line prints (issue #209; the reference implementation's map
|
|
1791
|
+
lacks the last term, so the two agree only at s = 1). `check --keep-stills`
|
|
1792
|
+
leaves that frame — rigc's render directory, its `frames.json` (viewport,
|
|
1793
|
+
background) beside the PNG — under `check/setup_still/`;
|
|
1723
1794
|
- **loop**: idle frame 0 against the frame at `t = duration`: max |d| exactly 0. The bar
|
|
1724
1795
|
measures the keys (issue #183): a rig that declares a physics constraint — a `rig.json`
|
|
1725
1796
|
`constraints` entry of `type` `"physics"`, or an entry of `motion.json`'s `physics`
|
|
@@ -2036,7 +2107,7 @@ rig directory, copied away from its `parts.json`, reads `4 of 9`: the gate, the
|
|
|
2036
2107
|
|
|
2037
2108
|
### Composing several characters (`compose`, issue #74)
|
|
2038
2109
|
|
|
2039
|
-
`rig-parts compose --scene <scene.json> --out <dir> [--requirements <file.json>]`
|
|
2110
|
+
`rig-parts compose --scene <scene.json> --out <dir> [--requirements <file.json>] [--accept <bar>[,<bar>…]]`
|
|
2040
2111
|
binds characters this package already built into one rig. Each character runs the
|
|
2041
2112
|
single-character path (§4, steps 0–9) on its own, already isolated input to a green
|
|
2042
2113
|
`build` first; compose reads what that build wrote and changes nothing in it.
|
|
@@ -2059,6 +2130,7 @@ single-character path (§4, steps 0–9) on its own, already isolated input to a
|
|
|
2059
2130
|
| `characters[].build` | a `build --out` directory (relative to the scene file) whose own `check/check.json` is green |
|
|
2060
2131
|
| `characters[].offset` | `[x, y]`, a translation from the build's rig px to canvas px. Every character is built at one `assemble.rig_scale`, so its rig px are canvas px at scale 1 |
|
|
2061
2132
|
| `characters[].scale` | optional, a positive number; absent is 1, and 1 composes to the bytes a scene without the key writes. The character's size on the canvas, about its stage's top-left corner: a rig px `p` lands at canvas px `scale * p + offset` (issue #197). A character scaled up past its art is drawn soft — the art is not resampled; rebuild it at a higher `assemble.rig_scale` if that matters |
|
|
2133
|
+
| `characters[].accept` | optional, a list of bar names: the bars this character's own check may have failed and still be composed (issue #203). `compose --accept <bar>[,<bar>…]` is the same list for every character; the two are joined, so the command line applies to every character and a character's list adds to it. Each name is one of the bars `check`'s summary names, less the gate — `loop`, `seam`, `BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`; anything else is `SCENE_ACCEPT_KNOWN`. A build is taken when every bar its `check.json` failed is named; its gate red, a declared requirement not PASS, or a bar not named is `SCENE_BUILD_GREEN` as before. **It is for looking, not for shipping:** the `[compose]` line says which failing bars were accepted, `scene.json` records them as the character's `accepted`, the composed rig's own check measures them again and reports them as it finds them, and the run exits 1 even when that check is PASS (a composed rig has no `parts.json`, so the seam and four judgement lines say SKIP there). A list that accepts nothing — every build green — composes to the bytes a scene without one writes |
|
|
2062
2134
|
| `order` | the draw order, back to front: a character id (its slots not named elsewhere, in its own order) or one `<id>:<slot>`. Every slot of every character is drawn exactly once. Interleaving is written by naming slots: `["a", "b:arm_l", "b"]` draws `b`'s left arm between `a` and the rest of `b` |
|
|
2063
2135
|
|
|
2064
2136
|
What is composed:
|
|
@@ -2128,7 +2200,8 @@ What is composed:
|
|
|
2128
2200
|
image, provenance, note, bone, slot, size, `judged_by: "nothing"`), per character
|
|
2129
2201
|
its build, offset, `scale` (only when it is not 1), `rig_size`, `rig_scale`, placed bounds (the union of its part
|
|
2130
2202
|
boxes, canvas px), shift and what it moved (`shifted`: the first-level bones, the
|
|
2131
|
-
regions on `root`, the count of weights bound to `root`),
|
|
2203
|
+
regions on `root`, the count of weights bound to `root`), its counts and `accepted`
|
|
2204
|
+
(the failing bars of its own check that an accept list took, only when there are any), and the
|
|
2132
2205
|
order —
|
|
2133
2206
|
as declared and as the slot list it expands to, `judged_by: "nothing"`.
|
|
2134
2207
|
|
package/docs/STABILITY.md
CHANGED
|
@@ -52,13 +52,13 @@ defaults are the help's too, and none is guessed from the art.
|
|
|
52
52
|
| `comfy` | `seethrough`: `--image`, `--out`; optional `--resolution`, `--steps`, `--seed`, `--prefix`, `--offload`, `--lama`, `--nf4`, `--host`, `--wait`, `--timeout`, `--poll` |
|
|
53
53
|
| `assemble` | `--propose-plan` with `--source`, `--full`, `--head`, `--config`; or `--source`, `--full`, `--head`, `--config`, `--out`, optional `--seam` (near-white, silhouette), `--project` (core, visible) |
|
|
54
54
|
| `propose` | `--head-box` with `--full`, `--canvas` |
|
|
55
|
-
| `propose` | `--parts`, `--source`, `--out`; optional `--compare` or `--from-config` (one of them), `--keypoints`, `--person` (with `--keypoints`) |
|
|
55
|
+
| `propose` | `--parts`, `--source`, `--out`; optional `--compare` or `--from-config` (one of them), `--keypoints`, `--person` and `--wrist-snap` (each with `--keypoints`) |
|
|
56
56
|
| `compare` | `--left`, `--right`; optional `--map` |
|
|
57
57
|
| `rig` | `--config`, `--parts`, `--out`; optional `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
|
|
58
|
-
| `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs` |
|
|
58
|
+
| `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills` |
|
|
59
59
|
| `loop` | `--frames`, `--out`; optional `--palette` |
|
|
60
60
|
| `build` | `--config`, `--source`, `--full`, `--head`, `--out`; optional `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--requirements`, `--idle-keys` |
|
|
61
|
-
| `compose` | `--scene`, `--out`; optional `--requirements` |
|
|
61
|
+
| `compose` | `--scene`, `--out`; optional `--requirements`, `--accept` |
|
|
62
62
|
| (none) | `--version`, `--help` |
|
|
63
63
|
<!-- /stable:commands -->
|
|
64
64
|
|
|
@@ -104,6 +104,7 @@ part name, `[i]` an entry of a list):
|
|
|
104
104
|
- **generation.loras[i]** — required: `name`, `strength`; optional: `strength_clip`
|
|
105
105
|
- **generation.sampler** — required: `steps`, `cfg`, `sampler`, `scheduler`
|
|
106
106
|
- **generation.control** — required: `skeleton`, `strength`, `end_percent`; optional: `model`
|
|
107
|
+
- **generation.control.skeleton**, the pose file it names when it is no built-in — required: `width`, `height`, `points`
|
|
107
108
|
- **seethrough** — required: `resolution`, `steps`, `seed`, `offload`; optional: `head_box`
|
|
108
109
|
- **assemble** — required: `rig_scale`, `plan` (from plain `assemble` on); optional: `extend_below_crop`, `patches`, `cuts`
|
|
109
110
|
- **assemble.extend_below_crop[i]** — required: `part`, `run`, `tag`
|
|
@@ -117,7 +118,7 @@ part name, `[i]` an entry of a list):
|
|
|
117
118
|
- **meshes.<part>.ribs.<chain>** — required: `stations`
|
|
118
119
|
- **meshes.<part>.contour** — required: `tolerance`, `margin`, `spacing`; optional: `budget`, `stray`, `regions`
|
|
119
120
|
- **meshes.<part>.contour.regions[i]** — required: `name`, `shape`, `bone`, `spacing`, `band`, and `cx`, `cy`, `r` for a circle or `points` for a polygon
|
|
120
|
-
- **meshes.<part>.auto** — required: `source`, `sourceBounds`, `targets`, `influences`, `budget`, `minArtSamples`, `motion`; optional: `protect`, `regions`,
|
|
121
|
+
- **meshes.<part>.auto** — required: `source`, `sourceBounds`, `targets`, `influences`, `budget`, `minArtSamples`, `motion`; optional: `protect`, `regions`, the three Stage B opt-ins `boundaryRuns`, `retriangulate`, `removalOrder`, and `stimulus`
|
|
121
122
|
- **meshes.<part>.auto.source** — required: `tolerance`, `margin`, `spacing`; optional: `stray`
|
|
122
123
|
- **meshes.<part>.auto.sourceBounds** and **meshes.<part>.auto.targets.artFit** — required: `minCoverage`, `maxOvershoot`, `maxUndercut` (each of the last two a number or null, the bound declared absent)
|
|
123
124
|
- **meshes.<part>.auto.targets** — required: `artFit`, `maxBoundaryDeviation`; optional: `minAngle`
|
|
@@ -129,6 +130,7 @@ part name, `[i]` an entry of a list):
|
|
|
129
130
|
- **meshes.<part>.auto.protect** — optional: `hull`, `vertices`, `edges`, `regionBoundaries`, `weightJump`, `influences`
|
|
130
131
|
- **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)
|
|
131
132
|
- **meshes.<part>.auto.boundaryRuns** — required: `maxVertices`
|
|
133
|
+
- **meshes.<part>.auto.stimulus**, or each entry of it when a list — required: `chain`, `degrees`
|
|
132
134
|
- **regions.<part>** — a bone name
|
|
133
135
|
- **motion** — required: `duration`, `tracks`; optional: `blink`, `animations_from`
|
|
134
136
|
- **motion.tracks[i]**, a single track — required: `bone`, `prop`, `amp`, `period`, `phase`; optional: `base`
|
|
@@ -156,7 +158,7 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
|
|
|
156
158
|
| `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from`, the box `x`, `y`, `w`, `h` (rig px), the pixel counts `src/parts.ts` documents (`opaque_px`, `visible_px`, `occluded_px`, `projected_core_px`, `source_px_taken`, `visible_not_projected_px`, `refused_drift_px`, `merged_px`, `seam_override_px`, and `fringe_pushed_back` when not empty); `rig_size`, `scale_rig_per_source`, `ghost_px`, `recomposite` |
|
|
157
159
|
| `rig/rig.json`, `rig/motion.json`, `rig/images/` | `rig`, `build`, `compose` | rig-c's rig spec and motion spec, `spec` `rigc-rig/1` and `rigc-motion/1`: the format is rig-c's, and this package writes only what rig-c's parser accepts |
|
|
158
160
|
| `rig/mesh_report.json` | `rig`, `build` | one row per mesh: `part`, `vertices`, `triangles`, `hull`, `bones`, `max_influences`, `mean_influences`, `art_coverage`, then `grid` (a lattice); `mode` "contour" with `params`, `contour`, `regions`; or `mode` "auto" with `settings`, `source`, `result`, `residuals`, `worst_residual`, `worst_region`, `motion_amplitude`, `termination`, `weights`, `regions`, `deformation`, `quality_report` (rig-c's `mesh-quality-report/1` document whole), `motion_report`, and, only when they apply, `stray_cleared` (after `source`, when `source.stray` is declared), `skinning_residual` and `replay` (`AutoMeshReport` in `src/rig.ts`); in every mode, `exponent` when the mesh declares one (after `grid`, or after `mode`); `ribs` when a contour or auto mesh declares them (after `exponent`, or after `mode`), and then `contour.ribs` (`source.contour.ribs` in the automatic mode) |
|
|
159
|
-
| `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), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `seam_pairs` after the seam figures when the seam bar fails or `--seam-pairs` asks (each row's picture under `check/seam/`), then the judgement lines (`BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`), `RECOMPOSITE_HOLES`, `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 |
|
|
161
|
+
| `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), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `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`), `RECOMPOSITE_HOLES`, `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 |
|
|
160
162
|
| `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections and `notes` |
|
|
161
163
|
| `basis.json` | `propose` | spec `spine-parts-basis/1` |
|
|
162
164
|
| the scene report | `compose` | spec `spine-parts-scene-report/1` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rig-parts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
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": {
|