angular-three-theatre 4.0.0-next.116 → 4.0.0-next.118

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,11 +7,45 @@ import { Group } from 'three';
7
7
  import { NgtsTransformControls } from 'angular-three-soba/gizmos';
8
8
  import { mergeInputs } from 'ngxtension/inject-inputs';
9
9
 
10
+ /**
11
+ * Component that creates and manages a Theatre.js project.
12
+ *
13
+ * A Theatre.js project is the top-level container for all animation data.
14
+ * It contains sheets, which in turn contain sheet objects that hold animatable properties.
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <theatre-project name="my-animation" [config]="{ state: savedState }">
19
+ * <ng-container sheet="scene1">
20
+ * <!-- sheet objects here -->
21
+ * </ng-container>
22
+ * </theatre-project>
23
+ * ```
24
+ */
10
25
  class TheatreProject {
11
26
  constructor() {
27
+ /**
28
+ * The name of the Theatre.js project.
29
+ * This name is used to identify the project and must be unique.
30
+ *
31
+ * @default 'default-theatre-project'
32
+ */
12
33
  this.name = input('default-theatre-project', ...(ngDevMode ? [{ debugName: "name" }] : []));
34
+ /**
35
+ * Configuration options for the Theatre.js project.
36
+ * Can include saved state data for restoring animations.
37
+ *
38
+ * @default {}
39
+ */
13
40
  this.config = input({}, ...(ngDevMode ? [{ debugName: "config" }] : []));
41
+ /**
42
+ * Computed signal containing the Theatre.js project instance.
43
+ */
14
44
  this.project = computed(() => getProject(this.name(), this.config()), ...(ngDevMode ? [{ debugName: "project" }] : []));
45
+ /**
46
+ * Internal registry of sheets created within this project.
47
+ * Tracks sheet instances and their reference counts for cleanup.
48
+ */
15
49
  this.sheets = {};
16
50
  effect(() => {
17
51
  const project = this.project();
@@ -34,8 +68,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
34
68
  }]
35
69
  }], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
36
70
 
