@remotion-studio/sdk 0.1.0
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.
- package/README.md +369 -0
- package/dist/runtime/compiler.d.ts +7 -0
- package/dist/runtime/compiler.js +131 -0
- package/dist/runtime/components.d.ts +4 -0
- package/dist/runtime/components.js +48 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +16 -0
- package/dist/sdk/client.d.ts +37 -0
- package/dist/sdk/client.js +413 -0
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +18 -0
- package/dist/sdk/types.d.ts +197 -0
- package/dist/sdk/types.js +2 -0
- package/dist/shared/artifact.d.ts +58 -0
- package/dist/shared/artifact.js +41 -0
- package/dist/shared/sanitize.d.ts +3 -0
- package/dist/shared/sanitize.js +48 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# Remotion Studio
|
|
2
|
+
|
|
3
|
+
Generate, edit, play, and render AI-created Remotion compositions from your own apps.
|
|
4
|
+
|
|
5
|
+
`@remotion-studio/sdk` is the official package for [Remotion Studio](https://remotionstudio.io). It gives you:
|
|
6
|
+
|
|
7
|
+
- `@remotion-studio/sdk` to call the Remotion Studio API
|
|
8
|
+
- `@remotion-studio/sdk/runtime` to render returned artifacts inside a Remotion project
|
|
9
|
+
|
|
10
|
+
If you want a visual workflow, use the Remotion Studio UI. If you want to automate generation, build editors, run async jobs, or embed generated scenes in your own product, use the SDK.
|
|
11
|
+
|
|
12
|
+
With this package you can:
|
|
13
|
+
|
|
14
|
+
- generate new Remotion compositions from prompts
|
|
15
|
+
- edit compositions through follow-up instructions
|
|
16
|
+
- play returned artifacts directly inside a Remotion app
|
|
17
|
+
- queue long-running async generation or edit jobs
|
|
18
|
+
- start Remotion Lambda renders and track render progress
|
|
19
|
+
- embed the returned artifact directly inside your own Remotion app
|
|
20
|
+
|
|
21
|
+
## Why Use It
|
|
22
|
+
|
|
23
|
+
- Generate motion graphics from prompts
|
|
24
|
+
- Edit existing compositions iteratively
|
|
25
|
+
- Play returned artifacts immediately in Remotion
|
|
26
|
+
- Stream generation output
|
|
27
|
+
- Queue long-running jobs and use polling or webhooks
|
|
28
|
+
- Start cloud renders and poll for the final video output
|
|
29
|
+
- Render the returned artifact directly inside Remotion
|
|
30
|
+
|
|
31
|
+
## Use It Two Ways
|
|
32
|
+
|
|
33
|
+
### 1. Use the UI
|
|
34
|
+
|
|
35
|
+
Use [Remotion Studio](https://remotionstudio.io) when you want a visual workflow:
|
|
36
|
+
|
|
37
|
+
- create and refine compositions in the browser
|
|
38
|
+
- manage prompts, edits, and threads
|
|
39
|
+
- create API tokens for external apps
|
|
40
|
+
|
|
41
|
+
### 2. Use the API and SDK
|
|
42
|
+
|
|
43
|
+
Use `@remotion-studio/sdk` when you want to:
|
|
44
|
+
|
|
45
|
+
- generate compositions from your own app
|
|
46
|
+
- build internal tools or automations
|
|
47
|
+
- trigger async jobs from servers or background workers
|
|
48
|
+
- start Remotion Lambda renders programmatically
|
|
49
|
+
- embed generated artifacts in a Remotion pipeline
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
Install:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install @remotion-studio/sdk
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pnpm add @remotion-studio/sdk
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bun add @remotion-studio/sdk
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Create a client:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createRemotionStudioClient } from "@remotion-studio/sdk";
|
|
71
|
+
|
|
72
|
+
const client = createRemotionStudioClient({
|
|
73
|
+
baseUrl: "https://your-remotionstudio-domain.com",
|
|
74
|
+
headers: {
|
|
75
|
+
Authorization: `Bearer ${process.env.REMOTIONSTUDIO_API_TOKEN}`,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Generate a composition:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const generated = await client.generate({
|
|
84
|
+
prompt: "A cinematic product hero reveal with dramatic lighting",
|
|
85
|
+
reasoningEffort: "none",
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Edit it:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const edited = await client.edit({
|
|
93
|
+
prompt: "Make it faster, cleaner, and more typography-driven",
|
|
94
|
+
currentCode: generated.code,
|
|
95
|
+
threadId: generated.thread?.id,
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use the artifact in Remotion:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { MotionGraphicsSlot } from "@remotion-studio/sdk/runtime";
|
|
103
|
+
|
|
104
|
+
export const MyComposition = ({ artifact }: { artifact: any }) => {
|
|
105
|
+
return <MotionGraphicsSlot artifact={artifact} />;
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Start a Remotion Lambda render:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const render = await client.render({
|
|
113
|
+
inputProps: {
|
|
114
|
+
code: generated.code,
|
|
115
|
+
durationInFrames: generated.artifact.composition.durationInFrames,
|
|
116
|
+
fps: generated.artifact.composition.fps,
|
|
117
|
+
},
|
|
118
|
+
threadId: generated.thread?.id,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const progress = await client.pollRenderProgress({
|
|
122
|
+
id: render.renderId,
|
|
123
|
+
bucketName: render.bucketName,
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Successful renders consume `0.1` credit when the final video is returned.
|
|
128
|
+
|
|
129
|
+
## Getting Access
|
|
130
|
+
|
|
131
|
+
To use the hosted product, create an account in [Remotion Studio](https://remotionstudio.io).
|
|
132
|
+
|
|
133
|
+
To generate, edit, or render compositions through the hosted product, you also need active access to Remotion Studio credits or a subscription plan.
|
|
134
|
+
|
|
135
|
+
For programmatic usage:
|
|
136
|
+
|
|
137
|
+
1. Sign in to Remotion Studio
|
|
138
|
+
2. Open `Settings -> API Tokens`
|
|
139
|
+
3. Create a token
|
|
140
|
+
4. Use it as a bearer token in the SDK client
|
|
141
|
+
|
|
142
|
+
The plaintext token is shown only once.
|
|
143
|
+
|
|
144
|
+
## What The SDK Returns
|
|
145
|
+
|
|
146
|
+
You do not import generated files directly.
|
|
147
|
+
|
|
148
|
+
Instead:
|
|
149
|
+
|
|
150
|
+
1. Call the API with `@remotion-studio/sdk`
|
|
151
|
+
2. Receive a JSON payload containing `artifact`
|
|
152
|
+
3. Pass `artifact` into `@remotion-studio/sdk/runtime`
|
|
153
|
+
|
|
154
|
+
The artifact is the stable contract between generation and playback.
|
|
155
|
+
|
|
156
|
+
## Core API
|
|
157
|
+
|
|
158
|
+
### Generate
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const generated = await client.generate({
|
|
162
|
+
prompt: "A clean fintech dashboard animation with sliding cards",
|
|
163
|
+
reasoningEffort: "high",
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Presets
|
|
168
|
+
|
|
169
|
+
Pass a `presetId` to generate compositions using a predefined style template:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const generated = await client.generate({
|
|
173
|
+
prompt: "A product showcase with smooth transitions",
|
|
174
|
+
presetId: "preset-abc123",
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The response includes preset information in the metadata:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
console.log(generated.metadata.preset);
|
|
182
|
+
// { id: "preset-abc123", name: "Corporate Minimal", source: "builtin" | "custom" }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Presets are created and managed in the Remotion Studio UI. Builtin presets are provided by Remotion Studio. Custom presets are user-created templates that encode style preferences, animation patterns, and design choices.
|
|
186
|
+
|
|
187
|
+
### Edit
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const edited = await client.edit({
|
|
191
|
+
prompt: "Use a brighter palette and add more depth",
|
|
192
|
+
currentCode: generated.code,
|
|
193
|
+
threadId: generated.thread?.id,
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Stream
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const result = await client.generateStream(
|
|
201
|
+
{
|
|
202
|
+
prompt: "A kinetic typography intro",
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
onMetadata: (metadata) => {
|
|
206
|
+
console.log(metadata);
|
|
207
|
+
},
|
|
208
|
+
onReasoning: (reasoning) => {
|
|
209
|
+
console.log(reasoning);
|
|
210
|
+
},
|
|
211
|
+
onCode: (partialCode) => {
|
|
212
|
+
console.log(partialCode);
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Async Jobs
|
|
219
|
+
|
|
220
|
+
Use async jobs for:
|
|
221
|
+
|
|
222
|
+
- high-reasoning generations
|
|
223
|
+
- server-to-server automation
|
|
224
|
+
- long-running edits
|
|
225
|
+
- webhook-driven integrations
|
|
226
|
+
|
|
227
|
+
Queue a generation:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
const job = await client.generateAsync({
|
|
231
|
+
prompt: "A premium SaaS launch video opener",
|
|
232
|
+
reasoningEffort: "high",
|
|
233
|
+
webhook: {
|
|
234
|
+
url: "https://your-app.example.com/remotionstudio/webhook",
|
|
235
|
+
headers: {
|
|
236
|
+
Authorization: "Bearer your-app-owned-callback-token",
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const generated = await client.pollGenerationJob(job.id, {
|
|
242
|
+
intervalMs: 2000,
|
|
243
|
+
timeoutMs: 10 * 60 * 1000,
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Queue an edit:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
const job = await client.editAsync({
|
|
251
|
+
prompt: "Add more contrast and speed up the transitions",
|
|
252
|
+
currentCode: generated.code,
|
|
253
|
+
threadId: generated.thread?.id,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const edited = await client.pollEditJob(job.id);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
If you provide a webhook, Remotion Studio sends the terminal job payload to your callback URL after completion or failure.
|
|
260
|
+
|
|
261
|
+
Webhook authentication is handled by caller-provided headers. Remotion Studio forwards those headers when delivering the callback.
|
|
262
|
+
|
|
263
|
+
There is no built-in webhook signature mechanism.
|
|
264
|
+
|
|
265
|
+
The recommended pattern is:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
await client.generateAsync({
|
|
269
|
+
prompt: "...",
|
|
270
|
+
webhook: {
|
|
271
|
+
url: "https://your-app.example.com/remotionstudio/webhook",
|
|
272
|
+
headers: {
|
|
273
|
+
Authorization: "Bearer your-app-owned-callback-token",
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Remotion Studio may include neutral metadata headers such as `X-RemotionStudio-Job-Id` and `X-RemotionStudio-Job-Type`, but it does not sign, mutate, wrap, or replace caller-provided webhook headers.
|
|
280
|
+
|
|
281
|
+
## Local Dev And Production
|
|
282
|
+
|
|
283
|
+
The async API contract stays the same across environments:
|
|
284
|
+
|
|
285
|
+
- local `next dev`: jobs are stored in the database and processed by a local runner
|
|
286
|
+
- Vercel preview/production: jobs are stored in the database and executed through Vercel Workflow
|
|
287
|
+
|
|
288
|
+
In both cases:
|
|
289
|
+
|
|
290
|
+
- polling endpoints remain the source of truth
|
|
291
|
+
- webhooks receive the same terminal payload shape
|
|
292
|
+
- transient webhook failures are retried
|
|
293
|
+
|
|
294
|
+
## Runtime
|
|
295
|
+
|
|
296
|
+
Use `@remotion-studio/sdk/runtime` when you want to render returned artifacts inside a Remotion project.
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
import { Composition } from "remotion";
|
|
300
|
+
import {
|
|
301
|
+
MotionGraphicsComposition,
|
|
302
|
+
calculateMotionGraphicsMetadata,
|
|
303
|
+
type MotionGraphicsCompositionProps,
|
|
304
|
+
} from "@remotion-studio/sdk/runtime";
|
|
305
|
+
|
|
306
|
+
export const RemotionRoot = ({ artifact }: MotionGraphicsCompositionProps) => {
|
|
307
|
+
return (
|
|
308
|
+
<Composition
|
|
309
|
+
id="GeneratedComposition"
|
|
310
|
+
component={MotionGraphicsComposition}
|
|
311
|
+
defaultProps={{ artifact }}
|
|
312
|
+
durationInFrames={180}
|
|
313
|
+
fps={30}
|
|
314
|
+
width={1920}
|
|
315
|
+
height={1080}
|
|
316
|
+
calculateMetadata={calculateMotionGraphicsMetadata}
|
|
317
|
+
/>
|
|
318
|
+
);
|
|
319
|
+
};
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
The runtime expects a normal Remotion project with the peer dependencies installed, including `react`, `remotion`, `three`, `@babel/standalone`, `@remotion/lottie`, `@remotion/shapes`, `@remotion/three`, and `@remotion/transitions`.
|
|
323
|
+
|
|
324
|
+
## Render API
|
|
325
|
+
|
|
326
|
+
If your Remotion Studio instance is configured with Remotion Lambda, the SDK also supports:
|
|
327
|
+
|
|
328
|
+
- `client.render()` to queue a render
|
|
329
|
+
- `client.getRenderProgress()` to fetch the latest render state
|
|
330
|
+
- `client.pollRenderProgress()` to wait until the render completes
|
|
331
|
+
|
|
332
|
+
The render endpoints return the Remotion Lambda render identifiers and progress state, including the final output URL when rendering is done.
|
|
333
|
+
|
|
334
|
+
## Model And Credit Notes
|
|
335
|
+
|
|
336
|
+
The base model is controlled by the Remotion Studio admin. External clients should usually send only `reasoningEffort`.
|
|
337
|
+
Supported `reasoningEffort` values are `none`, `low`, `medium`, `high`, and `xhigh`. Use `none` to explicitly disable reasoning.
|
|
338
|
+
|
|
339
|
+
Current credit usage is:
|
|
340
|
+
|
|
341
|
+
- default request or `reasoningEffort: "none"`: 1 credit
|
|
342
|
+
- successful render completion: 0.1 credit
|
|
343
|
+
- `low`: 2 credits
|
|
344
|
+
- `medium`: 3 credits
|
|
345
|
+
- `high`: 4 credits
|
|
346
|
+
- `xhigh`: 5 credits
|
|
347
|
+
|
|
348
|
+
Legacy clients may still send `model: "provider/model:medium"`, but only the reasoning suffix is used.
|
|
349
|
+
|
|
350
|
+
## API Docs
|
|
351
|
+
|
|
352
|
+
If you run your own Remotion Studio instance, the generated API reference is available at:
|
|
353
|
+
|
|
354
|
+
```text
|
|
355
|
+
https://your-remotionstudio-domain.com/api-docs
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Links
|
|
359
|
+
|
|
360
|
+
- Website: [remotionstudio.io](https://remotionstudio.io)
|
|
361
|
+
- Product: [Remotion Studio](https://remotionstudio.io)
|
|
362
|
+
- Repository: [github.com/prismosoft/remotionstudio](https://github.com/prismosoft/remotionstudio)
|
|
363
|
+
|
|
364
|
+
## Package Exports
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
import { createRemotionStudioClient } from "@remotion-studio/sdk";
|
|
368
|
+
import { MotionGraphicsSlot } from "@remotion-studio/sdk/runtime";
|
|
369
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { MotionGraphicsArtifact } from "../shared/artifact";
|
|
3
|
+
export interface CompilationResult {
|
|
4
|
+
Component: React.ComponentType<Record<string, unknown>> | null;
|
|
5
|
+
error: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function compileMotionGraphicsArtifact(artifact: MotionGraphicsArtifact): CompilationResult;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.compileMotionGraphicsArtifact = compileMotionGraphicsArtifact;
|
|
37
|
+
const Babel = __importStar(require("@babel/standalone"));
|
|
38
|
+
const lottie_1 = require("@remotion/lottie");
|
|
39
|
+
const RemotionShapes = __importStar(require("@remotion/shapes"));
|
|
40
|
+
const three_1 = require("@remotion/three");
|
|
41
|
+
const transitions_1 = require("@remotion/transitions");
|
|
42
|
+
const clock_wipe_1 = require("@remotion/transitions/clock-wipe");
|
|
43
|
+
const fade_1 = require("@remotion/transitions/fade");
|
|
44
|
+
const flip_1 = require("@remotion/transitions/flip");
|
|
45
|
+
const slide_1 = require("@remotion/transitions/slide");
|
|
46
|
+
const wipe_1 = require("@remotion/transitions/wipe");
|
|
47
|
+
const react_1 = __importStar(require("react"));
|
|
48
|
+
const remotion_1 = require("remotion");
|
|
49
|
+
const THREE = __importStar(require("three"));
|
|
50
|
+
const compilationCache = new Map();
|
|
51
|
+
function stripImportStatements(code) {
|
|
52
|
+
let cleaned = code;
|
|
53
|
+
cleaned = cleaned.replace(/import\s+type\s*\{[\s\S]*?\}\s*from\s*["'][^"']+["'];?/g, "");
|
|
54
|
+
cleaned = cleaned.replace(/import\s+\w+\s*,\s*\{[\s\S]*?\}\s*from\s*["'][^"']+["'];?/g, "");
|
|
55
|
+
cleaned = cleaned.replace(/import\s*\{[\s\S]*?\}\s*from\s*["'][^"']+["'];?/g, "");
|
|
56
|
+
cleaned = cleaned.replace(/import\s+\*\s+as\s+\w+\s+from\s*["'][^"']+["'];?/g, "");
|
|
57
|
+
cleaned = cleaned.replace(/import\s+\w+\s+from\s*["'][^"']+["'];?/g, "");
|
|
58
|
+
cleaned = cleaned.replace(/import\s*["'][^"']+["'];?/g, "");
|
|
59
|
+
return cleaned.trim();
|
|
60
|
+
}
|
|
61
|
+
function getExportedComponentName(code) {
|
|
62
|
+
const match = code.match(/export\s+const\s+(\w+)/);
|
|
63
|
+
return match?.[1] ?? null;
|
|
64
|
+
}
|
|
65
|
+
function buildExecutableSource(code) {
|
|
66
|
+
const cleaned = stripImportStatements(code);
|
|
67
|
+
const componentName = getExportedComponentName(cleaned);
|
|
68
|
+
if (!componentName) {
|
|
69
|
+
throw new Error('Code must export a component using `export const ComponentName = ...`.');
|
|
70
|
+
}
|
|
71
|
+
const executableSource = cleaned.replace(/export\s+const\s+(\w+)/, "const $1");
|
|
72
|
+
return {
|
|
73
|
+
executableSource,
|
|
74
|
+
componentName,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function createCompilationError(message) {
|
|
78
|
+
return {
|
|
79
|
+
Component: null,
|
|
80
|
+
error: message,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function compileMotionGraphicsArtifact(artifact) {
|
|
84
|
+
const code = artifact.code?.trim();
|
|
85
|
+
if (!code) {
|
|
86
|
+
return createCompilationError("No code provided");
|
|
87
|
+
}
|
|
88
|
+
const cached = compilationCache.get(code);
|
|
89
|
+
if (cached) {
|
|
90
|
+
return cached;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const { executableSource, componentName } = buildExecutableSource(code);
|
|
94
|
+
const transpiled = Babel.transform(executableSource, {
|
|
95
|
+
presets: ["react", "typescript"],
|
|
96
|
+
filename: "motion-graphics-artifact.tsx",
|
|
97
|
+
});
|
|
98
|
+
if (!transpiled.code) {
|
|
99
|
+
const result = createCompilationError("Transpilation failed");
|
|
100
|
+
compilationCache.set(code, result);
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
const wrappedCode = `${transpiled.code}\nreturn ${componentName};`;
|
|
104
|
+
const createComponent = new Function("React", "Remotion", "RemotionShapes", "Lottie", "ThreeCanvas", "THREE", "AbsoluteFill", "interpolate", "useCurrentFrame", "useVideoConfig", "spring", "Sequence", "Img", "useState", "useEffect", "useMemo", "useRef", "Rect", "Circle", "Triangle", "Star", "Polygon", "Ellipse", "Heart", "Pie", "makeRect", "makeCircle", "makeTriangle", "makeStar", "makePolygon", "makeEllipse", "makeHeart", "makePie", "TransitionSeries", "linearTiming", "springTiming", "fade", "slide", "wipe", "flip", "clockWipe", wrappedCode);
|
|
105
|
+
const Component = createComponent(react_1.default, {
|
|
106
|
+
AbsoluteFill: remotion_1.AbsoluteFill,
|
|
107
|
+
interpolate: remotion_1.interpolate,
|
|
108
|
+
useCurrentFrame: remotion_1.useCurrentFrame,
|
|
109
|
+
useVideoConfig: remotion_1.useVideoConfig,
|
|
110
|
+
spring: remotion_1.spring,
|
|
111
|
+
Sequence: remotion_1.Sequence,
|
|
112
|
+
Img: remotion_1.Img,
|
|
113
|
+
}, RemotionShapes, lottie_1.Lottie, three_1.ThreeCanvas, THREE, remotion_1.AbsoluteFill, remotion_1.interpolate, remotion_1.useCurrentFrame, remotion_1.useVideoConfig, remotion_1.spring, remotion_1.Sequence, remotion_1.Img, react_1.useState, react_1.useEffect, react_1.useMemo, react_1.useRef, RemotionShapes.Rect, RemotionShapes.Circle, RemotionShapes.Triangle, RemotionShapes.Star, RemotionShapes.Polygon, RemotionShapes.Ellipse, RemotionShapes.Heart, RemotionShapes.Pie, RemotionShapes.makeRect, RemotionShapes.makeCircle, RemotionShapes.makeTriangle, RemotionShapes.makeStar, RemotionShapes.makePolygon, RemotionShapes.makeEllipse, RemotionShapes.makeHeart, RemotionShapes.makePie, transitions_1.TransitionSeries, transitions_1.linearTiming, transitions_1.springTiming, fade_1.fade, slide_1.slide, wipe_1.wipe, flip_1.flip, clock_wipe_1.clockWipe);
|
|
114
|
+
if (typeof Component !== "function") {
|
|
115
|
+
const result = createCompilationError("Code must export a React component function");
|
|
116
|
+
compilationCache.set(code, result);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
const result = {
|
|
120
|
+
Component: Component,
|
|
121
|
+
error: null,
|
|
122
|
+
};
|
|
123
|
+
compilationCache.set(code, result);
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const result = createCompilationError(error instanceof Error ? error.message : "Unknown compilation error");
|
|
128
|
+
compilationCache.set(code, result);
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { MotionGraphicsCompositionProps } from "../shared/artifact";
|
|
3
|
+
export declare const MotionGraphicsComposition: React.FC<MotionGraphicsCompositionProps>;
|
|
4
|
+
export declare const MotionGraphicsSlot: React.FC<MotionGraphicsCompositionProps>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MotionGraphicsSlot = exports.MotionGraphicsComposition = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const remotion_1 = require("remotion");
|
|
7
|
+
const compiler_1 = require("./compiler");
|
|
8
|
+
const RuntimeErrorDisplay = ({ error }) => {
|
|
9
|
+
return ((0, jsx_runtime_1.jsxs)(remotion_1.AbsoluteFill, { style: {
|
|
10
|
+
backgroundColor: "#1a1a2e",
|
|
11
|
+
justifyContent: "center",
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
padding: 60,
|
|
14
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
15
|
+
color: "#ff6b6b",
|
|
16
|
+
fontSize: 42,
|
|
17
|
+
fontFamily: "system-ui, sans-serif",
|
|
18
|
+
textAlign: "center",
|
|
19
|
+
maxWidth: "80%",
|
|
20
|
+
}, children: "Compilation Error" }), (0, jsx_runtime_1.jsx)("div", { style: {
|
|
21
|
+
color: "#fff",
|
|
22
|
+
fontSize: 24,
|
|
23
|
+
fontFamily: "monospace",
|
|
24
|
+
marginTop: 24,
|
|
25
|
+
textAlign: "center",
|
|
26
|
+
maxWidth: "80%",
|
|
27
|
+
wordBreak: "break-word",
|
|
28
|
+
}, children: error })] }));
|
|
29
|
+
};
|
|
30
|
+
const MotionGraphicsRenderer = ({ artifact, componentProps, }) => {
|
|
31
|
+
const result = (0, react_1.useMemo)(() => (0, compiler_1.compileMotionGraphicsArtifact)(artifact), [artifact.code]);
|
|
32
|
+
if (result.error) {
|
|
33
|
+
return (0, jsx_runtime_1.jsx)(RuntimeErrorDisplay, { error: result.error });
|
|
34
|
+
}
|
|
35
|
+
if (!result.Component) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const Component = result.Component;
|
|
39
|
+
return (0, jsx_runtime_1.jsx)(Component, { ...(componentProps ?? {}) });
|
|
40
|
+
};
|
|
41
|
+
const MotionGraphicsComposition = (props) => {
|
|
42
|
+
return (0, jsx_runtime_1.jsx)(MotionGraphicsRenderer, { ...props });
|
|
43
|
+
};
|
|
44
|
+
exports.MotionGraphicsComposition = MotionGraphicsComposition;
|
|
45
|
+
const MotionGraphicsSlot = (props) => {
|
|
46
|
+
return (0, jsx_runtime_1.jsx)(MotionGraphicsRenderer, { ...props });
|
|
47
|
+
};
|
|
48
|
+
exports.MotionGraphicsSlot = MotionGraphicsSlot;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DEFAULT_MOTION_GRAPHICS_DURATION_IN_FRAMES, DEFAULT_MOTION_GRAPHICS_FPS, DEFAULT_MOTION_GRAPHICS_HEIGHT, DEFAULT_MOTION_GRAPHICS_WIDTH, MOTION_GRAPHICS_ARTIFACT_VERSION, MOTION_GRAPHICS_RUNTIME, calculateMotionGraphicsMetadata, type MotionGraphicsArtifact, type MotionGraphicsArtifactV1, type MotionGraphicsCompositionProps, type MotionGraphicsEditType, } from "../shared/artifact";
|
|
2
|
+
export { MotionGraphicsComposition, MotionGraphicsSlot } from "./components";
|
|
3
|
+
export { compileMotionGraphicsArtifact, type CompilationResult, } from "./compiler";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileMotionGraphicsArtifact = exports.MotionGraphicsSlot = exports.MotionGraphicsComposition = exports.calculateMotionGraphicsMetadata = exports.MOTION_GRAPHICS_RUNTIME = exports.MOTION_GRAPHICS_ARTIFACT_VERSION = exports.DEFAULT_MOTION_GRAPHICS_WIDTH = exports.DEFAULT_MOTION_GRAPHICS_HEIGHT = exports.DEFAULT_MOTION_GRAPHICS_FPS = exports.DEFAULT_MOTION_GRAPHICS_DURATION_IN_FRAMES = void 0;
|
|
4
|
+
var artifact_1 = require("../shared/artifact");
|
|
5
|
+
Object.defineProperty(exports, "DEFAULT_MOTION_GRAPHICS_DURATION_IN_FRAMES", { enumerable: true, get: function () { return artifact_1.DEFAULT_MOTION_GRAPHICS_DURATION_IN_FRAMES; } });
|
|
6
|
+
Object.defineProperty(exports, "DEFAULT_MOTION_GRAPHICS_FPS", { enumerable: true, get: function () { return artifact_1.DEFAULT_MOTION_GRAPHICS_FPS; } });
|
|
7
|
+
Object.defineProperty(exports, "DEFAULT_MOTION_GRAPHICS_HEIGHT", { enumerable: true, get: function () { return artifact_1.DEFAULT_MOTION_GRAPHICS_HEIGHT; } });
|
|
8
|
+
Object.defineProperty(exports, "DEFAULT_MOTION_GRAPHICS_WIDTH", { enumerable: true, get: function () { return artifact_1.DEFAULT_MOTION_GRAPHICS_WIDTH; } });
|
|
9
|
+
Object.defineProperty(exports, "MOTION_GRAPHICS_ARTIFACT_VERSION", { enumerable: true, get: function () { return artifact_1.MOTION_GRAPHICS_ARTIFACT_VERSION; } });
|
|
10
|
+
Object.defineProperty(exports, "MOTION_GRAPHICS_RUNTIME", { enumerable: true, get: function () { return artifact_1.MOTION_GRAPHICS_RUNTIME; } });
|
|
11
|
+
Object.defineProperty(exports, "calculateMotionGraphicsMetadata", { enumerable: true, get: function () { return artifact_1.calculateMotionGraphicsMetadata; } });
|
|
12
|
+
var components_1 = require("./components");
|
|
13
|
+
Object.defineProperty(exports, "MotionGraphicsComposition", { enumerable: true, get: function () { return components_1.MotionGraphicsComposition; } });
|
|
14
|
+
Object.defineProperty(exports, "MotionGraphicsSlot", { enumerable: true, get: function () { return components_1.MotionGraphicsSlot; } });
|
|
15
|
+
var compiler_1 = require("./compiler");
|
|
16
|
+
Object.defineProperty(exports, "compileMotionGraphicsArtifact", { enumerable: true, get: function () { return compiler_1.compileMotionGraphicsArtifact; } });
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createMotionGraphicsArtifact, type MotionGraphicsArtifact } from "../shared/artifact";
|
|
2
|
+
import type { EditAsyncRequest, EditJobAcceptedResponse, EditJobResponse, EditRequest, EditResponse, GenerateAsyncRequest, GenerationJobAcceptedResponse, GenerationJobResponse, PollEditJobOptions, PollRenderProgressOptions, GenerateRequest, GenerateResponse, PollGenerationJobOptions, GenerateStreamCallbacks, GenerateStreamResult, RenderProgressRequest, RenderProgressResponse, RenderRequest, RenderResponse, RemotionStudioErrorData, RemotionStudioErrorType } from "./types";
|
|
3
|
+
type FetchLike = typeof fetch;
|
|
4
|
+
type CreateRemotionStudioClientOptions = {
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
fetch?: FetchLike;
|
|
7
|
+
headers?: HeadersInit;
|
|
8
|
+
};
|
|
9
|
+
type RequestOptions = {
|
|
10
|
+
headers?: HeadersInit;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
};
|
|
13
|
+
export declare class RemotionStudioError extends Error {
|
|
14
|
+
readonly type: RemotionStudioErrorType;
|
|
15
|
+
readonly status?: number;
|
|
16
|
+
readonly failedEdit?: RemotionStudioErrorData["failedEdit"];
|
|
17
|
+
readonly availableCredits?: number;
|
|
18
|
+
readonly requiredCredits?: number;
|
|
19
|
+
constructor(data: RemotionStudioErrorData);
|
|
20
|
+
}
|
|
21
|
+
export declare const createRemotionStudioClient: ({ baseUrl, fetch: providedFetch, headers: defaultHeaders, }?: CreateRemotionStudioClientOptions) => {
|
|
22
|
+
generate(request: GenerateRequest, options?: RequestOptions): Promise<GenerateResponse>;
|
|
23
|
+
edit(request: EditRequest, options?: RequestOptions): Promise<EditResponse>;
|
|
24
|
+
generateAsync(request: GenerateAsyncRequest, options?: RequestOptions): Promise<GenerationJobAcceptedResponse>;
|
|
25
|
+
editAsync(request: EditAsyncRequest, options?: RequestOptions): Promise<EditJobAcceptedResponse>;
|
|
26
|
+
getGenerationJob(jobId: string, options?: RequestOptions): Promise<GenerationJobResponse>;
|
|
27
|
+
getEditJob(jobId: string, options?: RequestOptions): Promise<EditJobResponse>;
|
|
28
|
+
pollGenerationJob(jobId: string, options?: PollGenerationJobOptions): Promise<GenerateResponse>;
|
|
29
|
+
pollEditJob(jobId: string, options?: PollEditJobOptions): Promise<EditResponse>;
|
|
30
|
+
render(request: RenderRequest, options?: RequestOptions): Promise<RenderResponse>;
|
|
31
|
+
getRenderProgress(request: RenderProgressRequest, options?: RequestOptions): Promise<RenderProgressResponse>;
|
|
32
|
+
pollRenderProgress(request: RenderProgressRequest, options?: PollRenderProgressOptions): Promise<Extract<RenderProgressResponse, {
|
|
33
|
+
type: "done";
|
|
34
|
+
}>>;
|
|
35
|
+
generateStream(request: GenerateRequest, callbacks?: GenerateStreamCallbacks, options?: RequestOptions): Promise<GenerateStreamResult>;
|
|
36
|
+
};
|
|
37
|
+
export { createMotionGraphicsArtifact, type MotionGraphicsArtifact, };
|