spine-rigc 2.56.0 → 2.58.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 +3 -1
- package/docs/AUTHORING.md +709 -264
- package/package.json +1 -1
- package/skills/rigc/SKILL.md +7 -2
- package/skills/rigc-face/SKILL.md +3 -1
- package/skills/rigc-ingest/SKILL.md +3 -1
- package/skills/rigc-motion/SKILL.md +3 -1
- package/skills/rigc-rigging/SKILL.md +3 -1
- package/src/atlas.ts +10 -10
- package/src/cli/core_commands.ts +52 -0
- package/src/cli/shared.ts +119 -3
- package/src/compile.ts +356 -334
- package/src/deformgen.ts +28 -28
- package/src/emit_spine.ts +5 -5
- package/src/errors.ts +8 -0
- package/src/guide.ts +4 -9
- package/src/keys.ts +4 -4
- package/src/meshsplit.ts +683 -0
- package/src/model.ts +10 -10
- package/src/motion.ts +6 -6
- package/src/rig.ts +76 -76
- package/src/stop.ts +30 -30
- package/src/trackgen.ts +11 -11
package/src/model.ts
CHANGED
|
@@ -733,7 +733,7 @@ function ordered(record: object, keys: readonly string[], where: string, value:
|
|
|
733
733
|
const own = record as Record<string, unknown>;
|
|
734
734
|
for (const key of Object.keys(own)) {
|
|
735
735
|
if (!keys.includes(key)) {
|
|
736
|
-
throw new CompileError(`internal: the model document has no place for field "${key}" of ${where}; it writes [${keys.join(', ')}]
|
|
736
|
+
throw new CompileError(`internal: the model document has no place for field "${key}" of ${where}; it writes [${keys.join(', ')}]`, 'CE_MODEL_INTERNAL_FIELD_UNREPRESENTABLE');
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
const out: { [key: string]: DocValue } = {};
|
|
@@ -752,13 +752,13 @@ function ordered(record: object, keys: readonly string[], where: string, value:
|
|
|
752
752
|
function plain(value: unknown, where: string): DocValue {
|
|
753
753
|
if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;
|
|
754
754
|
if (typeof value === 'number') {
|
|
755
|
-
if (!Number.isFinite(value)) throw new CompileError(`internal: the model document cannot carry ${value} at ${where}; JSON writes it as null
|
|
756
|
-
if (Object.is(value, -0)) throw new CompileError(`internal: the model document cannot carry -0 at ${where}; JSON writes it as 0
|
|
755
|
+
if (!Number.isFinite(value)) throw new CompileError(`internal: the model document cannot carry ${value} at ${where}; JSON writes it as null`, 'CE_MODEL_INTERNAL_NONFINITE_NUMBER');
|
|
756
|
+
if (Object.is(value, -0)) throw new CompileError(`internal: the model document cannot carry -0 at ${where}; JSON writes it as 0`, 'CE_MODEL_INTERNAL_NEGATIVE_ZERO');
|
|
757
757
|
return value;
|
|
758
758
|
}
|
|
759
759
|
if (Array.isArray(value)) {
|
|
760
760
|
return value.map((item, i) => {
|
|
761
|
-
if (item === undefined) throw new CompileError(`internal: the model document cannot carry undefined at ${where}[${i}]; JSON writes it as null
|
|
761
|
+
if (item === undefined) throw new CompileError(`internal: the model document cannot carry undefined at ${where}[${i}]; JSON writes it as null`, 'CE_MODEL_INTERNAL_UNDEFINED_ELEMENT');
|
|
762
762
|
return plain(item, `${where}[${i}]`);
|
|
763
763
|
});
|
|
764
764
|
}
|
|
@@ -767,7 +767,7 @@ function plain(value: unknown, where: string): DocValue {
|
|
|
767
767
|
for (const [key, item] of Object.entries(value)) if (item !== undefined) out[key] = plain(item, `${where}.${key}`);
|
|
768
768
|
return out;
|
|
769
769
|
}
|
|
770
|
-
throw new CompileError(`internal: the model document cannot carry ${Object.prototype.toString.call(value)} at ${where}; it writes plain data only
|
|
770
|
+
throw new CompileError(`internal: the model document cannot carry ${Object.prototype.toString.call(value)} at ${where}; it writes plain data only`, 'CE_MODEL_INTERNAL_NONPLAIN_VALUE');
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
/** A `Map` as the array of its entries in the map's order, each `{ name, … }`. */
|
|
@@ -818,11 +818,11 @@ function verticesOf(vertices: ModelVertices, where: string): DocValue {
|
|
|
818
818
|
|
|
819
819
|
function attachmentOf(entry: SkinTableEntry, where: string): DocValue {
|
|
820
820
|
const fields = ATTACHMENT_FIELDS[entry.kind];
|
|
821
|
-
if (fields === undefined) throw new CompileError(`internal: the model document knows no attachment kind "${String(entry.kind)}" at ${where}
|
|
821
|
+
if (fields === undefined) throw new CompileError(`internal: the model document knows no attachment kind "${String(entry.kind)}" at ${where}`, 'CE_MODEL_INTERNAL_ATTACHMENT_KIND');
|
|
822
822
|
if (entry.kind === 'region' && (entry.atlas === undefined) === (entry.sequence === undefined)) {
|
|
823
823
|
throw new CompileError(
|
|
824
824
|
`internal: the region at ${where} carries ${entry.atlas === undefined ? 'neither an atlas rectangle nor a sequence' : 'both an atlas rectangle and a sequence'}; ` +
|
|
825
|
-
'a region states exactly one of the two, and a sequence holds a rectangle per frame (issue #935)',
|
|
825
|
+
'a region states exactly one of the two, and a sequence holds a rectangle per frame (issue #935)', 'CE_MODEL_INTERNAL_REGION_SOURCE',
|
|
826
826
|
);
|
|
827
827
|
}
|
|
828
828
|
return ordered(entry, fields, where, (key, v) => {
|
|
@@ -840,7 +840,7 @@ function attachmentOf(entry: SkinTableEntry, where: string): DocValue {
|
|
|
840
840
|
/** One rectangle, in `ModelAtlasRect`'s order, every field required. */
|
|
841
841
|
function atlasRectOf(rect: ModelAtlasRect, where: string): DocValue {
|
|
842
842
|
for (const key of ATLAS_RECT_FIELDS) {
|
|
843
|
-
if (rect[key] === undefined) throw new CompileError(`internal: the atlas rectangle at ${where} has no ${key}; it states all of [${ATLAS_RECT_FIELDS.join(', ')}]
|
|
843
|
+
if (rect[key] === undefined) throw new CompileError(`internal: the atlas rectangle at ${where} has no ${key}; it states all of [${ATLAS_RECT_FIELDS.join(', ')}]`, 'CE_MODEL_INTERNAL_ATLAS_FIELD_REQUIRED');
|
|
844
844
|
}
|
|
845
845
|
return ordered(rect, ATLAS_RECT_FIELDS, where);
|
|
846
846
|
}
|
|
@@ -922,7 +922,7 @@ function editorOrderOf(model: CompiledModel): DocValue {
|
|
|
922
922
|
if (skin !== undefined) same(`editorOrder.skins[${i}] "${entry.name}".slots`, entry.slots, Object.keys(skin.attachments));
|
|
923
923
|
}
|
|
924
924
|
same('editorOrder.animations', order.animations, [...model.animations.keys()]);
|
|
925
|
-
if (problems.length > 0) throw new CompileError(`internal: the model's editor order is not its own: ${problems.join('; ')}
|
|
925
|
+
if (problems.length > 0) throw new CompileError(`internal: the model's editor order is not its own: ${problems.join('; ')}`, 'CE_MODEL_INTERNAL_EDITOR_ORDER');
|
|
926
926
|
return {
|
|
927
927
|
skins: order.skins.map((entry, i) => ordered(entry, ['name', 'slots'], `editorOrder.skins[${i}]`)),
|
|
928
928
|
animations: plain(order.animations, 'editorOrder.animations'),
|
|
@@ -1040,7 +1040,7 @@ const MODEL_DOCUMENT_LEFT_OUT: readonly string[] = ['setupWorld'];
|
|
|
1040
1040
|
export function modelDocument(model: CompiledModel, skeletonText: string, atlasText: string): string {
|
|
1041
1041
|
for (const key of Object.keys(model)) {
|
|
1042
1042
|
if (!MODEL_DOCUMENT_FIELDS.includes(key) && !MODEL_DOCUMENT_LEFT_OUT.includes(key)) {
|
|
1043
|
-
throw new CompileError(`internal: the model document has no place for the model's field "${key}"; it writes [${MODEL_DOCUMENT_FIELDS.join(', ')}] and leaves out [${MODEL_DOCUMENT_LEFT_OUT.join(', ')}]
|
|
1043
|
+
throw new CompileError(`internal: the model document has no place for the model's field "${key}"; it writes [${MODEL_DOCUMENT_FIELDS.join(', ')}] and leaves out [${MODEL_DOCUMENT_LEFT_OUT.join(', ')}]`, 'CE_MODEL_INTERNAL_DOCUMENT_FIELD');
|
|
1044
1044
|
}
|
|
1045
1045
|
}
|
|
1046
1046
|
const doc: { [key: string]: DocValue } = {
|
package/src/motion.ts
CHANGED
|
@@ -289,7 +289,7 @@ function describe(v: unknown): string {
|
|
|
289
289
|
* has seen one has seen the format.
|
|
290
290
|
*/
|
|
291
291
|
function refuse(where: string, key: string, is: unknown, hint: string): never {
|
|
292
|
-
throw new CompileError(`${where}: \`${key}\` is ${describe(is)}; ${hint}
|
|
292
|
+
throw new CompileError(`${where}: \`${key}\` is ${describe(is)}; ${hint}`, 'CE_MOTION_FIELD_SHAPE');
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
/**
|
|
@@ -436,7 +436,7 @@ function parsePhysics(raw: unknown, where: string): void {
|
|
|
436
436
|
`${where}: \`${key}\` names a physics constraint "${EVERY_GLOBAL_PHYSICS}", and that name is reserved: a ` +
|
|
437
437
|
`track's \`"physics": "${EVERY_GLOBAL_PHYSICS}"\` is the timeline that names no constraint and drives ` +
|
|
438
438
|
'every one declaring the keyed property global, so a constraint called ' +
|
|
439
|
-
`"${EVERY_GLOBAL_PHYSICS}" could not be keyed by name. Give it another name`,
|
|
439
|
+
`"${EVERY_GLOBAL_PHYSICS}" could not be keyed by name. Give it another name`, 'CE_MOTION_PHYSICS_NAME_RESERVED',
|
|
440
440
|
);
|
|
441
441
|
}
|
|
442
442
|
const spec = needObj(entry, where, key,'a physics constraint is an object naming the bone it drives and the components it drives it in');
|
|
@@ -674,7 +674,7 @@ function parseSequence(raw: unknown, where: string, at: string): void {
|
|
|
674
674
|
: '') +
|
|
675
675
|
'. The runtime advances the frame by `(time - keyTime) / delay`, which is Infinity at 0, and ' +
|
|
676
676
|
'`Infinity | 0` is 0 — so the key shows its first frame for as long as it lasts, which is "hold" spelt ' +
|
|
677
|
-
`as "${mode}". State the seconds per frame, or write "hold"`,
|
|
677
|
+
`as "${mode}". State the seconds per frame, or write "hold"`, 'CE_MOTION_SEQUENCE_ADVANCE_ZERO_DELAY',
|
|
678
678
|
);
|
|
679
679
|
}
|
|
680
680
|
}
|
|
@@ -766,10 +766,10 @@ export function parseMotionSpec(raw: unknown, where: string): MotionSpec {
|
|
|
766
766
|
|
|
767
767
|
function parseMotionSpecInto(raw: unknown, where: string, visits: readonly ShapeVisit[]): MotionSpec {
|
|
768
768
|
if (!isObj(raw)) {
|
|
769
|
-
throw new CompileError(`${where}: a motion spec must be a JSON object, and this file holds ${describe(raw)}
|
|
769
|
+
throw new CompileError(`${where}: a motion spec must be a JSON object, and this file holds ${describe(raw)}`, 'CE_MOTION_SPEC_OBJECT');
|
|
770
770
|
}
|
|
771
771
|
if (raw.spec !== MOTION_SPEC_VERSION) {
|
|
772
|
-
throw new CompileError(`${where}: unknown motion spec version: ${String(raw.spec)}, expected "${MOTION_SPEC_VERSION}"
|
|
772
|
+
throw new CompileError(`${where}: unknown motion spec version: ${String(raw.spec)}, expected "${MOTION_SPEC_VERSION}"`, 'CE_MOTION_SPEC_VERSION');
|
|
773
773
|
}
|
|
774
774
|
// Before the field checks, for the reason `parseRigSpec` puts its own first: a
|
|
775
775
|
// key nothing reads is often the CAUSE of the field that is missing, and
|
|
@@ -793,7 +793,7 @@ function parseMotionSpecInto(raw: unknown, where: string, visits: readonly Shape
|
|
|
793
793
|
|
|
794
794
|
const animations = needObj(raw.animations, where, 'animations', 'it is a table keyed by animation name, `{ "<name>": { "duration": …, "tracks": [...] } }` (write `{}` for a static rig)');
|
|
795
795
|
for (const [name, anim] of Object.entries(animations)) {
|
|
796
|
-
if (name.length === 0) throw new CompileError(`${where}: an animation has an empty name
|
|
796
|
+
if (name.length === 0) throw new CompileError(`${where}: an animation has an empty name`, 'CE_MOTION_ANIMATION_NAME_EMPTY');
|
|
797
797
|
parseAnimation(anim, where, name);
|
|
798
798
|
}
|
|
799
799
|
|