Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
127 commits
Select commit Hold shift + click to select a range
4d8c049
ecs: order on System.render, one paint-ordered table across archetypes
krisnye Oct 22, 2026
84e31c9
ecs: compiled code imports the runtime from the importer's copy of th…
krisnye Oct 22, 2026
ef0b2e7
ecs: build `up` trees and orders in bulk after a load
krisnye Oct 22, 2026
46fc3ff
ecs: skip a sorted index rebuild's sort when entries are in key order
krisnye Oct 22, 2026
955a313
ecs: bind an ordered run's row in place when the archetype changes
krisnye Oct 22, 2026
8373dfb
ecs: followups: descending sorted indexes
krisnye Oct 22, 2026
38b10b2
ecs: version 0.1.1
krisnye Oct 23, 2026
cbb21ab
ecs: one open PR at a time
krisnye Oct 23, 2026
b5e2ea4
ecs: README for the transfers sample
krisnye Oct 23, 2026
57af1b1
ecs: dev serves the samples, with a sample browser, and opens no browser
krisnye Oct 23, 2026
0b2b8d8
ecs: a system's input is the type of its body's parameter after its c…
krisnye Oct 23, 2026
aff46bb
ecs: input types read the values of as const objects, and take any gl…
krisnye Oct 23, 2026
07d3db4
ecs: the loop churn benchmarks compare memory once the world keeps it…
krisnye Oct 23, 2026
998738a
ecs: one buffer spawns every report, and benchmarks after a run warm …
krisnye Oct 23, 2026
6554406
ecs: benchmarks moving one entity between two large buckets of a hash…
krisnye Oct 23, 2026
89bdcf5
ecs: long hash buckets are left unsorted by a change and sorted befor…
krisnye Oct 23, 2026
1b0a553
ecs: unsorted hash buckets are listed once each, short odd moves allo…
krisnye Oct 23, 2026
90d5503
ecs: joined finalizers read their thread's object resources from its …
krisnye Oct 23, 2026
110ee8c
ecs: joined finalizers read their thread's object resources only from…
krisnye Oct 23, 2026
837ab46
ecs: benchmarks of change filters finding one, a few or every changed…
krisnye Oct 23, 2026
7391fcc
ecs: block ticks, the newest tick per 64 rows, so change filters skip…
krisnye Oct 23, 2026
13eb6d6
ecs: tests for every block stamp, block before chunk in every writer,…
krisnye Oct 23, 2026
7a9e72f
ecs: retry a joined thread's task when a sync point applied during it…
krisnye Oct 23, 2026
318dc43
ecs: never cancel an observer post its thread claimed before a writer…
krisnye Oct 23, 2026
60947dc
ecs: report a lent worker its owner ends as terminated by its owner
krisnye Oct 23, 2026
6d0fd1c
ecs: retry a task's rebuild only for its own reason, after a turn of …
krisnye Oct 23, 2026
f4b94b5
ecs: a pool worker runs its window's tasks before it leaves the close…
krisnye Oct 23, 2026
5d99e25
ecs: test a pool worker's window and a task's wait on the structure e…
krisnye Oct 23, 2026
a03cfe0
ecs: joined threads' index lookups check archetypes once a run, not p…
krisnye Oct 23, 2026
3a2cf05
ecs: say why a joined directory's view drops move its count, and wher…
krisnye Oct 23, 2026
7e0f98a
ecs: joined finalizers read string resources from copies in the stop …
krisnye Oct 23, 2026
cf5d742
ecs: joined finalizers reading two or more string resources read them…
krisnye Oct 23, 2026
cd78b7f
ecs: joined finalizers read every resource as of before their stops' …
krisnye Oct 23, 2026
dc99f02
ecs: a joined finalizer's missing resource copies its start; tests of…
krisnye Oct 23, 2026
bed788e
ecs: report a lent worker its owner ends as terminated by its owner o…
krisnye Oct 23, 2026
360a0ee
ecs: plugin tests install a copy of the package built from its sources
krisnye Oct 23, 2026
e8350fe
ecs: the transfer benchmark's spread in chromium is its own, measured…
krisnye Oct 23, 2026
5331542
ecs: README lists the features and recorded performance
krisnye Oct 23, 2026
f23dcef
ecs: README outlines the features
krisnye Oct 23, 2026
7cb86a7
ecs: README says what allocates nothing; follow-up on a run's fixed a…
krisnye Oct 23, 2026
f87fe10
ecs: README notes change checks are O(1)
krisnye Oct 23, 2026
644a557
ecs: README opens with a higher-level summary
krisnye Oct 23, 2026
2050355
ecs: README summary names applications, simulations and games
krisnye Oct 23, 2026
2c939da
ecs: README summary says multithreaded and GPU-integrated
krisnye Oct 23, 2026
9026bfb
ecs: README summary drops GPU-integrated
krisnye Oct 23, 2026
7fc9d06
ecs: PRs bump this package by hand, never through the workspace bump
krisnye Oct 23, 2026
01732a1
ecs: follow-ups list the API optimizations the required plugin allows
krisnye Oct 23, 2026
be6d8f9
ecs: Schema.Type names the type a schema describes; the math types ar…
krisnye Oct 23, 2026
fabf18f
ecs: ids name their package's version; a module outside a named packa…
krisnye Oct 23, 2026
6c98193
ecs: the plugin registers what declare module blocks declare; types f…
krisnye Oct 23, 2026
730c62d
ecs: keys are declared once, in the augmentation; register leaves the…
krisnye Oct 23, 2026
7ea2e17
ecs: docs describe keys declared once and versioned ids
krisnye Oct 23, 2026
ba3f6d6
ecs: drop a compiler helper nothing uses since types follow into the …
krisnye Oct 23, 2026
a3ae0c7
ecs: keys register right after themselves, in the module declaring th…
krisnye Oct 23, 2026
b1ea504
ecs: the build's plugin is Compiler.plugin, the one export of @adobe/…
krisnye Oct 24, 2026
e13b1b6
ecs: declarations take no name: labels are bindings, reports give ids…
krisnye Oct 24, 2026
bb531ff
ecs: docs describe labels as bindings, report ids and reduce lists
krisnye Oct 24, 2026
81f822b
ecs: kernel is true, false or "gpu"; an unflagged row system compiles…
krisnye Oct 24, 2026
38c53de
ecs: benchmarks keep the path they measure with kernel: false; sample…
krisnye Oct 24, 2026
2b1049d
ecs: a union of number constants is stored as a number; errors say wh…
krisnye Oct 24, 2026
f63cf1c
ecs: an application's build reads a library's reduction operators fro…
krisnye Oct 24, 2026
0d8249a
ecs: kernel commands write their buffer directly, so a reoptimized ke…
krisnye Oct 24, 2026
4d0f6be
ecs: an unflagged body reading module data made by any expression run…
krisnye Oct 24, 2026
0698d92
ecs: a kernel compiled unflagged computes at the precision of its bod…
krisnye Oct 24, 2026
7ccf18a
ecs: kernels failing to load on the pool a run starts are a failure i…
krisnye Oct 24, 2026
86616e9
ecs: the pool starts for rows a kernel matches, which kernels report …
krisnye Oct 24, 2026
4ad8494
ecs: a library's reduction operators are read however its bundle wrot…
krisnye Oct 24, 2026
f938934
ecs: a union of number constants holding -0 stores as f64, and one wi…
krisnye Oct 24, 2026
304f6ac
ecs: kernel: "gpu" on a system without components is a type error, as…
krisnye Oct 24, 2026
35668e0
ecs: docs say the plugin's worker.format default applies to every wor…
krisnye Oct 24, 2026
501d0ce
ecs: calls made in another's arguments get labels too, and labels wai…
krisnye Oct 24, 2026
2d537e2
ecs: suites of the row path run again with unflagged bodies as writte…
krisnye Oct 24, 2026
e5bf76f
ecs: follow-up on f64 lanes for automatic kernels over f32 columns
krisnye Oct 24, 2026
d5d70fa
ecs: memory records the minimal, abstract surface the interface aims for
krisnye Oct 24, 2026
c4aa06c
ecs: kernels computing at the body's precision run f64 lanes across r…
krisnye Oct 24, 2026
5e716a1
ecs: generated code records declarations in a global map the registry…
krisnye Oct 24, 2026
f67b94c
ecs: a declaration without a literal default starts at its type's: it…
krisnye Oct 24, 2026
b496ffd
ecs: declarations drop defaults their types give; starts compared by …
krisnye Oct 24, 2026
97fca93
ecs: declarations say what bodies can't show; the build infers what t…
krisnye Oct 24, 2026
55d25f6
ecs: memory records that types and build errors, not editor affordanc…
krisnye Oct 24, 2026
f844050
ecs: docs say declarations hold what bodies can't show, and the build…
krisnye Oct 24, 2026
8c2da79
ecs: an unfollowed lookup reads all it requires; tests give unseen bo…
krisnye Oct 24, 2026
2707d83
ecs: follow-ups track persistence: a persist trait for stable ids, an…
krisnye Oct 24, 2026
890da3e
ecs: a declaration that doesn't hold fails each World.create call onc…
krisnye Oct 24, 2026
ecb13a5
ecs: the guide teaches lookups by entity
krisnye Oct 24, 2026
8329720
ecs: the guide teaches kernels, reductions, GPU kernels and render sy…
krisnye Oct 24, 2026
6cf92b8
ecs: follow-up on telling the world's thread a join finished
krisnye Oct 24, 2026
8779f2e
ecs: Archetype leaves the API; the build indexes every list of compon…
krisnye Oct 24, 2026
2180ed9
ecs: docs describe archetypes as lists declared as const, which the b…
krisnye Oct 24, 2026
025ead6
ecs: the test of lists left as written checks the code, since every s…
krisnye Oct 24, 2026
6dac50b
ecs: inference sees destructuring and loop targets, pattern defaults,…
krisnye Oct 24, 2026
0944cdd
ecs: lists made at runtime share one index per set of keys, so making…
krisnye Oct 24, 2026
eeb67a5
ecs: lists and spawn sites are hoisted out of a body only when no nam…
krisnye Oct 24, 2026
8c600e9
ecs: a declaration that fails registering fails only its own key's us…
krisnye Oct 24, 2026
4cb6d03
ecs: starts take each field's own default; every default is checked a…
krisnye Oct 24, 2026
730fc42
ecs: lists of symbols take their index where they're made, whenever t…
krisnye Oct 24, 2026
e04f416
ecs: tests of every member a key gets wrong, and of two copies of the…
krisnye Oct 24, 2026
cfc97ea
ecs: a change inside a data value fails its system's creation; one in…
krisnye Oct 24, 2026
4fbb3f2
ecs: the guide explains lookups and indexes before their code; design…
krisnye Oct 24, 2026
7aa2476
ecs: follow-ups queue a generated API reference, published without na…
krisnye Oct 24, 2026
3751b8c
ecs: build warnings name modules by their path in their package; no w…
krisnye Oct 24, 2026
600f08e
ecs: follow-ups grouped by priority: API changes, correctness, optimi…
krisnye Oct 24, 2026
db40dd3
ecs: follow-ups use with, not has or read
krisnye Oct 24, 2026
12c422d
ecs: schemas hold no defaults; a start is its declaration's, its type…
krisnye Oct 24, 2026
3024fb2
ecs: docs give starts from declarations and types' namespaces, never …
krisnye Oct 24, 2026
fe6689b
ecs: follow-ups record run results resolving to the body's value, and…
krisnye Oct 24, 2026
e54a84e
ecs: follow-ups track optional components
krisnye Oct 24, 2026
06ecd96
ecs: starts take imported namespaces' defaults at every depth, identi…
krisnye Oct 24, 2026
6cc499b
ecs: the build treats only observer: true as an observer, and labels …
krisnye Oct 24, 2026
e082b12
ecs: docs give the & identity by column, readonly defaults' casts, an…
krisnye Oct 24, 2026
1dca3c1
ecs: a readonly default may call a function whose declared return typ…
krisnye Oct 24, 2026
7909825
ecs: optional components in types: rows hold them or undefined, never…
krisnye Oct 24, 2026
e666bef
ecs: optional components bound per archetype, with no check per row; …
krisnye Oct 24, 2026
d73f6f5
ecs: benchmarks of a system with an optional component against one re…
krisnye Oct 24, 2026
7304d49
ecs: the guide and design describe optional components
krisnye Oct 24, 2026
294b6ac
ecs: generated API reference with typedoc over the public entry point…
krisnye Oct 24, 2026
2c8d85c
docs: the Pages site is assembled from each package's pages field, so…
krisnye Oct 24, 2026
74c09e5
ecs: kernels read optional components, testing presence once per call…
krisnye Oct 24, 2026
57d3825
ecs: tails and observer systems on joined threads read optional compo…
krisnye Oct 24, 2026
30f54ba
ecs: lookups by entity take optional components, read where an entity…
krisnye Oct 24, 2026
089f847
ecs: finalizers read optional components where the entity had them; s…
krisnye Oct 24, 2026
26bcb1f
ecs: docs describe optional components in kernels, lookups, finalizer…
krisnye Oct 24, 2026
7d314e4
ecs: test that an id-less finalizer on a joined thread's thread is re…
krisnye Oct 24, 2026
a92013c
ecs: optional components' rows key by which keys are optional; mixed …
krisnye Oct 24, 2026
502aa08
ci: API docs build on every pull request; pages paths stay inside the…
krisnye Oct 24, 2026
6c946c0
ecs: follow-ups note optional groups from boards' use of optional com…
krisnye Oct 24, 2026
7b5ef12
ecs: follow-ups drop the API reference, now built
krisnye Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@ jobs:
- name: Build (every package, topological)
run: pnpm -r run build

