@scenerok/cli 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +173 -0
  2. package/dist/commands/auth.d.ts +3 -0
  3. package/dist/commands/auth.d.ts.map +1 -0
  4. package/dist/commands/auth.js +94 -0
  5. package/dist/commands/cache.d.ts +3 -0
  6. package/dist/commands/cache.d.ts.map +1 -0
  7. package/dist/commands/cache.js +65 -0
  8. package/dist/commands/lint-video.d.ts +21 -0
  9. package/dist/commands/lint-video.d.ts.map +1 -0
  10. package/dist/commands/lint-video.js +122 -0
  11. package/dist/commands/project.d.ts +3 -0
  12. package/dist/commands/project.d.ts.map +1 -0
  13. package/dist/commands/project.js +173 -0
  14. package/dist/commands/render.d.ts +4 -0
  15. package/dist/commands/render.d.ts.map +1 -0
  16. package/dist/commands/render.js +242 -0
  17. package/dist/commands/skills.d.ts +3 -0
  18. package/dist/commands/skills.d.ts.map +1 -0
  19. package/dist/commands/skills.js +208 -0
  20. package/dist/commands/validate.d.ts +3 -0
  21. package/dist/commands/validate.d.ts.map +1 -0
  22. package/dist/commands/validate.js +254 -0
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +51 -0
  26. package/dist/lib/api.d.ts +268 -0
  27. package/dist/lib/api.d.ts.map +1 -0
  28. package/dist/lib/api.js +160 -0
  29. package/dist/lib/config.d.ts +13 -0
  30. package/dist/lib/config.d.ts.map +1 -0
  31. package/dist/lib/config.js +53 -0
  32. package/dist/lib/format-api-error.d.ts +2 -0
  33. package/dist/lib/format-api-error.d.ts.map +1 -0
  34. package/dist/lib/format-api-error.js +24 -0
  35. package/dist/lib/language.d.ts +3 -0
  36. package/dist/lib/language.d.ts.map +1 -0
  37. package/dist/lib/language.js +9 -0
  38. package/dist/lib/logger.d.ts +8 -0
  39. package/dist/lib/logger.d.ts.map +1 -0
  40. package/dist/lib/logger.js +51 -0
  41. package/dist/lib/project.d.ts +29 -0
  42. package/dist/lib/project.d.ts.map +1 -0
  43. package/dist/lib/project.js +156 -0
  44. package/dist/lib/sdk-scene-modules.d.ts +7 -0
  45. package/dist/lib/sdk-scene-modules.d.ts.map +1 -0
  46. package/dist/lib/sdk-scene-modules.js +35 -0
  47. package/dist/utils/skillsManifest.d.ts +42 -0
  48. package/dist/utils/skillsManifest.d.ts.map +1 -0
  49. package/dist/utils/skillsManifest.js +122 -0
  50. package/examples/system/3-tips-fitness.vid +45 -0
  51. package/examples/system/ecom-product-launch.vid +31 -0
  52. package/examples/system/glitch-title.vid +17 -0
  53. package/examples/system/meme-remix.vid +15 -0
  54. package/examples/system/minimal-text-reel.vid +11 -0
  55. package/examples/system/product-launch.vid +18 -0
  56. package/examples/system/rokmilk-chocolate-promo.vid +25 -0
  57. package/examples/system/testimonial-cut.vid +16 -0
  58. package/examples/system/ugc-testimonial-voiceover.vid +33 -0
  59. package/examples/system/voice-visual-promo.vid +21 -0
  60. package/package.json +51 -0
  61. package/skills/remote/ai-models.md +65 -0
  62. package/skills/remote/animations-catalog.md +89 -0
  63. package/skills/remote/animations-picker.md +77 -0
  64. package/skills/remote/brand-setup.md +69 -0
  65. package/skills/remote/catalog-index.json +1810 -0
  66. package/skills/remote/environments.md +73 -0
  67. package/skills/remote/intent-router.md +81 -0
  68. package/skills/remote/media-stdlib.md +66 -0
  69. package/skills/remote/music.md +69 -0
  70. package/skills/remote/sdk-guide.md +201 -0
  71. package/skills/remote/shaders-filters.md +97 -0
  72. package/skills/remote/text-styles.md +108 -0
  73. package/skills/remote/transitions-catalog.md +55 -0
  74. package/skills/remote/tts.md +82 -0
  75. package/skills/remote/vidscript-guide.md +574 -0
  76. package/skills/remote/vidscript-sample.md +28 -0
  77. package/skills/remote/vidscript-strict.md +251 -0
  78. package/skills/remote/workflow.md +72 -0
  79. package/skills/shared/SKILL.md +157 -0
