Token导航 LogoToken导航TokenDH.com
开发需要联网github未标认证来源可访问许可证需确认审计异常

bitecsbitecs 命令行

Agent Skill

bitecs 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

352

周安装

12

GitHub Stars

公开资料未说明

下载量

97
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:bitecs(bitecs 命令行)
来源仓库:https://github.com/kadajett/bitecs-agent-skill
仓库路径:skills/bitecs
安装命令:
npx skills add https://github.com/kadajett/bitecs-agent-skill --skill bitecs
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/kadajett/bitecs-agent-skill --skill bitecs

简介

bitecs 是 TypeScript 实现的轻量级 ECS 架构库,支持实体组件管理与查询系统。

  • 提供数据导向设计、实体层级构建与模板序列化等核心能力。
  • 适用于游戏开发、仿真系统及需要高性能实体管理的应用场景。
  • 需熟悉 SoA/AoS 内存布局与观察者模式实现原理方可有效使用。
  • bitecs 属于开发类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

bitECS v0.4.0 Agent Skill

This skill provides comprehensive guidance for using bitECS, a flexible, minimal, data-oriented Entity Component System (ECS) library for TypeScript.

When to Use This Skill

Use this skill when:

  • Building games or simulations using ECS architecture
  • Creating and managing entities with components
  • Defining component data structures (SoA or AoS)
  • Querying entities based on component composition
  • Building entity hierarchies with relationships
  • Implementing prefabs and entity templates
  • Serializing/deserializing ECS data for networking or save systems
  • Implementing observer patterns for reactive component changes
  • Working with multithreaded ECS systems

Installation

npm i bitecs

Module Structure

bitECS 0.4.0 provides three modules:

ModuleImportPurpose
CorebitecsMain ECS toolkit
Serializationbitecs/serializationBinary serialization utilities
Legacybitecs/legacyBackward compatibility with 0.3.x API

Core Concepts

World

A world is a container for ECS data. Entities are created in a world and data is queried based on the existence and shape of entities in a world. Each world is independent of all others.

import { createWorld, resetWorld, deleteWorld, getAllEntities, getWorldComponents } from 'bitecs'

// Basic world creation
const world = createWorld()

// World with custom context
const world = createWorld({
    time: { delta: 0, elapsed: 0, then: 0 },
    components: {
        Position: { x: [] as number[], y: [] as number[] }
    }
})

// Shared entity index between worlds
const entityIndex = createEntityIndex()
const worldA = createWorld(entityIndex)
const worldB = createWorld(entityIndex)

// Combined: custom context + shared entity index (any order)
createWorld({ data: 1 }, entityIndex)
createWorld(entityIndex, { data: 1 })

// World utilities
resetWorld(world)                    // Reset world state
deleteWorld(world)                   // Delete world and free resources
getAllEntities(world)                // Get all entities in world
getWorldComponents(world)            // Get all registered components

Entity

Entities are unique numerical identifiers (entity IDs or eids). They are unique across all worlds unless worlds share an entity index.

import {
    addEntity,
    removeEntity,
    entityExists,
    getEntityComponents,
    createEntityIndex,
    addEntityId,
    removeEntityId,
    isEntityIdAlive
} from 'bitecs'

// Basic entity operations
const eid = addEntity(world)
removeEntity(world, eid)

// Entity utilities
entityExists(world, eid)              // Check if entity exists
getEntityComponents(world, eid)       // Get all components for entity

// Direct entity index operations
const index = createEntityIndex()
const id = addEntityId(index)
removeEntityId(index, id)
isEntityIdAlive(index, id)

Entity ID Recycling

Entity IDs are recycled immediately after removal:

const eid1 = addEntity(world)
const eid2 = addEntity(world)
removeEntity(world, eid1)
const eid3 = addEntity(world)
// eid1 === eid3 (recycled)

Manual Entity ID Recycling (Recommended)

For more control over entity lifecycle, implement manual recycling:

const Removed = {}

const markEntityForRemoval = (world, eid) => {
    addComponent(world, eid, Removed)
}

