@scenerok/sdk 0.6.0 → 0.8.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.
@@ -0,0 +1,65 @@
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) # data URL of the middle frame, to look at
39
+
40
+ [0s .. d] = video hero
41
+ [d .. d + 2s] = hero.Trim(d / 2, d / 2 + 1s).Speed(0) # hold the middle frame for 2 s
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
+
@@ -0,0 +1,50 @@
1
+ # Generative Music
2
+
3
+ `import eleven from "@elevenlabs/music"`
4
+
5
+ ```vidscript
6
+ import eleven from "@elevenlabs/music"
7
+ let bed = eleven.music("Warm premium launch bed", duration: 15, instrumental: true)
8
+ [0s .. 15s] = audio bed, volume: 0.35, fade_out: 2s
9
+ ```
10
+
11
+ Use `let bed = eleven.music(...)` then `audio bed, volume: ...` for fades. Do not call `eleven.tts`.
12
+
13
+ ## Examples
14
+
15
+ **Drone underscore**
16
+
17
+ ```vidscript
18
+ import eleven from "@elevenlabs/music"
19
+
20
+ [0s .. 3s] = text "drift", font: "Inter", size: 120, color: "#6B7280", align: "center", letter_spacing: 12
21
+ [0s .. 3s] = audio eleven.music("dark ambient drone, minimal, cinematic tension, no percussion", duration: 3, force_instrumental: true)
22
+ ```
23
+
24
+ **Padscape**
25
+
26
+ ```vidscript
27
+ import eleven from "@elevenlabs/music"
28
+
29
+ [0s .. 3s] = text "ambient", font: "Inter", size: 140, color: "#9FB6FF", align: "center", letter_spacing: 8
30
+ [0s .. 3s] = audio eleven.music("ambient cinematic padscape, slow evolving, contemplative", duration: 3, force_instrumental: true)
31
+ ```
32
+
33
+ **4 s sting**
34
+
35
+ ```vidscript
36
+ import eleven from "@elevenlabs/music"
37
+
38
+ [0s .. 3s] = text "▶", font: "Inter Black", size: 200, color: "#FFD23F", align: "center"
39
+ [0s .. 3s] = audio eleven.music("short upbeat logo sting, claps, bright", duration: 3, force_instrumental: true)
40
+ ```
41
+
42
+ **Bright brand cue**
43
+
44
+ ```vidscript
45
+ import eleven from "@elevenlabs/music"
46
+
47
+ [0s .. 3s] = text "UPBEAT", font: "Inter Black", size: 180, color: "#FFFFFF", align: "center"
48
+ [0s .. 3s] = audio eleven.music("uplifting corporate brand cue, claps, bright synth, optimistic", duration: 3, force_instrumental: true)
49
+ ```
50
+
@@ -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 fragment
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 `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,100 @@
1
+ # Shaders and Filters
2
+
3
+ ## Built-in filters
4
+
5
+ A `filter` line grades everything on screen during its window. Add `target: clip` (or use `clip.Filter(…)`) to grade one clip; see `editing-actions.md` → Color and finishing for which filters can target a clip, plus LUTs and CDL.
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
27
+
28
+ Native VFX through the same `filter` keyword. They work on the whole frame in their window:
29
+
30
+ ```vidscript
31
+ input clip = "clip.mp4"
32
+ [0s .. 5s] = video clip
33
+ [0s .. 2s] = filter "liquid_glass", intensity: 0.6
34
+ ```
35
+
36
+ | Filter | Reach for it when… |
37
+ | --- | --- |
38
+ | `liquid_glass` | iOS-style glass morphism over footage |
39
+ | `magnetic` | UI magnet / snap aesthetic |
40
+ | `portal` | Sci-fi portal / warp hole |
41
+ | `text_cursor` | Typing / terminal cursor overlay |
42
+
43
+ ## Custom shaders
44
+
45
+ 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:
46
+
47
+ ```vidscript
48
+ import shader glow from "./shaders/glow.glsl"
49
+
50
+ [0s .. 5s] = text "Hello"
51
+ [0s .. 5s] = shader glow, intensity: 0.8
52
+ ```
53
+
54
+ Also works with npm package paths under `node_modules`:
55
+
56
+ ```vidscript fragment
57
+ import shader glow from "shader-pack/shaders/glow.glsl"
58
+ ```
59
+
60
+ | Use | Keyword |
61
+ | --- | --- |
62
+ | Built-in / VFX from the library | `filter "name", …` |
63
+ | Your own `.glsl` file | `import shader` + `shader name, …` |
64
+
65
+ **Fragment contract** (EffectComposer post-process):
66
+
67
+ - Fragment only — the engine supplies a shared vertex shader with `vUv`
68
+ - Declare `uniform sampler2D tDiffuse` and sample it
69
+ - Write `gl_FragColor`
70
+ - VidScript params become uniforms by **exact name** (`intensity: 0.8` → `uniform float intensity`)
71
+ - Optional: declare `uniform float uTime` and/or `uniform vec2 uResolution` — the renderer injects and updates them automatically
72
+
73
+ ```glsl
74
+ uniform sampler2D tDiffuse;
75
+ uniform float intensity;
76
+ varying vec2 vUv;
77
+
78
+ void main() {
79
+ vec4 texel = texture2D(tDiffuse, vUv);
80
+ gl_FragColor = texel * (1.0 + intensity);
81
+ }
82
+ ```
83
+
84
+ The compiler reads the file at compile time and embeds the GLSL into IR (`IRShaderEffect`). Relative paths resolve against the `.vid` directory (`workingDirectory` / `assetBaseDir`).
85
+
86
+ ## Scene transitions
87
+
88
+ Scene transitions use `@scenerok/transitions` — see `transitions-catalog.md`. They blend **two** clips at window boundaries; filters grade the picture.
89
+
90
+ ```vidscript
91
+ import tr from "@scenerok/transitions"
92
+
93
+ input clip_a = "clip-a.mp4"
94
+ input clip_b = "clip-b.mp4"
95
+ [0s .. 5s] = video clip_a
96
+ [5s .. 5.6s] = tr.dissolve()
97
+ [5.6s .. 10s] = video clip_b
98
+ ```
99
+
100
+ Do not confuse `tr.dissolve()` (a blend between two clips) with `filter "vignette"` (a grade).
@@ -0,0 +1,88 @@
1
+ # Text Styles and Motion Primitives
2
+
3
+ `import motion from "@scenerok/basic-animations"` — use with `animate:` on `text` blocks.
4
+
5
+ ## Motion primitives
6
+
7
+ | Primitive | Suits | Phase |
8
+ | --- | --- | --- |
9
+ | `motion.fadeIn` | subtle entrance | entry |
10
+ | `motion.fadeOut` | ending / cut-to-black | exit |
11
+ | `motion.slideX` | horizontal reveal | entry |
12
+ | `motion.slideY` | vertical rise / fall | entry |
13
+ | `motion.popIn` | impact / hero reveal | entry |
14
+ | `motion.riseIn` | title build-up | entry |
15
+ | `motion.swingIn` | playful entrance | entry |
16
+ | `motion.glitchIn` | energetic entrance | entry |
17
+ | `motion.float` | idle ambient drift | idle |
18
+ | `motion.typewriter` | technical typing reveal | entry |
19
+
20
+ ## Examples
21
+
22
+ ### Bold hero headline
23
+
24
+ Large sans-serif with shadow and fade entrance/exit.
25
+
26
+ **Center pop** — popIn entrance on a dark canvas.
27
+
28
+ ```vidscript
29
+ import motion from "@scenerok/basic-animations"
30
+
31
+ [0s .. 3s] = text "SCENEROK", font: "Inter Black", size: 200, color: "#7CFAC7", align: "center", letter_spacing: 6, animate: [motion.popIn(0.8), motion.fadeOut(0.5)]
32
+ ```
33
+
34
+ **Bottom-anchored** — position: "bottom", motion.fadeIn + fadeOut.
35
+
36
+ ```vidscript
37
+ import motion from "@scenerok/basic-animations"
38
+
39
+ [0s .. 3s] = text "Make videos from text.", font: "Inter Bold", size: 96, color: "#FFFFFF", position: "bottom", align: "center", shadow_color: "#000000", shadow_blur: 16, x: "50%", y: -180, animate: [motion.fadeIn(0.6), motion.fadeOut(0.6)]
40
+ ```
41
+
42
+ ### Motion presets
43
+
44
+ Composable motion.fadeIn, popIn, and float descriptors.
45
+
46
+ **Fade in + out** — motion.fadeIn(0.5) + motion.fadeOut(0.5).
47
+
48
+ ```vidscript
49
+ import motion from "@scenerok/basic-animations"
50
+
51
+ [0s .. 3s] = text "FADE", font: "Inter Black", size: 220, color: "#FFFFFF", align: "center", animate: [motion.fadeIn(0.5), motion.fadeOut(0.5)]
52
+ ```
53
+
54
+ **Pop + float** — popIn(0.7) then float(2.2, 12).
55
+
56
+ ```vidscript
57
+ import motion from "@scenerok/basic-animations"
58
+
59
+ [0s .. 3s] = text "POP", font: "Inter Black", size: 220, color: "#FFD7A0", align: "center", animate: [motion.popIn(0.7), motion.float(2.2, 12)]
60
+ ```
61
+
62
+ ### Typewriter reveal
63
+
64
+ motion.typewriter() reveals characters one at a time.
65
+
66
+ **Slow sans** — Inter, white, longer typewriter duration.
67
+
68
+ ```vidscript
69
+ import motion from "@scenerok/basic-animations"
70
+
71
+ [0s .. 3s] = text "Type. Render. Ship.", font: "Inter", size: 72, color: "#FFFFFF", align: "center", animate: [motion.typewriter(1.8), motion.fadeOut(0.4)]
72
+ ```
73
+
74
+ **Mono terminal** — JetBrains Mono, mint green on black.
75
+
76
+ ```vidscript
77
+ import motion from "@scenerok/basic-animations"
78
+
79
+ [0s .. 3s] = text "build videos from text.", font: "JetBrains Mono", size: 58, color: "#7CFAC7", align: "center", animate: [motion.typewriter(1.6), motion.fadeOut(0.3)]
80
+ ```
81
+
82
+ Kinetic titles with no HyperFrames block → `text` + `animate: motion.<primitive>`.
83
+
84
+ Richer pre-built text treatments (staggered word reveals, scramble decode, kinetic
85
+ word-per-beat typography, gradient sweeps, typed quotes, count-up stats, glitch, neon) →
86
+ `animations.text_*` blocks — see the `text-anim` rows in `animations-picker.md`.
87
+ Fully custom text animation (your own HTML/CSS/GSAP) → `animations.custom_html` in
88
+ `animations-catalog.md`.
@@ -0,0 +1,57 @@
1
+ # Transitions Catalog
2
+
3
+ All `tr.<fn>(...)` scene transitions from `@scenerok/transitions`. Total: **29** shaders.
4
+
5
+ ## Binding semantics
6
+
7
+ A transition window `[Ts .. Te]` binds the clip active at **Ts** (from) and **Te** (to):
8
+
9
+ ```vidscript
10
+ import tr from "@scenerok/transitions"
11
+
12
+ input clip_a = "clip-a.mp4"
13
+ input clip_b = "clip-b.mp4"
14
+ [0s .. 5s] = video clip_a
15
+ [5s .. 5.6s] = tr.dissolve()
16
+ [5.6s .. 10s] = video clip_b
17
+ ```
18
+
19
+ Common params: `direction`, `ease`, `strength`, `mode`.
20
+
21
+ | fn | shader | defaultDuration |
22
+ | --- | --- | --- |
23
+ | `dissolve` | `dissolve` | 0.6s |
24
+ | `push` | `push` | 0.6s |
25
+ | `cover` | `cover` | 0.6s |
26
+ | `radial` | `radial` | 0.6s |
27
+ | `grid` | `grid` | 0.6s |
28
+ | `scale` | `scale` | 0.6s |
29
+ | `cube` | `cube` | 0.6s |
30
+ | `blur` | `blur` | 0.6s |
31
+ | `distortion` | `distortion` | 0.6s |
32
+ | `destruction` | `destruction` | 0.6s |
33
+ | `light` | `light` | 0.6s |
34
+ | `mechanical` | `mechanical` | 0.6s |
35
+ | `wipe` | `wipe` | 0.6s |
36
+ | `cinematic_zoom` | `cinematic_zoom` | 0.6s |
37
+ | `whip_pan` | `whip_pan` | 0.6s |
38
+ | `light_leak` | `light_leak` | 0.6s |
39
+ | `flash` | `flash` | 0.6s |
40
+ | `warp_morph` | `warp_morph` | 0.6s |
41
+ | `domain_warp` | `domain_warp` | 0.6s |
42
+ | `chromatic_split` | `chromatic_split` | 0.6s |
43
+ | `lens` | `lens` | 0.6s |
44
+ | `glitch` | `glitch` | 0.6s |
45
+ | `swirl` | `swirl` | 0.6s |
46
+ | `thermal` | `thermal` | 0.6s |
47
+ | `ripple` | `ripple` | 0.6s |
48
+ | `iris` | `iris` | 0.6s |
49
+ | `burn` | `burn` | 0.6s |
50
+ | `shatter` | `shatter` | 0.6s |
51
+ | `liquid` | `liquid` | 0.6s |
52
+
53
+ ## VFX filters (single-clip)
54
+
55
+ See `shaders-filters.md` for `filter "liquid_glass"`, `magnetic`, `portal`, `text_cursor`.
56
+
57
+ Preview: https://scenerok.com/catalog#transitions
@@ -0,0 +1,64 @@
1
+ # Text-to-Speech
2
+
3
+ `import xai from "@scenerok/xai"` — voiceover via `audio xai.tts(...)`.
4
+
5
+ Voice IDs: `eve` (upbeat), `ara` (warm), `rex` (business), `sal` (balanced), `leo` (authoritative).
6
+ ```vidscript
7
+ import xai from "@scenerok/xai"
8
+ let vo = xai.tts("Welcome to SceneRok", voice: "eve")
9
+ [0 .. vo.duration] = audio vo
10
+ ```
11
+
12
+ **Never guess a TTS window.** You cannot know the audio length while writing the script. Either assign with `let` and use `vo.duration` in time expressions (measured from the generated file), or use `[-] = audio xai.tts(...)` blocks, which auto-size and never overlap each other. Guessed ranges like `[0s .. 3s] = audio xai.tts("long sentence...")` clip or collide when the real audio runs longer.
13
+
14
+ Chain multiple lines with symbolic arithmetic:
15
+
16
+ ```vidscript
17
+ import xai from "@scenerok/xai"
18
+ let vo1 = xai.tts("First line", voice: "eve")
19
+ let vo2 = xai.tts("Second line", voice: "eve")
20
+ [0 .. vo1.duration] = audio vo1
21
+ [vo1.duration + 0.3 .. vo1.duration + 0.3 + vo2.duration] = audio vo2
22
+ [0 .. vo1.duration] = text "First headline", area: "title" # visual spans the narration
23
+ ```
24
+
25
+ ## Examples
26
+
27
+ Catalog samples below use fixed example windows; in real scripts prefer `vo.duration` or `[-]` blocks as shown above.
28
+
29
+ **Leo — launch** — Product launch energy.
30
+
31
+ ```vidscript
32
+ import xai from "@scenerok/xai"
33
+
34
+ [0s .. 3s] = text "GO.", font: "Inter Black", size: 240, color: "#FF3B3B", align: "center"
35
+ [0s .. 3s] = audio xai.tts("Ship it. Right now.", voice: "leo")
36
+ ```
37
+
38
+ **Rex — countdown** — Punchy three-beat hook.
39
+
40
+ ```vidscript
41
+ import xai from "@scenerok/xai"
42
+
43
+ [0s .. 3s] = text "Drop it.", font: "Inter Black", size: 198, color: "#FFD23F", align: "center"
44
+ [0s .. 3s] = audio xai.tts("Three. Two. One. Drop it.", voice: "rex")
45
+ ```
46
+
47
+ **Ara — short line** — Single sentence under a headline.
48
+
49
+ ```vidscript
50
+ import xai from "@scenerok/xai"
51
+
52
+ [0s .. 3s] = text "Listen.", font: "Inter", size: 120, color: "#9FB6FF", align: "center"
53
+ [0s .. 3s] = audio xai.tts("One line of voice-over, baked into the mix.", voice: "ara")
54
+ ```
55
+
56
+ **Eve — narrative** — Long-form explanatory copy.
57
+
58
+ ```vidscript
59
+ import xai from "@scenerok/xai"
60
+
61
+ [0s .. 3s] = text "Voice from text.", font: "Inter Bold", size: 64, color: "#FFFFFF", align: "center"
62
+ [0s .. 3s] = audio xai.tts("Vidscript turns plain text into a fully rendered video. No timeline editing required.", voice: "eve")
63
+ ```
64
+