Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions packages/ecs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# @adobe/ecs

A data-oriented entity component system. Systems run on the main thread, on worker threads, as WASM kernels or on the GPU.

See the [guide](src/guide/guide.md) for how to use it.
1 change: 1 addition & 0 deletions packages/ecs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@adobe/ecs",
"version": "0.1.0",
"description": "Adobe ECS",
"license": "MIT",
"type": "module",
"sideEffects": false,
"private": false,
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/scripts/perf.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
// Runs the benchmarks, compares them with what this machine recorded last, and records them.
//
// pnpm perf [filter] node benchmarks whose names match the regular expression filter, each in a process
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/exports.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { cpSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, relative } from "node:path";
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/01-resources.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Entity, Resource, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/02-entities.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Archetype, Component, System, Vec3, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/03-systems.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Report, Resource, System, Vec3, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/04-ticks.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { always, cadence, clock, Resource, System, wake, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/05-scheduling.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/06-sync-points.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Resource, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/07-change-filters.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Resource, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/08-input.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Entity, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/09-rules.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Rule, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/10-finalizers.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Finalizer, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/11-traits.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Entity, System, World } from "../index.js";

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/11-traits.type-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { Component, Trait } from "../index.js";

type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/guide/13-indexes.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, Index, System, World } from "../index.js";

Expand Down
44 changes: 22 additions & 22 deletions packages/ecs/src/guide/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ await moon.run(read);
expect(values[0]).toBe(-1.6);
```

[`01-resources.test.ts`](01-resources.test.ts#L5-L45)
[`01-resources.test.ts`](01-resources.test.ts#L6-L46)

### 2. Entities, components and archetypes

Expand Down Expand Up @@ -143,7 +143,7 @@ expect(foes).toEqual([[0, 10, 0]]);
expect(particles).toBe(1);
```

