@rendiv/studio 0.1.4 → 0.1.6
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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/scaffold-project.d.ts +10 -0
- package/dist/scaffold-project.d.ts.map +1 -0
- package/dist/scaffold-project.js +181 -0
- package/dist/scaffold-project.js.map +1 -0
- package/dist/start-studio-workspace.d.ts +16 -0
- package/dist/start-studio-workspace.d.ts.map +1 -0
- package/dist/start-studio-workspace.js +110 -0
- package/dist/start-studio-workspace.js.map +1 -0
- package/dist/start-studio.d.ts +5 -0
- package/dist/start-studio.d.ts.map +1 -1
- package/dist/start-studio.js +8 -5
- package/dist/start-studio.js.map +1 -1
- package/dist/studio-entry-code.d.ts +7 -2
- package/dist/studio-entry-code.d.ts.map +1 -1
- package/dist/studio-entry-code.js +19 -4
- package/dist/studio-entry-code.js.map +1 -1
- package/dist/vite-plugin-studio.d.ts +4 -0
- package/dist/vite-plugin-studio.d.ts.map +1 -1
- package/dist/vite-plugin-studio.js +37 -28
- package/dist/vite-plugin-studio.js.map +1 -1
- package/dist/workspace-entry-code.d.ts +12 -0
- package/dist/workspace-entry-code.d.ts.map +1 -0
- package/dist/workspace-entry-code.js +38 -0
- package/dist/workspace-entry-code.js.map +1 -0
- package/dist/workspace-picker-server.d.ts +27 -0
- package/dist/workspace-picker-server.d.ts.map +1 -0
- package/dist/workspace-picker-server.js +199 -0
- package/dist/workspace-picker-server.js.map +1 -0
- package/package.json +5 -3
- package/ui/StudioApp.tsx +10 -0
- package/ui/TopBar.tsx +32 -2
- package/ui/WorkspacePicker.tsx +423 -0
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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"}
|
|
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;AACvF,OAAO,EAAE,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAyC,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAyC,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAA+C,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scaffold a new Rendiv project in the given workspace directory.
|
|
3
|
+
* Returns a promise that resolves when the project is fully created and deps installed.
|
|
4
|
+
* Calls `onProgress` with status messages for the UI.
|
|
5
|
+
*/
|
|
6
|
+
export declare function scaffoldProject(workspaceDir: string, name: string, onProgress?: (message: string) => void): Promise<{
|
|
7
|
+
success: boolean;
|
|
8
|
+
error?: string;
|
|
9
|
+
}>;
|
|
10
|
+
//# sourceMappingURL=scaffold-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold-project.d.ts","sourceRoot":"","sources":["../src/scaffold-project.ts"],"names":[],"mappings":"AA6HA;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACrC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA8D/C"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
// --- Inline project template (same as create-rendiv) ---
|
|
5
|
+
const PACKAGE_JSON_TEMPLATE = `{
|
|
6
|
+
"name": "{{PROJECT_NAME}}",
|
|
7
|
+
"private": true,
|
|
8
|
+
"type": "module",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"preview": "vite dev",
|
|
11
|
+
"studio": "rendiv studio src/index.tsx",
|
|
12
|
+
"render": "rendiv render src/index.tsx MyVideo out/my-video.mp4",
|
|
13
|
+
"still": "rendiv still src/index.tsx MyVideo out/still.png",
|
|
14
|
+
"compositions": "rendiv compositions src/index.tsx"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@rendiv/core": "^0.1.0",
|
|
18
|
+
"@rendiv/player": "^0.1.0",
|
|
19
|
+
"@rendiv/cli": "^0.1.0",
|
|
20
|
+
"react": "^19.0.0",
|
|
21
|
+
"react-dom": "^19.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/react": "^19.0.0",
|
|
25
|
+
"@types/react-dom": "^19.0.0",
|
|
26
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
27
|
+
"vite": "^6.0.0",
|
|
28
|
+
"typescript": "^5.7.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
const TSCONFIG_JSON = `{
|
|
33
|
+
"compilerOptions": {
|
|
34
|
+
"target": "ES2022",
|
|
35
|
+
"module": "ESNext",
|
|
36
|
+
"moduleResolution": "bundler",
|
|
37
|
+
"jsx": "react-jsx",
|
|
38
|
+
"strict": true,
|
|
39
|
+
"noEmit": true,
|
|
40
|
+
"esModuleInterop": true,
|
|
41
|
+
"skipLibCheck": true
|
|
42
|
+
},
|
|
43
|
+
"include": ["src"]
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
const VITE_CONFIG = `import { defineConfig } from 'vite';
|
|
47
|
+
import react from '@vitejs/plugin-react';
|
|
48
|
+
|
|
49
|
+
export default defineConfig({
|
|
50
|
+
plugins: [react()],
|
|
51
|
+
});
|
|
52
|
+
`;
|
|
53
|
+
const GITIGNORE = `node_modules
|
|
54
|
+
dist
|
|
55
|
+
out
|
|
56
|
+
.studio
|
|
57
|
+
`;
|
|
58
|
+
const INDEX_TSX = `import React from 'react';
|
|
59
|
+
import { setRootComponent, Composition } from '@rendiv/core';
|
|
60
|
+
import { MyVideo } from './MyVideo';
|
|
61
|
+
|
|
62
|
+
const Root: React.FC = () => (
|
|
63
|
+
<Composition
|
|
64
|
+
id="MyVideo"
|
|
65
|
+
component={MyVideo}
|
|
66
|
+
durationInFrames={150}
|
|
67
|
+
fps={30}
|
|
68
|
+
width={1920}
|
|
69
|
+
height={1080}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
setRootComponent(Root);
|
|
74
|
+
`;
|
|
75
|
+
const MY_VIDEO_TSX = `import React from 'react';
|
|
76
|
+
import { useFrame, useCompositionConfig, Fill, interpolate, spring } from '@rendiv/core';
|
|
77
|
+
|
|
78
|
+
export const MyVideo: React.FC = () => {
|
|
79
|
+
const frame = useFrame();
|
|
80
|
+
const { fps, durationInFrames } = useCompositionConfig();
|
|
81
|
+
|
|
82
|
+
const opacity = interpolate(frame, [0, 30], [0, 1]);
|
|
83
|
+
const scale = spring({ frame, fps, config: { damping: 12 } });
|
|
84
|
+
const progress = frame / durationInFrames;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Fill
|
|
88
|
+
style={{
|
|
89
|
+
background: \`linear-gradient(135deg, #0f0f0f \${(1 - progress) * 100}%, #1a1a2e 100%)\`,
|
|
90
|
+
display: 'flex',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
justifyContent: 'center',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<h1
|
|
96
|
+
style={{
|
|
97
|
+
color: 'white',
|
|
98
|
+
fontSize: 80,
|
|
99
|
+
fontFamily: 'system-ui, sans-serif',
|
|
100
|
+
opacity,
|
|
101
|
+
transform: \`scale(\${scale})\`,
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
Hello, Rendiv!
|
|
105
|
+
</h1>
|
|
106
|
+
</Fill>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
`;
|
|
110
|
+
function detectPackageManager() {
|
|
111
|
+
const agent = process.env.npm_config_user_agent ?? '';
|
|
112
|
+
if (agent.startsWith('pnpm'))
|
|
113
|
+
return 'pnpm';
|
|
114
|
+
if (agent.startsWith('yarn'))
|
|
115
|
+
return 'yarn';
|
|
116
|
+
if (agent.startsWith('bun'))
|
|
117
|
+
return 'bun';
|
|
118
|
+
return 'npm';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Scaffold a new Rendiv project in the given workspace directory.
|
|
122
|
+
* Returns a promise that resolves when the project is fully created and deps installed.
|
|
123
|
+
* Calls `onProgress` with status messages for the UI.
|
|
124
|
+
*/
|
|
125
|
+
export async function scaffoldProject(workspaceDir, name, onProgress) {
|
|
126
|
+
const projectDir = path.join(workspaceDir, name);
|
|
127
|
+
// Validate name
|
|
128
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
129
|
+
return { success: false, error: 'Project name must only contain letters, numbers, hyphens, and underscores.' };
|
|
130
|
+
}
|
|
131
|
+
if (fs.existsSync(projectDir)) {
|
|
132
|
+
return { success: false, error: `Directory "${name}" already exists.` };
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
onProgress?.('Creating project files...');
|
|
136
|
+
// Create directories
|
|
137
|
+
fs.mkdirSync(path.join(projectDir, 'src'), { recursive: true });
|
|
138
|
+
// Write template files
|
|
139
|
+
const pkgJson = PACKAGE_JSON_TEMPLATE.replace(/\{\{PROJECT_NAME\}\}/g, name);
|
|
140
|
+
fs.writeFileSync(path.join(projectDir, 'package.json'), pkgJson);
|
|
141
|
+
fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), TSCONFIG_JSON);
|
|
142
|
+
fs.writeFileSync(path.join(projectDir, 'vite.config.ts'), VITE_CONFIG);
|
|
143
|
+
fs.writeFileSync(path.join(projectDir, '.gitignore'), GITIGNORE);
|
|
144
|
+
fs.writeFileSync(path.join(projectDir, 'src', 'index.tsx'), INDEX_TSX);
|
|
145
|
+
fs.writeFileSync(path.join(projectDir, 'src', 'MyVideo.tsx'), MY_VIDEO_TSX);
|
|
146
|
+
onProgress?.('Installing dependencies...');
|
|
147
|
+
// Install dependencies
|
|
148
|
+
const pm = detectPackageManager();
|
|
149
|
+
await new Promise((resolve, reject) => {
|
|
150
|
+
const child = spawn(pm, ['install'], {
|
|
151
|
+
cwd: projectDir,
|
|
152
|
+
stdio: 'pipe',
|
|
153
|
+
shell: true,
|
|
154
|
+
});
|
|
155
|
+
child.stdout?.on('data', (data) => {
|
|
156
|
+
const line = data.toString().trim();
|
|
157
|
+
if (line)
|
|
158
|
+
onProgress?.(line);
|
|
159
|
+
});
|
|
160
|
+
child.stderr?.on('data', (data) => {
|
|
161
|
+
const line = data.toString().trim();
|
|
162
|
+
if (line)
|
|
163
|
+
onProgress?.(line);
|
|
164
|
+
});
|
|
165
|
+
child.on('close', (code) => {
|
|
166
|
+
if (code === 0)
|
|
167
|
+
resolve();
|
|
168
|
+
else
|
|
169
|
+
reject(new Error(`${pm} install exited with code ${code}`));
|
|
170
|
+
});
|
|
171
|
+
child.on('error', reject);
|
|
172
|
+
});
|
|
173
|
+
onProgress?.('Project created successfully!');
|
|
174
|
+
return { success: true };
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
178
|
+
return { success: false, error: message };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=scaffold-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold-project.js","sourceRoot":"","sources":["../src/scaffold-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface WorkspaceOptions {
|
|
2
|
+
workspaceDir: string;
|
|
3
|
+
port?: number;
|
|
4
|
+
host?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface WorkspaceResult {
|
|
7
|
+
url: string;
|
|
8
|
+
close: () => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Start Studio in workspace mode.
|
|
12
|
+
* Manages the lifecycle of switching between the workspace picker and individual project studios.
|
|
13
|
+
* All servers run on the same port — only one is active at a time.
|
|
14
|
+
*/
|
|
15
|
+
export declare function startStudioWorkspace(options: WorkspaceOptions): Promise<WorkspaceResult>;
|
|
16
|
+
//# sourceMappingURL=start-studio-workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-studio-workspace.d.ts","sourceRoot":"","sources":["../src/start-studio-workspace.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AA4BD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA+E9F"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { startStudio } from './start-studio.js';
|
|
4
|
+
import { startWorkspacePicker } from './workspace-picker-server.js';
|
|
5
|
+
/**
|
|
6
|
+
* Find the entry point for a Rendiv project.
|
|
7
|
+
* Checks src/index.tsx first, then parses package.json scripts.
|
|
8
|
+
*/
|
|
9
|
+
function findEntryPoint(projectDir) {
|
|
10
|
+
// Check common default
|
|
11
|
+
if (fs.existsSync(path.join(projectDir, 'src', 'index.tsx'))) {
|
|
12
|
+
return path.join(projectDir, 'src', 'index.tsx');
|
|
13
|
+
}
|
|
14
|
+
// Check package.json scripts for "rendiv studio <entry>"
|
|
15
|
+
try {
|
|
16
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(projectDir, 'package.json'), 'utf-8'));
|
|
17
|
+
const studioScript = pkg.scripts?.studio;
|
|
18
|
+
if (studioScript) {
|
|
19
|
+
const match = studioScript.match(/rendiv\s+studio\s+(\S+)/);
|
|
20
|
+
if (match)
|
|
21
|
+
return path.join(projectDir, match[1]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// ignore
|
|
26
|
+
}
|
|
27
|
+
// Fallback
|
|
28
|
+
return path.join(projectDir, 'src', 'index.tsx');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Start Studio in workspace mode.
|
|
32
|
+
* Manages the lifecycle of switching between the workspace picker and individual project studios.
|
|
33
|
+
* All servers run on the same port — only one is active at a time.
|
|
34
|
+
*/
|
|
35
|
+
export async function startStudioWorkspace(options) {
|
|
36
|
+
const { workspaceDir, port = 3000, host } = options;
|
|
37
|
+
let currentClose = null;
|
|
38
|
+
let switching = false;
|
|
39
|
+
let firstLaunch = true;
|
|
40
|
+
async function switchTo(projectPath) {
|
|
41
|
+
if (switching)
|
|
42
|
+
return;
|
|
43
|
+
switching = true;
|
|
44
|
+
try {
|
|
45
|
+
// Close the current server
|
|
46
|
+
if (currentClose) {
|
|
47
|
+
await currentClose();
|
|
48
|
+
currentClose = null;
|
|
49
|
+
}
|
|
50
|
+
if (projectPath) {
|
|
51
|
+
// Start project Studio
|
|
52
|
+
const entryPoint = findEntryPoint(projectPath);
|
|
53
|
+
const originalCwd = process.cwd();
|
|
54
|
+
process.chdir(projectPath);
|
|
55
|
+
try {
|
|
56
|
+
const result = await startStudio({
|
|
57
|
+
entryPoint,
|
|
58
|
+
port,
|
|
59
|
+
host,
|
|
60
|
+
workspaceDir,
|
|
61
|
+
onSwitchProject: (p) => switchTo(p),
|
|
62
|
+
});
|
|
63
|
+
currentClose = result.close;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
// If project Studio fails, fall back to workspace picker
|
|
67
|
+
process.chdir(originalCwd);
|
|
68
|
+
const result = await startWorkspacePicker({
|
|
69
|
+
workspaceDir,
|
|
70
|
+
port,
|
|
71
|
+
host,
|
|
72
|
+
onSwitchProject: (p) => switchTo(p),
|
|
73
|
+
openBrowser: false,
|
|
74
|
+
});
|
|
75
|
+
currentClose = result.close;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Start workspace picker
|
|
80
|
+
// Ensure CWD is the workspace dir
|
|
81
|
+
process.chdir(workspaceDir);
|
|
82
|
+
const result = await startWorkspacePicker({
|
|
83
|
+
workspaceDir,
|
|
84
|
+
port,
|
|
85
|
+
host,
|
|
86
|
+
onSwitchProject: (p) => switchTo(p),
|
|
87
|
+
openBrowser: firstLaunch,
|
|
88
|
+
});
|
|
89
|
+
currentClose = result.close;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
switching = false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Start with workspace picker
|
|
97
|
+
await switchTo(null);
|
|
98
|
+
firstLaunch = false;
|
|
99
|
+
const url = `http://localhost:${port}`;
|
|
100
|
+
return {
|
|
101
|
+
url,
|
|
102
|
+
close: async () => {
|
|
103
|
+
if (currentClose) {
|
|
104
|
+
await currentClose();
|
|
105
|
+
currentClose = null;
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=start-studio-workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-studio-workspace.js","sourceRoot":"","sources":["../src/start-studio-workspace.ts"],"names":[],"mappings":"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"}
|
package/dist/start-studio.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export interface StudioOptions {
|
|
2
2
|
entryPoint: string;
|
|
3
3
|
port?: number;
|
|
4
|
+
host?: string;
|
|
4
5
|
publicDir?: string;
|
|
6
|
+
/** When set, Studio is workspace-aware and shows a "Back to projects" button. */
|
|
7
|
+
workspaceDir?: string;
|
|
8
|
+
/** Callback to switch projects. Called with project path or null (back to picker). */
|
|
9
|
+
onSwitchProject?: (projectPath: string | null) => void;
|
|
5
10
|
}
|
|
6
11
|
export interface StudioResult {
|
|
7
12
|
url: string;
|
|
@@ -1 +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;
|
|
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,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACxD;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,CA2E/E"}
|
package/dist/start-studio.js
CHANGED
|
@@ -3,14 +3,14 @@ import react from '@vitejs/plugin-react';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { generateStudioEntryCode, generateStudioHtml, FAVICON_SVG } from './studio-entry-code.js';
|
|
6
|
+
import { generateStudioEntryCode, generateStudioHtml, generateStudioGlobals, FAVICON_SVG } from './studio-entry-code.js';
|
|
7
7
|
import { rendivStudioPlugin } from './vite-plugin-studio.js';
|
|
8
8
|
const STUDIO_DIR = '.studio';
|
|
9
9
|
const ENTRY_FILE = 'entry.tsx';
|
|
10
10
|
const HTML_FILE = 'studio.html';
|
|
11
11
|
const FAVICON_FILE = 'favicon.svg';
|
|
12
12
|
export async function startStudio(options) {
|
|
13
|
-
const { entryPoint, port = 3000, publicDir = 'public' } = options;
|
|
13
|
+
const { entryPoint, port = 3000, host, publicDir = 'public', workspaceDir, onSwitchProject } = options;
|
|
14
14
|
const cwd = process.cwd();
|
|
15
15
|
const absoluteEntry = path.isAbsolute(entryPoint)
|
|
16
16
|
? entryPoint
|
|
@@ -25,7 +25,8 @@ export async function startStudio(options) {
|
|
|
25
25
|
const studioHtmlFile = `${STUDIO_DIR}/${HTML_FILE}`;
|
|
26
26
|
const studioFaviconFile = `${STUDIO_DIR}/${FAVICON_FILE}`;
|
|
27
27
|
const entryCode = generateStudioEntryCode(absoluteEntry, studioUiDir, entryPoint);
|
|
28
|
-
const
|
|
28
|
+
const globalsScript = generateStudioGlobals(entryPoint, workspaceDir);
|
|
29
|
+
const htmlCode = generateStudioHtml(studioEntryFile, studioFaviconFile, globalsScript);
|
|
29
30
|
fs.writeFileSync(path.join(studioDir, ENTRY_FILE), entryCode);
|
|
30
31
|
fs.writeFileSync(path.join(studioDir, HTML_FILE), htmlCode);
|
|
31
32
|
fs.writeFileSync(path.join(studioDir, FAVICON_FILE), FAVICON_SVG);
|
|
@@ -38,7 +39,7 @@ export async function startStudio(options) {
|
|
|
38
39
|
publicDir: path.resolve(cwd, publicDir),
|
|
39
40
|
plugins: [
|
|
40
41
|
react(),
|
|
41
|
-
rendivStudioPlugin({ studioHtmlFileName: studioHtmlFile, entryPoint: absoluteEntry }),
|
|
42
|
+
rendivStudioPlugin({ studioHtmlFileName: studioHtmlFile, entryPoint: absoluteEntry, workspaceDir, onSwitchProject }),
|
|
42
43
|
],
|
|
43
44
|
resolve: {
|
|
44
45
|
// Force Vite to resolve these packages from the user's project root,
|
|
@@ -47,7 +48,9 @@ export async function startStudio(options) {
|
|
|
47
48
|
},
|
|
48
49
|
server: {
|
|
49
50
|
port,
|
|
50
|
-
|
|
51
|
+
host: host || undefined,
|
|
52
|
+
// Don't auto-open browser on workspace restarts — the browser is already open
|
|
53
|
+
open: !onSwitchProject,
|
|
51
54
|
},
|
|
52
55
|
optimizeDeps: {
|
|
53
56
|
entries: [studioEntryFile],
|
package/dist/start-studio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-studio.js","sourceRoot":"","sources":["../src/start-studio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,MAAM,sBAAsB,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"start-studio.js","sourceRoot":"","sources":["../src/start-studio.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
* This code imports the user's entry (which calls setRootComponent),
|
|
4
4
|
* then mounts the Studio React UI shell.
|
|
5
5
|
*/
|
|
6
|
-
export declare function generateStudioEntryCode(userEntryPoint: string, studioUiDir: string, relativeEntryPoint: string): string;
|
|
6
|
+
export declare function generateStudioEntryCode(userEntryPoint: string, studioUiDir: string, relativeEntryPoint: string, workspaceDir?: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Generates a small inline script that sets global config before module scripts load.
|
|
9
|
+
* This runs synchronously before ES module imports, ensuring globals are available.
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateStudioGlobals(relativeEntryPoint: string, workspaceDir?: string): string;
|
|
7
12
|
/** Favicon SVG content (icon-only version of the Rendiv logo). */
|
|
8
13
|
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
14
|
/**
|
|
10
15
|
* Generates the HTML template for the Studio shell.
|
|
11
16
|
*/
|
|
12
|
-
export declare function generateStudioHtml(entryFileName: string, faviconPath: string): string;
|
|
17
|
+
export declare function generateStudioHtml(entryFileName: string, faviconPath: string, globalsScript?: string): string;
|
|
13
18
|
//# sourceMappingURL=studio-entry-code.d.ts.map
|
|
@@ -1 +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,
|
|
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,EAC1B,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAWR;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,kBAAkB,EAAE,MAAM,EAC1B,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAQR;AAED,kEAAkE;AAClE,eAAO,MAAM,WAAW,+jBAMjB,CAAC;AAER;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAsB7G"}
|
|
@@ -3,18 +3,30 @@
|
|
|
3
3
|
* This code imports the user's entry (which calls setRootComponent),
|
|
4
4
|
* then mounts the Studio React UI shell.
|
|
5
5
|
*/
|
|
6
|
-
export function generateStudioEntryCode(userEntryPoint, studioUiDir, relativeEntryPoint) {
|
|
6
|
+
export function generateStudioEntryCode(userEntryPoint, studioUiDir, relativeEntryPoint, workspaceDir) {
|
|
7
7
|
// Normalize backslashes to forward slashes for import paths
|
|
8
8
|
const normalizedEntry = userEntryPoint.replace(/\\/g, '/');
|
|
9
9
|
const normalizedUiDir = studioUiDir.replace(/\\/g, '/');
|
|
10
10
|
return `
|
|
11
|
-
window.__RENDIV_STUDIO_ENTRY__ = ${JSON.stringify(relativeEntryPoint)};
|
|
12
11
|
import '${normalizedEntry}';
|
|
13
12
|
import { createStudioApp } from '${normalizedUiDir}/StudioApp.tsx';
|
|
14
13
|
|
|
15
14
|
createStudioApp(document.getElementById('root'));
|
|
16
15
|
`;
|
|
17
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Generates a small inline script that sets global config before module scripts load.
|
|
19
|
+
* This runs synchronously before ES module imports, ensuring globals are available.
|
|
20
|
+
*/
|
|
21
|
+
export function generateStudioGlobals(relativeEntryPoint, workspaceDir) {
|
|
22
|
+
const lines = [
|
|
23
|
+
`window.__RENDIV_STUDIO_ENTRY__ = ${JSON.stringify(relativeEntryPoint)};`,
|
|
24
|
+
];
|
|
25
|
+
if (workspaceDir) {
|
|
26
|
+
lines.push(`window.__RENDIV_WORKSPACE_DIR__ = ${JSON.stringify(workspaceDir)};`);
|
|
27
|
+
}
|
|
28
|
+
return lines.join('\n');
|
|
29
|
+
}
|
|
18
30
|
/** Favicon SVG content (icon-only version of the Rendiv logo). */
|
|
19
31
|
export const FAVICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
|
|
20
32
|
<rect x="6" y="8" width="26" height="20" rx="3" stroke="#58a6ff" stroke-width="2" opacity="0.35"/>
|
|
@@ -26,7 +38,10 @@ export const FAVICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
|
|
|
26
38
|
/**
|
|
27
39
|
* Generates the HTML template for the Studio shell.
|
|
28
40
|
*/
|
|
29
|
-
export function generateStudioHtml(entryFileName, faviconPath) {
|
|
41
|
+
export function generateStudioHtml(entryFileName, faviconPath, globalsScript) {
|
|
42
|
+
const globalsTag = globalsScript
|
|
43
|
+
? `\n <script>${globalsScript}</script>`
|
|
44
|
+
: '';
|
|
30
45
|
return `<!DOCTYPE html>
|
|
31
46
|
<html lang="en">
|
|
32
47
|
<head>
|
|
@@ -40,7 +55,7 @@ export function generateStudioHtml(entryFileName, faviconPath) {
|
|
|
40
55
|
</style>
|
|
41
56
|
</head>
|
|
42
57
|
<body>
|
|
43
|
-
<div id="root"></div
|
|
58
|
+
<div id="root"></div>${globalsTag}
|
|
44
59
|
<script type="module" src="/${entryFileName}"></script>
|
|
45
60
|
</body>
|
|
46
61
|
</html>`;
|
|
@@ -1 +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;
|
|
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,EAC1B,YAAqB;IAErB,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;UACC,eAAe;mCACU,eAAe;;;CAGjD,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,kBAA0B,EAC1B,YAAqB;IAErB,MAAM,KAAK,GAAG;QACZ,oCAAoC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,GAAG;KAC1E,CAAC;IACF,IAAI,YAAY,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,qCAAqC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;OAMpB,CAAC;AAER;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,aAAqB,EAAE,WAAmB,EAAE,aAAsB;IACnG,MAAM,UAAU,GAAG,aAAa;QAC9B,CAAC,CAAC,eAAe,aAAa,WAAW;QACzC,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;iDAKwC,WAAW;;;;;;;;yBAQnC,UAAU;gCACH,aAAa;;QAErC,CAAC;AACT,CAAC"}
|
|
@@ -2,6 +2,10 @@ import type { Plugin } from 'vite';
|
|
|
2
2
|
export interface StudioPluginOptions {
|
|
3
3
|
studioHtmlFileName: string;
|
|
4
4
|
entryPoint: string;
|
|
5
|
+
/** When set, Studio is in workspace mode and shows workspace controls. */
|
|
6
|
+
workspaceDir?: string;
|
|
7
|
+
/** Callback to switch projects. Pass null to go back to workspace picker. */
|
|
8
|
+
onSwitchProject?: (projectPath: string | null) => void;
|
|
5
9
|
}
|
|
6
10
|
export declare function rendivStudioPlugin(options: StudioPluginOptions): Plugin;
|
|
7
11
|
//# sourceMappingURL=vite-plugin-studio.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAKnC,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACxD;AAgKD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAqQvE"}
|