Case Study: The Eagles — Trenches, RPOs, and the Tush Push

How Philadelphia built three Super Bowl teams around the lines of scrimmage, and what the data says about its most famous yard

Show the Python (shared drawing helpers for this chapter)
import os
import logging
import shutil

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import animation
from matplotlib.patches import Ellipse, FancyArrowPatch, Patch
from matplotlib.lines import Line2D

from gridiron import Play, Player, Field, style, draw_marker

logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR)
style.apply()
PDF = os.environ.get("RTG_FORMAT", "").lower() in ("pdf", "typst", "print")
READ_GREEN = "#0f7a55"           # darker step of the aqua highlight, for text and read lines
OD, DD = style.OFFENSE_DARK, style.DEFENSE_DARK
LINE_D, OFF_BALL, GUN, PISTOL = -0.7, -1.5, -5.0, -4.0


def opp(n):
    """Line of scrimmage (BDB x) for a ball on the opponent's n-yard line. The goal line is x = 110."""
    return 110 - n


def own(n):
    """Line of scrimmage (BDB x) for a ball on the offense's own n-yard line."""
    return 10 + n


# ---------------------------------------------------------------- players and alignments
def O(key, pos, d, w, label=None):
    return Player(key, pos, "off", d, w, label=key if label is None else label)


def D(key, pos, d, w, label):
    return Player(key, pos, "def", d, w, label=label)


def line5(split=1.6, d=LINE_D):
    """Five offensive linemen; only the center is lettered."""
    return [O(k, k, d, m * split, "C" if k == "C" else "") for k, m in
            (("LT", -2), ("LG", -1), ("C", 0), ("RG", 1), ("RT", 2))]


def dline(w=(-5.4, -0.8, 2.4, 5.4), d=1.0):
    return [D("WDE", "DE", d, w[0], "E"), D("WDT", "DT", d, w[1], "T"),
            D("SDT", "DT", d, w[2], "T"), D("SDE", "DE", d, w[3], "E")]


def move_to(p, key, *pts, kind="block", delay=0.0, speed=None):
    """Move `key` through absolute (d, w) points as a block, rush, run or path."""
    start = np.array(p._cur(key))
    rel = [tuple(np.array(q) - start) for q in pts]
    if kind == "block":
        return p.block(key, pts=rel, delay=delay, speed=speed)
    if kind == "rush":
        return p.rush(key, pts=rel, delay=delay, speed=speed)
    return {"path": p.path, "run": p.run}[kind](key, rel, delay=delay, speed=speed)


# ---------------------------------------------------------------- drawing helpers
def P(fld, p, d, w):
    return fld.xy(*p.to_abs(d, w))


def clean(ax, numbers=False):
    """Drop the painted yard numbers unless asked (they sit where receivers stand); clip all text."""
    for t in list(ax.texts):
        if not numbers and t.get_text().isdigit() and t.get_alpha() == 0.55:
            t.remove()
        else:
            t.set_clip_on(True)


def draw(p, width_in=6.0, ax=None, numbers=False, **kw):
    fld = p.draw(width_in=width_in, ax=ax, title=False, **kw)
    clean(fld.ax, numbers)
    return fld


def say(fld, p, d, w, text, color=style.INK_2, fontsize=7.0, ha="center", weight="normal", box=True):
    x, y = P(fld, p, d, w)
    fld.ax.text(float(x), float(y), text, fontsize=fontsize, color=color, ha=ha, va="center", zorder=13,
                fontweight=weight, linespacing=1.15,
                bbox=dict(boxstyle="round,pad=0.18", fc=style.SURFACE, ec="none", alpha=0.9) if box else None)


def point_to(fld, p, text_at, target, text, color=style.INK_2, fontsize=7.0, ha="center"):
    (xt, yt), (xp, yp) = P(fld, p, *text_at), P(fld, p, *target)
    fld.ax.annotate(text, (float(xp), float(yp)), xytext=(float(xt), float(yt)), fontsize=fontsize,
                    color=color, ha=ha, va="center", zorder=13, linespacing=1.15,
                    arrowprops=dict(arrowstyle="-", color=color, lw=0.7, shrinkA=2, shrinkB=7),
                    bbox=dict(boxstyle="round,pad=0.18", fc=style.SURFACE, ec="none", alpha=0.9))


def branch(fld, p, pts, color=style.DEFENSE, lw=1.5, dash=(0, (3, 2.2)), end="arrow", z=5):
    """A path through absolute (d, w) points: by default a defender's reaction (orange dashes)."""
    xs, ys = P(fld, p, np.array([q[0] for q in pts]), np.array([q[1] for q in pts]))
    fld.ax.plot(xs, ys, color=color, lw=lw, ls=dash, zorder=z, solid_capstyle="round")
    if end == "arrow":
        fld.ax.add_patch(FancyArrowPatch((xs[-2], ys[-2]), (xs[-1], ys[-1]), arrowstyle="-|>",
                                         mutation_scale=10, color=color, lw=lw, zorder=z))
    elif end == "bar":
        v = np.array([xs[-1] - xs[-2], ys[-1] - ys[-2]])
        n = np.linalg.norm(v)
        if n > 0:
            q = np.array([-v[1], v[0]]) / n * 0.7
            fld.ax.plot([xs[-1] - q[0], xs[-1] + q[0]], [ys[-1] - q[1], ys[-1] + q[1]], color=color,
                        lw=lw + 0.6, zorder=z)


def oval(fld, p, center, size, color=style.DEFENSE, label=None, alpha=0.13, fs=7.0, ls=(0, (3, 2))):
    """A shaded area (depth, width) with an optional italic label at its centre."""
    x, y = P(fld, p, *center)
    fld.ax.add_patch(Ellipse((float(x), float(y)), size[1], size[0], fc=color, alpha=alpha, ec=color, lw=0.9,
                             ls=ls, zorder=1.6))
    if label:
        fld.ax.text(float(x), float(y), label, ha="center", va="center", fontsize=fs, color=style.INK_2,
                    style="italic", zorder=3)


def panel_title(ax, text, fs=8.6):
    ax.set_title(text, fontsize=fs, loc="left", color=style.INK, fontweight="bold")


def under_note(ax, text, fs=6.9):
    ax.text(0.5, -0.02, text, transform=ax.transAxes, ha="center", va="top", fontsize=fs, color=style.INK,
            linespacing=1.2)


LEGEND = {
    "route": Line2D([], [], color=style.OFFENSE, lw=1.8, label="route"),
    "carrier": Line2D([], [], color=style.OFFENSE_DARK, lw=2.6, label="ball carrier"),
    "block": Line2D([], [], color=style.OFFENSE_DARK, lw=1.8, marker="|", ms=7, label="block"),
    "react": Line2D([], [], color=style.DEFENSE, lw=1.4, ls=(0, (3, 2.2)), label="defender's path"),
    "rush": Line2D([], [], color=style.DEFENSE, lw=1.8, label="pass rusher"),
    "drop": Line2D([], [], color=style.DEFENSE, lw=1.3, ls=(0, (3, 2)), label="zone drop"),
    "ring": Line2D([], [], marker="o", ls="", ms=11, mfc="none", mec=style.THIRD, mew=2, label="player to watch"),
    "area": Patch(fc=style.DEFENSE, alpha=0.2, ec=style.DEFENSE, label="zone a defender guards"),
    "double": Patch(fc=style.THIRD, alpha=0.25, ec=style.THIRD, label="double team"),
    "climb": Line2D([], [], color=READ_GREEN, lw=1.4, ls=(0, (3, 2.2)), label="climb to a linebacker"),
    "option": Line2D([], [], color=style.OFFENSE_DARK, lw=1.4, ls=(0, (3, 2.2)), label="the back's options"),
    "ltg": Line2D([], [], color=style.LINE_TO_GAIN, lw=2.2, label="line to gain"),
}


def field_legend(ax, keys, fs=7.0, ncol=None, y=0.0):
    hs = [LEGEND[k] for k in keys]
    ax.legend(handles=hs, loc="upper center", bbox_to_anchor=(0.5, y), ncol=ncol or min(len(hs), 4),
              fontsize=fs, frameon=False, handlelength=2.0, columnspacing=1.2, borderaxespad=0.2)


# ---------------------------------------------------------------- motion: keyframes, frame strips, video
def set_tracks(p, tracks, t_first=-2.6):
    """Hand-made keyframes {key: [(t, d, w), ...]} that may start before the snap. Every listed player
    starts at his alignment at t_first; players not listed stand still. The Philly Special is a play of
    pitches and fakes that gridiron's routes can't time, so every moving body is keyframed by hand."""
    kf, _, t1 = p._compile()
    kf = dict(kf)
    for key, rows in tracks.items():
        q = p.players[key]
        kf[key] = np.array([(t_first, q.d, q.w)] + [tuple(r_) for r_ in rows], dtype=float)
    p._compiled = (kf, t_first, max(t1, *[rows[-1][0] for rows in tracks.values()]))


def ease(points, step=0.05):
    """Smooth keyframes through (t, d, w) waypoints (ease in and out on each leg)."""
    rows = []
    for (ta, da, wa), (tb, db, wb) in zip(points[:-1], points[1:]):
        for tt in np.arange(ta, tb, step):
            f = (tt - ta) / (tb - ta)
            f = f * f * (3 - 2 * f)
            rows.append((round(float(tt), 3), da + (db - da) * f, wa + (wb - wa) * f))
    rows.append(tuple(points[-1]))
    return rows


def frame(ax, p, t, lateral, window, rings=(), ltg=True, numbers=False, mr=0.75):
    """Everyone at time t (negative = before the snap), with faint trails of where they have been
    since the snap."""
    ylo, yhi = sorted((p.ball_y - lateral[0], p.ball_y - lateral[1]))
    fld = Field(ax=ax, orient="vertical", los=p.los, window=window, numbers=numbers, lateral=(ylo, yhi),
                to_go=p.to_go if ltg else None)
    ppy = fld.pts_per_yard()
    wl, wr = sorted(lateral)
    ring = dict(rings)
    for k, q in p.players.items():
        d, w = p.position(k, t)
        if not (window[0] + 0.4 < d < window[1] - 0.4 and wl + 0.4 < w < wr - 0.4):
            continue
        if t > 0:
            pts = np.array([p.position(k, tt) for tt in np.linspace(0.0, t, 40)])
            if np.ptp(pts[:, 0]) + np.ptp(pts[:, 1]) > 0.3:
                xs, ys = P(fld, p, pts[:, 0], pts[:, 1])
                ax.plot(xs, ys, color=style.OFFENSE if q.side == "off" else style.DEFENSE, lw=1.0,
                        alpha=0.5, zorder=3)
        x, y = P(fld, p, d, w)
        draw_marker(ax, float(x), float(y), q.side, q.label, ppy, ring=ring.get(k), r=mr)
    clean(ax, numbers)
    return fld


def strip_grid(p, times, notes, lateral, window, rings=(), ncols=2, width_in=6.5, deco=None, fs=6.9, ltg=True,
               mr=0.75):
    """Print stand-in for an animation: numbered panels, each with a sentence underneath."""
    nrows = int(np.ceil(len(times) / ncols))
    pw = width_in / ncols
    ph = pw * (window[1] - window[0]) / abs(lateral[1] - lateral[0])
    fig, axes = plt.subplots(nrows, ncols, squeeze=False, figsize=(width_in, nrows * (ph + 0.8)))
    for ax in axes.flat[len(times):]:
        ax.axis("off")
    for i, (ax, t) in enumerate(zip(axes.flat, times)):
        fld = frame(ax, p, t, lateral, window, rings, ltg=ltg, mr=mr)
        if deco:
            deco(t, fld, p)
        lab = "before the snap" if t < -1e-6 else ("snap" if abs(t) < 1e-6 else f"+{t:.1f} s")
        panel_title(ax, f"{i + 1}.  {lab}")
        under_note(ax, notes[i], fs=fs)
    fig.tight_layout(h_pad=3.2, w_pad=0.8)
    return fig


def video(p, lateral, window, t_end, rings=(), width_in=5.6, t_start=-0.4, notes=None, times=None, ltg=True,
          mr=0.75, deco=None):
    """Web version of a strip: the same frame drawn every tenth of a second (pre-snap frames
    included), with the strip's notes as a running caption."""
    from IPython.display import HTML, display
    span_w, span_d = abs(lateral[1] - lateral[0]), window[1] - window[0]
    fig, ax = plt.subplots(figsize=(width_in, width_in * span_d / span_w + 0.5))
    ts = np.round(np.arange(t_start, t_end + 1e-9, 0.1), 2)

    def update(i):
        ax.clear()
        t = float(ts[i])
        fld = frame(ax, p, t, lateral, window, rings, ltg=ltg, mr=mr)
        if deco:
            deco(t, fld, p)
        txt = "before the snap" if t < -1e-6 else ("snap" if abs(t) < 1e-6 else f"+{t:.1f} s")
        if notes and times:
            cur = [n for tt, n in zip(times, notes) if tt <= t + 1e-6]
            if cur:
                txt += "   " + cur[-1].replace("\n", " ")
        ax.set_title(txt, fontsize=8, loc="left", color=style.INK)
        return []

    fig.tight_layout()
    anim = animation.FuncAnimation(fig, update, frames=len(ts), interval=100, blit=False)
    html = (anim.to_html5_video(embed_limit=40).replace("<video ", '<video style="max-width:100%;height:auto" ')
            if shutil.which("ffmpeg") else anim.to_jshtml(default_mode="once"))
    plt.close(fig)
    display(HTML(html))


def pct(x, nd=0):
    return f"{100 * x:.{nd}f}%"


def pts_(x, sign=True):
    """A difference in rates as percentage points: +14 points, −3 points, +1 point."""
    v = round(100 * x)
    s = ('+' if v > 0 else ('−' if v < 0 else '')) if sign else ''
    return f"{s}{abs(v)} point{'' if abs(v) == 1 else 's'}"


def nth(n):
    n = int(round(n))
    return f"{n}{'th' if 10 <= n % 100 <= 20 else {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th')}"
Show the Python (the numbers behind this chapter: nflverse play-by-play, FTN charting, participation, draft picks and contracts)
from gridiron.data import nfl, pbp

# ---------------------------------------------------------------- play-by-play, 2016-2025
_cols = ["game_id", "play_id", "season", "season_type", "week", "posteam", "defteam", "down", "ydstogo",
         "yardline_100", "play_type", "qb_dropback", "qb_kneel", "qb_scramble", "two_point_attempt",
         "first_down", "touchdown", "epa", "sack", "rushing_yards", "rusher_player_name",
         "fourth_down_converted"]
ALL = pbp(list(range(2016, 2026)), columns=_cols)
REG = ALL[ALL["season_type"] == "REG"]
# scrimmage plays: runs and passes with a down, no kneel-downs, no two-point tries
SCRIM = REG[REG["play_type"].isin(["run", "pass"]) & REG["down"].notna() & REG["qb_kneel"].ne(1)
            & REG["two_point_attempt"].ne(1)].copy()
SCRIM["conv"] = SCRIM["first_down"].eq(1) | SCRIM["touchdown"].eq(1)

