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

ngx-three-engine

v21.5.1

Published

A simple WebGL/WebGPU-based game framework with Actor-Component logic on top of threejs, with cannon-es for physics.

Readme

ngx-three-engine

A WebGL/WebGPU game framework for Angular, built on top of Three.js with Cannon-ES physics. Provides an Unreal Engine-inspired Actor-Component architecture, enhanced input system, ECS, pluggable rendering strategies, and automatic GPU-based graphics scalability — all designed for Angular's zoneless signals architecture.

Features

  • Actor-Component system — Extend Actor (which extends Three.js Object3D) and attach reusable ActorComponent behaviors
  • Pawn & Controller pattern — Possess pawns with player or AI controllers, just like Unreal Engine
  • Enhanced Input System — Abstract input actions from physical keys with InputAction, InputMappingContext, and PlayerInput
  • ECS (Entity-Component-System) — Priority-sorted systems with a built-in TickSystem and PhysicsSystem
  • Physics — Cannon-ES integration with auto-synced rigid bodies, debug wireframe (F3), and character capsule colliders
  • Pluggable rendering — Swap between DeferredRenderStrategy (WebGPU pipeline) and PathTracingStrategy (GPU path tracer) at runtime
  • Auto GPU scalability — Benchmarks the GPU on first run and applies Low/Mid/High presets (shadow quality, anti-aliasing, pixel ratio, effects)
  • Object selection — Raycast-based picking with multi-select, hover events, and outline effects
  • Editor Mode & State — Game mode + state pattern for organizing initialization and gameplay logic
  • Settings panel — Built-in Angular component for checkboxes, dropdowns, and sliders
  • Built-in pawnsOrbitPawn (3D orbit controls), OrbitPawn2D (top-down pan/zoom), DefaultPawn (fly controls), Character (physics-based capsule)

Installation

npm install ngx-three-engine

Peer dependencies

ngx-three-engine only keeps the Angular framework packages and rxjs as peer dependencies, because those must match the host Angular app.

| Package | Version | | ---------------------- | -------- | | @angular/core | ^21.2.8 | | @angular/common | ^21.2.8 | | rxjs | ~7.8.2 |

The engine-specific packages (three, @types/three, cannon-es, @pmndrs/detect-gpu, and three-gpu-pathtracer) are installed automatically with ngx-three-engine.

If your own app imports those packages directly, add them to your app as direct dependencies too. For example, the code samples below import from three, so most projects should also run:

npm install three
npm install -D @types/three

Setup

1. Initialize the InjectorService

ngx-three-engine uses Angular's dependency injection internally. You must provide the injector at app startup:

// app.config.ts
import { ApplicationConfig, inject, Injector, provideAppInitializer } from "@angular/core";
import { InjectorService } from "ngx-three-engine";

export const appConfig: ApplicationConfig = {
  providers: [
    provideAppInitializer(() => {
      const injector = inject(Injector);
      InjectorService.setInjector(injector);
      return undefined;
    }),
    // ... other providers
  ],
};

2. Create a World

A World is your scene container — it manages the Three.js scene, camera, lighting, actors, physics, and render pipeline.

// my-world.ts
import { World } from "ngx-three-engine";
import { AmbientLight, DirectionalLight, Mesh, BoxGeometry, MeshStandardMaterial, PlaneGeometry } from "three";

export class MyWorld extends World {
  public override init(engineWrapper, rendererCanvas, renderPipeline, renderer, onWindowResize, onPreRender, onPostRender, useWebGlFallback): void {
    super.init(engineWrapper, rendererCanvas, renderPipeline, renderer, onWindowResize, onPreRender, onPostRender, useWebGlFallback);

    const scene = this.getScene();

    // Add lights
    scene.add(new AmbientLight(0x404040, 2));
    const sun = new DirectionalLight(0xffffff, 3);
    sun.position.set(5, 10, 7);
    sun.castShadow = true;
    scene.add(sun);

    // Add a ground plane
    const ground = new Mesh(new PlaneGeometry(20, 20), new MeshStandardMaterial({ color: 0x808080 }));
    ground.rotation.x = -Math.PI / 2;
    ground.receiveShadow = true;
    scene.add(ground);

    // Add a cube actor
    const cube = new Mesh(new BoxGeometry(1, 1, 1), new MeshStandardMaterial({ color: 0xe74c3c }));
    cube.position.set(0, 0.5, 0);
    cube.castShadow = true;
    scene.add(cube);

    // Position the camera
    const camera = this.getViewportCamera();
    camera.position.set(5, 4, 7);
    camera.lookAt(0, 1, 0);
  }

  public override tick(deltaTime: number): void {
    super.tick(deltaTime);
    // Per-frame game logic goes here
  }
}

3. Create a Mode, State, and Controller

The Mode ties together a State, Controller, and default Pawn. It handles instantiation and possession automatically.

// my-mode.ts
import { GameModeBase, OrbitPawn } from "ngx-three-engine";
import { MyState } from "./my-state";
import { MyController } from "./my-controller";

export class MyMode extends GameModeBase {
  constructor() {
    super(MyState, MyController, OrbitPawn);
    this.name = "My Game Mode";
  }
}
// my-state.ts
import { GameStateBase } from "ngx-three-engine";

export class MyState extends GameStateBase {
  // Add game state (score, level, etc.)
}
// my-controller.ts
import { PlayerController } from "ngx-three-engine";

export class MyController extends PlayerController {
  // Add input mapping contexts, handle input actions
}

4. Add the engine component

