That seems to optimise for usability/complexity ratio, while completely throwing coolness under the bus. But this is a ASCII video generator, I would've thought coolness was the point? I can't imagine a practical usecase for it...
> Local AI & LLM Ready: By reducing complex pixel streams into structured logical strings, ASCILINE acts as a perfect bridge for AI. Instead of feeding heavy computer vision models, lightweight LLMs can process semantic video summaries.
In what way is this semantic/structured?
> Bypassing Browser Constraints: Modern browsers aggressively throttle autoplay videos, and ad-blockers restrict traditional media frames. To the browser, ASCILINE is simply "JavaScript updating a canvas"—completely invisible to media restrictions.
So... just render the video to a canvas? What does ASCII have to do with it
> Bypassing Browser Constraints: Modern browsers aggressively throttle autoplay videos, and ad-blockers restrict traditional media frames. To the browser, ASCILINE is simply "JavaScript updating a canvas"—completely invisible to media restrictions.
The permission granted by this license explicitly EXCLUDES the right to use this software, in whole or in part, for the purpose of serving, delivering, or displaying digital advertisements, sponsored content, or any form of commercial marketing to end-users. Any such use immediately terminates this license.
ASCILINE is a high-performance, cross-platform real-time ASCII video rendering engine. Our core objective is to transform the web into a highly dynamic and interactive typographic canvas. By mapping pixels to text-based representations, we unlock new possibilities for web media delivery.
| Output | Details |
|---|---|
| Original Source Standard MP4 video file. |
|
| ASCII Mode Showcases rendered using Mode 3 (32K Colors) from a 30fps source. |
|
| PIXEL Mode Showcases rendered using Mode 5 (16m Colors) combined with the --pixel flag for ultra-high fidelity. |
Uint8Array) directly to the canvas, saving bandwidth and CPU.INIT handshake for dynamic resolution/FPS adjustment.The original binary protocol re-sends the full grid every frame. An opt-in adaptive codec picks the smallest of three encodings per frame and tags it in a 1-byte header — without changing the rendered output:
| tag | encoding | best for |
|---|---|---|
0 RAW |
framebuffer as-is (legacy) | incompressible frames |
1 ZLIB |
zlib(framebuffer) |
general motion |
2 DELTA |
only the cells that changed since the last frame | static / low-motion |
Clients opt in with /ws?codec=adaptive; omit it and you get the original
protocol byte-for-byte, so existing clients are unaffected. A keyframe is
forced periodically so dropped packets / late joiners resync. The decoder
(codec.js) is shared by the browser and the test suite, so the shipped path is
the tested one.
Measured wire savings (mode 5, 200×80 grid):
| content | vs. legacy |
|---|---|
| static screen / slideshow | 0.3% (≈375×) |
| pixel mode | 11.6% (≈8.6×) |
| high-motion / full-frame change | 63% (never worse than legacy) |
An optional --quality {lossless,high,balanced,low} enables lossy temporal
delta: a colour cell is only re-sent once it drifts past a tolerance from what
the viewer already sees (the character plane stays exact), cutting the hard
cases a further ~15–30% at imperceptible quality. Default is lossless
(bit-exact).
Monitor Bandwidth in Real-Time:
You can append the --debug flag when launching the server to see live bandwidth comparisons (RAW vs WIRE bytes) and the exact compression ratio in your terminal. This is highly useful for measuring the real-time savings of the adaptive codec on your specific video sources.
Verified two independent ways, both bit-exact: Python-encoded vectors decoded by
codec.jsin Node (experiments/gen_vectors.py→experiments/check_vectors.js), and a liveadaptive-vs-legacyWebSocket diff (experiments/test_e2e.js). Generate the test clips withexperiments/make_test_clips.sh. (A fuller mutation-test + Autobahn
LAN / Network Streaming:
To stream the video on your local network (Wi-Fi), use the --host flag:
python stream_server.py video.mp4 --host 0.0.0.0
git clone https://github.com/YusufB5/ASCILINE.git
cd ASCILINE
pip install fastapi uvicorn opencv-python numpy websockets
To enable server-side audio processing (Volume 1-5), you must have FFmpeg installed.
Option 1: Package Manager (Recommended)
winget install ffmpegbrew install ffmpegsudo apt install ffmpegOption 2: Manual Installation (Windows)
If you get a FileNotFoundError or don't want to modify system variables:
ffmpeg.exe from the bin folder.ASCILINE project folder alongside stream_server.py.Single video:
python stream_server.py video.mp4 --cols 240
Folder mode — drop your videos into videos/ and run:
python stream_server.py --folder videos --cols 200
python stream_server.py --folder videos --cols 230 --loop # infinite loop
python stream_server.py --folder videos --mode 5 --pixel --cols 320 --vol 2 # all videos same settings
Videos play in filesystem order (top to bottom as they appear in the folder, not alphabetically). Just add/remove files from the videos/ folder to control the queue.
JSON Playlist — full control per video:
python stream_server.py --playlist playlist.json --cols 220
python stream_server.py --playlist playlist.json --cols 220 --loop
Use playlist.json when you need different --mode or --vol settings for each video.
Open http://localhost:8000 in your browser.
If you prefer to bypass the web interface, you can render the video directly inside an ANSI-supported terminal (zero-flicker, true color):
python ascii_video_player2.py video.mp4 --cols 100 --quality 0
⚠️ Note: Do not resize your terminal window during playback, as dynamic text wrapping will corrupt the ASCII layout.
You can easily customize the look and feel of the engine:
Edit style.css to change the accent colors and typography using CSS variables:
:root {
--accent-color: #00ff41; /* Classic Matrix Green */
--bg-color: #050505;
}
The engine supports different fidelity levels via the --mode flag:
1: Black & White (DOM mode)2: 512 Colors3: 32K Colors4: 262K Colors5: 16M Colors (Ultra)python stream_server.py --mode 5 --cols 240 --rows 100
By default, you only need to specify the width (--cols). ASCILINE will automatically calculate the correct --rows based on the source video's aspect ratio to prevent stretching.
--cols 200 to --cols 240 (Best balance of text detail and cinematic 30 FPS performance).--cols 600 to --cols 900 (Provides near-HD visual quality. Performance heavily depends on your machine's CPU/VRAM).Smart Defaults: If you do not specify a
--colsvalue, ASCILINE automatically defaults to450when Pixel Mode is enabled, and200for standard ASCII text mode.
⚠️ Hardware Limits & A/V Sync: If you push the
--colstoo high for your specific hardware (e.g.,1350on a laptop vs a gaming desktop), the Python backend won't be able to encode and send the massive frames fast enough. When the video stream lags behind the audio, you will experience A/V desync (audio finishing early). If this happens, simply lower your--colsvalue!
python stream_server.py video.mp4 --mode 5 --cols 240
# Terminal will show: [AUTO] 1920x1080 → grid 240x67
Volume is controlled at the server level via the --vol flag (scale 0–5).
When set to 0, the audio engine (FFmpeg) never runs, saving CPU and bandwidth.
--vol |
FFmpeg Multiplier | Description |
|---|---|---|
0 |
— | Muted (no processing) |
1 |
1.0× | Normal (default) |
3 |
1.5× | Loud |
5 |
2.0× | Double volume |
python stream_server.py video.mp4 --pixel --cols 560 --vol 0 # Silent
python stream_server.py video.mp4 --cols 220 --vol 3 # Loud
playlist.json)Each entry can override the global --mode, --pixel, --vol, and --cols defaults:
[
{ "video": "intro.mp4", "mode": 1, "vol": 1 },
{ "video": "main.mp4", "mode": 5, "pixel": true, "vol": 3, "cols": 520 },
{ "video": "outro.mp4", "mode": 3, "vol": 2, "cols": 240 }
]
Video paths are resolved automatically — the engine checks the project root and the videos/ subfolder, so you can write just the filename.
Experience the ASCILINE engine running live directly in your browser with multiple rendering modes. 👉 Try it out at asciline.dev
If you find this project helpful, you can support me by donating crypto:
H1wSQAhjgsu7AxenF4e5ZBYiBjkhDLVzkKaZuVPcrE140x85B2f970045c0F7c282089Ab6CF897C20230e086bc1qvtcl55v54gkzwnp2zxn70usea3gf5ncncqa0fvASCILINE is distributed under the MIT License, but with an anti ad strict ethical guardrail.
See the LICENSE file for the full text, which includes the ANTI-ADVERTISEMENT RESTRICTION clause.