Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| RAPIER_TIMEOUT | No | Request timeout for the Rapier service in seconds. | 30.0 |
| PHYSICS_PROVIDER | No | Provider selection: 'analytic' for built-in formula-based calculations or 'rapier' for rigid-body simulations requiring an external service. | analytic |
| RAPIER_MAX_RETRIES | No | Maximum number of retries for Rapier service requests. | 3 |
| RAPIER_RETRY_DELAY | No | Delay between retries for Rapier service requests in seconds. | 1.0 |
| RAPIER_SERVICE_URL | No | The URL of the Rapier physics service. Defaults to the public service at https://rapier.chukai.io or http://localhost:9000 if running locally. | https://rapier.chukai.io |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| resources | {
"subscribe": false,
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| calculate_projectile_motion | Calculate projectile motion trajectory using kinematic equations. Computes the complete trajectory of a projectile launched at an angle,
including maximum height, range, time of flight, and sample trajectory points.
Perfect for ballistics, sports analysis, or educational demonstrations.
Args:
initial_velocity: Initial velocity in meters per second (m/s). Must be positive.
angle_degrees: Launch angle in degrees from horizontal (0-90).
0° = horizontal, 45° = maximum range, 90° = straight up
initial_height: Initial height above ground in meters. Default 0.0 (ground level).
gravity: Gravitational acceleration in m/s². Default 9.81 (Earth surface).
Use 1.62 for Moon, 3.71 for Mars, etc.
Returns:
ProjectileMotionResponse containing:
- max_height: Maximum height reached (meters)
- range: Horizontal distance traveled (meters)
- time_of_flight: Total time in air (seconds)
- trajectory_points: List of [x, y] sample points for plotting
Tips for LLMs:
- 45° gives maximum range on flat ground (no air resistance)
- For R3F visualization: convert trajectory_points to 3D by adding z=0
- trajectory_points are evenly spaced in time (50 samples)
- Air resistance is NOT modeled - this is ideal ballistic motion
- Use for: cannon balls, baseballs, basketball shots, water fountains
Example:
# Calculate trajectory of a cannonball fired at 50 m/s at 30°
result = await calculate_projectile_motion(
initial_velocity=50.0,
angle_degrees=30.0,
initial_height=2.0
)
print(f"Range: {result.range:.1f}m, Max height: {result.max_height:.1f}m") |
| check_collision | Check if two moving spherical objects will collide. Predicts whether two moving spheres will collide within a time window,
and if so, calculates when and where the collision occurs. Uses analytic
relative motion to find exact collision time (if any).
Args:
body1_position: Position of first object [x, y, z] in meters
body1_velocity: Velocity of first object [x, y, z] in m/s
body1_radius: Radius of first object in meters (must be positive)
body2_position: Position of second object [x, y, z] in meters
body2_velocity: Velocity of second object [x, y, z] in m/s
body2_radius: Radius of second object in meters (must be positive)
max_time: Maximum time to check in seconds. Default 10.0.
Returns:
CollisionCheckResponse containing:
- will_collide: True if collision will occur
- collision_time: Time until collision in seconds (if collision occurs)
- collision_point: Approximate collision location [x, y, z] (if collision occurs)
- impact_speed: Relative velocity at impact in m/s (if collision occurs)
- closest_approach_distance: Minimum distance between objects
- closest_approach_time: Time of closest approach
Tips for LLMs:
- Objects are modeled as spheres (point masses with radius)
- Collision detection is exact for constant velocity motion
- Returns earliest collision time if multiple intersections
- If no collision, check closest_approach_distance to see how close they get
- Use for: asteroid tracking, car crash prediction, sports ball interactions
- For complex shapes or forces, use create_simulation instead
Example:
# Check if two cars will collide
result = await check_collision(
body1_position=[0.0, 0.0, 0.0],
body1_velocity=[10.0, 0.0, 0.0],
body1_radius=2.0,
body2_position=[50.0, 1.0, 0.0],
body2_velocity=[-8.0, 0.0, 0.0],
body2_radius=2.0
)
if result.will_collide:
print(f"Collision in {result.collision_time:.2f} seconds at {result.impact_speed:.1f} m/s") |
| calculate_force | Calculate force from mass and acceleration using Newton's Second Law (F = ma). Computes the force vector required to produce a given acceleration on a mass.
Fundamental for dynamics, engineering, and understanding motion.
Args:
mass: Mass in kilograms (must be positive)
acceleration_x: X component of acceleration in m/s²
acceleration_y: Y component of acceleration in m/s²
acceleration_z: Z component of acceleration in m/s²
Returns:
ForceCalculationResponse containing:
- force: Force vector [x, y, z] in Newtons
- magnitude: Force magnitude in Newtons
Tips for LLMs:
- 1 Newton = force to accelerate 1 kg at 1 m/s²
- On Earth, weight force = mass × 9.81 N (vertical)
- Use magnitude to compare total force regardless of direction
- Common accelerations: car braking ~10 m/s², elevator ~2 m/s²
Example:
# Force to accelerate a 1500kg car at 3 m/s² forward
result = await calculate_force(
mass=1500.0,
acceleration_x=3.0,
acceleration_y=0.0,
acceleration_z=0.0
)
print(f"Required force: {result.magnitude:.0f} N") |
| calculate_kinetic_energy | Calculate kinetic energy from mass and velocity (KE = ½mv²). Computes the energy of motion for a moving object. Energy is scalar
(direction doesn't matter, only speed). Useful for collision analysis,
vehicle safety, and understanding energy transfer.
Args:
mass: Mass in kilograms (must be positive)
velocity_x: X component of velocity in m/s
velocity_y: Y component of velocity in m/s
velocity_z: Z component of velocity in m/s
Returns:
KineticEnergyResponse containing:
- kinetic_energy: Energy in Joules (J)
- speed: Velocity magnitude in m/s
Tips for LLMs:
- 1 Joule = 1 kg⋅m²/s² = energy to lift 102g by 1m on Earth
- Kinetic energy doubles mass → doubles energy, doubles speed → 4× energy
- Car at highway speed (~30 m/s, 1500 kg) ≈ 675,000 J
- Use to compare impact severity or stopping distances
Example:
# Energy of a 0.145kg baseball at 40 m/s
result = await calculate_kinetic_energy(
mass=0.145,
velocity_x=40.0,
velocity_y=0.0,
velocity_z=0.0
)
print(f"Kinetic energy: {result.kinetic_energy:.1f} J") |
| calculate_momentum | Calculate momentum from mass and velocity (p = mv). Computes the momentum vector, which represents "quantity of motion."
Momentum is conserved in collisions, making it crucial for analyzing
impacts, explosions, and rocket propulsion.
Args:
mass: Mass in kilograms (must be positive)
velocity_x: X component of velocity in m/s
velocity_y: Y component of velocity in m/s
velocity_z: Z component of velocity in m/s
Returns:
MomentumResponse containing:
- momentum: Momentum vector [x, y, z] in kg⋅m/s
- magnitude: Momentum magnitude in kg⋅m/s
Tips for LLMs:
- Momentum is a vector (has direction), unlike kinetic energy
- Total momentum before collision = total momentum after (conservation)
- Large mass × small velocity can equal small mass × large velocity
- Use to analyze: collisions, recoil, rocket thrust
Example:
# Momentum of a 70kg person running at 5 m/s
result = await calculate_momentum(
mass=70.0,
velocity_x=5.0,
velocity_y=0.0,
velocity_z=0.0
)
print(f"Momentum: {result.magnitude:.1f} kg⋅m/s") |
| calculate_potential_energy | Calculate gravitational potential energy. Computes PE = mgh (mass × gravity × height).
Also returns the equivalent velocity if the object falls from that height.
Args:
mass: Object mass in kilograms
height: Height above reference point in meters
gravity: Gravitational acceleration in m/s² (default 9.81 for Earth)
Returns:
Dict containing:
- potential_energy: PE in Joules
- equivalent_kinetic_velocity: Speed if dropped from height (m/s)
Example - Object at 10m height:
result = await calculate_potential_energy(mass=2.0, height=10.0)
# PE = 196.2 J
# Velocity if dropped = 14.0 m/s |
| calculate_work_power | Calculate work done by a force and optionally power. Work is the dot product: W = F · d
Power (if time given): P = W / t
Args:
force: Force vector [x, y, z] in Newtons (or JSON string)
displacement: Displacement vector [x, y, z] in meters (or JSON string)
time: Time taken in seconds (optional, for power calculation)
Returns:
Dict containing:
- work: Work done in Joules
- power: Power in Watts (if time provided, else None)
Example - Pushing box 5m with 100N force:
result = await calculate_work_power(
force=[100, 0, 0],
displacement=[5, 0, 0],
time=10.0
)
# Work = 500 J, Power = 50 W |
| calculate_elastic_collision | Calculate final velocities after a 1D elastic collision. Uses conservation of momentum and energy to solve for final velocities.
Assumes perfectly elastic collision (no energy loss).
Args:
mass1: Mass of first object in kg
velocity1: Initial velocity of first object in m/s (1D)
mass2: Mass of second object in kg
velocity2: Initial velocity of second object in m/s (1D)
Returns:
Dict containing:
- final_velocity1: Final velocity of object 1 in m/s
- final_velocity2: Final velocity of object 2 in m/s
- initial_kinetic_energy: Total KE before (J)
- final_kinetic_energy: Total KE after (J) - should equal initial
- initial_momentum: Total momentum before (kg⋅m/s)
- final_momentum: Total momentum after (kg⋅m/s) - should equal initial
Example - Pool ball collision:
result = await calculate_elastic_collision(
mass1=0.17, # kg (pool ball)
velocity1=2.0, # m/s (moving right)
mass2=0.17, # kg (pool ball)
velocity2=0.0 # m/s (stationary)
)
# Result: ball 1 stops, ball 2 moves at 2.0 m/s |
| calculate_centripetal_force | Calculate centripetal force: F_c = m v² / r. Force required to keep an object moving in a circle.
Always points toward the center of the circular path.
Args:
mass: Mass in kg
velocity: Speed (velocity magnitude) in m/s
radius: Radius of circular path in meters
Returns:
Dict containing:
- centripetal_force: F_c in Newtons
- centripetal_acceleration: a_c in m/s²
Tips for LLMs:
- Not a new force - it's the net inward force (tension, friction, gravity)
- Faster speed → much more force needed (v² relationship)
- Tighter turn → more force needed
- Use for: car turns, satellite orbits, centrifuges
Example - Car turning:
result = await calculate_centripetal_force(
mass=1500, # kg
velocity=20, # m/s (72 km/h)
radius=50 # meter turn radius
)
# F_c = 12000 N (provided by friction between tires and road) |
| calculate_orbital_period | Calculate orbital period: T = 2π√(r³/GM). Kepler's Third Law for circular orbits. Period depends on orbital
radius and central body mass.
Args:
orbital_radius: Orbital radius in meters (from center of central body)
central_mass: Mass of central body in kg
gravitational_constant: G in m³/(kg⋅s²) (default 6.674e-11)
Returns:
Dict containing:
- period: Orbital period in seconds
- orbital_velocity: v in m/s
- period_hours: Period in hours (for convenience)
- period_days: Period in days (for convenience)
Tips for LLMs:
- Higher orbit → longer period
- More massive central body → shorter period
- Earth: M = 5.972e24 kg, R = 6.371e6 m
- Moon orbit: r ≈ 384,400 km, T ≈ 27.3 days
- ISS orbit: r ≈ 6,771 km (altitude 400 km), T ≈ 90 minutes
Example - ISS orbit:
result = await calculate_orbital_period(
orbital_radius=6.771e6, # meters
central_mass=5.972e24 # Earth mass (kg)
)
# T ≈ 5,558 seconds ≈ 92.6 minutes |
| calculate_banking_angle | Calculate ideal banking angle: θ = arctan(v² / (rg)). For a banked curve, the ideal angle where no friction is needed
to maintain the turn at a given speed.
Args:
velocity: Speed in m/s
radius: Turn radius in meters
gravity: Gravitational acceleration in m/s² (default 9.81)
Returns:
Dict containing:
- angle_radians: Banking angle in radians
- angle_degrees: Banking angle in degrees
Tips for LLMs:
- Faster speed → steeper banking angle
- Tighter turn → steeper banking angle
- NASCAR tracks banked ~30° for high-speed turns
- At ideal angle, normal force provides all centripetal force
Example - Highway exit ramp:
result = await calculate_banking_angle(
velocity=25, # m/s (90 km/h)
radius=100 # meter radius turn
)
# θ ≈ 32.5° |
| calculate_escape_velocity | Calculate escape velocity: v_escape = √(2GM/r). Minimum speed needed to escape a celestial body's gravitational pull.
Independent of the escaping object's mass.
Args:
mass: Mass of celestial body in kg
radius: Radius of celestial body in meters
gravitational_constant: G in m³/(kg⋅s²) (default 6.674e-11)
Returns:
Dict containing:
- escape_velocity: v_escape in m/s
- escape_velocity_kmh: v_escape in km/h (for convenience)
Tips for LLMs:
- Earth: v_escape ≈ 11,200 m/s (40,320 km/h)
- Moon: v_escape ≈ 2,380 m/s
- Sun: v_escape ≈ 617,500 m/s
- Independent of escape direction or mass of escaping object
Example - Earth escape velocity:
result = await calculate_escape_velocity(
mass=5.972e24, # Earth mass (kg)
radius=6.371e6 # Earth radius (meters)
)
# v_escape ≈ 11,186 m/s |
| analyze_circular_orbit | Analyze circular orbit at given altitude above planet surface. Comprehensive orbital analysis combining period, velocity, and acceleration.
Args:
altitude: Altitude above surface in meters
planet_mass: Planet mass in kg
planet_radius: Planet radius in meters
gravitational_constant: G in m³/(kg⋅s²) (default 6.674e-11)
Returns:
Dict containing:
- orbital_radius: r from planet center in meters
- orbital_velocity: v in m/s
- period_seconds: Orbital period in seconds
- period_minutes: Orbital period in minutes
- centripetal_acceleration: a_c in m/s²
Example - LEO satellite at 400km altitude:
result = await analyze_circular_orbit(
altitude=400000, # 400 km
planet_mass=5.972e24, # Earth
planet_radius=6.371e6 # Earth
)
# v ≈ 7,670 m/s, T ≈ 92.6 min |
| calculate_inelastic_collision_3d | Calculate 3D collision with coefficient of restitution. Models realistic collisions where some kinetic energy is lost.
Coefficient of restitution (e) determines how much energy is retained.
Args:
mass1: Mass of object 1 in kg
velocity1: Velocity of object 1 [x, y, z] in m/s (or JSON string)
mass2: Mass of object 2 in kg
velocity2: Velocity of object 2 [x, y, z] in m/s (or JSON string)
coefficient_of_restitution: e (0.0 = perfectly inelastic, 1.0 = perfectly elastic)
Returns:
Dict containing:
- final_velocity1: Final velocity [x, y, z] in m/s
- final_velocity2: Final velocity [x, y, z] in m/s
- initial_momentum: Total initial momentum [x, y, z]
- final_momentum: Total final momentum [x, y, z]
- initial_kinetic_energy: Total initial KE in Joules
- final_kinetic_energy: Total final KE in Joules
- energy_loss: Energy lost in Joules
- energy_loss_percent: % of energy lost
Coefficient of restitution values:
- e = 0.0: Perfectly inelastic (clay, putty) - objects stick
- e = 0.5: Very inelastic (wet clay)
- e = 0.7: Moderately elastic (basketball)
- e = 0.9: Highly elastic (Super Ball)
- e = 1.0: Perfectly elastic (ideal, no energy loss)
Tips for LLMs:
- Momentum is always conserved (regardless of e)
- Energy lost = (1 - e²) × initial KE in center-of-mass frame
- Use e=1.0 for billiard balls, e=0.0 for car crashes
Example - Car crash:
result = await calculate_inelastic_collision_3d(
mass1=1500, # kg
velocity1=[20, 0, 0], # 20 m/s east
mass2=1200, # kg
velocity2=[-15, 0, 0], # 15 m/s west
coefficient_of_restitution=0.1 # very inelastic
)
# Massive energy loss, objects nearly stick together |
| calculate_elastic_collision_3d | Calculate 3D elastic collision (perfect energy conservation). Special case of collision where no kinetic energy is lost (e = 1.0).
Both momentum and energy are conserved.
Args:
mass1: Mass of object 1 in kg
velocity1: Velocity of object 1 [x, y, z] in m/s (or JSON string)
mass2: Mass of object 2 in kg
velocity2: Velocity of object 2 [x, y, z] in m/s (or JSON string)
Returns:
Dict containing:
- final_velocity1: Final velocity [x, y, z] in m/s
- final_velocity2: Final velocity [x, y, z] in m/s
- initial_momentum: Total momentum [x, y, z]
- final_momentum: Total momentum [x, y, z]
- initial_kinetic_energy: Total KE in Joules
- final_kinetic_energy: Total KE in Joules
Tips for LLMs:
- Ideal approximation for billiard balls, Newton's cradle
- Both momentum and energy conserved
- Equal masses + head-on → velocities exchange
- Use for educational examples, idealized systems
Example - Pool balls:
result = await calculate_elastic_collision_3d(
mass1=0.17, # kg (pool ball)
velocity1=[2, 0, 0], # 2 m/s
mass2=0.17, # kg
velocity2=[0, 0, 0] # stationary
)
# Result: ball 1 stops, ball 2 moves at 2 m/s |
| check_energy_conservation | Verify conservation of energy in a physics process. Checks whether total mechanical energy is conserved (or correctly dissipated).
Useful for validating simulation results and understanding energy transfer.
Args:
initial_kinetic_energy: Initial KE in Joules
final_kinetic_energy: Final KE in Joules
initial_potential_energy: Initial PE in Joules
final_potential_energy: Final PE in Joules
expected_energy_loss: Expected energy loss (from friction, etc.) in Joules
tolerance: Tolerance for conservation check (fraction, default 0.01 = 1%)
Returns:
Dict containing:
- initial_total_energy: Initial total energy in Joules
- final_total_energy: Final total energy in Joules
- energy_difference: Energy difference in Joules
- energy_difference_percent: % difference
- is_conserved: Whether energy is conserved within tolerance
- expected_loss: Expected energy loss in Joules
- actual_loss: Actual energy loss in Joules
Tips for LLMs:
- In isolated systems, total energy is conserved
- With friction/damping, expect energy loss
- Small numerical errors are normal in simulations
- Use to validate simulation accuracy
Example - Bouncing ball with energy loss:
result = await check_energy_conservation(
initial_kinetic_energy=0,
final_kinetic_energy=0,
initial_potential_energy=10, # J (at 1m height)
final_potential_energy=6.4, # J (bounced to 0.64m)
expected_energy_loss=3.6, # 36% loss (e=0.8)
tolerance=0.01
) |
| check_momentum_conservation | Verify conservation of momentum. Checks whether total momentum is conserved in a collision or interaction.
Momentum should be conserved in isolated systems (no external forces).
Args:
initial_momentum: Initial total momentum [x, y, z] in kg⋅m/s (or JSON string)
final_momentum: Final total momentum [x, y, z] in kg⋅m/s (or JSON string)
tolerance: Tolerance for conservation check (fraction, default 0.01 = 1%)
Returns:
Dict containing:
- initial_momentum_magnitude: Initial |p| in kg⋅m/s
- final_momentum_magnitude: Final |p| in kg⋅m/s
- momentum_difference: Difference [x, y, z]
- momentum_difference_magnitude: |Δp|
- momentum_difference_percent: % difference
- is_conserved: Whether momentum is conserved within tolerance
Tips for LLMs:
- Momentum is ALWAYS conserved in isolated systems
- Vector quantity - direction matters
- Use to validate collision calculations
- External forces (friction, etc.) can change total momentum
Example - Collision verification:
result = await check_momentum_conservation(
initial_momentum=[3000, 0, 0], # kg⋅m/s
final_momentum=[2995, 5, 0], # slightly off
tolerance=0.01
) |
| check_angular_momentum_conservation | Verify conservation of angular momentum. Checks whether total angular momentum is conserved. Angular momentum
is conserved when no external torques act on the system.
Args:
initial_angular_momentum: Initial L [x, y, z] in kg⋅m²/s (or JSON string)
final_angular_momentum: Final L [x, y, z] in kg⋅m²/s (or JSON string)
tolerance: Tolerance (fraction, default 0.01 = 1%)
Returns:
Dict containing:
- initial_L_magnitude: Initial |L| in kg⋅m²/s
- final_L_magnitude: Final |L| in kg⋅m²/s
- L_difference: Difference [x, y, z]
- L_difference_magnitude: |ΔL|
- L_difference_percent: % difference
- is_conserved: Whether L is conserved within tolerance
Tips for LLMs:
- Conserved when no external torques (isolated rotation)
- Ice skater spinning: pull arms in → I decreases → ω increases (L constant)
- Gyroscope: resists changes to L direction
- Planets orbiting: L conserved → elliptical orbits
Example - Figure skater:
# Arms extended → Arms pulled in
result = await check_angular_momentum_conservation(
initial_angular_momentum=[0, 15, 0], # kg⋅m²/s
final_angular_momentum=[0, 15.05, 0],
tolerance=0.01
) |
| track_energy_dissipation | Track energy dissipation over a trajectory. Analyzes how energy changes over time in a recorded trajectory.
Useful for understanding damping, bounces, and energy loss mechanisms.
Args:
trajectory_data: Trajectory data dict with 'frames' field
mass: Object mass in kg
gravity: Gravitational acceleration in m/s² (default 9.81)
reference_height: Reference height for PE in meters (default 0.0)
Returns:
Dict containing:
- frames: Energy data for each frame (time, KE, PE, total E)
- initial_total_energy: Initial total energy in Joules
- final_total_energy: Final total energy in Joules
- total_energy_loss: Total energy dissipated in Joules
- total_energy_loss_percent: % of energy lost
- average_power_dissipated: Average power in Watts (J/s)
Tips for LLMs:
- Use after record_trajectory or record_trajectory_with_events
- Visualize energy vs time to see where energy is lost
- Identifies bounces, friction effects, air resistance
- Power = rate of energy dissipation
Example - Bouncing ball energy analysis:
traj = await record_trajectory_with_events(sim_id, "ball", 600)
result = await track_energy_dissipation(
trajectory_data=traj.model_dump(),
mass=0.5, # 500g ball
gravity=9.81
)
# See how energy decreases with each bounce |
| calculate_drag_force | Calculate drag force for an object moving through a fluid. The drag force opposes motion and is given by:
F_drag = 0.5 * ρ * v² * C_d * A
Common drag coefficients:
- Sphere: 0.47
- Streamlined shape: 0.04
- Flat plate (perpendicular): 1.28
- Human (standing): 1.0-1.3
- Car: 0.25-0.35
Args:
velocity: Velocity vector [x, y, z] in m/s (or JSON string)
cross_sectional_area: Area perpendicular to flow in m²
fluid_density: Fluid density in kg/m³ (water=1000, air=1.225)
drag_coefficient: Drag coefficient (default 0.47 for sphere)
viscosity: Dynamic viscosity in Pa·s (water=1.002e-3, air=1.825e-5, oil=0.1).
If not provided, estimated from fluid_density for Reynolds number calculation.
Returns:
Drag force vector, magnitude, and Reynolds number
Example - Ball falling through water:
result = await calculate_drag_force(
velocity=[0, -5.0, 0],
cross_sectional_area=0.00785, # π * (0.05m)² for 10cm diameter
fluid_density=1000, # water
drag_coefficient=0.47,
viscosity=1.002e-3 # water viscosity for accurate Reynolds number
)
# Returns upward drag force opposing downward motion
Example - Ball falling through motor oil:
result = await calculate_drag_force(
velocity=[0, -2.0, 0],
cross_sectional_area=0.00785,
fluid_density=900, # oil
drag_coefficient=0.47,
viscosity=0.1 # motor oil is much more viscous
) |
| calculate_buoyancy | Calculate buoyancy force using Archimedes' principle. The buoyant force equals the weight of displaced fluid:
F_b = ρ_fluid * V_submerged * g
Args:
volume: Object volume in m³
fluid_density: Fluid density in kg/m³ (water=1000, air=1.225)
gravity: Gravitational acceleration in m/s² (default 9.81)
submerged_fraction: Fraction submerged 0.0-1.0 (default 1.0 = fully submerged)
Returns:
Buoyant force (upward) and displaced mass
Example - Checking if a 1kg ball will float:
# 10cm diameter sphere: V = (4/3)πr³ = 0.000524 m³
result = await calculate_buoyancy(
volume=0.000524,
fluid_density=1000 # water
)
# buoyant_force = 5.14 N
# If weight (mg) < buoyant force, it floats
# 1kg * 9.81 = 9.81 N > 5.14 N, so it sinks |
| calculate_terminal_velocity | Calculate terminal velocity when drag equals weight. At terminal velocity, forces balance:
F_drag = F_weight
v_terminal = √(2mg / ρC_dA)
Args:
mass: Object mass in kg
cross_sectional_area: Area perpendicular to fall direction in m²
fluid_density: Fluid density in kg/m³ (air=1.225, water=1000)
drag_coefficient: Drag coefficient (sphere=0.47, skydiver=1.0)
gravity: Gravitational acceleration in m/s² (default 9.81)
Returns:
Terminal velocity, time to 95%, and drag force at terminal
Example - Skydiver terminal velocity:
result = await calculate_terminal_velocity(
mass=70, # kg
cross_sectional_area=0.7, # m² (belly-down position)
fluid_density=1.225, # air
drag_coefficient=1.0, # human
)
# v_terminal ≈ 54 m/s (120 mph) |
| simulate_underwater_motion | Simulate underwater projectile motion with drag and buoyancy. Uses numerical integration to simulate motion under:
- Gravity (downward)
- Buoyancy (upward, from displaced fluid)
- Drag (opposes motion)
Args:
initial_velocity: Initial velocity [x, y, z] in m/s
mass: Object mass in kg
volume: Object volume in m³
cross_sectional_area: Cross-sectional area in m²
fluid_density: Fluid density in kg/m³ (default 1000 for water)
fluid_viscosity: Fluid viscosity in Pa·s (default 1.002e-3 for water)
initial_position: Initial position [x, y, z] in m (default [0,0,0])
drag_coefficient: Drag coefficient (default 0.47 for sphere)
gravity: Gravitational acceleration in m/s² (default 9.81)
duration: Simulation duration in seconds (default 10.0)
dt: Time step in seconds (default 0.01)
Returns:
Complete trajectory, final state, max depth, and total distance
Example - Torpedo launch:
result = await simulate_underwater_motion(
initial_velocity=[20, 0, 0], # 20 m/s forward
mass=100, # kg
volume=0.05, # m³
cross_sectional_area=0.03, # m²
fluid_density=1000, # water
drag_coefficient=0.04, # streamlined
duration=30.0
) |
| calculate_lift_force | Calculate lift force using: L = (1/2) ρ v² C_L A. Based on Bernoulli's principle and wing aerodynamics.
Args:
velocity: Flow velocity in m/s
wing_area: Wing area in m²
lift_coefficient: Lift coefficient C_L (dimensionless)
fluid_density: Fluid density in kg/m³ (air=1.225)
Returns:
Dict containing:
- lift_force: Lift force in Newtons
- dynamic_pressure: Dynamic pressure (q) in Pascals
Example - Aircraft wing:
result = await calculate_lift_force(
velocity=70, # m/s (~250 km/h)
wing_area=20.0, # m²
lift_coefficient=1.2,
fluid_density=1.225
) |
| calculate_magnus_force | Calculate Magnus force on a spinning ball. The Magnus force is perpendicular to both velocity and spin axis.
Causes curve balls in sports.
Args:
velocity: Ball velocity [x, y, z] in m/s (or JSON string)
angular_velocity: Angular velocity [x, y, z] in rad/s (or JSON string)
radius: Ball radius in meters
fluid_density: Fluid density in kg/m³ (air=1.225)
Returns:
Dict containing:
- magnus_force: Magnus force vector [x, y, z] in Newtons
- magnus_force_magnitude: Force magnitude in Newtons
- spin_rate: Spin rate (angular velocity magnitude) in rad/s
Example - Soccer ball curve:
result = await calculate_magnus_force(
velocity=[20, 0, 0], # 20 m/s forward
angular_velocity=[0, 0, 50], # 50 rad/s topspin
radius=0.11, # Soccer ball
fluid_density=1.225
) |
| calculate_bernoulli | Calculate Bernoulli's equation: P + (1/2)ρv² + ρgh = constant. Energy conservation for flowing fluids.
Args:
pressure1: Pressure at point 1 in Pascals
velocity1: Flow velocity at point 1 in m/s
height1: Height at point 1 in meters
velocity2: Flow velocity at point 2 in m/s (optional)
height2: Height at point 2 in meters (optional)
fluid_density: Fluid density in kg/m³ (default 1000 for water)
gravity: Gravitational acceleration in m/s² (default 9.81)
Returns:
Dict containing:
- total_pressure_1: Total pressure at point 1
- static_pressure_1: Static pressure component
- dynamic_pressure_1: Dynamic pressure component
- hydrostatic_pressure_1: Hydrostatic pressure component
- pressure2: Pressure at point 2 (if velocity2/height2 given)
Example - Water tank with outlet:
result = await calculate_bernoulli(
pressure1=101325, # Atmospheric at top
velocity1=0, # Still water
height1=10, # 10m height
velocity2=14, # Exit velocity
height2=0, # Ground level
fluid_density=1000
) |
| calculate_pressure_at_depth | Calculate pressure at depth: P = P_atm + ρgh. Hydrostatic pressure increases with depth.
Args:
depth: Depth below surface in meters
fluid_density: Fluid density in kg/m³ (water=1000, seawater=1025)
atmospheric_pressure: Pressure at surface in Pascals (default 101325)
gravity: Gravitational acceleration in m/s² (default 9.81)
Returns:
Dict containing:
- total_pressure: Total pressure in Pascals
- gauge_pressure: Pressure above atmospheric in Pascals
- pressure_atmospheres: Pressure in atmospheres (1 atm = 101325 Pa)
Example - Scuba diving at 30m:
result = await calculate_pressure_at_depth(
depth=30, # meters
fluid_density=1025, # seawater
atmospheric_pressure=101325
)
# Result: ~4 atmospheres |
| calculate_reynolds_number | Calculate Reynolds number: Re = ρvL/μ. Determines flow regime (laminar, transitional, turbulent).
Args:
velocity: Flow velocity in m/s
characteristic_length: Characteristic length in meters (pipe diameter, etc.)
fluid_density: Fluid density in kg/m³
dynamic_viscosity: Dynamic viscosity in Pa·s (water=0.001, air=1.8e-5)
Returns:
Dict containing:
- reynolds_number: Re (dimensionless)
- flow_regime: "laminar" (Re<2300), "transitional" (2300-4000), "turbulent" (Re>4000)
Example - Water in pipe:
result = await calculate_reynolds_number(
velocity=2.0, # m/s
characteristic_length=0.05, # 5cm diameter
fluid_density=1000, # water
dynamic_viscosity=0.001
)
# Re = 100,000 → turbulent |
| calculate_venturi_effect | Calculate Venturi effect (flow through constriction). Uses continuity equation and Bernoulli's principle.
Args:
inlet_diameter: Inlet diameter in meters
throat_diameter: Throat (constriction) diameter in meters
inlet_velocity: Inlet velocity in m/s
fluid_density: Fluid density in kg/m³
Returns:
Dict containing:
- throat_velocity: Velocity at throat in m/s
- pressure_drop: Pressure drop from inlet to throat in Pascals
- flow_rate: Volumetric flow rate in m³/s
Example - Venturi meter:
result = await calculate_venturi_effect(
inlet_diameter=0.1, # 10 cm
throat_diameter=0.05, # 5 cm
inlet_velocity=2.0, # m/s
fluid_density=1000 # water
)
# throat_velocity = 8 m/s (4x area reduction) |
| calculate_acceleration_from_position | Calculate acceleration by numerical differentiation of position data. Uses central differences for numerical differentiation:
v[i] ≈ (r[i+1] - r[i-1]) / (2Δt)
a[i] ≈ (v[i+1] - v[i-1]) / (2Δt)
Args:
times: Time values in seconds (or JSON string)
positions: Position vectors [[x,y,z], ...] in meters (or JSON string)
Returns:
Dict containing:
- velocities: Velocity vectors [[x,y,z], ...] in m/s
- accelerations: Acceleration vectors [[x,y,z], ...] in m/s²
- average_velocity: Average velocity [x,y,z] in m/s
- average_acceleration: Average acceleration [x,y,z] in m/s²
Example - Analyze recorded position data:
result = await calculate_acceleration_from_position(
times=[0, 1, 2, 3],
positions=[[0,0,0], [5,0,0], [10,0,0], [15,0,0]]
) |
| calculate_jerk | Calculate jerk (rate of change of acceleration). Jerk = da/dt is important for comfort in vehicles and mechanical design.
Args:
times: Time values in seconds (or JSON string)
accelerations: Acceleration vectors [[x,y,z], ...] in m/s² (or JSON string)
Returns:
Dict containing:
- jerks: Jerk vectors [[x,y,z], ...] in m/s³
- average_jerk: Average jerk [x,y,z] in m/s³
- max_jerk_magnitude: Maximum jerk magnitude in m/s³
Example:
result = await calculate_jerk(
times=[0, 1, 2, 3],
accelerations=[[0,0,0], [2,0,0], [4,0,0], [6,0,0]]
)
# jerk_x ≈ 2 m/s³ (constant) |
| fit_trajectory | Fit polynomial to trajectory data. Useful for smoothing noisy data or finding trajectory equations.
Default fit_type="quadratic" fits parabolic trajectory (constant acceleration).
Args:
times: Time values in seconds (or JSON string)
positions: Position vectors [[x,y,z], ...] in meters (or JSON string)
fit_type: Polynomial type - "linear", "quadratic", or "cubic" (default "quadratic")
Returns:
Dict containing:
- coefficients_x: Polynomial coefficients for x(t)
- coefficients_y: Polynomial coefficients for y(t)
- coefficients_z: Polynomial coefficients for z(t)
- r_squared: R² goodness of fit (0-1)
- predicted_positions: Fitted positions [[x,y,z], ...]
Example - Projectile motion:
result = await fit_trajectory(
times=[0, 1, 2, 3],
positions=[[0,0,0], [10,15,0], [20,20,0], [30,15,0]],
fit_type="quadratic"
)
# Fits x(t) = c0 + c1*t + c2*t² |
| generate_motion_graph | Generate motion graph data (position, velocity, acceleration vs time). Calculates velocity and acceleration from position data and extracts
the specified component for graphing.
Args:
times: Time values in seconds (or JSON string)
positions: Position vectors [[x,y,z], ...] in meters (or JSON string)
component: Which component to analyze - "x", "y", "z", or "magnitude" (default)
Returns:
Dict containing:
- times: Time values
- positions: Position values (selected component)
- velocities: Velocity values (selected component)
- accelerations: Acceleration values (selected component)
- max_velocity: Maximum velocity magnitude
- max_acceleration: Maximum acceleration magnitude
- component: Which component was analyzed
Example:
result = await generate_motion_graph(
times=[0, 1, 2, 3],
positions=[[0,0,0], [5,0,0], [20,0,0], [45,0,0]],
component="x"
)
# Automatically calculates v and a |
| calculate_average_speed | Calculate average speed along a path. Average speed = total distance / total time
(Distance is path length, not displacement)
Args:
positions: Position vectors [[x,y,z], ...] in meters (or JSON string)
times: Time values in seconds (or JSON string)
Returns:
Dict containing:
- average_speed: Average speed in m/s
- total_distance: Total path length in meters
- total_time: Total elapsed time in seconds
- displacement_magnitude: Straight-line displacement in meters
- displacement: Displacement vector [x,y,z] in meters
Example - Car on winding road:
result = await calculate_average_speed(
positions=[[0,0,0], [10,5,0], [20,10,0], [15,20,0]],
times=[0, 10, 20, 30]
) |
| calculate_instantaneous_velocity | Calculate instantaneous velocity at a specific time. Uses interpolation if target_time is between data points,
otherwise uses numerical differentiation.
Args:
positions: Position vectors [[x,y,z], ...] in meters (or JSON string)
times: Time values in seconds (or JSON string)
target_time: Time at which to calculate velocity in seconds
Returns:
Dict containing:
- velocity: Velocity vector [x,y,z] in m/s
- speed: Speed magnitude in m/s
- interpolated: Whether interpolation was used
- time: Target time (echo)
Example:
result = await calculate_instantaneous_velocity(
positions=[[0,0,0], [3,4,0], [6,8,0]],
times=[0, 1, 2],
target_time=1.0
)
# speed = 5 m/s |
| calculate_projectile_with_drag | Calculate projectile motion including air resistance (drag). Uses numerical integration (RK4) to solve motion equations with:
- Quadratic drag force: F_drag = 0.5 * ρ * v² * Cd * A
- Magnus force (spin effects): F_magnus = 0.5 * ρ * Cl * A * ω * r * v
- Wind effects (constant wind vector)
- Variable air density (altitude and temperature effects)
This provides REALISTIC trajectories for sports balls, projectiles,
and other objects moving through air or water. Compare with
calculate_projectile_motion (no drag) to see dramatic differences!
Common drag coefficients (Cd):
- Sphere: 0.47 (default)
- Baseball: 0.4
- Golf ball: 0.25 (dimples reduce drag)
- Football (American): 0.05-0.15 (orientation-dependent)
- Basketball: 0.55
- Soccer ball: 0.25
- Skydiver (belly-down): 1.0-1.3
- Streamlined car: 0.25-0.35
Args:
initial_velocity: Launch velocity in m/s
angle_degrees: Launch angle in degrees (0-90)
mass: Object mass in kg
cross_sectional_area: Cross-section perpendicular to motion in m²
initial_height: Launch height in meters (default 0)
drag_coefficient: Drag coefficient Cd (default 0.47 for sphere)
fluid_density: Fluid density in kg/m³ (air=1.225, water=1000)
gravity: Gravitational acceleration m/s² (default 9.81)
time_step: Integration time step in seconds (default 0.01)
max_time: Maximum simulation time in seconds (default 30)
spin_rate: Spin rate in rad/s for Magnus force (default 0, no spin)
spin_axis: Spin axis unit vector [x, y, z] (default [0, 0, 1] = vertical)
wind_velocity: Wind velocity [vx, vy] in m/s (default [0, 0], no wind)
altitude: Altitude above sea level in meters (default 0, affects air density)
temperature: Air temperature in Celsius (default 15, affects air density)
Returns:
Dict containing:
- max_height: Maximum altitude reached (m)
- range: Horizontal distance traveled (m)
- time_of_flight: Total flight time (s)
- impact_velocity: Speed at landing (m/s)
- impact_angle: Angle at landing (degrees below horizontal)
- trajectory_points: [[x, y], ...] for plotting
- energy_lost_to_drag: Energy dissipated by drag (J)
- initial_kinetic_energy: Initial KE (J)
- final_kinetic_energy: Final KE (J)
- lateral_deflection: Lateral deflection from spin/wind (m)
- magnus_force_max: Maximum Magnus force magnitude (N)
- wind_drift: Total wind drift (m)
- effective_air_density: Effective air density used (kg/m³)
Example - Baseball curveball (2500 rpm backspin):
result = await calculate_projectile_with_drag(
initial_velocity=40.23, # 90 mph
angle_degrees=10,
mass=0.145,
cross_sectional_area=0.0043,
drag_coefficient=0.4,
spin_rate=261.8, # 2500 rpm = 261.8 rad/s
spin_axis=[0, 0, 1] # Backspin (vertical axis)
)
# Backspin increases range and height!
Example - Golf ball at altitude (Denver, 1600m):
result = await calculate_projectile_with_drag(
initial_velocity=70,
angle_degrees=12,
mass=0.0459,
cross_sectional_area=0.00143,
drag_coefficient=0.25,
altitude=1600, # Denver elevation
temperature=20 # Summer day
)
# Less air resistance = longer drive!
Example - Soccer free kick with wind:
result = await calculate_projectile_with_drag(
initial_velocity=25,
angle_degrees=15,
mass=0.43,
cross_sectional_area=0.0388,
drag_coefficient=0.25,
wind_velocity=[5, 0], # 5 m/s tailwind
spin_rate=50, # Sidespin for curve
spin_axis=[0, 1, 0] # Horizontal axis
)
# Wind drift + Magnus curve! |
| calculate_hookes_law | Calculate spring force using Hooke's Law: F = -kx. The restoring force is proportional to displacement from equilibrium.
Fundamental for springs, elastic materials, and simple harmonic motion.
Args:
spring_constant: Spring constant k in N/m (stiffness)
displacement: Displacement from equilibrium in meters
Returns:
Dict containing:
- force: Restoring force magnitude in Newtons
- potential_energy: Elastic potential energy in Joules
Tips for LLMs:
- Stiffer spring → larger k → more force for same displacement
- Potential energy stored in spring: PE = (1/2)kx²
- Negative sign in F = -kx means force opposes displacement
Example - Compressing a car spring:
result = await calculate_hookes_law(
spring_constant=10000, # N/m (stiff car spring)
displacement=0.05 # 5cm compression
)
# Force = 500 N, PE = 12.5 J |
| calculate_spring_mass_period | Calculate period of spring-mass system: T = 2π√(m/k). Natural oscillation frequency of a mass attached to a spring.
Independent of amplitude (for ideal springs).
Args:
mass: Mass in kg
spring_constant: Spring constant k in N/m
Returns:
Dict containing:
- period: T in seconds
- frequency: f in Hz
- angular_frequency: ω in rad/s
Tips for LLMs:
- Heavier mass → longer period (slower oscillation)
- Stiffer spring → shorter period (faster oscillation)
- ω = 2πf = √(k/m)
Example - Mass on spring:
result = await calculate_spring_mass_period(
mass=0.5, # 500g mass
spring_constant=20.0 # N/m
)
# T ≈ 0.99s, f ≈ 1.01 Hz |
| calculate_simple_harmonic_motion | Calculate simple harmonic motion: x(t) = A cos(ωt + φ). Position, velocity, and acceleration for sinusoidal oscillation.
Models ideal springs, pendulums, and many other oscillating systems.
Args:
amplitude: Amplitude A in meters (maximum displacement)
angular_frequency: ω in rad/s (ω = 2πf)
time: Time t in seconds
phase: Phase shift φ in radians (default 0)
Returns:
Dict containing:
- position: x(t) in meters
- velocity: v(t) = -Aω sin(ωt + φ) in m/s
- acceleration: a(t) = -Aω² cos(ωt + φ) in m/s²
Tips for LLMs:
- Position and acceleration are 180° out of phase
- Maximum velocity occurs at equilibrium (x = 0)
- Maximum acceleration occurs at maximum displacement
Example - Oscillating mass:
result = await calculate_simple_harmonic_motion(
amplitude=0.1, # 10cm amplitude
angular_frequency=5.0, # rad/s
time=1.0 # at t = 1s
) |
| calculate_damped_oscillation | Calculate damped oscillation with friction/resistance. Real oscillators lose energy over time due to damping (air resistance,
friction). Three regimes: underdamped, critically damped, overdamped.
Args:
mass: Mass in kg
spring_constant: k in N/m
damping_coefficient: b in kg/s (damping strength)
time: Time t in seconds
initial_position: Initial position in meters (default 1.0)
initial_velocity: Initial velocity in m/s (default 0.0)
Returns:
Dict containing:
- position: x(t) in meters
- velocity: v(t) in m/s
- damping_ratio: ζ (zeta) = b/(2√(mk))
- regime: "underdamped", "critically_damped", or "overdamped"
Damping regimes:
- ζ < 1: Underdamped (oscillates, gradually decays)
- ζ = 1: Critically damped (returns fastest without oscillating)
- ζ > 1: Overdamped (slow return, no oscillation)
Example - Car suspension:
result = await calculate_damped_oscillation(
mass=300, # kg (quarter car mass)
spring_constant=20000, # N/m
damping_coefficient=2000, # kg/s
time=1.0
)
# Should be slightly underdamped for comfort |
| calculate_pendulum_period | Calculate pendulum period: T = 2π√(L/g). Period of a simple pendulum depends only on length and gravity
(for small amplitudes). Includes correction for large amplitudes.
Args:
length: Pendulum length in meters (pivot to center of mass)
gravity: Gravitational acceleration in m/s² (default 9.81)
amplitude_degrees: Amplitude in degrees (optional, for large angle correction)
Returns:
Dict containing:
- period: T in seconds
- frequency: f in Hz
- angular_frequency: ω in rad/s
- small_angle_approximation: Whether small angle formula was used
Tips for LLMs:
- Period independent of mass (Galileo's discovery)
- Period independent of amplitude (for small angles < 15°)
- Longer pendulum → longer period
- Use for: clocks, playground swings, seismometers
Example - Grandfather clock:
result = await calculate_pendulum_period(
length=0.994, # meters (for 2-second period)
gravity=9.81
)
# T = 2.0 seconds |
| calculate_torque | Calculate torque from force and position: τ = r × F (cross product). Torque is the rotational equivalent of force. It causes angular acceleration
and depends on both the force magnitude and the distance from the pivot point.
Args:
force_x: X component of force in Newtons
force_y: Y component of force in Newtons
force_z: Z component of force in Newtons
position_x: X component of position vector from pivot to force application (meters)
position_y: Y component of position vector from pivot to force application (meters)
position_z: Z component of position vector from pivot to force application (meters)
Returns:
Dict containing:
- torque: Torque vector [x, y, z] in N⋅m
- magnitude: Torque magnitude in N⋅m
Tips for LLMs:
- Torque direction follows right-hand rule (perpendicular to force and position)
- Maximum torque when force is perpendicular to position vector
- Zero torque when force is parallel to position vector
- Use for: wrenches, door hinges, motors, gears
Example - Opening a door:
result = await calculate_torque(
force_x=50.0, # Push perpendicular to door
force_y=0.0,
force_z=0.0,
position_x=0.0,
position_y=0.0,
position_z=0.8 # 0.8m from hinge
)
# Torque = 40 N⋅m |
| calculate_moment_of_inertia | Calculate moment of inertia for various shapes. Moment of inertia (I) is the rotational equivalent of mass. It determines
how difficult it is to change an object's rotation. Depends on both mass
distribution and rotation axis.
Args:
shape: Shape type - "sphere", "solid_sphere", "hollow_sphere", "rod", "disk", "cylinder", "box"
mass: Mass in kilograms
radius: Radius for sphere/disk/cylinder (meters)
length: Length for rod (meters)
width: Width for box (meters)
height: Height for box/cylinder (meters)
depth: Depth for box (meters)
axis: Rotation axis - "center", "end" (for rod), "x", "y", "z" (for box)
Returns:
Dict containing:
- moment_of_inertia: I in kg⋅m²
- shape: Shape type
- axis: Rotation axis
Common formulas:
- Solid sphere (center): I = (2/5)mr²
- Hollow sphere (center): I = (2/3)mr²
- Rod (center): I = (1/12)mL²
- Rod (end): I = (1/3)mL²
- Disk (center): I = (1/2)mr²
Example - Spinning wheel:
result = await calculate_moment_of_inertia(
shape="disk",
mass=5.0, # 5kg wheel
radius=0.3 # 30cm radius
)
# I = 0.225 kg⋅m² |
| calculate_angular_momentum | Calculate angular momentum: L = I × ω. Angular momentum is the rotational equivalent of linear momentum.
It's conserved in the absence of external torques (like ice skater spinning).
Args:
moment_of_inertia: Moment of inertia in kg⋅m²
angular_velocity_x: X component of angular velocity in rad/s
angular_velocity_y: Y component of angular velocity in rad/s
angular_velocity_z: Z component of angular velocity in rad/s
Returns:
Dict containing:
- angular_momentum: L vector [x, y, z] in kg⋅m²/s
- magnitude: L magnitude in kg⋅m²/s
Tips for LLMs:
- Angular momentum is conserved when no external torques act
- Ice skater pulls arms in → I decreases → ω increases (L constant)
- Gyroscopes resist changes in angular momentum direction
Example - Spinning figure skater:
# Arms extended: I = 3.0 kg⋅m², ω = 5 rad/s
result = await calculate_angular_momentum(
moment_of_inertia=3.0,
angular_velocity_x=0.0,
angular_velocity_y=5.0,
angular_velocity_z=0.0
)
# L = 15 kg⋅m²/s (conserved when arms pulled in) |
| calculate_rotational_kinetic_energy | Calculate rotational kinetic energy: KE_rot = (1/2) I ω². Energy of rotation. A spinning object has kinetic energy even if
its center of mass is stationary.
Args:
moment_of_inertia: Moment of inertia in kg⋅m²
angular_velocity: Angular velocity magnitude in rad/s
Returns:
Dict containing:
- rotational_ke: Rotational kinetic energy in Joules
Tips for LLMs:
- Total KE = translational KE + rotational KE
- Rolling object has both types of kinetic energy
- Flywheel energy storage uses this principle
Example - Car wheel at highway speed:
result = await calculate_rotational_kinetic_energy(
moment_of_inertia=0.5, # kg⋅m²
angular_velocity=100.0 # rad/s (fast spinning)
)
# KE_rot = 2500 J |
| calculate_angular_acceleration | Calculate angular acceleration: α = τ / I. Angular acceleration is the rotational equivalent of linear acceleration.
Determined by net torque and moment of inertia.
Args:
torque: Torque magnitude in N⋅m
moment_of_inertia: Moment of inertia in kg⋅m²
Returns:
Dict containing:
- angular_acceleration: α in rad/s²
Tips for LLMs:
- Rotational version of F = ma → τ = Iα
- Larger I means slower angular acceleration for same torque
- Use for: motor acceleration, spinning up flywheels
Example - Motor accelerating a wheel:
result = await calculate_angular_acceleration(
torque=10.0, # N⋅m
moment_of_inertia=0.5 # kg⋅m²
)
# α = 20 rad/s² |
| check_force_balance | Check if forces are in equilibrium: ΣF = 0. Verifies whether a system of forces is balanced (net force = 0).
Essential for statics problems and structural analysis.
Args:
forces: List of force vectors [[x,y,z], ...] in Newtons (or JSON string)
tolerance: Tolerance for equilibrium check (fraction, default 0.01)
Returns:
Dict containing:
- net_force: Net force vector [x, y, z] in Newtons
- net_force_magnitude: Net force magnitude in Newtons
- is_balanced: Whether forces are in equilibrium
- individual_magnitudes: Magnitude of each force
Example - Bridge support forces:
result = await check_force_balance(
forces=[[0, 1000, 0], [0, 500, 0], [0, -1500, 0]],
tolerance=0.01
)
# is_balanced = True if net force ≈ 0 |
| check_torque_balance | Check if torques are in equilibrium: Στ = 0. Verifies whether a system of torques is balanced (net torque = 0).
Essential for rotational equilibrium and lever problems.
Args:
torques: List of torque vectors [[x,y,z], ...] in N⋅m (or JSON string)
tolerance: Tolerance for equilibrium check (fraction, default 0.01)
Returns:
Dict containing:
- net_torque: Net torque vector [x, y, z] in N⋅m
- net_torque_magnitude: Net torque magnitude in N⋅m
- is_balanced: Whether torques are in equilibrium
- individual_magnitudes: Magnitude of each torque
Example - Seesaw balance:
result = await check_torque_balance(
torques=[[0, 0, 100], [0, 0, -100]],
tolerance=0.01
) |
| calculate_center_of_mass | Calculate center of mass for a system of point masses. Formula: r_cm = Σ(m_i × r_i) / Σm_i
Args:
masses: List of masses in kg (or JSON string)
positions: List of positions [[x,y,z], ...] in meters (or JSON string)
Returns:
Dict containing:
- center_of_mass: Position [x, y, z] in meters
- total_mass: Total system mass in kg
Example - Three-mass system:
result = await calculate_center_of_mass(
masses=[1.0, 2.0, 3.0],
positions=[[0,0,0], [1,0,0], [2,0,0]]
)
# center_of_mass ≈ [1.5, 0, 0] |
| calculate_static_friction | Calculate maximum static friction force: f_s,max = μ_s × N. Determines whether an object will slip under applied force.
Args:
normal_force: Normal force in Newtons
coefficient_static_friction: Coefficient of static friction μ_s
applied_force: Applied horizontal force in Newtons (optional)
Returns:
Dict containing:
- max_static_friction: Maximum static friction in Newtons
- will_slip: Whether object will slip (if applied_force provided)
- friction_force: Actual friction force (if applied_force provided)
Example - Box on floor:
result = await calculate_static_friction(
normal_force=100,
coefficient_static_friction=0.5,
applied_force=40
)
# will_slip = False (40N < 50N max) |
| calculate_normal_force | Calculate normal force on an inclined plane. On an incline at angle θ:
- N = mg cos(θ) + F_additional
- Weight component perpendicular: mg cos(θ)
- Weight component parallel: mg sin(θ)
Args:
mass: Object mass in kg
gravity: Gravitational acceleration in m/s² (default 9.81)
angle_degrees: Incline angle in degrees (0 = horizontal)
additional_force: Additional perpendicular force in Newtons (optional)
Returns:
Dict containing:
- normal_force: Normal force in Newtons
- weight_component_perpendicular: Weight component ⊥ to surface
- weight_component_parallel: Weight component ∥ to surface
Example - Box on 30° ramp:
result = await calculate_normal_force(
mass=10.0,
angle_degrees=30.0
)
# normal_force ≈ 84.9 N |
| check_equilibrium | Check complete static equilibrium: ΣF = 0 and Στ = 0. For static equilibrium, both force and torque must be balanced.
Args:
forces: List of force vectors [[x,y,z], ...] in N (or JSON string)
force_positions: Positions where forces applied [[x,y,z], ...] (or JSON string)
pivot_point: Pivot point for torque calculation [x,y,z] (default [0,0,0])
tolerance: Tolerance for equilibrium check (default 0.01)
Returns:
Dict containing:
- force_balanced: Whether ΣF = 0
- torque_balanced: Whether Στ = 0
- in_equilibrium: Whether system is in static equilibrium
- net_force: Net force [x, y, z] in N
- net_torque: Net torque [x, y, z] in N⋅m
Example - Beam with two forces:
result = await check_equilibrium(
forces=[[0, 100, 0], [0, -100, 0]],
force_positions=[[1, 0, 0], [2, 0, 0]]
) |
| calculate_beam_reactions | Calculate reaction forces for a simply supported beam. Uses moment equilibrium about supports to find reaction forces.
Args:
beam_length: Beam length in meters
loads: Point loads in Newtons (downward positive) (or JSON string)
load_positions: Positions of loads from left end in meters (or JSON string)
Returns:
Dict containing:
- reaction_left: Reaction force at left support in Newtons
- reaction_right: Reaction force at right support in Newtons
- total_load: Total downward load in Newtons
- is_balanced: Whether reactions balance loads
Example - Beam with two loads:
result = await calculate_beam_reactions(
beam_length=10.0,
loads=[1000, 500],
load_positions=[3.0, 7.0]
) |
| convert_unit | Convert a value from one unit to another.
Supports 62 unit types across 16 categories:
- Velocity: m/s, km/h, mph, ft/s, knots
- Distance: m, km, mi, ft, yd, in
- Mass: kg, g, lb, oz
- Force: N, kN, lbf
- Energy: J, kJ, cal, BTU, kWh
- Power: W, kW, hp
- Temperature: K, C, F
- Angle: rad, deg
- Pressure: Pa, kPa, bar, psi, atm
- Area: m², km², ft², acre
- Volume: m³, L, gal, ft³
- Time: s, min, hr, day
- Acceleration: m/s², g, ft/s²
- Torque: N·m, lb·ft, lb·in
- Frequency: Hz, kHz, MHz, GHz
- Data Size: B, KB, MB, GB
Enables natural language queries like:
- "Convert 60 mph to m/s"
- "How fast is 100 km/h in mph?"
- "Convert 10 kg to pounds"
Args:
value: The numeric value to convert
from_unit: Source unit (e.g., 'mph', 'kg', 'J')
to_unit: Target unit (e.g., 'm/s', 'lb', 'kWh')
Returns:
Dictionary with:
- original_value: Input value
- original_unit: Input unit
- converted_value: Result value
- converted_unit: Result unit
- formatted: Human-readable string
Examples:
>>> convert_unit(100, 'm/s', 'mph')
{
"original_value": 100,
"original_unit": "m/s",
"converted_value": 223.694,
"converted_unit": "mph",
"formatted": "100 m/s = 223.694 mph"
}
>>> convert_unit(60, 'mph', 'km/h')
{
"original_value": 60,
"original_unit": "mph",
"converted_value": 96.56064,
"converted_unit": "km/h",
"formatted": "60 mph = 96.56 km/h"
} |
| list_unit_conversions | List all supported unit conversions.
Returns a dictionary mapping category names to lists of supported units.
Returns:
Dictionary with supported unit categories:
- velocity: Speed units
- distance: Length units
- mass: Weight units
- force: Force units
- energy: Energy units
- power: Power units
- temperature: Temperature scales
- angle: Angular units
- pressure: Pressure units
- area: Area units
- volume: Volume units
Example:
>>> list_unit_conversions()
{
"velocity": ["m/s", "km/h", "mph", "ft/s", "knots"],
"distance": ["m", "km", "mi", "ft", "yd", "in"],
"mass": ["kg", "g", "lb", "oz"],
...
} |
| create_simulation | Create a new physics simulation using Rapier engine. Initializes a new rigid-body physics world with configurable gravity and
timestep. Returns a simulation ID used for all subsequent operations.
Args:
gravity_x: X component of gravity vector (m/s²). Default 0.0
gravity_y: Y component of gravity vector (m/s²). Default -9.81 (Earth down)
gravity_z: Z component of gravity vector (m/s²). Default 0.0
dimensions: 2 or 3 for 2D/3D simulation. Default 3.
dt: Simulation timestep in seconds. Default 0.016 (60 FPS).
Smaller = more accurate but slower, larger = faster but less stable
integrator: Integration method. Options: "euler", "verlet", "rk4". Default "verlet".
Returns:
SimulationCreateResponse containing:
- sim_id: Unique simulation identifier (use for all other sim calls)
- config: Echo of the configuration used
Tips for LLMs:
- Keep simulation IDs in memory for the conversation session
- Default gravity is Earth standard (9.81 m/s² down = -Y direction)
- dt=0.016 ≈ 60 FPS, dt=0.008 ≈ 120 FPS (higher accuracy)
- "verlet" integrator is good default (stable, energy-conserving)
- Remember to destroy_simulation when done to free resources
Requires:
- Rapier provider must be configured (see config.py)
- Rapier service must be running (see RAPIER_SERVICE.md)
Example:
# Create simulation with Earth gravity
sim = await create_simulation(
gravity_y=-9.81,
dt=0.016
)
# Use sim.sim_id for add_body, step_simulation, etc. |
| add_rigid_body | Add a rigid body to an existing simulation. Creates a new physics body (static, dynamic, or kinematic) with specified
shape, mass, and initial conditions. Bodies interact via collisions.
Args:
sim_id: Simulation ID from create_simulation
body_id: Unique identifier for this body (user-defined string)
body_type: "static", "dynamic", or "kinematic"
- static: Never moves (ground, walls)
- dynamic: Affected by forces and collisions
- kinematic: Moves but not affected by forces (scripted motion)
shape: Collider shape: "box", "sphere", "capsule", "cylinder", "plane"
size: Shape dimensions:
- box: [width, height, depth]
- sphere: [radius]
- capsule: [half_height, radius]
- cylinder: [half_height, radius]
- plane: not needed (use normal/offset instead)
mass: Mass in kilograms (for dynamic bodies). Default 1.0
normal: Normal vector [x, y, z] for plane shape. Default [0, 1, 0] (upward)
offset: Offset along normal for plane. Default 0.0
position: Initial position [x, y, z]. Default [0, 0, 0]
orientation: Initial orientation quaternion [x, y, z, w]. Default [0, 0, 0, 1] (identity)
velocity: Initial linear velocity [x, y, z]. Default [0, 0, 0]
angular_velocity: Initial angular velocity [x, y, z]. Default [0, 0, 0]
restitution: Bounciness (0.0 = no bounce, 1.0 = perfect bounce). Default 0.5
friction: Surface friction (0.0 = ice, 1.0 = rubber). Default 0.5
is_sensor: If true, detects collisions but doesn't respond physically. Default false
linear_damping: Linear velocity damping (0.0-1.0) - like air resistance. Default 0.0
angular_damping: Angular velocity damping (0.0-1.0) - like rotational friction. Default 0.0
drag_coefficient: Base drag coefficient (Cd) for orientation-dependent drag. Optional
drag_area: Reference cross-sectional area (m²) for drag calculation. Optional
drag_axis_ratios: Drag variation along body axes [x, y, z]. E.g., [1.0, 0.2, 1.0] for streamlined along Y. Optional
fluid_density: Fluid density (kg/m³). Air=1.225, Water=1000. Default 1.225
Returns:
body_id (echo of the input ID)
Tips for LLMs:
- Create ground FIRST: body_type="static", shape="plane", normal=[0, 1, 0]
- Box size is full width/height/depth (not half-extents)
- Sphere size is [radius] (array with one element)
- Quaternions: identity = [0, 0, 0, 1] (no rotation)
- Common restitution: steel=0.8, wood=0.5, clay=0.1
- Common friction: ice=0.05, wood=0.4, rubber=1.0
Example:
# Add a ground plane
await add_rigid_body(
sim_id=sim_id,
body_id="ground",
body_type="static",
shape="plane",
normal=[0, 1, 0]
)
# Add a bouncing ball
await add_rigid_body(
sim_id=sim_id,
body_id="ball",
body_type="dynamic",
shape="sphere",
size=[0.5], # radius = 0.5m
mass=1.0,
position=[0, 10, 0],
restitution=0.7
)
# Add a falling box
await add_rigid_body(
sim_id=sim_id,
body_id="box",
body_type="dynamic",
shape="box",
size=[1.0, 1.0, 1.0],
mass=10.0,
position=[0.0, 5.0, 0.0]
) |
| add_joint | Add a joint/constraint to connect two rigid bodies. Joints allow you to constrain the motion between bodies:
- FIXED: Rigid connection (glue objects together)
- REVOLUTE: Hinge rotation around an axis (doors, pendulums)
- SPHERICAL: Ball-and-socket rotation (ragdolls, gimbals)
- PRISMATIC: Sliding along an axis (pistons, elevators)
Args:
sim_id: Simulation identifier
joint: Joint definition with type and parameters
Returns:
joint_id: Unique identifier for the created joint
Example - Simple Pendulum:
# Create fixed anchor point
add_rigid_body(
sim_id=sim_id,
body_id="anchor",
body_type="static",
shape="sphere",
size=[0.05],
position=[0.0, 5.0, 0.0],
)
# Create pendulum bob
add_rigid_body(
sim_id=sim_id,
body_id="bob",
body_type="dynamic",
shape="sphere",
size=[0.1],
mass=1.0,
position=[0.0, 3.0, 0.0],
)
# Connect with revolute joint (hinge)
add_joint(
sim_id=sim_id,
joint=JointDefinition(
id="pendulum_joint",
joint_type="revolute",
body_a="anchor",
body_b="bob",
anchor_a=[0.0, 0.0, 0.0], # Center of anchor
anchor_b=[0.0, 0.1, 0.0], # Top of bob
axis=[0.0, 0.0, 1.0], # Rotate around Z-axis
),
) |
| step_simulation | Step the simulation forward in time. Advances the physics simulation by running the integrator for N steps.
Returns the complete state of all bodies after stepping.
Args:
sim_id: Simulation ID
steps: Number of timesteps to simulate. Default 1.
Example: steps=600 with dt=0.016 = 9.6 seconds of simulation
dt: Optional timestep override (seconds). If None, uses config default.
Returns:
SimulationStepResponse containing:
- sim_id: Simulation identifier
- time: Current simulation time in seconds
- bodies: List of all body states with positions, velocities, contacts
Tips for LLMs:
- Each body state includes position, orientation (quaternion), velocities
- contacts array shows active collisions with impulse magnitudes
- For real-time preview: steps=1, call repeatedly
- For final result: steps=1000+, call once
- Large step counts may timeout - limit to ~10,000 steps per call
Example:
# Simulate 10 seconds at 60 FPS
result = await step_simulation(
sim_id=sim_id,
steps=600 # 600 steps × 0.016s = 9.6s
)
for body in result.bodies:
print(f"{body.id}: position={body.position}") |
| record_trajectory | Record the trajectory of a specific body over time. Steps the simulation and records position/orientation/velocity at each
timestep for one body. Perfect for generating animation data for R3F.
Args:
sim_id: Simulation ID
body_id: ID of the body to track
steps: Number of timesteps to record
dt: Optional timestep override. If None, uses config default.
Returns:
TrajectoryResponse containing:
- body_id: Tracked body identifier
- frames: List of trajectory frames with time, position, orientation, velocity
- total_time: Total simulated time in seconds
- num_frames: Number of frames recorded
Tips for LLMs:
- Each frame has: time, position [x,y,z], orientation [x,y,z,w], velocity [x,y,z]
- Frames are evenly spaced in time (every dt seconds)
- Output is R3F-compatible: use position/orientation directly in Three.js
- For 60 FPS video: record at dt=1/60 ≈ 0.0167
- Typical recording: 100-1000 frames (1.6-16 seconds at 60 FPS)
Example:
# Record 5 seconds of a falling ball
traj = await record_trajectory(
sim_id=sim_id,
body_id="ball",
steps=300 # 300 × 0.016 ≈ 5 seconds
)
# Use traj.frames in React Three Fiber for animation |
| record_trajectory_with_events | Record trajectory and automatically detect collision and bounce events. This is an enhanced version of record_trajectory that analyzes the motion
and detects important events like bounces and collisions. Perfect for
answering questions like "how many times did the ball bounce?"
Args:
sim_id: Simulation ID
body_id: Body to track
steps: Number of simulation steps to record
dt: Optional custom timestep (overrides simulation default)
detect_bounces: Whether to detect bounce events (default True)
bounce_height_threshold: Maximum height to consider as "on ground" in meters (default 0.01)
Returns:
TrajectoryWithEventsResponse containing:
- frames: Trajectory frames (positions, velocities)
- bounces: Detected bounce events with energy loss
- contact_events: Contact/collision events (future)
Tips for LLMs:
- Use this instead of record_trajectory when you need event detection
- Bounces are detected from velocity reversals near the ground
- Each bounce includes: time, position, speeds before/after, energy loss
- Use `trajectory.bounces` to count or analyze bounces
- Adjust bounce_height_threshold for different ground shapes
Example:
# Record ball bouncing and count bounces
traj = await record_trajectory_with_events(
sim_id=sim_id,
body_id="ball",
steps=600,
detect_bounces=True,
bounce_height_threshold=0.01 # 1cm threshold
)
print(f"Detected {len(traj.bounces)} bounces")
for bounce in traj.bounces:
print(f"Bounce #{bounce.bounce_number} at t={bounce.time:.2f}s") |
| destroy_simulation | Destroy a simulation and free resources. Cleanup when done with a simulation. Important for long-running servers
to avoid memory leaks.
Args:
sim_id: Simulation ID to destroy
Returns:
Success message
Tips for LLMs:
- Always destroy simulations when conversation ends or changes topic
- Rapier service keeps simulations in memory until explicitly destroyed
- Good practice: destroy after recording trajectory or final state
Example:
await destroy_simulation(sim_id) |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |