Metadata-Version: 2.4
Name: animpy
Version: 3.5.0
Summary: A simple terminal animation library
Author: Samin Riyaz
License-Expression: MIT
Project-URL: Documentation, https://13DoesPython.github.io/animpy/
Project-URL: Homepage, https://github.com/13DoesPython/animpy
Project-URL: Issues, https://github.com/13DoesPython/animpy/issues
Project-URL: Repository, https://github.com/13DoesPython/animpy.git
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# Animpy

![PyPI - Version](https://img.shields.io/pypi/v/animpy?color=orange)
[![Downloads](https://static.pepy.tech/personalized-badge/animpy?period=total&units=INTERNATIONAL_SYSTEM&left_color=black&right_color=green&left_text=downloads)](https://pepy.tech/projects/animpy)
![GitHub License](https://img.shields.io/github/license/13DoesPython/animpy)

Animpy is a Python library for building lightweight terminal-based animations, visual effects, mini-games, and interactive apps. It gives you a simple API for placing text objects on a scene, moving them, coloring them, applying physics, reacting to input, playing sound, and even following a moving target with a camera-style offset.

It is built for developers who want to create animated terminal experiences without needing a full game engine or a graphical UI framework.

## What Animpy can do

- Create and animate text objects in the terminal
- Draw shapes such as rectangles, circles, polygons, lines, hearts, triangles, ellipses, squares, and donuts
- Create particle bursts, trails, and explosions
- Apply built-in visual effects such as shaking, gravity, decay, fading, interpolation, pulsing, and typing effects
- Build scenes with layered objects, background colors, offsets, and camera-style views
- Add physics behaviors such as gravity, friction, bounce, angular motion, and force pushes
- Handle keyboard and mouse input for interactive demos and games
- Play audio clips with basic playback controls
- Format terminal output with color, panels, centering helpers, and ANSI utilities

## Installation

```bash
pip install animpy
```

Animpy depends on the following packages:

- `pygame-ce`
- `keyboard`
- `mouse`
- `rich`

## Quick start

```python
import animpy

scene = animpy.Scene()
text = animpy.Text("Hello!", 10, 5, r=255, g=100, b=50)
scene.add(text)
scene.render()
```

A more animated example:

```python
import animpy
import time

scene = animpy.Scene()
text = animpy.Text("Hello", 0, 0, r=0, g=255, b=255)
scene.add(text)

for _ in range(20):
    text.moveX(1)
    scene.render()
    time.sleep(0.05)
```

## Core concepts

### 1. Scenes

A `Scene` is the container that holds objects to be rendered to the terminal. It manages the draw order, background color, offsets, and optional camera logic.

```python
scene = animpy.Scene()
scene.set_bg_rgb(0, 0, 30)
```

### 2. Renderer

`Renderer` is the compositing engine used by `Scene.render()`. It supports text,
particles, nested groups, z-order, scene offsets, cameras, and RGB backgrounds.
It can also render into a string or inspect a deterministic `Frame`, which is
useful for tests, recordings, and custom terminal integrations.

```python
from io import StringIO

renderer = animpy.Renderer(size=(80, 24))
frame = renderer.render_frame(scene)
plain_text = frame.plain_text()

output = StringIO()
animpy.Renderer(stream=output, size=(80, 24)).render(scene)
```

### 3. Text objects

`Text` is the basic object that can be placed on the screen and moved around. Text can also be created from a list of frames, which allows simple frame-based animation.

```python
text = animpy.Text("Hello", 5, 3)
text.moveX(4)
text.moveY(2)
text.set_color(255, 0, 0)
```

### 3. Effects and motion

`EffectText` adds common visual effects and movement helpers on top of `Text`.

```python
fx = animpy.EffectText("Bounce", 10, 2)
fx.shaking_text(intensity=2)
fx.gravity_text(floor=10, gravity=0.5)
```

### 4. Groups

A `Group` lets you manage many objects as one unit. Position and color changes can be applied to the entire group.

```python
group = animpy.Group()
group.add(animpy.Text("A", 1, 1), animpy.Text("B", 4, 1))
group.position(2, 0)
```

### 5. Camera

A `Camera` provides a simple view transform for a scene. You can point it at a target object or keep a custom offset.

```python
scene = animpy.Scene()
player = animpy.Text("P", 10, 5)
scene.add(player)

camera = animpy.Camera((0, 0), None)
camera.follow(player)
scene.camera = camera
scene.render()
```

## Feature reference

### Text

`Text` is the base class for terminal objects.

```python
text = animpy.Text("Hello", 2, 2, r=255, g=255, b=255)
```

Common methods:

- `change_frame()` — advance to the next frame if the text was created from a list
- `set_frame(index)` — switch to a specific frame
- `set_text(text)` — replace the text content or frame list
- `set_position(x, y)` — directly set the position
- `move_to(x, y)` — alias for `set_position`
- `set_color(r, g, b)` — update the color using RGB values
- `change_rgb_values(r, g, b)` — same as `set_color`
- `moveX(dx)` — move horizontally
- `moveY(dy)` — move vertically
- `slide_to_pos(new_pos, speed=1)` — move smoothly toward a coordinate-like object
- `centerX()` — center the text horizontally
- `centerY()` — center the text vertically
- `collides_with(other)` — test for bounding-box overlap
- `on_collide_callback(other, callback)` — run a callback when collision occurs
- `type_out(text, speed=0.05, scene=None)` — print text gradually, optionally rendering after each character
- `fall(velocity, floor)` — move the object downward until a floor is reached

Useful properties:

- `width` — number of characters in the current frame
- `height` — number of lines in the current frame
- `current_frame` — current frame index

### EffectText

`EffectText` extends `Text` with reusable animation effects and velocity support.

```python
fx = animpy.EffectText("Shaky", 5, 5)
fx.shaking_text(intensity=2)
fx.gravity_text(floor=10, gravity=0.5)
fx.pulse_text(time=1.0, pulse_rate=0.5)
```

Available methods:

- `gravity_text(floor=20, gravity=0.5)` — apply gravity and clamp to a floor
- `shaking_text(intensity=1)` — jitter position randomly
- `decaying_text(time, decay_rate=0.1)` — shorten the text over time
- `fade_out_text(time, fade_rate=0.1)` — fade the object toward black
- `lerp_text(target_x, target_y, t)` — interpolate smoothly to a target position
- `pulse_text(time, pulse_rate=0.5)` — change brightness over time
- `set_velocity(vx, vy)` — set motion in X/Y
- `reset_velocity()` — clear velocity values
- `apply_force(fx, fy)` — add to the current velocity
- `fade_in_text(time, fade_rate=0.1)` — fade in over time

### Shapes

Shapes return multi-line strings that can be used as text content.

```python
rect = animpy.Shapes.rectangle(8, 4, "#")
circle = animpy.Shapes.circle(4, "*")
line = animpy.Shapes.line(0, 0, 10, 4, "-")
heart = animpy.Shapes.heart(5, "♥")
triangle = animpy.Shapes.triangle(0, 0, 6, 0, 3, 5, "^")
ellipse = animpy.Shapes.ellipse(6, 3, 4, 2, "o")
square = animpy.Shapes.square(5, "#")
donut = animpy.Shapes.donut(5, 2, "#")
```

Supported builders:

- `rectangle(width, height, char)`
- `circle(radius, char)`
- `polygon(points, char)`
- `line(x1, y1, x2, y2, char)`
- `triangle(x1, y1, x2, y2, x3, y3, char)`
- `ellipse(center_x, center_y, radius_x, radius_y, char)`
- `heart(size, char)`
- `square(size, char)`
- `donut(outer_radius, inner_radius, char)`

### Group

A `Group` collects multiple objects so they can be moved or recolored together.

```python
group = animpy.Group()
text1 = animpy.Text("A", 0, 0)
text2 = animpy.Text("B", 2, 0)
group.add(text1, text2)

group.position(3, 1)
group.change_rgb_values(0, 255, 0)
```

Available methods:

- `add(*items)` — add one or more objects
- `remove(*items)` — remove one or more objects
- `clear()` — remove all items
- `contains(item)` — check if an item exists in the group
- `find_by_color(r, g, b)` — return matching items by color
- `position(newx, newy)` — shift every item by an offset
- `change_rgb_values(r, g, b)` — recolor every item
- `change_rgb_values_one(item, r, g, b)` — recolor a single item

### Coords, Keyframe, and KeyChains

These helpers support path-based movement.

```python
from animpy import Coords, Keyframe, KeyChains

start = Coords(0, 0)
mid = Coords(10, 3)
end = Coords(15, 8)

path = KeyChains(Keyframe(start), Keyframe(mid), Keyframe(end))
path.follow_path(text, speed=1)
```

- `Coords(x, y)` — simple coordinate container
- `distance_to(other)` — calculate Euclidean distance
- `offset(dx, dy)` — return a new offset coordinate
- `Keyframe(pos)` — stores a target position
- `set_pos(pos)` — update keyframe position
- `distance_to(other)` — measure the distance to another keyframe or coordinate
- `KeyChains(*keyframes)` — store a list of keyframes
- `append(keyframe)` — add a keyframe
- `clear()` — remove all keyframes
- `reverse_path()` — reverse the path order
- `is_complete` — becomes `True` once the path has no more keyframes
- `follow_path(obj, speed=1)` — moves an object toward the current keyframe

### Scene

A `Scene` handles rendering and object management.

```python
scene = animpy.Scene()
scene.add(text1, text2)
scene.remove(text2)
scene.render()
```

Useful methods:

- `add(*items)` — add objects to the scene
- `remove(*items)` — remove objects from the scene
- `render()` — draw the current frame to the terminal
- `update(delta_time)` — update particles and remove expired items
- `set_bg_rgb(r, g, b)` — set a background color
- `shake(intensity=1)` — apply a random shaking offset
- `clear()` — clear the terminal display
- `clear_items()` — remove every object from the scene
- `count_items()` — return the number of scene items
- `find_items_at(x, y)` — return the objects sitting at a coordinate

Scene properties:

- `dt` — elapsed time since the last frame
- `offset_x`, `offset_y` — manual rendering offsets
- `camera` — optional `Camera` attached to the scene

### Camera

The `Camera` helper lets a scene render from a different view.

```python
camera = animpy.Camera((0, 0), None)
camera.follow(player)
scene.camera = camera
scene.render()
```

Available methods:

- `move(new_position)` — set the camera position directly
- `look_at(new_target)` — point the camera at a new target
- `follow(target_object)` — track an object by reference
- `get_view_matrix()` — return the current view position as a tuple

### PhysicsScene

`PhysicsScene` adds simple physical motion helpers to a scene.

```python
scene = animpy.PhysicsScene()
ball = animpy.EffectText("O", 2, 2)
scene.add(ball)

scene.apply_gravity(ball)
scene.apply_friction(ball, friction=0.1)
scene.bounce(ball, bounce_factor=0.7)
scene.apply_physics(ball)
scene.angular_motion(ball, angle=45, speed=2.0)
scene.push(ball, force_x=0.5, force_y=-0.2)
```

Available methods:

- `apply_gravity(obj)` — move an object downward toward the floor
- `apply_friction(obj, friction=0.1)` — reduce velocity over time
- `bounce(obj, bounce_factor=0.5)` — reverse vertical motion when hitting the floor
- `apply_physics(obj)` — combine gravity, friction, and bounce
- `angular_motion(obj, angle, speed)` — set an angled velocity
- `push(obj, force_x, force_y)` — add force in X/Y directions

### InteractiveScene

`InteractiveScene` makes it possible to react to keyboard and mouse input.

```python
scene = animpy.InteractiveScene()
player = animpy.Text("P", 10, 10)
scene.add(player)

while True:
    if scene.key_pressed("w"):
        player.moveY(-1)
    if scene.key_pressed("s"):
        player.moveY(1)
    if scene.key_pressed("esc"):
        break
    scene.render()
```

Available methods:

- `key_pressed(key)` — check whether a key is held down
- `key_released(key)` — check whether a key has been released
- `on_key_press_callback(key, callback)` — run a callback when a key is pressed
- `on_key_release_callback(key, callback)` — run a callback when a key is released
- `mouse_pressed(button="left")` — check whether a mouse button is held down
- `mouse_position()` — return the current mouse position
- `on_mouse_press_callback(button, callback)` — run a callback when a mouse button is pressed
- `mouse_release(button, callback)` — run a callback when a button is released
- `mouse_release_callback(button, callback)` — alias for the release callback helper
- `quick_exit(key="esc")` — exit immediately when a key is pressed
- `quick_exit_callback(key, callback)` — run a callback when a key is pressed
- `limit_to_bounds(obj)` — keep an object inside the terminal area
- `limit_group_to_bounds(group)` — keep every object in a group inside the terminal area

### Particles

Particles are useful for trails, explosions, smoke, sparks, and other visual effects.

```python
particle = animpy.Particle("*", 10, 5, r=255, g=150, b=50, lifetime=2.0)
particle.burst(scene, count=20, speed=1.5)
```

Available methods:

- `update(delta_time)` — advance the particle in time
- `emit(scene)` — add a single particle to the scene
- `burst(scene, count=10, speed=1.0)` — create many particles with random velocities
- `change_rgb_values(r, g, b)` — change the particle color
- `set_velocity(vx, vy)` — set particle velocity
- `apply_force(fx, fy)` — add velocity changes
- `set_color(r, g, b)` — alias for setting color
- `reset(x, y, lifetime=None)` — reset particle position and age
- `is_alive()` — check whether the particle is still alive
- `update_all(delta_time)` — update all particle children created by the parent
- `is_dead()` — check whether all tracked particles are dead

There are also built-in particle presets:

- `Presets.create_explosion(x, y, count=20, speed=1.0, lifetime=1.0)`
- `Presets.create_smoke(x, y, count=10, speed=0.5, lifetime=2.0)`
- `Presets.create_firework(x, y, count=30, speed=2.0, lifetime=1.5)`

### Audio

Audio support is built on `pygame` and can be used to add music or effects.

```python
audio = animpy.Audio()
audio.load("bg", "music.mp3")
audio.play("bg", loop=-1)
audio.set_volume("bg", 0.5)
```

Available methods:

- `load(name, file_path)` — load an audio file
- `play(name, loop=0)` — start playback
- `stop(name)` — stop a specific sound
- `stop_all()` — stop everything
- `is_playing(name=None)` — check whether a sound is active
- `set_volume(name, volume)` — update a volume level
- `pause(name)` — pause playback
- `resume(name)` — resume playback
- `fade_out(name, duration)` — fade the sound out
- `fade_in(name, duration, loop=0)` — fade in and optionally loop
- `play_for_time(name, duration)` — play for a set length and stop automatically

### Terminal utilities

Animpy also includes helpers for terminal output.

```python
animpy.hide_cursor()
animpy.show_cursor()
animpy.clear_screen()
animpy.print_centered("Centered")
animpy.print_with_color("Colored", r=255, g=0, b=0)
animpy.print_panel("Hello", title="Info")
```

Available helpers:

- `lerp(start, end, t)` — linear interpolation
- `hide_cursor()` / `show_cursor()`
- `clear_screen()`
- `print_centered(text)`
- `print_with_color(text, r, g, b)`
- `print_panel(text, title="Panel", style="bold white on blue")`
- ANSI color constants such as `animpy.ANSI["red"]` and `animpy.ANSI["bg_blue"]`
- terminal size helpers such as `get_terminal_size()`, `set_terminal_size(columns, lines)`, `reset_terminal_size()`, `get_terminal_width()`, and `get_terminal_height()`

## Example projects

The repository contains examples for:

- basic movement and interpolation
- renderer compositing with camera, groups, particles, z-order, and backgrounds
- loading screens
- visual effects
- physics demos
- player controls
- collision and tag-style games
- audio playback

You can browse the examples folder in the project repository for complete scripts.

## Version history

### v2.6.0

Added a new `Camera` class for scene view transformation and object tracking. All existing particle and utility methods now work seamlessly with camera-enabled scenes.

**New Camera class:**

- `Camera(position, target=None)` — Constructor that creates a camera at a specific position with an optional target
  - `position` — tuple of (x, y) representing the camera's current location
  - `target` — optional object or position to point the camera at; defaults to `None`

**Camera methods:**

- `move(new_position)` — Directly set the camera position to a new tuple (x, y)
- `look_at(new_target)` — Point the camera at a new target position or object
- `follow(target_object)` — Continuously track a Text or object with `x` and `y` properties
- `get_view_matrix()` — Return the current camera view as a tuple (x, y)

**Scene camera support:**

- `Scene.camera` — New optional property to attach a Camera instance
  - Assign a Camera to enable camera-based rendering offsets
  - When set, all objects render relative to the camera's viewpoint
  - Works with all scene objects: Text, Particles, Shapes, Groups

**Particle class methods (now camera-compatible):**

- `update(delta_time)` — Advance particle age and position
- `emit(scene)` — Add a single particle instance to the scene
- `burst(scene, count=10, speed=1.0)` — Create multiple particles with random velocities in all directions
- `change_rgb_values(r, g, b)` — Update particle color
- `set_velocity(vx, vy)` — Set particle velocity directly
- `apply_force(fx, fy)` — Add velocity changes via force
- `set_color(r, g, b)` — Alias for changing color
- `reset(x, y, lifetime=None)` — Reset particle position and age
- `is_alive()` — Check if particle is still active
- `update_all(delta_time)` — Update all child particles created by burst
- `is_dead()` — Check if all tracked particles have expired

**Particle Presets class (now camera-compatible):**

- `Presets.create_explosion(x, y, count=20, speed=1.0, lifetime=1.0)` — Create an explosion effect
- `Presets.create_smoke(x, y, count=10, speed=0.5, lifetime=2.0)` — Create a smoke effect
- `Presets.create_firework(x, y, count=30, speed=2.0, lifetime=1.5)` — Create a firework effect

**Utility functions (now camera-compatible):**

- `lerp(start, end, t)` — Linear interpolation between start and end values
- `hide_cursor()` — Hide the terminal cursor
- `show_cursor()` — Show the terminal cursor
- `clear_screen()` — Clear terminal display
- `print_panel(text, title="Panel", style="bold white on blue")` — Print text in a styled panel
- `print_centered(text)` — Print text centered in the terminal
- `print_with_color(text, r, g, b)` — Print colored text using RGB values
- `get_terminal_size()` — Return current terminal dimensions
- `set_terminal_size(columns, lines)` — Set terminal size
- `reset_terminal_size()` — Reset terminal size to defaults
- `get_terminal_width()` — Get terminal column count
- `get_terminal_height()` — Get terminal line count
- `ANSI` — Dictionary of ANSI color and style codes for advanced terminal formatting

### v2.5.0
- Added coordinate helpers such as `Coords.distance_to()` and `Coords.offset()`
- Added `Keyframe` and `KeyChains` helpers for path-based motion
- Added `Audio.pause()`, `Audio.resume()`, `Audio.fade_in()`, and `Audio.fade_out()`
- Added `Group.clear()`, `Group.contains()`, and `Group.find_by_color()`
- Added particle helpers such as `set_velocity()`, `apply_force()`, `set_color()`, `reset()`, and `is_alive()`
- Added scene helpers such as `clear_items()`, `count_items()`, and `find_items_at()`
- Added shape builders `square()` and `donut()`
- Added text convenience setters such as `set_frame()`, `set_text()`, `set_position()`, `move_to()`, and `set_color()`

### v2.1.0
- Added `Shapes.line()`, `Shapes.ellipse()`, `Shapes.heart()`, and `Shapes.triangle()`
- Added `clear_screen()`, `print_centered()`, and `print_with_color()`

### v2.0.0
- Added `PhysicsScene` for gravity, friction, bounce, and force-driven motion
- Added `EffectText` animation helpers such as `fade_out_text()`, `lerp_text()`, and `pulse_text()`
- Added interactive scene helpers such as `limit_to_bounds()`, `quick_exit()`, and `limit_group_to_bounds()`

## Support

If you enjoy Animpy, please consider starring the project on GitHub:

https://github.com/13DoesPython/animpy
