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.4.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.4-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pydamicsvisual-0.1.4.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.4.tar.gz
Algorithm Hash digest
SHA256 21f1f4587b8d3f1c5b41126d00432a34887b7c7c159fac4a173d2e4b2e665a43
MD5 5d51616c81dd935a2e8c581377ba6546
BLAKE2b-256 90e8b124869b2d58d87a58b6d341a92a6d777e9049c6570477ddbf7786183d3c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydamicsvisual-0.1.4.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.4-py3-none-any.whl.

File metadata

  • Download URL: pydamicsvisual-0.1.4-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.4-py3-none-any.whl
Algorithm Hash digest
SHA256 68d765249483b19ea6773c1aa35febb1db3111b5381155a2549533a8270fbe7b
MD5 1d7c85cf1a6a99eab625ebc4f88a5793
BLAKE2b-256 f6fce8fe74636a5a4f49fe005b16e8894b052c25d5cae79105c15333ed948abf

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydamicsvisual-0.1.4-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