Introduction
angular-three-ecctrl is an Angular Three port of the default pmndrs/ecctrl core entry: a Rapier-backed dynamic capsule controller for characters.
Peer Dependencies
Section titled “Peer Dependencies”No additional peer dependencies required beyond the core dependencies.
Installation
Section titled “Installation”npm install angular-three-ecctrl angular-three-rapier @dimforge/rapier3d-compat# yarn add angular-three-ecctrl angular-three-rapier @dimforge/rapier3d-compat# pnpm add angular-three-ecctrl angular-three-rapier @dimforge/rapier3d-compatMake sure you already have
angular-threeinstalled.
angular-three-soba is an optional peer only for the /camera integration.
Basic Setup
Section titled “Basic Setup”NgteEcctrl is the ngte-ecctrl component and is exported as ecctrl. It creates a dynamic rigid body and capsule collider, and must be nested under NgtrPhysics. Project the character’s visual content into the controller:
import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';import { extend } from 'angular-three';import { NgteEcctrl, type NgteEcctrlMovementInput } from 'angular-three-ecctrl';import { NgteEcctrlAnimationState, type NgteEcctrlAnimationStateValue } from 'angular-three-ecctrl/animation';import { NgtrPhysics } from 'angular-three-rapier';import * as THREE from 'three';
extend(THREE);
@Component({ template: ` <ngtr-physics> <ng-template> <ngte-ecctrl #player="ecctrl" [movement]="movement()" [animationState]="true" (animationStateChange)="onAnimationStateChange($event)" > <ngt-mesh> <!-- Project the character's visual mesh or model here. --> </ngt-mesh> </ngte-ecctrl> </ng-template> </ngtr-physics> `, imports: [NgtrPhysics, NgteEcctrl, NgteEcctrlAnimationState], schemas: [CUSTOM_ELEMENTS_SCHEMA],})export class SceneGraph { readonly movement = signal<NgteEcctrlMovementInput>({ forward: false, backward: false, leftward: false, rightward: false, run: false, jump: false, joystick: { x: 0, y: 0 }, });
onAnimationStateChange(_state: NgteEcctrlAnimationStateValue) {}}animationState is optional and comes from the explicit /animation entry point. See Animation state for its API.
Component API
Section titled “Component API”| Surface | Public API |
|---|---|
| Selector / export | ngte-ecctrl / ecctrl |
| Models and inputs | options, position, rotation, quaternion, scale, userData, rigidBodyOptions, colliderOptions, movement |
| Rigid-body outputs | wake, sleep, collisionEnter, collisionExit, intersectionEnter, intersectionExit, contactForce |
| Public references | body is the controller rigid body, collider is its capsule collider, state is the live controller state, and handle is the programmatic controller handle. |
| Public methods | setMovement, setLockForward, setForwardDir |
Movement is source-agnostic. NgteEcctrlMovementInput has boolean forward, backward, leftward, rightward, run, and jump fields plus joystick: { x, y }. Bind the movement model from a keyboard, gamepad, virtual controls, or a custom adapter. Imperative sources can call player.setMovement({ forward: true }); the controller merges a partial update.
NgteEcctrlGroundDetection is 'shapeCast' | 'rayCast'. NgteEcctrlUserData supports ecctrl.excludeRay, ecctrl.excludeCharacterRay, and ecctrl.excludeVehicleRay for filtering Ecctrl ray queries.
NgteEcctrl forwards the listed transform inputs and rigid-body event outputs to its Rapier body. Use state to observe the controller and handle when an integration needs programmatic access; the component methods above update its movement and forward-direction behavior.
Options and Types
Section titled “Options and Types”NgteEcctrlOptions configures the core controller. Its fields are grouped below so option names remain discoverable without duplicating their defaults.
| Area | Fields |
|---|---|
| General and capsule | enable, debug, capsuleHalfHeight, capsuleRadius |
| Orientation | lockForward, useCustomForward, useCharacterUpAxis |
| Gravity | enableCustomGravity, customGravity, gravityField, gravityDirLerpSpeed |
| Movement | maxWalkVel, maxRunVel, accDeltaTime, decDeltaTime, rejectVelFactor, moveImpulsePointOffset |
| Jump and air | jumpVel, jumpDuration, slopeJumpFactor, airDragFactor, slideGripFactor, fallingGravityScale, fallingMaxVel, enableToggleRun |
| Ground and floating | groundDetection, slopeMaxAngle, floatHeight, rayOriginOffest, rayHitForgiveness, rayLength, rayRadius, springK, dampingC |
| Auto balance and platforms | autoBalance, autoBalanceSpringK, autoBalanceDampingC, autoBalanceSpringOnY, autoBalanceDampingOnY, followPlatform |
| Counter forces | massRatioFallOffCurveData, applyCounterMass, applyCounterJumpImp, counterJumpImpFactor, applyCounterMoveImp, counterMoveImpFactor |
rayOriginOffestis the intentionally retained upstream option spelling.
The root entry also exports NgteEcctrlRigidBodyOptions, NgteEcctrlColliderOptions, NgteEcctrlState, and NgteEcctrlHandle, alongside DEFAULT_ECCTRL_OPTIONS and DEFAULT_ECCTRL_POSITION. Use the options and companion input types to configure the controller, NgteEcctrlState to type observed state, and NgteEcctrlHandle to type programmatic controller references.
The controller’s configured custom gravity replaces its native response to Rapier world gravity. See Gravity fields for the distinct additive behavior of fields applied to arbitrary rigid bodies.
Canonical Entry Points
Section titled “Canonical Entry Points”The root entry contains the controller and its core types. Import each optional integration explicitly:
| Entry point | Reference |
|---|---|
angular-three-ecctrl | Core controller |
angular-three-ecctrl/animation | Animation state |
angular-three-ecctrl/camera | Camera follow |
angular-three-ecctrl/curves | Curves |
angular-three-ecctrl/gravity | Gravity fields |
angular-three-ecctrl/input | Input |
angular-three-ecctrl/time | Time control |
angular-three-ecctrl/vehicle | Vehicles |
There is intentionally no /all, /leva, or /utils entry point, and no backwards-compatibility shims. Optional secondary entry points are not root re-exports.