# ---------------------------------------------------------------- the sneak, 2022-2025 (FTN is_qb_sneak)
SEAS = [2022, 2023, 2024, 2025]
_ftn = nfl().load_ftn_charting(seasons=SEAS).to_pandas()
FTN_KEYS = ["nflverse_game_id", "nflverse_play_id"]
S4 = SCRIM[SCRIM["season"].isin(SEAS)].merge(
    _ftn[FTN_KEYS + ["is_qb_sneak", "is_rpo", "n_blitzers", "n_pass_rushers"]],
    left_on=["game_id", "play_id"], right_on=FTN_KEYS, how="left")
# FTN has no tush-push flag: is_qb_sneak covers the plain sneak and the pushed version alike
S4["sneak"] = S4["is_qb_sneak"].eq(True) & S4["play_type"].eq("run")
ONE = S4[S4["ydstogo"] == 1]
SNK = ONE[ONE["sneak"]]
Z90 = 1.645


def delta_rows(df):
    """Per season: Eagles rate, rest-of-league rate, the difference and its standard error."""
    out = []
    for s in SEAS:
        d = df[df["season"] == s]
        e, r = d[d["posteam"] == "PHI"]["conv"], d[d["posteam"] != "PHI"]["conv"]
        se = np.sqrt(e.mean() * (1 - e.mean()) / len(e) + r.mean() * (1 - r.mean()) / len(r))
        out.append(dict(season=s, n=len(e), phi=e.mean(), rest=r.mean(), d=e.mean() - r.mean(), se=se))
    return pd.DataFrame(out).set_index("season")


DS = delta_rows(SNK)          # sneaks only
DA = delta_rows(ONE)          # every 1-yard-to-go snap, whatever the call (no play-choice selection)
SN_PHI = SNK[SNK["posteam"] == "PHI"]["conv"]
SN_REST = SNK[SNK["posteam"] != "PHI"]["conv"]
USE = ONE.groupby(["season", "posteam"])["sneak"].mean().unstack()      # share of 1-to-go snaps that were sneaks
USE_PHI = ONE[ONE["posteam"] == "PHI"]["sneak"].mean()
USE_MED = ONE.groupby("posteam")["sneak"].mean().median()
OTHER_RUN = ONE[(ONE["play_type"] == "run") & ~ONE["sneak"] & ONE["qb_scramble"].ne(1)]["conv"].mean()
OTHER_PASS = ONE[ONE["qb_dropback"] == 1]["conv"].mean()
# what the edge was worth: extra conversions on ALL of the Eagles' 1-yard snaps, against the league's rate
XCONV = DA["d"] * DA["n"]
assert DS.loc[2023, "d"] > 0.08 and DS.loc[2025, "d"] < -0.05, "the sneak delta changed shape: re-read the text"
assert XCONV.loc[2023] > 7 and XCONV.loc[[2024, 2025]].abs().max() < 2, "the extra-conversion count changed: re-read"

# ---------------------------------------------------------------- RPOs (FTN is_rpo), 2022-2025
_rp = S4[S4["is_rpo"].notna()]
RPO = _rp.groupby(["season", "posteam"])["is_rpo"].mean().unstack()
RPO_RANK = RPO.rank(axis=1, ascending=False, method="min")["PHI"]
RPO22, RPO22_LG = RPO.loc[2022], _rp[_rp["season"] == 2022]["is_rpo"].mean()

# ---------------------------------------------------------------- the offense by season, 2021-2025
RUNS = SCRIM[(SCRIM["play_type"] == "run") & SCRIM["qb_scramble"].ne(1)]
DROP = SCRIM[SCRIM["qb_dropback"] == 1]
OC = {2021: "Steichen", 2022: "Steichen", 2023: "B. Johnson", 2024: "Moore", 2025: "Patullo"}
EPA = pd.DataFrame({
    "run": [RUNS[(RUNS["season"] == s) & (RUNS["posteam"] == "PHI")]["epa"].mean()
            - RUNS[RUNS["season"] == s]["epa"].mean() for s in OC],
    "drop": [DROP[(DROP["season"] == s) & (DROP["posteam"] == "PHI")]["epa"].mean()
             - DROP[DROP["season"] == s]["epa"].mean() for s in OC]}, index=list(OC))
# the same run line with every quarterback sneak removed (FTN flags exist from 2022 only)
_r4 = S4[(S4["play_type"] == "run") & S4["qb_scramble"].ne(1) & ~S4["sneak"]]
EPA["run_ns"] = [(_r4[(_r4["season"] == s) & (_r4["posteam"] == "PHI")]["epa"].mean()
                  - _r4[_r4["season"] == s]["epa"].mean()) if s in SEAS else np.nan for s in OC]
assert EPA.loc[[2022, 2024], "run_ns"].min() > 0.05, "runs without sneaks changed: re-read the Fig 3 text"
OFF_RANK = {s: SCRIM[SCRIM["season"] == s].groupby("posteam")["epa"].mean().rank(ascending=False)["PHI"] for s in OC}
DEF_RANK = {s: SCRIM[SCRIM["season"] == s].groupby("defteam")["epa"].mean().rank()["PHI"] for s in range(2016, 2026)}

_21 = SCRIM[(SCRIM["season"] == 2021) & (SCRIM["posteam"] == "PHI")]
RUN21_EARLY = (_21[_21["week"] <= 7]["play_type"] == "run").mean()
RUN21_LATE = (_21[_21["week"] >= 8]["play_type"] == "run").mean()
_ry = REG.groupby(["season", "posteam"])["rushing_yards"].sum().unstack() / 17
RUSH_YPG = {s: _ry.loc[s, "PHI"] for s in (2021, 2024, 2025)}
RUSH_RANK = {s: _ry.loc[s].rank(ascending=False)["PHI"] for s in (2021, 2024, 2025)}

_24 = SCRIM[SCRIM["season"] == 2024]
RUNSHARE24 = _24.groupby("posteam")["play_type"].apply(lambda x: (x == "run").mean())
BARKLEY_REG = REG[(REG["season"] == 2024) & (REG["rusher_player_name"] == "S.Barkley")]["rushing_yards"].sum()
BARKLEY_POST = ALL[(ALL["season"] == 2024) & (ALL["season_type"] == "POST")
                   & (ALL["rusher_player_name"] == "S.Barkley")]["rushing_yards"].sum()

_f17 = SCRIM[(SCRIM["season"] == 2017) & (SCRIM["down"] == 4)]
GO17 = _f17.groupby("posteam").size()
GO17_CONV = _f17[_f17["posteam"] == "PHI"]["fourth_down_converted"].mean()
_sk = REG[(REG["sack"] == 1) & (REG["season"] == 2022)].groupby("defteam").size()
SACKS22 = int(_sk["PHI"])
BARKLEY_25 = REG[(REG["season"] == 2025) & (REG["rusher_player_name"] == "S.Barkley")]["rushing_yards"].sum()
assert BARKLEY_REG == 2005 and SACKS22 == 70

# 2025 record and playoff result
_sch = nfl().load_schedules(seasons=[2025]).to_pandas()
_g = _sch[(_sch["home_team"] == "PHI") | (_sch["away_team"] == "PHI")].copy()
_g["pf"] = np.where(_g["home_team"] == "PHI", _g["home_score"], _g["away_score"])
_g["pa"] = np.where(_g["home_team"] == "PHI", _g["away_score"], _g["home_score"])
_gr = _g[_g["game_type"] == "REG"]
REC25 = f"{int((_gr['pf'] > _gr['pa']).sum())}–{int((_gr['pf'] < _gr['pa']).sum())}"
_wc = _g[_g["game_type"] == "WC"].iloc[0]
WC25 = dict(opp=_wc["away_team"] if _wc["home_team"] == "PHI" else _wc["home_team"], pf=int(_wc["pf"]), pa=int(_wc["pa"]))
assert REC25 == "11–6" and WC25 == dict(opp="SF", pf=19, pa=23)

_pp = nfl().load_participation(seasons=[2024, 2025]).to_pandas()[["nflverse_game_id", "play_id", "defenders_in_box"]]
_bx = SCRIM[SCRIM["season"].isin([2024, 2025]) & SCRIM["down"].isin([1, 2])].merge(
    _pp, left_on=["game_id", "play_id"], right_on=["nflverse_game_id", "play_id"], how="inner")
_bx["heavy"] = _bx["defenders_in_box"] >= 7
BOX7 = _bx[_bx["posteam"] == "PHI"].groupby("season")["heavy"].mean()
BOX7_RANK = _bx[_bx["season"] == 2025].groupby("posteam")["heavy"].mean().rank(ascending=False, method="min")["PHI"]

# ---------------------------------------------------------------- Super Bowl LIX and the 2024 pass rush
_p24 = nfl().load_participation(seasons=[2024]).to_pandas()[
    ["nflverse_game_id", "play_id", "was_pressure", "defense_coverage_type"]]
_ftn24 = nfl().load_ftn_charting(seasons=[2024]).to_pandas()[FTN_KEYS + ["n_blitzers", "n_pass_rushers"]]
_lix = pbp([2024], columns=["game_id", "play_id", "posteam", "qb_dropback", "two_point_attempt", "sack", "season_type",
                            "down", "defteam"])
_lix = (_lix.merge(_ftn24, left_on=["game_id", "play_id"], right_on=FTN_KEYS, how="left")
        .merge(_p24, left_on=["game_id", "play_id"], right_on=["nflverse_game_id", "play_id"], how="left",
               suffixes=("", "_p")))
SB = _lix[(_lix["game_id"] == "2024_22_KC_PHI") & (_lix["posteam"] == "KC") & (_lix["qb_dropback"] == 1)]
SB_SCR = SB[SB["two_point_attempt"].ne(1)]
LIX = dict(db=len(SB_SCR), all=len(SB), blitz=int((SB_SCR["n_blitzers"] > 0).sum()),
           four=int((SB["n_pass_rushers"] == 4).sum()), le4=int((SB["n_pass_rushers"] <= 4).sum()),
           c4=int((SB["defense_coverage_type"] == "COVER_4").sum()),
           two=int(SB["defense_coverage_type"].isin(["COVER_2", "2_MAN", "COVER_4", "COVER_6"]).sum()),
           press=int(SB["was_pressure"].eq(True).sum()), sacks=int(SB["sack"].sum()),
           max_scr=int(SB_SCR["n_pass_rushers"].max()),
           sim_rush=int(SB_SCR[SB_SCR["n_blitzers"] > 0]["n_pass_rushers"].max()))
_d24 = _lix[(_lix["season_type"] == "REG") & (_lix["qb_dropback"] == 1) & _lix["down"].notna()
            & _lix["n_pass_rushers"].notna()].copy()
# a blitz is five or more pass rushers (the glossary's definition and Next Gen Stats')
_d24["bl"] = _d24["n_pass_rushers"] >= 5
BLITZ24 = _d24.groupby("defteam")["bl"].mean()
BLITZ24_LG = _d24["bl"].mean()
_d22 = S4[(S4["season"] == 2022) & (S4["qb_dropback"] == 1) & S4["n_pass_rushers"].notna()].copy()
_d22["bl"] = _d22["n_pass_rushers"] >= 5
BLITZ22, BLITZ22_LG = _d22.groupby("defteam")["bl"].mean(), _d22["bl"].mean()
assert LIX["max_scr"] == 4 and BLITZ24.rank(ascending=False, method="min")["PHI"] >= 25
_cv = _d24[_d24["defense_coverage_type"].notna() & ~_d24["defense_coverage_type"].isin(["BLOWN", "COMBO"])]
TWOHIGH24_PHI = _cv[_cv["defteam"] == "PHI"]["defense_coverage_type"].isin(
    ["COVER_2", "2_MAN", "COVER_4", "COVER_6"]).mean()
assert LIX["blitz"] <= 1 and LIX["sacks"] == 6

# ---------------------------------------------------------------- roster building: draft capital and cap share
_dp = nfl().load_draft_picks().to_pandas()
_dp = _dp[_dp["season"].between(2013, 2025) & (_dp["round"] <= 2)].copy()
_dp["line"] = _dp["position"].isin(["T", "G", "C", "OL", "OT", "OG", "DE", "DT", "DL", "NT"])
DRAFT = _dp.groupby("team")["line"].agg(n="size", k="sum", share="mean")
DRAFT_RANK = DRAFT["share"].rank(ascending=False, method="min")["PHI"]

_c = nfl().load_contracts().to_pandas()
_rows, _seen = [], set()
for _, row in _c.iterrows():          # one row per player-season-team from each contract's season history
    for s in (row["season_history"] if row["season_history"] is not None else []):
        key = (row["otc_id"], s.get("year"), s.get("team"))
        if key in _seen or s.get("year") in (None, ""):
            continue
        _seen.add(key)
        _rows.append(dict(pos=row["position"], year=s.get("year"), team=s.get("team"), cap=s.get("cap_percent")))
CAP = pd.DataFrame(_rows)
CAP["year"] = pd.to_numeric(CAP["year"], errors="coerce")
CAP = CAP[CAP["year"].between(2017, 2025) & CAP["pos"].isin(["LT", "LG", "C", "RG", "RT"])]
_ol = CAP.groupby(["year", "team"])["cap"].sum().unstack()
OL_RANKS = _ol.rank(axis=1, ascending=False)["Eagles"]
OL_PHI_MEAN, OL_MED_MEAN = _ol["Eagles"].mean(), _ol.median(axis=1).mean()

Third-and-1 at midfield, and everybody in the stadium knows what is coming. The Philadelphia quarterback crouches under center. Two teammates line up so close behind him that they could rest their hands on his hips. The defense crowds the middle, linebackers rocking on their toes, ready to leap the pile. The broadcast cuts to a graphic about how often this works, the snap comes, the whole mass lurches forward, and the chains move. Seven years earlier the same franchise won its first Super Bowl with the most famous trick play of the century, a play built entirely on the defense not knowing what was coming. How does one team become famous for both? And is its signature yard really the edge everyone thinks it is? This chapter is about a franchise that answered the hardest question in roster building (“what do you build around when the quarterback, the coordinator and the scheme keep changing?”) with an unfashionable answer: the two lines of scrimmage.

You’ll be able to:

NoteYou’ll need
  • The Modern Era: the league since about 2017, when defenses answered spread passing by playing two deep safeties and offenses answered back with heavier personnel, more runs and more snaps from under center. The Eagles’ run game and Fangio’s defense are both chapters of that story.
  • Red Zone, Goal Line, Two-Point Plays, and Short Yardage: how the tush push works (a quarterback sneak with two or three teammates shoving him from behind), the mid-2000s rule change that made it legal, the 2025 ban vote, and the league-wide sneak numbers. This chapter builds on all of it and doesn’t redraw the play.
  • Helpful too: the chapter on RPOs (a run with a built-in throw, decided by one defender after the snap), the chapters on Zone Running and Gap Schemes (outside zone and duo), and the eligibility rules from the Formation Rules chapter (seven players on the line, and who may catch a forward pass).

Where the numbers come from. Three names recur. Pro Football Focus (PFF) and FTN are football-data companies whose staff watch video of every NFL play and chart it: tag what happened (how many rushed, whether it was an RPO, whether it was a quarterback sneak). FTN’s charting is free through nflverse, the open data project this book uses, so most of this chapter’s own calculations come from it. Next Gen Stats (NGS) is the NFL’s own player-tracking system, chips in the shoulder pads that record where everyone is ten times a second. Two charters watching the same play sometimes count it differently, so when they disagree the chapter says which one it is quoting.

