### Install miniplex-react and miniplex Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Install the necessary packages using npm, yarn, or pnpm. ```sh npm install miniplex miniplex-react ``` ```sh yarn add miniplex miniplex-react ``` ```sh pnpm add miniplex miniplex-react ``` -------------------------------- ### Miniplex Basic Usage Example Source: https://github.com/hmans/miniplex/blob/main/README.md Demonstrates defining an entity type, creating a world, adding entities, defining queries, creating systems, and reacting to entity events. Ensure all necessary types and functions are defined before use. ```typescript /* Define an entity type */ type Entity = { position: { x: number; y: number } velocity?: { x: number; y: number } health?: { current: number max: number } poisoned?: true } /* Create a world with entities of that type */ const world = new World() /* Create an entity */ const player = world.add({ position: { x: 0, y: 0 }, velocity: { x: 0, y: 0 }, health: { current: 100, max: 100 } }) /* Create another entity */ const enemy = world.add({ position: { x: 10, y: 10 }, velocity: { x: 0, y: 0 }, health: { current: 100, max: 100 } }) /* Create some queries: */ const queries = { moving: world.with("position", "velocity"), health: world.with("health"), poisoned: queries.health.with("poisoned") } /* Create functions that perform actions on entities: */ function damage({ health }: With, amount: number) { health.current -= amount } function poison(entity: With) { world.addComponent(entity, "poisoned", true) } /* Create a bunch of systems: */ function moveSystem() { for (const { position, velocity } of queries.moving) { position.x += velocity.x position.y += velocity.y } } function poisonSystem() { for (const { health, poisoned } of queries.poisoned) { health.current -= 1 } } function healthSystem() { for (const entity of queries.health) { if (entity.health.current <= 0) { world.remove(entity) } } } /* React to entities appearing/disappearing in queries: */ queries.poisoned.onEntityAdded.subscribe((entity) => { console.log("Poisoned:", entity) }) ``` -------------------------------- ### Install Miniplex using npm, yarn, or pnpm Source: https://github.com/hmans/miniplex/blob/main/README.md Add the miniplex package to your project using your preferred package manager. ```bash npm add miniplex yarn add miniplex pnpm add miniplex ``` -------------------------------- ### Create React API Bindings for Miniplex World Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Create a Miniplex world and export React bindings using `createReactAPI`. This setup is typically done in a central module for global access. ```typescript /* state.ts */ import { World } from "miniplex" import createReactAPI from "miniplex-react" /* Our entity type */ export type Entity = { /* ... */ } /* Create a Miniplex world that holds our entities */ const world = new World() /* Create and export React bindings */ export const ECS = createReactAPI(world) ``` -------------------------------- ### Initialize and Manage Entities with `@miniplex/bucket` Source: https://context7.com/hmans/miniplex/llms.txt Use the `Bucket` class for a reactive, framework-agnostic entity container. It provides O(1) removal, lifecycle events, and can be iterated safely even during removal. ```typescript import { Bucket } from "@miniplex/bucket" type Item = { id: number; label: string } const bucket = new Bucket() bucket.onEntityAdded.subscribe((item) => console.log("Added:", item.label)) bucket.onEntityRemoved.subscribe((item) => console.log("Removed:", item.label)) const a = bucket.add({ id: 1, label: "Alpha" }) // "Added: Alpha" const b = bucket.add({ id: 2, label: "Beta" }) // "Added: Beta" console.log(bucket.size) // 2 console.log(bucket.first) // { id: 1, label: "Alpha" } console.log(bucket.has(a)) // true console.log(bucket.version) // 2 (incremented on each add/remove) bucket.remove(a) // "Removed: Alpha" console.log(bucket.size) // 1 // Safe in-loop removal (iterates in reverse order) for (const item of bucket) { bucket.remove(item) } console.log(bucket.size) // 0 ``` -------------------------------- ### Get current entity context with `useCurrentEntity` hook Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Use the `useCurrentEntity` hook to retrieve the entity context from the nearest `` component within nested components. This is useful for accessing and manipulating the current entity's data. ```tsx const Health = () => { /* Retrieve the entity represented by the neares `` component */ const entity = ECS.useCurrentEntity() useEffect(() => { /* Do something with the entity here */ }) return null } ``` -------------------------------- ### Accessing Entity Context with useCurrentEntity Source: https://context7.com/hmans/miniplex/llms.txt Use this hook within a component to get the nearest entity provided by an ECS.Entity ancestor. It throws an error if called outside of an Entity subtree. This is useful for deeply nested components that need to interact with the entity without prop drilling. ```tsx import { useEffect } from "react" import { ECS, world } from "./ecs" const HealthBar = () => { const entity = ECS.useCurrentEntity() useEffect(() => { if (!entity.health) return console.log(`Health: ${entity.health.current} / ${entity.health.max}`) }) if (!entity.health) return null const pct = (entity.health.current / entity.health.max) * 100 return
} const Player = () => ( {/* can call useCurrentEntity() here */} ) ``` -------------------------------- ### Initialize Components on Entity Added Source: https://github.com/hmans/miniplex/blob/main/README.md Use `onEntityAdded` with a specific query to initialize components on newly spawned entities that match the query criteria. ```typescript const withHealth = world.with("health") withHealth.onEntityAdded.subscribe((entity) => { entity.health.current = entity.health.max }) ``` -------------------------------- ### Initialize and Reset Game State in React Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Spawns an initial number of enemies when a React component mounts and clears the world state when it unmounts. Ensure ECS is imported. ```tsx import { spawnEnemy } from "./enemies" export const GameState = () => { useEffect(() => { /* Initialize game state */ for (let i = 0; i < 10; i++) { spawnEnemy() } /* When unmounting, reset game state */ return () => { ECS.world.clear() } }, []) } ``` -------------------------------- ### Query entities with all specified components Source: https://context7.com/hmans/miniplex/llms.txt Use `world.with` to create a query for entities that possess all of the listed components. Queries are lazy and connect automatically when first accessed. ```typescript const world = new World() world.add({ position: { x: 0, y: 0, z: 0 }, velocity: { x: 1, y: 0, z: 0 } }) world.add({ position: { x: 5, y: 0, z: 0 } }) const moving = world.with("position", "velocity") function movementSystem(dt: number) { for (const { position, velocity } of moving) { position.x += velocity.x * dt position.y += velocity.y * dt position.z += velocity.z * dt } } movementSystem(0.016) console.log(moving.entities[0].position.x) // 0.016 ``` -------------------------------- ### createReactAPI(world) Source: https://context7.com/hmans/miniplex/llms.txt Creates React bindings for a Miniplex `World` instance. It returns an object containing the world instance and hooks/components for integrating ECS data into React applications. ```APIDOC ## `createReactAPI(world)` — Create React bindings for a world The default export of `miniplex-react`. Accepts a `World` instance and returns `{ world, Entity, Entities, Component, useCurrentEntity }`. Call this once, export the result, and import it wherever React components need ECS access. ### Parameters - **world** (World) - The Miniplex World instance to create bindings for. ### Returns - **object**: An object containing: - **world**: The provided `World` instance. - **Entity**: A React component for rendering a single entity. - **Entities**: A React component for rendering a collection of entities. - **Component**: A React component for rendering a specific component of an entity. - **useCurrentEntity**: A React hook to access the current entity in context. ### Example ```ts // ecs.ts import { World } from "miniplex" import createReactAPI from "miniplex-react" type Entity = { /* ... */ } export const world = new World() export const ECS = createReactAPI(world) // In another component: import { ECS } from './ecs' function MyComponent() { return {(entities) => (
{entities.map(entity => )}
)}
} ``` ``` -------------------------------- ### Iterate Over Queries using `for...of` (Recommended) Source: https://github.com/hmans/miniplex/blob/main/README.md Use `for...of` loops to iterate over queries. This is performant and allows safe removal of entities during iteration because it iterates in reverse order. ```typescript const withHealth = world.with("health") /* ✅ Recommended: */ for (const entity of withHealth) { if (entity.health <= 0) { world.remove(entity) } } ``` -------------------------------- ### Create a Miniplex World Source: https://github.com/hmans/miniplex/blob/main/README.md Initialize a new Miniplex world, which serves as a container for entities and the primary API for interacting with them. This is the first step in using Miniplex. ```typescript import { World } from "miniplex" const world = new World() ``` -------------------------------- ### world.with(...components) Source: https://context7.com/hmans/miniplex/llms.txt Queries entities that possess all of the specified components. This method returns a `Query` object that can be iterated over. ```APIDOC ## `world.with(...components)` — Query entities that have all listed components Returns (or reuses) a `Query>` that contains only entities possessing all of the specified component names. Queries are lazy and connect automatically the first time they are iterated or their entities are accessed. ### Example Usage: ```ts const world = new World() world.add({ position: { x: 0, y: 0, z: 0 }, velocity: { x: 1, y: 0, z: 0 } }) world.add({ position: { x: 5, y: 0, z: 0 } }) const moving = world.with("position", "velocity") function movementSystem(dt: number) { for (const { position, velocity } of moving) { position.x += velocity.x * dt position.y += velocity.y * dt position.z += velocity.z * dt } } movementSystem(0.016) console.log(moving.entities[0].position.x) // 0.016 ``` ``` -------------------------------- ### Implement systems with `useFrame` in React Three Fiber Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Implement Miniplex systems within a React Three Fiber application by using the `useFrame` hook. This allows systems to execute logic once per frame, updating entities based on their components. ```tsx import { useEntities } from "miniplex-react" import { useFrame } from "@react-three/fiber" import { ECS } from "./state" const movingEntities = ECS.world.with("position", "velocity") const MovementSystem = () => { useFrame((_, dt) => { for (const entity of movingEntities) { entity.position.x += entity.velocity.x * dt entity.position.y += entity.velocity.y * dt entity.position.z += entity.velocity.z * dt } }) return null } ``` -------------------------------- ### new World(entities?) Source: https://context7.com/hmans/miniplex/llms.txt Creates a new World instance, which is the central store for entities. It can optionally be pre-populated with an initial array of entities. The generic type E defines the shape of entities. ```APIDOC ## new World(entities?) ### Description Creates a new World instance, which is the central store for entities. It can optionally be pre-populated with an initial array of entities. The generic type E defines the shape of entities. ### Parameters - **entities** (Array) - Optional - An initial array of entities to populate the world with. ### Type Parameters - **E** - Describes the shape of all entities in the world. Component properties should be declared optional. ### Example ```ts import { World } from "miniplex" type Entity = { position: { x: number; y: number; z: number } velocity?: { x: number; y: number; z: number } health?: { current: number; max: number } dead?: true enemy?: true } // Create an empty world const world = new World() // Or pre-populate it const world2 = new World([ { position: { x: 0, y: 0, z: 0 } }, { position: { x: 10, y: 0, z: 0 }, enemy: true } ]) console.log(world2.entities.length) // 2 console.log(world2.size) // 2 console.log(world2.first) // { position: { x: 0, y: 0, z: 0 } } ``` ``` -------------------------------- ### new Bucket(entities?) Source: https://context7.com/hmans/miniplex/llms.txt A low-level, framework-agnostic container for entities. It stores entities in an array, provides O(1) removal, and fires `onEntityAdded` / `onEntityRemoved` events. Suitable for use cases not requiring full ECS query machinery. ```APIDOC ## `new Bucket(entities?)` — Reactive entity container `Bucket` is the low-level, framework-agnostic container underlying `World`. It stores entities in a plain array, uses a shuffle-pop strategy for O(1) removal, and fires `onEntityAdded` / `onEntityRemoved` events. It can be used standalone when you only need a reactive list without the full ECS query machinery. ### Parameters - **entities** (Iterable, optional) - An iterable of initial entities to populate the bucket. ### Methods - **add(entity: E)**: Adds an entity to the bucket. - **remove(entity: E)**: Removes an entity from the bucket. - **has(entity: E)**: Checks if an entity is present in the bucket. ### Properties - **size**: (number) - The current number of entities in the bucket. - **first**: (E | undefined) - The first entity in the bucket. - **version**: (number) - A version counter incremented on each add/remove operation. ### Events - **onEntityAdded**: An event emitter that fires when an entity is added. - **onEntityRemoved**: An event emitter that fires when an entity is removed. ### Example ```ts import { Bucket } from "@miniplex/bucket" type Item = { id: number; label: string } const bucket = new Bucket() const a = bucket.add({ id: 1, label: "Alpha" }) const b = bucket.add({ id: 2, label: "Beta" }) console.log(bucket.size) // 2 console.log(bucket.has(a)) // true bucket.remove(a) console.log(bucket.size) // 1 ``` ``` -------------------------------- ### world.without(...components) Source: https://context7.com/hmans/miniplex/llms.txt Queries entities that do not have any of the specified components. This can be chained with `with` for more complex queries. ```APIDOC ## `world.without(...components)` — Query entities that lack listed components Returns a `Query` containing only entities that do **not** have any of the specified components. Can be chained with `with` for compound exclusion queries. ### Example Usage: ```ts const world = new World() world.add({ position: { x: 0, y: 0, z: 0 } }) world.add({ position: { x: 1, y: 0, z: 0 }, dead: true }) // All living entities (those without the `dead` flag) const alive = world.without("dead") console.log(alive.entities.length) // 1 // Chained: living entities that can move const movingAlive = world.with("position", "velocity").without("dead") ``` ``` -------------------------------- ### Create React Bindings with `createReactAPI` from `miniplex-react` Source: https://context7.com/hmans/miniplex/llms.txt Use `createReactAPI` to generate React bindings for a Miniplex `World` instance. This function returns an object containing the world instance and hooks/components for integrating ECS data into React applications. ```typescript // ecs.ts import { World } from "miniplex" import createReactAPI from "miniplex-react" type Entity = { position: { x: number; y: number; z: number } velocity?: { x: number; y: number; z: number } health?: { current: number; max: number } enemy?: true } export const world = new World() export const ECS = createReactAPI(world) ``` -------------------------------- ### Recommended Query Reuse in Miniplex Source: https://github.com/hmans/miniplex/blob/main/README.md Create queries once and reuse them for systems that access the same components. This avoids redundant checks within the world. ```typescript /* ✅ Recommended: */ const movingEntities = world.with("position", "velocity") function movementSystem() { for (const { position, velocity } of movingEntities) { position.x += velocity.x position.y += velocity.y position.z += velocity.z } } ``` ```typescript /* ⛔️ Avoid: */ function movementSystem(world) { /* This will work, but now the world needs to check if a query for "position" and "velocity" already exists every time this function is called, which is pure overhead. */ for (const { position, velocity } of world.with("position", "velocity")) { position.x += velocity.x position.y += velocity.y position.z += velocity.z } } ``` -------------------------------- ### Render entities using render props with `` Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Utilize render props with `` by passing a function as a child. This function receives each entity and should return the JSX to render, allowing access to entity data for per-entity logic. ```tsx const enemies = ECS.world.with("enemy") const EnemyShips = () => ( {(entity) => { const health = Math.random() * 1000 return ( ) }} ) ``` -------------------------------- ### Alternative Entity Rendering with Children Prop Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Demonstrates alternative ways to use the `children` prop with the `` component, including passing a function or a React component directly. ```tsx export const Enemies = () => ( {(entity) => } ) ``` ```tsx export const Enemies = () => {Enemy} ``` -------------------------------- ### Compose Complex Queries by Chaining `with`, `without`, and `where` Source: https://context7.com/hmans/miniplex/llms.txt Chain query methods like `with`, `without`, and `where` to build complex, deduplicated queries. Query instances are reused if called with identical arguments, optimizing performance. ```typescript const world = new World() world.add({ position: { x: 0, y: 0, z: 0 }, velocity: { x: 1, y: 0, z: 0 }, enemy: true }) world.add({ position: { x: 1, y: 0, z: 0 }, velocity: { x: -1, y: 0, z: 0 } }) world.add({ position: { x: 2, y: 0, z: 0 }, dead: true }) // Enemies that are moving and not dead const activeEnemies = world .with("position", "velocity", "enemy") .without("dead") console.log(activeEnemies.entities.length) // 1 // Query reuse — same config = same object reference const q1 = world.with("position").without("dead") const q2 = world.without("dead").with("position") console.log(q1 === q2) // true ``` -------------------------------- ### Enhance Existing Entities with Components Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Use `` with an existing entity reference to add new components to it. Entities managed this way are not destroyed when the component unmounts. ```tsx import { ECS } from "./state" const Game = () => { const [player] = useState(() => ECS.world.add({ position: { x: 0, y: 0, z: 0 }, health: 100 }) ) return ( <> {/* All sorts of stuff */} {/* More stuff */} ) } const RenderPlayer = ({ player }) => ( ) ``` -------------------------------- ### Spawn Enemies Imperatively in React Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Defines a component to render enemies and a function to spawn new enemies imperatively. Use this for entities that are not directly managed by React components. ```tsx const enemies = ECS.world.with("enemy") export const Enemies = () => ( ) export const spawnEnemy = () => ECS.world.add({ position: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 }, health: 100, enemy: true }) ``` -------------------------------- ### Render entities from a static array with `` Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Pass a static array of entities to the `in` prop of `` to prevent re-renders when the underlying query changes. Access the entities via the `.entities` property of the query. ```tsx import { ECS } from "./state" import { AsteroidModel } from "./models" const asterois = ECS.world.with("isAsteroid") /* Note the .entities property! */ const Asteroids = () => ( ) ``` -------------------------------- ### Render list of entities with `` Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Use the `` component to render a list of entities matching a Miniplex query. It automatically re-renders when the query results change. ```tsx import { ECS } from "./state" import { AsteroidModel } from "./models" const asterois = ECS.world.with("isAsteroid") const Asteroids = () => ( ) ``` -------------------------------- ### Query Entities with Specific Components in Miniplex Source: https://github.com/hmans/miniplex/blob/main/README.md Create queries to fetch entities that possess specific components. This is useful for implementing systems that operate on a subset of entities. ```typescript /* Get all entities with position and velocity */ const movingEntities = world.with("position", "velocity") ``` -------------------------------- ### Subscribe to Entity Lifecycle Events with `world.onEntityAdded` and `world.onEntityRemoved` Source: https://context7.com/hmans/miniplex/llms.txt Utilize `onEntityAdded` and `onEntityRemoved` event objects on `World` or `Query` instances to execute initialization or cleanup logic when entities enter or leave. This is useful for managing component states or performing side effects. ```typescript const world = new World() const withHealth = world.with("health") // Initialize health to max whenever an entity gains a health component withHealth.onEntityAdded.subscribe((entity) => { entity.health!.current = entity.health!.max console.log("Entity initialized with full health:", entity.health) }) withHealth.onEntityRemoved.subscribe((entity) => { console.log("Entity lost its health component:", entity) }) // Triggers onEntityAdded on withHealth const entity = world.add({ position: { x: 0, y: 0, z: 0 }, health: { current: 0, max: 100 } }) // => "Entity initialized with full health: { current: 100, max: 100 }" world.removeComponent(entity, "health") // => "Entity lost its health component: ..." ``` -------------------------------- ### Declare Entities and Components in React Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Use the `` and `` components to declare entities and their components within your React application. Entities declared this way are automatically created on mount and destroyed on unmount. ```tsx import { ECS } from "./state" const Player = () => ( ) ``` -------------------------------- ### Query chaining Source: https://context7.com/hmans/miniplex/llms.txt Allows composing complex queries by chaining methods like `with`, `without`, and `where`. This creates new, deduplicated queries that refine the parent query's criteria. ```APIDOC ## Query chaining — Composing complex queries Queries returned by `with`, `without`, and `where` are themselves queryable. Chaining these methods produces new, deduplicated queries that extend the parent's criteria. Query instances are reused when called with identical arguments. ### Methods - **with(...components)**: Returns a new query including entities with the specified components. - **without(...components)**: Returns a new query excluding entities with the specified components. - **where(predicate)**: Returns a new query including entities that satisfy the given predicate function. ### Example ```ts const world = new World() world.add({ position: { x: 0, y: 0, z: 0 }, velocity: { x: 1, y: 0, z: 0 }, enemy: true }) world.add({ position: { x: 1, y: 0, z: 0 }, velocity: { x: -1, y: 0, z: 0 } }) world.add({ position: { x: 2, y: 0, z: 0 }, dead: true }) // Enemies that are moving and not dead const activeEnemies = world .with("position", "velocity", "enemy") .without("dead") console.log(activeEnemies.entities.length) // 1 ``` ``` -------------------------------- ### Implement Miniplex System for Movement Source: https://github.com/hmans/miniplex/blob/main/README.md Define a system function that iterates over entities matching a query and performs operations on their components. Entities can be destructured for easy component access. ```typescript function movementSystem() { for (const { position, velocity } of movingEntities) { position.x += velocity.x position.y += velocity.y position.z += velocity.z } } ``` -------------------------------- ### Alternative to `where` using Additional Components Source: https://github.com/hmans/miniplex/blob/main/README.md Rewrite queries that use `where` by introducing new components to represent states, avoiding the need for manual reindexing and leveraging Miniplex's reactive nature. ```typescript const damagedEntities = world.with("health", "damaged") const deadEntities = world.with("health", "dead") function damageEntity(entity: With, amount: number) { entity.health.current -= amount if (entity.health.current < entity.health.max) { world.addComponent(entity, "damaged") } if (entity.health.current <= 0) { world.addComponent(entity, "dead") } } ``` -------------------------------- ### Create an entity world with Miniplex Source: https://context7.com/hmans/miniplex/llms.txt Instantiate a new World, optionally pre-populating it with entities. The generic type parameter `E` defines the entity shape. ```typescript import { World } from "miniplex" type Entity = { position: { x: number; y: number; z: number } velocity?: { x: number; y: number; z: number } health?: { current: number; max: number } dead?: true enemy?: true } // Create an empty world const world = new World() // Or pre-populate it const world2 = new World([ { position: { x: 0, y: 0, z: 0 } }, { position: { x: 10, y: 0, z: 0 }, enemy: true } ]) console.log(world2.entities.length) // 2 console.log(world2.size) // 2 console.log(world2.first) // { position: { x: 0, y: 0, z: 0 } } ``` -------------------------------- ### Render Entities Using Children Prop Source: https://github.com/hmans/miniplex/blob/main/packages/react/README.md Renders entities using the `children` prop of the `` component, deferring entity rendering to a separate function. This is useful for reusable entity rendering components. ```tsx const enemies = ECS.world.with("enemy") export const Enemies = () => export const Enemy = (entity) => ( ) ``` -------------------------------- ### Declaratively Create or Wrap an Entity with ECS.Entity Source: https://context7.com/hmans/miniplex/llms.txt Use ECS.Entity to spawn new entities that are automatically removed on unmount, or to enhance existing entities with child components without taking ownership of their lifecycle. Supports ref forwarding and render-prop children. ```tsx import { ECS } from "./ecs" // Spawn a new entity — auto-removed when unmounted const Player = () => ( ) ``` ```tsx // Render-prop: receive the entity object inside children const PlayerWithRef = () => ( {(entity) => (
Entity exists in world: {String(ECS.world.has(entity))}
)}
) ``` ```tsx // Forward a ref to get the entity object import { useRef } from "react" const WithRef = () => { const ref = useRef(null) return // After render: ref.current === the entity object } ``` -------------------------------- ### world.addComponent(entity, name, value) Source: https://context7.com/hmans/miniplex/llms.txt Adds a specified component to an existing entity in the world. This action triggers reindexing to ensure queries remain consistent. If the component already exists, the operation has no effect. ```APIDOC ## world.addComponent(entity, name, value) ### Description Adds a specified component to an existing entity in the world. This action triggers reindexing to ensure queries remain consistent. If the component already exists, the operation has no effect. ### Parameters - **entity** (E) - Required - The entity to which the component will be added. - **name** (string) - Required - The name of the component to add. - **value** (any) - Required - The value of the component. ### Example ```ts const world = new World() const entity = world.add({ position: { x: 0, y: 0, z: 0 } }) const withHealth = world.with("health") console.log(withHealth.entities.length) // 0 world.addComponent(entity, "health", { current: 100, max: 100 }) console.log(withHealth.entities.length) // 1 console.log(entity.health) // { current: 100, max: 100 } ``` ``` -------------------------------- ### world.reindex(entity, future?) Source: https://context7.com/hmans/miniplex/llms.txt Manually re-evaluates an entity against all active queries. Essential after direct property mutations when predicate queries are used. ```APIDOC ## `world.reindex(entity, future?)` — Manually re-evaluate an entity against all queries Forces the world to re-evaluate an entity against every active query. Needed after direct property mutations when predicate queries are involved. The optional `future` argument lets you describe the entity's upcoming state before destructively changing it (preserving the old object in `onEntityRemoved` callbacks). ### Example Usage: ```ts const world = new World() const entity = world.add({ position: { x: 0, y: 0, z: 0 }, health: { current: 100, max: 100 } }) const critical = world.with("health").where(({ health }) => health.current < 30) console.log(critical.entities.length) // 0 entity.health!.current = 10 world.reindex(entity) console.log(critical.entities.length) // 1 ``` ``` -------------------------------- ### Query entities lacking specified components Source: https://context7.com/hmans/miniplex/llms.txt Use `world.without` to filter entities that do not have any of the specified components. This can be chained with `world.with` for more complex queries. ```typescript const world = new World() world.add({ position: { x: 0, y: 0, z: 0 } }) world.add({ position: { x: 1, y: 0, z: 0 }, dead: true }) // All living entities (those without the `dead` flag) const alive = world.without("dead") console.log(alive.entities.length) // 1 // Chained: living entities that can move const movingAlive = world.with("position", "velocity").without("dead") ``` -------------------------------- ### world.add(entity) Source: https://context7.com/hmans/miniplex/llms.txt Adds a plain JavaScript object as an entity to the world. This operation immediately triggers reindexing, making the entity available in relevant queries. ```APIDOC ## world.add(entity) ### Description Adds a plain JavaScript object as an entity to the world. This operation immediately triggers reindexing, making the entity available in relevant queries. ### Parameters - **entity** (E) - Required - The entity object to add to the world. ### Returns - **E** - The added entity object, potentially with its type narrowed. ### Example ```ts const world = new World() const player = world.add({ position: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 }, health: { current: 100, max: 100 } }) const enemy = world.add({ position: { x: 20, y: 0, z: 0 }, health: { current: 50, max: 50 }, enemy: true }) console.log(world.size) // 2 console.log(world.has(player)) // true ``` ``` -------------------------------- ### Subscribe to Entity Added Events Source: https://github.com/hmans/miniplex/blob/main/README.md Subscribe to the `onEntityAdded` event to be notified when a new entity is spawned in the world. This is useful for running initialization code. ```typescript world.onEntityAdded.subscribe((entity) => { console.log("A new entity has been spawned:", entity) }) ``` -------------------------------- ### world.id(entity) / world.entity(id) Source: https://context7.com/hmans/miniplex/llms.txt Provides stable numeric IDs for entities currently in the world and allows reverse lookup. Useful for serialization and interoperability. ```APIDOC ## `world.id(entity)` / `world.entity(id)` — Numeric entity IDs `world.id(entity)` lazily generates a stable numeric ID for an entity (only for entities currently in the world). `world.entity(id)` performs the reverse lookup. Useful when a numeric ID is required for serialization, networking, or interoperability with other systems. ### Parameters #### Path Parameters - **entity** (Entity) - Required - The entity to get the ID for. - **id** (number) - Required - The numeric ID to look up the entity for. ### Returns - **world.id(entity)**: (number | undefined) - The numeric ID of the entity, or undefined if the entity is not in the world. - **world.entity(id)**: (Entity | undefined) - The entity associated with the ID, or undefined if no entity has that ID. ### Example ```ts const world = new World() const player = world.add({ position: { x: 0, y: 0, z: 0 } }) const playerId = world.id(player)! // e.g. 0 console.log(world.entity(playerId) === player) // true ``` ``` -------------------------------- ### Query Entities by Component Value using `where` Source: https://github.com/hmans/miniplex/blob/main/README.md Use the `where` function to build queries that filter entities based on the values of their components. Note that these queries are not reactive. ```typescript const damagedEntities = world .with("health") .where(({ health }) => health.current < health.max) ``` ```typescript const deadEntities = world.with("health").where(({ health }) => health <= 0) ``` -------------------------------- ### Subscribe a Component to Bucket Changes with useEntities Hook Source: https://context7.com/hmans/miniplex/llms.txt The useEntities hook from miniplex-react subscribes the calling component to entity add/remove events on a given bucket or query, triggering re-renders on changes. It returns the bucket for convenient destructuring. ```tsx import { useEntities } from "miniplex-react" import { ECS, world } from "./ecs" const cameraTargets = world.with("position", "enemy") const HUD = () => { // Re-renders whenever cameraTargets changes const query = useEntities(cameraTargets) return (
    {query.entities.map((e) => (
  • Enemy @ ({e.position.x.toFixed(1)}, {e.position.y.toFixed(1)})
  • ))}
) } ``` -------------------------------- ### Define Entity Type with Miniplex Source: https://github.com/hmans/miniplex/blob/main/README.md Use TypeScript to define a type for your entities and provide it to the World constructor for type safety. ```typescript import { World } from "miniplex" type Entity = { position: { x: number; y: number; z: number } velocity?: { x: number; y: number; z: number } health?: number paused?: true } const world = new World() ``` -------------------------------- ### Query Entities Without Specific Components Source: https://github.com/hmans/miniplex/blob/main/packages/core/README.md Use `without` to retrieve entities that do not have certain components. Queries can be combined using chaining. ```typescript const active = world.without("paused") ``` ```typescript const movingEntities = world.with("position", "velocity").without("paused") ``` -------------------------------- ### world.update(entity, ...) Source: https://context7.com/hmans/miniplex/llms.txt Updates an entity's components and triggers reindexing. It supports multiple call signatures for flexibility in applying changes. ```APIDOC ## `world.update(entity, ...)` — Update a component and trigger reindexing A convenience method that applies a change to an entity and then reindexes it. Supports four call signatures: no second argument (reindex only), a partial object, a `(entity) => Partial | void` function, or a `(componentName, value)` pair. Use this whenever you change data that affects predicate-based (`where`) queries. ### Example Usage: ```ts const world = new World() const entity = world.add({ position: { x: 0, y: 0, z: 0 } }) // Partial object world.update(entity, { position: { x: 5, y: 0, z: 0 } }) // Component name + value world.update(entity, "position", { x: 10, y: 0, z: 0 }) // Updater function returning changes world.update(entity, (e) => ({ position: { x: e.position.x + 1, y: 0, z: 0 } })) // Updater function mutating directly, then reindex world.update(entity, (e) => { e.position.x = 99 }) // Reindex only (after a manual mutation) entity.position.x = 42 world.update(entity) console.log(entity.position.x) // 42 ``` ``` -------------------------------- ### Avoid Direct Query Entity Access for Iteration Source: https://github.com/hmans/miniplex/blob/main/packages/core/README.md Avoid iterating using `.entities` properties or `.forEach` as these methods do not guarantee safe removal during iteration and may be less performant. ```typescript /* ⛔️ Avoid: */ for (const entity of withHealth.entities) { if (entity.health <= 0) { world.remove(entity) } } ``` ```typescript /* ⛔️ Especially avoid: */ withHealth.entities.forEach((entity) => { if (entity.health <= 0) { world.remove(entity) } }) ``` -------------------------------- ### Avoid Direct Query Iteration using `.entities` Source: https://github.com/hmans/miniplex/blob/main/README.md Avoid iterating over `query.entities` directly, as it may not offer the same performance benefits or safety guarantees as the `for...of` loop. ```typescript /* ⛔️ Avoid: */ for (const entity of withHealth.entities) { if (entity.health <= 0) { world.remove(entity) } } ``` -------------------------------- ### Nested Queries in Miniplex Source: https://github.com/hmans/miniplex/blob/main/README.md Combine `with` and `without` methods to create more specific queries that filter entities based on the presence and absence of multiple components. ```typescript const movingEntities = world.with("position", "velocity").without("paused") ``` -------------------------------- ### Generate and Use Entity IDs Source: https://github.com/hmans/miniplex/blob/main/README.md Generate a unique numerical ID for an entity using `world.id(entity)` and retrieve the entity by its ID using `world.entity(id)`. This is useful when integrating with external systems. ```typescript const entity = world.add({ count: 10 }) const id = world.id(entity) ``` ```typescript const entity = world.entity(id) ``` -------------------------------- ### world.where(predicate) Source: https://context7.com/hmans/miniplex/llms.txt Filters entities using a predicate function. Requires `world.reindex(entity)` to be called after mutations to ensure query accuracy. ```APIDOC ## `world.where(predicate)` — Query entities matching a predicate function Returns a `Query` that filters entities through an arbitrary predicate. Because Miniplex cannot know when the predicate result changes, you must call `world.reindex(entity)` (or `world.update(entity)`) after mutations to keep the query current. ### Example Usage: ```ts const world = new World() const e1 = world.add({ position: { x: 0, y: 0, z: 0 }, health: { current: 100, max: 100 } }) const e2 = world.add({ position: { x: 1, y: 0, z: 0 }, health: { current: 20, max: 100 } }) const damaged = world .with("health") .where(({ health }) => health.current < health.max) console.log(damaged.entities.length) // 1 (e2) // After mutating, must reindex e1.health!.current = 50 world.reindex(e1) console.log(damaged.entities.length) // 2 (both entities now damaged) ``` ``` -------------------------------- ### world.onEntityAdded / world.onEntityRemoved Source: https://context7.com/hmans/miniplex/llms.txt Event objects that allow subscribing to entity lifecycle events (added or removed) within the world or a specific query. Useful for initialization and cleanup logic. ```APIDOC ## `world.onEntityAdded` / `world.onEntityRemoved` — Entity lifecycle events Both `World` and `Query` expose `onEntityAdded` and `onEntityRemoved` event objects (from `eventery`). Subscribe to run initialization or cleanup logic whenever entities enter or leave the world/query. ### Parameters - **subscribe** (function) - A callback function to be executed when the event is triggered. ### Example ```ts const world = new World() const withHealth = world.with("health") withHealth.onEntityAdded.subscribe((entity) => { entity.health!.current = entity.health!.max console.log("Entity initialized with full health:", entity.health) }) withHealth.onEntityRemoved.subscribe((entity) => { console.log("Entity lost its health component:", entity) }) ``` ``` -------------------------------- ### Query Entities Without Specific Components in Miniplex Source: https://github.com/hmans/miniplex/blob/main/README.md Use the `without` method on queries to retrieve entities that do not have certain components. This can be combined with `with` for more complex filtering. ```typescript const active = world.without("paused") ``` -------------------------------- ### Add Component to Entity with Miniplex Source: https://github.com/hmans/miniplex/blob/main/README.md Use addComponent to add a component to an existing entity in the Miniplex world. The entity object itself is passed as the first argument. ```typescript world.addComponent(entity, "velocity", { x: 10, y: 0, z: 0 }) ``` -------------------------------- ### Declaratively Attach a Component to an Entity with ECS.Component Source: https://context7.com/hmans/miniplex/llms.txt ECS.Component must be a descendant of ECS.Entity. It adds a component with data on mount, updates it on re-render, and removes it on unmount. It can also capture a React child's ref (e.g., Three.js mesh or DOM node) as component data. ```tsx import { ECS } from "./ecs" // Static data const Enemy = () => ( ) ``` ```tsx // Capture a Three.js mesh ref (react-three-fiber example) const PlayerMesh = () => ( {/* The mesh's ref is automatically stored as entity.mesh */} ) ```