71
+ /**
72
+ * Directive that creates and manages a Theatre.js sheet within a project.
73
+ *
74
+ * A sheet is a container for sheet objects and their animations. Multiple sheets
75
+ * can exist within a project, allowing you to organize animations into logical groups.
76
+ *
77
+ * The directive automatically handles reference counting and cleanup when the
78
+ * directive is destroyed.
79
+ *
80
+ * @example
81
+ * ```html
82
+ * <theatre-project>
83
+ * <ng-container sheet="mainScene">
84
+ * <!-- sheet objects here -->
85
+ * </ng-container>
86
+ * </theatre-project>
87
+ * ```
88
+ *
89
+ * @example
90
+ * ```html
91
+ * <!-- Using with template reference -->
92
+ * <ng-container sheet="mySheet" #sheetRef="sheet">
93
+ * {{ sheetRef.sheet().sequence.position }}
94
+ * </ng-container>
95
+ * ```
96
+ */
37
97
  let TheatreSheet$1 = class TheatreSheet {
38
98
  constructor() {
99
+ /**
100
+ * The name of the sheet within the project.
101
+ * This name must be unique within the parent project.
102
+ *
103
+ * @default 'default-theatre-sheet'
104
+ */
39
105
  this.name = input('default-theatre-sheet', { ...(ngDevMode ? { debugName: "name" } : {}), transform: (value) => {
40
106
  if (value === '')
41
107
  return 'default-theatre-sheet';
@@ -43,6 +109,11 @@ let TheatreSheet$1 = class TheatreSheet {
43
109
  },
44
110
  alias: 'sheet' });
45
111
  this.project = inject(TheatreProject);
112
+ /**
113
+ * Computed signal containing the Theatre.js sheet instance.
114
+ * Returns an existing sheet if one with the same name already exists,
115
+ * otherwise creates a new sheet.
116
+ */
46
117
  this.sheet = computed(() => {
47
118
  const name = this.name();
48
119
  const existing = this.project.sheets[name] || [];
@@ -74,13 +145,90 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
74
145
  args: [{ selector: '[sheet]', exportAs: 'sheet' }]
75
146
  }], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheet", required: false }] }] } });
76
147
 
148
+ /**
149
+ * Injection token for accessing the Theatre.js Studio instance.
150
+ *
151
+ * The studio provides a visual editor for creating and editing animations.
152
+ * This token is provided by the TheatreStudio directive and can be injected
153
+ * into child components.
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * import { THEATRE_STUDIO } from 'angular-three-theatre';
158
+ *
159
+ * @Component({...})
160
+ * export class MyComponent {
161
+ * private studio = inject(THEATRE_STUDIO, { optional: true });
162
+ *
163
+ * selectObject() {
164
+ * this.studio()?.setSelection([mySheetObject]);
165
+ * }
166
+ * }
167
+ * ```
168
+ */
77
169
  const THEATRE_STUDIO = new InjectionToken('Theatre Studio');
78
170
 
171
+ /**
172
+ * Directive that creates a Theatre.js sheet object for animating properties.
173
+ *
174
+ * A sheet object is a container for animatable properties within a sheet.
175
+ * This directive must be applied to an `ng-template` element and provides
176
+ * a structural context with access to the sheet object and its values.
177
+ *
178
+ * The template context includes:
179
+ * - `sheetObject`: The Theatre.js sheet object instance (read-only signal)
180
+ * - `values`: Current values of all animated properties (read-only signal)
181
+ * - `select()`: Method to select this object in Theatre.js Studio
182
+ * - `deselect()`: Method to deselect this object in Theatre.js Studio
183
+ *
184
+ * @example
185
+ * ```html
186
+ * <ng-template sheetObject="cube" [sheetObjectProps]="{ opacity: 1 }" let-values="values">
187
+ * <ngt-mesh>
188
+ * <ngt-mesh-standard-material [opacity]="values().opacity" />
189
+ * </ngt-mesh>
190
+ * </ng-template>
191
+ * ```
192
+ *
193
+ * @example
194
+ * ```html
195
+ * <!-- With selection support -->
196
+ * <ng-template
197
+ * sheetObject="cube"
198
+ * [(sheetObjectSelected)]="isSelected"
199
+ * let-select="select"
200
+ * let-deselect="deselect"
201
+ * >
202
+ * <ngt-mesh (click)="select()" />
203
+ * </ng-template>
204
+ * ```
205
+ */
79
206
  let TheatreSheetObject$1 = class TheatreSheetObject {
80
207
  constructor() {
208
+ /**
209
+ * Unique key identifying this sheet object within its parent sheet.
210
+ * This key is used by Theatre.js to track and persist animation data.
211
+ */
81
212
  this.key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}), alias: 'sheetObject' });
213
+ /**
214
+ * Initial properties and their default values for this sheet object.
215
+ * These properties will be animatable in Theatre.js Studio.
216
+ *
217
+ * @default {}
218
+ */
82
219
  this.props = input({}, { ...(ngDevMode ? { debugName: "props" } : {}), alias: 'sheetObjectProps' });
220
+ /**
221
+ * Whether to detach (remove) the sheet object when this directive is destroyed.
222
+ * When true, the animation data for this object will be removed from the sheet.
223
+ *
224
+ * @default false
225
+ */
83
226
  this.detach = input(false, { ...(ngDevMode ? { debugName: "detach" } : {}), transform: booleanAttribute, alias: 'sheetObjectDetach' });
227
+ /**
228
+ * Two-way bindable signal indicating whether this object is selected in Theatre.js Studio.
229
+ *
230
+ * @default false
231
+ */
84
232
  this.selected = model(false, { ...(ngDevMode ? { debugName: "selected" } : {}), alias: 'sheetObjectSelected' });
85
233
  this.templateRef = inject(TemplateRef);
86
234
  this.vcr = inject(ViewContainerRef);
@@ -91,7 +239,15 @@ let TheatreSheetObject$1 = class TheatreSheetObject {
91
239
  const sheet = this.sheet.sheet();
92
240
  return sheet.object(this.key(), untracked(this.props), { reconfigure: true });
93
241
  }, ...(ngDevMode ? [{ debugName: "originalSheetObject" }] : []));
242
+ /**
243
+ * Signal containing the Theatre.js sheet object instance.
244
+ * This is a linked signal that updates when the sheet or key changes.
245
+ */
94
246
  this.sheetObject = linkedSignal(this.originalSheetObject, ...(ngDevMode ? [{ debugName: "sheetObject" }] : []));
247
+ /**
248
+ * Signal containing the current values of all animated properties.
249
+ * Updates automatically when Theatre.js values change.
250
+ */
95
251
  this.values = linkedSignal(() => this.sheetObject().value, ...(ngDevMode ? [{ debugName: "values" }] : []));
96
252
  this.detached = false;
97
253
  this.aggregatedProps = {};
@@ -135,6 +291,10 @@ let TheatreSheetObject$1 = class TheatreSheetObject {
135
291
  }
136
292
  });
137
293
  }
