Configuration

reeln uses a layered JSON configuration system with XDG-compliant paths and environment variable overrides.

Config file locations

Platform

Config directory

macOS

~/Library/Application Support/reeln/

Linux

~/.config/reeln/

Windows

%APPDATA%\reeln\

The main config file is config.json within the config directory.

Loading order

Configuration is merged in this order (later values win):

  1. Bundled defaults — shipped with the package, always valid

  2. User configconfig.json in your config directory

  3. Game overridegame.json in the current game directory

  4. Environment variablesREELN_<SECTION>_<KEY>

Example config

{
  "config_version": 1,
  "sport": "hockey",
  "video": {
    "ffmpeg_path": null,
    "default_container": "mkv",
    "merge_strategy": "concat",
    "codec": "libx264",
    "preset": "medium",
    "crf": 18,
    "audio_codec": "aac",
    "audio_bitrate": "128k"
  },
  "paths": {
    "source_dir": "~/Videos/OBS",
    "source_glob": "Replay_*.mkv",
    "output_dir": "~/Movies",
    "temp_dir": null
  }
}

Paths section

Key

Default

Description

source_dir

null

Directory where replay files are captured (e.g. OBS output folder)

source_glob

Replay_*.mkv

Glob pattern for matching replay files in source_dir

output_dir

null

Base directory for game directories and output

temp_dir

null

Temporary file directory (default: system temp)

source_dir is used by both game segment (to collect replays) and render short (to auto-discover the latest clip when no argument is given).

Video section

Key

Default

Description

ffmpeg_path

null

Explicit path to ffmpeg binary (auto-discovered if null)

default_container

mkv

Default output container format

merge_strategy

concat

Merge strategy for segment processing

codec

libx264

Video codec for encoding

preset

medium

Encoder preset (ultrafast → veryslow)

crf

18

Constant Rate Factor — lower is higher quality

audio_codec

aac

Audio codec

audio_bitrate

128k

Audio bitrate

Video encoding settings apply to both game segment (when re-encoding mixed containers) and render short/render preview.

Render profiles section

Named render profiles define reusable rendering parameter overrides. Add a render_profiles section to your config:

{
  "render_profiles": {
    "fullspeed": {
      "speed": 1.0
    },
    "slowmo": {
      "speed": 0.5
    },
    "goal-overlay": {
      "speed": 0.5,
      "subtitle_template": "~/.config/reeln/templates/goal_overlay.ass"
    },
    "vertical-slowmo": {
      "width": 1080,
      "height": 1920,
      "crop_mode": "pad",
      "speed": 0.5
    }
  }
}

Key

Type

Description

speed

float

Playback speed (e.g. 0.5 for slow motion)

lut

string

Path to .cube LUT file for color grading

subtitle_template

string

Path to .ass subtitle template, or builtin:<name> for bundled templates. See Overlay templates.

width

int

Target width (short-form only, ignored for full-frame)

height

int

Target height (short-form only, ignored for full-frame)

crop_mode

string

"pad" or "crop" (short-form only)

anchor_x

float

Crop anchor X position, 0.0–1.0 (short-form only)

anchor_y

float

Crop anchor Y position, 0.0–1.0 (short-form only)

scale

float

Content scale, 0.5–3.0 (default: 1.0). Values > 1.0 zoom in.

smart

bool

Enable smart tracking via vision plugin

pad_color

string

Pad bar color (short-form only)

codec

string

Video codec override

preset

string

Encoder preset override

crf

int

CRF override

audio_codec

string

Audio codec override

audio_bitrate

string

Audio bitrate override

All fields are optional — null or omitted means “inherit from base config”.

Variable speed (speed_segments)

For variable-speed rendering within a single clip, use speed_segments instead of the scalar speed field. Each segment defines a speed and a source-time boundary:

{
  "render_profiles": {
    "slowmo-middle": {
      "speed_segments": [
        {"until": 5.0, "speed": 1.0},
        {"until": 8.0, "speed": 0.5},
        {"speed": 1.0}
      ]
    }
  }
}

This plays the first 5 seconds at normal speed, then 3 seconds at half speed, then the rest at normal speed. The last segment must omit until (it runs to the end of the clip).

Rules:

  • At least 2 segments required (use scalar speed for uniform speed)

  • until values must be strictly increasing and positive

  • Speeds must be in the range 0.25–4.0

  • speed and speed_segments are mutually exclusive — set one or the other, not both

  • speed_segments cannot be combined with --smart tracking

speed_segments is profile-only — there is no CLI flag for it. Configure it in a render profile and use --render-profile to apply it.

Profiles are used with --render-profile on render short, render preview, render apply, game segment, and game highlights.

Builtin templates

reeln ships with a bundled goal_overlay template. Reference it with the builtin: prefix instead of a file path:

