← All apps

SugarReel

🎬 SugarReel

Terminal video player

no single upstream mp4 gif ascii sixel kitty iterm2 ffmpeg ext-gd

Terminal video player — plays mp4, gif, avi, webm on the fly, rendering each frame as ASCII, ANSI 256-color, truecolor half-blocks, or via modern graphics protocols (sixel / kitty / iTerm2). PHP port of tplay, glyph, and video-to-ascii.

Install

composer require sugarcraft/sugar-reel

Quickstart

php examples/play.php video.mp4           # play a video
php examples/play.php                    # synthetic test pattern (no file needed)

# Programmatic:
use SugarCraft\Reel\Player;
$player = Player::open('clip.mp4', cols: 80, rows: 24);
(new \SugarCraft\Core\Program($player))->run();

Rendering modes

ModeDescriptionTerminal requirement
asciiGrayscale luminance rampAny
ansi256256-color cube + grey ramp256-color
truecolor24-bit RGB truecolor24-bit color
halfblock24-bit ▀ half-blocks, 2x vertical resolution24-bit color
sixelSixel raster graphics protocol (DEC)Sixel-capable
kittyKitty graphics protocol (DCS APC)Kitty-compatible
iterm2iTerm2 inline image (OSC 1337)iTerm2 / WezTerm

Keyboard controls

KeyAction
SpacePause / resume
Seek backward 10 frames
Seek forward 10 frames
[Decrease playback speed (-0.25x, min 0.25x)
]Increase playback speed (+0.25x, max 4.0x)
0-9Seek to 0-90% of video duration
mCycle to next rendering mode
q / EscQuit
resizeTerminal resize (SIGWINCH) re-scales video automatically

What's in the box

Multi-format decodeffmpeg for mp4/avi/webm, pure-PHP + ext-gd for GIF. No external deps beyond ffmpeg for video files.
7 rendering modesascii, ansi256, truecolor, half-block, sixel, kitty, iTerm2 — auto-detects terminal capability and picks the best available.
Auto terminal resizeSIGWINCH handler re-scales video to fit the new terminal dimensions without restarting playback.
Seek + speed controlKeyboard-driven seek (arrows, 0-9) and speed control ([ / ]) with frame-skip resync.
Audio companionAudioPlayer shells out to ffplay or mpv as the audio master clock; degrades gracefully when no audio track is present.
Loop playbackReel::new()->withLoop(true)->play() loops from end back to start automatically.
Delta repaintOnly changed cells are re-rendered each frame, dramatically reducing output for static scenes.
SGR run-length coalescingAsciiRenderer emits color SGR codes only on color transitions (~60% output reduction for typical frames).

Source & demos

Try the quickstart →

API

ClassMethodDescription
Reel::open(path)Open a video file
Reel::new()Create unbound player (synthetic test pattern)
ReelwithMode(Mode)Set rendering mode
ReelwithSize(cols, rows)Set terminal cell dimensions
ReelwithFps(?float)FPS override (null = auto-detect)
ReelwithLoop(bool)Enable/disable loop
Reelplay()Run the player
Player::open(path, cols, rows, fps, mode, loop)Open a video source
Player::openForTest(decoder, cols, rows, fps, mode, loop)Open with injected decoder for testing
LumaRamp::char(luma, ramp)Map 0-255 luminance to character
LumaRamp::compute(r, g, b)Compute BT.601 luma from RGB

Demos.

VHS-recorded GIFs of every example shipped with the app. Regenerated automatically on every push that touches the source.

Play

Play

Synthetic rainbow-gradient GIF rendered in all modes.