Terminal Media Engine — Pixel-Perfect Rendering at 60fps
Render images, play videos, and stream audio entirely inside your terminal. Native C engine with Sixel graphics, Lanczos3 interpolation, and quarter-block Unicode for HD output on any platform.
Author : MERO:TG@QP4RM
Version : 1.0.0
License : Proprietary (see LICENSE)
termflux is a Python library backed by a C rendering engine. It decodes media with FFmpeg and draws pixels directly into the terminal — no GUI, no browser, no external windows.
Three render modes:
| Mode | Resolution | Method | Terminal Support |
|---|---|---|---|
| Sixel | Up to 1920x1080 real pixels | Sixel bitmap protocol | mlterm, foot, WezTerm, iTerm2 |
| Quarter-Block | 2x columns, 2x rows | 16 Unicode block patterns | All terminals |
| Half-Block | columns, 2x rows | Upper/lower half blocks | All terminals |
Core capabilities:
- Image display with 24-bit true color
- Video playback at native framerate (up to 60fps)
- Audio playback with built-in terminal visualizer (waveform, progress, metadata)
- URL loading — pass a link, termflux downloads and renders
- Color filters: brightness, contrast, saturation, grayscale, invert
- 5 border styles with custom RGB colors, thickness 1-5, configurable padding
- 9 screen positions (center, top, bottom, left, right, corners)
- 3 aspect ratio modes (fit, fill, stretch)
- Cross-platform: Linux, Windows 10+, macOS, Android (Termux / Pydroid / QPython)
- Pure Python fallback when no C compiler is available
pip install termflux- Python >= 3.8
- FFmpeg (video/image decoding and audio playback)
# Debian / Ubuntu
sudo apt install ffmpeg
# macOS
brew install ffmpeg
# Windows
# Download from https://ffmpeg.org/download.html and add to PATH
# Android Termux
pkg install python ffmpeggit clone https://github.com/6x-u/termflux.git
cd termflux
pip install -e .The C extensions (_engine and _decoder) build automatically. If compilation fails (e.g., no FFmpeg dev headers), the library falls back to pure Python.
import termflux
img = termflux.Image("photo.jpg")
img.show(
border_style=termflux.BORDER_ROUND,
border_r=255, border_g=215, border_b=0,
render_mode=termflux.RENDER_QUARTER,
)
input()
termflux.reset()import termflux
vid = termflux.Video("video.mp4")
vid.play(
render_mode=termflux.RENDER_QUARTER,
with_audio=True,
brightness=1.05,
saturation=1.15,
)import termflux
audio = termflux.Audio("track.mp3")
audio.play()Displays a full terminal UI with waveform visualization, progress bar, elapsed time, codec info, and playback status.
import termflux
img = termflux.Image("https://example.com/photo.jpg")
img.show()
vid = termflux.Video("https://example.com/clip.mp4")
vid.play(with_audio=True)# Basic image display
termflux photo.jpg
# Gold round border
termflux photo.jpg -b round --border-color 255,215,0
# Video with audio
termflux video.mp4
# Sixel mode (pixel-perfect on supported terminals)
termflux photo.jpg -r sixel
# Grayscale with thick double border
termflux photo.jpg --grayscale -b double --border-thick 3
# High contrast vivid video
termflux video.mp4 --contrast 1.4 --saturation 1.6 --brightness 1.1
# Audio playback
termflux song.mp3 -t audio
# Custom position and size
termflux photo.jpg -p top-left -W 60 -H 30 -b single
# Inverted colors with padding
termflux photo.jpg --invert --padding 2 -b round
# Stretch to fill
termflux photo.jpg --aspect stretch
# Loop video
termflux video.mp4 -l| Option | Short | Default | Description |
|---|---|---|---|
source |
required | File path or URL | |
--type |
-t |
auto | Force type: image, video, audio |
--width |
-W |
auto | Width in columns |
--height |
-H |
auto | Height in rows |
--position |
-p |
center |
center, top, bottom, left, right, top-left, top-right, bottom-left, bottom-right |
--border |
-b |
none |
none, single, double, bold, round |
--border-color |
255,255,255 |
RGB values comma-separated | |
--border-thick |
1 |
Border thickness (1-5) | |
--padding |
0 |
Padding inside border | |
--render |
-r |
quarter |
sixel, quarter, half |
--aspect |
fit |
fit, fill, stretch |
|
--brightness |
1.0 |
0.0 - 3.0 | |
--contrast |
1.0 |
0.0 - 3.0 | |
--saturation |
1.0 |
0.0 - 3.0 | |
--grayscale |
false |
Convert to grayscale | |
--invert |
false |
Invert colors | |
--loop |
-l |
false |
Loop video |
img = termflux.Image(source) # file path or URL
img.width # source width in pixels
img.height # source height in pixels
img.pixels # raw RGB bytes (width * height * 3)
img.show(
border_style=termflux.BORDER_NONE, # BORDER_NONE / SINGLE / DOUBLE / BOLD / ROUND
border_r=255, border_g=255, border_b=255,
position="center",
width=None, height=None, # override display size
render_mode=termflux.RENDER_QUARTER, # RENDER_SIXEL / RENDER_QUARTER / RENDER_HALF
border_thick=1,
padding=0,
brightness=1.0,
contrast=1.0,
saturation=1.0,
grayscale=False,
invert=False,
aspect="fit", # fit / fill / stretch
)vid = termflux.Video(source)
vid.width # frame width
vid.height # frame height
vid.fps # frames per second
vid.duration # duration in seconds
vid.play(
border_style=termflux.BORDER_NONE,
border_r=255, border_g=255, border_b=255,
position="center",
width=None, height=None,
with_audio=True, # sync audio playback
loop=False,
render_mode=termflux.RENDER_QUARTER,
border_thick=1,
padding=0,
brightness=1.0,
contrast=1.0,
saturation=1.0,
grayscale=False,
invert=False,
aspect="fit",
)audio = termflux.Audio(source)
audio.play() # blocking, shows terminal UI
audio.play(show_ui=False) # blocking, no UI
audio.play_background() # non-blocking background playback
audio.stop()
audio.is_playing # boolp = termflux.Player(source, media_type=None) # auto-detects type
p.border(termflux.BORDER_ROUND, 255, 215, 0)
p.border_thickness(2)
p.set_padding(1)
p.position("center")
p.size(width=80, height=40)
p.render_mode(termflux.RENDER_QUARTER)
p.set_aspect("fit")
p.set_brightness(1.1)
p.set_contrast(1.2)
p.set_saturation(1.3)
p.set_grayscale(False)
p.set_invert(False)
p.loop(True)
p.show()# Terminal control
termflux.clear_screen()
termflux.hide_cursor()
termflux.show_cursor()
termflux.reset()
cols, rows = termflux.get_terminal_size()
# Render raw RGB data to terminal escape sequences
frame = termflux.render_frame(
pixels, width, height,
term_width=80, term_height=24,
offset_x=0, offset_y=0,
border_style=termflux.BORDER_NONE,
border_r=255, border_g=255, border_b=255,
render_mode=termflux.RENDER_QUARTER,
border_thick=1, padding=0,
brightness=1.0, contrast=1.0, saturation=1.0,
grayscale=0, invert=0,
)
termflux.flush_frame(frame)
# Scale pixel data (uses Lanczos3 for large ratios, bilinear otherwise)
scaled = termflux.scale(pixels, src_w, src_h, dst_w, dst_h)
# Precise sleep (nanosleep on POSIX, QueryPerformanceCounter on Windows)
termflux.sleep_precise(0.016)
# Windows ANSI support
termflux.enable_ansi()# Border styles
termflux.BORDER_NONE # 0
termflux.BORDER_SINGLE # 1 — ┌─┐│└─┘
termflux.BORDER_DOUBLE # 2 — ╔═╗║╚═╝
termflux.BORDER_BOLD # 3 — ┏━┓┃┗━┛
termflux.BORDER_ROUND # 4 — ╭─╮│╰─╯
# Render modes
termflux.RENDER_HALF # 0 — classic half-block
termflux.RENDER_QUARTER # 1 — HD quarter-block (default)
termflux.RENDER_SIXEL # 2 — pixel-perfect Sixel bitmapPixel-level bitmap rendering using the Sixel protocol. Renders actual pixels — not character approximations. Supports up to 256 colors with Floyd-Steinberg dithering and RLE compression. Best quality available.
Supported terminals: mlterm 3.9+, foot, WezTerm, iTerm2 3.3+, xterm (with sixel compiled in), mintty.
Uses 16 Unicode quarter-block characters (U+2580-U+259F) to render a 2x2 pixel grid per terminal cell. Each cell maps 4 sub-pixels to 2 colors (foreground + background) using perceptual color distance. Double the horizontal resolution of half-block mode.
Scaling uses Lanczos3 interpolation for downsampling ratios > 1.2x, producing sharper output than bilinear filtering.
Classic rendering using upper-half (▀) and lower-half (▄) block characters. One cell = 2 vertical pixels. Compatible with every terminal that supports 24-bit ANSI color.
| Platform | Engine | Audio | Video | Sixel |
|---|---|---|---|---|
| Linux x86_64 | C native | ffplay, mpv, aplay | FFmpeg C API | depends on terminal |
| Linux aarch64 | C native | ffplay, mpv, aplay | FFmpeg C API | depends on terminal |
| Windows x86 | C native | ffplay, mpv | FFmpeg C API | limited |
| Windows x64 | C native | ffplay, mpv | FFmpeg C API | limited |
| macOS | C native | ffplay, mpv, play | FFmpeg C API | iTerm2 |
| Android Termux | C native | termux-media-player, ffplay | FFmpeg C API | depends on terminal |
| Android Pydroid | Python fallback | limited | FFmpeg subprocess | limited |
| Android QPython | Python fallback | limited | FFmpeg subprocess | limited |
The pure Python fallback (_fallback.py) provides full rendering capabilities without requiring C compilation. It activates automatically when the C extension fails to load.
termflux/
├── _engine.c C rendering engine
│ - Bilinear + Lanczos3 scaling
│ - Half-block, quarter-block, Sixel renderers
│ - Color filters (brightness, contrast, saturation)
│ - Border drawing with 5 styles
│ - Perceptual color distance
│
├── _decoder.c C media decoder (FFmpeg API)
│ - Video frame extraction (rgb24)
│ - Seek support
│
├── _fallback.py Pure Python rendering engine
│ - Full feature parity with C engine
│ - Works on Android without C compiler
│
├── image.py Image display API
├── video.py Video playback with frame timing + audio sync
├── audio.py Audio playback with terminal UI visualizer
├── player.py Unified Player API
├── loader.py URL fetcher + file resolver
├── cli.py Command-line interface
└── __init__.py Package exports
See the examples/ directory:
| Script | Description |
|---|---|
show_image.py |
Display image with golden round border |
play_video.py |
Play video with pink bold border and audio |
play_audio.py |
Play audio with terminal visualizer |
color_filters.py |
Demonstrate brightness, contrast, saturation, grayscale, invert |
border_styles.py |
Show all 5 border styles side by side |
player_api.py |
Unified Player API usage |
video_with_headers.py |
Video playback with HUD overlay (title, progress, timer) |
demo.py |
Full feature demo script |
scripts/quick_image.sh # One-liner image display
scripts/quick_video.sh # One-liner video playback
scripts/quick_audio.sh # One-liner audio playbackpip install build
python -m buildThe repository includes GitHub Actions workflow (.github/workflows/build.yml) that builds:
- Linux: x86_64, aarch64 (manylinux)
- Windows: AMD64 (x64), x86 (32-bit)
- Source distribution: universal
Triggered on version tags (v*) or manual dispatch.
git tag v1.0.0
git push origin v1.0.0.png .jpg .jpeg .bmp .gif .tiff .webp .ico
.mp4 .avi .mkv .mov .webm .flv .wmv .m4v
.mp3 .wav .ogg .flac .aac .m4a .wma .opus
Any format supported by FFmpeg works. The above are auto-detected by file extension.
Proprietary. See LICENSE for terms.
- Free to use in personal and commercial projects
- Modification allowed
- Must retain author attribution: MERO:TG@QP4RM
- Must retain project name: termflux
- Cannot remove or change copyright notices
- Cannot redistribute as standalone library under different name/author
termflux v1.0.0
Author: MERO:TG@QP4RM
https://github.com/6x-u/termflux