We just released ECSY v0.4 and ECSY-THREE v0.1!
Since the initial release of ECSY we have been focusing on API stability and bug fixing as well as providing some features (such as components’ schemas) to improve the developer experience and provide better validation and descriptive errors when working in development mode.
The API layer hasn't changed that much since its original release but we introduced some new concepts:
Components schemas: Components are now required to have a schema (Unless you are defining a TagComponent
).
Defining a component schema is really simple, you just need to define the properties of your component, their types, and, optionally, their default values
class Velocity extends Component {}
Velocity.schema = {
x: { type: Types.Number, default: 0 },
y: { type: Types.Number, default: 0 }
};
We provide type definitions for the basic javascript types, and also on ecsy-three
for most of the three.js
data types, but you can create your own custom types too.
Defining a schema for a component will give you some benefits for free like:
- Default
copy
,clone
andreset
implementation for the component. Although you could define your own implementation for these functions for maximum performance. - Components pool to reuse instances to improve performance and GC stability.
- Tooling such as validators or editors which could show specific widgets depending on the data type and value.
- Serializers for components so we can store them in JSON or ArrayBuffers, useful for networking, tooling or multithreading.
Registering components: One of the requirements we introduced recently is that you must always register your components before using them, and that includes registering them before registering systems that use these components too. This was initially done to support an optimization to Queries, but we feel making this an explicit rule will also allow us to add further optimizations down the road, as well as just generally being easier to reason about.
Benchmarks: When building a framework like ECSY that is expected to be doing a lot of operations per frame, it’s hard to infer how a change in the implementation will impact the overall performance. So we introduced a benchmark command to run a set of tests and measure how long they take.
We can use this data to compare across different branches and get an estimation on how much specific changes are affecting the performance.
ECSY-THREE
We created ecsy-three
to facilitate developing applications using ECSY and three.js by providing a set of components and systems for interacting with ThreeJS from ECSY. In this release it has gotten a major refactor and we got rid of all the “extras” in the main repository, to focus on the “core” API to make it easy to use with three.js without adding unneeded abstractions.
We introduce extended implementations of ECSY's World
and Entity
classes (ECSYThreeWorld and ECSYThreeEntity) which provides some helpers to interact with three.js' Object3Ds
.
The main helper you will be using is Entity.addObject3DComponent(Object3D, parent)
that will add the Object3DComponent
to the entity holding a three.js' Object3D
reference, as well as adding extra tag components to indentify the type of Object3D
we are adding.
Please note that we have been adding tag components for almost every type of Object3D
in three.js
(Mesh
, Light
, Camera
, Scene
, …) but you could still add any other you may need.
For example:
// Create a three.js Mesh
let mesh = new THREE.Mesh(
new THREE.BoxBufferGeometry(),
new THREE.MeshBasicMaterial()
);
// Attach the mesh to a new ECSY entity
let entity = world.createEntity().addObject3DComponent(mesh);
If we inspect the entity, it will have the following components:
Object3DComponent
with{ value: mesh }
MeshTagComponent
. Automatically added byaddObject3DComponent
Then you can query for each one of these components in your systems and grab the Object3D
by using entity.getObject3D()
, which is an alias for entity.getComponent(Object3DComponent).value
.
import { MeshTagComponent, Object3DComponent } from "ecsy-three";
import { System } from "ecsy";
class RandomColorSystem extends System {
execute(delta) {
this.queries.entities.results.forEach(entity => {
// This will always return a Mesh since
// we are querying for the MeshTagComponent
const mesh = entity.getObject3D();
mesh.material.color.setHex(Math.random() * 0xffffff);
});
}
}
RandomColorSystem.queries = {
entities: {
components: [MeshTagComponent, Object3DComponent]
}
};
When removing Object3D components we also introduced the entity.removeObject3DComponent(unparent)
that will get rid of the Object3DComponent
as well as all the tag components introduced automatically (For example the MeshTagComponent
in the previous example).
One important difference between adding or removing the Object3D
components yourself or using these new helpers is that they can handle parenting/unparenting too.
For example the following code will attach the mesh
to the scene
(Internally it will be doing sceneEntity.getObject3D().add(mesh)
):
let entity = world.createEntity().addObject3DComponent(mesh, sceneEntity);
When removing the Object3D
component we can pass true
as parameter to indicate that we want to unparent this Object3D
from its current parent:
entity.removeObject3DComponent(true);
// The previous line is equivalent to:
entity.getObject3D().parent.remove(entity.getObject3D());
"Initialize" helper
Most ecsy & three.js applications will need a set of common components:
- World
- Camera
- Scene
- WebGLRenderer
- Render loop
So we added a helper function initialize in ecsy-three
that will create all these for you. It is completely optional, but is a great way to quickly bootstrap an application.
import { initialize } from "ecsy-three";
const { world, scene, camera, renderer } = initialize();
You can find a complete example using all these methods the following glitch:
Developer tools
We updated the developer tools extension (Read about them) to support the newest version of ECSY core, but it should still be backward compatible with previous versions.We fixed the remote debugging mode that allows you to run the extension in one browser while debugging an application in another browser or device (for example an Oculus Quest).You can grab them on your favourite browser extension store:
The community
We are so happy with how the community has been helping us build ECSY and the project that have emerged out of them.
We have a bunch of cool experiments around physics, networking, games, and boilerplates and bindings for pixijs, phaser, babylon, three.js, react, and many more!
It’s been especially useful for us to open a Discord where a lot of interesting discussions both ECSY or ECS as a paradigm have happened.
What's next?
There is still a long road ahead, and we have a lot of features and projects in mind to keep improving the ECSY ecosystem as for example:
- Revisit the current reactive queries implementation and design, especially the deferred removal step.
- Continue to experiment with using ECSY in projects internally at Mozilla, like Hubs and Spoke.
- Improving the sandbox and API examples
- Keep adding new systems and components for higher level functionality: physics, teleport, networking, hands & controllers, …
- Keep building new demos to showcase the features we are releasing
Please feel free to use our github repositories (ecsy, ecsy-three, ecsy-devtools) to follow the development, request new features or file issues on bugs you find. Also come participate in community discussions on our discourse forum and discord server.