Skip to content
🎉 Angular Three v4 is here! Read the announcement

Studio

Theatre.js Studio is a visual editor for creating and editing animations directly in the browser.

The studio directive initializes and manages Theatre.js Studio. It dynamically imports the studio to avoid including it in production builds.

<!-- Enable studio (default when attribute present) -->
<theatre-project studio>
<ng-container sheet="scene">...</ng-container>
</theatre-project>
<!-- Conditionally enable 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>
import { TheatreProject, TheatreStudio } from 'angular-three-theatre';
@Component({
imports: [TheatreProject, TheatreStudio],
// ...
})
OptionTypeDefaultDescription
studiobooleantrueWhether the studio UI is visible
ExportTypeDescription
studioSignal<IStudio | null>Theatre.js Studio instance (null while loading)

Typically, you want Studio enabled only during development:

import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TheatreProject, TheatreSheet, TheatreStudio } from 'angular-three-theatre';
import { environment } from '../environments/environment';
@Component({
template: `
<theatre-project name="My Project" [studio]="isDevelopment">
<ng-container sheet="Scene">
<!-- sheet objects here -->
</ng-container>
</theatre-project>
`,
imports: [TheatreProject, TheatreSheet, TheatreStudio],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class SceneGraph {
isDevelopment = !environment.production;
}

When Studio is enabled, you get access to:

  • Visual Timeline: Drag and drop keyframes to create animations
  • Property Editors: Adjust values with sliders, color pickers, and input fields
  • Selection: Click objects to select them in the editor
  • Scrubbing: Drag the playhead to preview animations
  • Export: Save animation state as JSON

Sheet objects can integrate with Studio’s selection system:

<ng-template sheetObject="cube" [(sheetObjectSelected)]="isCubeSelected" let-select="select" let-deselect="deselect">
<ngt-mesh (click)="select()" (pointerout)="deselect()">
<ngt-box-geometry />
<ngt-mesh-standard-material [color]="isCubeSelected() ? 'yellow' : 'white'" />
</ngt-mesh>
</ng-template>

To persist animations, export the state from Studio and load it via project config:

// 1. Export state from Studio (copy from browser console)
// studio.createContentOfSaveFile('your-project-name')
// 2. Save to a JSON file
import savedState from './animation-state.json';
@Component({
template: `
<theatre-project name="My Project" [config]="{ state: savedState }">
<!-- ... -->
</theatre-project>
`,
})
export class SceneGraph {
savedState = savedState;
}

The TheatreStudio directive provides the studio instance via injection token:

import { inject } from '@angular/core';
import { THEATRE_STUDIO } from 'angular-three-theatre';
@Directive({
/* ... */
})
export class MyDirective {
private studio = inject(THEATRE_STUDIO, { optional: true });
doSomething() {
const studioInstance = this.studio?.();
if (studioInstance) {
// Access studio API
studioInstance.setSelection([
/* objects */
]);
}
}
}
import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';
import { TheatreProject, TheatreSheet, TheatreSheetObject, TheatreStudio } from 'angular-three-theatre';
@Component({
template: `
<theatre-project name="Studio Demo" [studio]="studioEnabled()">
<ng-container sheet="Scene" [sequence]="{ autoplay: false }" #seq="sequence">
<div class="toolbar">
<label>
<input type="checkbox" [checked]="studioEnabled()" (change)="toggleStudio()" />
Show Studio
</label>
<button (click)="seq.play()">Play</button>
</div>
<ng-template sheetObject="light" [sheetObjectProps]="{ intensity: 1 }" let-values="values">
<ngt-directional-light [intensity]="values().intensity" [position]="[5, 5, 5]" />
</ng-template>
<ng-template sheetObject="cube">
<theatre-transform>
<ngt-mesh>
<ngt-box-geometry />
<ngt-mesh-standard-material color="coral" />
</ngt-mesh>
</theatre-transform>
</ng-template>
</ng-container>
</theatre-project>
`,
imports: [TheatreProject, TheatreSheet, TheatreSheetObject, TheatreStudio],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class StudioDemo {
studioEnabled = signal(true);
toggleStudio() {
this.studioEnabled.update((v) => !v);
}
}