npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

javascript-entity-component-system

v2.0.1

Published

A simple JavaScript entity-component-system for games

Downloads

60

Readme

Entity Component System for Javascript

npm version npm downloads

JECS (javascript-entity-component-system) is a easy to use Entity Component System for JavaScript. JECS will help you to easier develop your games by making composable pieces of code, mixing and remixing them with entities to your liking.

Installation

npm i javascript-entity-component-system

Features

  • Simple API - JECS has a very simple and easy to use API with a mix of object-oriented and prodecural style of methods.
  • 🥤 No Dependencies - JECS is built with TypeScript and compiled to JavaScript without the need of any external libraries. The source code is only ~400 lines long.
  • 💾 Lightweight - JECS is a lightweight library. The minified version sits at 3.80kb.
  • 🤝 TypeScript support - JECS is built and is best used with TypeScript. Type defintions and hinting are provided naturally.
  • 📄 Documentation - JECS has documentation for every method and often examples on how to use them.

Getting started

In essence it works like this:

  1. You write components and processors and register them in the system.
  2. You compose entities and register those in the system.
  3. You call the libraries update function ECS.update() in your gameloop.
  4. Profit

Import the Module

ES Modules / TypeScript

import {EntityComponentSystem} from "javascript-entity-component-system" // CLASS
import {Component, Entity, Processor} from "javascript-entity-component-system" // TYPES

const ECS = new EntityComponentSystem()

CommonJS / JavaScript

const {EntityComponentSystem} = require("javascript-entity-component-system") // CLASS

const ECS = new EntityComponentSystem()

Step 1: Components and Processors

Components

Let's start with components. Components are basically just containers with data. In Computer Science terms we call those Data Structures. This is the basic structure:

const PositionComponent: Component = {
  name: "position",
  state: {
    x: 0,
    y: 0
  }
}
const MassComponent: Component = {
  name: "mass",
  state: {
    mass: 1.5,
    velocityX: 0,
    velocityY: 0
  }
}

The name property is required. It will define the name of the component and is important because processor will use it to check if an entity has the required component.

The state property is required too. However, sometimes you don't need any state. In that case you just put in an empty object:

const OnDeathFadeComponent: Component = {
  name: "on_death_fade",
  state: {}
}

It works the same way as with state, except your processor won't have any data to use. Sometimes that's enough for a processor to do it's job. This is uncommon though.

Processors

Now that we have components defined, we can get on to Processors. The structure of them is similar:

const GravityProcessor: Processor = {
  name: "gravity_processor",
  required: ["position", "mass"],
  update(entity: Entity, components: Component[], processor: Processor) {
    // This will be called for every entity that has a position and mass component
  }
}

All properties are required. The first one is the name of the processor and the second one are the required components this processor will need. In this case it needs a position and mass component.

The third property is the update function, that's where all the logic will happen. This function will be called automagically for every entity that has a position and mass component attached. This is very nice because you can focus solely on the logic:

update(entity: Entity, components: Component[], processor: Processor) {
  const [position, mass] = components // The components hold the state of the entity -> change those!

  const gravity = 2 // Arbitrary gravity force
  const result = mass.state.mass * gravity

  mass.state.velocityY += result
  position.state.y += mass.state.velocityY

}

This processor will calculate the gravity force using the entities mass and apply that to it's velocity. To update it's position, we will then add the velocity to it's y position, resulting the entity to move down a bit. This function will be called every frame (inside your gameloop) e.g. it will look like gravity is pulling down on this entity.

Register components and processors

Before we can compose entities we need to register the components and processors in the system:

// Register Component
ECS.addComponent(PositionComponent)
ECS.addComponent(MassComponent)

// Register Processor
ECS.addProcessor(GravityProcessor)

Step 2: Entities

So after we registered our components and processors, we can now compose our entity:

const Player: Entity = ECS.createEntity("Player", ["position", "mass"], ["gravity_processor"])

After that you register it in the system:

ECS.addEntity(Player)

Step 3: Let the magic happen

You're soo close. Call the update function ECS.update() inside the gameloop.

// You should do this every frame. preferably inside your gameloop.
ECS.update()

What's next?

Well the only thing you have to worry about now is to make more components and processors that act upon them.

In a ECS, components and processors are your bread and butter. You write those to have effects on your entities. It's starts to become real fun when you realize that you can mix and match components and processors to your liking. This flexiblity is the real strength of an ECS. That's why it's such a often used pattern in game development. Enjoy :)

Documentation

Docs

Roadmap

  • v2.1.0
    • Implement .freeze() and .unfreeze() to make one-time effects possible
    • Better error handling