Skip to content

japes

Java Archetype-based Parallel Entity System — a high-throughput ECS for the JVM with first-class change detection, Flecs-style entity relations and a tier-1 bytecode generator that turns your system methods into direct-dispatch hidden classes.

Pre-release

The API is stable enough to benchmark but reserves the right to change before 1.0. Snapshot Maven artifacts are published from main to GitHub Packages — see Installation for the client-side wiring.

What japes is

record Position(float x, float y) {}
record Velocity(float dx, float dy) {}

class Physics {
    @System
    void integrate(@Read Velocity v, @Write Mut<Position> p) {
        var cur = p.get();
        p.set(new Position(cur.x() + v.dx(), cur.y() + v.dy()));
    }
}

var world = World.builder().addSystem(Physics.class).build();
world.spawn(new Position(0, 0), new Velocity(1, 1));
world.tick();

Everything is declarative. Components are plain records. Systems are annotated methods whose parameters tell the scheduler exactly what they read and write, so the DAG builder can run disjoint systems in parallel automatically — no manual locking, no priority tables. The scheduler then emits a hidden class per system: your user method is called via direct invokevirtual with every argument hoisted into a JIT register, so hot loops inline as if you'd hand-written one big monolithic method.

Feature grid

Archetype storage

Flat chunked arrays keyed by component signature. Every matching archetype iterates cache-linearly with zero type-based dispatch in the hot loop.

Tier-1 bytecode dispatch

Per-system hidden classes generated via java.lang.classfile. The JIT sees an ordinary virtual call and inlines your whole system body into the chunk loop.

Change detection

@Filter(Added.class) / @Filter(Changed.class) filters and RemovedComponents<T> service params, backed by per-component dirty lists — observers walk only entities that actually changed.

First-class relations

@Relation, @Pair(T.class), @ForEachPair(T.class) with non-fragmenting forward + reverse indices and archetype markers — Flecs-style without leaving Java.

Deferred structural edits

Commands buffers spawn/despawn/insert/remove operations from inside parallel systems and flushes them at stage boundaries — no locking, no race conditions.

Disjoint-access parallelism

The scheduler analyses each system's access set statically and runs everything that commutes on the multi-threaded executor — no annotations, no priorities.

Headline benchmark. With SoA storage, iterateWithWrite at 10k lands at japes 1.61 µs/op vs Bevy 0.15's 6.28 µs/op — 3.9× faster than the Rust reference on writes. Change detection stays strong: SparseDelta — data pending. The benchmarks section shows the full cross-library tables plus the predator/prey relations workload where data pending for 500 × 2000 tuples.

Where to start

I just want to ship code

Quick start → gradle dependency, first world, first system, first tick.

I want to learn the whole API

Tutorials → 22 chapters covering every annotation and service parameter, from components to relations.

I want the numbers

Benchmarks → methodology, per-benchmark analysis and the cross-library cost-model breakdown.

I want the design rationale

Reference → cheat sheet, tier-1/tier-2 fallback catalog, FAQ.

License

MIT. japes is single-author hobby research released in the hope it's useful. Contributions, issues and pull requests all welcome at github.com/zzuegg/japes.