@react-ecs/boids

<h1 align="center"> <br> <a href="https://react-ecs.ldlework.com"><img src="https://i.imgur.com/Rn6yLZs.gif" alt="React ECS" width="300"></a> <br> React ECS <br> <a href="https://react-ecs.ldlework.com">react-ecs.ldlework.com</a> </h1>

Usage no npm install needed!

<script type="module">
  import reactEcsBoids from 'https://cdn.skypack.dev/@react-ecs/boids';
</script>

README


React ECS
React ECS
react-ecs.ldlework.com

A declarative Entity Component System for React.

Documentation Link API Link Examples Link Blog Link

npm npm npm

Join Community Badge

An ECS, or Entity Component System is a design pattern popular in simulations, visualizations and game-development. It eschews rich objects and complex inheritence hierarchies.

Instead:

  • Entities: A simple bag of facets.
  • Facets: Simple data-only objects.
  • Queries: Track entities which have specific facets.
  • Systems: Process the facets of entities matched by queries.

React ECS helps you build your simulations and games using this pattern, in standard React JS fashion (hooks, components, etc)


What does it look like?

Let's make a simple simulation that updates a cube based on a Spinning facet, using React ECS' ThreeJS integration @react-ecs/three.  

First define a Facet

This facet just tracks how much its entity should spin.

// define a facet that get attached to entities
class Spinning extends Facet<Spinning> {
    rotation = new Vector3(0, 0, 0);
}

Then define a System

Systems use queries to track the entities they work upon.

This system uses a query to find entities with both the ThreeView and Spinning facets. ThreeView is facet provided by @react-ecs/three to visually display entities in a ThreeJS scene.

This system updates the entity's 3D rotation based on the Spinning facet:

// define a system which processes entity facets
const SpinningSystem = () => {
    // a query makes it easy to find entities the right facets
    const query = useQuery((e) => e.hasAll(ThreeView, Spinning));

    // systems are basically just update callbacks with priorities
    return useSystem((dt: number) => {
        // iterate the entities with the ThreeView and Spinning facets
        query.loop([ThreeView, Spinning], (e, [view, spin]) => {
            // receive typed facets for each matching entity
            const transform = view.object3d; // <ThreeView> Object3D
            const rotation = spin.rotation // <Spinning> facet
                .clone()
                .multiplyScalar(dt);
            // calculate new state
            const newRotation = transform.rotation.toVector3().add(rotation);
            // mutate facets, state is automatically handled
            transform.rotation.setFromVector3(newRotation);
        });
    });
};

Now put it all together

Now we can create a component to tie it all together. For more information see our documentation and examples.

export const SpinningCubeStory: FC = () => {
    // declare the ECS instance
    const ECS = useECS();

    // drive the ECS with requestAnimationFrame hook
    useAnimationFrame((_, dt) => ECS.update(dt));

    return (
          {/* use ECS as context provider */}
          <ECS.Provider>
              {/* add systems to the simulation */}
              <SpinningSystem />

              {/* entities are their own context provider */}
              <Entity>

                  {/* add facets to entities */}
                  <Spinning rotation={new Vector3(1, 1, 1)} />

                  {/* use integrations like react-three-fiber */}
                  <ThreeView>
                      <Box />
                  </ThreeView>

              </Entity>
          </ECS.Provider>
    );
};