294
+ /**
295
+ * Updates the sheet object with the current aggregated props.
296
+ * Detaches the existing object and creates a new one with reconfigured properties.
297
+ */
138
298
  update() {
139
299
  if (this.detached)
140
300
  return;
@@ -142,10 +302,22 @@ let TheatreSheetObject$1 = class TheatreSheetObject {
142
302
  sheet.detachObject(key);
143
303
  this.sheetObject.set(sheet.object(key, this.aggregatedProps, { reconfigure: true }));
144
304
  }
305
+ /**
306
+ * Adds new properties to the sheet object.
307
+ * The properties are merged with existing properties and the object is reconfigured.
308
+ *
309
+ * @param props - Properties to add to the sheet object
310
+ */
145
311
  addProps(props) {
146
312
  this.aggregatedProps = { ...this.aggregatedProps, ...props };
147
313
  this.update();
148
314
  }
315
+ /**
316
+ * Removes properties from the sheet object.
317
+ * If all properties are removed and `detach` is true, the object is detached from the sheet.
318
+ *
319
+ * @param props - Array of property names to remove
320
+ */
149
321
  removeProps(props) {
150
322
  const [detach, sheet, key] = [untracked(this.detach), untracked(this.sheet.sheet), untracked(this.key)];
151
323
  // remove props from sheet object
@@ -164,12 +336,20 @@ let TheatreSheetObject$1 = class TheatreSheetObject {
164
336
  this.update();
165
337
  }
166
338
  }
339
+ /**
340
+ * Selects this sheet object in Theatre.js Studio.
341
+ * Only works when the studio is available.
342
+ */
167
343
  select() {
168
344
  const studio = this.studio?.();
169
345
  if (!studio)
170
346
  return;
171
347
  studio.setSelection([this.sheetObject()]);
172
348
  }
349
+ /**
350
+ * Deselects this sheet object in Theatre.js Studio.
351
+ * Only deselects if this object is currently selected.
352
+ */
173
353
  deselect() {
174
354
  const studio = this.studio?.();
175
355
  if (!studio)
@@ -178,6 +358,14 @@ let TheatreSheetObject$1 = class TheatreSheetObject {
178
358
  studio.setSelection([]);
179
359
  }
180
360
  }
361
+ /**
362
+ * Type guard for the template context.
363
+ * Provides type safety for the template variables exposed by this directive.
364
+ *
365
+ * @param _ - The directive instance
366
+ * @param ctx - The template context
367
+ * @returns Type predicate for the template context
368
+ */
181
369
  static ngTemplateContextGuard(_, ctx) {
182
370
  return true;
183
371
  }
@@ -189,11 +377,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
189
377
  args: [{ selector: 'ng-template[sheetObject]', exportAs: 'sheetObject' }]
190
378
  }], ctorParameters: () => [], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheetObject", required: true }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheetObjectProps", required: false }] }], detach: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheetObjectDetach", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheetObjectSelected", required: false }] }, { type: i0.Output, args: ["sheetObjectSelectedChange"] }] } });
191
379
 
380
+ /**
381
+ * Factory function for creating a Theatre.js transformer.
382
+ *
383
+ * This is a convenience function that provides type inference for transformer creation.
384
+ *
385
+ * @param transformer - The transformer configuration object
386
+ * @returns The same transformer object (identity function with type inference)
387
+ *
388
+ * @example
389
+ * ```typescript
390
+ * import { createTransformer } from 'angular-three-theatre';
391
+ * import { types } from '@theatre/core';
392
+ *
393
+ * export const percentage = createTransformer({
394
+ * transform: (value) => types.number(value * 100, { range: [0, 100] }),
395
+ * apply: (target, property, value) => { target[property] = value / 100; }
396
+ * });
397
+ * ```
398
+ */
192
399
  function createTransformer(transformer) {
193
400
  return transformer;
194
401
  }
195
402
 
196
403
  const _color = new THREE.Color();
