Skip to content
FedgeNoPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Facer

A living ASCII face on your desktop.

Facer is a transparent, click-through Linux desktop overlay that renders a human face as animated ASCII. Faces breathe, blink, shimmer, and smoothly change expression while your mouse clicks pass through to the applications underneath.

The animation is stored as brightness maps, not ASCII frames. Every frame reinterprets those maps using your current character set, resolution, and a little evolving static.

Features

  • Four distinct faces, including the original short-haired face.
  • Five expressions: neutral, happy, sad, angry, and surprised.
  • Direct transitions between any two expressions, with smooth interruption mid-transition.
  • Smooth face switching that retains the selected emotion and rendering settings.
  • Independent blinking, subtle breathing and head movement, and continuous brightness noise.
  • Live control of character density, glyph selection, color, opacity, position, and animation speed.
  • A detached background process with terminal controls and a foreground mode for debugging.

Requirements

  • Linux with an active X11 or XWayland display.
  • A compositing desktop for window transparency.
  • Python 3.11–3.14 and uv.
  • Bash and GNU readlink for the launcher.

Facer has been tested on GNOME/Wayland using Qt's XCB backend through XWayland. Native Wayland-only sessions are not supported by this launcher. The overlay runs within your graphical session; it does not install a system service or automatic login startup.

Quick Start

Clone or download the repository, then run these commands from its root directory:

uv sync --locked
./facer start

The original face appears near the bottom-right of your primary monitor and automatically cycles through expressions. The included brightness maps are ready to use; no image generation or API key is required to run Facer.

./facer status
./facer stop

To run in the foreground instead:

./facer run

Press Ctrl+C to stop foreground mode. start detaches and returns after the overlay is ready. Starting it again reports the existing instance instead of opening another overlay.

Add Facer To Your PATH

From the repository root:

mkdir -p "$HOME/.local/bin"
ln -s "$PWD/facer" "$HOME/.local/bin/facer"

Ensure ~/.local/bin is on your PATH. You can then use facer from any directory. The launcher resolves the symlink back to the project, where its code, assets, and isolated .venv remain. If you move the project, update the symlink.

Choose A Face

facer faces
facer face bob
facer face silver
facer face copper
facer face original
Name Face Reference Sheet
original Original short-haired face; default at launch View
bob Woman with a dark bob View
silver Older man with a silver beard View
copper Freckled woman with copper curls View

Every face has all five expressions and its own closed-eye reference. Switching faces morphs from the currently visible face into the same expression on the new face, preserving automatic or held mode. The original assets are retained separately.

Choose a face when starting a new instance:

facer start --face silver
Original Photographic Expression References

These generated photographs supply the brightness maps. The running overlay draws ASCII characters, not these photographs.

Six photographic references: neutral, happy, sad, angry, surprised, and eyes closed

Control Expressions

facer expression happy
facer expression sad
facer expression angry
facer expression surprised
facer expression neutral
facer auto

Selecting an expression transitions to it and holds it. Breathing, blinking, and static continue. auto resumes automatic expression changes, with 4–7 second holds after transitions. Transitions take 2.4 seconds by default.

To start with a held expression:

facer start --face copper --expression happy --hold

Tune The Rendering

Settings can be changed while the overlay is running:

facer set --static 0.03
facer set --columns 140 --font-size 9
facer set --x 40 --y 80
facer set --color '#e8f0ee' --opacity 0.95
facer set --ramp ' .:-=+*#%@'
facer set --transition 3 --motion 0.7 --fps 30
facer set --contrast 1.3 --gamma 0.85
Option Default Range / Format Effect
--static 0.018 0.001–0.15 Amount of live brightness noise
--motion 1.0 0–4 Breathing and head movement amplitude
--transition 2.4 0.2–12 seconds Expression and face transition duration
--fps 30 5–60, integer Target frame rate
--columns 112 40–240, integer Horizontal character count
--font-size 9 6–24, integer pixels Glyph size
--opacity 0.95 0.1–1 Glyph opacity
--color #e8f0ee #RRGGBB Glyph color
--ramp .,:;irsXA253hMHGS#9B&@ Unique printable ASCII, starting with a space Available characters
--x, --y Near bottom-right -32768–32768, integer Desktop position
--contrast 1.2 0.2–3 Brightness multiplier before gamma
--gamma 0.85 0.2–3 Brightness exponent

