Metadata-Version: 2.4
Name: gummy-snake
Version: 0.5.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Artistic Software
Classifier: Topic :: Multimedia :: Graphics
Requires-Dist: opencv-python-headless>=4.13.0.92 ; extra == 'media'
Requires-Dist: numpy>=2.4.6 ; extra == 'numpy'
Provides-Extra: media
Provides-Extra: numpy
License-File: license.txt
Summary: A playful Python toolkit for creative coding and small games.
Keywords: creative-coding,games,graphics,python,sketches
License-Expression: LGPL-2.1-only
Requires-Python: >=3.12
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# Gummy Snake

[![PyPI](https://img.shields.io/pypi/v/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
[![Python Versions](https://img.shields.io/pypi/pyversions/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
[![License: LGPL-2.1](https://img.shields.io/badge/License-LGPL--2.1-blue.svg)](license.txt)
[![Downloads](https://img.shields.io/pypi/dm/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)

Gummy Snake is a playful Python toolkit for creative coding and small games. It
is for people who want to sketch with code: draw shapes, animate motion, react
to input, load sprites, play with pixels, and build visual toys without first
building a full app.

The public API is Python-first. Function names use `snake_case`, sketches are
ordinary Python files, and the renderer is powered by the packaged Rust canvas
runtime.

## Install

```sh
pip install gummy-snake
```

Published wheels include the required Rust `gummy_canvas` canvas runtime. Source
or editable installs must build that PyO3 module; there is no Python renderer
fallback for canvas-owned behavior.

Install optional media helpers when you need camera, video, or sound-related
extras:

```sh
pip install "gummy-snake[media]"
```

## First Sketch

Create a file named `circle_sketch.py`:

```python
import gummysnake as gs


@gs.setup
def setup() -> None:
    gs.create_canvas(400, 300)
    gs.no_stroke()


@gs.draw
def draw() -> None:
    gs.background(245)
    gs.fill(255, 90, 90)
    gs.circle(200, 150, 100)


gs.run()
```

Run it:

```sh
python circle_sketch.py
```

For repeatable scripts, use a bounded headless render:

```python
gs.run(headless=True, max_frames=1)
```

Callbacks can also be `async def`, which is useful with async-compatible asset
helpers:

```python
image = None


@gs.preload
async def preload() -> None:
    global image
    image = await gs.load_image_async("sprite.png")
```

## What You Can Make

- 2D drawings with shapes, curves, color, transforms, and blend modes.
- Animated sketches using the familiar `setup()` and `draw()` lifecycle.
- Decorator-based sketches, async-compatible callbacks, and object-oriented
  `Sketch` subclasses.
- Image and pixel experiments, including canvas export.
- Text, font measurement, and accessibility descriptions.
- Interactive sketches with mouse, keyboard, and touch state when native window
  support is available.
- Software 3D sketches with primitives, lights, materials, models, textures,
  and shader objects on the current Rust-backed software 3D path.
- Small games and visual toys using the examples as starting points.

Loaded images, models/meshes, and sounds keep Rust-managed asset handles behind
friendly Python wrappers. This is intentional for performance: bulk asset bytes,
geometry arrays, parsing, export, and metadata extraction should stay in the
Rust canvas runtime so sketches avoid repeated Python object materialization and
per-element loops. Normal `load_image(); image(...)` sprite drawing can stay on
the fast renderer path, model projection/export can use Rust-owned geometry
without first creating Python `Vec3` objects, and loaded sounds keep their bytes
and duration metadata in `CanvasSound` until user code asks for Python bytes.
Image-local resize, mask, filter, crop/copy, and alpha compositing delegate
bulk byte work to the Rust canvas runtime while keeping the Python `Image`
API and version semantics.
For pixel effects, `load_pixels()` returns a list-based pixel buffer and
`load_pixel_bytes()` provides a bytes readback path; `update_pixels()` accepts
lists and buffer-like inputs such as `bytes`, `bytearray`, and `memoryview`.
Small canvas `get()` and `set()` region operations use Rust region calls instead
of reconstructing the full canvas as a Python image.
For dense drawing loops, `gs.fast()` returns a frame-local facade that keeps
public style/transform state while reducing global-mode dispatch overhead.
Opt-in `enable_performance_diagnostics()` counters can identify readback, pixel
conversion, upload, texture cache, and CPU compositing fallback paths.

## Learn More

- [Getting started](docs/getting_started/index.md)
- [Examples](examples/README.md)
- [API reference](docs/reference/index.md)
- [Contributor docs](docs/contribute/index.md)

## For Contributors

This repository uses `uv` for Python commands:

```sh
uv sync --dev
uv run ruff check .
uv run mypy src
uv run pytest
```

The canvas runtime is a required PyO3 module for development/source installs:

```sh
uvx maturin develop --manifest-path crates/gummy_canvas/Cargo.toml --features extension-module
```

The refactored Python package is split by responsibility: public API modules in
`src/gummysnake/api/`, `SketchContext` mixins in `src/gummysnake/_context/`,
lifecycle code in `src/gummysnake/sketch/`, enum-backed constants in
`src/gummysnake/constants/`, and thin canvas backend/renderer facades over the
implementation modules in `src/gummysnake/backend/_canvas/`.

The contributor documentation explains the architecture, lifecycle, testing
workflow, and release shape in more detail:

- [Contributor guide](docs/contribute/index.md)
- [Architecture](docs/contribute/architecture.md)
- [Backend and renderer boundaries](docs/contribute/backend_renderer.md)
- [Runtime model](docs/contribute/runtime.md)
- [Runtime diagnostics](docs/contribute/runtime_diagnostics.md)
- [Build capabilities](docs/contribute/build_capabilities.md)
- [API performance policy](docs/contribute/api_performance_policy.md)
- [Testing and CI](docs/contribute/testing.md)

Performance benchmarks are opt-in:

```sh
uv run pytest tests/benchmark/test_canvas_backend_perf.py --run-benchmarks
uv run pytest tests/benchmark/test_api_overhead_perf.py --run-benchmarks
uv run pytest tests/benchmark/test_image_pipeline_perf.py --run-benchmarks
uv run pytest tests/benchmark/test_model_export_perf.py --run-benchmarks
uv run pytest tests/benchmark/test_webgl_3d_perf.py --run-benchmarks
```

Canvas benchmark scenarios are expected to average at least 120 FPS. Failures
below that floor are intentional optimization signals. Model export benchmarks
use a memory budget for streaming OBJ/STL output. Machine-specific baseline
snapshots live in `tests/benchmark/baselines/`.

Long-running resource lifecycle checks are also opt-in:

```sh
uv run pytest tests/stress --run-stress -q -s
```

## Compatibility

Gummy Snake keeps the sketch lifecycle familiar, but it is not a browser port.
It does not include DOM helpers, browser-only APIs, JavaScript aliases, or a
Pillow/Pyglet/Python renderer fallback. Unsupported features raise explicit
package errors so sketches fail clearly.

