UNPKG

angular-three-theatre

Version:
735 lines (722 loc) 27.1 kB
import * as _angular_core from '@angular/core'; import { ElementRef } from '@angular/core'; import * as _theatre_core from '@theatre/core'; import { IProjectConfig, ISheet, UnknownShorthandCompoundProps, types, ISequence } from '@theatre/core'; import { NgtsTransformControlsOptions } from 'angular-three-soba/gizmos'; import * as THREE from 'three'; import { IStudio } from '@theatre/studio'; /** * Component that creates and manages a Theatre.js project. * * A Theatre.js project is the top-level container for all animation data. * It contains sheets, which in turn contain sheet objects that hold animatable properties. * * @example * ```html * <theatre-project name="my-animation" [config]="{ state: savedState }"> * <ng-container sheet="scene1"> * <!-- sheet objects here --> * </ng-container> * </theatre-project> * ``` */ declare class TheatreProject { /** * The name of the Theatre.js project. * This name is used to identify the project and must be unique. * * @default 'default-theatre-project' */ name: _angular_core.InputSignal<string>; /** * Configuration options for the Theatre.js project. * Can include saved state data for restoring animations. * * @default {} */ config: _angular_core.InputSignal<IProjectConfig>; /** * Computed signal containing the Theatre.js project instance. */ project: _angular_core.Signal<_theatre_core.IProject>; /** * Internal registry of sheets created within this project. * Tracks sheet instances and their reference counts for cleanup. */ sheets: Record<string, [sheet: ISheet, count: number]>; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreProject, never>; static ɵcmp: _angular_core.ɵɵComponentDeclaration<TheatreProject, "theatre-project", never, { "name": { "alias": "name"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>; } /** * Directive that creates a Theatre.js sheet object for animating properties. * * A sheet object is a container for animatable properties within a sheet. * This directive must be applied to an `ng-template` element and provides * a structural context with access to the sheet object and its values. * * The template context includes: * - `sheetObject`: The Theatre.js sheet object instance (read-only signal) * - `values`: Current values of all animated properties (read-only signal) * - `select()`: Method to select this object in Theatre.js Studio * - `deselect()`: Method to deselect this object in Theatre.js Studio * * @example * ```html * <ng-template sheetObject="cube" [sheetObjectProps]="{ opacity: 1 }" let-values="values"> * <ngt-mesh> * <ngt-mesh-standard-material [opacity]="values().opacity" /> * </ngt-mesh> * </ng-template> * ``` * * @example * ```html * <!-- With selection support --> * <ng-template * sheetObject="cube" * [(sheetObjectSelected)]="isSelected" * let-select="select" * let-deselect="deselect" * > * <ngt-mesh (click)="select()" /> * </ng-template> * ``` */ declare class TheatreSheetObject$1 { /** * Unique key identifying this sheet object within its parent sheet. * This key is used by Theatre.js to track and persist animation data. */ key: _angular_core.InputSignal<string>; /** * Initial properties and their default values for this sheet object. * These properties will be animatable in Theatre.js Studio. * * @default {} */ props: _angular_core.InputSignal<UnknownShorthandCompoundProps>; /** * Whether to detach (remove) the sheet object when this directive is destroyed. * When true, the animation data for this object will be removed from the sheet. * * @default false */ detach: _angular_core.InputSignalWithTransform<boolean, unknown>; /** * Two-way bindable signal indicating whether this object is selected in Theatre.js Studio. * * @default false */ selected: _angular_core.ModelSignal<boolean>; private templateRef; private vcr; private sheet; private studio; private store; private originalSheetObject; /** * Signal containing the Theatre.js sheet object instance. * This is a linked signal that updates when the sheet or key changes. */ sheetObject: _angular_core.WritableSignal<_theatre_core.ISheetObject<UnknownShorthandCompoundProps>>; /** * Signal containing the current values of all animated properties. * Updates automatically when Theatre.js values change. */ values: _angular_core.WritableSignal<{ [x: string]: any; }>; private detached; private aggregatedProps; constructor(); /** * Updates the sheet object with the current aggregated props. * Detaches the existing object and creates a new one with reconfigured properties. */ update(): void; /** * Adds new properties to the sheet object. * The properties are merged with existing properties and the object is reconfigured. * * @param props - Properties to add to the sheet object */ addProps(props: UnknownShorthandCompoundProps): void; /** * Removes properties from the sheet object. * If all properties are removed and `detach` is true, the object is detached from the sheet. * * @param props - Array of property names to remove */ removeProps(props: string[]): void; /** * Selects this sheet object in Theatre.js Studio. * Only works when the studio is available. */ select(): void; /** * Deselects this sheet object in Theatre.js Studio. * Only deselects if this object is currently selected. */ deselect(): void; /** * Type guard for the template context. * Provides type safety for the template variables exposed by this directive. * * @param _ - The directive instance * @param ctx - The template context * @returns Type predicate for the template context */ static ngTemplateContextGuard(_: TheatreSheetObject$1, ctx: unknown): ctx is { select: TheatreSheetObject$1['select']; deselect: TheatreSheetObject$1['deselect']; sheetObject: ReturnType<TheatreSheetObject$1['sheetObject']['asReadonly']>; values: ReturnType<TheatreSheetObject$1['values']['asReadonly']>; }; static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreSheetObject$1, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TheatreSheetObject$1, "ng-template[sheetObject]", ["sheetObject"], { "key": { "alias": "sheetObject"; "required": true; "isSignal": true; }; "props": { "alias": "sheetObjectProps"; "required": false; "isSignal": true; }; "detach": { "alias": "sheetObjectDetach"; "required": false; "isSignal": true; }; "selected": { "alias": "sheetObjectSelected"; "required": false; "isSignal": true; }; }, { "selected": "sheetObjectSelectedChange"; }, never, never, true, never>; } /** * Type definition for a Theatre.js property transformer. * * Transformers are used to convert between Three.js property values and * Theatre.js animation values. This allows for proper representation * in the Theatre.js Studio UI (e.g., showing degrees instead of radians). * * Based on https://github.com/threlte/threlte/blob/main/packages/theatre/src/lib/sheetObject/transfomers/types.ts * * @typeParam Value - The type of the original Three.js property value * @typeParam TransformedValue - The type of the value used in Theatre.js * * @example * ```typescript * const myTransformer: TheatreTransformer<number, number> = { * transform: (value) => types.number(value * 100), * apply: (target, property, value) => { target[property] = value / 100; } * }; * ``` */ type TheatreTransformer<Value = any, TransformedValue = any> = { /** * The `transform` function is used to transform the value of a certain * Three.js objects proerty to a property that Theatre.js can use in an * `ISheetObject`. To ensure compatibility with the rest of the package, the * return value must be any one of the functions available at Theatre.js' * `types`. */ transform: (value: Value) => ReturnType<(typeof types)[keyof typeof types]>; /** * The `apply` function is used to apply the value to the target. `target` is * the parent object of the property (usually a Three.js object), `path` is * the name of the property and `value` is the value to apply. */ apply: (target: any, property: string, value: TransformedValue) => void; }; /** * Directive that synchronizes Three.js object properties with Theatre.js animations. * * This directive allows you to expose specific properties of a Three.js object * to Theatre.js for animation. It automatically handles property transformation * (e.g., converting Euler angles to degrees for the UI). * * Must be used within a `TheatreSheetObject` context. * * @example * ```html * <ng-template sheetObject="myMaterial"> * <ngt-mesh-standard-material * [sync]="material" * [syncProps]="['opacity', 'roughness', 'metalness']" * #material * /> * </ng-template> * ``` * * @example * ```html * <!-- With custom property mapping --> * <ng-template sheetObject="myLight"> * <ngt-point-light * [sync]="light" * [syncProps]="[ * ['intensity', { label: 'Light Intensity', key: 'lightIntensity' }], * 'color' * ]" * #light * /> * </ng-template> * ``` * * @typeParam TObject - The type of the Three.js object being synchronized */ declare class TheatreSheetObjectSync<TObject extends object> { /** * The Three.js object to synchronize with Theatre.js. * Can be an object reference, ElementRef, or a Signal of either. */ parent: _angular_core.InputSignal<TObject | ElementRef<TObject> | (() => TObject | ElementRef<TObject> | undefined | null)>; /** * Array of property paths to synchronize with Theatre.js. * * Each item can be: * - A string property path (e.g., 'opacity', 'position.x') * - A tuple of [propertyPath, keyOrOptions] where options can include: * - `label`: Display label in Theatre.js Studio * - `key`: Unique key for the property in Theatre.js * - `transformer`: Custom transformer for the property value * * @default [] */ props: _angular_core.InputSignal<(string | [string, string | { label?: string; key?: string; transformer?: TheatreTransformer; }])[]>; private theatreSheetObject; /** * Computed signal containing the Theatre.js sheet object instance. */ sheetObject: _angular_core.Signal<_theatre_core.ISheetObject<_theatre_core.UnknownShorthandCompoundProps>>; private studio; private parentRef; private resolvedProps; private propsToAdd; private propsMapping; constructor(); /** * Captures the current values of all synchronized properties from the Three.js object * and commits them to Theatre.js. * * This is useful for "baking" the current state of the Three.js object into the * Theatre.js animation. Requires Theatre.js Studio to be available. */ capture(): void; /** * Converts a property path (e.g., 'position.x') to a safe alphanumeric key. * * @param propPath - The property path to convert * @returns A safe alphanumeric key string */ private resolvePropertyPath; static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreSheetObjectSync<any>, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TheatreSheetObjectSync<any>, "[sync]", ["sync"], { "parent": { "alias": "sync"; "required": true; "isSignal": true; }; "props": { "alias": "syncProps"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; } /** * Component that provides transform controls for animating position, rotation, and scale * of child Three.js objects via Theatre.js. * * When the sheet object is selected in Theatre.js Studio, transform controls appear * allowing direct manipulation of the object's transform. Changes are captured and * committed to Theatre.js. * * Must be used within a `TheatreSheetObject` context. * * @example * ```html * <ng-template sheetObject="myCube"> * <theatre-transform> * <ngt-mesh> * <ngt-box-geometry /> * <ngt-mesh-standard-material /> * </ngt-mesh> * </theatre-transform> * </ng-template> * ``` * * @example * ```html * <!-- With custom key and options --> * <ng-template sheetObject="scene"> * <theatre-transform key="cubeTransform" label="Cube" [options]="{ mode: 'rotate' }"> * <ngt-mesh /> * </theatre-transform> * </ng-template> * ``` * * @typeParam TLabel - The type of the label string */ declare class TheatreSheetObjectTransform<TLabel extends string | undefined> { /** * Display label for the transform properties in Theatre.js Studio. */ label: _angular_core.InputSignal<TLabel | undefined>; /** * Unique key for grouping the transform properties in Theatre.js. * If provided, position/rotation/scale will be nested under this key. */ key: _angular_core.InputSignal<string | undefined>; /** * Options for the transform controls gizmo. * Allows configuring the transform mode, snap values, and coordinate space. * * @default {} */ options: _angular_core.InputSignal<Pick<NgtsTransformControlsOptions, "mode" | "translationSnap" | "scaleSnap" | "rotationSnap" | "space">>; /** * Reference to the Three.js Group element that wraps the transformed content. */ groupRef: _angular_core.Signal<ElementRef<THREE.Group<THREE.Object3DEventMap>>>; private controlsRef; private theatreSheetObject; /** * Computed signal containing the Theatre.js sheet object instance. */ sheetObject: _angular_core.Signal<_theatre_core.ISheetObject<_theatre_core.UnknownShorthandCompoundProps>>; private studio; protected selected: _angular_core.Signal<boolean>; private scrub?; private positionTransformer; private rotationTransformer; private scaleTransformer; protected onMouseDown(): void; protected onMouseUp(): void; protected onChange(): void; constructor(); private init; static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreSheetObjectTransform<any>, never>; static ɵcmp: _angular_core.ɵɵComponentDeclaration<TheatreSheetObjectTransform<any>, "theatre-transform", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "key": { "alias": "key"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>; } /** * Combined array of sheet object directives for convenient importing. * * Includes: * - `TheatreSheetObject` - Base directive for creating sheet objects * - `TheatreSheetObjectTransform` - Component for animating transform properties * - `TheatreSheetObjectSync` - Directive for syncing arbitrary object properties * * @example * ```typescript * import { TheatreSheetObject } from 'angular-three-theatre'; * * @Component({ * imports: [TheatreSheetObject], * template: ` * <ng-template sheetObject="myObject"> * <theatre-transform> * <ngt-mesh /> * </theatre-transform> * </ng-template> * ` * }) * export class MyComponent {} * ``` */ declare const TheatreSheetObject: (typeof TheatreSheetObject$1 | typeof TheatreSheetObjectSync | typeof TheatreSheetObjectTransform)[]; /** * Directive that initializes and manages the Theatre.js Studio. * * Theatre.js Studio is a visual editor that allows you to create and edit * animations directly in the browser. The studio UI is dynamically imported * to avoid including it in production builds. * * This directive must be applied to a `theatre-project` element and provides * the studio instance via the `THEATRE_STUDIO` injection token. * * @example * ```html * <!-- Enable studio (default) --> * <theatre-project studio> * <ng-container sheet="scene">...</ng-container> * </theatre-project> * * <!-- Conditionally enable/disable studio --> * <theatre-project [studio]="isDevelopment"> * <ng-container sheet="scene">...</ng-container> * </theatre-project> * * <!-- Disable studio --> * <theatre-project [studio]="false"> * <ng-container sheet="scene">...</ng-container> * </theatre-project> * ``` */ declare class TheatreStudio { /** * Whether the studio UI should be visible. * When false, the studio UI is hidden but the studio instance remains active. * * @default true */ enabled: _angular_core.InputSignalWithTransform<boolean, unknown>; private Studio; /** * Read-only signal containing the Theatre.js Studio instance. * May be null while the studio is being loaded. */ studio: _angular_core.Signal<IStudio | null>; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreStudio, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TheatreStudio, "theatre-project[studio]", ["studio"], { "enabled": { "alias": "studio"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; } /** * Options for attaching audio to a Theatre.js sequence. * * When audio is attached, the sequence playback will be synchronized * with the audio playback. */ interface AttachAudioOptions { /** * Either a URL to the audio file (eg "http://localhost:3000/audio.mp3") or an instance of AudioBuffer */ source: string | AudioBuffer; /** * An optional AudioContext. If not provided, one will be created. */ audioContext?: AudioContext; /** * An AudioNode to feed the audio into. Will use audioContext.destination if not provided. */ destinationNode?: AudioNode; } /** * Configuration options for the TheatreSequence directive. * * Extends Theatre.js sequence play options with additional Angular-specific options * for automatic playback control. */ type TheatreSequenceOptions = Parameters<ISequence['play']>[0] & { /** * Whether to automatically start playback when the sequence is initialized. * @default false */ autoplay: boolean; /** * Whether to automatically pause playback when the directive is destroyed. * @default false */ autopause: boolean; /** * Delay in milliseconds before autoplay starts. * @default 0 */ delay: number; /** * When to reset the sequence position to 0. * - 'init': Reset when the directive is initialized * - 'destroy': Reset when the directive is destroyed * - 'always': Reset on both init and destroy */ autoreset?: 'init' | 'destroy' | 'always'; }; /** * Directive that provides control over a Theatre.js sequence. * * A sequence controls the playback of animations within a sheet. This directive * provides methods to play, pause, and reset the sequence, as well as reactive * signals for the current position, playing state, and length. * * Must be used on an element that also has the `sheet` directive. * * @example * ```html * <ng-container sheet="scene" [sequence]="{ autoplay: true, rate: 1 }" #seq="sequence"> * <p>Position: {{ seq.position() }}</p> * <button (click)="seq.play()">Play</button> * <button (click)="seq.pause()">Pause</button> * </ng-container> * ``` * * @example * ```html * <!-- With audio synchronization --> * <ng-container * sheet="scene" * [sequence]="{ autoplay: true }" * [sequenceAudio]="{ source: '/audio/soundtrack.mp3' }" * /> * ``` */ declare class TheatreSequence { /** * Sequence configuration options. * Merged with default options using ngxtension's mergeInputs. * * @default { rate: 1, autoplay: false, autopause: false, delay: 0 } */ options: _angular_core.InputSignalWithTransform<{ iterationCount?: number; range?: [from: number, to: number]; rate?: number; direction?: "reverse" | "normal" | "alternate" | "alternateReverse"; rafDriver?: _theatre_core.IRafDriver; } & { /** * Whether to automatically start playback when the sequence is initialized. * @default false */ autoplay: boolean; /** * Whether to automatically pause playback when the directive is destroyed. * @default false */ autopause: boolean; /** * Delay in milliseconds before autoplay starts. * @default 0 */ delay: number; /** * When to reset the sequence position to 0. * - 'init': Reset when the directive is initialized * - 'destroy': Reset when the directive is destroyed * - 'always': Reset on both init and destroy */ autoreset?: "init" | "destroy" | "always"; }, "" | Partial<{ iterationCount?: number; range?: [from: number, to: number]; rate?: number; direction?: "reverse" | "normal" | "alternate" | "alternateReverse"; rafDriver?: _theatre_core.IRafDriver; } & { /** * Whether to automatically start playback when the sequence is initialized. * @default false */ autoplay: boolean; /** * Whether to automatically pause playback when the directive is destroyed. * @default false */ autopause: boolean; /** * Delay in milliseconds before autoplay starts. * @default 0 */ delay: number; /** * When to reset the sequence position to 0. * - 'init': Reset when the directive is initialized * - 'destroy': Reset when the directive is destroyed * - 'always': Reset on both init and destroy */ autoreset?: "init" | "destroy" | "always"; }>>; /** * Audio options for synchronizing playback with an audio file. * When provided, the sequence will be synchronized with the audio. */ audioOptions: _angular_core.InputSignal<AttachAudioOptions | undefined>; /** * Two-way bindable signal for the current playback position in seconds. * * @default 0 */ position: _angular_core.ModelSignal<number>; /** * Two-way bindable signal indicating whether the sequence is currently playing. * * @default false */ playing: _angular_core.ModelSignal<boolean>; /** * Two-way bindable signal for the total length of the sequence in seconds. * * @default 0 */ length: _angular_core.ModelSignal<number>; private playOptions; private autoplay; private autopause; private autoreset; private delay; private project; private sheet; /** * Computed signal containing the Theatre.js sequence instance. */ sequence: _angular_core.Signal<ISequence>; constructor(); /** * Pauses the sequence playback at the current position. */ pause(): void; /** * Starts or resumes sequence playback. * * Waits for the project to be ready before starting playback. * Options are merged with the configured play options. * * @param options - Optional play options that override the configured options */ play(options?: Parameters<ISequence['play']>[0]): void; /** * Resets the sequence position to 0. * * If the sequence was playing before reset, it will continue playing * from the beginning. */ reset(): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreSequence, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TheatreSequence, "[sheet][sequence]", ["sequence"], { "options": { "alias": "sequence"; "required": false; "isSignal": true; }; "audioOptions": { "alias": "sequenceAudio"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "playing": { "alias": "playing"; "required": false; "isSignal": true; }; "length": { "alias": "length"; "required": false; "isSignal": true; }; }, { "position": "positionChange"; "playing": "playingChange"; "length": "lengthChange"; }, never, never, true, never>; } /** * Directive that creates and manages a Theatre.js sheet within a project. * * A sheet is a container for sheet objects and their animations. Multiple sheets * can exist within a project, allowing you to organize animations into logical groups. * * The directive automatically handles reference counting and cleanup when the * directive is destroyed. * * @example * ```html * <theatre-project> * <ng-container sheet="mainScene"> * <!-- sheet objects here --> * </ng-container> * </theatre-project> * ``` * * @example * ```html * <!-- Using with template reference --> * <ng-container sheet="mySheet" #sheetRef="sheet"> * {{ sheetRef.sheet().sequence.position }} * </ng-container> * ``` */ declare class TheatreSheet$1 { /** * The name of the sheet within the project. * This name must be unique within the parent project. * * @default 'default-theatre-sheet' */ name: _angular_core.InputSignalWithTransform<string, string>; private project; /** * Computed signal containing the Theatre.js sheet instance. * Returns an existing sheet if one with the same name already exists, * otherwise creates a new sheet. */ sheet: _angular_core.Signal<_theatre_core.ISheet>; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration<TheatreSheet$1, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TheatreSheet$1, "[sheet]", ["sheet"], { "name": { "alias": "sheet"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; } /** * Angular Three Theatre.js integration library * * This library provides Angular components and directives for integrating * Theatre.js animation toolkit with Angular Three applications. * * @packageDocumentation */ /** * Combined array of TheatreSheet and TheatreSequence directives for convenient importing. * * @example * ```typescript * import { TheatreSheet } from 'angular-three-theatre'; * * @Component({ * imports: [TheatreSheet], * template: `<ng-container sheet="mySheet" sequence />` * }) * export class MyComponent {} * ``` */ declare const TheatreSheet: readonly [typeof TheatreSheet$1, typeof TheatreSequence]; export { TheatreProject, TheatreSequence, TheatreSheet, TheatreSheet$1 as TheatreSheetImpl, TheatreSheetObject, TheatreSheetObject$1 as TheatreSheetObjectImpl, TheatreSheetObjectSync, TheatreSheetObjectTransform, TheatreStudio }; export type { AttachAudioOptions, TheatreSequenceOptions };