const removeMarkedEntities = (world) => {
    for (const eid of query(world, [Removed])) {
        removeEntity(world, eid)
    }
}

Entity ID Versioning

Prevents collision issues with recycled IDs by adding version numbers:

import { createEntityIndex, withVersioning, getId, getVersion, incrementVersion } from 'bitecs'

// Version bits options:
// 8 bits: 16M entities / 256 recycles
// 10 bits: 4M entities / 1K recycles
// 12 bits: 1M entities / 4K recycles (default)
// 14 bits: 262K entities / 16K recycles
// 16 bits: 65K entities / 65K recycles

const entityIndex = createEntityIndex(withVersioning(8))
const world = createWorld(entityIndex)

const eid1 = addEntity(world)
removeEntity(world, eid1)
const eid2 = addEntity(world)
// eid1 !== eid2 (different versions)

// Version utilities
getId(entityIndex, eid)              // Extract entity ID without version
getVersion(entityIndex, eid)         // Extract version from entity ID
incrementVersion(entityIndex, eid)   // Increment version of entity ID

Warning: When using versioning with TypedArrays, ensure arrays are large enough as versioned IDs can be much larger than the base entity ID.

Component

Components are modular data containers representing specific attributes of an entity. Any valid JavaScript reference can serve as a component.

Component Formats

// SoA with regular arrays (recommended for minimal memory footprint)
const Position = {
    x: [] as number[],
    y: [] as number[],
}

// SoA with TypedArrays (recommended for threading and eliminating memory thrash)
const Position = {
    x: new Float64Array(10000),
    y: new Float64Array(10000),
}

// AoS (performant for small shapes with < 100k objects)
const Position = [] as { x: number; y: number }[]

// Array of TypedArrays
const Position = Array.from({ length: 10000 }, () => new Float32Array(3))

// Tag component (no data)
const Flying = {}

Component Operations

import {
    addComponent,
    addComponents,
    removeComponent,
    removeComponents,
    hasComponent,
    getComponent,
    setComponent,
    set,
    registerComponent,
    registerComponents
} from 'bitecs'

// Add single component
addComponent(world, eid, Position)

// Add with initial data (requires onSet observer)
addComponent(world, eid, set(Position, { x: 10, y: 20 }))

// Add multiple components
addComponents(world, eid, Position, Velocity, Mass)
addComponents(world, eid, [Position, Velocity, Mass])
addComponents(world, eid,
    set(Position, { x: 10, y: 20 }),
    set(Velocity, { x: 1, y: 1 }),
    Health
)

// Remove components
removeComponent(world, eid, Position)
removeComponent(world, eid, Position, Velocity)
removeComponents(world, eid, Position, Velocity)

// Check component presence
hasComponent(world, eid, Position)

// Get component data (triggers onGet observers)
const data = getComponent(world, eid, Position)

// Set component data (triggers onSet observers)
setComponent(world, eid, Position, { x: 10, y: 20 })

// Register components explicitly (automatic on first addComponent)
registerComponent(world, Position)
registerComponents(world, [Position, Velocity, Mass])

Component Data Access

addComponent(world, eid, Position)

// SoA access
Position.x[eid] = 0
Position.y[eid] = 0
Position.x[eid] += 1

// AoS access
Position[eid] = { x: 0, y: 0 }
Position[eid].x += 1

// Array of TypedArrays
const pos = Position[eid]
pos[0] += 1

Storing Components on World

// Components stored on world for clean access
const world = createWorld({
    components: {
        Position: Array(1e5).fill(3).map(n => new Float32Array(n))
    }
})

const { Position } = world.components

Query

Queries retrieve entities based on their components, relationships, or hierarchies.

import { query, And, Or, Not, All, Any, None, Hierarchy, Cascade, asBuffer, isNested, noCommit } from 'bitecs'

// Basic query
const entities = query(world, [Position, Mass])

