{"_id":"@codetypess/ecs-ts","name":"@codetypess/ecs-ts","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@codetypess/ecs-ts","version":"0.1.0","description":"A small TypeScript ECS focused on explicit runtime behavior and practical ergonomics.","license":"MIT","type":"module","sideEffects":false,"types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"repository":{"type":"git","url":"git+https://github.com/codetypess/ecs-ts.git"},"bugs":{"url":"https://github.com/codetypess/ecs-ts/issues"},"homepage":"https://github.com/codetypess/ecs-ts#readme","publishConfig":{"access":"public"},"keywords":["ecs","typescript","game-dev","runtime","scheduler"],"scripts":{"check":"npm run typecheck && npm run lint","clean:dist":"node scripts/clean-dist.mjs","lint":"eslint .","format":"prettier --write .","format:check":"prettier --check .","typecheck":"tsc --noEmit","build":"npm run clean:dist && tsc -p tsconfig.build.json","package:smoke":"node scripts/check-package.mjs","pack:check":"node scripts/pack-check.mjs","release:check":"npm run check && npm test && npm run examples:check && npm run benchmark:smoke && npm run build && npm run package:smoke && npm run pack:check","test":"node --import tsx --test tests/*.test.ts","examples:check":"node --import tsx scripts/check-examples.ts","benchmark":"node --import tsx benchmarks/ecs-benchmark.ts","benchmark:smoke":"node --import tsx benchmarks/ecs-benchmark.ts --profile smoke","benchmark:compare":"node --import tsx benchmarks/compare-benchmark.ts","benchmark:json":"node --import tsx benchmarks/ecs-benchmark.ts --json","example:changes":"node --import tsx examples/change-detection.ts","example:lifecycle":"node --import tsx examples/lifecycle.ts","example:messages":"node --import tsx examples/messages.ts","example:net-entity-map":"node --import tsx examples/net-entity-map.ts","example:per-system-changes":"node --import tsx examples/per-system-change-detection.ts","example:observer":"node --import tsx examples/observer.ts","example:query-advanced":"node --import tsx examples/query-filter-advanced.ts","example:query-ergonomics":"node --import tsx examples/query-ergonomics.ts","example:query":"node --import tsx examples/query-filter.ts","example:query-state":"node --import tsx examples/query-state.ts","example:removed":"node --import tsx examples/removed-reader.ts","example:resources":"node --import tsx examples/resource-change-detection.ts","example:scheduler":"node --import tsx examples/scheduler.ts","example:scheduler-showcase":"node --import tsx examples/scheduler-showcase.ts","example:state":"node --import tsx examples/state.ts","example:ui":"node --import tsx examples/ui-lifecycle.ts","prepublishOnly":"npm run release:check"},"devDependencies":{"@types/node":"^25.6.0","eslint":"^10.2.0","prettier":"^3.8.2","tsx":"^4.21.0","typescript":"^6.0.2","typescript-eslint":"^8.58.1"},"gitHead":"2c5af408bbe486f6a3877a9947b38d21aa5f22c8","_id":"@codetypess/ecs-ts@0.1.0","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-VRYV9FYRW1OSMkButpQuelz7GlWHEDYBKDzLfzEyjZb8b9ckCY7N3+vYAeRSnNLAE3Y2uAlrIcCBJmuAqQTlUQ==","shasum":"88f17db7d4c96f20fb5395a1d88e583c8aa18f29","tarball":"https://registry.npmjs.org/@codetypess/ecs-ts/-/ecs-ts-0.1.0.tgz","fileCount":123,"unpackedSize":454998,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIE/QzIZHocc2iVoVleUWYlKYMFezNTVDBrqJp6BlLze+AiEArsd2qKLKPtMYdpbFZtxceRToQiTILLQhIWhfd5bnNPk="}]},"_npmUser":{"name":"codetypess","email":"codetypess@gmail.com"},"directories":{},"maintainers":[{"name":"codetypess","email":"codetypess@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ecs-ts_0.1.0_1776957150542_0.6678314537802297"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-23T15:12:30.416Z","0.1.0":"2026-04-23T15:12:30.683Z","modified":"2026-04-23T15:12:30.868Z"},"maintainers":[{"name":"codetypess","email":"codetypess@gmail.com"}],"description":"A small TypeScript ECS focused on explicit runtime behavior and practical ergonomics.","homepage":"https://github.com/codetypess/ecs-ts#readme","keywords":["ecs","typescript","game-dev","runtime","scheduler"],"repository":{"type":"git","url":"git+https://github.com/codetypess/ecs-ts.git"},"bugs":{"url":"https://github.com/codetypess/ecs-ts/issues"},"license":"MIT","readme":"# ecs-ts\n\n`ecs-ts` 是一个偏重运行时语义清晰、结构修改可预测、同时保留足够易用性的 TypeScript ECS。\n\n它想解决的问题不是“把所有能力都塞进一个巨大框架里”，而是给你一个足够扎实的 ECS runtime：组件存储和查询有合理性能，world 的结构修改时机明确，常见业务代码写起来也不会太别扭。\n\nEnglish README: [README-en.md](README-en.md).\n\n## 这个项目想做什么\n\n它不是引擎，不是编辑器，也不是一份堆满类型技巧的 API 展示。\n\n它更像一个有明确边界的 runtime core：\n\n- Schema 是显式的。Component、resource、state、message 和 event 都归属于一个 registry。\n- World 修改是显式的。`spawn`、`addComponent`、`removeComponent`、`despawn`、`Commands` 和 `world.batch(...)` 都有明确语义。\n- 运行时不变量是认真的。跨 registry 误用会立刻失败，component 依赖可以被强约束，非法 batch 结果不会对外可见。\n- 易用性也要保留。常见 query、change detection、scheduler 和 lifecycle 场景不该写得很累。\n\n## API 背后的设计\n\n这个项目更想先讲清楚“这些方法背后的模型是什么”，而不只是把方法名平铺出来。\n\n这里的核心取向有几条：\n\n- `Registry` 负责 schema。你先定义世界里有哪些类型，再创建绑定这个 schema 的 `World`。\n- `World` 是运行时边界。查询、调度、资源、状态、事件和结构修改都围绕它展开。\n- Component payload 就是普通对象。语义直观，也更方便序列化和调试。\n- 结构安全是可选但真实存在的。组件一旦声明 `deps`，运行时就把它当成硬约束。\n\n这最后一点尤其重要。  \n如果 `Element` 依赖 `Transform`，那么只要一个 entity 上的 `Element` 已经对外可见，`Transform` 就一定存在。也就是说，`deps` 不只是用来报错，它还建立了一个可以放心依赖的运行时不变量，因此你可以安全地写 `mustGetComponent(...)`。\n\n## 快速示例\n\n```ts\nimport { World, createRegistry, withComponent, withMarker } from \"@codetypess/ecs-ts\";\n\nconst registry = createRegistry(\"ui\");\n\nconst Transform = registry.defineComponent<{ x: number; y: number }>(\"Transform\");\nconst Element = registry.defineComponent<{ name: string }>(\"Element\", {\n    deps: [Transform],\n});\nconst Selected = registry.defineComponent(\"Selected\");\n\nconst world = new World(registry);\n\nconst entity = world.spawn(\n    withComponent(Element, { name: \"button\" }),\n    withComponent(Transform, { x: 40, y: 80 }),\n    withMarker(Selected)\n);\n\nworld.eachWhere([Transform], { with: [Element] }, (_entity, transform) => {\n    transform.x += 10;\n});\n\nif (world.hasComponent(entity, Element)) {\n    // 因为 Element 声明了对 Transform 的硬依赖，所以这里可以放心 mustGet。\n    const transform = world.mustGetComponent(entity, Transform);\n    console.log(transform.x, transform.y);\n}\n```\n\n## 核心能力\n\n- 基于 SparseSet 的 component 存储，dense iteration，swap-remove 删除。\n- `with`、`without`、`or`、`added`、`changed` 等 query 过滤。\n- Optional query，以及 `hasAll`、`hasAny`、`single`、`trySingle` 这些常用 helper。\n- `QueryState`，用于缓存重复 query 的解析结果。\n- Per-system 语义的 component/resource change detection。\n- Removed reader 和显式 `drainRemoved`。\n- 通过 `Commands` 做延迟结构修改。\n- Component lifecycle hooks：`onAdd`、`onInsert`、`onReplace`、`onRemove`、`onDespawn`。\n- 通过 `deps` 表达硬依赖。\n- 通过 `world.batch(...)` 做 deferred structural validation。\n- Scheduler：stage、label、system set、排序、fixed update、可组合 `runIf`。\n- State machine、message、observer-style immediate event。\n\n## 包导出边界\n\n- 对外支持的入口只有包根：`import { ... } from \"@codetypess/ecs-ts\"`。\n- `dist/internal/*` 会作为运行时实现细节一起打包，但它们不是公开 API，也不承诺 semver 稳定。\n- 如果你要写应用代码、示例代码或第三方封装，应该只依赖根导出。\n\n## 结构修改语义\n\n- `Commands` 是 deferred queue。命令会在 `flush()` 或 system/observer 结束后统一执行。\n- `world.batch(...)` 会先验证最终结构状态，再一次性提交净变化；它更接近一次 transactional commit。\n- `commands.spawn(...)` 在 flush 前只返回一个保留的 entity handle，不会立刻变成 live entity。\n- `world.shutdown()` 是终态。shutdown 后再次 `update()` 不会继续跑 startup 或 update。\n\n## 推荐的阅读顺序\n\n如果你是第一次看这个项目，建议把它当成“几个工作流”来理解，而不是一口气扫完整个 API 表面：\n\n- [Queries](docs/zh/queries.md)：query、filter、optional component 和 `QueryState`。\n- [Scheduler](docs/zh/scheduler.md)：system 什么时候跑、怎么排序、怎么组合条件。\n- [Change Detection](docs/zh/change-detection.md)：`added`、`changed`、removed readers 和 message 的行为。\n\n如果你更想先看代码而不是说明，examples 是更好的入口：\n\n```sh\nnpm run examples:check\nnpm run example:lifecycle\nnpm run example:scheduler\nnpm run example:scheduler-showcase\nnpm run example:query\nnpm run example:query-advanced\nnpm run example:query-ergonomics\nnpm run example:query-state\nnpm run example:changes\nnpm run example:per-system-changes\nnpm run example:messages\nnpm run example:removed\nnpm run example:resources\nnpm run example:state\nnpm run example:observer\nnpm run example:net-entity-map\nnpm run example:ui\n```\n\n## 开发与验证\n\n```sh\nnpm test\nnpm run examples:check\nnpm run benchmark:smoke\nnpm run benchmark\nnpm run benchmark:json\nnpm run benchmark:compare -- --baseline /tmp/ecs-baseline.json --current /tmp/ecs-current.json\nnpm run build\nnpm run package:smoke\nnpm run release:check\n```\n\n测试通过 `tsx` 使用 Node 内置的 `node:test` runner。benchmark 同时提供更快的 smoke profile 和适合同机对比的完整 profile。\n\n如果你正在准备对外发布，可以参考 [发布说明](docs/zh/releasing.md)。\n\n## 当前状态\n\n这个项目已经有一套比较明确的设计方向，但仍然是一个持续打磨中的小型 ECS runtime。API 基本方向已经比较清楚，不过在文档、ergonomics 和部分内部性能权衡上，仍然会继续调整。\n","readmeFilename":"README.md","_rev":"1-507098dd7501cd77240cfab8a2e1f244"}