@scenerok/cli 1.0.8 → 1.0.10
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/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +9 -34
- package/package.json +3 -2
- package/skills/{aider → shared}/SKILL.md +36 -10
- package/skills/{claude → shared}/vidscript-guide.md +51 -3
- package/skills/{claude → shared}/vidscript-sample.md +1 -1
- package/skills/shared/vidscript-strict.md +176 -0
- package/skills/aider/vidscript-guide.md +0 -383
- package/skills/aider/vidscript-sample.md +0 -30
- package/skills/aider/vidscript-strict.md +0 -113
- package/skills/claude/SKILL.md +0 -194
- package/skills/claude/vidscript-strict.md +0 -113
- package/skills/codex/SKILL.md +0 -194
- package/skills/codex/vidscript-guide.md +0 -383
- package/skills/codex/vidscript-sample.md +0 -30
- package/skills/codex/vidscript-strict.md +0 -113
- package/skills/cursor/SKILL.md +0 -194
- package/skills/cursor/vidscript-guide.md +0 -383
- package/skills/cursor/vidscript-sample.md +0 -30
- package/skills/cursor/vidscript-strict.md +0 -113
- package/skills/opencode/SKILL.md +0 -194
- package/skills/opencode/vidscript-guide.md +0 -383
- package/skills/opencode/vidscript-sample.md +0 -30
- package/skills/opencode/vidscript-strict.md +0 -113
- package/skills/skills/aider/SKILL.md +0 -194
- package/skills/skills/aider/vidscript-guide.md +0 -383
- package/skills/skills/aider/vidscript-sample.md +0 -30
- package/skills/skills/aider/vidscript-strict.md +0 -113
- package/skills/skills/claude/SKILL.md +0 -194
- package/skills/skills/claude/vidscript-guide.md +0 -383
- package/skills/skills/claude/vidscript-sample.md +0 -30
- package/skills/skills/claude/vidscript-strict.md +0 -113
- package/skills/skills/codex/SKILL.md +0 -194
- package/skills/skills/codex/vidscript-guide.md +0 -383
- package/skills/skills/codex/vidscript-sample.md +0 -30
- package/skills/skills/codex/vidscript-strict.md +0 -113
- package/skills/skills/cursor/SKILL.md +0 -194
- package/skills/skills/cursor/vidscript-guide.md +0 -383
- package/skills/skills/cursor/vidscript-sample.md +0 -30
- package/skills/skills/cursor/vidscript-strict.md +0 -113
- package/skills/skills/opencode/SKILL.md +0 -194
- package/skills/skills/opencode/vidscript-guide.md +0 -383
- package/skills/skills/opencode/vidscript-sample.md +0 -30
- package/skills/skills/opencode/vidscript-strict.md +0 -113
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwGpC,eAAO,MAAM,aAAa,SA4DvB,CAAC"}
|
package/dist/commands/skills.js
CHANGED
|
@@ -4,64 +4,39 @@ import { existsSync, copyFileSync, mkdirSync, readdirSync } from 'node:fs';
|
|
|
4
4
|
import { join, dirname } from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
6
|
function getPlatformConfig(platform) {
|
|
7
|
-
const cwd = process.cwd();
|
|
8
7
|
const configs = {
|
|
9
8
|
opencode: {
|
|
10
9
|
name: 'OpenCode',
|
|
11
10
|
skillDir: join(homedir(), '.agents/skills/scenerok'),
|
|
12
|
-
files: [
|
|
13
|
-
{ source: 'skills/opencode/SKILL.md', dest: 'SKILL.md' },
|
|
14
|
-
{ source: 'skills/opencode/vidscript-guide.md', dest: 'vidscript-guide.md' },
|
|
15
|
-
{ source: 'skills/opencode/vidscript-sample.md', dest: 'vidscript-sample.md' },
|
|
16
|
-
{ source: 'skills/opencode/vidscript-strict.md', dest: 'vidscript-strict.md' },
|
|
17
|
-
],
|
|
18
11
|
},
|
|
19
12
|
claude: {
|
|
20
13
|
name: 'Claude Code',
|
|
21
14
|
skillDir: join(homedir(), '.claude/skills/scenerok'),
|
|
22
|
-
files: [
|
|
23
|
-
{ source: 'skills/claude/SKILL.md', dest: 'SKILL.md' },
|
|
24
|
-
{ source: 'skills/claude/vidscript-guide.md', dest: 'vidscript-guide.md' },
|
|
25
|
-
{ source: 'skills/claude/vidscript-sample.md', dest: 'vidscript-sample.md' },
|
|
26
|
-
{ source: 'skills/claude/vidscript-strict.md', dest: 'vidscript-strict.md' },
|
|
27
|
-
],
|
|
28
15
|
},
|
|
29
16
|
codex: {
|
|
30
17
|
name: 'Codex',
|
|
31
18
|
skillDir: join(homedir(), '.codex/skills/scenerok'),
|
|
32
|
-
files: [
|
|
33
|
-
{ source: 'skills/codex/SKILL.md', dest: 'SKILL.md' },
|
|
34
|
-
{ source: 'skills/codex/vidscript-guide.md', dest: 'vidscript-guide.md' },
|
|
35
|
-
{ source: 'skills/codex/vidscript-sample.md', dest: 'vidscript-sample.md' },
|
|
36
|
-
{ source: 'skills/codex/vidscript-strict.md', dest: 'vidscript-strict.md' },
|
|
37
|
-
],
|
|
38
19
|
},
|
|
39
20
|
cursor: {
|
|
40
21
|
name: 'Cursor',
|
|
41
22
|
skillDir: join(homedir(), '.cursor/skills/scenerok'),
|
|
42
|
-
files: [
|
|
43
|
-
{ source: 'skills/cursor/SKILL.md', dest: 'SKILL.md' },
|
|
44
|
-
{ source: 'skills/cursor/vidscript-guide.md', dest: 'vidscript-guide.md' },
|
|
45
|
-
{ source: 'skills/cursor/vidscript-sample.md', dest: 'vidscript-sample.md' },
|
|
46
|
-
{ source: 'skills/cursor/vidscript-strict.md', dest: 'vidscript-strict.md' },
|
|
47
|
-
],
|
|
48
23
|
},
|
|
49
24
|
aider: {
|
|
50
25
|
name: 'Aider',
|
|
51
26
|
skillDir: join(homedir(), '.aider/skills/scenerok'),
|
|
52
|
-
files: [
|
|
53
|
-
{ source: 'skills/aider/SKILL.md', dest: 'SKILL.md' },
|
|
54
|
-
{ source: 'skills/aider/vidscript-guide.md', dest: 'vidscript-guide.md' },
|
|
55
|
-
{ source: 'skills/aider/vidscript-sample.md', dest: 'vidscript-sample.md' },
|
|
56
|
-
{ source: 'skills/aider/vidscript-strict.md', dest: 'vidscript-strict.md' },
|
|
57
|
-
],
|
|
58
27
|
},
|
|
59
28
|
};
|
|
60
29
|
return configs[platform] || null;
|
|
61
30
|
}
|
|
31
|
+
const sharedSkillFiles = [
|
|
32
|
+
'SKILL.md',
|
|
33
|
+
'vidscript-guide.md',
|
|
34
|
+
'vidscript-sample.md',
|
|
35
|
+
'vidscript-strict.md',
|
|
36
|
+
].map((name) => ({ source: `skills/shared/${name}`, dest: name }));
|
|
62
37
|
async function findSkillSource(sourcePath) {
|
|
63
|
-
// Check relative to
|
|
64
|
-
const modulePath = join(dirname(new URL(import.meta.url).pathname), '
|
|
38
|
+
// Check relative to the installed @scenerok/cli package.
|
|
39
|
+
const modulePath = join(dirname(new URL(import.meta.url).pathname), '../..', sourcePath);
|
|
65
40
|
if (existsSync(modulePath))
|
|
66
41
|
return modulePath;
|
|
67
42
|
// Check relative to CWD
|
|
@@ -127,7 +102,7 @@ export const skillsCommand = new Command('skills')
|
|
|
127
102
|
if (!existsSync(config.skillDir)) {
|
|
128
103
|
mkdirSync(config.skillDir, { recursive: true });
|
|
129
104
|
}
|
|
130
|
-
for (const file of
|
|
105
|
+
for (const file of sharedSkillFiles) {
|
|
131
106
|
const source = await findSkillSource(file.source);
|
|
132
107
|
const dest = join(config.skillDir, file.dest);
|
|
133
108
|
if (!source) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scenerok/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "SceneRok CLI - Create videos from your terminal and agent workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
18
18
|
"dev": "tsc --watch",
|
|
19
|
-
"
|
|
19
|
+
"sync:skills": "node ../../scripts/sync-scenerok-skills.mjs",
|
|
20
|
+
"prepublishOnly": "npm run sync:skills && npm run build"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|
|
22
23
|
"scenerok",
|
|
@@ -7,11 +7,11 @@ description: >-
|
|
|
7
7
|
SceneRok, scenerok CLI, or terminal/agent video generation.
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# SceneRok Skill
|
|
10
|
+
# SceneRok Agent Skill
|
|
11
11
|
|
|
12
12
|
## Overview
|
|
13
13
|
|
|
14
|
-
You are a VidScript composer and video generation expert integrated with
|
|
14
|
+
You are a VidScript composer and video generation expert integrated with your agent. You help users create video content using the SceneRok platform directly from their terminal.
|
|
15
15
|
|
|
16
16
|
## Capabilities
|
|
17
17
|
|
|
@@ -21,6 +21,7 @@ You are a VidScript composer and video generation expert integrated with Aider.
|
|
|
21
21
|
- Check render status and retrieve output
|
|
22
22
|
- Guide users through video creation workflows
|
|
23
23
|
- Fill template placeholders and customize system templates
|
|
24
|
+
- When the user gives a product or website URL, use available browser or screenshot tools to capture selective real site visuals for VidScript assets when they improve the video
|
|
24
25
|
|
|
25
26
|
## VidScript Language
|
|
26
27
|
|
|
@@ -28,7 +29,7 @@ VidScript is a declarative language for describing video compositions using time
|
|
|
28
29
|
|
|
29
30
|
### Core Concepts
|
|
30
31
|
|
|
31
|
-
**Inputs** - Declare video sources:
|
|
32
|
+
**Inputs** - Declare video/image sources:
|
|
32
33
|
```vidscript
|
|
33
34
|
input hero = "https://cdn.example.com/hero.mp4"
|
|
34
35
|
input logo = "/uploads/logo.png"
|
|
@@ -91,7 +92,7 @@ import xai from "@scenerok/xai"
|
|
|
91
92
|
import eleven from "@elevenlabs/music"
|
|
92
93
|
import motion from "@scenerok/basic-animations"
|
|
93
94
|
|
|
94
|
-
[-] = video xai.imagine("Cinematic product shot", aspect_ratio: "9:16", duration: 5)
|
|
95
|
+
[-] = video xai.imagine("Cinematic product shot, premium lighting, no text, no words, no letters, no captions, no logos, no watermark, no readable UI copy", aspect_ratio: "9:16", duration: 5)
|
|
95
96
|
[-] = audio xai.tts("Welcome to SceneRok", voice: "eve")
|
|
96
97
|
|
|
97
98
|
# ElevenLabs music package functions require an import alias.
|
|
@@ -117,17 +118,42 @@ input hero = "{{hero_clip}}"
|
|
|
117
118
|
|
|
118
119
|
1. **Understand the goal** — What video does the user want? (promo, testimonial, meme, etc.)
|
|
119
120
|
2. **Plan the structure** — Time blocks, durations, inputs
|
|
120
|
-
3. **Gather assets** — Video URLs
|
|
121
|
-
4. **
|
|
122
|
-
5. **
|
|
123
|
-
6. **
|
|
124
|
-
7. **
|
|
121
|
+
3. **Gather assets** — Video URLs, local paths, generated clips, and selective website screenshots/images; when the user provides a URL, browser screenshots are optional source material, not a requirement to build the whole video from screenshots
|
|
122
|
+
4. **Probe asset type and dimensions** — Inspect every local or downloaded asset before placing it. Use `file` to identify image vs video, `ffprobe` for video/audio, `sips -g pixelWidth -g pixelHeight file` on macOS images, or `identify file` when ImageMagick is available.
|
|
123
|
+
5. **Prepare still images for render** — Plain VidScript input declarations can upload images, but production-safe timeline placement currently uses `video` clips. Do not write `[time] = video some_png_input` directly. Convert still images/screenshots/logos to short H.264 MP4 plates first, then use those MP4s as `video` inputs. Plugin-generated image surfaces are separate and only safe when a plugin explicitly returns a `surface` result.
|
|
124
|
+
6. **Compose VidScript** — Write the full script using measured dimensions, aspect-ratio-preserving scale, centered/safe-area placement, and entry/exit animation beats for each visual asset
|
|
125
|
+
7. **Validate** — Run `scenerok validate script.vid`
|
|
126
|
+
8. **Render** — Run `scenerok render script.vid --watch`
|
|
127
|
+
9. **Deliver** — Share the download URL when complete
|
|
128
|
+
|
|
129
|
+
## Website URL Asset Workflow
|
|
130
|
+
|
|
131
|
+
When the user provides a product, company, landing page, app store listing, or ecommerce URL, treat the site as a useful source of truth for claims, brand cues, and optional visual assets.
|
|
132
|
+
|
|
133
|
+
1. Visit the URL with an available browser tool before composing the final VidScript.
|
|
134
|
+
2. Capture website screenshots sparingly and intentionally. Prefer above-the-fold screenshots, product/app closeups, visible hero sections, pricing/offer cards, testimonials, and other viewable page states. Avoid full-page or very long screenshots as backgrounds because their text becomes illegible in video.
|
|
135
|
+
3. Crop or frame screenshots to the specific visual evidence needed. Do not use screenshots as the only visual style by default, and do not build a whole video as a sequence of unreadable full-page captures.
|
|
136
|
+
4. Detect and save usable product images, app screenshots, brand marks, and logos from the page when available. Prefer direct image assets when they are accessible and clearly match the product; use browser screenshots as supporting assets when they communicate something visible at video size.
|
|
137
|
+
5. Probe saved asset type and dimensions before composing. Record file type, width, height, aspect ratio, and duration if video; never guess dimensions from filenames or screenshots.
|
|
138
|
+
6. If a saved asset is a still image (`png`, `jpg`, `webp`, `gif`, `avif`, `svg`) and you want to place it on the timeline, convert it to a short H.264 MP4 plate with matching duration before using it as a `video` input. Keep the original still file too, but do not place it as `video`.
|
|
139
|
+
7. Use captured assets or converted plates as grounded proof points alongside other visual material. A good ad can combine product/logo/app screenshots, generated video clips, motion backgrounds, text primitives, and music.
|
|
140
|
+
8. Scale assets from their measured aspect ratio to fit the output frame and safe areas. For 1080x1920 ads, keep primary visuals inside roughly 80-88% of frame width and reserve enough top/bottom room for text.
|
|
141
|
+
9. Animate visual assets intentionally: use entry animations such as `motion.popIn`, `motion.riseIn`, or `motion.slideY`; use short exit fade/slide segments when a clean transition is needed. For static plates, split the asset into a main segment and a final 0.4-0.7s segment with `motion.fadeOut(...)` to create a real exit.
|
|
142
|
+
10. Generative visuals such as `xai.imagine` are allowed and often useful for product context, lifestyle scenes, abstract transitions, or polished motion. Use website screenshots as optional evidence, not as a rule that forbids generative clips.
|
|
143
|
+
11. For every generated visual prompt, explicitly require a clean scene with no text, no words, no letters, no captions, no logos, no watermarks, and no readable UI copy. AI video generation often corrupts text; all final titles, offers, captions, CTAs, prices, and labels must be created with VidScript `text` primitives.
|
|
144
|
+
12. Do not invent product claims. Extract copy, pricing, feature names, social proof, and CTA language from the site or ask the user.
|
|
125
145
|
|
|
126
146
|
## Best Practices
|
|
127
147
|
|
|
128
148
|
- **Use dynamic timeblocks** — `[-]` auto-advances the cursor, reducing calculation errors
|
|
129
149
|
- **Use `prev` for offsets** — `[prev + 0.5s .. prev + 2s]` for gaps between content
|
|
130
150
|
- **Named arguments for clarity** — `hero.Trim(start: 0s, end: 5s)` over `hero.Trim(0s, 5s)`
|
|
151
|
+
- **Use website assets judiciously for URL-based ads** — browser screenshots, product images, app screenshots, and logos can ground the ad, but they are optional ingredients, not the whole recipe
|
|
152
|
+
- **Avoid full-page screenshot backgrounds** — use above-fold, cropped, or focused screenshots that remain legible at video size; never rely on long website screenshots where the text becomes unreadable
|
|
153
|
+
- **Probe before placing** — get exact dimensions for every real asset, calculate scale from aspect ratio, and set `width`, `height`, `x`, and `y` explicitly
|
|
154
|
+
- **Match asset type to placement** — use real video files for `video` clips. Convert still screenshots/images to MP4 plates before timeline placement; do not point `video` at `.png`, `.jpg`, or `.webp` files.
|
|
155
|
+
- **Animate assets, not only text** — give product screenshots/logos/cards a clear entrance and a clean exit; split static visuals into main and fade-out segments if needed
|
|
156
|
+
- **Keep generated media text-free** — prompts for AI-generated images/videos must explicitly say no text, no words, no letters, no captions, no logos, no watermarks, and no readable UI copy; add all final copy with VidScript `text` primitives
|
|
131
157
|
- Use 1080x1920 for vertical content (TikTok/Instagram)
|
|
132
158
|
- Use 1920x1080 for horizontal content (YouTube)
|
|
133
159
|
- Hook viewers in the first 3 seconds
|
|
@@ -167,7 +193,7 @@ If a render fails:
|
|
|
167
193
|
Always ask clarifying questions about:
|
|
168
194
|
- Target platform (TikTok, Instagram, YouTube, etc.)
|
|
169
195
|
- Brand colors and fonts
|
|
170
|
-
- Existing assets
|
|
196
|
+
- Existing assets, product URLs, optional browser-captured screenshots, logos, page images, and generative visual directions
|
|
171
197
|
- Desired duration and style
|
|
172
198
|
- Whether they want to start from a template or from scratch
|
|
173
199
|
|
|
@@ -8,7 +8,12 @@ VidScript is a declarative DSL for composing short-form videos. Write a script,
|
|
|
8
8
|
2. **Validate early** — `scenerok validate file.vid` (errors show as `Line N:C — message`).
|
|
9
9
|
3. **Music package syntax** — `import eleven from "@elevenlabs/music"`, then call `eleven.music(...)`, `eleven.generateMusic(...)`, or `eleven.composeMusic(...)`.
|
|
10
10
|
4. **Copy working examples** — see `examples/system/` in this skill folder (e.g. `minimal-text-reel.vid`, `ecom-product-launch.vid`, `rokmilk-chocolate-promo.vid`).
|
|
11
|
-
5. **
|
|
11
|
+
5. **Use URL assets selectively** — if the user gives a website or product URL and browser screenshot tools are available, you can capture above-fold screenshots, product images, app screenshots, and logos for VidScript `input` assets. Do not treat screenshots as mandatory or as the only visual source.
|
|
12
|
+
6. **Probe asset type and dimensions** — before placing real assets, identify image vs video with `file`; inspect width, height, and duration with `ffprobe`, `sips`, or `identify`; then scale from the measured aspect ratio and set explicit `width`, `height`, `x`, and `y`.
|
|
13
|
+
7. **Use still images correctly** — local image inputs can be uploaded, but plain VidScript timeline placement currently uses `video` clips. Convert screenshots/logos/stills to short H.264 MP4 plates before writing `[time] = video asset`.
|
|
14
|
+
8. **Animate real assets** — visual inputs should have entry motion and, where transitions matter, an exit beat. For static plates, split into a main segment and a short final `motion.fadeOut(...)` segment.
|
|
15
|
+
9. **Generated media has no text** — prompts for AI-generated images/videos must explicitly ask for no text, no words, no letters, no captions, no logos, no watermarks, and no readable UI copy. Use VidScript `text` primitives for all final copy.
|
|
16
|
+
10. **Strict rules** — see `vidscript-strict.md` for invalid patterns (bare `xai.imagine`, bare `eleven.music(...)` without import, trailing params after direct plugin calls, nested quotes in prompts).
|
|
12
17
|
|
|
13
18
|
### Common validation failures
|
|
14
19
|
|
|
@@ -39,7 +44,46 @@ input hero = "https://cdn.example.com/hero.mp4"
|
|
|
39
44
|
input logo = "./assets/logo.png"
|
|
40
45
|
```
|
|
41
46
|
|
|
42
|
-
Supports HTTP(S) URLs, `/uploads/` paths, and local paths.
|
|
47
|
+
Supports HTTP(S) URLs, `/uploads/` paths, and local paths for video/image assets.
|
|
48
|
+
|
|
49
|
+
For ads based on a supplied URL, browser tools can capture real website visuals and save product images or logos when useful. Use screenshots sparingly: favor above-fold, cropped, or focused captures that remain legible at video size. Avoid full-page or long scrolling screenshots as backgrounds because their text will usually become unreadable.
|
|
50
|
+
|
|
51
|
+
Website captures are optional grounding assets, not a ban on generated video. A strong ad may combine product/logo/app screenshots with generated lifestyle clips, motion backgrounds, transitions, and VidScript text primitives. Use generative clips when they improve storytelling, show context, or make the ad feel more polished.
|
|
52
|
+
|
|
53
|
+
After declaring or downloading assets, probe file type and dimensions before placing them:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
file asset.png
|
|
57
|
+
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,duration -of csv=p=0 asset.mp4
|
|
58
|
+
sips -g pixelWidth -g pixelHeight asset.png
|
|
59
|
+
identify asset.webp
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use real videos as `video` clips. For still images such as screenshots, logos, product photos, or PNG captures, create a video plate first:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ffmpeg -y -loop 1 -t 4.5 -i screenshot.png -vf "scale=ceil(iw/2)*2:ceil(ih/2)*2,format=yuv420p" -r 30 screenshot-plate.mp4
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then declare the plate:
|
|
69
|
+
|
|
70
|
+
```vidscript
|
|
71
|
+
input screenshot = "assets/video-plates/screenshot-plate.mp4"
|
|
72
|
+
[0s .. 4.5s] = video screenshot, width: 1080, height: 1920, x: 0, y: 0, animate: motion.fadeIn(0.35s)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Do not write `[0s .. 4s] = video screenshot_png` when `screenshot_png` points to `.png`, `.jpg`, or `.webp`. Plugin-generated image surfaces are separate from local still inputs and are only safe when a plugin explicitly returns a `surface` result.
|
|
76
|
+
|
|
77
|
+
Use the measured width and height to preserve aspect ratio. For a 1080x1920 vertical ad, a common centered fit is:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
scaledWidth = min(assetWidth * scale, 900)
|
|
81
|
+
scaledHeight = scaledWidth / (assetWidth / assetHeight)
|
|
82
|
+
x = (1080 - scaledWidth) / 2
|
|
83
|
+
y = chosen safe-area top offset
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Do not guess asset size. Tiny logos, wide screenshots, and tall app screenshots need different scale and placement.
|
|
43
87
|
|
|
44
88
|
### Output Declaration
|
|
45
89
|
|
|
@@ -233,7 +277,7 @@ import xai from "@scenerok/xai"
|
|
|
233
277
|
import eleven from "@elevenlabs/music"
|
|
234
278
|
import motion from "@scenerok/basic-animations"
|
|
235
279
|
|
|
236
|
-
[-] = video xai.imagine("Cinematic product shot", aspect_ratio: "9:16", duration: 5)
|
|
280
|
+
[-] = video xai.imagine("Cinematic product shot, premium lighting, no text, no words, no letters, no captions, no logos, no watermark, no readable UI copy", aspect_ratio: "9:16", duration: 5)
|
|
237
281
|
[-] = audio xai.tts("Welcome to SceneRok", voice: "eve")
|
|
238
282
|
|
|
239
283
|
# ElevenLabs music package functions require an import alias.
|
|
@@ -272,6 +316,10 @@ import motion from "@scenerok/basic-animations"
|
|
|
272
316
|
|
|
273
317
|
[-] = video hero, animate: [motion.fadeIn(0.5s), motion.slideY(-40, 0, 1.2s)]
|
|
274
318
|
|
|
319
|
+
# Static asset with measured 4:3-ish aspect ratio, centered in a vertical 1080x1920 frame.
|
|
320
|
+
[0s .. 3.4s] = video app_screen, width: 760, height: 615, x: 160, y: 300, animate: [motion.riseIn(0.6s, 70), motion.float(2.4s, 8)]
|
|
321
|
+
[3.4s .. 4s] = video app_screen, width: 760, height: 615, x: 160, y: 300, animate: motion.fadeOut(0.6s)
|
|
322
|
+
|
|
275
323
|
[0s .. 2s] = text "Title", animate: {
|
|
276
324
|
type: "fade",
|
|
277
325
|
from: { opacity: 0 },
|
|
@@ -15,7 +15,7 @@ input cta_text = "{{cta_text | visit your nearest grocery store}}"
|
|
|
15
15
|
[2s .. 4.5s] = text hook_text, font: "Outfit", size: 52, color: "#FFFFFF", x: "50%", y: "45%", align: center, stroke: "#3E1C00", stroke_width: 3, animate: motion.riseIn(0.8s)
|
|
16
16
|
|
|
17
17
|
[-] = video xai.imagine(
|
|
18
|
-
"Premium lifestyle product shot of " + product_name + " chocolate milk in 250ml carton, cinematic lighting, 9:16 vertical",
|
|
18
|
+
"Premium lifestyle product shot of " + product_name + " chocolate milk in 250ml carton, cinematic lighting, 9:16 vertical, no text, no words, no letters, no captions, no logos, no watermark, no readable UI copy",
|
|
19
19
|
aspect_ratio: "9:16",
|
|
20
20
|
duration: 6
|
|
21
21
|
)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# VidScript v2 — Strict Agent Reference
|
|
2
|
+
|
|
3
|
+
Follow these rules exactly. When in doubt, copy a file from `examples/system/` (installed with `scenerok skills install`).
|
|
4
|
+
|
|
5
|
+
## Rule 1: Package imports are mandatory
|
|
6
|
+
|
|
7
|
+
```vidscript
|
|
8
|
+
import xai from "@scenerok/xai"
|
|
9
|
+
import eleven from "@elevenlabs/music"
|
|
10
|
+
import motion from "@scenerok/basic-animations"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Without the owning import, calls like `xai.imagine`, `xai.tts`, `eleven.music`, and `motion.fadeIn` fail validation.
|
|
14
|
+
|
|
15
|
+
**Never** call package functions without importing the package alias first.
|
|
16
|
+
|
|
17
|
+
## Rule 2: Use URL assets selectively
|
|
18
|
+
|
|
19
|
+
When the user gives a product, company, ecommerce, landing page, or app URL and you have browser/screenshot capability, you can visit the page and capture useful visual evidence. Favor above-fold screenshots, product views, app screenshots, pricing/offer cards, testimonials, and detectable logos or brand marks.
|
|
20
|
+
|
|
21
|
+
Do not use full-page or very long website screenshots as video backgrounds; their text is usually illegible at output size. Crop or frame screenshots to the specific visual proof point, and use them sparingly.
|
|
22
|
+
|
|
23
|
+
Website screenshots are optional source material, not a requirement to build the whole video from screenshots. You may combine them with `xai.imagine` or other generative video plugins for lifestyle scenes, motion backgrounds, transitions, or product context. Do not invent claims; use website copy or ask the user.
|
|
24
|
+
|
|
25
|
+
## Rule 2.5: Probe real asset type and dimensions before placement
|
|
26
|
+
|
|
27
|
+
Before writing `width`, `height`, `x`, or `y` for a real image/video/screenshot/logo, identify the asset type and inspect the actual dimensions and duration:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
file asset.png
|
|
31
|
+
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,duration -of csv=p=0 asset.mp4
|
|
32
|
+
sips -g pixelWidth -g pixelHeight asset.png
|
|
33
|
+
identify asset.webp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Use real video files for `video` clips. Plain VidScript input declarations can upload still images, but direct timeline placement currently does not expose a production-safe `[time] = image input` syntax. Do not point `video` at `.png`, `.jpg`, or `.webp` inputs.
|
|
37
|
+
|
|
38
|
+
For screenshots, logos, and other stills, convert the still to an H.264 MP4 plate first:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ffmpeg -y -loop 1 -t 4 -i screenshot.png -vf "scale=ceil(iw/2)*2:ceil(ih/2)*2,format=yuv420p" -r 30 screenshot-plate.mp4
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then use the plate:
|
|
45
|
+
|
|
46
|
+
```vidscript
|
|
47
|
+
input screenshot = "assets/video-plates/screenshot-plate.mp4"
|
|
48
|
+
[0s .. 4s] = video screenshot, width: 1080, height: 1920, x: 0, y: 0, animate: motion.fadeIn(0.35s)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Use measured aspect ratio and safe-area math. Do not guess sizes or blindly resize every asset to the same box. Center visuals with explicit pixel placement when possible:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
x = (outputWidth - scaledWidth) / 2
|
|
55
|
+
y = safeAreaTop
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Add entry motion to real assets, not only text. When a static visual needs a clean exit, split it:
|
|
59
|
+
|
|
60
|
+
```vidscript
|
|
61
|
+
import motion from "@scenerok/basic-animations"
|
|
62
|
+
|
|
63
|
+
[0s .. 3.4s] = video product, width: 760, height: 615, x: 160, y: 300, animate: [motion.riseIn(0.6s, 70), motion.float(2.4s, 8)]
|
|
64
|
+
[3.4s .. 4s] = video product, width: 760, height: 615, x: 160, y: 300, animate: motion.fadeOut(0.6s)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Rule 3: Generated media prompts must forbid text
|
|
68
|
+
|
|
69
|
+
AI-generated images and videos must not contain readable text. In every prompt for generated visual media, explicitly ask for no text, no words, no letters, no captions, no logos, no watermarks, and no readable UI copy. SceneRok has strong text primitives; all final titles, subtitles, offers, prices, feature labels, disclaimers, and CTAs must be added with VidScript `text` instructions instead of being baked into generated media.
|
|
70
|
+
|
|
71
|
+
Good prompt pattern:
|
|
72
|
+
|
|
73
|
+
```vidscript
|
|
74
|
+
[-] = video xai.imagine("Clean cinematic product background, premium lighting, no text, no words, no letters, no captions, no logos, no watermark, no readable UI copy", aspect_ratio: "9:16", duration: 5)
|
|
75
|
+
[0.5s .. 3s] = text "Launch offer", style: title, color: "#FFFFFF", x: "50%", y: "30%", stroke: "#000000", stroke_width: 3
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Invalid: asking the generator for signs, labels, packaging text, app UI text, title cards, lower thirds, prices, CTA buttons, or any readable copy.
|
|
79
|
+
|
|
80
|
+
## Rule 4: Use registered plugin surfaces
|
|
81
|
+
|
|
82
|
+
```vidscript
|
|
83
|
+
import xai from "@scenerok/xai"
|
|
84
|
+
import eleven from "@elevenlabs/music"
|
|
85
|
+
|
|
86
|
+
[-] = video xai.imagine("Prompt here, no text, no words, no letters, no captions, no logos, no watermark, no readable UI copy", aspect_ratio: "9:16", duration: 5)
|
|
87
|
+
[-] = audio xai.tts("Voiceover line", voice: "eve")
|
|
88
|
+
[0s .. 15s] = audio eleven.music("Warm premium music bed", duration: 15, instrumental: true)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For ElevenLabs music, import `@elevenlabs/music` and use `eleven.music(...)`, `eleven.generateMusic(...)`, or `eleven.composeMusic(...)`.
|
|
92
|
+
|
|
93
|
+
## Rule 5: Time ranges use `..`
|
|
94
|
+
|
|
95
|
+
```vidscript
|
|
96
|
+
[0s .. 5s] = text "Hello"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Not `[0s - 5s]`.
|
|
100
|
+
|
|
101
|
+
## Rule 6: Text params stay on one line
|
|
102
|
+
|
|
103
|
+
```vidscript
|
|
104
|
+
[0.5s .. 3s] = text "Headline", font: "Inter", size: 64, color: "#FFFFFF", x: "50%", y: "30%", align: center
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Rule 7: Quote safety in prompts
|
|
108
|
+
|
|
109
|
+
Use only straight `"` inside `xai.imagine("...")`. Do not nest quotes inside the prompt string (e.g. avoid `"RokMilk"` inside the prompt — say `labeled RokMilk` without extra quotes).
|
|
110
|
+
|
|
111
|
+
## Rule 8: Audio syntax
|
|
112
|
+
|
|
113
|
+
```vidscript
|
|
114
|
+
import xai from "@scenerok/xai"
|
|
115
|
+
import eleven from "@elevenlabs/music"
|
|
116
|
+
|
|
117
|
+
[-] = audio xai.tts("Spoken line", voice: "eve", speed: 1.0)
|
|
118
|
+
|
|
119
|
+
# Direct music call, no trailing audio params.
|
|
120
|
+
[0s .. 15s] = audio eleven.music("Soft premium ad music", duration: 15, instrumental: true)
|
|
121
|
+
|
|
122
|
+
# Use a binding when you need volume or fades.
|
|
123
|
+
let bed = eleven.music("Soft premium ad music", duration: 15, instrumental: true)
|
|
124
|
+
[0s .. 15s] = audio bed, volume: 0.35, fade_out: 2s
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Invalid:** `audio eleven.music("...", duration: 15), volume: 0.35` — trailing `, volume` after a direct plugin call is a parse error.
|
|
128
|
+
|
|
129
|
+
**Invalid:** `eleven.generateMusic(...)` without `import eleven from "@elevenlabs/music"`.
|
|
130
|
+
|
|
131
|
+
## Rule 9: Filters
|
|
132
|
+
|
|
133
|
+
```vidscript
|
|
134
|
+
[0s .. 15s] = filter "vignette", intensity: 0.3
|
|
135
|
+
[0s .. 15s] = filter "saturation", value: 1.12
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`saturation` uses `value`, not `intensity`.
|
|
139
|
+
|
|
140
|
+
## Rule 10: Always end with output
|
|
141
|
+
|
|
142
|
+
```vidscript
|
|
143
|
+
output to "video.mp4", resolution: "1080x1920", fps: 30
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Do **not** use legacy `config { }` blocks — they are not part of VidScript v2.
|
|
147
|
+
|
|
148
|
+
## Animations (after import)
|
|
149
|
+
|
|
150
|
+
```vidscript
|
|
151
|
+
import motion from "@scenerok/basic-animations"
|
|
152
|
+
|
|
153
|
+
[0s .. 2s] = text "Launch", x: "50%", y: "50%", animate: motion.popIn(0.7s)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Available: `fadeIn`, `fadeOut`, `slideX`, `slideY`, `popIn`, `riseIn`, `swingIn`, `glitchIn`, `float`, `typewriter`.
|
|
157
|
+
|
|
158
|
+
## Validate before render
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
scenerok validate my-video.vid
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Each error line includes `Line N:C — message` when the server returns location info.
|
|
165
|
+
|
|
166
|
+
## Bundled examples
|
|
167
|
+
|
|
168
|
+
| File | Use case |
|
|
169
|
+
|------|----------|
|
|
170
|
+
| `minimal-text-reel.vid` | Text-only, no API keys |
|
|
171
|
+
| `product-launch.vid` | User video input + text + vignette |
|
|
172
|
+
| `ecom-product-launch.vid` | xAI product visuals + CTA |
|
|
173
|
+
| `3-tips-fitness.vid` | Multiple `[-]` blocks + xAI per segment |
|
|
174
|
+
| `rokmilk-chocolate-promo.vid` | 15s generated-video promo pattern |
|
|
175
|
+
|
|
176
|
+
Full grammar: https://scenerok.com/docs/vidscript
|