@rig-c/parts 1.15.0 → 1.17.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 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
@@ -20,7 +20,8 @@ import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns,
20
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 { PartsError, problemLine } from './src/errors.ts';
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';
@@ -136,7 +137,11 @@ usage:
136
137
  hip (the midpoint of r_hip and l_hip), the chest half way along neck ->
137
138
  hip, and each sleeve chain shoulder -> elbow with its tip at the wrist
138
139
  when every handwear part holds a wrist; a missing joint leaves its bone to
139
- the rule. One note per joint says which. LINT then reads the torso along
140
+ the rule. One note per joint says which. Each arm and leg so placed is a
141
+ limb (issue #349): proposal.json's "limbs" cuts its layer at the elbow or
142
+ the knee into parts rigid on its links (and, when every ankle lies on a
143
+ footwear part, a foot on a bone of its own at the ankle that keeps its
144
+ setup angle); assemble with the block makes the cut. LINT then reads the torso along
140
145
  the neck -> hips line and each sleeve chain along shoulder -> wrist
141
146
  instead of by screen y, and prints the rule set it used first. Without
142
147
  --keypoints nothing changes. A wrist holds a part when it lies within
@@ -350,9 +355,13 @@ usage:
350
355
  holds an animation, ANIMATIONS_DO_NOT_FOLD reads each, the idle included,
351
356
  with rigc render --folds, physics constraints left out: a mesh triangle turned
352
357
  over against the setup pose fails, unless the --requirements file's
353
- may_fold declares that slot and animation with a why. The last line says
354
- how many of the bars measured — nine, ten with the fold bar — and names
355
- the skipped ones.
358
+ may_fold declares that slot and animation with a why. Where a footwear
359
+ part rides a bone that hangs from another, FEET_STAY_LEVEL reads the
360
+ same render's geometry: while a bone above that bone is turned, the
361
+ part's drawing must stay within ±10 degrees of its setup pose (HQ's
362
+ line); config.bones' "inherit" on the foot is what keeps it there. The
363
+ last line says how many of the bars measured — nine, ten with the fold
364
+ bar, eleven with the feet-level bar — and names the skipped ones.
356
365
  --source adds SETUP_POSE_VS_SOURCE: REPORTED, never a FAIL — the setup
357
366
  pose against the painting by assemble's own recomposite figures (mean |d|,
358
367
  % within 8, error px over 40, uncovered error px where the pose has alpha
@@ -430,11 +439,16 @@ usage:
430
439
  drawn "back", "front" or {"before": <plan part>}, recorded in parts.json
431
440
  as from "painting:<name>" and counted 100 % source — and .cuts — a plan
432
441
  part's pixels inside a rig-pixel polygon taken into a new part, drawn the
433
- same way, recorded with the plan part's from — and no rig section:
442
+ same way, recorded with the plan part's from — and .limbs (issue #349),
443
+ with the bones they name: each limb's layer cut at its joints into one
444
+ part per segment, each lower part carrying a cap past its joint, the
445
+ upper drawn over the lower — and no other rig section:
434
446
  bones, meshes, regions and motion need not exist yet, because propose
435
447
  drafts them from these parts (AUTHORING §4, the table).
