Specification

Whilst everything described here still works, you usually won't write the spec yourself anymore but use the auto spec to create one.

However, the information on this page might still be relevant to you, as it will help you adjust the auto generated spec to your likings if you need to.

What does the Specification do?

The Specification is a declarative description for handling Variants, Elements and VariantInstances in a Babylon.js Scene. It is written in JSON, so it is often called "Specification JSON".

What exactly is a declarative description in context of the Specification?

In computer science, declarative programming is a paradigm. It means that you are building a structure to express a certain state without describing its control flow. With the Specification, you describe an initial state of your 3D-models as well as possible Variants of that state. Therefore, the Viewer is responsible for handling different defined states of your desired 3D-models. The Viewer is not responsible for the visual aesthetic of the 3D-models.

Where do I start?

If you build a new project, the main part you have to deal with is the StructureJson. The documentation of the StructureJson gives you more information about the options and possibilities in detail. The so called "Index JSON" of a project is a StructureJson declaring a SceneJson, a SetupJson and at least one Variant (which in turn is a StructureJson). The StructureJson can be nested, so you can define Variants in Variants and therefore build a tree. The following keys need to be defined as an index to build a working project.

{
scene?: string | SceneJson,
setup?: string | SetupJson,
variants?: {
[id: string]: StructureJson,
}
}

What about Variants?

The StructureJson offers both keys for the index and for the declaration of the Variants. This might be a little confusing at the beginning, so let's have a look at the keys declaring a Variant.

{
file?: string
glTF?: Asset | string,
parameterDeclaration?: ParameterDeclaration,
parameters?: ParameterBag,
elements?: ElementDefinitions,
lights?: LightDefinitions,
variants?: {
[id: string]: StructureJson,
}
}
  • file could be a URL to a file on the webserver that describes the Variant in an external JSON.
  • glTF is responsible to define the Asset of the 3D-model's glTF.
  • parameterDeclaration gives you the possibility to declare own parameters.
  • parameters describes the ParameterBag of this level.
  • elements describes all parts of a 3D-model and the path/paths to certain meshes.
  • lights describes the lights for the Variant of a 3D-Model.
  • variants refers to a list of Variants with all the described keys as a sub Variant.

What are Variant Instances?

A VariantInstance is one representation of a defined Variant at runtime. It is possible to instantiate multiple instances of one and the same Variant declaration. VariantInstances are handled by the VariantInstanceManager. You can access this manager directly via variantInstances. Instances are defined via the setup.instances key in the index StructureJson as VariantInstanceDefinition.

Please explain Parameters!

This page describes our legacy parameter system which has been superseded by our new tag based parameter system.

Whilst all the features of the parameter system described here still work as explained, this is considered obsolete and should not be used anymore in new projects.

Parameters abstract different states of parts of a 3D-model in the Babylon.js scene. Parameters for example are "visible", "position", "rotation" and so on. You can define them in the Specification as well as mutate them at runtime by calling commitParameters or commitParameters (or the single flavor commitParameter or commitParameter). A set of parameters is handled by the ParameterBag. You can even call commitParameters to commit a ParameterBag to all VariantInstances in your Viewer instance. For a detailed documentation of built in parameters and how to declare your own "custom parameters" see Parameters.

Please give me an example!

{
scene: { /* ... */ },
setup: {
instances: [
{
name: 'MyLightBulbInstance',
variant: 'MyLightBulb',
parameters: {
visible: true
}
}
]
},
variants: {
'MyLightBulb': {
glTF: '/assets/my_light_bulb/model.glb',
// alternative: glTF: { rootUrl: '/assets/my_light_bulb',
// fileName: 'model.glb' }
elements: {
'Glass': {
paths: {
include: [
'__root__.bulb_glass'
],
exclude: [
'__root__.bulb_glass.bulb_glass_shady'
]
}
},
'Filament': [
'__root__.bulb_filament'
],
'Socket': {
paths: {
include: [
'__root__.bulb_socket'
]
}
}
}
parameterDeclaration: {
'wattage': {
'type': 'select',
'options': ['1W', '20W', '100W'],
'default': '1W'
}
},
parameters: {
'Socket.visible': false,
'Filament.color': '#ff0000',
'Glass.position': '(3, 0, 1)',
'wattage': '20W',
'rotation: '(-325, 95, 20)'
},
variants: {
'MyLightBulbSpecial': { // could also be a POJO with keys described above
file: '/assets/my_light_bulb/special.json'
}
}
}
}
}

What is happening in this example?

We define an "Index JSON" with a SceneJson (not part of this example), a SetupJson and nested Variants. Our first Variant at level 1 defines a light bulb "MyLightBulb" with Elements "Glass", " Filament" and "Socket". The Variant "MyLightBulbSpecial" at level 2 inherits all Elements and parameters from the Variant "MyLightBulb" at level 1 (parent > child). We declared a so called "custom parameter" with key "wattage", which does nothing as long as we do not provide an implementation for it via addParameterObserver (hint: every Variant and Element is a ParameterObservable, see Parameters for an example). When bootstrapping the Viewer, it will instantiate the VariantInstance "MyLightBulbInstance" with the declaration from the Variant "MyLightBulb".

Why are there dots in between Parameters?

You can access parameters of an Element via its Variant by using the DottedPath. A DottedPath represents a relative path to Variants, Elements and parameters. Have a look at getDescendant to get an idea how to use it for Variants. When using parameters, the last part of the DottedPath always represents the parameter itself. The preceding parts represent the relative path to the Element (or Variant if you are using a Variant tree and inheritance and if you want to commit the parameter to the Variant).

Okay, and how do I bootstrap a Viewer instance?

To get a working environment, just create an instance of the Viewer with a Canvas element in your DOM, the Specification and bootstrap it.

const canvas = document.getElementById('viewer-canvas');
const specification = {
/* your spec goes here */
};
const viewer = new Viewer(canvas, specification);

await viewer.bootstrap([]);

Generated using TypeDoc