yamlreel 0.2.1__tar.gz

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.
yamlreel-0.2.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nitin Sijwali
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,352 @@
1
+ Metadata-Version: 2.4
2
+ Name: yamlreel
3
+ Version: 0.2.1
4
+ Summary: Spec-driven generator for short project, system-design and demo videos (YouTube, Shorts, LinkedIn).
5
+ Author: Nitin Sijwali
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nsijwali/yamlreel
8
+ Project-URL: Repository, https://github.com/nsijwali/yamlreel
9
+ Project-URL: Issues, https://github.com/nsijwali/yamlreel/issues
10
+ Project-URL: Changelog, https://github.com/nsijwali/yamlreel/releases
11
+ Keywords: text-to-video,video-generation,youtube-shorts,explainer-video,system-design,yaml,ffmpeg,voiceover,tts,manim-alternative
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Education
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Multimedia :: Video
22
+ Classifier: Topic :: Multimedia :: Graphics :: Presentation
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: pillow>=10
27
+ Requires-Dist: numpy>=1.24
28
+ Requires-Dist: pyyaml>=6
29
+ Provides-Extra: capture
30
+ Requires-Dist: playwright>=1.40; extra == "capture"
31
+ Provides-Extra: ffmpeg
32
+ Requires-Dist: imageio-ffmpeg>=0.5; extra == "ffmpeg"
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ <div align="center">
38
+
39
+ # yamlreel
40
+
41
+ **Write a short YAML file. Get a finished video.**
42
+
43
+ yamlreel turns a YAML file into a finished video: system-design explainers, code tips, project launches and
44
+ feature demos for YouTube, Shorts and LinkedIn, with diagrams, typed code, original music and an optional
45
+ voiceover in your own voice.
46
+
47
+ [![ci](https://github.com/nsijwali/yamlreel/actions/workflows/ci.yml/badge.svg)](https://github.com/nsijwali/yamlreel/actions/workflows/ci.yml)
48
+ ![python](https://img.shields.io/badge/python-3.10%2B-blue)
49
+ ![license](https://img.shields.io/badge/license-MIT-green)
50
+
51
+ <img src="https://raw.githubusercontent.com/nsijwali/yamlreel/main/docs/demo.gif" alt="A diagram building itself: a YAML spec and VoiceStudio feed yamlreel, which hands frames and audio to ffmpeg to produce the video" width="720">
52
+
53
+ **▶ [Watch the 1-minute demo](https://github.com/nsijwali/yamlreel/releases/tag/v0.2.0)**: a video about yamlreel, made by yamlreel from one YAML file, with no video editor.
54
+
55
+ <img src="https://raw.githubusercontent.com/nsijwali/yamlreel/main/docs/preview.jpg" alt="Contact sheet of a rendered video: a typed hook, a cache diagram, bullet lists, highlighted code, a big stat and an end card" width="820">
56
+
57
+ <sub>Every scene of <a href="https://github.com/nsijwali/yamlreel/blob/main/examples/cache-stampede-45s.yaml">examples/cache-stampede-45s.yaml</a>, rendered from one YAML file.</sub>
58
+
59
+ </div>
60
+
61
+ ---
62
+
63
+ ## What you get
64
+
65
+ Every render writes this layout (the output folder is `yamlreel-output/` unless you pass `--out DIR`):
66
+
67
+ ```
68
+ yamlreel-output/
69
+ ├── vertical/ one folder per format: landscape 1920×1080, vertical 1080×1920, square 1080×1080
70
+ │ ├── video.mp4 H.264 (+ AAC when there is music or a voice). Frame 0 is the poster, so the thumbnail is never blank.
71
+ │ ├── poster.jpg the settled hook frame, ready to upload as a thumbnail
72
+ │ └── contact.png two labelled stills per scene: look at this before you publish
73
+ └── share-copy.txt title, description and hashtags for the whole video, ready to paste
74
+ ```
75
+
76
+ `share-copy.txt` adds `#Shorts` for vertical clips up to 60 seconds. Videos can be any length, and only a
77
+ vertical video over 3 minutes gets a warning. Music is generated on your machine (plucked strings in a
78
+ Japanese scale), so there is nothing to license or credit.
79
+
80
+ ## Quick start
81
+
82
+ You need **Python 3.10 or newer**. pip installs everything else except fonts on macOS and Windows (see the note below).
83
+
84
+ ```bash
85
+ python3 -m venv .venv && source .venv/bin/activate
86
+ pip install "yamlreel[ffmpeg]"
87
+ ```
88
+
89
+ Prefer an isolated command-line install? `pipx install "yamlreel[ffmpeg]"` works too. (The `vidgen` package on
90
+ PyPI is unrelated to this project, which was called vidgen before 0.2.)
91
+
92
+ Make your first video:
93
+
94
+ ```bash
95
+ yamlreel init system-design my-video.yaml # a starter spec (or: project, code-tip)
96
+ yamlreel render my-video.yaml --preview # half size, 12 fps: check layout and timing in seconds
97
+ yamlreel render my-video.yaml # full quality, every format in the spec
98
+ ```
99
+
100
+ Open `yamlreel-output/<format>/contact.png` first. To try the showcased example without setting up a voice:
101
+
102
+ ```bash
103
+ curl -LO https://raw.githubusercontent.com/nsijwali/yamlreel/main/examples/cache-stampede-45s.yaml
104
+ yamlreel render cache-stampede-45s.yaml --no-voice
105
+ ```
106
+
107
+ > **Fonts on macOS and Windows:** yamlreel draws text with the free DejaVu fonts, which most Linux systems
108
+ > include. On macOS run `brew install --cask font-dejavu` once. On Windows, install them from
109
+ > [dejavu-fonts.github.io](https://dejavu-fonts.github.io) ("Install for me" is fine).
110
+
111
+ <details>
112
+ <summary><b>Install details for each system</b></summary>
113
+
114
+ <br>
115
+
116
+ | | macOS | Linux | Windows (PowerShell) |
117
+ | --- | --- | --- | --- |
118
+ | Python 3.10+ | `brew install python@3.12` or [python.org](https://www.python.org/downloads/) | usually installed; Debian/Ubuntu also need `python3-venv` | [python.org](https://www.python.org/downloads/), then use `py` instead of `python3` |
119
+ | Activate the venv | `source .venv/bin/activate` | same | `.venv\Scripts\Activate.ps1` (if scripts are blocked: `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`) |
120
+ | ffmpeg | the `[ffmpeg]` extra (or `brew install ffmpeg`) | the extra, or `sudo apt install ffmpeg`. On Fedora use the extra: its own `ffmpeg-free` cannot encode H.264 | the `[ffmpeg]` extra |
121
+ | Fonts | `brew install --cask font-dejavu` | Debian/Ubuntu: `sudo apt install fonts-dejavu-core`; Fedora: `sudo dnf install dejavu-sans-fonts dejavu-serif-fonts dejavu-sans-mono-fonts`; Arch: `sudo pacman -S ttf-dejavu` | DejaVu from [dejavu-fonts.github.io](https://dejavu-fonts.github.io) |
122
+ | Web captures (optional) | `pip install "yamlreel[capture]"` then `playwright install chromium` | same | same |
123
+
124
+ - **ffmpeg:** yamlreel uses the `ffmpeg` on your PATH if there is one, and otherwise the copy that the `[ffmpeg]` extra (the `imageio-ffmpeg` package) brings along. You only need one of them.
125
+ - **Fonts:** yamlreel looks in your `font_dir` setting (or `YAMLREEL_FONT_DIR`) first, then the system font folders, then your own (`~/Library/Fonts` on macOS, `%LOCALAPPDATA%\Microsoft\Windows\Fonts` on Windows). If your fonts live anywhere else, point `font_dir` at that folder. Japanese text uses Noto CJK when it is installed.
126
+ - **Web captures** are only needed for `shot` scenes that screenshot a URL. `chromium_path` in your user config (or `YAMLREEL_CHROMIUM`) picks a different browser.
127
+ - **Windows** is not covered by CI yet. Reports are welcome.
128
+
129
+ </details>
130
+
131
+ ## Examples
132
+
133
+ | Spec | What it is |
134
+ | --- | --- |
135
+ | [`examples/cache-stampede-45s.yaml`](https://github.com/nsijwali/yamlreel/blob/main/examples/cache-stampede-45s.yaml) | A 45-second system-design explainer with a diagram, code and a narrated script. |
136
+
137
+ It is narrated; add `--no-voice` to render it with music only. For more starting points, run
138
+ `yamlreel init` with the `system-design`, `project` or `code-tip` template.
139
+
140
+ ## Commands
141
+
142
+ | Command | What it does |
143
+ | --- | --- |
144
+ | `yamlreel init <template> <file>` | Writes a starter spec: `system-design`, `project` or `code-tip`. |
145
+ | `yamlreel validate <spec>` | Checks a spec and prints its scene count and length, without rendering. |
146
+ | `yamlreel render <spec>` | Renders. Useful flags: `--preview`, `--out DIR`, `--format vertical\|landscape\|square\|all`, `--music koto\|none\|file.mp3`, `--fps N`, `--no-voice`, `--voice-url URL`, `--read-screen`, `--allow-path DIR`, `--allow-private-hosts`. |
147
+ | `yamlreel config init [--user]` / `config show` | Writes a starter config, or shows the merged settings and the files they came from. |
148
+ | `yamlreel music --seconds 30 --out track.wav` | Generates the music track on its own (`--bpm`, `--root`, `--scale`, `--seed`). |
149
+
150
+ ## Writing a spec
151
+
152
+ A spec is a list of scenes. Each scene has a `type`, how many `seconds` it lasts, and an optional `caption`
153
+ (a lower third that fades in).
154
+
155
+ ```yaml
156
+ meta: {title: "Cache stampede in 45 seconds", tags: [systemdesign, caching]}
157
+ theme: midnight # sumi | washi | midnight | your own
158
+ formats: [vertical, landscape]
159
+ scenes:
160
+ - type: type
161
+ text: What is a cache stampede?
162
+ seconds: 3
163
+ - type: bullets
164
+ title: The fix
165
+ items: [Let one request rebuild the key, Serve stale while it refreshes, Add jitter to every TTL]
166
+ - type: stat
167
+ value: "10,000 → 1"
168
+ label: database queries per expiry
169
+ ```
170
+
171
+ | Scene | Shows | Main fields |
172
+ | --- | --- | --- |
173
+ | `title` | eyebrow, title, subtitle and URL, easing in line by line | `title`, `eyebrow`, `subtitle`, `url` |
174
+ | `type` | one line typed out with a cursor: your hook | `text` |
175
+ | `bullets` | points that appear one at a time | `title`, `items` |
176
+ | `code` | code typed on screen, with highlighted lines | `code`, `highlight`, `title` |
177
+ | `stat` | one big number or phrase | `value`, `label`, `eyebrow` |
178
+ | `diagram` | boxes and arrows that appear in order, packets flowing, nodes flashing | `nodes`, `edges`, `flash`, `title` |
179
+ | `shot` | a screenshot of a URL or an image, with a slow camera move | `source`, `zoom`, `focus`, `fit`, `click`, `scroll_y` |
180
+
181
+ <details>
182
+ <summary><b>All spec options</b></summary>
183
+
184
+ <br>
185
+
186
+ ```yaml
187
+ meta: {title, description, tags: [], links: [], credits: []}
188
+ theme: sumi | washi | midnight | <a theme from your config>
189
+ formats: [vertical, landscape, square]
190
+ music: {style: koto | none | path/to.mp3, bpm: 72, root: D, scale: hirajoshi, seed: 7, snap: false, volume: 0.9}
191
+ watermark: "Your Name" # or {text|image: logo.png, position: top-left|top-right|bottom-left|bottom-right, opacity: 0.75, size: 30}
192
+ poster: {scene: 0, at: 2.6} # optional; default is the first scene, just before it ends
193
+ voiceover: {voice, language, gap, music_level, read_screen}
194
+ scenes: [...]
195
+ ```
196
+
197
+ - **Diagrams:** `nodes` take `id, label, kind (client|service|cache|db), x, y, at`, where `x` and `y` are fractions of the frame. `vx, vy` override them in vertical frames, so one diagram fits both shapes. `edges` take `from, to, label, bad, dashed, at, color` and `flash` takes `node, at, text, color`.
198
+ - **Shots:** `source` (URL or image), `fit: cover | card`, `zoom: [from, to]`, `focus: [x, y]`, `focus_to`, `click: [selectors]`, `scroll_y`, `wait_ms`, `viewport`, `scale`. Screenshots are cached in `<output folder>/.cache`; delete it to capture again.
199
+ - **Files:** images, pages, music and logos must sit in the spec's folder, a config folder, or a folder you allow with `--allow-path DIR` (or `allow_paths` in your user config).
200
+ - **Music:** `seed` changes the melody and `snap: true` rounds scene lengths to beats. To use your own track, point `style` at an audio file and credit it in `meta.credits`.
201
+ - **Watermark:** appears on every frame and the poster. The default corner is bottom-right for landscape and top-left for vertical, because the Shorts buttons cover the right edge and the bottom.
202
+
203
+ </details>
204
+
205
+ **Tips**
206
+ - Text never silently overflows. It wraps, then shrinks, and `render` warns you when it had to.
207
+ - In vertical frames, content sits above the lower third, clear of the Shorts UI.
208
+ - A 15-second video carries one idea. Before you publish, check anything you simplified.
209
+
210
+ ## Voiceover in your own voice
211
+
212
+ Give a scene a `narration:` line and yamlreel speaks it, lowers the music under the voice, and makes the scene as
213
+ long as the speech needs. Speech comes from a text-to-speech server running **on your own machine**, for example
214
+ [VoiceStudio](https://github.com/debpalash/VoiceStudio), which can also clone your voice from a short recording.
215
+
216
+ ```yaml
217
+ scenes:
218
+ - type: type
219
+ text: What is a cache stampede?
220
+ narration: Ever seen one expired cache key take down a whole database? That's a cache stampede.
221
+ - type: title
222
+ title: Cache stampede
223
+ narration: false # silent end card
224
+ ```
225
+
226
+ > **Write narration, don't read the screen.** The voice sounds natural when it *explains* what the viewer sees,
227
+ > in a sentence or two. `read_screen: true` (or `--read-screen`) speaks every title, bullet and caption word
228
+ > for word, for scenes without their own `narration:`. That is fine as a quick draft, but it sounds robotic in a
229
+ > finished video. `--no-voice` renders any spec with music only.
230
+
231
+ <details>
232
+ <summary><b>Set up VoiceStudio, step by step</b></summary>
233
+
234
+ <br>
235
+
236
+ 1. **Install and open VoiceStudio.** Use the [desktop app](https://github.com/debpalash/VoiceStudio/releases/latest)
237
+ (easiest), or run it from source (`uv sync`, then `uv run uvicorn main:app --app-dir backend --port 3900`).
238
+ Its speech server listens on `http://127.0.0.1:3900/mcp/` while it is running.
239
+ 2. **Accept the model licences.** Open *Model Catalogue* and accept the terms for **OmniVoice** and its audio
240
+ tokenizer. Until you do, every request fails with `403 Forbidden`. The first request also downloads the
241
+ model (about 2.3 GB).
242
+ 3. **(Optional) Clone your voice.** In *Voice cloning*, add a 5 to 10 second recording of yourself in a quiet
243
+ room, with its exact transcript. Copy the voice's **profile id**.
244
+ 4. **Tell yamlreel where the server is, once.** Run `yamlreel config init --user` and open
245
+ `~/.config/yamlreel/config.yaml`. At the bottom, uncomment `voice_server:` and its `url:` line. Under the
246
+ existing `voiceover:` block, uncomment `voice:` and paste your profile id there (leave it out to use the
247
+ server's default voice). You can also pass `--voice-url http://127.0.0.1:3900/mcp/` on each render.
248
+
249
+ Prefer to record yourself? Use `narration_audio: clip.wav` (PCM WAV, inside the spec folder or an allowed
250
+ folder) instead of `narration:`.
251
+
252
+ </details>
253
+
254
+ <details>
255
+ <summary><b>How voiceover works: other servers, privacy, caching</b></summary>
256
+
257
+ <br>
258
+
259
+ - **Any compatible server works.** yamlreel speaks MCP "Streamable HTTP" and calls the server's `generate_speech` tool, which must return the audio inline (VoiceStudio's default). VoiceStudio is just one server that does this.
260
+ - **Privacy:** narration text is sent only to the server you configured. A spec cannot choose the server: the address comes only from your user config or the command line.
261
+ - **Precedence:** a scene's own `narration:` wins over `read_screen`, and `narration: false` keeps a scene silent.
262
+ - **Caching:** audio is cached per text and voice in `<output folder>/.cache`, so re-renders do not speak lines again. If you change the recording behind a voice, delete `<output folder>/.cache/narration-*.wav`.
263
+ - **Licences:** VoiceStudio is AGPL-3.0, and its models have their own licences, which its Model Catalogue shows per model. OmniVoice's weights are non-commercial (CC-BY-NC), and that may carry over to the speech they generate. Check before you monetise a video.
264
+
265
+ </details>
266
+
267
+ ## Configuration
268
+
269
+ Defaults live in a config file, so a spec only needs to say what is different for that video. You can adapt
270
+ yamlreel to your own name, colours and music without touching code.
271
+
272
+ ```bash
273
+ yamlreel config init # ./yamlreel.config.yaml: this project (add it to your .gitignore)
274
+ yamlreel config init --user # ~/.config/yamlreel/config.yaml: every project
275
+ yamlreel config show # the merged settings, and the files they came from
276
+ ```
277
+
278
+ Settings apply in this order, lowest to highest: **built-in defaults → user config → project config → the spec → command-line flags**.
279
+ Nested settings merge, so setting only `music.bpm` keeps the rest. `meta.tags`, `links` and `credits` add up across layers.
280
+
281
+ What you can set: `theme`, your own `themes` (colours, `extends`, `display: serif | sans`, `frame`), `formats`,
282
+ `fps`, `output_dir`, `watermark` (text or a logo), `music`, `voiceover`, `meta` defaults and `limits`. Your name,
283
+ watermark and default tags belong in config, not in code. Every option is explained in
284
+ [`yamlreel/templates/config.example.yaml`](https://github.com/nsijwali/yamlreel/blob/main/yamlreel/templates/config.example.yaml).
285
+
286
+ A few settings widen what a spec can touch, so yamlreel only reads them from your **user** config or the command
287
+ line, never from a spec or project config you downloaded: `allow_paths`, `allow_private_hosts`,
288
+ `chromium_path`, `font_dir` and `voice_server`. See [SECURITY.md](https://github.com/nsijwali/yamlreel/blob/main/SECURITY.md).
289
+
290
+ ## Troubleshooting
291
+
292
+ | You see | Fix |
293
+ | --- | --- |
294
+ | `ffmpeg not found` | `pip install "yamlreel[ffmpeg]"`, or install ffmpeg with your package manager. |
295
+ | `font 'DejaVuSans-Bold.ttf' not found` | Install DejaVu (see *Install details*), or point `font_dir` in your user config at the folder that holds them. |
296
+ | `scene 0 has narration but no voice server is configured` | Start VoiceStudio and set `voice_server` in your user config, pass `--voice-url`, or render with `--no-voice`. |
297
+ | `cannot reach the voice server … Is VoiceStudio running?` | Start VoiceStudio and check that the URL ends in `/mcp/`. |
298
+ | `Client error '403 Forbidden' for url '…/generate'` | Accept the OmniVoice and tokenizer licences in VoiceStudio's Model Catalogue. |
299
+ | `Server error '500'` from the voice server, or the server is killed | The machine is out of memory. Close other apps, and use a 5 to 10 second voice sample: a longer reference needs over 2 GB on the CPU. |
300
+ | `voice server reply had no audio` | VoiceStudio is set to `OMNIVOICE_MCP_OUTPUT_MODE=files`. yamlreel needs the default inline mode. |
301
+ | `capturing a URL needs playwright` | `pip install "yamlreel[capture]"`, then `playwright install chromium`. |
302
+ | `could not capture … Executable doesn't exist` | Run `playwright install chromium`, or set `chromium_path` in your user config. |
303
+ | `… outside the folders this run may read` | Move the file next to your spec, or pass `--allow-path DIR`. For localhost pages, add `--allow-private-hosts`. |
304
+ | A narration line still uses an old voice | Delete `<output folder>/.cache/narration-*.wav`. |
305
+ | Homebrew fails to build ffmpeg or Python | Older macOS versions get no prebuilt packages. Use the `[ffmpeg]` extra for ffmpeg, and [python.org](https://www.python.org/downloads/) or `uv` for Python. |
306
+
307
+ ## Built with
308
+
309
+ | | Used for |
310
+ | --- | --- |
311
+ | [Pillow](https://python-pillow.org), [NumPy](https://numpy.org), [PyYAML](https://pyyaml.org) | drawing every frame, generating the music, reading specs |
312
+ | [FFmpeg](https://ffmpeg.org) (or [imageio-ffmpeg](https://github.com/imageio/imageio-ffmpeg)) | encoding the video |
313
+ | [Playwright](https://playwright.dev/python/) | capturing web pages for `shot` scenes (optional) |
314
+ | [DejaVu fonts](https://dejavu-fonts.github.io) | all on-screen text |
315
+ | [VoiceStudio](https://github.com/debpalash/VoiceStudio) with [OmniVoice](https://huggingface.co/k2-fsa/OmniVoice) | the optional local voiceover, including voice cloning (not bundled) |
316
+ | [Claude Code](https://claude.com/claude-code) | building, testing and reviewing yamlreel |
317
+
318
+ If you publish a video voiced with OmniVoice, credit it and keep it non-commercial: its licence (CC-BY-NC)
319
+ requires both, and VoiceStudio's audio tokenizer has its own terms (see *Licences* above). yamlreel puts a
320
+ spec's `meta.credits` into `share-copy.txt` for you.
321
+
322
+ ## Why yamlreel
323
+
324
+ - **Manim** is excellent for math animation, but each animation is code you write. yamlreel is a spec: you describe scenes, not frames.
325
+ - **Remotion** renders video from React and is very flexible. yamlreel trades that flexibility for zero JavaScript and a fixed set of scene types.
326
+ - **MoviePy** edits and composes video clips you already have. yamlreel generates frames and music itself and adds an optional voiceover.
327
+ - **Online AI video tools** are quick but run in the cloud, usually cost money, and your script and voice leave your machine. yamlreel runs locally and is MIT licensed.
328
+
329
+ ## Contributing
330
+
331
+ Bug reports, new scene types, examples and docs are welcome. See [CONTRIBUTING.md](https://github.com/nsijwali/yamlreel/blob/main/CONTRIBUTING.md)
332
+ for setup and the pull request flow.
333
+
334
+ ## Development
335
+
336
+ ```bash
337
+ git clone https://github.com/nsijwali/yamlreel.git
338
+ cd yamlreel
339
+ python3 -m venv .venv && source .venv/bin/activate
340
+ pip install -e '.[dev,ffmpeg]'
341
+ pytest -q
342
+ ```
343
+
344
+ Tests never read your own user or project config. Checks that need `ffprobe`, Playwright or Chromium are skipped
345
+ when those tools are missing. CI runs on Ubuntu with Python 3.10 and 3.12.
346
+
347
+ ## Security and licence
348
+
349
+ Specs are treated as untrusted input. File access is confined, URL captures are checked, and settings that widen
350
+ access come only from you. [SECURITY.md](https://github.com/nsijwali/yamlreel/blob/main/SECURITY.md) covers the details and how to report a vulnerability.
351
+
352
+ yamlreel is [MIT licensed](https://github.com/nsijwali/yamlreel/blob/main/LICENSE). Tools you pair it with keep their own licences.