rig-parts 1.87.0 → 2.0.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 +16 -12
- package/docs/AUTHORING.md +83 -5
- package/docs/STABILITY.md +53 -15
- package/package.json +2 -2
- package/src/apng.ts +2 -2
- package/src/assemble.ts +2 -10
- package/src/build.ts +12 -8
- package/src/check.ts +11 -10
- package/src/config.ts +16 -5
- package/src/coords.ts +3 -3
- package/src/instruments.ts +1 -1
- package/src/propose.ts +1 -1
- package/src/raster/png.ts +7 -7
- package/src/raster/types.ts +1 -1
- package/src/remesh.ts +2 -2
- package/src/requirements.ts +2 -2
- package/src/rig.ts +19 -2
- package/src/scene.ts +1 -1
- package/src/seamrule.ts +11 -0
- package/src/setuppainting.ts +6 -1
- package/src/sheet.ts +1 -1
- package/src/structure.ts +2 -2
- package/src/turn.ts +1 -1
- package/src/turncoverage.ts +2 -2
- package/src/turnoverlap.ts +1 -1
package/cli.ts
CHANGED
|
@@ -555,7 +555,8 @@ usage:
|
|
|
555
555
|
[--page-edges pot|free] [--pack-shape rect|polygon]
|
|
556
556
|
[--requirements <file.json>] [--seam-pairs] [--keep-stills]
|
|
557
557
|
[--set <name> | --all-sets] [--environment <schedule.json>]
|
|
558
|
-
[--wind-band <spec.json>]
|
|
558
|
+
[--wind-band <spec.json>] [--json]
|
|
559
|
+
--json prints the completed check.json object only, with unchanged exit codes.
|
|
559
560
|
Build, gate, render and measure a rig through rig-c's CLI (the rigc at
|
|
560
561
|
node_modules/.bin/rigc, or on PATH). --rig holds rig.json and motion.json:
|
|
561
562
|
a rig spec, which rigc build compiles, not a compiled skeleton.json.
|
|
@@ -777,7 +778,7 @@ usage:
|
|
|
777
778
|
extends below a crop (ASSEMBLE_SINGLE_RUN_PLAN), and the config sets no
|
|
778
779
|
seethrough.head_box (ASSEMBLE_SINGLE_RUN_HEAD_BOX).
|
|
779
780
|
Writes nothing unless every check passed.
|
|
780
|
-
--seam
|
|
781
|
+
--seam overrides config.assemble.seam, otherwise ${DEFAULT_SEAM_RULE}. --project says where a layer takes
|
|
781
782
|
the painting's pixel: core (the reference's) erodes every layer's top-most
|
|
782
783
|
opaque area by 5x5 first, so a part a few pixels wide takes none; visible
|
|
783
784
|
erodes only along a rim where a later layer is in front. It defaults to
|
|
@@ -861,7 +862,7 @@ usage:
|
|
|
861
862
|
green build ends with the pack line beside the spineboy yardstick and the
|
|
862
863
|
three artifact paths — skeleton .json, .atlas and the packed page: the
|
|
863
864
|
packed atlas is the result, the loose parts are the intermediate it was
|
|
864
|
-
made from. --seam
|
|
865
|
+
made from. --seam overrides config.assemble.seam, otherwise ${DEFAULT_SEAM_RULE}; --project to
|
|
865
866
|
${DEFAULT_PROJECT_RULE} (both as for assemble), --page-edges to ${DEFAULT_PAGE_EDGES} and
|
|
866
867
|
--pack-shape to ${DEFAULT_PACK_SHAPE} (as for check; both packed builds, rig's gate
|
|
867
868
|
and check's artifact, take them). --requirements is forwarded to check
|
|
@@ -1095,7 +1096,7 @@ const TAKES = {
|
|
|
1095
1096
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
1096
1097
|
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'] },
|
|
1097
1098
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
1098
|
-
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements', '--set', '--environment', '--wind-band'], switches: ['--seam-pairs', '--keep-stills', '--all-sets', '--no-extremes'] },
|
|
1099
|
+
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'] },
|
|
1099
1100
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
1100
1101
|
assemble: { valued: ['--source', '--full', '--head', '--config', '--out', '--seam', '--project', '--alt', '--write-config', '--requirements'], switches: ['--propose-plan'] },
|
|
1101
1102
|
'comfy seethrough': { valued: ['--image', '--out', '--resolution', '--steps', '--seed', '--prefix', '--host', '--wait', '--timeout', '--poll', '--config', '--depth-run'], switches: ['--offload', '--no-offload', '--lama', '--nf4'] },
|
|
@@ -1338,6 +1339,8 @@ function flags(args: string[], command: Command, required: readonly string[]): M
|
|
|
1338
1339
|
|
|
1339
1340
|
function cmdCheck(args: string[]): number {
|
|
1340
1341
|
// The switches check takes (issues #202, #209, #454): they carry no value, so they are taken out before the valued flags are read.
|
|
1342
|
+
const json = args.filter((a) => a === '--json').length;
|
|
1343
|
+
if (json > 1) return usage('--json is given twice');
|
|
1341
1344
|
const seamPairs = args.filter((a) => a === '--seam-pairs').length;
|
|
1342
1345
|
if (seamPairs > 1) return usage('--seam-pairs is given twice');
|
|
1343
1346
|
const keepStills = args.filter((a) => a === '--keep-stills').length;
|
|
@@ -1347,7 +1350,7 @@ function cmdCheck(args: string[]): number {
|
|
|
1347
1350
|
const allSets = args.filter((a) => a === '--all-sets').length;
|
|
1348
1351
|
if (allSets > 1) return usage('--all-sets is given twice');
|
|
1349
1352
|
const f = flags(
|
|
1350
|
-
args.filter((a) => a !== '--seam-pairs' && a !== '--keep-stills' && a !== '--all-sets' && a !== '--no-extremes'),
|
|
1353
|
+
args.filter((a) => a !== '--seam-pairs' && a !== '--keep-stills' && a !== '--all-sets' && a !== '--no-extremes' && a !== '--json'),
|
|
1351
1354
|
'check',
|
|
1352
1355
|
['--rig', '--out'],
|
|
1353
1356
|
);
|
|
@@ -1365,8 +1368,9 @@ function cmdCheck(args: string[]): number {
|
|
|
1365
1368
|
{ rig, parts: f.get('--parts'), source: f.get('--source'), out, pageEdges: edges, packShape: shape, requirements: f.get('--requirements'), seamPairs: seamPairs === 1, keepStills: keepStills === 1, noExtremes: noExtremes === 1, ...(f.has('--set') ? { set: f.get('--set') as string } : {}), allSets: allSets === 1, ...(f.has('--environment') ? { environment: f.get('--environment') as string } : {}), ...(f.has('--wind-band') ? { windBand: f.get('--wind-band') as string } : {}) },
|
|
1366
1369
|
rigcRunner(bin),
|
|
1367
1370
|
bin,
|
|
1368
|
-
console.log,
|
|
1371
|
+
json === 1 ? () => {} : console.log,
|
|
1369
1372
|
);
|
|
1373
|
+
if (json === 1) process.stdout.write(`${JSON.stringify(r.figures, null, 1)}\n`);
|
|
1370
1374
|
return r.figures.PASS ? EXIT_OK : EXIT_REFUSED;
|
|
1371
1375
|
} catch (err) {
|
|
1372
1376
|
return printRefusal(err);
|
|
@@ -1726,8 +1730,8 @@ function cmdAssemble(args: string[]): number {
|
|
|
1726
1730
|
if (propose && (flags.has('--out') || flags.has('--seam') || flags.has('--project') || alts.length > 0)) return usage('--propose-plan prints to the console; it takes none of --out, --seam, --project, --alt');
|
|
1727
1731
|
if (!propose && flags.has('--write-config')) return usage('--write-config belongs to assemble --propose-plan');
|
|
1728
1732
|
if (!propose && !flags.has('--out')) return usage('assemble needs --out <dir>');
|
|
1729
|
-
const seam = flags.get('--seam')
|
|
1730
|
-
if (!(SEAM_RULES as readonly string[]).includes(seam)) return usage(`--seam ${seam}; one of ${SEAM_RULES.join(', ')} is required`);
|
|
1733
|
+
const seam = flags.get('--seam');
|
|
1734
|
+
if (seam !== undefined && !(SEAM_RULES as readonly string[]).includes(seam)) return usage(`--seam ${seam}; one of ${SEAM_RULES.join(', ')} is required`);
|
|
1731
1735
|
const project = flags.get('--project') ?? DEFAULT_PROJECT_RULE;
|
|
1732
1736
|
if (!(PROJECT_RULES as readonly string[]).includes(project)) return usage(`--project ${project}; one of ${PROJECT_RULES.join(', ')} is required`);
|
|
1733
1737
|
const [source, full, config] = ['--source', '--full', '--config'].map((f) => flags.get(f) as string);
|
|
@@ -1755,7 +1759,7 @@ function cmdAssemble(args: string[]): number {
|
|
|
1755
1759
|
}
|
|
1756
1760
|
const out = flags.get('--out') as string;
|
|
1757
1761
|
assembleStage(
|
|
1758
|
-
{ source, full, head, config, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), seam: seam as SeamRule, project: project as ProjectRule, ...(alts.length === 0 ? {} : { alts }) },
|
|
1762
|
+
{ source, full, head, config, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), ...(seam === undefined ? {} : { seam: seam as SeamRule }), project: project as ProjectRule, ...(alts.length === 0 ? {} : { alts }) },
|
|
1759
1763
|
{ partsJson: join(out, 'rig', 'parts.json'), partsDir: join(out, 'rig', 'parts'), recomposite: join(out, 'render', 'recomposite_rig.png'), errorMap: join(out, 'render', ERROR_MAP_FILE) },
|
|
1760
1764
|
console.log,
|
|
1761
1765
|
);
|
|
@@ -1946,8 +1950,8 @@ function cmdBuild(args: string[]): number {
|
|
|
1946
1950
|
// --head is optional (issue #359), as for assemble.
|
|
1947
1951
|
for (const f of ['--config', '--source', '--full', '--out']) if (!flags.has(f)) return usage(`build needs ${f}`);
|
|
1948
1952
|
if (on.has('--all-sets') && flags.has('--set')) return usage('--set and --all-sets are two modes; give one');
|
|
1949
|
-
const seam = flags.get('--seam')
|
|
1950
|
-
if (!(SEAM_RULES as readonly string[]).includes(seam)) return usage(`--seam ${seam}; one of ${SEAM_RULES.join(', ')} is required`);
|
|
1953
|
+
const seam = flags.get('--seam');
|
|
1954
|
+
if (seam !== undefined && !(SEAM_RULES as readonly string[]).includes(seam)) return usage(`--seam ${seam}; one of ${SEAM_RULES.join(', ')} is required`);
|
|
1951
1955
|
const project = flags.get('--project') ?? DEFAULT_PROJECT_RULE;
|
|
1952
1956
|
if (!(PROJECT_RULES as readonly string[]).includes(project)) return usage(`--project ${project}; one of ${PROJECT_RULES.join(', ')} is required`);
|
|
1953
1957
|
const edges = pageEdgesOf(flags.get('--page-edges'));
|
|
@@ -1971,7 +1975,7 @@ function cmdBuild(args: string[]): number {
|
|
|
1971
1975
|
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-build-'));
|
|
1972
1976
|
try {
|
|
1973
1977
|
const r = build(
|
|
1974
|
-
{ config, source, full, head, out, seam: seam as SeamRule, project: project as ProjectRule, loop, pageEdges: edges, packShape: shape, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), idleKeys: keys, ...(leadText === undefined ? {} : { leadIn: Number(leadText) }), seamPairs: on.has('--seam-pairs'), keepStills: on.has('--keep-stills'), noExtremes: on.has('--no-extremes'), ...(alts.length === 0 ? {} : { alts }), ...(flags.has('--set') ? { set: flags.get('--set') as string } : {}), allSets: on.has('--all-sets'), ...(flags.has('--environment') ? { environment: flags.get('--environment') as string } : {}), ...(flags.has('--wind-band') ? { windBand: flags.get('--wind-band') as string } : {}) },
|
|
1978
|
+
{ config, source, full, head, out, ...(seam === undefined ? {} : { seam: seam as SeamRule }), project: project as ProjectRule, loop, pageEdges: edges, packShape: shape, ...(flags.has('--requirements') ? { requirements: flags.get('--requirements') as string } : {}), idleKeys: keys, ...(leadText === undefined ? {} : { leadIn: Number(leadText) }), seamPairs: on.has('--seam-pairs'), keepStills: on.has('--keep-stills'), noExtremes: on.has('--no-extremes'), ...(alts.length === 0 ? {} : { alts }), ...(flags.has('--set') ? { set: flags.get('--set') as string } : {}), allSets: on.has('--all-sets'), ...(flags.has('--environment') ? { environment: flags.get('--environment') as string } : {}), ...(flags.has('--wind-band') ? { windBand: flags.get('--wind-band') as string } : {}) },
|
|
1975
1979
|
{ rig: rigcRunner(bin), check: rigcRunner(bin), checkBin: bin, scratch: join(scratch, 'rig-gate'), stages: {
|
|
1976
1980
|
assemble: (input, outputs) => runBuildProcess({ stage: 'assemble', bin, input, outputs }, join(scratch, 'workers')),
|
|
1977
1981
|
rig: (input, _rigc, gateScratch) => runBuildProcess({ stage: 'rig', bin, input, scratch: gateScratch }, join(scratch, 'workers')),
|
package/docs/AUTHORING.md
CHANGED
|
@@ -147,6 +147,7 @@ read by no CPU stage).
|
|
|
147
147
|
| `seethrough.steps`, `.seed`, `.offload` | `comfy seethrough --config` | run inputs when `--config <config.json>` is given; explicit CLI flags override them, including `--no-offload` for false |
|
|
148
148
|
| `seethrough.head_box` | inputs (cuts the head image there; optional at the first call); assemble — where the head run sits on the painting | **proposed** by `propose --head-box` from the full run, square, source pixels, shifted inside the painting when needed; the head run must then be fed exactly that crop. With one run (no `--head`, issue #359: an artist's own file, §4 *For artists*) it is left out — there is no crop to place — and a config that sets it is refused (`ASSEMBLE_SINGLE_RUN_HEAD_BOX`) |
|
|
149
149
|
| `seethrough.arm_split` | assemble, `assemble --propose-plan` — separates a single full-run `handwear-r` or `handwear-l` layer that holds both overlapping arms into both arm tags | **authored**, optional (issue #439): `{x?: number, line?: [[x, y], …], order: ["handwear-r", "handwear-l"] \| ["handwear-l", "handwear-r"]}` in `seethrough.resolution` full-run pixels. Exactly one of `x` (image column, `0 <= x <= resolution`) or `line` (a polyline of two or more `[x, y]` points in `[0, resolution]`, interpolated in x along y and clamped above/below its endpoints) is required (`CONFIG_FIELD_PRESENT`, `CONFIG_FIELD_TYPE`), and `order` is `[back_tag, front_tag]`, the draw order of the two separated arm layers (`CONFIG_FIELD_PRESENT`, `CONFIG_FIELD_TYPE`). Pixels at `< splitX(y)` go to `handwear-r` (image left, the subject's right arm) and pixels at `>= splitX(y)` go to `handwear-l` (image right, the subject's left arm). A split line that cuts a horizontal opaque run of the arm layer into more than two segments is refused (`ASSEMBLE_ARM_SPLIT_CUTS_ARM`). Without the declaration, when one arm layer's 8-connected component reaches both wrists under `propose --keypoints`, `propose` emits an `overlapping-arms` `LINT` naming the part, both wrists and `seethrough.arm_split`; absent, no byte of any output moves |
|
|
150
|
+
| `assemble.seam` | assemble, build | **authored**, optional `"near-white"` or `"silhouette"` (issue #905). An explicit `--seam` overrides the config; otherwise this field overrides the existing `near-white` default. An invalid value is `CONFIG_FIELD_TYPE` at `config.assemble.seam`, including when a CLI override is given. Absent, existing build bytes are unchanged. |
|
|
150
151
|
| `assemble.rig_scale` | assemble — the rig is `trunc(w × rig_scale)` x `trunc(h × rig_scale)`, and every rig-px value after it (`bones`, `meshes`, `motion`, `patches`, `cuts`) is in that rig's pixels; `check --source` (`CHECK_SOURCE_SIZE`) and `compose` (`SCENE_RIG_SCALE_AGREES`) read it back off `parts.json` | authored; rig pixels per source pixel. 0.5 in both examples (a 1664x2432 painting makes an 832x1216 rig). **Keep the figure about 1,100 to 1,200 rig px tall** — the `H` of `propose`'s `mesh spacing:` note, the height of the parts' boxes together — so for another painting, about 1,150 over the figure's height in painting px: that is the size the proposer's spacing divisor was calibrated at (H 1106–1185, the `mesh spacing` note says so) and the size of the two examples `check`'s bars are derived from, and the proposer and `check` also hold fixed rig-px values that do not scale with it (the fringe's 10 px step, the trunk segments' 18, 20, 30 and 100 px, the 15 px wrist tolerance, the 10-row pendant floor, the seam bar's 50 rig px over 40). What else it trades, measured on `demo` with the README loop from a fresh config at 0.25, 0.5 and 1 (issue #345, rig-c 2.47.1): the same plan and the same ten chains; every bar but the one the uncorrected `demo` always fails (`bottomwear` `TIP_OVER_ROOT`, the README loop's `RL01`) passing at all three; the atlas page 418x606, 832x1205 and 1825x2047; the figure's mesh spacing 16, 32 and 64, so 830, 868 and 932 triangles; the breath 2.5 % of a torso that scales with it; and the proposed bones, scaled to 0.5, off the 0.5 proposal's by up to 38 px at 0.25 and 22.5 px at 1 (the hairpin's origin; the skirt roots 20 and 10.5) — the fixed-px values above. `propose` records it on the proposal as `proposed_rig_scale` (issue #354), and changing `assemble.rig_scale` after the rig sections are written is refused (`CONFIG_PROPOSED_RIG_SCALE`): without that refusal `demo`'s tracked config built at 0.25 gated green and `check` failed only `TIP_OVER_ROOT` on both sleeves (`propose --from-config` named 54 `LINT` lines, links off the art) — re-run `assemble` and `propose` at the new scale. Absent: `CONFIG_FIELD_PRESENT`; 0, negative or not a number: `CONFIG_FIELD_TYPE`; a rig under 1x1: `ASSEMBLE_RIG_SIZE` |
|
|
151
152
|
| `assemble.plan` | assemble; also the list every `meshes`/`regions` key must come from | **proposed** by `assemble --propose-plan`. `[part name, "full" \| "head", See-through tag]`, in draw order back to front. Names are free; roles come from the tag. A layer the author made and added to a run takes `author:<label>` in the tag's place, and has no role (§5, *A layer the author made*). When `generation.control.skeleton` is present and a full-run `handwear-r` or `handwear-l` layer merges sleeve, bare hand and overgarment drape into one layer — a skin-coloured hand cluster (`>= 40` run px, `GHOST_MIN_AREA`, measured `516..4,787` run px across the 9-standee corpus) lies within `0.35` forearm lengths of `<s>_wrist` and non-skin pixels reach more than `1.0x` the forearm length (`<s>_elbow -> <s>_wrist`) below `<s>_wrist` (issue #490; measured `-0.15x..0.45x` on the 6 clean standees vs `1.25x..2.02x` on the 3 merged standees, placing `1.0x` inside the `0.45x..1.25x` gap) — the layer is split into `drape-<s>`, `handwear-<s>` and `hand-<s>` (back to front) when the Euclidean RGB distance between the sleeve median colour above `<s>_wrist` and the drape median colour below `<s>_wrist` is at least `80` (`ARM_DRAPE_COLOR_DISTANCE`, measured `103.6..236.0` on the two distinct-colour merged standees vs `20.8..28.2` on the same-colour merged standee, placing `80` between `28.2` and `103.6`), or refused with `SEETHROUGH_ARM_RUN_MERGED` when the distance is under `80` |
|
|
152
153
|
| `assemble.extend_below_crop` | assemble | **proposed** with the plan: `{part, run, tag}` — a head-run part that reaches the bottom of the head crop is continued from a full-run layer, whole connected components |
|
|
@@ -172,7 +173,7 @@ read by no CPU stage).
|
|
|
172
173
|
| `motion.blink.still` | rig | **proposed** only for a lash `propose` notes (below), then checked: `{<part>: {row, bone}}` — the rows of that region part above `row` (rig px, y down) are drawn by a second slot `<part>_still` on `bone` and do not blink; rows from `row` down keep the part's slot and blink. The part must be a region on a bone `eyes` names, `bone` one it does not (`CONFIG_STILL_OFF_THE_BLINK`), and `row` a row of the part with no art across its whole width (`RIG_STILL_ROW_CLEAR`) |
|
|
173
174
|
| `motion.animations_from` | rig; check (named; read for folds) | optional, never proposed (issue #183): a path, relative to the config file's directory, to a file in rig-c's motion-spec shape, `{"spec": "rigc-motion/1", "animations": {"<name>": {"duration": …, "tracks": [...]}, …}}` — an expression, a gesture, anything beside the idle. On every `rig` and `build` each of its animations is written into `rig/motion.json` after `idle`, as read: nothing added, re-keyed or judged here (except `derive` keys on `turn`/`tilt`, issue #436, and `{"t": …, "set": "<name>" \| null}` keys on slot `"attachment"` tracks, issue #473, which expand to `"v": "<set>_<slot>"` or `"v": null` when the set hides the slot, or `"v": "<slot>"` for `null`, refused with `CONFIG_SET_COVERS_SLOT` when the set is undeclared or does not cover the track's slot), and each is rigc's to accept or refuse at the rig stage's gate, in rigc's words. It may name what `motion.json` already holds — the bones `bones` declares, the easings `shut` and `open`, the groups `eyes` and `brows` when the blink writes them — and nothing else from the file reaches it. The loader refuses, every problem at once: no such file or one that cannot be read (`CONFIG_FILE_PRESENT`), text that is not JSON (`CONFIG_IS_JSON`), a file that is not an object, a `spec` other than `"rigc-motion/1"`, an `animations` that is not a table of objects (`CONFIG_FIELD_TYPE`), any other key — rig-c's `easings`, `groups`, `setup`, `physics`, `mix`, `archetype` and `cut` included, which would be read and not written (`CONFIG_KEY_KNOWN`), an animation named `idle` (`CONFIG_ANIMATION_NAME_FREE`), and a key written twice in one object of the file, which JSON would fold into its last value without a word (`CONFIG_KEY_UNIQUE`). `check` names the others on one line (`beside the idle: …`) and reads each for folds, with the idle — `ANIMATIONS_DO_NOT_FOLD` (§7, issues #320, #333); every other bar reads the idle. Absent, `motion.json` holds the idle alone, byte for byte as before, and `check` reads that idle for folds |
|
|
174
175
|
| `constraints` | rig (handed to rig-c as `rig.json`'s `constraints`); `compare` and the coverage lines (roles) | **authored**, optional; `propose` writes none, but with `--cloth` (issue #364), where it writes the recipe's physics and swing transforms (*Recipe: cloth and hair that answer the world*, below). A list of constraints in **rig-c's own rig-spec shape** (`RigConstraint`: `ik`, `transform`, `path`, `physics`, `slider` — rig-c's `src/rig.ts` documents every field), in the order rigc applies them. The loader checks only what this package owns: each entry is an object with a `type` rigc names (`CONFIG_CONSTRAINT_TYPE_KNOWN`) and a non-empty `name`, unique within its kind as rigc finds constraints (`CONFIG_CONSTRAINT_NAME_UNIQUE`; an ik and a transform may share one); every bone it names — `bones`, an ik's `target`, a transform's `source`, a physics or slider constraint's `bone` — is a bone `bones` declares, a chain link as `<chain><i>` (`CONFIG_NAME_RESOLVES`); the bone a constraint follows does not sit under a bone it drives (`CONFIG_CONSTRAINT_TARGET_DETACHED`). Every other field (`mix`, `softness`, `properties`, a path's `slot`, a slider's `animation`) and every value is rigc's to accept or refuse at the rig stage's gate, in rigc's words (`RIG_RIGC_GREEN`) — an ik's `bones` as a shape too: from rig-c 2.15.0 rigc refuses an ik over more than two bones, or over a pair whose second bone is not the first's child (issue #103; this loader refused both itself until then). A note and an `x-` record may ride on an entry; the rig stage leaves them out of what it hands rigc. Under the default `--idle-keys ctl` a two-bone ik whose child link the idle keys is split by that link's control, and rigc refuses the pair: run `rig --idle-keys direct` or `build --idle-keys direct` (the rig stage adds that sentence, naming the flag on the command that ran, to rigc's line; `build` forwards it to its rig stage, issue #95). Each bone a constraint follows is declared to rigc as `invariants.detached` from every bone it drives, which rigc's gate rule `A25` checks |
|
|
175
|
-
| `stops` | rig (handed to rig-c as `rig.json`'s `stops`, and moves slots, mesh weights and child bones on stopped links onto `<link>_d`); `propose --from-config` (`LINT stop on <chain> …`) | **authored**, optional (issues #404, #447): `[{chain, links?, against, at, inward, outward, lower?: {inward, outward}}]` — rig-c's leg stops (`RigStop`, rig-c 2.56.0, `@rig-c/core/
|
|
176
|
+
| `stops` | rig (handed to rig-c as `rig.json`'s `stops`, and moves slots, mesh weights and child bones on stopped links onto `<link>_d`); `propose --from-config` (`LINT stop on <chain> …`) | **authored**, optional (issues #404, #447): `[{chain, links?, against, at, inward, outward, lower?: {inward, outward}}]` — rig-c's leg stops (`RigStop`, rig-c 2.56.0, `@rig-c/core/stop`). `chain` is a chain `bones` declares (`CONFIG_NAME_RESOLVES`, `RIG_NAME_RESOLVES`); `links`, optional, is a non-empty list of links of that chain (`CONFIG_NAME_RESOLVES`, `CONFIG_FIELD_TYPE`), or absent for every link of `chain` in chain order; `against` is a bone `bones` declares, a chain link as `<chain><i>` (`CONFIG_NAME_RESOLVES`, `RIG_NAME_RESOLVES`); `at` is `[x, y]` in `against`'s local space, as rig-c's stop takes it (`CONFIG_FIELD_TYPE`): since each chain link (`leg_r0`, `leg_r1`) is turned to point along its segment (`+x` from origin to next link or tip, `+y` 90° counter-clockwise in Spine world), `at: [d, n]` sits `d` px from `against`'s origin toward its end and `n` px perpendicular to it; `inward`, `outward` and `lower.inward`, `lower.outward` are finite numbers (`CONFIG_FIELD_TYPE`). Every other stop rule — non-negative bounds, each stopped link written by a constraint, `against` not under the stopped chain, the aim not degenerate, `\|rest\| + outward <= 180°` (`RIG_STOP_BOUNDS`) — is rigc's to accept or refuse at the rig stage's gate, in rigc's words (`RIG_RIGC_GREEN`). **Rising-limb / prone geometry (issue #447):** rig-c's `expandStops` aims `<chain>_rest` from `links[0]`'s setup origin at `<chain>_touch` (`at` in `against`'s local frame) and clamps `<link>_d` inside `[rest − inward, rest + outward]`; Spine wraps rotation at `±180°`, so `\|rest\| + outward <= 180°` is required (`RIG_STOP_BOUNDS`). Whenever `<chain>_touch` lies **above** `links[0]`'s root in rig pixels (`ty < y0`, i.e. higher Spine `y` — e.g. stopping a hanging cloth chain against a rising shin `leg_<s1>` in a prone or kneeling pose where the knee sits below `links[0]` and the ankle above it, so positive `at[0]` walks upward along the shin past `links[0]`'s root), `rest` lands in the upper half-plane (`\|rest\| > 90°`) and `\|rest\| + outward` exceeds `180°`. Stop against the descending thigh (`leg_<s0>`), set `links` to start at a link whose root sits above `<chain>_touch`, or omit the stop when the rising shin sits outside the hanging chain's sweep; `propose --from-config` prints `LINT stop on <chain> …` with the exact coordinates and angles when `<chain>_touch` lies above `links[0]`'s root or `\|rest\| + outward > 180°`. For every stopped link `<link>`, the rig stage moves any slot on `<link>`, any mesh weight on `<link>`, and any bone whose parent is `<link>` (a branched cloth tree's branches hanging from `<trunk_last>`, before `--idle-keys ctl` adds `<bone>_ctl` and before `turn` adds `turn_<part>_<bone>`) onto `<link>_d`, the drawn link bone rig-c's `expandStops` creates at `<link>`'s setup frame to carry the clamped rotation. Absent, `rig.json` carries no `stops` and no byte of any output moves |
|
|
176
177
|
| `turn` | rig (adds the turn control or 2.5D head-turn producer) | **proposed** only with `propose --full`/`--head` (issue #251), then corrected, or **authored** for 2.5D depth-sampled head turns (issue #763): `{pivot?, depths?, deform?, band?, radius?, surface?: {radius?}, head?: {pivot?, radius?}, roles?, counter?, grid?, unitDepths?, body?}`. When `roles` is declared (`{<part>: "surface" \| "unit" \| "rear"}`, issue #763; `CONFIG_TURN_ROLE_UNKNOWN`, `CONFIG_TURN_SURFACE_REQUIRED`, `RIG_TURN_SURFACE_MESH_BINDINGS`, `CONFIG_TURN_UNIT_MESH_BONES`), the rig stage runs the 2.5D depth-sampled head-turn producer: it edge-extends each turn-bound part's depth sheet across its transparent border and semi-transparent fringe from the nearest fully opaque (`alpha === 255`) texel before `PAD = 4` clamping (`padTurnDepthSheet`, `DEPTH_SILHOUETTE_SIZE_MISMATCH`), keeps authored `"surface"` meshes and their skinning (#795), sampling each vertex at its weighted setup position on its own extended sheet and emitting one inverse-setup-bone offset per influence (`D = -(pivot + z - zRef) * sin(angle)`, on x for yaw and y for pitch, with no narrowing or 2D spin); shared frames moved by another turn role are refused (`RIG_TURN_SURFACE_MESH_BINDINGS`), as are alternate drawings without their own depth sampling frame (`RIG_TURN_SURFACE_MESH_ATTACHMENT`). It promotes `"surface"` regions to `generator: {kind: "grid", cols, rows, depth}` (`grid`: `[cols, rows]` or `{<part>: [cols, rows]}`, default `[13, 16]`, bounded at `<= 2,400` triangles per slot and `<= 4,000` total, `RIG_TURN_GRID_BUDGET`, `RIG_TURN_SURFACE_DEPTH_REQUIRED`, `RIG_TURN_SHARED_DEPTH_SCALE`), emits `faceshift` and `rear_shift` under `head` (`CONFIG_TURN_HEAD_BONE`, `RIG_TURN_HEAD_BONE`), `<part>_surface` and `<part>_unit` under `faceshift`, and `yaw_dial` and `pitch_dial` under `root` (`CONFIG_TURN_BONE_FREE`, `RIG_TURN_NAME_FREE`), re-parents `"unit"` region bones and `"rear"` bones and mesh weights to `faceshift` and `rear_shift` (while `"unit"` mesh parts receive their own `<part>_unit` carrier under `faceshift`, rebind direct `"head"` weights to `<part>_unit`, reparent bound chain roots to `<part>_unit` while keeping chain skinning weights intact, and key `<part>_unit` in `turn_units`, #790), samples each `"unit"` bone's depth from the `"surface"` depth sheet at its rest position (or reads `unitDepths.<part>`, `RIG_TURN_UNIT_DEPTH_REQUIRED`), enforces ear occlusion (`ear_r`/`ear_l` drawn before the `face` surface in `assemble.plan`, `CONFIG_TURN_EAR_DRAW_ORDER`, and behind the cheek surface, `RIG_TURN_EAR_DEPTH_BEHIND_CHEEK`), and writes `turn` and `tilt` `derive` tracks (`pivot` default `55` rig px, `counter` default `0.1` in `[0, 1]`, `CONFIG_TURN_COUNTER_RANGE`). `depths` holds, per part, the See-through layer's `depth_median` the part came from (larger = further back), read from the run the part was assembled from; a `painting:` patch has none and is not carried. A rider (issue #271) — a part from an `eyewhite`, `irides`, `eyelash`, `eyebrow`, `nose` or `mouth` layer — is drafted at the `face` part's depth, 0.001 nearer when parts.json draws it after the face and 0.001 further when before: See-through makes no depth of its own for the eye group (it cuts them from one depth map of the combined eyes) and clamps nose and mouth to the face's median − 0.001, and the two runs' own medians for these layers disagreed by up to 0.47 and swapped their order against the face. Every other layer — ears, headwear and earwear included — keeps its own median, unless it rides another part's bone. With no `face` part, or more than one, the riders keep their own and a note says so. A rider by bone (issue #535) — a part every *ownable* bone of which (a chain link, or a bone no other bone hangs from; `head`, `chest` and any bone with a child are shared and never count on their own) is *hosted* by another carried part, the host of a bone being the carried part that binds it (its region's bone; a mesh's `segments`, `contour` and `auto` regions' bones) with the most `opaque_px`, the earlier in parts.json on a tie, and which hosts no bone itself — is drafted at its host's depth, 0.001 nearer when drawn after the host and 0.001 further when before, and a note names the host, the bones and its own median: a pin, clip or ornament on the back hair's links travels with the back hair, not with its own layer's depth. `propose` reads the proposal's own `bones`, `meshes` and `regions`; the face riders are read by their tag first and never by their bones. A part bound to two hosts' bones rides neither and a note says so. In the rig stage, an authored depth on a rider by bone whose fraction differs from its host's by more than 0.1 of the dial (`TURN_RIDER_APART`, a share of `pivot − nearest`) is refused (`CONFIG_TURN_RIDER_DEPTH`); the host is read off `parts.json`'s `opaque_px`, so the config loader cannot see it. One note lists each part's depth and where it came from; a carrier the other run places more than 10 % of `pivot − nearest` away gets a note naming both values and the run read — the two runs are not reconciled. `pivot` is the depth that stays put; `propose` drafts the mean of the parts' depths weighted by `opaque_px`, the one depth at which the painted pixels' centroid does not slide under the dial. The rig stage adds a bone `turn` under `root` at its origin that nothing keys — its local x is the dial, in rig px — and carries each part by `(pivot − depth) / (pivot − nearest depth)` of it: the nearest part all of it, a part behind the pivot the other way, a part at the pivot not at all. Each part rides leaf twins (`turn_<part>_<bone>`, an identity child of every bone its slot and weights bind) moved by one `transform` constraint (`turn_<part>`, after the config's own); the idle's keys, the `<bone>_ctl` controls and a physics constraint stay on the bones, and the dial moves none of them. Optional `deform` (`Partial<FaceDeformFractions>`, issue #436) overrides the Set B ×2.5 face surface deformation table (`FACE_DEFORM_FRACTIONS`, checked against `FACE_DEFORM_RANGES` by `CONFIG_TURN_DEFORM_RANGE`); when `applyFaceSurfaceDeform` runs on a rig whose `motion` carries `tilt` or `turn` slider `derive` keys, it requires `config.turn` (`CONFIG_TURN_REQUIRED`, issue #478; `propose --full`/`--head` drafts it), promotes `face` on `head` (or `turn_face_head` when `turn` is declared) to the uneven 5×5 grid mesh, keys `face`, `hair_front` and `hair_back` deform timelines and ear/topknot tracks from `evalPitchFaceSurface` and `evalYawFaceSurface`, and samples the same deform field across each `features` member's rest span (`featRx = (24 / 106) · W`, `featRy = (12 / 128) · H`) with its depth fraction `z / zRef` as the field's angle input and chord foreshortening (`scalex` narrowing on the leading side and widening on the trailing side, `scaley` on pitch) so every feature's bounding box stays inside the deformed face plate across the rated band (issue #468). On yaw (`issue #479`), `evalYawFaceSurface` evaluates a **cylinder projection** (`cylinderYawDx`: `Δx(x, θ, R) = R · (sin(clamp(arcsin(clamp(x / R, −1, 1)) − θ, −π/2, π/2)) − clamp(x / R, −1, 1))`) of radius `R` (`turnSurfaceRadius`: `turn.surface.radius ?? turn.radius ?? turn.head.radius`, positive rig px checked by `CONFIG_FIELD_TYPE`, defaulting to half the face plate's opaque width `W / 2`) tapered by a cubic Hermite outline weight (`wOutline = 1` for `\|ux\| <= 0.7`, reaching `0` at `\|ux\| = 1.0`) so features slide across a fixed outline (`iris` shift within `±2%` of `cylinderYawDx`), the trailing cheek strip widens (`>= 1.54×` at `±15°`), and the leading jaw edge holds fixed (`0 px` shift) unless explicit horizontal `turn.deform` overrides (`turn_mid_x`, `turn_lead_compress_x`, `turn_trail_shift_x`) request the flat yaw table. On yaw (`issue #478`), `applyFaceSurfaceDeform` also derives a **head-only pivot** (`headTurnPivot`: `turn.head.pivot` when authored, otherwise the `opaque_px`-weighted mean of `depths[part]` across the head parts `DEFAULT_HEAD_TURN_PARTS` — `face`, `hair_front`, `hair_back`, `ear_r`, `ear_l`, `hairpin` — from `parts.json`, falling back to `turn.pivot`) so a forward torso or arm in `turn.depths` does not pull the head's rotation axis in front of `face`: `hair_back` (`depth_median > headPivot`, negative `headTurnFraction`) and `hairpin` behind `headPivot` translate opposite to the face's turn (`dx = s · turn_face_center_x · W · (headPivot − depth) / (headPivot − nearestHeadDepth)`), emerging on the trailing side to compensate for the leading-cheek foreshortening and keeping the combined head silhouette width near-constant across `±15°` without any same-sign `turn_hair_back_cheek_x` term. Optional `band` (`number` or `{yaw?, pitch?}`, positive degrees, issue #472) declares the rig's rated face turn band (default `FACE_RATED_BAND`: `yaw <= 15°`, `pitch <= 12°`); declaring a `turn.band` or a `motion.animations_from` `turn`/`tilt` `derive.degrees` above `±15°` yaw or `±12°` pitch without an `assemble.alternates` entry that replaces `face` is refused (`CONFIG_FACE_BAND_EXCEEDED`), and on a single-plate rig `applyFaceSurfaceDeform` adds self-targeting transform constraints `yaw_clamp` (`[-15, 15]`) and `pitch_clamp` (`[-12, 12]`) ahead of the slider constraints so driving `yaw` or `pitch` beyond the rated band clamps at the boundary. At rest: with `turn` declared, no pixel differs by more than 1 level at dial 0 (not byte-identical; the cause is float noise in the identity child bones, and the constraints add nothing); without `turn`, byte-identical. Neither `pivot` nor `depths` has a default (`CONFIG_FIELD_PRESENT`); `pivot` and `head.pivot` must lie behind the nearest part (`CONFIG_TURN_PIVOT_BEHIND_NEAREST`). Absent, no control is added and no byte of any output moves |
|
|
177
178
|
| `scene` | assemble (the recomposite, its holes and the figure's mask); check, through `parts.json`'s `scene` block (`RECOMPOSITE_HOLES`, the seam) | **authored**, optional; `propose` writes none (issue #242). `{}` declares the painting a scene: the figure and its surroundings in one image, See-through's full run holding only the figure. With it, `assemble` reads the recomposite figures, the hole list and the `uncovered:` lines inside the figure — the rig pixels where any full-run layer's alpha is above 8 (`OPAQUE_ALPHA_ABOVE`, the cut every layer's painted pixels are read by) — each line starting `inside the figure (config.scene: …, <n> of <m> rig px)`; writes that figure as `figure_rig.png` (white on black) beside the recomposite, and a `scene` block in `parts.json`; flags error pixels on the error map inside it only (outside, the painting grey); and `check` leaves out of the seam every frame pixel whose composite sample reaches the painting's outermost row or column, saying how many (`seam_border` in `check.json`, and on the seam line). It takes no field: the figure and its threshold are derived. A key in it other than a record or an annotation is `CONFIG_KEY_KNOWN`. Absent, no byte of any output moves |
|
|
178
179
|
| `cloth` | `propose --cloth` only; no other stage reads it, so it moves no byte of any build | **authored**, optional (issue #364): one recipe per tag, `{"bottomwear": {…}, "back hair": {…}, "front hair": {…}}`, each `{chains, links, wind, gravity, split?, length_ratio?, strength?, damping?, alternate_damping?, translate?, swing?, part?, influence?}`. `influence` (issue #518) — `{across, max, shape, radius?}`: the parts this recipe meshes are drafted in the influence mode (`meshes.<part>.influence` above) at their lattice's cell, with `across`, `max` and `shape` as declared (each required — the reading behind the radius did not vary them) and `radius` as declared or, absent, drafted as the farthest vertex's distance plus 3 cells (the `influence.radius` row); without it the parts keep their lattice. `chains` — trees across the piece (for `back hair`, per side of the eye axis), a whole number, 1 or more; `links` — links from root to tip on every path, 1 or more; `split` — `{at, into}`: the first `at` links are the trunk, which forks into `into` (2 or more) branches; `at` below `links` (`CONFIG_CLOTH_SPLIT_BEFORE_TIP`); `length_ratio` — a path's last link over its first, above 0, default 0.5; `strength` — `{trunk, branch, edge}`, each above 0 and below the spring's stability bound (`CONFIG_CLOTH_SPRING_STABLE`), default 100 / 100 / 50; `damping` — in [0, 1], absent: rig-c's default; `alternate_damping` — the odd trees' damping, in [0, 1], beside `damping` and different from it (`CONFIG_CLOTH_ALTERNATE_DIFFERS`); `wind`, `gravity` — `[root, tip]`, each 0 or more, tip at or above root (`CONFIG_CLOTH_RESPONSE_GROWS_TO_TIP`); `translate` — the x and y mix of a dangling end's flutter, above 0 and at most 1; `swing` — `bottomwear` only, `{scales}`, one positive scale per tree (`CONFIG_CLOTH_SWING_SCALE_PER_TREE`); `part` — `bottomwear` only (`CONFIG_CLOTH_PART_ON_BOTTOMWEAR`), a non-empty part or cut-piece name: the `topwear` part that holds a skirt See-through returned inside it (a dress), or its skirt piece cut by `assemble.cuts`, which takes the skirt's trees (issue #402, *A skirt inside topwear* below; the part is checked by `propose`, `PROPOSE_CLOTH_PART`). The two defaults are the recipe's own, measured on its synthetic fixture (the recipe below). The recipe below says what each field drafts. The config written: `propose --cloth <config.json> --write-config <out.json>` (issue #537) writes this config's own text back with the sections the recipe drafts spliced in — `meshes.<part>` and `regions.<part>`, and `bones`, `constraints` and `motion.tracks` entry by entry by name (issue #552) — and every other byte as read; `--from <previous config>` (issue #571) takes an entry equal to the previous recipe's draft as the recipe's (*The config written*, under the recipe below) |
|
|
@@ -5084,7 +5085,7 @@ documents do not ship). Each is an input this package built; none is an author's
|
|
|
5084
5085
|
| <a id="REQUIREMENTS_MAY_FOLD"></a>`REQUIREMENTS_MAY_FOLD` | a `may_fold` entry names a slot with no mesh attachment — a region is one quad and cannot fold (issue #320). Refused before anything is built. Before issue #333 an entry naming the idle was refused here too; the bar reads the idle now, and `idle` is an animation name like any other | a mesh slot |
|
|
5085
5086
|
| <a id="REQUIREMENTS_NOT_PLANTED"></a>`REQUIREMENTS_NOT_PLANTED` | a `not_planted` name is a part `check` does not read as a planted foot — it does not come from a See-through `footwear` layer — or there is no `parts.json` to choose the feet by (issue #231). Refused before anything is built | a `footwear` part's name |
|
|
5086
5087
|
| <a id="REQUIREMENTS_TIP_EXCEPTION"></a>`REQUIREMENTS_TIP_EXCEPTION` | a `not_swinging`, `rises` or `rests` name is a part `TIP_OVER_ROOT` does not read — not from a See-through `handwear` or `bottomwear` layer — or there is no `parts.json` (refused before anything is built); or a `rises` part is not carried by a chain that rises: the chain's **last link**, at the setup pose, runs other than up — from its origin along its `length` (the extent the rig stage turns a link to), or, a last link with no length, from the link before's origin to its own — the detail giving the link read and the direction measured (refused after the idle is rendered, before `check.json` is written) (issues #231, #322; until #322 it read the chain's first link's origin to its last's, which refused a folded arm — a link that hangs, then a forearm raised) | a swinging part's name; for `rises`, a part whose chain does rise |
|
|
5087
|
-
| <a id="CHECK_ENVIRONMENT"></a>`CHECK_ENVIRONMENT` | `check --environment` (or `build --environment`, forwarded): the schedule is refused, the detail rigc's own sentence verbatim. Read once by rig-c's reader (`readEnvironmentSchedule`, `@rig-c/core/
|
|
5088
|
+
| <a id="CHECK_ENVIRONMENT"></a>`CHECK_ENVIRONMENT` | `check --environment` (or `build --environment`, forwarded): the schedule is refused, the detail rigc's own sentence verbatim. Read once by rig-c's reader (`readEnvironmentSchedule`, `@rig-c/core/environment`) before anything is built — nothing at the path, a file that is not JSON or not an object, a `spec` other than `rigc-environment/1`, a key besides `spec`, `steps` or a step's `t`, `wind`, `gravity`, no step, a `t` not finite, below 0 or not after the step before, a `wind` or `gravity` not a pair of finite numbers (JSON's `1e999` reads as `Infinity` and is refused), a step stating neither — and `--out` is not written (`build` refuses under `[assemble]`, before it assembles). After the build, what `rigc render --environment` refuses of a well-formed schedule on this rig, quoted from its `--environment <path>:` line: no physics constraint, a half no constraint answers, two steps on one frame at 12 fps, a step after the last frame of the animation rendered. Also refused before anything is built: a `motion.json` with no animation, where no render `check` makes could pose the schedule | the schedule — rigc's sentence names the entry, the field, the value found and the value required; for a rig with no physics constraint, drop the flag: no world moves it |
|
|
5088
5089
|
| <a id="CHECK_WIND_BAND"></a>`CHECK_WIND_BAND` | `check --wind-band` (or `build --wind-band`, forwarded, issue #590): the sweep file is refused before anything is built, or cannot be measured against the rig. Refused before the build (`build` refuses under `[assemble]` before it assembles, and `--out` is not written): nothing at the path, a file that is not a JSON object, an unknown key (besides `note`, `*_note` and `x-…`), a missing or malformed field (`spec` must be `"rig-parts-wind-band/1"`; `min`, `max`, `step` finite numbers with `min < max`, `step > 0`, and `(max - min) / step` within `1e-6` of an integer at most `64`; `fps` a positive integer; `max_gap` and `max_ghost` non-negative integers; `pairs` a non-empty array of unique `"<a>:<b>"` strings with `a !== b`). Refused against the rig before `rigc build`: a slot in `pairs` not in `rig.json`'s `slots`, `motion.json` with no animation, a rig with no physics constraint, or a rig where no physics constraint has a non-zero `wind`. Refused after the first sweep render (before `check.json` is written, with `--out` cleaned): a pair in `pairs` whose drawings share no overlap band at the setup pose (`status: "skip"` or `banded === 0` in `seam.json`) | the `--wind-band` file or the rig — every field in `"rig-parts-wind-band/1"` is required (nothing falls back to `SEAM_OVER_MOTION`), each `"<a>:<b>"` pair must name two distinct slots whose art overlaps at rest, and the rig must declare at least one physics constraint that answers `wind` |
|
|
5089
5090
|
| <a id="REQUIREMENTS_SEAM"></a>`REQUIREMENTS_SEAM` | a `seam` cannot be read against the rig: there is no `parts.json` (a merged rig, §7 *Measuring a rig rig-parts did not assemble*), or the two parts' art does not meet at the setup pose (no 4-adjacent pair). Refused before anything is built | two parts whose art touches, on a rig with its `parts.json` |
|
|
5090
5091
|
|
|
@@ -5157,7 +5158,7 @@ Absent declaration retains existing output bytes except optional new evidence on
|
|
|
5157
5158
|
|
|
5158
5159
|
**Body-root seam identity** (issue #686). A limb must have exactly one segment0 part. Its declared bone must have one named immediate parent; the root slot must bind that bone (or its declared turn child). Non-limb parts with `topwear` or `bottomwear` source provenance, a slot on that parent (directly or through its verified generated turn child) and a named default-skin drawing are candidates. The body-side child must match `applyTurn`'s exact generated name, unique identity bone and parent, control and per-part transform binding; a similarly named bone alone is not proof (issue #708). The original carrier and pair slot names do not change under turn; stock setup pose `render --seam` selects all matching drawings with `banded > 0` (its existing alpha-overlap band, without dilation), so one selects one pair and two select both pairs. When eligible candidates all return valid setup banded 0, that limb has no selected root pair: `unmeasuredRoots` retains its limb, bone, parent, segment0 part, candidates and named reason, reported as SKIP, not measured PASS. Part spelling, nearest geometry and shared mesh influences select nothing. On `wind` the pairs are `topwear|upperarm_r`, `topwear|upperarm_l`, `bottomwear|thigh_r` and `bottomwear|thigh_l`; “trunk” is not a part name. Existing pairs keep their order; a reversed explicit declaration deduplicates with the root pair and retains both declarations. An ambiguous/missing named binding, no eligible candidate, or unreadable/undrawn setup data is `CHECK_MOTION_SEAM_ROOT`, naming the part and candidates. Valid zero-band metadata is carried separately as optional `roots.unmeasured`, never as a fabricated measured pair. The all-zero root block remains present and its bar is skipped; measured FAIL takes precedence over SKIP, while measured PASS plus any unmeasured root stays SKIP. No body provenance leaves legacy pair selection unchanged and supplies no body-root coverage.
|
|
5159
5160
|
|
|
5160
|
-
Renderer metadata and exact raster reads use the promised `@rig-c/core/render-shared` entry (rig-c
|
|
5161
|
+
Renderer metadata and exact raster reads use the promised `@rig-c/core/render-shared` entry (from rig-c 2.69.0). It registers no Spine runtime; where that runtime resolves from rig-c's own package root, the existing `@rig-c/core/render` entry registers the official Spine side explicitly. An install without Spine keeps rig-c's own candidate chooser and gate; candidate or loader failures never select a guessed fallback.
|
|
5161
5162
|
|
|
5162
5163
|
The body-root bar counts stock partitions `gapOpen` plus `ghostA` or `ghostB` owned by the pair's UNDER-owned drawing in resolved draw order on each active frame, comparing their summed cells against the unchanged strict floor `px > round(max(box width, box height) / cell)` on the original raw kind boxes (their union when both kinds contribute), never the narrowed partition boxes; `gapCovered` and OVER-owned ghost cells do not count (issue #711). The metric mode is `gap-open+under-ghost`; rows retain the exact partition counts, UNDER owner and counted total in `cells`, including excluded and under-floor readings. Missing partitions, inconsistent sums or unavailable ownership are named `FRAMES_SIDECAR` refusals, never inferred zero. An active rendered environment fails `CHECK_SEAM_OVER_MOTION` above that floor, setting overall PASS false and exits 1. Existing internal-joint and explicit-only pairs remain warnings: their PASS, exit status and bar count are unchanged; reference worlds remain informational. The root bar is counted once, and absence is not a zero or a PASS. No whole-box alpha exemption or consumer compositor is used. This gate samples the supplied animations at 12 fps, not another motion or player scene.
|
|
5163
5164
|
|
|
@@ -5233,6 +5234,7 @@ and stay absent).
|
|
|
5233
5234
|
| <a id="RIG_TURN_SURFACE_MESH_BINDINGS"></a>`RIG_TURN_SURFACE_MESH_BINDINGS` | an authored surface mesh has unresolved/nonclosing weights or shares a frame moved by a unit/rear turn carrier; declared stop draw aliases resolve to their links for setup sampling | provide weighted bindings closing at 1 in the authored frame; `<link>_d` resolves only for links declared in `config.stops`; use independent chains for parts with different roles |
|
|
5234
5235
|
| <a id="RIG_TURN_SURFACE_MESH_ATTACHMENT"></a>`RIG_TURN_SURFACE_MESH_ATTACHMENT` | a surface mesh has an alternate drawing without its own registered depth sampling frame | use the base attachment; explicit islands retain their own slot, attachment and bindings |
|
|
5235
5236
|
| <a id="RIG_TURN_BODY_UNCOVERED"></a>`RIG_TURN_BODY_UNCOVERED` | **Warning:** a shown part without a body role overlaps a moved `turn.body` surface at setup alpha >= 128 and has different emitted endpoint displacement | declare the intended body role and inspect both endpoints; no role or depth is inferred |
|
|
5237
|
+
| <a id="RIG_TURN_HEAD_ROLL"></a>`RIG_TURN_HEAD_ROLL` | **Warning:** a declared head turn has an absolute authored-eye-origin roll above the empirical limit displayed as 18.485385 degrees; names the face/eye parts, both eye bones, signed roll and limit | inspect the neck at both extremes; this proxy does not detect the painting independently, correct tilt or change emitted bytes; see [Head roll before a declared turn](#head-roll-before-a-declared-turn) |
|
|
5236
5238
|
| <a id="RIG_TURN_SURFACE_DEPTH_REQUIRED"></a>`RIG_TURN_SURFACE_DEPTH_REQUIRED` | a part with role `"surface"` in `config.turn.roles` or `config.turn.body.roles` carries no depth sheet in `parts.json` | run `assemble` with `config.depth` or provide `<part>_depth.png` in `parts.json` |
|
|
5237
5239
|
| <a id="RIG_TURN_GRID_BUDGET"></a>`RIG_TURN_GRID_BUDGET` | a `"surface"` grid exceeds 2,400 triangles on one slot or 4,000 triangles across all `"surface"` slots | lower `config.turn.grid` / `config.turn.body.grid` `[cols, rows]` within the per-slot and total budgets |
|
|
5238
5240
|
| <a id="RIG_TURN_HEAD_BONE"></a>`RIG_TURN_HEAD_BONE` | `buildRig` found no `"head"` (or body turn root) bone when emitting 2.5D turn carriers | declare `"head"` (or the body turn root bone) in `config.bones` |
|
|
@@ -5663,7 +5665,7 @@ Under `--source <painting.png>`, a second reported line, also never a FAIL
|
|
|
5663
5665
|
| line | reports | bar | `reference-demo` | `reference-sample` | SKIP when |
|
|
5664
5666
|
| --- | --- | --- | --- | --- | --- |
|
|
5665
5667
|
| <a id="SETUP_POSE_VS_SOURCE"></a>`SETUP_POSE_VS_SOURCE` | the setup pose against the painting, by `assemble`'s own `measureRecomposite` over the stage's pixels — `mean_abs` and `within_share` (mean channel, within 8), `error_px` (max channel over 40), `uncovered_error_px` (of those, where the pose has alpha 128 or less), `hole_count` and the largest hole's box — with `painting_px`, `stage_px`, `render_px` and `render_scale` beside them. The painting is resampled onto the stage as assemble resamples it (lanczos3, alpha dropped). rigc renders onto an opaque grey, so the pose over white and its alpha are read off a second still of the same pose with every slot tinted black; both are carried onto the stage with the seam's map turned round (bilinear) | none — status `REPORTED`; assemble applies no bar to the figures it measures, so none is derived here | 3.146 / 93.43 % / 12,399 / 1,732, 518 holes, the largest 61 px at 351,157 6x20 (assemble's recomposite: 2.391 / 95.81 % / 11,050 / 1,564, 453) | 1.095 / 97.30 % / 5,348 / 1,239, 313 holes, the largest 88 px at 479,416 6x29 (assemble's: 0.835 / 97.95 % / 4,512 / 1,185, 259) | not written without `--source` |
|
|
5666
|
-
| <a id="SETUP_MATCHES_PAINTING"></a>`SETUP_MATCHES_PAINTING` | declared region count, native box, limit and actual top contributor rows | PASS/FAIL against authored limits; no limit is SKIP; undeclared regions are not judged |
|
|
5668
|
+
| <a id="SETUP_MATCHES_PAINTING"></a>`SETUP_MATCHES_PAINTING` | declared region count, native box, limit and actual top contributor rows | PASS/FAIL against authored limits; no limit is SKIP; with `--source`, no declaration is SKIP with its reason and declaration remedy; undeclared regions are not judged |
|
|
5667
5669
|
|
|
5668
5670
|
The figures are assemble's by construction, not a second definition beside them;
|
|
5669
5671
|
what differs is what they are taken of — the pose rigc draws, not the flat stack —
|
|
@@ -6229,7 +6231,22 @@ maximum absolute RGB-channel difference is **strictly greater** than that
|
|
|
6229
6231
|
value. The region passes when its total count is at most its authored
|
|
6230
6232
|
nonnegative integer `max_pixels`. Without that limit the region reports
|
|
6231
6233
|
**SKIP**, including a zero-count region. An undeclared region has no verdict.
|
|
6232
|
-
|
|
6234
|
+
With `--source` but no `setup_painting` declaration, `SETUP_MATCHES_PAINTING`
|
|
6235
|
+
is explicitly **SKIP** in the console, `check.json`, the report's skipped-bar
|
|
6236
|
+
list and `check --json`. Its reason says the comparison was not measured and
|
|
6237
|
+
asks for `--requirements <file>` declaring `setup_painting.rgb_tolerance` and
|
|
6238
|
+
named `regions` with `box` and authored `max_pixels` limits. The SKIP changes
|
|
6239
|
+
no exit code and invents no metric, region or limit. This applies both without
|
|
6240
|
+
a requirements file and with one that omits the key. Without `--source` and
|
|
6241
|
+
without the declaration, the line stays absent. Declared observations retain
|
|
6242
|
+
their output bytes and renderer calls.
|
|
6243
|
+
|
|
6244
|
+
`check --json` prints only the completed `check.json` object to stdout, with
|
|
6245
|
+
the same bytes as the file and the same exit code as ordinary `check` (0 or 1).
|
|
6246
|
+
Early input refusals and usage errors retain their named text and exits (1 or 2);
|
|
6247
|
+
they have no completed check object. `build --json` is refused by name: run
|
|
6248
|
+
`check --rig <out>/rig --parts <out> --out <dir> --json` after the build to read
|
|
6249
|
+
the completed check object.
|
|
6233
6250
|
|
|
6234
6251
|
The observation is the actual renderer's setup pose, without animation or
|
|
6235
6252
|
physics advancement, from the already gated setup candidate. Its viewport is
|
|
@@ -6566,6 +6583,47 @@ art. An authored `parts.json` depth reference remains an active standalone
|
|
|
6566
6583
|
guards still apply. With binding inactive there is no added reference, file or
|
|
6567
6584
|
legacy-byte change. #773 adds no image generation, geometry or motion model.
|
|
6568
6585
|
|
|
6586
|
+
### Head roll before a declared turn
|
|
6587
|
+
|
|
6588
|
+
`rig` and `build` report `WARN RIG_TURN_HEAD_ROLL` when a declared head
|
|
6589
|
+
turn (`turn.depths` or `turn.roles`, including the depth-sampled producer)
|
|
6590
|
+
has an absolute setup eye-line roll above 18.485385 degrees (six-place display).
|
|
6591
|
+
The line names the face part (or the eye parts without a face), the signed
|
|
6592
|
+
roll, its absolute value, the limit, and both eye bones and parts. It reads
|
|
6593
|
+
the existing `eyeLineDegrees` on the authored `eye_r` and `eye_l` origins,
|
|
6594
|
+
image-left to image-right in Spine degrees, counter-clockwise; it does not
|
|
6595
|
+
detect the painting's tilt independently of those authored origins, estimate
|
|
6596
|
+
tilt from a bounding box, or invent a reading without both eye parts
|
|
6597
|
+
and bones or when their origins share a column.
|
|
6598
|
+
|
|
6599
|
+
The limit is the midpoint between the maximum absolute roll of the measured
|
|
6600
|
+
public controls, 4.864514 degrees, and the tilted `three-quarter`
|
|
6601
|
+
input from issue #900, 32.106256 degrees. The comparison uses the unrounded
|
|
6602
|
+
midpoint. The controls are the five
|
|
6603
|
+
parts examples plus the published dancer config and head-turn demo's compiled
|
|
6604
|
+
setup eye origins. The named quiet controls read 3.239700 degrees
|
|
6605
|
+
(`reference-demo`), -1.941486 degrees (`dancer`), and
|
|
6606
|
+
0.520856 degrees (head-turn demo). This is an empirical separation
|
|
6607
|
+
of these inputs, not an anatomical limit or a visual-quality verdict.
|
|
6608
|
+
|
|
6609
|
+
The parts configs were read at
|
|
6610
|
+
[`38e5f574`](https://github.com/rig-c/parts/tree/38e5f574a88b2e6753a982b0ee0952dbf273a12e/examples),
|
|
6611
|
+
the [dancer config](https://github.com/rig-c/examples/blob/564285414fccf7b47df32501c0b3c2968db77691/dancer/config.json)
|
|
6612
|
+
at `56428541`, and the
|
|
6613
|
+
[head-turn model](https://github.com/rig-c/rig-c.github.io/blob/989cebbd6733a58142923cec96fe2333da08194a/demos/head-turn/bundle/skeleton.model.json)
|
|
6614
|
+
at `989cebbd`. The [issue #900](https://github.com/rig-c/parts/issues/900)
|
|
6615
|
+
bootstrap used public `three-quarter` inputs at examples commit
|
|
6616
|
+
`ba99e403d4058fc1cfe40699bdcde8aaf00a90c0`; its authored crop-pixel eye origins
|
|
6617
|
+
are `[236, 136]` and `[287, 104]`. The compiled demo is a setup metric control,
|
|
6618
|
+
not a rebuild of its unavailable parts config.
|
|
6619
|
+
|
|
6620
|
+
An already rolled head is turned about upright yaw/pitch axes; inspect its
|
|
6621
|
+
neck at both extremes before accepting that motion. This warning does not
|
|
6622
|
+
refuse the build, correct the tilt, add a roll axis, or change any pose or
|
|
6623
|
+
emitted file. With no head turn, including a body-only turn, it adds no warning.
|
|
6624
|
+
With an unreadable eye line the existing face-axis report retains its reason;
|
|
6625
|
+
silence is not a measured zero. The warning lives only in the stage report.
|
|
6626
|
+
|
|
6569
6627
|
### Missing body-turn coverage
|
|
6570
6628
|
|
|
6571
6629
|
`RIG_TURN_BODY_UNCOVERED` warns when a shown part without a
|
|
@@ -6682,6 +6740,26 @@ The trial's role relief/width ratios (face 0.1264803, front hair 0.1018772,
|
|
|
6682
6740
|
back hair 0.0857722, ornament 0.0375868, garment 0.0990473) came from one
|
|
6683
6741
|
head-turn demo's p5..p95 depth and part widths. They are measured starting
|
|
6684
6742
|
points for declared proportions, not anatomical laws or default calibration.
|
|
6743
|
+
For a head-referenced calibration, declare
|
|
6744
|
+
`relief = referenceRoleRelief * targetFaceWidth / referenceFaceWidth`, using
|
|
6745
|
+
the assembled target face width and the same declared reference head measure
|
|
6746
|
+
for every role. This keeps head relief on one scale when a hair silhouette
|
|
6747
|
+
is much wider than the face. In contrast, `roleRatio * targetPartWidth`
|
|
6748
|
+
increases relief with that silhouette while the group's `zScale` stays fixed.
|
|
6749
|
+
An ornament narrower than its reference can gain relief under the head rule;
|
|
6750
|
+
inspect it as well as the widest part. The command derives neither rule:
|
|
6751
|
+
write the resulting rig-pixel `relief` explicitly in each recipe entry.
|
|
6752
|
+
|
|
6753
|
+
Compare calibrations on identical prepared inputs and numeric maps, with the
|
|
6754
|
+
same medians, group pivot and `zScale`; only the declared relief changes.
|
|
6755
|
+
Read each named report row's `relief`, `zScale` and `clipFraction` before
|
|
6756
|
+
judging its render. The clipping denominator is every original part pixel
|
|
6757
|
+
with alpha >=128, including boundary support, never the padded input area.
|
|
6758
|
+
A low clipped fraction does not establish shape quality. Inspect setup,
|
|
6759
|
+
both yaw endpoints and their difference at native scale, then enlarge the
|
|
6760
|
+
same pixels with nearest-neighbour sampling. Neither clipping nor agreement
|
|
6761
|
+
with a reference map substitutes for that inspection.
|
|
6762
|
+
|
|
6685
6763
|
The owner's preference for per-part volume is subjective provenance, not an
|
|
6686
6764
|
automated quality conclusion. Model licence posture remains the owner's choice.
|
|
6687
6765
|
|
package/docs/STABILITY.md
CHANGED
|
@@ -62,7 +62,7 @@ defaults are the help's too, and none is guessed from the art.
|
|
|
62
62
|
| `propose` | `--parts`, `--source`, `--out`, `--full`, `--head`, `--write-config` together: the [neck draft](AUTHORING.md#a-neck-that-moves-on-its-own) for an existing config with `turn.body` and one neck plan row; reassembles under `<out>/rig`, preserves the sampled turn and drafts a rigid neck unit (issue #826) |
|
|
63
63
|
| `compare` | `--left`, `--right`; optional `--map` |
|
|
64
64
|
| `rig` | `--config`, `--parts`, `--out`; optional `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
|
|
65
|
-
| `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills`, `--no-extremes` (issue #829), `--set` or `--all-sets` (issue #454), `--environment` (issue #538, additive), `--wind-band` (issue #590, additive) |
|
|
65
|
+
| `check` | `--rig`, `--out`; optional `--parts`, `--source`, `--page-edges`, `--pack-shape`, `--requirements`, `--seam-pairs`, `--keep-stills`, `--no-extremes` (issue #829), `--set` or `--all-sets` (issue #454), `--environment` (issue #538, additive), `--wind-band` (issue #590, additive), `--json` (issue #904) |
|
|
66
66
|
| `loop` | `--frames`, `--out`; optional `--palette` |
|
|
67
67
|
| `build` | `--config`, `--source`, `--full`, `--out`; optional `--head` (as for `assemble`), `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--lead-in`, `--requirements`, `--idle-keys`, `--seam-pairs`, `--keep-stills`, `--no-extremes` (issue #829), `--alt` (as for `assemble`, issue #454), `--set` or `--all-sets` (as for `check`, issue #454), `--environment` (as for `check`, issue #538, additive), `--wind-band` (as for `check`, issue #590, additive) |
|
|
68
68
|
| `compose` | `--scene`, `--out`; optional `--requirements`, `--accept` |
|
|
@@ -116,6 +116,18 @@ rules that make the contract:
|
|
|
116
116
|
- **`turn`** (issue #251) adds a control bone `turn` under `root` that nothing
|
|
117
117
|
keys, and carries each part in `depths` by `(pivot − depth) / (pivot − nearest
|
|
118
118
|
depth)` of its x. Without the field no byte of any output moves.
|
|
119
|
+
A declared head turn (`depths` or `roles`) reports `RIG_TURN_HEAD_ROLL`
|
|
120
|
+
when the absolute setup eye-line roll exceeds the limit displayed as
|
|
121
|
+
18.485385 degrees
|
|
122
|
+
(issue #903). This empirical limit is the midpoint of the measured public
|
|
123
|
+
control maximum, 4.864514 degrees, and `three-quarter`,
|
|
124
|
+
32.106256 degrees (the comparison uses the unrounded midpoint). The warning
|
|
125
|
+
names the face/eye parts, the eye
|
|
126
|
+
bones, signed roll and limit. It is report-only: no refusal, field, pose or
|
|
127
|
+
emitted-byte change. No head turn, a body-only turn, or an unreadable eye
|
|
128
|
+
line adds no warning; unreadable retains the existing face-axis reason.
|
|
129
|
+
See [Head roll before a declared turn](AUTHORING.md#head-roll-before-a-declared-turn)
|
|
130
|
+
for the measurement scope and its limits.
|
|
119
131
|
- **`scene`** (issue #242) declares the painting a scene — the figure and what
|
|
120
132
|
is round it — and takes no field: `{}`. With it `assemble` reads the
|
|
121
133
|
recomposite inside the figure (the union of the full run's layers at alpha
|
|
@@ -135,7 +147,7 @@ part name, `[i]` an entry of a list):
|
|
|
135
147
|
- **generation.control.skeleton**, the pose file it names when it is no built-in — required: `width`, `height`, `points`
|
|
136
148
|
- **seethrough** — required: `resolution`, `steps`, `seed`, `offload`; optional: `head_box`, `arm_split`
|
|
137
149
|
- **seethrough.arm_split** — required: `order`, and one of `x` or `line` (issue #439)
|
|
138
|
-
- **assemble** — required: `rig_scale`, `plan` (from plain `assemble` on); optional: `extend_below_crop`, `patches`, `cuts`, `alternates`, `head_face_underfill`, `yield_refused`, `keep_under_occluders`, `extend_painting`, `take`
|
|
150
|
+
- **assemble** — required: `rig_scale`, `plan` (from plain `assemble` on); optional: `seam`, `extend_below_crop`, `patches`, `cuts`, `alternates`, `head_face_underfill`, `yield_refused`, `keep_under_occluders`, `extend_painting`, `take`
|
|
139
151
|
- **assemble.alternates[i]** — required: `name`; optional: `source`, `full`, `head`, `parts`, `hides`, `head_box`, `cuts`, `skeleton`, `anchor`, `base_anchor`, `drawn`, `tips`, `front`, `layers`, `focus` (issues #454, #465, #543, #652, #664, #666, #719, #780). `focus` is an authored finite `[x, y]` in painting pixels, within its canvas (edges included), refused as CONFIG_SET_FOCUS before assemble output when invalid; only when present, `parts.json` records it with focus_source_size and `sets.json` emits it in setup-world coordinates through the actual rig resize and `src/coords.ts`. Absent focus emits no field or inferred value; changing/removing it requires reassembly
|
|
140
152
|
- **assemble.extend_below_crop[i]** — required: `part`, `run`, `tag`
|
|
141
153
|
- **assemble.extend_painting[i]** — required: `part`, `band`, `max_distance`; optional: `min_held_alpha`, `order` (issues #848, #854, #855; explicit final layer-derived part, half-open rig band and positive four-neighbour path bound; base painting only). The optional integer floor 1–255 admits exact original alpha-over coverage strictly below it; absent or 1 blocks every nonzero holder. Only selected target samples below the floor may take painting RGBA; target samples at/above the floor and every non-target holder remain exact. By default overlapping reachable claims refuse. With `order` on every entry (unique nonnegative safe integers), lower values claim first and their gains block later candidates and paths; array order never breaks ties or supplies missing precedence
|
|
@@ -206,6 +218,11 @@ part name, `[i]` an entry of a list):
|
|
|
206
218
|
- **waist** — required: `top`, `bottom`, `upper`, `lower`, `bone`, `constraint` (#650; absent keeps the ordinary bindings and graph)
|
|
207
219
|
<!-- /stable:config -->
|
|
208
220
|
|
|
221
|
+
`assemble.seam` accepts `near-white` or `silhouette` (issue #905). CLI
|
|
222
|
+
`--seam` overrides config, then the existing `near-white` default applies.
|
|
223
|
+
Invalid values refuse as `CONFIG_FIELD_TYPE` at `config.assemble.seam`;
|
|
224
|
+
an absent field preserves existing output bytes.
|
|
225
|
+
|
|
209
226
|
`TY14` holds the set of field names in backticks above to the set of names the
|
|
210
227
|
loader's object checks spell (every `c.object(…)` in `src/config.ts`, with the lists
|
|
211
228
|
they name), in both directions, and refuses an object check whose key list it cannot
|
|
@@ -252,7 +269,7 @@ keeps complete canonical raw pair data (boxes/cut metadata included), omitting
|
|
|
252
269
|
`picture` unless its image exists. Semantic signatures preserve original source
|
|
253
270
|
attachment UVs/topology/weights, own image content and world vertices/colour,
|
|
254
271
|
not atlas pages/UVs or global piece ordinals. Unknown/no-art support stays conservative.
|
|
255
|
-
Renderer metadata and exact raster reads use the promised `@rig-c/core/render-shared` entry (rig-c
|
|
272
|
+
Renderer metadata and exact raster reads use the promised `@rig-c/core/render-shared` entry (from rig-c 2.69.0). It registers no Spine runtime; where that runtime resolves from rig-c's own package root, the existing `@rig-c/core/render` entry registers the official Spine side explicitly. An install without Spine keeps rig-c's own candidate chooser and gate; candidate or loader failures never select a guessed fallback.
|
|
256
273
|
|
|
257
274
|
An unavailable, nonfinite, unrepresentable or oversized union, or nonempty official pinned.outside, refuses `CHECK_SEAM_DOMAIN`. Geometry margins outside the authored canvas are included in U, not treated as opaque-clip evidence. State-by-state geometry reads retain bounds/identities rather than all decoded pages or poses. `--keep-stills` keeps
|
|
258
275
|
canonical frames in `setup_still/` and fitted diagnostics in `setup_still_auto/`.
|
|
@@ -311,20 +328,28 @@ in the package.
|
|
|
311
328
|
|
|
312
329
|
## rig-c
|
|
313
330
|
|
|
314
|
-
`dependencies` takes `@rig-c/core` `
|
|
331
|
+
`dependencies` takes `@rig-c/core` `3.0.0` exactly. Bun 1.4 or later
|
|
315
332
|
is the declared floor (`engines.bun` `>=1.4.0`; older 1.4 releases are not tested in
|
|
316
333
|
CI, which runs `latest`, and compatibility with an older 1.4 release is handled when
|
|
317
334
|
reported as an issue). What this package relies on in rig-c, every import
|
|
318
335
|
read off `src/` and `cli.ts`:
|
|
319
336
|
|
|
320
|
-
- the named entries `@rig-c/core
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
`@rig-c/core/
|
|
326
|
-
`
|
|
327
|
-
`@rig-c/core/
|
|
337
|
+
- the named entries its `exports` map carries (from `@rig-c/core` 3.0.0 `./*.ts` deep
|
|
338
|
+
file paths are gone, and `TY39` refuses any in the tree):
|
|
339
|
+
`@rig-c/core/mesh` (the outline functions, `measureAuthoredMeshFit`, `reduceMesh`,
|
|
340
|
+
`skinningEnvelopeBone`, `writeMeshQualityReport` and their types),
|
|
341
|
+
`@rig-c/core/meshcompare` (`compareMeshesInMotion`, `comparePreparedMotion`,
|
|
342
|
+
`prepareMotionReference`), `@rig-c/core/compile` (`f32`), `@rig-c/core/core`
|
|
343
|
+
(`RUNTIME_PI`), `@rig-c/core/deformgen` (`evaluateDeformTransform`),
|
|
344
|
+
`@rig-c/core/environment` (`ENVIRONMENT_SPEC`, `EnvironmentError`,
|
|
345
|
+
`environmentResponse`, `readEnvironmentSchedule`), `@rig-c/core/errors`
|
|
346
|
+
(`CompileError`), `@rig-c/core/font5x7` (`GLYPH_H`, `drawText`),
|
|
347
|
+
`@rig-c/core/passthrough` (`DRAWN_ALPHA`), `@rig-c/core/plate` (the PNG codec),
|
|
348
|
+
`@rig-c/core/png` (`assertPng`), `@rig-c/core/render` (`GeometryFile`,
|
|
349
|
+
`GeometryFrame`), `@rig-c/core/render-shared` (`Viewport`), `@rig-c/core/rig`
|
|
350
|
+
(`parseRigSpec`, `RIG_SPEC_VERSION`, the constraint keys and types),
|
|
351
|
+
`@rig-c/core/stop` (`expandStops`) and `@rig-c/core/transform` (the y flip and
|
|
352
|
+
frame transforms, through `src/coords.ts` only);
|
|
328
353
|
- the `rigc` command: `build` and `render`, and `--version`, whose `entry:` line
|
|
329
354
|
says which validator gated a build (`check.json`'s `rigc_entry`).
|
|
330
355
|
|
|
@@ -507,10 +532,17 @@ The separate ordering scalar is unchanged. No-image outputs retain legacy bytes.
|
|
|
507
532
|
### Declared setup-painting regions
|
|
508
533
|
|
|
509
534
|
The optional `setup_painting` key in `spine-parts-requirements/1` adds a
|
|
510
|
-
`SETUP_MATCHES_PAINTING`
|
|
535
|
+
`SETUP_MATCHES_PAINTING` measurement when declared. It requires authored
|
|
511
536
|
`rgb_tolerance` and named native-stage boxes. Each optional `max_pixels` is
|
|
512
|
-
that whole region's limit; omission is SKIP, never PASS.
|
|
513
|
-
|
|
537
|
+
that whole region's limit; omission is SKIP, never PASS. With `--source` but
|
|
538
|
+
no declaration, the console, `check.json` and the report's skipped-bar list now
|
|
539
|
+
say SKIP with the reason and the `--requirements` declaration remedy; exit
|
|
540
|
+
codes stay unchanged. No metric, region or limit is invented. Without source
|
|
541
|
+
and without the key, the line stays absent. Declared output bytes and renderer
|
|
542
|
+
calls remain unchanged. `check --json` prints the completed `check.json` bytes
|
|
543
|
+
to stdout and keeps the ordinary check's exit code; early input refusals and
|
|
544
|
+
usage errors keep their existing named text and exits. `build --json` is refused
|
|
545
|
+
with a `check --json` remedy; build keeps its multi-stage text report. Other requirement fields
|
|
514
546
|
remain independent. The [authoring contract](AUTHORING.md#setup-against-the-painting)
|
|
515
547
|
defines white compositing, the figure domain, strict RGB comparison, top
|
|
516
548
|
contributor attribution and named measurement refusals. The check observes the
|
|
@@ -540,3 +572,9 @@ encoding, convexity sign and refusal remedies are in
|
|
|
540
572
|
calls these stages; no-config builds retain their existing behavior and bytes.
|
|
541
573
|
Group numbers and unit depths are explicit; no provider or absolute scale is
|
|
542
574
|
inferred. A new depth stage never replaces Core's rig gate.
|
|
575
|
+
`relief` is an explicit rig-pixel value, not an implicit width multiplier.
|
|
576
|
+
Part-width and head-referenced calibrations are authored recipe choices;
|
|
577
|
+
changing a calibration requires preparing its recipe again. Compare the same
|
|
578
|
+
provider maps and preserve their provenance. Each report row names the part,
|
|
579
|
+
declared relief, group `zScale` and clipping over original alpha>=128 support;
|
|
580
|
+
it remains a measurement rather than a shape-quality gate.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rig-parts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "AI-authored 2D character parts from one anime painting and its See-through layer decomposition: measured parts, weighted-mesh rig specs, verified through rig-c before anything is written. A CLI for agents that cannot see the image.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"ag-psd": "^31.0.2",
|
|
70
|
-
"@rig-c/core": "
|
|
70
|
+
"@rig-c/core": "3.0.0"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@esotericsoftware/spine-core": "4.3.13",
|
package/src/apng.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Pure: bytes in, bytes out, no clock, no file system. The only thing it leans
|
|
6
6
|
* on is `node:zlib` for DEFLATE, which is also all rig-c's own PNG codec
|
|
7
|
-
* (
|
|
7
|
+
* (`@rig-c/core/plate`) leans on; the chunk framing and CRC are that
|
|
8
8
|
* codec's `pngChunk`, so there is one PNG chunk writer in the dependency tree,
|
|
9
9
|
* not two.
|
|
10
10
|
*
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* bitstream encoder, and none ships here.
|
|
35
35
|
*/
|
|
36
36
|
import { deflateSync } from 'node:zlib';
|
|
37
|
-
import { PNG_SIGNATURE, pngChunk } from '@rig-c/core/
|
|
37
|
+
import { PNG_SIGNATURE, pngChunk } from '@rig-c/core/plate';
|
|
38
38
|
import { histogram, mapToPalette, medianCut, type PaletteError, paletteError, type Rgba } from './palette.ts';
|
|
39
39
|
import type { Raster } from './raster/types.ts';
|
|
40
40
|
|
package/src/assemble.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SeamRule } from './seamrule.ts';
|
|
1
2
|
import { edgeLength } from './length.ts';
|
|
2
3
|
import { materialSource, type MaterialSource, materialRows, polygonMaterialEdges, type MaterialRow, type MaterialEdge, type PlacedArt } from './cutmaterial.ts';
|
|
3
4
|
import { unionTakenSources } from './takesource.ts';
|
|
@@ -188,16 +189,7 @@ export const SILHOUETTE_BORDER = 8;
|
|
|
188
189
|
/** `figureSilhouette`: a pixel is figure where it differs from that median by more than this, max channel. */
|
|
189
190
|
export const SILHOUETTE_LIMIT = 40;
|
|
190
191
|
|
|
191
|
-
export type SeamRule
|
|
192
|
-
export const SEAM_RULES: readonly SeamRule[] = ['near-white', 'silhouette'];
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* The seam rule a run uses when none is named. Set by measurement, not taste:
|
|
196
|
-
* the silhouette rule ships as the default only if it lowers the error pixel
|
|
197
|
-
* count on every oracle character without raising mean |d| on any
|
|
198
|
-
* (ORACLE_assemble.md, *faithful vs silhouette*).
|
|
199
|
-
*/
|
|
200
|
-
export const DEFAULT_SEAM_RULE: SeamRule = 'near-white';
|
|
192
|
+
export { DEFAULT_SEAM_RULE, SEAM_RULES, type SeamRule } from './seamrule.ts';
|
|
201
193
|
|
|
202
194
|
/**
|
|
203
195
|
* Where a layer may take the painting's pixel (`projectSource`). `core` is the
|
package/src/build.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_SEAM_RULE } from './seamrule.ts';
|
|
1
2
|
import { SETUP_PAINTING_LINE, setupPaintingLines } from './setuppainting.ts';
|
|
2
3
|
import { writeMaterialSources } from './cutmaterialio.ts';
|
|
3
4
|
import { CUT_MATERIAL_LINE, CUT_MATERIAL_SOURCES, materialLines } from './cutmaterial.ts';
|
|
@@ -164,7 +165,7 @@ export interface AssembleStageInput {
|
|
|
164
165
|
/** The head run, or null for one run that holds the face (issue #359). */
|
|
165
166
|
head: string | null;
|
|
166
167
|
config: string;
|
|
167
|
-
seam
|
|
168
|
+
seam?: SeamRule;
|
|
168
169
|
project: ProjectRule;
|
|
169
170
|
/** `--alt` entries, merged with `config.assemble.alternates` by set name (issue #454). */
|
|
170
171
|
alts?: readonly AlternateCliInput[];
|
|
@@ -327,13 +328,14 @@ export function assembleStage(input: AssembleStageInput, outs: AssembleOutputs,
|
|
|
327
328
|
// The early door: assemble runs before propose has drafted bones, meshes,
|
|
328
329
|
// regions and motion, so it requires only what it reads (issue #20).
|
|
329
330
|
const cfg = loadEarlyConfig(input.config, 'assemble');
|
|
331
|
+
const seam = input.seam ?? cfg.assemble.seam ?? DEFAULT_SEAM_RULE;
|
|
330
332
|
const src = readSource(input.source);
|
|
331
333
|
const runs = applyTakenLayers(readRuns(input.full, input.head), src, cfg, input.config);
|
|
332
334
|
for (const note of runs.notes) log(`note: ${note}`);
|
|
333
335
|
const fields = stageFields(cfg, runs.single ? { w: src.width, h: src.height } : null);
|
|
334
336
|
const under = readUnders(input.config, fields.cuts);
|
|
335
337
|
const caps = fields.limbs === undefined ? undefined : readCaps(input.config, fields.limbs);
|
|
336
|
-
const result = assemble({ source: src, full: runs.full, head: runs.head, depth: cfg.depth, depthBase: dirname(resolve(input.config)), ...fields, under, ...(caps === undefined ? {} : { caps }), seamRule:
|
|
338
|
+
const result = assemble({ source: src, full: runs.full, head: runs.head, depth: cfg.depth, depthBase: dirname(resolve(input.config)), ...fields, under, ...(caps === undefined ? {} : { caps }), seamRule: seam, projectRule: input.project });
|
|
337
339
|
|
|
338
340
|
// Issue #454: alternate painting sets, assembled before any file is written.
|
|
339
341
|
const configDir = dirname(resolve(input.config));
|
|
@@ -673,7 +675,7 @@ export function assembleStage(input: AssembleStageInput, outs: AssembleOutputs,
|
|
|
673
675
|
...(fields.yieldRefused === undefined ? {} : { yieldRefused: fields.yieldRefused }),
|
|
674
676
|
...(fields.turnMovingPair === undefined ? {} : { turnMovingPair: fields.turnMovingPair }),
|
|
675
677
|
...(fields.turn === undefined ? {} : { turn: fields.turn, regions: fields.regions, meshes: fields.meshes, motion: fields.motion }),
|
|
676
|
-
seamRule:
|
|
678
|
+
seamRule: seam,
|
|
677
679
|
projectRule: input.project,
|
|
678
680
|
...(altExclude.length === 0 ? {} : { exclude: altExclude }),
|
|
679
681
|
...(altIslands.length === 0 ? {} : { limbIslands: altIslands }),
|
|
@@ -2218,7 +2220,7 @@ export interface BuildInput {
|
|
|
2218
2220
|
/** The head run, or null for one run that holds the face (issue #359). */
|
|
2219
2221
|
head: string | null;
|
|
2220
2222
|
out: string;
|
|
2221
|
-
seam
|
|
2223
|
+
seam?: SeamRule;
|
|
2222
2224
|
project: ProjectRule;
|
|
2223
2225
|
loop: boolean;
|
|
2224
2226
|
/** `--page-edges` for both packed builds, the rig stage's gate and the check's artifact. */
|
|
@@ -2253,7 +2255,7 @@ export interface BuildInput {
|
|
|
2253
2255
|
windBand?: string;
|
|
2254
2256
|
}
|
|
2255
2257
|
|
|
2256
|
-
/** What `build` does with one flag `check` takes: hands it to its check stage, takes it as its own, or refuses it because build supplies the value itself. */
|
|
2258
|
+
/** What `build` does with one flag `check` takes: hands it to its check stage, takes it as its own, or refuses it because build supplies the value or report itself. */
|
|
2257
2259
|
export type CheckFlagInBuild =
|
|
2258
2260
|
| { as: 'forwarded' }
|
|
2259
2261
|
| { as: 'own'; why: string }
|
|
@@ -2280,6 +2282,7 @@ export const CHECK_FLAGS_IN_BUILD: Readonly<Record<string, CheckFlagInBuild>> =
|
|
|
2280
2282
|
'--no-extremes': { as: 'forwarded' },
|
|
2281
2283
|
'--environment': { as: 'forwarded' },
|
|
2282
2284
|
'--wind-band': { as: 'forwarded' },
|
|
2285
|
+
'--json': { as: 'supplied', why: 'build supplies its multi-stage text report; run check --rig <out>/rig --parts <out> --out <dir> --json for the completed check object' },
|
|
2283
2286
|
};
|
|
2284
2287
|
|
|
2285
2288
|
/** The requirements file build's check reads (issue #556): `read` is where it is opened, `recorded` what `check.json` names it by. */
|
|
@@ -2315,7 +2318,7 @@ export function buildRequirements(flag: string | undefined, declared: string | u
|
|
|
2315
2318
|
]);
|
|
2316
2319
|
}
|
|
2317
2320
|
|
|
2318
|
-
/** The `build` refusal of a `check` flag build supplies itself ({@link CHECK_FLAGS_IN_BUILD}), or null for any other flag. */
|
|
2321
|
+
/** The `build` refusal of a `check` flag whose value or report build supplies itself ({@link CHECK_FLAGS_IN_BUILD}), or null for any other flag. */
|
|
2319
2322
|
export function suppliedCheckFlag(flag: string): string | null {
|
|
2320
2323
|
const row = Object.hasOwn(CHECK_FLAGS_IN_BUILD, flag) ? CHECK_FLAGS_IN_BUILD[flag] : undefined;
|
|
2321
2324
|
return row?.as === 'supplied' ? `build does not take "${flag}"; ${row.why}` : null;
|
|
@@ -2408,7 +2411,6 @@ export function build(input: BuildInput, run: BuildRunners, log: Log): BuildResu
|
|
|
2408
2411
|
rmSync(join(out, FIGURE_MASK_FILE), { force: true });
|
|
2409
2412
|
// The idle-keys value is named only when it is not the default, so a build without the flag, or with the default, prints the line it printed before issue #95.
|
|
2410
2413
|
const idleKeys = input.idleKeys ?? DEFAULT_IDLE_KEYS;
|
|
2411
|
-
log(`rig-parts build: ${input.config} -> ${out}, seam rule ${input.seam}, projection rule ${input.project}, page edges ${input.pageEdges}, pack shape ${input.packShape ?? DEFAULT_PACK_SHAPE}${idleKeys === DEFAULT_IDLE_KEYS ? '' : `, idle keys ${idleKeys}`}${input.loop ? `, with the idle loop${input.leadIn === undefined ? '' : ` after a lead-in of ${input.leadIn} period(s)`}` : ''}`);
|
|
2412
2414
|
|
|
2413
2415
|
let req: BuildRequirements | null = null;
|
|
2414
2416
|
let configRecord: InputFileRecord | null = null;
|
|
@@ -2420,6 +2422,8 @@ export function build(input: BuildInput, run: BuildRunners, log: Log): BuildResu
|
|
|
2420
2422
|
// Issue #556: the flag, or the config's declaration when there is none; both naming other bytes is refused here.
|
|
2421
2423
|
// Issue #607: the bytes this read parsed are the ones check.json's config record hashes, under the path as typed.
|
|
2422
2424
|
const loaded = loadConfigWithBytes(input.config);
|
|
2425
|
+
const seam = input.seam ?? loaded.config.assemble.seam ?? DEFAULT_SEAM_RULE;
|
|
2426
|
+
log(`rig-parts build: ${input.config} -> ${out}, seam rule ${seam}, projection rule ${input.project}, page edges ${input.pageEdges}, pack shape ${input.packShape ?? DEFAULT_PACK_SHAPE}${idleKeys === DEFAULT_IDLE_KEYS ? '' : `, idle keys ${idleKeys}`}${input.loop ? `, with the idle loop${input.leadIn === undefined ? '' : ` after a lead-in of ${input.leadIn} period(s)`}` : ''}`);
|
|
2423
2427
|
configRecord = inputFileRecord(loaded.bytes, input.config);
|
|
2424
2428
|
req = buildRequirements(input.requirements, loaded.config.requirements, input.config);
|
|
2425
2429
|
// The same for the requirements file's own shape; its names resolve against the rig, in the check, before it builds.
|
|
@@ -2429,7 +2433,7 @@ export function build(input: BuildInput, run: BuildRunners, log: Log): BuildResu
|
|
|
2429
2433
|
// And the steady-wind band spec (issue #590), as check reads it.
|
|
2430
2434
|
if (input.windBand !== undefined) readWindBand(input.windBand);
|
|
2431
2435
|
stages.assemble(
|
|
2432
|
-
{ source: input.source, full: input.full, head: input.head, config: input.config, seam
|
|
2436
|
+
{ source: input.source, full: input.full, head: input.head, config: input.config, seam, project: input.project, ...(req === null ? {} : { requirements: req.read }), ...(input.alts === undefined ? {} : { alts: input.alts }) },
|
|
2433
2437
|
{ partsJson: join(out, 'parts.json'), partsDir: join(out, 'parts'), recomposite: join(out, 'recomposite_rig.png'), errorMap: join(out, ERROR_MAP_FILE) },
|
|
2434
2438
|
prefixed('assemble'),
|
|
2435
2439
|
);
|
package/src/check.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SETUP_PAINTING_LINE, setupPaintingBounds, setupPaintingLine, type SetupPainting, type SetupPaintingLine } from './setuppainting.ts';
|
|
1
|
+
import { SETUP_PAINTING_LINE, UNDECLARED_SETUP_PAINTING_REASON, setupPaintingBounds, setupPaintingLine, type SetupPainting, type SetupPaintingLine, type SetupPaintingObservation } from './setuppainting.ts';
|
|
2
2
|
import { readMaterialSources } from './cutmaterialio.ts';
|
|
3
3
|
import { CUT_MATERIAL_LINE, checkJointMaterial, type MaterialLine } from './cutmaterial.ts';
|
|
4
4
|
import { ART_JOINT_LINE, artJointLine, type ArtJointLine } from './artjoints.ts';
|
|
@@ -170,9 +170,9 @@ import {
|
|
|
170
170
|
type SeamPair,
|
|
171
171
|
stretchRequirementLine,
|
|
172
172
|
} from './requirements.ts';
|
|
173
|
-
import { RIG_BONE_INHERIT, type RigSpec as RigcRigSpec } from '@rig-c/core/
|
|
174
|
-
import { expandStops } from '@rig-c/core/
|
|
175
|
-
import { ENVIRONMENT_SPEC, EnvironmentError, environmentResponse, readEnvironmentSchedule } from '@rig-c/core/
|
|
173
|
+
import { RIG_BONE_INHERIT, type RigSpec as RigcRigSpec } from '@rig-c/core/rig';
|
|
174
|
+
import { expandStops } from '@rig-c/core/stop';
|
|
175
|
+
import { ENVIRONMENT_SPEC, EnvironmentError, environmentResponse, readEnvironmentSchedule } from '@rig-c/core/environment';
|
|
176
176
|
import { ART_ALPHA } from './mesh.ts';
|
|
177
177
|
import { connectedComponents } from './raster/components.ts';
|
|
178
178
|
import { alphaComposite } from './raster/composite.ts';
|
|
@@ -329,8 +329,8 @@ export const DEFAULT_PACK_MODE: PackMode = { pageEdges: DEFAULT_PAGE_EDGES, pack
|
|
|
329
329
|
/**
|
|
330
330
|
* The profile every rigc build this package runs is gated under. rig-c 2.50.0
|
|
331
331
|
* renamed `spine-html` to `rig-play` and runs the same rules under it; the old
|
|
332
|
-
* name
|
|
333
|
-
*
|
|
332
|
+
* name was removed in rig-c 3.0.0 (selftest `CK20` holds every stage's build to
|
|
333
|
+
* the new name and verifies the old one is refused).
|
|
334
334
|
*/
|
|
335
335
|
export const GATE_PROFILE = 'rig-play';
|
|
336
336
|
|
|
@@ -2730,8 +2730,8 @@ export interface CheckFigures {
|
|
|
2730
2730
|
requirements?: RequirementsBlock;
|
|
2731
2731
|
/** Issue #880: only when requirements declares fixed_skeleton. */
|
|
2732
2732
|
[ART_JOINT_LINE]?: ArtJointLine;
|
|
2733
|
-
/**
|
|
2734
|
-
[SETUP_PAINTING_LINE]?:
|
|
2733
|
+
/** Under --source: the declared observation, or an explicit undeclared SKIP. */
|
|
2734
|
+
[SETUP_PAINTING_LINE]?: SetupPaintingObservation;
|
|
2735
2735
|
[CUT_MATERIAL_LINE]?: MaterialLine;
|
|
2736
2736
|
PASS: boolean;
|
|
2737
2737
|
}
|
|
@@ -5309,7 +5309,7 @@ function environmentRefused(given: string, sentence: string): PartsError {
|
|
|
5309
5309
|
|
|
5310
5310
|
/**
|
|
5311
5311
|
* `--environment <file>` read once, before anything is built (issue #538): the file's bytes hashed and handed to
|
|
5312
|
-
* rig-c's own reader, `readEnvironmentSchedule` (
|
|
5312
|
+
* rig-c's own reader, `readEnvironmentSchedule` (`@rig-c/core/environment`), which refuses every malformed schedule
|
|
5313
5313
|
* — a `spec` other than {@link ENVIRONMENT_SPEC}, a key it does not read, no step, a `t` that is not finite, at or
|
|
5314
5314
|
* above 0 and after the step before, a `wind` or `gravity` that is not a pair of finite numbers, a step that changes
|
|
5315
5315
|
* nothing — by entry, field, the value found and the value required. Nothing here reads the schedule's meaning: its
|
|
@@ -6476,7 +6476,8 @@ export function runCheck(rigDir: string, outDir: string, rigc: RigcRunner, parts
|
|
|
6476
6476
|
const setHints = new Map<string, string>();
|
|
6477
6477
|
const fixedSkeleton = reqFile?.fixed_skeleton;
|
|
6478
6478
|
let artJoints: ArtJointLine | null = null;
|
|
6479
|
-
let setupPainting:
|
|
6479
|
+
let setupPainting: SetupPaintingObservation | null = inp.source !== null && reqFile?.setup_painting === undefined
|
|
6480
|
+
? { status: 'SKIP', reason: UNDECLARED_SETUP_PAINTING_REASON } : null;
|
|
6480
6481
|
if (inp.parts !== null || inp.source !== null || fixedSkeleton !== undefined) {
|
|
6481
6482
|
try {
|
|
6482
6483
|
mkdirSync(stillDir, { recursive: true });
|
package/src/config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SEAM_RULES, type SeamRule } from './seamrule.ts';
|
|
1
2
|
import type { TakeLayers } from './takelayers.ts';
|
|
2
3
|
import { paintingExtensionProblems, type PaintingExtension } from './paintingextension.ts';
|
|
3
4
|
import { baseAnchorProblems, type BaseAnchor } from './baseanchor.ts';
|
|
@@ -40,7 +41,7 @@ import type { DepthConfig } from './depthsheets.ts';
|
|
|
40
41
|
*
|
|
41
42
|
* Coordinates in `bones`, `meshes` and `motion` are RIG pixels, y down, origin
|
|
42
43
|
* top-left — the parts' own space. The y flip to Spine happens once, in
|
|
43
|
-
*
|
|
44
|
+
* `@rig-c/core/transform` (see `src/coords.ts`), when the rig is built.
|
|
44
45
|
*
|
|
45
46
|
* 🔗 **`constraints` is rig-c's, verbatim (issue #92).** An optional list
|
|
46
47
|
* of constraint objects in rig-c's own rig-spec shape (`RigConstraint`:
|
|
@@ -90,7 +91,7 @@ import type { DepthConfig } from './depthsheets.ts';
|
|
|
90
91
|
*/
|
|
91
92
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
92
93
|
import { dirname, resolve } from 'node:path';
|
|
93
|
-
import { RIG_BONE_INHERIT, RIG_SKIN_CONSTRAINT_KEYS, type RigBoneInherit, type RigConstraint, type RigSkinConstraintKey, type RigStop } from '@rig-c/core/
|
|
94
|
+
import { RIG_BONE_INHERIT, RIG_SKIN_CONSTRAINT_KEYS, type RigBoneInherit, type RigConstraint, type RigSkinConstraintKey, type RigStop } from '@rig-c/core/rig';
|
|
94
95
|
import { pyRound } from './round.ts';
|
|
95
96
|
import { motionSeamProblems, type MotionSeamDeclaration } from './motionseams.ts';
|
|
96
97
|
import { REQUIREMENTS_SPEC } from './requirements.ts';
|
|
@@ -300,6 +301,8 @@ export interface AlternateSetConfig {
|
|
|
300
301
|
}
|
|
301
302
|
|
|
302
303
|
export interface Assemble {
|
|
304
|
+
/** Optional per-character seam rule; an explicit CLI flag wins. */
|
|
305
|
+
seam?: SeamRule;
|
|
303
306
|
/** Verified named replacements from another See-through run (#866). */
|
|
304
307
|
take?: TakeLayers[];
|
|
305
308
|
/** Rig pixels per source pixel. */
|
|
@@ -1622,7 +1625,7 @@ export interface EarlyConfig {
|
|
|
1622
1625
|
depth?: DepthConfig;
|
|
1623
1626
|
key: string;
|
|
1624
1627
|
seethrough: SeeThrough;
|
|
1625
|
-
assemble: { rig_scale: number; take?: TakeLayers[]; head_face_underfill?: boolean; yield_refused?: boolean; keep_under_occluders?: string[]; extend_painting?: PaintingExtension[] };
|
|
1628
|
+
assemble: { rig_scale: number; seam?: SeamRule; take?: TakeLayers[]; head_face_underfill?: boolean; yield_refused?: boolean; keep_under_occluders?: string[]; extend_painting?: PaintingExtension[] };
|
|
1626
1629
|
}
|
|
1627
1630
|
|
|
1628
1631
|
/** What plain `assemble` reads: the early config plus the plan `--propose-plan` printed. */
|
|
@@ -1691,8 +1694,9 @@ function parseEarlyConfigFrom(raw: Json, door: EarlyDoor, base: string | null):
|
|
|
1691
1694
|
if (door === 'layers') {
|
|
1692
1695
|
if ('seethrough' in t) checkSeeThrough(c, t.seethrough);
|
|
1693
1696
|
if ('assemble' in t) {
|
|
1694
|
-
const a = c.object('config.assemble', t.assemble, sectionRequired(door, 'assemble'), ['plan', 'extend_below_crop', 'patches', 'cuts', 'alternates', 'head_face_underfill', 'yield_refused', 'keep_under_occluders', 'extend_painting', 'take']);
|
|
1697
|
+
const a = c.object('config.assemble', t.assemble, sectionRequired(door, 'assemble'), ['plan', 'extend_below_crop', 'patches', 'cuts', 'alternates', 'head_face_underfill', 'yield_refused', 'keep_under_occluders', 'extend_painting', 'take', 'seam']);
|
|
1695
1698
|
if (a !== null) {
|
|
1699
|
+
checkSeam(c, a);
|
|
1696
1700
|
if ('rig_scale' in a) c.number('config.assemble.rig_scale', a.rig_scale, 'positive');
|
|
1697
1701
|
if ('head_face_underfill' in a && typeof a.head_face_underfill !== 'boolean') {
|
|
1698
1702
|
c.fail('CONFIG_FIELD_TYPE', 'config.assemble.head_face_underfill', `is ${show(a.head_face_underfill)}; true or false is required`);
|
|
@@ -2457,10 +2461,17 @@ function checkTakeLayers(c: Check, value: Json): void {
|
|
|
2457
2461
|
});
|
|
2458
2462
|
}
|
|
2459
2463
|
|
|
2464
|
+
function checkSeam(c: Check, a: Record<string, Json>): void {
|
|
2465
|
+
if ('seam' in a && !(SEAM_RULES as readonly unknown[]).includes(a.seam)) {
|
|
2466
|
+
c.fail('CONFIG_FIELD_TYPE', 'config.assemble.seam', `is ${show(a.seam)}; one of ${SEAM_RULES.join(', ')} is required`);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2460
2470
|
function checkAssemble(c: Check, v: Json, door: 'assemble' | 'full'): { parts: string[]; patches: string[]; cuts: string[] } {
|
|
2461
2471
|
const required = sectionRequired(door, 'assemble');
|
|
2462
|
-
const a = c.object('config.assemble', v, required.filter((k) => k !== 'plan'), ['plan', 'extend_below_crop', 'patches', 'cuts', 'alternates', 'head_face_underfill', 'yield_refused', 'keep_under_occluders', 'extend_painting', 'take']);
|
|
2472
|
+
const a = c.object('config.assemble', v, required.filter((k) => k !== 'plan'), ['plan', 'extend_below_crop', 'patches', 'cuts', 'alternates', 'head_face_underfill', 'yield_refused', 'keep_under_occluders', 'extend_painting', 'take', 'seam']);
|
|
2463
2473
|
if (a === null) return { parts: [], patches: [], cuts: [] };
|
|
2474
|
+
checkSeam(c, a);
|
|
2464
2475
|
if (required.includes('plan') && !('plan' in a)) {
|
|
2465
2476
|
c.fail('CONFIG_FIELD_PRESENT', 'config.assemble.plan', 'is absent and required; `assemble --propose-plan` prints one from the two runs — paste its plan and extend_below_crop into config.assemble');
|
|
2466
2477
|
}
|
package/src/coords.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* `flattenRig` goes back through `toWorld`. No rotation matrix is written out
|
|
23
23
|
* by hand in this package.
|
|
24
24
|
*/
|
|
25
|
-
import { cropToSpineY } from '@rig-c/core/
|
|
25
|
+
import { cropToSpineY } from '@rig-c/core/transform';
|
|
26
26
|
|
|
27
27
|
/** A painting point on the accepted integer rig canvas, in setup-world coordinates. */
|
|
28
28
|
export function paintingToSetupPoint(point: readonly number[], sourceSize: readonly number[], rigSize: readonly number[]): [number, number] {
|
|
@@ -34,5 +34,5 @@ export function setupToPaintingPoint(point: readonly number[], sourceSize: reado
|
|
|
34
34
|
return [(point[0] + rigSize[0] / 2) / (rigSize[0] / sourceSize[0]), cropToSpineY(point[1], rigSize[1]) / (rigSize[1] / sourceSize[1])];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export { computeExactFrameTransforms, computeWorldTransforms, cropToSpineY, normaliseDegrees, toBoneLocal, toBoneLocalVector, toWorld } from '@rig-c/core/
|
|
38
|
-
export type { BoneTransform } from '@rig-c/core/
|
|
37
|
+
export { computeExactFrameTransforms, computeWorldTransforms, cropToSpineY, normaliseDegrees, toBoneLocal, toBoneLocalVector, toWorld } from '@rig-c/core/transform';
|
|
38
|
+
export type { BoneTransform } from '@rig-c/core/transform';
|
package/src/instruments.ts
CHANGED
|
@@ -962,7 +962,7 @@ export function partWorldBox(p: PartRecord, rigH: number, stage: StageBox): Worl
|
|
|
962
962
|
/**
|
|
963
963
|
* How many floating-point roundings stand between the rig and one coordinate
|
|
964
964
|
* of a displacement {@link stillReading} returns, on its longest path. Every
|
|
965
|
-
* number on it is a double: rigc's core poser (
|
|
965
|
+
* number on it is a double: rigc's core poser (`@rig-c/core/core`,
|
|
966
966
|
* rig-c 2.15.0) reads a vertex's local coordinates and weights through
|
|
967
967
|
* `Math.fround` and does the arithmetic in doubles, and `geometry.json` carries
|
|
968
968
|
* those doubles. The float32 inputs are the same numbers in the rest vertex and
|
package/src/propose.ts
CHANGED
|
@@ -131,7 +131,7 @@ import { explicitWeightRows, regionBone, type RegionSpec } from './config.ts';
|
|
|
131
131
|
*/
|
|
132
132
|
import { existsSync } from 'node:fs';
|
|
133
133
|
import { join } from 'node:path';
|
|
134
|
-
import { drawText, GLYPH_H } from '@rig-c/core/
|
|
134
|
+
import { drawText, GLYPH_H } from '@rig-c/core/font5x7';
|
|
135
135
|
import { type BoneEntry, type CharacterConfig, type ConfigConstraint, type ConfigStop, contourRegionsOf, deriveBustRegions, type Limb, type MeshSpec, type PartBinding, parseConfig, type Point, type Segment, type SkeletonSections, turnRidersByBone } from './config.ts';
|
|
136
136
|
export { contourRegionsOf, deriveBustRegions };
|
|
137
137
|
import { computeExactFrameTransforms, cropToSpineY, normaliseDegrees, toWorld } from './coords.ts';
|
package/src/raster/png.ts
CHANGED
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
* refuses by name rather than misreading. So adding `pngjs` would have been a
|
|
13
13
|
* second codec for the same bytes, and two codecs are two answers.
|
|
14
14
|
*
|
|
15
|
-
* 🔌 **The
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* 🔌 **The named entries are the interface.** `@rig-c/core/plate` and
|
|
16
|
+
* `@rig-c/core/png` are how a consumer reaches the codec and what the
|
|
17
|
+
* installed package resolves. If a rigc release moves or drops these entries,
|
|
18
|
+
* this import is what breaks, by name, and `bun run smoke` is where that is
|
|
19
|
+
* seen first.
|
|
20
20
|
*/
|
|
21
|
-
import { assertPng } from '@rig-c/core/
|
|
22
|
-
import { decodePng, encodePng } from '@rig-c/core/
|
|
21
|
+
import { assertPng } from '@rig-c/core/png';
|
|
22
|
+
import { decodePng, encodePng } from '@rig-c/core/plate';
|
|
23
23
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
24
24
|
import { type FloatImage, newFloatImage, newRaster, type Raster, RasterError } from './types.ts';
|
|
25
25
|
|
package/src/raster/types.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* feathered blend weight).
|
|
12
12
|
*
|
|
13
13
|
* Nothing here knows about Spine's y-up world. The only conversion between the
|
|
14
|
-
* two lives in
|
|
14
|
+
* two lives in `@rig-c/core/transform`, re-exported by `src/coords.ts`.
|
|
15
15
|
*/
|
|
16
16
|
export interface Raster {
|
|
17
17
|
readonly width: number;
|
package/src/remesh.ts
CHANGED
|
@@ -75,8 +75,8 @@ import { applyMeshEdit, type DeltaApplied, type DeltaPlant, deltaSourceProblems,
|
|
|
75
75
|
import { DEFAULT_IDLE_KEYS, type IdleKeys, type MeshAttachment, meshBoundBones, rigJsonText, type RigSpec } from './rig.ts';
|
|
76
76
|
import { readRequirements } from './requirements.ts';
|
|
77
77
|
import { pyRound } from './round.ts';
|
|
78
|
-
import { type RigSpec as RigcRigSpec } from '@rig-c/core/
|
|
79
|
-
import { expandStops } from '@rig-c/core/
|
|
78
|
+
import { type RigSpec as RigcRigSpec } from '@rig-c/core/rig';
|
|
79
|
+
import { expandStops } from '@rig-c/core/stop';
|
|
80
80
|
|
|
81
81
|
/** The provenance file's spec. */
|
|
82
82
|
export const REMESH_SPEC = 'rig-parts-remesh/1';
|
package/src/requirements.ts
CHANGED
|
@@ -50,8 +50,8 @@ import { fixedSkeletonProblems, type FixedSkeleton } from './artjoints.ts';
|
|
|
50
50
|
*/
|
|
51
51
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
52
52
|
import { resolve } from 'node:path';
|
|
53
|
-
import { CompileError } from '@rig-c/core/
|
|
54
|
-
import { splitRigSkin, type RigSkin } from '@rig-c/core/
|
|
53
|
+
import { CompileError } from '@rig-c/core/errors';
|
|
54
|
+
import { splitRigSkin, type RigSkin } from '@rig-c/core/rig';
|
|
55
55
|
import { cropToSpineY } from './coords.ts';
|
|
56
56
|
import type { Problem } from './errors.ts';
|
|
57
57
|
import { refuseIfAny } from './errors.ts';
|
package/src/rig.ts
CHANGED
|
@@ -138,12 +138,12 @@ import { explicitAttachment, type ExplicitMeshReport } from './explicitmesh.ts';
|
|
|
138
138
|
* order the objects are built in, and every number is rounded by `pyRound`).
|
|
139
139
|
*/
|
|
140
140
|
import { type AutoSpec, type BoneEntry, type InfluenceMeshSpec, type WeightRule, type CharacterConfig, type ConfigConstraint, type ConfigStop, CONSTRAINT_FOLLOWS, constraintForRig, contourRegionsOf, type ContourSpec, DEFAULT_BUST_BONE_L, DEFAULT_BUST_BONE_R, type Point, type RibsSpec, ROOT_BONE, stopForRig, turnRidersByBone, weightsABone } from './config.ts';
|
|
141
|
-
import { RUNTIME_PI } from '@rig-c/core/
|
|
141
|
+
import { RUNTIME_PI } from '@rig-c/core/core';
|
|
142
142
|
import { type BoneTransform, computeExactFrameTransforms, computeWorldTransforms, cropToSpineY, normaliseDegrees, paintingToSetupPoint, setupToPaintingPoint, toBoneLocal, toWorld } from './coords.ts';
|
|
143
143
|
import { type Problem, refuseIfAny, PartsError } from './errors.ts';
|
|
144
144
|
import { recordedFocusProblems } from './setfocus.ts';
|
|
145
145
|
import { eyeLineDegrees } from './headframe.ts';
|
|
146
|
-
import type { RigBoneInherit, RigStop } from '@rig-c/core/
|
|
146
|
+
import type { RigBoneInherit, RigStop } from '@rig-c/core/rig';
|
|
147
147
|
import { f32 } from '@rig-c/core/compile';
|
|
148
148
|
import type { MeshCounts, MeshQualityReport, MeshReductionInput, MotionAmplitude, ReducedMesh, Termination } from '@rig-c/core/mesh';
|
|
149
149
|
import { bindWeightedVertices, buildGridMesh, buildSegmentsLattice, type EntrySegment, influenceShares, segmentDistance as rigcSegmentDistance, type SegmentsLattice, type SegmentsLatticeReport } from '@rig-c/core/mesh';
|
|
@@ -309,6 +309,14 @@ function lineGap(a: number, b: number): number {
|
|
|
309
309
|
/** The bones the face's line runs through: rigc's A51 draws its line through their origins, and the face bones are turned to that same line. */
|
|
310
310
|
export const EYE_BONES: readonly [string, string] = ['eye_r', 'eye_l'];
|
|
311
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Issue #903: midpoint of absolute setup eye-line rolls measured on the public
|
|
314
|
+
* controls (maximum 4.864514437760526 degrees across the five parts examples,
|
|
315
|
+
* dancer and the head-turn demo) and three-quarter (32.106255955117845 degrees).
|
|
316
|
+
* This separates those inputs; it is not an anatomical or visual-quality bar.
|
|
317
|
+
*/
|
|
318
|
+
const HEAD_TURN_ROLL_LIMIT = (4.864514437760526 + 32.106255955117845) / 2;
|
|
319
|
+
|
|
312
320
|
/**
|
|
313
321
|
* The eye line (issue #239). It exists when parts.json holds an eye on each
|
|
314
322
|
* side — the first part tagged `eyewhite-r` and the first tagged `eyewhite-l`
|
|
@@ -3656,6 +3664,15 @@ export function buildWaistPairSource(
|
|
|
3656
3664
|
boneLandmarks.set(bName, [bEntry.x, bEntry.y]);
|
|
3657
3665
|
}
|
|
3658
3666
|
const turnWarnings: Problem[] = [];
|
|
3667
|
+
if ((cfg.turn?.depths !== undefined || cfg.turn?.roles !== undefined) && line.degrees !== null && Math.abs(line.degrees) > HEAD_TURN_ROLL_LIMIT) {
|
|
3668
|
+
const faces = parts.parts.filter(p => tagOf(p.from) === 'face' && p.cut_from === undefined).map(p => p.name);
|
|
3669
|
+
const names = faces.length === 0 ? line.parts : faces;
|
|
3670
|
+
turnWarnings.push({
|
|
3671
|
+
code: 'RIG_TURN_HEAD_ROLL',
|
|
3672
|
+
object: `${names.length === 1 ? 'part' : 'parts'} ${names.map(n => `"${n}"`).join(', ')}`,
|
|
3673
|
+
detail: `setup eye-line roll ${pyRound(line.degrees, 6)} degrees (Spine, counter-clockwise), absolute ${pyRound(Math.abs(line.degrees), 6)} exceeds limit ${pyRound(HEAD_TURN_ROLL_LIMIT, 6)} degrees; read through authored ${EYE_BONES.join(' and ')} origins on ${line.parts.map(n => `"${n}"`).join(' and ')} (an eye-origin proxy, not painting detection); the declared head turn uses upright yaw/pitch axes on an already rolled head; inspect the neck at both turn extremes; warning only, no pose or output changed`,
|
|
3674
|
+
});
|
|
3675
|
+
}
|
|
3659
3676
|
if (cfg.turn?.roles !== undefined || cfg.turn?.body !== undefined) {
|
|
3660
3677
|
buildDepth25DTurn(rig, motion, {
|
|
3661
3678
|
warnings: turnWarnings,
|
package/src/scene.ts
CHANGED
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
*/
|
|
94
94
|
import { existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
95
95
|
import { dirname, join, resolve } from 'node:path';
|
|
96
|
-
import type { RigStop } from '@rig-c/core/
|
|
96
|
+
import type { RigStop } from '@rig-c/core/rig';
|
|
97
97
|
import { checkStage, gateThroughRigc, type Log } from './build.ts';
|
|
98
98
|
import { ACCEPTABLE_BARS, barsNotMet, type CheckReport, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, type PackMode, requirementsNotPass, type RigcRunner } from './check.ts';
|
|
99
99
|
import { CONSTRAINT_BONE_FIELDS, ROOT_BONE } from './config.ts';
|
package/src/seamrule.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Shared seam choices for the config reader and assembly. */
|
|
2
|
+
export type SeamRule = 'near-white' | 'silhouette';
|
|
3
|
+
export const SEAM_RULES: readonly SeamRule[] = ['near-white', 'silhouette'];
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The seam rule a run uses when none is named. Set by measurement, not taste:
|
|
7
|
+
* the silhouette rule ships as the default only if it lowers the error pixel
|
|
8
|
+
* count on every oracle character without raising mean |d| on any
|
|
9
|
+
* (ORACLE_assemble.md, *faithful vs silhouette*).
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_SEAM_RULE: SeamRule = 'near-white';
|
package/src/setuppainting.ts
CHANGED
|
@@ -74,6 +74,10 @@ export interface SetupPaintingLine {
|
|
|
74
74
|
reason?: string;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/** An undeclared observation has no measured pixels, inferred regions or limit. */
|
|
78
|
+
export type SetupPaintingObservation = SetupPaintingLine | { status: 'SKIP'; reason: string };
|
|
79
|
+
export const UNDECLARED_SETUP_PAINTING_REASON = 'setup_painting is undeclared; setup-to-painting was not measured. To measure it, give --requirements <file> declaring setup_painting.rgb_tolerance and setup_painting.regions with name, box and authored max_pixels limits';
|
|
80
|
+
|
|
77
81
|
/** Pixel metric only. Caller supplies the actual renderer's textured setup and
|
|
78
82
|
* its per-pixel drawn-piece owners on precisely the source grid. RGB under
|
|
79
83
|
* zero alpha is ignored: both observations are source-over white first.
|
|
@@ -119,7 +123,8 @@ export function setupPaintingLine(
|
|
|
119
123
|
...(noLimit ? { reason: 'a region has no declared max_pixels; it is measured as SKIP, never PASS' } : {}) };
|
|
120
124
|
}
|
|
121
125
|
|
|
122
|
-
export function setupPaintingLines(line:
|
|
126
|
+
export function setupPaintingLines(line: SetupPaintingObservation): string[] {
|
|
127
|
+
if (!('regions' in line)) return [`${SETUP_PAINTING_LINE}: SKIP — ${line.reason}`];
|
|
123
128
|
return [`${SETUP_PAINTING_LINE}: ${line.status}${line.reason === undefined ? '' : ` — ${line.reason}`}; ${line.registration}; ${line.compositing}`,
|
|
124
129
|
...line.regions.flatMap(r => [`${SETUP_PAINTING_LINE}: region "${r.name}" ${r.status} — box [${r.box.join(', ')}], pixelcount ${r.pixel_count}, limit ${r.limit ?? 'undeclared (SKIP)'}, RGB tolerance ${line.rgb_tolerance}`,
|
|
125
130
|
...r.slots.map(s => `${SETUP_PAINTING_LINE}: slot "${s.slot}" region "${r.name}" — box [${s.box.join(', ')}], pixelcount ${s.pixel_count}; region total ${r.pixel_count}, limit ${r.limit ?? 'undeclared (SKIP)'}`)])];
|
package/src/sheet.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { existsSync } from 'node:fs';
|
|
20
20
|
import { basename, dirname, join } from 'node:path';
|
|
21
|
-
import { drawText, GLYPH_H } from '@rig-c/core/
|
|
21
|
+
import { drawText, GLYPH_H } from '@rig-c/core/font5x7';
|
|
22
22
|
import { type Problem, refuseIfAny } from './errors.ts';
|
|
23
23
|
import { type LayerSet, OPAQUE_ALPHA_ABOVE, readLayers } from './layers.ts';
|
|
24
24
|
import { readParts } from './parts.ts';
|
package/src/structure.ts
CHANGED
|
@@ -71,8 +71,8 @@ import { explicitWeightRows, regionBone } from './config.ts';
|
|
|
71
71
|
* Pure but for reading the three files it is handed.
|
|
72
72
|
*/
|
|
73
73
|
import { existsSync, readFileSync } from 'node:fs';
|
|
74
|
-
import { CompileError } from '@rig-c/core/
|
|
75
|
-
import { parseRigSpec, RIG_SPEC_VERSION, type RigBone as RigcBone, type RigSpec as RigcSpec, splitRigSkin } from '@rig-c/core/
|
|
74
|
+
import { CompileError } from '@rig-c/core/errors';
|
|
75
|
+
import { parseRigSpec, RIG_SPEC_VERSION, type RigBone as RigcBone, type RigSpec as RigcSpec, splitRigSkin } from '@rig-c/core/rig';
|
|
76
76
|
import { type ConfigConstraint, CONSTRAINT_FOLLOWS, contourRegionsOf, parseConfig, parseProposalSections, type Point, ROOT_BONE, type SkeletonSections, weightsABone } from './config.ts';
|
|
77
77
|
import { computeExactFrameTransforms, cropToSpineY, normaliseDegrees, toWorld } from './coords.ts';
|
|
78
78
|
import { PartsError, type Problem, refuseIfAny } from './errors.ts';
|
package/src/turn.ts
CHANGED
|
@@ -38,7 +38,7 @@ import { sampleTurnTriangleField, turnTriangleCoordinates } from './turnfield.ts
|
|
|
38
38
|
import { PartsError } from './errors.ts';
|
|
39
39
|
import { f32 } from '@rig-c/core/compile';
|
|
40
40
|
import { warnUncoveredBodyTurn } from './turncoverage.ts';
|
|
41
|
-
import { evaluateDeformTransform } from '@rig-c/core/
|
|
41
|
+
import { evaluateDeformTransform } from '@rig-c/core/deformgen';
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* The layers that ride on the face (issue #271): See-through makes no depth
|
package/src/turncoverage.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Report missing body-turn declarations from shown setup alpha and emitted fields. */
|
|
2
2
|
import { f32 } from '@rig-c/core/compile';
|
|
3
|
-
import { DRAWN_ALPHA } from '@rig-c/core/
|
|
4
|
-
import { evaluateDeformTransform, type DeformTransform } from '@rig-c/core/
|
|
3
|
+
import { DRAWN_ALPHA } from '@rig-c/core/passthrough';
|
|
4
|
+
import { evaluateDeformTransform, type DeformTransform } from '@rig-c/core/deformgen';
|
|
5
5
|
import { computeWorldTransforms, paintingToSetupPoint, toWorld } from './coords.ts';
|
|
6
6
|
import { extendDepthSilhouette, sampleDepthFloat } from './depthsheets.ts';
|
|
7
7
|
import { edgeLength } from './length.ts';
|
package/src/turnoverlap.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Source-alpha overlap selects turn fields, never skin bindings. */
|
|
2
|
-
import { DRAWN_ALPHA } from '@rig-c/core/
|
|
2
|
+
import { DRAWN_ALPHA } from '@rig-c/core/passthrough';
|
|
3
3
|
import { computeWorldTransforms, setupToPaintingPoint, toWorld } from './coords.ts';
|
|
4
4
|
import type { Depth25DTurnOptions } from './turn.ts';
|
|
5
5
|
import type { Problem } from './errors.ts';
|