Skip to main content

bruhanimate

Downloads

Terminal animations for Python 3.13+. Built-in simulations, custom drawing callbacks, and layered scenes all run through one player.

The 1.x API is a breaking change from 0.2.x. See the migration guide for changes from 0.2.x.

Install

pip install --upgrade "bruhanimate>=1,<2"
# Optional audio capture dependencies:
pip install --upgrade "bruhanimate[audio]>=1,<2"

For unreleased changes, install the source checkout with pip install . or pip install ".[audio]". The commands above require a published 1.x release.

Play an effect

from bruhanimate import SnowSettings, play

play("snow", settings=SnowSettings(intensity=0.02, wind=0.2),
     fps=60, updates_per_second=30)

q, Escape, or Ctrl+C exits and restores the terminal. frames=120 limits presentations. fps controls drawing; updates_per_second controls simulation. Without an explicit update rate, the player updates once per presentation. Built-in simulations advance one step per tick; their settings use tick units.

Discover effects and presets:

from bruhanimate import effect_registry

for name, entry in effect_registry.entries().items():
    print(name, entry.description, list(entry.presets))

Registered effects: audio, automaton, boids, diffusion, drawlines, fire, firework, gol, julia, matrix, noise, offset, perlin, plasma, rain, sand, snow, stars, static, twinkle, and voronoi.

Compose content

from bruhanimate import ImageEffect, Scene, effect_registry, get_image, play

def build(buffer):
    return Scene(
        effect_registry.create("snow", buffer, " ", preset="light"),
        ImageEffect(get_image("bruh")),
    )

play(effect_factory=build, fps=60, updates_per_second=30)

Scenes paint from back to front. None cells reveal lower layers; wrap an animation in Layer(animation, transparent=True) to reveal them through plain spaces too. ImageEffect centers by default, supports explicit x/y coordinates, and accepts a velocity in cells per second for panning.

get_image() retrieves bundled ASCII art. text_to_image() uses PyFiglet; it does not load raster image files.

Draw your own animation

from bruhanimate import CallbackEffect, play

state = {"step": 0}

def update(dt):
    state["step"] += 1

def draw(buffer):
    buffer.put_at_center(buffer.height() // 2, f"Puzzle step: {state['step']}")

play(CallbackEffect(draw, update=update), fps=60, updates_per_second=10)

Advance the puzzle in update, and only read its state in draw. For persistent raster simulations, subclass BaseEffect and implement update(dt); its default draw copies the current raster without advancing it. Use an effect factory to receive a correctly sized private buffer.

Animate solver snapshots

from bruhanimate import Playback, draw_grid, play

board = ("S...", ".##.", "...E")

def states():
    yield from ((0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (3, 2))

def draw(position, buffer):
    grid = draw_grid(buffer, board, spacing=(2, 1))
    grid.put(*position, "@")

animation = Playback(states(), draw, steps_per_second=5)
play(animation, fps=60, event_handler=animation.handle_event, on_complete="exit")

Space pauses, n/right steps, +/- changes speed, and q quits. Playback consumes states lazily and closes its iterator on exhaustion or early quit. Grid drawing handles centering, spacing, camera offsets, and clipping. See the solver playback guide for snapshots and completion.

Demos and documentation

python -m bruhanimate.demos.snow_demo
python -m bruhanimate.demos.shared_player_demo
python -m bruhanimate.demos.grid_demo
python -m bruhanimate.demos.terminal_demo

All demos expose run(frames=None, fps=...). The terminal demo is a pipe-based command console: Escape exits and printable q goes to the shell. It does not emulate a PTY or interpret terminal escape sequences.

Inspired by Asciimatics. Licensed under Apache 2.0; see LICENSE.

Contributing and releasing

Use Python 3.13 and uv 0.13.4. Start with AGENTS.md for architecture and contribution conventions, and keep public docstrings/examples synchronized.

python -m pip install uv==0.13.4
uv sync --locked --group docs
uv run --locked ruff check .
uv run --locked pytest
uv run --locked python scripts/check_examples.py
uv run --locked --group docs python scripts/build_docs.py

For an existing standalone uv installation, update with uv self update 0.13.4.

CI tests Linux, Windows and macOS, verifies source/installed packages, and builds Sphinx documentation strictly. The committed uv.lock pins contributor and CI environments without pinning consumers to that environment. uv handles the development workflow and builds; poetry-core remains only as the build backend. Publishing uses the PyPA action for Trusted Publishing attestations.

Publishing is tag-driven: merging into main does not publish to PyPI. The release workflow validates a matching vMAJOR.MINOR.PATCH tag on a main-branch commit and publishes the tested distributions. The publish helper previews by default; write/commit/push/PR operations require explicit flags.

# Validate the currently prepared 1.0.0 without bumping it:
uv run --locked python publish.py --check
# Preview a future release:
uv run --locked python publish.py 1.1.0

Read the release guide for tag commands, Trusted Publishing or existing-token setup, environment requirements and retry procedures.

Metadata

Release files for bruhanimate 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bruhanimate 1.0.0
File Size Uploaded Provenance
bruhanimate-1.0.0.tar.gz 92.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for bruhanimate 1.0.0
File Interpreter ABI Platform
bruhanimate-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 231.4 kB

Release files / bruhanimate-1.0.0.tar.gz

Download URL bruhanimate-1.0.0.tar.gz
Size 92.7 kB
Tags Source
SHA-256 checksum
How to use checksums
5cf74fdcef6680f1e035db942a5516cdb869c78a7020244ed66472005bafa945
BLAKE2b-256 checksum
How to use checksums
9d6389d7a118f0c55104299c1dc55af9f94ea1b9c1895b313e8c1aab067c4e6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / bruhanimate-1.0.0-py3-none-any.whl

Download URL bruhanimate-1.0.0-py3-none-any.whl
Size 138.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e790f4c5aac8f1a11822c115713406722528b75c39ea509a115cfdd07cccc86d
BLAKE2b-256 checksum
How to use checksums
d742234266640d2c512e00599255e0f98f257b37f4429ccdfd44199d70182e9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for bruhanimate 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page