@hology/core 0.0.195 → 0.0.197

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.
Files changed (37) hide show
  1. package/dist/effects/sequence/sequence-action.d.ts +8 -1
  2. package/dist/effects/sequence/sequence-actor.d.ts +14 -2
  3. package/dist/effects/sequence/sequence-actor.js +1 -1
  4. package/dist/effects/sequence/sequence-data.d.ts +67 -2
  5. package/dist/effects/sequence/sequence-data.js +1 -1
  6. package/dist/effects/sequence/sequence-definitions.d.ts +11 -7
  7. package/dist/effects/sequence/sequence-definitions.js +1 -1
  8. package/dist/effects/sequence/sequence-ops.js +1 -1
  9. package/dist/effects/sequence/sequence-player.d.ts +59 -2
  10. package/dist/effects/sequence/sequence-player.js +1 -1
  11. package/dist/effects/sequence/sequence-value-lane.d.ts +1 -0
  12. package/dist/effects/sequence/sequence-value-lane.js +1 -1
  13. package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
  14. package/dist/gameplay/actors/builtin/post-process-volume-actor.js +1 -1
  15. package/dist/gameplay/initiate.d.ts +1 -0
  16. package/dist/gameplay/initiate.js +1 -1
  17. package/dist/gameplay/services/physics/physics-system.js +1 -1
  18. package/dist/gameplay/services/render.d.ts +15 -2
  19. package/dist/gameplay/services/render.js +1 -1
  20. package/dist/rendering.d.ts +5 -1
  21. package/dist/rendering.js +1 -1
  22. package/dist/scene/asset-resource-loader.js +1 -1
  23. package/dist/scene/collision/collision-shape-import.js +1 -1
  24. package/dist/scene/collision/collision-shape.js +1 -1
  25. package/dist/scene/materializer.js +1 -1
  26. package/dist/scene/storage/storage.d.ts +2 -0
  27. package/dist/scene/storage/storage.js +1 -1
  28. package/dist/shader/builtin/standard-shader.js +1 -1
  29. package/dist/test/collision-shape-import.test.js +1 -1
  30. package/dist/test/sequence-camera-control.test.d.ts +2 -0
  31. package/dist/test/sequence-camera-control.test.js +4 -0
  32. package/dist/test/sequence-property-parameters.test.d.ts +2 -0
  33. package/dist/test/sequence-property-parameters.test.js +4 -0
  34. package/dist/test/storage-case-collision.test.d.ts +2 -0
  35. package/dist/test/storage-case-collision.test.js +4 -0
  36. package/package.json +1 -1
  37. package/tsconfig.tsbuildinfo +1 -1
@@ -8,11 +8,18 @@ import { SequenceLocatorReader } from './sequence-locator.js';
8
8
  export interface SequenceAction extends SequenceLocatorReader {
9
9
  /** Bind a role to a runtime target for dynamic actor binding */
10
10
  bindRole(role: SequenceRole, target: BaseActor | Object3D): void;
11
- play(): void;
11
+ play(options?: SequencePlayOptions): void;
12
12
  pause(): void;
13
13
  stop(): void;
14
14
  restart(): void;
15
15
  seek(time: number): void;
16
16
  dispose(): void;
17
17
  }
18
+ export interface SequencePlayOptions {
19
+ /**
20
+ * When true, camera clips are allowed to take control of the local render camera
21
+ * for this playback.
22
+ */
23
+ cameraControlEnabled?: boolean;
24
+ }
18
25
  //# sourceMappingURL=sequence-action.d.ts.map
@@ -4,7 +4,7 @@ import { SequencePlaybackState } from './sequence-player.js';
4
4
  import { Asset } from '../../scene/model.js';
5
5
  import { Subject } from 'rxjs';
6
6
  import { Object3D } from 'three';
7
- import { SequenceAction } from './sequence-action.js';
7
+ import { SequenceAction, SequencePlayOptions } from './sequence-action.js';
8
8
  import { SequenceLocatorSnapshot } from './sequence-locator.js';
9
9
  /**
10
10
  * SequenceActor is an actor that plays a sequence in the world.
@@ -38,6 +38,17 @@ export declare class SequenceActor extends BaseActor implements SequenceAction {
38
38
  * If set, this takes precedence over inline sequenceData.
39
39
  */
40
40
  sequenceAssetId: string | null;
41
+ /**
42
+ * When true, camera clips in this sequence are allowed to take control of
43
+ * the local rendered camera. Keep this disabled for remote/simulated ability
44
+ * playback and enable only on the locally controlled client.
45
+ */
46
+ private _cameraControlEnabled;
47
+ get cameraControlEnabled(): boolean;
48
+ set cameraControlEnabled(value: boolean);
49
+ private _cameraControlTrackId;
50
+ get cameraControlTrackId(): string | null;
51
+ set cameraControlTrackId(value: string | null);
41
52
  /**
42
53
  * Playback rate multiplier
43
54
  */