// Query operators
query(world, [Position, Velocity])                    // AND (default)
query(world, [And(Position, Velocity)])               // Explicit AND
query(world, [All(Position, Velocity)])               // Alias for AND
query(world, [Or(Position, Velocity)])                // OR
query(world, [Any(Position, Velocity)])               // Alias for OR
query(world, [Position, Not(Velocity)])               // NOT
query(world, [Position, None(Velocity)])              // Alias for NOT

// Complex combinations
query(world, [
    Position,                    // Must have Position
    Or(Health, Shield),          // Must have Health OR Shield
    Not(Stunned, Paralyzed)      // Must NOT have Stunned AND must NOT have Paralyzed
])

Query Options and Modifiers

// Options object approach
query(world, [Position], { commit: false })                   // Skip pending removals
query(world, [Position], { buffered: true })                  // Returns Uint32Array
query(world, [Position], { commit: false, buffered: true })   // Combined

// Query modifier approach
query(world, [Position], isNested)                            // Safe nested iteration
query(world, [Position], noCommit)                            // Alias for isNested
query(world, [Position], asBuffer)                            // Returns Uint32Array
query(world, [Position], asBuffer, isNested)                  // Combined modifiers

Nested Queries for Safe Iteration

When iterating over query results, calling another query will flush pending removals. Use isNested or noCommit for safe nested iteration:

for (const entity of query(world, [Position, Velocity])) {
    // Use nested to prevent removals during iteration
    for (const inner of query(world, [Mass], isNested)) {
        // Safe nested iteration
    }
}

Hierarchical Queries

Query entities in topological order (parents before children):

import { Hierarchy, Cascade, getHierarchyDepth, getMaxHierarchyDepth } from 'bitecs'

const ChildOf = createRelation()

// All entities with Position in hierarchy order
for (const eid of query(world, [Position, Hierarchy(ChildOf)])) {
    // Parents processed before children
}

// Entities at specific depth level
for (const eid of query(world, [Position, Hierarchy(ChildOf, 2)])) {
    // Only entities at depth 2
}

// Cascade is an alias for Hierarchy
query(world, [Position, Cascade(ChildOf)])

// Hierarchy utilities
getHierarchyDepth(world, eid, ChildOf)    // Get depth of entity
getMaxHierarchyDepth(world, ChildOf)      // Get max depth in hierarchy

Relationships

Relationships define how entities relate to each other.

import {
    createRelation,
    withStore,
    makeExclusive,
    withAutoRemoveSubject,
    withOnTargetRemoved,
    withValidation,
    getRelationTargets,
    Wildcard,
    Pair
} from 'bitecs'

// Basic relation
const ChildOf = createRelation()

// Relation with data store
const Contains = createRelation(
    withStore(() => ({ amount: [] as number[] }))
)
// Or with options object:
const Contains = createRelation({
    store: () => ({ amount: [] as number[] })
})

// Auto-remove subject when target is removed
const ChildOf = createRelation(withAutoRemoveSubject)
// Or: createRelation({ autoRemoveSubject: true })

// Exclusive relation (subject can only relate to one target)
const Targeting = createRelation(makeExclusive)
// Or: createRelation({ exclusive: true })

// Custom callback when target removed
const Following = createRelation(
    withOnTargetRemoved((subject, target) => {
        console.log(`${subject} lost target ${target}`)
    })
)

// Validation
const ValidatedRelation = createRelation(
    withValidation((target) => target > 0)
)

Using Relationships

const inventory = addEntity(world)
const gold = addEntity(world)
const silver = addEntity(world)

// Add relationships
addComponent(world, inventory, Contains(gold))
Contains(gold).amount[inventory] = 5

addComponent(world, inventory, Contains(silver))
Contains(silver).amount[inventory] = 12

// Query relationships
const children = query(world, [ChildOf(parent)])

// Get relation targets
const targets = getRelationTargets(world, inventory, Contains)  // [gold, silver]

Relationship Wildcards

// Find all entities with any Contains relationship
query(world, [Contains('*')])
query(world, [Contains(Wildcard)])

// Inverted wildcard: find all entities related TO a specific target
const earth = addEntity(world)
addComponent(world, earth, OrbitedBy(moon))
addComponent(world, earth, IlluminatedBy(sun))
query(world, [Wildcard(earth)])  // Entities related to earth

