Skip to main content

pydamicsvisual

Matplotlib + pygame rendering extension for pydamics, a small chainable-syntax 2D physics engine.

pydamics itself stays dependency-free (just the physics). This package is the opt-in visual layer on top.

Install

pip install pydamicsvisual        # once published to PyPI -- also installs pydamics
# or, from source:
pip install -e .

Note: this uses pygame-ce (Community Edition), not the classic pygame package. It's a drop-in replacement (import pygame works identically) but is actively maintained and ships wheels for current Python versions -- classic pygame still only has wheels up to Python 3.12, which causes a source-build failure (needs Visual Studio Build Tools) on 3.13/3.14.

Usage

from pydamics import Entity, World
from pydamicsvisual import MatplotlibRenderer, PygameRenderer, floor_bounce

ball = Entity(mass=1.0, position=(2, 10))
ball.physics2d.gravity(force=9.8)
ball.physics2d.fluid(density=1.0, drag=0.2)

world = World()
world.add(ball)
world.on_step = floor_bounce(floor_y=0.0, radius=0.4, damping=0.65)

Headless GIF (matplotlib)

renderer = MatplotlibRenderer(world, xlim=(-1, 8), ylim=(0, 16))
renderer.track(ball, radius=0.4)
renderer.save_gif("out.gif", frames=180, dt=1/60)

Interactive window (pygame)

renderer = PygameRenderer(world, width=800, height=600, ppu=40, floor_y=0.0)
renderer.track(ball, radius=0.4)
renderer.on_click(lambda x, y: print("clicked at", x, y))  # e.g. spawn a new ball
renderer.run(dt=1/120)   # blocks until window closed / ESC -- simple demos

For anything beyond a simple demo -- a HUD, a pause overlay, custom key handling, driving your own timing -- use step() instead of run():

renderer.on_key(lambda key, pressed: ...)              # any key, not just click
renderer.on_frame(lambda screen, dt: draw_hud(screen))  # draw after entities, before flip
renderer.draw_text("Score: 10", pos=(10, 10))           # call from inside on_frame

clock = pygame.time.Clock()
while renderer.step(dt=1/120):   # returns False once quit is requested
    clock.tick(60)

run() is just a thin convenience wrapper around step() -- physics steps synchronously inside step() (not on a background thread like early versions), so it's straightforward to reason about and test.

Shapes beyond circles

renderer.track(crate, shape="box", width=2, height=1)     # a box, not just circles
renderer.track_solid(wall)                                 # reads an SEO object's OWN shape

track_solid() is the one to reach for when tracking a pydamics solid (solidify()/.seo.solid()) -- it reads the shape directly off the object, so the drawn geometry can never drift out of sync with what actually collides. Works with both renderers.

API

floor_bounce(floor_y=0.0, radius=0.4, damping=0.65, x_bounds=None) Returns a callable for world.on_step that keeps entities above the floor (and optionally between walls), bouncing with energy loss on contact. This is demo-level logic -- use pydamics' real collision/SEO system for anything beyond quick demo purposes.

MatplotlibRenderer(world, xlim, ylim, floor_y=0.0, title=..., figsize=(6,6))

  • .track(entity, color=None, radius=0.4, shape="circle", width=None, height=None) — register an entity to draw; pass shape="box" + width/height for a rectangle
  • .track_solid(seo_obj, color=None) — track an SEO object, reading its shape directly
  • .label(position, text, color="black", fontsize=10) — thin wrapper over ax.text()
  • .animate(frames=180, dt=1/60, steps_per_frame=1, interval=33) — returns a FuncAnimation
  • .save_gif(path, frames=180, dt=1/60, steps_per_frame=1, fps=30) — steps the sim and saves a GIF
  • .save_png(path, after_steps=0, dt=1/60) — a single static frame, optionally stepping forward first

PygameRenderer(world, width=800, height=600, ppu=40, floor_y=0.0, title=...)

  • .track(entity, color=None, radius=0.4, shape="circle", width=None, height=None) — same shape options as matplotlib
  • .track_solid(seo_obj, color=None) — track an SEO object, reading its shape directly
  • .on_click(callback)callback(x_world, y_world) fires on every mouse click
  • .on_key(callback)callback(key, pressed) fires on every KEYDOWN/KEYUP
  • .on_frame(callback)callback(screen, dt) fires once per step(), after drawing, before flip
  • .on_event(callback)callback(event) fires for every raw pygame event (escape hatch)
  • .draw_text(text, pos, size=24, color=(255,255,255), family=None) — HUD text; call from inside on_frame. Fonts are cached by (family, size), not recreated every call
  • .step(dt=1/120) — advance and draw exactly one frame; returns False once quit is requested
  • .run(dt=1/120, fps=60) — convenience wrapper around step(), blocks until closed/ESC

Examples

pip install -e ".[dev]"
python examples/matplotlib_demo.py      # -> examples/falling_balls.gif
python examples/matplotlib_v013_demo.py # box shapes, track_solid, label, save_png
python examples/pygame_demo.py          # interactive window, click to drop balls
python examples/v013_demo.py            # step()-driven loop, HUD, pause, box wall

Roadmap

Staged for v0.1.4: rotation/orientation support, velocity-based dynamic color, camera pan/zoom/follow, trigger-zone/debug-shape visualization (paired with pydamics core once it ships), and sprite/image support.

Publishing (for maintainers)

Same flow as pydamics itself:

git init
git add .
git commit -m "Initial commit: pydamicsvisual"
git branch -M main
git remote add origin https://github.com/<your-username>/pydamicsvisual.git
git push -u origin main

Then set up a PyPI Trusted Publisher (pypi.org → account → Publishing) with:

  • PyPI project name: pydamicsvisual
  • Owner: <your-github-username>
  • Repository: pydamicsvisual
  • Workflow: publish.yml
  • Environment: pypi

Create a matching pypi environment under GitHub repo Settings → Environments, then ship a release (tag v0.1.0) to trigger the publish workflow.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydamicsvisual-0.1.3.tar.gz (14.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydamicsvisual-0.1.3-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file pydamicsvisual-0.1.3.tar.gz.

File metadata

  • Download URL: pydamicsvisual-0.1.3.tar.gz
  • Upload date:
  • Size: 14.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pydamicsvisual-0.1.3.tar.gz
Algorithm Hash digest
SHA256 faf79b8647da842929530be4572493b98384d4055f81556ad9b846ba1b016164
MD5 32488b383191a454bbf73ea723844ddd
BLAKE2b-256 443096fd15c6caf271d910fd7fcffce072d287f05206e74b97111cc9f34f9321

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydamicsvisual-0.1.3.tar.gz:

Publisher: publish.yml on Reeed-cell/PydamicsVisual

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pydamicsvisual-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: pydamicsvisual-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pydamicsvisual-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e2598c2fa9dc3518c0a4af77354e9df644d735fa7c7e2995c67cfebe80c31c53
MD5 f8ee76fa6637c0a6096412665283da5f
BLAKE2b-256 08da6d4e3ea34d84907bd2d64729788cd6a62fa34d896547f52f7e3734b82d8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydamicsvisual-0.1.3-py3-none-any.whl:

Publisher: publish.yml on Reeed-cell/PydamicsVisual

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page