How to read the diagrams. Offense is blue circles, defense orange squares, and left and right always mean the offense’s. On offense, Q is the quarterback, R the running back, X and Z wide receivers, H a slot receiver, Y and U tight ends, and C the center; the other linemen are unlettered. On defense, E and T are the ends and tackles of the defensive line, M and W linebackers, $ the nickel back (the fifth defensive back), CB a cornerback, and SS and FS the safeties. Solid blue arrows are routes, the thick dark arrow is the ball carrier, lines ending in a short bar are blocks, dashed blue lines are movement before the snap (or, where a legend says so, a runner’s options), solid orange arrows are pass rushers, dashed orange lines are a defender’s path, shaded ovals are zones, and brown dashes are the ball in the air. The yellow line is the line to gain.

The problem: a franchise built to outlast its quarterbacks

Every NFL team says it builds around its quarterback. The Eagles of the last decade had a harder problem: their quarterback situation kept changing under them. In 2017 the starter, Carson Wentz, tore his ACL in December, and the Super Bowl was won by his backup. In 2020 the team drafted Jalen Hurts in the second round, a pick many questioned barely a year after Wentz had signed a long extension, and within a year he was the starter in an offense rebuilt to suit him. Around the quarterback, the play-callers changed too: Nick Sirianni is in his sixth season as head coach (2021–2026), and he has had five offensive coordinators in those six seasons: Shane Steichen for the first two, then a new one every year.

What did not change, for more than a decade, was the line of scrimmage. Look at who stayed:1

Constant Role Years with the Eagles
Howie Roseman General manager (the man who builds the roster) 2010–2014 and 2016–present (Chip Kelly controlled the roster in 2015)
Jeff Stoutland Offensive line coach 2013–2025
Lane Johnson Right tackle (4th overall pick, 2013) 2013–present (2026 is his 14th season)
Jason Kelce Center (6th-round pick, 2011) 2011–2023

That table is the thesis of this chapter. The Eagles treated their two lines as the part of the team that lasts, and everything else (the quarterback, the play-caller, the scheme of the season) as the part that changes. It is not the fashionable approach. Modern team building chases the highest-impact positions: the quarterback first, then the players who rush the passer and those who catch or cover passes. Offensive linemen and run-stuffing tackles are often treated as the places to save money. Philadelphia’s bet was that an elite line makes every quarterback better, survives every coordinator, and turns ordinary plays (a sneak, an inside run, a four-man rush) into extraordinary ones.

The rest of the chapter tests that bet across three Super Bowl teams: 2017, 2022 and 2024.

2017: RPOs, a backup quarterback, and an aggressive coach

Doug Pederson came to Philadelphia in 2016 from Andy Reid’s staff in Kansas City, and he brought Reid’s offense with him, including its fondness for the RPO (run-pass option), a run play with a quick throw attached that the quarterback chooses between after the snap by watching one defender. By PFF’s count, the 2017 Eagles ranked second in the league in RPO usage, behind only Reid’s Chiefs.2 The RPOs chapter tells the mechanics and that season’s story in full; here is what matters for this case study.

The RPO as a quarterback simplifier. Wentz was playing at an MVP level when he tore his ACL against the Rams on December 10, 2017. His backup, Nick Foles, was a pocket passer with a fine arm and none of Wentz’s improvising. The coaches leaned harder on RPOs, because an RPO hands the quarterback his answer: if the defender he is reading plays the run, throw; if he drops into coverage, hand off. A quarterback who reads one man and throws on time does not need to be a star. By PFF’s charting, Foles completed 15 of his 16 RPO throws in his first five starts after the injury,3 and in the playoffs the Eagles scored 38 points against the league’s best defense in the NFC Championship and 41 in the Super Bowl.

An offensive line that made the run real. An RPO only works if the run part is a real threat. If the defense can stop the handoff with the players it already has in the box, it never has to choose. The 2017 line (Jason Peters at left tackle until he tore his ACL and MCL on October 23, then Halapoulivaati Vaitai;4 Stefen Wisniewski, Kelce, Brandon Brooks and Lane Johnson inside and at right tackle) was one of the best in football, and Jay Ajayi, LeGarrette Blount and Corey Clement ran behind it.

Aggression on fourth down. Pederson was also one of the first NFL coaches to act on what analysts had been saying for years: that teams punt and kick far too often on fourth-and-short. An analyst on his staff, Ryan Paganetti, sat on the headset during games feeding him the math on fourth downs.5 In 2017 the Eagles went for it on fourth down 26 times, the 2nd-most in the league, and converted 65%.6 That habit produced the two most important snaps of their Super Bowl: a fourth-and-1 conversion in their own territory late in the fourth quarter (the Film room box at the end of this section), and the most famous trick play of the century.

The Philly Special

Super Bowl LII, February 4, 2018, in Minneapolis. The Eagles led New England 15–12 with 38 seconds left in the first half and faced fourth-and-goal from the 1. Almost every coach of that era would have kicked the field goal. During a timeout, Foles walked over to Pederson and asked, in words a sideline microphone caught, “You want Philly Philly?” Pederson paused, then said, “Yeah, let’s do it.”7

The play they called is the Philly Special, a direct snap to the running back, a reverse to a tight end, and a pass from the tight end back to the quarterback. Take it a step at a time, because each step has a reason; the four panels of Figure 64.1, after the steps, show them from the shotgun alignment to the catch.

  1. Foles walks up, and stays eligible. Only a few players may catch a forward pass: the two players on the ends of the line, and the backs, the players lined up at least a yard behind it. A quarterback under center, with his hands under the center’s to take the snap, is the one back who is not eligible. A quarterback in the shotgun is just a back. Foles started in the shotgun, so he was eligible from the start, and the walk didn’t change that: he stood behind his right tackle, more than a yard off the line, and never put his hands under the center. The walk was for deception. The gesturing, the shouted words and the walk itself told the defense he was changing the protection, the most ordinary thing a quarterback does before a snap. A walk like that is a shift, so the rules then require every offensive player to stand still for a full second before the snap, and Foles did. At the snap he did nothing for a beat, which is the hardest part of selling it.
  2. The direct snap goes to the running back. Kelce snapped the ball straight to Clement, who had motioned in behind Foles before the walk. To eleven defenders, a running back with the ball on the 1-yard line means a run, and every one of them has a run responsibility. The linebackers and the defenders on Clement’s side chased him.
  3. The reverse brings the ball back. Clement pitched to Burton, a tight end coming the other way. A reverse is a misdirection play by itself; here it moved the ball away from the defenders who had just committed to Clement. The pitch has to go sideways or backward. A team gets only one forward pass on a play, and only from behind the line; a forward toss here would have used it up, and Burton could not have thrown.
  4. The throw. Burton had played quarterback in high school and taken snaps at quarterback at Florida. He rolled right and lobbed the ball to Foles, who had walked into the end zone after every defender near him had turned toward the run and nobody had stayed with him. (The right end in panel 3 ran past Foles: his job was the ball, and the ball was in the backfield.) Torrey Smith, crossing the end zone, was a second option Burton didn’t need.
Show the Python
T0 = -4.4        # the clip starts with everyone set in the shotgun formation


def philly_special():
    """Every body keyframed by hand: (t, d, w) waypoints, t in seconds from the snap."""
    off = line5() + [O("QB", "QB", -4.2, 0.0, "Q"), O("RB", "RB", -4.3, 1.9, "R"),
                     O("Z", "WR", LINE_D, -7.4, "Z"), O("Y", "TE", -2.6, -7.4, "Y"),
                     O("U", "TE", -1.6, -5.4, "U"), O("X", "WR", LINE_D, 12.0, "X")]
    dfn = [D("LE", "DE", 0.8, -4.4, "E"), D("LT_", "DT", 0.8, -0.9, "T"), D("RT_", "DT", 0.8, 0.9, "T"),
           D("RE", "DE", 0.8, 4.4, "E"), D("MIKE", "LB", 2.3, -1.4, "M"), D("WILL", "LB", 2.2, 3.3, "W"),
           D("LCB", "CB", 1.8, -9.0, "CB"), D("NB", "NB", 2.8, -6.4, "$"), D("SS", "SS", 4.2, -3.4, "SS"),
           D("RCB", "CB", 1.6, 12.0, "CB"), D("FS", "FS", 6.4, 1.2, "FS")]
    p = Play(off, dfn, los=opp(1), to_go=1)
    T = {
        # Foles: shotgun, then (after Clement's motion) walks up behind the right tackle and is set from -1.6,
        # more than the full second the rules require after a shift; at the snap he waits, then drifts right
        "QB": [(-3.0, -4.2, 0.0), (-1.6, -1.9, 3.9), (0.7, -1.9, 3.9), (1.2, -1.0, 5.3), (1.9, 1.4, 5.7),
               (2.5, 2.7, 5.9)],
        # Clement: motions from beside Foles to directly behind him, then takes the direct snap and runs left
        "RB": [(-4.0, -4.3, 1.9), (-3.2, -6.0, 0.0), (0.0, -6.0, 0.0), (0.35, -5.9, -0.5), (0.7, -6.0, -2.0),
               (1.0, -6.0, -3.4), (1.6, -5.6, -6.4), (2.2, -5.2, -7.6)],
        # Burton: drops back from behind Smith and comes across DEEPER than Clement, so the pitch goes backward
        "Y": [(0.0, -2.6, -7.4), (0.5, -4.6, -6.6), (1.0, -7.4, -4.2), (1.3, -7.5, -1.6), (1.7, -7.0, 1.2),
              (2.0, -6.3, 3.2), (2.6, -5.9, 4.0)],
        # Smith: across the end zone as the second option; Ertz seals the left end; Jeffery takes his corner deep
        "Z": [(0.0, LINE_D, -7.4), (0.6, 1.6, -6.6), (1.3, 4.4, -3.0), (2.0, 5.6, 0.0), (2.6, 5.9, 1.4)],
        "U": [(0.0, -1.6, -5.4), (0.5, -0.5, -5.3)],
        "X": [(0.0, LINE_D, 12.0), (0.8, 3.4, 11.6), (1.6, 7.4, 9.8), (2.6, 8.6, 8.4)],
        "LT": [(0.0, LINE_D, -3.2), (0.4, -0.5, -3.2)], "LG": [(0.0, LINE_D, -1.6), (0.4, -0.5, -1.6)],
        "C": [(0.0, LINE_D, 0.0), (0.4, -0.5, 0.0)], "RG": [(0.0, LINE_D, 1.6), (0.4, -0.5, 1.6)],
        "RT": [(0.0, LINE_D, 3.2), (0.4, -0.5, 3.2)],
        # the defense: everyone near the ball flows left with the run; the right end rushes upfield past
        # Foles toward the ball; the backside players lose Foles
        "LE": [(0.0, 0.8, -4.4), (0.5, 0.9, -4.9)],
        "LT_": [(0.0, 0.8, -0.9), (0.4, 0.75, -0.9)], "RT_": [(0.0, 0.8, 0.9), (0.4, 0.75, 0.9)],
        "RE": [(0.0, 0.8, 4.4), (0.6, 0.0, 5.6), (1.1, -2.6, 7.6), (2.0, -4.6, 6.8), (2.6, -5.0, 5.8)],
        "MIKE": [(0.0, 2.3, -1.4), (0.8, 2.0, -3.4), (1.3, 1.9, -3.6), (2.0, 1.8, -2.0), (2.6, 2.2, -0.2)],
        "WILL": [(0.0, 2.2, 3.3), (0.7, 1.9, 1.8), (1.4, 2.1, 1.0), (2.0, 2.0, 1.3), (2.6, 2.0, 1.6)],
        "LCB": [(0.0, 1.8, -9.0), (0.6, 3.4, -8.4), (1.3, 3.0, -4.4), (2.0, 4.2, -1.4), (2.6, 4.6, -0.2)],
        "NB": [(0.0, 2.8, -6.4), (0.7, 1.2, -8.4), (1.2, 0.4, -8.2), (1.9, 1.4, -6.6), (2.6, 2.3, -5.2)],
        "SS": [(0.0, 4.2, -3.4), (0.7, 4.6, -5.2), (1.3, 4.6, -5.6), (1.9, 3.8, -3.6), (2.6, 3.4, -2.0)],
        "RCB": [(0.0, 1.6, 12.0), (0.8, 3.6, 13.2), (1.6, 7.4, 11.4), (2.6, 8.8, 10.0)],
        "FS": [(0.0, 6.4, 1.2), (0.8, 6.2, 0.0), (1.6, 6.2, 1.0), (2.6, 5.8, 3.0)],
    }
    set_tracks(p, {k: ease([(T0, p.players[k].d, p.players[k].w)] + v) for k, v in T.items()}, t_first=T0)
    return p


BALL_OFF = np.array([-0.55, 0.95])    # the ball is drawn beside the carrier, never on his letter
T_PITCH, T_CATCH_PITCH, T_THROW, T_CATCH = 1.0, 1.15, 2.0, 2.55


def ps_ball_at(p, t):
    """Where the ball is: on the ground at the snap, then to Clement, Burton and Foles in turn."""
    if t <= 0.0:
        return np.array([0.0, 0.0])
    if t < 0.35:
        return (p.position("RB", 0.35) + BALL_OFF) * t / 0.35
    if t < T_PITCH:
        return p.position("RB", t) + BALL_OFF
    if t < T_CATCH_PITCH:
        a, b = p.position("RB", T_PITCH) + BALL_OFF, p.position("Y", T_CATCH_PITCH) + BALL_OFF
        return a + (b - a) * (t - T_PITCH) / (T_CATCH_PITCH - T_PITCH)
    if t < T_THROW:
        return p.position("Y", t) + BALL_OFF
    if t < T_CATCH:
        a, b = p.position("Y", T_THROW) + BALL_OFF, p.position("QB", T_CATCH) + BALL_OFF
        return a + (b - a) * (t - T_THROW) / (T_CATCH - T_THROW)
    return p.position("QB", t) + BALL_OFF


def ghost(fld, p, d, w, letter):
    """A dashed outline where a player started before the snap."""
    x, y = P(fld, p, d, w)
    r = 0.62
    fld.ax.add_patch(Ellipse((float(x), float(y)), 2 * r, 2 * r, fc="none", ec=style.OFFENSE, lw=1.0,
                             ls=(0, (2, 1.5)), zorder=3))
    fld.ax.text(float(x), float(y), letter, ha="center", va="center", fontsize=6.0, color=style.OFFENSE,
                fontweight="bold", zorder=3)