436
448
  Prints one line per part, one \`cut:\` line per part a cut split (its
437
- opaque pixels = what it kept + what each cut took), the seam override
449
+ opaque pixels = what it kept + what each cut took), one \`limb cut:\`
450
+ line per part a limb took and one \`limb cap:\` line per joint (the cap's
451
+ pixels from the layer and missing, and the box to paint them into), the seam override
438
452
  counts, the \`pixels:\` totals
439
453
  (opaque = visible + occluded; taken from the painting; visible but not
440
454
  projected), and \`recomposite vs source\` (mean |d| and % within 8 over the
@@ -590,6 +604,23 @@ usage:
590
604
  line and ${SCENE_REPORT_FILE} name what was accepted, and the run exits 1.
591
605
  Exit 0 when the check is PASS and nothing was accepted, 1 otherwise.
592
606
 
607
+ rig-parts guide <RULE | §<n> | §<n>.<m> | §<n>.<m>.<k>>
608
+ Print a slice of ${GUIDE_DOC}, the guide this package ships, read
609
+ from the installed file at the moment of the call; nothing is kept
610
+ apart from it. Every FAIL line ends with the command that prints its
611
+ rule's row: "(see rig-parts guide <RULE>)". guide <RULE> prints
612
+ "docs/AUTHORING.md §<addr>, line <N> — under "<heading>"" and the one
613
+ row naming the rule; a refusal and the bar it enforces (CHECK_<LINE>
614
+ and <LINE>) print one after the other, joined by "paired with
615
+ <OTHER>:". A name no row holds is refused on stderr
616
+ (GUIDE_RULE_KNOWN), with the three nearest names the guide holds,
617
+ and nothing printed in their place. guide §<n> prints section n,
618
+ after its subsections' numbers and sizes in KB; §<n>.<m>
619
+ is the m-th ### heading under it and §<n>.<m>.<k> the k-th #### under
620
+ that, counted as the file stands (the headings carry no number), and
621
+ §<n>.<m> lists its ####s as §<n> lists its ###s. Exit 0 printed, 1
622
+ refused, 2 usage.
623
+
593
624
  rig-parts --version
594
625
  rig-parts --help
595
626
 
@@ -598,7 +629,7 @@ ${LATER.length === 0 ? '' : `not implemented in this version (each exits 2):\n${
598
629
 
599
630
  function printRefusal(err: unknown): number {
600
631
  if (err instanceof PartsError) {
601
- for (const p of err.problems) console.log(` FAIL ${problemLine(p)}`);
632
+ for (const p of err.problems) console.log(failLine(p));
602
633
  console.log(`refused: ${err.problems.length} problem(s)`);
603
634
  return EXIT_REFUSED;
604
635
  }
@@ -606,11 +637,28 @@ function printRefusal(err: unknown): number {
606
637
  }
607
638
 
608
639
  function usage(message: string): number {
609
- console.log(` FAIL USAGE: ${message}`);
640
+ console.log(` FAIL USAGE: ${message}${guidePointer('USAGE')}`);
610
641
  console.log('rig-parts --help lists the commands');
611
642
  return EXIT_USAGE;
612
643
  }
613
644
 
645
+ /** `guide`: one argument, a rule name or a section; the slice printed, or the refusal. */
646
+ function cmdGuide(args: string[]): number {
647
+ if (args.length !== 1) return usage(`guide takes one rule name or one §<n> / §<n>.<m> / §<n>.<m>.<k>; got ${args.length} argument(s)`);
648
+ if (args[0].startsWith('-')) return usage(`guide takes no flag; "${args[0]}" is neither a rule name nor §<n> / §<n>.<m>`);
649
+ const path = join(import.meta.dir, GUIDE_DOC);
650
+ 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' }]));
651
+ const text = readFileSync(path, 'utf8');
652
+ const answer: GuideAnswer = args[0].startsWith('§') ? guideSection(text, args[0]) : guideRule(text, args[0]);
653
+ // The shared form: an unknown name or section is one coded FAIL line on stderr, exit 1.
654
+ if ('problem' in answer) {
655
+ console.error(failLine(answer.problem));
656
+ return EXIT_REFUSED;
657
+ }
658
+ for (const l of answer.lines) console.log(l);
659
+ return EXIT_OK;
660
+ }
661
+
614
662
  function fixed(v: number | null): string {
615
663
  return v === null ? '-' : v.toFixed(4);
616
664
  }
@@ -655,7 +703,8 @@ function printLayerTable(set: LayerSet): void {
655
703
  /**
656
704
  * Every flag each command takes: `valued` flags carry a value, `switches` are bare. Each parser reads its row to
657
705
  * 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 no flag, so it has no row.
706
+ * lists exactly the flags the parser accepts (CL26). `layers` takes one positional path and `guide` one positional
707
+ * argument, and neither takes a flag, so neither has a row.
659
708
  */
660
709
  const TAKES = {
661
710
  sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
@@ -1047,7 +1096,7 @@ function cmdCompare(args: string[]): number {
1047
1096
  console.log(`rig-parts compare: left ${left}, right ${right}${map === null ? ', no map' : `, map ${map}`}`);
1048
1097
  for (const l of structureLines(c)) console.log(l);
1049
1098
  const missing = requiredProblems(c, map ?? 'the map');
1050
- for (const p of missing) console.log(` FAIL ${problemLine(p)}`);
1099
+ for (const p of missing) console.log(failLine(p));
1051
1100
  return missing.length > 0 ? EXIT_REFUSED : EXIT_OK;
1052
1101
  } catch (err) {
1053
1102
  return printRefusal(err);
@@ -1398,9 +1447,10 @@ function main(argv: string[]): number | Promise<number> {
1398
1447
  if (command === 'build') return cmdBuild(rest);
1399
1448
  if (command === 'compose') return cmdCompose(rest);
1400
1449
  if (command === 'mesh-draft') return cmdMeshDraft(rest);
1450
+ if (command === 'guide') return cmdGuide(rest);
1401
1451
  const later = LATER.find(([name]) => name === command);
1402
1452
  if (later !== undefined) {
1403
- console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}`);
1453
+ console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}${guidePointer('NOT_IMPLEMENTED')}`);
1404
1454
  return EXIT_USAGE;
1405
1455
  }
1406
1456
  return usage(`unknown command "${command}"`);