// Find all parents (entities that have children)
query(world, [Wildcard(ChildOf)])

// Find all children (entities that have parents)
query(world, [ChildOf(Wildcard)])

Prefabs

Prefabs are reusable entity templates.

import { addPrefab, IsA } from 'bitecs'

// Create prefab
const Animal = addPrefab(world)
addComponent(world, Animal, Vitals)
Vitals.health[Animal] = 100

// Inheritance with IsA relation
const Sheep = addPrefab(world)
addComponent(world, Sheep, IsA(Animal))  // Inherits Vitals
addComponent(world, Sheep, Contains(Wool))

// Instantiate from prefab
const sheep = addEntity(world)
addComponent(world, sheep, IsA(Sheep))
hasComponent(world, sheep, Contains(Wool))  // true

// Query instances
query(world, [IsA(Animal)])  // Returns all animals

Note: Prefabs do not appear in queries themselves. For inheritance to work with component values, you must define onSet and onGet observers:

observe(world, onSet(Vitals), (eid, params) => {
    Vitals.health[eid] = params.health
})
observe(world, onGet(Vitals), (eid) => ({
    health: Vitals.health[eid]
}))

Observers

Observers react to component changes.

import { observe, onAdd, onRemove, onSet, onGet } from 'bitecs'

// Observe component additions
const unsubscribe = observe(world, onAdd(Position), (eid) => {
    console.log(`Entity ${eid} gained Position`)
})

// Observe component removals
observe(world, onRemove(Health), (eid) => {
    console.log(`Entity ${eid} lost Health`)
})

// Complex observation patterns
observe(world, onAdd(Position, Not(Velocity)), (eid) => {
    console.log(`Entity ${eid} has Position but no Velocity`)
})

// onSet: Called when setComponent or set() helper is used
observe(world, onSet(Position), (eid, params) => {
    Position.x[eid] = params.x
    Position.y[eid] = params.y
    console.log(`Position set for ${eid}:`, params)
})

// onGet: Called when getComponent is used
observe(world, onGet(Position), (eid) => ({
    x: Position.x[eid],
    y: Position.y[eid]
}))

// Computed values
observe(world, onSet(Health), (eid, params) => {
    return { value: Math.max(0, Math.min(100, params.value)) }
})

// Network synchronization
observe(world, onSet(Inventory), (eid, params) => {
    syncWithServer(eid, 'inventory', params)
    return params
})

// Unsubscribe when done
unsubscribe()

Systems

Systems define entity behavior. bitECS doesn't enforce a specific implementation, but recommends simple chainable functions:

const moveBody = (world) => {
    for (const entity of query(world, [Position, Velocity])) {
        Position.x[entity] += Velocity.x[entity] * world.time.delta
        Position.y[entity] += Velocity.y[entity] * world.time.delta
    }
}

const applyGravity = (world) => {
    const gravity = 9.81
    for (const entity of query(world, [Position, Mass])) {
        Position.y[entity] -= gravity * Mass.value[entity] * world.time.delta
    }
}

const timeSystem = (world) => {
    const now = performance.now()
    world.time.delta = (now - world.time.then) / 1000
    world.time.elapsed += world.time.delta
    world.time.then = now
}

// Game loop
const update = (world) => {
    timeSystem(world)
    moveBody(world)
    applyGravity(world)
}

// Browser
requestAnimationFrame(function animate() {
    update(world)
    requestAnimationFrame(animate)
})

// Node
setInterval(() => update(world), 1000/60)

Serialization Module

Import from bitecs/serialization.

Data Type Tags

For regular arrays, use type tags to specify serialization format:

TagDescription
u8(), i8()8-bit unsigned/signed integers
u16(), i16()16-bit unsigned/signed integers
u32(), i32()32-bit unsigned/signed integers
f32()32-bit floats
f64()64-bit floats (default)
str()UTF-8 strings
array(type)Arrays of specified type

