diff --git a/README.md b/README.md index 5b93d17..7d407ba 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,13 @@ specialized loop per archetype — which is what lets it beat bitECS, and it hol edge as the world grows (no pre-sizing required; it falls back to a plain loop where a strict CSP or sandbox forbids dynamic compilation). +You don't have to choose between the readable `.each` body and that speed: +[`query.compile`](https://github.com/andymai/ecsia/blob/main/website/guide/performance.md#compile-the-ergonomic-path-compile) +takes the same `e.position.x += …` callback, rewrites it into the `bindColumns`-shape loop, and lands +near `eachChunk` — roughly 6× faster than the plain `.each` it's written like — while still feeding +`.changed()`/observers. It's a pure speedup that falls back to the normal loop for anything it can't +compile. + Worker-thread speedup on a compute-heavy simulation (8,192 entities, 512 physics steps per frame, 60 frames), with every threaded run byte-identical to the single-threaded result: diff --git a/website/guide/core-concepts.md b/website/guide/core-concepts.md index 46602cf..9cd5ca0 100644 --- a/website/guide/core-concepts.md +++ b/website/guide/core-concepts.md @@ -104,9 +104,14 @@ for (const e of world.query(read(Velocity), write(Position))) { Other query terms — `has(C)`, `without(C)`, and `optional(C)` — refine which entities match without (or optionally) binding accessors. -For the rare loop that needs every nanosecond, queries also offer a bind-once fast path, -[`bindColumns`](/guide/performance#bind-your-loop-once-bindcolumns) — the -[performance page](/guide/performance) covers it. +When a hot loop matters, keep this exact ergonomic body and hand it to +[`query.compile`](/guide/performance#compile-the-ergonomic-path-compile): it rewrites your +`e.position.x += …` callback into a specialized column loop — roughly **6× faster than the plain +`.each`**, on par with raw column access, and it still feeds `.changed()`/observers. It is a pure +speedup that falls back to the normal loop for anything it can't compile, so there's no syntax to +learn and no result to second-guess. (For the last nanosecond on a loop you're willing to write +against raw typed arrays, [`bindColumns`](/guide/performance#bind-your-loop-once-bindcolumns) drops +the reactivity bookkeeping too — the [performance page](/guide/performance) covers both.) ### Deriving narrower queries `query.derive(...terms)` builds the query for *this query's terms plus the new ones*.