retiam 1.0.0 → 1.0.1

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/bin/snapshot.js CHANGED
@@ -1,231 +1,231 @@
1
- #!/usr/bin/env node
2
-
3
- // =========================================================================
4
- // File: bin/snapshot.js - Retiam Agent-Native Visual Keyframe Snapshotter
5
- // =========================================================================
6
-
7
- import fs from 'fs';
8
- import path from 'path';
9
- import puppeteer from 'puppeteer';
10
- import { createServer } from 'vite';
11
-
12
- const projectRoot = process.cwd();
13
- const args = process.argv.slice(2);
14
-
15
- let targetFile = null;
16
- let times = [1.0, 2.5]; // default snapshot times in seconds
17
- let width = 1280;
18
- let height = 720;
19
- let outDir = path.resolve(projectRoot, 'outputs/snapshot');
20
- let jsonOutput = false;
21
-
22
- // Check for --help before parsing options
23
- const isHelp = args.includes('--help') || args.some((arg, idx) => arg === '-h' && (idx + 1 >= args.length || isNaN(parseInt(args[idx + 1], 10))));
24
- if (isHelp) {
25
- console.log(`
26
- 📸 Retiam WebGPU Engine - Keyframe Snapshotter
27
-
28
- Usage:
29
- npx retiam snapshot <path/to/Scene.ts> [options]
30
-
31
- Arguments:
32
- <file> Target scene TypeScript file (e.g. src/scenes/AStarScene.ts)
33
-
34
- Options:
35
- --times <sec,sec,...> Comma-separated list of timeline seconds to capture (default: 1.0, 2.5)
36
- -w, --width <px> Snapshot width in pixels (default: 1280)
37
- -h, --height <px> Snapshot height in pixels (default: 720)
38
- -o, --out <dir> Output directory for snapshot images (default: ./outputs/snapshot)
39
- --json Output machine-readable JSON for agents and automation
40
- --help Show this help message and exit
41
-
42
- Examples:
43
- npx retiam snapshot src/scenes/AStarScene.ts
44
- npx retiam snapshot src/scenes/AStarScene.ts --times 1.0,3.5,7.0 -w 1920 -h 1080
45
- npx retiam snapshot src/scenes/AStarScene.ts --times 5.0 --out ./outputs/snapshot --json
46
- `);
47
- process.exit(0);
48
- }
49
-
50
- for (let i = 0; i < args.length; i++) {
51
- if (args[i] === '--json') {
52
- jsonOutput = true;
53
- } else if (args[i] === '-w' || args[i] === '--width') {
54
- width = parseInt(args[++i], 10);
55
- } else if (args[i] === '-h' || args[i] === '--height') {
56
- height = parseInt(args[++i], 10);
57
- } else if (args[i] === '-o' || args[i] === '--out') {
58
- outDir = path.resolve(projectRoot, args[++i]);
59
- } else if (args[i] === '--times') {
60
- times = args[++i].split(',').map(s => parseFloat(s.trim())).filter(n => !isNaN(n)).sort((a, b) => a - b);
61
- } else if (!args[i].startsWith('-') && !targetFile) {
62
- targetFile = args[i];
63
- }
64
- }
65
-
66
- if (!targetFile) {
67
- if (jsonOutput) {
68
- console.log(JSON.stringify({ status: 'error', message: 'No target scene file specified.' }));
69
- } else {
70
- console.error('❌ Error: No target scene file specified.');
71
- console.log('Usage: npx retiam snapshot <path/to/Scene.ts> [--times 1.0,2.5,4.0] [--out ./outputs/snapshot] [--json]');
72
- console.log('Run "npx retiam snapshot --help" for more details.');
73
- }
74
- process.exit(1);
75
- }
76
-
77
- const resolvedScenePath = path.resolve(projectRoot, targetFile);
78
- if (!fs.existsSync(resolvedScenePath)) {
79
- if (jsonOutput) {
80
- console.log(JSON.stringify({ status: 'error', message: `Scene file not found: ${targetFile}` }));
81
- } else {
82
- console.error(`❌ Error: Scene file not found: ${resolvedScenePath}`);
83
- }
84
- process.exit(1);
85
- }
86
-
87
- if (!fs.existsSync(outDir)) {
88
- fs.mkdirSync(outDir, { recursive: true });
89
- }
90
-
91
- let viteServer = null;
92
- let browser = null;
93
-
94
- const cleanup = async () => {
95
- if (browser) try { await browser.close(); } catch (e) {}
96
- if (viteServer) try { await viteServer.close(); } catch (e) {}
97
- };
98
-
99
- process.on('SIGINT', async () => {
100
- await cleanup();
101
- process.exit(1);
102
- });
103
-
104
- (async () => {
105
- try {
106
- if (!jsonOutput) {
107
- console.log(`\n📸 Starting Retiam Keyframe Snapshotter`);
108
- console.log(` Scene: ${targetFile}`);
109
- console.log(` Resolution: ${width}x${height}`);
110
- console.log(` Timestamps: ${times.map(t => `${t}s`).join(', ')}`);
111
- console.log(` Output Dir: ${outDir}\n`);
112
- console.log(`🚀 Starting local Vite server...`);
113
- }
114
-
115
- const userViteConfig = path.resolve(projectRoot, 'vite.config.ts');
116
- viteServer = await createServer({
117
- configFile: fs.existsSync(userViteConfig) ? userViteConfig : undefined,
118
- root: projectRoot,
119
- server: { port: 5199, strictPort: false },
120
- logLevel: 'error'
121
- });
122
- await viteServer.listen();
123
-
124
- const address = viteServer.httpServer.address();
125
- const actualPort = (address && typeof address === 'object') ? address.port : 5199;
126
-
127
- if (!jsonOutput) console.log(`🌐 Launching headless browser with WebGPU...`);
128
-
129
- const launchArgs = [
130
- '--enable-unsafe-webgpu',
131
- '--disable-web-security',
132
- '--no-sandbox',
133
- '--enable-experimental-web-platform-features',
134
- '--autoplay-policy=no-user-gesture-required'
135
- ];
136
-
137
- try {
138
- browser = await puppeteer.launch({
139
- headless: "new",
140
- args: launchArgs,
141
- channel: 'chrome'
142
- });
143
- } catch (e) {
144
- // Fallback to default bundled Chromium
145
- browser = await puppeteer.launch({
146
- headless: "new",
147
- args: launchArgs
148
- });
149
- }
150
-
151
- const page = await browser.newPage();
152
- await page.setViewport({ width, height, deviceScaleFactor: 1.0 });
153
-
154
- page.on('console', msg => {
155
- if (msg.type() === 'error') {
156
- console.error(`[BROWSER ERROR] ${msg.text()}`);
157
- } else {
158
- console.log(`[BROWSER LOG] ${msg.text()}`);
159
- }
160
- });
161
- page.on('requestfailed', request => {
162
- console.error(`[REQUEST FAILED] ${request.url()} - ${request.failure()?.errorText}`);
163
- });
164
- page.on('response', response => {
165
- if (response.status() >= 400) {
166
- console.error(`[HTTP ${response.status()}] ${response.url()}`);
167
- }
168
- });
169
-
170
- const url = `http://localhost:${actualPort}?file=${targetFile}`;
171
- await page.goto(url, { waitUntil: 'domcontentloaded' });
172
-
173
- // Wait for canvas to be present
174
- await page.waitForSelector('canvas', { timeout: 15000 });
175
-
176
- const baseSceneName = path.basename(targetFile, path.extname(targetFile));
177
- const snapshots = [];
178
-
179
- let lastTimeSec = 0;
180
- for (const timeSec of times) {
181
- const deltaMs = Math.max(0, (timeSec - lastTimeSec) * 1000);
182
- if (deltaMs > 0) {
183
- await new Promise(resolve => setTimeout(resolve, deltaMs));
184
- }
185
- lastTimeSec = timeSec;
186
-
187
- const filename = `snapshot_${baseSceneName}_${timeSec.toFixed(1)}s.png`;
188
- const filePath = path.join(outDir, filename);
189
-
190
- await page.screenshot({ path: filePath, type: 'png' });
191
-
192
- snapshots.push({
193
- timeSeconds: timeSec,
194
- filename,
195
- path: filePath,
196
- width,
197
- height
198
- });
199
-
200
- if (!jsonOutput) {
201
- console.log(` ✅ Captured snapshot at ${timeSec.toFixed(1)}s -> ${filename}`);
202
- }
203
- }
204
-
205
- await cleanup();
206
-
207
- if (jsonOutput) {
208
- console.log(JSON.stringify({
209
- status: 'success',
210
- scene: targetFile,
211
- snapshots
212
- }, null, 2));
213
- } else {
214
- console.log(`\n🎉 All keyframe snapshots successfully generated in: ${outDir}\n`);
215
- }
216
-
217
- process.exit(0);
218
- } catch (err) {
219
- await cleanup();
220
- if (jsonOutput) {
221
- console.log(JSON.stringify({
222
- status: 'error',
223
- message: err.message,
224
- stack: err.stack
225
- }));
226
- } else {
227
- console.error('\n❌ Snapshotting failed:', err);
228
- }
229
- process.exit(1);
230
- }
231
- })();
1
+ #!/usr/bin/env node
2
+
3
+ // =========================================================================
4
+ // File: bin/snapshot.js - Retiam Agent-Native Visual Keyframe Snapshotter
5
+ // =========================================================================
6
+
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import puppeteer from 'puppeteer';
10
+ import { createServer } from 'vite';
11
+
12
+ const projectRoot = process.cwd();
13
+ const args = process.argv.slice(2);
14
+
15
+ let targetFile = null;
16
+ let times = [1.0, 2.5]; // default snapshot times in seconds
17
+ let width = 1280;
18
+ let height = 720;
19
+ let outDir = path.resolve(projectRoot, 'outputs/snapshot');
20
+ let jsonOutput = false;
21
+
22
+ // Check for --help before parsing options
23
+ const isHelp = args.includes('--help') || args.some((arg, idx) => arg === '-h' && (idx + 1 >= args.length || isNaN(parseInt(args[idx + 1], 10))));
24
+ if (isHelp) {
25
+ console.log(`
26
+ 📸 Retiam WebGPU Engine - Keyframe Snapshotter
27
+
28
+ Usage:
29
+ npx retiam snapshot <path/to/Scene.ts> [options]
30
+
31
+ Arguments:
32
+ <file> Target scene TypeScript file (e.g. src/scenes/AStarScene.ts)
33
+
34
+ Options:
35
+ --times <sec,sec,...> Comma-separated list of timeline seconds to capture (default: 1.0, 2.5)
36
+ -w, --width <px> Snapshot width in pixels (default: 1280)
37
+ -h, --height <px> Snapshot height in pixels (default: 720)
38
+ -o, --out <dir> Output directory for snapshot images (default: ./outputs/snapshot)
39
+ --json Output machine-readable JSON for agents and automation
40
+ --help Show this help message and exit
41
+
42
+ Examples:
43
+ npx retiam snapshot src/scenes/AStarScene.ts
44
+ npx retiam snapshot src/scenes/AStarScene.ts --times 1.0,3.5,7.0 -w 1920 -h 1080
45
+ npx retiam snapshot src/scenes/AStarScene.ts --times 5.0 --out ./outputs/snapshot --json
46
+ `);
47
+ process.exit(0);
48
+ }
49
+
50
+ for (let i = 0; i < args.length; i++) {
51
+ if (args[i] === '--json') {
52
+ jsonOutput = true;
53
+ } else if (args[i] === '-w' || args[i] === '--width') {
54
+ width = parseInt(args[++i], 10);
55
+ } else if (args[i] === '-h' || args[i] === '--height') {
56
+ height = parseInt(args[++i], 10);
57
+ } else if (args[i] === '-o' || args[i] === '--out') {
58
+ outDir = path.resolve(projectRoot, args[++i]);
59
+ } else if (args[i] === '--times') {
60
+ times = args[++i].split(',').map(s => parseFloat(s.trim())).filter(n => !isNaN(n)).sort((a, b) => a - b);
61
+ } else if (!args[i].startsWith('-') && !targetFile) {
62
+ targetFile = args[i];
63
+ }
64
+ }
65
+
66
+ if (!targetFile) {
67
+ if (jsonOutput) {
68
+ console.log(JSON.stringify({ status: 'error', message: 'No target scene file specified.' }));
69
+ } else {
70
+ console.error('❌ Error: No target scene file specified.');
71
+ console.log('Usage: npx retiam snapshot <path/to/Scene.ts> [--times 1.0,2.5,4.0] [--out ./outputs/snapshot] [--json]');
72
+ console.log('Run "npx retiam snapshot --help" for more details.');
73
+ }
74
+ process.exit(1);
75
+ }
76
+
77
+ const resolvedScenePath = path.resolve(projectRoot, targetFile);
78
+ if (!fs.existsSync(resolvedScenePath)) {
79
+ if (jsonOutput) {
80
+ console.log(JSON.stringify({ status: 'error', message: `Scene file not found: ${targetFile}` }));
81
+ } else {
82
+ console.error(`❌ Error: Scene file not found: ${resolvedScenePath}`);
83
+ }
84
+ process.exit(1);
85
+ }
86
+
87
+ if (!fs.existsSync(outDir)) {
88
+ fs.mkdirSync(outDir, { recursive: true });
89
+ }
90
+
91
+ let viteServer = null;
92
+ let browser = null;
93
+
94
+ const cleanup = async () => {
95
+ if (browser) try { await browser.close(); } catch (e) {}
96
+ if (viteServer) try { await viteServer.close(); } catch (e) {}
97
+ };
98
+
99
+ process.on('SIGINT', async () => {
100
+ await cleanup();
101
+ process.exit(1);
102
+ });
103
+
104
+ (async () => {
105
+ try {
106
+ if (!jsonOutput) {
107
+ console.log(`\n📸 Starting Retiam Keyframe Snapshotter`);
108
+ console.log(` Scene: ${targetFile}`);
109
+ console.log(` Resolution: ${width}x${height}`);
110
+ console.log(` Timestamps: ${times.map(t => `${t}s`).join(', ')}`);
111
+ console.log(` Output Dir: ${outDir}\n`);
112
+ console.log(`🚀 Starting local Vite server...`);
113
+ }
114
+
115
+ const userViteConfig = path.resolve(projectRoot, 'vite.config.ts');
116
+ viteServer = await createServer({
117
+ configFile: fs.existsSync(userViteConfig) ? userViteConfig : undefined,
118
+ root: projectRoot,
119
+ server: { port: 5199, strictPort: false },
120
+ logLevel: 'error'
121
+ });
122
+ await viteServer.listen();
123
+
124
+ const address = viteServer.httpServer.address();
125
+ const actualPort = (address && typeof address === 'object') ? address.port : 5199;
126
+
127
+ if (!jsonOutput) console.log(`🌐 Launching headless browser with WebGPU...`);
128
+
129
+ const launchArgs = [
130
+ '--enable-unsafe-webgpu',
131
+ '--disable-web-security',
132
+ '--no-sandbox',
133
+ '--enable-experimental-web-platform-features',
134
+ '--autoplay-policy=no-user-gesture-required'
135
+ ];
136
+
137
+ try {
138
+ browser = await puppeteer.launch({
139
+ headless: "new",
140
+ args: launchArgs,
141
+ channel: 'chrome'
142
+ });
143
+ } catch (e) {
144
+ // Fallback to default bundled Chromium
145
+ browser = await puppeteer.launch({
146
+ headless: "new",
147
+ args: launchArgs
148
+ });
149
+ }
150
+
151
+ const page = await browser.newPage();
152
+ await page.setViewport({ width, height, deviceScaleFactor: 1.0 });
153
+
154
+ page.on('console', msg => {
155
+ if (msg.type() === 'error') {
156
+ console.error(`[BROWSER ERROR] ${msg.text()}`);
157
+ } else {
158
+ console.log(`[BROWSER LOG] ${msg.text()}`);
159
+ }
160
+ });
161
+ page.on('requestfailed', request => {
162
+ console.error(`[REQUEST FAILED] ${request.url()} - ${request.failure()?.errorText}`);
163
+ });
164
+ page.on('response', response => {
165
+ if (response.status() >= 400) {
166
+ console.error(`[HTTP ${response.status()}] ${response.url()}`);
167
+ }
168
+ });
169
+
170
+ const url = `http://localhost:${actualPort}?file=${targetFile}`;
171
+ await page.goto(url, { waitUntil: 'domcontentloaded' });
172
+
173
+ // Wait for canvas to be present
174
+ await page.waitForSelector('canvas', { timeout: 15000 });
175
+
176
+ const baseSceneName = path.basename(targetFile, path.extname(targetFile));
177
+ const snapshots = [];
178
+
179
+ let lastTimeSec = 0;
180
+ for (const timeSec of times) {
181
+ const deltaMs = Math.max(0, (timeSec - lastTimeSec) * 1000);
182
+ if (deltaMs > 0) {
183
+ await new Promise(resolve => setTimeout(resolve, deltaMs));
184
+ }
185
+ lastTimeSec = timeSec;
186
+
187
+ const filename = `snapshot_${baseSceneName}_${timeSec.toFixed(1)}s.png`;
188
+ const filePath = path.join(outDir, filename);
189
+
190
+ await page.screenshot({ path: filePath, type: 'png' });
191
+
192
+ snapshots.push({
193
+ timeSeconds: timeSec,
194
+ filename,
195
+ path: filePath,
196
+ width,
197
+ height
198
+ });
199
+
200
+ if (!jsonOutput) {
201
+ console.log(` ✅ Captured snapshot at ${timeSec.toFixed(1)}s -> ${filename}`);
202
+ }
203
+ }
204
+
205
+ await cleanup();
206
+
207
+ if (jsonOutput) {
208
+ console.log(JSON.stringify({
209
+ status: 'success',
210
+ scene: targetFile,
211
+ snapshots
212
+ }, null, 2));
213
+ } else {
214
+ console.log(`\n🎉 All keyframe snapshots successfully generated in: ${outDir}\n`);
215
+ }
216
+
217
+ process.exit(0);
218
+ } catch (err) {
219
+ await cleanup();
220
+ if (jsonOutput) {
221
+ console.log(JSON.stringify({
222
+ status: 'error',
223
+ message: err.message,
224
+ stack: err.stack
225
+ }));
226
+ } else {
227
+ console.error('\n❌ Snapshotting failed:', err);
228
+ }
229
+ process.exit(1);
230
+ }
231
+ })();
@@ -1,4 +1,4 @@
1
- import { g as P0 } from "./index-CnM0BhUR.js";
1
+ import { g as P0 } from "./index-C7UzgTiw.js";
2
2
  function M0(H, ee) {
3
3
  for (var te = 0; te < ee.length; te++) {
4
4
  const P = ee[te];