TypedArrays (Uint8Array, Float32Array, etc.) don't need tags.

SoA Serialization

For Structure of Arrays component data:

import { createSoASerializer, createSoADeserializer, f32, u8, str, array } from 'bitecs/serialization'

const Position = { x: f32([]), y: f32([]) }
const Velocity = { vx: f32([]), vy: f32([]) }
const Health = new Uint8Array(1e5)
const Meta = { name: str([]), tags: array(str) }

const components = [Position, Velocity, Health, Meta]

const serialize = createSoASerializer(components)
const deserialize = createSoADeserializer(components)

// Set data
Position.x[eid] = 10.5
Position.y[eid] = 20.2
Health[eid] = 100
Meta.name[eid] = 'Player'
Meta.tags[eid] = ['hero', 'active']

// Serialize entities
const buffer = serialize([eid])

// Deserialize
deserialize(buffer)

// ID mapping for network/save systems
const idMap = new Map([[1, 10]])  // Map entity 1 to 10
deserialize(buffer, idMap)

Serializer Options

const serialize = createSoASerializer(components, {
    diff: true,                          // Only serialize changed values
    buffer: new ArrayBuffer(1 << 20),    // 1MB backing buffer (default: 100MB)
    epsilon: 1e-3                         // Float comparison threshold (default: 0.0001)
})

const deserialize = createSoADeserializer(components, { diff: true })

Nested Arrays

const Inventory = {
    pages: array(array(u8))  // Array of arrays of u8
}

Inventory.pages[eid] = [
    [1, 2, 3],      // Page 1
    [10, 20],       // Page 2
    [100, 101, 102] // Page 3
]

AoS Serialization

For Array of Structures component data:

import { createAoSSerializer, createAoSDeserializer, f32, u8, str, array } from 'bitecs/serialization'

const Position = Object.assign([], { x: f32(), y: f32() })
const Health = u8()
const Meta = Object.assign([], { name: str(), tags: array(str) })

const serialize = createAoSSerializer(components, { diff: true })
const deserialize = createAoSDeserializer(components, { diff: true })

const buffer = serialize([0, 1])

// ID mapping
const idMap = new Map([[0, 10], [1, 11]])
deserialize(buffer, idMap)

Observer Serialization

Tracks entity/component additions and removals:

import { createObserverSerializer, createObserverDeserializer } from 'bitecs/serialization'

const Networked = {}  // Tag component for network entities

const serializer = createObserverSerializer(world, Networked, [Position, Health], {
    buffer: new ArrayBuffer(1 << 20)  // Optional backing buffer
})

const deserializer = createObserverDeserializer(world, Networked, [Position, Health], {
    idMap: new Map()  // Optional initial ID mapping
})

// Add components
addComponent(world, eid, Networked)
addComponent(world, eid, Position)
addComponent(world, eid, Health)

// Serialize changes
const buffer = serializer()

// Deserialize on receiver
deserializer(buffer)
// Or with override ID map
deserializer(buffer, new Map([[1, 100]]))

Snapshot Serialization

Captures complete world state:

import { createSnapshotSerializer, createSnapshotDeserializer, f32, u8 } from 'bitecs/serialization'

const Position = { x: f32([]), y: f32([]) }
const Health = u8([])

const serialize = createSnapshotSerializer(world, [Position, Health])
const deserialize = createSnapshotDeserializer(world, [Position, Health])

// Capture full state
const buffer = serialize()

// Restore state
deserialize(buffer)
// Or with ID mapping
deserialize(buffer, new Map([[1, 10]]))

Multithreading

bitECS is designed to work efficiently with worker threads.

SharedArrayBuffer Components

const MAX_ENTS = 1e6
const world = createWorld({
    components: {
        Position: {
            x: new Float32Array(new SharedArrayBuffer(MAX_ENTS * Float32Array.BYTES_PER_ELEMENT)),
            y: new Float32Array(new SharedArrayBuffer(MAX_ENTS * Float32Array.BYTES_PER_ELEMENT))
        }
    }
})

Query with asBuffer

