@deepblend/dsh-blender-contracts 0.2.15 → 0.2.17
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/lib/scene-spec.js +21 -0
- package/lib/schemas/scene-spec.schema.json +56 -3
- package/package.json +1 -1
package/lib/scene-spec.js
CHANGED
|
@@ -96,6 +96,8 @@ export const ANIMATION_PROPERTIES_BY_KIND = Object.freeze({
|
|
|
96
96
|
export function collectionNameForKind(kind) {
|
|
97
97
|
if (kind === 'camera') return 'cameras'
|
|
98
98
|
if (kind === 'material') return 'materials'
|
|
99
|
+
// A BONE TRACK RESOLVES AGAINST THE ARMATURES, because that is the collection its id belongs to.
|
|
100
|
+
if (kind === 'bone') return 'armatures'
|
|
99
101
|
return 'entities'
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -360,6 +362,25 @@ export function validateSceneSpec(spec) {
|
|
|
360
362
|
// is what every track written before kinds existed meant.
|
|
361
363
|
const kind = track.targetKind ?? 'entity'
|
|
362
364
|
requiresId(collectionNameForKind(kind), track.targetEntityId, `${at}.targetEntityId`, kind)
|
|
365
|
+
// AND THE BONE INSIDE IT. MEASURED: this is the same shape as `armatureId` last round — the schema
|
|
366
|
+
// can say `boneName` is a string, and only a cross-reference can say the armature HAS that bone.
|
|
367
|
+
// A track pointing at a bone nobody declares animates nothing while the file says the rig moves.
|
|
368
|
+
if (kind === 'bone') {
|
|
369
|
+
if (typeof track.boneName !== 'string' || track.boneName.length === 0) {
|
|
370
|
+
errors.push({
|
|
371
|
+
severity: 'error', code: 'SCENE_REFERENCE_MISSING', path: `${at}.boneName`,
|
|
372
|
+
message: 'a bone track must name the bone it drives',
|
|
373
|
+
})
|
|
374
|
+
} else {
|
|
375
|
+
const armature = (document.armatures ?? []).find(entry => entry?.id === track.targetEntityId)
|
|
376
|
+
if (armature !== undefined && !(armature.bones ?? []).some(bone => bone?.name === track.boneName)) {
|
|
377
|
+
errors.push({
|
|
378
|
+
severity: 'error', code: 'SCENE_REFERENCE_MISSING', path: `${at}.boneName`,
|
|
379
|
+
message: `bone "${track.boneName}" does not exist in armature "${track.targetEntityId}"`,
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
363
384
|
|
|
364
385
|
// A property that does not belong to the target's kind is not a typo the
|
|
365
386
|
// compiler can shrug off: `emissionStrength` on an entity, or `location.x` on a
|
|
@@ -31,7 +31,23 @@
|
|
|
31
31
|
"items": {
|
|
32
32
|
"$ref": "#/$defs/armature"
|
|
33
33
|
},
|
|
34
|
-
"description": "Armatures this scene declares (SPEC \u00a720 M6, character animation). Each is one skeleton, created as its own object and named `<prefix><id>` like every other product object.
|
|
34
|
+
"description": "Armatures this scene declares (SPEC \u00a720 M6, character animation). Each is one skeleton, created as its own object and named `<prefix><id>` like every other product object. Entities are skinned to an armature (`entity.armatureId`, with Blender's automatic weights) and animation tracks can drive a bone of it (`targetKind: \"bone\"` with `boneName`), so a rig both moves and moves its mesh."
|
|
35
|
+
},
|
|
36
|
+
"simulation": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"properties": {
|
|
40
|
+
"gravity": {
|
|
41
|
+
"type": "number",
|
|
42
|
+
"description": "Downward acceleration in m/s\u00b2. Blender's own default (-9.81) applies when absent."
|
|
43
|
+
},
|
|
44
|
+
"bake": {
|
|
45
|
+
"type": "boolean",
|
|
46
|
+
"default": true,
|
|
47
|
+
"description": "Whether the compile bakes the simulation into the checkpoint. Baking is what makes a render show the physics rather than the initial pose, and it is not instant \u2014 so a build that wants the SETUP without paying for the bake can say so."
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"description": "Scene-level physics settings. The bodies themselves are per-entity (`entity.rigidBody`), because which things move is a property of those things."
|
|
35
51
|
},
|
|
36
52
|
"materials": {
|
|
37
53
|
"type": "array",
|
|
@@ -477,6 +493,10 @@
|
|
|
477
493
|
"type": "string",
|
|
478
494
|
"description": "The armature this entity is skinned to, named by `armatures[].id`. The compiler binds the mesh with Blender's own automatic weights, so the entity follows the bones with no weight table to write by hand. A name the scene does not declare is refused rather than ignored, because an entity that is silently unskinned renders as a static object while the file says it is rigged."
|
|
479
495
|
},
|
|
496
|
+
"rigidBody": {
|
|
497
|
+
"$ref": "#/$defs/rigidBody",
|
|
498
|
+
"description": "This entity takes part in physics (SPEC \u00a720 M6, complex simulation). WHAT THIS SLICE DOES: rigid bodies \u2014 active ones fall and collide, passive ones are what they collide with, and the compile BAKES the result into the checkpoint so a render shows it. WHAT IT DOES NOT DO YET: cloth, soft bodies and fluids, which are the next slices."
|
|
499
|
+
},
|
|
480
500
|
"generator": {
|
|
481
501
|
"$ref": "#/$defs/generator"
|
|
482
502
|
},
|
|
@@ -677,15 +697,21 @@
|
|
|
677
697
|
"enum": [
|
|
678
698
|
"entity",
|
|
679
699
|
"camera",
|
|
680
|
-
"material"
|
|
700
|
+
"material",
|
|
701
|
+
"bone"
|
|
681
702
|
],
|
|
682
703
|
"default": "entity",
|
|
683
|
-
"description": "What `targetEntityId` names: an entity (default), a camera, or
|
|
704
|
+
"description": "What `targetEntityId` names: an entity (default), a camera, a material, or AN ARMATURE whose bone this track drives (with `boneName`). Ids are unique per collection, so the kind is the only thing that says whether \"watch-dial\" means the mesh or the material \u2014 and `bone` is what made a rig able to move rather than merely exist."
|
|
684
705
|
},
|
|
685
706
|
"targetEntityId": {
|
|
686
707
|
"type": "string",
|
|
687
708
|
"description": "The id of the target named by `targetKind`. The field name says Entity because every track written before target kinds existed used it and revisions are immutable; renaming it would make r0001-r0023 unreadable. Resolution is against the collection `targetKind` names, which matters because ids are unique per collection, not globally."
|
|
688
709
|
},
|
|
710
|
+
"boneName": {
|
|
711
|
+
"type": "string",
|
|
712
|
+
"maxLength": 64,
|
|
713
|
+
"description": "Required when targetKind is `bone`: the name of the bone inside the named armature. A name the armature does not have is refused \u2014 a track that silently animates nothing is a scene that claims to move and does not."
|
|
714
|
+
},
|
|
689
715
|
"property": {
|
|
690
716
|
"type": "string",
|
|
691
717
|
"enum": [
|
|
@@ -857,6 +883,33 @@
|
|
|
857
883
|
"$ref": "#/$defs/transform"
|
|
858
884
|
}
|
|
859
885
|
}
|
|
886
|
+
},
|
|
887
|
+
"rigidBody": {
|
|
888
|
+
"type": "object",
|
|
889
|
+
"additionalProperties": false,
|
|
890
|
+
"required": [
|
|
891
|
+
"kind"
|
|
892
|
+
],
|
|
893
|
+
"properties": {
|
|
894
|
+
"kind": {
|
|
895
|
+
"type": "string",
|
|
896
|
+
"enum": [
|
|
897
|
+
"active",
|
|
898
|
+
"passive"
|
|
899
|
+
],
|
|
900
|
+
"description": "`active` means physics moves it; `passive` means it moves nothing and everything collides with it \u2014 a floor is passive, which is why the two are one field rather than a boolean: a body that is not simulated and a body that is simulated are not the only two things a body can be."
|
|
901
|
+
},
|
|
902
|
+
"mass": {
|
|
903
|
+
"type": "number",
|
|
904
|
+
"exclusiveMinimum": 0,
|
|
905
|
+
"description": "Kilograms, for an active body. Blender's own default applies when it is absent, and the default is stated rather than duplicated: a second copy of it here is the one that would go stale."
|
|
906
|
+
},
|
|
907
|
+
"friction": {
|
|
908
|
+
"type": "number",
|
|
909
|
+
"minimum": 0,
|
|
910
|
+
"description": "Blender's own default applies when absent."
|
|
911
|
+
}
|
|
912
|
+
}
|
|
860
913
|
}
|
|
861
914
|
}
|
|
862
915
|
}
|
package/package.json
CHANGED