npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

threaded-three

v0.2.0

Published

Multithreaded ECS runtime for Three.js scenes with worker pools, background jobs, and benchmark tooling

Readme

threaded-three

Multithreaded ECS runtime for Three.js scenes with worker pools, background jobs, adaptive dispatch, and benchmark tooling.

threaded-three is designed for simulation-heavy Three.js apps that need more than a single main-thread update loop. It uses SharedArrayBuffer, double-buffered component storage, compute workers, and an optional render worker to keep ECS work off the main thread.

Install

npm install threaded-three three

Requirements

  • Modern browser with SharedArrayBuffer support
  • Cross-origin isolation enabled in development and production:
    • Cross-Origin-Opener-Policy: same-origin
    • Cross-Origin-Embedder-Policy: require-corp

Without those headers you can still run in single mode, but the multithreaded worker runtime will not be available.

Quick Start

import { World, System, Component } from 'threaded-three';

class MovementSystem extends System {
  components = ['position', 'velocity'];

  static config = {
    pool: 'physics',
    allowStealing: true,
    dynamicSplit: true,
    writeComponents: ['position']
  };

  execute(chunk, dt) {
    const position = chunk.comp0;
    const velocity = chunk.comp1;

    for (let i = 0; i < chunk.count; i++) {
      const base = i * 3;
      position[base] += velocity[base] * dt;
      position[base + 1] += velocity[base + 1] * dt;
      position[base + 2] += velocity[base + 2] * dt;
    }
  }
}

const world = new World({
  totalWorkers: 'auto',
  reserveWorkers: 2,
  backgroundWorkers: 'off',
  componentLayout: {
    position: Component.f32x3,
    velocity: Component.f32x3
  },
  maxEntities: 50000
});

world.addSystem(MovementSystem);

const entities = world.createEntity(1000);
for (const entity of entities) {
  world.writeInitialComponent('position', entity, [0, 0, 0]);
  world.writeInitialComponent('velocity', entity, [1, 0, 0]);
}

world.onUpdate(({ stats }) => {
  console.log(stats.frameNumber, stats.lastTickMs);
});

await world.start({ mode: 'multi' });

Public API

Component

Use component descriptors when building a world layout.

Component.f32
Component.f32x3
Component.i32
Component.ofSize(n)

System

Subclass System and implement execute(chunk, dt).

Useful static config keys:

  • pool: named pool, usually physics, ai, or global
  • allowStealing: lets other pools steal this system's jobs
  • dynamicSplit: uses adaptive chunking
  • minThreads: lower bound for dispatch parallelism
  • writeComponents: explicit write set for phase planning

World

Main runtime entry point.

Common constructor options:

  • totalWorkers: number or 'auto'
  • reserveWorkers: CPU headroom to leave unused
  • pools: pool sizes such as { physics: { size: 'auto' }, ai: { size: 'auto' }, global: { size: 'auto' } }
  • backgroundWorkers: number, 'auto', or 'off'
  • componentLayout: component descriptors keyed by name
  • render: optional render configuration for worker or main-thread renderer
  • maxEntities: maximum entity capacity
  • metrics: metrics collection config

Useful instance methods:

  • addSystem(SystemClassOrInstance)
  • createEntity(count = 1)
  • writeComponent(name, entityId, bufferId, values)
  • writeInitialComponent(name, entityId, values)
  • getComponentView(name, bufferId?)
  • readComponent(name, entityId, bufferId?)
  • onUpdate(callback)
  • start({ mode, canvas })
  • stop()
  • getStats(options?)
  • resetPerformanceMetrics(options?)
  • registerBackgroundJob(name, handler)
  • runBackgroundJob(name, payload)
  • createBenchmarkReport(options?)

Rendering Modes

Simulation Only

await world.start({ mode: 'multi' });

Worker Render

const canvas = document.querySelector('canvas');
await world.start({ mode: 'multi', canvas });

If OffscreenCanvas transfer is not available, the runtime falls back to a main-thread renderer.

Background Jobs

await world.registerBackgroundJob('scanGrid', ({ width, height }) => {
  let total = 0;
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      total += x + y;
    }
  }
  return total;
});

const result = await world.runBackgroundJob('scanGrid', { width: 64, height: 64 });

Benchmarks

threaded-three also exports benchmark helpers used in this repo:

import {
  runBenchmark,
  runBenchmarkSeries,
  compareBenchmarkReports,
  runBenchmarkMatrix,
  compareBenchmarkMatrices
} from 'threaded-three';

These are useful for validating runtime changes, but they are optional for application consumers.

Notes

  • three is a peer dependency.
  • Worker URLs are bundled from the library build, so consumers should import the package from a modern ESM bundler environment.
  • For Node-based tests you may need a requestAnimationFrame shim when exercising render or benchmark paths.

Development

npm install
npm run build
npm test
npm run test:e2e