Returns SAB-backed Uint32Array for thread sharing:

const entities = query(world, [Position, Mass], asBuffer)

Worker Communication Pattern

// Main thread
const worker = new Worker('./worker.js')

worker.postMessage({
    entities: query(world, [world.components.Position], asBuffer),
    components: world.components
})

worker.on('message', ({ removeQueue }) => {
    for (let i = 0; i < removeQueue.length; i++) {
        removeEntity(world, removeQueue[i])
    }
})

// Worker thread (worker.js)
const MAX_CMDS = 1e6
const removeQueue = new Uint32Array(new SharedArrayBuffer(MAX_CMDS * Uint32Array.BYTES_PER_ELEMENT))

self.onmessage = ({ data }) => {
    const { entities, components: { Position } } = data
    let removeCount = 0

    for (let i = 0; i < entities.length; i++) {
        const eid = entities[i]
        Position.x[eid] += 1
        Position.y[eid] += 1
        removeQueue[removeCount++] = eid
    }

    self.postMessage({ removeQueue: removeQueue.subarray(0, removeCount) })
}

Parallel Processing Pattern

const WORKER_COUNT = 4
const workers = Array(WORKER_COUNT).fill(null).map(() => new Worker('worker.js'))

let completedWorkers = 0
workers.forEach(worker => worker.on('message', () => {
    completedWorkers++
    if (completedWorkers === WORKER_COUNT) {
        processQueues()
        completedWorkers = 0
    }
}))

function processEntitiesParallel(world) {
    const entities = query(world, [Position], asBuffer)
    const partitionSize = Math.ceil(entities.length / WORKER_COUNT)

    for (let i = 0; i < WORKER_COUNT; i++) {
        const start = i * partitionSize
        const end = Math.min(start + partitionSize, entities.length)
        workers[i].postMessage({
            entities: entities.subarray(start, end),
            components: world.components
        })
    }
}

Important: ECS API functions (addEntity, removeEntity, addComponent, etc.) cannot be used directly in workers. Use message queues to send commands back to the main thread.


Complete API Reference

World Functions

FunctionSignatureDescription
createWorld(context?, entityIndex?) => WorldCreate a new world
resetWorld(world) => WorldReset world state
deleteWorld(world) => voidDelete world and free resources
getAllEntities(world) => number[]Get all entities in world
getWorldComponents(world) => ComponentRef[]Get all registered components

Entity Functions

FunctionSignatureDescription
addEntity(world) => numberAdd new entity
removeEntity(world, eid) => voidRemove entity
entityExists(world, eid) => booleanCheck if entity exists
getEntityComponents(world, eid) => ComponentRef[]Get entity's components

Entity Index Functions

FunctionSignatureDescription
createEntityIndex(options?) => EntityIndexCreate entity index
withVersioning(versionBits?) => optionsConfigure versioning
addEntityId(index) => numberAdd ID to index
removeEntityId(index, id) => voidRemove ID from index
isEntityIdAlive(index, id) => booleanCheck if ID is alive
getId(index, id) => numberExtract entity ID
getVersion(index, id) => numberExtract version
incrementVersion(index, id) => numberIncrement version

Component Functions

FunctionSignatureDescription
addComponent(world, eid, component) => booleanAdd component to entity
addComponents(world, eid,...components) => voidAdd multiple components
removeComponent(world, eid,...components) => voidRemove components
removeComponents(world, eid,...components) => voidAlias for removeComponent
hasComponent(world, eid, component) => booleanCheck component presence
getComponent(world, eid, component) => anyGet component data
setComponent(world, eid, component, data) => voidSet component data
set(component, data) => ComponentSetterCreate component setter
registerComponent(world, component) => ComponentDataRegister component
registerComponents(world, components) => voidRegister multiple

Query Functions

