# 3D Plotting

    library(orbitr)

All simulations in `orbitr` run in full 3D — every body always has `x`, `y`, and `z` coordinates. When all motion happens in the XY plane (i.e., `z = 0` and `vz = 0` for every body), `plot_orbits()` produces a static 2D `ggplot2` chart. The moment any body has non-zero Z motion, `plot_orbits()` automatically switches to an interactive 3D `plotly` visualization — no code changes needed.

You can also force 3D rendering for planar data with `three_d = TRUE`, which can be useful if you want the interactive rotation and zoom capabilities even for a flat system.

## How the 2D/3D Dispatch Works

`plot_orbits()` checks whether `any(sim_data$z != 0)`. If there’s any Z-axis movement — or if you pass `three_d = TRUE` — it hands off to `plot_orbits_3d()`, which uses `plotly` for interactive 3D rendering. Otherwise it falls back to a static `ggplot2` chart.

If `plotly` isn’t installed, the function warns you and falls back to the 2D plot even for 3D data.

## A Tilted Lunar Orbit

The Moon’s real orbit is inclined about 5° to the ecliptic. You can approximate this by giving the Moon a small `vz` component:

    create_system() |>
      add_body("Earth", mass = mass_earth) |>
      add_body("Moon",  mass = mass_moon,
               x = distance_earth_moon,
               vy = speed_moon * cos(5 * pi / 180),
               vz = speed_moon * sin(5 * pi / 180)) |>
      simulate_system(time_step = seconds_per_hour, duration = seconds_per_day * 28) |>
      plot_orbits()

Because `vz` is non-zero, `plot_orbits()` detects 3D motion and returns an interactive plotly widget. You can drag to rotate, scroll to zoom, and hover to see timestamps.

## Forcing 3D for Flat Data

Even if your system is entirely planar, you can opt into the interactive 3D viewer:

    create_system() |>
      add_body("Earth", mass = mass_earth) |>
      add_body("Moon",  mass = mass_moon, x = distance_earth_moon, vy = speed_moon) |>
      simulate_system(time_step = seconds_per_hour, duration = seconds_per_day * 28) |>
      plot_orbits(three_d = TRUE)

This gives you the same rotation and zoom controls, even though all the Z values are zero.