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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[tools]
pnpm = "11.15.1"
node = "26.5.0"
pnpm = "12.12.1"
node = "26.11.1"
63 changes: 29 additions & 34 deletions packages/examples/src/demos/shmup/systems/collision-system.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { intersects } from "#/lib/collision/aabb.ts";
import { World } from "objecs";
import { Config } from "../config.ts";
import { EnemyType } from "../constants.ts";
Expand Down Expand Up @@ -31,6 +30,16 @@ export function collisionSystemFactory({
continue;
}

const { boxCollider, transform } = entity;
const collisionLayer = entity.collisionLayer;

// Hoist the outer entity's bounds out of the inner loop. The previous
// version recomputed these for every otherEntity.
const left = transform.position.x + boxCollider.offsetX;
const top = transform.position.y + boxCollider.offsetY;
const right = left + boxCollider.width;
const bottom = top + boxCollider.height;

for (const otherEntity of collidables.entities) {
if (entity === otherEntity) {
continue;
Expand All @@ -42,42 +51,28 @@ export function collisionSystemFactory({

// Make sure entityA's collision layer is a subset of entityB's
// collision mask
if (
(entity.collisionLayer & otherEntity.collisionMask) !==
entity.collisionLayer
) {
if ((collisionLayer & otherEntity.collisionMask) !== collisionLayer) {
continue;
}

const { boxCollider, transform } = entity;

const { boxCollider: otherBoxCollider, transform: otherTransform } =
otherEntity;

const x = transform.position.x + boxCollider.offsetX;
const y = transform.position.y + boxCollider.offsetY;
const otherX = otherTransform.position.x + otherBoxCollider.offsetX;
const otherY = otherTransform.position.y + otherBoxCollider.offsetY;

const aabb = {
position: {
x,
y,
},
width: boxCollider.width,
height: boxCollider.height,
};

const otherAabb = {
position: {
x: otherX,
y: otherY,
},
width: otherBoxCollider.width,
height: otherBoxCollider.height,
};

if (!intersects(aabb, otherAabb)) {
const otherBoxCollider = otherEntity.boxCollider;
const otherTransform = otherEntity.transform;

const otherLeft = otherTransform.position.x + otherBoxCollider.offsetX;
const otherTop = otherTransform.position.y + otherBoxCollider.offsetY;

// Inlined AABB intersection test. The previous version allocated
// two temp AABB literals (four objects) on every pair check; this
// reads the hoisted bounds directly. Same comparison as
// `intersects()` in lib/collision/aabb.ts.
if (
!(
left < otherLeft + otherBoxCollider.width &&
right > otherLeft &&
top < otherTop + otherBoxCollider.height &&
bottom > otherTop
)
) {
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/examples/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const demoInputs = await fs

export default defineConfig({
build: {
rollupOptions: {
rolldownOptions: {
input: {
main: resolve(__dirname, "index.html"),
...demoInputs,
Expand Down
17 changes: 17 additions & 0 deletions packages/perf-proofs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,20 @@ node --expose-gc src/object/hasown-vs-undefined-check.ts
### function/

- **call-vs-direct-invocation** — `Function.prototype.call()` vs direct invocation in tight loops. Maps to `EntityCollection.forEach()`.

### worker/

Spike category — evaluating parallel producer systems (Worker threads +
shared read-only snapshots). Unlike the other categories, these benchmarks
depend on the built `objecs` package and gate on correctness assertions
before reporting timings.

- **collision-serial** — three serial collision kernels (faithful shmup replica,
precomputed, packed SoA) establishing the baseline any Worker variant must
beat. Maps to `packages/examples/src/demos/shmup/systems/collision-system.ts`.

See [`src/worker/README.md`](src/worker/README.md) for results and status.

```bash
pnpm --filter perf-proofs start:worker
```
6 changes: 4 additions & 2 deletions packages/perf-proofs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"start": "for f in $(find src -name '*.ts' | sort); do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start": "for f in $(find src -name '*.ts' -not -path '*/lib/*' | sort); do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:object": "for f in src/object/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:array": "for f in src/array/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:map-set": "for f in src/map-set/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:set": "for f in src/set/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:iteration": "for f in src/iteration/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:function": "for f in src/function/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"start:worker": "pnpm --filter objecs build && for f in src/worker/*.ts; do echo \"\\n--- $f ---\"; node --expose-gc \"$f\"; done",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"mitata": "^1.0.34"
"mitata": "^1.0.34",
"objecs": "workspace:*"
},
"devDependencies": {
"@types/node": "^26.1.1",
Expand Down
Loading