FunctionSignatureDescription
query(world, terms,...modifiers) => QueryResultQuery entities
And / All(...components) => OpReturnTypeAND operator
Or / Any(...components) => OpReturnTypeOR operator
Not / None(...components) => OpReturnTypeNOT operator
Hierarchy / Cascade(relation, depth?) => HierarchyTermHierarchy ordering
asBufferQueryModifierReturn Uint32Array
isNested / noCommitQueryModifierSafe nested iteration
commitRemovals(world) => voidCommit pending removals
registerQuery(world, terms, options?) => QueryRegister query
removeQuery(world, terms) => voidRemove query

Hierarchy Functions

FunctionSignatureDescription
getHierarchyDepth(world, eid, relation) => numberGet entity depth
getMaxHierarchyDepth(world, relation) => numberGet max depth
ensureDepthTracking(world, relation) => voidInitialize tracking

Relation Functions

FunctionSignatureDescription
createRelation(...modifiers) => RelationCreate relation
withStore(createStore) => modifierAdd data store
makeExclusive(relation) => RelationMake exclusive
withAutoRemoveSubject(relation) => RelationAuto-remove subject
withOnTargetRemoved(callback) => modifierTarget removed callback
withValidation(validateFn) => modifierAdd validation
getRelationTargets(world, eid, relation) => number[]Get targets
Pair(relation, target) => componentCreate pair
WildcardRelationWildcard relation
IsARelationInheritance relation
isRelation(component) => booleanCheck if relation
isWildcard(relation) => booleanCheck if wildcard

Prefab Functions

FunctionSignatureDescription
addPrefab(world) => EntityIdCreate prefab entity

Observer Functions

FunctionSignatureDescription
observe(world, hook, callback) => unsubscribeSubscribe to changes
onAdd(...terms) => ObservableHookAddition hook
onRemove(...terms) => ObservableHookRemoval hook
onSet(component) => ObservableHookSet hook
onGet(component) => ObservableHookGet hook

Serialization Functions (bitecs/serialization)

FunctionSignatureDescription
createSoASerializer(components, options?) => (entities) => ArrayBufferSoA serializer
createSoADeserializer(components, options?) => (buffer, idMap?) => voidSoA deserializer
createAoSSerializer(components, options?) => (entities) => ArrayBufferAoS serializer
createAoSDeserializer(components, options?) => (buffer, idMap?) => voidAoS deserializer
createObserverSerializer(world, tag, components, options?) => () => ArrayBufferObserver serializer
createObserverDeserializer(world, tag, components, options?) => (buffer, idMap?) => voidObserver deserializer
createSnapshotSerializer(world, components, buffer?) => () => ArrayBufferSnapshot serializer
createSnapshotDeserializer(world, components) => (buffer, idMap?) => voidSnapshot deserializer
f32, f64, u8, u16, u32, i8, i16, i32(array?) => TypedArrayType tags
str(array?) => string[]String type tag
array(type) => arrayArray type tag

Best Practices

Component Design

  1. Prefer SoA format for optimal cache performance and memory efficiency
  2. Use TypedArrays for threading compatibility and predictable memory
  3. Keep components small and focused on a single concern
  4. Use tag components (empty objects) for boolean flags
  5. Pre-allocate TypedArrays based on expected entity count
// Good: Focused components
const Position = { x: new Float32Array(MAX_ENTS), y: new Float32Array(MAX_ENTS) }
const Velocity = { x: new Float32Array(MAX_ENTS), y: new Float32Array(MAX_ENTS) }
const Flying = {}  // Tag

// Avoid: Monolithic components
const Entity = { x: [], y: [], vx: [], vy: [], health: [], name: [] }

Query Optimization

  1. Query once per system, iterate results
  2. Use isNested for nested queries to prevent removal issues
  3. Use asBuffer for threading or when you need Uint32Array
  4. Avoid querying in tight loops
// Good: Query once
const moveSystem = (world) => {
    const entities = query(world, [Position, Velocity])
    for (const eid of entities) {
        Position.x[eid] += Velocity.x[eid]
    }
}

// Avoid: Query in loop
for (let i = 0; i < 1000; i++) {
    const entities = query(world, [Position])  // Inefficient
}

Entity Lifecycle

  1. Use manual recycling for controlled removal timing
  2. Consider versioning if entity ID reuse causes issues
  3. Batch entity removals for better performance
