Metadata-Version: 2.4
Name: attractor-tools
Version: 0.2.1
Summary: An API to animate the Simon fractal
Home-page: https://github.com/beasty79/attractor_api
Author: Silas Schimpeler
Author-email: "Silas .S" <silasfelix2005@gmail.com>
License: MIT
Keywords: video,attractor,rendering,simon,multiprocessing
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: matplotlib
Requires-Dist: numpy
Requires-Dist: numba
Requires-Dist: opencv-python
Requires-Dist: pyqt6
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# Attractor Tools

**Attractor-tools** is a Python module for animating the **Simon fractal** using efficient rendering. It provides a clean API to generate frames, assinging colormaps, and export visualizations as videos.

---
## ✨ Features
- Animate the Simon fractal with customizable parameters
- NumPy, Numba and Multiprocessing for performance
- Automate Parameters using interpolation between a set of points
---

## Example:
![alt text]()

## 📦 Installation
```bash
pip install attractor-tools
```

## Example usage
```python
from attractor import sinspace, Performance_Renderer, ColorMap

def main():
    # array with values from lower to upper using a sinewave (p=1)
    # a, b are the initial values of the system used in the attractor
    # To animate this effectively, at least one of these parameters should change each frame
    a = sinspace(0.32, 0.38, 100)

    # Main rendering class
    # Use this when rendering a video with multiple frames.
    # For single-frame rendering, this class is overkill — use 'render_frame(...)' instead.
    renderer = Performance_Renderer(
        a=a,
        b=1.5,
        colormap=ColorMap("viridis"),
        frames=len(a),
        fps=10
    )

    # Important: 'a' is an array of values, one per frame (a[i] used for frame i)
    # So we need to mark it as non-static to allow per-frame variation
    renderer.set_static("a", False)

    # Set how many processes/threads to use (via multiprocessing.Pool)
    # Use None for unlimited; here we use 4 threads with a chunk size of 4
    renderer.start_render_process("./your_filename.mp4", threads=4, chunksize=4)

if __name__ == "__main__":
    # see all colormaps available
    print(ColorMap.colormaps())
    main()
```

### Automations
```python
def keyframe_example():
    # generic animation option (20 frames)
    opts = Option.from_time(
        seconds=4,
        fps=5
    )

    # KeyframeInterpolator is similar to linspace, sinspace, sqaurespace, ...
    # The difference you can define a set of point: point(value, frame)
    # between this points linspace is used to interpolate between those
    interpolation = KeyframeInterpolator(opts, 0.32, 0.32)
    interpolation.add_keyframe(Point(frame=5, value=0.4))
    interpolation.add_keyframe(Point(frame=10, value=0.4))
    interpolation.add_keyframe(Point(frame=15, value=0.32))

    a = interpolation.to_array()

    renderer = Performance_Renderer(
        opts=opts,
        a=a,
        b=1.5,
        iterations=3_000_000
    )
    renderer.set_static("a", False)
    renderer.show_demo(nth_frame=1)
```
### Generic mp4
```python
def generic_example():
    opts = Option.from_time(
        seconds=4,
        fps=5
    )

    renderer = Performance_Renderer(
        opts=opts,
        a=0.35,
        b=1.5,
        iterations=3_000_000
    )  
    # Set generic flag to save image in grayscale
    renderer.start_render_process("demo.mp4", save_as_generic=True)

    # after rendering you can apply a colormap (still takes some time)
    # make sure to use the same fps and frames as the rendering
    color_generic("demo.mp4", ColorMap("viridis"), opts.fps, frames=opts.frames)
```