{
  "render_profiles": {
    "player-overlay": {
      "speed": 0.5,
      "subtitle_template": "builtin:goal_overlay"
    }
  }
}

The goal_overlay template renders a lower-third banner showing the scorer name, up to two assists, and the team name. Font size scales dynamically for long names, and assists are hidden when not present.

A default player-overlay profile (native speed + goal overlay) and goal iteration mapping are included in the bundled config, so goal events render with the overlay out of the box:

# Tag a goal with player and assists
reeln game event tag <event-id> --type goal --player "#17 Smith" \
  --meta "assists=#22 Jones, #5 Brown"

# Render with the overlay
reeln render short clip.mkv --render-profile player-overlay \
  --game-dir . --event <event-id>

# Or use iterations (auto-applies player-overlay for goals)
reeln render short clip.mkv --iterate --game-dir . --event <event-id>

Smart tracking

Smart tracking (--smart or "smart": true in a profile) requires a vision plugin that handles the ON_FRAMES_EXTRACTED hook. Without one, --smart falls back to static center positioning with a warning.

The reeln-plugin-openai package provides smart zoom via OpenAI’s vision API. Enable it in plugin settings:

{
  "plugins": {
    "enabled": ["openai"],
    "settings": {
      "openai": {
        "api_key": "sk-...",
        "smart_zoom_enabled": true,
        "smart_zoom_model": "gpt-4o"
      }
    }
  }
}

When smart tracking is active, the render pipeline:

  1. Extracts frames from the clip (--zoom-frames controls how many, default 5)

  2. Emits ON_FRAMES_EXTRACTED — the vision plugin analyzes frames and returns a zoom path

  3. Builds dynamic ffmpeg expressions that follow the action throughout the clip

Smart tracking composes with both crop modes:

  • crop + smart — the crop window tracks the action point

  • pad + smart — pillarbox bars pan horizontally to center the action (vertical position stays fixed)

Iterations section

The iterations section maps event types to ordered lists of profile names. This is used for multi-iteration rendering where each event type gets a different sequence of render passes:

{
  "iterations": {
    "default": ["fullspeed"],
    "goal": ["fullspeed", "slowmo", "goal-overlay"],
    "save": ["slowmo"]
  }
}

When rendering an event, the iterations config determines which profiles to apply based on the event type. Events without a matching type fall back to the "default" key.

Use --iterate on render or game commands to activate multi-iteration rendering:

# Render a short through iteration profiles
reeln render short clip.mkv --iterate

# Apply iterations after segment merge
reeln game segment 1 --iterate

# Apply iterations after highlights merge
reeln game highlights --iterate

Each profile in the list is applied in order, and the iteration outputs are concatenated end-to-end into a single final file. For example, a goal event with profiles ["fullspeed", "slowmo", "goal-overlay"] produces a video that plays the clip at full speed, then slow motion, then with the goal overlay — all stitched together automatically.

Branding section

The branding section controls the branding overlay shown at the start of rendered shorts:

{
  "branding": {
    "enabled": true,
    "template": "builtin:branding",
    "duration": 5.0
  }
}

Key

Default

Description

enabled

true

Whether to show branding overlay

template

"builtin:branding"

Template path — "builtin:branding" for the default, or a path to a custom .ass file

duration

5.0

How long the branding is visible in seconds

The builtin branding overlay displays “reeln v{version} by https://streamn.dad” in bold white text with a black outline at the top of the video, fading in over 300ms and fading out over 800ms. To disable branding entirely, set enabled to false or use --no-branding on the CLI.

Orchestration section

The orchestration section controls the plugin pipeline behavior:

{
  "orchestration": {
    "upload_bitrate_kbps": 5000,
    "sequential": true
  }
}

Key

Default

Description

upload_bitrate_kbps

0

Maximum upload rate in KB/s (0 = unlimited)

sequential

true

Run all plugin operations sequentially

Plugins section

The plugins section controls plugin discovery and per-plugin settings:

{
  "plugins": {
    "enabled": ["youtube", "llm"],
    "disabled": ["meta"],
    "settings": {
      "youtube": {
        "api_key": "...",
        "playlist_id": "..."
      }
    }
  }
}

Key

Default

Description

enabled

[]

List of plugin names to enable (empty = all discovered)

disabled

[]

List of plugin names to disable

settings

{}

Per-plugin configuration passed during instantiation

registry_url

""

Custom plugin registry URL (empty = default GitHub URL)

enforce_hooks

true

Restrict plugins to hooks declared in the registry (set false for local plugin development)

When enabled is empty, all discovered plugins are loaded except those in disabled. When enabled is non-empty, only those named plugins are loaded (minus any in disabled).