def ps_deco(t, fld, p):
    """End-zone label; before the snap the shotgun spots and the dashed pre-snap moves; after it, the
    ball, the backward pitch and the throw (brown dashes)."""
    say(fld, p, 10.2, -4.5, "END ZONE", color=style.INK_2, fontsize=6.4, box=False)
    if t <= 0.0:
        for k, a, b in (("RB", -4.0, -3.2), ("QB", -3.0, -1.6)):
            q = p.players[k]
            ghost(fld, p, q.d, q.w, q.label)
            if t > a:
                pts = np.array([p.position(k, tt) for tt in np.linspace(a, min(t, b), 20)])
                xs, ys = P(fld, p, pts[:, 0], pts[:, 1])
                fld.ax.plot(xs, ys, color=style.OFFENSE, lw=1.3, ls=(0, (3, 2)), zorder=4)
        return                       # before the snap the ball is under the center's hand
    if T_PITCH < t < 1.8:
        a, b = p.position("RB", T_PITCH) + BALL_OFF, p.position("Y", T_CATCH_PITCH) + BALL_OFF
        branch(fld, p, [tuple(a), tuple(b)], color=style.BALL, lw=1.4, dash=(0, (2, 1.5)), z=9)
        if True:
            point_to(fld, p, (-8.9, -6.6), tuple((a + b) / 2), "pitch goes backward,\nso Burton may throw",
                     color=style.INK_2, fontsize=6.2)
    if t > T_THROW:
        a = p.position("Y", T_THROW) + BALL_OFF
        ts = np.linspace(T_THROW, min(t, T_CATCH), 12)
        b = np.array([ps_ball_at(p, tt) for tt in ts])
        xs, ys = P(fld, p, np.r_[a[0], b[:, 0]], np.r_[a[1], b[:, 1]])
        fld.ax.plot(xs, ys, color=style.BALL, lw=1.4, ls=(0, (2, 1.5)), zorder=9)
    bd, bw = ps_ball_at(p, t)
    x, y = P(fld, p, bd, bw)
    fld.ax.add_patch(Ellipse((float(x), float(y)), 0.95, 0.6, fc=style.BALL, ec="white", lw=0.6, zorder=12))


PS = philly_special()
PS_T = [-1.0, 0.6, 1.45, 2.6]
PS_N = ["Foles has walked up from the shotgun\nand is set behind the right tackle.",
        "Direct snap to Clement, who runs\nleft. The defense flows with him.",
        "Clement pitches back to Burton. The\nend (E) rushes past Foles to the ball.",
        "Burton throws to Foles, alone in\nthe end zone. Touchdown."]
PS_LAT, PS_WIN = (-12.5, 15.5), (-11.0, 12.0)
PS_LEG = [Line2D([], [], color=style.OFFENSE, lw=1.3, ls=(0, (3, 2)), label="move before the snap"),
          Line2D([], [], marker="o", ls="", ms=8, mfc="none", mec=style.OFFENSE, label="where he started"),
          Line2D([], [], color=style.OFFENSE, lw=1.0, alpha=0.5, label="path since the snap"),
          Line2D([], [], marker="o", ls="", ms=6, mfc=style.BALL, mec="white", label="the ball"),
          Line2D([], [], color=style.BALL, lw=1.4, ls=(0, (2, 1.5)), label="pitch or pass"),
          LEGEND["ring"]]
if PDF:
    fig = strip_grid(PS, PS_T, PS_N, PS_LAT, PS_WIN, rings=(("QB", style.THIRD),), deco=ps_deco, ltg=False,
                     mr=0.62)
    fig.legend(handles=PS_LEG, loc="upper center", bbox_to_anchor=(0.5, 0.0), ncol=3, fontsize=7,
               frameon=False, handlelength=2.0, columnspacing=1.4)
    plt.show()
else:
    video(PS, PS_LAT, PS_WIN, 2.9, rings=(("QB", style.THIRD),), t_start=T0, deco=ps_deco, ltg=False, mr=0.62,
          notes=["Shotgun. Clement motions from beside Foles to behind him.",
                 "Foles walks up behind the right tackle, as if changing the play, and sets."] + PS_N[1:],
          times=[T0, -3.0, 0.6, 1.05, 2.0])
Figure 64.1: The Philly Special, Super Bowl LII, fourth-and-goal from the 1 (simulated, BDB-format tracking generated by gridiron, not recorded; alignments follow film breakdowns of the play, with defenders’ exact spots approximate). The shaded band at the top is the end zone; its bottom edge is the goal line, one yard ahead of the ball. Foles (Q, ringed) began in the shotgun with Corey Clement (R) beside him; Torrey Smith (Z) and Trey Burton (Y) are stacked on the left with Zach Ertz (U), and Alshon Jeffery (X) is alone on the right. Panel 1 shows the two moves before the snap as dashed blue lines from where each player started (dashed circles). The numbered steps in the text explain each panel.

Why does it work? Because the defense’s rules, not its effort, let it down. At the goal line every defender has a gap to fill or a receiver to cover, and nobody has “the quarterback,” because the quarterback is the one player a defense never has to cover. The play turns that rule into a hole. It also lands at the perfect moment: fourth-and-goal from the 1 is when a defense is most committed to stopping the run, and least able to think about anything else.

What it gives up is just as clear. A trick play is a one-time bet. If a single defender stays home on the quarterback, Burton is rolling right with the ball and nowhere to throw it, on fourth down. And it can only fool a defense that hasn’t seen it, so its value falls every time it’s run.

It wasn’t new, either. The Eagles found it on film of the Chicago Bears, who had run a version of it for a touchdown against Minnesota late in the 2016 season and called it the “Clemson Special,” after a college team that had used it years before. Wide receivers coach Mike Groh, who had coached in Chicago, helped install it, and the Eagles had considered running it in the NFC Championship Game before the score made it unnecessary.8 Even the alignment was argued about afterward: the former officiating chief Mike Pereira said Alshon Jeffery, alone on the right, was a step off the line. The offense must have at least seven players on the line of scrimmage, so with Jeffery off it there would have been only six: an illegal formation. Jeffery had checked with the official before the snap, and no flag was thrown.9

CautionCommon misconception

“The Philly Special was a gamble a coach dreamed up on the sideline.” It was a gamble, but not an improvised one. The play had been installed and practised for the playoffs, the coaches had chosen the situation for it in advance, and the quarterback asked for it by name. What was bold was the decision to go for it on fourth down at all, and that was the 2017 Eagles’ habit, not a one-off. Trick plays look like inspiration; they are usually homework.

NoteFilm room: Philadelphia Eagles 2017

The season: 13–3 and the NFC’s top seed, despite losing Wentz, Peters and other starters to injury; a 38–7 win over Minnesota in the NFC Championship, then a 41–33 win over New England in Super Bowl LII, with Foles the game’s MVP.10

What to notice on the Super Bowl film: the Philly Special is the famous snap, but watch the fourth-and-1 at the Eagles’ 45 with 5:39 left in the fourth quarter. The Eagles were behind by a point. A punt would have given Tom Brady the ball with a lead and five minutes to run out the clock. Instead Foles took a shotgun snap and threw a quick pass to Ertz in the flat for two yards. The drive ended with Ertz’s touchdown catch that put Philadelphia ahead for good. The same coach made both fourth-down calls in the same game, and the same reasoning was behind each: a yard is usually worth more than the kick.

2021–2025: Sirianni, Hurts, and a run game built in the trenches

Pederson was fired after the 2020 season, and Nick Sirianni, the Colts’ offensive coordinator, replaced him in January 2021. His first offense started like most modern offenses: in the shotgun, throwing the ball. After seven games the Eagles were 2–5, and two things changed at once. Sirianni handed play-calling to his offensive coordinator, Shane Steichen, and the offense turned around. In weeks 1–7 the Eagles ran on 38% of their snaps; from week 8 on, on 59%. They won seven of their last ten games, made the playoffs, and led the league in rushing at 160 yards a game.11 Be careful about crediting either change alone: the play-caller and the run share changed in the same week, and seven games against ten is far too little to tell them apart. What the next five seasons show is that the running stuck after the play-caller left.

Why would a modern offense get better by running more? Because of who was running it.

The quarterback as an extra blocker

On a normal handoff, the quarterback gives the ball away and stops mattering, so the offense blocks with ten players against eleven defenders. Jalen Hurts is strong, fast and hard to tackle, so a defense has to account for him on every snap, and that changes the arithmetic. On a zone read one defender is left unblocked, and Hurts reads him: hand off if that defender crashes inside, keep it if he stays outside. On a designed quarterback run (QB power or QB counter), the running back becomes a blocker. Either way the offense blocks with one more player than usual. Coaches call a blocker a “hat,” so this is the “extra hat” idea from the Option Football chapter.

The RPO came back too, now with a quarterback who could also run. In 2022, FTN’s charting has Philadelphia using RPOs on 14% of its plays, more than any other team and well above the league’s 5%.12 The richest versions read two defenders in sequence. First, at the handoff, Hurts watched the unblocked end: if the end crashed toward the back, Hurts pulled the ball. Then, with the ball still in his hands, he watched a second defender, a linebacker or the nickel back: if that man came up to stop the quarterback run, Hurts threw behind him; if he stayed back, Hurts ran. Each defender had to guess right, and one wrong guess was enough. The share fell back toward the league’s in later seasons (4% in 2024, 13th in the league, and 6% in 2025) as the offense leaned on Barkley’s handoffs instead.

2022: the line-first idea on both sides

The second Super Bowl team, in Steichen’s second season as play-caller, is the clearest picture of the line-first idea working on both sides of the ball. The 2022 Eagles went 14–3. The offense ranked 3rd in EPA per play (expected points added), with Hurts the MVP runner-up and the tush push at the start of its run. The defense recorded 70 sacks, the most in the league and tied for the third-most by any team in NFL history, and it was the first team ever with four players reaching double figures.13 They lost Super Bowl LVII to Kansas City 38–35, a game in which Hurts ran for 70 yards and three touchdowns and threw for 304 more.

NoteFilm room: Philadelphia Eagles 2022

What to notice: on their 2022 film, how often the four-man rush got home by itself. Haason Reddick, Josh Sweat, Javon Hargrave and Brandon Graham each had at least ten sacks. Jonathan Gannon’s defense sent five or more rushers on 19% of dropbacks by FTN’s charting, about the league rate of 20% that season,14 and it didn’t need more: the sacks came from the linemen. Two years later Fangio built his Super Bowl plan on the same principle.

The line, and the man who coached it

None of that works without the five men in front. Jeff Stoutland came to Philadelphia in 2013 from Nick Saban’s Alabama, hired by Chip Kelly, and he stayed through Pederson and Sirianni. That run is rare in a league where position coaches usually leave with the head coach who hired them. He was the Eagles’ run game coordinator as well as their line coach, and his reputation rested on turning unlikely players into starters:

  • Jordan Mailata, an Australian rugby league player who had never played a down of American football, was a seventh-round pick in 2018. He made his first starts in 2020, was the full-time left tackle from 2021, and in 2024 signed a three-year, $66 million extension that made him one of the four highest-paid tackles in the league.
  • Jason Kelce, a sixth-round pick in 2011, became a six-time first-team All-Pro. He was undersized for a center, and size is usually the point of the position: a center’s hardest job is holding his ground against a nose tackle lined up directly over him, often the heaviest man on the defense. The Eagles asked Kelce to move instead, reaching defenders on zone runs, pulling, and racing out to block for screens, where quickness matters more than mass, and his timing made their sneak the most feared in football.
  • Mekhi Becton, a former first-round pick the Jets had given up on as a tackle, signed a one-year deal in 2024, moved inside to right guard at the Eagles’ request, and started 15 games for a Super Bowl champion.15

Figure 64.2 shows the two runs that line was built for in 2024, with Saquon Barkley carrying.

Show the Python
def nickel_two_high():
    """Even front, two linebackers, the nickel over the slot, two safeties deep: six in the box."""
    return [D("WDE", "DE", 1.0, -4.0, "E"), D("NT", "DT", 1.0, -0.8, "T"), D("DT", "DT", 1.0, 2.3, "T"),
            D("SDE", "DE", 1.0, 5.9, "E"), D("WILL", "LB", 4.6, -2.2, "W"), D("MIKE", "LB", 4.6, 1.4, "M"),
            D("NB", "NB", 4.2, -8.0, "$"), D("FS", "FS", 12.0, -6.5, "FS"), D("SS", "SS", 12.0, 6.5, "SS")]


def eagles_11(qb_d, rb):
    return line5() + [O("Y", "TE", LINE_D, 4.8, "Y"), O("H", "WR", OFF_BALL, -8.6, "H"),
                      O("QB", "QB", qb_d, 0.0, "Q"), O("RB", "RB", *rb, "R")]


def pair_oval(fld, p, d, w, wid=3.0, dep=2.6):
    x, y = P(fld, p, d, w)
    fld.ax.add_patch(Ellipse((float(x), float(y)), wid, dep, fc=style.THIRD, alpha=0.22, ec=style.THIRD, lw=0.9,
                             zorder=1.7))


def option(fld, p, pts):
    """One of the back's choices: a thin dashed line with a small head on its last stretch only."""
    xs, ys = P(fld, p, np.array([q[0] for q in pts]), np.array([q[1] for q in pts]))
    fld.ax.plot(xs, ys, color=OD, lw=1.2, ls=(0, (3, 2.2)), zorder=5)
    x0, y0 = xs[-2] + 0.82 * (xs[-1] - xs[-2]), ys[-2] + 0.82 * (ys[-1] - ys[-2])
    fld.ax.add_patch(FancyArrowPatch((x0, y0), (xs[-1], ys[-1]), arrowstyle="-|>", mutation_scale=9, color=OD,
                                     lw=1.2, zorder=5))


def climb(fld, p, pts):
    """A lineman coming off a double team to a linebacker: starts at HIS shoulder, curls round the tackle."""
    branch(fld, p, pts, color=READ_GREEN, end="bar", lw=1.3)


fig, axes = plt.subplots(1, 2, figsize=(6.6, 4.9))
LAT, WIN = (-10.6, 10.6), (-9.8, 14.2)

# --- duo from the gun: C+LG double the 1-tech (LG climbs to W); RG+RT double the 3-tech (RG climbs to M)
p = Play(eagles_11(GUN, (GUN, -2.1)), nickel_two_high(), los=own(35), to_go=None)
for k, end in (("LG", (0.25, -1.15)), ("C", (0.25, -0.45)), ("RG", (0.25, 1.95)), ("RT", (0.25, 2.65)),
               ("Y", (0.35, 5.4)), ("LT", (0.35, -3.6))):
    move_to(p, k, end)
move_to(p, "RB", (-2.4, 0.8), (0.3, 0.8), kind="run")
p.highlight("RB")
f = draw(p, ax=axes[0], lateral=LAT, window=WIN)
pair_oval(f, p, 0.4, -0.8)
pair_oval(f, p, 0.4, 2.3)
climb(f, p, [(0.2, -1.95), (1.9, -2.15), (3.55, -2.2)])
climb(f, p, [(0.2, 1.2), (1.9, 1.15), (3.55, 1.35)])
option(f, p, [(0.3, 0.8), (3.0, 0.7)])
option(f, p, [(0.3, 0.8), (3.2, 3.4)])
say(f, p, 8.5, 0.0, "6 in the box vs 6 blockers", color=READ_GREEN, fontsize=6.8, weight="bold")
say(f, p, -7.6, 5.0, "doubles drive the\ntackles back", color=READ_GREEN, fontsize=6.4)
point_to(f, p, (-7.6, -5.4), (-5.0, -2.1), "R reads the Mike:\nA gap or B gap", color=OD, fontsize=6.4)
panel_title(axes[0], "Duo: straight ahead")

# --- outside zone right from the pistol
p = Play(eagles_11(PISTOL, (-7.0, 0.0)), nickel_two_high(), los=own(35), to_go=None)
# LG and RT stay drawn at their stances: each one's job is the green climb to a linebacker after helping
# on the double team, so a block line of their own would only clutter the picture
for k, end in (("LT", (0.3, -2.9)),      # scoops the backside B gap
               ("C", (0.4, -0.3)),       # reaches the 1-tech's playside shoulder
               ("RG", (0.45, 2.35)),     # reaches the 3-tech
               ("Y", (0.4, 6.6))):       # reaches the end
    move_to(p, k, end)
