Made for Intersession 2026
Project description
PDASC (Panda ASCII)
A high-performance terminal-based ASCII art converter that transforms images, videos, and live camera feeds into colored ASCII art. Features hardware-accelerated processing with Numba, custom font-based character mapping, and a proprietary .asc file format with Zstandard compression for instant playback.
Example: High-resolution image converted to colored ASCII art
Example: Video playback with synchronized audio
Features
-
Multiple Input Sources
- Static images (PNG, JPG, GIF, BMP, TIFF, WebP)
- Video files (MP4, AVI, MOV, MKV, WebM, FLV, WMV, M4V)
- Live camera feed with real-time processing
- Pre-encoded
.ascfiles for instant playback
-
Advanced Processing
- Hardware-accelerated conversion using Numba JIT compilation
- Customizable character sets generated from any TrueType font
- Configurable ASCII density (number of characters used)
- Adjustable block size for quality vs. performance tuning
- Full RGB color support with terminal ANSI 24-bit color codes
-
Audio Support
- Synchronized audio playback for videos
- Real-time audio streaming during live camera mode
- PCM16 audio encoding in
.ascformat
-
Instant Playback
- Custom
.asc(ASCII Container) binary format with Zstandard compression - Pre-rendered ANSI escape sequences stored directly
- Minimal processing overhead during playback (decompression only)
- Frame-accurate synchronization with audio
- Custom
-
Web Interface
- Interactive image converter with real-time preview
- Adjustable sliders for ASCII density and block size
- Color toggle for colored/grayscale output
- Drag-and-drop image upload
- Video player with full controls for
.asc.mp4files
-
GPU-Accelerated Video Processing
- OpenGL shader-based ASCII rendering for videos
- Outputs
.asc.mp4format for web playback - Necessary for smooth browser performance (browsers can't efficiently update thousands of span tags at 30+ FPS)
Table of Contents
- Installation
- Quick Start
- Usage
- The .asc File Format
- How It Works
- Performance Optimization
- Examples
- Troubleshooting
- License
Installation
Prerequisites
- Python 3.10 or higher
- A modern terminal with 24-bit color support (most modern terminals)
- FFmpeg (required for all video and audio processing) - download from ffmpeg.org
Install with pip
pip install -r requirements.txt
Install with uv
# Install uv if you haven't already
pip install uv
# Install dependencies
uv sync
Required packages:
numpy- Fast numerical operationsPillow- Image processingnumba- JIT compilation for performancesounddevice- Audio playbackopencv-python- Camera and video processingzstandard- Fast compression/decompressionflask- Web server for interactive interfacemoderngl- GPU-accelerated video processing
Font Setup
The project comes pre-bundled with two fonts in the fonts/ directory:
CascadiaMono.ttf- Default monospace font (Windows Terminal default)font8x8.ttf- 8×8 pixel font for compact rendering
You can also use any TrueType font by specifying a custom path with the --font option.
Other recommended fonts:
- JetBrains Mono
- Fira Code
- Any monospace TrueType font
Quick Start
# Display an image in terminal
python cli.py play image.png
# Play a video with audio in terminal
python cli.py play video.mp4
# Use your webcam
python cli.py play camera
# Encode a video to .asc format for instant playback
python cli.py encode video.mp4 -o output.asc
# Play the encoded file (blazing fast!)
python cli.py play output.asc
# Launch interactive web interface
python cli.py website
# Convert video with GPU acceleration and play in browser
python cli.py play video.mp4 --website
Usage
The CLI has three main commands: play (for displaying/playing), encode (for creating .asc files), and website (for launching the web interface).
Play Command
Display images, play videos, stream from camera, or play .asc files.
python cli.py play <input> [options]
Input types:
- Path to an image file
- Path to a video file
- Path to a
.ascfile - Path to a
.asc.mp4file (GPU-processed video for web) camerafor webcam input
Examples:
# Display an image in terminal
python cli.py play photo.png
# Play a video without audio
python cli.py play movie.mp4 --no-audio
# Use webcam with higher ASCII density
python cli.py play camera -n 70
# Play with larger block size (lower resolution, better performance)
python cli.py play video.mp4 -b 16
# Play with custom font
python cli.py play image.png -f "fonts/JetBrainsMono.ttf"
# Use a different camera (default is 0)
python cli.py play camera -c 1
# Convert video with GPU and play in browser (only -n supported, not -b)
python cli.py play video.mp4 --website -n 32
# Specify custom output path for web video
python cli.py play video.mp4 --website -o custom_output.asc.mp4
# Play existing .asc.mp4 file in browser
python cli.py play output.asc.mp4 --website
# Enable debug mode to show FPS
python cli.py play video.mp4 --debug
Encode Command
Convert images or videos to the .asc format for instant playback with minimal processing overhead.
python cli.py encode <input> -o <output.asc> [options]
Examples:
# Encode a video with default settings
python cli.py encode movie.mp4 -o movie.asc
# Encode an image without color
python cli.py encode photo.png -o photo.asc --no-color
# Encode with custom ASCII density
python cli.py encode video.mp4 -o video.asc -n 70
# Encode with larger blocks for better performance
python cli.py encode large_video.mp4 -o output.asc -b 16
Website Command
Launch an interactive web interface for real-time ASCII art conversion.
python cli.py website
Features:
- Drag-and-drop image upload
- Real-time ASCII preview
- Adjustable ASCII character count (2-64)
- Adjustable block size (2-32)
- Color toggle
- Auto-scaling to fit browser window
The website will be available at http://localhost:5000 by default.
Command Options
| Option | Short | Default | Description | Availability |
|---|---|---|---|---|
--block-size |
-b |
8 |
Size of character blocks (pixels per character). Must be a factor of image dimensions. Higher = lower resolution but better performance | play (except with --website), encode |
--num-ascii |
-n |
8 |
Number of ASCII characters to use (2-95, capped at available characters). Higher = more detail in grayscale gradients | play, encode |
--font |
-f |
fonts/CascadiaMono.ttf |
Path to TrueType font file for character generation | play, encode |
--no-color |
- | False |
Disable color output (grayscale only) | play, encode |
--no-audio |
- | False |
Disable audio playback for videos | play, encode |
--camera |
-c |
0 |
Camera index when using camera input | play |
--output |
-o |
ascii_out.asc |
Output file path | encode, play --website |
--debug |
- | False |
Enable debug mode to show FPS and other debug info | play |
--website |
- | False |
Open a local website to display the ASCII video | play |
Note on block size: The block size must be a factor of both the image width and height, and must not be larger than the image dimensions. If invalid, the program will fail.
Note on ASCII characters: The --num-ascii parameter will automatically cap at the total number of available ASCII characters (95 printable characters).
The .asc File Format
The .asc (ASCII Container) format is a custom binary format designed for instant playback of ASCII art animations. It stores pre-rendered ANSI escape sequences compressed with Zstandard, enabling near-instant decompression and zero conversion overhead during playback.
Storage Characteristics
The .asc format typically requires ~20× more storage than the original image/video due to storing complete ANSI escape sequences for every frame. However, Zstandard compression (level 5) significantly reduces this overhead.
Example compression results (see sizes.txt for detailed benchmarks):
- 5326 frames, 720p (960×720), block-size 4, num-ascii 32, colored with audio:
- Original video (H.264): 48.3 MB
- Uncompressed ANSI: 3.62 GB
- Zstandard level 5 (colored): 722.15 MB (~5× compression)
- Zstandard level 5 (no color): 93.55 MB (~38.7× compression)
- Audio (uncompressed PCM16): 35.85 MB
Color output requires significantly more storage than grayscale due to RGB color codes for each character.
Design Philosophy
The .asc format prioritizes instant playback over storage efficiency. By pre-rendering all frames as complete ANSI strings during encoding and compressing them with Zstandard (level 5), playback requires only decompression—no conversion processing. The format balances reasonable file sizes with minimal CPU overhead during playback, making it ideal for smooth, frame-accurate video playback in terminal environments.
Format Specification
Header (24 bytes)
| Offset | Size | Type | Description |
|---|---|---|---|
| 0x00 | 4 | char | Magic number: "ASII" (ASCII with compression) |
| 0x04 | 2 | uint16 | Version number (currently 2) |
| 0x06 | 2 | uint16 | Flags (bit field) |
| 0x08 | 4 | float | FPS (frames per second) |
| 0x0C | 4 | uint32 | Frame count |
| 0x10 | 8 | - | Reserved for future use |
Flags (bit field)
Bit 0: IS_VIDEO (0x01) - Multiple frames (video)
Bit 1: HAS_AUDIO (0x02) - Audio data is present
Bits 2-15: Reserved
Frame Index Section
Following the header, frame lengths are stored for quick random access:
| Offset | Size | Type | Description |
|---|---|---|---|
| variable | 4 | uint32 | Frame 1 uncompressed length (bytes) |
| +4 | 4 | uint32 | Frame 2 uncompressed length (bytes) |
| ... | ... | ... | ... (one entry per frame) |
Compressed Frame Data
After the frame index:
| Offset | Size | Type | Description |
|---|---|---|---|
| variable | 4 | uint32 | Compressed data size (bytes) |
| +4 | variable | bytes | Zstandard-compressed frame data |
The compressed data contains all frames concatenated together. Each frame string contains:
- ANSI 24-bit color escape sequences (
\033[38;2;R;G;Bm) - ASCII characters (typically doubled for better aspect ratio)
- Newline characters for row separation
- ANSI reset sequences
Example frame string structure (before compression):
\033[38;2;45;67;89m##\033[38;2;50;70;92m##...\n\033[38;2;42;65;88m##...
Audio Section (optional)
If HAS_AUDIO flag is set, audio data follows the compressed frames:
| Offset | Size | Type | Description |
|---|---|---|---|
| variable | 4 | uint32 | Audio data size in bytes |
| +4 | 1 | uint8 | Audio format (1 = PCM16) |
| +5 | 4 | uint32 | Sample rate (Hz) |
| +9 | 1 | uint8 | Number of channels |
| +10 | variable | bytes | Raw PCM16 audio data |
Why Use .asc Files?
Despite requiring ~20× more raw storage before compression, .asc files offer significant advantages:
- Minimal processing overhead - Only decompression, no conversion
- Frame-perfect synchronization - Eliminates conversion lag
- Consistent performance - Predictable CPU usage
- Instant startup - Fast initial decompression
- Reasonable file sizes - Good compression with Zstandard
- Predictable playback - Same experience on all hardware
The format is ideal for scenarios where smooth, reliable playback is more important than real-time conversion.
How It Works
1. Character Mapping Generation
The system analyzes a TrueType font to create an optimal character-to-brightness mapping:
# Generate luminance values for each printable ASCII character
color_ramp = generate_color_ramp(font_path="fonts/CascadiaMono.ttf")
# Select N characters with the most uniform brightness distribution
char_map = get_charmap(color_ramp, levels=8)
# Result: " .:-=+*#%@" (from darkest to brightest)
Each character is rendered at 48×48 pixels, and its average luminance is computed. Characters are then mapped to the nearest quantized luminance value to create a uniform grayscale ramp.
2. Image Processing Pipeline
Input Image/Frame
↓
Divide into blocks (e.g., 8×8 pixels)
↓
Compute average color per block (Numba-accelerated)
↓
Calculate luminance: L = 0.2126R + 0.7152G + 0.0722B
↓
Map luminance to character index
↓
Generate ANSI escape sequence with RGB color
↓
Assemble complete frame string
↓
Compress with Zstandard (encode) or Render to terminal (play)
3. Numba Acceleration
The core processing loop is JIT-compiled with Numba for near-C performance:
@njit(parallel=True, fastmath=True, cache=True)
def compute_blocks(img, cs, gray_levels, color):
# Parallel processing of image blocks
# Significantly faster than pure Python
...
4. GPU Video Rendering for Web Playback
For video playback in browsers with the --website flag, PDASC uses ModernGL with OpenGL shaders to render ASCII video. This approach is necessary because browsers cannot efficiently update thousands of nested span tags at 30+ FPS:
# Fragment shader processes each pixel in parallel
# Converts RGB to ASCII character lookup
# Outputs .asc.mp4 for web playback
The GPU rendering outputs to ascii_{video_name}.asc.{video_ext} by default, or to a custom path specified with the -o parameter when using play --website. This creates a standard video file that browsers can play smoothly.
5. Terminal Rendering
Output uses ANSI escape sequences for:
- 24-bit true color:
\033[38;2;{r};{g};{b}m - Cursor positioning:
\033[H(home position) - Alternate screen buffer:
\033[?1049h(enter) /\033[?1049l(exit) - Cursor visibility:
\033[?25l(hide) /\033[?25h(show)
6. Encoding Process
When encoding to .asc format:
- Process each video frame through the conversion pipeline
- Render each frame to a complete ANSI string
- Compress all frames together using Zstandard level 5
- Write frame length index for random access
- Write compressed frame data
- Optionally extract and append PCM16 audio data
- Store metadata (FPS, frame count, flags) in header
7. Playback Process
When playing .asc files:
- Read header to determine FPS and frame count
- Decompress all frames using Zstandard (fast one-time operation)
- Write strings directly to terminal at target FPS
- Stream audio in parallel if present
- No conversion or re-processing required
Performance Optimization
Block Size vs. Quality
| Block Size | Resolution | Performance | Use Case |
|---|---|---|---|
| 4×4 | Very High | Good | High-quality images and videos |
| 8×8 | High | Better | Default, recommended |
| 16×16 | Medium | Best | Lower-end hardware |
| 32×32 | Low | Fastest | Very limited hardware |
Note: Block size affects encoding time and output quality. Playback performance depends mainly on decompression speed. Block size must be a factor of both image width and height.
Number of ASCII Characters
| Num ASCII | Detail | Character Set Size | Use Case |
|---|---|---|---|
| 4-16 | Low | Small | Artistic effect, retro look |
| 32-64 | Medium | Medium | Good balance |
| 70-95 | High | Large | Maximum detail preservation |
Best Practices
- For webcam/real-time: Use
-b 8 -n 32for smooth live processing - For high-quality images: Use
-b 4 -n 70for maximum detail - For video playback: Always encode to
.ascfirst for best performance - For web playback: Use
--websiteflag with GPU acceleration - For storage constraints: Use grayscale (
--no-color) for 5-8× smaller files - For terminal size constraints: Match block size to terminal dimensions
Examples
Example 1: Display an Image
python cli.py play landscape.png -n 50 -b 8
Landscape image with 50 ASCII characters
Example 2: Webcam Streaming
python cli.py play camera -b 12 -n 40
Real-time webcam feed at 30 FPS
Example 3: Grayscale Art
python cli.py play artwork.png --no-color -n 95
Black and white image with maximum character variety
Example 4: Interactive Web Interface
python cli.py website
Then open http://localhost:5000 in your browser to use the interactive converter.
Example 5: GPU-Rendered Web Video
python cli.py play movie.mp4 --website
Renders the video using GPU shaders and opens a web player for smooth browser playback. The output is saved to ascii_movie.asc.mp4 by default.
Troubleshooting
Camera Not Working
# Error: "Could not open camera 0"
# Solution: Try different camera index
python cli.py play camera -c 1
# On Linux, check available cameras:
ls /dev/video*
Video Playback Issues
Frames dropping or stuttering:
- Increase block size during encoding:
-b 16 - Reduce ASCII density:
-n 32 - Ensure you're playing from
.ascfile, not converting in real-time
Audio out of sync:
- This typically occurs when processing frames in real-time
- Always encode to
.ascformat first for perfect synchronization
Terminal Issues
Colors not displaying:
- Ensure your terminal supports 24-bit color
- Test with:
printf "\x1b[38;2;255;100;0mTRUECOLOR\x1b[0m\n" - Try different terminal emulators (Windows Terminal, iTerm2, Alacritty)
Display cut off:
- The program automatically scales to fit terminal size
- Maximize your terminal window for best results
- Use smaller block sizes for more content in limited space
FFmpeg Errors
FFmpeg not found:
- Download and install FFmpeg from ffmpeg.org
- Ensure FFmpeg is in your system PATH
- Test with:
ffmpeg -version
Install instructions:
- Ubuntu/Debian:
sudo apt install ffmpeg - macOS:
brew install ffmpeg - Windows: Download from ffmpeg.org and add to PATH
Out of memory during encoding:
- Process videos in smaller chunks
- Use larger block sizes to reduce frame string size
- Close other applications to free RAM
Compression takes too long:
- This is normal for long videos with high detail
- Consider using larger block sizes (
-b 16or-b 32) - Compression is a one-time cost for much faster playback
Font Errors
# Error: "Font file not found"
# Solution: Use bundled fonts or specify full path
python cli.py play image.png -f "fonts/CascadiaMono.ttf"
python cli.py play image.png -f "fonts/font8x8.ttf"
# Or use system fonts
python cli.py play image.png -f "/usr/share/fonts/truetype/jetbrains/JetBrainsMono.ttf"
Web Interface Issues
Website won't start:
- Ensure Flask is installed:
pip install flask - Check if port 5000 is already in use
- Try a different port by modifying the Flask app
Image upload fails:
- Check file size (max 16MB by default)
- Ensure image format is supported
- Check browser console for errors
Block Size Errors
# Error: Block size must be a factor of image dimensions
# Solution: Choose a block size that divides evenly into width and height
# For a 1920×1080 image, valid block sizes include: 2, 4, 5, 8, 10, 12, 15, 16, 20, 24, etc.
python cli.py play image.png -b 8 # Works for most images
License
MIT License
Copyright (c) 2026 Colin Politi (ColinThePanda)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pdasc-0.1.1.tar.gz.
File metadata
- Download URL: pdasc-0.1.1.tar.gz
- Upload date:
- Size: 359.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6f6b7b2c3401fceee23415d352f91dc10d41012fc3fda7f0a3f7ed35ff033c9
|
|
| MD5 |
98c714556cd1cc488cc85a7c8a13d7d3
|
|
| BLAKE2b-256 |
3c3ecb240387ab02ecb9dee21e3930cd8919f0f07208552ad04eaf956fe5f269
|
File details
Details for the file pdasc-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pdasc-0.1.1-py3-none-any.whl
- Upload date:
- Size: 356.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1f14495b891b5b078d9fc6c2a834ca6d4ada68b2a999c94423c6c107e660459
|
|
| MD5 |
6a0b7a129ff56af14b47d8520666f132
|
|
| BLAKE2b-256 |
aec174cee61714f97cf4d53510133f8cf9a2308bd2c7b98c5d5b504d77c64c4a
|