@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
192 lines (191 loc) • 10.7 kB
TypeScript
import { AnimationClip, Object3D } from "three";
import type { Light, Material, PerspectiveCamera } from "three";
import { AnimatorController } from "./AnimatorController.js";
import { type TrackDescriptor, type TrackOptions, type AnimationKeyframe, type Tween, type Vec3Value, type QuatValue, type EulerValue, type ColorValue } from "./AnimationBuilder.js";
/** Keyframe array or tween shorthand */
type KF<V> = AnimationKeyframe<V>[] | Tween<V>;
/** Extracts parameter names of a given type from the builder's tracked parameter map */
type ParamNamesOfType<TParams, PType extends string> = {
[K in keyof TParams & string]: TParams[K] extends PType ? K : never;
}[keyof TParams & string];
/**
* Configuration for an animation state in the builder
*/
export declare type StateOptions = {
/**
* The animation clip for this state. Accepts:
* - A pre-built `AnimationClip`
* - A single {@link TrackDescriptor} from {@link track}
* - An array of {@link TrackDescriptor}s (multiple tracks combined into one clip)
*
* When omitted, use {@link AnimatorControllerBuilder.track .track()} to define animation tracks inline.
*/
clip?: AnimationClip | TrackDescriptor | TrackDescriptor[];
/** Whether the animation should loop (default: false) */
loop?: boolean;
/** Base speed multiplier (default: 1) */
speed?: number;
/** Name of a float parameter to multiply with speed */
speedParameter?: string;
/** Normalized cycle offset 0-1 (default: 0) */
cycleOffset?: number;
/** Name of a float parameter to use as cycle offset */
cycleOffsetParameter?: string;
};
/**
* Configuration for a transition in the builder
*/
export declare type TransitionOptions = {
/** Duration of the crossfade in seconds (default: 0) */
duration?: number;
/** Normalized exit time 0-1. When set, the transition waits until the source animation reaches this point before transitioning. */
exitTime?: number;
/** Normalized offset into the destination state's animation (default: 0) */
offset?: number;
/** Whether duration is in seconds (true) or normalized (false) (default: false) */
hasFixedDuration?: boolean;
};
/** String condition modes for the builder, mapped to {@link AnimatorConditionMode} */
export type ConditionMode = "if" | "ifNot" | "greater" | "less" | "equals" | "notEqual";
/**
* A fluent builder for creating {@link AnimatorController} instances from code.
*
* Use {@link AnimatorControllerBuilder.create} or {@link AnimatorController.build} to create a new builder.
*
* The builder tracks state names and parameter types through the fluent chain,
* providing autocomplete for state names in `.transition()` and type-aware
* `.condition()` calls (e.g., trigger parameters don't require a mode argument).
*
* @example With pre-built AnimationClips
* ```ts
* const controller = AnimatorControllerBuilder.create("CharacterController")
* .floatParameter("Speed", 0)
* .triggerParameter("Jump")
* .state("Idle", { clip: idleClip, loop: true })
* .state("Walk", { clip: walkClip, loop: true })
* .state("Jump", { clip: jumpClip })
* .transition("Idle", "Walk", { duration: 0.25 })
* .condition("Speed", "greater", 0.1)
* .transition("Walk", "Idle", { duration: 0.25 })
* .condition("Speed", "less", 0.1)
* .transition("*", "Jump", { duration: 0.1 })
* .condition("Jump")
* .transition("Jump", "Idle", { hasExitTime: true, exitTime: 0.9, duration: 0.25 })
* .build();
* ```
*
* @example With inline tracks (no pre-built clips needed)
* ```ts
* const controller = AnimatorControllerBuilder.create("Door")
* .boolParameter("Open", false)
* .state("Closed", { loop: true })
* .track(door, "position", { from: [0, 0, 0], to: [0, 0, 0], duration: 1 })
* .state("Open", { loop: true })
* .track(door, "position", { from: [0, 0, 0], to: [2, 0, 0], duration: 1 })
* .track(light, "intensity", { from: 0, to: 5, duration: 1 })
* .transition("Closed", "Open", { duration: 0.25 })
* .condition("Open", "if")
* .transition("Open", "Closed", { duration: 0.25 })
* .condition("Open", "ifNot")
* .build(room);
* ```
*
* @typeParam TStates - Union of state names added via `.state()`. Used for autocomplete and validation in `.transition()` and `.defaultState()`.
* @typeParam TParams - Record mapping parameter names to their types (`"trigger"`, `"bool"`, `"float"`, `"int"`). Used for type-aware `.condition()` overloads.
*
* @category Animation and Sequencing
* @group Utilities
*/
export declare class AnimatorControllerBuilder<TStates extends string = never, TParams extends Record<string, "trigger" | "bool" | "float" | "int"> = {}> {
private _name;
private _parameters;
private _states;
private _anyStateTransitions;
private _defaultStateName;
private _lastTransition;
private _lastState;
/**
* Creates a new AnimatorControllerBuilder instance.
* @param name - Optional name for the controller
*/
static create(name?: string): AnimatorControllerBuilder;
constructor(name?: string);
/** Adds a float parameter */
floatParameter<N extends string>(name: N, defaultValue?: number): AnimatorControllerBuilder<TStates, TParams & Record<N, "float">>;
/** Adds an integer parameter */
intParameter<N extends string>(name: N, defaultValue?: number): AnimatorControllerBuilder<TStates, TParams & Record<N, "int">>;
/** Adds a boolean parameter */
boolParameter<N extends string>(name: N, defaultValue?: boolean): AnimatorControllerBuilder<TStates, TParams & Record<N, "bool">>;
/** Adds a trigger parameter */
triggerParameter<N extends string>(name: N): AnimatorControllerBuilder<TStates, TParams & Record<N, "trigger">>;
/**
* Adds a state to the controller. The first state added becomes the default state.
*
* When `options.clip` is provided, the state uses that clip directly.
* When omitted, chain `.track()` calls to define animation tracks inline:
* ```ts
* .state("Open", { loop: true })
* .track(door, "position", { from: [0,0,0], to: [2,0,0], duration: 1 })
* .track(light, "intensity", { from: 0, to: 5, duration: 1 })
* ```
*
* @param name - Unique name for the state
* @param options - State configuration including clip, loop, speed. When omitted, use `.track()` to add animation data.
*/
state<N extends string>(name: N, options?: StateOptions): AnimatorControllerBuilder<TStates | N, TParams>;
/**
* Adds a transition between two states.
* Use `"*"` as the source to create a transition from any state.
* Chain `.condition()` calls after this to add conditions.
* @param from - Source state name, or `"*"` for any-state transition
* @param to - Destination state name
* @param options - Transition configuration
*/
transition(from: TStates | "*", to: TStates, options?: TransitionOptions): AnimatorControllerBuilder<TStates, TParams>;
/**
* Adds a condition to the most recently added transition.
* Multiple conditions on the same transition are AND-ed together.
*
* The required arguments depend on the parameter type:
* - **Trigger**: `.condition("Jump")` — mode defaults to `"if"`, no threshold needed
* - **Bool**: `.condition("Open", "if")` or `.condition("Open", "ifNot")`
* - **Float/Int**: `.condition("Speed", "greater", 0.1)`
*
* @param parameter - Name of the parameter to evaluate
*/
condition(parameter: ParamNamesOfType<TParams, "trigger">, mode?: "if" | "ifNot"): AnimatorControllerBuilder<TStates, TParams>;
condition(parameter: ParamNamesOfType<TParams, "bool">, mode: "if" | "ifNot"): AnimatorControllerBuilder<TStates, TParams>;
condition(parameter: ParamNamesOfType<TParams, "float" | "int">, mode: "greater" | "less" | "equals" | "notEqual", threshold?: number): AnimatorControllerBuilder<TStates, TParams>;
/** Adds an animation track for an Object3D's position or scale to the current state */
track(target: Object3D, property: "position" | "scale", keyframes: KF<Vec3Value>, options?: TrackOptions): this;
/** Adds an animation track for an Object3D's quaternion to the current state */
track(target: Object3D, property: "quaternion", keyframes: KF<QuatValue>, options?: TrackOptions): this;
/** Adds an animation track for an Object3D's rotation (Euler, converted to quaternion) to the current state */
track(target: Object3D, property: "rotation", keyframes: KF<EulerValue>, options?: TrackOptions): this;
/** Adds an animation track for an Object3D's visibility to the current state */
track(target: Object3D, property: "visible", keyframes: KF<boolean>, options?: TrackOptions): this;
/** Adds an animation track for a material's numeric property to the current state */
track(target: Material, property: "opacity" | "roughness" | "metalness" | "alphaTest" | "emissiveIntensity" | "envMapIntensity" | "bumpScale" | "displacementScale" | "displacementBias", keyframes: KF<number>, options?: TrackOptions): this;
/** Adds an animation track for a material's color property to the current state */
track(target: Material, property: "color" | "emissive", keyframes: KF<ColorValue>, options?: TrackOptions): this;
/** Adds an animation track for a light's numeric property to the current state */
track(target: Light, property: "intensity" | "distance" | "angle" | "penumbra" | "decay", keyframes: KF<number>, options?: TrackOptions): this;
/** Adds an animation track for a light's color to the current state */
track(target: Light, property: "color", keyframes: KF<ColorValue>, options?: TrackOptions): this;
/** Adds an animation track for a camera's numeric property to the current state */
track(target: PerspectiveCamera, property: "fov" | "near" | "far" | "zoom", keyframes: KF<number>, options?: TrackOptions): this;
/**
* Sets which state is the default/entry state.
* If not called, the first added state is used.
* @param name - Name of the state
*/
defaultState(name: TStates): AnimatorControllerBuilder<TStates, TParams>;
/**
* Builds and returns the {@link AnimatorController}.
* Resolves all state name references to indices.
* @param root - Optional root Object3D for resolving {@link TrackDescriptor} track paths.
* When provided, tracks targeting a different object use `target.name` for named resolution.
*/
build(root?: Object3D): AnimatorController;
}
export {};