When enforce_hooks is true (the default), plugins may only register hooks declared in their registry entry. Undeclared hooks are silently blocked with a warning log. Set to false during local plugin development to bypass enforcement.

Plugin config schemas

Plugins can declare the configuration fields they accept via a config_schema class attribute. When a plugin declares a schema:

  • Default seeding — running reeln plugins enable <name> or reeln plugins install <name> writes the plugin’s default values into plugins.settings automatically, so reeln config show reflects them immediately.

  • Validationreeln config doctor checks plugin settings against declared schemas and warns about missing required fields or type mismatches.

  • Discoveryreeln plugins info <name> displays the schema (field names, types, required/optional, defaults, descriptions).

Default seeding only adds missing keys — it never overwrites values you’ve already set. Plugins without a schema are unaffected; they continue to work with opaque settings dicts.

Supported field types

Type

JSON equivalent

Notes

str

string

Default

int

number (integer)

Rejects booleans

float

number

Accepts int values

bool

boolean

list

array

Example schema output

$ reeln plugins info youtube
Name:         youtube
Package:      reeln-youtube
...
Config schema:
  api_key: str (required)  — YouTube Data API key
  playlist_id: str  — Default playlist for uploads
  privacy: str [default: unlisted]  — Video privacy setting

Logging

The default log level is WARNING. Override it with --log-level or the REELN_LOG_LEVEL environment variable:

# CLI flag
reeln game init --log-level DEBUG ...

# Environment variable
export REELN_LOG_LEVEL=DEBUG
reeln game init ...

Valid levels: DEBUG, INFO, WARNING, ERROR, CRITICAL (case-insensitive).

The log output format is controlled by --log-format / REELN_LOG_FORMAT (default: human). Set to json for structured logging in CI/automation.

Environment variable overrides

Any config value can be overridden with an environment variable using the convention REELN_<SECTION>_<KEY>:

export REELN_VIDEO_CRF=22
export REELN_VIDEO_CODEC=libx265
export REELN_VIDEO_AUDIO_CODEC=opus
export REELN_SPORT=hockey

Config file path via environment

You can also set which config file to load via environment variables:

Variable

Description

REELN_CONFIG

Absolute or ~-relative path to a config file

REELN_PROFILE

Named profile (loads config.<profile>.json)

Priority order (highest wins):

  1. --config CLI flag

  2. REELN_CONFIG env var

  3. --profile CLI flag

  4. REELN_PROFILE env var

  5. Default XDG path (config.json)

This priority applies to both reading and writing. When a command modifies config (e.g. reeln plugins enable), the changes are written back to the same resolved path.

# Use a specific config file
export REELN_CONFIG=~/projects/tournament/reeln.json

# Or select a named profile
export REELN_PROFILE=tournament

Named profiles

In addition to the default config.json, you can create named profiles:

  • Default: config.json

  • Named: config.<profile>.json

Select a profile with the --profile flag or REELN_PROFILE env var:

reeln game init --sport hockey --home team-a --away team-b --profile tournament

# Or via env var
export REELN_PROFILE=tournament
reeln game segment 1

Profiles inherit from the default config and override specific keys.

Debug artifacts

When any command is run with --debug, pipeline debug artifacts are written to {game_dir}/debug/. This includes:

  • Per-operation JSON files — ffmpeg command, filter chain, input/output file metadata (duration, fps, resolution, codec)

  • HTML index (debug/index.html) — browsable summary linking to all debug artifacts and processed videos

Debug artifacts are automatically removed by game prune (no --all flag needed). Open debug/index.html in a browser for a quick overview of all operations performed on a game.

Team profiles and rosters

Team profiles are stored as JSON files in the config directory under teams/{level}/{slug}.json. When you initialize a game with --level, the team level and slugs are persisted in game.json, enabling roster-based player lookup during rendering.

Setting up rosters for player number lookup

  1. Create team profiles with roster_path pointing to a CSV file:

{
  "team_name": "Eagles",
  "short_name": "EGL",
  "level": "bantam",
  "roster_path": "/path/to/eagles_roster.csv",
  "colors": ["#C8102E", "#000000"]
}
  1. Create the roster CSV with number, name, and position columns:

number,name,position
48,John Smith,C
24,Jane Doe,D
2,Bob Jones,RW
  1. Initialize games with --level to persist team profile references:

reeln game init eagles bears --level bantam --sport hockey
  1. Use --player-numbers during rendering to look up players from the roster:

reeln render short clip.mkv --player-numbers 48,24,2 --event-type HOME_GOAL -r overlay

This resolves to #48 Smith (scorer) with assists #24 Doe and #2 Jones.

Schema versioning

Every config file includes a config_version field. When the schema changes, reeln provides migration functions to upgrade configs automatically.

Viewing and validating config

# Show the fully resolved config
reeln config show

# Validate config and check for issues
reeln config doctor