rig-parts 1.50.0 → 1.52.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/cli.ts +52 -7
- package/docs/AUTHORING.md +152 -24
- package/docs/PAINTING.md +27 -2
- package/docs/STABILITY.md +5 -4
- package/package.json +1 -1
- package/src/assemble.ts +185 -7
- package/src/build.ts +30 -8
- package/src/check.ts +130 -10
- package/src/clothconfig.ts +67 -13
- package/src/config.ts +25 -9
- package/src/meshstats.ts +57 -0
- package/src/parts.ts +37 -5
package/cli.ts
CHANGED
|
@@ -30,7 +30,8 @@ import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJo
|
|
|
30
30
|
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, proposeWithBasis, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
31
31
|
import { BASIS_FILE, BASIS_SPEC, basisFile, basisLine, coverageLines, serializeBasis } from './src/diagnostics.ts';
|
|
32
32
|
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';
|
|
33
|
-
import {
|
|
33
|
+
import { meshStatsStage } from './src/meshstats.ts';
|
|
34
|
+
import { clothConfigEdits, editPaths, previousCount, writtenClothConfig } from './src/clothconfig.ts';
|
|
34
35
|
import { PROVENANCE_FILE, REMESH_SPEC, remeshStage } from './src/remesh.ts';
|
|
35
36
|
import { RETUNE_FILE, RETUNE_SPEC, retuneStage } from './src/retune.ts';
|
|
36
37
|
import { checkPainting } from './src/paintcheck.ts';
|
|
@@ -226,7 +227,7 @@ usage:
|
|
|
226
227
|
a LINT line names each drafted radius and both figures. Without --cloth
|
|
227
228
|
nothing changes.
|
|
228
229
|
|
|
229
|
-
rig-parts propose … --cloth <config.json> [--write-config <out.json>]
|
|
230
|
+
rig-parts propose … --cloth <config.json> [--write-config <out.json> [--from <previous.json>]]
|
|
230
231
|
Also write the --cloth config's own text with what the recipe drafts
|
|
231
232
|
spliced in (issue #537), the way mesh-draft writes its config, so that
|
|
232
233
|
rig --config <out.json> builds it. What is spliced is measured: the
|
|
@@ -246,6 +247,14 @@ usage:
|
|
|
246
247
|
(PROPOSE_WRITE_CONFIG_CONFLICT), or when the spliced text does not
|
|
247
248
|
parse to the config with the sections set, naming the first key
|
|
248
249
|
that moved (PROPOSE_WRITE_CONFIG_SPLICE).
|
|
250
|
+
--from <previous.json> (issue #571, only with --write-config) names
|
|
251
|
+
the config the recipe is changed from: its cloth block is read as
|
|
252
|
+
--cloth's is, the same parts are drafted a third time with it, and an
|
|
253
|
+
entry equal to that previous recipe's draft is the recipe's, replaced
|
|
254
|
+
(or removed) as one equal to the draft without the recipe is; an entry
|
|
255
|
+
equal to none of the three drafts is still refused by name, its field
|
|
256
|
+
read against the previous recipe's draft. The write line counts the
|
|
257
|
+
entries the previous draft vouched for. Without --from nothing changes.
|
|
249
258
|
|
|
250
259
|
rig-parts propose --parts <dir> --source <painting.png> --out <dir> --from-config <config.json>
|
|
251
260
|
Draw the config's CURRENT bones instead (<out>/render/landmarks_config.png
|
|
@@ -365,6 +374,21 @@ usage:
|
|
|
365
374
|
Written only when the drafted config's check is PASS. --requirements, --idle-keys,
|
|
366
375
|
--page-edges and --pack-shape are as for rig and check.
|
|
367
376
|
|
|
377
|
+
rig-parts mesh-stats --config <config.json> --parts <dir>
|
|
378
|
+
Print the vertices and triangles of every mesh the config states, as the
|
|
379
|
+
rig stage would make them from the parts in --parts (the directory
|
|
380
|
+
holding parts.json and parts/<name>.png), and their total, in seconds:
|
|
381
|
+
the rig stage's own mesh construction, without rigc, without assemble
|
|
382
|
+
and without check (issue #566). One line per mesh in parts.json's order,
|
|
383
|
+
"mesh-stats: <part> — <mode> <V> vertices, <T> triangles" (mode lattice,
|
|
384
|
+
contour, auto or influence), then "mesh-stats: total <N> triangles over
|
|
385
|
+
<M> mesh(es)"; the counts are the ones the rig stage writes to
|
|
386
|
+
mesh_report.json, except an auto part's when rigc's motion gate refuses
|
|
387
|
+
its reduction and the rig stage replays an earlier accepted step, which
|
|
388
|
+
the auto line says. A problem the rig stage refuses (a missing part PNG,
|
|
389
|
+
an outline that does not close, a bone no config entry declares) is the
|
|
390
|
+
rig stage's own refusal, exit 1. Writes nothing.
|
|
391
|
+
|
|
368
392
|
rig-parts remesh --rig <dir> --config <config.json> --parts <dir> --part <name>
|
|
369
393
|
--mesh <entry.json> --out <dir> [--requirements <file.json>]
|
|
370
394
|
(or --delta <mesh-edit.json> in place of --mesh)
|
|
@@ -915,7 +939,7 @@ const TAKES = {
|
|
|
915
939
|
layers: { valued: ['--export', '--template', '--canvas'], switches: [] },
|
|
916
940
|
sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
|
|
917
941
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
918
|
-
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule', '--cloth', '--write-config'], switches: ['--head-box', '--no-back-hair'] },
|
|
942
|
+
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'] },
|
|
919
943
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
920
944
|
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements', '--set', '--environment'], switches: ['--seam-pairs', '--keep-stills', '--all-sets'] },
|
|
921
945
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
@@ -926,6 +950,7 @@ const TAKES = {
|
|
|
926
950
|
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'] },
|
|
927
951
|
compose: { valued: ['--scene', '--out', '--requirements', '--accept'], switches: [] },
|
|
928
952
|
'mesh-draft': { valued: ['--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: ['--more-triangles'] },
|
|
953
|
+
'mesh-stats': { valued: ['--config', '--parts'], switches: [] },
|
|
929
954
|
remesh: { valued: ['--rig', '--config', '--parts', '--part', '--mesh', '--delta', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
930
955
|
retune: { valued: ['--rig', '--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
931
956
|
painting: { valued: ['--keypoints', '--person'], switches: [] },
|
|
@@ -1316,6 +1341,9 @@ function cmdPropose(args: string[]): number {
|
|
|
1316
1341
|
const writeArg = flags.get('--write-config');
|
|
1317
1342
|
if (writeArg !== undefined && flags.has('--from-config')) return usage('--write-config writes what the recipe drafts into its config; --from-config proposes nothing');
|
|
1318
1343
|
if (writeArg !== undefined && clothArg === undefined) return usage('--write-config writes the --cloth config with what its recipe drafts spliced in; give --cloth <config.json>');
|
|
1344
|
+
// 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.
|
|
1345
|
+
const fromArg = flags.get('--from');
|
|
1346
|
+
if (fromArg !== undefined && writeArg === undefined) return usage('--from names the config the recipe is changed from, for --write-config; give --write-config <out.json>');
|
|
1319
1347
|
if (writeArg !== undefined) {
|
|
1320
1348
|
const ours = ['proposal.json', BASIS_FILE].map((f) => resolve(out, f));
|
|
1321
1349
|
if (existsSync(writeArg) || ours.includes(resolve(writeArg))) {
|
|
@@ -1323,6 +1351,7 @@ function cmdPropose(args: string[]): number {
|
|
|
1323
1351
|
}
|
|
1324
1352
|
}
|
|
1325
1353
|
const cloth = clothArg === undefined ? null : loadClothConfig(clothArg).cloth;
|
|
1354
|
+
const previousCloth = fromArg === undefined ? null : loadClothConfig(fromArg).cloth;
|
|
1326
1355
|
const partsDir = existsSync(partsArg) && statSync(partsArg).isFile() ? dirname(partsArg) : partsArg;
|
|
1327
1356
|
if (!existsSync(source)) {
|
|
1328
1357
|
throw new PartsError([{ code: 'PROPOSE_SOURCE_PRESENT', object: source, detail: 'no such file; the painting is drawn under the overlay' }]);
|
|
@@ -1366,8 +1395,10 @@ function cmdPropose(args: string[]): number {
|
|
|
1366
1395
|
: (() => {
|
|
1367
1396
|
const text = readFileSync(clothArg, 'utf8');
|
|
1368
1397
|
// Issue #552: bones, constraints and motion.tracks entry by entry; a hand edit the recipe would drop is refused by name.
|
|
1369
|
-
|
|
1370
|
-
|
|
1398
|
+
// Issue #571: with --from, the same parts drafted a third time with the previous recipe.
|
|
1399
|
+
const previous = previousCloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, previousCloth).proposal;
|
|
1400
|
+
const edits = clothConfigEdits(drafted, proposeWithBasis(P, joints, wristSnap, gridRule, null).proposal, JSON.parse(text) as unknown, false, previous);
|
|
1401
|
+
return { at: writeArg, text: writtenClothConfig(clothArg, text, edits), paths: editPaths(edits), vouched: previousCount(edits), relative: relativeConfigPaths(dirname(resolve(clothArg)), JSON.parse(text) as Record<string, unknown>) };
|
|
1371
1402
|
})();
|
|
1372
1403
|
const bfile = basisFile(P, prop, basis, cfg === null || cmpPath === undefined ? null : { where: cmpPath, config: cfg });
|
|
1373
1404
|
const img = drawLandmarks(P, painting, prop.bones, 'PROPOSAL - CORRECT ME');
|
|
@@ -1385,10 +1416,11 @@ function cmdPropose(args: string[]): number {
|
|
|
1385
1416
|
printLint(P, prop, joints, draftLint);
|
|
1386
1417
|
console.log(basisLine(bfile, out));
|
|
1387
1418
|
if (written !== null && clothArg !== undefined) {
|
|
1419
|
+
const from = fromArg === undefined ? '' : `; --from ${fromArg}: ${written.vouched} ${written.vouched === 1 ? 'entry' : 'entries'} taken as the previous recipe's draft`;
|
|
1388
1420
|
console.log(
|
|
1389
1421
|
written.paths.length > 0
|
|
1390
|
-
? `wrote ${written.at}: ${clothArg}'s text with ${written.paths.join(', ')} spliced in from the draft; every other byte as read`
|
|
1391
|
-
: `wrote ${written.at}: ${clothArg}'s text byte for byte; every entry the recipe drafts is already as drafted`,
|
|
1422
|
+
? `wrote ${written.at}: ${clothArg}'s text with ${written.paths.join(', ')} spliced in from the draft; every other byte as read${from}`
|
|
1423
|
+
: `wrote ${written.at}: ${clothArg}'s text byte for byte; every entry the recipe drafts is already as drafted${from}`,
|
|
1392
1424
|
);
|
|
1393
1425
|
if (written.relative.length > 0 && dirname(resolve(written.at)) !== dirname(resolve(clothArg))) {
|
|
1394
1426
|
console.log(`note: ${written.relative.map((r) => `${r.at} "${r.value}"`).join(', ')} written as stated; the loader resolves each against the directory the config sits in, ${dirname(written.at)} for ${written.at}, not ${dirname(clothArg)}; put the config beside ${clothArg} or rewrite them`);
|
|
@@ -1774,6 +1806,18 @@ function cmdMeshDraft(args: string[]): number {
|
|
|
1774
1806
|
}
|
|
1775
1807
|
}
|
|
1776
1808
|
|
|
1809
|
+
/** `mesh-stats --config <config.json> --parts <dir>` (issue #566): every configured mesh's counts, through the rig stage's own `buildRig`, without rigc. Writes nothing. */
|
|
1810
|
+
function cmdMeshStats(args: string[]): number {
|
|
1811
|
+
const f = flags(args, 'mesh-stats', ['--config', '--parts']);
|
|
1812
|
+
if (typeof f === 'string') return usage(f);
|
|
1813
|
+
try {
|
|
1814
|
+
meshStatsStage({ config: f.get('--config') as string, parts: f.get('--parts') as string }, console.log);
|
|
1815
|
+
return EXIT_OK;
|
|
1816
|
+
} catch (err) {
|
|
1817
|
+
return printRefusal(err);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1777
1821
|
/** `remesh` (issue #495): one part of a gated rig re-fitted under a requested mesh entry, into a new revision. */
|
|
1778
1822
|
function cmdRemesh(args: string[]): number {
|
|
1779
1823
|
const f = flags(args, 'remesh', ['--rig', '--config', '--parts', '--part', '--out']);
|
|
@@ -1922,6 +1966,7 @@ function main(argv: string[]): number | Promise<number> {
|
|
|
1922
1966
|
if (command === 'build') return cmdBuild(rest);
|
|
1923
1967
|
if (command === 'compose') return cmdCompose(rest);
|
|
1924
1968
|
if (command === 'mesh-draft') return cmdMeshDraft(rest);
|
|
1969
|
+
if (command === 'mesh-stats') return cmdMeshStats(rest);
|
|
1925
1970
|
if (command === 'remesh') return cmdRemesh(rest);
|
|
1926
1971
|
if (command === 'retune') return cmdRetune(rest);
|
|
1927
1972
|
if (command === 'painting') return cmdPainting(rest);
|