spine-rigc 0.36.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/cli.ts +15 -1
- package/docs/AUTHORING.md +113 -23
- package/docs/INGEST.md +0 -1
- package/docs/SPEC_COVERAGE.md +1 -1
- package/package.json +1 -1
- package/src/atlas.ts +41 -3
- package/src/compile.ts +164 -41
- package/src/ingest.ts +8 -13
- package/src/rig.ts +24 -10
- package/src/timelines.ts +227 -18
- package/src/transform.ts +141 -13
- package/src/types.ts +22 -10
- package/src/validate.ts +45 -11
- package/tools/editor_roundtrip.ts +75 -6
package/src/compile.ts
CHANGED
|
@@ -95,6 +95,7 @@ import {
|
|
|
95
95
|
pageFootprint,
|
|
96
96
|
pageGridSaid,
|
|
97
97
|
pageGridSentence,
|
|
98
|
+
canonicalAtlasShape,
|
|
98
99
|
parseAtlasText,
|
|
99
100
|
rewritePageNames,
|
|
100
101
|
writeAtlasText,
|
|
@@ -2463,6 +2464,14 @@ function compileInto(opts: CompileOptions, droppedStates: DroppedState[]): Compi
|
|
|
2463
2464
|
// for — `scale:` most expensively — so the text passes through by line and only
|
|
2464
2465
|
// the name lines are replaced (`rewritePageNames`).
|
|
2465
2466
|
//
|
|
2467
|
+
// 🔸 Its BLANK lines are the one thing put into rigc's shape
|
|
2468
|
+
// (`canonicalAtlasShape`, issue #803): none before the first entry, one between
|
|
2469
|
+
// blocks, one trailing newline. The runtime reads any run of blank lines as
|
|
2470
|
+
// one, and a 3.8-era packer opens every file with one, which `A07` read at
|
|
2471
|
+
// `line 1` and refused — the gate refusing a whitespace choice of a packer
|
|
2472
|
+
// rigc re-anchored, on a pack every 4.x runtime loads. Non-blank lines are
|
|
2473
|
+
// untouched, so a pack already in that shape is emitted byte for byte as before.
|
|
2474
|
+
//
|
|
2466
2475
|
// ⚠️ Regions the rig does not use stay in the emitted atlas. They are not a
|
|
2467
2476
|
// defect: a real pack is shared between cuts, an unused region costs a consumer
|
|
2468
2477
|
// nothing, and dropping them would make `--out` disagree with the pack it was
|
|
@@ -2470,8 +2479,8 @@ function compileInto(opts: CompileOptions, droppedStates: DroppedState[]): Compi
|
|
|
2470
2479
|
const atlasText =
|
|
2471
2480
|
atlasIn === null
|
|
2472
2481
|
? buildAtlasText(images)
|
|
2473
|
-
:
|
|
2474
|
-
relative(outDir, resolve(atlasIn.dir, name)).split('\\').join('/'),
|
|
2482
|
+
: canonicalAtlasShape(
|
|
2483
|
+
rewritePageNames(atlasIn.parsed, (name) => relative(outDir, resolve(atlasIn.dir, name)).split('\\').join('/')),
|
|
2475
2484
|
);
|
|
2476
2485
|
|
|
2477
2486
|
// -- 3. bones --------------------------------------------------------------
|
|
@@ -2523,10 +2532,32 @@ function compileInto(opts: CompileOptions, droppedStates: DroppedState[]): Compi
|
|
|
2523
2532
|
};
|
|
2524
2533
|
/** Linked meshes to resolve once every skin exists — see `resolveLinkedMeshes`. */
|
|
2525
2534
|
const pendingLinks: PendingLink[] = [];
|
|
2526
|
-
|
|
2527
|
-
//
|
|
2528
|
-
//
|
|
2529
|
-
//
|
|
2535
|
+
// 🔑 **A `default` skin is emitted exactly when the spec has one** (issue #801):
|
|
2536
|
+
// the rig spec's `skins` carries the key — empty or not — or a manifest part
|
|
2537
|
+
// files its states under it (the loop below). Otherwise there is none, which is
|
|
2538
|
+
// the shape the editor's own export has: a rig whose art all lives in named
|
|
2539
|
+
// skins came back from 4.3.26 with `skins` 3 → 2, the empty `default` gone,
|
|
2540
|
+
// and `SkeletonBinary.readSkin` returns null for a default skin with no slots,
|
|
2541
|
+
// so the binary half cannot even hold one. The runtime treats the two
|
|
2542
|
+
// spellings alike — `SkeletonData.defaultSkin` is null or an empty skin, and
|
|
2543
|
+
// `Skeleton.getAttachment` finds nothing in either (`Skeleton.js:335-346`).
|
|
2544
|
+
// This line used to create it unconditionally, "even when it is empty", which
|
|
2545
|
+
// made every rebuild of such an export differ from it by one skin — a value
|
|
2546
|
+
// the spec never stated.
|
|
2547
|
+
//
|
|
2548
|
+
// Created HERE, before the slot loop, rather than lazily by the first part
|
|
2549
|
+
// that fills it, so `skinTables` keeps `default` first whichever of the two
|
|
2550
|
+
// put it there, and every refusal that lists the emitted skins lists them in
|
|
2551
|
+
// the order it did before.
|
|
2552
|
+
const partsFillDefault = rig.slots.some(
|
|
2553
|
+
(rigSlot) =>
|
|
2554
|
+
partBySlot.has(rigSlot.name) &&
|
|
2555
|
+
(slotAttachments.get(rigSlot.name) ?? rigAttachmentNames.get(rigSlot.name) ?? []).length > 0,
|
|
2556
|
+
);
|
|
2557
|
+
if (skinNames.includes(DEFAULT_SKIN) || partsFillDefault) tableFor(DEFAULT_SKIN);
|
|
2558
|
+
// ...and every skin the rig declares: a skin can carry `bones`/constraint lists
|
|
2559
|
+
// with no attachments at all, and a skin that only switches bones on would
|
|
2560
|
+
// otherwise never reach the emitted array.
|
|
2530
2561
|
for (const skinName of skinNames) tableFor(skinName);
|
|
2531
2562
|
const meshBones = new Set<string>();
|
|
2532
2563
|
const meshes: CompileResult['meshes'] = [];
|
|
@@ -4028,6 +4059,17 @@ function setupWorldVertices(
|
|
|
4028
4059
|
* two are the outer control handles of the end knots, which no curve uses. A
|
|
4029
4060
|
* closed path instead rotates by one and repeats the first knot at the end.
|
|
4030
4061
|
* Either way what comes out is a `3K + 1` chain: knot, handle, handle, knot, …
|
|
4062
|
+
*
|
|
4063
|
+
* ⭐ **`lengths` is measured over the CLOSED chain whether the path is closed or
|
|
4064
|
+
* not** (issue #804), because that is the array the format holds: the parser
|
|
4065
|
+
* sizes it `vertexCount / 3` on both (`SkeletonJson.js:601`), which on an open
|
|
4066
|
+
* path is one more than its curves, and the editor fills that last entry with
|
|
4067
|
+
* the wrap-around curve's cumulative — measured on a 4.3 production export, all
|
|
4068
|
+
* four of whose entries the closed chain over the runtime's own posed vertices
|
|
4069
|
+
* reproduces to the digit it prints. The open chain is the closed chain's
|
|
4070
|
+
* prefix, so the entries the runtime reads are the same numbers either way; the
|
|
4071
|
+
* trailing one is read by nothing, and is written so a rebuild is the file the
|
|
4072
|
+
* editor writes rather than one entry short of it.
|
|
4031
4073
|
*/
|
|
4032
4074
|
function pathChain(points: Array<[number, number]>, closed: boolean): Array<[number, number]> {
|
|
4033
4075
|
if (!closed) return points.slice(1, points.length - 1);
|
|
@@ -4050,11 +4092,33 @@ function pathChain(points: Array<[number, number]>, closed: boolean): Array<[num
|
|
|
4050
4092
|
* — `0.1875 = 3t²`, `0.09375 = 6t³`, `0.75 = 3t`, `0.16666667` standing in for
|
|
4051
4093
|
* 1/6 — accumulating four `Math.sqrt` terms per curve into a running
|
|
4052
4094
|
* `pathLength`, and writing the running value into `curves[i]` at each curve's
|
|
4053
|
-
* end. The Spine editor's exported `lengths` are that same computation
|
|
4054
|
-
*
|
|
4055
|
-
*
|
|
4056
|
-
*
|
|
4057
|
-
*
|
|
4095
|
+
* end. The Spine editor's exported `lengths` are that same computation, and the
|
|
4096
|
+
* loop below is a transcription of it, not a sampler that happens to agree.
|
|
4097
|
+
*
|
|
4098
|
+
* 🚨 **What that computation is fed decides the number, and this comment once
|
|
4099
|
+
* claimed more than was measured** (issue #804). It said the loop matched the
|
|
4100
|
+
* editor to every digit it printed — true on the two exports it was measured on,
|
|
4101
|
+
* one open and one closed path on unweighted, unscaled, unconstrained rigs, and
|
|
4102
|
+
* false in production on two counts:
|
|
4103
|
+
*
|
|
4104
|
+
* - **Geometry.** The editor measures the world positions of the posed
|
|
4105
|
+
* vertices. rigc blends weighted vertices through its own setup transforms,
|
|
4106
|
+
* which until #804 ignored bone scale, shear and `inherit` — 2.35× the
|
|
4107
|
+
* runtime's own `curves` on a production rig's weighted path, 0.752× on a
|
|
4108
|
+
* 50/50 probe over a bone at scale 2. `computeWorldTransforms` is now the
|
|
4109
|
+
* runtime's, and the gap is gone on both.
|
|
4110
|
+
* - **Constraints.** The runtime measures the pose its update order hands the
|
|
4111
|
+
* path constraint at the first `updateWorldTransform`: a transform
|
|
4112
|
+
* constraint on the path's slot bone ordered BEFORE the path constraint
|
|
4113
|
+
* moves the curves (416.14 → 551.59 on a probe), one ordered after does
|
|
4114
|
+
* not. A production 4.2 export's four numbers are the constrained pose's to
|
|
4115
|
+
* the digit, and its unconstrained setup measures 76.08 against 76.65 on the
|
|
4116
|
+
* first curve. Reproducing that means solving every constraint type in
|
|
4117
|
+
* update order, which is posing — and `src/compile.ts` does not link the
|
|
4118
|
+
* runtime. ⇒ **An omitted `lengths` is measured on the unconstrained setup
|
|
4119
|
+
* pose**, and a path whose bones a constraint moves at rest gets that
|
|
4120
|
+
* figure. What closes the gap for an editor export is not measuring at all:
|
|
4121
|
+
* a stated `lengths` is carried (`buildRigPath`).
|
|
4058
4122
|
*
|
|
4059
4123
|
* ⚠️ rigc measured this with a 64-chord sum until issue #560, and the comment
|
|
4060
4124
|
* that stood here argued the difference was inside anything's tolerance. It was
|
|
@@ -4065,7 +4129,7 @@ function pathChain(points: Array<[number, number]>, closed: boolean): Array<[num
|
|
|
4065
4129
|
* two apart and since issue #716 rigc's own file can only where the two land on
|
|
4066
4130
|
* either side of a float's boundary. Under the six-decimal rounding that stood
|
|
4067
4131
|
* until then it could: on both measured rigs the two spellings differed on the
|
|
4068
|
-
* LAST curve, where the accumulated difference is largest. `PS67
|
|
4132
|
+
* LAST curve, where the accumulated difference is largest. `PS67`, `PS68` and `PS186` in `selftest.ts` compare
|
|
4069
4133
|
* this against `PathConstraint`'s own `curves` array read off a posed skeleton,
|
|
4070
4134
|
* which is the only oracle that can see that gap.
|
|
4071
4135
|
*
|
|
@@ -4118,20 +4182,17 @@ function pathCurveLengths(chain: Array<[number, number]>): number[] {
|
|
|
4118
4182
|
* groups of six then straddle the knots, and bones slide along a curve
|
|
4119
4183
|
* nobody drew. Too few points is the same failure with fewer symptoms — an
|
|
4120
4184
|
* open path needs 6 for one curve, a closed one 3.
|
|
4121
|
-
* 2.
|
|
4122
|
-
*
|
|
4123
|
-
*
|
|
4124
|
-
*
|
|
4125
|
-
*
|
|
4185
|
+
* 2. **A stated `lengths` is carried as stated** (issue #804), and checked for
|
|
4186
|
+
* the one shape the parser cannot hold: `vertexCount / 3` entries, each
|
|
4187
|
+
* finite and none below the one before it. The file is the record of what
|
|
4188
|
+
* was measured, and the number an editor export states is the editor's
|
|
4189
|
+
* measurement of a pose rigc cannot reproduce without posing (see
|
|
4190
|
+
* `pathCurveLengths`) — so re-deriving it moved a production rig's bones by
|
|
4191
|
+
* up to 0.0054 in issue #804's pose comparison, where carrying it moved none.
|
|
4192
|
+
* 3. **An omitted one is measured**, `vertexCount / 3` entries over the closed
|
|
4193
|
+
* chain (`pathChain`), on the unconstrained setup pose.
|
|
4126
4194
|
*/
|
|
4127
4195
|
function buildRigPath(att: RigPathAttachment, where: string, ctx: AttachmentContext): SpinePathAttachment {
|
|
4128
|
-
if (att.lengths !== undefined) {
|
|
4129
|
-
throw new CompileError(
|
|
4130
|
-
`${where}: "lengths" is not authored — rigc measures the setup arc length of each curve off the geometry, the ` +
|
|
4131
|
-
'same way it measures a region\'s size off its PNG. A restated length that disagrees with the vertices is ' +
|
|
4132
|
-
'invisible until `constantSpeed` is false, and then it rescales the whole traversal in silence.',
|
|
4133
|
-
);
|
|
4134
|
-
}
|
|
4135
4196
|
const vertices = buildVertexGeometry(att, where, ctx);
|
|
4136
4197
|
const count = att.vertexCount;
|
|
4137
4198
|
const closed = att.closed === true;
|
|
@@ -4149,15 +4210,25 @@ function buildRigPath(att: RigPathAttachment, where: string, ctx: AttachmentCont
|
|
|
4149
4210
|
`${closed ? 'a closed path of K curves carries 3K points' : 'an open one carries 3(K + 1), the first and last being the end knots\' outer handles'}`,
|
|
4150
4211
|
);
|
|
4151
4212
|
}
|
|
4152
|
-
const
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
);
|
|
4213
|
+
const entries = count / 3;
|
|
4214
|
+
let lengths: number[];
|
|
4215
|
+
if (att.lengths !== undefined) {
|
|
4216
|
+
lengths = statedPathLengths(att.lengths, entries, closed, where);
|
|
4217
|
+
} else {
|
|
4218
|
+
const anchor = ctx.transforms.get(ctx.anchorBone);
|
|
4219
|
+
if (!anchor) throw new CompileError(`${where}: slot bone "${ctx.anchorBone}" has no setup transform`);
|
|
4220
|
+
const points = setupWorldVertices(vertices, count, anchor, ctx.bones, ctx.transforms, where);
|
|
4221
|
+
lengths = pathCurveLengths(pathChain(points, true));
|
|
4222
|
+
// The total the runtime reads is the last CURVE's entry, `lengths[vertexCount
|
|
4223
|
+
// / 3 - (closed ? 1 : 2)]` (`PathConstraint.js:204-206`) — on an open path
|
|
4224
|
+
// the one before the trailing wrap-around entry, which nothing reads.
|
|
4225
|
+
const total = lengths[closed ? entries - 1 : entries - 2];
|
|
4226
|
+
if (lengths.length !== entries || !lengths.every((n) => Number.isFinite(n)) || !(total > 0)) {
|
|
4227
|
+
throw new CompileError(
|
|
4228
|
+
`${where}: the geometry measures ${lengths.length} entry(ies) where the parser sizes ${entries}, of total ` +
|
|
4229
|
+
`length ${String(total)}; a path of zero length divides by zero the first time a bone is placed on it`,
|
|
4230
|
+
);
|
|
4231
|
+
}
|
|
4161
4232
|
}
|
|
4162
4233
|
// Field order is the parser's reading order (`:606-623`), and each optional key
|
|
4163
4234
|
// is present exactly when the spec declared it — the rule the whole rig spec
|
|
@@ -4173,6 +4244,50 @@ function buildRigPath(att: RigPathAttachment, where: string, ctx: AttachmentCont
|
|
|
4173
4244
|
};
|
|
4174
4245
|
}
|
|
4175
4246
|
|
|
4247
|
+
/**
|
|
4248
|
+
* A stated `lengths`, checked for the shape the parser needs and returned as
|
|
4249
|
+
* stated (issue #804).
|
|
4250
|
+
*
|
|
4251
|
+
* 🔒 **The count is the parser's, not the constraint's.** `SkeletonJson.js:601`
|
|
4252
|
+
* allocates `vertexCount / 3` entries on an open path and a closed one alike and
|
|
4253
|
+
* copies what the file gives: a SHORT array leaves zeros the constraint then
|
|
4254
|
+
* reads as a curve's end (a position divided by 0, in silence), and a LONG one
|
|
4255
|
+
* grows the array past what the attachment's own geometry has. Both are refused
|
|
4256
|
+
* with the two counts rather than trimmed or padded, because either repair is a
|
|
4257
|
+
* value the spec did not state.
|
|
4258
|
+
*
|
|
4259
|
+
* ⚠️ Equal neighbours are accepted here and refused by `A33` where the runtime
|
|
4260
|
+
* reads them — a zero-length curve is a fact about the pose, which the gate
|
|
4261
|
+
* measures; a DECREASING entry is not a cumulative length at all, on any pose.
|
|
4262
|
+
*/
|
|
4263
|
+
function statedPathLengths(stated: unknown, entries: number, closed: boolean, where: string): number[] {
|
|
4264
|
+
if (!Array.isArray(stated)) {
|
|
4265
|
+
throw new CompileError(`${where}: "lengths" is ${JSON.stringify(stated)}; it is an array of ${entries} number(s)`);
|
|
4266
|
+
}
|
|
4267
|
+
if (stated.length !== entries) {
|
|
4268
|
+
throw new CompileError(
|
|
4269
|
+
`${where}: "lengths" has ${stated.length} entry(ies) where the parser sizes ${entries} — vertexCount / 3 on ` +
|
|
4270
|
+
`${closed ? 'a closed' : 'an open'} path${closed ? '' : ', one more than its curves: the editor writes the wrap-around curve\'s cumulative last and nothing reads it'}. ` +
|
|
4271
|
+
'Give the array the source states, or leave the field out and rigc measures it',
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
let previous = 0;
|
|
4275
|
+
for (let i = 0; i < stated.length; i++) {
|
|
4276
|
+
const value: unknown = stated[i];
|
|
4277
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4278
|
+
throw new CompileError(`${where}: "lengths"[${i}] is ${JSON.stringify(value)}; every entry is a finite cumulative length`);
|
|
4279
|
+
}
|
|
4280
|
+
if (value < previous) {
|
|
4281
|
+
throw new CompileError(
|
|
4282
|
+
`${where}: "lengths"[${i}] is ${value}, below ${i === 0 ? '0' : `the ${previous} before it`}. The array is CUMULATIVE — the length at ` +
|
|
4283
|
+
'the end of each curve — so no entry is below its predecessor',
|
|
4284
|
+
);
|
|
4285
|
+
}
|
|
4286
|
+
previous = value;
|
|
4287
|
+
}
|
|
4288
|
+
return stated as number[];
|
|
4289
|
+
}
|
|
4290
|
+
|
|
4176
4291
|
/**
|
|
4177
4292
|
* The compiled image an attachment's `image` names — or a refusal that names the
|
|
4178
4293
|
* file and says what is actually wrong with it.
|
|
@@ -4857,13 +4972,21 @@ function resolveLinkedMeshes(
|
|
|
4857
4972
|
): void {
|
|
4858
4973
|
const skinNames = [...tables.keys()];
|
|
4859
4974
|
for (const link of links) {
|
|
4860
|
-
// ⚠️
|
|
4861
|
-
//
|
|
4862
|
-
//
|
|
4863
|
-
//
|
|
4864
|
-
//
|
|
4865
|
-
//
|
|
4975
|
+
// ⚠️ An omitted `skin` can miss here too since issue #801: rigc emits a
|
|
4976
|
+
// `default` skin only when the spec has one, and the parser's default for a
|
|
4977
|
+
// link is `skeletonData.defaultSkin`, which is then null — the runtime reads
|
|
4978
|
+
// `getAttachment` off it and throws a `TypeError` naming neither. So the
|
|
4979
|
+
// omitted case is said separately, because "the skin is default" would be a
|
|
4980
|
+
// sentence about a value nobody wrote.
|
|
4866
4981
|
const table = tables.get(link.skin);
|
|
4982
|
+
if (table === undefined && !link.skinStated) {
|
|
4983
|
+
throw new CompileError(
|
|
4984
|
+
`${link.where}: no "skin" is stated, so the parser looks for the source "${link.source}" in the default ` +
|
|
4985
|
+
`skin — and this rig declares no default skin. The rig's skins are ${skinNames.map((s) => JSON.stringify(s)).join(', ')}. ` +
|
|
4986
|
+
'State the skin the source is filed under. Left to the round trip this is a `TypeError` off the null ' +
|
|
4987
|
+
'`SkeletonData.defaultSkin`, which names neither this attachment nor where it was looking.',
|
|
4988
|
+
);
|
|
4989
|
+
}
|
|
4867
4990
|
if (table === undefined) {
|
|
4868
4991
|
throw new CompileError(
|
|
4869
4992
|
`${link.where}: "skin" is ${JSON.stringify(link.skin)}, and the rig declares no such skin. The rig's skins ` +
|
|
@@ -7189,8 +7312,8 @@ function deformGeometryOf(
|
|
|
7189
7312
|
//
|
|
7190
7313
|
// - `lengths` is a field of the ATTACHMENT. The format has nowhere to put
|
|
7191
7314
|
// a per-key length, so no export of any tool carries a re-measured one;
|
|
7192
|
-
// the editor's own is the setup measurement, which
|
|
7193
|
-
// `pathCurveLengths`
|
|
7315
|
+
// the editor's own is the setup measurement, which a stated array
|
|
7316
|
+
// carries and `pathCurveLengths` measures when none is stated.
|
|
7194
7317
|
// - `PathConstraint.computeWorldPositions` reads that field only under
|
|
7195
7318
|
// `constantSpeed: false` (`PathConstraint.js:205`). Under the parser's
|
|
7196
7319
|
// default, `true`, it re-measures the curve from the posed world
|
package/src/ingest.ts
CHANGED
|
@@ -124,8 +124,8 @@ export class IngestSpecRefused extends Error {
|
|
|
124
124
|
* - `judgement` — the skeleton does not carry it and somebody decided. There
|
|
125
125
|
* are exactly two: a stage the caller supplied, and an animation's duration.
|
|
126
126
|
* - `lossy` — the skeleton's spelling and rigc's differ, on purpose, and the
|
|
127
|
-
* difference is named: a value rigc re-derives rather than takes (
|
|
128
|
-
*
|
|
127
|
+
* difference is named: a value rigc re-derives rather than takes (the
|
|
128
|
+
* `spine` version), a field the spec has no home for (`hash`), or
|
|
129
129
|
* a default the source left to the format and the rebuild writes out
|
|
130
130
|
* (`HEADER_ORIGIN`, issue #622). The rebuilt file is a different file in that
|
|
131
131
|
* field; it is not a different rig.
|
|
@@ -1407,17 +1407,12 @@ function ingestAttachment(
|
|
|
1407
1407
|
out.vertexCount = att.vertexCount;
|
|
1408
1408
|
geometry(vertexCount);
|
|
1409
1409
|
for (const field of ['closed', 'constantSpeed', 'color']) if (att[field] !== undefined) out[field] = att[field];
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
'`PathConstraint` does (issue #560, `pathCurveLengths`). Dropping it is correct: the field is the ' +
|
|
1417
|
-
"runtime's own four-sample forward difference, not an arc length, and a transcribed one would freeze " +
|
|
1418
|
-
'whatever produced the source',
|
|
1419
|
-
);
|
|
1420
|
-
}
|
|
1410
|
+
// Carried verbatim (issue #804), where until then it was dropped as `LOSS
|
|
1411
|
+
// PATH_LENGTHS` and re-measured. The editor measures it on the pose the
|
|
1412
|
+
// first update gives the path constraint — constraints applied — and rigc
|
|
1413
|
+
// does not pose, so the re-measure was a different number on every path a
|
|
1414
|
+
// constraint moves at rest, and on every weighted path over a scaled bone.
|
|
1415
|
+
if (att.lengths !== undefined) out.lengths = att.lengths;
|
|
1421
1416
|
} else {
|
|
1422
1417
|
note(
|
|
1423
1418
|
'blocker',
|
package/src/rig.ts
CHANGED
|
@@ -827,7 +827,7 @@ export interface RigLinkedMeshAttachment {
|
|
|
827
827
|
sequence?: RigSequence;
|
|
828
828
|
/**
|
|
829
829
|
* 🚫 Every geometry field a mesh may state, refused by name on a link. They
|
|
830
|
-
* are declared
|
|
830
|
+
* are declared so the refusal can name them: a key the shape
|
|
831
831
|
* does not hold at all comes back as *keys this compiler does not read … fix
|
|
832
832
|
* the spelling or remove it*, and the remedy sentence is wrong here — the
|
|
833
833
|
* fault is not a typo, it is that the parser reads none of them on a link.
|
|
@@ -938,12 +938,22 @@ export interface RigClippingAttachment extends RigVertexGeometry {
|
|
|
938
938
|
* six then straddle the knots, and the constraint slides bones along a curve
|
|
939
939
|
* nobody drew.
|
|
940
940
|
*
|
|
941
|
-
*
|
|
942
|
-
*
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
*
|
|
941
|
+
* ⭐ `lengths` is **stated or measured** (issue #804). It is the cumulative
|
|
942
|
+
* length at the end of each curve, in world units, and `vertexCount / 3` entries
|
|
943
|
+
* on an open path and a closed one alike — the parser's allocation, one more
|
|
944
|
+
* than an open path's curves, the last being the wrap-around curve's cumulative,
|
|
945
|
+
* which nothing reads. Stated, it is emitted as stated: that is what `ingest`
|
|
946
|
+
* writes from an export, because the editor measured it on a pose rigc does not
|
|
947
|
+
* reproduce (below). Left out, rigc measures it off the geometry on the
|
|
948
|
+
* unconstrained setup pose. Only `constantSpeed: false` reads it.
|
|
949
|
+
*
|
|
950
|
+
* ⚠️ Why a stated one is not re-measured: the editor's numbers are
|
|
951
|
+
* `PathConstraint`'s own measurement of the pose the first update gives it —
|
|
952
|
+
* with every constraint ordered before the path constraint applied. rigc does
|
|
953
|
+
* not pose, so an authored path whose bones a constraint moves at rest gets the
|
|
954
|
+
* unconstrained figure, and an export's own array is the only way to carry the
|
|
955
|
+
* constrained one. Re-deriving it moved 232 of a production rig's 259 bones in
|
|
956
|
+
* issue #804's pose comparison.
|
|
947
957
|
*
|
|
948
958
|
* 🔸 *Which* length, exactly, is `SpinePathAttachment`'s subject in
|
|
949
959
|
* [`types.ts`](types.ts) and it is not the arc: it is `PathConstraint`'s own
|
|
@@ -966,8 +976,8 @@ export interface RigPathAttachment extends RigVertexGeometry {
|
|
|
966
976
|
*/
|
|
967
977
|
constantSpeed?: boolean;
|
|
968
978
|
/**
|
|
969
|
-
*
|
|
970
|
-
*
|
|
979
|
+
* Stated: exactly `vertexCount / 3` finite entries, none below the one before
|
|
980
|
+
* it, emitted as stated. Absent: measured — see the note above.
|
|
971
981
|
*/
|
|
972
982
|
lengths?: number[];
|
|
973
983
|
}
|
|
@@ -1631,7 +1641,11 @@ export interface RigSpec {
|
|
|
1631
1641
|
bones: RigBone[];
|
|
1632
1642
|
slots: RigSlot[];
|
|
1633
1643
|
/**
|
|
1634
|
-
*
|
|
1644
|
+
* `default`, if the rig has one, becomes `skeletonData.defaultSkin` (`:441`).
|
|
1645
|
+
* It is emitted exactly when this map carries the key — an empty `{}` included
|
|
1646
|
+
* — or a manifest part files its states under it; a rig whose art is all in
|
|
1647
|
+
* named skins states no `default` and gets none, which is what the editor's
|
|
1648
|
+
* export of such a rig declares (issue #801).
|
|
1635
1649
|
*
|
|
1636
1650
|
* Each entry is either the short form — `slotName -> placeholderName ->
|
|
1637
1651
|
* attachment` — or the long one, `{ "attachments": {…}, "bones": [...],
|