[`02-entities.test.ts`](02-entities.test.ts#L5-L58)
[`02-entities.test.ts`](02-entities.test.ts#L6-L59)

### 3. Systems

Expand Down Expand Up @@ -179,7 +179,7 @@ await world.run(read);
expect(moved).toEqual([[1, 0, 0]]);
```

[`03-systems.test.ts`](03-systems.test.ts#L34-L68)
[`03-systems.test.ts`](03-systems.test.ts#L35-L69)

```ts
const fail = System.create({ name: "fail" }, () => {
Expand All @@ -200,7 +200,7 @@ expect(run).toBe(1);
expect(logged).toEqual(["fail: broken"]);
```

[`03-systems.test.ts`](03-systems.test.ts#L70-L86)
[`03-systems.test.ts`](03-systems.test.ts#L71-L87)

### 4. Ticks and cadence

Expand Down Expand Up @@ -228,7 +228,7 @@ expect(await ticked).toBeGreaterThanOrEqual(30);
world.remove(advance);
```

[`04-ticks.test.ts`](04-ticks.test.ts#L17-L51)
[`04-ticks.test.ts`](04-ticks.test.ts#L18-L52)

```ts
// A system asks for another tick by contributing a time to wake: the first tick at or after it runs. Work that a tick's
Expand All @@ -244,7 +244,7 @@ world.add(step);
await world.run(System.create(() => {}));
```

[`04-ticks.test.ts`](04-ticks.test.ts#L53-L74)
[`04-ticks.test.ts`](04-ticks.test.ts#L54-L75)

## Intermediate

Expand All @@ -263,7 +263,7 @@ const heal = System.create({ components: { write: [health] }, after: [hit] }, ro
const frame = System.create([heal, hit]);
```

[`05-scheduling.test.ts`](05-scheduling.test.ts#L18-L42)
[`05-scheduling.test.ts`](05-scheduling.test.ts#L19-L43)

```ts
// Phases are systems that do nothing; a system during one runs after what the phase follows and before what follows it.
Expand All @@ -278,7 +278,7 @@ const report = System.create({ components: { read: [health] }, during: [render]
const phased = System.create([report, poison, update, render]);
```

[`05-scheduling.test.ts`](05-scheduling.test.ts#L44-L61)
[`05-scheduling.test.ts`](05-scheduling.test.ts#L45-L62)

### 6. Sync points

Expand All @@ -298,7 +298,7 @@ const count = System.create({ components: { has: [health] }, resources: { write:
const frame = System.create([spawn, count]);
```

[`06-sync-points.test.ts`](06-sync-points.test.ts#L20-L52)
[`06-sync-points.test.ts`](06-sync-points.test.ts#L21-L53)

```ts
// An observer runs after the sync point of every run and tick it's added to, reading what it left; it writes nothing.
Expand All @@ -307,7 +307,7 @@ const watch = System.create({ observer: true, components: { read: [health] } },
});
```

[`06-sync-points.test.ts`](06-sync-points.test.ts#L35-L38)
[`06-sync-points.test.ts`](06-sync-points.test.ts#L36-L39)

### 7. Change filters and conditions

Expand All @@ -323,7 +323,7 @@ const show = System.create({ components: { read: [score], write: [shown], change
});
```

[`07-change-filters.test.ts`](07-change-filters.test.ts#L35-L65)
[`07-change-filters.test.ts`](07-change-filters.test.ts#L36-L66)

```ts
// Runs only while each resource in is is neither null nor false, and each in not is; is reads it narrowed.
Expand All @@ -332,7 +332,7 @@ const step = System.create({ resources: { is: [map], not: [paused], write: [step
});
```

[`07-change-filters.test.ts`](07-change-filters.test.ts#L67-L88)
[`07-change-filters.test.ts`](07-change-filters.test.ts#L68-L89)

### 8. Input

Expand All @@ -359,7 +359,7 @@ await world.run(hit, { amount: 3 });
await world.run(heal, { entity: player, amount: 1 });
```

[`08-input.test.ts`](08-input.test.ts#L18-L48)
[`08-input.test.ts`](08-input.test.ts#L19-L49)

### 9. Rules

Expand All @@ -383,7 +383,7 @@ Rule.create({ components: { has: [sprite], not: [hidden] }, derive: [drawn] });
Rule.create({ components: { has: [drawn] }, derive: [layer] });
```

[`09-rules.test.ts`](09-rules.test.ts#L10-L58)
[`09-rules.test.ts`](09-rules.test.ts#L11-L59)

### 10. Finalizers and change sets

Expand All @@ -397,7 +397,7 @@ Finalizer.create({ components: { read: [handle] } }, row => {
await world.dispose();
```

[`10-finalizers.test.ts`](10-finalizers.test.ts#L15-L47)
[`10-finalizers.test.ts`](10-finalizers.test.ts#L16-L48)

```ts
// Sees each sync point's structural changes to the components it watches, grouped by how entities changed, with
Expand All @@ -409,7 +409,7 @@ Finalizer.changes({ watch: [handle] }, changes => {
});
```

[`10-finalizers.test.ts`](10-finalizers.test.ts#L49-L65)
[`10-finalizers.test.ts`](10-finalizers.test.ts#L50-L66)

### 11. Traits, within and references

Expand Down Expand Up @@ -441,7 +441,7 @@ const spawn = System.create(({ commands }) => {
});
```

[`11-traits.test.ts`](11-traits.test.ts#L11-L59)
[`11-traits.test.ts`](11-traits.test.ts#L12-L60)

```ts
// A trait of your own is a member of Traits<N>: the value it allows on key N, or never where it doesn't apply.
Expand All @@ -457,7 +457,7 @@ Trait.register(instanced);
check<Equal<Extract<Component.With<typeof instanced>, typeof transform | typeof name>, typeof transform>>();
```

[`11-traits.type-test.ts`](11-traits.type-test.ts#L6-L27)
[`11-traits.type-test.ts`](11-traits.type-test.ts#L7-L28)

## Advanced

Expand All @@ -478,7 +478,7 @@ const count = System.create({ components: { read: [cell], write: [crowded] }, lo
});
```

[`13-indexes.test.ts`](13-indexes.test.ts#L27-L34)
[`13-indexes.test.ts`](13-indexes.test.ts#L28-L35)

```ts
// A sorted index keeps its key's order: lookups take a range, and `order` runs a system's rows in it.
Expand All @@ -497,7 +497,7 @@ const list = System.create({ observer: true, components: { read: [player] }, ord
});
```

[`13-indexes.test.ts`](13-indexes.test.ts#L36-L49)
[`13-indexes.test.ts`](13-indexes.test.ts#L37-L50)

```ts
// A unique index gives one row, or null.
Expand All @@ -508,7 +508,7 @@ const find = System.create({ input: { type: "object", properties: { id: { type:
});
```

[`13-indexes.test.ts`](13-indexes.test.ts#L51-L56)
[`13-indexes.test.ts`](13-indexes.test.ts#L52-L57)

```ts
// An index without a key holds every entity with its components, in entity order. With changed: true, this observer
Expand All @@ -520,7 +520,7 @@ const countPlayers = System.create({ observer: true, lookup: { players: { index:
});
```

[`13-indexes.test.ts`](13-indexes.test.ts#L58-L64)
[`13-indexes.test.ts`](13-indexes.test.ts#L59-L65)

A list stays valid until its call site runs again. Lists and rows read only what the index holds and its lookup's
`read` names, and `list.changed` tells whether an entity entered, left or moved in it since the system last ran. A
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/access.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Node } from 'estree';
import { entityRead } from './columns.js';
import { fail } from './failure.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/assign.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { AssignmentExpression, Expression as SourceExpression, Node, Pattern, UpdateExpression } from 'estree';
import { access } from './access.js';
import { failPattern } from './bind.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/bind.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Identifier, Node, Pattern } from 'estree';
import { access } from './access.js';
import { set } from './booleans.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/body-access.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Node, ObjectExpression, Pattern } from 'estree';
import { children, declaredIn, patternNames } from './estree.js';
import type { Used } from './exact.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/booleans.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Expression, Statement } from './ir.js';
import { references } from './ir.js';
import type { Unit } from './unit.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/branches.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Node } from 'estree';
import { set } from './booleans.js';
import { dataValue, leavesOf, mapLeaves, sameShape, type Data } from './data.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/calls.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { SimpleCallExpression, Expression as SourceExpression, Node, SpreadElement, Statement as SourceStatement } from 'estree';
import { mergeBranches } from './branches.js';
import { bind } from './bind.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/columns.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Path } from '../world/kernel.js';
import type { Expression } from './ir.js';
import type { Unit } from './unit.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/compile-kernel.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Node, ObjectExpression } from 'estree';
import { bind } from './bind.js';
import { requireExact } from './exact.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/data.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Node } from 'estree';
import type { Path } from '../world/kernel.js';
import { fail } from './failure.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/estree.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Node, Pattern, Program } from 'estree';
import type { parseAst } from 'vite';

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/exact.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Expression, ObjectExpression, Pattern } from 'estree';
import { fail } from './failure.js';
import type { Lists } from './lists.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/expression.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { ConditionalExpression, Identifier, LogicalExpression, Node } from 'estree';
import { access } from './access.js';
import { observe, set } from './booleans.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/failure.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
/** Where an inlined function failed: the function, and the failing line in its file. */
export type Frame = { readonly name: string; readonly file: string; readonly line: number; readonly column: number };

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/hygiene.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { expect, it } from "vitest";
import { Component, System } from "../../index.js";
import { workers } from "../../interface/resources/workers.js";
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/identify.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { describe, expect, test } from 'vitest';
import { parseAst } from 'vite';
import { idOfKey, takeIdOfDeclaration } from '../../interface/registry/ids.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/identify.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
/// <reference types="node" />
import type { Expression, Node, Program } from 'estree';
import { posix } from 'node:path';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
export * from './plugin.js';
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/ir.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { BinaryOperator } from 'estree';
import type { Path, Program } from '../world/kernel.js';
import type { Out } from './out.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/kernel-id.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
/// <reference types="node" />
import { createHash } from 'node:crypto';

Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/key.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { AssignmentProperty, MemberExpression, Node, Property } from 'estree';
import { fail } from './failure.js';
import type { Out } from './out.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/link.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import { describe, expect, test } from 'vitest';
import { parseAst } from 'vite';
import { createLinker, isPending, resolveExport, type Link, type LinkHost } from './link.js';
Expand Down
1 change: 1 addition & 0 deletions packages/ecs/src/implementation/compiler/link.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
import type { Program } from 'estree';
import { createModule, locateIn, type Module, type ModuleBinding } from './module-scope.js';

Expand Down
Loading
Loading