@scenerok/cli 1.0.7 → 1.0.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6EpC,eAAO,MAAM,aAAa,SAAwB,CAAC;AAEnD,eAAO,MAAM,aAAa,SA0FtB,CAAC"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/commands/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoFpC,eAAO,MAAM,aAAa,SAAwB,CAAC;AAEnD,eAAO,MAAM,aAAa,SAqItB,CAAC"}
@@ -2,9 +2,10 @@ import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
3
  import ora from 'ora';
4
4
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
5
- import { join, resolve } from 'node:path';
6
- import { submitRender, getRenderStatus, downloadRender } from '../lib/api.js';
5
+ import { basename, join, resolve } from 'node:path';
6
+ import { submitRender, getRenderStatus, downloadRender, uploadCliAssets } from '../lib/api.js';
7
7
  import { isAuthenticated } from '../lib/config.js';
8
+ import { prepareProject, getMimeType, rewritePreparedVidscriptWithAssetUrls, writeAssetManifest, } from '../lib/project.js';
8
9
  function formatDuration(ms) {
9
10
  const totalSeconds = Math.max(0, Math.round(ms / 1000));
10
11
  const minutes = Math.floor(totalSeconds / 60);
@@ -81,11 +82,54 @@ export const renderCommand = new Command('render')
81
82
  process.exit(1);
82
83
  }
83
84
  let vidscript;
85
+ let preparedProject = null;
84
86
  try {
85
- vidscript = readFileSync(file, 'utf-8');
87
+ preparedProject = prepareProject(file);
88
+ vidscript = preparedProject.rewrittenVidscript;
86
89
  }
87
90
  catch {
88
- console.log(chalk.red(`❌ Could not read file: ${file}`));
91
+ try {
92
+ vidscript = readFileSync(file, 'utf-8');
93
+ }
94
+ catch {
95
+ console.log(chalk.red(`❌ Could not read file: ${file}`));
96
+ process.exit(1);
97
+ }
98
+ }
99
+ if (preparedProject && preparedProject.assets.length > 0) {
100
+ const assetSpinner = ora(`Uploading ${preparedProject.assets.length} local asset${preparedProject.assets.length === 1 ? '' : 's'}...`).start();
101
+ try {
102
+ const formData = new FormData();
103
+ for (const asset of preparedProject.assets) {
104
+ const bytes = readFileSync(asset.absolutePath);
105
+ const blob = new Blob([new Uint8Array(bytes)], { type: getMimeType(asset.absolutePath) });
106
+ formData.append('asset', blob, basename(asset.absolutePath));
107
+ formData.append('assetPath', asset.localPath);
108
+ }
109
+ const uploaded = await uploadCliAssets(formData);
110
+ const mappings = uploaded.assets.map((asset, index) => ({
111
+ localPath: preparedProject.assets[index].localPath,
112
+ id: asset.id,
113
+ url: asset.url,
114
+ mimeType: asset.mimeType,
115
+ fileSize: asset.fileSize,
116
+ }));
117
+ vidscript = rewritePreparedVidscriptWithAssetUrls(vidscript, mappings);
118
+ const manifestPath = writeAssetManifest(preparedProject, mappings);
119
+ assetSpinner.succeed(`Uploaded ${uploaded.assets.length} asset${uploaded.assets.length === 1 ? '' : 's'}`);
120
+ console.log(chalk.dim(` Manifest: ${manifestPath}`));
121
+ }
122
+ catch (error) {
123
+ assetSpinner.fail('Asset upload failed');
124
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
125
+ process.exit(1);
126
+ }
127
+ }
128
+ else if (preparedProject) {
129
+ vidscript = preparedProject.originalVidscript;
130
+ }
131
+ if (vidscript.includes('__SCENEROK_ASSET_')) {
132
+ console.log(chalk.red('❌ Some local assets could not be uploaded or mapped.'));
89
133
  process.exit(1);
90
134
  }
91
135
  const spinner = ora('Submitting render job...').start();
package/dist/lib/api.d.ts CHANGED
@@ -90,6 +90,17 @@ export declare function uploadProject(formData: FormData): Promise<{
90
90
  }>;