@@ -0,0 +1,73 @@
1
+ # Agent Runtime Environments
2
+
3
+ SceneRok skills are shared across several runtimes. **Detect where you are running** before choosing tools, asking questions, or fetching docs.
4
+
5
+ ## Quick detection
6
+
7
+ | Signal | Environment | Primary actions |
8
+ | --- | --- | --- |
9
+ | Embedded in SceneRok web editor; `patch_vidscript` tool available; no shell | **Web editor** | Patch in-place; use editor asset library URLs |
10
+ | `scenerok` CLI on user's machine; file system access | **Desktop agent (CLI)** | `scenerok validate` / `render`; local asset paths |
11
+ | ChatGPT Actions, OAuth to SceneRok, `openaiFileIdRefs` | **ChatGPT GPT** | `validateVidscript` → `renderVideo`; import uploads first |
12
+ | Gemini Gem or Grok Skill; may lack HTTP tools | **Consumer chat (limited)** | Compose VidScript; user renders elsewhere if no API |
13
+ | `scenerok-mcp` tools (`scenerok_validate_vidscript`, `scenerok_render_video`, …) or remote `https://mcp.scenerok.com/mcp` | **MCP host** | MCP tools instead of raw CLI |
14
+ | Reading bundled `SKILL.md` only | **Router-only** | Fetch remote docs from index (next section) |
15
+
16
+ When unsure, ask one clarifying question: *"Are we in the SceneRok editor, your terminal, or a chat app like ChatGPT?"*
17
+
18
+ ## Remote doc loading (router-only / desktop)
19
+
20
+ 1. Fetch `https://scenerok.com/.well-known/agent-skills/index.json`
21
+ 2. **Always load** `vidscript-strict.md` and `intent-router.md`
22
+ 3. Load `environments.md` (this file) on first turn
23
+ 4. Conditionally load catalogs per `intent-router.md`
24
+ 5. Offline: `scenerok skills sync` then read local skill directory
25
+ 6. Freshness: `scenerok skills check` · update: `scenerok skills update`
26
+
27
+ Base URL: `https://scenerok.com/.well-known/agent-skills/{filename}`
28
+
29
+ ## Capability matrix
30
+
31
+ | Capability | Web editor | CLI / MCP | ChatGPT Action | Gemini / Grok (no API) |
32
+ | --- | --- | --- | --- | --- |
33
+ | Edit VidScript in place | `patch_vidscript` | Write `.vid` / `.ts` file | Return script to user | Return script |
34
+ | Validate | Editor API (VidScript) | `scenerok validate` (`.vid` or `.ts`) | `validateVidscript` (+ `language` for SDK) | Explain only |
35
+ | Render | Editor UI / API (VidScript) | `scenerok render` (`.vid` or `.ts`) | `renderVideo` + poll | Instruct user |
36
+ | Shell / ffprobe / sips | No | Yes | No | No |
37
+ | Browse product URL | If browser tool | If browser tool | Limited | Limited |
38
+ | User asset library | Yes (logged in) | Via URLs / uploads | Via `importOpenAIConversationFiles` | Ask for public URLs |
39
+ | Ask brand questions | Yes (chat) | Yes (terminal) | Yes (chat) | Yes (chat) |
40
+ | OAuth / API tokens | Session cookie | `scenerok auth login` | OAuth per user | Manual token fallback |
41
+
42
+ ## Environment-specific rules
43
+
44
+ ### Web editor
45
+ - Do **not** instruct the user to run CLI commands — the editor validates and renders in-app.
46
+ - Prefer `patch_vidscript` for small edits; full fenced `vidscript` blocks for rewrites.
47
+ - Use asset URLs from the user's SceneRok library when shown in context.
48
+ - Load `brand-setup.md` when colors/logo are unknown and the user is building a branded promo.
49
+
50
+ ### Desktop agent (CLI / Cursor / Claude Code / Codex)
51
+ - Run `scenerok validate` before every render (`.vid` or `.ts`).
52
+ - Prefer `@scenerok/sdk` for agent-authored complex scenes; VidScript for short human edits.
53
+ - Probe local assets with `loadVideo` / media stdlib, or `file` / `ffprobe` / `sips` / `identify` before placement.
54
+ - Install router: `scenerok skills install <platform> [--sync]`
55
+ - Full offline bundle: `scenerok skills sync`
56
+
57
+ ### ChatGPT GPT
58
+ - Load `consumer-chat-apps.md` and `chatgpt-gpt-instructions.md` for OAuth and file import.
59
+ - Never use `/mnt/data/...` paths — import via `importOpenAIConversationFiles` first.
60
+ - Always validate before render; poll `getRenderStatus` until complete.
61
+
62
+ ### Consumer chat without API (Gemini Gem, Grok Skill)
63
+ - Compose and explain VidScript; tell the user to render via SceneRok web, CLI, or ChatGPT Action.
64
+ - Load `gemini-gem-instructions.md` or `grok-skill.md` as appropriate.
65
+
66
+ ## What to ignore per environment
67
+
68
+ | Instruction in other docs | Web editor | ChatGPT |
69
+ | --- | --- | --- |
70
+ | `scenerok render ...` | Use editor render | Use `renderVideo` action |
71
+ | `scenerok auth login` | N/A (session) | OAuth instead |
72
+ | Fetch remote skill URLs | Already inlined locally | Fetch if network tool exists |
73
+ | Local file paths in VidScript | Use library HTTPS URLs | Use imported asset URLs |
@@ -0,0 +1,81 @@
1
+ # SceneRok Intent Router
2
+
3
+ Load after **`vidscript-strict.md`** and **`environments.md`** when the user wants a video.
4
+
5
+ **Remote base:** `https://scenerok.com/.well-known/agent-skills/`
6
+
7
+ ## Step 0 — Detect environment
8
+
9
+ Follow `environments.md`. Web editor → patch tool, no CLI. ChatGPT → Actions + file import. Desktop → CLI validate/render.
10
+
11
+ ## Disambiguation (≤2 questions)
12
+
13
+ Defaults unless the user says otherwise:
14
+
15
+ - **16:9** — YouTube, desktop, explainers
16
+ - **9:16** — TikTok, Reels, Stories
17
+ - **English** copy and VO
18
+ - **3–15 s** social hooks · **15–60 s** promos
19
+
20
+ | Signal | Workflow |
21
+ | --- | --- |
22
+ | Data/code/stats/maps, motion-first, &lt;10 s | Motion graphic |
23
+ | Product URL + CTA + lifestyle b-roll | Product promo |
24
+ | Tweet / Reddit / Spotify / follow card | Social proof card |
25
+ | Multiple clips + cross-fades / whips | Scene montage |
26
+ | Voiceover explainer | Narrated explainer |
27
+ | PR / code walk / terminal | Code demo |
28
+
29
+ ## Workflow → docs → APIs
30
+
31
+ | Workflow | Load these slugs | Primary APIs (VidScript · SDK) |
32
+ | --- | --- | --- |
33
+ | **Product promo** | `ai-models.md`, `text-styles.md`, `music.md`, `workflow.md`, `brand-setup.md` (+ `sdk-guide.md` if TS) | `xai.imagine` / `await xai.genVideo(...)`, `motion.popIn` / `fadeIn`, `eleven.music` |
34
+ | **Motion graphic** | `animations-picker.md` (+ `animations-catalog.md` if needed) | `animations.*` (VidScript HyperFrames; prefer VidScript for catalog blocks) |
35
+ | **Social proof card** | `animations-picker.md` | `animations.x_post`, `reddit_post`, … (VidScript) |
36
+ | **Scene montage** | `transitions-catalog.md`, `ai-models.md` (+ `sdk-guide.md` if TS loops) | `tr.dissolve` · SDK: `import tr from '@scenerok/transitions'` + `t[start][end] = tr.dissolve()` |
37
+ | **Narrated explainer** | `tts.md`, `text-styles.md`, `music.md`, `workflow.md` (+ `sdk-guide.md` if TS) | `xai.tts` · `await xai.tts(...)` + `t.push(vo)` |
38
+ | **Code demo / PR** | `animations-picker.md` (code rows) | `code_typing`, `code_diff` (VidScript) |
39
+ | **Text animation / headline / stat** | `animations-picker.md` (text-anim rows) | `animations.text_*` (VidScript) · SDK kinetic: `text` + `fadeIn` / `popIn` |
40
+ | **Kinetic title only** | `text-styles.md` (+ `sdk-guide.md` if TS) | `text` + `motion.*` · SDK: `text(..., { area })` + `.animate(fadeIn(...))` |
41
+ | **Custom-authored animation (no block fits)** | `animations-catalog.md` → "Custom HTML" | `animations.custom_html` (VidScript) |
42
+ | **Complex / data-driven timeline** | `sdk-guide.md`, `media-stdlib.md` | `@scenerok/sdk` — `timeline`, `t.grid`, `loadVideo`, AI plugins |
43
+
44
+ ## Staged routing
45
+
46
+ 1. **Classify** — workflow from table above
47
+ 2. **Choose authoring** — short/human → VidScript; complex/agent (loops, computed timing, multi-clip arithmetic) → `@scenerok/sdk` (`sdk-guide.md`)
48
+ 3. **Load catalogs** — only what that workflow needs (conditional loading)
49
+ 4. **Name block or API** — VidScript: pick `animations.<fn>` from `animations-picker.md`. SDK: factories (`video` / `loadVideo`, `text`, `fadeIn`) + AI imports (`@scenerok/xai`, …)
50
+ 5. **Brand** — if promo and missing colors/logo, one message per `brand-setup.md`
51
+ 6. **Probe assets** — dimensions / duration (`media-stdlib.md`, `loadVideo`, or CLI `ffprobe`)
52
+ 7. **Place text** — VidScript `area:` / `grid`; SDK `t.grid({...})` + `text(..., { area })`
53
+ 8. **Compose** — VidScript or SDK TS + validate
54
+ 9. **Render** — per environment (`environments.md`)
55
+
56
+ ## Reuse-first
57
+
58
+ - `animations.<fn>(...)` over hand-authored HTML when a block fits
59
+ - Text/headline treatments: try `animations.text_*` (text-anim family) before `motion.*` primitives or custom HTML
60
+ - `tr.<fn>()` for scene transitions; `filter "…"` for single-clip VFX
61
+ - No matching block → `text` + `animate: motion.<primitive>`, or `animations.custom_html(...)` to author your own HTML/CSS + GSAP / Three.js / any seekable JS animation lib (full author contract + minimal template in `animations-catalog.md` → "Custom HTML")
62
+ - Unverified blocks (`verified: no`) ship demo content — prefer verified families
63
+ - Complex procedural timelines → TypeScript `@scenerok/sdk` (`sdk-guide.md`) instead of exploding VidScript
64
+
65
+ ## Conditional loading
66
+
67
+ - Skip `animations-catalog.md` unless you need full param tables
68
+ - Skip `transitions-catalog.md` unless multiple clips or explicit transition ask
69
+ - Always `vidscript-strict.md` before VidScript composition
70
+ - Load `sdk-guide.md` before TypeScript SDK composition (scheduling, `t.grid`, AI plugin imports, `async main`)
71
+ - Load `media-stdlib.md` when probing durations, grabbing frames, `loadVideo`, or layout-fitting assets
72
+ - Load `ai-models.md` / `tts.md` / `music.md` for generative media in **either** language (examples cover both)
73
+ - `vidscript-guide.md` only for grammar questions
74
+
75
+ ## Reference
76
+
77
+ - Grammar: `vidscript-guide.md` or https://scenerok.com/.well-known/agent-skills/vidscript-guide.md
78
+ - SDK: `sdk-guide.md` or https://scenerok.com/.well-known/agent-skills/sdk-guide.md
79
+ - Media stdlib: `media-stdlib.md`
80
+ - Machine-readable: `catalog-index.json`
81
+ - Browse UI: https://scenerok.com/catalog
@@ -0,0 +1,66 @@
1
+ # Media standard library
2
+
3
+ Shared Pass-1 host APIs for probing media and extracting frames. Available in **both** authoring languages.
4
+
5
+ Prefer `loadVideo` / `loadAudio` from `@scenerok/sdk` when you only need duration for scheduling — they call the stdlib under the hood.
6
+
7
+ ## TypeScript (`@scenerok/stdlib` or `@scenerok/sdk`)
8
+
9
+ ```ts
10
+ import { timeline, loadVideo, text, s } from '@scenerok/sdk'
11
+ import { getVideoLength, grabFrame, getDimensions, getLoudness, beats } from '@scenerok/stdlib'
12
+
13
+ export default async function main() {
14
+ const path = './hero.mp4'
15
+ const clip = await loadVideo(path) // fills duration via stdlib
16
+ const d = await getVideoLength(path)
17
+ const { width, height } = await getDimensions(path)
18
+ const loudness = await getLoudness(path)
19
+ const thumb = await grabFrame(path, d / 2, { width: 720 })
20
+
21
+ const t = timeline({ width: 1080, height: 1920, fps: 30 })
22
+ t[0][clip.duration] = clip
23
+ t[0][s(2)] = text(`${width}x${height}`, { size: 40, area: 'caption' })
24
+ t[0][beats(120, 4)] = text(`${loudness.integratedLufs} LUFS`, { size: 32, area: 'lower-third' })
25
+ // thumb is a data URL — schedule with video(thumb, { duration: 2 }) if needed
26
+ return t.toIR()
27
+ }
28
+ ```
29
+
30
+ ## VidScript (`@scenerok/media`)
31
+
32
+ ```vidscript
33
+ import media from "@scenerok/media"
34
+
35
+ input hero = "./hero.mp4"
36
+ let d = media.length(hero)
37
+ let loudness = media.loudness(hero)
38
+ let thumb = media.grabFrame(hero, d / 2)
39
+
40
+ [0s .. d] = video hero
41
+ [0s .. 2s] = video thumb, width: 400
42
+ ```
43
+
44
+ `media.length` returns a time value usable in arithmetic and `[start .. end]` ranges.
45
+ `media.info(hero).duration` / `.width` work via property access on the data result.
46
+ `media.loudness(hero).integratedLufs` returns measured loudness data from ffmpeg (`truePeakDb`, `loudnessRange`, and `duration` are also available).
47
+
48
+ ## API surface
49
+
50
+ | Function | TS | VidScript | Returns |
51
+ |----------|----|-----------|---------|
52
+ | `getVideoLength` / `length` | yes | `media.length` | seconds |
53
+ | `getAudioLength` | yes | `media.getAudioLength` | seconds |
54
+ | `getMediaInfo` / `info` | yes | `media.info` | `{ duration, width, height, fps, hasAudio, kind, ... }` |
55
+ | `getDimensions` / `dimensions` | yes | `media.dimensions` | `{ width, height }` |
56
+ | `getFps` / `fps` | yes | `media.fps` | number \| null |
57
+ | `hasAudio` | yes | `media.hasAudio` | boolean |
58
+ | `getLoudness` / `loudness` | yes | `media.loudness` | `{ integratedLufs, truePeakDb, loudnessRange, duration }` |
59
+ | `mediaKind` / `kind` | yes | `media.kind` | `video` \| `audio` \| `image` |
60
+ | `grabFrame` | yes | `media.grabFrame` | data URL (or uploaded URL) |
61
+ | `grabFrameAtFraction` | yes | `media.grabFrameAtFraction` | data URL |
62
+ | `measureText` | yes | `media.measureText` | `{ width, height, lines }` |
63
+ | `fitContain` / `fitCover` | yes | `media.fitContain` | `{ width, height, x, y }` |
64
+ | `parseTime` / `timecode` / `beats` / `clampTime` | yes | yes | time helpers |
65
+
66
+ Implementation: `src/lib/media/stdlib/`. VidScript plugin: `src/plugins/media/`.
@@ -0,0 +1,69 @@
1
+ # Generative Music
2
+
3
+ `import eleven from "@elevenlabs/music"`
4
+
5
+ ### VidScript
6
+
7
+ ```vidscript
8
+ import eleven from "@elevenlabs/music"
9
+ let bed = eleven.music("Warm premium launch bed", duration: 15, instrumental: true)
10
+ [0s .. 15s] = audio bed, volume: 0.35, fade_out: 2s
11
+ ```
12
+
13
+ ### TypeScript SDK
14
+
15
+ ```ts
16
+ import { timeline } from '@scenerok/sdk'
17
+ import eleven from '@elevenlabs/music'
18
+
19
+ export default async function main() {
20
+ const t = timeline({ width: 1080, height: 1920, fps: 30 })
21
+ const bed = await eleven.music('Warm premium launch bed', {
22
+ duration: 15,
23
+ force_instrumental: true,
24
+ })
25
+ t.push(bed.with({ volume: 0.35, fadeOut: 2 }))
26
+ return t.toIR()
27
+ }
28
+ ```
29
+
30
+ Use a binding (`let bed` / `const bed`) when you need volume or fades. Do not call `eleven.tts` — use `xai.tts` for voiceover.
31
+
32
+ ## Examples (VidScript)
33
+
34
+ **Drone underscore**
35
+
36
+ ```vidscript
37
+ import eleven from "@elevenlabs/music"
38
+
39
+ [0s .. 3s] = text "drift", font: "Inter", size: 120, color: "#6B7280", align: "center", letter_spacing: 12
40
+ [0s .. 3s] = audio eleven.music("dark ambient drone, minimal, cinematic tension, no percussion", duration: 3, force_instrumental: true)
41
+ ```
42
+
43
+ **Padscape**
44
+
45
+ ```vidscript
46
+ import eleven from "@elevenlabs/music"
47
+
48
+ [0s .. 3s] = text "ambient", font: "Inter", size: 140, color: "#9FB6FF", align: "center", letter_spacing: 8
49
+ [0s .. 3s] = audio eleven.music("ambient cinematic padscape, slow evolving, contemplative", duration: 3, force_instrumental: true)
50
+ ```
51
+
52
+ **4 s sting**
53
+
54
+ ```vidscript
55
+ import eleven from "@elevenlabs/music"
56
+
57
+ [0s .. 3s] = text "▶", font: "Inter Black", size: 200, color: "#FFD23F", align: "center"
58
+ [0s .. 3s] = audio eleven.music("short upbeat logo sting, claps, bright", duration: 3, force_instrumental: true)
59
+ ```
60
+
61
+ **Bright brand cue**
62
+
63
+ ```vidscript
64
+ import eleven from "@elevenlabs/music"
65
+
66
+ [0s .. 3s] = text "UPBEAT", font: "Inter Black", size: 180, color: "#FFFFFF", align: "center"
67
+ [0s .. 3s] = audio eleven.music("uplifting corporate brand cue, claps, bright synth, optimistic", duration: 3, force_instrumental: true)
68
+ ```
69
+
@@ -0,0 +1,201 @@
1
+ # @scenerok/sdk — TypeScript authoring for complex scenes
2
+
3
+ Use **TypeScript + `@scenerok/sdk`** when the scene needs loops, branches, arithmetic timing, or data-driven composition. Keep **VidScript** for short human-authored promos and templates.
4
+
5
+ Both paths emit the same `IRTimeline`. Preview and render (Pass 2) are unchanged.
6
+
7
+ ## When to choose which
8
+
9
+ | Signal | Language |
10
+ |--------|----------|
11
+ | Short promo, human edit, template placeholders | VidScript (`.vid`) |
12
+ | Loop over clips, computed `start`/`end`, agent-authored complex timeline | TypeScript + `@scenerok/sdk` (`.ts`) |
13
+
14
+ ## Schedule syntax
15
+
16
+ JavaScript has no `t[0, end]` dual key (comma operator collapses to one index). Use dual-index assignment:
17
+
18
+ ```ts
19
+ import { timeline, loadVideo, text, audio, s, fadeIn } from '@scenerok/sdk'
20
+
21
+ export default async function main() {
22
+ const t = timeline({ width: 1080, height: 1920, fps: 30 })
23
+ const scene1 = await loadVideo('./hero.mp4')
24
+
25
+ t[0][scene1.duration] = scene1.animate(fadeIn(s(0.4)))
26
+ t['0s']['3s'] = text('Hello', { size: 72 })
27
+ t[scene1.duration][scene1.duration + s(2)] = text('Next')
28
+ t.push(audio('./bed.mp3', { duration: 7, volume: 0.4 }))
29
+
30
+ return t.toIR()
31
+ }
32
+ ```
33
+
34
+ | Form | Meaning |
35
+ |------|---------|
36
+ | `t[start][end] = value` | Preferred dual-index schedule |
37
+ | `t.range(start, end, value)` | Explicit call (no Proxy) |
38
+ | `t['-'] = value` / `t.push(value)` | Auto-append at playhead |
39
+
40
+ `start` / `end` accept numbers (seconds), `s(3)` / `ms(300)`, or strings (`'3s'`, `'1:30'`). Full JS arithmetic works.
41
+
42
+ No `video` / `text` keywords after `=` — factories return typed values and the runtime infers IR kind.
43
+
44
+ Use `loadVideo(path)` / `loadAudio(path)` to probe duration through the media stdlib when `duration` is omitted:
45
+
46
+ ```ts
47
+ const clip = await loadVideo('./hero.mp4')
48
+ t[0][clip.duration] = clip
49
+ ```
50
+
51
+ Use the sync `video(path, { duration })` / `audio(path, { duration })` factories when you already know the timing.
52
+
53
+ ## Grid areas
54
+
55
+ Same CSS-grid regions as VidScript. Declare a grid on the timeline, then place text with `area:`:
56
+
57
+ ```ts
58
+ import { timeline, text, s } from '@scenerok/sdk'
59
+
60
+ export default function main() {
61
+ const t = timeline({ width: 1080, height: 1920, fps: 30 })
62
+
63
+ t.grid({
64
+ rows: '20% 1fr 30%',
65
+ cols: '1fr 1fr',
66
+ areas: ['title title', 'left right', 'caption caption'],
67
+ })
68
+
69
+ t[0][s(3)] = text('BIG SALE', { size: 72, area: 'title' })
70
+ t[0][s(3)] = text('Left column', { size: 40, area: 'left' })
71
+
72
+ return t.toIR()
73
+ }
74
+ ```
75
+
76
+ Without `t.grid(...)`, `area: 'title' | 'stage' | 'lower-third' | 'caption'` uses the built-in social-video preset (portrait vs landscape). Explicit `x` / `y` / `maxWidth` / `maxHeight` override the area.
77
+
78
+ Helpers also available: `resolveGridAreas`, `defaultGridSpec`, `placeInArea`.
79
+
80
+ Same semantics as VidScript `grid rows: ..., areas: [...]` — see `vidscript-guide.md` → Grid Areas.
81
+
82
+ ## Transitions
83
+
84
+ Same `@scenerok/transitions` package as VidScript. Schedule a transition window between abutting clips; `toIR()` binds `fromId` / `toId` automatically:
85
+
86
+ ```ts
87
+ import { timeline, video } from '@scenerok/sdk'
88
+ import tr from '@scenerok/transitions'
89
+
90
+ export default function main() {
91
+ const t = timeline({ width: 1080, height: 1920, fps: 30 })
92
+
93
+ t[0][5] = video('./a.mp4', { duration: 5 })
94
+ t[5][5.6] = tr.dissolve()
95
+ t[5.6][10] = video('./b.mp4', { duration: 4.4 })
96
+
97
+ // Or auto-append with catalog default (0.6s):
98
+ // t.push(tr.push({ direction: 'right' }))
99
+
100
+ return t.toIR()
101
+ }
102
+ ```
103
+
104
+ Common options: `direction`, `ease`, `strength`, `mode` (`roll` | `freeze`). Full catalog: `transitions-catalog.md`.
105
+
106
+ ## Entry contract
107
+
108
+ Export `default async function main()` (or sync `main`) that returns either:
109
+
110
+ - `t.toIR()`, or
111
+ - an `IRTimeline` object
112
+
113
+ `async main` is supported so you can `await loadVideo(...)`, `await getVideoLength(...)`, or `await grabFrame(...)`.
114
+
115
+ ## Validate / render
116
+
117
+ ```bash
118
+ scenerok validate scene.ts
119
+ scenerok render scene.ts --watch
120
+ ```
121
+
122
+ You can also **include** an SDK scene from VidScript:
123
+
124
+ ```vidscript
125
+ import intro from "./intro.ts"
126
+ use intro at 0s .. 0s with {}
127
+ output to "reel.mp4"
128
+ ```
129
+
130
+ See `vidscript-guide.md` → Include TypeScript / JavaScript scenes.
131
+
132
+ MCP:
133
+
134
+ - `scenerok_validate_vidscript` with `language: "typescript"`
135
+ - `scenerok_render_video` with `language: "typescript"`
136
+ - `scenerok_get_sdk_guide` for this document
137
+
138
+ ## AI plugins (xAI / Cloudflare / ElevenLabs)
139
+
140
+ Same packages as VidScript. Import them in TypeScript; the SceneRok compile host runs the real plugins and returns SDK `video` / `audio` nodes:
141
+
142
+ ```ts
143
+ import { timeline } from '@scenerok/sdk'
144
+ import xai from '@scenerok/xai'
145
+ import cf from '@scenerok/cloudflare'
146
+ import eleven from '@elevenlabs/music'
147
+
148
+ export default async function main() {
149
+ const t = timeline({ width: 1080, height: 1920, fps: 30 })
150
+ const clip = await xai.genVideo('Cinematic drone over mountains', {
151
+ duration: 5,
152
+ aspect_ratio: '9:16',
153
+ resolution: '720p',
154
+ })
155
+ const still = await cf.image('Product on seamless backdrop', { aspect_ratio: '9:16' })
156
+ const vo = await xai.tts('Welcome to SceneRok', { voice: 'eve' })
157
+ const bed = await eleven.music('Warm lo-fi bed', { duration: 12 })
158
+
159
+ t[0][clip.duration] = clip
160
+ t[clip.duration][clip.duration + still.duration] = still
161
+ t.push(vo)
162
+ t.push(bed)
163
+ return t.toIR()
164
+ }
165
+ ```
166
+
167
+ | Package | Import | Key functions |
168
+ |---------|--------|---------------|
169
+ | `@scenerok/xai` | `import xai from '@scenerok/xai'` | `imagine`, `genVideo`, `image`, `imageToVideo`, `referenceToVideo`, `extendVideo`, `tts`, `listVoices` |
170
+ | `@scenerok/cloudflare` | `import cf from '@scenerok/cloudflare'` | `video` / `imagine`, `image`, `imageToVideo`, `extendVideo`, `listModels` |
171
+ | `@elevenlabs/music` | `import eleven from '@elevenlabs/music'` | `music`, `generateMusic`, `composeMusic` |
172
+
173
+ Requires the same env secrets as VidScript (`XAI_API_KEY`, `ELEVENLABS_API_KEY`, Cloudflare AI Gateway credentials). Generation is billed on render the same way as VidScript plugins.
174
+
175
+ ## MVP limits
176
+
177
+ - Prefer `getVideoLength(path)` from `@scenerok/stdlib` instead of hard-coding `duration:` when assets exist on disk
178
+ - `--generate-assets` remains VidScript-only (SDK scripts generate assets during `scenerok render` when plugins are called)
179
+
180
+ ## Media stdlib
181
+
182
+ ```ts
183
+ import { loadVideo, getVideoLength, grabFrame, beats } from '@scenerok/sdk'
184
+
185
+ export default async function main() {
186
+ const clip = await loadVideo('./hero.mp4')
187
+ const d = await getVideoLength('./hero.mp4')
188
+ const thumb = await grabFrame('./hero.mp4', d / 2)
189
+ // ...
190
+ }
191
+ ```
192
+
193
+ Same functions are available in VidScript via `import media from "@scenerok/media"`.
194
+
195
+ See `skills/remote/media-stdlib.md` and `ai-models.md` / `tts.md` / `music.md` for prompt guidance.
196
+
197
+ ## Related
198
+
199
+ - VidScript grammar: `vidscript-guide.md`
200
+ - Intent routing: `intent-router.md`
201
+ - Package README: `packages/scenerok-sdk/README.md`
@@ -0,0 +1,97 @@
1
+ # Shaders and Filters
2
+
3
+ ## Built-in filters
4
+
5
+ Apply on a time block with the clip active:
6
+
7
+ ```vidscript
8
+ [0s .. 5s] = filter "vignette", intensity: 0.4
9
+ [2s .. 4s] = filter "sepia", intensity: 0.6
10
+ ```
11
+
12
+ | Filter | Typical use |
13
+ | --- | --- |
14
+ | `monochrome` | Desaturated / B&W look |
15
+ | `sepia` | Warm vintage tone |
16
+ | `blur` | Soft focus / depth |
17
+ | `chromatic` | Lens aberration / glitch accent |
18
+ | `glitch` | Digital distortion |
19
+ | `vignette` | Edge darkening — finishing pass |
20
+ | `contrast` | Punch up midtones |
21
+ | `saturation` | Color intensity |
22
+ | `brightness` | Exposure lift/drop |
23
+
24
+ Use filters as optional finishing tools — do not add by default.
25
+
26
+ ## VFX filters (single-clip)
27
+
28
+ Native VFX via `filter` keyword on one clip:
29
+
30
+ ```vidscript
31
+ [0s .. 5s] = video clip
32
+ [0s .. 2s] = filter "liquid_glass", intensity: 0.6
33
+ ```
34
+
35
+ | Filter | Reach for it when… |
36
+ | --- | --- |
37
+ | `liquid_glass` | iOS-style glass morphism over footage |
38
+ | `magnetic` | UI magnet / snap aesthetic |
39
+ | `portal` | Sci-fi portal / warp hole |
40
+ | `text_cursor` | Typing / terminal cursor overlay |
41
+
42
+ ## Custom shaders
43
+
44
+ Author fragment GLSL in a `.glsl` file and import it — same idea as `animations.custom_html(src:)` for HTML, but via the first-class shader import:
45
+
46
+ ```vidscript
47
+ import shader glow from "./shaders/glow.glsl"
48
+
49
+ [0s .. 5s] = text "Hello"
50
+ [0s .. 5s] = shader glow, intensity: 0.8
51
+ ```
52
+
53
+ Also works with npm package paths under `node_modules`:
54
+
55
+ ```vidscript
56
+ import shader glow from "shader-pack/shaders/glow.glsl"
57
+ ```
58
+
59
+ | Use | Keyword |
60
+ | --- | --- |
61
+ | Built-in / VFX from the library | `filter "name", …` |
62
+ | Your own `.glsl` file | `import shader` + `shader name, …` |
63
+
64
+ **Fragment contract** (EffectComposer post-process):
65
+
66
+ - Fragment only — the engine supplies a shared vertex shader with `vUv`
67
+ - Declare `uniform sampler2D tDiffuse` and sample it
68
+ - Write `gl_FragColor`
69
+ - VidScript params become uniforms by **exact name** (`intensity: 0.8` → `uniform float intensity`)
70
+ - Optional: declare `uniform float uTime` and/or `uniform vec2 uResolution` — the renderer injects and updates them automatically
71
+
72
+ ```glsl
73
+ uniform sampler2D tDiffuse;
74
+ uniform float intensity;
75
+ varying vec2 vUv;
76
+
77
+ void main() {
78
+ vec4 texel = texture2D(tDiffuse, vUv);
79
+ gl_FragColor = texel * (1.0 + intensity);
80
+ }
81
+ ```
82
+
83
+ The compiler reads the file at compile time and embeds the GLSL into IR (`IRShaderEffect`). Relative paths resolve against the `.vid` directory (`workingDirectory` / `assetBaseDir`).
84
+
85
+ ## Scene transitions
86
+
87
+ Scene transitions use `@scenerok/transitions` — see `transitions-catalog.md`. They blend **two** clips at window boundaries; filters operate on **one** clip.
88
+
89
+ ```vidscript
90
+ import tr from "@scenerok/transitions"
91
+
92
+ [0s .. 5s] = video clip_a
93
+ [5s .. 5.6s] = tr.dissolve()
94
+ [5.6s .. 10s] = video clip_b
95
+ ```
96
+
97
+ Do not confuse `tr.dissolve()` (two-texture blend) with `filter "vignette"` (single-clip post).