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

@driftengine/entities

v4.3.0

Published

Entities with generational identity, component storage, systems and scenes

Downloads

3,043

Readme

@driftengine/entities

Entities with generational identity, component storage, queries, systems with declared reads and writes, prefabs and scene serialization.

It imports no other engine package. An entity model that knew what a Transform was would be an entity model that knew it had a scene — and the argument for declared reads and writes is that a declaration is about a component id rather than about what the component means.

It also declares no component types. A consumer writes the ones its world needs, or takes them from whichever package owns the subsystem.

import { EntityAllocator } from '@driftengine/entities';

const entities = new EntityAllocator();
const player = entities.create();
entities.destroy(player);
entities.alive(player); // false — and the entity that takes the slot is a different handle

The handle

An entity is one number: a 26-bit index and a 27-bit generation, combined arithmetically. The generation is what stops a stale handle addressing a live entity — an index freed and reused makes every old reference silently valid, pointing at a different thing with no error anywhere.

The conventional packed Uint32 splits 24 and 8, so a slot's 257th reuse hands back a handle identical to its first. This split gives sixty-seven million entities and 134 million reuses of each slot, and costs four bytes per stored entity because a handle lives in a Float64Array.

26 + 27 is the whole 53-bit budget, exactly. There is no headroom, deliberately, and a test asserts the top handle so that is discovered here rather than in a wrong comparison.

Systems declare what they touch

const schedule = buildSchedule([
  { name: 'hunger', writes: [Hunger], everyTicks: 60, run(view) { … } },
  { name: 'decay', reads: [Hunger], writes: [Health], after: ['hunger'], run(view) { … } },
]);
runSchedule(world, schedule, tick);

The declaration is enforced. A system that writes something it did not declare is refused naming both — a schedule derived from a lie is worse than no schedule. writes implies reads.

Order is declaration order, adjusted only by after, which is topologically sorted with declaration order as the tie-break. A cycle in after is refused naming the systems.

everyTicks strides the fixed step and is never a rate in seconds: a rate in wall-clock time leaves the determinism contract on its first dropped frame.

Destroying from inside a system is deferred to after it returns. A removal swaps the last dense entry into the hole, so removing mid-walk moves an entity the cursor has already passed into a position it has already visited — and that entity is never seen, silently, and only whichever one happened to be last. create and add are immediate, and a newly added entity may be visited in the same pass.

Prefabs and scenes

const guard = definePrefab('guard', [
  [Health, { current: 100 }],
  [Perception, { sightRange: 40 }],
]);
const spawned = instantiate(world, guard, { Perception: { sightRange: 60 } });

const scene = serializeWorld(world, [Health, Perception]);
const result = deserializeWorld(fresh, scene, [Health, Perception]);

A prefab is a value with no link back to its instances. A live link is what an editor wants, and it costs every instance a record of which fields it has overridden; Track K can add that record without changing what a prefab is.

A scene addresses every value by a stable field id, never a name and never a position. A field inserted in the middle would renumber everything after it, and a save would then load the right names with the wrong values — worse than failing, because it looks like it worked.

Loading across a change goes through driftscript's migration, unchanged: a field added since arrives with its default, one removed is dropped, and one whose type changed is refused naming it. Nothing is written into the world until every entity has migrated, so a refusal on the fifth does not leave four behind.

Entity references are remapped on load rather than preserved, because a saved handle's slot may be live in the world being loaded into. That only works for fields declared Entity; a number that happens to hold one is a number.

Documentation

This file is the reference, including the five things the model refuses and what would reverse each.