@@ -114,10 +125,11 @@ export declare class SequenceActor extends BaseActor implements SequenceAction {
114
125
  bindObject(objectId: string, target: Object3D | BaseActor): void;
115
126
  getLocator(bindingId: string): SequenceLocatorSnapshot | null;
116
127
  getLocators(bindingId: string): SequenceLocatorSnapshot[];
128
+ getActiveTrackObjects(trackId: string): Object3D[];
117
129
  /**
118
130
  * Start or resume playback
119
131
  */
120
- play(): void;
132
+ play(options?: SequencePlayOptions): void;
121
133
  /**
122
134
  * Pause playback
123
135
  */
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import{Actor as s,BaseActor as r}from"../../gameplay/actors/actor.js";import{inject as i}from"../../gameplay/inject.js";import{ViewController as a}from"../../gameplay/services/render.js";import{AssetLoader as o}from"../../gameplay/services/asset-loader.js";import{World as l}from"../../gameplay/services/world.js";import{ActorFactory as p}from"../../gameplay/actors/factory.js";import{VfxService as n}from"../../effects/vfx/vfx-service.js";import{Parameter as h}from"../../shader/parameter.js";import{createSequenceData as c}from"./sequence-data.js";import{SequencePlayer as y,SequencePlaybackState as d}from"./sequence-player.js";import{Subject as m,takeUntil as u}from"rxjs";let f=class extends r{constructor(){super(...arguments),this.sequenceData=c(),this.sequenceAssetId=null,this.onComplete=new m,this.onLoop=new m,this.player=new y,this.viewController=i(a),this.assetLoader=i(o),this.world=i(l),this.actorFactory=i(p),this.vfxService=i(n),this.sourceAsset=null}get timescale(){return this.player.timescale}set timescale(e){this.player.timescale=e}get loop(){return this.player.loop}set loop(e){this.player.loop=e}get state(){return this.player.state}get time(){return this.player.time}get duration(){return this.player.duration}get paused(){return this.player.state===d.Paused}get externalTimeControl(){return this.player.externalTimeControl}set externalTimeControl(e){this.player.externalTimeControl=e}get inEditor(){return this.player.inEditor}set inEditor(e){this.player.inEditor=e}async onInit(){this.player.setWorld(this.world),this.player.setAudioListener(this.viewController.audioListener),this.player.setAssetLoader(this.assetLoader),this.player.setActorFactory(this.actorFactory),this.player.setVfxService(this.vfxService),this.viewController.onUpdate(this).pipe(u(this.disposed)).subscribe(e=>this.player.update(e)),this.player.onComplete.pipe(u(this.disposed)).subscribe(()=>this.onComplete.next()),this.player.onLoop.pipe(u(this.disposed)).subscribe(e=>this.onLoop.next(e)),this.sequenceAssetId?await this.loadFromAssetId(this.sequenceAssetId):this.sequenceData&&this.player.load(this.sequenceData)}async loadFromAsset(e){if("sequence"!==e.type)throw new Error(`Asset must be a sequence asset but is ${e.type}`);this.sourceAsset=e,this.sourceAsset.sequence&&(this.sequenceData=this.sourceAsset.sequence,this.player.load(this.sequenceData))}async loadFromAssetId(e){const t=await this.assetLoader.getAsset(e);t&&await this.loadFromAsset(t)}setSequenceData(e){this.sequenceData=e,this.player.load(e)}bindRole(e,t){this.player.bindRole(e,t)}bindObject(e,t){this.player.bindObject(e,t)}getLocator(e){return this.player.getLocator(e)}getLocators(e){return this.player.getLocators(e)}play(){this.player.play()}pause(){this.player.pause()}stop(){this.player.stop()}restart(){this.player.restart()}seek(e){this.player.seek(e)}refreshAsset(e){this.player.refreshAsset(e)}onUpdate(e){}onEndPlay(){this.player.dispose()}dispose(){this.world.removeActor(this)}};e([h({label:"Sequence Data"}),t("design:type",Object)],f.prototype,"sequenceData",void 0),f=e([s()],f);export{f as SequenceActor};/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import{Actor as s,BaseActor as r}from"../../gameplay/actors/actor.js";import{inject as a}from"../../gameplay/inject.js";import{ViewController as o}from"../../gameplay/services/render.js";import{AssetLoader as i}from"../../gameplay/services/asset-loader.js";import{World as l}from"../../gameplay/services/world.js";import{ActorFactory as n}from"../../gameplay/actors/factory.js";import{VfxService as p}from"../../effects/vfx/vfx-service.js";import{Parameter as c}from"../../shader/parameter.js";import{createSequenceData as h}from"./sequence-data.js";import{SequencePlayer as d,SequencePlaybackState as m}from"./sequence-player.js";import{Subject as y,takeUntil as u}from"rxjs";let b=class extends r{constructor(){super(...arguments),this.sequenceData=h(),this.sequenceAssetId=null,this._cameraControlEnabled=!1,this._cameraControlTrackId=null,this.onComplete=new y,this.onLoop=new y,this.player=new d,this.viewController=a(o),this.assetLoader=a(i),this.world=a(l),this.actorFactory=a(n),this.vfxService=a(p),this.sourceAsset=null}get cameraControlEnabled(){return this._cameraControlEnabled}set cameraControlEnabled(e){this._cameraControlEnabled=e,this.player.cameraControlEnabled=e}get cameraControlTrackId(){return this._cameraControlTrackId}set cameraControlTrackId(e){this._cameraControlTrackId=e,this.player.cameraControlTrackId=e}get timescale(){return this.player.timescale}set timescale(e){this.player.timescale=e}get loop(){return this.player.loop}set loop(e){this.player.loop=e}get state(){return this.player.state}get time(){return this.player.time}get duration(){return this.player.duration}get paused(){return this.player.state===m.Paused}get externalTimeControl(){return this.player.externalTimeControl}set externalTimeControl(e){this.player.externalTimeControl=e}get inEditor(){return this.player.inEditor}set inEditor(e){this.player.inEditor=e}async onInit(){this.player.setWorld(this.world),this.player.setViewController(this.viewController),this.player.setAudioListener(this.viewController.audioListener),this.player.setAssetLoader(this.assetLoader),this.player.setActorFactory(this.actorFactory),this.player.setVfxService(this.vfxService),this.viewController.onUpdate(this).pipe(u(this.disposed)).subscribe(e=>this.player.update(e)),this.player.onComplete.pipe(u(this.disposed)).subscribe(()=>this.onComplete.next()),this.player.onLoop.pipe(u(this.disposed)).subscribe(e=>this.onLoop.next(e)),this.sequenceAssetId?await this.loadFromAssetId(this.sequenceAssetId):this.sequenceData&&this.player.load(this.sequenceData)}async loadFromAsset(e){if("sequence"!==e.type)throw new Error(`Asset must be a sequence asset but is ${e.type}`);this.sourceAsset=e,this.sourceAsset.sequence&&(this.sequenceData=this.sourceAsset.sequence,this.player.load(this.sequenceData))}async loadFromAssetId(e){const t=await this.assetLoader.getAsset(e);t&&await this.loadFromAsset(t)}setSequenceData(e){this.sequenceData=e,this.player.load(e)}bindRole(e,t){this.player.bindRole(e,t)}bindObject(e,t){this.player.bindObject(e,t)}getLocator(e){return this.player.getLocator(e)}getLocators(e){return this.player.getLocators(e)}getActiveTrackObjects(e){return this.player.getActiveTrackObjects(e)}play(e){this.player.cameraControlEnabled=e?.cameraControlEnabled??this.cameraControlEnabled,this.player.play()}pause(){this.player.pause()}stop(){this.player.stop()}restart(){this.player.restart()}seek(e){this.player.seek(e)}refreshAsset(e){this.player.refreshAsset(e)}onUpdate(e){}onEndPlay(){this.player.dispose()}dispose(){this.world.removeActor(this)}};e([c({label:"Sequence Data"}),t("design:type",Object)],b.prototype,"sequenceData",void 0),e([c({label:"Camera Control Enabled"}),t("design:type",Boolean),t("design:paramtypes",[Boolean])],b.prototype,"cameraControlEnabled",null),b=e([s()],b);export{b as SequenceActor};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,5 +1,23 @@
1
1
  import { AssetId, CustomParamValue, SerializedParamType } from '../../scene/model.js';
2
2
  import { AudioParameterId } from './audio-parameters.js';
3
+ export interface SequencePropertyOption {
4
+ name: string;
5
+ value: unknown;
6
+ }
7
+ export interface PropertySubTrackOptions {
8
+ propertyPath: string;
9
+ propertyType: SerializedParamType;
10
+ name?: string;
11
+ label?: string;
12
+ group?: string;
13
+ help?: string;
14
+ range?: [number, number];
15
+ precision?: number;
16
+ stepSize?: number;
17
+ options?: SequencePropertyOption[];
18
+ editorInput?: 'colorGrade';
19
+ defaultValue?: CustomParamValue;
20
+ }
3
21
  /**
4
22
  * The main sequence data structure containing all tracks and playback settings.
5
23
  * This is stored as a parameter on SequenceActor or as part of a SequenceAsset.
@@ -89,6 +107,12 @@ export interface LocatorTrack extends BaseTrack {
89
107
  */
90
108
  export interface CameraTrack extends BaseTrack {
91
109
  type: 'camera';
110
+ /** Runtime role used as the camera's parent/anchor when set. */
111
+ parentRole?: SequenceRole | null;
112
+ /** Optional socket/bone name on parentRole. */
113
+ parentRoleSocketName?: string;
114
+ /** Camera shot clips placed on the timeline */
115
+ clips: CameraClipInstance[];
92
116
  /** Camera settings */
93
117
  cameraSettings: {
94
118
  fov: number;
@@ -202,6 +226,24 @@ export interface PropertySubTrack extends BaseSubTrack {
202
226
  propertyPath: string;
203
227
  /** The type of property being animated */
204
228
  propertyType: SerializedParamType;
229
+ /** Artist-facing parameter label */
230
+ label?: string;
231
+ /** Optional editor group for the parameter */
232
+ group?: string;
233
+ /** Help text shown in the editor */
234
+ help?: string;
235
+ /** Numeric range for scalar/vector editing */
236
+ range?: [number, number];
237
+ /** Numeric display precision */
238
+ precision?: number;
239
+ /** Drag/edit step size */
240
+ stepSize?: number;
241
+ /** Discrete options for enum-like values */
242
+ options?: SequencePropertyOption[];
243
+ /** Specialized editor input hint */
244
+ editorInput?: 'colorGrade';
245
+ /** Default keyframe value when adding new keys */
246
+ defaultValue?: CustomParamValue;
205
247
  /** Keyframes for property animation */
206
248
  keyframes: PropertyKeyframe[];
207
249
  }
@@ -248,7 +290,7 @@ export interface AudioParameterSubTrack extends BaseSubTrack {
248
290
  export type SubTrack = TransformSubTrack | AnimationSubTrack | PropertySubTrack | MaterialSubTrack | VisibilitySubTrack | EventSubTrack | AudioParameterSubTrack;
249
291
  export type SequenceValueSubTrack = PropertySubTrack | MaterialSubTrack | AudioParameterSubTrack;
250
292
  export type SequenceKeyframeSubTrack = TransformSubTrack | PropertySubTrack | MaterialSubTrack | VisibilitySubTrack | AudioParameterSubTrack;
251
- export type SequenceDirectClipTrack = AudioTrack | VfxTrack | SpawnTrack;
293
+ export type SequenceDirectClipTrack = CameraTrack | AudioTrack | VfxTrack | SpawnTrack;
252
294
  export type SequenceAnimationHostTrack = ObjectTrack | CameraTrack | SpawnTrack;
253
295
  export type AnimationClipRetimingMode = 'uniform' | 'impact' | 'advanced';
254
296
  export interface AnimationClipRetimingPoint {
@@ -310,6 +352,25 @@ export interface VisibilityKeyframe {
310
352
  /** Whether the object is visible */
311
353
  visible: boolean;
312
354
  }
355
+ /**
356
+ * A camera shot clip placed on the timeline.
357
+ * While active, the camera track can take over the rendered view if the
358
+ * SequenceActor has camera control enabled.
359
+ */
360
+ export interface CameraClipInstance {
361
+ /** Unique identifier */
362
+ id: string;
363
+ /** Start time of this clip on the timeline */
364
+ startTime: number;
365
+ /** Duration of this clip instance */
366
+ duration: number;
367
+ /** Blend from the current gameplay camera into this shot. */
368
+ blendInDuration: number;
369
+ /** Blend from this shot back to the current gameplay camera. */
370
+ blendOutDuration: number;
371
+ /** Interpolation curve for blend in/out. */
372
+ blendInterpolation: InterpolationMode;
373
+ }
313
374
  /**
314
375
  * An instance of an animation clip placed on the timeline
315
376
  */
@@ -428,6 +489,10 @@ export declare function createObjectTrack(name?: string): ObjectTrack;
428
489
  * Creates a new camera track
429
490
  */
430
491
  export declare function createCameraTrack(name?: string): CameraTrack;
492
+ /**
493
+ * Creates a new camera shot clip instance
494
+ */
495
+ export declare function createCameraClipInstance(startTime: number, duration: number): CameraClipInstance;
431
496
  /**
432
497
  * Creates a new audio track
433
498
  */
@@ -463,7 +528,7 @@ export declare function createAudioParameterSubTrack(parameter?: AudioParameterI
463
528
  /**
464
529
  * Creates a new property sub-track
465
530
  */
466
- export declare function createPropertySubTrack(propertyPath?: string, propertyType?: SerializedParamType): PropertySubTrack;
531
+ export declare function createPropertySubTrack(options?: PropertySubTrackOptions | string, propertyType?: SerializedParamType): PropertySubTrack;
467
532
  /**
468
533
  * Creates a new material sub-track
469
534
  */
@@ -1,4 +1,4 @@
1
- import{SerializedParamType as e}from"../../scene/model.js";import{randomString as t}from"../../utils/math.js";import{getAudioParameterDefinition as r}from"./audio-parameters.js";export class Sequence{constructor(e){this.data=e}}export var SequenceRole;!function(e){e.Self="self",e.Target="target",e.Target2="target2",e.Target3="target3",e.Secondary="secondary"}(SequenceRole||(SequenceRole={}));export function createSequenceData(){return{duration:5,loop:!1,playbackRate:1,tracks:[]}}export function createObjectTrack(e="Object Track"){return{id:t(),name:e,type:"object",muted:!1,locked:!1,targetId:null,role:null,subTracks:[]}}export function createCameraTrack(e="Camera Track"){return{id:t(),name:e,type:"camera",muted:!1,locked:!1,cameraSettings:{fov:60,near:.1,far:1e3},subTracks:[]}}export function createAudioTrack(e="Audio Track"){return{id:t(),name:e,type:"audio",muted:!1,locked:!1,clips:[],subTracks:[],volume:1,spatial:!1}}export function createVfxTrack(e="VFX Track"){return{id:t(),name:e,type:"vfx",muted:!1,locked:!1,clips:[],position:[0,0,0],rotation:[0,0,0],scale:[1,1,1],subTracks:[]}}export function createSpawnTrack(e="Spawn Track"){return{id:t(),name:e,type:"spawn",muted:!1,locked:!1,spawnType:"mesh",role:null,clips:[],subTracks:[]}}export function createSpawnClipInstance(e,r){return{id:t(),startTime:e,duration:r}}export function createGroupTrack(e="Group"){return{id:t(),name:e,type:"group",muted:!1,locked:!1,collapsed:!1,childTracks:[],subTracks:[]}}export function createTransformSubTrack(){return{id:t(),name:"Transform",type:"transform",muted:!1,components:{position:!0,rotation:!0,scale:!0},keyframes:[]}}export function createAnimationSubTrack(e="Animation"){return{id:t(),name:e,type:"animation",muted:!1,clips:[]}}export function createAudioParameterSubTrack(e="volume"){const a=r(e);return{id:t(),name:a.displayName,type:"audioParameter",muted:!1,parameter:e,keyframes:[]}}export function createPropertySubTrack(r="",a=e.Number){return{id:t(),name:r||"Property",type:"property",muted:!1,propertyPath:r,propertyType:a,keyframes:[]}}export function createMaterialSubTrack(r="",a=e.Number,n=0){return{id:t(),name:r||"Material",type:"material",muted:!1,materialSlot:n,uniformName:r,uniformType:a,keyframes:[]}}export function createVisibilitySubTrack(e="Visibility"){return{id:t(),name:e,type:"visibility",muted:!1,keyframes:[]}}export function createTransformKeyframe(e){return{id:t(),time:e,position:[0,0,0],rotation:[0,0,0],scale:[1,1,1],interpolation:"cubic"}}export function createPropertyKeyframe(r,a={type:e.Number,value:0}){return{id:t(),time:r,value:a,interpolation:"linear"}}export function createAnimationClipInstance(e,r,a){return{id:t(),animationClipAssetId:e,startTime:r,duration:a,clipStartOffset:0,clipEndOffset:0,playbackRate:1,fadeInDuration:.2,retiming:void 0,rootMotion:!1}}export function createAnimationClipRetimingPoint(e=.35,r=.55){return{id:t(),clipProgress:e,sourceProgress:r}}export function createAnimationClipRetiming(e="impact",t=("uniform"===e?[]:[createAnimationClipRetimingPoint()])){return{mode:e,points:t}}export function createAudioClipInstance(e,r,a){return{id:t(),audioAssetId:e,startTime:r,duration:a,clipStartOffset:0,playbackRate:1,volume:1,fadeInDuration:0,fadeOutDuration:0,volumeRandomization:0,pitchRandomization:0}}export function createVfxClipInstance(e,r,a){return{id:t(),vfxAssetId:e,startTime:r,duration:a,endBehavior:"finish",expireWithinSeconds:.25}}export function createEventSubTrack(e="Events"){return{id:t(),name:e,type:"event",muted:!1,events:[]}}export function createSequenceEventData(e,r=""){return{id:t(),time:e,editorOnly:!1,functionName:r,arguments:[]}}export function createLocatorTrack(e="Locator"){return{id:t(),name:e,type:"locator",muted:!1,locked:!1,subTracks:[]}}/*
1
+ import{SerializedParamType as e}from"../../scene/model.js";import{randomString as t}from"../../utils/math.js";import{getAudioParameterDefinition as r}from"./audio-parameters.js";export class Sequence{constructor(e){this.data=e}}export var SequenceRole;!function(e){e.Self="self",e.Target="target",e.Target2="target2",e.Target3="target3",e.Secondary="secondary"}(SequenceRole||(SequenceRole={}));export function createSequenceData(){return{duration:5,loop:!1,playbackRate:1,tracks:[]}}export function createObjectTrack(e="Object Track"){return{id:t(),name:e,type:"object",muted:!1,locked:!1,targetId:null,role:null,subTracks:[]}}export function createCameraTrack(e="Camera Track"){return{id:t(),name:e,type:"camera",muted:!1,locked:!1,parentRole:null,clips:[],cameraSettings:{fov:60,near:.1,far:1e3},subTracks:[]}}export function createCameraClipInstance(e,r){return{id:t(),startTime:e,duration:r,blendInDuration:.2,blendOutDuration:.2,blendInterpolation:"cubic"}}export function createAudioTrack(e="Audio Track"){return{id:t(),name:e,type:"audio",muted:!1,locked:!1,clips:[],subTracks:[],volume:1,spatial:!1}}export function createVfxTrack(e="VFX Track"){return{id:t(),name:e,type:"vfx",muted:!1,locked:!1,clips:[],position:[0,0,0],rotation:[0,0,0],scale:[1,1,1],subTracks:[]}}export function createSpawnTrack(e="Spawn Track"){return{id:t(),name:e,type:"spawn",muted:!1,locked:!1,spawnType:"mesh",role:null,clips:[],subTracks:[]}}export function createSpawnClipInstance(e,r){return{id:t(),startTime:e,duration:r}}export function createGroupTrack(e="Group"){return{id:t(),name:e,type:"group",muted:!1,locked:!1,collapsed:!1,childTracks:[],subTracks:[]}}export function createTransformSubTrack(){return{id:t(),name:"Transform",type:"transform",muted:!1,components:{position:!0,rotation:!0,scale:!0},keyframes:[]}}export function createAnimationSubTrack(e="Animation"){return{id:t(),name:e,type:"animation",muted:!1,clips:[]}}export function createAudioParameterSubTrack(e="volume"){const a=r(e);return{id:t(),name:a.displayName,type:"audioParameter",muted:!1,parameter:e,keyframes:[]}}export function createPropertySubTrack(r="",a=e.Number){const n="string"==typeof r?{propertyPath:r,propertyType:a}:r;return{id:t(),name:n.name??n.label??n.propertyPath??"Property",type:"property",muted:!1,propertyPath:n.propertyPath,propertyType:n.propertyType,label:n.label,group:n.group,help:n.help,range:n.range,precision:n.precision,stepSize:n.stepSize,options:n.options,editorInput:n.editorInput,defaultValue:n.defaultValue,keyframes:[]}}export function createMaterialSubTrack(r="",a=e.Number,n=0){return{id:t(),name:r||"Material",type:"material",muted:!1,materialSlot:n,uniformName:r,uniformType:a,keyframes:[]}}export function createVisibilitySubTrack(e="Visibility"){return{id:t(),name:e,type:"visibility",muted:!1,keyframes:[]}}export function createTransformKeyframe(e){return{id:t(),time:e,position:[0,0,0],rotation:[0,0,0],scale:[1,1,1],interpolation:"cubic"}}export function createPropertyKeyframe(r,a={type:e.Number,value:0}){return{id:t(),time:r,value:a,interpolation:"linear"}}export function createAnimationClipInstance(e,r,a){return{id:t(),animationClipAssetId:e,startTime:r,duration:a,clipStartOffset:0,clipEndOffset:0,playbackRate:1,fadeInDuration:.2,retiming:void 0,rootMotion:!1}}export function createAnimationClipRetimingPoint(e=.35,r=.55){return{id:t(),clipProgress:e,sourceProgress:r}}export function createAnimationClipRetiming(e="impact",t=("uniform"===e?[]:[createAnimationClipRetimingPoint()])){return{mode:e,points:t}}export function createAudioClipInstance(e,r,a){return{id:t(),audioAssetId:e,startTime:r,duration:a,clipStartOffset:0,playbackRate:1,volume:1,fadeInDuration:0,fadeOutDuration:0,volumeRandomization:0,pitchRandomization:0}}export function createVfxClipInstance(e,r,a){return{id:t(),vfxAssetId:e,startTime:r,duration:a,endBehavior:"finish",expireWithinSeconds:.25}}export function createEventSubTrack(e="Events"){return{id:t(),name:e,type:"event",muted:!1,events:[]}}export function createSequenceEventData(e,r=""){return{id:t(),time:e,editorOnly:!1,functionName:r,arguments:[]}}export function createLocatorTrack(e="Locator"){return{id:t(),name:e,type:"locator",muted:!1,locked:!1,subTracks:[]}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,5 +1,6 @@
1
- import { AnimationClipInstance, SequenceTrack, SequenceTrackType, SubTrack, SubTrackType } from './sequence-data.js';
1
+ import { AnimationClipInstance, PropertySubTrackOptions, SequenceTrack, SequenceTrackType, SubTrack, SubTrackType } from './sequence-data.js';
2
2
  import { AudioParameterId } from './audio-parameters.js';
3
+ import { SerializedParamType } from '../../scene/model.js';
3
4
  export type SequenceTrackRuntimeEvaluator = 'object' | 'locator' | 'camera' | 'audio' | 'vfx' | 'spawn' | 'group';
4
5
  export type SequenceSubTrackRuntimeEvaluator = 'transform' | 'animation' | 'visibility' | 'parameter' | 'event';
5
6
  export type SequenceSubTrackLaneKind = 'keyframes' | 'clips' | 'events';
@@ -23,9 +24,7 @@ export interface SequenceSubTrackDefinition<TSubTrack extends SubTrack = SubTrac
23
24
  icon: string;
24
25
  laneKind: SequenceSubTrackLaneKind;
25
26
  runtimeEvaluator: SequenceSubTrackRuntimeEvaluator;
26
- createSubTrack: (options?: {
27
- parameter?: AudioParameterId;
28
- }) => TSubTrack;
27
+ createSubTrack: (options?: SequenceSubTrackCreateOptions) => TSubTrack;
29
28
  createClip?: (startTime?: number, defaultDuration?: number) => AnimationClipInstance;
30
29
  supportedTrackTypes: readonly SequenceTrackType[];
31
30
  allowMultiple?: boolean;
@@ -34,20 +33,25 @@ export interface SequenceSubTrackDefinition<TSubTrack extends SubTrack = SubTrac
34
33
  kind: 'number' | 'customParam';
35
34
  };
36
35
  }
36
+ export interface SequenceSubTrackCreateOptions {
37
+ parameter?: AudioParameterId;
38
+ propertyPath?: string;
39
+ propertyType?: SerializedParamType;
40
+ property?: PropertySubTrackOptions;
41
+ }
37
42
  export interface AudioParameterSubTrackOption {
38
43
  parameter: AudioParameterId;
39
44
  label: string;
40
45
  icon: string;
41
46
  }
42
47
  export declare const audioParameterSubTrackOptions: AudioParameterSubTrackOption[];
48
+ export declare const cameraPropertySubTrackOptions: PropertySubTrackOptions[];
43
49
  export declare function getSequenceTrackDefinitions(): SequenceTrackDefinition[];
44
50
  export declare function getSequenceSubTrackDefinitions(): SequenceSubTrackDefinition[];
45
51
  export declare function getSequenceTrackDefinition(type: SequenceTrackType): SequenceTrackDefinition;
46
52
  export declare function getSequenceSubTrackDefinition(type: SubTrackType): SequenceSubTrackDefinition;
47
53
  export declare function getEditorSequenceTrackDefinitions(): SequenceTrackDefinition[];
48
54
  export declare function getEditorSequenceSubTrackDefinitions(track: SequenceTrack): SequenceSubTrackDefinition[];
49
- export declare function canTrackAddSubTrack(track: SequenceTrack, type: SubTrackType, options?: {
50
- parameter?: AudioParameterId;
51
- }): boolean;
55
+ export declare function canTrackAddSubTrack(track: SequenceTrack, type: SubTrackType, options?: SequenceSubTrackCreateOptions): boolean;
52
56
  export {};
53
57
  //# sourceMappingURL=sequence-definitions.d.ts.map
@@ -1,4 +1,4 @@
1
- import{createAnimationClipInstance as e,createAnimationSubTrack as a,createAudioClipInstance as r,createAudioParameterSubTrack as t,createAudioTrack as n,createCameraTrack as o,createEventSubTrack as i,createGroupTrack as l,createLocatorTrack as p,createMaterialSubTrack as c,createObjectTrack as u,createPropertySubTrack as s,createSpawnClipInstance as m,createSpawnTrack as d,createTransformSubTrack as T,createVfxClipInstance as b,createVfxTrack as k,createVisibilitySubTrack as y}from"./sequence-data.js";const f=[{type:"object",label:"Object Track",icon:"mdil-hexagon",runtimeEvaluator:"object",createTrack:()=>u(),allowedSubTrackTypes:["transform","animation","property","material","visibility","event"],supportsParenting:!0,exposedInEditor:!1},{type:"locator",label:"Locator",icon:"mdil-map-marker-radius",runtimeEvaluator:"locator",createTrack:()=>p(),allowedSubTrackTypes:["transform"],supportsParenting:!0,exposedInEditor:!0},{type:"camera",label:"Camera Track",icon:"mdil-camcorder",runtimeEvaluator:"camera",createTrack:(r=0,t=2)=>{const n=o(),i=a();return i.clips.push(e(null,r,t)),n.subTracks.push(i),n},allowedSubTrackTypes:["transform","animation","property","event"],exposedInEditor:!0},{type:"audio",label:"Audio Track",icon:"mdil-volume-high",runtimeEvaluator:"audio",createTrack:(e=0,a=2)=>{const t=n();return t.clips.push(r(null,e,a)),t},createDirectClip:(e=0,a=2)=>r(null,e,a),allowedSubTrackTypes:["audioParameter"],supportsParenting:!0,exposedInEditor:!0},{type:"vfx",label:"VFX Track",icon:"mdil-star",runtimeEvaluator:"vfx",createTrack:(e=0,a=2)=>{const r=k();return r.clips.push(b(null,e,a)),r},createDirectClip:(e=0,a=2)=>b(null,e,a),allowedSubTrackTypes:["transform"],supportsParenting:!0,exposedInEditor:!0},{type:"spawn",label:"Spawn Track",icon:"mdil-plus-box",runtimeEvaluator:"spawn",createTrack:(e=0,a=2)=>{const r=d();return r.clips.push(m(e,a)),r},createDirectClip:(e=0,a=2)=>m(e,a),allowedSubTrackTypes:["transform","animation","property","event"],supportsParenting:!0,exposedInEditor:!0},{type:"group",label:"Group",icon:"mdil-folder",runtimeEvaluator:"group",createTrack:()=>l(),allowedSubTrackTypes:[],exposedInEditor:!1}],v=[{type:"transform",label:"Transform",icon:"mdil-move-resize",laneKind:"keyframes",runtimeEvaluator:"transform",createSubTrack:()=>T(),supportedTrackTypes:["object","locator","camera","spawn","vfx"],exposedInEditor:!0},{type:"animation",label:"Animation",icon:"mdil-run",laneKind:"clips",runtimeEvaluator:"animation",createSubTrack:()=>a(),createClip:(a=0,r=2)=>e(null,a,r),supportedTrackTypes:["object","camera","spawn"],exposedInEditor:!0},{type:"property",label:"Property",icon:"mdil-tune",laneKind:"keyframes",runtimeEvaluator:"parameter",createSubTrack:()=>s(),supportedTrackTypes:["object","camera","spawn"],exposedInEditor:!1,valueLane:{kind:"customParam"}},{type:"material",label:"Material",icon:"mdil-palette",laneKind:"keyframes",runtimeEvaluator:"parameter",createSubTrack:()=>c(),supportedTrackTypes:["object","spawn"],exposedInEditor:!1,valueLane:{kind:"customParam"}},{type:"visibility",label:"Visibility",icon:"mdil-eye",laneKind:"keyframes",runtimeEvaluator:"visibility",createSubTrack:()=>y(),supportedTrackTypes:["object","spawn","vfx"],exposedInEditor:!1},{type:"event",label:"Events",icon:"mdil-flash-outline",laneKind:"events",runtimeEvaluator:"event",createSubTrack:()=>i(),supportedTrackTypes:["object","spawn","camera"],exposedInEditor:!0},{type:"audioParameter",label:"Audio Parameter",icon:"mdil-tune",laneKind:"keyframes",runtimeEvaluator:"parameter",createSubTrack:e=>t(e?.parameter),supportedTrackTypes:["audio"],allowMultiple:!0,exposedInEditor:!0,valueLane:{kind:"number"}}];export const audioParameterSubTrackOptions=[{parameter:"volume",label:"Volume",icon:"mdil-tune"},{parameter:"detune",label:"Detune",icon:"mdil-music-note"},{parameter:"pan",label:"Pan",icon:"mdil-panorama-horizontal"},{parameter:"spatialBlend",label:"Spatial Blend",icon:"mdil-cube-outline"},{parameter:"lowpass",label:"Low Pass Filter",icon:"mdil-filter-variant"},{parameter:"highpass",label:"High Pass Filter",icon:"mdil-filter-variant"}];const E=new Map(f.map(e=>[e.type,e])),x=new Map(v.map(e=>[e.type,e]));export function getSequenceTrackDefinitions(){return f}export function getSequenceSubTrackDefinitions(){return v}export function getSequenceTrackDefinition(e){return E.get(e)}export function getSequenceSubTrackDefinition(e){return x.get(e)}export function getEditorSequenceTrackDefinitions(){return f.filter(e=>!1!==e.exposedInEditor)}export function getEditorSequenceSubTrackDefinitions(e){return v.filter(a=>!1!==a.exposedInEditor&&a.supportedTrackTypes.some(a=>a===e.type))}export function canTrackAddSubTrack(e,a,r){if(e.locked)return!1;const t=getSequenceSubTrackDefinition(a);return!!t.supportedTrackTypes.some(a=>a===e.type)&&("audioParameter"===a?!!r?.parameter&&!e.subTracks.some(e=>"audioParameter"===e.type&&e.parameter===r.parameter):!!t.allowMultiple||!e.subTracks.some(e=>e.type===a))}/*
1
+ import{createAnimationClipInstance as e,createAnimationSubTrack as r,createAudioClipInstance as a,createAudioParameterSubTrack as t,createAudioTrack as o,createCameraClipInstance as n,createCameraTrack as i,createEventSubTrack as p,createGroupTrack as l,createLocatorTrack as c,createMaterialSubTrack as u,createObjectTrack as s,createPropertySubTrack as m,createSpawnClipInstance as d,createSpawnTrack as y,createTransformSubTrack as T,createVfxClipInstance as b,createVfxTrack as k,createVisibilitySubTrack as f}from"./sequence-data.js";import{SerializedParamType as v}from"../../scene/model.js";const E=[{type:"object",label:"Object Track",icon:"mdil-hexagon",runtimeEvaluator:"object",createTrack:()=>s(),allowedSubTrackTypes:["transform","animation","property","material","visibility","event"],supportsParenting:!0,exposedInEditor:!1},{type:"locator",label:"Locator",icon:"mdil-map-marker-radius",runtimeEvaluator:"locator",createTrack:()=>c(),allowedSubTrackTypes:["transform"],supportsParenting:!0,exposedInEditor:!0},{type:"camera",label:"Camera Track",icon:"mdil-camcorder",runtimeEvaluator:"camera",createTrack:(e=0,r=2)=>{const a=i();return a.clips.push(n(e,r)),a.subTracks.push(T()),a},createDirectClip:(e=0,r=2)=>n(e,r),allowedSubTrackTypes:["transform","property"],exposedInEditor:!0},{type:"audio",label:"Audio Track",icon:"mdil-volume-high",runtimeEvaluator:"audio",createTrack:(e=0,r=2)=>{const t=o();return t.clips.push(a(null,e,r)),t},createDirectClip:(e=0,r=2)=>a(null,e,r),allowedSubTrackTypes:["audioParameter"],supportsParenting:!0,exposedInEditor:!0},{type:"vfx",label:"VFX Track",icon:"mdil-star",runtimeEvaluator:"vfx",createTrack:(e=0,r=2)=>{const a=k();return a.clips.push(b(null,e,r)),a},createDirectClip:(e=0,r=2)=>b(null,e,r),allowedSubTrackTypes:["transform"],supportsParenting:!0,exposedInEditor:!0},{type:"spawn",label:"Spawn Track",icon:"mdil-plus-box",runtimeEvaluator:"spawn",createTrack:(e=0,r=2)=>{const a=y();return a.clips.push(d(e,r)),a},createDirectClip:(e=0,r=2)=>d(e,r),allowedSubTrackTypes:["transform","animation","property","event"],supportsParenting:!0,exposedInEditor:!0},{type:"group",label:"Group",icon:"mdil-folder",runtimeEvaluator:"group",createTrack:()=>l(),allowedSubTrackTypes:[],exposedInEditor:!1}],x=[{type:"transform",label:"Transform",icon:"mdil-move-resize",laneKind:"keyframes",runtimeEvaluator:"transform",createSubTrack:()=>T(),supportedTrackTypes:["object","locator","camera","spawn","vfx"],exposedInEditor:!0},{type:"animation",label:"Animation",icon:"mdil-run",laneKind:"clips",runtimeEvaluator:"animation",createSubTrack:()=>r(),createClip:(r=0,a=2)=>e(null,r,a),supportedTrackTypes:["object","camera","spawn"],exposedInEditor:!0},{type:"property",label:"Property",icon:"mdil-tune",laneKind:"keyframes",runtimeEvaluator:"parameter",createSubTrack:e=>m(e?.property??{propertyPath:e?.propertyPath??"",propertyType:e?.propertyType??v.Number}),supportedTrackTypes:["object","camera","spawn"],allowMultiple:!0,exposedInEditor:!0,valueLane:{kind:"customParam"}},{type:"material",label:"Material",icon:"mdil-palette",laneKind:"keyframes",runtimeEvaluator:"parameter",createSubTrack:()=>u(),supportedTrackTypes:["object","spawn"],exposedInEditor:!1,valueLane:{kind:"customParam"}},{type:"visibility",label:"Visibility",icon:"mdil-eye",laneKind:"keyframes",runtimeEvaluator:"visibility",createSubTrack:()=>f(),supportedTrackTypes:["object","spawn","vfx"],exposedInEditor:!1},{type:"event",label:"Events",icon:"mdil-flash-outline",laneKind:"events",runtimeEvaluator:"event",createSubTrack:()=>p(),supportedTrackTypes:["object","spawn"],exposedInEditor:!0},{type:"audioParameter",label:"Audio Parameter",icon:"mdil-tune",laneKind:"keyframes",runtimeEvaluator:"parameter",createSubTrack:e=>t(e?.parameter),supportedTrackTypes:["audio"],allowMultiple:!0,exposedInEditor:!0,valueLane:{kind:"number"}}];export const audioParameterSubTrackOptions=[{parameter:"volume",label:"Volume",icon:"mdil-tune"},{parameter:"detune",label:"Detune",icon:"mdil-music-note"},{parameter:"pan",label:"Pan",icon:"mdil-panorama-horizontal"},{parameter:"spatialBlend",label:"Spatial Blend",icon:"mdil-cube-outline"},{parameter:"lowpass",label:"Low Pass Filter",icon:"mdil-filter-variant"},{parameter:"highpass",label:"High Pass Filter",icon:"mdil-filter-variant"}];export const cameraPropertySubTrackOptions=[{name:"FOV",label:"FOV",propertyPath:"fov",propertyType:v.Number,group:"Camera",help:"Camera field of view in degrees.",range:[1,179],precision:1,stepSize:.1,defaultValue:{type:v.Number,value:60}}];const S=new Map(E.map(e=>[e.type,e])),w=new Map(x.map(e=>[e.type,e]));export function getSequenceTrackDefinitions(){return E}export function getSequenceSubTrackDefinitions(){return x}export function getSequenceTrackDefinition(e){return S.get(e)}export function getSequenceSubTrackDefinition(e){return w.get(e)}export function getEditorSequenceTrackDefinitions(){return E.filter(e=>!1!==e.exposedInEditor)}export function getEditorSequenceSubTrackDefinitions(e){return x.filter(r=>!1!==r.exposedInEditor&&r.supportedTrackTypes.some(r=>r===e.type))}export function canTrackAddSubTrack(e,r,a){if(e.locked)return!1;const t=getSequenceSubTrackDefinition(r);if(!t.supportedTrackTypes.some(r=>r===e.type))return!1;if("audioParameter"===r)return!!a?.parameter&&!e.subTracks.some(e=>"audioParameter"===e.type&&e.parameter===a.parameter);if("property"===r){const r=a?.property?.propertyPath??a?.propertyPath;return!!r&&!e.subTracks.some(e=>"property"===e.type&&e.propertyPath===r)}return!!t.allowMultiple||!e.subTracks.some(e=>e.type===r)}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{randomString as r}from"../../utils/math.js";import{sortTimedSequenceItems as e}from"./sequence-value-lane.js";export function addTrack(r,e){return{...r,tracks:[...r.tracks,e]}}export function updateTrack(r,e,t){return{...r,tracks:r.tracks.map(r=>r.id===e?t(r):r)}}export function removeTrack(r,e){return{...r,tracks:r.tracks.filter(r=>r.id!==e)}}export function moveTrack(r,e,t){const a=r.tracks.findIndex(r=>r.id===e);if(a<0)return r;const n="up"===t?a-1:a+1;if(n<0||n>=r.tracks.length)return r;const i=[...r.tracks];return[i[a],i[n]]=[i[n],i[a]],{...r,tracks:i}}export function duplicateTrack(r,e){const t=r.tracks.findIndex(r=>r.id===e);if(t<0)return{data:r};const a=cloneTrackWithFreshIds(r.tracks[t]);a.name=`${r.tracks[t].name} (Copy)`;const n=[...r.tracks];return n.splice(t+1,0,a),{data:{...r,tracks:n},ref:{trackId:a.id}}}export function addSubTrack(r,e,t){return{data:updateTrack(r,e,r=>({...r,subTracks:[...r.subTracks,t]})),ref:{trackId:e,subTrackId:t.id}}}export function updateSubTrack(r,e,t,a){return updateTrack(r,e,r=>({...r,subTracks:r.subTracks.map(r=>r.id===t?a(r):r)}))}export function removeSubTrack(r,e,t){return updateTrack(r,e,r=>({...r,subTracks:r.subTracks.filter(r=>r.id!==t)}))}export function addTrackClip(r,e,t){return{data:updateTrack(r,e,r=>i(r)?{...r,clips:[...r.clips,t]}:r),ref:{trackId:e,clipId:t.id}}}export function updateTrackClip(r,e,t,a){return updateTrack(r,e,r=>i(r)?{...r,clips:r.clips.map(r=>r.id===t?a(r):r)}:r)}export function removeTrackClip(r,e,t){return updateTrack(r,e,r=>i(r)?{...r,clips:r.clips.filter(r=>r.id!==t)}:r)}export function addAnimationClip(r,e,t,a){return{data:n(r,e,t,r=>({...r,clips:[...r.clips,a]})),ref:{trackId:e,subTrackId:t,clipId:a.id}}}export function updateAnimationClip(r,e,t,a,i){return n(r,e,t,r=>({...r,clips:r.clips.map(r=>r.id===a?i(r):r)}))}export function removeAnimationClip(r,e,t,a){return n(r,e,t,r=>({...r,clips:r.clips.filter(r=>r.id!==a)}))}export function addSubTrackKeyframe(r,t,a,n){let i=-1,p="transform";return{data:updateSubTrack(r,t,a,r=>{if(p=r.type,u(r)&&d(n)){const t=e([...r.events,n]);return i=t.findIndex(r=>r.id===n.id),{...r,events:t}}if(c(r)&&!d(n)){const t=e([...r.keyframes,n]);return i=t.findIndex(r=>r.id===n.id),{...r,keyframes:t}}return r}),ref:-1===i?void 0:{trackId:t,subTrackId:a,keyframeId:n.id,keyframeIndex:i,subTrackType:p,time:n.time}}}export function updateSubTrackKeyframe(r,t,a,n,i){let d;return{data:updateSubTrack(r,t,a,r=>{if(u(r)){const c=e(r.events.map(r=>r.id===n?i(r):r)),u=c.findIndex(r=>r.id===n);return u>=0&&(d={trackId:t,subTrackId:a,keyframeId:n,keyframeIndex:u,subTrackType:r.type,time:c[u].time}),{...r,events:c}}if(c(r)){const c=e(r.keyframes.map(r=>r.id===n?i(r):r)),u=c.findIndex(r=>r.id===n);return u>=0&&(d={trackId:t,subTrackId:a,keyframeId:n,keyframeIndex:u,subTrackType:r.type,time:c[u].time}),{...r,keyframes:c}}return r}),ref:d}}export function removeSubTrackKeyframe(r,e,t,a){return updateSubTrack(r,e,t,r=>u(r)?{...r,events:r.events.filter(r=>r.id!==a)}:c(r)?{...r,keyframes:r.keyframes.filter(r=>r.id!==a)}:r)}export function cloneTrackWithFreshIds(r){return t(JSON.parse(JSON.stringify(r)))}function t(e){return e.id=r(),e.subTracks=e.subTracks.map(a),"group"===e.type&&(e.childTracks=e.childTracks.map(r=>t(r))),i(e)&&(e.clips=e.clips.map(e=>({...e,id:r()}))),e}function a(e){return e.id=r(),"animation"===e.type?(e.clips=e.clips.map(e=>({...e,id:r()})),e):"event"===e.type?(e.events=e.events.map(e=>({...e,id:r()})),e):(c(e)&&(e.keyframes=e.keyframes.map(e=>({...e,id:r()}))),e)}function n(r,e,t,a){return updateSubTrack(r,e,t,r=>"animation"===r.type?a(r):r)}function i(r){return"audio"===r.type||"vfx"===r.type||"spawn"===r.type}function c(r){return"transform"===r.type||"property"===r.type||"audioParameter"===r.type||"material"===r.type||"visibility"===r.type}function u(r){return"event"===r.type}function d(r){return"arguments"in r}/*
1
+ import{randomString as r}from"../../utils/math.js";import{sortTimedSequenceItems as e}from"./sequence-value-lane.js";export function addTrack(r,e){return{...r,tracks:[...r.tracks,e]}}export function updateTrack(r,e,t){return{...r,tracks:r.tracks.map(r=>r.id===e?t(r):r)}}export function removeTrack(r,e){return{...r,tracks:r.tracks.filter(r=>r.id!==e)}}export function moveTrack(r,e,t){const a=r.tracks.findIndex(r=>r.id===e);if(a<0)return r;const n="up"===t?a-1:a+1;if(n<0||n>=r.tracks.length)return r;const i=[...r.tracks];return[i[a],i[n]]=[i[n],i[a]],{...r,tracks:i}}export function duplicateTrack(r,e){const t=r.tracks.findIndex(r=>r.id===e);if(t<0)return{data:r};const a=cloneTrackWithFreshIds(r.tracks[t]);a.name=`${r.tracks[t].name} (Copy)`;const n=[...r.tracks];return n.splice(t+1,0,a),{data:{...r,tracks:n},ref:{trackId:a.id}}}export function addSubTrack(r,e,t){return{data:updateTrack(r,e,r=>({...r,subTracks:[...r.subTracks,t]})),ref:{trackId:e,subTrackId:t.id}}}export function updateSubTrack(r,e,t,a){return updateTrack(r,e,r=>({...r,subTracks:r.subTracks.map(r=>r.id===t?a(r):r)}))}export function removeSubTrack(r,e,t){return updateTrack(r,e,r=>({...r,subTracks:r.subTracks.filter(r=>r.id!==t)}))}export function addTrackClip(r,e,t){return{data:updateTrack(r,e,r=>i(r)?{...r,clips:[...r.clips,t]}:r),ref:{trackId:e,clipId:t.id}}}export function updateTrackClip(r,e,t,a){return updateTrack(r,e,r=>i(r)?{...r,clips:r.clips.map(r=>r.id===t?a(r):r)}:r)}export function removeTrackClip(r,e,t){return updateTrack(r,e,r=>i(r)?{...r,clips:r.clips.filter(r=>r.id!==t)}:r)}export function addAnimationClip(r,e,t,a){return{data:n(r,e,t,r=>({...r,clips:[...r.clips,a]})),ref:{trackId:e,subTrackId:t,clipId:a.id}}}export function updateAnimationClip(r,e,t,a,i){return n(r,e,t,r=>({...r,clips:r.clips.map(r=>r.id===a?i(r):r)}))}export function removeAnimationClip(r,e,t,a){return n(r,e,t,r=>({...r,clips:r.clips.filter(r=>r.id!==a)}))}export function addSubTrackKeyframe(r,t,a,n){let i=-1,p="transform";return{data:updateSubTrack(r,t,a,r=>{if(p=r.type,u(r)&&d(n)){const t=e([...r.events,n]);return i=t.findIndex(r=>r.id===n.id),{...r,events:t}}if(c(r)&&!d(n)){const t=e([...r.keyframes,n]);return i=t.findIndex(r=>r.id===n.id),{...r,keyframes:t}}return r}),ref:-1===i?void 0:{trackId:t,subTrackId:a,keyframeId:n.id,keyframeIndex:i,subTrackType:p,time:n.time}}}export function updateSubTrackKeyframe(r,t,a,n,i){let d;return{data:updateSubTrack(r,t,a,r=>{if(u(r)){const c=e(r.events.map(r=>r.id===n?i(r):r)),u=c.findIndex(r=>r.id===n);return u>=0&&(d={trackId:t,subTrackId:a,keyframeId:n,keyframeIndex:u,subTrackType:r.type,time:c[u].time}),{...r,events:c}}if(c(r)){const c=e(r.keyframes.map(r=>r.id===n?i(r):r)),u=c.findIndex(r=>r.id===n);return u>=0&&(d={trackId:t,subTrackId:a,keyframeId:n,keyframeIndex:u,subTrackType:r.type,time:c[u].time}),{...r,keyframes:c}}return r}),ref:d}}export function removeSubTrackKeyframe(r,e,t,a){return updateSubTrack(r,e,t,r=>u(r)?{...r,events:r.events.filter(r=>r.id!==a)}:c(r)?{...r,keyframes:r.keyframes.filter(r=>r.id!==a)}:r)}export function cloneTrackWithFreshIds(r){return t(JSON.parse(JSON.stringify(r)))}function t(e){return e.id=r(),e.subTracks=e.subTracks.map(a),"group"===e.type&&(e.childTracks=e.childTracks.map(r=>t(r))),i(e)&&(e.clips=e.clips.map(e=>({...e,id:r()}))),e}function a(e){return e.id=r(),"animation"===e.type?(e.clips=e.clips.map(e=>({...e,id:r()})),e):"event"===e.type?(e.events=e.events.map(e=>({...e,id:r()})),e):(c(e)&&(e.keyframes=e.keyframes.map(e=>({...e,id:r()}))),e)}function n(r,e,t,a){return updateSubTrack(r,e,t,r=>"animation"===r.type?a(r):r)}function i(r){return"camera"===r.type||"audio"===r.type||"vfx"===r.type||"spawn"===r.type}function c(r){return"transform"===r.type||"property"===r.type||"audioParameter"===r.type||"material"===r.type||"visibility"===r.type}function u(r){return"event"===r.type}function d(r){return"arguments"in r}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -10,6 +10,7 @@ import { PrefabInstance } from '../../scene/objects/prefab.js';
10
10
  import { SequenceData, SequenceRole, SequenceTrack } from './sequence-data.js';
11
11
  import { SequenceLocatorReader, SequenceLocatorSnapshot } from './sequence-locator.js';
12
12
  import { CharacterAnimationComponent } from '../../gameplay/actors/index.js';
13
+ import type { ViewController } from '../../gameplay/services/render.js';
13
14
  /**
14
15
  * Playback state of the sequence
15
16
  */
@@ -96,8 +97,17 @@ export declare class SequencePlayer implements SequenceLocatorReader {
96
97
  readonly onTimeUpdate: import("rxjs").Observable<number>;
97
98
  readonly onStateChange: import("rxjs").Observable<SequencePlaybackState>;
98
99
  private loopCount;
99
- private sequenceCamera;
100
- private originalCamera;
100
+ private viewController;
101
+ private _cameraControlEnabled;
102
+ private _cameraControlTrackId;
103
+ private sequenceCameras;
104
+ private cameraPlayables;
105
+ private cameraBlendCamera;
106
+ private cameraBlendSource;
107
+ private cameraBlendOutSource;
108
+ private cameraOverrideHandle;
109
+ private activeCameraClipKey;
110
+ private cameraBlendOutClipKey;
101
111
  private audioListener;
102
112
  private audioBuffers;
103
113
  private loadingAudioBuffers;
@@ -121,6 +131,9 @@ export declare class SequencePlayer implements SequenceLocatorReader {
121
131
  private activeVfxClips;
122
132
  private locatorMarkers;
123
133
  private clearCounter;
134
+ private propertyPathSegments;
135
+ private propertyResolutionCache;
136
+ private propertySnapshots;
124
137
  private audioFilters;
125
138
  private audioPannerNodes;
126
139
  private firedEvents;
@@ -164,6 +177,20 @@ export declare class SequencePlayer implements SequenceLocatorReader {
164
177
  */
165
178
  get inEditor(): boolean;
166
179
  set inEditor(value: boolean);
180
+ /**
181
+ * When true, active camera clips are allowed to control the local rendered view.
182
+ * Gameplay should enable this only for the locally controlled actor/client.
183
+ */
184
+ get cameraControlEnabled(): boolean;
185
+ set cameraControlEnabled(value: boolean);
186
+ /**
187
+ * Optional editor/runtime pilot filter. When set, camera control only considers
188
+ * clips from this camera track; null preserves the normal sequence-wide camera
189
+ * priority behavior.
190
+ */
191
+ get cameraControlTrackId(): string | null;
192
+ set cameraControlTrackId(value: string | null);
193
+ setViewController(viewController: ViewController): void;
167
194
  /**
168
195
  * Set world dependency
169
196
  */
@@ -249,6 +276,7 @@ export declare class SequencePlayer implements SequenceLocatorReader {
249
276
  private evaluateTrack;
250
277
  private evaluateObjectTrack;
251
278
  private evaluateLocatorTrack;
279
+ getActiveTrackObjects(trackId: string): Object3D[];
252
280
  private evaluateSubTracks;
253
281
  private evaluateTransformSubTrack;
254
282
  private evaluateAnimationSubTrack;
@@ -257,6 +285,28 @@ export declare class SequencePlayer implements SequenceLocatorReader {
257
285
  private evaluateParameterSubTrack;
258
286
  private evaluateEventSubTrack;
259
287
  private evaluateCameraTrack;
288
+ private getCameraPlayable;
289
+ private ensureSequenceCamera;
290
+ private clearSequenceCameras;
291
+ private applyCameraTrackSettings;
292
+ private getCurrentCameraAspect;
293
+ private updateCameraControl;
294
+ private findActiveCameraShot;
295
+ private findBlendOutCameraShot;
296
+ private isCameraControlTrackEligible;
297
+ private updateActiveCameraShot;
298
+ private updateCameraBlendOut;
299
+ private ensureCameraBlendCamera;
300
+ private ensureCameraBlendSource;
301
+ private ensureCameraBlendOutSource;
302
+ private ensureCameraOverride;
303
+ private releaseCameraOverride;
304
+ private isCameraClipActive;
305
+ private getCameraClipEnd;
306
+ private getCameraClipKey;
307
+ private evaluateCameraBlendAlpha;
308
+ private copyCameraState;
309
+ private blendCameraState;
260
310
  private evaluateAudioTrack;
261
311
  private tryStartAudioClip;
262
312
  private applyAudioParameters;
@@ -327,6 +377,13 @@ export declare class SequencePlayer implements SequenceLocatorReader {
327
377
  private spawnForClip;
328
378
  private getPlayableObject;
329
379
  private applyResolvedPropertyValue;
380
+ private getPropertyResolution;
381
+ private getPropertyPathSegments;
382
+ private getPropertySnapshotKey;
383
+ private capturePropertySnapshot;
384
+ private restorePropertySnapshotsForInstance;
385
+ private restorePropertySnapshotsForTarget;
386
+ private restoreAllPropertySnapshots;
330
387
  private applyResolvedMaterialValue;
331
388
  private ensureAnimationClip;
332
389
  private prepareAnimationPlayback;