miski

An ECS architecture in Typescript

Usage no npm install needed!

<script type="module">
  import miski from 'https://cdn.skypack.dev/miski';
</script>

README

🍬 Miski ECS

Miski: Quechuan adjective meaning "sweet".

ECS: Entity-Component-System; A software architecture pattern.

Miski ECS: A sweet ECS architecture written in Typescript.

⚠️ Miski is currently in alpha. Expect breaking changes every version until beta.

Contents

Purpose

Miski's purpose is to provide a stable, user-friendly ECS architecture for modern Javascript projects.

Goals

  • To provide good and predictable performance
  • To provide a developer-friendly and user-friendly API
  • To provide a clean, readable, self-documenting, open-source codebase

Not Goals

Because Miski is designed to be used inside other projects, we'll let those devs configure bundling and tune performance to suit their needs, therefore the following are not goals of this project:

  • To be the fastest or smallest ECS on the web
  • To provide polyfills, workarounds, or older browser support for modern ECMAScript features

Features

  • Simple, human-friendly API
  • Modern ES2020 data-oriented Typescript codebase
  • No dependencies
  • Memory-friendly archetype-based ECS model
  • Ability to use more than 32 components in one world using Uint32Array bitfields
  • Basic serialization methods (world.load & world.save)
  • Fast, cache-friendly ArrayBuffer-based component data storage
  • Define components and queries once, reuse them across multiple worlds
  • AND,OR,NOT operators in Queries
  • world.getQueryEntered & world.getQueryExited methods

Install

The javascript module miski.min.js is found in the ./dist folder, along with a sourcemap file and typescript definitions .d.ts file.

import { createComponent, createQuery, createSystem, createWorld } from './miski.min.js';

See API Reference below for a complete list of named exports.

Various type definitions are also exported - see index.ts for a complete list.

API Reference

This is the complete API:

🧩 Components // Schema = Record<string, TypedArrayConstructor>. E.g., { r: Uint8ClampedArray, g: Uint8ClampedArray, b: Uint8ClampedArray };
createComponent: <T extends Schema<T>>(spec: ComponentSpec<T>) => Component<T>;

πŸ”Ž Queries
createQuery: (spec: QuerySpec) => Query;

πŸ”ƒ Systems // optional but helps with type safety - A system is a function of any arity where the first parameter is the World
createSystem: <T, U>(system: System<T, U>) => (world: World) => (...args: U) => ReturnType<T>;

🌍 World
createWorld: (spec: WorldSpec) => World;

  ❓ World info
  world.capacity: number; // Maximum number of Entities
  world.getVacancyCount: () => number; // Number of available (i.e., unused) Entities
  world.version: string; // Miski build version

  πŸ‘Ύ World Entity methods // ('Entity' is just a type alias for 'number')
  world.createEntity: () => Entity | undefined;
  world.destroyEntity: (entity: Entity) => boolean;
  world.hasEntity: (entity: Entity) => boolean;
  world.getEntityArchetype: (entity: Entity) => Archetype | undefined;
  world.entityHasComponent: <T>(entity: Entity, component: Component<T>) => boolean;

  🧩 World Component methods
  world.addComponentToEntity: <T>(component: Component<T>, entity: Entity, props?: SchemaProps<T>) => boolean;
  world.removeComponentFromEntity: <T>(component: Component<T>, entity: Entity) => boolean;

  πŸ”Ž World Query methods
  world.getQueryResult: (query: Query) => [Entity[], ComponentRecord];
  world.getQueryEntered: (query: Query) => Entity[];
  world.getQueryExited: (query: Query) => Entity[];

  πŸ’Ύ World serialization methods
  world.load: (data: MiskiData) => boolean;
  world.save: () => Readonly<MiskiData>;

  πŸ”§ World maintenance methods
  world.refresh: () => void;
  world.purgeCaches: () => void;

Demos

See ./demo for demo code or the demo page for live examples.

Benchmarks

Soonℒ️

Building

To build Miski from source, run:

npm run build

To-Do

Before Beta

  1. Finalise API
  2. Write comprehensive tests
  3. Write consistent code documentation throughout

Before 1.0.0

  1. Optimise performance
  2. Consistent code style throughout

Future

  1. Allow for "changed" in queries
  2. Multithreading support / playing nicely with WebWorkers / SharedArrayBuffers
  3. Proper Deno support
  4. Resizable/dynamic component data storage
  5. Object pooling where necessary

Contributing

Contributions are also welcome and invited. See CONTRIBUTING.md for details.

Feature Requests

Feature requests are welcome and invited. Please open an issue on Github to make a request.

Acknowledgements

Miski is inspired by ape-ecs, BECSY, bitECS, ECSY, Geotic, HECS, and Wolf ECS.

License

© 2021-2022 P. Hughes. All rights reserved.

Miski ECS is released under the MIT license. See LICENSE for further details.