plansi
plansi - Plays videos as differential ANSI in terminals.
plansi.player
Main Player class that orchestrates video playback with differential rendering.
Player Objects
class Player()
Video player that generates (timestamp, ansi_str) tuples.
__init__
def __init__(width: int = 80,
color_threshold: float = 5.0,
fps: float = None,
no_diff: bool = False,
debug: bool = False,
realtime: bool = True)
Initialize video player.
Arguments:
width
- Terminal width in characterscolor_threshold
- RGB distance threshold for color changes (0.0-441.0)fps
- Target playback FPS, None for original rateno_diff
- Disable differential renderingdebug
- Enable debug outputrealtime
- Skip frames to maintain real-time playback (True for console, False for cast files)
play
def play(video_path: str) -> Iterator[Tuple[float, str]]
Generate (timestamp, ansi_str) tuples for video playbook.
Arguments:
video_path
- Path to video file
Yields:
Tuples of (timestamp_seconds, ansi_escape_sequences)
frames
def frames(video_path: str) -> Iterator[Tuple[float, str]]
Generate raw frame data without timing delays.
Arguments:
video_path
- Path to video file
Yields:
Tuples of (timestamp_seconds, ansi_escape_sequences)
cast_entries
def cast_entries(video_path: str) -> Iterator[str]
Generate .cast file entries (JSON lines).
Arguments:
video_path
- Path to video file
Yields:
JSON strings for .cast file format
plansi.core.video
Video frame extraction using PyAV with scaling.
VideoExtractor Objects
class VideoExtractor()
Extracts and scales video frames using PyAV.
__init__
def __init__(video_path: str, width: int, fps: float = None)
Initialize video extractor.
Arguments:
video_path
- Path to video filewidth
- Target width in characters (height auto-calculated)fps
- Target FPS, None for original rate
frames
def frames() -> Iterator[Tuple[float, Image.Image]]
Generate (timestamp, PIL.Image) tuples.
plansi.core
plansi.core.terminal_render
ANSI rendering using bittty terminal emulator with dual buffer approach.
TerminalRenderer Objects
class TerminalRenderer()
Renders frames using bittty dual buffer approach.
- Main buffer: What we’ve sent to the real terminal
- Alt buffer: New frame rendered with chafa
- Diff the buffers and output only changed cells
__init__
def __init__(width: int,
height: int,
color_threshold: float = 5.0,
debug: bool = False)
Initialize terminal renderer.
Arguments:
width
- Width in character cellsheight
- Height in character cellscolor_threshold
- RGB distance threshold for color changes (0.0-441.67)debug
- Enable debug output
render_differential
def render_differential(
image: Image.Image, changed_cells: Set[Tuple[int,
int]]) -> Tuple[str, int]
Render only changed cells using dual buffer approach.
Arguments:
image
- Current frame as PIL Imagechanged_cells
- Set of (cell_x, cell_y) that have changed (IGNORED)
Returns:
Tuple of (ANSI string with cursor movements and cell updates, number of changed cells)
clear_cache
def clear_cache()
Clear both buffers to force full refresh.
plansi.__main__
Command-line interface for plansi.
main
def main()
Main CLI entry point.
play_to_console
def play_to_console(player: Player, video_path: str)
Play video to console (timing handled by Player.play() with realtime flag).
write_cast_file
def write_cast_file(player: Player, video_path: str, output_path: str)
Write video to .cast file format.