move_to(p, "RB", (-4.6, 3.2), (-1.8, 6.4), kind="run")
move_to(p, "QB", (-4.8, -2.6), kind="path", delay=0.3)      # the keep (bootleg) fake
p.highlight("RB")
f = draw(p, ax=axes[1], lateral=LAT, window=WIN)
pair_oval(f, p, 0.3, -1.0, wid=3.4)
pair_oval(f, p, 0.4, 2.6, wid=3.4)
climb(f, p, [(-0.05, -1.75), (2.2, -1.95), (3.55, -2.15)])
climb(f, p, [(-0.1, 3.75), (1.6, 3.7), (2.6, 3.1), (3.55, 1.7)])
for pts in ([(-1.8, 6.4), (3.0, 8.8)], [(-1.8, 6.4), (3.0, 4.9)],
            [(-1.8, 6.4), (-1.7, 3.9), (-0.6, 1.4), (3.2, 0.6)]):
    option(f, p, pts)
say(f, p, 4.0, 8.2, "bounce", color=OD, fontsize=6.0)
say(f, p, 3.7, 5.3, "bang", color=OD, fontsize=6.0)
say(f, p, 2.7, -0.5, "bend", color=OD, fontsize=6.0)
say(f, p, 8.5, 0.0, "the whole line steps right", color=OD, fontsize=6.8, weight="bold")
point_to(f, p, (-7.8, 5.8), (-1.8, 6.4), "aim at Y's\noutside leg", color=OD, fontsize=6.4)
point_to(f, p, (-7.8, -5.0), (1.0, -4.0), "end left unblocked:\nQ's keep fake holds him", color=DD, fontsize=6.2)
panel_title(axes[1], "Outside zone: across, then up")
fig.tight_layout(w_pad=0.8)
field_legend(axes[0], ["carrier", "block", "double", "climb", "option"], y=-0.01, ncol=5, fs=6.6)
axes[0].get_legend().set_bbox_to_anchor((1.05, -0.01))
plt.show()
Figure 64.2: The two runs at the heart of the 2024 Eagles’ ground game, against a two-high nickel defense (illustrative, not one specific play; the wide receivers are off the picture). Left, duo from the shotgun: two double teams (green ovals) drive the defensive tackles straight back, and one man from each double climbs to a linebacker (green dashes). Barkley (R, ringed) runs right at the doubles, which freezes the linebackers, and reads the Mike (M), hitting whichever gap he leaves. Right, outside zone from the pistol: the line steps right together, with two reach-and-overtake doubles, and the backside end is left unblocked because Hurts’s keep threat holds him. Barkley aims at Y’s outside leg and takes one of three answers (dashed): bounce outside, bang up inside the tight end, or bend back against the flow.

The two plays ask different things of the line, and the Eagles’ line could do both. Duo (taught in the Gap Schemes chapter) is a straight-ahead shoving match: two double teams move the two defensive tackles backward, and the back runs through whichever gap the Mike linebacker leaves open. It needs linemen strong enough to move a 300-pound man two yards against his will. (This book files duo with the gap runs because it has no zone footwork; many coaches, especially in the Shanahan family, teach it as inside zone’s cousin, “power without the puller.” It is the same play under either label.) Outside zone (from the Zone Running chapter) is a race: the whole line steps sideways together, the defense has to run with it, and somewhere a defender overruns his gap and opens a seam. The back’s answers are the zone chapter’s bang, bend, bounce; against a light box that is chasing the play sideways, the bend, cutting back behind the defenders who overran it, is often the big one. It needs linemen quick enough to get their heads across a defender’s body. Johnson, Mailata, Landon Dickerson and Kelce (and from 2024 his successor at center, Cam Jurgens) were rare in being good at both.

Notice who is not blocked on outside zone: the backside end. Nobody has time to reach him, so the play leaves him alone and lets the quarterback hold him. If he chases Barkley from behind, Hurts can pull the ball and run (or roll out to throw) where the end used to be. That is the extra-blocker idea from the previous section, working on a handoff.

Why did all this matter so much in 2024? Because of what defenses were doing. Across the league, defenses were playing more and more two-high coverage, keeping both safeties deep to stop explosive passes, which leaves only six defenders near the line: a light box (the Modern Era chapter tells that story). A light box is the defense making a bet: we’ll give you four or five yards on the ground rather than twenty in the air. The Eagles’ line, with Barkley behind it, made that a losing bet.

NoteFilm room: Saquon Barkley, 2024

The season: Barkley signed a three-year contract with the Eagles in March 2024 after six seasons with the Giants, and ran for 2,005 yards in the regular season, becoming the ninth player in NFL history to reach 2,000. Counting his 499 in the playoffs, he ran for 2,504 yards in one season, more than any player before him. He was the league’s Offensive Player of the Year. The Eagles ran the ball on 55% of their snaps, the highest share in the league, and averaged 179 rushing yards a game.16

What to notice: what happens after the line has done its job. Barkley is a big back with sprinter’s speed, and in 2024 his long runs came on ordinary-looking plays: duo or zone, a crease at the line, one missed tackle at the second level, and then nobody left, because the safeties start twelve yards deep. Count, on his long runs, how many defenders are within three yards of the line of scrimmage at the snap.

The coordinator churn

If the line was the constant, the play-caller was the variable. Look at the list:

Season Offensive coordinator What happened next
2021–2022 Shane Steichen (play-caller from midway through 2021) Hired as the Colts’ head coach, February 2023
2023 Brian Johnson Not retained after a late-season collapse
2024 Kellen Moore Hired as the Saints’ head coach, February 2025
2025 Kevin Patullo Replaced after one season
2026 Sean Mannion (from the Packers, where he coached quarterbacks) A first-time play-caller, calling the plays in 202617

Mannion’s hiring in January 2026 made him, in the Associated Press’s count, the Eagles’ fifth offensive coordinator in five seasons.18 Some of the churn is the price of success: Steichen and Moore left for head-coaching jobs because their offenses had been good. Some of it is not. Brian Johnson was let go after the 2023 team collapsed down the stretch, and Kevin Patullo was replaced after the 2025 offense slipped to the middle of the league. Figure 64.3 puts each season’s offense next to its coordinator.

Show the Python
fig, ax = plt.subplots(figsize=(6.4, 3.4))
xs = np.arange(len(EPA))
ax.axhline(0, color=style.INK_2, lw=0.9)
ax.plot(xs, EPA["run"], marker="o", ms=6, color=style.SERIES[0], label="designed runs", zorder=4)
ax.plot(xs, EPA["run_ns"], marker="o", ms=4, mfc="white", color=style.SERIES[0], lw=1.1, ls=(0, (3, 2)),
        alpha=0.8, label="designed runs without sneaks", zorder=3)
ax.plot(xs, EPA["drop"], marker="s", ms=5.5, color=style.SERIES[1], label="dropbacks (passes, sacks, scrambles)",
        zorder=4)
for x, (r, d) in zip(xs, EPA[["run", "drop"]].values):
    # put each run label on the side of the blue dot away from the orange one, so it can't be misread
    # (when the two dots almost touch, the label goes to the right of both, above the falling lines)
    off = (24, 4) if abs(r - d) < 0.01 else ((-11, 7) if r >= d else (0, -11))
    ax.annotate(f"{r:+.2f}", (x, r), xytext=off, textcoords="offset points", ha="center",
                va="center", fontsize=6.8, color=style.SERIES[0], fontweight="bold")
ax.set_xticks(xs)
ax.set_xticklabels([f"{s}\n{OC[s]}" for s in EPA.index], fontsize=7.5)
ax.set_ylabel("EPA per play, Eagles minus league", fontsize=8)
ax.set_ylim(-0.06, 0.17)
ax.set_xlim(-0.4, len(xs) - 0.6)
ax.tick_params(axis="y", labelsize=7)
ax.grid(axis="x", visible=False)
ax.legend(fontsize=7.0, loc="lower left", ncol=2)
fig.tight_layout()
plt.show()
Figure 64.3: The Eagles’ offense against the league, by season and offensive coordinator, 2021–2025 regular seasons: expected points added (EPA) per play on designed runs and on dropbacks, minus the league average (above zero is better than average; the numbers are the designed-run values). The faint dashed blue line removes every quarterback sneak from the runs (FTN charting, so 2022 onward only): it is lower, because the tush push was the Eagles’ most efficient run, but still well above average in 2022 and 2024. Notice that neither line falls when the coordinator changes in 2023 or 2024; both fall together in 2025. Data: nflverse play-by-play joined to FTN charting (runs exclude quarterback scrambles, which count as dropbacks).

The chart says three things. (EPA, expected points added, scores each play by how much it changed the offense’s expected points; a run game +0.10 above average adds about a point every ten carries.) First, the Eagles’ run game was one of the league’s best for four straight seasons under three play-callers. Taking out the sneaks lowers it, most of all in 2023 (+0.03 without them), but it stays well above average in 2022 and 2024, so the push alone doesn’t explain it. Second, the passing game was above average in all five seasons too, and it didn’t fall when the play-caller changed either. Third, in 2025 both lines sank together: the run game finished +0.01 against the league, roughly average, the Eagles ran for 117 yards a game, 18th in the league, and the offense ranked 15th in EPA per play.

What does that rule in or out? It argues against the coordinator being the source of the offense’s quality, because three of them came and went without the lines moving. It doesn’t say the source was the line alone. Hurts was the quarterback in every one of these seasons, so the chart can’t separate the line from the quarterback behind it, and Barkley arrived in 2024. The honest summary is that the Eagles’ offense was built on things that stayed (the line and Hurts), not on the play-caller who changed.

Be careful with the “why” of 2025, too. Several things changed at once: a new play-caller, a Barkley coming off the heaviest workload of his career (he ran for 1,140 yards, down from 2,005), defenses that crowded the box more often (see “How opponents responded”), and, according to reporting by the Philadelphia Inquirer and ESPN, a push by Sirianni and Patullo to diversify the run game that cut into Stoutland’s role as its designer; he lost the title of run game coordinator during the season. The Eagles still went 11–6 and won the NFC East, then lost at home to San Francisco in the wild-card round, 23–19.19 On February 4, 2026, Stoutland announced that he was leaving, after 13 seasons; his replacement is Chris Kuper, the Vikings’ line coach from 2022 to 2025, who had worked under Fangio in Denver.20 A single season can’t separate those causes. What it can tell you is that the one stable thing in the Eagles’ offense was also the one that slipped.

The tush push as a talent edge

The chapter on Red Zone, Goal Line, Two-Point Plays, and Short Yardage explains how the tush push works and shows that league-wide, quarterback sneaks of every kind (FTN charts the plain sneak and the push under one label) convert about four times in five on 1 yard to go. It ends on a puzzle: the Eagles’ conversion rate on the play sits close to the league line, even though they ran it far more often than anyone, against defenses that knew it was coming. This section takes that puzzle up. If the push is the Eagles’ signature, how big was their edge, really?

The ingredients are not in doubt. Hurts has unusual leg strength for a quarterback, and he took the snap already crouched, ready to drive. Kelce, and the guards beside him, fired out low at the snap. The two pushers lined up against Hurts’s hips, where a shove moves the whole man rather than bending his back. Johnson, Mailata and Dickerson were among the best linemen at their positions, and Stoutland drilled the play’s timing until the line moved as one at the instant of the snap. The question is what those ingredients produced.

Show the Python
fig, ax = plt.subplots(figsize=(6.4, 3.4))
xs = np.arange(len(SEAS))
ax.axhline(0, color=style.INK_2, lw=0.9)
for off, df, c, m, lab in ((-0.12, DS, style.SERIES[0], "o", "sneaks only"),
                           (0.12, DA, style.SERIES[1], "s", "every 1-yard-to-go snap")):
    ax.errorbar(xs + off, 100 * df["d"], yerr=100 * Z90 * df["se"], fmt=m, ms=6, color=c, ecolor=c,
                elinewidth=1.4, capsize=0, alpha=0.95, label=lab)
    for x, v in zip(xs + off, df["d"]):
        ax.text(x + (0.09 if off > 0 else -0.09), 100 * v, f"{100 * v:+.0f}", fontsize=6.8, color=c,
                ha="left" if off > 0 else "right", va="center")
ax.set_xticks(xs)
ax.set_xticklabels([f"{s}\n{int(DS.loc[s, 'n'])} sneaks" for s in SEAS], fontsize=7.5)
ax.axvline(1.5, color=style.BASELINE, lw=0.9, ls=(0, (3, 3)))
ax.text(1.52, 27, "Kelce retires\nafter 2023", fontsize=6.8, color=style.INK_2, va="top")
ax.set_ylabel("Eagles minus league,\npercentage points", fontsize=8)
ax.set_ylim(-34, 30)
ax.set_xlim(-0.5, len(xs) - 0.5)
ax.tick_params(axis="y", labelsize=7)
ax.grid(axis="x", visible=False)
ax.legend(fontsize=7.2, loc="lower left", ncol=2)
fig.tight_layout()
plt.show()
Figure 64.4: The tush push as an edge: Eagles minus the rest of the league, in percentage points of conversions (first down or touchdown) on 1 yard to go, 2022–2025 regular seasons. Each vertical bar is a 90% interval, the range the true difference plausibly lies in given how few plays there are; a bar that crosses zero means a gap that size could easily be luck. Blue: quarterback sneaks only (the push and the plain sneak). Orange: every snap on 1 yard to go, whatever the call, which removes the question of which plays a team chose to sneak on. Only 2023 stands clearly above zero on either measure. By 2025 the Eagles’ sneaks converted less often than the league’s, but on all their 1-yard snaps together the Eagles never fell below the league in any season. The labels under each season give the Eagles’ number of sneaks. Data: nflverse play-by-play joined to FTN charting.

Read the blue dots first. Over the four seasons, the Eagles converted 82% of their 137 sneaks on 1 yard to go, and the rest of the league converted 81% of theirs: a difference of about 1 point.21 Season by season, the edge was +3 points in 2022, +14 points in 2023, −3 points in 2024 and −14 points in 2025. That is not what a near-unstoppable play looks like. Three things explain the gap between the reputation and the numbers, and they are worth learning, because they apply to almost every “Team X is great at Y” claim you will hear on a broadcast.

1. Small samples. Thirty or forty sneaks a season is not many. A play that truly succeeds 82% of the time will, in a season of 35 tries, land anywhere from about 71% to 93% just by chance. That is what the vertical bars show, and in three of the four seasons the bar crosses zero. A single good or bad season of sneaks tells you very little. Four seasons pooled tell you more, and they say: about league average.

2. Selection. Every other team chose its sneaks. They could run the play when the ball was spotted inches from the line to gain, against a defense that looked soft in the middle, and call something else when it wasn’t. The Eagles ran it on 51% of all their 1-yard-to-go snaps in these four seasons, against a league median of 14%, so they must have sneaked on many snaps other teams would have passed up, against defenses that had a week to plan for it. The data can’t confirm that their snaps were harder: the play-by-play records anything from an inch to a full yard as “1 yard to go.” It is an inference from how often they called it, and it means a league-average rate on the Eagles’ sneaks probably hides some edge. That is why the orange dots matter. They compare every snap on 1 yard to go, whatever the call, so no team gets to pick its spots: a team that sneaks only on the easy ones has to convert the hard ones some other way, and both count. On that measure the Eagles converted more often than the league in every season, but only 2023, at +14 points, is clearly more than noise.

