screenkit 0.0.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.
- checksums.yaml +7 -0
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +4 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ruby-tests.yml +51 -0
- data/.gitignore +12 -0
- data/.rubocop.yml +14 -0
- data/CHANGELOG.md +16 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +80 -0
- data/DOCUMENTATION.md +972 -0
- data/Gemfile +5 -0
- data/LICENSE.md +20 -0
- data/README.md +49 -0
- data/Rakefile +15 -0
- data/bin/console +16 -0
- data/bin/setup +10 -0
- data/exe/screenkit +5 -0
- data/lib/screen_kit.rb +79 -0
- data/lib/screenkit/anchor.rb +19 -0
- data/lib/screenkit/animation_filters.rb +114 -0
- data/lib/screenkit/banner.rb +46 -0
- data/lib/screenkit/callout/styles/base.rb +101 -0
- data/lib/screenkit/callout/styles/default.rb +144 -0
- data/lib/screenkit/callout/styles/inline_block.rb +123 -0
- data/lib/screenkit/callout/text_style.rb +44 -0
- data/lib/screenkit/callout.rb +98 -0
- data/lib/screenkit/cli/base.rb +24 -0
- data/lib/screenkit/cli/episode.rb +78 -0
- data/lib/screenkit/cli/root.rb +73 -0
- data/lib/screenkit/cli.rb +9 -0
- data/lib/screenkit/config/base.rb +51 -0
- data/lib/screenkit/config/episode.rb +42 -0
- data/lib/screenkit/config/project.rb +47 -0
- data/lib/screenkit/content_type.rb +12 -0
- data/lib/screenkit/core_ext/json.rb +47 -0
- data/lib/screenkit/core_ext/string.rb +28 -0
- data/lib/screenkit/exporter/demotape.rb +26 -0
- data/lib/screenkit/exporter/episode.rb +565 -0
- data/lib/screenkit/exporter/image.rb +31 -0
- data/lib/screenkit/exporter/intro.rb +261 -0
- data/lib/screenkit/exporter/outro.rb +183 -0
- data/lib/screenkit/exporter/segment.rb +258 -0
- data/lib/screenkit/exporter/video.rb +33 -0
- data/lib/screenkit/generators/episode/config.yml.erb +106 -0
- data/lib/screenkit/generators/episode/content/001.tape +4 -0
- data/lib/screenkit/generators/episode/scripts/001.txt +1 -0
- data/lib/screenkit/generators/episode.rb +31 -0
- data/lib/screenkit/generators/project/Gemfile.erb +7 -0
- data/lib/screenkit/generators/project/resources/backtracks/default.aac +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OFL.txt +93 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-Bold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-BoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-ExtraBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-ExtraBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-Italic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-Light.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-LightItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-Medium.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-MediumItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-Regular.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-SemiBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans-SemiBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-Bold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-BoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-ExtraBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-Italic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-Light.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-LightItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-Medium.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-MediumItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-Regular.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-SemiBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-Bold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-Italic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-Light.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-Medium.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-Regular.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
- data/lib/screenkit/generators/project/resources/fonts/opensans/README.txt +100 -0
- data/lib/screenkit/generators/project/resources/images/logo.png +0 -0
- data/lib/screenkit/generators/project/resources/images/watermark.png +0 -0
- data/lib/screenkit/generators/project/resources/sounds/chime.mp3 +0 -0
- data/lib/screenkit/generators/project/resources/sounds/pop.mp3 +0 -0
- data/lib/screenkit/generators/project/resources/sounds/whoosh.mp3 +0 -0
- data/lib/screenkit/generators/project/screenkit.yml +189 -0
- data/lib/screenkit/generators/project.rb +34 -0
- data/lib/screenkit/logfile.rb +33 -0
- data/lib/screenkit/parallel_processor.rb +50 -0
- data/lib/screenkit/path_lookup.rb +27 -0
- data/lib/screenkit/resources/mute.mp3 +0 -0
- data/lib/screenkit/resources/transparent.png +0 -0
- data/lib/screenkit/schema_validator.rb +14 -0
- data/lib/screenkit/schemas/callouts/default.json +44 -0
- data/lib/screenkit/schemas/callouts/inline_block.json +20 -0
- data/lib/screenkit/schemas/episode.json +74 -0
- data/lib/screenkit/schemas/project.json +37 -0
- data/lib/screenkit/schemas/refs/anchor.json +17 -0
- data/lib/screenkit/schemas/refs/animation.json +7 -0
- data/lib/screenkit/schemas/refs/background.json +14 -0
- data/lib/screenkit/schemas/refs/callout.json +27 -0
- data/lib/screenkit/schemas/refs/color.json +7 -0
- data/lib/screenkit/schemas/refs/directory.json +20 -0
- data/lib/screenkit/schemas/refs/intro.json +30 -0
- data/lib/screenkit/schemas/refs/logo.json +26 -0
- data/lib/screenkit/schemas/refs/outro.json +26 -0
- data/lib/screenkit/schemas/refs/position.json +38 -0
- data/lib/screenkit/schemas/refs/scenes.json +27 -0
- data/lib/screenkit/schemas/refs/size.json +19 -0
- data/lib/screenkit/schemas/refs/sound.json +36 -0
- data/lib/screenkit/schemas/refs/spacing.json +22 -0
- data/lib/screenkit/schemas/refs/text_style.json +18 -0
- data/lib/screenkit/schemas/refs/transition.json +15 -0
- data/lib/screenkit/schemas/refs/tts.json +47 -0
- data/lib/screenkit/schemas/refs/watermark.json +18 -0
- data/lib/screenkit/schemas/tts/elevenlabs.json +67 -0
- data/lib/screenkit/schemas/tts/say.json +16 -0
- data/lib/screenkit/shell.rb +58 -0
- data/lib/screenkit/sound.rb +44 -0
- data/lib/screenkit/spacing.rb +23 -0
- data/lib/screenkit/spinner.rb +39 -0
- data/lib/screenkit/transition.rb +16 -0
- data/lib/screenkit/tts/eleven_labs.rb +51 -0
- data/lib/screenkit/tts/say.rb +31 -0
- data/lib/screenkit/utils.rb +87 -0
- data/lib/screenkit/version.rb +5 -0
- data/lib/screenkit/watermark.rb +34 -0
- data/lib/screenkit.rb +3 -0
- data/screenkit.gemspec +56 -0
- metadata +426 -0
data/DOCUMENTATION.md
ADDED
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
# ScreenKit Documentation
|
|
2
|
+
|
|
3
|
+
**Terminal to screencast, simplified**
|
|
4
|
+
|
|
5
|
+
ScreenKit is a Ruby-based tool for creating professional screencasts from
|
|
6
|
+
terminal recordings. It automates the process of combining intro/outro scenes,
|
|
7
|
+
terminal recordings (via [demotapes](https://github.com/fnando/demotape)),
|
|
8
|
+
voiceovers, background music, callouts (lower thirds), and watermarks into
|
|
9
|
+
polished video content.
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Quick Start](#quick-start)
|
|
15
|
+
- [CLI Commands](#cli-commands)
|
|
16
|
+
- [Project Configuration](#project-configuration)
|
|
17
|
+
- [Episode Configuration](#episode-configuration)
|
|
18
|
+
- [Scenes](#scenes)
|
|
19
|
+
- [Callouts](#callouts)
|
|
20
|
+
- [Text-to-Speech (TTS)](#text-to-speech-tts)
|
|
21
|
+
- [Animations](#animations)
|
|
22
|
+
- [File Structure](#file-structure)
|
|
23
|
+
- [Advanced Features](#advanced-features)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
gem install screenkit
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or add to your Gemfile:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
gem "screenkit"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### 1. Create a New Project
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
screenkit new my-screencast
|
|
47
|
+
cd my-screencast
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This generates:
|
|
51
|
+
|
|
52
|
+
- `screenkit.yml` - Project configuration
|
|
53
|
+
- `episodes/` - Directory for episodes
|
|
54
|
+
- `resources/` - Images, sounds, fonts, etc.
|
|
55
|
+
- `output/` - Generated videos
|
|
56
|
+
|
|
57
|
+
### 2. Create a New Episode
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
screenkit episode new --title "My First Episode"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This creates an episode directory with:
|
|
64
|
+
|
|
65
|
+
- `config.yml` - Episode configuration
|
|
66
|
+
- `content/` - Terminal recording files (`.tape` files)
|
|
67
|
+
- `scripts/` - Voiceover scripts (`.txt` files)
|
|
68
|
+
- `voiceovers/` - Generated voiceover audio
|
|
69
|
+
- `resources/` - Episode-specific resources
|
|
70
|
+
|
|
71
|
+
### 3. Export the Episode
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
screenkit episode export --dir episodes/001-my-first-episode
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The final video is saved to the `output/` directory.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## CLI Commands
|
|
82
|
+
|
|
83
|
+
### Root Commands
|
|
84
|
+
|
|
85
|
+
#### `screenkit new PATH`
|
|
86
|
+
|
|
87
|
+
Create a new ScreenKit project at the specified path.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
screenkit new my-project
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### `screenkit callout`
|
|
94
|
+
|
|
95
|
+
Generate a standalone callout PNG for testing.
|
|
96
|
+
|
|
97
|
+
**Options:**
|
|
98
|
+
|
|
99
|
+
- `--type` (required) - Callout type (e.g., `info`, `warning`)
|
|
100
|
+
- `--title` (required) - Callout title text
|
|
101
|
+
- `--body` (required) - Callout body text
|
|
102
|
+
- `--output` - Output path for PNG (optional)
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
screenkit callout --type info --title "Note" --body "This is important" --output callout.png
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Episode Commands
|
|
109
|
+
|
|
110
|
+
#### `screenkit episode new`
|
|
111
|
+
|
|
112
|
+
Create a new episode.
|
|
113
|
+
|
|
114
|
+
**Options:**
|
|
115
|
+
|
|
116
|
+
- `--title` (required) - Episode title
|
|
117
|
+
- `--config` - Path to project config file (default: `screenkit.yml`)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
screenkit episode new --title "Getting Started with Ruby"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `screenkit episode export`
|
|
124
|
+
|
|
125
|
+
Export an episode to video.
|
|
126
|
+
|
|
127
|
+
**Options:**
|
|
128
|
+
|
|
129
|
+
- `--dir` (required) - Episode directory path
|
|
130
|
+
- `--voice-api-key` - API key for TTS service (e.g., ElevenLabs)
|
|
131
|
+
- `--overwrite` - Overwrite existing exported files (default: `false`)
|
|
132
|
+
- `--match-segment` - Only export segments matching this string
|
|
133
|
+
- `--output-dir` - Custom output directory path
|
|
134
|
+
- `--banner` - Display ScreenKit banner (default: `true`)
|
|
135
|
+
- `--require` - Additional Ruby files to require (can be used multiple times)
|
|
136
|
+
- `--config` - Path to project config file (default: `screenkit.yml`)
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
screenkit episode export --dir episodes/001-getting-started
|
|
140
|
+
screenkit episode export --dir episodes/001-getting-started --overwrite
|
|
141
|
+
screenkit episode export --dir episodes/001-getting-started --match-segment "002"
|
|
142
|
+
|
|
143
|
+
# Load custom TTS engines or callout styles
|
|
144
|
+
screenkit episode export --dir episodes/001-getting-started --require ./lib/custom_tts.rb
|
|
145
|
+
screenkit episode export --dir episodes/001-getting-started --require ./lib/custom_tts.rb --require ./lib/custom_callout.rb
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Project Configuration
|
|
151
|
+
|
|
152
|
+
The `screenkit.yml` file defines project-wide settings.
|
|
153
|
+
|
|
154
|
+
### Schema
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
schema: 1 # Required: Schema version (currently 1)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Directory Structure
|
|
161
|
+
|
|
162
|
+
```yaml
|
|
163
|
+
# Episode directory naming pattern
|
|
164
|
+
# Supports placeholders: %{episode_number}, %{episode_slug}, %{date}
|
|
165
|
+
# Use %<episode_number>03d for padded numbers (e.g., 001)
|
|
166
|
+
episode_dir: episodes/%<episode_number>03d-%{episode_slug}
|
|
167
|
+
|
|
168
|
+
# Output directory for generated videos
|
|
169
|
+
# Supports placeholder: %{episode_dirname}
|
|
170
|
+
output_dir: output/%{episode_dirname}
|
|
171
|
+
|
|
172
|
+
# Resource directories (searched in order)
|
|
173
|
+
resources_dir:
|
|
174
|
+
- .
|
|
175
|
+
- "%{episode_dir}"
|
|
176
|
+
- resources
|
|
177
|
+
- "%{episode_dir}/resources"
|
|
178
|
+
- ~/Library/Fonts
|
|
179
|
+
- /usr/share/fonts
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Background Music
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
# String: Path to specific backtrack file
|
|
186
|
+
backtrack: resources/music/background.mp3
|
|
187
|
+
|
|
188
|
+
# String: Directory - random file selected
|
|
189
|
+
backtrack: backtracks/
|
|
190
|
+
|
|
191
|
+
# Boolean: Disable backtrack
|
|
192
|
+
backtrack: false
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Watermark
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
# Simple string path
|
|
199
|
+
watermark: watermark.png
|
|
200
|
+
|
|
201
|
+
# Detailed configuration
|
|
202
|
+
watermark:
|
|
203
|
+
path: "watermark.png"
|
|
204
|
+
anchor: [right, bottom] # Positioning
|
|
205
|
+
margin: 100 # Margin from edge (pixels)
|
|
206
|
+
opacity: 0.8 # 0.0 to 1.0
|
|
207
|
+
|
|
208
|
+
# Disable watermark
|
|
209
|
+
watermark: false
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Callout Definitions
|
|
213
|
+
|
|
214
|
+
Define reusable callout styles:
|
|
215
|
+
|
|
216
|
+
```yaml
|
|
217
|
+
callouts:
|
|
218
|
+
default:
|
|
219
|
+
background_color: "#ffff00"
|
|
220
|
+
shadow: "#2242d3" # Color string or false
|
|
221
|
+
|
|
222
|
+
# Title styling
|
|
223
|
+
title_style:
|
|
224
|
+
color: "#000000"
|
|
225
|
+
size: 40
|
|
226
|
+
font_path: opensans/OpenSans-ExtraBold.ttf
|
|
227
|
+
|
|
228
|
+
# Body styling
|
|
229
|
+
body_style:
|
|
230
|
+
color: "#000000"
|
|
231
|
+
size: 32
|
|
232
|
+
font_path: opensans/OpenSans-Semibold.ttf
|
|
233
|
+
|
|
234
|
+
# Positioning
|
|
235
|
+
anchor: [left, bottom] # [horizontal, vertical]
|
|
236
|
+
margin: 100 # Margin from anchor edge
|
|
237
|
+
padding: 50 # Internal padding
|
|
238
|
+
|
|
239
|
+
# Animation
|
|
240
|
+
animation: fade # "fade" or "slide"
|
|
241
|
+
|
|
242
|
+
# Transitions
|
|
243
|
+
in_transition:
|
|
244
|
+
duration: 0.4
|
|
245
|
+
sound: pop.mp3
|
|
246
|
+
|
|
247
|
+
out_transition:
|
|
248
|
+
duration: 0.3
|
|
249
|
+
sound:
|
|
250
|
+
path: pop.mp3
|
|
251
|
+
volume: 0.7 # 0.0 to 1.0
|
|
252
|
+
|
|
253
|
+
warning:
|
|
254
|
+
background_color: "#ff6600"
|
|
255
|
+
# ... additional callout types
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Episode Configuration
|
|
261
|
+
|
|
262
|
+
The `episodes/*/config.yml` file defines episode-specific settings.
|
|
263
|
+
|
|
264
|
+
### Basic Settings
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
# Required: Episode title (displayed in intro)
|
|
268
|
+
title: "Creating Screencasts with ScreenKit"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Episode-Specific Overrides
|
|
272
|
+
|
|
273
|
+
Episodes can override project settings:
|
|
274
|
+
|
|
275
|
+
```yaml
|
|
276
|
+
# Override backtrack
|
|
277
|
+
backtrack: resources/custom-music.mp3
|
|
278
|
+
backtrack: false # Disable for this episode
|
|
279
|
+
|
|
280
|
+
# Override TTS settings
|
|
281
|
+
tts:
|
|
282
|
+
engine: elevenlabs
|
|
283
|
+
voice_id: custom_voice_id
|
|
284
|
+
|
|
285
|
+
# Override watermark
|
|
286
|
+
watermark: false
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Callout Instances
|
|
290
|
+
|
|
291
|
+
Define when and where callouts appear:
|
|
292
|
+
|
|
293
|
+
```yaml
|
|
294
|
+
callouts:
|
|
295
|
+
- type: info # References callout defined in project config
|
|
296
|
+
title: "ScreenKit"
|
|
297
|
+
body: "Visit https://github.com/fnando/screenkit"
|
|
298
|
+
starts_at: 3 # Start time (seconds or HH:MM:SS)
|
|
299
|
+
duration: 5 # Duration in seconds
|
|
300
|
+
width: 600 # Optional: Override width (pixels or percentage)
|
|
301
|
+
|
|
302
|
+
- type: warning
|
|
303
|
+
title: "Important"
|
|
304
|
+
body: "Remember to save your work"
|
|
305
|
+
starts_at: "00:01:30" # HH:MM:SS format
|
|
306
|
+
duration: 4
|
|
307
|
+
width: "50%" # Percentage of screen width
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### Time Formats
|
|
311
|
+
|
|
312
|
+
- **Seconds**: `starts_at: 90` (90 seconds)
|
|
313
|
+
- **HH:MM:SS**: `starts_at: "00:01:30"` (1 minute 30 seconds)
|
|
314
|
+
- **Duration**: Always in seconds or time units (`5s`, `2m`, `1h`)
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Scenes
|
|
319
|
+
|
|
320
|
+
ScreenKit supports three scene types: **intro**, **outro**, and **segment**.
|
|
321
|
+
|
|
322
|
+
### Intro Scene
|
|
323
|
+
|
|
324
|
+
Opening scene with logo and title.
|
|
325
|
+
|
|
326
|
+
```yaml
|
|
327
|
+
scenes:
|
|
328
|
+
intro:
|
|
329
|
+
duration: 5.5 # Scene duration (seconds)
|
|
330
|
+
fade_in: 0 # Fade-in duration
|
|
331
|
+
fade_out: 0.5 # Fade-out duration
|
|
332
|
+
|
|
333
|
+
# Background (color or image path)
|
|
334
|
+
background: "#100f50"
|
|
335
|
+
background: resources/intro-bg.png
|
|
336
|
+
|
|
337
|
+
# Title text
|
|
338
|
+
title:
|
|
339
|
+
x: 100 # X position (pixels or "center")
|
|
340
|
+
y: 300 # Y position (pixels or "center")
|
|
341
|
+
font_path: opensans/OpenSans-ExtraBold.ttf
|
|
342
|
+
size: 144 # Font size
|
|
343
|
+
color: "#ffffff"
|
|
344
|
+
|
|
345
|
+
# Logo
|
|
346
|
+
logo:
|
|
347
|
+
path: logo.png
|
|
348
|
+
x: 100 # X position (pixels or "center")
|
|
349
|
+
y: 200 # Y position (pixels or "center")
|
|
350
|
+
width: 300 # Width in pixels (height auto-calculated)
|
|
351
|
+
|
|
352
|
+
# Sound effect
|
|
353
|
+
sound: chime.mp3
|
|
354
|
+
sound: false # Disable sound
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Outro Scene
|
|
358
|
+
|
|
359
|
+
Closing scene with logo.
|
|
360
|
+
|
|
361
|
+
```yaml
|
|
362
|
+
scenes:
|
|
363
|
+
outro:
|
|
364
|
+
duration: 5.5
|
|
365
|
+
fade_in: 0.5
|
|
366
|
+
fade_out: 0.5
|
|
367
|
+
background: "#100f50"
|
|
368
|
+
|
|
369
|
+
logo:
|
|
370
|
+
path: logo.png
|
|
371
|
+
x: center # Center horizontally
|
|
372
|
+
y: center # Center vertically
|
|
373
|
+
width: 300
|
|
374
|
+
|
|
375
|
+
sound: chime.mp3
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Segment Scene
|
|
379
|
+
|
|
380
|
+
Main content configuration.
|
|
381
|
+
|
|
382
|
+
```yaml
|
|
383
|
+
scenes:
|
|
384
|
+
segment:
|
|
385
|
+
# Crossfade duration between video segments
|
|
386
|
+
crossfade_duration: 0.5
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Callouts
|
|
392
|
+
|
|
393
|
+
Callouts (also known as lower thirds) are informational overlays that appear
|
|
394
|
+
during the video.
|
|
395
|
+
|
|
396
|
+
### Callout Styles
|
|
397
|
+
|
|
398
|
+
ScreenKit provides two built-in callout styles:
|
|
399
|
+
|
|
400
|
+
#### Default Style
|
|
401
|
+
|
|
402
|
+
The default style displays a title and body in a box with optional shadow.
|
|
403
|
+
|
|
404
|
+
```yaml
|
|
405
|
+
callouts:
|
|
406
|
+
info:
|
|
407
|
+
style: default # Optional: defaults to "default"
|
|
408
|
+
background_color: "#ffff00" # Background color (hex)
|
|
409
|
+
|
|
410
|
+
# Shadow
|
|
411
|
+
shadow: "#2242d3" # Simple shadow (color)
|
|
412
|
+
shadow: # Detailed shadow
|
|
413
|
+
color: "#2242d3"
|
|
414
|
+
offset: 10 # Shadow offset in pixels
|
|
415
|
+
shadow: false # No shadow
|
|
416
|
+
|
|
417
|
+
# Text Styles
|
|
418
|
+
title_style:
|
|
419
|
+
color: "#000000"
|
|
420
|
+
size: 40
|
|
421
|
+
font_path: opensans/OpenSans-ExtraBold.ttf
|
|
422
|
+
|
|
423
|
+
body_style:
|
|
424
|
+
color: "#000000"
|
|
425
|
+
size: 32
|
|
426
|
+
font_path: opensans/OpenSans-Semibold.ttf
|
|
427
|
+
|
|
428
|
+
# Layout
|
|
429
|
+
padding: 50 # Internal padding (pixels)
|
|
430
|
+
margin: 100 # Margin from edge (pixels)
|
|
431
|
+
anchor: [left, bottom] # Position anchor point
|
|
432
|
+
|
|
433
|
+
# Animation
|
|
434
|
+
animation: fade # "fade" or "slide"
|
|
435
|
+
|
|
436
|
+
# Transitions
|
|
437
|
+
in_transition:
|
|
438
|
+
duration: 0.4 # Transition duration (seconds)
|
|
439
|
+
sound: pop.mp3 # Sound effect
|
|
440
|
+
|
|
441
|
+
out_transition:
|
|
442
|
+
duration: 0.3
|
|
443
|
+
sound:
|
|
444
|
+
path: pop.mp3
|
|
445
|
+
volume: 0.7 # Volume (0.0 to 1.0)
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Usage in episode:**
|
|
449
|
+
|
|
450
|
+
```yaml
|
|
451
|
+
callouts:
|
|
452
|
+
- type: info
|
|
453
|
+
title: "ScreenKit"
|
|
454
|
+
body: "Visit https://github.com/fnando/screenkit"
|
|
455
|
+
starts_at: 3
|
|
456
|
+
duration: 5
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
#### Inline Block Style
|
|
460
|
+
|
|
461
|
+
The inline block style displays text with a background highlight on each line,
|
|
462
|
+
similar to syntax highlighting or code comments. Perfect for displaying code
|
|
463
|
+
snippets, commands, or short inline text.
|
|
464
|
+
|
|
465
|
+
```yaml
|
|
466
|
+
callouts:
|
|
467
|
+
code:
|
|
468
|
+
style: inline_block
|
|
469
|
+
background_color: "#000000" # Background color (hex)
|
|
470
|
+
|
|
471
|
+
# Text Style (single style for all text)
|
|
472
|
+
text_style:
|
|
473
|
+
color: "#ffffff"
|
|
474
|
+
size: 40
|
|
475
|
+
font_path: opensans/OpenSans-ExtraBold.ttf
|
|
476
|
+
|
|
477
|
+
# Layout
|
|
478
|
+
padding: 20 # Padding around text (pixels)
|
|
479
|
+
margin: 100 # Margin from edge (pixels)
|
|
480
|
+
anchor: [left, center] # Position anchor point
|
|
481
|
+
width: 600 # Maximum width (pixels)
|
|
482
|
+
|
|
483
|
+
# Animation
|
|
484
|
+
animation: fade # "fade" or "slide"
|
|
485
|
+
|
|
486
|
+
# Transitions
|
|
487
|
+
in_transition:
|
|
488
|
+
duration: 0.4
|
|
489
|
+
sound: false
|
|
490
|
+
|
|
491
|
+
out_transition:
|
|
492
|
+
duration: 0.3
|
|
493
|
+
sound: false
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Usage in episode:**
|
|
497
|
+
|
|
498
|
+
```yaml
|
|
499
|
+
callouts:
|
|
500
|
+
# Single line text (auto-wrapped)
|
|
501
|
+
- type: code
|
|
502
|
+
text: "npm install screenkit --save-dev"
|
|
503
|
+
starts_at: 5
|
|
504
|
+
duration: 4
|
|
505
|
+
|
|
506
|
+
# Multi-line text (explicit line breaks)
|
|
507
|
+
- type: code
|
|
508
|
+
text: |
|
|
509
|
+
git add .
|
|
510
|
+
git commit -m "Update"
|
|
511
|
+
git push
|
|
512
|
+
starts_at: 15
|
|
513
|
+
duration: 6
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**Key differences from default style:**
|
|
517
|
+
|
|
518
|
+
- Uses `text` instead of `title` and `body`
|
|
519
|
+
- Only one `text_style` (no separate title/body styles)
|
|
520
|
+
- No `shadow` option
|
|
521
|
+
- Each line gets its own background rectangle
|
|
522
|
+
- Text can include manual line breaks (`\n`)
|
|
523
|
+
- Auto-wraps based on `width` if no line breaks present
|
|
524
|
+
|
|
525
|
+
### Anchor Positions
|
|
526
|
+
|
|
527
|
+
Anchor determines where the callout is positioned:
|
|
528
|
+
|
|
529
|
+
**Horizontal**: `left`, `center`, `right`
|
|
530
|
+
**Vertical**: `top`, `center`, `bottom`
|
|
531
|
+
|
|
532
|
+
```yaml
|
|
533
|
+
anchor: [left, top] # Top-left corner
|
|
534
|
+
anchor: [center, center] # Center of screen
|
|
535
|
+
anchor: [right, bottom] # Bottom-right corner
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Position Values
|
|
539
|
+
|
|
540
|
+
- **Pixels**: `x: 100`, `y: 200`
|
|
541
|
+
- **Center**: `x: center`, `y: center`
|
|
542
|
+
|
|
543
|
+
### Size Values
|
|
544
|
+
|
|
545
|
+
- **Pixels**: `width: 600`
|
|
546
|
+
- **Percentage**: `width: "50%"` (percentage of screen width)
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Text-to-Speech (TTS)
|
|
551
|
+
|
|
552
|
+
ScreenKit supports multiple TTS engines for voiceovers.
|
|
553
|
+
|
|
554
|
+
### macOS `say` Engine
|
|
555
|
+
|
|
556
|
+
Uses the built-in macOS `say` command.
|
|
557
|
+
|
|
558
|
+
```yaml
|
|
559
|
+
tts:
|
|
560
|
+
engine: say
|
|
561
|
+
voice: Alex # Optional: Voice name
|
|
562
|
+
rate: 150 # Words per minute (optional)
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### ElevenLabs Engine
|
|
566
|
+
|
|
567
|
+
Professional AI voice synthesis.
|
|
568
|
+
|
|
569
|
+
```yaml
|
|
570
|
+
tts:
|
|
571
|
+
engine: elevenlabs
|
|
572
|
+
voice_id: "56AoDkrOh6qfVPDXZ7Pt" # Required: ElevenLabs voice ID
|
|
573
|
+
language_code: en # 2-letter language code
|
|
574
|
+
|
|
575
|
+
# Optional: Voice settings
|
|
576
|
+
voice_settings:
|
|
577
|
+
speed: 0.9 # Speech speed (default: 1.0)
|
|
578
|
+
stability: 0.5 # Voice stability (0.0 - 1.0)
|
|
579
|
+
similarity: 0.75 # Voice similarity (0.0 - 1.0)
|
|
580
|
+
style: 0.0 # Speaking style (0.0+)
|
|
581
|
+
|
|
582
|
+
# Optional: Output format
|
|
583
|
+
output_format: mp3_44100_128
|
|
584
|
+
|
|
585
|
+
# Optional: Model ID
|
|
586
|
+
model_id: eleven_monolingual_v1
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
#### ElevenLabs Output Formats
|
|
590
|
+
|
|
591
|
+
- MP3: `mp3_22050_32`, `mp3_44100_128`, `mp3_44100_192`
|
|
592
|
+
- PCM: `pcm_16000`, `pcm_24000`, `pcm_44100`
|
|
593
|
+
- Opus: `opus_48000_32`, `opus_48000_64`
|
|
594
|
+
- Others: `ulaw_8000`, `alaw_8000`
|
|
595
|
+
|
|
596
|
+
### Disable TTS
|
|
597
|
+
|
|
598
|
+
```yaml
|
|
599
|
+
tts: false
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Custom TTS Engines
|
|
603
|
+
|
|
604
|
+
You can create custom TTS engines by placing them in the `ScreenKit::TTS`
|
|
605
|
+
module. Custom engines must implement the `generate` method:
|
|
606
|
+
|
|
607
|
+
```ruby
|
|
608
|
+
module ScreenKit
|
|
609
|
+
module TTS
|
|
610
|
+
class CustomEngine
|
|
611
|
+
include Shell
|
|
612
|
+
extend SchemaValidator
|
|
613
|
+
|
|
614
|
+
# Optional: Define schema path for validation
|
|
615
|
+
def self.schema_path
|
|
616
|
+
ScreenKit.root_dir.join("screenkit/schemas/tts/custom_engine.json")
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
def initialize(**options)
|
|
620
|
+
@options = options
|
|
621
|
+
# Validate options against schema if defined
|
|
622
|
+
self.class.validate!(@options) if respond_to?(:validate!)
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def generate(text:, output_path:, log_path: nil)
|
|
626
|
+
# Generate audio file from text
|
|
627
|
+
# Write output to output_path
|
|
628
|
+
# Optionally log to log_path
|
|
629
|
+
|
|
630
|
+
# Example implementation:
|
|
631
|
+
# File.write(output_path, generated_audio_data)
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Configuration:**
|
|
639
|
+
|
|
640
|
+
```yaml
|
|
641
|
+
tts:
|
|
642
|
+
engine: custom_engine # Camelized to CustomEngine
|
|
643
|
+
# Add your custom options here
|
|
644
|
+
api_key: your_api_key
|
|
645
|
+
custom_option: value
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
The engine name is camelized (e.g., `custom_engine` → `CustomEngine`,
|
|
649
|
+
`google_cloud` → `GoogleCloud`) and loaded as
|
|
650
|
+
`ScreenKit::TTS::#{CamelizedName}`.
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## Animations
|
|
655
|
+
|
|
656
|
+
ScreenKit supports two animation types for callouts:
|
|
657
|
+
|
|
658
|
+
### Fade Animation
|
|
659
|
+
|
|
660
|
+
Callouts fade in and out with opacity changes.
|
|
661
|
+
|
|
662
|
+
```yaml
|
|
663
|
+
animation: fade
|
|
664
|
+
in_transition:
|
|
665
|
+
duration: 0.4
|
|
666
|
+
out_transition:
|
|
667
|
+
duration: 0.3
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
**Behavior:**
|
|
671
|
+
|
|
672
|
+
- Fades in from transparent to opaque
|
|
673
|
+
- Remains visible
|
|
674
|
+
- Fades out to transparent
|
|
675
|
+
|
|
676
|
+
### Slide Animation
|
|
677
|
+
|
|
678
|
+
Callouts slide in from the left and slide out to the left with blur effects.
|
|
679
|
+
|
|
680
|
+
```yaml
|
|
681
|
+
animation: slide
|
|
682
|
+
in_transition:
|
|
683
|
+
duration: 0.4
|
|
684
|
+
out_transition:
|
|
685
|
+
duration: 0.3
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**Behavior:**
|
|
689
|
+
|
|
690
|
+
- Slides in from left (off-screen to position) with blur
|
|
691
|
+
- Sharp focus when static
|
|
692
|
+
- Slides out to left with blur
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
## File Structure
|
|
697
|
+
|
|
698
|
+
### Episode Directory Structure
|
|
699
|
+
|
|
700
|
+
```
|
|
701
|
+
episodes/001-episode-name/
|
|
702
|
+
├── config.yml # Episode configuration
|
|
703
|
+
├── content/ # Terminal recordings
|
|
704
|
+
│ ├── 001.tape # VHS tape files
|
|
705
|
+
│ ├── 002.tape
|
|
706
|
+
│ └── ...
|
|
707
|
+
├── scripts/ # Voiceover scripts
|
|
708
|
+
│ ├── 001.txt # Text for TTS
|
|
709
|
+
│ ├── 002.txt
|
|
710
|
+
│ └── ...
|
|
711
|
+
├── voiceovers/ # Generated audio
|
|
712
|
+
│ ├── 001.aiff
|
|
713
|
+
│ ├── 002.aiff
|
|
714
|
+
│ └── ...
|
|
715
|
+
└── resources/ # Episode-specific resources
|
|
716
|
+
├── images/
|
|
717
|
+
├── sounds/
|
|
718
|
+
└── fonts/
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### VHS Tape Files
|
|
722
|
+
|
|
723
|
+
ScreenKit uses [VHS](https://github.com/charmbracelet/vhs) tape files for
|
|
724
|
+
terminal recordings:
|
|
725
|
+
|
|
726
|
+
```tape
|
|
727
|
+
# content/001.tape
|
|
728
|
+
Type "echo 'Hello, World!'"
|
|
729
|
+
Sleep 100ms
|
|
730
|
+
Enter
|
|
731
|
+
Sleep 2s
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Script Files
|
|
735
|
+
|
|
736
|
+
Plain text files for voiceover generation:
|
|
737
|
+
|
|
738
|
+
```txt
|
|
739
|
+
# scripts/001.txt
|
|
740
|
+
Welcome to this tutorial on ScreenKit.
|
|
741
|
+
Today we'll learn how to create amazing screencasts.
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Naming Convention
|
|
745
|
+
|
|
746
|
+
Files are matched by number:
|
|
747
|
+
|
|
748
|
+
- `content/001.tape` → `scripts/001.txt` → `voiceovers/001.aiff`
|
|
749
|
+
- Segments are processed in numerical order
|
|
750
|
+
- Missing scripts create silent segments
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## Advanced Features
|
|
755
|
+
|
|
756
|
+
### Resource Lookup
|
|
757
|
+
|
|
758
|
+
Resources are searched in order from `resources_dir`:
|
|
759
|
+
|
|
760
|
+
1. Current directory
|
|
761
|
+
2. Episode directory
|
|
762
|
+
3. Project resources
|
|
763
|
+
4. Episode resources
|
|
764
|
+
5. System font directories
|
|
765
|
+
|
|
766
|
+
Reference resources by partial path:
|
|
767
|
+
|
|
768
|
+
```yaml
|
|
769
|
+
font_path: opensans/OpenSans-Bold.ttf # Found in resources/fonts/
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
### Placeholders
|
|
773
|
+
|
|
774
|
+
#### Project Configuration
|
|
775
|
+
|
|
776
|
+
- `%{episode_number}` - Episode number (1, 2, 3...)
|
|
777
|
+
- `%<episode_number>03d` - Padded episode number (001, 002, 003...)
|
|
778
|
+
- `%{episode_slug}` - URL-friendly episode title
|
|
779
|
+
- `%{date}` - Current date (`YYYY-MM-DD`)
|
|
780
|
+
- `%{episode_dirname}` - Episode directory name
|
|
781
|
+
|
|
782
|
+
```yaml
|
|
783
|
+
episode_dir: episodes/%<episode_number>03d-%{episode_slug}
|
|
784
|
+
output_dir: output/%{episode_dirname}
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### Color Formats
|
|
788
|
+
|
|
789
|
+
Colors support hex format with optional alpha channel:
|
|
790
|
+
|
|
791
|
+
```yaml
|
|
792
|
+
# 6-character hex (RGB)
|
|
793
|
+
color: "#ffffff" # White
|
|
794
|
+
|
|
795
|
+
# 8-character hex (RGBA) - includes alpha channel for transparency
|
|
796
|
+
color: "#ffffff80" # White with 50% transparency
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
Alpha channel values range from `00` (fully transparent) to `ff` (fully opaque).
|
|
800
|
+
|
|
801
|
+
### Sound Configuration
|
|
802
|
+
|
|
803
|
+
Three ways to specify sounds:
|
|
804
|
+
|
|
805
|
+
```yaml
|
|
806
|
+
# String path
|
|
807
|
+
sound: pop.mp3
|
|
808
|
+
|
|
809
|
+
# Detailed configuration
|
|
810
|
+
sound:
|
|
811
|
+
path: pop.mp3
|
|
812
|
+
volume: 0.7 # 0.0 to 1.0
|
|
813
|
+
|
|
814
|
+
# Disable
|
|
815
|
+
sound: false
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
### Shadow Configuration
|
|
819
|
+
|
|
820
|
+
```yaml
|
|
821
|
+
# Simple color
|
|
822
|
+
shadow: "#2242d3"
|
|
823
|
+
|
|
824
|
+
# Detailed configuration
|
|
825
|
+
shadow:
|
|
826
|
+
color: "#2242d3"
|
|
827
|
+
offset: 10 # Pixels
|
|
828
|
+
|
|
829
|
+
# Disable
|
|
830
|
+
shadow: false
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Background Configuration
|
|
834
|
+
|
|
835
|
+
```yaml
|
|
836
|
+
# Solid color
|
|
837
|
+
background: "#100f50"
|
|
838
|
+
|
|
839
|
+
# Image path
|
|
840
|
+
background: resources/background.png
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### Spacing Configuration
|
|
844
|
+
|
|
845
|
+
Spacing values accept:
|
|
846
|
+
|
|
847
|
+
```yaml
|
|
848
|
+
margin: 100 # Single value (all sides)
|
|
849
|
+
padding: 50 # Single value (all sides)
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
### Text Wrapping
|
|
853
|
+
|
|
854
|
+
Long titles are automatically wrapped based on approximate text width. Manual
|
|
855
|
+
line breaks in the episode title are preserved.
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
## Schema Validation
|
|
860
|
+
|
|
861
|
+
ScreenKit validates configurations against JSON schemas:
|
|
862
|
+
|
|
863
|
+
- **Project**: `lib/screenkit/schemas/project.json`
|
|
864
|
+
- **Episode**: `lib/screenkit/schemas/episode.json`
|
|
865
|
+
- **Callouts**: `lib/screenkit/schemas/callouts/*.json`
|
|
866
|
+
- **TTS**: `lib/screenkit/schemas/tts/*.json`
|
|
867
|
+
|
|
868
|
+
Use the `yaml-language-server` comment for IDE support:
|
|
869
|
+
|
|
870
|
+
```yaml
|
|
871
|
+
# yaml-language-server: $schema=../../schemas/project.json
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
876
|
+
## Export Process
|
|
877
|
+
|
|
878
|
+
When exporting an episode, ScreenKit:
|
|
879
|
+
|
|
880
|
+
1. **Validates** project and episode configurations
|
|
881
|
+
2. **Generates voiceovers** from script files (if TTS enabled)
|
|
882
|
+
3. **Renders terminal recordings** from tape files using VHS
|
|
883
|
+
4. **Combines segments** with crossfade transitions
|
|
884
|
+
5. **Adds intro/outro** scenes
|
|
885
|
+
6. **Overlays callouts** with animations
|
|
886
|
+
7. **Applies watermark** (if configured)
|
|
887
|
+
8. **Mixes background music** (if configured)
|
|
888
|
+
9. **Outputs final video** to the output directory
|
|
889
|
+
|
|
890
|
+
### Segment Filtering
|
|
891
|
+
|
|
892
|
+
Export only specific segments:
|
|
893
|
+
|
|
894
|
+
```bash
|
|
895
|
+
screenkit episode export --dir episodes/001-test --match-segment "002"
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
This processes only segments matching "002" (e.g., `002.tape`, `003.tape` won't
|
|
899
|
+
be processed).
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## Tips & Best Practices
|
|
904
|
+
|
|
905
|
+
### Performance
|
|
906
|
+
|
|
907
|
+
- Use `--match-segment` during development to export only changed segments
|
|
908
|
+
- Place frequently-accessed resources in the first `resources_dir` entry
|
|
909
|
+
- Use high-resolution logos (2x target size) for best quality
|
|
910
|
+
|
|
911
|
+
### Audio
|
|
912
|
+
|
|
913
|
+
- Keep voiceover scripts concise and natural
|
|
914
|
+
- Test TTS voices before bulk generation
|
|
915
|
+
- Background music volume is automatically adjusted to not overpower voiceovers
|
|
916
|
+
|
|
917
|
+
### Visuals
|
|
918
|
+
|
|
919
|
+
- Use consistent branding across callouts
|
|
920
|
+
- Test callout timing with `screenkit callout` command
|
|
921
|
+
- PNG images with transparency work best for logos and watermarks
|
|
922
|
+
|
|
923
|
+
### Organization
|
|
924
|
+
|
|
925
|
+
- Use numbered segments (001, 002, etc.) for proper ordering
|
|
926
|
+
- Keep episode-specific resources in episode directories
|
|
927
|
+
- Use descriptive callout type names (`info`, `warning`, `tip`, etc.)
|
|
928
|
+
|
|
929
|
+
---
|
|
930
|
+
|
|
931
|
+
## Troubleshooting
|
|
932
|
+
|
|
933
|
+
### Common Issues
|
|
934
|
+
|
|
935
|
+
**"Gem not found" error:**
|
|
936
|
+
|
|
937
|
+
```bash
|
|
938
|
+
bundle install
|
|
939
|
+
bundle exec screenkit ...
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
**"Schema validation failed":**
|
|
943
|
+
|
|
944
|
+
- Check YAML syntax
|
|
945
|
+
- Verify required fields are present
|
|
946
|
+
- Use schema hints with `yaml-language-server`
|
|
947
|
+
|
|
948
|
+
**Missing resources:**
|
|
949
|
+
|
|
950
|
+
- Check `resources_dir` configuration
|
|
951
|
+
- Verify file paths are relative to resource directories
|
|
952
|
+
- Use absolute paths for system resources
|
|
953
|
+
|
|
954
|
+
**TTS not working:**
|
|
955
|
+
|
|
956
|
+
- For ElevenLabs: Set `--voice-api-key` or `ELEVENLABS_API_KEY` env variable
|
|
957
|
+
- For macOS `say`: Verify voice name with `say -v ?`
|
|
958
|
+
|
|
959
|
+
---
|
|
960
|
+
|
|
961
|
+
## Contributing
|
|
962
|
+
|
|
963
|
+
For development and contribution guidelines, see:
|
|
964
|
+
|
|
965
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
966
|
+
- [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
967
|
+
|
|
968
|
+
---
|
|
969
|
+
|
|
970
|
+
## License
|
|
971
|
+
|
|
972
|
+
MIT License - See [LICENSE.md](LICENSE.md)
|