rig-parts 1.9.1 → 1.10.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 +2 -1
- package/cli.ts +128 -15
- package/docs/AUTHORING.md +121 -20
- package/docs/STABILITY.md +16 -7
- package/package.json +1 -1
- package/src/assemble.ts +100 -22
- package/src/build.ts +62 -9
- package/src/check.ts +150 -32
- package/src/config.ts +52 -6
- package/src/contour.ts +40 -2
- package/src/layers.ts +12 -7
- package/src/meshdraft.ts +887 -0
- package/src/parts.ts +41 -10
- package/src/propose.ts +137 -25
- package/src/requirements.ts +21 -6
- package/src/rig.ts +4 -3
- package/src/tags.ts +86 -0
- package/src/turn.ts +31 -0
package/README.md
CHANGED
|
@@ -283,12 +283,13 @@ agent skill.
|
|
|
283
283
|
| `propose --head-box --full <run> --canvas WxH` | propose `seethrough.head_box` from the full run, held inside the painting |
|
|
284
284
|
| `propose --parts --source --out [--compare <config>]` | 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 |
|
|
285
285
|
| `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)) |
|
|
286
|
+
| `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) |
|
|
286
287
|
| `propose … --from-config <config>` | draw and LINT the config's current bones (by the joints too, given `--keypoints`) |
|
|
287
288
|
| `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) |
|
|
288
289
|
| `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`) |
|
|
289
290
|
| `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*) |
|
|
290
291
|
| `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
|
|
291
|
-
| `build --config --source --full --head --out [--seam] [--project] [--loop] [--lead-in <periods>] [--requirements] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements`
|
|
292
|
+
| `build --config --source --full --head --out [--seam] [--project] [--loop] [--lead-in <periods>] [--requirements] [--seam-pairs] [--keep-stills] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements`, `--seam-pairs` and `--keep-stills` are forwarded to check, `--idle-keys` to rig; `--lead-in` (with `--loop`) encodes the loop from the last of n + 1 idle periods played back to back, for a rig whose physics does not end where the render starts it |
|
|
292
293
|
| `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*) |
|
|
293
294
|
|
|
294
295
|
`rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
|
package/cli.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, wri
|
|
|
16
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
|
-
import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns, readSource, rigStage } from './src/build.ts';
|
|
19
|
+
import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns, readSource, rigStage, suppliedCheckFlag } from './src/build.ts';
|
|
20
20
|
import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, 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
22
|
import { type CharacterConfig, loadConfig, loadEarlyConfig, loadPaintConfig } from './src/config.ts';
|
|
@@ -26,13 +26,15 @@ 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, draftTurn, drawLandmarks, FRINGE_STEP_PX, HIP_MIN_FRACTION, lint, lintLine, type PartSet, proposeWithBasis, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
29
|
+
import { basisLines, checkProposal, compare, compareLines, DEFAULT_GRID_RULE, draftTurn, drawLandmarks, FIGURE_GRID_DIVISOR, FRINGE_STEP_PX, GRID_RULES, type GridRule, HIP_MIN_FRACTION, lint, lintLine, type PartSet, proposeWithBasis, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
30
30
|
import { BASIS_FILE, BASIS_SPEC, basisFile, basisLine, coverageLines, serializeBasis } from './src/diagnostics.ts';
|
|
31
|
+
import { BEND_DEGREES, BEND_WORST_SHARE, DUST_MAX_PX, DUST_MAX_SHARE, IDLE_BOUND_PX, MESH_DRAFT_REPORT, MESH_DRAFT_SPEC, meshDraftStage, MORE_TRIANGLES_FLAG, TOLERANCE_FIGURE_DIVISOR } from './src/meshdraft.ts';
|
|
31
32
|
import { readPng, writePng } from './src/raster/png.ts';
|
|
32
33
|
import { REQUIREMENTS_SENTENCE } from './src/requirements.ts';
|
|
33
34
|
import { composeStage, IMAGE_SEP, PLATE, PROVENANCES, SCENE_REPORT_FILE, SCENE_REPORT_SPEC, SCENE_SPEC } from './src/scene.ts';
|
|
34
35
|
import { buildSheet, defaultCaption, type Tile, tilesFrom } from './src/sheet.ts';
|
|
35
36
|
import { loadComparison, requiredProblems, structureLines } from './src/structure.ts';
|
|
37
|
+
import { authorLayerLine } from './src/tags.ts';
|
|
36
38
|
|
|
37
39
|
const EXIT_OK = 0;
|
|
38
40
|
const EXIT_REFUSED = 1;
|
|
@@ -62,9 +64,11 @@ usage:
|
|
|
62
64
|
(alpha below 128), background share (min channel above 235) and area as a
|
|
63
65
|
multiple of the rest of the figure (the other layers' union). A layer that
|
|
64
66
|
crosses a plausibility rule gets a WARN line naming the rule and the bar;
|
|
65
|
-
--propose-plan leaves it out.
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
--propose-plan leaves it out. A layer named author:<label> is one the
|
|
68
|
+
author made by hand: its group is author, and a line says it has no
|
|
69
|
+
role. Refuses, by name, a missing file, an unknown tag, a PNG whose
|
|
70
|
+
size is not its box, and anything else outside the input contract —
|
|
71
|
+
never a WARN.
|
|
68
72
|
|
|
69
73
|
rig-parts sheet --source <painting.png> --layers <path> [--layers <path> ...]
|
|
70
74
|
--out <sheet.png> [--cell <px>] [--cols <n>]
|
|
@@ -77,7 +81,8 @@ usage:
|
|
|
77
81
|
rig-parts propose --parts <dir> --source <painting.png> --out <dir> [--compare <config.json>]
|
|
78
82
|
Propose bones, meshes, regions and an idle from the assembled parts (<dir>
|
|
79
83
|
holds parts.json and parts/). Roles come from each part's See-through tag,
|
|
80
|
-
never its name
|
|
84
|
+
never its name; a part from an author:<label> layer has no role and
|
|
85
|
+
rides the nearest trunk bone until the config names one. Writes <out>/proposal.json (config-shaped: bones, meshes,
|
|
81
86
|
regions, motion with its blink — and a blink.still cut for a lash that
|
|
82
87
|
reaches far above its eyewhite, when a clear row allows one; no blink
|
|
83
88
|
when no part is an eyewhite, and no brows in it when no part is an
|
|
@@ -149,6 +154,16 @@ usage:
|
|
|
149
154
|
or a layer with no depth is refused by name. Without either flag nothing
|
|
150
155
|
changes.
|
|
151
156
|
|
|
157
|
+
rig-parts propose … [--grid-rule figure|part]
|
|
158
|
+
How each drafted lattice's spacing (meshes.<part>.grid) is chosen.
|
|
159
|
+
figure, the default: round(H / ${FIGURE_GRID_DIVISOR}) rig px for every lattice, H the
|
|
160
|
+
height of every part's box together, and a part whose own spacing is
|
|
161
|
+
already coarser keeps it; a note says which parts took it, that it was
|
|
162
|
+
calibrated on three figures of similar size, and what it costs (the
|
|
163
|
+
idle moved against the finer lattice, which no bar reads). part: the
|
|
164
|
+
reference's rule, a tenth of the part's short side clamped to 5..36.
|
|
165
|
+
r is the part rule's under both.
|
|
166
|
+
|
|
152
167
|
rig-parts propose --parts <dir> --source <painting.png> --out <dir> --from-config <config.json>
|
|
153
168
|
Draw the config's CURRENT bones instead (<out>/render/landmarks_config.png
|
|
154
169
|
and _head) and LINT them (by the joints too, given --keypoints), with the
|
|
@@ -226,6 +241,42 @@ usage:
|
|
|
226
241
|
rig-c 1.3.0 or later and makes A15 a SKIP that prints its cost (the
|
|
227
242
|
stage prints that SKIP line). The pose is the same to one level of float
|
|
228
243
|
rounding, and so is the per-frame mesh work (AUTHORING §5).
|
|
244
|
+
rig-parts mesh-draft --config <config.json> --parts <dir> --out <dir> [--requirements <file.json>]
|
|
245
|
+
[--idle-keys ctl|direct] [--page-edges pot|free] [--pack-shape rect|polygon]
|
|
246
|
+
[--more-triangles]
|
|
247
|
+
Draft a traced outline around a coarse grid for every lattice mesh the
|
|
248
|
+
config states, and keep it only where it holds against that part's
|
|
249
|
+
lattice (issue #265). The config is read, never written: --out receives
|
|
250
|
+
config.json — the input's own text with each drafted part's meshes entry
|
|
251
|
+
replaced, every other byte as read — and ${MESH_DRAFT_REPORT} (spec
|
|
252
|
+
"${MESH_DRAFT_SPEC}": the rules, both checks' bars, and per part its
|
|
253
|
+
lattice and candidate triangles and overdraw, the five readings, each
|
|
254
|
+
with its margin to its line, and the note). H is the height of the union of the parts' boxes; the candidate is
|
|
255
|
+
contour {tolerance T, margin T, spacing S, maxEdge S, stray} with
|
|
256
|
+
T = max(1, round(H / ${TOLERANCE_FIGURE_DIVISOR})) and S = round(H / ${FIGURE_GRID_DIVISOR}) (a figure whose S is 0 is
|
|
257
|
+
refused, MESH_DRAFT_FIGURE), stray the largest dust island (at most
|
|
258
|
+
${DUST_MAX_PX} px and ${DUST_MAX_SHARE * 100} % of the part's art); a part with any other extra island
|
|
259
|
+
keeps its lattice. The config as written must build and check PASS first
|
|
260
|
+
(MESH_DRAFT_LATTICE_GREEN). Then each candidate is held to its lattice:
|
|
261
|
+
every check bar that reads the part passes on the drafted rig; within
|
|
262
|
+
${IDLE_BOUND_PX} rig px of the lattice over the idle; at the bend set (every chain
|
|
263
|
+
link the part's segments name turned ${BEND_DEGREES} degrees, both ways) no more
|
|
264
|
+
inverted triangles than the lattice and the worst sample within
|
|
265
|
+
${BEND_WORST_SHARE * 100} % of the lattice's, both against a denser lattice of the same
|
|
266
|
+
part; and no more triangles than the lattice — every motion reading
|
|
267
|
+
rig-c's (check, and compareMeshesInMotion over three unpacked gate
|
|
268
|
+
builds). The lattice is the config's own grid entry: for a proposed
|
|
269
|
+
config, the figure's spacing propose drafts. The gate is a judgment
|
|
270
|
+
relative to that lattice, not an absolute quality: when the lattice
|
|
271
|
+
coarsens, the reference moves with it. --more-triangles drafts a
|
|
272
|
+
candidate that holds the four motion readings even with more triangles
|
|
273
|
+
than its lattice, and the report records each part's triangle and
|
|
274
|
+
overdraw difference. A part that passes is drafted, its note saying
|
|
275
|
+
what it was measured against; one that fails keeps its entry, and the
|
|
276
|
+
report names each failed reading and by how much. Written only when the
|
|
277
|
+
drafted config's check is PASS. --requirements, --idle-keys,
|
|
278
|
+
--page-edges and --pack-shape are as for rig and check.
|
|
279
|
+
|
|
229
280
|
rig-parts check --rig <dir> --out <dir> [--parts <dir>] [--source <painting.png>]
|
|
230
281
|
[--page-edges pot|free] [--pack-shape rect|polygon]
|
|
231
282
|
[--requirements <file.json>] [--seam-pairs] [--keep-stills]
|
|
@@ -436,7 +487,7 @@ usage:
|
|
|
436
487
|
--head <dir|psd> --out <dir> [--seam near-white|silhouette]
|
|
437
488
|
[--project core|visible] [--page-edges pot|free]
|
|
438
489
|
[--pack-shape rect|polygon] [--loop] [--requirements <file.json>]
|
|
439
|
-
[--idle-keys ctl|direct] [--lead-in <periods>]
|
|
490
|
+
[--idle-keys ctl|direct] [--lead-in <periods>] [--seam-pairs] [--keep-stills]
|
|
440
491
|
assemble, then rig, then check, in one process, each stage's own lines
|
|
441
492
|
printed under [assemble], [rig] and [check]; the first stage that refuses
|
|
442
493
|
stops the build with its own FAIL lines. The config must already carry
|
|
@@ -459,6 +510,13 @@ usage:
|
|
|
459
510
|
and check's artifact, take them). --requirements is forwarded to check
|
|
460
511
|
(as for check); the file's own shape is read before assemble runs, and
|
|
461
512
|
its names resolve against the rig in the check, before it builds.
|
|
513
|
+
--seam-pairs and --keep-stills are forwarded to check (as for check:
|
|
514
|
+
the seam split by pair on a pass too, under check/seam/; the setup-pose
|
|
515
|
+
still under check/setup_still/). check's --rig and --parts are refused:
|
|
516
|
+
build's check reads the rig and the parts it wrote, <out>/rig and <out>.
|
|
517
|
+
build's --source is the painting assemble reads and is not handed to
|
|
518
|
+
the check, so check.json carries no SETUP_POSE_VS_SOURCE; run check
|
|
519
|
+
--rig <out>/rig --parts <out> --source <painting> for that line.
|
|
462
520
|
--idle-keys is forwarded to the rig stage (as for rig) and defaults to
|
|
463
521
|
ctl; the first line names it when it is direct. A config with a
|
|
464
522
|
two-bone ik over chain links the idle keys needs --idle-keys direct:
|
|
@@ -568,6 +626,8 @@ function printLayerTable(set: LayerSet): void {
|
|
|
568
626
|
for (const r of rows) console.log(line(r));
|
|
569
627
|
const painted = set.layers.filter((l) => l.opaquePx > 0).length;
|
|
570
628
|
console.log(` ${set.layers.length} layer(s): ${painted} with opaque pixels, ${set.layers.length - painted} with none`);
|
|
629
|
+
// Issue #256: a layer the author made is said to be one, so it never reads as See-through's. None, no line.
|
|
630
|
+
for (const l of set.layers) if (l.tag.group === 'author') console.log(` ${authorLayerLine(l.name)}`);
|
|
571
631
|
// A reader refuses nothing on plausibility: it says what --propose-plan will leave out, and why.
|
|
572
632
|
let warned = 0;
|
|
573
633
|
for (const f of figures) {
|
|
@@ -587,7 +647,7 @@ function printLayerTable(set: LayerSet): void {
|
|
|
587
647
|
const TAKES = {
|
|
588
648
|
sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
|
|
589
649
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
590
|
-
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap'], switches: ['--head-box'] },
|
|
650
|
+
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule'], switches: ['--head-box'] },
|
|
591
651
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
592
652
|
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements'], switches: ['--seam-pairs', '--keep-stills'] },
|
|
593
653
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
@@ -595,8 +655,9 @@ const TAKES = {
|
|
|
595
655
|
'comfy seethrough': { valued: ['--image', '--out', '--resolution', '--steps', '--seed', '--prefix', '--host', '--wait', '--timeout', '--poll'], switches: ['--offload', '--lama', '--nf4'] },
|
|
596
656
|
'comfy paint': { valued: ['--config', '--out', '--seeds', '--seed0', '--host', '--wait', '--timeout', '--poll'], switches: [] },
|
|
597
657
|
inputs: { valued: ['--source', '--config', '--out'], switches: [] },
|
|
598
|
-
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys', '--lead-in'], switches: ['--loop'] },
|
|
658
|
+
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys', '--lead-in'], switches: ['--loop', '--seam-pairs', '--keep-stills'] },
|
|
599
659
|
compose: { valued: ['--scene', '--out', '--requirements', '--accept'], switches: [] },
|
|
660
|
+
'mesh-draft': { valued: ['--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: ['--more-triangles'] },
|
|
600
661
|
} as const satisfies Record<string, { valued: readonly string[]; switches: readonly string[] }>;
|
|
601
662
|
|
|
602
663
|
type Command = keyof typeof TAKES;
|
|
@@ -891,6 +952,11 @@ function cmdPropose(args: string[]): number {
|
|
|
891
952
|
}
|
|
892
953
|
wristSnap = Number(snapArg);
|
|
893
954
|
}
|
|
955
|
+
// Issue #265: the drafted lattice's spacing; the figure's unless the reference's per-part rule is asked for.
|
|
956
|
+
const ruleArg = flags.get('--grid-rule');
|
|
957
|
+
if (ruleArg !== undefined && flags.has('--from-config')) return usage('--grid-rule chooses the drafted spacing; --from-config proposes nothing');
|
|
958
|
+
if (ruleArg !== undefined && !(GRID_RULES as readonly string[]).includes(ruleArg)) return usage(`--grid-rule ${ruleArg}; one of ${GRID_RULES.join(', ')} is required`);
|
|
959
|
+
const gridRule = (ruleArg ?? DEFAULT_GRID_RULE) as GridRule;
|
|
894
960
|
const partsDir = existsSync(partsArg) && statSync(partsArg).isFile() ? dirname(partsArg) : partsArg;
|
|
895
961
|
if (!existsSync(source)) {
|
|
896
962
|
throw new PartsError([{ code: 'PROPOSE_SOURCE_PRESENT', object: source, detail: 'no such file; the painting is drawn under the overlay' }]);
|
|
@@ -918,7 +984,7 @@ function cmdPropose(args: string[]): number {
|
|
|
918
984
|
}
|
|
919
985
|
const cmpPath = flags.get('--compare');
|
|
920
986
|
const cfg = cmpPath === undefined ? null : loadConfig(cmpPath);
|
|
921
|
-
const { proposal: drafted, basis } = proposeWithBasis(P, joints, wristSnap);
|
|
987
|
+
const { proposal: drafted, basis } = proposeWithBasis(P, joints, wristSnap, gridRule);
|
|
922
988
|
const fullRun = flags.get('--full');
|
|
923
989
|
const headRun = flags.get('--head');
|
|
924
990
|
const prop =
|
|
@@ -1175,14 +1241,19 @@ function cmdInputs(args: string[]): number {
|
|
|
1175
1241
|
|
|
1176
1242
|
function cmdBuild(args: string[]): number {
|
|
1177
1243
|
const flags = new Map<string, string>();
|
|
1178
|
-
|
|
1244
|
+
// The bare switches build takes: --loop its own, --seam-pairs and --keep-stills check's, forwarded (issue #257).
|
|
1245
|
+
const on = new Set<string>();
|
|
1246
|
+
const switches: readonly string[] = TAKES.build.switches;
|
|
1179
1247
|
for (let i = 0; i < args.length; i++) {
|
|
1180
1248
|
const flag = args[i];
|
|
1181
|
-
if (flag
|
|
1182
|
-
if (
|
|
1183
|
-
|
|
1249
|
+
if (switches.includes(flag)) {
|
|
1250
|
+
if (on.has(flag)) return usage(`${flag} is given twice`);
|
|
1251
|
+
on.add(flag);
|
|
1184
1252
|
continue;
|
|
1185
1253
|
}
|
|
1254
|
+
// A check flag whose value build supplies itself (--rig, --parts) is refused with what build reads instead (issue #257).
|
|
1255
|
+
const supplied = suppliedCheckFlag(flag);
|
|
1256
|
+
if (supplied !== null) return usage(supplied);
|
|
1186
1257
|
if (!takesValued('build', flag)) return usage(notTaken('build', flag));
|
|
1187
1258
|
const value = args[i + 1];
|
|
1188
1259
|
if (value === undefined) return usage(`${flag} needs a value`);
|
|
@@ -1201,6 +1272,7 @@ function cmdBuild(args: string[]): number {
|
|
|
1201
1272
|
if (!isPackShape(shape)) return usage(shape);
|
|
1202
1273
|
const keys = idleKeysOf(flags.get('--idle-keys'));
|
|
1203
1274
|
if (!isIdleKeys(keys)) return usage(keys);
|
|
1275
|
+
const loop = on.has('--loop');
|
|
1204
1276
|
const leadText = flags.get('--lead-in');
|
|
1205
1277
|
if (leadText !== undefined && !/^[1-9][0-9]*$/.test(leadText)) return usage(`--lead-in ${leadText}; a whole number of idle periods, 1 or more, is required`);
|
|
1206
1278
|
if (leadText !== undefined && !loop) return usage('--lead-in needs --loop; it says which frames the loop is encoded from');
|
|
@@ -1214,7 +1286,7 @@ function cmdBuild(args: string[]): number {
|
|
|
1214
1286
|
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-build-'));
|
|
1215
1287
|
try {
|
|
1216
1288
|
const r = build(
|
|
1217
|
-
{ 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) }) },
|
|
1289
|
+
{ 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') },
|
|
1218
1290
|
{ rig: rigcRunner(bin), check: rigcRunner(bin), checkBin: bin, scratch: join(scratch, 'rig-gate') },
|
|
1219
1291
|
console.log,
|
|
1220
1292
|
);
|
|
@@ -1248,6 +1320,46 @@ function cmdCompose(args: string[]): number {
|
|
|
1248
1320
|
}
|
|
1249
1321
|
}
|
|
1250
1322
|
|
|
1323
|
+
function cmdMeshDraft(args: string[]): number {
|
|
1324
|
+
// The one switch mesh-draft takes (#295): taken out before the valued flags are read.
|
|
1325
|
+
const more = args.filter((a) => a === MORE_TRIANGLES_FLAG).length;
|
|
1326
|
+
if (more > 1) return usage(`${MORE_TRIANGLES_FLAG} is given twice`);
|
|
1327
|
+
const f = flags(
|
|
1328
|
+
args.filter((a) => a !== MORE_TRIANGLES_FLAG),
|
|
1329
|
+
'mesh-draft',
|
|
1330
|
+
['--config', '--parts', '--out'],
|
|
1331
|
+
);
|
|
1332
|
+
if (typeof f === 'string') return usage(f);
|
|
1333
|
+
const keys = idleKeysOf(f.get('--idle-keys'));
|
|
1334
|
+
if (!isIdleKeys(keys)) return usage(keys);
|
|
1335
|
+
const edges = pageEdgesOf(f.get('--page-edges'));
|
|
1336
|
+
if (!isPageEdges(edges)) return usage(edges);
|
|
1337
|
+
const shape = packShapeOf(f.get('--pack-shape'));
|
|
1338
|
+
if (!isPackShape(shape)) return usage(shape);
|
|
1339
|
+
let bin: string;
|
|
1340
|
+
try {
|
|
1341
|
+
bin = findRigc(import.meta.dir, process.env.PATH ?? '');
|
|
1342
|
+
} catch (err) {
|
|
1343
|
+
return printRefusal(err);
|
|
1344
|
+
}
|
|
1345
|
+
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-mesh-draft-'));
|
|
1346
|
+
try {
|
|
1347
|
+
const req = f.get('--requirements');
|
|
1348
|
+
meshDraftStage(
|
|
1349
|
+
{ config: f.get('--config') as string, parts: f.get('--parts') as string, out: f.get('--out') as string, idleKeys: keys, pageEdges: edges, packShape: shape, ...(req === undefined ? {} : { requirements: req }), ...(more === 1 ? { moreTriangles: true } : {}) },
|
|
1350
|
+
rigcRunner(bin),
|
|
1351
|
+
bin,
|
|
1352
|
+
scratch,
|
|
1353
|
+
console.log,
|
|
1354
|
+
);
|
|
1355
|
+
return EXIT_OK;
|
|
1356
|
+
} catch (err) {
|
|
1357
|
+
return printRefusal(err);
|
|
1358
|
+
} finally {
|
|
1359
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1251
1363
|
function main(argv: string[]): number | Promise<number> {
|
|
1252
1364
|
const [command, ...rest] = argv;
|
|
1253
1365
|
if (command === undefined || command === '--help' || command === '-h' || command === 'help') {
|
|
@@ -1270,6 +1382,7 @@ function main(argv: string[]): number | Promise<number> {
|
|
|
1270
1382
|
if (command === 'comfy') return cmdComfy(rest);
|
|
1271
1383
|
if (command === 'build') return cmdBuild(rest);
|
|
1272
1384
|
if (command === 'compose') return cmdCompose(rest);
|
|
1385
|
+
if (command === 'mesh-draft') return cmdMeshDraft(rest);
|
|
1273
1386
|
const later = LATER.find(([name]) => name === command);
|
|
1274
1387
|
if (later !== undefined) {
|
|
1275
1388
|
console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}`);
|