Turn a photo into a self-typing, monochrome ASCII portrait SVG that animates inside a GitHub profile README. No JavaScript, no third-party stats service, no token.

Why SVG

GitHub strips <script> from READMEs and sanitizes almost all inline CSS. But it does render SVGs embedded via <img>, and it runs their SMIL animations. So all the motion has to live inside the SVG file itself. The README just places it.

Setup

# the magic repo: name it exactly your GitHub username
gh repo create <your-username> --public --clone
cd <your-username>

pip install pillow numpy opencv-python-headless rembg onnxruntime

First run downloads a ~176 MB u2net.onnx model for background removal. One time only.

The pipeline

Four stages. Each one exists because skipping it makes the output worse.

1. Cut out the background

rembg isolates the subject. Everything outside the matte gets forced to pure white, which maps to the blank end of the character ramp. Without this the background fills with @ and % and drowns the portrait.

2. CLAHE for local contrast

Contrast-limited adaptive histogram equalization. Regular autocontrast works globally and leaves a flatly-lit face as one uniform mid-tone. CLAHE boosts contrast per-tile, so the face gets real highlights and shadows.

clipLimit around 2.2 to 3.0 is the useful range. Higher amplifies skin texture into noise. Run a bilateral filter first to smooth skin while keeping edges.

3. Map brightness to characters

RAMP = " .`:-=+*cs#%@"   # bright/sparse -> dark/dense
#        ^ leading space clears the background to nothing

Monospace characters are roughly twice as tall as wide, so the row count is cols * (h/w) * 0.48.

Two choices that matter:

4. Animate the typing