@rig-c/parts 1.24.0 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cli.ts +22 -6
- package/docs/AUTHORING.md +76 -36
- package/docs/MIGRATION.md +1 -1
- package/docs/STABILITY.md +10 -8
- package/package.json +2 -2
- package/skills/rig-parts/SKILL.md +1 -1
- package/src/assemble.ts +142 -29
- package/src/automesh.ts +2 -1
- package/src/build.ts +23 -9
- package/src/check.ts +227 -44
- package/src/cloth.ts +22 -7
- package/src/config.ts +161 -12
- package/src/headbox.ts +68 -34
- package/src/limbs.ts +171 -0
- package/src/propose.ts +301 -49
- package/src/rig.ts +186 -18
- package/src/scene.ts +87 -7
- package/src/squeeze.ts +161 -1
package/README.md
CHANGED
|
@@ -250,7 +250,7 @@ rig-parts assemble --source painting.png --full layers/full --head layers/head -
|
|
|
250
250
|
# -> a large red hole neither run holds? add an assemble.patches entry (cut from the painting) and assemble again
|
|
251
251
|
rig-parts propose --parts work/rig --source painting.png --out work
|
|
252
252
|
# -> proposal.json, basis.json (what each bone rests on) and render/landmarks.png; per-bone coverage lines;
|
|
253
|
-
# correct it, copy bones/meshes/regions/limbs/motion/constraints/turn into config.json, each it wrote
|
|
253
|
+
# correct it, copy bones/meshes/regions/limbs/motion/constraints/turn/proposed_rig_scale into config.json, each it wrote
|
|
254
254
|
# (limbs only with --keypoints, constraints only with --cloth, turn only with --full/--head;
|
|
255
255
|
# a limbs block left out is refused next)
|
|
256
256
|
rig-parts propose --parts work/rig --source painting.png --out work --from-config config.json
|
package/cli.ts
CHANGED
|
@@ -27,7 +27,7 @@ import { makeInputs } from './src/inputs.ts';
|
|
|
27
27
|
import { idleKeysOf, isIdleKeys } from './src/rig.ts';
|
|
28
28
|
import { depthSkipLine, exportLayers, figuresPhrase, hiddenLayerLine, implausibleRules, layerFigures, type LayerSet, layerSetDiff, pct, readLayers, readWrapperLayers, ruleSummary, templateLayerNames, templatePsdBytes, times } from './src/layers.ts';
|
|
29
29
|
import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJoints, toRigJoints } from './src/keypoints.ts';
|
|
30
|
-
import { basisLines, checkProposal, compare, compareLines, DEFAULT_GRID_RULE, draftTurn, drawLandmarks, FIGURE_GRID_DIVISOR, FRINGE_STEP_PX, GRID_RULES, type GridRule, HIP_MIN_FRACTION, lint, lintLine, type PartSet, proposeWithBasis, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
30
|
+
import { basisLines, branchSqueezeLine, checkProposal, compare, compareLines, DEFAULT_GRID_RULE, draftTurn, drawLandmarks, FIGURE_GRID_DIVISOR, FRINGE_STEP_PX, GRID_RULES, type GridRule, HIP_MIN_FRACTION, lint, lintLine, type PartSet, proposeWithBasis, readPartSet, serializeProposal, withTurn, WRIST_ON_PART_PX } from './src/propose.ts';
|
|
31
31
|
import { BASIS_FILE, BASIS_SPEC, basisFile, basisLine, coverageLines, serializeBasis } from './src/diagnostics.ts';
|
|
32
32
|
import { BEND_DEGREES, BEND_WORST_SHARE, DUST_MAX_PX, DUST_MAX_SHARE, IDLE_BOUND_PX, MESH_DRAFT_REPORT, MESH_DRAFT_SPEC, meshDraftStage, MORE_TRIANGLES_FLAG, TOLERANCE_FIGURE_DIVISOR } from './src/meshdraft.ts';
|
|
33
33
|
import { checkPainting } from './src/paintcheck.ts';
|
|
@@ -220,11 +220,13 @@ usage:
|
|
|
220
220
|
coverage lines after them; no ${BASIS_FILE}, as nothing is proposed.
|
|
221
221
|
Exits 1 when any LINT line is printed.
|
|
222
222
|
|
|
223
|
-
rig-parts propose --head-box --full <dir | layers.json | file.psd> --canvas <W>x<H>
|
|
223
|
+
rig-parts propose --head-box --full <dir | layers.json | file.psd> --canvas <W>x<H> [--no-back-hair]
|
|
224
224
|
Propose seethrough.head_box (source px, square) from the full run's
|
|
225
225
|
layers for a painting of WxH px (portrait or landscape: the full run is
|
|
226
226
|
mapped back through the pad inputs added), held inside the painting; a
|
|
227
|
-
shift is printed when one was needed.
|
|
227
|
+
shift is printed when one was needed. When "back hair" contributes, prints
|
|
228
|
+
the box without it and how much of the side and area it took;
|
|
229
|
+
--no-back-hair leaves "back hair" out of the box.
|
|
228
230
|
|
|
229
231
|
rig-parts compare --left <file> --right <file> [--map <bonemap.json>]
|
|
230
232
|
Compare two skeletons bone by bone. Each file is a config, a proposal.json
|
|
@@ -780,7 +782,7 @@ const TAKES = {
|
|
|
780
782
|
layers: { valued: ['--export', '--template', '--canvas'], switches: [] },
|
|
781
783
|
sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
|
|
782
784
|
rig: { valued: ['--config', '--parts', '--out', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
783
|
-
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule', '--cloth'], switches: ['--head-box'] },
|
|
785
|
+
propose: { valued: ['--parts', '--source', '--out', '--from-config', '--compare', '--full', '--head', '--canvas', '--keypoints', '--person', '--wrist-snap', '--grid-rule', '--cloth'], switches: ['--head-box', '--no-back-hair'] },
|
|
784
786
|
compare: { valued: ['--left', '--right', '--map'], switches: [] },
|
|
785
787
|
check: { valued: ['--rig', '--out', '--parts', '--source', '--page-edges', '--pack-shape', '--requirements'], switches: ['--seam-pairs', '--keep-stills'] },
|
|
786
788
|
loop: { valued: ['--frames', '--out'], switches: ['--palette'] },
|
|
@@ -1064,6 +1066,7 @@ function printLint(P: PartSet, spec: { bones: CharacterConfig['bones']; meshes:
|
|
|
1064
1066
|
for (const m of res.unknownMeshes) console.log(`note: mesh ${JSON.stringify(m)} names no part in parts.json, so it was not linted`);
|
|
1065
1067
|
for (const w of res.lockUnread) console.log(`note: off-lock not read: ${w}`);
|
|
1066
1068
|
for (const w of res.squeezeUnread) console.log(`note: squeeze not read: ${w}`);
|
|
1069
|
+
for (const b of res.branchSqueezes) console.log(branchSqueezeLine(b));
|
|
1067
1070
|
for (const b of res.missingTorsoBones) {
|
|
1068
1071
|
console.log(
|
|
1069
1072
|
res.basis?.torso.read === true
|
|
@@ -1080,12 +1083,18 @@ function printLint(P: PartSet, spec: { bones: CharacterConfig['bones']; meshes:
|
|
|
1080
1083
|
function cmdPropose(args: string[]): number {
|
|
1081
1084
|
const flags = new Map<string, string>();
|
|
1082
1085
|
let headBox = false;
|
|
1086
|
+
let noBackHair = false;
|
|
1083
1087
|
for (let i = 0; i < args.length; i++) {
|
|
1084
1088
|
const flag = args[i];
|
|
1085
1089
|
if (flag === '--head-box') {
|
|
1086
1090
|
headBox = true;
|
|
1087
1091
|
continue;
|
|
1088
1092
|
}
|
|
1093
|
+
if (flag === '--no-back-hair') {
|
|
1094
|
+
if (noBackHair) return usage('--no-back-hair is given twice');
|
|
1095
|
+
noBackHair = true;
|
|
1096
|
+
continue;
|
|
1097
|
+
}
|
|
1089
1098
|
if (!takesValued('propose', flag)) return usage(notTaken('propose', flag));
|
|
1090
1099
|
const value = args[i + 1];
|
|
1091
1100
|
if (value === undefined) return usage(`${flag} needs a value`);
|
|
@@ -1103,16 +1112,23 @@ function cmdPropose(args: string[]): number {
|
|
|
1103
1112
|
if (canvasArg === undefined) return usage('--head-box needs --canvas <W>x<H>, the painting\'s size in px');
|
|
1104
1113
|
const canvas = parseCanvas(canvasArg);
|
|
1105
1114
|
if (canvas === null) return usage(`--canvas ${canvasArg} is not <W>x<H> in integer px`);
|
|
1106
|
-
const r = proposeHeadBox(readLayers(full), canvas);
|
|
1115
|
+
const r = proposeHeadBox(readLayers(full), canvas, { backHair: !noBackHair });
|
|
1107
1116
|
console.log(`rig-parts propose --head-box: ${full}`);
|
|
1108
1117
|
console.log(` painting ${canvas.w}x${canvas.h}; head layers ${r.layers.map(([n, c]) => `${n} ${c} px`).join(', ')}`);
|
|
1109
1118
|
if (r.shift[0] !== 0 || r.shift[1] !== 0) {
|
|
1110
1119
|
console.log(` clamped: the proposed box [${r.unclamped.join(', ')}] leaves the ${canvas.w}x${canvas.h} painting; shifted by ${r.shift[0]},${r.shift[1]} px at the same size`);
|
|
1111
1120
|
} else console.log(' inside the painting, no shift');
|
|
1112
|
-
|
|
1121
|
+
const edge = r.head_box[2] - r.head_box[0];
|
|
1122
|
+
const w = r.without_back_hair;
|
|
1123
|
+
if (w !== undefined) {
|
|
1124
|
+
const share = edge > 0 ? Math.round((1 - (w.edge * w.edge) / (edge * edge)) * 100) : 0;
|
|
1125
|
+
console.log(` back hair: without "back hair" the box is ${w.head_box !== null ? `[${w.head_box.join(', ')}], ` : ''}${w.edge}x${w.edge} ("back hair" adds ${edge - w.edge} px to the side, ${share}% of the box's area; pass --no-back-hair to leave it out)`);
|
|
1126
|
+
}
|
|
1127
|
+
console.log(` head_box [${r.head_box.join(', ')}], ${edge}x${r.head_box[3] - r.head_box[1]}`);
|
|
1113
1128
|
console.log(JSON.stringify({ head_box: r.head_box }));
|
|
1114
1129
|
return EXIT_OK;
|
|
1115
1130
|
}
|
|
1131
|
+
if (noBackHair) return usage('--no-back-hair belongs to --head-box');
|
|
1116
1132
|
if (flags.has('--canvas')) return usage('--canvas belongs to --head-box');
|
|
1117
1133
|
const partsArg = flags.get('--parts');
|
|
1118
1134
|
const source = flags.get('--source');
|
package/docs/AUTHORING.md
CHANGED
|
@@ -102,13 +102,13 @@ read by no CPU stage).
|
|
|
102
102
|
| `seethrough.resolution` | assemble — each run's canvas must be `resolution` square (`ASSEMBLE_RUN_CANVAS`); with one run (no `--head`, issue #366) the file may be smaller on either side, and is padded to the `resolution` square, centred | recorded from the See-through runs; 1024 in both examples. With one run it is the square the file is read on: at least the file's longer side (`ASSEMBLE_RUN_CANVAS` otherwise), and nothing a part records depends on how much larger |
|
|
103
103
|
| `seethrough.steps`, `.seed`, `.offload` | no CPU stage | recorded from the runs |
|
|
104
104
|
| `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`) |
|
|
105
|
-
| `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.
|
|
105
|
+
| `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` |
|
|
106
106
|
| `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*) |
|
|
107
107
|
| `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 |
|
|
108
108
|
| `assemble.patches` | assemble; `meshes`/`regions` keys may name them too | **authored**, optional: `[{name, box, alpha, draw}]` — an extra part cut from the **painting** itself, for figure no See-through layer holds (a hem both runs dropped). `box` is `[x0, y0, x1, y1]` in **rig** pixels, `x1`/`y1` exclusive — the space of `parts.json` and `recomposite_rig.png`, where the hole is found; `alpha` is `"silhouette"` (the painting's figure silhouette inside the box, the one `--seam silhouette` uses) or `"box"` (the whole box); `draw` is `"back"`, `"front"` or `{"before": "<plan part>"}`. A patch is always a region: its bone is `regions.<name>`, in the one place every region's bone lives, and a `meshes` entry for it is refused. See §5 for how to place one |
|
|
109
109
|
| `assemble.cuts` | assemble; `meshes`/`regions` keys may name the new parts too, and must (each is a part like any other) | **authored**, optional (issue #170): `[{from, into, polygon, draw, overlap, under, under_fill}]`, `under` and `under_fill` optional — a plan part's layer cut by a polygon the author draws: the pixels of plan part `from` whose **centre** lies inside `polygon` (even-odd; a centre exactly on an edge is outside) leave `from` and make the new part `into`, colour and alpha, so every pixel of the layer ends in exactly one of the two. `polygon` is `[[x, y], …]`, at least three points, non-negative integer **rig** pixels — the space of `parts.json` and of the patches' boxes. The file that shows the layer in those coordinates is `assemble`'s own `rig/parts/<from>.png`, placed at its `parts.json` `x`, `y` (the PNG's pixel `(i, j)` is rig pixel `(x + i, y + j)`), or `render/recomposite_rig.png`, the whole rig 1:1; the contact sheets (`sheet`) are scaled and carry no coordinates. `draw` is `"back"`, `"front"` or `{"before": "<plan part>"}`, as for a patch (to keep the setup pose, draw the piece immediately in front of `from` — `{"before": "<the plan part after from>"}`, or `"front"` when `from` is the last plan part; `{"before": "<from>"}` draws it behind `from`, which `under` refuses as `ASSEMBLE_UNDER_DRAW` because the fill would hide it). `from` must be a plan part (`CONFIG_NAME_RESOLVES`; a patch or another cut's piece is refused), `into` a new name (`CONFIG_PART_UNIQUE`), the polygon three or more integer points (`CONFIG_FIELD_TYPE`). The piece's `parts.json` record carries `from`'s `<run>:<tag>` and its own counts, each split from the layer's by where the pixel lies; it is a mesh or a region under its own name, and the coverage rule holds it like a plan part. What the config cannot know the stage refuses: a polygon point past the rig (`ASSEMBLE_CUT_INSIDE`), two cuts of one part sharing a pixel (`ASSEMBLE_CUT_OVERLAP`), a cut that takes none of the layer's opaque pixels or leaves `from` none (`ASSEMBLE_CUT_PIXELS`). `overlap` is required, a non-negative integer of rig pixels with no default (`CONFIG_FIELD_TYPE`): the **band** — the polygon's pixels within `overlap` px of its edge by Chebyshev distance (the polygon's mask less its erosion by a `2 * overlap + 1` square) — stays in `from` as well as going to the piece, so the piece's resampled edge has art under it; the counts stay a strict partition and the band is the base's extra copy, printed on the `cut:` line. At `0` the two abut and `check`'s seam bar judges the edge between them (`CHECK_SEAM_WITHIN_BAR`, §5). A band only covers the edge at rest: a piece that swings well clear of where it was painted shows the hole it leaves, and a thin piece's band shows a ghost of the piece. `under` (issue #193), optional, is the author's image of what lies under the piece: a PNG path relative to the config's directory (`CONFIG_FIELD_TYPE` unless a non-empty string), in rig pixels over the polygon's **bounding box** — the least and greatest polygon x and y, so the image is `max x − min x` by `max y − min y` and its pixel `(i, j)` is rig pixel `(min x + i, min y + j)`. Where the cut removed pixels from `from` — the piece's pixels (alpha above 0) less the band — `from` takes the image's pixel, colour and alpha wherever the image's alpha is at least the alpha the cut removed there (**filled**); elsewhere `from` stays empty there (**left empty**): a transparent pixel is the author's statement that nothing lies under it (the background, or a part drawn behind), and a less opaque one is not half-filled. The image is read nowhere else, so its pixels over the band, over the box outside the polygon or where the layer had no art never change `from`. The `cut:` line then ends `; under <n> px filled, <m> px left empty` (`n + m` is every removed pixel), so an unintended hole is a number in the log, not a guess; the filled pixels count in `from`'s `opaque_px` and `occluded_px` (the piece is drawn over them), never as visible or projected. The stage refuses: a file that is not there (`ASSEMBLE_UNDER_PRESENT`) or not a PNG (`ASSEMBLE_UNDER_DECODES`), an image not exactly the box's size (`ASSEMBLE_UNDER_SIZE`, both sizes given), an image that fills none of the removed pixels — all transparent there, or another file (`ASSEMBLE_UNDER_EMPTY`; to leave the whole hole, drop `under`), and a piece drawn behind `from` (`ASSEMBLE_UNDER_DRAW`: the fill would hide it; draw it `"front"` or `{"before": "<the plan part after from>"}`). Producing the image is the author's, by whatever means; absent, `from` keeps only its band. `under_fill` (issue #360), optional, is the one value `"colour"` (`CONFIG_FIELD_TYPE` on any other): the same pixels are filled and left empty, and a filled pixel takes the image's **colour** at the alpha the cut removed there instead of the image's alpha, so `from`'s alpha is the uncut layer's wherever the image fills and its silhouette does not grow — an opaque image over a soft edge leaves the edge soft. It applies to the part's hidden-art layer as well as to a file; a cut with neither is refused (`ASSEMBLE_UNDER_FILL_SOURCE`). The `cut:` line's filled count then says how many took the colour only: `; under 190 px filled (190 colour only, at the alpha the cut removed), 0 px left empty`. Absent, a filled pixel takes the image's colour and alpha, as above |
|
|
110
110
|
| `limbs` | assemble (the cut and the caps), rig (through `regions`), check (`LIMB_ONE_BONE`) | **proposed** by `propose --keypoints` (issue #349), then checked: `{<limb>: {segments: [{part, from, bone}, {part, from, bone, joint, range?, cap?, edge?, cap_shape?, cut_band?}, …]}}`, the upper segment first. The rule is *Limbs: cut at their joints* below the table. `part` is a new part (`CONFIG_PART_NAME`, `CONFIG_PART_UNIQUE` against the plan, patches, cuts and every other limb part); `from` a plan part or a cut's piece (`CONFIG_NAME_RESOLVES`) — the layer the segment's pixels come from, which is cut into the limb parts and is not itself made: a `meshes` or `regions` entry for it is `CONFIG_NAME_RESOLVES`, and the segments of one limb that take one part are consecutive (`CONFIG_LIMB_FROM_RUN`); `bone` a declared bone, each segment's the child of the one before (`CONFIG_LIMB_BONES_CHAIN`); the upper segment names no `joint`, `range`, `cap`, `edge`, `cap_shape` or `cut_band` (`CONFIG_KEY_KNOWN`), every other names its `joint` (`CONFIG_FIELD_PRESENT`) — the joint is its bone's origin; `range` is `[min, max]` degrees from rest with `min <= 0 <= max` (`CONFIG_LIMB_RANGE`), which `assemble` writes into the lower part's `parts.json` record and `check` poses the joint at — its two ends and its middle — reading the seam there (`SEAM_OVER_RANGE`, issue #360; rig-c needs no rotation limit); `cap` a PNG path relative to the config's directory (`CONFIG_FIELD_TYPE`); `edge` `"feather"` and `cap_shape` `"disc"` (issue #360), each the one value its field takes (`CONFIG_FIELD_TYPE` on any other) — the cut's geometry at that joint, *Limbs: cut at their joints* below; absent, the cut is hard and the cap the layer's half-disc of half the limb's width; `cut_band` a whole number of px, 1 or more (`CONFIG_FIELD_TYPE`), on a segment that takes the segment above's part — between two layers nothing is cut, so a band there is `CONFIG_KEY_KNOWN` — places the cut within that many px of the joint line (issue #360, *Limbs: cut at their joints*); absent, the cut is the joint line. Each limb part is attached like any part — `regions.<part>`, which must be the segment's `bone` (`CONFIG_LIMB_BONE`), or a mesh, which `check` holds to that bone alone (`LIMB_ONE_BONE`). With `limbs`, `assemble` reads `bones` too (`CONFIG_FIELD_PRESENT` without it). Absent, nothing is cut at a joint and no byte of any output moves |
|
|
111
|
-
| `bones` | rig; `propose --from-config` | **proposed** by `propose`, then corrected. A single bone `{name, parent, at, tip?}` or a chain `{chain, parent, points, tip}` whose links are named `<chain>0 … <chain>n`. Parents come before children. In `rig.json` each link is **turned along its chain** — `rotation` is the direction from its origin to the next link's (the last link's to `tip`) and `length` that distance (issue #73), so a physics constraint added downstream finds a lever; under `--idle-keys ctl` the link's `<link>_ctl` carries the turn and the length and the link sits at local rotation 0 beneath it. A single bone with a `tip` is turned the same way, towards its tip, with that distance as its length (issue #239); a tip on the bone's own origin is refused (`RIG_TIP_DISTINCT`). The five face bones `eye_r`, `eye_l`, `brow_r`, `brow_l` and `mouth` (by name, when one has no tip of its own) are turned to the eye line — the line through the origins of `eye_r` and `eye_l` as `bones` writes them, read image-left to image-right, drawn when parts.json holds both an `eyewhite-r` and an `eyewhite-l` part — so the blink's `scaley` squashes across the eye line on a tilted head; move an eye bone and the line moves with it. With one eyewhite or none, or an eye bone missing, the rig stage's `face axis:` line says so and they keep the page's axes. A bone under a face bone keeps the face's axis. With the line, `rig.json` also declares `invariants.axes` — one entry, `"face"`, through `eye_r` and `eye_l`, holding the turned face bones (and their controls) — so rig-c's gate holds the build to the line; the line is the one rigc draws through the same two bones, so the tolerance is only the float floor — the largest gap the emitted (float32) bones have to it, rounded up to 6 places plus one 6-place unit — and the `face axis:` line prints it. With the line the rig stage also adds `head_up` (issue #250): a slotless bone under `head`, at head's origin, turned to the eye line + 90 degrees and as long as the eye midpoint lies from head's origin along that axis — the head's frame, which a rule that needs it reads; `head` keeps its own frame, so no key on it or under it changes meaning, and a config bone of that name is refused (`RIG_HEAD_UP_NAME_FREE`). A face bone with its own `tip` is held too (issue #258), in a second entry, `"face_tips"`, when its tip lies along the line within whole-pixel rounding — a tip written in whole pixels sits at most sqrt(2)/2 px off the point of the line it stands for, so its direction may sit up to asin((sqrt(2)/2) / length) degrees off — with its tolerance measured the same way; a tip further off is the bone's own axis, and the `face axis:` line names it with its gap and that bound. A failure is rig-c's `A51_BONES_LIE_ALONG_THEIR_DECLARED_AXIS` line, which names the bone and the fix (rig-c's `docs/AUTHORING.md` §3.7 and §5.2); with no line no entry is written and A51 reports SKIP. Every region on a turned bone is turned back, so the setup pose does not move. Any other single bone keeps world rotation 0; one whose parent is a link is turned back upright. A single bone may declare `inherit` (issue #348): what it takes from its parent's transform, one of rig-c's own mode names exactly as rig-c's table spells them — `normal`, `onlyTranslation`, `noRotationOrReflection`, `noScale`, `noScaleOrReflection` (rig-c's `RigBone.inherit`) — written to that bone in `rig.json` as declared; any other spelling, `"NoScale"` included (the runtime would fold its first letter; nothing here folds or maps), is refused (`CONFIG_BONE_INHERIT`), and a chain takes no `inherit` (`CONFIG_KEY_KNOWN`). Its setup rotation is the turn from where rig-c's own poser puts the bone with no rotation of its own under that mode, so it still stands upright (or along its tip) at the setup pose. Where the idle gives the bone a `<bone>_ctl`, the mode goes on the control: the control is the bone the parent's rotation reaches, and the bone under it inherits normally, so the idle's keys moved onto the control still turn it. A foot that does not take its shin's rotation (`noRotationOrReflection` or `onlyTranslation`) keeps its shoe level while the leg is posed (`FEET_STAY_LEVEL`, §7); which mode is the author's. An automatic mesh weighted through a bone with a mode other than `normal` gets no derived amplitude (its row names the bone) and no residual envelope (rig-c's `SKINNING_RANGE_UNSUPPORTED`). Absent, `rig.json` carries no `inherit` and no byte moves |
|
|
111
|
+
| `bones` | rig; `propose --from-config` | **proposed** by `propose`, then corrected. A single bone `{name, parent, at, tip?}` or a chain `{chain, parent, points, tip, link_inherit?}` whose links are named `<chain>0 … <chain>n`. Parents come before children. In `rig.json` each link is **turned along its chain** — `rotation` is the direction from its origin to the next link's (the last link's to `tip`) and `length` that distance (issue #73), so a physics constraint added downstream finds a lever; under `--idle-keys ctl` the link's `<link>_ctl` carries the turn and the length and the link sits at local rotation 0 beneath it. A single bone with a `tip` is turned the same way, towards its tip, with that distance as its length (issue #239); a tip on the bone's own origin is refused (`RIG_TIP_DISTINCT`). The five face bones `eye_r`, `eye_l`, `brow_r`, `brow_l` and `mouth` (by name, when one has no tip of its own) are turned to the eye line — the line through the origins of `eye_r` and `eye_l` as `bones` writes them, read image-left to image-right, drawn when parts.json holds both an `eyewhite-r` and an `eyewhite-l` part — so the blink's `scaley` squashes across the eye line on a tilted head; move an eye bone and the line moves with it. With one eyewhite or none, or an eye bone missing, the rig stage's `face axis:` line says so and they keep the page's axes. A bone under a face bone keeps the face's axis. With the line, `rig.json` also declares `invariants.axes` — one entry, `"face"`, through `eye_r` and `eye_l`, holding the turned face bones (and their controls) — so rig-c's gate holds the build to the line; the line is the one rigc draws through the same two bones, so the tolerance is only the float floor — the largest gap the emitted (float32) bones have to it, rounded up to 6 places plus one 6-place unit — and the `face axis:` line prints it. With the line the rig stage also adds `head_up` (issue #250): a slotless bone under `head`, at head's origin, turned to the eye line + 90 degrees and as long as the eye midpoint lies from head's origin along that axis — the head's frame, which a rule that needs it reads; `head` keeps its own frame, so no key on it or under it changes meaning, and a config bone of that name is refused (`RIG_HEAD_UP_NAME_FREE`). A face bone with its own `tip` is held too (issue #258), in a second entry, `"face_tips"`, when its tip lies along the line within whole-pixel rounding — a tip written in whole pixels sits at most sqrt(2)/2 px off the point of the line it stands for, so its direction may sit up to asin((sqrt(2)/2) / length) degrees off — with its tolerance measured the same way; a tip further off is the bone's own axis, and the `face axis:` line names it with its gap and that bound. A failure is rig-c's `A51_BONES_LIE_ALONG_THEIR_DECLARED_AXIS` line, which names the bone and the fix (rig-c's `docs/AUTHORING.md` §3.7 and §5.2); with no line no entry is written and A51 reports SKIP. Every region on a turned bone is turned back, so the setup pose does not move. Any other single bone keeps world rotation 0; one whose parent is a link is turned back upright. A single bone may declare `inherit` (issue #348): what it takes from its parent's transform, one of rig-c's own mode names exactly as rig-c's table spells them — `normal`, `onlyTranslation`, `noRotationOrReflection`, `noScale`, `noScaleOrReflection` (rig-c's `RigBone.inherit`) — written to that bone in `rig.json` as declared; any other spelling, `"NoScale"` included (the runtime would fold its first letter; nothing here folds or maps), is refused (`CONFIG_BONE_INHERIT`), and a chain takes no `inherit` (`CONFIG_KEY_KNOWN`). A chain may instead declare `link_inherit` (issue #369), an object mapping its own expanded link names to those same modes, for example `"link_inherit": {"leg_r1": "noScale"}`. Only the named link changes; omitted links inherit normally. A key outside this chain is `CONFIG_NAME_RESOLVES`, with this chain's valid link names in the detail; a non-object or non-string mode is `CONFIG_FIELD_TYPE`, and another mode spelling is `CONFIG_BONE_INHERIT`. The mode is forwarded to the expanded link, or to its control under `--idle-keys ctl`, by the same rule as a single bone. This is an authored opt-in: `propose` does not add it. Its setup rotation is the turn from where rig-c's own poser puts the bone with no rotation of its own under that mode, so it still stands upright (or along its tip) at the setup pose. Where the idle gives the bone a `<bone>_ctl`, the mode goes on the control: the control is the bone the parent's rotation reaches, and the bone under it inherits normally, so the idle's keys moved onto the control still turn it. A foot that does not take its shin's rotation (`noRotationOrReflection` or `onlyTranslation`) keeps its shoe level while the leg is posed (`FEET_STAY_LEVEL`, §7); which mode is the author's. `noScale` keeps a shin or shoe's shape under a scaled parent but still takes the parent's rotation: a shoe that must also stay level needs a separate rotation constraint, for example a transform constraint from an unrotated bone. This does not change the proposed feet's existing inheritance or `FEET_STAY_LEVEL` default. An automatic mesh weighted through a bone with a mode other than `normal` gets no derived amplitude (its row names the bone) and no residual envelope (rig-c's `SKINNING_RANGE_UNSUPPORTED`). Absent, `rig.json` carries no `inherit` and no byte moves |
|
|
112
112
|
| `meshes.<part>` | rig | **proposed**, then corrected. Exactly one of `grid` (the lattice: cell size, px — what `propose` writes: by default one spacing for the figure, round(H / 37) rig px with H the height of every part's box together, a part whose tenth of its short side is already coarser keeping that, and under `propose --grid-rule part` the reference's tenth of the part's short side clamped to 5..36, issue #265), `contour` (the outline mode, authored; the next row and "A contour mesh" below) or `auto` (the automatic mode, authored; "An automatic mesh" below) — two, or none, is `CONFIG_MESH_MODE`. In every mode: `r` (added to every distance before weighting: `w = 1/(d + r)²`), `segments` (a chain name, a bone name with a `tip`, or `[bone, [x0,y0], [x1,y1]]`), and, **authored**, optional, `exponent` (issue #161): a number above 0 that replaces the 2 in that rule, `w = 1/(d + r)^exponent` — a larger one hands each vertex more fully to its nearest bone; absent is 2 and changes no byte, a value that is not a number above 0 is `CONFIG_FIELD_TYPE` at `meshes.<part>.exponent`, and a declared one is echoed as `exponent` in the mesh's `mesh_report.json` row; the exponent is the distance rule's, so declared beside `rule: "heat"` it is refused (`CONFIG_FIELD_TYPE` at `meshes.<part>.exponent`). The segment list is the one authored decision about a layer: which bones may pull it. The slot's bone is the first segment's. Optional `rule` (issue #161): `"distance"` — the rule above, and what an absent `rule` means (every byte is the same) — or `"heat"`, bone heat over the part's own silhouette, in every mode: the lattice's art (alpha above 8, less any island a declared `stray` left out) with holes filled, or for `contour` and `auto` the silhouette their outline is traced from (that mode's art — alpha above 8 for `contour`, alpha 1 and above for `auto` — less any island a declared `stray` left out, holes filled, grown by its `margin`); each bound bone's sources are the silhouette pixels whose centre lies within 0.75 px of its segment (a pixel two bones reach goes to the nearer, a tie to the first listed), held at 1 for that bone and 0 for the others; the field is solved by row-major Gauss–Seidel over-relaxation to a sweep change under 1e-7 within 20000 sweeps; a vertex reads the nearest silhouette pixel and takes the same cap and floor (and `regions`) as the distance rule; `r` is not read. The mesh's `mesh_report.json` row gains `heat` (the constants, each bone's sources and sweeps, the residual). Any other value is `CONFIG_FIELD_TYPE`; a bound bone with no source pixel is `RIG_HEAT_BONE_SOURCE`, an island no bone has a source in `RIG_HEAT_ISLAND_SOURCE`, a solve past its sweep bound `RIG_HEAT_CONVERGED` — none is weighted 0. The rule is chosen per mesh, so `RIG_HEAT_BONE_SOURCE` names three remedies: move the segment onto the art, take the bone out of `segments`, or keep this part on the distance rule — the one to take when the bone anchors the part from outside its art (a torso bone under a neck), since the first moves a bone another part placed and the second drops the anchor (issue #303). On a lattice, `RIG_HEAT_ISLAND_SOURCE` on an island that is dust — at most 4 px and at most 0.1 % of the part's art px, `mesh-draft`'s line — names `meshes.<part>.stray` and the figure that leaves it out, with the value declared; an island above that line keeps the segment remedy, a real piece being a real authoring question |
|
|
113
113
|
| `meshes.<part>.contour` | rig | **authored**, optional (issue #84): `{tolerance, margin, spacing, maxEdge?, budget?, stray?, bridges?, regions?}`. `tolerance` — rig-c's Douglas–Peucker tolerance on the traced outline, px, 0 or more; `margin` — how far the silhouette grows before it is traced, px: 0, or 1 or more (a pixel joins when its centre lies within `margin` of an art pixel's centre; a value above 0 and below 1 adds nothing and is refused, `CONFIG_FIELD_TYPE`); `spacing` — the background interior spacing, px, above 0; `maxEdge` (issue #265) — the longest outline edge, px, above 0: every simplified edge longer than it is cut into `ceil(length / maxEdge)` equal pieces, each cut point on the 1/256 px grid, before any region or rib touches the outline (absent: nothing is cut, and no byte moves; under 2/256 px the rig stage refuses it, `CONTOUR_PARAMETER`, because two cut points could snap together); the row echoes it in `params` and counts the points it added in `contour.outlineCut`, both only when declared; `budget` — the most vertices the mesh may have (refused above it, nothing thinned); `stray` — the largest island, in art pixels, that may be left out of the mesh (absent: none is); `bridges` (issue #326) — `true`, its one value: islands are read in this order — **dust first** (those `stray` leaves out), **then faint islands** (every pixel's alpha under 64, a quarter of full opacity: left out the same way, their pixels kept in the image but not meshed, so not drawn, and named in the row's `contour.bridges.faint` with their px, brightest alpha and box), **then every visible island is meshed and bridged, whatever the bridge costs** — overdraw is reported, never a reason to drop art; the largest island, or a tie for it, is never left out, faint or not: dropping it would draft the part without its art, and a part whose main body is faint is a question about the layer, which the plan and the author own, not one for the mesh — and the pieces are joined into the one outline rig-c takes by bridges — the kept islands, holes filled, grow together by `margin`, so islands closer than about twice the margin are one grown silhouette, traced as one; each silhouette is traced, simplified, capped, refined and triangulated as a one-island mesh is; then, starting from the silhouette with the most art, the nearest pair of a vertex on the joined outline and one on a silhouette still apart whose quad holds (wound as the mesh, crossing no outline, holding no other vertex, one closed outline after) is joined by that quad, two triangles over no art, until none is apart. Coverage and overshoot read the silhouettes' triangles; a bridge's area is in `meshArea` and in the row's `contour.bridges` (`islands`, `units`, and per join `unit`, `span` — its two crossing edges, px — `area`, `vertices`, `pair`; and `faint`, only when an island was left out as faint), and the row's `params` echoes `bridges`, both only when declared; `art_coverage` counts a faint island's pixels as art not covered. Absent, a second island is refused as below and no byte moves; on one island it writes the mesh the undeclared entry writes. Any other value is `CONFIG_FIELD_TYPE`; beside `ribs` it is `CONTOUR_PARAMETER` (a rib runs across one outline); a join no pair makes is `CONTOUR_BRIDGE`. A bridge stretches with whatever pulls its two ends apart, so it belongs on a part whose pieces ride one bone — the only case `mesh-draft` drafts; `regions` — local deformation regions, each `{name, shape, bone, spacing, band}` with `shape` `"circle"` (`cx, cy, r`) or `"polygon"` (`points`, 3 or more): `bone` is the region's control bone (any bone `bones` declares), `spacing` the interior spacing inside the region and its band, `band` the width the bone's weight falls across. Every length and position is **rig px**, like every other in the config; the part image is the rig less `(x − 4, y − 4)` (its box less the pad), a translation, so a length is the same number in both. A region's `cx`, `cy`, `r`, `band` and `points` are multiples of 1/256 px (`CONFIG_FIELD_TYPE` otherwise); region names are unique per mesh (`CONFIG_REGION_NAME_UNIQUE`). The alpha threshold is not a field: art is alpha above 8, the lattice's and `check`'s |
|
|
114
114
|
| `meshes.<part>.ribs` | rig | **authored**, optional (issue #188), in the `contour` and `auto` modes: `{<chain>: {stations}, …}`, each key a chain this mesh's `segments` name. Each link of the chain gets a row of vertices across the part at its origin and at `stations` points evenly between its origin and its end (`stations`, a whole number, 0 or more, required; a chain of L links carries L × (stations + 1) ribs), each rib a row of vertices across the part, kept as a row of locked edges; the rule is "Ribs along a chain" under "A contour mesh". Absent places none and changes no byte. Refused: a lattice mesh with ribs (`CONFIG_RIBS_MODE` — its vertices are its grid's corners), a key that is not one of the mesh's chains (`CONFIG_NAME_RESOLVES`), an object naming no chain or a `stations` that is not a whole number from 0 (`CONFIG_FIELD_TYPE`); at the rig stage `CONTOUR_RIB_ART`, `CONTOUR_RIB_LINK`, `CONTOUR_RIB_CROSSING`, `CONTOUR_RIB_EDGE` (the contour refusals). The mesh's `mesh_report.json` row gains `ribs` — the declaration, the ribs placed and the vertices they hold — and its contour report (the source's, in `auto`) lists each rib's vertices |
|
|
@@ -121,9 +121,11 @@ read by no CPU stage).
|
|
|
121
121
|
| `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`) |
|
|
122
122
|
| `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, 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 |
|
|
123
123
|
| `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 |
|
|
124
|
+
| `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`) | **authored**, optional (issue #404): `[{chain, links?, against, at, inward, outward, lower?: {inward, outward}}]` — rig-c's leg stops (`RigStop`, rig-c 2.56.0, `rig-c/src/stop.ts`). `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`); `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 — is rigc's to accept or refuse at the rig stage's gate, in rigc's words (`RIG_RIGC_GREEN`). 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 |
|
|
124
125
|
| `turn` | rig (adds the turn control) | **proposed** only with `propose --full`/`--head` (issue #251), then corrected: `{pivot, depths}`. `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. With no `face` part, or more than one, the riders keep their own and a note says so. 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. 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 field has a default (`CONFIG_FIELD_PRESENT`); the pivot must lie behind the nearest part (`CONFIG_TURN_PIVOT_BEHIND_NEAREST`). Absent, no control is added and no byte of any output moves |
|
|
125
126
|
| `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 |
|
|
126
|
-
| `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?}`. `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 name: the `topwear` part that holds a skirt See-through returned inside it (a dress), which takes the skirt's trees
|
|
127
|
+
| `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?}`. `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 |
|
|
128
|
+
| `proposed_rig_scale` | assemble, rig, build, `propose --from-config`/`--compare` | **proposed** by `propose` (issue #354): `parts.json`'s `scale_rig_per_source`, the `assemble.rig_scale` the rig sections (`bones`, `meshes`, `limbs`, `motion`) were drafted at. Held equal to `assemble.rig_scale` when present (`CONFIG_PROPOSED_RIG_SCALE`; 0, negative or not a number: `CONFIG_FIELD_TYPE`). Absent on a hand-authored config, where no byte of any output moves |
|
|
127
129
|
|
|
128
130
|
**A scene target is an ordinary bone.** A target the scene places — a point a hand
|
|
129
131
|
reaches for, a face something turns toward — is a single bone parented to `root`,
|
|
@@ -1583,13 +1585,13 @@ What each rule drafts (`src/cloth.ts` holds them):
|
|
|
1583
1585
|
| rule | drafts | from |
|
|
1584
1586
|
| --- | --- | --- |
|
|
1585
1587
|
| where | `bottomwear`: from `hip`, the root row 20 px below hip's y (the keyed chains' row), the tip row 4 px above the part's bottom. `back hair` that reaches below the shoulders: from `head`, per side of the eye axis (twin tails are a side each), the eye line to 4 px above its bottom. `front hair`: each strand that hangs below the chin (the lock rule's), from `head`, 0.22 face heights above the eye line to 5 px below the strand; the fringe's three columns keep their two links and their places | the keyed chains' own rows, which these replace |
|
|
1586
|
-
| trees | tree k of `chains` owns the cell k/N .. (k+1)/N of the art's width in every row, and its links sit at the cell's centre in the 24-row band there, so a piece that widens fans its trees. With `split`, the trunk's tip is the fork, and branch b of `into` follows the centre of its share of the cell. Chains are named `<prefix><k>_` (trunk) and `<prefix><k><a, b, …>_` (branches): `skirt`, `hairback_r`/`hairback_l`, `lockt` | `chains`, `links`, `split` |
|
|
1588
|
+
| trees | tree k of `chains` owns the cell k/N .. (k+1)/N of the art's width in every row, and its links sit at the cell's centre in the 24-row band there, so a piece that widens fans its trees. On `back hair`, `chains` is optional (issue #390): when omitted, `propose --cloth` derives the largest tree count per side up to 2 (`RECIPE_BACK_HAIR_CHAINS`) that fits the narrower side's opaque width at the eye-line root row (`max(1, min(floor(w_r / grid), floor(w_l / grid)))`) and places every root inside the 15 px dilated art mask; an explicit `chains` that exceeds that width cap or places a root off the art is refused (`PROPOSE_CLOTH_BACK_HAIR_CHAINS`). With `split`, the trunk's tip is the fork, and branch b of `into` follows the centre of its share of the cell. Chains are named `<prefix><k>_` (trunk) and `<prefix><k><a, b, …>_` (branches): `skirt`, `hairback_r`/`hairback_l`, `lockt`. With `split.hold_tip: true` (issues #403, #392), sibling branches keep `strength.branch` across the fork, the mesh's `r` is raised to `grid`, and the rig stage blends each fork's sibling branch weight shares across four passes of 1-ring mesh-edge averaging (self weight 0.5, floor 0.005, cap 8 influences) with trunk and fixed shares held in place, holding the triangles where two branches' cells meet | `chains`, `links`, `split` |
|
|
1587
1589
|
| lengths | link j's length is the first's times q^j, q = `length_ratio`^(1/(links − 1)), the whole spanning root row to tip row: the links shorten toward the tip | `length_ratio` (default 0.5, below) |
|
|
1588
|
-
| stiffness | a trunk link takes `strength.trunk`, a branch link `strength.branch`, and the edge — the outermost branch on each outer side of the piece (both sides of a skirt or a strand; the outer side of each back-hair side), or without `split` the outermost tree — `strength.edge`; a fringe column is a trunk, its outer two the edge. **Strength does not fall along a chain**: a tip reads soft because each link turns on top of every link above it, so the motion accumulates down the chain at one strength. Only the edge is declared softer | `strength` (default trunk 100, branch 100, edge 50, below) |
|
|
1590
|
+
| stiffness | a trunk link takes `strength.trunk`, a branch link `strength.branch`, and the edge — the outermost branch on each outer side of the piece (both sides of a skirt or a strand; the outer side of each back-hair side; or, under `split.hold_tip: true` with `strength` left out, kept at `strength.branch` so a fork's sibling branches do not pull apart at the default 2:1 stiffness), or without `split` the outermost tree — `strength.edge`; a fringe column is a trunk, its outer two the edge. **Strength does not fall along a chain**: a tip reads soft because each link turns on top of every link above it, so the motion accumulates down the chain at one strength. Only the edge is declared softer | `strength` (default trunk 100, branch 100, edge 50, below) |
|
|
1589
1591
|
| response | link j of an n-link path takes `wind` and `gravity` at j/(n − 1) of the way from the root value to the tip value; a single-link path takes the tip value. Each is a scalar **multiplier** of the environment the consumer sets (spine-core's skeleton `windX, windY`, `gravityX, gravityY`; rig-c 2.52.0's live track `setEnvironment`, rig-play 1.10.0's `environment()`): no direction is drafted | `wind`, `gravity` |
|
|
1590
1592
|
| out of phase | the odd trees take `alternate_damping`, the even ones `damping` | `damping`, `alternate_damping` |
|
|
1591
1593
|
| flutter | the last link of every path gets a second physics constraint, `<bone>_translate`, moving x and y by `translate`, with the link's stiffness and damping and **no** wind or gravity response. spine-core scales a translate spring's response by the skeleton's reference scale (100) and a rotation's by the link's length over it, so one response on both pushes an end about 100/length times further than it turns it (the table below) | `translate` |
|
|
1592
|
-
| part | `bottomwear` only (issue #402): the named `topwear` part takes the skirt's rule as the `bottomwear` parts do — trees from `hip` over its art below the hip, its waist line, and, as its art reaches above the chest, the chest segment the long-robe `bottomwear` keeps — in place of the two robe chains the topwear rule drafts; the prefix is `skirt` when it is the only skirt, `skirt_<part>` beside another | `part` |
|
|
1594
|
+
| part | `bottomwear` only (issue #402): the named `topwear` part takes the skirt's rule as the `bottomwear` parts do — trees from `hip` over its art below the hip, its waist line, and, as its art reaches above the chest, the chest segment the long-robe `bottomwear` keeps — in place of the two robe chains the topwear rule drafts; the prefix is `skirt` when it is the only skirt, `skirt_<part>` beside another. A `bottomwear` part lying on the named part's tree links rides them and drafts no trees of its own (issue #416, *What rides a dress* below) | `part` |
|
|
1593
1595
|
| swing | `bottomwear` only: a bone `<prefix>_swing` under `hip` at the centre of the root row, one link long, straight down, with physics (the trunk's stiffness, the root's response); each tree's first link takes the swing's rotation times its scale — a transform `<swing>_<k>`, local source and target, additive, the swing's setup rotation in hip's frame (−90: hip is drafted unturned) subtracted — and no physics of its own | `swing.scales` |
|
|
1594
1596
|
|
|
1595
1597
|
Every link but a swing-driven first link gets `<bone>_physics` (`rotate` 1), and no
|
|
@@ -1623,6 +1625,39 @@ Since issue #411 the bar reads the breath alone, and on that fixture the breath
|
|
|
1623
1625
|
the dress 0.106 and the robe-chained dress 2.62: both fail, and the 3.9 was the robe
|
|
1624
1626
|
chains' keyed swing below the hip, not the breath (the CK502 and CK503 controls).
|
|
1625
1627
|
|
|
1628
|
+
**A skirt cut at the waist (issue #412).** `cloth.bottomwear.part` resolves the exact
|
|
1629
|
+
name in the assembled `parts.json`, after `assemble.cuts`. It may name the lower
|
|
1630
|
+
piece cut from a `topwear` dress, for example `"part": "skirt_piece"` for a cut
|
|
1631
|
+
`from: "dress", into: "skirt_piece"`. The piece keeps `cut_from: "dress"` and its
|
|
1632
|
+
source tag; it receives the same skirt recipe over its own art. When that art starts
|
|
1633
|
+
below chest, the existing waist-hung rule omits the chest segment. The retained
|
|
1634
|
+
bodice, when it stops above the waist line, keeps its trunk segments without robe
|
|
1635
|
+
chains falling below its art. This names one target: other cut pieces remain
|
|
1636
|
+
excluded from automatic tag rules, and an unknown name, a non-topwear source or a
|
|
1637
|
+
target ending above the waist line is still `PROPOSE_CLOTH_PART`. Without `part`,
|
|
1638
|
+
cut selection and proposals are unchanged. The named piece also carries an
|
|
1639
|
+
overlapping hem by the same rule below.
|
|
1640
|
+
|
|
1641
|
+
**What rides a dress** (issue #416). With `part` declared, a `bottomwear` part lying on
|
|
1642
|
+
the dress — a ruffle hem See-through returned as a layer of its own — rides the dress's
|
|
1643
|
+
tree links by the rule a part wrapped round a tail does (*What rides a tail*, below): each
|
|
1644
|
+
of its pixels over the dress's art is given to the span of the dress's mesh nearest it
|
|
1645
|
+
(a fixed segment, chest or the waist line, or one tree link), and the part rides when one
|
|
1646
|
+
of those spans is a link. Its mesh's segments are then the spans it lies on, it drafts
|
|
1647
|
+
no trees of its own, and a note names each span with its pixel count; a `bottomwear` part
|
|
1648
|
+
over no link keeps its own trees. Before, the hem took the skirt's recipe by its tag as
|
|
1649
|
+
well, so one skirt carried two sets of trees, each on its own physics. Measured once on
|
|
1650
|
+
the selftest's dress fixture with a 112x26 hem across its last tier (`fixtures/cloth.ts`,
|
|
1651
|
+
`HEM`; the hip from joints at y 164; rig-c 2.54.0, `check`'s idle, physics on), before
|
|
1652
|
+
this rule and with it: the trees drafted went from four (`skirt_hem0_`, `skirt_hem1_`,
|
|
1653
|
+
`skirt_dress0_`, `skirt_dress1_`) to two (`skirt0_`, `skirt1_`), and their physics
|
|
1654
|
+
constraints from 8 to 4; `TEXTURE_STRETCH` read 1.275 both ways (its worst mesh is the
|
|
1655
|
+
back hair), the hem's own mesh 1.034 with its own trees and 1.045 riding, and the largest
|
|
1656
|
+
opening of the hem's seam with the dress 0.502 and 0.432 px (CK510 holds the one set and
|
|
1657
|
+
the pass). The hip rule still reads a `bottomwear` part's top edge as the waist, so a
|
|
1658
|
+
hem and no hip joints put the hip at the hem: on the same fixture without joints, y 277,
|
|
1659
|
+
and the dress's trees run up from y 297 to 286. Without `part` nothing here runs.
|
|
1660
|
+
|
|
1626
1661
|
**What rides a tail** (issue #391). An accessory wrapped round a tail the `back hair`
|
|
1627
1662
|
recipe drafts — a ribbon, in See-through's `headwear` or `earwear` layer — rides that
|
|
1628
1663
|
tail's links, not `head`: under the recipe the tail moves by the world, and a part left on
|
|
@@ -1798,7 +1833,7 @@ full loader before its assemble stage writes anything.
|
|
|
1798
1833
|
no later stage can see — then
|
|
1799
1834
|
`rig-parts propose --parts work/rig --source inputs/painting.png --out work` →
|
|
1800
1835
|
`work/proposal.json` and `work/render/landmarks.png` (+ `_head`). Copy
|
|
1801
|
-
each of `bones`, `meshes`, `regions`, `limbs`, `motion`, `constraints` and `
|
|
1836
|
+
each of `bones`, `meshes`, `regions`, `limbs`, `motion`, `constraints`, `turn` and `proposed_rig_scale` it
|
|
1802
1837
|
wrote into the config: `limbs` is written only with `--keypoints`, `constraints`
|
|
1803
1838
|
only with `--cloth` and `turn` only with `--full`/`--head` (`PROPOSAL_CONFIG_SECTIONS` in `src/propose.ts` is the list,
|
|
1804
1839
|
and the selftest's `TY18` holds this sentence to it). A `limbs` block left out
|
|
@@ -2566,14 +2601,14 @@ See-through with another seed.
|
|
|
2566
2601
|
| rule | means | change |
|
|
2567
2602
|
| --- | --- | --- |
|
|
2568
2603
|
| <a id="CONFIG_FILE_PRESENT"></a><a id="CONFIG_IS_JSON"></a>`CONFIG_FILE_PRESENT`, `CONFIG_IS_JSON` | no such file, or not JSON | `--config` |
|
|
2569
|
-
| <a id="CONFIG_KEY_KNOWN"></a><a id="CONFIG_KEY_RETIRED"></a><a id="CONFIG_FIELD_PRESENT"></a><a id="CONFIG_FIELD_TYPE"></a>`CONFIG_KEY_KNOWN`, `CONFIG_KEY_RETIRED`, `CONFIG_FIELD_PRESENT`, `CONFIG_FIELD_TYPE` | an unknown key (a retired one says what replaces it), a missing one, a wrong type; a project's own record under a plain key, or an annotation (`note`, `<name>_note`) holding something other than a string; in `meshes.<part>.auto` (§3, *An automatic mesh*), a missing or out-of-range number, a Stage B opt-in that is not exactly a value rig-c accepts, or a field the mode does not have — a bound on one of the five allocation rows, or an authored `motionAmplitude` (it is derived, never written); under `comfy paint`, `CONFIG_FIELD_PRESENT` on `config.generation`: a config with no `generation` block (the line names the fields it holds) | the named field; a record goes under a key beginning `x-` (any JSON, read by nothing), a remark under `note` or `<name>_note` (a string) — §3; under `comfy paint`, `config.generation` |
|
|
2604
|
+
| <a id="CONFIG_KEY_KNOWN"></a><a id="CONFIG_KEY_RETIRED"></a><a id="CONFIG_FIELD_PRESENT"></a><a id="CONFIG_FIELD_TYPE"></a>`CONFIG_KEY_KNOWN`, `CONFIG_KEY_RETIRED`, `CONFIG_FIELD_PRESENT`, `CONFIG_FIELD_TYPE` | an unknown key (a retired one says what replaces it), a missing one, a wrong type (`bones[i].link_inherit` must be an object whose values are strings); a project's own record under a plain key, or an annotation (`note`, `<name>_note`) holding something other than a string; in `meshes.<part>.auto` (§3, *An automatic mesh*), a missing or out-of-range number, a Stage B opt-in that is not exactly a value rig-c accepts, or a field the mode does not have — a bound on one of the five allocation rows, or an authored `motionAmplitude` (it is derived, never written); under `comfy paint`, `CONFIG_FIELD_PRESENT` on `config.generation`: a config with no `generation` block (the line names the fields it holds) | the named field; a record goes under a key beginning `x-` (any JSON, read by nothing), a remark under `note` or `<name>_note` (a string) — §3; under `comfy paint`, `config.generation` |
|
|
2570
2605
|
| <a id="CONFIG_KEY_UNIQUE"></a>`CONFIG_KEY_UNIQUE` | a key written twice in one object of a file the config names — the pose file `generation.control.skeleton` names, or the `motion.animations_from` file; JSON keeps only the last value, so every other would be dropped without a word | that file: each key once |
|
|
2571
2606
|
| <a id="CONFIG_ANIMATION_NAME_FREE"></a>`CONFIG_ANIMATION_NAME_FREE` | the `motion.animations_from` file holds an animation named `idle`, the animation `config.motion` writes | rename that animation |
|
|
2572
2607
|
| <a id="CONFIG_HEAD_BOX_SQUARE"></a>`CONFIG_HEAD_BOX_SQUARE` | `seethrough.head_box` is not a non-empty square | `head_box` — take `propose --head-box`'s |
|
|
2573
2608
|
| <a id="CONFIG_TAG_KNOWN"></a><a id="CONFIG_PART_NAME"></a><a id="CONFIG_PART_UNIQUE"></a>`CONFIG_TAG_KNOWN`, `CONFIG_PART_NAME`, `CONFIG_PART_UNIQUE` | a plan or extend entry names neither a v3 tag nor `author:<label>` (an `author:` tag with a malformed label says what the label must be), a part name that is not a file name, or a part or layer twice — a patch named like a plan part or another patch, and a cut's `into` named like a plan part, a patch or another cut's, included | `assemble.plan`, `assemble.patches`, `assemble.cuts` |
|
|
2574
|
-
| <a id="CONFIG_NAME_RESOLVES"></a>`CONFIG_NAME_RESOLVES` | a parent, segment, region, track, blink member, blink still part or bone, extend part, patch or cut `draw.before`, or cut `from` names nothing declared above it (a cut's `from` must be a plan part); or a constraint's `bones`, `target`, `source` or `bone` names a bone `bones` does not declare (the detail names the constraint and lists the bones that exist); in `meshes.<part>.auto`, a bone or region name nothing declares | the named reference, or the declaration it needs |
|
|
2609
|
+
| <a id="CONFIG_NAME_RESOLVES"></a>`CONFIG_NAME_RESOLVES` | a parent, segment, region, track, blink member, blink still part or bone, extend part, patch or cut `draw.before`, or cut `from` names nothing declared above it (a cut's `from` must be a plan part); or a constraint's `bones`, `target`, `source` or `bone` names a bone `bones` does not declare (the detail names the constraint and lists the bones that exist); in `meshes.<part>.auto`, a bone or region name nothing declares; or `bones[i].link_inherit` names a link outside its own chain (the detail lists that chain's expanded links) | the named reference, or the declaration it needs |
|
|
2575
2610
|
| <a id="CONFIG_BONE_UNIQUE"></a>`CONFIG_BONE_UNIQUE` | a bone or chain declared twice, or `root` declared | `bones` |
|
|
2576
|
-
| <a id="CONFIG_BONE_INHERIT"></a>`CONFIG_BONE_INHERIT` | a single bone's `inherit` is a string that is not one of rig-c's five mode names as its table spells them (issue #348); the line lists all five. `"NoScale"` is refused too: the runtime would fold the first letter, and this loader folds and maps nothing | `bones[i].inherit` — `normal`, `onlyTranslation`, `noRotationOrReflection`, `noScale` or `noScaleOrReflection` (§3, `bones`) |
|
|
2611
|
+
| <a id="CONFIG_BONE_INHERIT"></a>`CONFIG_BONE_INHERIT` | a single bone's `inherit`, or a chain's `link_inherit.<link>`, is a string that is not one of rig-c's five mode names as its table spells them (issue #348); the line lists all five. `"NoScale"` is refused too: the runtime would fold the first letter, and this loader folds and maps nothing | `bones[i].inherit` or `bones[i].link_inherit.<link>` — `normal`, `onlyTranslation`, `noRotationOrReflection`, `noScale` or `noScaleOrReflection` (§3, `bones`) |
|
|
2577
2612
|
| <a id="CONFIG_LIMB_BONE"></a><a id="CONFIG_LIMB_BONES_CHAIN"></a><a id="CONFIG_LIMB_FROM_RUN"></a><a id="CONFIG_LIMB_RANGE"></a>`CONFIG_LIMB_BONE`, `CONFIG_LIMB_BONES_CHAIN`, `CONFIG_LIMB_FROM_RUN`, `CONFIG_LIMB_RANGE` | `config.limbs` (issue #349): a limb part's `regions` entry names a bone other than its segment's; a segment's bone is not the child of the segment above's (the lower segment turns about the joint on a bone that hangs from the upper's); two segments of one limb take one part with another part between them; a `range` without `min <= 0 <= max` | `regions.<part>` the segment's `bone`; `bones` (parent the lower bone under the upper) or the segment's `bone`; the segments' order or `from`; the `range` (degrees from rest, rest in it) |
|
|
2578
2613
|
| <a id="CONFIG_PART_ATTACHED"></a>`CONFIG_PART_ATTACHED` | a plan part or a cut's piece with neither or both of a mesh and a region; a patch with a mesh, or with no region | `meshes` / `regions` |
|
|
2579
2614
|
| <a id="CONFIG_RIBS_MODE"></a>`CONFIG_RIBS_MODE` | `meshes.<part>.ribs` on a lattice (`grid`) mesh: its vertices are its grid's corners, which no row can move (issue #188) | put the part in `contour` or `auto`, or remove `ribs` |
|
|
@@ -2598,6 +2633,7 @@ See-through with another seed.
|
|
|
2598
2633
|
| <a id="CONFIG_CLOTH_PART_ON_BOTTOMWEAR"></a>`CONFIG_CLOTH_PART_ON_BOTTOMWEAR` | `part` on a `cloth` recipe for a tag other than `bottomwear` (issue #402) | leave it out there; `part` hands the skirt's recipe to a `topwear` part that holds a skirt (a dress) |
|
|
2599
2634
|
| <a id="CONFIG_CLOTH_SPRING_STABLE"></a>`CONFIG_CLOTH_SPRING_STABLE` | a `cloth` recipe's strength — declared, or the default 100 / 100 / 50 — whose spring is unstable at a damping the recipe runs at (`damping`, `alternate_damping`, or rig-c's 0.85 when `damping` is left out): k = strength·massInverse·step² at or past 2(1 + damping^(60·step)), step 1/60 and mass 1 (rig-c's defaults; the recipe sets neither). The detail gives k and the bound | a lower strength, or a higher damping |
|
|
2600
2635
|
| <a id="CONFIG_TURN_BONE_FREE"></a>`CONFIG_TURN_BONE_FREE` | the config has `turn` and `bones` declares a bone named `turn`, the control the rig stage adds | rename that bone |
|
|
2636
|
+
| <a id="CONFIG_PROPOSED_RIG_SCALE"></a>`CONFIG_PROPOSED_RIG_SCALE` | `proposed_rig_scale` (the `scale_rig_per_source` `propose` drafted the rig sections at, issue #354) differs from `assemble.rig_scale`: the coordinates in `bones`, `meshes`, `limbs` and `motion` are in that rig canvas's pixels and do not scale when `assemble.rig_scale` changes | re-run `assemble` and `propose` at the new `assemble.rig_scale`, or restore `assemble.rig_scale` to `proposed_rig_scale` |
|
|
2601
2637
|
|
|
2602
2638
|
### inputs
|
|
2603
2639
|
|
|
@@ -2678,7 +2714,8 @@ says why each requirement exists and what breaks without it.
|
|
|
2678
2714
|
| <a id="PROPOSE_CUT_FROM_RECORDED"></a>`PROPOSE_CUT_FROM_RECORDED` | two parts share one layer and none of them records `cut_from`: a `parts.json` an `assemble` before 1.6.0 wrote with `assemble.cuts`. The records are in draw order, so which is the plan part and which the piece cannot be read off the file; the message names the parts and the layer. Every other reader still takes the file | `--parts`: re-run assemble (1.6.0+) to record `cut_from` |
|
|
2679
2715
|
| <a id="PROPOSE_LIMB_PARTS"></a>`PROPOSE_LIMB_PARTS` | `parts.json` holds parts `config.limbs` cut at their joints (issue #349); the limbs are drafted from the parts before the cut, which the rules read by layer | `--parts` a build assembled with the config's `limbs` left out; keep the block the config holds (its caps and ranges are the author's). `propose --from-config` reads the config's bones on either build |
|
|
2680
2716
|
| <a id="PROPOSE_CLOTH_DRAFTED"></a>`PROPOSE_CLOTH_DRAFTED` | with `--cloth` (issue #364): the config's `cloth` block holds a recipe for a tag the proposer drafts no chain on — no part has that tag, or every `back hair` part ends above the shoulders (a bun bone, no chain). A `bottomwear` recipe with no `bottomwear` part names every `topwear` part shaped like a skirt (issue #402) | leave that recipe out, or assemble the layer it is for, or declare the named part in `cloth.bottomwear.part` |
|
|
2681
|
-
| <a id="PROPOSE_CLOTH_PART"></a>`PROPOSE_CLOTH_PART` | with `--cloth` (issue #402): `cloth.bottomwear.part` names no part, a part
|
|
2717
|
+
| <a id="PROPOSE_CLOTH_PART"></a>`PROPOSE_CLOTH_PART` | with `--cloth` (issue #402): `cloth.bottomwear.part` names no part, a part or cut piece whose source is not `topwear` (a `bottomwear` part takes the recipe by its tag already), or a target whose box ends above the hip + 0.25 face heights, the topwear rule's waist line | name the `topwear` part or its cut skirt piece that holds the skirt, or leave `part` out |
|
|
2718
|
+
| <a id="PROPOSE_CLOTH_BACK_HAIR_CHAINS"></a>`PROPOSE_CLOTH_BACK_HAIR_CHAINS` | with `--cloth` (issue #390): `cloth."back hair".chains` exceeds what the narrower side's opaque width at the eye-line root row holds at the part's mesh grid (`max(1, min(floor(w_r / grid), floor(w_l / grid)))`), or places a tree root outside the 15 px dilated art mask of the `back hair` part (e.g. an inner twin-tail root over the face where the hair has no pixel); the message names the part, each side's root-row width, the grid spacing, and any off-art root with its pixel alpha | lower `cloth."back hair".chains` to at most the max fit named in the message, or omit `chains` so `propose --cloth` derives the tree count per side from the root-row tail widths |
|
|
2682
2719
|
| <a id="PROPOSE_ACCESSORY_BODY"></a>`PROPOSE_ACCESSORY_BODY` | an accessory has nothing above its pendant rows to hang its bone on | that part's plan entry, or author its bones by hand |
|
|
2683
2720
|
| <a id="PROPOSE_TURN_RUN_GIVEN"></a><a id="PROPOSE_TURN_LAYER_PRESENT"></a><a id="PROPOSE_TURN_DEPTH_PRESENT"></a>`PROPOSE_TURN_RUN_GIVEN`, `PROPOSE_TURN_LAYER_PRESENT`, `PROPOSE_TURN_DEPTH_PRESENT` | with `--full`/`--head` (issue #251): a part came from a run whose layers were not given, the run given holds no layer of the part's tag, or its layer carries no `depth_median` while another part's layer carries one; a run with no depth on any part's layer (a PSD, or an export of one) is not refused — the turn is skipped, and the note says `turn: SKIP` and names the run (issue #359) | give the run the parts were assembled from, as the wrapper's `layers.json` |
|
|
2684
2721
|
| <a id="BASIS_RECORDS_EVERY_BONE"></a><a id="BASIS_NAMES_RESOLVE"></a><a id="BASIS_KIND_KNOWN"></a><a id="BASIS_KIND_HOLDS"></a>`BASIS_RECORDS_EVERY_BONE`, `BASIS_NAMES_RESOLVE`, `BASIS_KIND_KNOWN`, `BASIS_KIND_HOLDS` | `propose --keypoints`'s record of how it placed each bone, `basis.json`, does not hold to the proposal it was written with: a proposed bone with no record, one recorded twice or out of the proposal's order; a part, bone or frame quantity it names that is not there; a placement kind outside the known ones; or a placement that does not hold what its kind says (a joint placement with no joint, a non-joint one with a joint, a derived one with no bone, a constant that is not finite). Nothing is written | a proposer bug, not an input problem: report it with the line |
|
|
@@ -2781,7 +2818,7 @@ documents do not ship). Each is an input this package built; none is an author's
|
|
|
2781
2818
|
| <a id="CHECK_TIP_OVER_ROOT"></a>`CHECK_TIP_OVER_ROOT` | a `handwear`/`bottomwear` part's art in the lower half of its box travels less than 1.4725 times as far as in the upper half, measured from the idle's posed geometry (rig px quoted) | the chain track's `amps` (grow toward the tip), or the mesh's `segments` (the chain must be among them), or its mode: on `scarf`'s short skirt the proposal's lattice read 1.207 and the same part in `contour` mode 1.738 with the same segments and idle (issue #118) — both carried the `chest` segment #262 removed, after which the lattice reads 3.487. When the detail says `the root travels with the breath (x px of y px): it is carried by \`<bone>\`` (issue #262) the chain is not the cause: a bone an idle `translate` track moves (the breath) moves the root more than the tip, and with that translate held still (the part posed again without it, in proportion to each vertex's weight on the bone and those under it) the ratio passes — the row adds `carried_by`, `breath_rig_px`, `root_without_breath_rig_px` and `tip_without_breath_rig_px`; take that bone's segment off the mesh, or bind the root to the bone the part hangs from. A part the scene file declares `rests` (issue #245) is held the other way, its tip half's travel at most its root half's (ratio ≤ 1); the detail then reads `the scene file's rests declares its tip at rest, so a ratio <= 1 is required`, and for it the fix is the chain's `amps` (shrinking toward the tip) or the mesh's tip weighted to a bone the idle does not swing |
|
|
2782
2819
|
| <a id="CHECK_STILL_REGIONS_DARK"></a>`CHECK_STILL_REGIONS_DARK` | a slot of the face's still set (the `face` slots and every slot drawn over the face that the head bone alone carries) moves relative to the bone the face's slot rides, or a `footwear` slot moves on the screen, by more than the arithmetic's own rounding — measured from the idle's posed geometry (the slot, its largest displacement in rig px, the idle frame and the tolerance quoted) | on the face: a face mesh with a weight on a bone other than the head (`segments`), or one deformed by another bone; on the feet: a mesh weighted to a swinging bone, or a region on the wrong bone. A bang swinging over the face is not this line's failure: its depth is reported (`crossing`), with no bar |
|
|
2783
2820
|
| <a id="CHECK_TEXTURE_STRETCH"></a>`CHECK_TEXTURE_STRETCH` | a mesh triangle's edge, in some idle frame, is more than 1.926544 times its rest length or less than 1/1.926544 of it (the mesh, triangle, its three vertices, the edge and the frame are named, and — issue #314 — the bones the edge's two vertices hang on: each vertex's two largest weights from `rig.json`, `vertex <i> is weighted to "<bone>" <w>, …`, then `on the idle's chains, the chain from "<first link>" carries "<bone>", …` — each chain `CHAIN_LAG` reads named once, by its first link — with a bone on no chain said, or `none of these bones hangs on a chain of the idle`); or a rest edge has length 0 | the chain tracks' `amps` on the bones that mesh is weighted to (the stretch grows with them), or the mesh's `segments` — a vertex blending two bones that swing against each other. Two chains named, with opposed amplitudes: give both one sign, or drop one — `propose --from-config` measures the pair before a build (§3, *Two chains on one lattice*). An edge whose two ends disagree on whether a bone's small share survives the 0.03 cut (one vertex keeps the bone at a few hundredths, the next drops it — read the two vertices' weights the line quotes): declare `influences: {floor: "continuous"}` on that mesh first, `rule: "heat"` second; the weight `exponent` moves the figure without removing the cut (issue #115, `reference-demo` `hair_back` as contour at tolerance 1, rig-c 2.47.1: 2.535 as drafted; continuous floor 1.422, heat 1.816, both PASS; exponent 1.5 / 3 / 4 / 6 read 2.564 / 1.902 / 2.119 / 4.816, the one pass on the same cut at another edge) |
|
|
2784
|
-
| <a id="CHECK_ANIMATIONS_DO_NOT_FOLD"></a>`CHECK_ANIMATIONS_DO_NOT_FOLD` | an animation, the idle included, turns a mesh triangle over against the setup pose on some frame, read by `rigc render --folds` over the build with its physics constraints left out (issues #320, #333); the object names the animation and the mesh, the detail quotes rigc's line — the frames, the worst frame, which triangles, their world box and setup-pose area. Or a `may_fold` entry of the `--requirements` file names a slot and animation that does not fold: an exception that excepts nothing | the clip's keys on the bones that mesh is weighted to (a bend past what the weights carry, a translate that carries one row of vertices past the next), or the mesh's `segments`; to look, `rigc inspect --candidate <out>/check/build --show art,folds,mesh --animation <name> --at <the worst frame's time> --zoom folds`. A fold the art means (a sleeve behind the body) is declared, `"may_fold": [{ "slot": …, "animation": …, "why": … }]` (§7, *Declared requirements*); a stale entry is taken out |
|
|
2821
|
+
| <a id="CHECK_ANIMATIONS_DO_NOT_FOLD"></a>`CHECK_ANIMATIONS_DO_NOT_FOLD` | an animation, the idle included, turns a mesh triangle over against the setup pose on some frame, read by `rigc render --folds` over the build with its physics on — and with its physics constraints left out beside it when the rig declares any, so each row reports `physics_on` and `physics_off` side by side (issues #320, #333, #363); the object names the animation and the mesh, the detail quotes rigc's line — the frames, the worst frame, which triangles, their world box and setup-pose area — and when the fold appears only with physics on, names the physics constraint(s) on the mesh's bones and the worst frame. Or a `may_fold` entry of the `--requirements` file names a slot and animation that does not fold: an exception that excepts nothing | the physics constraint(s) the line names (lower `inertia`, raise `strength`, or lower `damping`), the clip's keys on the bones that mesh is weighted to (a bend past what the weights carry, a translate that carries one row of vertices past the next), or the mesh's `segments`; to look, `rigc inspect --candidate <out>/check/build --show art,folds,mesh --animation <name> --at <the worst frame's time> --zoom folds`. A fold the art means (a sleeve behind the body) is declared, `"may_fold": [{ "slot": …, "animation": …, "why": … }]` (§7, *Declared requirements*); a stale entry is taken out |
|
|
2785
2822
|
| <a id="CHECK_FEET_STAY_LEVEL"></a>`CHECK_FEET_STAY_LEVEL` | a `footwear` part riding a bone that hangs from another turns more than ±10 degrees from its setup pose on a frame where a bone above that bone is turned (issue #348) — the bar is HQ's line (rig-c/parts#347 ruling 4), not a figure measured here; the object names the part, its bone and the bone it hangs from, the detail the animation, frame and time, the turned bone and its turn, the drawing's turn, and every bone the turn came through with its `inherit` | config.bones' `inherit` on the foot's bone (§3, `bones`): a mode that does not take the parent's rotation (`noRotationOrReflection`, `onlyTranslation`) keeps the drawing at its setup angle; which mode is the author's. Or the clip's keys on the foot's own bone, which turn the shoe whatever its mode |
|
|
2786
2823
|
| <a id="CHECK_STRESS_OFF_CHAIN"></a>`CHECK_STRESS_OFF_CHAIN` | a mesh from a See-through `handwear` layer that rides one chain of the idle does not turn rigidly with it: with the chain's first link turned 90°, −90° or 180° on a throwaway copy (physics left out, posed by rigc, issue #347), its worst edge reads above 1.0000 as max(ratio, 1/ratio) against the setup pose. The object names the mesh, the link and the turn; the detail quotes the edge and names each bone the mesh is weighted to off the chain, with how many vertices carry it and the largest weight. Or the turned render shows no mesh on the slot: not read is not a pass | the mesh's `segments`: drop the segment on the bone the line names (a 16 px `chest` stub at the shoulder, as `propose` drafted until issue #347), so the sleeve rides its chain alone. Measured (rigc 2.47.1): `demo`'s sleeves read 2.46 to 254.7 with the stub and 1.0000 without it, and the setup-pose seam does not move (mean 0.147, 0 px over 40, both ways) |
|
|
2787
2824
|
| <a id="CHECK_LIMB_ONE_BONE"></a>`CHECK_LIMB_ONE_BONE` | a part a `config.limbs` segment made is bound in `rig.json` to a bone besides its segment's — a mesh weighted to a second bone, or a slot on another bone — or to none (issue #349); the object names the part, its limb and its bone, the detail every other bone | `regions.<part>` the segment's bone, or a mesh whose `segments` name that bone alone: a bend is a rotation at the joint |
|
|
@@ -2829,8 +2866,8 @@ and stay absent).
|
|
|
2829
2866
|
| <a id="SCENE_CHARACTER_INSIDE_CANVAS"></a>`SCENE_CHARACTER_INSIDE_CANVAS` | a character's part boxes, placed at its offset, leave the canvas (the boxes and the canvas px quoted) | the offset, or the canvas |
|
|
2830
2867
|
| <a id="SCENE_ORDER_RESOLVES"></a>`SCENE_ORDER_RESOLVES` | an order entry names no character, or `<id>:<slot>` names a slot that character does not have (its slots listed) | the entry |
|
|
2831
2868
|
| <a id="SCENE_ORDER_ONCE"></a><a id="SCENE_ORDER_COMPLETE"></a>`SCENE_ORDER_ONCE`, `SCENE_ORDER_COMPLETE` | a slot is drawn twice (a slot entry repeated, or an id listed twice), or never (the character's id is absent and some of its slots are named nowhere — they are listed) | name each slot once, or the id for the slots not named elsewhere |
|
|
2832
|
-
| <a id="SCENE_NAME_PREFIXED"></a><a id="SCENE_NAME_RESOLVES"></a>`SCENE_NAME_PREFIXED`, `SCENE_NAME_RESOLVES` | a build's constraint or `invariants.detached` names a bone its own character does not declare — one another character does (`…_PREFIXED`, naming the prefixed names it could have meant) or none does (`…_RESOLVES`); or a `--requirements` name (bone, target bone, constraint, slot, attachment, seam part) is a bare name some character holds, which the composed rig holds only prefixed | a bone of the same character; in a requirements file, `<id>:<name>` |
|
|
2833
|
-
| <a id="SCENE_ROOT_SHARED"></a>`SCENE_ROOT_SHARED` | a character's idle keys `root` (a track, or a group holding it), or one of its constraints names `root`: the root is every character's, so either would move or reach them all | key or
|
|
2869
|
+
| <a id="SCENE_NAME_PREFIXED"></a><a id="SCENE_NAME_RESOLVES"></a>`SCENE_NAME_PREFIXED`, `SCENE_NAME_RESOLVES` | a build's constraint, `stops` entry or `invariants.detached` names a bone its own character does not declare — one another character does (`…_PREFIXED`, naming the prefixed names it could have meant) or none does (`…_RESOLVES`); or a `--requirements` name (bone, target bone, constraint, slot, attachment, seam part) is a bare name some character holds, which the composed rig holds only prefixed | a bone of the same character; in a requirements file, `<id>:<name>` |
|
|
2870
|
+
| <a id="SCENE_ROOT_SHARED"></a>`SCENE_ROOT_SHARED` | a character's idle keys `root` (a track, or a group holding it), or one of its constraints or `stops` entries names `root`: the root is every character's, so either would move or reach them all | key, constrain or stop a bone of the character's own |
|
|
2834
2871
|
| <a id="SCENE_INVARIANT_AGREES"></a>`SCENE_INVARIANT_AGREES` | two characters declare `invariants.idleDrivesMeshes` with different `why`s | rebuild with this package's `--idle-keys direct`, whose `why` is one sentence |
|
|
2835
2872
|
| <a id="SCENE_IMAGE_NAME_FREE"></a>`SCENE_IMAGE_NAME_FREE` | two images compose to one file name (`<id>.<file>`: an id `x` with an image `y.cloth.png`, and an id `x.y` with `cloth.png`) | another id |
|
|
2836
2873
|
| <a id="COMPOSE_RIGC_GREEN"></a>`COMPOSE_RIGC_GREEN` | rig-c refused the composed rig; its line is quoted. A field compose carries as written (a constraint's `mix`, a slot's setup attachment) is rigc's to judge | the build whose field it names |
|
|
@@ -3114,14 +3151,15 @@ mesh for both sleeves, as `reference-demo` and `reference-sample` have) stretche
|
|
|
3114
3151
|
by construction and is listed under `not_read` with that reason, and a one-chain pendant on
|
|
3115
3152
|
another tag is not read — `reference-demo`'s `hairpin`, its tassel turned 180°, reads 23.7.
|
|
3116
3153
|
|
|
3117
|
-
**`ANIMATIONS_DO_NOT_FOLD`: every animation, the idle included (issues #320, #333).** The one
|
|
3154
|
+
**`ANIMATIONS_DO_NOT_FOLD`: every animation, the idle included (issues #320, #333, #363).** The one
|
|
3118
3155
|
bar that reads an animation other than the idle, and it reads the idle with them, written — as
|
|
3119
3156
|
a key of `check.json` after `TEXTURE_STRETCH`, and a console line after the judgement lines —
|
|
3120
3157
|
whenever `motion.json` holds an animation: a rig of the idle alone writes it too, and the
|
|
3121
3158
|
summary counts ten bars. `TEXTURE_STRETCH` reads how far the idle's triangles stretch; a
|
|
3122
3159
|
triangle that turns inside out is this bar's defect, on the idle as on any clip (issue #333;
|
|
3123
|
-
until then the idle was read for folds by hand, beside the build). It is rig-c's reading, not this package's:
|
|
3124
|
-
`rigc render --folds` over every animation of the build
|
|
3160
|
+
until then the idle was read for folds by hand, beside the build). It is rig-c's reading, not this package's:
|
|
3161
|
+
`rigc render --folds` over every animation of the build with its physics stepping on the render clock (issue #363),
|
|
3162
|
+
and, when the rig declares physics constraints, over the keyed build with its physics left out beside it, at 12 fps (the idle's rate, under
|
|
3125
3163
|
`--requirements` too: the file's `fps` is its requirements', and a file moves only what it
|
|
3126
3164
|
declares), with frames drawn at rigc's smallest
|
|
3127
3165
|
`--max`, 16, because the reading is of posed vertices in world units and the frame size does
|
|
@@ -3137,26 +3175,27 @@ exemption that exempts nothing.
|
|
|
3137
3175
|
| `status` | `PASS` or `FAIL` |
|
|
3138
3176
|
| `animations` | every animation, the idle included, in `motion.json`'s order: each one read |
|
|
3139
3177
|
| `fps` | the rate the reading sampled at |
|
|
3140
|
-
| `physics_left_out` | how many physics constraints the
|
|
3141
|
-
| `folding` | one row per mesh that folds in an animation: `animation`, `slot`, `attachment`, `frames` (how many show a folded triangle), `worst_frame`, `worst_triangles`, `triangles` (the mesh's), `declared` (the `may_fold` why, or null) and `line`, rigc's printed line verbatim |
|
|
3178
|
+
| `physics_left_out` | how many physics constraints the rig declares — stepped in `physics_on` and left out in `physics_off` (0 without any) |
|
|
3179
|
+
| `folding` | one row per mesh that folds in an animation: `animation`, `slot`, `attachment`, `frames` (how many show a folded triangle), `worst_frame`, `worst_triangles`, `triangles` (the mesh's), `physics_on` and `physics_off` (`{ frames, worst_frame, worst_triangles, line }` or null, side by side so a reader sees which folds physics adds), `physics_constraints` (the physics constraints on the mesh's bones, `"<name> on <bone>"`, when the fold appears only with physics on; empty otherwise), `declared` (the `may_fold` why, or null) and `line`, rigc's printed line verbatim |
|
|
3142
3180
|
| `folding_undeclared` | the rows no `may_fold` entry takes: the bar's figure |
|
|
3143
3181
|
| `declared_not_folding` | the `may_fold` entries no row matches, each a failure |
|
|
3144
3182
|
| `bar` | 0 |
|
|
3145
3183
|
|
|
3146
|
-
⭐ **
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
`
|
|
3184
|
+
⭐ **Judged with physics on, and reported with physics on and off side by side** (issue #363).
|
|
3185
|
+
Before issue #363 the check stripped every physics constraint before posing (issues #320, #333),
|
|
3186
|
+
so a skirt whose physics flipped it over the hips (inertia 0.75, strength 100, damping 0.975 on
|
|
3187
|
+
all nine links: 30 of 104 triangles folded on a dance rig, and 47 of 292 on `demo`'s `hop`)
|
|
3188
|
+
passed unchanged. Now `check` poses the animations with physics stepping on the render clock, and
|
|
3189
|
+
also poses the keyed build (physics left out) when the rig declares physics constraints, reporting
|
|
3190
|
+
`physics_on` and `physics_off` side by side on every folding row and naming the mesh, the physics
|
|
3191
|
+
constraint(s) on its bones and the worst frame when a fold appears only with physics on. On `scarf`,
|
|
3192
|
+
lowering the short skirt's `inertia` from 0.12 to 0.1 keeps `hop` fold-free at 12 fps as well as at
|
|
3193
|
+
10, 15, 24, 30, 36, 48 and 60 fps.
|
|
3155
3194
|
|
|
3156
3195
|
On the examples: `demo` (the idle and 7 animations), `scarf` (the idle and 7),
|
|
3157
|
-
`reference-sample` (the idle and 1)
|
|
3158
|
-
and neither does the trailer's idle (`rig-c/trailer`, its parts built by this tree, and its film
|
|
3159
|
-
rig's `idle` and `show`)
|
|
3196
|
+
`reference-sample` (the idle and 1), `reference-demo` (the idle alone) and `wind` (the idle alone) read no folding mesh
|
|
3197
|
+
with physics on or off, and neither does the trailer's idle (`rig-c/trailer`, its parts built by this tree, and its film
|
|
3198
|
+
rig's `idle` and `show`). What the
|
|
3160
3199
|
reading adds to `check`, measured with `/usr/bin/time` on `demo`'s keyed build (median of
|
|
3161
3200
|
three, user + sys, a machine under load, so the wall figures are not quoted): one run over the
|
|
3162
3201
|
idle and its 7 animations 4.1 s, the idle alone 2.9 s, and the same rig with its 7 animations
|
|
@@ -3331,7 +3370,7 @@ single-character path (§4, steps 0–9) on its own, already isolated input to a
|
|
|
3331
3370
|
| --- | --- |
|
|
3332
3371
|
| `canvas` | the shared stage, canvas px, y down. The composed rig's stage is the canvas, `root` at its bottom centre, as a single character's is its own |
|
|
3333
3372
|
| `plate` | optional. `image` (relative to the scene file) is a PNG of exactly the canvas's size; `provenance` is `observed` (the painting's own pixels), `generated` or `unknown` (a residual after the people were removed is `unknown` where they stood, and the author says so); `note` is free text. Both are copied into `scene.json` and **judged by nothing** |
|
|
3334
|
-
| `characters[].id` | the prefix: every bone, slot, attachment (skin entry), constraint (its name, and every bone and path slot it names), `invariants.detached` bone, track, group and easing of that character is renamed `<id>:<name>`. `root` is the one shared root. A name resolves to exactly one character, and nothing resolves across characters without its prefix |
|
|
3373
|
+
| `characters[].id` | the prefix: every bone, slot, attachment (skin entry), constraint (its name, and every bone and path slot it names), `stops` entry (its `chain`, `links` and `against`, issue #431), `invariants.detached` bone, track, group and easing of that character is renamed `<id>:<name>`. `root` is the one shared root. A name resolves to exactly one character, and nothing resolves across characters without its prefix |
|
|
3335
3374
|
| `characters[].build` | a `build --out` directory (relative to the scene file) whose own `check/check.json` is green |
|
|
3336
3375
|
| `characters[].offset` | `[x, y]`, a translation from the build's rig px to canvas px. Every character is built at one `assemble.rig_scale`, so its rig px are canvas px at scale 1 |
|
|
3337
3376
|
| `characters[].scale` | optional, a positive number; absent is 1, and 1 composes to the bytes a scene without the key writes. The character's size on the canvas, about its stage's top-left corner: a rig px `p` lands at canvas px `scale * p + offset` (issue #197). A character scaled up past its art is drawn soft — the art is not resampled; rebuild it at a higher `assemble.rig_scale` if that matters |
|
|
@@ -3355,7 +3394,7 @@ What is composed:
|
|
|
3355
3394
|
local to a bone the shift already moved. In Spine's axes the shift is the
|
|
3356
3395
|
character's stage corner carried to its canvas place — `scene.json` records it per
|
|
3357
3396
|
character, with what it moved. The root is shared, so a character whose idle keys
|
|
3358
|
-
it, or whose constraint names it, is refused (`SCENE_ROOT_SHARED`): it would move
|
|
3397
|
+
it, or whose constraint or stop names it, is refused (`SCENE_ROOT_SHARED`): it would move
|
|
3359
3398
|
every character.
|
|
3360
3399
|
- **The scale** (issue #197) is applied with the offset: every length the character
|
|
3361
3400
|
carries is multiplied by it exactly where Spine's own loader multiplies by its
|
|
@@ -3366,18 +3405,19 @@ What is composed:
|
|
|
3366
3405
|
the `offset` and `max` of an `x`/`y` target, its `scale` by the target's unit over
|
|
3367
3406
|
the source's; a path's `position` under `positionMode` Fixed and its `spacing` under
|
|
3368
3407
|
`spacingMode` Length or Fixed; a physics `limit`; a slider driven by a bone's `x` or
|
|
3369
|
-
`y`, its `from` scaled and its `scale` divided;
|
|
3408
|
+
`y`, its `from` scaled and its `scale` divided; each stop's `at` offset in its
|
|
3409
|
+
`against` bone's local frame (issue #431); and the translate keys (`translate`,
|
|
3370
3410
|
`translatex`, `translatey`), their curves' values with them. An absent field whose
|
|
3371
3411
|
Spine default is not 0 (a physics `limit`, 5000; a transform target's `max`, 1; a
|
|
3372
3412
|
slider's `scale`, 1) is written as that default scaled. Degrees, mixes, ratios,
|
|
3373
|
-
physics rates and a mesh's `width`/`height` (its image's, nonessential) are not
|
|
3413
|
+
physics rates, a stop's `inward`/`outward` bounds and a mesh's `width`/`height` (its image's, nonessential) are not
|
|
3374
3414
|
lengths and stay. Then what sits in `root`'s own frame takes the shift, so the
|
|
3375
3415
|
character's stage corner lands at `offset`. `scene.json` writes `scale` beside the
|
|
3376
3416
|
offset only when it is not 1, and the `[compose]` line always prints it.
|
|
3377
3417
|
- **The plate** is a region on the bone `plate` under `root`, the first slot, its
|
|
3378
3418
|
image at canvas (0, 0).
|
|
3379
3419
|
- **One `idle`** holds every character's tracks; the characters' idles must be of one
|
|
3380
|
-
duration. Constraints are carried in character order with their
|
|
3420
|
+
duration. Constraints and `stops` entries are carried in character order with their
|
|
3381
3421
|
`invariants.detached`; `invariants.idleDrivesMeshes` once, when any character
|
|
3382
3422
|
declares it.
|
|
3383
3423
|
- **Every animation beside a character's idle** — what `motion.animations_from`
|
package/docs/MIGRATION.md
CHANGED
|
@@ -301,7 +301,7 @@ either (the examples' `expected/` and every existing control are unchanged).
|
|
|
301
301
|
|
|
302
302
|
What to do: nothing. To draft a skirt or hair that the consumer's wind and gravity move,
|
|
303
303
|
add a `cloth` block and propose with `--cloth`; copy each of `bones`, `meshes`, `regions`,
|
|
304
|
-
`limbs`, `motion`, `constraints` and `
|
|
304
|
+
`limbs`, `motion`, `constraints`, `turn` and `proposed_rig_scale` the proposal wrote into the config, as before
|
|
305
305
|
(`constraints` is the one `--cloth` adds).
|
|
306
306
|
|
|
307
307
|
## After 1.20.0: the seam over a joint's range
|