Shellfie header logo

Deterministic terminal visuals and executable sessions from YAML

Gem Version Downloads Ruby Version License

Features · Installation · Quick Start · Terminal Sessions · Configuration · Automation


Shellfie compiles YAML into deterministic terminal images, animations, and semantic transcripts. When explicitly requested, it can also run real PTY sessions, assert their output, record cassettes, and replay them offline.

Shellfie generating and validating an animated terminal demo
Generated by Shellfie from examples/demo_animation.yml.

Features

  • Deterministic compose mode that never executes configuration content
  • Optional PTY execution with waits, assertions, captures, and redaction
  • Editable recordings and offline cassette replay
  • PNG, WebP, native SVG, HTML, GIF, APNG, MP4, WebM, and PNG sequence output
  • Plain text, ANSI, JSON, and asciinema v2 semantic transcripts
  • macOS, Ubuntu, Windows, and custom window styles, plus a headless mode
  • ANSI colors and controls, Unicode grapheme handling, and configurable ambiguous width
  • JSON Schemas, source-aware diagnostics, formatting, compilation, completion, and watch commands
  • Resource limits, path policies, dependency preflight, and atomic output replacement

Installation

Add Shellfie to your Gemfile:

gem "shellfie"

Then install:

bundle install

Or install it directly:

gem install shellfie

Requirements

  • Ruby 3.0+
  • ImageMagick
  • ffmpeg for MP4, WebM, and APNG output

Install media dependencies on macOS:

brew install imagemagick ffmpeg

On Ubuntu or Debian:

sudo apt install imagemagick ffmpeg

Static and animated composition works on macOS, Linux, and Windows. Live PTY sessions are not supported on native Windows.

Quick Start

Create terminal.yml:

version: 1
theme: macos
title: "Terminal"

lines:
  - prompt: "$ "
    command: "echo hello"
  - output: "hello"

Generate an image:

shellfie generate terminal.yml -o terminal.png

Without -o, Shellfie writes terminal.png beside the input. shf is available as a short alias for shellfie.

Output Formats

Kind Formats
Static PNG, WebP, native selectable-text SVG, accessible HTML
Animated GIF, WebP, APNG, MP4, WebM, event-duration PNG sequence with timeline.json
Semantic TXT, ANSI, JSON, asciinema v2 (asciicast or cast)

Use svg-raster only when the legacy PNG-backed SVG behavior is required.

CLI

Command Purpose
generate Render a version 1 compose configuration
run Execute and render a version 2 terminal session
record Execute a session and save a cassette or editable YAML
replay Render a cassette without executing its commands
new / init Create or print starter configuration
format Normalize YAML formatting
compile Print the resolved configuration or session IR
validate Validate input as text, JSON, SARIF, or JUnit
inspect Show resolved settings, dimensions, fonts, and resource estimates
schema Print the version 1 or version 2 JSON Schema
completion Print bash, zsh, fish, or PowerShell completion
watch Regenerate when a configuration or include changes
themes List available themes and color schemes
doctor Check media tools, formats, fonts, policies, and storage
version Show the installed Shellfie version

Terminal Sessions

Version 2 sessions execute commands only through run or record; review a session before running it. A minimal session looks like this:

version: 2
mode: run
title: "Recorded shell"
theme: macos

terminal:
  shell: /bin/sh
  columns: 80
  rows: 16
  timeout: 10s

steps:
  - type: printf 'hello from shellfie\n'
    speed: 30cps
  - key: enter
  - expect:
      screen_contains: hello from shellfie
      exit_status: 0
  - capture: complete

outputs:
  - path: session.svg
    format: svg
    capture: complete
  - path: session.txt
    format: txt

Run, record, or replay it:

shellfie run session.yml
shellfie record session.yml --cassette session.json
shellfie record session.yml --yaml editable-recording.yml
shellfie replay session.json -o session.gif --animate

Session Actions

Action Purpose
run Execute a command directly, hidden by default
type Type visible text at a configurable rate
key Send Enter, arrows, modifiers, and other terminal keys
sleep Add a deterministic presentation pause
wait Wait for screen, line, prompt, exit, or stable-screen conditions
expect Assert screen text, lines, exit status, cursor, elapsed time, or a text golden
hide / show Control whether preparation and cleanup are recorded
capture Name an intermediate screen for a specific output

Sessions also support requires, step-level working directories, multiple outputs, reusable includes, environment allowlists, total and per-step timeouts, and redaction patterns. Set terminal.cwd_policy: root to confine working directories to the session root. Use async: true before interacting with a long-running or full-screen process, then synchronize with wait.

Variables use {{name}} placeholders. Reusable step_sets expand through use, repeat repeats a step or set, and if can select steps by OS, shell, Ruby requirement, or explicitly configured environment values. Expansion is bounded and cycles are rejected.

Authoring

Create and inspect configurations without rendering them:

shellfie new terminal.yml --template static
shellfie new demo.yml --template animation
shellfie new session.yml --template run
shellfie format terminal.yml
shellfie compile terminal.yml --format json
shellfie validate terminal.yml --format sarif
shellfie inspect terminal.yml --json
shellfie watch terminal.yml -o terminal.png

Templates include static, animation, run, tui, ci, and theme-gallery. JSON Schemas live in schema/; add the following directive for editor validation:

# yaml-language-server: $schema=../schema/shellfie-v1.schema.json

Use schema version 2 for executable sessions. Run shellfie schema 1 or shellfie schema 2 to print either schema, and shellfie completion zsh to generate shell completion.

Automation

Use the Docker-based GitHub Action to generate an output or fail when a committed output is stale:

- uses: ydah/shellfie@main
  with:
    input: examples/simple.yml
    output: docs/terminal.png
    check: "true"

Or build and run the included container locally:

docker build -t shellfie .
docker run --rm -v "$PWD:/work" shellfie \
  generate /work/examples/simple.yml -o /work/terminal.png --force

Use --manifest manifest.json during generation to record configuration and output hashes, Ruby, OS, ImageMagick, ffmpeg, and resolved font fingerprints.

Configuration

Compose Configuration

Key Purpose
theme macos, ubuntu, windows, or custom
window_theme Window chrome to use with a custom theme
color_scheme Built-in palette: dracula, one_dark, solarized_dark, or catppuccin_mocha
colors Individual color overrides
window Width, height, padding, wrapping, clipping, scrolling, and terminal policies
font Family, fallback families, size, and line height
animation Typing, timing, playback, loop, palette, and encoder controls
cursor Cursor style and color
headless Hide window chrome
lines Initial or static terminal content
frames Animated terminal events
limits Source, output-frame, pixel, and temporary-storage ceilings

Static content uses lines; animations add frames:

version: 1
theme: macos
title: "Demo"

window:
  width: 600
  padding: 20
  visible_lines: 8
  overflow: clip

animation:
  typing_speed: 50
  framerate: 30
  playback_speed: 1.0
  cursor_blink: true
  loop: true
  seed: 1

lines:
  - output: "Ready"

frames:
  - prompt: "$ "
    type: "echo hello"
    delay: 500
  - output: "hello"
    delay: 1000

A frame delay is applied after its action; on a type frame it overrides animation.command_delay. When both lines and frames are present, lines initialize the screen before animated events run.

Generate Options

Option Description
-o, --output PATH Output path or {name}-{theme}-{scale}.{format} template
--preset NAME Exact readme, ogp, widescreen, standard, or vertical canvas
-t, --theme NAME Override the theme
-a, --animate Render animation
-s, --scale FACTOR Output scale: 1, 2, or 3
-w, --width PIXELS Override width
--format FORMAT Select an output format
--check Fail if an existing output is stale without replacing it
--jobs N Render up to 32 inputs in parallel after preflight
--typing-rate CPS Override typing rate in characters per second
--framerate FPS Set output timing precision
--seed N Set the deterministic animation seed
--playback-speed FACTOR Scale the final timeline
--overflow MODE clip, wrap, or scroll
--no-shadow Disable the window shadow
--transparent Use a transparent background
--no-header Hide window chrome
--force Replace an existing output

Advanced Controls

  • Set animation.direction to forward, reverse, or ping_pong; animation.loop_offset selects a different initial frame.
  • Tune GIF colors and optimization, WebP quality and lossless mode, APNG prediction and loop count, and scroll easing under animation.
  • Set window.ambiguous_width to 1 or 2; inspection and manifests report the active Unicode and width-table profile.
  • Set window.osc_policy: preserve to keep bounded http, https, and mailto OSC 8 links in SVG and HTML.
  • Set window.graphics_policy: error to reject SIXEL, Kitty, or iTerm2 graphics instead of discarding them.
  • Use include for shared YAML. Set include_policy: root to reject paths outside the root configuration directory, including symlink escapes.
  • Set resource ceilings under limits; Shellfie checks source size, pixels, frame work, and temporary storage before expensive rendering.

How It Works

  1. Configuration parsing resolves includes, validates input, and reports source locations.
  2. Compose, live PTY, or cassette input is normalized into terminal events.
  3. The terminal screen applies Unicode, ANSI, cursor, erase, alternate-screen, and scroll behavior.
  4. Raster, SVG, HTML, video, or semantic renderers produce the requested outputs.
  5. Output files are written atomically after dependency, collision, and resource preflight.

generate is deterministic and never runs configuration content. run and record opt into PTY execution. replay uses a cassette and does not execute the recorded commands.

Development

bundle install
bundle exec rspec
gem build shellfie.gemspec

Contributing

Bug reports and pull requests are welcome. See CONTRIBUTING.md and SECURITY.md before submitting changes or security reports.

License

Released under the MIT License.