rig-parts 2.8.0 → 2.9.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 +1 -1
- package/cli.ts +42 -5
- package/docs/AUTHORING.md +204 -12
- package/docs/MIGRATION.md +20 -1
- package/docs/STABILITY.md +7 -1
- package/package.json +1 -1
- package/skills/rig-parts/SKILL.md +1 -1
- package/src/assemble.ts +32 -11
- package/src/build.ts +29 -7
- package/src/check.ts +201 -30
- package/src/coincide.ts +157 -0
- package/src/coincideio.ts +79 -0
- package/src/config.ts +41 -4
- package/src/diffcomponents.ts +208 -0
- package/src/edgeresidual.ts +191 -0
- package/src/mesh.ts +29 -2
- package/src/meshdraft.ts +8 -49
- package/src/propose.ts +150 -5
- package/src/supportdomains.ts +76 -0
- package/tools/build-process.ts +31 -9
package/README.md
CHANGED
|
@@ -276,7 +276,7 @@ rig-parts assemble --source painting.png --full layers/full --head layers/head -
|
|
|
276
276
|
# -> read the `uncovered hole N:` lines and look at work/render/recomposite_error_rig.png:
|
|
277
277
|
# red is painting that no part holds, and no later gate can see it
|
|
278
278
|
# -> a large red hole neither run holds? add an assemble.patches entry (cut from the painting) and assemble again
|
|
279
|
-
rig-parts propose --parts work/rig --source painting.png --out work
|
|
279
|
+
rig-parts propose --parts work/rig --bust-landmarks bust-landmarks.json --source painting.png --out work
|
|
280
280
|
# -> proposal.json, basis.json (what each bone rests on) and render/landmarks.png; per-bone coverage lines;
|
|
281
281
|
# correct it, copy bones/meshes/regions/limbs/motion/constraints/turn/motion_seams/proposed_rig_scale into config.json, each it wrote
|
|
282
282
|
# (limbs only with --keypoints, constraints only with --cloth, turn only with --full/--head;
|
package/cli.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { diffComponentsCommand } from './src/diffcomponents.ts';
|
|
2
3
|
import { applyTakenLayers } from './src/takelayers.ts';
|
|
3
4
|
import { applyDepth, prepareDepth } from './src/depthworkflow.ts';
|
|
4
5
|
/**
|
|
@@ -33,7 +34,7 @@ import { makeInputs } from './src/inputs.ts';
|
|
|
33
34
|
import { idleKeysOf, isIdleKeys } from './src/rig.ts';
|
|
34
35
|
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';
|
|
35
36
|
import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJoints, toRigJoints } from './src/keypoints.ts';
|
|
36
|
-
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';
|
|
37
|
+
import { basisLines, branchSqueezeLine, checkProposal, compare, compareLines, DEFAULT_GRID_RULE, draftTurn, drawLandmarks, FIGURE_GRID_DIVISOR, FRINGE_STEP_PX, GRID_RULES, type GridRule, type BustDraft, HIP_MIN_FRACTION, type DraftLintFinding, lint, lintLine, type PartSet, PROPOSAL_CONFIG_SECTIONS, proposalAsConfig, proposeWithBasis, readBustLandmarks, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
37
38
|
import { BASIS_FILE, BASIS_SPEC, basisFile, basisLine, coverageLines, legChainChoice, serializeBasis } from './src/diagnostics.ts';
|
|
38
39
|
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, relativeConfigPaths, TOLERANCE_FIGURE_DIVISOR } from './src/meshdraft.ts';
|
|
39
40
|
import { meshStatsStage } from './src/meshstats.ts';
|
|
@@ -68,6 +69,11 @@ const LATER: ReadonlyArray<[string, string]> = [];
|
|
|
68
69
|
const HELP = `rig-parts ${version()} — Spine-ready parts from one painting and its See-through layers
|
|
69
70
|
|
|
70
71
|
usage:
|
|
72
|
+
rig-parts diff-components --stack <png> --painting <png> --parts <parts.json> --floor <px>
|
|
73
|
+
[--threshold <channel>] [--figure <binary-png>] (--out <json> | --verify <json>)
|
|
74
|
+
Exhaustive native difference inventory; default max RGB channel > 40.
|
|
75
|
+
|
|
76
|
+
|
|
71
77
|
rig-parts depth-prepare --parts <assembled-dir> --config <depth-recipe.json> --out <empty-dir>
|
|
72
78
|
Write per-part inference PNGs on neutral gray, upscaled and padded as
|
|
73
79
|
declared, plus a source-hashed manifest. No model is bundled or called.
|
|
@@ -177,6 +183,10 @@ usage:
|
|
|
177
183
|
bone differs (origin, tip, parent; how far, in px). No confidence is
|
|
178
184
|
computed. It prints "wrote ${BASIS_FILE} (…)" after the coverage lines.
|
|
179
185
|
|
|
186
|
+
rig-parts propose … (--bust-landmarks <landmarks.json> | --no-bust <reason>)
|
|
187
|
+
Draft the chest-holding topwear as contour. Landmark JSON declares apex_r,
|
|
188
|
+
apex_l and optional cleavage in rig pixels. Without cleavage, intersect
|
|
189
|
+
their segment with the neck-to-hip midline. --no-bust needs a stated reason.
|
|
180
190
|
rig-parts propose … [--keypoints <keypoints.json> [--person <id>] [--wrist-snap <px>]]
|
|
181
191
|
Read the figure's pose from one explicit file (spec "${KEYPOINTS_SPEC}"):
|
|
182
192
|
its space (painting-px, origin top-left, y down — another is refused),
|
|
@@ -1016,6 +1026,14 @@ function usage(message: string): number {
|
|
|
1016
1026
|
return EXIT_USAGE;
|
|
1017
1027
|
}
|
|
1018
1028
|
|
|
1029
|
+
function cmdDiffComponents(args: string[]): number {
|
|
1030
|
+
for (let i = 0; i < args.length; i += 2) {
|
|
1031
|
+
if (!takesValued('diff-components', args[i])) return usage(notTaken('diff-components', args[i]));
|
|
1032
|
+
if (args[i + 1] === undefined || args[i + 1].startsWith('--')) return usage(`diff-components ${args[i]} requires a value`);
|
|
1033
|
+
}
|
|
1034
|
+
try { diffComponentsCommand(args); return EXIT_OK; } catch (err) { return printRefusal(err); }
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1019
1037
|
/** `guide`: one argument, a rule name or a section; the slice printed, or the refusal. */
|
|
1020
1038
|
function cmdGuide(args: string[]): number {
|
|
1021
1039
|
if (args.length !== 1) return usage(`guide takes one rule name or one §<n> / §<n>.<m> / §<n>.<m>.<k>; got ${args.length} argument(s)`);
|
|
@@ -1104,12 +1122,13 @@ function printLayerTable(set: LayerSet): void {
|
|
|
1104
1122
|
* no row; `layers` takes one positional path beside its flags (issue #359).
|
|
1105
1123
|
*/
|
|
1106
1124
|
const TAKES = {
|
|
1125
|
+
'diff-components': { valued: ['--stack', '--painting', '--parts', '--figure', '--floor', '--threshold', '--out', '--verify'], switches: [] },
|
|
1107
1126
|
'depth-prepare': { valued: ['--parts', '--config', '--out'], switches: [] },
|
|
1108
1127
|
'depth-apply': { valued: ['--parts', '--manifest', '--config', '--rig-config', '--out'], switches: [] },
|
|
1109
1128
|
layers: { valued: ['--export', '--template', '--canvas', '--full', '--source', '--config'], switches: [] },
|
|
1110
1129
|
sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
|
|
1111
1130
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
1112
|
-
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'] },
|
|
1131
|
+
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule', '--cloth', '--write-config', '--from', '--bust-landmarks', '--no-bust'], switches: ['--head-box', '--no-back-hair', '--only-missing'] },
|
|
1113
1132
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
1114
1133
|
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements', '--set', '--environment', '--wind-band'], switches: ['--seam-pairs', '--keep-stills', '--all-sets', '--no-extremes', '--json'] },
|
|
1115
1134
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
@@ -1557,6 +1576,7 @@ function cmdPropose(args: string[]): number {
|
|
|
1557
1576
|
return EXIT_OK;
|
|
1558
1577
|
}
|
|
1559
1578
|
}
|
|
1579
|
+
if (flags.has('--from-config') && (flags.has('--bust-landmarks') || flags.has('--no-bust'))) return usage('--bust-landmarks and --no-bust draft a torso. --from-config reads authored meshes');
|
|
1560
1580
|
const P = readPartSet(partsDir);
|
|
1561
1581
|
const painting = readPng(source);
|
|
1562
1582
|
// Issue #75: the keypoint file, held to this painting's size and taken to rig px by the overlay's map.
|
|
@@ -1580,7 +1600,23 @@ function cmdPropose(args: string[]): number {
|
|
|
1580
1600
|
}
|
|
1581
1601
|
const cmpPath = flags.get('--compare');
|
|
1582
1602
|
const cfg = cmpPath === undefined ? null : loadConfig(cmpPath);
|
|
1583
|
-
const
|
|
1603
|
+
const noBust = flags.get('--no-bust');
|
|
1604
|
+
const bustPath = flags.get('--bust-landmarks');
|
|
1605
|
+
if (noBust !== undefined && (noBust.trim().length === 0 || bustPath !== undefined)) return usage('--no-bust requires a non-blank reason and cannot accompany --bust-landmarks');
|
|
1606
|
+
const bust: BustDraft = {};
|
|
1607
|
+
if (noBust !== undefined) bust.noBust = noBust;
|
|
1608
|
+
if (bustPath !== undefined) {
|
|
1609
|
+
try {
|
|
1610
|
+
bust.landmarks = readBustLandmarks(JSON.parse(readFileSync(bustPath, 'utf8')) as unknown);
|
|
1611
|
+
} catch (error) {
|
|
1612
|
+
if (error instanceof PartsError) throw error;
|
|
1613
|
+
throw new PartsError([{
|
|
1614
|
+
code: 'PROPOSE_BUST_INPUT', object: '--bust-landmarks',
|
|
1615
|
+
detail: `cannot read the declared JSON file (${error instanceof Error ? error.message : String(error)}). Give an object with apex_r, apex_l and optional cleavage in rig pixels`,
|
|
1616
|
+
}]);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
const { proposal: drafted, basis, draftLint } = proposeWithBasis(P, joints, wristSnap, gridRule, cloth, true, bust);
|
|
1584
1620
|
const fullRun = flags.get('--full');
|
|
1585
1621
|
const headRun = flags.get('--head');
|
|
1586
1622
|
const prop =
|
|
@@ -1590,7 +1626,7 @@ function cmdPropose(args: string[]): number {
|
|
|
1590
1626
|
// Emit only after green: a proposal the config loader would refuse is not written, nor a basis record that does not hold to it.
|
|
1591
1627
|
checkProposal(P, prop);
|
|
1592
1628
|
// The same parts drafted without the recipe: what --write-config measures its edits against, and what issue #572's chain reading compares with.
|
|
1593
|
-
const plain = cloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, null).proposal;
|
|
1629
|
+
const plain = cloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, null, true, bust).proposal;
|
|
1594
1630
|
// Issue #537: the sections the recipe moves, measured against the same parts drafted without it, spliced before anything is written.
|
|
1595
1631
|
const written =
|
|
1596
1632
|
writeArg === undefined || clothArg === undefined || plain === null
|
|
@@ -1599,7 +1635,7 @@ function cmdPropose(args: string[]): number {
|
|
|
1599
1635
|
const text = readFileSync(clothArg, 'utf8');
|
|
1600
1636
|
// Issue #552: bones, constraints and motion.tracks entry by entry; a hand edit the recipe would drop is refused by name.
|
|
1601
1637
|
// Issue #571: with --from, the same parts drafted a third time with the previous recipe.
|
|
1602
|
-
const previous = previousCloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, previousCloth).proposal;
|
|
1638
|
+
const previous = previousCloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, previousCloth, true, bust).proposal;
|
|
1603
1639
|
const edits = clothConfigEdits(drafted, plain, JSON.parse(text) as unknown, false, previous);
|
|
1604
1640
|
return { at: writeArg, input: text, text: writtenClothConfig(clothArg, text, edits), paths: editPaths(edits), vouched: previousCount(edits), returned: plainCount(edits), relative: relativeConfigPaths(dirname(resolve(clothArg)), JSON.parse(text) as Record<string, unknown>) };
|
|
1605
1641
|
})();
|
|
@@ -2257,6 +2293,7 @@ function main(argv: string[]): number | Promise<number> {
|
|
|
2257
2293
|
console.log(version());
|
|
2258
2294
|
return EXIT_OK;
|
|
2259
2295
|
}
|
|
2296
|
+
if (command === 'diff-components') return cmdDiffComponents(rest);
|
|
2260
2297
|
if (command === 'layers') return cmdLayers(rest);
|
|
2261
2298
|
if (command === 'depth-prepare') return cmdDepthPrepare(rest);
|
|
2262
2299
|
if (command === 'depth-apply') return cmdDepthApply(rest);
|