@rig-c/parts 1.14.0 → 1.16.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 +4 -0
- package/cli.ts +52 -14
- package/docs/AUTHORING.md +288 -208
- package/docs/MIGRATION.md +62 -0
- package/docs/STABILITY.md +7 -5
- package/package.json +1 -1
- package/skills/rig-parts/SKILL.md +8 -1
- package/src/build.ts +14 -12
- package/src/check.ts +100 -24
- package/src/contour.ts +41 -5
- package/src/errors.ts +16 -0
- package/src/guide.ts +255 -0
- package/src/meshdraft.ts +28 -6
- package/src/requirements.ts +6 -5
- package/src/rig.ts +1 -1
- package/src/scene.ts +2 -2
package/README.md
CHANGED
|
@@ -291,9 +291,13 @@ agent skill.
|
|
|
291
291
|
| `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
|
|
292
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 |
|
|
293
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*) |
|
|
294
|
+
| `guide <RULE \| §<n> \| §<n>.<m> \| §<n>.<m>.<k>>` | print the one row of [docs/AUTHORING.md](docs/AUTHORING.md) that names a rule (a refusal and the bar it enforces, `CHECK_<LINE>` and `<LINE>`, print together), or one section, `###` subsection or `####` under it, read from the installed file when it runs |
|
|
294
295
|
|
|
295
296
|
`rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
|
|
296
297
|
reason is a FAIL line), 2 a usage error or a command this version does not implement.
|
|
298
|
+
Every FAIL line ends with `(see rig-parts guide <RULE>)`, the command that prints the
|
|
299
|
+
guide's row for that rule, and each row is anchored on the web as
|
|
300
|
+
`docs/AUTHORING.md#<RULE>`.
|
|
297
301
|
|
|
298
302
|
What 1.0.0 holds stable — these commands and their flags, the config
|
|
299
303
|
fields, the files a build writes and their spec ids, the environment, and what this
|
package/cli.ts
CHANGED
|
@@ -17,10 +17,11 @@ 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
19
|
import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns, readSource, rigStage, suppliedCheckFlag } from './src/build.ts';
|
|
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';
|
|
20
|
+
import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, rigcRunnerAt, 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';
|
|
23
|
-
import {
|
|
23
|
+
import { failLine, guidePointer, PartsError } from './src/errors.ts';
|
|
24
|
+
import { GUIDE_DOC, type GuideAnswer, guideRule, guideSection } from './src/guide.ts';
|
|
24
25
|
import { proposeHeadBox } from './src/headbox.ts';
|
|
25
26
|
import { makeInputs } from './src/inputs.ts';
|
|
26
27
|
import { idleKeysOf, isIdleKeys } from './src/rig.ts';
|
|
@@ -347,8 +348,8 @@ usage:
|
|
|
347
348
|
BREATH_VISIBLE, BLINK_NO_HOLE, TIP_OVER_ROOT, STILL_REGIONS_DARK and
|
|
348
349
|
RECOMPOSITE_HOLES; without an idle the loop and every line that reads idle
|
|
349
350
|
frames, and no idle is rendered. The gate always runs. When motion.json
|
|
350
|
-
holds an animation
|
|
351
|
-
rigc render --folds, physics constraints left out: a mesh triangle turned
|
|
351
|
+
holds an animation, ANIMATIONS_DO_NOT_FOLD reads each, the idle included,
|
|
352
|
+
with rigc render --folds, physics constraints left out: a mesh triangle turned
|
|
352
353
|
over against the setup pose fails, unless the --requirements file's
|
|
353
354
|
may_fold declares that slot and animation with a why. The last line says
|
|
354
355
|
how many of the bars measured — nine, ten with the fold bar — and names
|
|
@@ -590,6 +591,23 @@ usage:
|
|
|
590
591
|
line and ${SCENE_REPORT_FILE} name what was accepted, and the run exits 1.
|
|
591
592
|
Exit 0 when the check is PASS and nothing was accepted, 1 otherwise.
|
|
592
593
|
|
|
594
|
+
rig-parts guide <RULE | §<n> | §<n>.<m> | §<n>.<m>.<k>>
|
|
595
|
+
Print a slice of ${GUIDE_DOC}, the guide this package ships, read
|
|
596
|
+
from the installed file at the moment of the call; nothing is kept
|
|
597
|
+
apart from it. Every FAIL line ends with the command that prints its
|
|
598
|
+
rule's row: "(see rig-parts guide <RULE>)". guide <RULE> prints
|
|
599
|
+
"docs/AUTHORING.md §<addr>, line <N> — under "<heading>"" and the one
|
|
600
|
+
row naming the rule; a refusal and the bar it enforces (CHECK_<LINE>
|
|
601
|
+
and <LINE>) print one after the other, joined by "paired with
|
|
602
|
+
<OTHER>:". A name no row holds is refused on stderr
|
|
603
|
+
(GUIDE_RULE_KNOWN), with the three nearest names the guide holds,
|
|
604
|
+
and nothing printed in their place. guide §<n> prints section n,
|
|
605
|
+
after its subsections' numbers and sizes in KB; §<n>.<m>
|
|
606
|
+
is the m-th ### heading under it and §<n>.<m>.<k> the k-th #### under
|
|
607
|
+
that, counted as the file stands (the headings carry no number), and
|
|
608
|
+
§<n>.<m> lists its ####s as §<n> lists its ###s. Exit 0 printed, 1
|
|
609
|
+
refused, 2 usage.
|
|
610
|
+
|
|
593
611
|
rig-parts --version
|
|
594
612
|
rig-parts --help
|
|
595
613
|
|
|
@@ -598,7 +616,7 @@ ${LATER.length === 0 ? '' : `not implemented in this version (each exits 2):\n${
|
|
|
598
616
|
|
|
599
617
|
function printRefusal(err: unknown): number {
|
|
600
618
|
if (err instanceof PartsError) {
|
|
601
|
-
for (const p of err.problems) console.log(
|
|
619
|
+
for (const p of err.problems) console.log(failLine(p));
|
|
602
620
|
console.log(`refused: ${err.problems.length} problem(s)`);
|
|
603
621
|
return EXIT_REFUSED;
|
|
604
622
|
}
|
|
@@ -606,11 +624,28 @@ function printRefusal(err: unknown): number {
|
|
|
606
624
|
}
|
|
607
625
|
|
|
608
626
|
function usage(message: string): number {
|
|
609
|
-
console.log(` FAIL USAGE: ${message}`);
|
|
627
|
+
console.log(` FAIL USAGE: ${message}${guidePointer('USAGE')}`);
|
|
610
628
|
console.log('rig-parts --help lists the commands');
|
|
611
629
|
return EXIT_USAGE;
|
|
612
630
|
}
|
|
613
631
|
|
|
632
|
+
/** `guide`: one argument, a rule name or a section; the slice printed, or the refusal. */
|
|
633
|
+
function cmdGuide(args: string[]): number {
|
|
634
|
+
if (args.length !== 1) return usage(`guide takes one rule name or one §<n> / §<n>.<m> / §<n>.<m>.<k>; got ${args.length} argument(s)`);
|
|
635
|
+
if (args[0].startsWith('-')) return usage(`guide takes no flag; "${args[0]}" is neither a rule name nor §<n> / §<n>.<m>`);
|
|
636
|
+
const path = join(import.meta.dir, GUIDE_DOC);
|
|
637
|
+
if (!existsSync(path)) return printRefusal(new PartsError([{ code: 'GUIDE_FILE_PRESENT', object: path, detail: 'no such file; the guide ships in the package beside cli.ts' }]));
|
|
638
|
+
const text = readFileSync(path, 'utf8');
|
|
639
|
+
const answer: GuideAnswer = args[0].startsWith('§') ? guideSection(text, args[0]) : guideRule(text, args[0]);
|
|
640
|
+
// The shared form: an unknown name or section is one coded FAIL line on stderr, exit 1.
|
|
641
|
+
if ('problem' in answer) {
|
|
642
|
+
console.error(failLine(answer.problem));
|
|
643
|
+
return EXIT_REFUSED;
|
|
644
|
+
}
|
|
645
|
+
for (const l of answer.lines) console.log(l);
|
|
646
|
+
return EXIT_OK;
|
|
647
|
+
}
|
|
648
|
+
|
|
614
649
|
function fixed(v: number | null): string {
|
|
615
650
|
return v === null ? '-' : v.toFixed(4);
|
|
616
651
|
}
|
|
@@ -655,7 +690,8 @@ function printLayerTable(set: LayerSet): void {
|
|
|
655
690
|
/**
|
|
656
691
|
* Every flag each command takes: `valued` flags carry a value, `switches` are bare. Each parser reads its row to
|
|
657
692
|
* decide what it accepts, and {@link notTaken} prints the same row in the unknown-flag refusal, so the refusal
|
|
658
|
-
* lists exactly the flags the parser accepts (CL26). `layers` takes one positional path and
|
|
693
|
+
* lists exactly the flags the parser accepts (CL26). `layers` takes one positional path and `guide` one positional
|
|
694
|
+
* argument, and neither takes a flag, so neither has a row.
|
|
659
695
|
*/
|
|
660
696
|
const TAKES = {
|
|
661
697
|
sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
|
|
@@ -825,14 +861,15 @@ function cmdRig(args: string[]): number {
|
|
|
825
861
|
* `cli_core.ts` and rigc's own validator where it does not. No stage runs a
|
|
826
862
|
* rigc source file by path: under rig-c 2.0, `cli.ts` by path is the
|
|
827
863
|
* spine-core entry whether or not spine-core is there. `src/` is pure and takes
|
|
828
|
-
* the spawn from here.
|
|
864
|
+
* the spawn from here. A call that fails carries which rigc ran it, path and
|
|
865
|
+
* version ({@link rigcRunnerAt}, issue #337), and every refusal quoting it says so.
|
|
829
866
|
*/
|
|
830
867
|
function rigcRunner(bin: string): RigcRunner {
|
|
831
|
-
return (args) => {
|
|
832
|
-
const r = spawnSync(
|
|
833
|
-
if (r.error !== undefined) return { status: 127, out: `could not start ${
|
|
868
|
+
return rigcRunnerAt(bin, (b, args) => {
|
|
869
|
+
const r = spawnSync(b, [...args], { encoding: 'utf8', maxBuffer: 1 << 28 });
|
|
870
|
+
if (r.error !== undefined) return { status: 127, out: `could not start ${b}: ${r.error.message}` };
|
|
834
871
|
return { status: r.status ?? 1, out: `${r.stdout ?? ''}${r.stderr ?? ''}` };
|
|
835
|
-
};
|
|
872
|
+
});
|
|
836
873
|
}
|
|
837
874
|
|
|
838
875
|
/** The command's valued flags as `--flag value` pairs, each one its {@link TAKES} row holds; `required` must all be given. Its bare switches are taken out by the caller before this reads the rest. A string is a usage error. */
|
|
@@ -1046,7 +1083,7 @@ function cmdCompare(args: string[]): number {
|
|
|
1046
1083
|
console.log(`rig-parts compare: left ${left}, right ${right}${map === null ? ', no map' : `, map ${map}`}`);
|
|
1047
1084
|
for (const l of structureLines(c)) console.log(l);
|
|
1048
1085
|
const missing = requiredProblems(c, map ?? 'the map');
|
|
1049
|
-
for (const p of missing) console.log(
|
|
1086
|
+
for (const p of missing) console.log(failLine(p));
|
|
1050
1087
|
return missing.length > 0 ? EXIT_REFUSED : EXIT_OK;
|
|
1051
1088
|
} catch (err) {
|
|
1052
1089
|
return printRefusal(err);
|
|
@@ -1397,9 +1434,10 @@ function main(argv: string[]): number | Promise<number> {
|
|
|
1397
1434
|
if (command === 'build') return cmdBuild(rest);
|
|
1398
1435
|
if (command === 'compose') return cmdCompose(rest);
|
|
1399
1436
|
if (command === 'mesh-draft') return cmdMeshDraft(rest);
|
|
1437
|
+
if (command === 'guide') return cmdGuide(rest);
|
|
1400
1438
|
const later = LATER.find(([name]) => name === command);
|
|
1401
1439
|
if (later !== undefined) {
|
|
1402
|
-
console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}`);
|
|
1440
|
+
console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}${guidePointer('NOT_IMPLEMENTED')}`);
|
|
1403
1441
|
return EXIT_USAGE;
|
|
1404
1442
|
}
|
|
1405
1443
|
return usage(`unknown command "${command}"`);
|