- name: API docs (every package that defines them; warnings fail)
run: pnpm -r run docs

- name: Test (each package runs its own complete suite)
run: pnpm -r run test
26 changes: 5 additions & 21 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,20 @@ jobs:

- run: pnpm install --frozen-lockfile

- run: pnpm run build
working-directory: packages/data
- run: pnpm -r run build

- run: cp -r packages/data/dist packages/data/docs/dist
- run: pnpm -r run docs

- run: pnpm --filter @adobe/data-sync build

- run: pnpm --filter @adobe/data-lit build

- run: pnpm --filter @adobe/data-gpu build

- run: pnpm --filter data-p2p-tictactoe build
env:
CI: true

- run: cp -r packages/data-p2p-tictactoe/dist packages/data/docs/p2p-tictactoe

- run: pnpm --filter data-gpu-samples build
env:
CI: true

- run: cp -r packages/data-gpu-samples/dist packages/data/docs/gpu-samples
# Each package's package.json `pages` field says what it publishes where.
- run: node scripts/collect-pages.mjs site

- uses: actions/configure-pages@v5
with:
enablement: true

- uses: actions/upload-pages-artifact@v3
with:
path: packages/data/docs
path: site

deploy:
needs: build
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ source.txt
# Generated Docs (typedoc output)
docs/api
packages/data/docs/api
packages/ecs/docs
packages/data/references

