spine-rigc 0.35.0 โ 0.35.1
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/docs/AUTHORING.md +36 -0
- package/package.json +1 -1
- package/src/compile.ts +92 -19
- package/src/types.ts +2 -1
package/docs/AUTHORING.md
CHANGED
|
@@ -1045,6 +1045,15 @@ page:
|
|
|
1045
1045
|
| leaves a remaining **tie in the order your file declares it** | `turn` before `Turn`; `Mango` before `mango` โ each given in that order and returned in it |
|
|
1046
1046
|
| writes **leaves then folders at the root**, and **sub-folders then leaves inside a folder** | `h` before `f/sub1/deep/q`; `f/sub1/x` before `f/leafA` |
|
|
1047
1047
|
|
|
1048
|
+
๐ธ **One clause of the rule is not from those files.** Before comparing, the
|
|
1049
|
+
comparator reads U+3000 IDEOGRAPHIC SPACE as a space and the full-width digits
|
|
1050
|
+
U+FF10โU+FF19 as `0`โ`9`. No probe carried either; the fold was measured on a
|
|
1051
|
+
production skin's slot keys ([#791](https://github.com/firejune/rigc/issues/791),
|
|
1052
|
+
ยง10.6b says what was measured and why it is those two classes and not NFKC), and
|
|
1053
|
+
it applies here because R10, R11 and a skin's slot keys are one comparator. So
|
|
1054
|
+
`shot๏ผ` sorts before `shot10`, and a pair an ideographic space decides is
|
|
1055
|
+
ordered rather than refused as `separator`.
|
|
1056
|
+
|
|
1048
1057
|
โญ **A tie is not an ambiguity, and that is what retired most of this rule's
|
|
1049
1058
|
refusals.** Two names the comparator cannot separate come back in the order the
|
|
1050
1059
|
file gave them, so the order rigc emits for such a pair is **your own declaration
|
|
@@ -8161,6 +8170,33 @@ says which.**
|
|
|
8161
8170
|
t=0, so the editor wrote them `value` alone, and that rule would have moved
|
|
8162
8171
|
`time` โ first in every other key kind the editor writes โ behind `value`.
|
|
8163
8172
|
|
|
8173
|
+
๐ฌ **Two positions and one fold are measured on a production set, not on
|
|
8174
|
+
`examples/`** ([#791](https://github.com/firejune/rigc/issues/791)). The twelve
|
|
8175
|
+
exports carry no mesh `path` or `color` and no slot name outside ASCII โ `IG84`
|
|
8176
|
+
and `IG85` count both on every run with a corpus โ so the table cannot learn
|
|
8177
|
+
either, and what rigc writes for them was read off 42 production exports
|
|
8178
|
+
instead:
|
|
8179
|
+
|
|
8180
|
+
- **A mesh attachment writes `path` and `color` right after `type`, `path` before `color` โ measured on a production set (#791), not on `examples/`.**
|
|
8181
|
+
18 meshes whose `path` differs from their name wrote it second, and 1 with a
|
|
8182
|
+
`color` wrote that second; no mesh carried both. The row does not list them,
|
|
8183
|
+
so the position is the constructor's โ `meshTextureKeys` in
|
|
8184
|
+
[`src/compile.ts`](../src/compile.ts), which every mesh route spreads right
|
|
8185
|
+
after `type` (`S104`). A region's `path` and a linked mesh's keys stay where
|
|
8186
|
+
they were: neither was in the set, and an analogy is not a measurement.
|
|
8187
|
+
- **A skin's slot keys are compared after `foldBeforeComparing`, which reads U+3000 as U+0020 and U+FF10โU+FF19 as U+0030โU+0039** โ
|
|
8188
|
+
the ideographic space as a space, the full-width digits as `0`โ`9`
|
|
8189
|
+
(`EDITOR_NAME_FOLD`). One map of 95 slot keys, 7 of them carrying those
|
|
8190
|
+
characters, came back in an order this reproduces 95 of 95 and neither a
|
|
8191
|
+
codepoint sort nor the comparator without the fold does (`S105`). It is **not**
|
|
8192
|
+
`normalize('NFKC')`, though NFKC folds both the same way: NFKC, a classifier
|
|
8193
|
+
that reads every Unicode digit as a digit and every space separator as a space,
|
|
8194
|
+
and a width fold alone all reproduce that map and disagree past it (on `๏ฌ`,
|
|
8195
|
+
`ยฒ`, `ูฃ`, `๏ผก`, a no-break space), and what all three agree on is exactly
|
|
8196
|
+
these two classes. The comparator is R10's, so animation and skin names are
|
|
8197
|
+
compared after the fold too. A pair the fold does not close โ a tab, a
|
|
8198
|
+
no-break space โ still keeps the map in rigc's order, whole (`S106`).
|
|
8199
|
+
|
|
8164
8200
|
๐ธ **An object keyed by NAMES is not a field order**, and the table does not
|
|
8165
8201
|
touch one. A bone's or a slot's timelines, and a transform constraint's
|
|
8166
8202
|
`properties` and each `to` inside them, are read into the runtime's arrays in the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-rigc",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.1",
|
|
4
4
|
"description": "Rig compiler for Spine โ declarative rig specs in, Spine 4.3 skeleton data out, verified by a spine-core round-trip. Built so AI agents can author rigs and check their own work; the output imports into the Spine editor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/compile.ts
CHANGED
|
@@ -400,7 +400,11 @@ function editorSkinOrder<T extends { name: string }>(skins: readonly T[]): T[] {
|
|
|
400
400
|
* partly sorted:
|
|
401
401
|
*
|
|
402
402
|
* - a pair the comparator leaves open (`editorNameOrder`'s number, separator and
|
|
403
|
-
* folder cases)
|
|
403
|
+
* folder cases). Since #791 a name carrying U+3000 or a full-width digit is
|
|
404
|
+
* not one: the comparator folds both first (`EDITOR_NAME_FOLD`), which is
|
|
405
|
+
* what a production map of 95 slot keys was measured to need, so such a map
|
|
406
|
+
* is sorted where it used to be kept whole โ or, with only full-width digits
|
|
407
|
+
* in it, sorted with the digits at their code points;
|
|
404
408
|
* - any slot name holding `/`. The folder rule was measured on skin and
|
|
405
409
|
* animation names, which the editor files in folders; slots it files under
|
|
406
410
|
* bones, and no round trip carried a slot name with a `/` in it.
|
|
@@ -465,10 +469,59 @@ interface ReadName {
|
|
|
465
469
|
skipped: number;
|
|
466
470
|
}
|
|
467
471
|
|
|
472
|
+
/**
|
|
473
|
+
* The characters the editor folds before it compares two names, as
|
|
474
|
+
* `[first, last, to]` code point ranges: each of `first`โฆ`last` is read as
|
|
475
|
+
* `to` plus its offset from `first` (issue #791).
|
|
476
|
+
*
|
|
477
|
+
* ๐ฌ **Measured on a production set, not on the probes or `examples/`.** One
|
|
478
|
+
* skin's `attachments` map of 95 slot keys, 7 of them carrying U+3000
|
|
479
|
+
* IDEOGRAPHIC SPACE or a full-width digit (U+FF12, U+FF14), came back in an
|
|
480
|
+
* order this comparator reproduces **95 of 95** once U+3000 is read as U+0020
|
|
481
|
+
* and U+FF10โU+FF19 as `0`โ`9` โ an order neither a plain codepoint sort nor a
|
|
482
|
+
* case-insensitive sort without the fold reproduces. No name in the five probes, the
|
|
483
|
+
* twelve exports or any spec in this tree carries either character, so the set
|
|
484
|
+
* is the only measurement of them there is.
|
|
485
|
+
*
|
|
486
|
+
* โ ๏ธ **Exactly those two classes, and not `normalize('NFKC')`, although NFKC
|
|
487
|
+
* folds both the same way.** Three readings reproduce the measurement and
|
|
488
|
+
* disagree past it: NFKC (which also turns `๏ฌ` into `fi`, `ยฒ` and `โ ` into
|
|
489
|
+
* digits, U+00A0 and U+2000โU+200A into a space, and composes `e` + U+0301
|
|
490
|
+
* into `รฉ`); a classifier that reads every Unicode decimal digit as a digit and
|
|
491
|
+
* every space separator as a space (which also reads `ูฃ` as 3, and does none
|
|
492
|
+
* of NFKC's other folds); and a width fold alone (which also reads `๏ผก` as `A`,
|
|
493
|
+
* and folds no other space). What all three agree on is exactly U+3000 and the
|
|
494
|
+
* ten full-width digits โ the ten are one class under every reading, so the
|
|
495
|
+
* eight the set did not carry are folded with the two it did โ and that
|
|
496
|
+
* intersection is what is applied. Every other character is compared at its own
|
|
497
|
+
* code point as before, and a whitespace character that is not a space is still
|
|
498
|
+
* `leafOrder`'s `separator`.
|
|
499
|
+
*
|
|
500
|
+
* One comparator (#728), so the fold reaches `skins` and `animations` too: an
|
|
501
|
+
* animation name with a full-width digit was compared at the digit's code point,
|
|
502
|
+
* the order the only measurement of such a name contradicts, and a pair that
|
|
503
|
+
* U+3000 decided was refused as `separator` and is now ordered.
|
|
504
|
+
*/
|
|
505
|
+
export const EDITOR_NAME_FOLD: ReadonlyArray<readonly [number, number, number]> = [
|
|
506
|
+
[0x3000, 0x3000, 0x0020],
|
|
507
|
+
[0xff10, 0xff19, 0x0030],
|
|
508
|
+
];
|
|
509
|
+
|
|
510
|
+
/** `name` with every character `EDITOR_NAME_FOLD` covers read as the character it folds to. */
|
|
511
|
+
function foldBeforeComparing(name: string): string {
|
|
512
|
+
let out = '';
|
|
513
|
+
for (const char of name) {
|
|
514
|
+
const code = char.codePointAt(0) ?? 0;
|
|
515
|
+
const range = EDITOR_NAME_FOLD.find(([first, last]) => code >= first && code <= last);
|
|
516
|
+
out += range === undefined ? char : String.fromCodePoint(range[2] + code - range[0]);
|
|
517
|
+
}
|
|
518
|
+
return out;
|
|
519
|
+
}
|
|
520
|
+
|
|
468
521
|
function readName(name: string, skip: RegExp): ReadName {
|
|
469
522
|
const chars: string[] = [];
|
|
470
523
|
let skipped = 0;
|
|
471
|
-
for (const char of foldUp(name)) {
|
|
524
|
+
for (const char of foldUp(foldBeforeComparing(name))) {
|
|
472
525
|
if (skip.test(char)) skipped++;
|
|
473
526
|
else chars.push(char);
|
|
474
527
|
}
|
|
@@ -4292,6 +4345,33 @@ function attachmentPath(att: { path?: string; image?: string }, placeholder: str
|
|
|
4292
4345
|
return region === placeholder ? undefined : region;
|
|
4293
4346
|
}
|
|
4294
4347
|
|
|
4348
|
+
/**
|
|
4349
|
+
* A mesh attachment's `path` and `color`, in that order โ the two keys every
|
|
4350
|
+
* mesh constructor spreads right after `type` (issue #791).
|
|
4351
|
+
*
|
|
4352
|
+
* ๐ฌ The editor writes a mesh `type, path, color, uvs, โฆ`: right after `type`,
|
|
4353
|
+
* `path` before `color` โ measured on a production set (#791), not on
|
|
4354
|
+
* `examples/`. There 18 meshes whose `path` differs from their name wrote it
|
|
4355
|
+
* second and 1 mesh with a `color` wrote that second; no object carried both, so
|
|
4356
|
+
* `path` before `color` is the order the two measured positions leave, not a
|
|
4357
|
+
* third measurement. The twelve exports carry neither key on a mesh, which is
|
|
4358
|
+
* why `EDITOR_KEY_ORDER`'s `mesh attachment` row does not list them: an unlisted
|
|
4359
|
+
* key keeps its constructor's index, so the position is stated HERE, and the
|
|
4360
|
+
* row stays what the public exports derive.
|
|
4361
|
+
*
|
|
4362
|
+
* โ ๏ธ Not a linked mesh's, and not a region's. Neither was in the measured set โ
|
|
4363
|
+
* a region's `path` stays where `buildRigRegion` puts it, a linked mesh's
|
|
4364
|
+
* keys where `buildRigLinkedMesh` does โ because the analogy to a mesh is
|
|
4365
|
+
* obvious and it is not a measurement.
|
|
4366
|
+
*/
|
|
4367
|
+
function meshTextureKeys(att: { path?: string; image?: string; color?: string }, placeholder: string): Pick<SpineMeshAttachment, 'path' | 'color'> {
|
|
4368
|
+
const out: Pick<SpineMeshAttachment, 'path' | 'color'> = {};
|
|
4369
|
+
const path = attachmentPath(att, placeholder);
|
|
4370
|
+
if (path !== undefined) out.path = path;
|
|
4371
|
+
if (att.color !== undefined) out.color = att.color;
|
|
4372
|
+
return out;
|
|
4373
|
+
}
|
|
4374
|
+
|
|
4295
4375
|
/**
|
|
4296
4376
|
* The atlas region frame `i` of a sequence resolves to โ `Sequence.getPath`
|
|
4297
4377
|
* (`Sequence.js:124-132`) transcribed: the stem, then `start + i` left-padded
|
|
@@ -4707,6 +4787,7 @@ function buildRigMesh(
|
|
|
4707
4787
|
}
|
|
4708
4788
|
const out: SpineMeshAttachment = {
|
|
4709
4789
|
type: 'mesh',
|
|
4790
|
+
...meshTextureKeys(att, placeholder),
|
|
4710
4791
|
uvs: att.uvs.map(f32),
|
|
4711
4792
|
triangles: att.triangles,
|
|
4712
4793
|
vertices,
|
|
@@ -4715,9 +4796,6 @@ function buildRigMesh(
|
|
|
4715
4796
|
width: f32(width),
|
|
4716
4797
|
height: f32(height),
|
|
4717
4798
|
};
|
|
4718
|
-
const path = attachmentPath(att, placeholder);
|
|
4719
|
-
if (path !== undefined) out.path = path;
|
|
4720
|
-
if (att.color !== undefined) out.color = att.color;
|
|
4721
4799
|
if (att.sequence !== undefined) out.sequence = emitSequence(att.sequence);
|
|
4722
4800
|
// Register it as `authored`: geometry rigc did not build and whose topology it
|
|
4723
4801
|
// therefore gets to assume nothing about. The generator-topology assertions
|
|
@@ -4998,6 +5076,7 @@ function buildGeneratedMesh(
|
|
|
4998
5076
|
});
|
|
4999
5077
|
const out: SpineMeshAttachment = {
|
|
5000
5078
|
type: 'mesh',
|
|
5079
|
+
...meshTextureKeys(att, placeholder),
|
|
5001
5080
|
uvs: geometry.uvs.map(f32),
|
|
5002
5081
|
triangles: geometry.triangles,
|
|
5003
5082
|
vertices: vertices.map(f32),
|
|
@@ -5005,9 +5084,6 @@ function buildGeneratedMesh(
|
|
|
5005
5084
|
width: f32(w),
|
|
5006
5085
|
height: f32(h),
|
|
5007
5086
|
};
|
|
5008
|
-
const path = attachmentPath(att, placeholder);
|
|
5009
|
-
if (path !== undefined) out.path = path;
|
|
5010
|
-
if (att.color !== undefined) out.color = att.color;
|
|
5011
5087
|
return out;
|
|
5012
5088
|
}
|
|
5013
5089
|
|
|
@@ -5565,6 +5641,7 @@ function buildGridAttachment(
|
|
|
5565
5641
|
});
|
|
5566
5642
|
const out: SpineMeshAttachment = {
|
|
5567
5643
|
type: 'mesh',
|
|
5644
|
+
...meshTextureKeys(att, placeholder),
|
|
5568
5645
|
uvs: geometry.uvs.map(f32),
|
|
5569
5646
|
triangles: geometry.triangles,
|
|
5570
5647
|
vertices: vertices.map(f32),
|
|
@@ -5572,9 +5649,6 @@ function buildGridAttachment(
|
|
|
5572
5649
|
width: f32(w),
|
|
5573
5650
|
height: f32(h),
|
|
5574
5651
|
};
|
|
5575
|
-
const path = attachmentPath(att, placeholder);
|
|
5576
|
-
if (path !== undefined) out.path = path;
|
|
5577
|
-
if (att.color !== undefined) out.color = att.color;
|
|
5578
5652
|
return out;
|
|
5579
5653
|
}
|
|
5580
5654
|
|
|
@@ -5726,8 +5800,15 @@ function buildContourAttachment(
|
|
|
5726
5800
|
holePixels: geometry.contour?.holePixels,
|
|
5727
5801
|
depth: depth?.summary,
|
|
5728
5802
|
});
|
|
5803
|
+
// Same rule a region attachment follows: the atlas region is the PNG's
|
|
5804
|
+
// basename, so a placeholder named anything else needs `path` written down or
|
|
5805
|
+
// the loader resolves nothing. Stated once in `attachmentPath` since #577 โ
|
|
5806
|
+
// this comment used to be the rule's only statement, beside four emit sites
|
|
5807
|
+
// that disagreed with it โ and spread right after `type` by
|
|
5808
|
+
// `meshTextureKeys` since #791.
|
|
5729
5809
|
const out: SpineMeshAttachment = {
|
|
5730
5810
|
type: 'mesh',
|
|
5811
|
+
...meshTextureKeys(att, placeholder),
|
|
5731
5812
|
uvs: geometry.uvs.map(f32),
|
|
5732
5813
|
triangles: geometry.triangles,
|
|
5733
5814
|
vertices: vertices.map(f32),
|
|
@@ -5735,14 +5816,6 @@ function buildContourAttachment(
|
|
|
5735
5816
|
width: f32(w),
|
|
5736
5817
|
height: f32(h),
|
|
5737
5818
|
};
|
|
5738
|
-
// Same rule a region attachment follows: the atlas region is the PNG's
|
|
5739
|
-
// basename, so a placeholder named anything else needs `path` written down or
|
|
5740
|
-
// the loader resolves nothing. Stated once in `attachmentPath` since #577 โ
|
|
5741
|
-
// this comment used to be the rule's only statement, beside four emit sites
|
|
5742
|
-
// that disagreed with it.
|
|
5743
|
-
const path = attachmentPath(att, placeholder);
|
|
5744
|
-
if (path !== undefined) out.path = path;
|
|
5745
|
-
if (att.color !== undefined) out.color = att.color;
|
|
5746
5819
|
return out;
|
|
5747
5820
|
}
|
|
5748
5821
|
|
package/src/types.ts
CHANGED
|
@@ -888,7 +888,9 @@ export interface SpineMeshAttachment {
|
|
|
888
888
|
type: 'mesh';
|
|
889
889
|
/** See `SpineRegionAttachment.name` โ and it takes `path` with it. */
|
|
890
890
|
name?: string;
|
|
891
|
+
/** `path` and `color` are written right after `type` โ `compile.ts`'s `meshTextureKeys` says where that is measured. */
|
|
891
892
|
path?: string;
|
|
893
|
+
color?: string;
|
|
892
894
|
uvs: number[];
|
|
893
895
|
triangles: number[];
|
|
894
896
|
/** Weighted encoding: boneCount, (boneIndex, bindX, bindY, weight)*n, repeated. */
|
|
@@ -910,7 +912,6 @@ export interface SpineMeshAttachment {
|
|
|
910
912
|
/** Nonessential, but they make the mesh budget assertions readable. */
|
|
911
913
|
width: number;
|
|
912
914
|
height: number;
|
|
913
|
-
color?: string;
|
|
914
915
|
sequence?: SpineSequence;
|
|
915
916
|
}
|
|
916
917
|
|