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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zakkster/lite-ecs

v1.0.0

Published

Zero-GC Entity Component System built on monomorphic bitwise masks and preallocated object pools.

Readme

@zakkster/lite-ecs

npm version npm bundle size npm downloads npm total downloads TypeScript License: MIT

A zero-GC Entity Component System engineered for 60fps browser games. Built on top of pre-allocated object pools and silicon-speed bitwise filtering.

The ECS architecture that prevents frame drops and memory leaks.


Why lite-ecs?

Most JavaScript game loops rely on OOP (class Player extends Sprite) and object dictionary lookups (if (obj.velocity) { ... }). This creates constant garbage collection (GC) spikes and destroys CPU cache locality.

lite-ecs solves this by fusing two high-performance primitives:

  1. lite-object-pool — Entities are never created or destroyed during gameplay. They are acquired and released from a pre-allocated stack. Zero allocations.
  2. @zakkster/lite-fastbit32 — Systems filter entities using O(1) branchless bitwise operations. Zero dictionary lookups.

| Feature | lite-ecs | Standard JS OOP | | ------------------------ | ---------------------------- | ---------------------------- | | Memory footprint | Flat, pre-allocated | Fragmented | | System filtering | O(1) bitwise mask | O(N) dictionary lookups | | Mid-frame death guard| ✅ Automatic | ❌ Prone to null-ref crashes | | Level transitions | ✅ Zero-GC world.clear() | ❌ Massive GC spikes | | Reentrancy guard | ✅ Built in | ❌ Prone to stack overflows | | Bundle size | < 3KB gzipped | N/A |


Learn the Architecture

Want to know exactly how this engine works under the hood?

The full Lite ECS Masterclass & Handbook walks you through every design decision. You will learn data-oriented design, how to implement FastBit32 state flags, build pre-allocated Object Pools, and architect your own Zero-GC game engine from scratch.

👉 Get the Masterclass & Handbook on itch.io


Installation

npm install @zakkster/lite-ecs

Quick Start

import { World, Entity, System } from '@zakkster/lite-ecs';

// 1. Define your flat data shell
class GameEntity extends Entity {
    constructor() {
        super();
        this.x = 0; this.y = 0;
        this.vx = 0; this.vy = 0;
    }
    reset() {
        super.reset();
        this.x = 0; this.y = 0;
        this.vx = 0; this.vy = 0;
    }
}

// 2. Write pure-logic systems
class PhysicsSystem extends System {
    constructor() { super(['Position', 'Velocity']); }
    update(entity, dt) {
        entity.x += entity.vx * dt;
        entity.y += entity.vy * dt;
    }
}

// 3. Boot the world
const world = new World({
    components: ['Position', 'Velocity'],
    entityFactory: () => new GameEntity(),
    maxEntities: 5000
});
world.addSystem(new PhysicsSystem());

// 4. Spawn and tick
const bullet = world.spawn();
bullet.vx = 200;
bullet.addComponent(world.C('Position'))
      .addComponent(world.C('Velocity'));

world.tick(1 / 60);

API Reference

World

The orchestrator. Manages memory and executes systems.

| Method | Description | | ------------------- | --------------------------------------------------------------------------- | | addSystem(sys) | Mounts a system. Throws if called after the first tick(). | | spawn() | Acquires a clean entity from the pool. Returns null if the pool is capped.| | destroy(entity) | Releases an entity back to the pool instantly. | | C('String') | Translates a component string name into its raw integer bit. | | tick(dt) | Executes all systems against all active entities. Reentrancy-safe. | | clear() | Releases all active entities and resets systems. Perfect for level changes. |

System

Pure logic blocks.

| Method | Description | | ------------------------ | ---------------------------------------------------------------------------- | | constructor(['Names']) | Pass an array of required component strings to subscribe the system. | | update(entity, dt) | Override this. Runs once per matching entity per frame. | | reset() | Optional override. Called when world.clear() is triggered. |

Entity

The zero-GC data shell. You must extend this class to hold your custom fields.

| Method | Description | | ------------------------- | --------------------------------------------------------------------------- | | addComponent(bit) | Attaches a component flag. Expects the integer from world.C(). | | removeComponent(bit) | Removes a component flag. | | reset() | Override this. Called automatically on release. Always call super.reset().|


Recipes

Never iterate arrays calling delete when the player beats a level — it causes frame drops. Use clear() to instantly wipe the board without re-allocating memory.

function onLevelComplete() {
    // 1. Releases all 5,000 active bullets and enemies back to the pool
    // 2. Calls reset() on all Systems to clear their internal state
    world.clear();

    // Load next level — zero allocations, zero GC pressure
    loadLevel(2);
}

You can dynamically change how systems interact with an entity by toggling its bits.

class PowerupSystem extends System {
    constructor() { super(['Player', 'Invincible']); }

    update(entity, dt) {
        entity.invincibleTimer -= dt;
        if (entity.invincibleTimer <= 0) {
            // Instantly un-subscribes the player from this system!
            entity.removeComponent(world.C('Invincible'));
        }
    }
}

If DamageSystem kills an entity earlier in the frame, RenderSystem running later is guaranteed to skip it. The alive flag is checked automatically by the tick loop.

class DamageSystem extends System {
    constructor(world) {
        super(['Health']);
        this.world = world;
    }
    update(entity) {
        if (entity.hp <= 0) this.world.destroy(entity); // entity.alive = false
    }
}
// Any later system in this frame will skip this entity.

Learn More

The full ECS Handbook walks you through every design decision and teaches you to build a Zero-GC game architecture from scratch.

License

MIT — Zahary Shinikchiev