Render your first reel¶
By the end of this you'll have a real 1080×1920 H.264 mp4 on disk, built by Keryx from a storyboard you wrote. About fifteen minutes.
There's no narration and no music in this one, and no AI generation of any kind. That means no API keys and nothing to pay for — which makes it the fastest way to see whether Keryx is doing what you expect before you point money at it. Adding voice, music and generated card art comes later, and the how-to guides cover each.
Before you start¶
You'll need:
- Go 1.26 or newer, if you're installing from source.
ffmpegon yourPATH. Keryx shells out to it by default.ffmpeg -versionshould print something. (There's a second renderer that needs no systemffmpegat all — see the last section.)- A directory to work in. Keryx keeps no state of its own; everything lives in the project directory you run it from, so a scratch folder is fine for now.
Install Keryx¶
That puts a keryx binary in $(go env GOPATH)/bin. Check it:
Pre-built archives are attached to each release on GitLab if you'd rather not build from source.
Write the configuration file¶
Keryx refuses to run without a configuration file. Every command fails the same way until one exists:
ERRO failed to load configuration: no config file found hints="Run 'keryx init' to create a configuration."
So do that:
$ keryx init
INFO Initialising configuration
INFO configuration initialised path=/home/you/.keryx/config.yaml
That writes ~/.keryx/config.yaml with sensible defaults — every posting platform
disabled, alerting off, no themes. On a terminal it also offers to walk you through
credential set-up; you don't need any of that today, and keryx init --skip-ai
--skip-login --skip-key skips the prompts entirely.
Have a look at what it wrote. It ships with an example avatar and voice registered
under the name matt, which are the author's own — harmless, but not yours. Delete the
avatars: and voices: blocks if you find them confusing.
Add a theme, because there isn't one¶
Keryx has no built-in themes at all. Palette, fonts, card treatment, music tone and voice settings are configuration, never code — so nothing is seeded and the first generation you attempt will say so:
Add a minimal reel theme with two palette roles and a card treatment:
keryx theme add starter --type reel \
--set 'palette.charcoal=#1A1D21' \
--set 'palette.cream=#F4F1EA' \
--set 'card.mode=block'
The first theme of a type becomes that type's default, so you won't have to name it
again. card.mode=block means each card is one line of text over a solid palette
colour — the treatment that needs no illustration, which is exactly what you want with
no image provider configured.
Check it landed:
It went into ~/.keryx/themes.yaml, so it's available to every project on this
machine. A project can carry its own themes in a .keryx.yaml at its root instead.
Create a reel workspace¶
Move into your working directory and create one:
That's a directory holding everything for one reel: an empty storyboard, the vo/ and
cards/ directories, the disposable takes/ and .cache/ directories, and a
.gitignore so the disposable parts stay out of git. The full list of what goes where
is in the workspace layout reference.
The slug has to be lowercase kebab-case — hello-keryx is fine, Hello Keryx is not.
Write a three-card storyboard¶
The storyboard is the creative seed: an ordered JSON array, one object per card. Open
reels/hello-keryx/storyboard.json — reel new left it as an empty array — and
replace it with this:
[
{ "text": "Keryx turns a post", "bg": "charcoal", "fg": "cream", "dur": 2.0 },
{ "text": "into a short reel.", "bg": "charcoal", "fg": "cream", "dur": 2.0 },
{ "text": "keryx.phpboyscout.uk", "bg": "cream", "fg": "charcoal", "mono": true, "dur": 2.5 }
]
Four things worth knowing about those fields:
bgandfgare palette role names, not colours. They have to match roles you defined on the theme —charcoalandcreamabove. A role the theme doesn't define is a validation error, which is the point: change the theme and every card follows.duris seconds on screen, and it's only used when there's no narration. Once a card has a voice-over clip, the clip's length drives the timing andduris ignored.monoswitches that card to the theme's monospace font — the convention for a closing URL card.- There's no
titleordurationfield. The full set is in the storyboard reference.
Render it¶
$ keryx reel build --workspace hello-keryx --silent
rendered 3 cards (5.7s) -> reels/hello-keryx/reel-hello-keryx.mp4
assets: 0 selected, 0 locked
--silent says "video only, no narration and no music", and it's what makes each
card fall back to its dur. Without it, Keryx expects promoted voice-over clips and
will name any card that has neither a clip nor a dur.
On an interactive terminal you'll see a rendering… NN% line while it works. It's
written to stderr, so piping the output somewhere leaves you with just the result.
The reel is 5.7 seconds rather than the 6.5 you might expect from adding up the dur
values. Cards crossfade into each other by 0.4 s, and two transitions cost 0.8 s.
Check the file is what it claims to be:
$ ffprobe -v error -show_entries stream=width,height,codec_name \
-of default=nw=1 reels/hello-keryx/reel-hello-keryx.mp4
codec_name=h264
width=1080
height=1920
Play it. Three cards, a crossfade between each, no sound.
Change something and watch it change¶
The build is cheap and repeatable, so this is the loop you'll spend most of your time in. Swap the palette roles on the last card:
Run the same build again. It overwrites the mp4 in place — nothing accumulates, and nothing else in the workspace is touched.
Get a palette role wrong and the build stops before rendering anything:
$ keryx reel build --workspace hello-keryx --silent
ERRO invalid storyboard:
- card 1: bg references undefined palette role "nosuchrole"
You can also see what a build would do without doing it:
$ keryx reel plan --workspace hello-keryx
reel plan: hello-keryx [silent fallback (storyboard dur — no promoted VO)]
card dur start vo_delay source
1 2.000 0.000 0.500 storyboard
2 2.000 1.600 2.100 storyboard
3 2.500 3.200 3.700 storyboard
total: 5.700s music bed: 35.000s (35000ms)
assets: 0 selected, 0 locked
5 pre-build gap(s):
- [missing_vo] card 1: no VO — silent fallback
- [missing_vo] card 2: no VO — silent fallback
- [missing_vo] card 3: no VO — silent fallback
- [missing_cover] no cover.png
- [no_music] no music bed
The start column shows the crossfade at work — card 2 starts at 1.6 s, not 2.0 s.
The gaps are expected here; every one of them is something you haven't generated yet.
The 35 s music bed is the fallback length used when no narration exists to size a bed
against.
Rendering without a system ffmpeg¶
If ffmpeg isn't installed and you'd rather not install it, Keryx ships a second
renderer that runs FFmpeg compiled to WebAssembly, entirely in memory:
The first render downloads a pinned ffmpeg-wasi module — a few tens of megabytes —
verifies its SHA-256 and caches it, so only the first run is slow. You don't need to
fetch anything by hand.
One limit worth knowing before you set it: because providers.render is a plain value
and providers.render.module is a nested one, you cannot select afmpeg in config
and also override its module in config. If you need a locally-built or mirrored
module, point at it with the KERYX_FFMPEG_WASI environment variable instead.
Where to go next¶
- Make a reel, stage by stage — add narration, a music bed and generated card art, taste-gating each stage.
- Configuration keys — every key, its default, and what happens when it's wrong.
- What Keryx does not do — worth ten minutes before you build a workflow on it.