Package Exports
- @weed.js/engine
- @weed.js/engine/src
- @weed.js/engine/src/components/BulletComponent.js
- @weed.js/engine/src/components/Collider.js
- @weed.js/engine/src/components/DecorationComponent.js
- @weed.js/engine/src/components/FlashComponent.js
- @weed.js/engine/src/components/LightEmitter.js
- @weed.js/engine/src/components/ParticleComponent.js
- @weed.js/engine/src/components/RigidBody.js
- @weed.js/engine/src/components/ShadowCaster.js
- @weed.js/engine/src/components/SpriteRenderer.js
- @weed.js/engine/src/components/Transform.js
- @weed.js/engine/src/core/BigAtlasInspector.js
- @weed.js/engine/src/core/BulletPool.js
- @weed.js/engine/src/core/Camera.js
- @weed.js/engine/src/core/ColliderUtils.js
- @weed.js/engine/src/core/Component.js
- @weed.js/engine/src/core/ConfigDefaults.js
- @weed.js/engine/src/core/Constraint.js
- @weed.js/engine/src/core/DebugFlags.js
- @weed.js/engine/src/core/DebugUI.css
- @weed.js/engine/src/core/DebugUI.js
- @weed.js/engine/src/core/DecorationPool.js
- @weed.js/engine/src/core/FSM.js
- @weed.js/engine/src/core/FSMState.js
- @weed.js/engine/src/core/Flash.js
- @weed.js/engine/src/core/Grid.js
- @weed.js/engine/src/core/InlineWorkers.generated.js
- @weed.js/engine/src/core/Keyboard.js
- @weed.js/engine/src/core/Mouse.js
- @weed.js/engine/src/core/NavGrid.js
- @weed.js/engine/src/core/ParticleEmitter.js
- @weed.js/engine/src/core/QuerySystem.js
- @weed.js/engine/src/core/Ray.js
- @weed.js/engine/src/core/Scene.js
- @weed.js/engine/src/core/SharedAtomicPool.js
- @weed.js/engine/src/core/SoundManager.js
- @weed.js/engine/src/core/SpriteSheetRegistry.js
- @weed.js/engine/src/core/Sun.js
- @weed.js/engine/src/core/gameEngine.js
- @weed.js/engine/src/core/gameObject.js
- @weed.js/engine/src/core/utils.js
- @weed.js/engine/src/index.js
- @weed.js/engine/src/lib/howler.core.js
- @weed.js/engine/src/lib/pixi-tilemap-module.js
- @weed.js/engine/src/workers/AbstractWorker.js
- @weed.js/engine/src/workers/logic_worker.js
- @weed.js/engine/src/workers/particle_worker.js
- @weed.js/engine/src/workers/physics_worker.js
- @weed.js/engine/src/workers/pixi8webworker.js
- @weed.js/engine/src/workers/pixi_worker.js
- @weed.js/engine/src/workers/pre_render_worker.js
- @weed.js/engine/src/workers/spatial_worker.js
- @weed.js/engine/src/workers/workers-utils.js
Readme
WeedJS 🌿
20,000 entities. 60fps. In your browser. No, seriously.
Most web game engines tap out around 2000 sprites and call it a day. WeedJS looked at that, took a hit, and said "what if we just... didn't have that problem?"
The result: a multithreaded 2D engine where your game logic, physics, spatial queries, particles, and rendering all run on separate threads through SharedArrayBuffer pipelines. Zero message-passing bottlenecks. Zero main-thread rendering. Just raw parallel throughput.
🔗 Live Demo: https://multithreaded-game-engine.vercel.app/demos