3. Volume, and what it was worth. Across the league, sneaks on 1 yard to go converted 81%, other runs 70% and passes 58%. Don’t read that as “a sneak adds eleven points of success on any snap”: those other plays were chosen too, often on the longer “1 yards” a team didn’t trust its sneak on, so the gap overstates what calling a sneak every time would add. What it does show is why a team that can call its best short-yardage play on most short-yardage snaps, without the rate collapsing, gains something. Most teams can’t: their quarterback isn’t built for it, their line can’t win the snap every time, or their coach won’t put the starter at the bottom of a pile forty times a year.

How much did the Eagles gain? The orange dots answer it directly. Multiply each season’s edge on all 1-yard snaps by the number of those snaps, and you get the extra first downs (or touchdowns) the Eagles converted compared with a league-average offense facing the same snaps: about 2 in 2022, 9 in 2023, and fewer than one in 2024 and in 2025.22 In 2023 that came to about one extra first down every other game, often the one that keeps a drive alive. That was a real edge. In the other three seasons the gain was small enough to be luck. The talent edge, in other words, wasn’t a higher sneak rate. It was being able to put the sneak on half of all short-yardage snaps and still convert like the league, and only in 2023 did that add up to much more.

And then it faded. The 2023 season, Kelce’s last, was the peak. In 2024 the sneak rate fell back to the league’s; in 2025 the Eagles converted 65% of their sneaks, well below the rest of the league’s 80%, and ran fewer of them (26). Their other plays on 1 yard to go picked up the slack, so across all their 1-yard snaps they still matched the league (the orange dot, +1 point); what disappeared was the push’s own advantage. The candidate explanations are the ones in “How opponents responded”: the center who timed the snap had retired, defenses had studied the play for three years, and the league told its officials to watch for linemen moving early. The sample is too small to rank those causes. The direction is not in doubt.

2024: Barkley, Fangio, and a four-man rush

The 2023 Eagles started 10–1 and collapsed, losing six of their last seven games, including a lopsided wild-card loss in Tampa. The defense was the main culprit: by EPA per play it ranked 29th in the league.23 Brian Johnson’s offense had slipped too, from 3rd the year before to 8th, but it was still one of the better offenses in football; a defense ranked 29th is what sank the season. The offseason that followed was the most consequential in the franchise’s recent history:

  • Vic Fangio was hired as defensive coordinator. Then 65, he had first coached in the NFL in 1986 and spent most of the four decades since in the league, and he was the man behind the two-high, light-box defenses that had spread across the league from his late-2010s Bears and Broncos24 (his ideas are the subject of their own case study). He was still the Eagles’ coordinator in 2026.
  • Saquon Barkley signed as a free agent, the rare case of the Eagles paying a running back.
  • The draft brought two rookie defensive backs, cornerback Quinyon Mitchell in the first round and Cooper DeJean in the second, who both started on a Super Bowl defense as rookies.
  • Zack Baun signed a one-year deal. The front office saw him as a backup edge rusher and special-teams player; Fangio, from a handful of snaps on Baun’s New Orleans film, saw an inside linebacker, moved him there that spring, and Baun became a first-team All-Pro.25 That is coaching as roster building: the cheapest way to add a star is to find one playing the wrong position.
  • Kellen Moore became offensive coordinator, the third in three seasons.

The result was a 14–3 season and a defense that allowed the fewest yards in the league and ranked 2nd in EPA per play, a year after ranking 29th. Fangio’s defense blitzed less than most. A blitz is a pass rush with five or more rushers, one more than the usual four; by FTN’s charting, the 2024 Eagles sent one on 19% of dropbacks, 28th of 32 teams, against a league rate of 26%.26 Their four rushers were usually, though not always, the four down linemen. It trusted those four to get there and kept seven players in coverage. Then, in the Super Bowl, it did that on every snap.

Super Bowl LIX: four rushers, no blitzes

February 9, 2025, New Orleans: Eagles 40, Chiefs 22. The Eagles led 24–0 at halftime and 34–0 late in the third quarter, and the defense did it without blitzing. NFL Next Gen Stats counted 42 Patrick Mahomes dropbacks and zero blitzes, only the fourth time a defense had gone a whole game without blitzing since it began tracking in 2014, and still credited the Eagles with 16 pressures, a pressure on 38.1% of dropbacks, and six sacks, the most Mahomes had taken in a game in his career.27 FTN’s charting agrees on the count that matters: it never had more than four Eagles rushing on any scrimmage dropback.28 After the game the defensive end Josh Sweat, who had 2.5 sacks, put it plainly: “Vic didn’t want to blitz. We knew if we had to blitz, we’d be in trouble.” Figure 64.5, below, shows the shape of it.

Why would not blitzing be the right plan against the league’s best quarterback? Think about what a blitz gives a quarterback like Mahomes, and what it costs.

  • A blitz trades coverage for speed. Every extra rusher is one fewer defender in coverage, so somebody is uncovered or left one-on-one. A quarterback who reads the blitz before the snap knows where that somebody is, and Mahomes was as good as anyone at punishing it with a quick throw or a scramble into the space the rushers left.
  • Four plus seven takes away the quick answer. With seven in coverage, here a quarters shell (four deep, three underneath, from the Quarters and Match chapter), every route has a defender near it. FTN charted the Eagles in quarters (Cover 4) on 27 of the 45 dropbacks, and in some two-deep-safety coverage (quarters, Cover 2 or Cover 6) on 30, far more than the 34% two-high rate it charted for them in the regular season. The quarterback has to hold the ball, and every half-second he holds it is another half-second for the rush.
  • It only works if four can win. That is the condition, and it is mostly a roster condition. Jalen Carter, Milton Williams, Jordan Davis, Josh Sweat and Nolan Smith could beat blockers one-on-one, on the interior as well as the edges. And that night the matchup helped: after an injury to Kansas City’s left tackle in December, Joe Thuney, an All-Pro left guard, had moved out to left tackle and started there in the Super Bowl, which weakened the edge and the interior at once.29 Most defenses can’t get to the quarterback rushing four, so they have to blitz.
Show the Python
from gridiron import routes as r

off = line5() + [O("QB", "QB", GUN, 0.0, "Q"), O("RB", "RB", GUN, 2.1, "R"),
                 O("X", "WR", LINE_D, -19.8, "X"), O("H", "WR", OFF_BALL, -11.0, "H"),
                 O("Y", "TE", OFF_BALL, 8.5, "Y"), O("Z", "WR", LINE_D, 18.8, "Z")]
dfn = dline(w=(-5.0, -0.8, 2.4, 5.2)) + [
    D("WILL", "LB", 5.0, -3.0, "W"), D("MIKE", "LB", 5.0, 2.6, "M"), D("NB", "NB", 4.6, -10.0, "$"),
    D("LCB", "CB", 6.5, -17.9, "CB"), D("RCB", "CB", 6.5, 16.9, "CB"),
    D("FS", "FS", 12.0, -8.0, "FS"), D("SS", "SS", 12.0, 8.0, "SS")]
p = Play(off, dfn, los=own(30), to_go=9)
p.dropback(2.0)
move_to(p, "RB", (-5.6, 1.3), kind="path", speed=2.0)
# a plausible Kansas City dropback concept: X dig at 12, H seam, Y option at 6, Z curl at 12
p.route("X", [(12.0, 0.0), (12.0, -9.0)], frame="side")
p.route("H", [(16.0, 1.5)], frame="side")
p.route("Y", [(6.0, 0.0), (6.0, -2.5)], frame="side")
p.route("Z", [(12.0, 0.0), (10.8, -1.2)], frame="side")
for k, end in (("WDE", (-5.4, -2.6)), ("WDT", (-4.0, -0.9)), ("SDT", (-4.0, 1.2)), ("SDE", (-5.5, 2.9))):
    move_to(p, k, end, kind="rush")
for k, to, zone in (("LCB", (14.5, -17.0), (8.0, 10.0)), ("FS", (13.5, -7.0), (8.0, 10.5)),
                    ("SS", (13.5, 7.0), (8.0, 10.5)), ("RCB", (14.5, 16.8), (8.0, 10.0)),
                    ("NB", (7.5, -12.5), (5.5, 9.0)), ("WILL", (8.0, -3.5), (5.5, 8.0)),
                    ("MIKE", (8.0, 6.0), (5.5, 9.0))):
    p.drop(k, to, zone=zone)
f = draw(p, lateral=(-22.5, 22.5), window=(-9.5, 22.5), width_in=6.4)
say(f, p, -6.2, -11.0, "4 rush: they must\nwin one-on-one", color=DD, fontsize=6.8, weight="bold")
say(f, p, 20.4, 0.0, "7 in coverage: 4 deep quarters + 3 underneath", color=DD, fontsize=6.9, weight="bold")
say(f, p, -6.6, 7.0, "6 to block 4", color=OD, fontsize=6.6)
field_legend(f.ax, ["route", "rush", "drop", "area"], y=0.0, ncol=4)
plt.show()
Figure 64.5: The Super Bowl LIX plan, typical snap (illustrative; based on the charting of the game, not one specific play): Kansas City in 11 personnel from the shotgun against the Eagles’ nickel. Four rushers (solid orange) take on five linemen and a back who stays in to block; seven defenders drop into coverage, here a quarters shell: four deep defenders (CB, FS, SS, CB) and three underneath. The ovals are where each defender starts responsible; in Fangio’s quarters the safeties read the slot receivers and can come down hard on a short route or carry a seam, so the coverage matches the routes rather than sitting in spots (see the Quarters and Match chapter). Every route ends inside or under a defender’s area, so the quarterback has nowhere quick to throw, and the four rushers have time to win one-on-one.

That last point is the whole chapter in miniature. Fangio’s plan was a clever plan, but plenty of coordinators would have liked to rush four and drop seven. Fangio could do it because the front office had spent first-round picks on Davis (2022), Carter and Smith (2023), had developed Williams from a third-round pick, and had kept a deep rotation of linemen: eight or nine of them who all play, in shifts, so the four on the field are fresh on every snap, which matters when four men have to do all the rushing. The scheme was possible because of the roster.

NoteFilm room: Super Bowl LIX (February 9, 2025)

The game: Hurts completed 17 of 22 passes for 221 yards and two touchdowns, ran for 72 yards and scored on a tush push in the first quarter, and was the game’s MVP. DeJean, the rookie, intercepted Mahomes and returned it 38 yards for a touchdown, on his 22nd birthday. Baun added a second interception before halftime.30

What to notice: count the rushers on every Kansas City dropback. You will count four every time, and usually the four linemen you saw in their stances, with no linebacker or safety joining them. Then watch the middle of the pocket. Carter and Williams pushed the interior back toward Mahomes, so he had no room to step up, and the ends closed in from outside. The pressure came from straight ahead, where a quarterback can’t escape it by drifting sideways.

Roster building: paying for the lines

How did the Eagles keep elite lines for a decade? The tempting answer is “they spent their high draft picks on linemen,” and it is only partly true. From 2013 to 2025 the Eagles spent 7 of their 25 first- and second-round picks on offensive or defensive linemen (28%), 30th among the 32 franchises and below the league median of 38%.31 Their famous lines were built another way:

  1. Develop the unlikely. Mailata (seventh round), Kelce (sixth round), Isaac Seumalo (third round) and Becton (another team’s discarded first-rounder) were turned into starters by Stoutland’s coaching. That is cheap talent, and a team that can make it has money left for everything else. (Baun’s move to inside linebacker was the same trick on defense.)
  2. Pay to keep them. When those players became good, the Eagles paid them. Using contract data from Over the Cap, a website that tracks every NFL contract, the Eagles’ offensive line took up 18.2% of the salary cap in an average season from 2017 to 2025, against a league median of 15.2%, and ranked between 4th and 13th in the league every year.32
  3. Spend the big picks where they move the needle. The first-round picks of the 2021–2025 drafts went to a wide receiver (DeVonta Smith, 2021), two defensive tackles and an edge rusher (Davis, Carter, Nolan Smith), a cornerback (Mitchell) and a linebacker (Jihaad Campbell, 2025). Pass rushers who win one-on-one are the scarcest players in football after quarterbacks, and you usually can’t develop them from the seventh round.
  4. Use the quarterback’s cheap years. In 2022 Hurts was still on his second-round rookie contract, among the cheapest starting quarterbacks in the league. That gap between what a good young quarterback earns and what a veteran costs is the rookie-contract window, and the Eagles spent it: they traded for the receiver A.J. Brown and signed Reddick that spring. Hurts’s five-year, $255 million extension came in April 2023.33

Notice how each choice connects to a scheme choice. A team that develops linemen cheaply can afford a run-first offense, because the line is good enough to win without trickery. A run game that wins with five blockers frees the quarterback from carrying the offense. A pass rush that wins with four lets the defensive coordinator play coverage instead of guessing with blitzes. And a sneak that converts four times in five, and can be called on almost every short-yardage snap, makes fourth-and-1 a play to run, not a gamble. The roster is the scheme.

The trade-offs are real too. Money spent on linemen is money not spent on receivers or a second cornerback. Linemen get old together: the Eagles had to replace Kelce, Brooks and Peters within a few seasons of one another. And an offense whose identity is “our line is better than yours” has a hard time when the line is merely good, which is one way to read 2025.

How opponents responded

The league’s responses to the Eagles came in three forms.

On the field. Defenses attacked the push the only way it can be attacked: by winning the snap. They crowded both A gaps beside the center with their biggest linemen, timed the cadence so their tackles were moving as the ball was, and sent linebackers leaping over the pile to meet Hurts before it moved. Some defensive linemen began jumping the snap count on purpose, accepting an occasional offside penalty for the chance to get into the backfield first. Against the run game, defenses crowded the box: on first and second down, the Eagles faced seven or more defenders in the box on 34% of snaps in 2024 and 42% in 2025, when only 5 offenses saw heavy boxes more often.34 (The details of those tactics are in the Red Zone, Goal Line, Two-Point Plays, and Short Yardage chapter.)

The most vivid version came in the NFC Championship Game on January 26, 2025. With the Eagles in their push formation at the Washington 2, linebacker Frankie Luvu tried to time a leap over the pile and was flagged for jumping early, twice; a defensive lineman then jumped a hard count for a third penalty. The referee, Shawn Hochuli, announced that the officials could award a touchdown if Washington kept fouling to prevent one. The Eagles scored anyway and won 55–23.35 The leap itself is legal on a running play if it is timed after the snap. (Since 2017 it has been banned only on field-goal and extra-point tries, a safety rule for kicks that fans often assume covers every play.36) Luvu’s problem was the clock: to beat the push he had to leave before the ball moved.

In the rulebook. When you can’t stop a play, you can try to ban it. In 2025 Green Bay proposed a rule against pushing the runner; after being tabled once, a revised version failed 22–10 on May 21, two votes short of the 24 needed. The league answered by telling its officials to watch more closely for false starts and players lined up in the neutral zone on the play. In 2026 no team proposed a ban, and the push is legal this season.37

By copying. The sincerest response was imitation. Other teams, Buffalo most of all, ran sneaks and pushes in large numbers, and the light-box run game that Philadelphia and others built became one of the league’s standard answers to two-high defenses. And other teams hired the Eagles’ coordinators: Steichen to Indianapolis and Moore to New Orleans as head coaches, and Jonathan Gannon, the 2021–22 defensive coordinator, to Arizona as head coach in 2023. Success exported the people who had built it, which is the other cause of the churn.