404
+ /**
405
+ * Transformer for Three.js Color objects.
406
+ *
407
+ * Converts Three.js Color to Theatre.js RGBA format for the color picker UI.
408
+ * Uses sRGB color space for accurate color representation.
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * import { color } from 'angular-three-theatre';
413
+ *
414
+ * // Used automatically for Color properties, or manually:
415
+ * [sync]="material"
416
+ * [syncProps]="[['emissive', { transformer: color }]]"
417
+ * ```
418
+ */
197
419
  const color = createTransformer({
198
420
  transform(value) {
199
421
  value.getRGB(_color, THREE.SRGBColorSpace);
@@ -204,6 +426,21 @@ const color = createTransformer({
204
426
  },
205
427
  });
206
428
 
429
+ /**
430
+ * Transformer for radian values that displays as degrees in the UI.
431
+ *
432
+ * Converts between radians (used by Three.js) and degrees (more intuitive for users).
433
+ * Used automatically for rotation.x, rotation.y, and rotation.z properties.
434
+ *
435
+ * @example
436
+ * ```typescript
437
+ * import { degrees } from 'angular-three-theatre';
438
+ *
439
+ * // Used automatically for rotation components, or manually:
440
+ * [sync]="camera"
441
+ * [syncProps]="[['fov', { transformer: degrees }]]"
442
+ * ```
443
+ */
207
444
  const degrees = createTransformer({
208
445
  transform(target) {
209
446
  return types.number(target * THREE.MathUtils.RAD2DEG);
@@ -213,6 +450,23 @@ const degrees = createTransformer({
213
450
  },
214
451
  });
215
452
 
453
+ /**
454
+ * Transformer for Three.js Euler rotation objects.
455
+ *
456
+ * Converts Euler angles from radians to degrees for display in Theatre.js Studio.
457
+ * Creates a compound property with x, y, z components shown in degrees.
458
+ *
459
+ * Used automatically for properties where `isEuler` is true (e.g., Object3D.rotation).
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * import { euler } from 'angular-three-theatre';
464
+ *
465
+ * // Used automatically for Euler properties, or manually:
466
+ * [sync]="mesh"
467
+ * [syncProps]="[['rotation', { transformer: euler }]]"
468
+ * ```
469
+ */
216
470
  const euler = createTransformer({
217
471
  transform(value) {
218
472
  return types.compound({
@@ -228,6 +482,26 @@ const euler = createTransformer({
228
482
  },
229
483
  });
230
484
 
485
+ /**
486
+ * Generic fallback transformer that handles common JavaScript types.
487
+ *
488
+ * Automatically detects the value type and applies the appropriate Theatre.js type:
489
+ * - Numbers → `types.number` (Infinity converted to MAX_VALUE)
490
+ * - Strings → `types.string`
491
+ * - Booleans → `types.boolean`
492
+ * - Objects → `types.compound` (spreads properties)
493
+ *
494
+ * Used as the default transformer when no specific transformer matches.
495
+ *
496
+ * @example
497
+ * ```typescript
498
+ * import { generic } from 'angular-three-theatre';
499
+ *
500
+ * // Explicitly use generic transformer:
501
+ * [sync]="mesh"
502
+ * [syncProps]="[['customProperty', { transformer: generic }]]"
503
+ * ```
504
+ */
231
505
  const generic = createTransformer({
232
506
  transform(value) {
233
507
  if (typeof value === 'number') {
@@ -251,6 +525,22 @@ const generic = createTransformer({
251
525
  },
252
526
  });
253
527
 
528
+ /**
529
+ * Transformer for normalized values in the 0-1 range.
530
+ *
531
+ * Creates a number input with a slider constrained to the 0-1 range.
532
+ * Used automatically for material properties like opacity, roughness,
533
+ * metalness, transmission, and color components (r, g, b).
534
+ *
535
+ * @example
536
+ * ```typescript
537
+ * import { normalized } from 'angular-three-theatre';
538
+ *
539
+ * // Used automatically for common properties, or manually:
540
+ * [sync]="material"
541
+ * [syncProps]="[['customNormalizedValue', { transformer: normalized }]]"
542
+ * ```
543
+ */
254
544
  const normalized = createTransformer({
255
545
  transform(value) {
256
546
  return types.number(value, { range: [0, 1] });
@@ -260,6 +550,23 @@ const normalized = createTransformer({
260
550
  },
261
551
  });
262
552
 
553
+ /**
554
+ * Transformer for Three.js material side property.
555
+ *
556
+ * Converts between Three.js side constants (FrontSide, BackSide, DoubleSide)
557
+ * and a switch UI in Theatre.js Studio with human-readable labels.
558
+ *
559
+ * Used automatically for the `side` property on materials.
560
+ *
561
+ * @example
562
+ * ```typescript
563
+ * import { side } from 'angular-three-theatre';
564
+ *
565
+ * // Used automatically for material.side, or manually:
566
+ * [sync]="material"
567
+ * [syncProps]="[['side', { transformer: side }]]"
568
+ * ```
569
+ */
263
570
  const side = createTransformer({
264
571
  transform(value) {
265
572
  // TODO: fix this type
@@ -270,9 +577,42 @@ const side = createTransformer({
270
577
  },
271
578
  });
272
579
 
580
+ /**
581
+ * Checks if a property path matches a pattern exactly or ends with the pattern.
582
+ *
583
+ * @param fullPropertyPath - The full property path (e.g., 'material.opacity')
584
+ * @param pattern - The pattern to match (e.g., 'opacity')
585
+ * @returns True if the path matches or ends with the pattern
586
+ */
273
587
  function isFullOrEndingPattern(fullPropertyPath, pattern) {
274
588
  return fullPropertyPath.endsWith(`.${pattern}`) || fullPropertyPath === pattern;
275
589
  }
590
+ /**
591
+ * Determines the appropriate transformer for a Three.js property based on its type and path.
592
+ *
593
+ * This function automatically selects the best transformer for common Three.js properties:
594
+ * - Euler rotations → `euler` transformer (degrees display)
595
+ * - Color values → `color` transformer (RGBA picker)
596
+ * - Rotation components (x, y, z) → `degrees` transformer
597
+ * - Color components (r, g, b) → `normalized` transformer (0-1 range)
598
+ * - Material properties (opacity, roughness, metalness, transmission) → `normalized` transformer
599
+ * - Side property → `side` transformer (Front/Back/Double switch)
600
+ * - All others → `generic` transformer
601
+ *
602
+ * @param target - The parent object containing the property
603
+ * @param path - The property name on the target
604
+ * @param fullPropertyPath - The full dot-notation path to the property
605
+ * @returns The appropriate transformer for the property
606
+ *
607
+ * @example
608
+ * ```typescript
609
+ * import { getDefaultTransformer } from 'angular-three-theatre';
610
+ *
611
+ * const mesh = new THREE.Mesh();
612
+ * const transformer = getDefaultTransformer(mesh, 'rotation', 'rotation');
613
+ * // Returns the euler transformer
614
+ * ```
615
+ */
276
616
  function getDefaultTransformer(target, path, fullPropertyPath) {
277
617
  const property = target[path];
278
618
  if (property.isEuler)
@@ -305,11 +645,67 @@ function getDefaultTransformer(target, path, fullPropertyPath) {
305
645
  }
306
646
 
307
647
  const updateProjectionMatrixKeys = ['fov', 'near', 'far', 'zoom', 'left', 'right', 'top', 'bottom', 'aspect'];
648
+ /**
649
+ * Directive that synchronizes Three.js object properties with Theatre.js animations.
650
+ *
651
+ * This directive allows you to expose specific properties of a Three.js object
652
+ * to Theatre.js for animation. It automatically handles property transformation
653
+ * (e.g., converting Euler angles to degrees for the UI).
654
+ *
655
+ * Must be used within a `TheatreSheetObject` context.
656
+ *
657
+ * @example
658
+ * ```html
659
+ * <ng-template sheetObject="myMaterial">
660
+ * <ngt-mesh-standard-material
661
+ * [sync]="material"
662
+ * [syncProps]="['opacity', 'roughness', 'metalness']"
663
+ * #material
664
+ * />
665
+ * </ng-template>
666
+ * ```
667
+ *
668
+ * @example
669
+ * ```html
670
+ * <!-- With custom property mapping -->
671
+ * <ng-template sheetObject="myLight">
672
+ * <ngt-point-light
673
+ * [sync]="light"
674
+ * [syncProps]="[
675
+ * ['intensity', { label: 'Light Intensity', key: 'lightIntensity' }],
676
+ * 'color'
677
+ * ]"
678
+ * #light
679
+ * />
680
+ * </ng-template>
681
+ * ```
682
+ *
683
+ * @typeParam TObject - The type of the Three.js object being synchronized
684
+ */
308
685
  class TheatreSheetObjectSync {
309
686
  constructor() {
687
+ /**
688
+ * The Three.js object to synchronize with Theatre.js.
689
+ * Can be an object reference, ElementRef, or a function returning either.
690
+ */
310
691
  this.parent = input.required({ ...(ngDevMode ? { debugName: "parent" } : {}), alias: 'sync' });
692
+ /**
693
+ * Array of property paths to synchronize with Theatre.js.
694
+ *
695
+ * Each item can be:
696
+ * - A string property path (e.g., 'opacity', 'position.x')
697
+ * - A tuple of [propertyPath, keyOrOptions] where options can include:
698
+ * - `label`: Display label in Theatre.js Studio
699
+ * - `key`: Unique key for the property in Theatre.js
700
+ * - `transformer`: Custom transformer for the property value
701
+ *
702
+ * @default []
703
+ */
311
704
  this.props = input([], { ...(ngDevMode ? { debugName: "props" } : {}), alias: 'syncProps' });
312
705
  this.theatreSheetObject = inject(TheatreSheetObject$1);
706
+ /**
707
+ * Computed signal containing the Theatre.js sheet object instance.
708
+ */
313
709
  this.sheetObject = computed(() => this.theatreSheetObject.sheetObject(), ...(ngDevMode ? [{ debugName: "sheetObject" }] : []));
314
710
  this.studio = inject(THEATRE_STUDIO, { optional: true });
315
711
  this.parentRef = computed(() => {
@@ -389,6 +785,13 @@ class TheatreSheetObjectSync {
389
785
  this.theatreSheetObject.removeProps(Object.keys(this.propsMapping));
390
786
  });
391
787
  }
788
+ /**
789
+ * Captures the current values of all synchronized properties from the Three.js object
790
+ * and commits them to Theatre.js.
791
+ *
792
+ * This is useful for "baking" the current state of the Three.js object into the
793
+ * Theatre.js animation. Requires Theatre.js Studio to be available.
794
+ */
392
795
  capture() {
393
796
  const studio = this.studio?.();
394
797
  if (!studio)
@@ -414,6 +817,12 @@ class TheatreSheetObjectSync {
414
817
  });
415
818
  scrub.commit();
416
819
  }
820
+ /**
821
+ * Converts a property path (e.g., 'position.x') to a safe alphanumeric key.
822
+ *
823
+ * @param propPath - The property path to convert
824
+ * @returns A safe alphanumeric key string
825
+ */
417
826
  resolvePropertyPath(propPath) {
418
827
  return (propPath
419
828
  // make the label alphanumeric by first removing dots (fundamental feature for pierced props)
@@ -431,6 +840,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
431
840
  args: [{ selector: '[sync]', exportAs: 'sync' }]
432
841
  }], ctorParameters: () => [], propDecorators: { parent: [{ type: i0.Input, args: [{ isSignal: true, alias: "sync", required: true }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "syncProps", required: false }] }] } });
433
842
 
843
+ /**
844
+ * Component that provides transform controls for animating position, rotation, and scale
845
+ * of child Three.js objects via Theatre.js.
846
+ *
847
+ * When the sheet object is selected in Theatre.js Studio, transform controls appear
848
+ * allowing direct manipulation of the object's transform. Changes are captured and
849
+ * committed to Theatre.js.
850
+ *
851
+ * Must be used within a `TheatreSheetObject` context.
852
+ *
853
+ * @example
854
+ * ```html
855
+ * <ng-template sheetObject="myCube">
856
+ * <theatre-transform>
857
+ * <ngt-mesh>
858
+ * <ngt-box-geometry />
859
+ * <ngt-mesh-standard-material />
860
+ * </ngt-mesh>
861
+ * </theatre-transform>
862
+ * </ng-template>
863
+ * ```
864
+ *
865
+ * @example
866
+ * ```html
867
+ * <!-- With custom key and options -->
868
+ * <ng-template sheetObject="scene">
869
+ * <theatre-transform key="cubeTransform" label="Cube" [options]="{ mode: 'rotate' }">
870
+ * <ngt-mesh />
871
+ * </theatre-transform>
872
+ * </ng-template>
873
+ * ```
874
+ *
875
+ * @typeParam TLabel - The type of the label string
876
+ */
434
877
  class TheatreSheetObjectTransform {
435
878
  onMouseDown() {
436
879
  if (!this.studio)
@@ -465,12 +908,31 @@ class TheatreSheetObjectTransform {
465
908
  });
466
909
  }
467
910
  constructor() {
911
+ /**
912
+ * Display label for the transform properties in Theatre.js Studio.
913
+ */
468
914
  this.label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
915
+ /**
916
+ * Unique key for grouping the transform properties in Theatre.js.
917
+ * If provided, position/rotation/scale will be nested under this key.
918
+ */
469
919
  this.key = input(...(ngDevMode ? [undefined, { debugName: "key" }] : []));
920
+ /**
921
+ * Options for the transform controls gizmo.
922
+ * Allows configuring the transform mode, snap values, and coordinate space.
923
+ *
924
+ * @default {}
925
+ */
470
926
  this.options = input({}, ...(ngDevMode ? [{ debugName: "options" }] : []));
927
+ /**
928
+ * Reference to the Three.js Group element that wraps the transformed content.
929
+ */
471
930
  this.groupRef = viewChild.required('group');
472
931
  this.controlsRef = viewChild(NgtsTransformControls, ...(ngDevMode ? [{ debugName: "controlsRef" }] : []));
473
932
  this.theatreSheetObject = inject(TheatreSheetObject$1);
933
+ /**
934
+ * Computed signal containing the Theatre.js sheet object instance.
935
+ */
474
936
  this.sheetObject = computed(() => this.theatreSheetObject.sheetObject(), ...(ngDevMode ? [{ debugName: "sheetObject" }] : []));
475
937
  this.studio = inject(THEATRE_STUDIO, { optional: true });
476
938
  this.selected = this.theatreSheetObject.selected.asReadonly();
@@ -580,12 +1042,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
580
1042
  }]
581
1043
  }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], groupRef: [{ type: i0.ViewChild, args: ['group', { isSignal: true }] }], controlsRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => NgtsTransformControls), { isSignal: true }] }] } });
582
1044
 
1045
+ /**
1046
+ * Combined array of sheet object directives for convenient importing.
1047
+ *
1048
+ * Includes:
1049
+ * - `TheatreSheetObject` - Base directive for creating sheet objects
1050
+ * - `TheatreSheetObjectTransform` - Component for animating transform properties
1051
+ * - `TheatreSheetObjectSync` - Directive for syncing arbitrary object properties
1052
+ *
1053
+ * @example
1054
+ * ```typescript
1055
+ * import { TheatreSheetObject } from 'angular-three-theatre';
1056
+ *
1057
+ * @Component({
1058
+ * imports: [TheatreSheetObject],
1059
+ * template: `
1060
+ * <ng-template sheetObject="myObject">
1061
+ * <theatre-transform>
1062
+ * <ngt-mesh />
1063
+ * </theatre-transform>
1064
+ * </ng-template>
1065
+ * `
1066
+ * })
1067
+ * export class MyComponent {}
1068
+ * ```
1069
+ */
583
1070
  const TheatreSheetObject = [TheatreSheetObject$1, TheatreSheetObjectTransform, TheatreSheetObjectSync];
584
1071
 
1072
+ /**
1073
+ * Directive that initializes and manages the Theatre.js Studio.
1074
+ *
1075
+ * Theatre.js Studio is a visual editor that allows you to create and edit
1076
+ * animations directly in the browser. The studio UI is dynamically imported
1077
+ * to avoid including it in production builds.
1078
+ *
1079
+ * This directive must be applied to a `theatre-project` element and provides
1080
+ * the studio instance via the `THEATRE_STUDIO` injection token.
1081
+ *
1082
+ * @example
1083
+ * ```html
1084
+ * <!-- Enable studio (default) -->
1085
+ * <theatre-project studio>
1086
+ * <ng-container sheet="scene">...</ng-container>
1087
+ * </theatre-project>
1088
+ *
1089
+ * <!-- Conditionally enable/disable studio -->
1090
+ * <theatre-project [studio]="isDevelopment">
1091
+ * <ng-container sheet="scene">...</ng-container>
1092
+ * </theatre-project>
1093
+ *
1094
+ * <!-- Disable studio -->
1095
+ * <theatre-project [studio]="false">
1096
+ * <ng-container sheet="scene">...</ng-container>
1097
+ * </theatre-project>
1098
+ * ```
1099
+ */
585
1100
  class TheatreStudio {
586
1101
  constructor() {
1102
+ /**
1103
+ * Whether the studio UI should be visible.
1104
+ * When false, the studio UI is hidden but the studio instance remains active.
1105
+ *
1106
+ * @default true
1107
+ */
587
1108
  this.enabled = input(true, { ...(ngDevMode ? { debugName: "enabled" } : {}), alias: 'studio', transform: booleanAttribute });
588
1109
  this.Studio = signal(null, ...(ngDevMode ? [{ debugName: "Studio" }] : []));
1110
+ /**
1111
+ * Read-only signal containing the Theatre.js Studio instance.
1112
+ * May be null while the studio is being loaded.
1113
+ */
589
1114
  this.studio = this.Studio.asReadonly();
590
1115
  import('@theatre/studio').then((m) => {
591
1116
  const Studio = 'default' in m.default ? m.default.default : m.default;
@@ -630,12 +1155,65 @@ const defaultOptions = {
630
1155
  autopause: false,
631
1156
  delay: 0,
632
1157
  };
1158
+ /**
1159
+ * Directive that provides control over a Theatre.js sequence.
1160
+ *
1161
+ * A sequence controls the playback of animations within a sheet. This directive
1162
+ * provides methods to play, pause, and reset the sequence, as well as reactive
1163
+ * signals for the current position, playing state, and length.
1164
+ *
1165
+ * Must be used on an element that also has the `sheet` directive.
1166
+ *
1167
+ * @example
1168
+ * ```html
1169
+ * <ng-container sheet="scene" [sequence]="{ autoplay: true, rate: 1 }" #seq="sequence">
1170
+ * <p>Position: {{ seq.position() }}</p>
1171
+ * <button (click)="seq.play()">Play</button>
1172
+ * <button (click)="seq.pause()">Pause</button>
1173
+ * </ng-container>
1174
+ * ```
1175
+ *
1176
+ * @example
1177
+ * ```html
1178
+ * <!-- With audio synchronization -->
1179
+ * <ng-container
1180
+ * sheet="scene"
1181
+ * [sequence]="{ autoplay: true }"
1182
+ * [sequenceAudio]="{ source: '/audio/soundtrack.mp3' }"
1183
+ * />
1184
+ * ```
1185
+ */
633
1186
  class TheatreSequence {
634
1187
  constructor() {
1188
+ /**
1189
+ * Sequence configuration options.
1190
+ * Merged with default options using ngxtension's mergeInputs.
1191
+ *
1192
+ * @default { rate: 1, autoplay: false, autopause: false, delay: 0 }
1193
+ */
635
1194
  this.options = input(defaultOptions, { ...(ngDevMode ? { debugName: "options" } : {}), alias: 'sequence', transform: mergeInputs(defaultOptions) });
1195
+ /**
1196
+ * Audio options for synchronizing playback with an audio file.
1197
+ * When provided, the sequence will be synchronized with the audio.
1198
+ */
636
1199
  this.audioOptions = input(undefined, { ...(ngDevMode ? { debugName: "audioOptions" } : {}), alias: 'sequenceAudio' });
1200
+ /**
1201
+ * Two-way bindable signal for the current playback position in seconds.
1202
+ *
1203
+ * @default 0
1204
+ */
637
1205
  this.position = model(0, ...(ngDevMode ? [{ debugName: "position" }] : []));
1206
+ /**
1207
+ * Two-way bindable signal indicating whether the sequence is currently playing.
1208
+ *
1209
+ * @default false
1210
+ */
638
1211
  this.playing = model(false, ...(ngDevMode ? [{ debugName: "playing" }] : []));
1212
+ /**
1213
+ * Two-way bindable signal for the total length of the sequence in seconds.
1214
+ *
1215
+ * @default 0
1216
+ */
639
1217
  this.length = model(0, ...(ngDevMode ? [{ debugName: "length" }] : []));
640
1218
  this.playOptions = omit(this.options, ['autoplay', 'autopause', 'delay', 'autoreset']);
641
1219
  this.autoplay = pick(this.options, 'autoplay');
@@ -644,6 +1222,9 @@ class TheatreSequence {
644
1222
  this.delay = pick(this.options, 'delay');
645
1223
  this.project = inject(TheatreProject);
646
1224
  this.sheet = inject(TheatreSheet$1, { host: true });
1225
+ /**
1226
+ * Computed signal containing the Theatre.js sequence instance.
1227
+ */
647
1228
  this.sequence = computed(() => this.sheet.sheet().sequence, ...(ngDevMode ? [{ debugName: "sequence" }] : []));
648
1229
  effect((onCleanup) => {
649
1230
  const autoplay = untracked(this.autoplay);
@@ -698,10 +1279,21 @@ class TheatreSequence {
698
1279
  });
699
1280
  });
700
1281
  }
1282
+ /**
1283
+ * Pauses the sequence playback at the current position.
1284
+ */
701
1285
  pause() {
702
1286
  const sequence = this.sequence();
703
1287
  sequence.pause();
704
1288
  }
1289
+ /**
1290
+ * Starts or resumes sequence playback.
1291
+ *
1292
+ * Waits for the project to be ready before starting playback.
1293
+ * Options are merged with the configured play options.
1294
+ *
1295
+ * @param options - Optional play options that override the configured options
1296
+ */
705
1297
  play(options = {}) {
706
1298
  const sequence = this.sequence();
707
1299
  const project = this.project.project();
@@ -709,6 +1301,12 @@ class TheatreSequence {
709
1301
  sequence.play({ ...this.playOptions(), ...options });
710
1302
  });
711
1303
  }
1304
+ /**
1305
+ * Resets the sequence position to 0.
1306
+ *
1307
+ * If the sequence was playing before reset, it will continue playing
1308
+ * from the beginning.
1309
+ */
712
1310
  reset() {
713
1311
  const sequence = this.sequence();
714
1312
  const isPlaying = val(sequence.pointer.playing);
@@ -724,6 +1322,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
724
1322
  args: [{ selector: '[sheet][sequence]', exportAs: 'sequence' }]
725
1323
  }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "sequence", required: false }] }], audioOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "sequenceAudio", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }, { type: i0.Output, args: ["positionChange"] }], playing: [{ type: i0.Input, args: [{ isSignal: true, alias: "playing", required: false }] }, { type: i0.Output, args: ["playingChange"] }], length: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }, { type: i0.Output, args: ["lengthChange"] }] } });
726
1324
 
1325
+ /**
1326
+ * Angular Three Theatre.js integration library
1327
+ *
1328
+ * This library provides Angular components and directives for integrating
1329
+ * Theatre.js animation toolkit with Angular Three applications.
1330
+ *
1331
+ * @packageDocumentation
1332
+ */
1333
+ /**
1334
+ * Combined array of TheatreSheet and TheatreSequence directives for convenient importing.
1335
+ *
1336
+ * @example
1337
+ * ```typescript
1338
+ * import { TheatreSheet } from 'angular-three-theatre';
1339
+ *
1340
+ * @Component({
1341
+ * imports: [TheatreSheet],
1342
+ * template: `<ng-container sheet="mySheet" sequence />`
1343
+ * })
1344
+ * export class MyComponent {}
1345
+ * ```
1346
+ */
727
1347
  const TheatreSheet = [TheatreSheet$1, TheatreSequence];
728
1348
 
729
1349
  /**