// app.ts
import { Component, signal } from "@angular/core";
import { ThreejsEngineComponent } from "ngx-three-engine";
import { MyMode } from "./my-mode";
import { MyWorld } from "./my-world";

@Component({
  selector: "app-root",
  imports: [ThreejsEngineComponent],
  template: `<threejs-engine [world]="world()" />`,
})
export class App {
  protected readonly world = signal(new MyWorld(new MyMode()));
}

That's it — the engine will auto-detect your GPU, pick a graphics preset, create a WebGPU renderer (with WebGL fallback), and start rendering.

Changing the Pawn

The default OrbitPawn gives you orbit camera controls. Switch to a different pawn by passing it to your Mode:

import { GameModeBase, DefaultPawn, OrbitPawn, OrbitPawn2D } from "ngx-three-engine";

// 3D orbit camera (default)
super(MyState, MyController, OrbitPawn);

// Free-fly camera
super(MyState, MyController, DefaultPawn);

// 2D top-down orthographic camera
super(MyState, MyController, OrbitPawn2D);

Or create a custom pawn:

import { Pawn } from "ngx-three-engine";

export class MyPawn extends Pawn {
  public override awake(): void {
    this.tickComponent.activate();
    // Setup camera, mesh, etc.
  }

  public override tick(deltaTime: number): void {
    // Per-frame pawn logic
  }

  public override possessed(controller: Controller): void {
    super.possessed(controller);
    // Controller just took control of this pawn
  }
}

Enhanced Input System

Inspired by Unreal Engine 5's Enhanced Input, abstracting actions from physical keys:

import { InputAction, InputMappingContext, PlayerController, Pawn } from "ngx-three-engine";

// 1. Define actions
const IA_Jump = new InputAction("IA_Jump");                // boolean (pressed/released)
const IA_Move = new InputAction("IA_Move", "axis2d");      // { x, y } vector
const IA_Fire = new InputAction("IA_Fire");

// 2. Map actions to keys
const gameplayContext = new InputMappingContext("Gameplay");
gameplayContext
  .mapAction(IA_Jump, "Space")
  .mapAction(IA_Move, "KeyW")        // Uses KeyboardEvent.code
  .mapAction(IA_Fire, "Mouse:Left");

// 3. Bind in your controller
export class MyController extends PlayerController {
  public override possessed(pawn: Pawn): void {
    super.possessed(pawn);

    this.addMappingContext(gameplayContext);

    this.playerInput.onInputAction.subscribe(({ action, event, value }) => {
      // event: "started" | "triggered" | "completed"
      if (action === IA_Jump && event === "started") {
        // Jump!
      }
    });
  }
}

Actors & Components

Every object in your world is an Actor (extends Three.js Object3D). Attach ActorComponent instances for reusable behavior:

import { Actor, TickComponent } from "ngx-three-engine";
import { Mesh, SphereGeometry, MeshStandardMaterial } from "three";

export class EnemyActor extends Actor {
  public override awake(): void {
    this.tickComponent.activate();

    const mesh = new Mesh(new SphereGeometry(0.5), new MeshStandardMaterial({ color: 0xff0000 }));
    this.add(mesh);
  }

  public override tick(deltaTime: number): void {
    this.rotation.y += deltaTime;
  }
}

// Add to your world:
const enemy = new EnemyActor();
this.addActor(enemy);

ECS Systems

Register custom systems with priority ordering:

import { System, World } from "ngx-three-engine";

export class ScoreSystem extends System {
  constructor() {
    super(50); // priority — lower runs first (TickSystem = 0, PhysicsSystem = 100)
  }

  public override execute(deltaTime: number, world: World): void {
    // Runs every frame
  }
}

// Register in your world:
this.systemManager.registerSystem(new ScoreSystem());

Physics

Cannon-ES is integrated via PhysicsSystem. The Character pawn provides a physics-based capsule collider out of the box. Press F3 at runtime to toggle the physics debug wireframe.

Graphics Scalability

On first launch, the engine benchmarks the GPU and selects a preset:

| Preset | Anti-Aliasing | Shadows | Shadow Map | Pixel Ratio | Effects | | ------ | ------------- | ---------------- | ---------- | ----------- | ----------- | | Low | FXAA | None | 512px | 1x | — | | Mid | SMAA | PCF Soft Shadows | 2048px | 2x | GTAO | | High | TAA | VSM | 4096px | 3x | SSGI |

The selected preset is saved to localStorage and reused on subsequent visits.

API Overview

| Concept | Base Class / Service | Purpose | | -------------- | ----------------------------------- | ------------------------------------------------- | | Engine | ThreejsEngineComponent | Angular component — drop into your template | | World | World | Scene, camera, systems, actors, physics | | Actor | Actor | Base game object (extends Object3D) | | Component | ActorComponent | Reusable actor behavior | | Pawn | Pawn, OrbitPawn, DefaultPawn | Controllable actor with camera | | Controller | PlayerController, AIController | Possesses and controls a pawn | | Mode | GameModeBase | Ties together state + controller + pawn | | State | GameStateBase | Holds game state (score, level, etc.) | | Input | InputAction, InputMappingContext| Abstract/bind input | | System | System, SystemManager | ECS frame-processing systems | | Selection | ObjectSelector, SelectionComponent | Raycast picking + hover/select events | | Rendering | RendererManager, RenderStrategy | Pluggable render backends | | Scalability | GraphicsScalabilityConfigsManager | Auto GPU detection + quality presets | | Settings | SettingsService, SettingsPanelComponent | Runtime settings UI | | Injector | InjectorService | Angular DI bridge — must be initialized at startup |

License

MIT