@rig-c/parts 1.38.0 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.ts +72 -1
- package/docs/AUTHORING.md +90 -2
- package/docs/MIGRATION.md +21 -0
- package/docs/STABILITY.md +3 -1
- package/package.json +1 -1
- package/src/build.ts +25 -2
- package/src/check.ts +187 -0
- package/src/meshdraft.ts +42 -30
- package/src/remesh.ts +617 -0
package/cli.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { tmpdir } from 'node:os';
|
|
|
17
17
|
import { basename, dirname, extname, join } from 'node:path';
|
|
18
18
|
import { DEFAULT_PROJECT_RULE, DEFAULT_SEAM_RULE, HOLES_LISTED, PROJECT_RULES, type ProjectRule, proposeFields, proposePlan, proposeSinglePlan, SEAM_RULES, type SeamRule } from './src/assemble.ts';
|
|
19
19
|
import { type AlternateCliInput, assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns, readSource, rigStage, suppliedCheckFlag } from './src/build.ts';
|
|
20
|
-
import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, rigcRunnerAt, type PackShape, PAGE_EDGES, type PageEdges, PARTS_HOME_SENTENCE, RIGC_GEOMETRY_VERSION, type RigcRunner, NO_PARTS_SENTENCE, SEAM_MEAN_BAR, SOURCE_SENTENCE, SEAM_PX_BAR, SEAM_PX_LEVEL, SPINEBOY_YARDSTICK, TEXTURE_STRETCH_CEILING } from './src/check.ts';
|
|
20
|
+
import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, rigcRunnerAt, type PackShape, PAGE_EDGES, type PageEdges, PARTS_HOME_SENTENCE, RIGC_GEOMETRY_VERSION, rigcRanClause, type RigcRunner, NO_PARTS_SENTENCE, SEAM_MEAN_BAR, SOURCE_SENTENCE, SEAM_PX_BAR, SEAM_PX_LEVEL, SPINEBOY_YARDSTICK, TEXTURE_STRETCH_CEILING } from './src/check.ts';
|
|
21
21
|
import { ComfyClient, resolveHost, runPainting, runSeeThrough } from './src/comfy/index.ts';
|
|
22
22
|
import { type CharacterConfig, loadClothConfig, loadConfig, loadEarlyConfig, loadPaintConfig } from './src/config.ts';
|
|
23
23
|
import { failLine, guidePointer, PartsError } from './src/errors.ts';
|
|
@@ -30,6 +30,7 @@ import { checkImageSize, choosePerson, KEYPOINTS_SPEC, loadKeypoints, type RigJo
|
|
|
30
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
|
+
import { PROVENANCE_FILE, REMESH_SPEC, remeshStage } from './src/remesh.ts';
|
|
33
34
|
import { checkPainting } from './src/paintcheck.ts';
|
|
34
35
|
import { readPng, writePng } from './src/raster/png.ts';
|
|
35
36
|
import { REQUIREMENTS_SENTENCE } from './src/requirements.ts';
|
|
@@ -336,6 +337,35 @@ usage:
|
|
|
336
337
|
Written only when the drafted config's check is PASS. --requirements, --idle-keys,
|
|
337
338
|
--page-edges and --pack-shape are as for rig and check.
|
|
338
339
|
|
|
340
|
+
rig-parts remesh --rig <dir> --config <config.json> --parts <dir> --part <name>
|
|
341
|
+
--mesh <entry.json> --out <dir> [--requirements <file.json>]
|
|
342
|
+
[--idle-keys ctl|direct] [--page-edges pot|free] [--pack-shape rect|polygon]
|
|
343
|
+
Re-fit one part's mesh of a gated rig (the directory rig writes) under
|
|
344
|
+
the mesh entry --mesh holds — what config.json would hold at
|
|
345
|
+
meshes.<name>: a grid, a contour or an auto entry, its bounds the
|
|
346
|
+
entry's own — and write a new revision into --out, which must not
|
|
347
|
+
exist (REMESH_OUT_FRESH); the input is never written. --config and
|
|
348
|
+
--parts are what the input was built from: the config as written must
|
|
349
|
+
reproduce the input's part (its attachment, image and mesh_report.json
|
|
350
|
+
row) and its bones, and for an auto entry its motion
|
|
351
|
+
(REMESH_BASELINE_MISMATCH); every other part is carried over as bytes,
|
|
352
|
+
whether or not the config reproduces it. The part must be a mesh nothing
|
|
353
|
+
else is bound to — no linked mesh, no deform timeline
|
|
354
|
+
(REMESH_TARGET_MESH, REMESH_TARGET_CLOSED). The entry is built through
|
|
355
|
+
the rig stage, its mode's own checks and an auto entry's motion gate
|
|
356
|
+
(REMESH_CANDIDATE_REFUSED, quoting each), and may not move a bone, a
|
|
357
|
+
motion key or the part's image (REMESH_REQUEST_HELD). Every file but
|
|
358
|
+
rig.json and mesh_report.json is the input's bytes, rig.json is the
|
|
359
|
+
input's outside the part's attachment, and every other report row is
|
|
360
|
+
the input's (REMESH_PRESERVED); rigc's build gate passes over the
|
|
361
|
+
revision (REMESH_RIGC_GREEN); check measures every bar on it that it
|
|
362
|
+
measures on the input and fails none the input meets
|
|
363
|
+
(REMESH_CHECK_HELD). --out receives the revision and ${PROVENANCE_FILE}
|
|
364
|
+
(spec "${REMESH_SPEC}": the request, both versions, every input file's
|
|
365
|
+
SHA-256, the part's counts before and after, both checks and their
|
|
366
|
+
scope) — no path and no clock, so the same request writes the same bytes.
|
|
367
|
+
Prints the part's counts and a hash table of every file.
|
|
368
|
+
|
|
339
369
|
rig-parts check --rig <dir> --out <dir> [--parts <dir>] [--source <painting.png>]
|
|
340
370
|
[--page-edges pot|free] [--pack-shape rect|polygon]
|
|
341
371
|
[--requirements <file.json>] [--seam-pairs] [--keep-stills]
|
|
@@ -799,6 +829,7 @@ const TAKES = {
|
|
|
799
829
|
build: { valued: ['--config', '--source', '--full', '--head', '--out', '--seam', '--project', '--page-edges', '--pack-shape', '--requirements', '--idle-keys', '--lead-in', '--alt', '--set'], switches: ['--loop', '--seam-pairs', '--keep-stills', '--all-sets'] },
|
|
800
830
|
compose: { valued: ['--scene', '--out', '--requirements', '--accept'], switches: [] },
|
|
801
831
|
'mesh-draft': { valued: ['--config', '--parts', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: ['--more-triangles'] },
|
|
832
|
+
remesh: { valued: ['--rig', '--config', '--parts', '--part', '--mesh', '--out', '--requirements', '--idle-keys', '--page-edges', '--pack-shape'], switches: [] },
|
|
802
833
|
painting: { valued: ['--keypoints', '--person'], switches: [] },
|
|
803
834
|
} as const satisfies Record<string, { valued: readonly string[]; switches: readonly string[] }>;
|
|
804
835
|
|
|
@@ -1611,6 +1642,45 @@ function cmdMeshDraft(args: string[]): number {
|
|
|
1611
1642
|
}
|
|
1612
1643
|
}
|
|
1613
1644
|
|
|
1645
|
+
/** `remesh` (issue #495): one part of a gated rig re-fitted under a requested mesh entry, into a new revision. */
|
|
1646
|
+
function cmdRemesh(args: string[]): number {
|
|
1647
|
+
const f = flags(args, 'remesh', ['--rig', '--config', '--parts', '--part', '--mesh', '--out']);
|
|
1648
|
+
if (typeof f === 'string') return usage(f);
|
|
1649
|
+
const keys = idleKeysOf(f.get('--idle-keys'));
|
|
1650
|
+
if (!isIdleKeys(keys)) return usage(keys);
|
|
1651
|
+
const edges = pageEdgesOf(f.get('--page-edges'));
|
|
1652
|
+
if (!isPageEdges(edges)) return usage(edges);
|
|
1653
|
+
const shape = packShapeOf(f.get('--pack-shape'));
|
|
1654
|
+
if (!isPackShape(shape)) return usage(shape);
|
|
1655
|
+
let bin: string;
|
|
1656
|
+
try {
|
|
1657
|
+
bin = findRigc(import.meta.dir, process.env.PATH ?? '');
|
|
1658
|
+
} catch (err) {
|
|
1659
|
+
return printRefusal(err);
|
|
1660
|
+
}
|
|
1661
|
+
const runner = rigcRunner(bin);
|
|
1662
|
+
const said = runner(['--version']);
|
|
1663
|
+
const rigcVersion = said.status === 0 ? (said.out.trim().split('\n')[0] ?? '') : '';
|
|
1664
|
+
if (rigcVersion === '') return printRefusal(new PartsError([{ code: 'REMESH_RIGC_GREEN', object: 'rigc --version', detail: `exited ${said.status}${rigcRanClause(said)}; the provenance names the rigc that gated the revision, so its version is required` }]));
|
|
1665
|
+
const scratch = mkdtempSync(join(tmpdir(), 'rig-parts-remesh-'));
|
|
1666
|
+
try {
|
|
1667
|
+
const req = f.get('--requirements');
|
|
1668
|
+
remeshStage(
|
|
1669
|
+
{ rig: f.get('--rig') as string, config: f.get('--config') as string, parts: f.get('--parts') as string, part: f.get('--part') as string, mesh: f.get('--mesh') as string, out: f.get('--out') as string, idleKeys: keys, pageEdges: edges, packShape: shape, ...(req === undefined ? {} : { requirements: req }) },
|
|
1670
|
+
runner,
|
|
1671
|
+
bin,
|
|
1672
|
+
{ parts: version(), rigc: rigcVersion },
|
|
1673
|
+
scratch,
|
|
1674
|
+
console.log,
|
|
1675
|
+
);
|
|
1676
|
+
return EXIT_OK;
|
|
1677
|
+
} catch (err) {
|
|
1678
|
+
return printRefusal(err);
|
|
1679
|
+
} finally {
|
|
1680
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1614
1684
|
/**
|
|
1615
1685
|
* `painting --keypoints <k.json> [--person <id>] <painting.png>` (issue #350): what the painting must be before
|
|
1616
1686
|
* See-through runs on it, read off its pixels and the body-18 joints `propose --keypoints` reads. Writes nothing.
|
|
@@ -1680,6 +1750,7 @@ function main(argv: string[]): number | Promise<number> {
|
|
|
1680
1750
|
if (command === 'build') return cmdBuild(rest);
|
|
1681
1751
|
if (command === 'compose') return cmdCompose(rest);
|
|
1682
1752
|
if (command === 'mesh-draft') return cmdMeshDraft(rest);
|
|
1753
|
+
if (command === 'remesh') return cmdRemesh(rest);
|
|
1683
1754
|
if (command === 'painting') return cmdPainting(rest);
|
|
1684
1755
|
if (command === 'guide') return cmdGuide(rest);
|
|
1685
1756
|
const later = LATER.find(([name]) => name === command);
|
package/docs/AUTHORING.md
CHANGED
|
@@ -1766,7 +1766,7 @@ translate mix at 0.2 / 0.5 / 1): as drafted, no response on the translate, 1.382
|
|
|
1766
1766
|
|
|
1767
1767
|
**What moves them.** Physics answers motion of the bones above it and the environment.
|
|
1768
1768
|
The drafted idle keys `chest` (the breath) and the head chain, never `hip`, and the
|
|
1769
|
-
recipe adds no key: under the idle alone a skirt's trees move only by the environment.
|
|
1769
|
+
recipe adds no key: under the idle alone a skirt's trees move only by the environment. Under rigc's default environment that motion is the physics reset at frame 0 dying out, and `check` says so by name: `CLOTH_SETTLES` (§6, issue #501) warns on each chain whose tip comes to rest before the idle's loop length — on `wind`, the skirt's eight trees and its swing, between 1.5 and 2.75 s of a 3.333 s idle.
|
|
1770
1770
|
`rigc render` and `check` pose under spine-core's default, wind (1, 0) and gravity
|
|
1771
1771
|
(0, 1), so on the fixture `check` reads `check: PASS`, `TEXTURE_STRETCH` 1.382,
|
|
1772
1772
|
`TIP_OVER_ROOT` ratio 15.06 (root 0.095, tip 1.438 rig px), `CHAIN_LAG` PASS,
|
|
@@ -1780,6 +1780,68 @@ by up to 10.396 and 10.188, `skirt` 3.390 and 3.382, and `hair_front` 2.131 and
|
|
|
1780
1780
|
px, either way alike; held three cycles each from a fresh track, 10.299 / 10.277,
|
|
1781
1781
|
3.390 / 3.382 and 2.119 / 2.115.
|
|
1782
1782
|
|
|
1783
|
+
**A standing cloth is the consumer's to drive** (issue #502). The drafted idle keys no
|
|
1784
|
+
`hip`, and that is a measured decision, not an omission. A hip sway was tried on every
|
|
1785
|
+
public example: a `motion.tracks` entry `{ "bone": "hip", "prop": "rotate", "amp": a,
|
|
1786
|
+
"period": <the idle's>, "phase": 0 }` at the breathing period, a = 0.1°, 0.2° and 0.3°
|
|
1787
|
+
(this port's build of each, rig-c 2.60.0, `check`'s idle at 12 fps). Every sway keeps the
|
|
1788
|
+
chains it reaches above `CLOTH_SETTLES`'s floor, and every one turns a passing `check` red:
|
|
1789
|
+
|
|
1790
|
+
| example | chains no idle key drives | 0.1° | 0.2° and 0.3° | idle frames changed by 0.1° |
|
|
1791
|
+
| --- | --- | --- | --- | --- |
|
|
1792
|
+
| `demo` | 0 | `CHAIN_LAG` | `CHAIN_LAG`, `TIP_OVER_ROOT` | 11.91 % of pixels, up to 148 levels |
|
|
1793
|
+
| `scarf` | 0 | `CHAIN_LAG`, `TIP_OVER_ROOT` | the same | the framing box changes, 201 to 202 px wide |
|
|
1794
|
+
| `wind` | 9, the skirt | `CHAIN_LAG`, `BREATH_VISIBLE`, `STILL_REGIONS_DARK` | those and `TIP_OVER_ROOT` | 17.42 %, up to 203 |
|
|
1795
|
+
| `reference-sample` | 1, `hip_jiggle` | `CHAIN_LAG` | the same | 29.42 %, up to 121 |
|
|
1796
|
+
| `reference-demo` | 0 (no physics) | `CHAIN_LAG` | the same | 47.63 %, up to 222 |
|
|
1797
|
+
|
|
1798
|
+
Two of those are not the amplitude's to fix. `CHAIN_LAG` reads a lag modulo a quarter
|
|
1799
|
+
cycle, and the keyed chains under `hip` start at phases from the neck's 0.08 to the third
|
|
1800
|
+
skirt chain's 0.38: a span of 0.30 cycle on `demo`, `scarf`, `reference-sample` and
|
|
1801
|
+
`reference-demo`, so no phase of a hip turn at the idle's period has all of them lagging
|
|
1802
|
+
it. `wind`'s span, 0.08 to 0.29, admits phase 0.06, and there 0.1° still fails
|
|
1803
|
+
`BREATH_VISIBLE`, `STILL_REGIONS_DARK` and `TIP_OVER_ROOT`. And the legs hang from `hip`:
|
|
1804
|
+
a hip turn moves the feet (0.857 rig px at 0.1° on `wind`), which a standing character
|
|
1805
|
+
holds still. So a cloth that should move while the character stands is moved by the
|
|
1806
|
+
world, which the consumer sets when it plays the rig (rig-c's live track
|
|
1807
|
+
`setEnvironment`, rig-play's `environment()`). `rigc render --environment` reads the
|
|
1808
|
+
same world from a file, to look at the response before a player exists (rig-c's
|
|
1809
|
+
AUTHORING §8.4: each step holds from its `t`, x right and y down). A worked schedule for
|
|
1810
|
+
`wind`, tracked as `examples/wind/breeze.json`, is a breeze that changes every half
|
|
1811
|
+
second:
|
|
1812
|
+
|
|
1813
|
+
```json
|
|
1814
|
+
{
|
|
1815
|
+
"spec": "rigc-environment/1",
|
|
1816
|
+
"steps": [
|
|
1817
|
+
{ "t": 0, "wind": [0.4, 0] },
|
|
1818
|
+
{ "t": 0.5, "wind": [1, 0] },
|
|
1819
|
+
{ "t": 1, "wind": [0.2, 0] },
|
|
1820
|
+
{ "t": 1.5, "wind": [0.8, 0] },
|
|
1821
|
+
{ "t": 2, "wind": [0.3, 0] },
|
|
1822
|
+
{ "t": 2.5, "wind": [1, 0] },
|
|
1823
|
+
{ "t": 3, "wind": [0.4, 0] }
|
|
1824
|
+
]
|
|
1825
|
+
}
|
|
1826
|
+
```
|
|
1827
|
+
|
|
1828
|
+
```bash
|
|
1829
|
+
rigc render --candidate out/check/build --animation idle --fps 12 --max 640 --geometry \
|
|
1830
|
+
--environment examples/wind/breeze.json --out out/breeze
|
|
1831
|
+
```
|
|
1832
|
+
|
|
1833
|
+
Read by `CLOTH_SETTLES`'s own definition on the `geometry.json` that writes, none of the
|
|
1834
|
+
16 chains settles. The nine that settle under the default world keep moving to the last
|
|
1835
|
+
frame: the skirt's eight trees end at 7.66 to 23.79 rig px/s, and the swing at 2.778
|
|
1836
|
+
(selftest `CH21` holds this). `check` itself always reads the default world, so `wind`'s
|
|
1837
|
+
`check.json` keeps its WARN. The WARN states what the rig does with nothing driving it;
|
|
1838
|
+
it is not a fault (`CH20` holds that the idle keys no hip and that the chains which
|
|
1839
|
+
settle are exactly the ones no idle key drives). A soft region with no wind response,
|
|
1840
|
+
such as `reference-sample`'s `hip_jiggle`, is not reached by an environment at all:
|
|
1841
|
+
`rigc render --environment` refuses the schedule by name, since no physics constraint
|
|
1842
|
+
answers wind. It answers the body, so what moves it is a consumer's animation that
|
|
1843
|
+
moves `hip`, such as a walk or a turn, not the idle.
|
|
1844
|
+
|
|
1783
1845
|
**Not in this recipe.**
|
|
1784
1846
|
|
|
1785
1847
|
- **Weights across neighbouring chains** (rig-c/core#1415's per-vertex weights, a vertex
|
|
@@ -2175,7 +2237,7 @@ move off it (`AS245`).
|
|
|
2175
2237
|
| `propose` | `note:` lines, `LINT` lines, the `coverage` lines, `landmarks.png`, `basis.json` | no LINT line: every chain link lies on its mesh's art, and the hip is below the chest and the figure's top quarter; the `coverage:` summary says how many bones that verdict covers — a `not checked` bone was read by no check (its line says why), and a `ratio` or `fallback` bone in `basis.json` is a guess | a link off the art (a bone on the background) — move it onto the layer; `LINT <link> at … runs to … N degrees off the head's down axis …` — a fringe link that does not lean with the head (§3, the fringe in the head's frame): move it along the lock it drives; `LINT hairback_… on mesh '<part>' (side <r\|l>): <N> tree(s) for <M> visible hair mass(es) (mass 0 columns x=<minX>..<maxX>, y=<minY>..<maxY>; …)` — back-hair cloth trees whose count does not match the side's visible hair masses (`max(1, floor(w / (4 * grid)) + 1)` per mass) or whose link or tip leaves its mass's column range (issues #445, #461): omit `chains` on `cloth."back hair"` or draft trees per visible hair mass inside its columns; `LINT <a_limb> and <b_limb> on <part> (<from>) cross at [x, y] with no per-limb split: …` — two limbs sharing one layer cross in an X without a per-limb split (issue #446): declare `config.limbs.<covering>.split` (`{ "line": [[x, y], …] }` or `{ "edge": "painting" }`, §3 *Which limb*); `LINT stop on <chain> (<firstLink> at [x0, y0]) against <against> (at [ax, ay]) places <chain>_touch at [tx, ty], above <firstLink>'s root (rest R deg, \|rest\| + outward B deg): …` — a stop's contact point `<chain>_touch` lies above `links[0]`'s root in rig px or pushes `\|rest\| + outward` past `180°` (issue #447, §2 `stops`): stop against the descending limb bone below `firstLink`, set `links` to start at a link below `<chain>_touch`, or omit the stop on a rising limb; `LINT hip at [x, y] is not below chest at [x, y]: …` or `LINT hip at [x, y] is above 0.25 of the figure height (figure y T..B, so hip y must be at least L): a hip at the shoulders` — move `hip` down to the waist (and `chest` between it and the neck); a `hanging strand … -- no chain proposed` note — that strand hangs stiff until you add a chain down the x and rows it names (§3); a `no blink: …` or `blink without brows: …` note — the idle will not blink (or its brows will not drop), because no part came from an `eyewhite` (or `eyebrow`) layer; the note names the tags looked for; a `no eyewhite part for eye_<s> …` note — the iris and lash parts it names ride `head` and do not blink, because no `eyewhite-<s>` part made that side's eye bone: take the eyewhite from the other run, or keep them on `head`; a `no face part: face box derived from …` note (always the first) — `head`, `neck` and every face-height scale come from a box guessed off the hair and neck (§3): check `head` and `neck` on `landmarks_head.png` and move them; when it adds `the blink shuts the eyes over no face part`, read `BLINK_NO_HOLE` after `check` — an eye with no face under it can open a hole (the `reference-sample` with only its face removed: 587 px). Under `--keypoints`: the `lint rule set:` line first (joints, or screen and why), then the joint notes — `missing: the rule "…" placed bone X instead` is a bone still guessed; `not used — …` names why an arm's joints did not place its sleeve (for a wrist on no part, the nearest part and the `--wrist-snap` that would bind it); a `wrist snap: …` note is a wrist bound past 15 px by the flag — check that chain's tip on `landmarks.png`; a `one handwear part holds both wrists` note is two chains on one mesh — cut the part with `assemble.cuts` to separate them; `LINT chest at … is not between the neck joint …`, `LINT hip at … is not past chest …`, `LINT hip at … is nearer the neck joint …` and `LINT <chain><i> at … does not advance from <s>_shoulder toward <s>_wrist` are the joint-frame lines: move that bone between, past or along the joints they name |
|
|
2176
2238
|
| `compare` | one line per pair (origin, parent, tip, length, direction — or SKIP and why), then the per-row summary, the unmapped bones of each side, `required:`, each side's roles and the `controls:` line | proposal against the config you corrected: the rows you changed and no others. Config against the `rig.json` `build` writes for it: measured on both examples, every origin within 6.19e-7 px (the rig's offsets are written to 6 places) and every chain link's tip and length within 4.99e-4 px (`length` is written to 3), printed to three places as `0.000` (a signed figure as `+0.000` or `-0.000`); `parent … is the right's ancestor at depth 2, <bone>_ctl between` for every keyed mesh bone, no `DIFFERENT` and no `NOT MAPPED` | `parent DIFFERENT: left a, right b` — a bone hangs from another parent than the other side's; `frames not related` — a rig with no stage (`skeleton.width`/`height`), two configs at different `rig_scale`: the distance rows SKIP, so declare the frame in a `--map` file if the author knows it; `FAIL STRUCTURE_REQUIRED_PRESENT` — a bone the map requires is missing through its pairs |
|
|
2177
2239
|
| `rig` (inside `build`) | one line per mesh: vertices, triangles, bones, influences, `cover`; the `bones` line; the `idle keys` line; then rigc's gate lines (with A15's declared SKIP under `--idle-keys direct`); in `rig.json`, each chain link's (or its `_ctl`'s) `length` and `rotation` | `cover 1.00000` on every mesh, both gate summaries `0 failed` (the compile and the packed pages); every link's `length` the distance to the next link and `rotation` its direction (Spine degrees, counter-clockwise, y up, local to the parent), every offset under it — a child bone's `x, y`, a weight's bind `x, y`, a region's `x, y` — in that turned frame, and a region on a link carrying `rotation` that turns it back upright. Nothing moved: `flattenRig` (`src/rig.ts`) turns every offset back and gives the unturned numbers | `RIG_LATTICE_ONE_LOOP`: change that mesh's `grid` |
|
|
2178
|
-
| `check` (inside `build`) | the gate lines verbatim, the pack line, `loop:` (and `loop physics:` when the rig declares a physics constraint, §7), `seam:`, the six judgement lines, then — when `motion.json` holds an animation, the idle included — `ANIMATIONS_DO_NOT_FOLD` and one `folds` line per folding mesh, rigc's own (issues #320, #333), then — where a `footwear` part rides a bone that hangs from another — `FEET_STAY_LEVEL` and one `foot` line per such part (issue #348), then — when `parts.json` names a `handwear` part and there is an idle — `STRESS_OFF_CHAIN` (issue #347), then — where `parts.json` holds a limb segment's part — `LIMB_ONE_BONE` and one `limb` line per such part (issue #349), then — where a limb record carries a `range` — `SEAM_OVER_RANGE` and one `joint` line per joint and angle (issue #360), then `SEAM_OVER_MOTION` — a SKIP naming why on a rig that declares no neighbour pair, else the pairs read in every animation and one `WARN seam` line per pair and animation over the one-cell floor (issue #493, a warning and never a bar), `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the bars measured — nine, ten with the fold bar, one more each with the feet-level bar, the stress bar, the limb bar and the range bar — and names the ones that said SKIP, then — where `SEAM_OVER_MOTION` read a pair — how many warnings it printed, `; N warning(s) (SEAM_OVER_MOTION, not a bar)
|
|
2240
|
+
| `check` (inside `build`) | the gate lines verbatim, the pack line, `loop:` (and `loop physics:` when the rig declares a physics constraint, §7), `seam:`, the six judgement lines, then — when `motion.json` holds an animation, the idle included — `ANIMATIONS_DO_NOT_FOLD` and one `folds` line per folding mesh, rigc's own (issues #320, #333), then — where a `footwear` part rides a bone that hangs from another — `FEET_STAY_LEVEL` and one `foot` line per such part (issue #348), then — when `parts.json` names a `handwear` part and there is an idle — `STRESS_OFF_CHAIN` (issue #347), then — where `parts.json` holds a limb segment's part — `LIMB_ONE_BONE` and one `limb` line per such part (issue #349), then — where a limb record carries a `range` — `SEAM_OVER_RANGE` and one `joint` line per joint and angle (issue #360), then `SEAM_OVER_MOTION` — a SKIP naming why on a rig that declares no neighbour pair, else the pairs read in every animation and one `WARN seam` line per pair and animation over the one-cell floor (issue #493, a warning and never a bar), then `CLOTH_SETTLES` — a SKIP naming why on a rig with no physics constraint, else the chains read and one `WARN chain` line per chain whose tip comes to rest before the idle's loop length (issue #501, a warning and never a bar), `RECOMPOSITE_HOLES` and, under `--source`, `SETUP_POSE_VS_SOURCE` (§7), `check.json`; the last line says how many of the bars measured — nine, ten with the fold bar, one more each with the feet-level bar, the stress bar, the limb bar and the range bar — and names the ones that said SKIP, then — where `SEAM_OVER_MOTION` read a pair — how many warnings it printed, `; N warning(s) (SEAM_OVER_MOTION, not a bar)` — with `CLOTH_SETTLES` named beside it, and N their sum, where the rig declares a physics constraint — which no bar counts | `check: PASS; 11 of 11 bar(s) measured, 0 skipped` on `demo` and `scarf`, whose sleeves each ride one chain; `check: PASS; 10 of 11 bar(s) measured, 1 skipped (STRESS_OFF_CHAIN)` on `reference-demo` and `reference-sample`, whose one `sleeves` mesh rides both sleeve chains (issue #347) — no example writes `FEET_STAY_LEVEL`, every shoe riding `root`; a judgement line SKIP only where the character lacks what it reads; on a rig spec with no `parts.json` or no `idle` (a merged rig, §7 *Measuring a rig rig-parts did not assemble*), PASS with the skipped bars named | `CHECK_SEAM_WITHIN_BAR` or `CHECK_LOOP_CLOSES` (§6); `CHECK_ANIMATIONS_DO_NOT_FOLD` — a clip turns a mesh over (§6); `CHECK_STRESS_OFF_CHAIN` — a sleeve weighted off its chain (§6); `CHECK_LIMB_ONE_BONE` — a limb part on a second bone (§6); `CHECK_SEAM_OVER_RANGE` — a joint that opens when bent (§6) |
|
|
2179
2241
|
| `check --requirements` (and `build --requirements`) | after the lines above, one line per declared requirement, `NAME: PASS`, `FAIL` or `NOT MEASURABLE — …` with its figures, the bar as declared and the worst frame; then `requirements: N declared — M measured (P PASS, F FAIL), K NOT MEASURABLE; not declared: <kinds>`; `check.json`'s `requirements` block; the renders under `requirements/` (§7, *Declared requirements*) | every line PASS and `0 NOT MEASURABLE`; a follow's `released_copy` says whether rigc's consumer-driven door was taken on the throwaway copy; a `stretch` line's `held_by` (issue #321), right after `worst`, names the bones the worst edge's two vertices hang on and their idle chains, in `CHECK_TEXTURE_STRETCH`'s words (§6) and by the same function, on a PASS as on a FAIL | `CHECK_REQUIREMENT_MET` (a figure past its bar; the line names the frame) or `CHECK_REQUIREMENT_MEASURABLE` (the quantity is undefined in the frames: a tip or an axis on a bone of length 0, an aim with no line, a follow no frame of which reaches its least drive); the last line then reads `check: FAIL — B bar(s) not met, R declared requirement(s) not PASS` |
|
|
2180
2242
|
| `compose` | the `[compose]` lines: one per character (its offset, its scale, its placed bounds, the shift and how many first-level bones, regions on `root` and weights bound to `root` it moved, its bone, slot, track and constraint counts, its `rig_scale` and idle), the declared order and the slot count it expands to, rigc's gate lines; then the `[check]` lines as for `check`, and `scene.json` | both gate summaries `0 failed`, `check: PASS` with the bars that measured and the ones that said SKIP named — on a composed rig `4 of 9`: the gate, the loop, `CHAIN_LAG` and `TEXTURE_STRETCH` (there is no `parts.json`; each character's own `build` measured all nine). `scene.json`'s `order.slots` is the order the compiled skeleton draws | a `SCENE_*` refusal (§6, *compose*) — the scene file, a build, or the order; `COMPOSE_RIGC_GREEN` — rigc's own line, quoted |
|
|
2181
2243
|
| `loop` (inside `build --loop`, or `loop --frames … --out …`) | the dropped-duplicate line, or, when the end frame is not frame 0, the jump line: its max \|d\| and px over 40, then why — under `build`, `the rig holds N physics constraint(s), and rigc's render starts every one at rest at frame 0` with the remedy `build --loop --lead-in <n>`, or `the rig holds no physics constraint, so the idle itself does not close` (`CHECK_LOOP_CLOSES`); under `loop --frames`, which reads frames alone, both causes (issue #325); under `build --lead-in`, the lead-in line in its place (the frames kept and the jump at the wrap); each file's line, then `loop: idle.png N B (lossless); idle-indexed.png N B (max …, mean …); idle.gif N B (max …, mean …)` | `f0048.png equals f0000.png byte for byte, so it is dropped` | `LOOP_ENCODE` (§6) |
|
|
@@ -2842,6 +2904,31 @@ says why each requirement exists and what breaks without it.
|
|
|
2842
2904
|
A part that fails a reading is not a refusal: it keeps its lattice, the command
|
|
2843
2905
|
exits 0, and `mesh_draft.json` and the console name the reading and the amount.
|
|
2844
2906
|
|
|
2907
|
+
### remesh
|
|
2908
|
+
|
|
2909
|
+
| rule | means | change |
|
|
2910
|
+
| --- | --- | --- |
|
|
2911
|
+
| <a id="REMESH_OUT_FRESH"></a>`REMESH_OUT_FRESH` | `--out` exists, or lies inside `--rig`: a revision is a new directory beside the input, never written over it | name a directory that does not exist yet |
|
|
2912
|
+
| <a id="REMESH_INPUT_PRESENT"></a>`REMESH_INPUT_PRESENT` | `--rig` is not the directory `rig` writes: `rig.json`, `motion.json`, `mesh_report.json` or `images/` is missing | point `--rig` at a `rig` output (`build`'s `rig/`) |
|
|
2913
|
+
| <a id="REMESH_INPUT_WRITTEN"></a>`REMESH_INPUT_WRITTEN` | `rig.json` or `mesh_report.json` is not the text this package's writer prints for its value (reformatted, or written by something else); the revision is spliced as text, so it could not carry every other byte over | use the files as `rig` wrote them |
|
|
2914
|
+
| <a id="REMESH_MESH_JSON"></a>`REMESH_MESH_JSON` | `--mesh` is missing, does not parse, or is not one JSON object | write the entry `config.json` would hold at `meshes.<part>`; its fields are then the config loader's to judge (`CONFIG_*` at `meshes.<part>`) |
|
|
2915
|
+
| <a id="REMESH_TARGET_MESH"></a>`REMESH_TARGET_MESH` | `--part` is not a `mesh` attachment of the input rig (`skins.default.<part>.<part>`), or not an entry of the config's `meshes` | name a part the rig meshes and the config states |
|
|
2916
|
+
| <a id="REMESH_TARGET_CLOSED"></a>`REMESH_TARGET_CLOSED` | a `linkedmesh` borrows the part's geometry, or an animation keys a `deform` timeline on it: both index the vertex list the remesh replaces | remesh the source and its links together by rebuilding from the config |
|
|
2917
|
+
| <a id="REMESH_BASELINE_MISMATCH"></a>`REMESH_BASELINE_MISMATCH` | the config as written does not build, or does not reproduce the input's part (its attachment, image or `mesh_report.json` row) or its bones — or, for an `auto` entry, its motion; the first differing leaf is named. A part the producer cannot reproduce is not one it can re-fit with every other byte kept | pass the config and parts the input was built from |
|
|
2918
|
+
| <a id="REMESH_CANDIDATE_REFUSED"></a>`REMESH_CANDIDATE_REFUSED` | the rig stage refused the requested entry — its mode's own checks, an `auto` entry's bounds or its motion gate; each problem is quoted with its measured figure, and nothing was written | loosen the bound the quoted problem names, or ask for another mode |
|
|
2919
|
+
| <a id="REMESH_REQUEST_HELD"></a>`REMESH_REQUEST_HELD` | the requested entry moves a bone (a `<bone>_ctl` added or dropped), a motion key, or the part's image: no longer a remesh of one part | make it a config change and rebuild |
|
|
2920
|
+
| <a id="REMESH_PRESERVED"></a>`REMESH_PRESERVED` | the spliced revision differs from the input outside the part's attachment and its report row; the file and the part that moved are named | a defect in this package: report it with the line |
|
|
2921
|
+
| <a id="REMESH_RIGC_GREEN"></a>`REMESH_RIGC_GREEN` | rigc's build gate refused the revision (its lines quoted), or `rigc --version` named no version for the provenance | read rigc's line; nothing was written |
|
|
2922
|
+
| <a id="REMESH_CHECK_HELD"></a>`REMESH_CHECK_HELD` | `check` on the revision did not measure a bar it measured on the input, or failed a bar the input met; the revision's own FAIL line is quoted | ask for a finer entry, or a different mode, for the part the line names |
|
|
2923
|
+
|
|
2924
|
+
A remesh changes one part's mesh and nothing else: every file of the input but
|
|
2925
|
+
`rig.json` and `mesh_report.json` is copied as bytes, `rig.json` keeps every byte
|
|
2926
|
+
outside the part's attachment, and the parts the config does not reproduce — repairs
|
|
2927
|
+
accepted after the config was written — are carried over as they are. `remesh.json`
|
|
2928
|
+
names the input's SHA-256 per file, the request, both versions, the part's counts
|
|
2929
|
+
before and after and both checks, and quotes `check`'s own physics line as the scope
|
|
2930
|
+
of the revision's check.
|
|
2931
|
+
|
|
2845
2932
|
### rig-c's mesh refusals, quoted in a line
|
|
2846
2933
|
|
|
2847
2934
|
rig-c's mesh library refuses a malformed input by throwing with a code of its own. This
|
|
@@ -2894,6 +2981,7 @@ documents do not ship). Each is an input this package built; none is an author's
|
|
|
2894
2981
|
| <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 |
|
|
2895
2982
|
| <a id="CHECK_SEAM_OVER_RANGE"></a>`CHECK_SEAM_OVER_RANGE` | a limb joint with a declared `range` (issue #360), bent to one of its range's ends or its middle, fails the rest-pose seam's bar against the same pose with the joint's own art drawn under the limb — the bend uncovers the joint; the object names the joint, its limb and segment, the part, the bone and the angle. Under `cap_shape: "disc"` (issue #360, unit B), also any pixel of the disc over 40 at a pose, under the seam's bar or not. Also a joint the line cannot read (its bone has no parent in `rig.json`, no slot shows its limb, or its cap's disc holds no opaque art), and, refused, two renders of the bent copy that rigc did not put on one grid | a cap that covers the turn: the layer's art within the cap's radius on the upper side of the joint line, or a `cap` image painting what the layer lacks (`limb cap:` names the missing pixels); or a narrower `range` |
|
|
2896
2983
|
| <a id="SEAM_OVER_MOTION"></a>`SEAM_OVER_MOTION` | **a warning, never a refusal** (issue #493; the owner's ruling, 2026-10-18: a seam that opens in motion may be intended). Every declared neighbour pair — each limb's two segments at a joint, the upper and the one below (`parts.json`'s limb records, `config.limbs`), and under `--requirements` each `seam`'s `part` and `neighbour`, one pair however many declare it — read in every animation `motion.json` holds, the idle included, by rig-c's seam reading: one `rigc render --seam <a>:<b>,… --fps 12` over the packed build as played (physics on), whose `seam.json` (`rigc-seam/1`, rig-c's AUTHORING §8.8) names per pair and frame a **gap** (background inside the joint) or a **ghost** (one piece's overlap band swung clear of its partner), each frame's cells (`px`, one texel of the coarser drawing — a rig px on a build at scale 1), its cell size and its world box. Printed per pair and animation with a frame over the floor: `WARN seam "<a>\|<b>" opens on N frame(s) [<frames>] max <px> px in "<animation>" — over the one-cell floor`, then how many more frames rigc named that were under it. **The floor**: a frame's gap or ghost is reported when it holds more cells than its box is long (its longer side, in cells) — thicker than one cell. A cell is drawn when the renderer paints its centre at half opacity, so an outline that moves by less than a cell flips the cells along it: a line one cell deep, joined or scattered, holds at most as many cells as its box is long, and a hole of any area more. The rule types no number; measured on `examples/wind`'s idle, rigc names 43 openings over its six limb pairs (the two elbows, 1 to 5 cells, boxes up to 17 cells long), every one one cell thick, and on rig-c's `gallery/walk` 13 joint cracks of 1 to 3 cells, all one cell thick. `check.json`'s `SEAM_OVER_MOTION` holds `status` (`WARN`, `CLEAR`), `fps`, `floor`, `pairs`, `animations`, `warnings` and one row per pair and animation (`opens` and `px` over the floor, `max_px`, `under_floor`, rigc's `status`, `drawn` and `banded`); it moves no exit status, no `check: PASS` and no bar count — the summary ends `; N warning(s) (SEAM_OVER_MOTION, not a bar)`. **SKIP**, named: no pair declared (no limb segment, no `seam`; then `check.json` has no key), no `parts.json`, no animation, every pair naming a slot `rig.json` lacks (each printed `not read`), or rigc reading no band on any frame of any pair (rigc's own `skip`: the two drawings share no cell at rest) — nothing measured, never a pass | if the opening is not intended: a cap that covers the turn (`config.limbs`, *Limbs: cut at their joints*; `limb cap:` names the pixels the layer lacks), or a motion that bends that joint less; if it is intended, nothing |
|
|
2984
|
+
| <a id="CLOTH_SETTLES"></a>`CLOTH_SETTLES` | **a warning, never a refusal** (issue #501; the owner's ruling: cloth at rest while the character stands may be intended). Every physics chain, read by its tip on the idle `check` renders — `rigc render --animation idle --fps 12 --geometry`, physics on, rigc's default environment. A chain is a **physics leaf** — a bone a physics constraint names (`rig.json`'s `constraints` or `motion.json`'s `physics`) with no such bone under it — and the run of physics bones above it; its tip is the leaf's end (origin plus `length` along its world x axis), or its origin when the leaf has no length; its speed between frames is the tip's distance over their time, from the idle's `geometry.json`. A chain **settles** at the first frame from which every speed to the idle's last frame is under the floor, and each one that does — before the loop's length is out — prints `WARN chain "<root>" .. "<tip>" (N physics link(s)) settles at <t> s of the <d> s idle — its tip's end under 0.01694 rig px/s from there to the last frame (fastest on the idle <v> rig px/s)`. **The floor**, 0.01694 rig px/s, is derived, not chosen: half the slowest tip an idle key drives on the public examples (the repository's floor rule, half the weaker figure) — measured with this port's build of each (rig-c 2.60.0), over the 31 chains a keyed bone at or above the leaf drives (`demo` 12, `reference-sample` 1, `scarf` 11, `wind` 7) the slowest frame-to-frame tip speed is `scarf`'s `skirt_l2`, 0.03388 rig px/s; the ten no key drives — `wind`'s skirt, eight trees and the swing, hung from a `hip` its idle never keys, and `reference-sample`'s `hip_jiggle` — fall under it from 1.5 to 2.75 s on a 3.333 s idle (`hip_jiggle` at 0 s: it never moves) and end at 0.0025 rig px/s or less. `check.json`'s `CLOTH_SETTLES` holds `status` (`WARN`, `CLEAR`), `fps`, `frames`, `duration`, `floor_rig_px_per_s`, `floor`, `levers`, `warnings` and one row per chain (`tip`, `root`, `links`, `point` — `end` or `origin` — `settles_at`, null when it does not, `max_rig_px_per_s`, `min_rig_px_per_s`); it moves no exit status, no `check: PASS` and no bar count — the summary's warning clause names it, `; N warning(s) (CLOTH_SETTLES, not a bar)` (with `SEAM_OVER_MOTION` before it, and N their sum, where that read a pair). It reads the idle alone, one loop from rigc's physics reset at frame 0: a chain that settles later than the idle is long is not seen. **SKIP**, named: no physics constraint (then `check.json` has no key), or no idle — nothing measured, never a pass | if the chain should move while the character stands, one of the consumer's two levers: an environment at render (`rigc render --environment`, wind and gravity in time — rig-c's AUTHORING §8.4), or a consumer's animation that moves the bone the chain hangs from. The drafted idle keys no hip, by measurement: a hip turn at the idle's period fails a bar on all five public examples (issue #502, §3 *What moves them*). A `cloth` recipe's skirt hangs from `hip`, which the drafted idle never keys (§3, *Recipe: cloth and hair that answer the world*, *What moves them*, which has a worked schedule for `wind`). If it is intended, nothing |
|
|
2897
2985
|
| <a id="CHECK_FOLDS_READ"></a>`CHECK_FOLDS_READ` | the fold render's `frames.json` names no set for an animation, a `folds.json` is missing, not `rigc-folds/1`, another animation's or another rate's, or a folding mesh has no line rigc printed for it | a rigc problem; report it, with `rigc --version` |
|
|
2898
2986
|
| <a id="CHECK_SEAM_FRAME_SIZE"></a><a id="FRAMES_SIDECAR"></a><a id="CHECK_GEOMETRY_FILE"></a>`CHECK_SEAM_FRAME_SIZE`, `FRAMES_SIDECAR`, `CHECK_GEOMETRY_FILE` | rigc's render is not what its `frames.json` says, or its `geometry.json` is not a whole `rigc-geometry/1` export of the frames beside it (a frame count, a mesh whose vertex count differs from its rest entry; for the face half, another viewport than `frames.json`'s, other frame indices, the head bone or a feature's bone missing from a frame, a non-finite transform or time) | a rigc problem; report it |
|
|
2899
2987
|
| <a id="LOOP_ENCODE"></a>`LOOP_ENCODE` | the loop encoder refused a frame (translucent pixel in a GIF, a size change) | the frames; for a translucent frame write the lossless or the indexed APNG, which keep alpha |
|
package/docs/MIGRATION.md
CHANGED
|
@@ -341,3 +341,24 @@ moves (AUTHORING §6, `SEAM_OVER_MOTION`).
|
|
|
341
341
|
What to do: nothing. A warning names the pair, the animation, the frames and the cells;
|
|
342
342
|
an opening that is not intended wants a cap that covers the turn, or a motion that bends
|
|
343
343
|
less.
|
|
344
|
+
|
|
345
|
+
## After 1.38.0: cloth that comes to rest on the idle
|
|
346
|
+
|
|
347
|
+
Issue #501 reads every physics chain by its tip on the idle `check` renders (physics on,
|
|
348
|
+
rigc's default environment): a chain settles at the first frame from which its tip moves
|
|
349
|
+
slower than 0.01694 rig px/s to the idle's last frame, and the line warns when one
|
|
350
|
+
settles before the loop's length is out. It is a warning, never a bar: cloth at rest
|
|
351
|
+
while the character stands may be intended, so no exit status, no `check: PASS` and no
|
|
352
|
+
bar count moves (AUTHORING §6, `CLOTH_SETTLES`).
|
|
353
|
+
|
|
354
|
+
| change | before | after |
|
|
355
|
+
| --- | --- | --- |
|
|
356
|
+
| `check` on a rig with a physics constraint and an idle | not read | `CLOTH_SETTLES` in `check.json` after `SEAM_OVER_MOTION` (where that is written; else where it would be), its console lines after the `SEAM_OVER_MOTION` lines, one `WARN chain` line per chain that settles, and the summary's warning clause names it: `; N warning(s) (CLOTH_SETTLES, not a bar)`, or `(SEAM_OVER_MOTION, CLOTH_SETTLES, not a bar)` with N their sum where both read |
|
|
357
|
+
| `check` on any other rig | — | one console line, `CLOTH_SETTLES: SKIP — …`, naming why; no key in `check.json` |
|
|
358
|
+
| the public examples' `expected/check.json` | — | `demo`, `reference-sample`, `scarf` and `wind` gain the block: `wind`'s skirt (eight trees and the swing) and `reference-sample`'s `hip_jiggle` settle, every chain an idle key drives does not |
|
|
359
|
+
|
|
360
|
+
What to do: nothing. A warning names the chain and the second it comes to rest; a chain
|
|
361
|
+
that should keep moving wants an environment at render (`rigc render --environment`;
|
|
362
|
+
AUTHORING §3, *What moves them*, has a worked schedule for `wind`) or a consumer's
|
|
363
|
+
animation that moves the bone it hangs from. The drafted idle keys no hip: issue #502
|
|
364
|
+
measured a hip sway at the idle's period on every public example, and each failed a bar.
|
package/docs/STABILITY.md
CHANGED
|
@@ -61,6 +61,7 @@ defaults are the help's too, and none is guessed from the art.
|
|
|
61
61
|
| `build` | `--config`, `--source`, `--full`, `--out`; optional `--head` (as for `assemble`), `--seam`, `--project`, `--page-edges`, `--pack-shape`, `--loop`, `--lead-in`, `--requirements`, `--idle-keys`, `--seam-pairs`, `--keep-stills`, `--alt` (as for `assemble`, issue #454), `--set` or `--all-sets` (as for `check`, issue #454) |
|
|
62
62
|
| `compose` | `--scene`, `--out`; optional `--requirements`, `--accept` |
|
|
63
63
|
| `mesh-draft` | `--config`, `--parts`, `--out`; optional `--requirements`, `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon), `--more-triangles` |
|
|
64
|
+
| `remesh` | `--rig`, `--config`, `--parts`, `--part`, `--mesh`, `--out`; optional `--requirements`, `--idle-keys` (ctl, direct), `--page-edges` (pot, free), `--pack-shape` (rect, polygon) |
|
|
64
65
|
| `painting` | one positional path, the painting; `--keypoints`; optional `--person` |
|
|
65
66
|
| `guide` | one positional argument: a rule name, `§<n>`, `§<n>.<m>` or `§<n>.<m>.<k>` |
|
|
66
67
|
| (none) | `--version`, `--help` |
|
|
@@ -190,12 +191,13 @@ every number) are AUTHORING §3's tables, and the loader refuses any other by na
|
|
|
190
191
|
| `parts.json`, `parts/<name>.png` | `assemble`, `build` | one record per part: `from` (`<run>:<tag>` with a See-through v3 tag, `<run>:author:<label>` for a layer the author made — issue #256, read by no role rule — or `painting:<name>` for a patch), `cut_from` on a cut's piece only (the plan part it was cut from, issue #230), `limb` on a limb segment's part only (issue #349: `name`, `segment`, `of`, `bone`, and below a joint `joint`, `range` when the config segment declares one (issue #360), and `cap` — `at`, `width`, `radius`, `box`, `layer_px`, `image_px` with a cap image, `image_layer` after it when that image was a hidden-art layer — issue #359, `<run>:<layer>:hidden` — `missing_px`, then `shape` and `upper_px` under the segment's `cap_shape`, and `edge`, `feather_radius` and `feathered_px` under its `edge`, and `cut_band`, `cut_offset`, `cut_at`, `cut_crossed`, `joint_crossed`, `band_px` and `stroke_luma_max` (when the band has a split) under its `cut_band`, issue #360), the box `x`, `y`, `w`, `h` (rig px), the pixel counts `src/parts.ts` documents (`opaque_px`, `visible_px`, `occluded_px`, `projected_core_px`, `source_px_taken`, `visible_not_projected_px`, `refused_drift_px`, `merged_px`, `seam_override_px`, and `fringe_pushed_back` when not empty); `rig_size`, `scale_rig_per_source`, `ghost_px`, `recomposite`, and `scene` (`figure_alpha_above`, `figure_px`, `figure_mask`) under `config.scene` only, with the figure's mask `figure_rig.png` beside the recomposite (issue #242); `single_run_pad` (`file_size`, `side`, `left`, `top`) last, only for one run whose file is not the `seethrough.resolution` square (issue #366) |
|
|
191
192
|
| `rig/rig.json`, `rig/motion.json`, `rig/images/` | `rig`, `build`, `compose` | rig-c's rig spec and motion spec, `spec` `rigc-rig/1` and `rigc-motion/1`: the format is rig-c's, and this package writes only what rig-c's parser accepts; a bone carries `inherit` only where config.bones declares one, rig-c's mode name as written (issue #348) |
|
|
192
193
|
| `rig/mesh_report.json` | `rig`, `build` | one row per mesh: `part`, `vertices`, `triangles`, `hull`, `bones`, `max_influences`, `mean_influences`, `art_coverage`, then `grid` (a lattice); `mode` "contour" with `params`, `contour`, `regions` (`params.maxEdge` and `contour.outlineCut` only when the mesh declares `contour.maxEdge`; `params.bridges` and `contour.bridges` — `islands`, `units`, `joins`, and `faint` only when an island was left out as faint — only when it declares `contour.bridges`); or `mode` "auto" with `settings`, `source`, `result`, `residuals`, `worst_residual`, `worst_region`, `motion_amplitude`, `termination`, `weights`, `regions`, `deformation`, `quality_report` (rig-c's `mesh-quality-report/1` document whole), `motion_report`, and, only when they apply, `stray_cleared` (after `source`, when `source.stray` is declared), `skinning_residual` and `replay` (`AutoMeshReport` in `src/rig.ts`); in every mode, `exponent` when the mesh declares one (after `grid`, or after `mode`); `influences`, as declared, when a lattice or contour mesh declares it (after `exponent`, or where `exponent` would be); `stray` and `stray_cleared` when a lattice mesh declares `stray` (after `influences`, or where `influences` would be); `ribs` when a contour or auto mesh declares them (after `exponent`, or after `mode`), and then `contour.ribs` (`source.contour.ribs` in the automatic mode) |
|
|
193
|
-
| `check/check.json` and the rest of `check/` | `check`, `build`, `compose` | the reference's fields in its order (`gate_spine_html_green`, `rigc_entry`, `pack_mode`, `loop_max_diff`, the seam figures — `seam_mean`, `seam_px_over_40`, `seam_px_over_80` and, from issue #216, `seam_frame_scale`, the frame scale the bar divides the count by), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `seam_border` after the seam figures when `parts.json` declares a scene (issue #242), `seam_pairs` after the seam figures when the seam bar fails or `--seam-pairs` asks (each row's picture under `check/seam/`; `--keep-stills` leaves the setup-pose still and its `frames.json` under `check/setup_still/`), then the judgement lines (`BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`), `ANIMATIONS_DO_NOT_FOLD` after them when `motion.json` holds an animation, the idle included — on every rig with an idle since issue #333 (issues #320, #363: `status`, `animations`, `fps`, `physics_left_out`, `folding` — each `animation`, `slot`, `attachment`, `frames`, `worst_frame`, `worst_triangles`, `triangles`, `physics_on`, `physics_off`, `physics_constraints`, `declared`, `line` — `folding_undeclared`, `declared_not_folding`, `bar`), `FEET_STAY_LEVEL` after it when a `footwear` part rides a bone that hangs from another and `motion.json` holds an animation (issue #348: `status`, `reason` on a SKIP only, `animations`, `fps`, `physics_left_out`, `bar_degrees`, `bar`, `feet` — each `part`, `bone`, `hangs_from`, `status`, `frames_posed`, `worst`), `LIMB_ONE_BONE` after it (and after `STRESS_OFF_CHAIN` where that is written) when `parts.json` holds a limb segment's part (issue #349: `status`, `parts` — each `part`, `limb`, `bone`, `status`, `others`), `SEAM_OVER_RANGE` after it when a limb record carries a `range` (issue #360: `status`, `frame_scale`, `physics_left_out`, `bar` — `mean`, `rig_px_over_40`, `level` — and `joints`, each `part`, `limb`, `segment`, `joint`, `bone`, `range`, `at`, `radius`, `under_px`, `status`, `poses` — each `degrees`, `status`, `mean`, `px_over_40`, `px_over_80`, `rig_px_over_40` — and `unread` on a joint not read), `SEAM_OVER_MOTION` after it when `parts.json` holds a limb segment or `--requirements` a `seam` (issue #493, a warning and not a bar: `status` — `WARN`, `CLEAR` or `SKIP` — `reason` on a SKIP only, `fps`, `floor`, `pairs` — each `pair`, `a`, `b`, `declared`, and `unread` on a pair not read — `animations`, `warnings`, `rows` — each `pair`, `animation`, `status`, `drawn`, `banded`, `opens`, `px`, `max_px`, `under_floor`), `RECOMPOSITE_HOLES` (its first figure `declared_scene` when `parts.json` declares a scene), `SETUP_POSE_VS_SOURCE`, `skipped`, a `requirements` block under `--requirements`, and `PASS`; `check/build/skeleton.json`, `.atlas` and `.png` are the packed artifact rig-c writes |
|
|
194
|
+
| `check/check.json` and the rest of `check/` | `check`, `build`, `compose` | the reference's fields in its order (`gate_spine_html_green`, `rigc_entry`, `pack_mode`, `loop_max_diff`, the seam figures — `seam_mean`, `seam_px_over_40`, `seam_px_over_80` and, from issue #216, `seam_frame_scale`, the frame scale the bar divides the count by), `loop_physics` after `loop_max_diff` when the rig declares a physics constraint, `seam_border` after the seam figures when `parts.json` declares a scene (issue #242), `seam_pairs` after the seam figures when the seam bar fails or `--seam-pairs` asks (each row's picture under `check/seam/`; `--keep-stills` leaves the setup-pose still and its `frames.json` under `check/setup_still/`), then the judgement lines (`BREATH_VISIBLE`, `BLINK_NO_HOLE`, `CHAIN_LAG`, `TIP_OVER_ROOT`, `STILL_REGIONS_DARK`, `TEXTURE_STRETCH`), `ANIMATIONS_DO_NOT_FOLD` after them when `motion.json` holds an animation, the idle included — on every rig with an idle since issue #333 (issues #320, #363: `status`, `animations`, `fps`, `physics_left_out`, `folding` — each `animation`, `slot`, `attachment`, `frames`, `worst_frame`, `worst_triangles`, `triangles`, `physics_on`, `physics_off`, `physics_constraints`, `declared`, `line` — `folding_undeclared`, `declared_not_folding`, `bar`), `FEET_STAY_LEVEL` after it when a `footwear` part rides a bone that hangs from another and `motion.json` holds an animation (issue #348: `status`, `reason` on a SKIP only, `animations`, `fps`, `physics_left_out`, `bar_degrees`, `bar`, `feet` — each `part`, `bone`, `hangs_from`, `status`, `frames_posed`, `worst`), `LIMB_ONE_BONE` after it (and after `STRESS_OFF_CHAIN` where that is written) when `parts.json` holds a limb segment's part (issue #349: `status`, `parts` — each `part`, `limb`, `bone`, `status`, `others`), `SEAM_OVER_RANGE` after it when a limb record carries a `range` (issue #360: `status`, `frame_scale`, `physics_left_out`, `bar` — `mean`, `rig_px_over_40`, `level` — and `joints`, each `part`, `limb`, `segment`, `joint`, `bone`, `range`, `at`, `radius`, `under_px`, `status`, `poses` — each `degrees`, `status`, `mean`, `px_over_40`, `px_over_80`, `rig_px_over_40` — and `unread` on a joint not read), `SEAM_OVER_MOTION` after it when `parts.json` holds a limb segment or `--requirements` a `seam` (issue #493, a warning and not a bar: `status` — `WARN`, `CLEAR` or `SKIP` — `reason` on a SKIP only, `fps`, `floor`, `pairs` — each `pair`, `a`, `b`, `declared`, and `unread` on a pair not read — `animations`, `warnings`, `rows` — each `pair`, `animation`, `status`, `drawn`, `banded`, `opens`, `px`, `max_px`, `under_floor`), `CLOTH_SETTLES` after it when the rig declares a physics constraint and has an idle (issue #501, a warning and not a bar: `status` — `WARN` or `CLEAR` — `fps`, `frames`, `duration`, `floor_rig_px_per_s`, `floor`, `levers`, `warnings`, `rows` — each `tip`, `root`, `links`, `point`, `settles_at`, `max_rig_px_per_s`, `min_rig_px_per_s`), `RECOMPOSITE_HOLES` (its first figure `declared_scene` when `parts.json` declares a scene), `SETUP_POSE_VS_SOURCE`, `skipped`, a `requirements` block under `--requirements`, and `PASS`; `check/build/skeleton.json`, `.atlas` and `.png` are the packed artifact rig-c writes |
|
|
194
195
|
| `layers.json`, `<index>_<name>.png` | `layers --export` | the wrapper form `layers` reads (issue #359): `width`, `height`, then `layers` — each `name`, `filename`, `left`, `top`, `right`, `bottom`, `depth_median` (the input's own; `null` for a PSD, the manifest's order then being the draw order) — drawn layers in draw order, then the hidden-art layers; a PNG's name is its index and its layer's name, and the manifest, not the file name, says which layer it is |
|
|
195
196
|
| the template `.psd` | `layers --template` | one empty layer per name `templateLayerNames` (`src/layers.ts`) holds, bottom first; the same canvas writes the same bytes |
|
|
196
197
|
| `proposal.json`, `render/landmarks*.png` | `propose` | the config's four rig sections, `constraints` with `--cloth` (issue #364: a physics constraint per tree link named `<bone>_physics`, a dangling end's `<bone>_translate`, and a skirt swing's transforms `<swing>_<tree>`), `turn` with `--full`/`--head`, `proposed_rig_scale` (issue #354), and `notes` |
|
|
197
198
|
| `basis.json` | `propose` | spec `spine-parts-basis/1` |
|
|
198
199
|
| `config.json`, `mesh_draft.json` | `mesh-draft` | `config.json` is the config read, byte for byte, but for each drafted part's `meshes` entry; `mesh_draft.json` is spec `rig-parts-mesh-draft/1`: `rules`, `lattice_check`, `draft_check`, `figure_overdraw`, and per lattice part `part`, `mode`, `lattice`, `candidate` (with `bridges` — `units`, `joins` of `span` and `area_px2`, `area_px2`, `overdraw`, and `faint` only when an island was left out as faint — only when the candidate is a bridged one, issue #326), `delta` (under `--more-triangles` only), `readings`, `gate` (each line's `reading`, `pass`, `text`, `margin`), `note`; and `not_compared` (issue #307), only when the config holds an `auto` or `contour` entry: per such entry, in config order, `part`, `mode` and `note` — the part was neither drafted nor compared, and a config of lattices alone writes no such key |
|
|
200
|
+
| `rig.json`, `motion.json`, `mesh_report.json`, `images/`, `remesh.json` | `remesh` | the input revision's files, `rig.json` and `mesh_report.json` with the part's attachment and row replaced, every other file byte for byte; `remesh.json` is spec `rig-parts-remesh/1`: `request` (`part`, `mesh`, `mesh_sha256`, `idle_keys`, `page_edges`, `pack_shape`), `versions` (`parts`, `rigc`), `input` (`rig` — `path`, `bytes`, `sha256` per file — `config_sha256`, `parts_json_sha256`), `baseline` (`reproduced`, `not_compared`), `target` (`before`, `after`: `vertices`, `triangles`, `hull`), `preserved` (`identical`, `spliced`), `revision` (per file as `input.rig`), `check` (`input`, `revision`: `pass`, `measured`, `not_met`, `skipped`, `physics`; `scope`) |
|
|
199
201
|
| the scene report | `compose` | spec `spine-parts-scene-report/1` |
|
|
200
202
|
| `idle.png`, `idle-indexed.png`, `idle.gif` | `loop`, `build --loop` | APNG and GIF encodings of the rendered idle |
|
|
201
203
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rig-c/parts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.40.0",
|
|
4
4
|
"description": "AI-authored 2D character parts from one anime painting and its See-through layer decomposition: measured parts, weighted-mesh rig specs, verified through rig-c before anything is written. A CLI for agents that cannot see the image.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/build.ts
CHANGED
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
splitSchedule,
|
|
71
71
|
untestedIntervals,
|
|
72
72
|
} from './autoreplay.ts';
|
|
73
|
-
import { besideIdleLine, frameRuns, MOTION_SEAM_LINE, type MotionSeamLine, type MotionSeamPlant, motionSeamWarnText, FOLD_LINE, type FoldsLine, LEVEL_LINE, type LevelLine, LIMB_LINE, type LimbLine, STRESS_LINE, SWEEP_LINE, type SweepLine, buildGateLines, causeLines, IDLE_FPS, IDLE_MAX_PX, maxRgbDiff, REQUIREMENTS_DIR, type CheckReport, type PackLine, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, GATE_PROFILE, JUDGEMENT_LINES, type JudgementLine, packedBuildArgs, packedBuildLabel, type PackMode, type PackShape, type PageEdges, readFrameSet, rigcFailed, rigcIdentity, rigcRanClause, REPORTED_LINES, type ReportedLine, type RigcRunner, runCheck, SEAM_DIR, SEAM_MEAN_BAR, seamPairText, seamRigPxText, SOURCE_LINE, SEAM_PX_BAR, SEAM_PX_LEVEL, SEAM_PX_LEVEL_HIGH, SPINEBOY_YARDSTICK, STILL_DIR } from './check.ts';
|
|
73
|
+
import { besideIdleLine, CLOTH_LINE, type ClothLine, clothWarnText, frameRuns, MOTION_SEAM_LINE, type MotionSeamLine, type MotionSeamPlant, motionSeamWarnText, FOLD_LINE, type FoldsLine, LEVEL_LINE, type LevelLine, LIMB_LINE, type LimbLine, STRESS_LINE, SWEEP_LINE, type SweepLine, buildGateLines, causeLines, IDLE_FPS, IDLE_MAX_PX, maxRgbDiff, REQUIREMENTS_DIR, type CheckReport, type PackLine, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, GATE_PROFILE, JUDGEMENT_LINES, type JudgementLine, packedBuildArgs, packedBuildLabel, type PackMode, type PackShape, type PageEdges, readFrameSet, rigcFailed, rigcIdentity, rigcRanClause, REPORTED_LINES, type ReportedLine, type RigcRunner, runCheck, SEAM_DIR, SEAM_MEAN_BAR, seamPairText, seamRigPxText, SOURCE_LINE, SEAM_PX_BAR, SEAM_PX_LEVEL, SEAM_PX_LEVEL_HIGH, SPINEBOY_YARDSTICK, STILL_DIR } from './check.ts';
|
|
74
74
|
import { type Cut, type Extend, type Limb, loadConfig, loadConfigAndAnimations, loadEarlyConfig, type Patch, type PlanEntry } from './config.ts';
|
|
75
75
|
import { failLine, PartsError, type Problem, refuseIfAny } from './errors.ts';
|
|
76
76
|
import type { MeshQualityReport, MotionSchedule } from 'rig-c/mesh';
|
|
@@ -1506,6 +1506,28 @@ export function motionSeamLines(line: MotionSeamLine, plant: MotionSeamPlant = {
|
|
|
1506
1506
|
];
|
|
1507
1507
|
}
|
|
1508
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* The cloth reading (issue #501) as the console prints it: the status, what was read, the floor, the levers and that it
|
|
1511
|
+
* is not a bar, then one WARN line per chain that settles. A SKIP prints its reason alone. `silent` is the mutant that
|
|
1512
|
+
* removes the reading's lines.
|
|
1513
|
+
*/
|
|
1514
|
+
export function clothLines(line: ClothLine, plant: { silent?: boolean } = {}): string[] {
|
|
1515
|
+
if (plant.silent === true) return [];
|
|
1516
|
+
if (line.status === 'SKIP') return [`${CLOTH_LINE}: SKIP — ${String(line.reason)}`];
|
|
1517
|
+
const read = `${line.rows.length} physics chain(s) read by their tip on the idle as rendered (${line.frames} frame(s) at ${line.fps} fps over ${line.duration} s, physics on)`;
|
|
1518
|
+
return [
|
|
1519
|
+
`${CLOTH_LINE}: ${line.status} — ${read}: ${line.warnings} of them settle before the loop's length — ${line.warnings} warning(s), never a bar; ${line.floor}; ${line.levers}`,
|
|
1520
|
+
...line.rows.filter((r) => r.settles_at !== null).map((r) => clothWarnText(r, line.duration)),
|
|
1521
|
+
];
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
/** The summary's warning clause: each warning line that read something, named, with the warnings they printed together; empty when none read. */
|
|
1525
|
+
export function warningsClause(r: Pick<CheckReport, 'motionSeam' | 'cloth'>): string {
|
|
1526
|
+
const read = [...(r.motionSeam.status === 'SKIP' ? [] : [{ name: MOTION_SEAM_LINE, n: r.motionSeam.warnings }]), ...(r.cloth.status === 'SKIP' ? [] : [{ name: CLOTH_LINE, n: r.cloth.warnings }])];
|
|
1527
|
+
if (read.length === 0) return '';
|
|
1528
|
+
return `; ${read.reduce((a, x) => a + x.n, 0)} warning(s) (${read.map((x) => x.name).join(', ')}, not a bar)`;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1509
1531
|
/** A requirement's line as the console prints it: its name and status, the reason first when NOT MEASURABLE, then its figures as check.json holds them. */
|
|
1510
1532
|
export function requirementText(name: string, line: RequirementLine): string {
|
|
1511
1533
|
const rest = Object.entries(line).filter(([k]) => k !== 'status' && k !== 'reason');
|
|
@@ -1565,6 +1587,7 @@ export function checkStage(input: CheckStageInput, rigc: RigcRunner, bin: string
|
|
|
1565
1587
|
const sweep = fig[SWEEP_LINE];
|
|
1566
1588
|
if (sweep !== undefined) for (const [i, l] of sweepCheckLines(sweep).entries()) log(` ${i === 0 ? '' : ' '}${l}`);
|
|
1567
1589
|
for (const [i, l] of motionSeamLines(r.motionSeam).entries()) log(` ${i === 0 ? '' : ' '}${l}`);
|
|
1590
|
+
for (const [i, l] of clothLines(r.cloth).entries()) log(` ${i === 0 ? '' : ' '}${l}`);
|
|
1568
1591
|
for (const name of REPORTED_LINES) log(` ${judgementLine(name, fig[name])}`);
|
|
1569
1592
|
if (fig.sets !== undefined) {
|
|
1570
1593
|
for (const [setName, setFig] of Object.entries(fig.sets)) {
|
|
@@ -1582,7 +1605,7 @@ export function checkStage(input: CheckStageInput, rigc: RigcRunner, bin: string
|
|
|
1582
1605
|
for (const p of r.problems) log(failLine(p));
|
|
1583
1606
|
const reqNotPass = r.requirements === null ? 0 : r.requirements.summary.declared - r.requirements.summary.pass;
|
|
1584
1607
|
const notMet = r.requirements === null ? `${r.problems.length} bar(s) not met` : `${r.problems.length - reqNotPass} bar(s) not met, ${reqNotPass} declared requirement(s) not PASS`;
|
|
1585
|
-
log(`${fig.PASS ? 'check: PASS' : `check: FAIL — ${notMet}`}; ${barsSummary(r)}${r
|
|
1608
|
+
log(`${fig.PASS ? 'check: PASS' : `check: FAIL — ${notMet}`}; ${barsSummary(r)}${warningsClause(r)}`);
|
|
1586
1609
|
return r;
|
|
1587
1610
|
}
|
|
1588
1611
|
|