@rendiv/studio 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.
@@ -0,0 +1,2 @@
1
+ export { startStudio, type StudioOptions, type StudioResult } from './start-studio.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { startStudio } from './start-studio.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAyC,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface StudioOptions {
2
+ entryPoint: string;
3
+ port?: number;
4
+ publicDir?: string;
5
+ }
6
+ export interface StudioResult {
7
+ url: string;
8
+ close: () => Promise<void>;
9
+ }
10
+ export declare function startStudio(options: StudioOptions): Promise<StudioResult>;
11
+ //# sourceMappingURL=start-studio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-studio.d.ts","sourceRoot":"","sources":["../src/start-studio.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAOD,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAwE/E"}
@@ -0,0 +1,74 @@
1
+ import { createServer } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { generateStudioEntryCode, generateStudioHtml, FAVICON_SVG } from './studio-entry-code.js';
7
+ import { rendivStudioPlugin } from './vite-plugin-studio.js';
8
+ const STUDIO_DIR = '.studio';
9
+ const ENTRY_FILE = 'entry.tsx';
10
+ const HTML_FILE = 'studio.html';
11
+ const FAVICON_FILE = 'favicon.svg';
12
+ export async function startStudio(options) {
13
+ const { entryPoint, port = 3000, publicDir = 'public' } = options;
14
+ const cwd = process.cwd();
15
+ const absoluteEntry = path.isAbsolute(entryPoint)
16
+ ? entryPoint
17
+ : path.resolve(cwd, entryPoint);
18
+ // Locate the ui/ directory shipped with this package
19
+ const thisDir = path.dirname(fileURLToPath(import.meta.url));
20
+ const studioUiDir = path.resolve(thisDir, '..', 'ui');
21
+ // Generate and write temp entry files under .studio/
22
+ const studioDir = path.join(cwd, STUDIO_DIR);
23
+ fs.mkdirSync(studioDir, { recursive: true });
24
+ const studioEntryFile = `${STUDIO_DIR}/${ENTRY_FILE}`;
25
+ const studioHtmlFile = `${STUDIO_DIR}/${HTML_FILE}`;
26
+ const studioFaviconFile = `${STUDIO_DIR}/${FAVICON_FILE}`;
27
+ const entryCode = generateStudioEntryCode(absoluteEntry, studioUiDir, entryPoint);
28
+ const htmlCode = generateStudioHtml(studioEntryFile, studioFaviconFile);
29
+ fs.writeFileSync(path.join(studioDir, ENTRY_FILE), entryCode);
30
+ fs.writeFileSync(path.join(studioDir, HTML_FILE), htmlCode);
31
+ fs.writeFileSync(path.join(studioDir, FAVICON_FILE), FAVICON_SVG);
32
+ // configFile: false prevents Vite from loading the user's vite.config.ts,
33
+ // which may already include @vitejs/plugin-react. Adding it twice causes
34
+ // React Refresh to inject duplicate preamble declarations.
35
+ const server = await createServer({
36
+ configFile: false,
37
+ root: cwd,
38
+ publicDir: path.resolve(cwd, publicDir),
39
+ plugins: [
40
+ react(),
41
+ rendivStudioPlugin({ studioHtmlFileName: studioHtmlFile, entryPoint: absoluteEntry }),
42
+ ],
43
+ resolve: {
44
+ // Force Vite to resolve these packages from the user's project root,
45
+ // not from the studio UI files' location (which is outside the project).
46
+ dedupe: ['react', 'react-dom', '@rendiv/core', '@rendiv/player'],
47
+ },
48
+ server: {
49
+ port,
50
+ open: true,
51
+ },
52
+ optimizeDeps: {
53
+ entries: [studioEntryFile],
54
+ exclude: ['@rendiv/core', '@rendiv/player'],
55
+ },
56
+ logLevel: 'info',
57
+ });
58
+ await server.listen();
59
+ const resolvedPort = server.config.server.port ?? port;
60
+ const url = `http://localhost:${resolvedPort}`;
61
+ const cleanup = () => {
62
+ if (fs.existsSync(studioDir)) {
63
+ fs.rmSync(studioDir, { recursive: true, force: true });
64
+ }
65
+ };
66
+ return {
67
+ url,
68
+ close: async () => {
69
+ await server.close();
70
+ cleanup();
71
+ },
72
+ };
73
+ }
74
+ //# sourceMappingURL=start-studio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-studio.js","sourceRoot":"","sources":["../src/start-studio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Generates the JSX entry code for the Studio.
3
+ * This code imports the user's entry (which calls setRootComponent),
4
+ * then mounts the Studio React UI shell.
5
+ */
6
+ export declare function generateStudioEntryCode(userEntryPoint: string, studioUiDir: string, relativeEntryPoint: string): string;
7
+ /** Favicon SVG content (icon-only version of the Rendiv logo). */
8
+ export declare const FAVICON_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" fill=\"none\">\n <rect x=\"6\" y=\"8\" width=\"26\" height=\"20\" rx=\"3\" stroke=\"#58a6ff\" stroke-width=\"2\" opacity=\"0.35\"/>\n <rect x=\"12\" y=\"14\" width=\"26\" height=\"20\" rx=\"3\" stroke=\"#58a6ff\" stroke-width=\"2\"/>\n <clipPath id=\"ic\"><rect x=\"12\" y=\"14\" width=\"26\" height=\"20\" rx=\"3\"/></clipPath>\n <g clip-path=\"url(#ic)\"><polygon points=\"12,34 30,14 38,14 38,34\" fill=\"#58a6ff\" opacity=\"0.25\"/></g>\n <path d=\"M22 20L30 24L22 28Z\" fill=\"#58a6ff\"/>\n</svg>";
9
+ /**
10
+ * Generates the HTML template for the Studio shell.
11
+ */
12
+ export declare function generateStudioHtml(entryFileName: string, faviconPath: string): string;
13
+ //# sourceMappingURL=studio-entry-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-entry-code.d.ts","sourceRoot":"","sources":["../src/studio-entry-code.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAYR;AAED,kEAAkE;AAClE,eAAO,MAAM,WAAW,+jBAMjB,CAAC;AAER;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAkBrF"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Generates the JSX entry code for the Studio.
3
+ * This code imports the user's entry (which calls setRootComponent),
4
+ * then mounts the Studio React UI shell.
5
+ */
6
+ export function generateStudioEntryCode(userEntryPoint, studioUiDir, relativeEntryPoint) {
7
+ // Normalize backslashes to forward slashes for import paths
8
+ const normalizedEntry = userEntryPoint.replace(/\\/g, '/');
9
+ const normalizedUiDir = studioUiDir.replace(/\\/g, '/');
10
+ return `
11
+ window.__RENDIV_STUDIO_ENTRY__ = ${JSON.stringify(relativeEntryPoint)};
12
+ import '${normalizedEntry}';
13
+ import { createStudioApp } from '${normalizedUiDir}/StudioApp.tsx';
14
+
15
+ createStudioApp(document.getElementById('root'));
16
+ `;
17
+ }
18
+ /** Favicon SVG content (icon-only version of the Rendiv logo). */
19
+ export const FAVICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
20
+ <rect x="6" y="8" width="26" height="20" rx="3" stroke="#58a6ff" stroke-width="2" opacity="0.35"/>
21
+ <rect x="12" y="14" width="26" height="20" rx="3" stroke="#58a6ff" stroke-width="2"/>
22
+ <clipPath id="ic"><rect x="12" y="14" width="26" height="20" rx="3"/></clipPath>
23
+ <g clip-path="url(#ic)"><polygon points="12,34 30,14 38,14 38,34" fill="#58a6ff" opacity="0.25"/></g>
24
+ <path d="M22 20L30 24L22 28Z" fill="#58a6ff"/>
25
+ </svg>`;
26
+ /**
27
+ * Generates the HTML template for the Studio shell.
28
+ */
29
+ export function generateStudioHtml(entryFileName, faviconPath) {
30
+ return `<!DOCTYPE html>
31
+ <html lang="en">
32
+ <head>
33
+ <meta charset="UTF-8" />
34
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
35
+ <link rel="icon" type="image/svg+xml" href="/${faviconPath}" />
36
+ <title>Rendiv Studio</title>
37
+ <style>
38
+ * { margin: 0; padding: 0; box-sizing: border-box; }
39
+ html, body, #root { width: 100%; height: 100vh; overflow: hidden; }
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <div id="root"></div>
44
+ <script type="module" src="/${entryFileName}"></script>
45
+ </body>
46
+ </html>`;
47
+ }
48
+ //# sourceMappingURL=studio-entry-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-entry-code.js","sourceRoot":"","sources":["../src/studio-entry-code.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,cAAsB,EACtB,WAAmB,EACnB,kBAA0B;IAE1B,4DAA4D;IAC5D,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAExD,OAAO;mCAC0B,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;UAC3D,eAAe;mCACU,eAAe;;;CAGjD,CAAC;AACF,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;OAMpB,CAAC;AAER;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAqB,EAAE,WAAmB;IAC3E,OAAO;;;;;iDAKwC,WAAW;;;;;;;;;gCAS5B,aAAa;;QAErC,CAAC;AACT,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Plugin } from 'vite';
2
+ export interface StudioPluginOptions {
3
+ studioHtmlFileName: string;
4
+ entryPoint: string;
5
+ }
6
+ export declare function rendivStudioPlugin(options: StudioPluginOptions): Plugin;
7
+ //# sourceMappingURL=vite-plugin-studio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin-studio.d.ts","sourceRoot":"","sources":["../src/vite-plugin-studio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AA4HD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAmFvE"}
@@ -0,0 +1,173 @@
1
+ let renderJobs = [];
2
+ let nextJobId = 1;
3
+ let activeJobId = null;
4
+ let activeAbortController = null;
5
+ function readBody(req) {
6
+ return new Promise((resolve, reject) => {
7
+ const chunks = [];
8
+ req.on('data', (chunk) => chunks.push(chunk));
9
+ req.on('end', () => resolve(Buffer.concat(chunks).toString()));
10
+ req.on('error', reject);
11
+ });
12
+ }
13
+ function processQueue(entryPoint) {
14
+ if (activeJobId)
15
+ return;
16
+ const nextJob = renderJobs.find((j) => j.status === 'queued');
17
+ if (!nextJob)
18
+ return;
19
+ activeJobId = nextJob.id;
20
+ const abortController = new AbortController();
21
+ activeAbortController = abortController;
22
+ const updateJob = (updates) => {
23
+ const job = renderJobs.find((j) => j.id === activeJobId);
24
+ if (job)
25
+ Object.assign(job, updates);
26
+ };
27
+ (async () => {
28
+ updateJob({ status: 'bundling', progress: 0 });
29
+ try {
30
+ const { bundle } = await import('@rendiv/bundler');
31
+ const { selectComposition, renderMedia, closeBrowser } = await import('@rendiv/renderer');
32
+ // Step 1: Bundle
33
+ const bundlePath = await bundle({
34
+ entryPoint,
35
+ onProgress: (p) => {
36
+ updateJob({ progress: p });
37
+ },
38
+ });
39
+ if (abortController.signal.aborted) {
40
+ updateJob({ status: 'cancelled' });
41
+ return;
42
+ }
43
+ // Step 2: Get composition metadata
44
+ const composition = await selectComposition(bundlePath, nextJob.compositionId, nextJob.inputProps);
45
+ if (abortController.signal.aborted) {
46
+ updateJob({ status: 'cancelled' });
47
+ return;
48
+ }
49
+ // Step 3: Render
50
+ updateJob({ status: 'rendering', renderedFrames: 0, totalFrames: composition.durationInFrames, progress: 0 });
51
+ await renderMedia({
52
+ composition,
53
+ serveUrl: bundlePath,
54
+ codec: nextJob.codec,
55
+ outputLocation: nextJob.outputPath,
56
+ inputProps: nextJob.inputProps,
57
+ onProgress: ({ progress, renderedFrames, totalFrames }) => {
58
+ if (progress < 0.9) {
59
+ updateJob({ status: 'rendering', renderedFrames, totalFrames, progress });
60
+ }
61
+ else if (progress < 1) {
62
+ updateJob({ status: 'encoding' });
63
+ }
64
+ },
65
+ cancelSignal: abortController.signal,
66
+ });
67
+ if (abortController.signal.aborted) {
68
+ updateJob({ status: 'cancelled' });
69
+ }
70
+ else {
71
+ updateJob({ status: 'done', progress: 1 });
72
+ }
73
+ await closeBrowser();
74
+ }
75
+ catch (err) {
76
+ const message = err instanceof Error ? err.message : String(err);
77
+ updateJob({ status: 'error', error: message });
78
+ try {
79
+ const { closeBrowser } = await import('@rendiv/renderer');
80
+ await closeBrowser();
81
+ }
82
+ catch {
83
+ // ignore cleanup errors
84
+ }
85
+ }
86
+ finally {
87
+ activeJobId = null;
88
+ activeAbortController = null;
89
+ processQueue(entryPoint);
90
+ }
91
+ })();
92
+ }
93
+ function jsonResponse(res, data, status = 200) {
94
+ res.writeHead(status, { 'Content-Type': 'application/json' });
95
+ res.end(JSON.stringify(data));
96
+ }
97
+ export function rendivStudioPlugin(options) {
98
+ const { studioHtmlFileName, entryPoint } = options;
99
+ return {
100
+ name: 'rendiv-studio',
101
+ configureServer(server) {
102
+ // Render queue API endpoints
103
+ server.middlewares.use((req, res, next) => {
104
+ // GET /queue — return all jobs
105
+ if (req.method === 'GET' && req.url === '/__rendiv_api__/render/queue') {
106
+ jsonResponse(res, { jobs: renderJobs });
107
+ return;
108
+ }
109
+ // POST /queue/clear — clear finished jobs (must be before :id/cancel match)
110
+ if (req.method === 'POST' && req.url === '/__rendiv_api__/render/queue/clear') {
111
+ renderJobs = renderJobs.filter((j) => j.status !== 'done' && j.status !== 'error' && j.status !== 'cancelled');
112
+ jsonResponse(res, { ok: true });
113
+ return;
114
+ }
115
+ // POST /queue — add a new job
116
+ if (req.method === 'POST' && req.url === '/__rendiv_api__/render/queue') {
117
+ readBody(req).then((raw) => {
118
+ const body = JSON.parse(raw);
119
+ const job = {
120
+ id: String(nextJobId++),
121
+ compositionId: body.compositionId,
122
+ compositionName: body.compositionName ?? body.compositionId,
123
+ codec: body.codec ?? 'mp4',
124
+ outputPath: body.outputPath,
125
+ inputProps: body.inputProps ?? {},
126
+ status: 'queued',
127
+ progress: 0,
128
+ renderedFrames: 0,
129
+ totalFrames: body.totalFrames ?? 0,
130
+ };
131
+ renderJobs.push(job);
132
+ processQueue(entryPoint);
133
+ jsonResponse(res, { job });
134
+ });
135
+ return;
136
+ }
137
+ // POST /queue/:id/cancel — cancel a specific job
138
+ const cancelMatch = req.url?.match(/^\/__rendiv_api__\/render\/queue\/([^/]+)\/cancel$/);
139
+ if (req.method === 'POST' && cancelMatch) {
140
+ const jobId = cancelMatch[1];
141
+ const job = renderJobs.find((j) => j.id === jobId);
142
+ if (job) {
143
+ if (job.status === 'queued') {
144
+ job.status = 'cancelled';
145
+ }
146
+ else if (activeJobId === jobId && activeAbortController) {
147
+ activeAbortController.abort();
148
+ }
149
+ }
150
+ jsonResponse(res, { ok: true });
151
+ return;
152
+ }
153
+ // DELETE /queue/:id — remove a finished job
154
+ const deleteMatch = req.url?.match(/^\/__rendiv_api__\/render\/queue\/([^/]+)$/);
155
+ if (req.method === 'DELETE' && deleteMatch) {
156
+ const jobId = deleteMatch[1];
157
+ renderJobs = renderJobs.filter((j) => j.id !== jobId);
158
+ jsonResponse(res, { ok: true });
159
+ return;
160
+ }
161
+ next();
162
+ });
163
+ // Rewrite root requests to serve the studio HTML instead of the user's index.html
164
+ server.middlewares.use((req, _res, next) => {
165
+ if (req.url === '/' || req.url === '/index.html') {
166
+ req.url = `/${studioHtmlFileName}`;
167
+ }
168
+ next();
169
+ });
170
+ },
171
+ };
172
+ }
173
+ //# sourceMappingURL=vite-plugin-studio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin-studio.js","sourceRoot":"","sources":["../src/vite-plugin-studio.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@rendiv/studio",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "ui"
17
+ ],
18
+ "dependencies": {
19
+ "@vitejs/plugin-react": "^4.3.0",
20
+ "vite": "^6.0.0",
21
+ "@rendiv/renderer": "0.1.0",
22
+ "@rendiv/bundler": "0.1.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^22.0.0",
26
+ "typescript": "^5.7.0",
27
+ "@rendiv/tsconfig": "0.0.0"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc",
31
+ "dev": "tsc --watch",
32
+ "typecheck": "tsc --noEmit",
33
+ "clean": "rm -rf dist"
34
+ }
35
+ }