# Playwright MCP capture artifacts
.playwright-mcp/

# Vitest browser attachments and failure screenshots
.vitest/
/site/
6 changes: 6 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ Standard script names a package may define:
that the uniform pipeline does not call.
- **`lint`** — lint the package.
- **`dev`** — local dev/watch.
- **`docs`** — generate the package's documentation (e.g. typedoc). What a
package publishes to the GitHub Pages site is its `pages` field: a list of
`{ "from", "to" }`, a folder of the package and its path on the site (`"."`
for the root). The docs workflow runs `pnpm -r run build` and
`pnpm -r run docs`, then `scripts/collect-pages.mjs` copies every package's
`pages`, so publishing never names a package.

Do **not** add a `publish-public` (or similar) script. Publishing is governed
*only* by the `private` field: `pnpm -r publish` publishes every package with
Expand Down
3 changes: 3 additions & 0 deletions packages/data-gpu-samples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"description": "WebGPU samples built on @adobe/data-gpu",
"type": "module",
"private": true,
"pages": [
{ "from": "dist", "to": "gpu-samples" }
],
"scripts": {
"predev": "pnpm --filter @adobe/data-gpu build",
"dev": "vite",
Expand Down
4 changes: 2 additions & 2 deletions packages/data-gpu-samples/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ export default defineConfig({
},
},
root: ".",
// In production (GitHub Pages) the app lives at /data/graphics-samples/.
// In production (GitHub Pages) the app lives at /data/gpu-samples/, its `pages` target.
// The dev server ignores this — it always serves from /.
base: process.env.CI ? "/data/graphics-samples/" : "/",
base: process.env.CI ? "/data/gpu-samples/" : "/",
build: { outDir: "dist" },
server: { port: 3008, open: false },
});
3 changes: 3 additions & 0 deletions packages/data-p2p-tictactoe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"description": "Serverless P2P tic-tac-toe — WebRTC DataChannel + @adobe/data-sync",
"type": "module",
"private": true,
"pages": [
{ "from": "dist", "to": "p2p-tictactoe" }
],
"scripts": {
"dev": "vite",
"build": "vite build",
Expand Down
1 change: 1 addition & 0 deletions packages/data/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ <h1>@adobe/data</h1>
<ul>
<li><a href="./api/">API Reference</a></li>
<li><a href="./api/modules/observe.html">Observable API</a></li>
<li><a href="./ecs/">@adobe/ecs API Reference</a></li>
<li><a href="./perftest.html">ECS Performance Test</a></li>
<li><a href="https://github.com/adobe/data">Source on GitHub</a></li>
</ul>
Expand Down
6 changes: 5 additions & 1 deletion packages/data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"type": "module",
"sideEffects": false,
"private": false,
"pages": [
{ "from": "docs", "to": "." },
{ "from": "dist", "to": "dist" }
],
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
Expand All @@ -19,8 +23,8 @@
"scripts": {
"build": "pnpm build-assembly && run-p build:*",
"build:code": "tsc -b",
"build:apidocs": "typedoc",
"typecheck": "pnpm build-assembly && tsc -b",
"docs": "typedoc",
"build-assembly": "run-p asbuild:release",
"clean": "rm -rf dist build node_modules",
"clean-cache": "rm -rf node_modules/.cache",
Expand Down
9 changes: 8 additions & 1 deletion packages/ecs/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Humans own the interface and agents own the implementation: agents don't add to
It's a project of its own: nothing in it imports from outside it. Each type exists once, there.
- **`src/implementation`** holds `createWorld` and everything behind it, the kernel compiler included. It imports
types and the registry's read side from `src/interface`.
- **`src/samples`** holds one folder per sample, its page included; `pnpm sample` serves them.
- **`src/samples`** holds one folder per sample, its page included. `pnpm dev` (or `pnpm sample`, without
the type-check watch) serves them, with a sample browser at the root that has a tab for each.
- `src/index.ts` exports `src/interface`, and `World` as a value too, whose `create` and `join` are the
implementation's, so `import { World } from "@adobe/ecs"` gives consumers the type, `World.create` and `World.join`,
the only entry points. Samples and the guide use them; tests and benchmarks may take `createWorld` from
Expand All @@ -44,6 +45,12 @@ when a measured win conflicts with a style or design preference, take the win an
row as low as it can be, and allocate nothing on those paths: reuse arrays, buffers and objects, share read-only
empties, and avoid closures, spreads and awaits there. Measure changes with `pnpm perf` against the recorded baseline.

## Pull requests

Each PR costs a review, a merge and a publish, so keep one open PR at a time. Add new work and fixes to it as more
commits; never open stacked or parallel PRs. Keep it rebased on main, with this package's version one above main's.
Bump it by hand in `package.json`; never run the workspace `bump` script, which bumps packages this PR didn't change.

## Memory

Decisions about working on this package live in `memory.md`; add new ones there.
Expand Down
53 changes: 51 additions & 2 deletions packages/ecs/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
# @adobe/ecs

A data-oriented entity component system. Systems run on the main thread, on worker threads, as WASM kernels or on the GPU.
A high-performance, multithreaded Entity Component System for web-based applications, simulations and games.

See the [guide](src/guide/guide.md) for how to use it.
## Features

- **Linear, gapless structure-of-arrays component storage**
- Fixed-length values (numbers, tuples, structs) in a `SharedArrayBuffer`
- Shared across the main thread and all workers
- Read by WASM kernels without copying
- WebGPU-compatible struct layout for fast uploads
- WebGPU storage for GPU system kernels
- Synced back to shared memory only when the CPU reads it
- Strings in shared memory, readable on every thread
- Objects and other variable-length values on the thread that owns them
- **Declarations**
- Components and resources declared once, as TypeScript types; the build registers them
- Named types such as `F32`, `U32` and your own `Schema.Type`s give storage precision, width and bounds
- **Systems**
- Plain TypeScript bodies with declared reads and writes
- Kernels compiled and checked at build time to optimized JavaScript, WASM and WGSL
- Balanced scheduling across the main thread, workers and the GPU
- Typed input, with its schema generated from the TypeScript type
- Render systems that draw straight from component storage
- Observer systems for reading state into a UI
- **Changes**
- Per-component added and changed ticks: an O(1) check per entity, with each change seen exactly once
- Filters that skip unchanged chunks and 64-row blocks
- Structural changes batched at sync points, so memory never moves while systems run
- Rules, finalizers and traits for derived components, cleanup and references
- **Queries**
- Hash, unique, sorted and keyless indexes, all updated incrementally
- Hierarchy traversal that reruns only below what changed
- **Threads**
- Worlds shared with other threads through a `MessagePort` or worker
- Joined threads run their own systems and observers, and lend their workers to the pool
- **Runtime**
- Kernels allocate nothing per row; commands, lookups and reports reuse their buffers
- Errors reported as data, in each run's report

## Setup

```ts
// vite.config.ts
import { Compiler } from "@adobe/ecs/compiler";
export default defineConfig({ plugins: [Compiler.plugin()] });
```

A library builds with `Compiler.plugin({ library: true })`, so its build ships the registrations its declarations give.

## Guide

See the [guide](src/guide/guide.md) for how to use it, and the [API reference](https://adobe.github.io/data/ecs/) for
every type and function.
Loading
Loading