{"id":13807372,"url":"https://github.com/demike/ngx-three","last_synced_at":"2026-01-16T19:46:26.608Z","repository":{"id":38398893,"uuid":"319639755","full_name":"demike/ngx-three","owner":"demike","description":"Use three.js with your Angular project in a declarative way. ngx-three generates Angular components for many three.js classes","archived":false,"fork":false,"pushed_at":"2025-02-26T08:52:46.000Z","size":39270,"stargazers_count":76,"open_issues_count":9,"forks_count":25,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-25T18:11:38.955Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://demike.github.io/ngx-three/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/demike.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-08T13:00:39.000Z","updated_at":"2025-03-30T22:09:04.000Z","dependencies_parsed_at":"2023-10-16T10:40:06.408Z","dependency_job_id":"fd33b396-3bfb-4b20-9349-91f8c1f654e3","html_url":"https://github.com/demike/ngx-three","commit_stats":{"total_commits":357,"total_committers":8,"mean_commits":44.625,"dds":"0.12885154061624648","last_synced_commit":"756f71fa9afce8292827a75380268d6a99016c7c"},"previous_names":[],"tags_count":73,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demike%2Fngx-three","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demike%2Fngx-three/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demike%2Fngx-three/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demike%2Fngx-three/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/demike","download_url":"https://codeload.github.com/demike/ngx-three/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254046290,"owners_count":22005569,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T01:01:24.793Z","updated_at":"2026-01-16T19:46:26.600Z","avatar_url":"https://github.com/demike.png","language":"TypeScript","funding_links":[],"categories":["Framework Interoperability"],"sub_categories":["Wrappers"],"readme":"# NgxThree [![npm version](https://badge.fury.io/js/ngx-three.svg)](https://badge.fury.io/js/ngx-three) ![Build](https://github.com/demike/ngx-three/actions/workflows/.github/workflows/ci-cd.yml/badge.svg)\n\nNgxThree wraps [three.js](https://threejs.org/) in Angular components.\nIt allows to render 3d Scenes in a declarative way. And you can leverage\nthe angular features and ecosystem your are familiar with.\n\n## What's in the box\n\nngx-three uses code generation to be able to provide as much functionality from three js.\nThis approach makes it possible to follow three.js updates with minimal effort.\n\nngx-three:\n\n- generates wrappers (\u003e 130) for three.js class categories:\n  - Object3d,\n  - Material,\n  - Geometry,\n  - Post processing passes,\n  - Controls\n  - Textures\n- Adds support for simple pointer event handling\n- Easy handling of async model loading\n- Supports Multi-View / Multi-Scene scenarios\n- enables declarative post processing\n- ...\n\nThe project is inspired by the great [react three fiber](https://github.com/pmndrs/react-three-fiber) library.\nBut in contrast to RTF angular components are generated that wrap three.js classes.\n\nCheck out some [examples](https://demike.github.io/ngx-three/)\n\n## Performance\n\nFrom a performance perspective it's important to know, that ngx-three components\ndo not produce any DOM elements.\n\nIn addition the generate classes use OnPush change detection strategy\nand the scene rendering runs outside the angular zone.\n\nThis means there is no overhead because of additional DOM elements and the impact of angular's change detection\nmechanism should be minimized.\n\n# Installation\n\n```\nnpm install ngx-three\n```\n\nIn addition to ngx-three you have to install it's peer dependencies\nAngular ([setup howto](https://angular.io/guide/setup-local)), three.js and its typings\n\n```\nnpm install three\nnpm install @types/three\n```\n\nYou can use npm to get the exact peer dependency versions for ngx-three\n\n```\nnpm info ngx-three peerDependencies\n```\n\n# Introductory Example\n\nWe are going to create a basic example showing a cube,\nwith animation and interaction.\n\n## Step 1) Basic Angular Component\n\nLets start by creating a simple component with an empty template.\n\n```typescript\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'app-example',\n  template: ` \u003c!-- Step 2 Content  --\u003e `,\n})\nexport class ExampleComponent {}\n```\n\n## Step 2) Add a Canvas\n\nAs a second step we start filling the template with\na canvas and a scene (the most basic setup).\n\n```html\n\u003cth-canvas\u003e\n  \u003cth-scene\u003e\n    \u003c!-- Step 3 Content --\u003e\n  \u003c/th-scene\u003e\n\u003c/th-canvas\u003e\n```\n\n## Step 3) Adding a Mesh ( The Box )\n\nIn this step we are adding a mesh with material and geometry.\nYou can add material and geometry to the mesh by nesting `th-*Material` and `th-*Geometry` components\ninside a `th-mesh` componet.\n\nBy means of the `args` attribute you can pass parameters\nto the constructor of the three.js basic material.\n\n```html\n\u003cth-mesh\u003e\n  \u003cth-boxGeometry\u003e\u003c/th-boxGeometry\u003e\n  \u003cth-meshBasicMaterial [args]=\"{color: 'purple'}\"\u003e \u003c/th-meshBasicMaterial\u003e\n\u003c/th-mesh\u003e\n\u003c!-- Step 4 Content --\u003e\n```\n\n## Step 4) Camera and Light\n\nNow lets bring some (ambient)light to the scene.\n\nThe perspective camera takes multiple constructor arguments.  \nThese can be passed to the camera constructor by passing an\nan array holding the arguments to `args`.\n\nThe position of the camera is set by means of the `position` attribute.\n\n```html\n\u003cth-ambientLight\u003e \u003c/th-ambientLight\u003e\n\u003cth-perspectiveCamera [args]=\"[75, 2, 0.1, 1000]\" [position]=\"[1,1,5]\"\u003e\n\u003c/th-perspectiveCamera\u003e\n```\n\n## Step 5) Interacting with the box\n\nBy adding a boolean member `selected` to our class\nwe can modify the scale of the cube\n\n```html\n\u003cth-mesh\u003e\n  (onClick)=\"selected = !selected\" [scale]=\"selected ? [2, 2, 2] : [1, 1, 1]\"\n  ...\n\u003c/th-mesh\u003e\n```\n\n## Step 6) Animating the box\n\nBy reacting to the canvas' `onRender`\nwe can animate the box by setting its rotation.\n\nTemplate:\n\n```html\n\u003cth-canvas (onRender)=\"this.onBeforeRender()\"\u003e\n  ...\n  \u003cth-mesh [rotation]=\"rotation\" ...\u003e ... \u003c/th-mesh\u003e\n  ...\n\u003c/th-canvas\u003e\n```\n\nComponent:\n\n```typescript\n  ...\n  public rotation: [x: number, y: number, z: number] = [0, 0, 0];\n  public onBeforeRender() {\n    this.rotation = [0, this.rotation[2] + 0.01, this.rotation[2] + 0.01];\n  }\n  ...\n```\n\n## Step 7) Creating a reusable Angular component\n\nThe mesh part of the current code can be seperated into its own class\nThen we can use two instances ot the box component in the app component\nTake a look at the [working example](https://demike.github.io/ngx-three/introductory-example)\n\nBox Template:\n\n```html\n\u003cth-mesh\n  [rotation]=\"rotation\"\n  [position]=\"position\"\n  (onClick)=\"selected = !selected\"\n  [scale]=\"selected ? [2, 2, 2] : [1, 1, 1]\"\n\u003e\n  \u003cth-boxGeometry\u003e\u003c/th-boxGeometry\u003e\n  \u003cth-meshBasicMaterial [args]=\"{color: 'purple'}\"\u003e\u003c/th-meshBasicMaterial\u003e\n\u003c/th-mesh\u003e\n```\n\nBox Component:\n\n```typescript\n@Component({\n  selector: 'app-box',\n  template: `...`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Box {\n  selected = false;\n  @Input()\n  public rotation: [x: number, y: number, z: number] = [0, 0, 0];\n  @Input()\n  public position: [x: number, y: number, z: number] = [0, 0, 0];\n}\n```\n\nApp Template:\n\n```html\n\u003cth-canvas (onRender)=\"this.onBeforeRender()\"\u003e\n  \u003cth-scene\u003e\n    \u003cth-box [position]=\"[-2,0,0]\" [rotation]=\"rotation\"\u003e \u003c/th-box\u003e\n    \u003cth-box [position]=\"[2,0,0]\" [rotation]=\"rotation\"\u003e \u003c/th-box\u003e\n    \u003cth-ambientLight\u003e \u003c/th-ambientLight\u003e\n    \u003cth-perspectiveCamera\n      [args]=\"[75, 2, 0.1, 1000]\"\n      [position]=\"[1,1,5]\"\n    \u003e\u003c/th-perspectiveCamera\u003e\n  \u003c/th-scene\u003e\n\u003c/th-canvas\u003e\n```\n\nApp Component:\n\n```typescript\n@Component({\n  selector: 'app-example',\n  template: `...`\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ExampleComponent {\n  public rotation: [x: number, y: number, z: number] = [0, 0, 0];\n  public onBeforeRender() {\n    this.rotation = [0, this.rotation[2] + 0.01, this.rotation[2] + 0.01];\n  }\n}\n```\n\n# Canvas / View / Scene / Renderers\n\nCanvas View and Scene are the main building blocks of ngx-three.\n\n## ThCanvas\n\nIn general the `ThCanvas` contains [ThView](#ThView) istances, and a\n[ThView](#ThView) contains a [ThScene](#ThScene).\n\nIn a standard scenario `ThCanvas` provides (or actually 'is') the default view.\nSo a typical template might look like this\n\n```html\n\u003cth-canvas\u003e\n  \u003cth-scene\u003e ... \u003c/th-scene\u003e\n\u003c/th-canvas\u003e\n```\n\n`ThCanvas` creates the canvas dom element that's used\nfor rendering. Actually ThCanvas is the \u003cb\u003eonly\u003c/b\u003e ngx-three component that inserts an element into dom!\n\n`ThCanvas` provides the [ThEngineService](#Render-Loop-/-ThEngineService).\nThat means if you have multiple `ThCanvas` instances\nevery one gets its own engine service.\n\nAs `ThCanvas` is derived from `ThView` it also shares its inputs / outputs\n\nIn addition `ThCanvas` also provides an input `rendererParameters`. It takes a configuration object\nthat allows for setting all the members provided by the\n[THREE.WebGLRenderer](https://threejs.org/docs/#api/en/renderers/WebGLRenderer).\n\n## ThView\n\nOne can say that `ThView` provides the view port.\nThe view consists of:\n\n- a scene [ThScene](#ThScene)\n- a camera (`ThCamera`)\n- and an \u003cb\u003eoptional\u003c/b\u003e effect composer (`ThEffectComposer`)\n\nThis combination makes it possible to render multiple scenarios\n\n- The same scene with multiple camera perspectives ([Multi View Example](https://demike.github.io/ngx-three/views-example))\n  \u003cimg src=\"./docs/multi-view.png\" width=\"50%\" style=\"display:block\"/\u003e\n- mutliple scenes with the same camera ([Multi Scene Example](https://demike.github.io/ngx-three/multi-scene-example))\n  \u003cimg src=\"./docs/multi-scene.png\" width=\"50%\" style=\"display:block\"/\u003e\n- one / multiple scene with multiple effects ([Multi Effects Example](https://demike.github.io/ngx-three/multi-view-postprocessing-example))\n  \u003cimg src=\"./docs/multi-view-postprocessing.png\" width=\"50%\" style=\"display:block\"\u003e\n\n## ThScene\n\n`ThScene` is the ngx-three wrapper of THREE.Scene and provides all\nof its members as inputs. It is \u003cb\u003emandatory\u003c/b\u003e for rendering.\n\n## Renderers\n\nngx-thre supports different renderers provided by three.js:\n- WebGLRenderer\n- CSS3DRenderer\n- CSS2DRenderer\n\nAnd they can be combined too!\n\nYou can configure them in two different ways\n- by providing them with the helper functions `provideWebGLRenderer`, `provideCSS2dRenderer` and `provideCSS3dRenderer`:\n  ```ts\n    @Component({\n    selector: 'app-example',\n    providers: [provideCSS3dRenderer({...})],\n    ...\n  })\n  ```\n  or `provideWebGLRenderer({...})` or `provideCSS2dRenderer({...})` \n\n- or by means of structural directives:\n  ```html\n  \u003cth-canvas \n      *rendererParameters=\"{ ...WebGLRendererOptions... }\"\u003e\n  ... \n  \u003c/th-canvas\u003e\n  ```\n  or `*css2dRendererParameters]=\"{...}\"`, `*css3dRendererParameters]=\"{...}\"`\n\nIf you do not provide any renderer the WebGLRenderer is used as the default renderer with its default configuration.\n\nExamples:\n- [CSS3DRenderer Example](https://demike.github.io/ngx-three/css3d-renderer-example)\n- [Multi Renderer Example](https://demike.github.io/ngx-three/multi-renderer-example)\n- [Html with CSS3D Renderer Example](https://demike.github.io/ngx-three/html-with-css3d-example)\n\n\n\n## ThAnimationLoop / ThEngineService / ThRenderDirective\n\n### Render Loop\nThe `ThAnimationLoop` service runs the render loop.\nYou can `start` and `stop` the loop.\nIn addition you can request a 'one-shot` rendering\nby calling the Service-method `requestAnimationFrame`;\n\nYou can react to a 'global' render event by means of listening to the \n`ThAnimationLoop.beforeRender$` observable\nor by using the `beforeRender` output of the `ThRenderDirective`.\n\n```html\n\u003cth-object3D (beforeRender)=\"doSomething()\" \u003e\u003c/th-object3D\u003e\n```\n\nIn addition you can react to the `onRender`\noutputs of the `ThView` (`ThCanvas` is derived from it) instances.\n\n```html\n\u003cth-canvas (onRender)=\"doSomething()\"\u003e\u003c/th-canvas\u003e\n```\n\n### Resize-Handling \u0026 Device Pixel Ratio\n\nFor common scenarios ngx-three handles resizing automatically by observing the\nsize of the canvas.\n\nBut for special scenarios ([Multi View Example](https://demike.github.io/ngx-three/views-example)) you might have to do calculations when the size changes.\nThis can be achieved by:\n- using the `onResize` event of the `ThRenderDirective`.\n```html\n\u003cth-object3D (onResize)=calculateSomething($event)\u003e\u003c/th-object3D\u003e\n```\n- or by subscribing to the `resize$` of the `ThEngineService`\n\nThe `ThEngineService` takes care of resizing, does the rendering and organizes the available views ([ThView](#ThView))\n\n\u003e Note: The engine service **automatically** takes into account the device pixel ratio when calculating the renderer dimensions. This works dynamically i.e.: when moving the window from one display to a second one with different device pixel ratio.\n\n### On-Demand Rendering\n\nIn case you do not need an animation (i.e.: static model viewer)\nyou can disable the animation loop by setting `renderOnDemand` to true.\nFrom this time on the render calls only happen in following cases:\n- Angular change detection is triggered for one of `ThCanvas`' children \n- A controller fires an event\n\nThis works with `OrbitControls`, `MapControls`, `DragControls`, `TransformControls` and `ArcBallControls`.\nBut `FlyControls`, `TrackbalControls` and `FirstPersonControls` need a render loop.\nYou can play with these controls and on-demand rendering in the [On-Demand Example](https://demike.github.io/ngx-three/on-demand-example).\n\nExample:\n\nThis allows to render only once to show a scene (i.e.: resulting from a loaded GLB file). \nAnd while you move the camera by means of the orbit control continuous render calls will be triggered. When you stop moving no render calls will happen.\n\nLet's say you change the background color that is bound in a template.\nIn this case the angular changed detection mechanism triggers and the\nscene is rendered (once).\n\n```html\n\u003cth-canvas [renderOnDemand]=\"doOnDemandRendering\"\u003e\u003c/th-canvas\u003e\n```\n\n# Objects / Meshes\n\nIn three.js anything that can be added to a Scene is an `Object3D`.\nIn ngx-three the component `ThObject3D` with the tag `th-object3D` can be seen as the equivalent.\n\nA mesh (`Three.Mesh`) can be represented by `th-mesh` in ngx-three.\nA mesh can have a material (`ThMaterial`) and a Geometry(`ThGeometry`).\n\n```html\n\u003cth-mesh\u003e\n  \u003cth-boxGeometry\u003e\u003c/th-boxGeometry\u003e\n  \u003cth-meshBasicMaterial\u003e\u003c/th-meshBasicMaterial\u003e\n\u003c/th-mesh\u003e\n```\n\nEvery ngx-three object has a member called\n`objRef` this one holds the reference to the\nthree.js object.\nFor example `ThMesh` has a member `objRef: THREE.Mesh`.\n\n\u003c!-- TODO: GO ON --\u003e\n\n## Referencing objects in a component\n\nThere are two ways to reference existing ngx-three object\nclass instances.\n\n### 1) ViewChild\n\nYou can use ViewChild to reference template objects\nfrom within the component code.\n\n```typescript\n@Component({\n  selector: 'app-myapp',\n  template: ` \u003cth-mesh\u003e\u003c/th-mesh\u003e `,\n})\nexport class MyApp {\n  @ViewChild(ThMesh, { static: true }) mesh: ThMesh;\n}\n```\n\n### 2) Angular Template Variables\n\nReferencing ngx-three objects (`th-object3D`) can be\neasiliy referenced from within the template by means\nof template variables\n\n```html\n\u003cth-mesh\u003e\n  \u003cth-boxGeometry #theGeo\u003e\u003c/th-boxGeometry\u003e\n\u003c/th-mesh\u003e\n\u003cth-mesh\u003e\n  \u003cth-material [objRef]=\"theGeo.objRef\"\u003e\u003c/th-material\u003e\n  \u003cth-meshBasicMaterial\u003e\u003c/th-meshBasicMaterial\u003e\n\u003c/th-mesh\u003e\n```\n\n## How to put existing THREE.Object3D objects into the angular template\n\nIf you want to put an existing object into the angular component tree\n(maybe it was easier to construct the specific object in an imperative way)\nthis can be easily achieved by setting the `objRef` Attribute\n\n```\n\u003cth-object3D [objRef]=\"existingObj\"\u003e\u003c/th-object3D\u003e\n```\n\n# Model Loading\n\nngx-three provides an easy way to load models / scenes and apply it\nto a `th-object3D` element.\nIt implements a generic loader service, loader directive and loader pipe,\nThat is then used by the specific loader implementations\n\nAll types of loaders can load models by means of:\n\n- a loader service\n  - provides a Promise of the resulting 'model'\n  - a progress callback\n- a directive\n  - applies the model to the host `ThObject3d` component ( to its `objRef`)\n  - provides a progress output\n  - provides a loaded output\n- a pipe\n  - provides a progress callback\n\nunder the hood the directive and the pipe use the service\nOne example is the GLTF-Loader\n\n## GLTF Loader\n\nLoading GLTF / GLB files can be achieved\nby using the `loadGLTF` directive:\n\n```html\n\u003cth-object3D loadGLTF url=\"assets/helmet.glb\"\u003e \u003c/th-object3D\u003e\n```\n\nthe `loadGLTF` pipe:\n\n```html\n\u003cth-object3D [objRef]=\"('assets/helmet.glb' | loadGLTF | async).scene\"\u003e \u003c/th-object3D\u003e\n```\n\nor by using the GLTFLoaderService directly:\n\n```ts\n...\nconstructor(private service: GLTFLoaderService) {\n}\n\nasync ngOnInit() {\n  const result: GLTF = await service.load('assets/helmet.glb');\n}\n```\n\nthe `load` method of the service uses the three.js Loader.loadAsync method under the hood\nand also provides the same parameters\n\n```ts\nload(url: string, onProgress?: (event: ProgressEvent) =\u003e void): Promise\u003cany\u003e;\n```\n\nYou can find an example [here](https://demike.github.io/ngx-three/loader-example)\n\n### DRACO Compression\n\nTo load draco compressed gltf files you have to specify the path to a folder containing the WASM/JS decoding libraries.\nAll you have to do is to inject the `DRACOLoaderService` and set the decoder path.\n\n```ts\nconstructor(dracoLoader: DRACOLoaderService) {\n    // specify the draco decoder path used by the gltf loader instances\n    dracoLoader.setDecoderPath('https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/jsm/libs/draco/gltf/');\n}\n```\n\nYou may have to specify a different crossOrigin string to implement CORS\ni.e.: \n```ts\ndracoLoader.setCrossOrigin('no-cors'); // just for testing (default: \"anonymous\")\n```\n\nBy default, a single DRACOLoader is reused when loading consecutive models.\nTo change this behaviour, explicitly disable it:\n```ts\ndracoLoader.setReuseInstance(false); // (default: true)\n```\n\nYou can find an example [here](https://demike.github.io/ngx-three/ref-by-id-example)\n\n### Meshopt Decoder\nTo load meshopt encoded gltf files you have to provide the meshopt decoder:\n\n```ts \nimport { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';\n\nproviders: [\n  ...\n  provideMeshoptDecoder(MeshoptDecoder),\n  ...\n],\n```\n\n\n## Creating your own Loader\n\nIn addition to the pre-defined loaders it is actually quite simple to add additional\nloader Service / Directive / Pipe.\n\nThe below example shows how to implement simple 'obj' loading\n\nCreating the service is as simple as deriving from `ThAsyncLoaderService\u003cOBJLoader\u003e`\nand setting the `clazz` member to the Loader class provided by three.js.\n\n```ts\n@Injectable({\n  providedIn: 'root',\n})\nexport class OBJLoaderService extends ThAsyncLoaderService\u003cOBJLoader\u003e {\n  public readonly clazz = OBJLoader;\n}\n```\n\nCreating your own loader pipe is equaly simple. You just have to derive from\n`ThAsyncLoaderBasePipe\u003cOBJLoader\u003e` and inject the previously defined service.\n\n```ts\n@Pipe({\n  name: 'loadObj',\n  pure: true,\n})\nexport class ThObjLoaderPipe\n  extends ThAsyncLoaderBasePipe\u003cOBJLoader\u003e\n  implements PipeTransform\n{\n  constructor(protected service: OBJLoaderService) {\n    super();\n  }\n}\n```\n\nThe directive can be implemented as follows:\n\n```ts\n@Directive({\n  selector: '[loadObj]',\n})\nexport class ThObjLoaderDirective extends ThAsyncLoaderBaseDirective\u003cOBJLoader\u003e {\n  service = inject(OBJLoaderService);\n\n  protected getRefFromResponse(response: Group) {\n    return response;\n  }\n}\n```\n\n- you have to inject the previously implemented service\n- and implement the method `getRefFromResponse`.\n  The value returned by this method is applied to the host ThObject3D's `objRef` member.\n\n## FBXLoader\n\nThe FBXLoader can be used like the GLTF loader\nby using the `loadFBX` directive:\n\n```html\n\u003cth-object3D loadFBX url=\"assets/model.fbx\"\u003e \u003c/th-object3D\u003e\n```\n\nthe `loadFBX` pipe:\n\n```html\n\u003cth-object3D [objRef]=\"'assets/model.fbx' | loadFBX\"\u003e \u003c/th-object3D\u003e\n```\n\nor by using the FBXLoaderService directly.\n\n## PLYLoader\n\nThe PLYLoader is a little bit different than the previous Loaders (i.e.: GLTFLoader).\nBecause the PLYLoader only provides/loads geometry and no material.\nIn contrast the GLTFLoader loads a full scene.\n\nYou can use the PLYLoader directive:\n\n```html\n\u003cth-mesh\u003e\n  \u003c!-- PLY file ( only provides geometry! ) --\u003e\n  \u003cth-bufferGeometry loadPLY [url]=\"assets/dolphins.ply\"\u003e \u003c/th-bufferGeometry\u003e\n  \u003cth-meshStandardMaterial\n    [args]=\"{ color: '#0055ff' }\"\n  \u003e\u003c/th-meshStandardMaterial\u003e\n\u003c/th-mesh\u003e\n```\n\nor the pipe\n\n```html\n\u003cth-mesh\u003e\n  \u003c!-- PLY file ( only provides geometry! ) --\u003e\n  \u003cth-bufferGeometry [objRef]=\"'assets/dolphins.ply' | loadPLY\"\u003e\n  \u003c/th-bufferGeometry\u003e\n  \u003cth-meshStandardMaterial\n    [args]=\"{ color: '#0055ff' }\"\n  \u003e\u003c/th-meshStandardMaterial\u003e\n\u003c/th-mesh\u003e\n```\n\nor you can use the PLYLoader service directly.\n\nYou can find an example [here](https://demike.github.io/ngx-three/plyloader-example)\n\n## Caching Models\n\nto enable loader caching you can use three.js' built in [cache](https://threejs.org/docs/#api/en/loaders/Cache):\n\n```typescript\nTHREE.Cache.enabled = true;\n```\n\n# Texture Loading\n\nngx-three generates wrappers for\n\n- CanvasTexture\n- CompressedTexture\n- CubeTexture\n- DataTexture\n- DataTexture2DArray\n- DataTexture3D\n- DepthTexture\n- Texture\n- VideoTexture\n- FramebufferTexture\n\nall those wrappers can be placed in an angular template\n\n```html\n\u003cth-Texture #myTexture\u003e\u003c/th-Texture\u003e\n```\n\nand you can reuse it in the template by means of a template reference (i.e.: `myTexture`);\n\nTo load a Texture you have 3 possibilities (service, pipe, directive)\n\n- place a loader directive on a wrapper component\n  ```html\n  \u003cth-Texture loadTexture url=\"thetexture.jpg\"\u003e\u003c/th-Texture\u003e\n  ```\n- use the loader pipe\n  ```html\n  \u003cth-MeshBasicMaterial [map]='\"thetexture.jpg\" | loadTexture'\u003e\n  \u003c/th-MeshBasicMaterial\u003e\n  ```\n- use the injected service\n\n  ```ts\n  ...\n  constructor(service: TextureLoaderService) {\n    const texture = service.load('thetexture.jpg')\n  }\n  ```\n\n  the loaders provide event emitters / callbacks for 'loaded' and 'progress'\n\n  Following texture loaders are available:\n\n  - TextureLoaderService, ThTextureLoaderDirective, ThTextureLoaderPipe\n  - CubeTextureLoaderService, ThCubeTextureLoaderDirective, ThCubeTextureLoaderPipe,\n  - Data Texture Loaders\n    - ThDDSLoaderDirective, ThDDSLoaderPipe, DDSLoaderService\n    - ThKTXLoaderDirective, ThKTXLoaderPipe, KTXLoaderService\n    - ThKTX2LoaderDirective, ThKTX2LoaderPipe, ThKTX2LoaderService\n    - ThPVRLoaderDirective, ThPVRLoaderPipe, PVRLoaderService\n  - Compressed Texture Loaders\n    - ThEXRLoaderDirective, ThEXRLoaderPipe, EXRLoaderService\n    - ThRGBELoaderDirective, ThRGBELoaderPipe, RGBELoaderService\n    - ThRGBMLoaderDirective, ThRGBMLoaderPipe, RGBMLoaderService\n    - ThTGALoaderDirective, ThTGALoaderPipe, TGALoaderService\n\n  the pipe and directive names follow a naming scheme\n  `load*Texture` where `*` can be `''`, `Cube`, `DDS`, `EXR` ...\n\n# Event Handling\n\n## Mouse / Pointer Events\n\nngx-three supports the following mouse/pointer events:\n\n- onClick\n- onMouseEnter\n- onMouseExit\n- onPointerDown\n- onPointerUp\n\nAll of them return a [RaycasterEmitEvent](./projects/ngx-three/src/lib/events/raycaster.events.directive.ts#L7)\nthat holds the target component and the intersection data of [raycaster.intersectObject](https://threejs.org/docs/#api/en/core/Raycaster.intersectObject) (except for `onMouseExit`)\n\n## Object 3D Events\n\nEvery `th-object3D` element emits property changes.\nyou can listen to it like this:\n\n```\n\u003cth-object3D (onUpdate)=\"doSomething($event)\u003e\u003c/th-object3D\u003e\n```\n\n[Events Example](https://demike.github.io/ngx-three/events-example)\n\n## three.js Events\n\nEvery wrapper can be used to bind to three js events\nwithin an Angular template.\nFor this purpose you can pass an object ( key = event name, value = callback) to the `threeEvents` input.\nYou have to make shure that context of the callback functions get preserved.\nThis can be done \n- by means of using the [bind pipe](#bind-pipe)\n- or by using fat arrow function members instead of methods (see example below)\n\ncomponent:\n```ts\n\n@Component({\n  // ...\n})\nexport class TestComponent {\n  public onOrbitControlChange(evt: Event) {\n      // ...\n  }\n  public onOrbitControlEnd = (evt: Event) =\u003e {  // \u003c-- preserves this context when used in template\n    // ...\n  }\n}\n\n```\ntemplate:\n```html\n     \u003c!-- \n      binding to three.js events:\n        1) change: with bind directive for preserving this scope\n        2) end: using a fat arrow member function for preserving this scope\n      --\u003e\n      \u003cth-orbitControls\n        [threeEvents]=\"{\n          'change': onOrbitControlChange | bind : this,\n          'end': onOrbitControlEnd\n        }\"\u003e\u003c/th-orbitControls\u003e\n    \n    \u003c/th-perspectiveCamera\u003e\n```\n\n\n\n# Utilitiy Pipes / Directives\n\nngx-three provides some utility pipes that ease input assignments\n\n## ThRenderDirective\n\nThis directive can be used to react to 'global' rendering loop events.\n\nListen to the `beforeRender` output to to apply changes\nbefore the next rendering run happens.\n\nIf you want to do something directly after the rendering pass use `afterRender`.\n\n## color pipe\n\nUse this pipe to create a Color from any of it's constructor parameters\n\n```html\n\u003cth-ambientLight [color]=\"'#aabbcc' | color\"\u003e \u003c/th-ambientLight\u003e ...\n```\n\n## vector pipes\n\nthe `vector2`, `vector3`, and `vector4` construct the respective vector from an array of numbers\nusage:\n\n```html\n\u003cth-object3D [position]=\"[1,2,3] | vector3\"\u003e \u003c/th-object3D\u003e\n```\n\n## clone pipe\n\ncalls clone on a clonable three.js instance (or it's ngx-three wrapper)\nand ensures that the clone call only happens once\n\n```html\n\u003cth-hemisphereLight #light ...\u003e\u003c/th-hemisphereLight\u003e\n\n\u003cth-light [objRef]=\"light | clone\"\u003e\u003c/th-light\u003e\n```\n\n## bind pipe\n\nbinds a function to an object by means of [Function.prototype.bind()](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)\n\n\n```html\n\u003cth-orbitControls [threeEvents]=\"{ end: onOrbitEnd | bind: this }\"\u003e\u003c/th-orbitControls\u003e\n```\n\n## plane pipe\n\ncreates a three.js [plane](https://threejs.org/docs/#api/en/math/Plane) instance from an array of numbers `[x,y,z]` ( = normal vector ) and an optional \nargument ( = constant: the signed distance from the origin to the plane ).\n\n```html\n\u003cth-planeHelper [args]=\"[[0,1,0] | plane: 2\"\u003e\u003c/th-planeHelper\u003e\n```\n\n## ref-by-id directive\n\nA utility directive that helps you selecting\na specific node of a model.\n\n```html\n\n\u003cth-object3d [loadGltf]=\"head.glb\"\u003e\n  \u003cth-mesh refById=\"left-eye\" \u003e\n    \u003cth-meshBasicMaterial [args]=\"{color: 'purple'}\"\u003e\u003c/th-meshBasicMaterial\u003e\n  \u003c/th-mesh\u003e\n\u003c/th-object3d\u003e\n\n```\n\nYou can find an example [here](https://demike.github.io/ngx-three/ref-by-id-example)\n\n## Stats Directive\n\nIf you want to display the well known stats panel\n\u003cimg src=\"./docs/stats-panel.png\" style=\"vertical-align:middle\"/\u003e\nyou can do that simply by adding the `thStats` directive\nto the canvas.\n\n```html\n\u003cth-canvas [thStats]=\"true\"\u003e ... \u003c/th-canvas\u003e\n```\n\n# Debugging\nWith ngx-three you can leverage the full potential of [Angular DevTools](https://angular.io/guide/devtools)\nwithout sacrificing performance.\n\nIn dev-mode (`ng serve`) ngx-three can be debugged with the DevTools:\n\u003cimg src='./docs/angular-dev-tools.png'/\u003e\nby inserting the Angular components into the dom:\n\u003cimg src='./docs/dev-mode-dom.png'/\u003e\n\nAnd in production mode / build not a single additional dom node is inserted for the wrapped three.js objects:\n\u003cimg src='./docs/prod-mode-dom.png'/\u003e\n\nIF you create your own components intended to be rendered inside of the three.js node tree don't forget to insert a `\u003cng-content /\u003e` inside of your template.\nThen you can see child nodes attached to your component in debug mode!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdemike%2Fngx-three","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdemike%2Fngx-three","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdemike%2Fngx-three/lists"}