Code
from tesserax import Canvas, Circle, Rect
# 1. Setup the Scene
with Canvas() as canvas:
floor = Rect(100, 20, fill="#333").translated(0, 200)
ball = Circle(20, fill="#ff0055").translated(00, 0)Tesserax includes a built-in, deterministic, baked physics engine. Unlike real-time game engines that calculate physics during the render loop, Tesserax calculates the entire simulation upfront and “bakes” it into standard KeyframeAnimation tracks.
This architecture offers two major advantages:
A high-level overview of the workflow is as follows:
World.Shape objects to the world (creates Body wrappers).Fields (like Gravity) and global constraints.world.simulate(duration) to generate an Animation.Scene.Here is a complete example of a ball falling under gravity and bouncing on a static floor. First we will create the scene.
Next, we define the physical world. This involves wrapping the existing shapes that will undergo physical simulation as Bodys and place them in a World. Once set up, we bake the physics animation with world.simulate(...).
from tesserax.physics import World, Gravity, Material, CircleCollider
world = World()
world.fields.append(Gravity()) # Downward acceleration (pixels/s^2)
world.add(floor, static=True, material=Material(restitution=0.8))
world.add(
ball,
material=Material(restitution=0.8, friction=0.5),
collider=CircleCollider(ball.r),
)
simulation = world.simulate(duration=5.0)Finally, we run the animation as normal. Notice we can simulate at some fixed framerate and render at a completely different rate. The property simulation.bounds has a precomputed approximate bounding box of the entire simulation so we can fit to it.
Tesserax physics engine also supports some simple constraints like Springs (soft constraints) and Rods (hard constraints). These work by applying forces and corrections to bodies during simulation.
from tesserax import Canvas, Rect, Circle, Line, Point
from tesserax.animation import Scene
from tesserax.physics import World, Gravity, Material
from tesserax.physics.constraints import Spring, Rod
with Canvas() as canvas:
r1 = Rect(20, 20, fill="steelblue").translated(50, 0)
ball = Circle(15, fill="orange").translated(100, 0)
r2 = Rect(20, 20, fill="green").translated(150, 0)
spring_line = Line(
lambda: r1.anchor("center"),
lambda: ball.anchor("center"),
stroke="gray",
width=3,
)
rod_line = Line(
lambda: ball.anchor("center"),
lambda: r2.anchor("center"),
stroke="gray",
width=3,
)
world = World()
world.fields.append(Gravity())
body_r1 = world.add(r1)
body_ball = world.add(
ball,
material=Material(restitution=0.8),
collider=CircleCollider(15),
static=True,
)
body_r2 = world.add(r2)
body_r2.angular_vel = 5.0 # Radians/sec
# Physics Constraint
world.constraint(Spring(body_r1, body_ball, length=30, k=50))
world.constraint(Spring(body_ball, body_r2, length=30, k=50))
# 3. Bake
simulation = world.simulate(duration=5.0)
canvas.fit(10, bounds=simulation.bounds)
# 4. Play
scene = Scene(canvas)
scene.play(simulation, duration=5.0)
scene.display()