Core Concepts: Components
Components are the primary way to attach data and behavior to <bml-entity> elements in BabylonML. They are defined using HTML attributes and manage specific aspects of the entity's corresponding Babylon.js node(s).
Purpose
- Encapsulation: Each component focuses on a single aspect (e.g., position, geometry, material, light, custom behavior).
- Reusability: Components can be applied to any entity.
- Declarative Approach: Define an entity's properties directly in HTML using component attributes.
- Extensibility: You can register custom components to add new functionality.
Defining Components
Components are attached to <bml-entity> elements via attributes. The name of the attribute corresponds to the registered component name.
<bml-entity
position="x: 0; y: 1; z: -5" <!-- Position component -->
geometry="type: box; size: 2" <!-- Geometry component -->
material="type: standard; diffuseColor: yellow" <!-- Material component -->
>
</bml-entity>
Component Schema and Parsing
- Schema: Each component defines a
schemathat specifies the expected data structure and default values for its properties. This helps with parsing and validation. BabylonML currently supports simple types (string,number,boolean) and amaptype for key-value string parsing (likepositionorgeometry). - Parsing: The framework uses parsers (like
parseVector3,parseColor3,parseObjectStringfound insrc/core/parsers.js) to convert the attribute string value into a JavaScript object or value based on the component's schema. - Data Object: The parsed attribute value is passed as the
dataobject to the component's lifecycle methods (init,update,remove).
Component Lifecycle Methods
When a component is registered, it provides an object containing lifecycle methods:
schema(Required): Defines the expected data structure and defaults.javascript schema: { type: 'map', // or 'string', 'number', 'vec3', etc. default: { x: 0, y: 0, z: 0 } // Default value if attribute is empty or missing properties }init(data)(Optional): Called once when the component is first attached to the entity and the entity is connected to the DOM. Use this for one-time setup related to the component.datacontains the initial parsed attribute value.update(data, oldData)(Optional): Called initially afterinitand subsequently whenever the component's corresponding attribute value changes on the HTML element.datais the new parsed value,oldDatais the previous value. Use this to apply changes to the Babylon.js scene based on the new data.remove(data)(Optional): Called when the component is detached from the entity (e.g., the attribute is removed) or when the entity itself is removed from the DOM. Use this for cleanup, like disposing of Babylon.js objects created by the component.datacontains the last known parsed value.
this Context: Inside these lifecycle methods, this refers to the <bml-entity> HTML element instance the component is attached to. This allows access to this.babylonNode (the entity's TransformNode/Mesh) and this.sceneElement (the parent <bml-scene>).
Component Manager
The ComponentManager (in src/core/ComponentManager.js) is a central registry and handler for components:
- Registration:
ComponentManager.registerComponent(name, definition)is used to register a new component type. - Lifecycle Invocation: It hooks into the entity's lifecycle (
connectedCallback,attributeChangedCallback,disconnectedCallback) to call the appropriateinit,update, orremovemethods on the relevant components. - Attribute Observation: It provides the list of all registered component attribute names to
BmlEntity.observedAttributesso the browser knows which attribute changes to monitor. - Parsing: It uses the component's schema and the core parsers to handle attribute string conversion.
Example: Position Component (Simplified)
// Simplified structure - see src/components/position.js for full example
ComponentManager.registerComponent('position', {
schema: { type: 'vec3', default: { x: 0, y: 0, z: 0 } }, // Expects parseVector3
update(data) {
// 'this' is the <bml-entity> element
if (this.babylonNode) {
this.babylonNode.position.set(data.x, data.y, data.z);
}
}
// No init or remove needed for simple position updates
});
This component system provides a structured way to extend BabylonML's capabilities declaratively through HTML attributes.