Why It Hits Different
Other engines serialize everything through one thread and pray. WeedJS splits the work across 6+ dedicated Web Workers that share memory directly:
| Worker | What It Does |
|---|---|
spatial_worker (1..N) |
Spatial hashing, neighbor detection. Knows who's near who. |
physics_worker (1) |
Verlet integration, collision resolution. Solid and predictable. |
logic_worker (1..N) |
Your tick() code runs here. AI, behaviors, the fun stuff. |
particle_worker (1) |
Particles, decals, navigation, visibility lists. The multitasker. |
pre_render_worker (1) |
Animation, Y-sorting, render queue assembly. The stage manager. |
pixi_worker (1) |
PixiJS on an OffscreenCanvas. Draws frames, stays out of your way. |
All backed by typed arrays on SharedArrayBuffers. Single-writer ownership per data region. No locks, no Atomics spam, no drama.
The Stupid-Simple API
You define entities. You give them components. You write a tick(). That's it.
import WEED from '/src/index.js';
const { GameObject, Scene, RigidBody, Collider, SpriteRenderer } = WEED;
class Zombie extends GameObject {
static scriptUrl = import.meta.url;
static components = [RigidBody, Collider, SpriteRenderer];
setup() {
this.collider.radius = 12;
this.collider.visualRange = 160;
this.rigidBody.maxVel = 2.5;
this.rigidBody.friction = 0.02;
}
onSpawned({ x = 0, y = 0 } = {}) {
this.x = x;
this.y = y;
this.setSpritesheet('zombie');
this.setAnimation('walk_down');
}
tick(dtRatio) {
// Neighbors are pre-computed by the spatial worker. Just use them.
for (let n = 0; n < this.neighborCount; n++) {
const neighborIndex = this.getNeighbor(n);
// chase, flee, bite, whatever
}
}
}
class ZombieScene extends Scene {
static config = {
worldWidth: 5000,
worldHeight: 3000,
spatial: { cellSize: 128, maxNeighbors: 500 },
logic: { numberOfLogicWorkers: 2 },
};
static entities = [[Zombie, 20000]];
create() {
for (let i = 0; i < 20000; i++) {
this.spawnEntity(Zombie, {
x: Math.random() * 5000,
y: Math.random() * 3000,
});
}
}
}
const game = new WEED.GameEngine({ debug: true });
await game.loadScene(ZombieScene);20,000 zombies with spatial awareness, physics, and animations. All at 60fps. You're welcome.
What's In The Box
- Pooled ECS -- entities are indices into typed arrays, not objects on the heap. Spawn and despawn cost basically nothing.
- Spatial hashing -- neighbor queries are automatic. Every entity knows who's nearby without you writing a single spatial algorithm.
- 2D lighting & shadows -- point lights, shadow casters, sun/day cycle, muzzle flashes. All rendered on a separate thread.
- Particles & decals -- blood, sparks, smoke, floor stamps. Separate optimized pool, not full entities.
- Flowfield + A* navigation -- request a direction vector and the engine handles pathfinding in the background.
- Collision callbacks --
onCollisionEnter,onCollisionStay,onCollisionExit. Unity vibes, worker performance. - FSM system -- built-in finite state machines for animation and behavior, component-style.
- Debug UI -- real-time FPS per worker, entity inspector, visual debugging. Toggle it on and watch the machine breathe.
APIs You'll Actually Use
// Input
Keyboard.isDown('w');
Mouse.isButton0Down;
(Mouse.x, Mouse.y);
// Camera
Camera.follow(this.x, this.y);
Camera.setZoom(1.5);
// Particles
ParticleEmitter.emit({
texture: 'blood',
x: this.x,
y: this.y,
angleXY: { min: 0, max: 360 },
speed: { min: 1, max: 3 },
lifespan: 800,
stayOnTheFloor: true,
});
// Flashes
Flash.create({ x: this.x, y: this.y, z: 30, lifespan: 50, color: 0xffaa00, intensity: 10000 });
// Queries (inside worker/entity code)
const enemies = query([RigidBody, EnemyComponent]);Quick Start
git clone https://github.com/your-repo/weedjs.git
cd weedjs
node server/node_server.jsOpen http://localhost:3000/demos/.
SharedArrayBufferrequires cross-origin isolation headers. The included server handles this.
🌿 Why "WeedJS"?
Because it grows fast, spreads everywhere, and just won't die. Also, this engine is dope.
Docs
| File | What's In It |
|---|---|
docs/bible_of_weed_js.md |
Quick reference for the engine |
docs/WORKERS_ARCHITECTURE.md |
Worker roles and data flow |
docs/MEMORY_STRUCTURE.md |
SAB layout and ownership model |
docs/ENTITY_TEMPLATE.js |
Copy-paste starter entity |
License
ISC