const Removed = {}
const removeSystem = (world) => {
    for (const eid of query(world, [Removed])) {
        removeEntity(world, eid)
    }
}

Observer Usage

  1. Use observers for cross-cutting concerns (logging, sync, validation)
  2. Keep observer callbacks lightweight
  3. Unsubscribe when no longer needed
  4. Define onSet/onGet for prefab inheritance

Serialization

  1. Use Observer + SoA serializers together for complete network sync
  2. Pre-allocate serialization buffers to avoid GC pressure
  3. Use diff mode for bandwidth-sensitive applications
  4. Map entity IDs when deserializing to different worlds

Threading

  1. Use SharedArrayBuffer for cross-thread component stores
  2. Use asBuffer queries for thread-safe entity lists
  3. Implement command queues for main thread operations
  4. Partition work across workers for parallel processing

Migration from 0.3.x

Key Changes

0.3.x0.4.0
defineComponent({x: Types.f32}){x: [] as number[]} or {x: new Float32Array(n)}
addComponent(world, Component, eid)addComponent(world, eid, Component)
defineQuery([A, B]) then query(world)query(world, [A, B])
enterQuery(query)observe(world, onAdd(...), cb)
exitQuery(query)observe(world, onRemove(...), cb)
Changed(Component)observe(world, onSet(Component), cb)
Types.eid for referencescreateRelation()

Legacy Module

For gradual migration, use bitecs/legacy:

import {
    defineComponent,
    defineQuery,
    enterQuery,
    exitQuery,
    Types,
    addComponent  // Uses old parameter order
} from 'bitecs/legacy'

Common Patterns

Enter/Exit Queues

const world = createWorld({
    enteredMovers: [] as number[],
    exitedMovers: [] as number[]
})

observe(world, onAdd(Position, Velocity), (eid) => world.enteredMovers.push(eid))
observe(world, onRemove(Position, Velocity), (eid) => world.exitedMovers.push(eid))

const movementSystem = (world) => {
    // Process entered
    for (const eid of world.enteredMovers.splice(0)) {
        console.log(`${eid} started moving`)
    }

    // Process exited
    for (const eid of world.exitedMovers.splice(0)) {
        console.log(`${eid} stopped moving`)
    }
}

Parent-Child Hierarchies

const ChildOf = createRelation(withAutoRemoveSubject)

// Create hierarchy
const parent = addEntity(world)
const child = addEntity(world)
addComponent(world, child, ChildOf(parent))

// Process in order
for (const eid of query(world, [Transform, Hierarchy(ChildOf)])) {
    // Parents processed before children
    updateWorldTransform(eid)
}

Inventory System

const Contains = createRelation(withStore(() => ({ amount: [] as number[] })))

const chest = addEntity(world)
const gold = addEntity(world)

addComponent(world, chest, Contains(gold))
Contains(gold).amount[chest] = 100

// Get all items in chest
const items = getRelationTargets(world, chest, Contains)

Network Replication

import { createObserverSerializer, createObserverDeserializer, createSoASerializer, createSoADeserializer } from 'bitecs/serialization'

const Networked = {}
const components = [Position, Velocity, Health]

// Server
const observerSerializer = createObserverSerializer(world, Networked, components)
const dataSerializer = createSoASerializer(components)

const sendUpdate = () => {
    const entities = query(world, [Networked])
    const observerPacket = observerSerializer()
    const dataPacket = dataSerializer(entities)
    broadcast({ observer: observerPacket, data: dataPacket })
}

// Client
const observerDeserializer = createObserverDeserializer(world, Networked, components)
const dataDeserializer = createSoADeserializer(components)

const receiveUpdate = ({ observer, data }) => {
    observerDeserializer(observer)
    dataDeserializer(data)
}

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.64%
按下载量换算33

Claude

27.87%
按下载量换算27

Cursor

20.75%
按下载量换算20

Gemini CLI

9.28%
按下载量换算9

安全审计

Gen Agent Trust Hub

通过

Socket

未通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills