
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
triangular-engine
Advanced tools
Angular-first 3D engine powered by Three.js and optional physics engines (Rapier or Jolt). Declarative components for scenes, meshes, materials, lights, GLTF, post-processing, and physics.
Angular-first 3D engine powered by Three.js and Rapier. Build interactive 3D scenes using ergonomic standalone Angular components for scenes, cameras, meshes, lights, materials, GLTF loading, physics, and more.
This README contains the full documentation needed to use the library on npm. No external links are required.
See CHANGELOG.md for release history.
| Dependency | Version | Notes |
|---|---|---|
| Angular | ^20.3.3 | Required - Angular 20.3.3 or higher |
| Three.js | ^0.183.0 | Required |
| Dexie | ^4.2.1 | Required |
| Rapier 3D | ^0.18.0 | Optional - for physics support |
| Jolt Physics | ^0.38.0 | Optional - alternative physics engine |
scene, camera, mesh, materials, lights, gltf, physics, css2d/css3d, post-processing, and moreposition, rotation, scale, and common optionsnpm i triangular-engine three three-mesh-bvh
(optionally add @dimforge/rapier3d-compat OR jolt-physics for physics)
These are expected to be provided by your app (see package.json for exact versions):
{
"@angular/common": "^20.3.3",
"@angular/core": "^20.3.3",
"three": "^0.183.0",
"dexie": "^4.2.1"
}
Optional peer dependencies:
{
"@dimforge/rapier3d-compat": "^0.18.0",
OR
"jolt-physics": "^0.38.0"
}
Provide the engine per component/page that hosts a <scene> using the recommended helper:
EngineService.provide(...). Then render a minimal scene.
import { Component } from "@angular/core";
import { EngineModule, EngineService } from "triangular-engine";
@Component({
selector: "app-demo",
standalone: true,
imports: [EngineModule],
template: `
<scene>
<camera [position]="[4, 3, 6]" [lookAt]="[0, 0, 0]" />
<directionalLight [position]="[3, 5, 2]" />
<mesh>
<boxGeometry [params]="[2, 2, 2]" />
<meshStandardMaterial />
</mesh>
</scene>
`,
providers: EngineService.provide({ showFPS: true }),
})
export class DemoComponent {}
If you load DRACO-compressed GLTF assets, add the decoder to your angular.json assets:
{
"glob": "**/*",
"input": "node_modules/three/examples/jsm/libs/draco/",
"output": "draco/"
}
Ensure you have the following in your angular.json assets:
{
"glob": "**/*",
"input": "node_modules/triangular-engine/assets",
"output": "triangular-engine"
}
All components are standalone and can be nested inside <scene>.
scene: hosts the renderer canvas, handles resize, and drives the render loopgroup, mesh, points, sprite, gridHelper, arrowHelpereffect-composer, unrealBloomPass, glitchPass, outputPass, smaaPass, shaderPassboxGeometry, sphereGeometry, planeGeometry, bufferGeometry, capsuleGeometry, bufferAttributemeshStandardMaterial, meshNormalMaterial, meshBasicMaterial, shaderMaterial, rawShaderMaterial, pointsMaterial, spriteMaterialambientLight, directionalLight, pointLightcamera, orbitControlsgltfcss2d, css3dphysics, rigidBody, collider family, fixedJoint, sphericalJoint, instancedRigidBodyskyBox, ocean, performanceMonitor, sceneTree, engine-ui, engine-stats, [engineSlot], [raycast]Example mesh:
<mesh [position]="[0,1,0]" [castShadow]="true">
<boxGeometry [params]="[1,1,1]" />
<meshStandardMaterial [params]="{ color: '#88c' }" />
<!-- or <meshStandardMaterial [map]="'assets/textures/wood.jpg'" /> -->
<!-- or <meshNormalMaterial /> -->
<!-- or <shaderMaterial /> -->
<!-- or <rawShaderMaterial /> -->
<!-- or <pointsMaterial /> -->
<!-- or <spriteMaterial /> -->
</mesh>
<gltf [gltfPath]="'assets/models/thing.glb'" [enableBVH]="true" />
enableBVH: builds per-mesh BVH using three-mesh-bvh (if installed) for faster raycastscachePath: custom key for the in-memory GLTF cacheWrap physics-enabled content in <physics>:
<physics [gravity]="[0,-9.81,0]" [debug]="false">
<rigidBody [rigidBodyType]="1">
<cuboidCollider [halfExtents]="[50, 0.5, 50]" />
<mesh [position]="[0, -0.5, 0]">
<boxGeometry [params]="[100, 1, 100]" />
<meshStandardMaterial [params]="{ color: '#666' }" />
</mesh>
</rigidBody>
<rigidBody [rigidBodyType]="0" [position]="[0, 4, 0]">
<ballCollider [radius]="0.5" />
<mesh>
<sphereGeometry [params]="{ radius: 0.5, widthSegments: 32, heightSegments: 16 }" />
<meshNormalMaterial />
</mesh>
</rigidBody>
</physics>
Rigid body types: 0 Dynamic, 1 Fixed, 2 KinematicPositionBased, 3 KinematicVelocityBased.
Provide per component where you host <scene>:
providers: EngineService.provide({ showFPS: true });
scene, renderer, tick$, elapsedTime$, setFPSLimit, input streams (keydown$, mousemove$, mousewheel$, etc.), camera$, switchCamera(camera), requestSingleRender()World, beforeStep$, stepped$, setSimulatePhysics(), setDebugState()loadAndCacheGltf(path, cachePath?, force?), loadAndCacheTexture(path); sets Draco path to /draco/; builds userData.objectMap for GLTF lookupList of selectors available in templates (not exhaustive):
scene, group, mesh, points, sprite, primitive, gridHelper, arrowHelpereffect-composer, unrealBloomPass, glitchPass, outputPass, smaaPass, shaderPasscamera, orbitControlsbufferGeometry, bufferAttribute, boxGeometry, sphereGeometry, planeGeometry, capsuleGeometrymaterial, meshStandardMaterial, meshNormalMaterial, meshBasicMaterial, shaderMaterial, rawShaderMaterial, pointsMaterial, spriteMateriallight, ambientLight, directionalLight, pointLightgltfcss2d, css3dphysics, rigidBody, collider family, cuboidCollider, ballCollider, capsuleCollider, cylinderCollider, coneCollider, fixedJoint, sphericalJoint, instancedRigidBodyskyBox, ocean, performanceMonitor, sceneTree, engine-ui, engine-stats, [engineSlot], [raycast]Textures: pass a map to meshStandardMaterial to auto-load a texture path
<meshStandardMaterial [map]="'assets/textures/wood.jpg'" />
Direct loaders/exporters: access via LoaderService if you need BufferGeometryLoader, ObjectLoader, SVGLoader, STLLoader, FBXLoader, GLTFExporter
Error: NullInjectorError: No provider for _EngineService
Fix: Provide EngineService.provide(...) in every component that hosts a <scene>.
If serving both triangular-engine and your app locally, link the package:
# in this repo
npm run link
# in your app
npm link triangular-engine
Important: Set "preserveSymlinks": true in your app's angular.json build options to avoid runtime injection errors (such as _HighContrastModeDetector token injection failures). Also add the following to your tsconfig.json:
{
"compilerOptions": {
"paths": {
"triangular-engine": ["node_modules/triangular-engine"]
}
}
}
import { Component } from "@angular/core";
import { EngineModule, EngineService } from "triangular-engine";
@Component({
selector: "app-basic",
standalone: true,
imports: [EngineModule],
template: `
<scene>
<camera [position]="[4, 3, 6]" [lookAt]="[0, 0, 0]" />
<directionalLight [position]="[3, 5, 2]" />
<physics [gravity]="[0, -9.81, 0]" [debug]="false">
<rigidBody [rigidBodyType]="1">
<cuboidCollider [halfExtents]="[50, 0.5, 50]" />
<mesh [position]="[0, -0.5, 0]">
<boxGeometry [params]="[100, 1, 100]" />
<meshStandardMaterial [params]="{ color: '#666' }" />
</mesh>
</rigidBody>
<rigidBody [rigidBodyType]="0" [position]="[0, 4, 0]">
<ballCollider [radius]="0.5" />
<mesh>
<sphereGeometry [params]="{ radius: 0.5, widthSegments: 32, heightSegments: 16 }" />
<meshNormalMaterial />
</mesh>
</rigidBody>
</physics>
</scene>
`,
providers: EngineService.provide({ showFPS: true }),
})
export class BasicComponent {}
npm loginprojects/triangular-engine/package.json if needednpm run publishThe publish script builds with development configuration (required for npm) and publishes from dist/triangular-engine. For local development with jolt-physics, the workspace uses a local file override in its devDependencies; the published package lists jolt-physics as an optional ^0.38.0 peer dependency.
If anything is missing from this README, please open an issue or PR. This file is designed to render correctly on npm without relying on external docs.
FAQs
Angular-first 3D engine powered by Three.js and optional physics engines (Rapier or Jolt). Declarative components for scenes, meshes, materials, lights, GLTF, post-processing, and physics.
We found that triangular-engine demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.