Understand every pitch.

Mound retrieves, analyzes and visualizes MLB pitch-level data from the command line or a few lines of Python. Start from a player’s name. No MLB IDs to look up, no undocumented APIs to learn.

$pip install mound
zsh — mound
$ mound arsenal "Roki Sasaki" --game 825051
                    pitches  velocity  spin_rate  release_extension  horizontal_break  induced_vertical_break  whiff_rate  chase_rate
pitch_type
four-seam fastball       35      98.8     2427.1                7.1              11.2                    16.9        27.3         6.2
splitter                 32      90.2      868.1                7.2               5.3                     1.0        13.6        57.9
slider                   14      87.1     2099.3                7.1               3.0                     0.1        40.0        33.3
forkball                  5      88.2      758.2                7.1               2.8                    -2.0        50.0         0.0

One start, one table. The four-seamer lives in the zone and gets missed when hitters swing at it; the splitter’s whole job is to be chased below it, and it was, 57.9% of the time.

Find answers to questions about a pitcher’s arsenal.

  • 01

    How many splitters did Roki Sasaki throw against the Diamondbacks last night?

  • 02

    How often has he thrown it relative to his other pitches over his last four starts?

  • 03

    What does its location look like over that period?

  • 04

    How does he attack one particular hitter, and does that hitter chase the splitter?

Mound answers all four with a few CLI commands or a few lines of Python, and it never asks you for an MLB player ID to get there.

A small surface, pointed at one job.

Eight commands and one Python object, sharing the same implementation underneath. Anything you can do in the shell, you can also do in a script.

mound search "Roki Sasaki"

Start from a name

Resolve a player to an MLB ID, accents optional. Every other command takes the name directly, so you rarely need the ID at all.

--last 4 --pitch splitter

Filter how you'd ask

Last N appearances, a date range, one game, one pitch type, one batter side, one at-bat, one exact pitch. Filters compose freely.

mound arsenal

Stuff and results together

Velocity, spin and movement next to whiff and chase rate, so how nasty a pitch was gets answered from three angles in one table.

mound zone --kind heatmap

Charts that arrive finished

A headline, dek and source render around the strike zone. Scatter, heatmap or KDE, optionally split into vs-LHB and vs-RHB panels.

--batter perdomo

Matchups from either side

Pitcher(batter=...) and Batter(pitcher=...) return the same pitches. Pick whichever player the question is actually about.

mound video --limit 1

Broadcast clips, by pitch

Download the video for one pitch, one at-bat or a whole filtered collection, resolved straight from each pitch's own ID.

--cache

A cache that can't go stale

A finished game never changes, so a hit is always good. A game in progress is never written, so tonight's fourth inning never sticks.

--export roki.csv

Export anywhere

CSV, JSON or Parquet from the CLI, or to_frame() for a pandas DataFrame with every field the feed returned.

Three angles on “how nasty was it?”

Roki Sasaki, game 825051
PitchNo.VeloSpinWhiffChase
four-seam fastball3598.82427.127.3%6.2%
splitter3290.2868.113.6%57.9%
slider1487.12099.340.0%33.3%
forkball588.2758.250.0%0.0%
Swing rate
Swings over every pitch thrown. How often hitters were tempted at all.
Whiff rate
Swings that missed, over swings — Baseball Savant’s own convention, not misses over every pitch. A pitch rarely swung at can still post a high number.
Chase rate
Swings over pitches outside the zone. Read from location geometry rather than the strike ruling, because those are genuinely different things.

Charts that arrive finished.

A headline, a dek and a source line render around the strike zone itself, so a plot is publishable the moment it comes out of the function. All three are generated for you and all three are overridable.

Strike zone scatter plot of Roki Sasaki's splitter locations
kind="scatter"

The default. Points colored by pitch type, using the same fixed palette across every chart.

Strike zone heatmap of Edwin Díaz's four-seam fastball locations
kind="heatmap"

Binned density for larger samples. No colorbar — darker means more pitches, and the panel stays aligned with every other kind.

Roki Sasaki's splitter locations split into versus-LHB and versus-RHB panels
split_by="stand"

Location isn't mirrored for handedness, so mixing lefties and righties in one panel blurs the picture. Split it into a pair, each with its own zone and pitch count.

Then watch the pitch that did the damage.

Every pitch carries a pitch_id that doubles as the play ID on a Baseball Savant clip page. Any pitch you can filter to is a pitch you can download.

$ mound video-id a08dfb7d-1acd-3776-a6d8-0f5e80cdb0c6 --out clips/perdomo_triple_aug8.mp4$ mound video-id 13f4b8d1-39f4-3499-b696-8a3311899fde --out clips/carroll_triple_aug8.mp4

Geraldo Perdomo Triple

Four-seam fastball, 96.5 mph, middle third of the zone and 0.06 feet off the center of the plate.

Corbin Carroll Triple

Four-seam fastball, 98.6 mph, middle third of the zone and 0.07 feet off the center of the plate.

Back-to-back triples off Edwin Díaz in the ninth at Chase Field on Aug. 8, 2026. Both were four-seam fastballs in the middle third of the zone, less than an inch off the center of the plate — the two pitches at the center of the blown-save walkthrough.

Two minutes to your first pitch.

Install it, point it at a name and start asking. The worked example goes all the way from a pitcher’s postgame quote to the video of the pitches that disproved it.

$pip install mound
$mound search "Roki Sasaki"
$mound arsenal "Roki Sasaki" --last 4

Add pip install "mound[viz]" for KDE heatmaps, or "mound[parquet]" for Parquet export.