What survives

As of the 2026 season, here is where the experiment stands.

  • The head coach and the defense survive. Sirianni is in his sixth season, and Fangio is still the defensive coordinator. The four-man rush philosophy depends on the front office continuing to find linemen who can win one-on-one.
  • The quarterback survives. Hurts, under contract for the long term, is the constant on offense, and so is his ability to make the defense account for him as a runner.
  • The architect does not. Stoutland, the line coach behind every Eagles line since 2013, is gone, and the offense has its fifth coordinator in Sirianni’s six seasons. The most interesting question for the 2026 Eagles is whether the trench identity was a system that outlives its coach, or a person.
  • The push is legal, but its edge has shrunk. This chapter’s data stop at the end of 2025, so here is your baseline: in 2025 the Eagles sneaked on 54% of their 1-yard snaps and converted 65% of those sneaks, against 80% for the rest of the league. Whether the 2026 Eagles, with a new line coach, still call it that often, and whether it climbs back to the league’s rate, is the cleanest test you can run from your couch this season.
TipWatch for it

Trench check, on any Eagles third- or fourth-and-short:

  • Before the snap, guess the call. Hurts under center with two players tight behind him: push. Hurts in the shotgun: almost anything but a sneak. Under center with backs at normal depth: a sneak is still possible, but so is a handoff or a play-action pass.
  • Count the defense’s middle. How many linemen are in the A gaps beside the center? Is there a linebacker standing a couple of yards behind the pile, ready to leap? Did a defensive lineman jump early?
  • Watch the snap, not the pile. On a push that works, the Eagles’ line moves before the defensive linemen have risen out of their stances. On one that fails, the defense moved first.
  • Keep a tally. Calls, conversions, and the distance (inches or a full yard). After a few weeks you will have your own version of Figure 64.4, and you will see the selection problem for yourself.
  • On the Eagles’ defense, count rushers on passing downs. Four, with seven in coverage, is the Fangio default. A fifth rusher means he thinks the four can’t win against this line.

Predict the play

TipPredict the play 1: the 2017 RPO
Show the Python
off = line5() + [O("QB", "QB", GUN, 0.0, "Q"), O("RB", "RB", GUN, -2.2, "R"),
                 O("X", "WR", LINE_D, -17.0, "X"), O("Y", "TE", LINE_D, 4.8, "Y"),
                 O("H", "WR", OFF_BALL, 10.5, "H"), O("Z", "WR", OFF_BALL, 16.5, "Z")]
dfn = dline() + [D("WILL", "LB", 4.8, -2.4, "W"), D("MIKE", "LB", 4.8, 1.6, "M"),
                 D("NB", "NB", 4.4, 6.6, "$"), D("RCB", "CB", 6.0, 16.5, "CB"),
                 D("SS", "SS", 9.0, 11.5, "SS"), D("LCB", "CB", 6.0, -17.0, "CB"),
                 D("FS", "FS", 13.5, -1.0, "FS")]
p = Play(off, dfn, los=own(40), to_go=10)
f = draw(p, lateral=(-20.0, 20.0), window=(-7.5, 16.5), width_in=6.4)
plt.show()
Figure 64.6: First-and-10, the 2017 Eagles in 11 personnel from the shotgun: the tight end (Y) attached to the right tackle, and two receivers (H in the slot, Z wide) outside him. The call is an RPO: inside zone to R, with a quick screen to H attached. The quarterback can count before the snap, and a look at the nickel back after the snap confirms the count.

Hand off or throw? Count before you answer.

Throw the quick screen to H. Count the box first: four linemen, two linebackers, and the nickel back ($), who has walked in to the tight end’s outside shoulder at linebacker depth. That is seven defenders against six blockers (five linemen and Y), so the handoff is a man short. Now count outside the tight end: two receivers (H and Z) against two defenders, the cornerback over Z and the strong safety, who is nine yards deep. Z blocks the corner, H catches the ball, and the nearest unblocked defender is a safety nine yards away.

The count can be made before the snap, and the RPO lets the quarterback check it after: if the nickel steps toward the run at the snap, the screen is open; if he backs out toward H, the box is six against six and the handoff is the play. This is exactly the read the RPO hands a quarterback, and it is why the 2017 Eagles leaned on it with Foles: the defense makes the decision, and the quarterback only has to see it. What would change it: the nickel lined up over H instead of in the box. Then it is six against six inside, and the ball goes to the back. The throw and the run are never both bad, which is the point.

TipPredict the play 2: second-and-6, 2024
Show the Python
off = line5() + [O("QB", "QB", GUN, 0.0, "Q"), O("RB", "RB", GUN, -2.2, "R"),
                 O("Y", "TE", LINE_D, 4.8, "Y"), O("X", "WR", LINE_D, -17.5, "X"),
                 O("H", "WR", OFF_BALL, -10.5, "H"), O("Z", "WR", OFF_BALL, 16.5, "Z")]
dfn = [D("WDE", "DE", 1.0, -4.0, "E"), D("NT", "DT", 1.0, -0.8, "T"), D("DT", "DT", 1.0, 2.3, "T"),
       D("SDE", "DE", 1.0, 5.9, "E"), D("WILL", "LB", 4.8, -2.2, "W"), D("MIKE", "LB", 4.8, 1.4, "M"),
       D("NB", "NB", 4.6, -10.0, "$"), D("LCB", "CB", 7.6, -17.5, "CB"), D("RCB", "CB", 7.6, 16.5, "CB"),
       D("FS", "FS", 12.5, -7.0, "FS"), D("SS", "SS", 12.5, 7.0, "SS")]
p = Play(off, dfn, los=own(45), to_go=6)
f = draw(p, lateral=(-20.0, 20.0), window=(-7.5, 16.5), width_in=6.4)
say(f, p, 8.4, 0.0, "how many in the box?", color=style.INK_2, fontsize=6.8)
plt.show()
Figure 64.7: Second-and-6, the 2024 Eagles in 11 personnel from the shotgun, Barkley beside Hurts, against a nickel defense with both safeties twelve yards deep.

What is the most likely call, and why?

A run: duo or zone to Barkley, quite possibly with a throw attached. Count the box: four linemen and two linebackers, six defenders. The nickel ($) doesn’t count: he is over the slot receiver, about ten yards outside the tackle, too far to fill a gap before the back gets there. The offense has five linemen and a tight end, six blockers, and Hurts as a possible runner. Both safeties start twelve yards deep, so the first defender who can arrive unblocked is two seconds and ten yards away. This is the bet the 2024 Eagles punished all season: they ran on more of their snaps than any other team, mostly against looks like this.

What would change it: a safety walking down toward the line before the snap. Then there are seven in the box against six blockers, and the better play is a throw behind the safety who left, or a run with Hurts reading the extra defender.

TipPredict the play 3: third-and-9 against Fangio
Show the Python
off = line5() + [O("QB", "QB", GUN, 0.0, "Q"), O("RB", "RB", GUN, -2.2, "R"),
                 O("X", "WR", LINE_D, -18.0, "X"), O("Y", "TE", OFF_BALL, 6.5, "Y"),
                 O("H", "WR", OFF_BALL, 11.5, "H"), O("Z", "WR", LINE_D, 17.5, "Z")]
dfn = dline(w=(-5.0, -0.8, 2.4, 5.2)) + [
    D("WILL", "LB", 5.0, -2.6, "W"), D("MIKE", "LB", 5.0, 2.6, "M"), D("NB", "NB", 5.0, 10.0, "$"),
    D("LCB", "CB", 7.0, -18.0, "CB"), D("RCB", "CB", 7.0, 17.0, "CB"),
    D("FS", "FS", 13.0, -7.0, "FS"), D("SS", "SS", 13.0, 7.0, "SS")]
p = Play(off, dfn, los=own(25), to_go=9)
f = draw(p, lateral=(-20.5, 20.5), window=(-7.5, 16.5), width_in=6.4)
plt.show()
Figure 64.8: Third-and-9, Kansas City in 11 personnel from the shotgun, three receivers to the right, against the 2024 Eagles’ nickel: four down linemen, both linebackers at their normal depth of five yards, the nickel over the slot, and both safeties 13 yards deep. Nothing is disguised. Kansas City’s back (R) will stay in to block.

How many will rush? Then count: how many receivers go out against how many defenders in coverage, and how many blockers against how many rushers? Where does the pressure have to come from?

Four will rush, the four linemen; this defense blitzed less than almost any in the league. Now the counts. With the back staying in, Kansas City has six blockers against four rushers, so two blockers are spare and can double the most dangerous rushers. It has four receivers going out against seven defenders in coverage, so every receiver has a defender on him and three more are sitting in the throwing lanes. Nothing quick is open.

So the defense is betting on time. It concedes that the rush will rarely be free; it needs the four to beat their blockers anyway, and it needs the push to come up the middle, because a quarterback can drift away from edge rushers but not from a tackle in his face. That is why Carter and Williams mattered so much in Super Bowl LIX.

Compare the double A-gap mug in the drill at the end of the Zone Blitzes, Fire Zones, and Simulated Pressure chapter: a pressure look shows six to force the offense to keep the back in, which produces this same four-against-seven count. But if the mugged linebackers then drop, the center and guards are freed to double a rusher, so a mug pays off only when the rush runs a twist into a protection that has set the wrong way. Fangio got the count without showing anything. What would change it: Kansas City sending the back out too (five receivers against seven, five blockers against four), or a defense that doesn’t trust its four, which has to blitz and give up a defender in coverage.

Takeaways

  • The Eagles’ decade is one long bet on the lines of scrimmage: elite blockers and pass rushers as the stable core, and the quarterback, the coordinator and the scheme around them allowed to change.
  • 2017 won with a backup quarterback because RPOs gave him simple reads, the line made the run real, and Pederson went for it on fourth down when others kicked. The Philly Special worked by exploiting a defensive rule (nobody covers the quarterback) at the moment the defense was most committed to the run.
  • The Sirianni-era offense ran because Hurts made the defense account for an extra runner and the line could win both the shoving match of duo and the race of outside zone. That made Barkley’s 2,000-yard season possible against the league’s light boxes. The offense held up through three play-callers, which says it rested on what stayed (the line and Hurts) more than on who called the plays.
  • The tush push edge was real but smaller than its reputation. The Eagles’ sneaks converted at about the league’s rate while they called the play far more often than anyone; counting every 1-yard snap, the edge was worth about ten extra first downs in 2023 and only a couple or fewer in 2022, 2024 and 2025. By 2025 the push itself converted below the league, though the Eagles’ 1-yard plays as a whole still matched it.
  • Super Bowl LIX was won with a four-man rush and seven in coverage (no blitzes, by Next Gen Stats’ count), which is possible only for a team whose four linemen can win one-on-one. That scheme was a consequence of draft picks, helped that night by a Kansas City line playing a guard at left tackle.
  • Roster and scheme are one decision. Develop linemen cheaply, pay to keep the good ones, spend first-round picks on pass rushers, and you can run, sneak and rush four. Everything has a price, and the Eagles paid theirs at receiver, at cornerback depth and in the age curve of a veteran line.

Connections

Builds on: The Modern Era (two-high defenses, light boxes and the run game’s return), Red Zone, Goal Line, Two-Point Plays, and Short Yardage (the sneak, the push, the ban vote), RPOs, Zone Running, Gap Schemes, Option Football and Quarters and Match.

Sets up:

If you want to go deeper: Doug Pederson’s memoir, written with Dan Pompei, Fearless: How an Underdog Becomes a Champion (Hachette, 2018), on the 2017 season and the Philly Special; Brian Baldinger’s “Baldy’s Breakdowns” film videos, many of them on Eagles linemen; Jimmy Kempski’s coverage at PhillyVoice and Sheil Kapadia’s writing on the Eagles’ roster building; and the FTN charting data in nflverse, which lets you rebuild Figure 64.4 for any team and any season (the Tendencies chapter shows how).

NoteGo deeper

From simulation to real tracking data. The Philly Special animation is a gridiron simulation written in NFL Big Data Bowl (BDB) coordinates; there is no public tracking data from 2017. The 2025 Big Data Bowl release (2022 season, weeks 1–9) does cover the Eagles’ first big season of tush pushes, ten frames a second before and after the snap, so you can draw real ones with the same code. The data lives on Kaggle and needs your own free login, so the code below (on the website, under “Show the Python”) is not run when the book is built.

Show the Python (real Big Data Bowl tracking; not run in the build)
import pandas as pd
from gridiron import bdb, show_animation

plays = pd.read_csv("data/bdb/plays.csv")
# Eagles quarterback runs on 1 yard to go: the sneaks and pushes of 2022
pushes = plays[(plays["possessionTeam"] == "PHI") & (plays["yardsToGo"] <= 1)
               & plays["playDescription"].str.contains("J.Hurts", na=False)
               & plays["playDescription"].str.contains("up the middle|guard", case=False, na=False)]