Settings are session-only. All options above except contrast and gamma can also be supplied to start or run. Launch options apply only when creating a new instance; use set or face to change an existing one.

Noise evolves gradually between frames. Its nonzero minimum keeps the ASCII lively even when head motion is disabled. Characters are sorted by their measured density in the actual font, so custom ramps do not need to be manually ordered.

More columns preserve more facial detail and increase the overlay's width at a fixed font size. Row count follows the glyph dimensions to preserve the portrait's proportions. Try dark text such as --color '#182020' against a light desktop.

How It Works

  1. Six photographic expression references are converted into 320 × 320 floating-point luminance maps and soft transparency masks.
  2. Bidirectional optical flow warps the current and target expressions before blending their brightness values.
  3. A localized closed-eye reference provides blinking, while small spatial warps add breathing and head movement.
  4. The result is sampled at the current character resolution. Temporally correlated noise perturbs the sampled brightness.
  5. Brightness selects ASCII glyphs by measured font density. Qt paints the glyphs onto a transparent, input-pass-through window.

Optical flow and rendered frames stay in memory. No ASCII frame sequences are saved. The result is an ASCII interpretation of the photographic shading, with detail limited by the selected character resolution.

Project Layout

Path Purpose
facer Bash launcher with symlink support
facer.py Command-line interface and daemon lifecycle
overlay.py Qt overlay, glyph rendering, and local control socket
animation.py Brightness morphs, blinking, motion, and static
faces.py Face catalog and asset paths
prepare-maps.py Reference-sheet conversion
test-animation.py Animation and rendering tests
assets/ Original face references, prompt, maps, and metadata
assets/faces/ Separate bob, silver, and copper assets
pyproject.toml, uv.lock Dependencies and locked versions

Each face set includes expression-reference.png, generation-prompt.txt, brightness-maps.npz, and brightness-maps.json. The fictional face references were created with the built-in image generation tool; the exact prompts are included alongside each set.

The NPZ files contain brightness and masks arrays, expression names, and a format version. Brightness uses float32 display-referred luminance in the 0–1 range. Load these files with numpy.load(path, allow_pickle=False).

Development

The renderer uses Python, PySide6/Qt, NumPy, and OpenCV. Pillow is used when preparing maps from reference images.

uv sync --locked
uv run python test-animation.py -v

Tests cover expression endpoints, interruption continuity, held-face static, localized blinking, face switching, live settings, and transparent rendering. Qt tests run offscreen.

To rebuild a face's maps from its included reference sheet:

uv run python prepare-maps.py --face original
uv run python prepare-maps.py --face bob
uv run python prepare-maps.py --face silver
uv run python prepare-maps.py --face copper

The converter expects a three-column, two-row atlas in this order: neutral, happy, sad, angry, surprised, closed eyes. Rebuilding overwrites that face's map and metadata files. Restart the overlay or reselect the face to load rebuilt maps.

Troubleshooting

  • Startup fails: inspect .local/facer.log or use facer run for foreground output. An active X11/XWayland DISPLAY is required.
  • Qt reports an XCB plugin error: check the log for the missing library and install the corresponding runtime package for your Linux distribution.
  • The face is difficult to see: adjust its color, opacity, contrast, or desktop position.
  • The overlay is too large: reduce --columns or --font-size.
  • Brightness maps are missing: run the indicated prepare-maps.py --face … command using that face's reference sheet.
  • You cannot click the face: this is intentional. Use the terminal commands to control it or facer stop to close it.

The daemon uses a per-project, user-only Unix socket in the session runtime directory and a file lock to prevent duplicate instances. Logs and lock files are kept in the ignored .local/ directory.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages