rig-parts 1.51.0 → 1.53.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 +64 -8
- package/docs/AUTHORING.md +324 -26
- package/docs/PAINTING.md +27 -2
- package/docs/STABILITY.md +2 -1
- package/package.json +1 -1
- package/src/assemble.ts +180 -14
- package/src/build.ts +23 -5
- package/src/check.ts +139 -12
- package/src/clothconfig.ts +78 -1
- package/src/config.ts +34 -16
- package/src/instruments.ts +9 -2
- package/src/limbs.ts +10 -0
- package/src/meshstats.ts +57 -0
- package/src/parts.ts +36 -5
- package/src/propose.ts +204 -11
package/cli.ts
CHANGED
|
@@ -27,10 +27,11 @@ import { makeInputs } from './src/inputs.ts';
|
|
|
27
27
|
import { idleKeysOf, isIdleKeys } from './src/rig.ts';
|
|
28
28
|
import { depthSkipLine, exportLayers, figuresPhrase, hiddenLayerLine, implausibleRules, layerFigures, type LayerSet, layerSetDiff, pct, readLayers, readWrapperLayers, ruleSummary, templateLayerNames, templatePsdBytes, times } from './src/layers.ts';
|
|
29
29
|
import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJoints, toRigJoints } from './src/keypoints.ts';
|
|
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';
|
|
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, proposalAsConfig, 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 { chainsLeftBehind, 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';
|
|
@@ -223,8 +224,12 @@ usage:
|
|
|
223
224
|
({across, max, shape}, issue #518) drafts the parts it meshes in the
|
|
224
225
|
influence mode at their lattice's cell, the radius as stated or drafted
|
|
225
226
|
as the farthest lattice vertex from its nearest link plus 3 cells, and
|
|
226
|
-
a LINT line names each drafted radius and both figures.
|
|
227
|
-
|
|
227
|
+
a LINT line names each drafted radius and both figures. A keyed bone
|
|
228
|
+
the recipe leaves the only keyed child of its parent joins it in one
|
|
229
|
+
chain CHAIN_LAG holds to non-decreasing amplitudes (issue #572): a LINT
|
|
230
|
+
line names each link of such a chain below the link above, with both
|
|
231
|
+
amplitudes and the least that passes; no amplitude is changed. Without
|
|
232
|
+
--cloth nothing changes.
|
|
228
233
|
|
|
229
234
|
rig-parts propose … --cloth <config.json> [--write-config <out.json> [--from <previous.json>]]
|
|
230
235
|
Also write the --cloth config's own text with what the recipe drafts
|
|
@@ -373,6 +378,21 @@ usage:
|
|
|
373
378
|
Written only when the drafted config's check is PASS. --requirements, --idle-keys,
|
|
374
379
|
--page-edges and --pack-shape are as for rig and check.
|
|
375
380
|
|
|
381
|
+
rig-parts mesh-stats --config <config.json> --parts <dir>
|
|
382
|
+
Print the vertices and triangles of every mesh the config states, as the
|
|
383
|
+
rig stage would make them from the parts in --parts (the directory
|
|
384
|
+
holding parts.json and parts/<name>.png), and their total, in seconds:
|
|
385
|
+
the rig stage's own mesh construction, without rigc, without assemble
|
|
386
|
+
and without check (issue #566). One line per mesh in parts.json's order,
|
|
387
|
+
"mesh-stats: <part> — <mode> <V> vertices, <T> triangles" (mode lattice,
|
|
388
|
+
contour, auto or influence), then "mesh-stats: total <N> triangles over
|
|
389
|
+
<M> mesh(es)"; the counts are the ones the rig stage writes to
|
|
390
|
+
mesh_report.json, except an auto part's when rigc's motion gate refuses
|
|
391
|
+
its reduction and the rig stage replays an earlier accepted step, which
|
|
392
|
+
the auto line says. A problem the rig stage refuses (a missing part PNG,
|
|
393
|
+
an outline that does not close, a bone no config entry declares) is the
|
|
394
|
+
rig stage's own refusal, exit 1. Writes nothing.
|
|
395
|
+
|
|
376
396
|
rig-parts remesh --rig <dir> --config <config.json> --parts <dir> --part <name>
|
|
377
397
|
--mesh <entry.json> --out <dir> [--requirements <file.json>]
|
|
378
398
|
(or --delta <mesh-edit.json> in place of --mesh)
|
|
@@ -934,6 +954,7 @@ const TAKES = {
|
|
|
934
954
|
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'] },
|
|
935
955
|
compose: { valued: ['--scene', '--out', '--requirements', '--accept'], switches: [] },
|
|
936
956
|
'mesh-draft': { valued: ['--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: ['--more-triangles'] },
|
|
957
|
+
'mesh-stats': { valued: ['--config', '--parts'], switches: [] },
|
|
937
958
|
remesh: { valued: ['--rig', '--config', '--parts', '--part', '--mesh', '--delta', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
938
959
|
retune: { valued: ['--rig', '--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
939
960
|
painting: { valued: ['--keypoints', '--person'], switches: [] },
|
|
@@ -1371,18 +1392,39 @@ function cmdPropose(args: string[]): number {
|
|
|
1371
1392
|
: withTurn(drafted, draftTurn(P, { ...(fullRun === undefined ? {} : { full: readLayers(fullRun) }), ...(headRun === undefined ? {} : { head: readLayers(headRun) }) }, drafted));
|
|
1372
1393
|
// Emit only after green: a proposal the config loader would refuse is not written, nor a basis record that does not hold to it.
|
|
1373
1394
|
checkProposal(P, prop);
|
|
1395
|
+
// The same parts drafted without the recipe: what --write-config measures its edits against, and what issue #572's chain reading compares with.
|
|
1396
|
+
const plain = cloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, null).proposal;
|
|
1374
1397
|
// Issue #537: the sections the recipe moves, measured against the same parts drafted without it, spliced before anything is written.
|
|
1375
1398
|
const written =
|
|
1376
|
-
writeArg === undefined || clothArg === undefined
|
|
1399
|
+
writeArg === undefined || clothArg === undefined || plain === null
|
|
1377
1400
|
? null
|
|
1378
1401
|
: (() => {
|
|
1379
1402
|
const text = readFileSync(clothArg, 'utf8');
|
|
1380
1403
|
// Issue #552: bones, constraints and motion.tracks entry by entry; a hand edit the recipe would drop is refused by name.
|
|
1381
1404
|
// Issue #571: with --from, the same parts drafted a third time with the previous recipe.
|
|
1382
1405
|
const previous = previousCloth === null ? null : proposeWithBasis(P, joints, wristSnap, gridRule, previousCloth).proposal;
|
|
1383
|
-
const edits = clothConfigEdits(drafted,
|
|
1384
|
-
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>) };
|
|
1406
|
+
const edits = clothConfigEdits(drafted, plain, JSON.parse(text) as unknown, false, previous);
|
|
1407
|
+
return { at: writeArg, input: text, text: writtenClothConfig(clothArg, text, edits), paths: editPaths(edits), vouched: previousCount(edits), relative: relativeConfigPaths(dirname(resolve(clothArg)), JSON.parse(text) as Record<string, unknown>) };
|
|
1385
1408
|
})();
|
|
1409
|
+
// Issue #572: the keyed chains CHAIN_LAG reads only once the recipe took its trees' idle keys — in the config written
|
|
1410
|
+
// against the --cloth config with --write-config, else in the proposal against the draft without the recipe.
|
|
1411
|
+
const leftBehind: { findings: DraftLintFinding[]; unread: string | null } = (() => {
|
|
1412
|
+
if (plain === null) return { findings: [], unread: null };
|
|
1413
|
+
if (written === null) return { findings: chainsLeftBehind(proposalAsConfig(P, plain), proposalAsConfig(P, prop)), unread: null };
|
|
1414
|
+
const read = (what: string, text: string): CharacterConfig | string => {
|
|
1415
|
+
try {
|
|
1416
|
+
return proposalAsConfig(P, JSON.parse(text) as Record<string, unknown>);
|
|
1417
|
+
} catch (err) {
|
|
1418
|
+
if (!(err instanceof PartsError)) throw err;
|
|
1419
|
+
return `${what} does not load as a config (${err.problems[0].code}: ${err.problems[0].object})`;
|
|
1420
|
+
}
|
|
1421
|
+
};
|
|
1422
|
+
const before = read(String(clothArg), written.input);
|
|
1423
|
+
const after = read(written.at, written.text);
|
|
1424
|
+
if (typeof before === 'string') return { findings: [], unread: before };
|
|
1425
|
+
if (typeof after === 'string') return { findings: [], unread: after };
|
|
1426
|
+
return { findings: chainsLeftBehind(before, after), unread: null };
|
|
1427
|
+
})();
|
|
1386
1428
|
const bfile = basisFile(P, prop, basis, cfg === null || cmpPath === undefined ? null : { where: cmpPath, config: cfg });
|
|
1387
1429
|
const img = drawLandmarks(P, painting, prop.bones, 'PROPOSAL - CORRECT ME');
|
|
1388
1430
|
mkdirSync(render, { recursive: true });
|
|
@@ -1396,7 +1438,8 @@ function cmdPropose(args: string[]): number {
|
|
|
1396
1438
|
}
|
|
1397
1439
|
console.log(`wrote proposal.json (${prop.bones.length} bone entries, ${Object.keys(prop.meshes).length} meshes) and render/landmarks.png (+_head) under ${out}`);
|
|
1398
1440
|
for (const n of prop.notes) console.log(`note: ${n}`);
|
|
1399
|
-
|
|
1441
|
+
if (leftBehind.unread !== null) console.log(`note: the keyed chains were not read after the recipe (issue #572): ${leftBehind.unread}`);
|
|
1442
|
+
printLint(P, prop, joints, [...draftLint, ...leftBehind.findings]);
|
|
1400
1443
|
console.log(basisLine(bfile, out));
|
|
1401
1444
|
if (written !== null && clothArg !== undefined) {
|
|
1402
1445
|
const from = fromArg === undefined ? '' : `; --from ${fromArg}: ${written.vouched} ${written.vouched === 1 ? 'entry' : 'entries'} taken as the previous recipe's draft`;
|
|
@@ -1789,6 +1832,18 @@ function cmdMeshDraft(args: string[]): number {
|
|
|
1789
1832
|
}
|
|
1790
1833
|
}
|
|
1791
1834
|
|
|
1835
|
+
/** `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. */
|
|
1836
|
+
function cmdMeshStats(args: string[]): number {
|
|
1837
|
+
const f = flags(args, 'mesh-stats', ['--config', '--parts']);
|
|
1838
|
+
if (typeof f === 'string') return usage(f);
|
|
1839
|
+
try {
|
|
1840
|
+
meshStatsStage({ config: f.get('--config') as string, parts: f.get('--parts') as string }, console.log);
|
|
1841
|
+
return EXIT_OK;
|
|
1842
|
+
} catch (err) {
|
|
1843
|
+
return printRefusal(err);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1792
1847
|
/** `remesh` (issue #495): one part of a gated rig re-fitted under a requested mesh entry, into a new revision. */
|
|
1793
1848
|
function cmdRemesh(args: string[]): number {
|
|
1794
1849
|
const f = flags(args, 'remesh', ['--rig', '--config', '--parts', '--part', '--out']);
|
|
@@ -1937,6 +1992,7 @@ function main(argv: string[]): number | Promise<number> {
|
|
|
1937
1992
|
if (command === 'build') return cmdBuild(rest);
|
|
1938
1993
|
if (command === 'compose') return cmdCompose(rest);
|
|
1939
1994
|
if (command === 'mesh-draft') return cmdMeshDraft(rest);
|
|
1995
|
+
if (command === 'mesh-stats') return cmdMeshStats(rest);
|
|
1940
1996
|
if (command === 'remesh') return cmdRemesh(rest);
|
|
1941
1997
|
if (command === 'retune') return cmdRetune(rest);
|
|
1942
1998
|
if (command === 'painting') return cmdPainting(rest);
|