print(len(pushes), "candidate pushes")
g, pl = pushes.iloc[0][["gameId", "playId"]]
trk = bdb.load_tracking("data/bdb/tracking_week_*.csv")
one = bdb.prepare(trk, plays, game_id=g, play_id=pl)
show_animation(one, times=[-0.5, 0.0, 0.5, 1.0])

  1. Roseman’s 2015 loss and late-2015 return of roster control: Bleeding Green Nation (Dec. 31, 2015), https://www.bleedinggreennation.com/2015/12/31/10693256/eagles-howie-roseman-tom-donahoe-general-manager-jeffrey-lourie-chip-kelly-fired-power-structure. Johnson’s return for a 14th season: NFL.com (Feb. 2026), https://www.nfl.com/news/longtime-eagles-ot-lane-johnson-to-return-for-14th-season-with-philadelphia. Stoutland’s tenure: the CBS Sports and 6abc reports cited for his departure below.↩︎

  2. Anthony Treash, “The RPO and the Andy Reid coaching tree,” PFF (May 17, 2019): https://www.pff.com/news/pro-the-rpo-and-the-andy-reid-coaching-tree (the Eagles ranked second in RPO usage in 2017, behind the Chiefs; Pederson had been on Reid’s staff in Kansas City from 2013 to 2015).↩︎

  3. Dom Cosentino, “How Nick Foles Did It,” Deadspin (Jan. 24, 2018), citing Pro Football Focus: “on RPOs he’s 15-for-16, with 7.2 yards per attempt”: https://deadspin.com/how-nick-foles-did-it-1822300742/.↩︎

  4. “Eagles offensive tackle Jason Peters has torn ACL and MCL, will miss season,” CBS Sports (Oct. 2017): https://www.cbssports.com/nfl/news/eagles-offensive-tackle-jason-peters-reportedly-tears-acl-and-mcl-will-miss-season; Vaitai’s move to left tackle: 6abc, https://6abc.com/post/eagles-lt-jason-peters-lb-jordan-hicks-out-for-season/2560965/.↩︎

  5. Tim McManus, “Eagles provide roadmap to analytics-driven future of NFL,” ESPN (Sept. 11, 2019): https://www.espn.com/blog/nflnation/post/_/id/300217/eagles-provide-roadmap-to-analytics-driven-future-of-nfl (Paganetti told Pederson before the third-and-goal snap that, on fourth down, “the light is green”).↩︎

  6. This book’s calculation from nflverse play-by-play, 2017 regular season: fourth-down plays recorded as a run or a pass (kicks, kneel-downs and penalties without a play excluded), by offense; conversions from fourth_down_converted.↩︎

  7. The situation (fourth-and-goal from the 1, 0:38 left in the second quarter, Philadelphia leading 15–12) and the result (22–12 at halftime) from nflverse play-by-play for game 2017_21_PHI_NE. The exchange between Foles and Pederson was caught on sideline audio released two days later: “Philly Special,” Wikipedia: https://en.wikipedia.org/wiki/Philly_Special, citing Austin Knoblauch, NFL.com (Feb. 7, 2018).↩︎

  8. Dave Zangaro, “Looking at film of the Philly Special and its origins,” NBC Sports Philadelphia (Feb. 9, 2018): alignments (Smith and Burton stacked on the left, Jeffery alone on the right, Clement taking the snap), the Bears’ version in the 2016 season finale and its name, and Groh’s role: https://www.nbcsportsphiladelphia.com/nfl/looking-at-film-of-the-philly-special-and-its-origins/341755/. Clemson’s earlier version (a 2012 two-point conversion against Georgia Tech) and Reich’s consideration of the play for the NFC Championship: “Philly Special,” Wikipedia, cited above.↩︎

  9. “Mike Pereira agrees: Eagles lined up in illegal formation on ‘Philly Special’ play in Super Bowl,” 98.5 The Sports Hub (Feb. 13, 2018): https://985thesportshub.com/2018/02/13/philly-special-illegal-formation/.↩︎

  10. NFC Championship, January 21, 2018: Philadelphia 38, Minnesota 7. Super Bowl LII, February 4, 2018, U.S. Bank Stadium, Minneapolis: Philadelphia 41, New England 33; Foles 28 of 43 for 373 yards and three touchdowns, and a touchdown catch. The fourth-and-1 (5:39, fourth quarter, own 45, Foles to Ertz for 2 yards) and Ertz’s 11-yard touchdown at 2:25: nflverse play-by-play, game 2017_21_PHI_NE, this book’s check.↩︎

  11. Record, run shares and rushing yards: nflverse play-by-play, 2021 regular season (2–5 after the week 7 loss at Las Vegas; 9–8 final; run share of the Eagles’ runs and passes, weeks 1–7 vs weeks 8–18; 159.7 rushing yards a game, first in the NFL). The play-calling change: “Gannon says he suggested Sirianni give up play-calling in 2021,” NBC Sports Philadelphia: https://www.nbcsportsphiladelphia.com/nfl/philadelphia-eagles/gannon-says-he-suggested-sirianni-give-up-play-calling-in-2021/534748/.↩︎

  12. FTN charting via nflverse (is_rpo), 2022 regular season, runs and passes with a down; this book’s calculation. RPOs shows the full team-by-season chart.↩︎

  13. Sack total and league rank: nflverse play-by-play, 2022 regular season. Historical rank (1984 Bears 72, 1989 Vikings 71, 1987 Bears 70) and the four double-digit sackers (Reddick 16, Sweat 11, Hargrave 11, Graham 11): “2022 Philadelphia Eagles season,” Wikipedia: https://en.wikipedia.org/wiki/2022_Philadelphia_Eagles_season.↩︎

  14. FTN charting via nflverse (n_pass_rushers >= 5), 2022 regular season, dropbacks with a down; this book’s calculation. 2022 is FTN’s first charted season.↩︎

  15. “Mekhi Becton plans to join Eagles on one-year deal, agents say,” ABC7/ESPN (April 2024): https://abc7ny.com/post/mekhi-becton-plans-to-join-eagles-on-one-year-deal-agents-say/14741162/; his move to right guard and 15 starts: “Mekhi Becton,” Wikipedia: https://en.wikipedia.org/wiki/Mekhi_Becton. Mailata’s background, 2018 seventh-round selection and 2024 extension: “Jordan Mailata,” Wikipedia: https://en.wikipedia.org/wiki/Jordan_Mailata. Kelce’s draft slot and six first-team All-Pro selections (2017–2019, 2021–2023): “Jason Kelce,” Wikipedia: https://en.wikipedia.org/wiki/Jason_Kelce.↩︎

  16. Contract: ESPN via 6abc, “Eagles to sign ex-Giants RB Saquon Barkley to 3-year deal, ESPN sources say” (March 2024): https://6abc.com/philadelphia-eagles-saquon-barkley-news-nfl/14514611/. Yards, run share and rushing yards a game: nflverse play-by-play, 2024 regular season and playoffs, this book’s calculation. Ninth 2,000-yard season and the regular-season-plus-playoffs record: “Saquon Barkley,” Wikipedia: https://en.wikipedia.org/wiki/Saquon_Barkley.↩︎

  17. Dave Zangaro, NBC Sports Philadelphia (May 22, 2026), on Mannion preparing to call plays in 2026 as a first-time play-caller: https://www.nbcsportsphiladelphia.com/nfl/philadelphia-eagles/sean-mannion-ready-eagles-offensive-coordinator-play-caller-2026-season-otas-green-bay/734275/.↩︎

  18. Associated Press, “Eagles hire Packers QBs coach Sean Mannion as their 5th offensive coordinator in 5 seasons” (Jan. 29, 2026): https://www.castanetkamloops.net/news/NFL/596857/Eagles-hire-Packers-QBs-coach-Sean-Mannion-as-their-5th-offensive-coordinator-in-5-seasons. Steichen’s and Moore’s head-coaching hires: “Shane Steichen,” https://en.wikipedia.org/wiki/Shane_Steichen; “Kellen Moore,” https://en.wikipedia.org/wiki/Kellen_Moore.↩︎

  19. Record and wild-card score (San Francisco 23, Philadelphia 19, January 11, 2026, in Philadelphia): nflverse load_schedules(), 2025 season; division title: the 2025 NFC seeding (Philadelphia third, as NFC East champion), “2025–26 NFL playoffs,” Wikipedia: https://en.wikipedia.org/wiki/2025%E2%80%9326_NFL_playoffs. Barkley’s 2025 rushing yards: nflverse play-by-play.↩︎

  20. Kuper’s hiring (Feb. 9, 2026), his Vikings tenure and his time on Fangio’s Broncos staff (2019–2021): PhillyVoice, https://www.phillyvoice.com/report-eagles-hire-chris-kuper-new-offensive-line-coach-jeff-stoutland; NBC Sports Philadelphia, https://www.nbcsportsphiladelphia.com/nfl/philadelphia-eagles/chris-kuper-jeff-stoutland-offensive-line-2026-nfl-season/736307/. “Jeff Stoutland leaving Eagles: Heralded OL coach steps away amid offseason of major change for Philadelphia,” CBS Sports (Feb. 2026): https://www.cbssports.com/nfl/news/jeff-stoutland-leaving-philadelphia-eagles-offensive-line-coach-nick-sirianni/; “Eagles offensive line coach Jeff Stoutland says he won’t return next season,” 6abc (Feb. 2026): https://6abc.com/post/philadelphia-eagles-offensive-line-coach-jeff-stoutland-says-he-return-season/18546314/. The lost run-game title and the run-game changes (Inquirer and ESPN reporting): “The end of the Jeff Stoutland era got ugly,” FootballScoop (Feb. 5, 2026): https://www.footballscoop.com/2026/02/05/end-of-jeff-stoutland-era-got-ugly-philadelphia-eagles.↩︎

  21. This book’s calculation from nflverse play-by-play joined to FTN charting (load_ftn_charting(), is_qb_sneak), 2022–2025 regular seasons: runs flagged as sneaks with exactly 1 yard to go (the play-by-play records anything from an inch to a yard as “1”); kneel-downs and two-point tries excluded; a conversion is a first down or a touchdown. “Rest of the league” is every other team’s sneaks pooled. The intervals use the normal approximation for a difference of two proportions.↩︎

  22. This book’s calculation: for each season, the Eagles’ conversion rate on all 1-yard-to-go snaps minus the rest of the league’s (the orange dots), multiplied by the Eagles’ number of such snaps (70 in 2022, 70 in 2023, 82 in 2024, 48 in 2025). It assumes a league-average offense would have converted at the league’s rate on the Eagles’ snaps, which ignores differences in where the ball was spotted.↩︎

  23. This book’s calculation from nflverse play-by-play, regular seasons: EPA per play allowed on runs and passes, by defense, ranked from best (1st) to worst (32nd); 2024 yards allowed, fewest in the league, from the same data.↩︎

  24. “Vic Fangio,” Wikipedia (born August 22, 1958; Saints linebackers coach from 1986; Bears defensive coordinator 2015–2018; Eagles defensive coordinator from January 2024): https://en.wikipedia.org/wiki/Vic_Fangio. Baun’s one-year deal (March 2024) and 2024 first-team All-Pro selection: “Zack Baun,” Wikipedia: https://en.wikipedia.org/wiki/Zack_Baun.↩︎

  25. Dave Zangaro, “Why Eagles are taking a long look at Zack Baun at linebacker this spring,” NBC Sports Philadelphia (2024): https://www.nbcsportsphiladelphia.com/nfl/philadelphia-eagles/why-eagles-are-taking-a-long-look-at-zack-baun-at-linebacker-this-spring/588773/; “Why Eagles’ Vic Fangio knew Zack Baun could play inside LB despite different observation from Howie Roseman,” CBS Sports: https://www.cbssports.com/nfl/news/why-eagles-vic-fangio-knew-zack-baun-could-play-inside-lb-despite-different-observation-from-howie-roseman/.↩︎

  26. FTN charting via nflverse (n_pass_rushers >= 5, the glossary’s definition of a blitz and the one Next Gen Stats uses), 2024 regular season, dropbacks with a down; this book’s calculation. FTN’s own n_blitzers flag counts any rusher who isn’t a defensive lineman, so it also counts simulated pressures (a linebacker rushes, a lineman drops, still four rushers); by that flag the Eagles were 25th, at 24.3%. Kevin Kinkead, “The Eagles Sacked Patrick Mahomes Six Times Without Blitzing Once,” Crossing Broad (Feb. 9, 2025), using a different count, had the Eagles blitzing 20.2% of the time, 27th in the league: https://crossingbroad.com/?p=213401.↩︎

  27. Dave Zangaro, NBC Sports Philadelphia (Feb. 10, 2025), citing Next Gen Stats for zero blitzes on 42 dropbacks, 16 pressures, a 38.1% pressure rate, six sacks (Sweat 2.5, Williams 2, Davis 1, Hunt 0.5) and Sweat’s quote: https://www.nbcsportsphiladelphia.com/nfl/philadelphia-eagles/defensive-line-super-bowl-lix-chiefs-josh-sweat-milton-williams/648656/; Blake McQueary, Medill Reports (Feb. 10, 2025), on the fourth no-blitz game since NGS tracking began and Mahomes’s career-high six sacks: https://news.medill.northwestern.edu/chicago/?p=104930.↩︎

  28. FTN charting (n_blitzers, n_pass_rushers) and FTN-sourced participation (defense_coverage_type, was_pressure) via nflverse, game 2024_22_KC_PHI, Kansas City dropbacks; this book’s calculation. FTN charted 42 Kansas City scrimmage dropbacks. It had exactly four rushers on 40 of all 45 dropbacks including two-point tries and four or fewer on 44; the one exception was a five-man rush on a fourth-quarter two-point try. FTN’s n_blitzers flag marks 1 scrimmage dropback, also in the fourth quarter, with a non-lineman rushing, but only 4 rushers in all: a simulated pressure, not a blitz in the five-rusher sense. FTN’s pressure flag counted 14 pressures, fewer than Next Gen Stats’ 16; the two services define a pressure differently. The regular-season two-high rate is the share of the Eagles’ FTN-labelled 2024 dropbacks charted as Cover 2, 2-man, Cover 4 or Cover 6.↩︎

  29. “Joe Thuney,” Wikipedia (moved to left tackle in Week 15 of 2024 after an injury to D.J. Humphries, and stayed there through the postseason): https://en.wikipedia.org/wiki/Joe_Thuney; “Chiefs to stick with Joe Thuney at left tackle vs. Eagles in Super Bowl LIX,” Arrowhead Pride (Jan. 30, 2025): https://www.arrowheadpride.com/2025/1/30/24355408/chiefs-to-stick-with-joe-thuney-at-left-tackle-vs-eagles-in-super-bowl-lix.↩︎

  30. nflverse play-by-play, game 2024_22_KC_PHI (Hurts’s line; DeJean’s interception at 7:16 of the second quarter; Baun’s at 1:49); MVP: CBS News, https://www.cbsnews.com/amp/news/nfl-mvp-super-bowl-jalen-hurts-eagles. DeJean’s birthday and the 38-yard return: “Super Bowl LIX,” Wikipedia: https://en.wikipedia.org/wiki/Super_Bowl_LIX.↩︎

  31. This book’s calculation from nflverse load_draft_picks(), drafts 2013–2025, rounds 1 and 2; “linemen” are players listed at T, G, C, OL, DE, DT, DL or NT (edge rushers listed as OLB, such as Nolan Smith in 2023, are not counted, which slightly understates every team that drafts 3-4 edge rushers).↩︎

  32. This book’s calculation from nflverse load_contracts() (Over the Cap), using each contract’s season-by-season cap figures for players listed at LT, LG, C, RG or RT, summed by team and season, 2017–2025. Dead money and players without a contract record are missing, so the shares are approximate; the ranks are the more reliable number.↩︎

  33. “Jalen Hurts signs a record 5-year, $255 million contract with the Philadelphia Eagles,” NPR via KUOW (Apr. 17, 2023): https://www.kuow.org/stories/jalen-hurts-signs-a-record-5-year-255-million-contract-with-the-philadelphia-eagles.↩︎

  34. This book’s calculation from nflverse load_participation() (defenders_in_box, FTN-sourced from 2023) joined to play-by-play, 2024–2025 regular seasons, first- and second-down runs and passes by the Eagles.↩︎

  35. “Frankie Luvu’s goal-line ‘timing’ led to Commanders’ flags,” ESPN (Jan. 27, 2025), including Hochuli’s announcement: https://www.espn.com/nfl/story/_/id/43578317/frankie-luvu-goal-line-timing-led-commanders-flags.↩︎

  36. “NFL expected to pass rule prohibiting leaper block attempts on field goals, extra point attempts,” ESPN (March 28, 2017): https://www.espn.com/nfl/story/_/id/19021659/nfl-expected-pass-rule-prohibiting-leaper-block-attempts-field-goals-extra-point-attempts. The current wording is Rule 12, Section 3, Article 1(r) of the NFL rulebook, quoted in the Red Zone chapter.↩︎

  37. The 2025 vote: “Packers’ proposal to ban Eagles’ tush push fails again,” Sports Illustrated (May 21, 2025): https://www.si.com/nfl/packers/packers-proposal-to-ban-eagles-tush-push-fails-again. 2026: “Competition committee co-chairman Rich McKay doesn’t expect tush push ban proposal in 2026,” NFL.com (Feb. 2026): https://www.nfl.com/news/competition-committee-co-chairman-rich-mckay-doesn-t-expect-tush-push-ban-proposal-in-2026; Washington Times (Feb. 24, 2026) on no proposal being submitted: https://www.washingtontimes.com/news/2026/feb/24/nfl-receives-no-tush-push-ban-proposal-year-effort-last-year-ban/.↩︎