https://github.com/shotstack/shotstack-studio-sdk
A JavaScript library for creating and editing videos in the browser.
https://github.com/shotstack/shotstack-studio-sdk
Last synced: 3 months ago
JSON representation
A JavaScript library for creating and editing videos in the browser.
- Host: GitHub
- URL: https://github.com/shotstack/shotstack-studio-sdk
- Owner: shotstack
- License: other
- Created: 2024-05-30T10:41:55.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2026-03-10T13:05:41.000Z (3 months ago)
- Last Synced: 2026-03-10T15:53:26.027Z (3 months ago)
- Language: TypeScript
- Homepage: https://shotstack.io
- Size: 4.23 MB
- Stars: 20
- Watchers: 1
- Forks: 16
- Open Issues: 3
-
Metadata Files:
- Readme: readme.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Shotstack Studio
[](https://www.npmjs.com/package/@shotstack/shotstack-studio)
[](https://polyformproject.org/licenses/shield/1.0.0/)
[](https://www.typescriptlang.org/)
A JavaScript SDK for browser-based video editing with timeline, canvas preview, and export.
## Interactive Examples
Try Shotstack Studio in your preferred framework:
[](https://stackblitz.com/fork/github/shotstack/shotstack-studio-sdk-demos/tree/master/typescript)
[](https://stackblitz.com/fork/github/shotstack/shotstack-studio-sdk-demos/tree/master/react)
[](https://stackblitz.com/fork/github/shotstack/shotstack-studio-sdk-demos/tree/master/vue)
[](https://stackblitz.com/fork/github/shotstack/shotstack-studio-sdk-demos/tree/master/angular)
[](https://stackblitz.com/fork/github/shotstack/shotstack-studio-sdk-demos/tree/master/nextjs)
## Features
- Template-driven editing with undo/redo command model
- Canvas preview rendering
- Visual timeline with drag, resize, selection, and snapping
- Extensible UI via `UIController` button API
- Browser export pipeline via `VideoExporter`
## Installation
```bash
npm install @shotstack/shotstack-studio
```
```bash
yarn add @shotstack/shotstack-studio
```
## Quick Start
```typescript
import { Edit, Canvas, Controls, Timeline, UIController } from "@shotstack/shotstack-studio";
// 1) Load a template
const response = await fetch("https://shotstack-assets.s3.amazonaws.com/templates/hello-world/hello.json");
const template = await response.json();
// 2) Create core components
const edit = new Edit(template);
const canvas = new Canvas(edit);
const ui = UIController.create(edit, canvas);
// 3) Load canvas and edit
await canvas.load();
await edit.load();
// 4) Register toolbar buttons
ui.registerButton({
id: "text",
icon: ``,
tooltip: "Add Text"
});
// 5) Handle button clicks
ui.on("button:text", ({ position }) => {
edit.addTrack(0, {
clips: [
{
asset: {
type: "rich-text",
text: "Title",
font: { family: "Work Sans", size: 72, weight: 600, color: "#ffffff", opacity: 1 },
align: { horizontal: "center", vertical: "middle" }
},
start: position,
length: 5,
width: 500,
height: 200
}
]
});
});
// 6) Initialize the Timeline
const timelineContainer = document.querySelector("[data-shotstack-timeline]") as HTMLElement;
const timeline = new Timeline(edit, timelineContainer, { resizable: true });
await timeline.load();
// 7) Add keyboard controls
const controls = new Controls(edit);
await controls.load();
// 8) Add event handlers
edit.events.on("clip:selected", data => {
console.log("Clip selected:", data);
});
```
Your HTML must include both containers:
```html
```
## Main Components
### Edit
`Edit` is the runtime editing session and source of truth for document mutations.
```typescript
import { Edit } from "@shotstack/shotstack-studio";
const edit = new Edit(templateJson);
await edit.load();
await edit.loadEdit(nextTemplateJson);
// Playback (seconds)
edit.play();
edit.pause();
edit.seek(2);
edit.stop();
// Mutations
await edit.addTrack(0, { clips: [] });
await edit.addClip(0, {
asset: { type: "image", src: "https://example.com/image.jpg" },
start: 0,
length: 5
});
await edit.updateClip(0, 0, { length: 6 });
await edit.deleteClip(0, 0);
// History
await edit.undo();
await edit.redo();
// Clip operations
await edit.deleteTrack(0);
// Output settings
await edit.setOutputSize(1920, 1080);
await edit.setOutputFps(30);
await edit.setOutputFormat("mp4");
await edit.setOutputResolution("hd");
await edit.setOutputAspectRatio("16:9");
await edit.setTimelineBackground("#000000");
// Read state
const time = edit.playbackTime;
const playing = edit.isPlaying;
const clip = edit.getClip(0, 0);
const track = edit.getTrack(0);
const snapshot = edit.getEdit();
const durationSeconds = edit.totalDuration;
```
#### Events
Listen using string event names:
```typescript
const unsubscribeClipSelected = edit.events.on("clip:selected", data => {
console.log("Selected clip", data.trackIndex, data.clipIndex);
});
edit.events.on("clip:updated", data => {
console.log("Updated from", data.previous, "to", data.current);
});
edit.events.on("playback:play", () => {
console.log("Playback started");
});
// Unsubscribe when no longer needed
unsubscribeClipSelected();
```
Available event names:
| Category | Event Names |
| --- | --- |
| Playback | `playback:play`, `playback:pause` |
| Timeline | `timeline:updated`, `timeline:backgroundChanged`, `timeline:resized` |
| Clip lifecycle | `clip:added`, `clip:selected`, `clip:updated`, `clip:deleted`, `clip:restored`, `clip:copied`, `clip:loadFailed`, `clip:unresolved` |
| Selection | `selection:cleared` |
| Edit state | `edit:changed`, `edit:undo`, `edit:redo` |
| Track | `track:added`, `track:removed` |
| Duration | `duration:changed` |
| Output | `output:resized`, `output:resolutionChanged`, `output:aspectRatioChanged`, `output:fpsChanged`, `output:formatChanged`, `output:destinationsChanged` |
| Merge fields | `mergefield:changed` |
### Canvas
`Canvas` renders the current edit.
```typescript
import { Canvas } from "@shotstack/shotstack-studio";
const canvas = new Canvas(edit);
await canvas.load();
canvas.centerEdit();
canvas.zoomToFit();
canvas.setZoom(1.25);
canvas.resize();
const zoom = canvas.getZoom();
canvas.dispose();
```
### UIController
`UIController` manages built-in UI wiring and extensible button events.
```typescript
import { UIController } from "@shotstack/shotstack-studio";
const ui = UIController.create(edit, canvas, { mergeFields: true });
ui.registerButton({
id: "add-title",
icon: `...`,
tooltip: "Add Title"
});
const unsubscribe = ui.on("button:add-title", ({ position }) => {
console.log("Button clicked at", position, "seconds");
});
ui.unregisterButton("add-title");
unsubscribe();
ui.dispose();
```
### Timeline
`Timeline` provides visual clip editing.
The container must have an explicit CSS `height` (e.g. `height: 300px`) and `overflow: hidden`. Avoid `flex-grow` or `!important` on height — the resize handle sets height via inline style.
```typescript
import { Timeline } from "@shotstack/shotstack-studio";
const container = document.querySelector("[data-shotstack-timeline]") as HTMLElement;
const timeline = new Timeline(edit, container, { resizable: true });
await timeline.load();
timeline.zoomIn();
timeline.zoomOut();
timeline.dispose();
```
Pass `{ resizable: false }` to hide the drag handle. When enabled (default), a `timeline:resized` event fires with `{ height }` after the user finishes dragging or double-clicks to reset.
### Controls
`Controls` enables keyboard playback/edit shortcuts.
```typescript
import { Controls } from "@shotstack/shotstack-studio";
const controls = new Controls(edit);
await controls.load();
```
### VideoExporter
`VideoExporter` exports a timeline render from the browser runtime.
```typescript
import { VideoExporter } from "@shotstack/shotstack-studio";
const exporter = new VideoExporter(edit, canvas);
await exporter.export("my-video.mp4", 25);
```
## Merge Fields
Merge fields are template placeholders, typically in the form `{{ FIELD_NAME }}`.
```json
{
"asset": {
"type": "text",
"text": "{{ TITLE }}"
}
}
```
When merge-field-aware UI is required, enable it via `UIController` options:
```typescript
const ui = UIController.create(edit, canvas, { mergeFields: true });
```
You can also subscribe to merge field events when integrations update merge data:
```typescript
edit.events.on("mergefield:changed", ({ fields }) => {
console.log("Merge fields updated:", fields.length);
});
```
## Custom UI Buttons
Use `UIController` to register and handle custom button actions.
```typescript
ui.registerButton({
id: "text",
icon: `...`,
tooltip: "Add Text",
dividerBefore: true
});
ui.on("button:text", ({ position, selectedClip }) => {
console.log("Current time (seconds):", position);
console.log("Current selection:", selectedClip);
});
ui.unregisterButton("text");
```
## API Reference
For schema-level details and type definitions, see the [Shotstack API Reference](https://shotstack.io/docs/api/#tocs_edit).
## License
PolyForm Shield License 1.0.0