91
91
  render?: Awaited<ReturnType<typeof submitRender>> | null;
92
92
  }>;
93
+ export declare function uploadCliAssets(formData: FormData): Promise<{
94
+ assets: Array<{
95
+ id: number;
96
+ filename: string;
97
+ url: string;
98
+ mimeType: string | null;
99
+ fileType: string;
100
+ fileSize: number;
101
+ externalId: string | null;
102
+ }>;
103
+ }>;
93
104
  export declare function listProjects(): Promise<{
94
105
  projects: Array<{
95
106
  id: number;
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAUA,cAAM,QAAS,SAAQ,KAAK;IAGjB,MAAM,EAAE,MAAM;IACd,YAAY,CAAC,EAAE,OAAO;gBAF7B,OAAO,EAAE,MAAM,EACR,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,OAAO,YAAA;CAKhC;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,KAAK,GAAG,WAAW,GAAG,MAAM,GAAG,eAAe,CAAC;QAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ;AAoGD,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM;WAE9C,OAAO;iBACD,MAAM;aACV,MAAM;eACJ,MAAM;eACN,MAAM,EAAE;wBACC,KAAK,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,SAAS,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;qBACe,MAAM;mBACR,kBAAkB;aACxB,MAAM,EAAE;YACT,MAAM;GAEjB;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;cAEhF,MAAM;YACR,MAAM;gBACF,MAAM;oBACF,MAAM;eACX,MAAM;iBACJ,MAAM;aACV,MAAM;kBACD,MAAM;gBACR,MAAM,GAAG,IAAI;GAE5B;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM;QAE9C,MAAM;YACF,MAAM;cACJ,MAAM;eACL,MAAM,GAAG,IAAI;oBACR,MAAM;eACX,MAAM;iBACJ,MAAM;mBACJ,OAAO;WACf,MAAM,GAAG,IAAI;eACT,MAAM;iBACJ,MAAM,GAAG,IAAI;uBACP,MAAM,GAAG,IAAI;GAEnC;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmBpG;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ;aAEzC;QACP,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB;YACO,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;aACO,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,GAAG,IAAI;GAE3D;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,QAAQ;YAE5C,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;GAEL;AAED,wBAAsB,YAAY;cAEpB,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;GAEL;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO;aAMxE,KAAK,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;GAEL;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE;aAE5C,KAAK,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;GAEL;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM;iBAE1C,MAAM;eACR,MAAM;sBACC,MAAM;gBACZ,MAAM;cACR,MAAM;GAEnB;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM;YAE3C,MAAM;mBACC,MAAM;iBACR,MAAM;iBACN,MAAM;YACX,MAAM;GAEjB;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
package/dist/lib/api.js CHANGED
@@ -112,6 +112,9 @@ export async function downloadRender(renderId) {
112
112
  export async function uploadProject(formData) {
113
113
  return apiFormCall('/api/cli/projects', formData);
114
114
  }
115
+ export async function uploadCliAssets(formData) {
116
+ return apiFormCall('/api/cli/assets', formData);
117
+ }
115
118
  export async function listProjects() {
116
119
  return apiCall('GET', '/api/cli/projects');
117
120
  }
@@ -6,9 +6,24 @@ export interface PreparedProject {
6
6
  assets: Array<{
7
7
  localPath: string;
8
8
  absolutePath: string;
9
+ size: number;
10
+ sha256: string;
9
11
  }>;
10
12
  }
13
+ export declare function getMimeType(filePath: string): string;
11
14
  export declare function listAssetFiles(assetDir: string): string[];
12
15
  export declare function prepareProject(entryFile: string, assetDirs?: string[]): PreparedProject;
13
16
  export declare function appendProjectToForm(formData: FormData, project: PreparedProject): Promise<void>;
17
+ export declare function buildAssetToken(localPath: string): string;
18
+ export declare function rewritePreparedVidscriptWithAssetUrls(vidscript: string, mappings: Array<{
19
+ localPath: string;
20
+ url: string;
21
+ }>): string;
22
+ export declare function writeAssetManifest(project: PreparedProject, mappings: Array<{
23
+ localPath: string;
24
+ url: string;
25
+ id?: number;
26
+ mimeType?: string | null;
27
+ fileSize?: number;
28
+ }>): string;
14
29
  //# sourceMappingURL=project.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/lib/project.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,KAAK,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AAuBD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBzD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,eAAe,CAgD3F;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrG"}
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/lib/project.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,KAAK,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAcD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAepD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAoBzD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,eAAe,CAiE3F;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrG;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,qCAAqC,CACnD,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5G,MAAM,CAwBR"}
@@ -1,11 +1,21 @@
1
- import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
3
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
3
4
  const INPUT_RE = /^(\s*input\s+[A-Za-z_][A-Za-z0-9_]*\s*=\s*)(["'])([^"']+)(\2)/gm;
5
+ const ASSET_IMPORT_RE = /^(\s*)import\s+([A-Za-z_][A-Za-z0-9_]*)\s+from\s+(["'])([^"']+)\3\s*;?\s*$/gm;
4
6
  const HTTP_RE = /^https?:\/\//i;
7
+ const MEDIA_EXT_RE = /\.(mp4|mov|m4v|webm|mp3|wav|m4a|aac|ogg|png|jpe?g|webp|gif|avif|svg)(?:[?#].*)?$/i;
5
8
  function isRenderableLocalPath(value) {
6
- return Boolean(value) && !HTTP_RE.test(value) && !value.startsWith('/uploads/') && !value.startsWith('data:');
9
+ return Boolean(value)
10
+ && !HTTP_RE.test(value)
11
+ && !value.startsWith('scenerok://')
12
+ && !value.startsWith('/uploads/')
13
+ && !value.startsWith('data:');
7
14
  }
8
- function getMimeType(filePath) {
15
+ function isAssetImportPath(value) {
16
+ return isRenderableLocalPath(value) && MEDIA_EXT_RE.test(value);
17
+ }
18
+ export function getMimeType(filePath) {
9
19
  const ext = filePath.toLowerCase().split('.').pop();
10
20
  switch (ext) {
11
21
  case 'mp4': return 'video/mp4';
@@ -60,6 +70,18 @@ export function prepareProject(entryFile, assetDirs = []) {
60
70
  assetsByPath.set(localPath, absolutePath);
61
71
  return `${prefix}${quote}{{asset:${localPath}}}${suffix}`;
62
72
  });
73
+ rewrittenVidscript = rewrittenVidscript.replace(ASSET_IMPORT_RE, (match, indent, localName, _quote, rawPath) => {
74
+ if (!isAssetImportPath(rawPath)) {
75
+ return match;
76
+ }
77
+ const absolutePath = isAbsolute(rawPath) ? rawPath : resolve(rootDir, rawPath);
78
+ if (!existsSync(absolutePath)) {
79
+ return match;
80
+ }
81
+ const localPath = relative(rootDir, absolutePath).replace(/\\/g, '/');
82
+ assetsByPath.set(localPath, absolutePath);
83
+ return `${indent}input ${localName} = "{{asset:${localPath}}}"`;
84
+ });
63
85
  for (const dir of assetDirs) {
64
86
  const absoluteDir = resolve(dir);
65
87
  for (const absolutePath of listAssetFiles(absoluteDir)) {
@@ -79,6 +101,8 @@ export function prepareProject(entryFile, assetDirs = []) {
79
101
  assets: Array.from(assetsByPath.entries()).map(([localPath, absolutePath]) => ({
80
102
  localPath,
81
103
  absolutePath,
104
+ size: statSync(absolutePath).size,
105
+ sha256: createHash('sha256').update(readFileSync(absolutePath)).digest('hex'),
82
106
  })),
83
107
  };
84
108
  }
@@ -95,3 +119,38 @@ export async function appendProjectToForm(formData, project) {
95
119
  }
96
120
  formData.set('vidscript', serverVidscript);
97
121
  }
122
+ export function buildAssetToken(localPath) {
123
+ return `__SCENEROK_ASSET_${Buffer.from(localPath).toString('base64url')}__`;
124
+ }
125
+ export function rewritePreparedVidscriptWithAssetUrls(vidscript, mappings) {
126
+ let next = vidscript;
127
+ for (const mapping of mappings) {
128
+ next = next.replaceAll(buildAssetToken(mapping.localPath), mapping.url);
129
+ }
130
+ return next;
131
+ }
132
+ export function writeAssetManifest(project, mappings) {
133
+ const manifestDir = join(project.rootDir, '.scenerok');
134
+ mkdirSync(manifestDir, { recursive: true });
135
+ const manifestPath = join(manifestDir, 'assets.manifest.json');
136
+ const byLocalPath = new Map(project.assets.map((asset) => [asset.localPath, asset]));
137
+ const manifest = {
138
+ version: 1,
139
+ entryFile: project.entryFile,
140
+ generatedAt: new Date().toISOString(),
141
+ assets: mappings.map((mapping) => {
142
+ const localAsset = byLocalPath.get(mapping.localPath);
143
+ return {
144
+ localPath: mapping.localPath,
145
+ absolutePath: localAsset?.absolutePath,
146
+ size: localAsset?.size ?? mapping.fileSize,
147
+ sha256: localAsset?.sha256,
148
+ assetId: mapping.id,
149
+ mimeType: mapping.mimeType,
150
+ url: mapping.url,
151
+ };
152
+ }),
153
+ };
154
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
155
+ return manifestPath;
156
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scenerok/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "SceneRok CLI - Create videos from your terminal and agent workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,8 +1,17 @@
1
- # SceneRok Skill for Claude Code
1
+ ---
2
+ name: scenerok
3
+ description: >-
4
+ Compose VidScript v2 scripts and render videos with the SceneRok CLI
5
+ (scenerok validate, render, status). Use when the user asks to create
6
+ promos, reels, social videos, product launches, or mentions VidScript,
7
+ SceneRok, scenerok CLI, or terminal/agent video generation.
8
+ ---
9
+
10
+ # SceneRok Skill for Aider
2
11
 
3
12
  ## Overview
4
13
 
5
- You are a VidScript composer and video generation expert integrated with Claude Code. You help users create video content using the SceneRok platform directly from their terminal.
14
+ You are a VidScript composer and video generation expert integrated with Aider. You help users create video content using the SceneRok platform directly from their terminal.
6
15
 
7
16
  ## Capabilities
8
17
 
@@ -171,6 +180,15 @@ Always ask clarifying questions about:
171
180
  | `vidscript-sample.md` | Minimal promo with xAI import |
172
181
  | `examples/system/*.vid` | Official SceneRok templates (text-only, product launch, xAI reels) |
173
182
 
183
+ ## SceneRok codebase development
184
+
185
+ This skill covers **VidScript composition and rendering videos**. For engineering on the SceneRok platform (parser, render subsystem, API, billing, GPU workers), load the **`scenerok-development`** skill from `.agents/skills/scenerok-development/` in the SceneRok repository.
186
+
187
+ | Doc | Purpose |
188
+ |-----|---------|
189
+ | `plan-v1/35-render-subsystem-architecture.md` | Render registries, IR flow, extension points |
190
+ | `AGENTS.md` | Project context, env vars, dev commands |
191
+
174
192
  ## Full Reference
175
193
 
176
194
  https://scenerok.com/docs/vidscript
@@ -152,7 +152,7 @@ hero.Speed(factor: 1.5)
152
152
  | `x` | number \| string | Horizontal position. Number = px from left. `"50%"` = percent of width. Overrides `position`. |
153
153
  | `y` | number \| string | Vertical position. Number = px from top. `"50%"` = percent of height. Overrides `position`. |
154
154
  | `color` | string | Hex color |
155
- | `size` | number | Font size in pixels |
155
+ | `size` | number \| string | Font size in output canvas pixels. `size: 72` is shorthand for `size: "72px"`. |
156
156
  | `font` | string | Font family. System fonts or Google Fonts: `"Inter"`, `"Bebas Neue"`, `"Space Grotesk"`, `"Outfit"`, etc. |
157
157
  | `align` | string | `left`, `center`, `right`. Default: `center` |
158
158
  | `line_height` | number | Line height multiplier for multi-line text. Default: 1.2 |
@@ -254,68 +254,73 @@ let bed = eleven.music("Warm premium launch bed", duration: 15, instrumental: tr
254
254
  [0s .. 15s] = audio eleven.music("..."), volume: 0.5 # trailing params after direct plugin call
255
255
  ```
256
256
 
257
- ## Animations, Effects & Plugins (v2 Extensibility)
257
+ ## Animations, Effects & Rendering (v2)
258
258
 
259
- VidScript v2 uses a **minimal-grammar, plugin-first** architecture for animations and effects.
259
+ VidScript v2 uses a **minimal-grammar, plugin-first** architecture. The compiler lowers VidScript into `IRTimeline` — the single contract shared by browser preview and final render.
260
260
 
261
- Instead of adding dozens of animation keywords to the language, we use two powerful parameters:
261
+ User-facing extension uses two parameters on any text or video surface:
262
262
 
263
- - `animate:`
264
- - `effects:`
265
-
266
- These accept either plugin function calls or plain object descriptors.
263
+ - `animate:` — motion over time (plugin calls or object descriptors)
264
+ - `effects:` — post-processing filters with optional animated params
267
265
 
268
266
  ### animate: parameter
269
267
 
270
- Attach animations to **any** text or video surface.
271
-
272
268
  ```vidscript
273
269
  import motion from "@scenerok/basic-animations"
274
270
 
275
- text "Hello", animate: motion.fadeIn(0.8s)
271
+ [0s .. 3s] = text "Hello", x: "50%", y: "50%", animate: motion.fadeIn(0.8s)
276
272
 
277
- video hero, animate: [motion.fadeIn(0.5s), motion.slideY(-40, 0, 1.2s)]
273
+ [-] = video hero, animate: [motion.fadeIn(0.5s), motion.slideY(-40, 0, 1.2s)]
278
274
 
279
- text "Title", animate: {
275
+ [0s .. 2s] = text "Title", animate: {
280
276
  type: "fade",
281
277
  from: { opacity: 0 },
282
278
  to: { opacity: 1 },
283
279
  start: 0,
284
- end: 1.5
280
+ end: 1.5,
281
+ easing: "easeOutQuad"
285
282
  }
286
283
  ```
287
284
 
288
- ### effects: parameter
285
+ Compiler lowers `animate:` into `IRMotionTrack[]` (property-path keyframes). Legacy `IRAnimation` descriptors are adapted at runtime for backward compatibility.
289
286
 
290
- Attach post-processing effects, with support for animated parameters.
287
+ ### effects: parameter
291
288
 
292
289
  ```vidscript
293
- text "Dramatic", effects: [grayscale(intensity: 0.8)]
290
+ [0s .. 5s] = filter "vignette", intensity: 0.4
294
291
 
295
- video hero, effects: [{
296
- name: "glitch",
297
- strength: animate: { type: "fade", from: { strength: 0 }, to: { strength: 1 } }
298
- }]
292
+ [0s .. 5s] = filter "glitch", intensity: 0.5, animate: motion.fadeIn(1s)
299
293
  ```
300
294
 
301
- ### Currently Available Animation Functions (`basic-animations` plugin)
302
-
303
- | Function | Description |
304
- |---------------------------|------------------------------|
305
- | `motion.fadeIn(duration?)` | Opacity 0 → 1 |
306
- | `motion.fadeOut(duration?)` | Opacity 1 → 0 |
307
- | `motion.slideX(from, to, dur?)` | Horizontal slide |
308
- | `motion.slideY(from, to, dur?)` | Vertical slide |
309
- | `motion.popIn(duration?)` | Scale + fade entrance |
310
- | `motion.riseIn(duration?, dist?)` | Upward fade entrance |
311
- | `motion.swingIn(duration?)` | Rotating slide/fade |
312
- | `motion.glitchIn(duration?)` | Jitter + flash entrance |
313
- | `motion.float(duration?, amp?)` | Gentle vertical bob |
314
- | `motion.typewriter(duration?)` | Character reveal |
315
-
316
- More plugins (advanced text animations, pixel effects, 3D, etc.) are planned.
295
+ Built-in filters: `monochrome`, `sepia`, `blur`, `chromatic`, `glitch`, `vignette`, `contrast`, `saturation`, `brightness`.
317
296
 
318
- The full architecture and IR details live in `plan-v1/29-surface-animation-effect-plugin-architecture.md`.
297
+ ### Animation functions (`@scenerok/basic-animations`)
298
+
299
+ | Function | Description |
300
+ |----------|-------------|
301
+ | `motion.fadeIn(duration?)` | Opacity 0 → 1 |
302
+ | `motion.fadeOut(duration?)` | Opacity 1 → 0 |
303
+ | `motion.slideX(from, to, dur?)` | Horizontal slide |
304
+ | `motion.slideY(from, to, dur?)` | Vertical slide |
305
+ | `motion.popIn(duration?)` | Scale + fade entrance |
306
+ | `motion.riseIn(duration?, dist?)` | Upward fade entrance |
307
+ | `motion.swingIn(duration?)` | Rotating slide/fade |
308
+ | `motion.glitchIn(duration?)` | Jitter + flash entrance |
309
+ | `motion.float(duration?, amp?)` | Gentle vertical bob |
310
+ | `motion.typewriter(duration?)` | Character reveal |
311
+
312
+ ### Render architecture (contributors)
313
+
314
+ Implemented registry-based rendering. See `plan-v1/35-render-subsystem-architecture.md`.
315
+
316
+ | Registry | Path | Add via |
317
+ |----------|------|---------|
318
+ | Motion | `src/lib/motion/registry.ts` | `registerEasing`, `registerMotionBehavior` |
319
+ | Surface | `src/render/surfaces/registry.ts` | `registerSurfaceRenderer` |
320
+ | Effect | `src/render/effects/registry.ts` | `registerEffect` or `src/shaders/library.ts` |
321
+ | Engine | `src/render/engine/index.ts` | `createRenderEngine` backends |
322
+
323
+ For SceneRok platform engineering, load the **`scenerok-development`** skill (`.agents/skills/scenerok-development/`).
319
324
 
320
325
  ## Expressions
321
326
 
@@ -1,3 +1,12 @@
1
+ ---
2
+ name: scenerok
3
+ description: >-
4
+ Compose VidScript v2 scripts and render videos with the SceneRok CLI
5
+ (scenerok validate, render, status). Use when the user asks to create
6
+ promos, reels, social videos, product launches, or mentions VidScript,
7
+ SceneRok, scenerok CLI, or terminal/agent video generation.
8
+ ---
9
+
1
10
  # SceneRok Skill for Claude Code
2
11
 
3
12
  ## Overview
@@ -171,6 +180,15 @@ Always ask clarifying questions about:
171
180
  | `vidscript-sample.md` | Minimal promo with xAI import |
172
181
  | `examples/system/*.vid` | Official SceneRok templates (text-only, product launch, xAI reels) |
173
182
 
183
+ ## SceneRok codebase development
184
+
185
+ This skill covers **VidScript composition and rendering videos**. For engineering on the SceneRok platform (parser, render subsystem, API, billing, GPU workers), load the **`scenerok-development`** skill from `.agents/skills/scenerok-development/` in the SceneRok repository.
186
+
187
+ | Doc | Purpose |
188
+ |-----|---------|
189
+ | `plan-v1/35-render-subsystem-architecture.md` | Render registries, IR flow, extension points |
190
+ | `AGENTS.md` | Project context, env vars, dev commands |
191
+
174
192
  ## Full Reference
175
193
 
176
194
  https://scenerok.com/docs/vidscript
@@ -152,7 +152,7 @@ hero.Speed(factor: 1.5)
152
152
  | `x` | number \| string | Horizontal position. Number = px from left. `"50%"` = percent of width. Overrides `position`. |
153
153
  | `y` | number \| string | Vertical position. Number = px from top. `"50%"` = percent of height. Overrides `position`. |
154
154
  | `color` | string | Hex color |
155
- | `size` | number | Font size in pixels |
155
+ | `size` | number \| string | Font size in output canvas pixels. `size: 72` is shorthand for `size: "72px"`. |
156
156
  | `font` | string | Font family. System fonts or Google Fonts: `"Inter"`, `"Bebas Neue"`, `"Space Grotesk"`, `"Outfit"`, etc. |
157
157
  | `align` | string | `left`, `center`, `right`. Default: `center` |
158
158
  | `line_height` | number | Line height multiplier for multi-line text. Default: 1.2 |
@@ -254,68 +254,73 @@ let bed = eleven.music("Warm premium launch bed", duration: 15, instrumental: tr
254
254
  [0s .. 15s] = audio eleven.music("..."), volume: 0.5 # trailing params after direct plugin call
255
255
  ```
256
256
 
257
- ## Animations, Effects & Plugins (v2 Extensibility)
257
+ ## Animations, Effects & Rendering (v2)
258
258
 
259
- VidScript v2 uses a **minimal-grammar, plugin-first** architecture for animations and effects.
259
+ VidScript v2 uses a **minimal-grammar, plugin-first** architecture. The compiler lowers VidScript into `IRTimeline` — the single contract shared by browser preview and final render.
260
260
 
261
- Instead of adding dozens of animation keywords to the language, we use two powerful parameters:
261
+ User-facing extension uses two parameters on any text or video surface:
262
262
 
263
- - `animate:`
264
- - `effects:`
265
-
266
- These accept either plugin function calls or plain object descriptors.
263
+ - `animate:` — motion over time (plugin calls or object descriptors)
264
+ - `effects:` — post-processing filters with optional animated params
267
265
 
268
266
  ### animate: parameter
269
267
 
270
- Attach animations to **any** text or video surface.
271
-
272
268
  ```vidscript
273
269
  import motion from "@scenerok/basic-animations"
274
270
 
275
- text "Hello", animate: motion.fadeIn(0.8s)
271
+ [0s .. 3s] = text "Hello", x: "50%", y: "50%", animate: motion.fadeIn(0.8s)
276
272
 
277
- video hero, animate: [motion.fadeIn(0.5s), motion.slideY(-40, 0, 1.2s)]
273
+ [-] = video hero, animate: [motion.fadeIn(0.5s), motion.slideY(-40, 0, 1.2s)]
278
274
 
279
- text "Title", animate: {
275
+ [0s .. 2s] = text "Title", animate: {
280
276
  type: "fade",
281
277
  from: { opacity: 0 },
282
278
  to: { opacity: 1 },
283
279
  start: 0,
284
- end: 1.5
280
+ end: 1.5,
281
+ easing: "easeOutQuad"
285
282
  }
286
283
  ```
287
284
 
288
- ### effects: parameter
285
+ Compiler lowers `animate:` into `IRMotionTrack[]` (property-path keyframes). Legacy `IRAnimation` descriptors are adapted at runtime for backward compatibility.
289
286
 
290
- Attach post-processing effects, with support for animated parameters.
287
+ ### effects: parameter
291
288
 
292
289
  ```vidscript
293
- text "Dramatic", effects: [grayscale(intensity: 0.8)]
290
+ [0s .. 5s] = filter "vignette", intensity: 0.4
294
291
 
295
- video hero, effects: [{
296
- name: "glitch",
297
- strength: animate: { type: "fade", from: { strength: 0 }, to: { strength: 1 } }
298
- }]
292
+ [0s .. 5s] = filter "glitch", intensity: 0.5, animate: motion.fadeIn(1s)
299
293
  ```
300
294
 
301
- ### Currently Available Animation Functions (`basic-animations` plugin)
302
-
303
- | Function | Description |
304
- |---------------------------|------------------------------|
305
- | `motion.fadeIn(duration?)` | Opacity 0 → 1 |
306
- | `motion.fadeOut(duration?)` | Opacity 1 → 0 |
307
- | `motion.slideX(from, to, dur?)` | Horizontal slide |
308
- | `motion.slideY(from, to, dur?)` | Vertical slide |
309
- | `motion.popIn(duration?)` | Scale + fade entrance |
310
- | `motion.riseIn(duration?, dist?)` | Upward fade entrance |
311
- | `motion.swingIn(duration?)` | Rotating slide/fade |
312
- | `motion.glitchIn(duration?)` | Jitter + flash entrance |
313
- | `motion.float(duration?, amp?)` | Gentle vertical bob |
314
- | `motion.typewriter(duration?)` | Character reveal |
315
-
316
- More plugins (advanced text animations, pixel effects, 3D, etc.) are planned.
295
+ Built-in filters: `monochrome`, `sepia`, `blur`, `chromatic`, `glitch`, `vignette`, `contrast`, `saturation`, `brightness`.
317
296
 
318
- The full architecture and IR details live in `plan-v1/29-surface-animation-effect-plugin-architecture.md`.
297
+ ### Animation functions (`@scenerok/basic-animations`)
298
+
299
+ | Function | Description |
300
+ |----------|-------------|
301
+ | `motion.fadeIn(duration?)` | Opacity 0 → 1 |
302
+ | `motion.fadeOut(duration?)` | Opacity 1 → 0 |
303
+ | `motion.slideX(from, to, dur?)` | Horizontal slide |
304
+ | `motion.slideY(from, to, dur?)` | Vertical slide |
305
+ | `motion.popIn(duration?)` | Scale + fade entrance |
306
+ | `motion.riseIn(duration?, dist?)` | Upward fade entrance |
307
+ | `motion.swingIn(duration?)` | Rotating slide/fade |
308
+ | `motion.glitchIn(duration?)` | Jitter + flash entrance |
309
+ | `motion.float(duration?, amp?)` | Gentle vertical bob |
310
+ | `motion.typewriter(duration?)` | Character reveal |
311
+
312
+ ### Render architecture (contributors)
313
+
314
+ Implemented registry-based rendering. See `plan-v1/35-render-subsystem-architecture.md`.
315
+
316
+ | Registry | Path | Add via |
317
+ |----------|------|---------|
318
+ | Motion | `src/lib/motion/registry.ts` | `registerEasing`, `registerMotionBehavior` |
319
+ | Surface | `src/render/surfaces/registry.ts` | `registerSurfaceRenderer` |
320
+ | Effect | `src/render/effects/registry.ts` | `registerEffect` or `src/shaders/library.ts` |
321
+ | Engine | `src/render/engine/index.ts` | `createRenderEngine` backends |
322
+
323
+ For SceneRok platform engineering, load the **`scenerok-development`** skill (`.agents/skills/scenerok-development/`).
319
324
 
320
325
  ## Expressions
321
326
 
@@ -1,8 +1,17 @@
1
- # SceneRok Skill for Claude Code
1
+ ---
2
+ name: scenerok
3
+ description: >-
4
+ Compose VidScript v2 scripts and render videos with the SceneRok CLI
5
+ (scenerok validate, render, status). Use when the user asks to create
6
+ promos, reels, social videos, product launches, or mentions VidScript,
7
+ SceneRok, scenerok CLI, or terminal/agent video generation.
8
+ ---
9
+
10
+ # SceneRok Skill for Codex
2
11
 
3
12
  ## Overview
4
13
 
5
- You are a VidScript composer and video generation expert integrated with Claude Code. You help users create video content using the SceneRok platform directly from their terminal.
14
+ You are a VidScript composer and video generation expert integrated with Codex. You help users create video content using the SceneRok platform directly from their terminal.
6
15
 
7
16
  ## Capabilities
8
17
 
@@ -171,6 +180,15 @@ Always ask clarifying questions about:
171
180
  | `vidscript-sample.md` | Minimal promo with xAI import |
172
181
  | `examples/system/*.vid` | Official SceneRok templates (text-only, product launch, xAI reels) |
173
182
 
183
+ ## SceneRok codebase development
184
+
185
+ This skill covers **VidScript composition and rendering videos**. For engineering on the SceneRok platform (parser, render subsystem, API, billing, GPU workers), load the **`scenerok-development`** skill from `.agents/skills/scenerok-development/` in the SceneRok repository.
186
+
187
+ | Doc | Purpose |
188
+ |-----|---------|
189
+ | `plan-v1/35-render-subsystem-architecture.md` | Render registries, IR flow, extension points |
190
+ | `AGENTS.md` | Project context, env vars, dev commands |
191
+
174
192
  ## Full Reference
175
193
 
176
194
  https://scenerok.com/docs/vidscript