rig-parts 1.64.0 → 1.66.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 +5 -4
- package/cli.ts +60 -21
- package/docs/AUTHORING.md +166 -26
- package/docs/MIGRATION.md +11 -0
- package/docs/STABILITY.md +17 -5
- package/package.json +1 -1
- package/skills/rig-parts/SKILL.md +1 -1
- package/src/assemble.ts +86 -7
- package/src/build.ts +20 -4
- package/src/check.ts +537 -18
- package/src/clothconfig.ts +3 -2
- package/src/config.ts +32 -5
- package/src/layers.ts +62 -0
- package/src/parts.ts +90 -32
- package/src/propose.ts +35 -1
- package/src/rig.ts +54 -8
- package/tools/configwrite.ts +3 -3
package/README.md
CHANGED
|
@@ -272,7 +272,7 @@ Use the graph's node classes and the host's `/object_info` when checking the ada
|
|
|
272
272
|
```sh
|
|
273
273
|
rig-parts inputs --source painting.png --config config.json --out inputs # st_input_full.png; the config needs assemble.rig_scale
|
|
274
274
|
# See-through on st_input_full.png (external, or `rig-parts comfy seethrough`) -> layers/full
|
|
275
|
-
rig-parts layers layers/full #
|
|
275
|
+
rig-parts layers layers/full # drawn(a>8)/opaque(a>=250) boxes, CORE body-group height in input-canvas px, WARNs
|
|
276
276
|
rig-parts propose --head-box --full layers/full --canvas 1664x2432
|
|
277
277
|
# -> seethrough.head_box into config.json
|
|
278
278
|
rig-parts inputs --source painting.png --config config.json --out inputs # now st_input_head.png too
|
|
@@ -291,7 +291,8 @@ rig-parts propose --parts work/rig --source painting.png --out work
|
|
|
291
291
|
# (limbs only with --keypoints, constraints only with --cloth, turn only with --full/--head;
|
|
292
292
|
# a limbs block left out is refused next)
|
|
293
293
|
rig-parts propose --parts work/rig --source painting.png --out work --from-config config.json
|
|
294
|
-
# -> LINT lines; exit 1 while any remain
|
|
294
|
+
# -> LINT lines; exit 1 while any remain (takes --parts, --source, --out, --from-config and optional --keypoints [--person] only;
|
|
295
|
+
# proposes nothing, so --full, --head, --cloth, --write-config, --wrist-snap, --grid-rule, --only-missing and --compare are refused)
|
|
295
296
|
rig-parts build --config config.json --source painting.png --full layers/full --head layers/head --out out --loop
|
|
296
297
|
# -> read out/check/check.json; every FAIL line names what has to change
|
|
297
298
|
```
|
|
@@ -333,7 +334,7 @@ agent skill.
|
|
|
333
334
|
| `inputs --source <png> --config <json> --out <dir>` | the two images See-through is fed: the painting on a white square, and the head box's crop once the config has one |
|
|
334
335
|
| `comfy paint --config --out [--host]` | optional: generate the painting on a ComfyUI box from the config's `generation` block |
|
|
335
336
|
| `comfy seethrough --image --out [--host]` | optional: run the ComfyUI See-through wrapper on one image and write the form `layers` reads |
|
|
336
|
-
| `layers <dir \| layers.json \| file.psd>` |
|
|
337
|
+
| `layers <dir \| layers.json \| file.psd>` | keep the existing columns (`opaque_px` still means alpha >8) and append source-alpha boxes `drawn(a>8)` / `opaque(a>=250)` with exclusive right/bottom; name absent boxes, report the existing body-group union height at **CORE_ALPHA (>=250)** in **input-canvas px**, and show its >8 union separately; no anatomical height, ownership/erosion or painting registration is inferred ([units and rig-scale guidance](docs/AUTHORING.md#4-the-command-order)) |
|
|
337
338
|
| `sheet --source <png> --layers <path>… --out <png>` | a labelled contact sheet of the painting and every layer or part |
|
|
338
339
|
| `assemble --propose-plan … [--write-config <config>]` | propose `assemble.plan` and `extend_below_crop` from the two runs, leaving out an implausible layer with a note naming the rule, naming in a note any full-run body no planned part covers, and naming every layer no row takes with why (empty, taken from the other run only, a plausibility rule; `nose`, never planned, with the row that lets `propose` read the head's pitch) |
|
|
339
340
|
| `assemble --source --full --head --config --out [--seam] [--project]` | merge the two runs into rig-space parts, `parts.json`, the recomposite and its error map, and list the uncovered holes |
|
|
@@ -341,7 +342,7 @@ agent skill.
|
|
|
341
342
|
| `propose --parts --source --out [--compare <config>] [--write-config <config> [--only-missing]]` | propose bones, meshes, regions and an idle; draw the overlay; print, per bone, which check read it or that none did and why (its role, its kind of segment), and write `basis.json` beside the proposal — what each bone rests on (a joint, a part's mask, a ratio, other bones) and, with `--compare`, whether the config's bone differs |
|
|
342
343
|
| `propose … --keypoints <file> [--person <id>]` | read a posed figure's joints from one explicit file (space, image size, people, each joint observed, occluded or missing, its source): a joint with a position places the neck, hip, chest or a sleeve chain as given, a note says how every joint was used or which rule stood in, and LINT reads the torso and sleeves along the joints instead of by screen y ([AUTHORING §3](docs/AUTHORING.md)) |
|
|
343
344
|
| `propose … --grid-rule figure\|part` | how each drafted lattice's spacing is chosen: `figure` (the default) one spacing for the figure, round(H / 37) rig px, a part already coarser keeping its own, with a note on its calibration and cost; `part` the reference's rule, a tenth of the part's short side (the oracle examples are proposed under it) |
|
|
344
|
-
| `propose
|
|
345
|
+
| `propose --parts --source --out --from-config <config> [--keypoints <file> [--person <id>]]` | draw and LINT the config's current bones (by the joints too, given `--keypoints`); proposes nothing, so takes only these flags (not `--full`, `--head`, `--cloth`, `--write-config`, `--wrist-snap`, `--grid-rule`, `--only-missing` or `--compare`) |
|
|
345
346
|
| `compare --left <file> --right <file> [--map <bonemap.json>]` | compare two skeletons — a config, a proposal or a `rig.json` — bone by bone: origin, parent, tip, length and direction per pair, the bones neither side pairs, the required ones missing, and each side's roles read off the spec; no frame is guessed, and nothing pairs by resemblance (`propose --compare` reads origins only) |
|
|
346
347
|
| `rig --config --parts --out [--idle-keys ctl\|direct]` | author `rig.json` + `motion.json`, written only after rig-c's gate is green; each mesh is in the mode its config entry names — `grid` (the lattice, what `propose` writes), `contour` (the traced outline with declared interior points) or `auto` (the contour mesh at alpha 1 and above, reduced and locally refined by rig-c's `reduceMesh` under the author's declared bounds, written only when its motion against the unreduced source on the idle passes the author's `motion` bounds through rig-c's `compareMeshesInMotion`; [AUTHORING §3](docs/AUTHORING.md)); every chain link is turned along its chain and carries its `length`, so a physics constraint added later has a lever, with every offset under it in the turned frame so nothing moves; `--idle-keys` says whether the idle's keys on mesh-driving bones go through `<bone>_ctl` parents (default) or stay on the bones with `invariants.idleDrivesMeshes` declared; the config's `constraints` go to rigc as written, and a two-bone ik over keyed links needs `--idle-keys direct` (on `rig` or `build`) |
|
|
347
348
|
| `check --rig --out [--parts] [--source] [--requirements]` | build packed, gated under `rig-play`, 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*) |
|
package/cli.ts
CHANGED
|
@@ -28,7 +28,7 @@ import { GUIDE_DOC, type GuideAnswer, guideRule, guideSection } from './src/guid
|
|
|
28
28
|
import { proposeHeadBox } from './src/headbox.ts';
|
|
29
29
|
import { makeInputs } from './src/inputs.ts';
|
|
30
30
|
import { idleKeysOf, isIdleKeys } from './src/rig.ts';
|
|
31
|
-
import { depthSkipLine, exportLayers, figuresPhrase, hiddenLayerLine, implausibleRules, layerFigures, type LayerSet, layerSetDiff, pct, readLayers, readWrapperLayers, ruleSummary, templateLayerNames, templatePsdBytes, times } from './src/layers.ts';
|
|
31
|
+
import { bodyCoreBox, bodyOpaqueBox, CORE_ALPHA, depthSkipLine, exportLayers, figuresPhrase, hiddenLayerLine, implausibleRules, layerCoreBox, layerFigures, layerOpaqueBox, type LayerSet, layerSetDiff, type OpaqueBox, OPAQUE_ALPHA_ABOVE, pct, readLayers, readWrapperLayers, ruleSummary, templateLayerNames, templatePsdBytes, times } from './src/layers.ts';
|
|
32
32
|
import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJoints, toRigJoints } from './src/keypoints.ts';
|
|
33
33
|
import { basisLines, branchSqueezeLine, checkProposal, compare, compareLines, DEFAULT_GRID_RULE, draftTurn, drawLandmarks, FIGURE_GRID_DIVISOR, FRINGE_STEP_PX, GRID_RULES, type GridRule, HIP_MIN_FRACTION, type DraftLintFinding, lint, lintLine, type PartSet, PROPOSAL_CONFIG_SECTIONS, proposalAsConfig, proposeWithBasis, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
34
34
|
import { BASIS_FILE, BASIS_SPEC, basisFile, basisLine, coverageLines, legChainChoice, serializeBasis } from './src/diagnostics.ts';
|
|
@@ -79,6 +79,11 @@ usage:
|
|
|
79
79
|
where something covers it: listed apart, never drawn, never a part. An
|
|
80
80
|
input with no depth (a PSD, or depth_median null on every layer, whose
|
|
81
81
|
manifest order is then the draw order) prints one SKIP depth line.
|
|
82
|
+
Trailing boxes name both source-alpha cuts: drawn(a>8), and opaque
|
|
83
|
+
(a>=250, CORE_ALPHA). The legacy opaque_px still counts alpha above 8.
|
|
84
|
+
Right/bottom are exclusive, in INPUT-CANVAS px; absent boxes are named.
|
|
85
|
+
The body-group union height uses alpha >=250, with the >8 union shown
|
|
86
|
+
separately: no cleanup, ownership, anatomical height or painting map.
|
|
82
87
|
Refuses, by name, a missing file, an unknown tag, a PNG whose
|
|
83
88
|
size is not its box, and anything else outside the input contract —
|
|
84
89
|
never a WARN.
|
|
@@ -268,9 +273,10 @@ usage:
|
|
|
268
273
|
|
|
269
274
|
rig-parts propose --parts <dir> --source <painting.png> --out <dir> --from-config <config.json>
|
|
270
275
|
Draw the config's CURRENT bones instead (<out>/render/landmarks_config.png
|
|
271
|
-
and _head) and LINT them (by the joints too, given --keypoints), with the
|
|
272
|
-
coverage lines after them; no ${BASIS_FILE}, as nothing is proposed
|
|
273
|
-
|
|
276
|
+
and _head) and LINT them (by the joints too, given --keypoints [--person]), with the
|
|
277
|
+
coverage lines after them; no ${BASIS_FILE}, as nothing is proposed (takes
|
|
278
|
+
--parts, --source, --out, --from-config and optional --keypoints [--person]
|
|
279
|
+
only). Exits 1 when any LINT line is printed.
|
|
274
280
|
|
|
275
281
|
rig-parts propose … --write-config <config.json>
|
|
276
282
|
Without --cloth, update an existing config with the whole proposal's
|
|
@@ -416,7 +422,8 @@ usage:
|
|
|
416
422
|
rig-parts mesh-stats --config <config.json> --parts <dir>
|
|
417
423
|
Print the vertices and triangles of every mesh the config states, as the
|
|
418
424
|
rig stage would make them from the parts in --parts (the directory
|
|
419
|
-
holding parts.json and parts
|
|
425
|
+
holding parts.json and parts/ — work/rig from assemble --out work, or
|
|
426
|
+
out from build --out out), and their total, in seconds:
|
|
420
427
|
the rig stage's own mesh construction, without rigc, without assemble
|
|
421
428
|
and without check (issue #566). One line per mesh in parts.json's order,
|
|
422
429
|
"mesh-stats: <part> — <mode> <V> vertices, <T> triangles" (mode lattice,
|
|
@@ -523,6 +530,7 @@ usage:
|
|
|
523
530
|
[--page-edges pot|free] [--pack-shape rect|polygon]
|
|
524
531
|
[--requirements <file.json>] [--seam-pairs] [--keep-stills]
|
|
525
532
|
[--set <name> | --all-sets] [--environment <schedule.json>]
|
|
533
|
+
[--wind-band <spec.json>]
|
|
526
534
|
Build, gate, render and measure a rig through rig-c's CLI (the rigc at
|
|
527
535
|
node_modules/.bin/rigc, or on PATH). --rig holds rig.json and motion.json:
|
|
528
536
|
a rig spec, which rigc build compiles, not a compiled skeleton.json.
|
|
@@ -671,6 +679,14 @@ usage:
|
|
|
671
679
|
response or no band is SKIP; no pair or animation gives no worlds.
|
|
672
680
|
Nonphysics output is unchanged. In rig-play environment(null) returns
|
|
673
681
|
to the default world, not still air (AUTHORING, Physics seam environments).
|
|
682
|
+
--wind-band <spec.json> sweeps steady wind [x, 0], gravity [0, 1] at t = 0
|
|
683
|
+
over [min, max] in step increments through rigc render --seam (spec
|
|
684
|
+
"rig-parts-wind-band/1"; every field required: spec, min, max, step, fps,
|
|
685
|
+
max_gap, max_ghost, pairs; refused by CHECK_WIND_BAND before anything is
|
|
686
|
+
written). Prints WIND_BAND: REPORTED with the steady-wind band and one
|
|
687
|
+
WIND_BAND: line per pair that breaks inside [min, max], and records
|
|
688
|
+
WIND_BAND in check.json. Steady wind only; it does not measure gusts or
|
|
689
|
+
transient overshoot (AUTHORING §6, Steady-wind seam band).
|
|
674
690
|
|
|
675
691
|
rig-parts loop --frames <dir> --out <file.png | file.gif> [--palette]
|
|
676
692
|
Encode a frame set rigc render wrote (its --out directory, or the set
|
|
@@ -788,7 +804,7 @@ usage:
|
|
|
788
804
|
[--pack-shape rect|polygon] [--loop] [--requirements <file.json>]
|
|
789
805
|
[--idle-keys ctl|direct] [--lead-in <periods>] [--seam-pairs] [--keep-stills]
|
|
790
806
|
[--alt <name>=<source>:<full>[:<head>]] [--set <name> | --all-sets]
|
|
791
|
-
[--environment <schedule.json>]
|
|
807
|
+
[--environment <schedule.json>] [--wind-band <spec.json>]
|
|
792
808
|
assemble, then rig, then check, in one process, each stage's own lines
|
|
793
809
|
printed under [assemble], [rig] and [check]; the first stage that refuses
|
|
794
810
|
stops the build with its own FAIL lines. The config must already carry
|
|
@@ -819,6 +835,9 @@ usage:
|
|
|
819
835
|
--environment is forwarded to check (as for check); the schedule is read
|
|
820
836
|
by rig-c's reader before assemble runs, so a malformed one is refused,
|
|
821
837
|
CHECK_ENVIRONMENT, under [assemble] before anything is assembled.
|
|
838
|
+
--wind-band is forwarded to check (as for check); the spec is read before
|
|
839
|
+
assemble runs, so a malformed one is refused, CHECK_WIND_BAND, under
|
|
840
|
+
[assemble] before anything is assembled.
|
|
822
841
|
--seam-pairs and --keep-stills are forwarded to check (as for check:
|
|
823
842
|
the seam split by pair on a pass too, under check/seam/; the setup-pose
|
|
824
843
|
still under check/setup_still/). check's --rig and --parts are refused:
|
|
@@ -981,10 +1000,29 @@ function printLayerTable(set: LayerSet): void {
|
|
|
981
1000
|
const head = ['order', 'name', 'group', 'left,top', 'right,bottom', 'size', 'opaque_px', 'depth', 'translucent', 'background', 'area'];
|
|
982
1001
|
const widths = head.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
983
1002
|
const line = (cells: string[]): string => ` ${cells.map((c, i) => c.padEnd(widths[i])).join(' ')}`.trimEnd();
|
|
984
|
-
|
|
985
|
-
|
|
1003
|
+
// Keep every legacy line byte-for-byte as a prefix; size the trailing fields separately.
|
|
1004
|
+
const legacy = [line(head), ...rows.map(line)];
|
|
1005
|
+
const legacyWidth = Math.max(...legacy.map(l => l.length));
|
|
1006
|
+
const drawn = `drawn(a>${OPAQUE_ALPHA_ABOVE})`;
|
|
1007
|
+
const opaque = `opaque(a>=${CORE_ALPHA})`;
|
|
1008
|
+
const boxes = set.layers.map(l => [layerOpaqueBox(l), layerCoreBox(l)] as const);
|
|
1009
|
+
const opaqueHead = [drawn, opaque].flatMap(label => [`${label}_left,top`, `${label}_right,bottom`, `${label}_size`]);
|
|
1010
|
+
const opaqueRows = boxes.map(pair => pair.flatMap(b => b === null ? ['none', 'none', 'none'] : [`${b.left},${b.top}`, `${b.right},${b.bottom}`, `${b.right - b.left}x${b.bottom - b.top}`]));
|
|
1011
|
+
const opaqueWidths = opaqueHead.map((h, i) => Math.max(h.length, ...opaqueRows.map(r => r[i].length)));
|
|
1012
|
+
for (const [i, cells] of [opaqueHead, ...opaqueRows].entries()) {
|
|
1013
|
+
console.log(`${legacy[i].padEnd(legacyWidth)} ${cells.map((c, j) => c.padEnd(opaqueWidths[j])).join(' ')}`.trimEnd());
|
|
1014
|
+
}
|
|
986
1015
|
const painted = set.layers.filter((l) => l.opaquePx > 0).length;
|
|
987
1016
|
console.log(` ${set.layers.length} layer(s): ${painted} with opaque pixels, ${set.layers.length - painted} with none`);
|
|
1017
|
+
console.log(` source-alpha boxes: ${drawn}, ${opaque}; legacy opaque_px remains alpha > ${OPAQUE_ALPHA_ABOVE}; INPUT-CANVAS px; right/bottom exclusive`);
|
|
1018
|
+
for (const [i, [drawnBox, coreBox]] of boxes.entries()) {
|
|
1019
|
+
if (drawnBox === null) console.log(` layer "${set.layers[i].name}": no ${drawn} box (no pixels with alpha > ${OPAQUE_ALPHA_ABOVE})`);
|
|
1020
|
+
if (coreBox === null) console.log(` layer "${set.layers[i].name}": no ${opaque} box (no pixels with alpha >= ${CORE_ALPHA})${drawnBox === null ? '' : `; ${drawn} box is present`}`);
|
|
1021
|
+
}
|
|
1022
|
+
const bodyBounds = (body: OpaqueBox | null): string => body === null ? 'none; height unavailable INPUT-CANVAS px' : `${body.left},${body.top} to ${body.right},${body.bottom}; size ${body.right - body.left}x${body.bottom - body.top}; height ${body.bottom - body.top} INPUT-CANVAS px`;
|
|
1023
|
+
console.log(` body-group union [${opaque}]: ${bodyBounds(bodyCoreBox(set))}; source alpha >= ${CORE_ALPHA} only, not an owned/eroded core or anatomical height`);
|
|
1024
|
+
console.log(` body-group union [${drawn}]: ${bodyBounds(bodyOpaqueBox(set))}; source alpha > ${OPAQUE_ALPHA_ABOVE} only; not an anatomical height`);
|
|
1025
|
+
console.log(' body-group population: drawn group=body (includes hair/head/wings/objects; excludes face/headwear, author and hidden art); before cleanup, resampling or painting registration');
|
|
988
1026
|
// Issue #256: a layer the author made is said to be one, so it never reads as See-through's. None, no line.
|
|
989
1027
|
for (const l of set.layers) if (l.tag.group === 'author') console.log(` ${authorLayerLine(l.name)}`);
|
|
990
1028
|
// Issue #359: a hidden-art layer is listed apart, never in the drawn table. None, no line.
|
|
@@ -1014,13 +1052,13 @@ const TAKES = {
|
|
|
1014
1052
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
1015
1053
|
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule', '--cloth', '--write-config', '--from'], switches: ['--head-box', '--no-back-hair', '--only-missing'] },
|
|
1016
1054
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
1017
|
-
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements', '--set', '--environment'], switches: ['--seam-pairs', '--keep-stills', '--all-sets'] },
|
|
1055
|
+
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements', '--set', '--environment', '--wind-band'], switches: ['--seam-pairs', '--keep-stills', '--all-sets'] },
|
|
1018
1056
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
1019
1057
|
assemble: { valued: ['--source', '--full', '--head', '--config', '--out', '--seam', '--project', '--alt', '--write-config'], switches: ['--propose-plan'] },
|
|
1020
1058
|
'comfy seethrough': { valued: ['--image', '--out', '--resolution', '--steps', '--seed', '--prefix', '--host', '--wait', '--timeout', '--poll'], switches: ['--offload', '--lama', '--nf4'] },
|
|
1021
1059
|
'comfy paint': { valued: ['--config', '--out', '--seeds', '--seed0', '--host', '--wait', '--timeout', '--poll'], switches: [] },
|
|
1022
1060
|
inputs: { valued: ['--source', '--config', '--out'], switches: [] },
|
|
1023
|
-
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys', '--lead-in', '--alt', '--set', '--environment'], switches: ['--loop', '--seam-pairs', '--keep-stills', '--all-sets'] },
|
|
1061
|
+
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys', '--lead-in', '--alt', '--set', '--environment', '--wind-band'], switches: ['--loop', '--seam-pairs', '--keep-stills', '--all-sets'] },
|
|
1024
1062
|
compose: { valued: ['--scene', '--out', '--requirements', '--accept'], switches: [] },
|
|
1025
1063
|
'mesh-draft': { valued: ['--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: ['--more-triangles'] },
|
|
1026
1064
|
'mesh-stats': { valued: ['--config', '--parts'], switches: [] },
|
|
@@ -1271,7 +1309,7 @@ function cmdCheck(args: string[]): number {
|
|
|
1271
1309
|
try {
|
|
1272
1310
|
const bin = findRigc(import.meta.dir, process.env.PATH ?? '');
|
|
1273
1311
|
const r = checkStage(
|
|
1274
|
-
{ rig, parts: f.get('--parts'), source: f.get('--source'), out, pageEdges: edges, packShape: shape, requirements: f.get('--requirements'), seamPairs: seamPairs === 1, keepStills: keepStills === 1, ...(f.has('--set') ? { set: f.get('--set') as string } : {}), allSets: allSets === 1, ...(f.has('--environment') ? { environment: f.get('--environment') as string } : {}) },
|
|
1312
|
+
{ rig, parts: f.get('--parts'), source: f.get('--source'), out, pageEdges: edges, packShape: shape, requirements: f.get('--requirements'), seamPairs: seamPairs === 1, keepStills: keepStills === 1, ...(f.has('--set') ? { set: f.get('--set') as string } : {}), allSets: allSets === 1, ...(f.has('--environment') ? { environment: f.get('--environment') as string } : {}), ...(f.has('--wind-band') ? { windBand: f.get('--wind-band') as string } : {}) },
|
|
1275
1313
|
rigcRunner(bin),
|
|
1276
1314
|
bin,
|
|
1277
1315
|
console.log,
|
|
@@ -1339,11 +1377,12 @@ function cmdPropose(args: string[]): number {
|
|
|
1339
1377
|
}
|
|
1340
1378
|
// Issue #671: --only-missing adds entries to an existing config for the parts it attaches by neither section; it
|
|
1341
1379
|
// belongs to the ordinary proposal's --write-config alone.
|
|
1380
|
+
const fromConfigTakes = '(takes --parts, --source, --out, --from-config and optional --keypoints [--person] only)';
|
|
1342
1381
|
if (onlyMissing) {
|
|
1343
1382
|
const mode = 'propose --parts … --write-config <config.json> --only-missing';
|
|
1344
1383
|
if (headBox) return usage(`--only-missing belongs to ${mode}; --head-box writes seethrough.head_box only`);
|
|
1345
1384
|
if (!flags.has('--parts')) return usage(`--only-missing belongs to ${mode}; give --parts <dir>, the parts the entries are drafted from`);
|
|
1346
|
-
if (flags.has('--from-config')) return usage(`--only-missing belongs to ${mode}; --from-config proposes nothing`);
|
|
1385
|
+
if (flags.has('--from-config')) return usage(`--only-missing belongs to ${mode}; --from-config proposes nothing ${fromConfigTakes}`);
|
|
1347
1386
|
if (flags.has('--cloth')) return usage(`--only-missing belongs to ${mode}; --cloth writes a new config with the recipe's entries spliced in`);
|
|
1348
1387
|
if (!flags.has('--write-config')) return usage(`--only-missing belongs to ${mode}; give --write-config <config.json>, the existing config the entries are added to`);
|
|
1349
1388
|
}
|
|
@@ -1388,17 +1427,17 @@ function cmdPropose(args: string[]): number {
|
|
|
1388
1427
|
if (partsArg === undefined) return usage('propose needs --parts <dir>, the directory holding parts.json and parts/');
|
|
1389
1428
|
if (source === undefined) return usage('propose needs --source <painting.png>, drawn under the overlay');
|
|
1390
1429
|
if (out === undefined) return usage('propose needs --out <dir>');
|
|
1391
|
-
if (flags.has('--from-config') && flags.has('--compare')) return usage(
|
|
1430
|
+
if (flags.has('--from-config') && flags.has('--compare')) return usage(`--from-config and --compare are two modes; give one (--from-config ${fromConfigTakes.slice(1, -1)})`);
|
|
1392
1431
|
if (flags.has('--person') && !flags.has('--keypoints')) return usage('--person names a person in the --keypoints file; give --keypoints <file>');
|
|
1393
1432
|
// Issue #251: the See-through runs the turn control's depths are read from; without them nothing is drafted.
|
|
1394
|
-
if (flags.has('--from-config') && (flags.has('--full') || flags.has('--head'))) return usage(
|
|
1433
|
+
if (flags.has('--from-config') && (flags.has('--full') || flags.has('--head'))) return usage(`--full and --head draft the turn control while proposing; --from-config proposes nothing ${fromConfigTakes}`);
|
|
1395
1434
|
// Issue #199: a declared tolerance for a wrist on no handwear part. Whole px above the built-in one: the distance is
|
|
1396
1435
|
// counted in whole px, so a fraction would bind what its floor binds, and a value at or under the built-in binds nothing.
|
|
1397
1436
|
const snapArg = flags.get('--wrist-snap');
|
|
1398
1437
|
let wristSnap: number | null = null;
|
|
1399
1438
|
if (snapArg !== undefined) {
|
|
1400
1439
|
if (!flags.has('--keypoints')) return usage('--wrist-snap binds a wrist joint to a handwear part; give --keypoints <file>');
|
|
1401
|
-
if (flags.has('--from-config')) return usage(
|
|
1440
|
+
if (flags.has('--from-config')) return usage(`--wrist-snap binds a wrist while proposing; --from-config proposes nothing ${fromConfigTakes}`);
|
|
1402
1441
|
if (!/^[0-9]+$/.test(snapArg) || Number(snapArg) <= WRIST_ON_PART_PX) {
|
|
1403
1442
|
return usage(`--wrist-snap ${snapArg} is not an integer above ${WRIST_ON_PART_PX}, the px within which a wrist already holds a part`);
|
|
1404
1443
|
}
|
|
@@ -1406,15 +1445,15 @@ function cmdPropose(args: string[]): number {
|
|
|
1406
1445
|
}
|
|
1407
1446
|
// Issue #265: the drafted lattice's spacing; the figure's unless the reference's per-part rule is asked for.
|
|
1408
1447
|
const ruleArg = flags.get('--grid-rule');
|
|
1409
|
-
if (ruleArg !== undefined && flags.has('--from-config')) return usage(
|
|
1448
|
+
if (ruleArg !== undefined && flags.has('--from-config')) return usage(`--grid-rule chooses the drafted spacing; --from-config proposes nothing ${fromConfigTakes}`);
|
|
1410
1449
|
if (ruleArg !== undefined && !(GRID_RULES as readonly string[]).includes(ruleArg)) return usage(`--grid-rule ${ruleArg}; one of ${GRID_RULES.join(', ')} is required`);
|
|
1411
1450
|
const gridRule = (ruleArg ?? DEFAULT_GRID_RULE) as GridRule;
|
|
1412
1451
|
// Issue #364: the cloth and hair recipe, read from a config's cloth block; without it nothing changes.
|
|
1413
1452
|
const clothArg = flags.get('--cloth');
|
|
1414
|
-
if (clothArg !== undefined && flags.has('--from-config')) return usage(
|
|
1453
|
+
if (clothArg !== undefined && flags.has('--from-config')) return usage(`--cloth drafts trees while proposing; --from-config proposes nothing ${fromConfigTakes}`);
|
|
1415
1454
|
// Issue #537: the --cloth config's own text with what its recipe drafts spliced in, beside proposal.json.
|
|
1416
1455
|
const writeArg = flags.get('--write-config');
|
|
1417
|
-
if (writeArg !== undefined && flags.has('--from-config')) return usage(
|
|
1456
|
+
if (writeArg !== undefined && flags.has('--from-config')) return usage(`--write-config writes what the recipe drafts into its config; --from-config proposes nothing ${fromConfigTakes}`);
|
|
1418
1457
|
// Issue #571: the config the recipe is changed from; an entry equal to its recipe's draft is the recipe's, not a hand edit.
|
|
1419
1458
|
const fromArg = flags.get('--from');
|
|
1420
1459
|
if (fromArg !== undefined && writeArg === undefined) return usage('--from names the config the recipe is changed from, for --write-config; give --write-config <out.json>');
|
|
@@ -1422,7 +1461,7 @@ function cmdPropose(args: string[]): number {
|
|
|
1422
1461
|
if (writeArg !== undefined && clothArg !== undefined) {
|
|
1423
1462
|
const ours = ['proposal.json', BASIS_FILE, 'render/landmarks.png', 'render/landmarks_head.png'].map((f) => resolve(out, f));
|
|
1424
1463
|
if (existsSync(writeArg) || ours.includes(resolve(writeArg))) {
|
|
1425
|
-
throw new PartsError([{ code: 'PROPOSE_WRITE_CONFIG_FRESH', object: writeArg, detail: existsSync(writeArg) ? 'exists; the config is written to a new file, never over the --cloth config or an earlier one' : `is a file this run writes under ${out}; name another file` }]);
|
|
1464
|
+
throw new PartsError([{ code: 'PROPOSE_WRITE_CONFIG_FRESH', object: writeArg, detail: existsSync(writeArg) ? 'exists; the config is written to a new file, never over the --cloth config or an earlier one (unlike assemble --propose-plan and propose without --cloth, which update an existing --config in place)' : `is a file this run writes under ${out}; name another file` }]);
|
|
1426
1465
|
}
|
|
1427
1466
|
separateConfigWriteTarget({ path: resolve(writeArg) }, ours, 'PROPOSE_WRITE_CONFIG_FRESH');
|
|
1428
1467
|
}
|
|
@@ -1630,7 +1669,7 @@ function cmdAssemble(args: string[]): number {
|
|
|
1630
1669
|
const [source, full, config] = ['--source', '--full', '--config'].map((f) => flags.get(f) as string);
|
|
1631
1670
|
const head = flags.get('--head') ?? null;
|
|
1632
1671
|
const writePath = flags.get('--write-config');
|
|
1633
|
-
if (writePath !== undefined && resolve(writePath) !== resolve(config)) return usage('--write-config must name the same file as --config for assemble --propose-plan');
|
|
1672
|
+
if (writePath !== undefined && resolve(writePath) !== resolve(config)) return usage('--write-config must name the same file as --config for assemble --propose-plan (assemble --propose-plan updates --config in place; only propose --cloth --write-config writes to a new file)');
|
|
1634
1673
|
let staged: StagedConfigWrite | null = null;
|
|
1635
1674
|
try {
|
|
1636
1675
|
if (propose) {
|
|
@@ -1857,7 +1896,7 @@ function cmdBuild(args: string[]): number {
|
|
|
1857
1896
|
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-build-'));
|
|
1858
1897
|
try {
|
|
1859
1898
|
const r = build(
|
|
1860
|
-
{ config, source, full, head, out, seam: seam as SeamRule, project: project as ProjectRule, loop, pageEdges: edges, packShape: shape, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), idleKeys: keys, ...(leadText === undefined ? {} : { leadIn: Number(leadText) }), seamPairs: on.has('--seam-pairs'), keepStills: on.has('--keep-stills'), ...(alts.length === 0 ? {} : { alts }), ...(flags.has('--set') ? { set: flags.get('--set') as string } : {}), allSets: on.has('--all-sets'), ...(flags.has('--environment') ? { environment: flags.get('--environment') as string } : {}) },
|
|
1899
|
+
{ config, source, full, head, out, seam: seam as SeamRule, project: project as ProjectRule, loop, pageEdges: edges, packShape: shape, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), idleKeys: keys, ...(leadText === undefined ? {} : { leadIn: Number(leadText) }), seamPairs: on.has('--seam-pairs'), keepStills: on.has('--keep-stills'), ...(alts.length === 0 ? {} : { alts }), ...(flags.has('--set') ? { set: flags.get('--set') as string } : {}), allSets: on.has('--all-sets'), ...(flags.has('--environment') ? { environment: flags.get('--environment') as string } : {}), ...(flags.has('--wind-band') ? { windBand: flags.get('--wind-band') as string } : {}) },
|
|
1861
1900
|
{ rig: rigcRunner(bin), check: rigcRunner(bin), checkBin: bin, scratch: join(scratch, 'rig-gate'), stages: {
|
|
1862
1901
|
assemble: (input, outputs) => runBuildProcess({ stage: 'assemble', bin, input, outputs }, join(scratch, 'workers')),
|
|
1863
1902
|
rig: (input, _rigc, gateScratch) => runBuildProcess({ stage: 'rig', bin, input, scratch: gateScratch }, join(scratch, 'workers')),
|