Zone Running: Inside Zone, Outside Zone, Split Zone, and the Cutback

Why five linemen step the same way at the snap, and how the running back finds a hole nobody drew

Show the Python (shared helpers for this chapter’s diagrams)
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Ellipse, FancyArrowPatch, FancyBboxPatch, RegularPolygon
from gridiron import (Play, Player, Field, offense, technique, style, show_animation)

OL_NAMES = {"LT": "LT", "LG": "LG", "C": "C", "RG": "RG", "RT": "RT"}
ZONE_GREEN = "#0f7a55"   # darker step of the aqua highlight, for text on the light field
PURPLE = style.SERIES[6]  # a ring colour that is neither offense blue nor defense orange


def named_line(players):
    """Label the five offensive linemen so the reader can follow each one."""
    return [p.moved(label=OL_NAMES[p.key]) if p.key in OL_NAMES else p for p in players]


def ace_condensed():
    """12 personnel: two in-line tight ends (Y right, U left), both receivers off the ball in tight splits."""
    off = named_line(offense("ace"))
    return [q.moved(w=-9.0) if q.key == "X" else (q.moved(w=9.0) if q.key == "Z" else q) for q in off]


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


def secondary(cb_w=15.0):
    """Two corners and two deep safeties (a two-high shell)."""
    sw = min(9.0, cb_w - 1.5)
    return [D("LCB", "CB", 6.5, -cb_w, "CB"), D("RCB", "CB", 6.5, cb_w, "CB"),
            D("FS", "FS", 11.5, -sw, "FS"), D("SS", "SS", 11.5, sw, "SS")]


def even_front(playside=1, sam_w=6.6, cb_w=15.0):
    """A generic four-man even front (named in 05-02), linemen labelled by technique number:
    5-technique, 1-technique, 3-technique, 5-technique, three linebackers, two deep safeties.
    playside=+1 puts the 1-technique on the play side (the offense's right)."""
    s = playside
    return [
        D("PE", "DE", 1.0, technique("5", s), "5"),     # play-side end
        D("PT", "DT", 1.0, technique("1", s), "1"),     # play-side tackle, shaded on the center
        D("BT", "DT", 1.0, technique("3", -s), "3"),    # backside 3-technique
        D("BE", "DE", 1.0, technique("5", -s), "5"),    # backside end
        D("SAM", "SAM", 4.0, s * sam_w, "S"),
        D("MIKE", "MIKE", 4.5, s * 1.6, "M"),
        D("WILL", "WILL", 4.5, -s * 2.6, "W"),
    ] + secondary(cb_w)


def front7(playside=1):
    return [q for q in even_front(playside) if q.key in ("PE", "PT", "BT", "BE", "SAM", "MIKE", "WILL")]


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


def _P(fld, p, d, w):
    return fld.xy(*p.to_abs(d, w))


def branch(fld, p, pts, color=style.THIRD, label=None, label_at=None, lw=2.0, fontsize=8,
           dash=(0, (3, 2.2)), end="arrow"):
    """A dashed 'option' path through absolute (d, w) points, with an arrowhead (or block tee)."""
    xs, ys = _P(fld, p, np.array([q[0] for q in pts]), np.array([q[1] for q in pts]))
    if end == "arrow":
        fld.ax.plot(xs[:-1], ys[:-1], color=color, lw=lw, ls=dash, zorder=6, solid_capstyle="round")
        fld.ax.add_patch(FancyArrowPatch((xs[-2], ys[-2]), (xs[-1], ys[-1]), arrowstyle="-|>",
                                         mutation_scale=11, color=color, lw=lw, zorder=6))
    else:  # a block: dashed line ending in a T-bar
        fld.ax.plot(xs, ys, color=color, lw=lw, ls=dash, zorder=6)
        v = np.array([xs[-1] - xs[-2], ys[-1] - ys[-2]])
        perp = np.array([-v[1], v[0]]) / np.linalg.norm(v) * 0.75
        fld.ax.plot([xs[-1] - perp[0], xs[-1] + perp[0]], [ys[-1] - perp[1], ys[-1] + perp[1]],
                    color=color, lw=lw + 0.6, zorder=6)
    if label:
        x, y = _P(fld, p, *(label_at or pts[-1]))
        fld.ax.text(x, y, label, fontsize=fontsize, color=color, fontweight="bold", ha="center",
                    va="center", zorder=9,
                    bbox=dict(boxstyle="round,pad=0.2", fc=style.SURFACE, ec=color, lw=0.8))


def overtake(fld, p, key, via, end, color=ZONE_GREEN, lw=2.4):
    """An overtake block (dashed green, T-bar end) from `key`'s alignment through `via` to `end`."""
    q = p.players[key]
    branch(fld, p, [(q.d, q.w), *via, end], color=color, end="tee", lw=lw)


def pair_oval(fld, p, d, w, width, height=2.5, color=ZONE_GREEN):
    """A faint oval around a double team (two blockers and their defender)."""
    x, y = _P(fld, p, d, w)
    fld.ax.add_patch(Ellipse((float(x), float(y)), width, height, fc=color, alpha=0.24, ec="none", zorder=1.5))
    fld.ax.add_patch(Ellipse((float(x), float(y)), width, height, fc="none", ec=color, lw=1.8,
                             ls=(0, (4, 2)), zorder=1.6))


def spot(fld, p, d, w, color=style.THIRD):
    """Mark an aiming point with an X."""
    x, y = _P(fld, p, d, w)
    fld.ax.plot([x], [y], marker="X", ms=9, color=color, mec="white", mew=0.8, zorder=9)


def say(fld, p, d, w, text, color=style.INK_2, fontsize=7.5, ha="center"):
    """A short on-field label at (d, w)."""
    x, y = _P(fld, p, d, w)
    fld.ax.text(x, y, text, fontsize=fontsize, color=color, ha=ha, va="center", zorder=9,
                bbox=dict(boxstyle="round,pad=0.18", fc=style.SURFACE, ec="none", alpha=0.9))


def point_to(fld, p, text_at, target, text, color=style.INK_2, fontsize=7):
    """A label with a thin leader line to the player or spot it names."""
    (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="center", va="center", zorder=9,
                    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 clean(ax):
    """Box-zoomed diagrams: drop hash ticks and yard numbers, clip anything outside the window."""
    for ln in list(ax.lines):
        xs, ys = ln.get_data()
        if len(xs) == 2 and ln.get_linewidth() == 0.5 and np.hypot(xs[1] - xs[0], ys[1] - ys[0]) < 1.0:
            ln.remove()
    for t in list(ax.texts):
        if t.get_text().isdigit() and t.get_alpha() == 0.55:   # yard numbers, not technique labels
            t.remove()
        else:
            t.set_clip_on(True)


def draw(p, width_in=5.8, ax=None, **kw):
    """Play.draw, sized for the page, cleaned for a box-sized window."""
    fld = p.draw(width_in=width_in, ax=ax, **kw)
    clean(fld.ax)
    return fld


def play_arrow(fld, p, d, w0, w1, text):
    """A broad 'the play goes this way' arrow at depth d, from w0 to w1."""
    (x0, y0), (x1, y1) = _P(fld, p, d, w0), _P(fld, p, d, w1)
    fld.ax.add_patch(FancyArrowPatch((x0, y0), (x1, y1), arrowstyle="-|>", mutation_scale=16,
                                     color=style.OFFENSE, lw=2.2, zorder=3))
    xm, ym = _P(fld, p, d + 0.9, (w0 + w1) / 2)
    fld.ax.text(xm, ym, text, fontsize=7.5, color=style.OFFENSE_DARK, ha="center", va="center", zorder=4,
                fontweight="bold")


def pdf_build():
    return os.environ.get("RTG_FORMAT", "").lower() in ("pdf", "typst", "print")


MARK_R = 0.6      # frame-strip marker radius in yards: smaller than the static diagrams, so engaged
                  # blockers and defenders (about a yard apart) stay separate in print


def tracking(play):
    df = play.to_tracking()
    df["_id"] = df["displayName"].astype(str)
    return df


def panel(ax, play, df, t, lateral, window, rings=(), down=None):
    """One moment of a simulated play on `ax`: markers, trails of on-screen players, rings, cut fades."""
    tmap = df.groupby("frameId")["time"].first()
    fid = int((tmap - t).abs().idxmin())
    ylo, yhi = sorted((play.ball_y - lateral[0], play.ball_y - lateral[1]))
    fld = Field(ax=ax, orient="vertical", los=play.los, window=window, numbers=False, hashes=False,
                lateral=(ylo, yhi), to_go=play.to_go)
    cur = df[df["frameId"] == fid]
    shown = cur[cur["x"].between(play.los + window[0] + 0.4, play.los + window[1] - 0.4)
                & cur["y"].between(ylo + 0.4, yhi - 0.4)]
    ids = set(shown["_id"])
    trails = df[(df["frameId"] <= fid) & df["_id"].isin(ids) & (df["side"] != "ball")
                & df["x"].between(play.los + window[0], play.los + window[1])]
    for (_, side), g in trails.groupby(["_id", "side"]):        # trails only for players in the panel
        xs, ys = fld.xy(g["x"].values, g["y"].values)
        ax.plot(xs, ys, color=style.OFFENSE if side == "off" else style.DEFENSE, lw=0.9, alpha=0.4, zorder=3)
    ppy = fld.pts_per_yard()
    downed = [k for k, t_down in (down or {}).items() if t >= t_down]
    for _, r in shown.iterrows():
        x, y = (float(v) for v in fld.xy(r["x"], r["y"]))
        if r["side"] == "ball":
            ax.add_patch(Ellipse((x, y + 0.45), 0.7, 0.42, fc=style.BALL, ec="white", lw=0.5, zorder=9))
            continue
        lab = str(r.get("label", "") or "")
        if r["side"] == "off":
            ax.add_patch(Circle((x, y), MARK_R, fc=style.OFFENSE, ec="white", lw=0.6, zorder=8))
            tc = "white"
        else:
            gone = r["displayName"] in downed            # cut to the ground: faded, under the blockers
            ax.add_patch(RegularPolygon(
                (x, y), 4, radius=MARK_R * 1.3, orientation=np.pi / 4, fc=style.DEFENSE_TINT,
                ec=style.DEFENSE, lw=1.0, zorder=6 if gone else 8, alpha=0.4 if gone else 1.0))
            tc = style.MUTED if gone else style.INK
        fs = max(4.0, min(8.0, ppy * (0.8 if len(lab) <= 1 else 0.6)))
        ax.text(x, y, lab, ha="center", va="center", fontsize=fs, color=tc, fontweight="bold",
                zorder=10 if tc != style.MUTED else 6.5)
    for key, col in rings:
        r = cur[cur["displayName"] == key].iloc[0]
        x, y = fld.xy(r["x"], r["y"])
        ax.add_patch(Circle((float(x), float(y)), 1.05, fc="none", ec=col, lw=1.7, zorder=7))
    if downed:                                           # one "cut" tag beside them (backside)
        rr = cur[cur["displayName"].isin(downed)]
        x, y = fld.xy(rr["x"].mean(), rr["y"].max())
        ax.text(float(x) - 0.9, float(y), "cut", fontsize=7, color=style.DEFENSE_DARK, ha="right",
                va="center", fontweight="bold", zorder=12,
                bbox=dict(boxstyle="round,pad=0.1", fc=style.SURFACE, ec="none", alpha=0.85))
    return fld


def strip(play, times, lateral=(-12, 12), window=(-8, 13), ncols=3, notes=None, rings=(("RB", style.THIRD),),
          down=None, title=None, width_in=6.5):
    """Frame strip with a fixed, box-sized window so markers stay legible in print.
    rings: players to circle in every frame; down: {key: t} players cut to the ground from time t."""
    df = tracking(play)
    nrows = int(np.ceil(len(times) / ncols))
    pw = width_in / ncols
    span_w, span_d = lateral[1] - lateral[0], window[1] - window[0]
    fig, axes = plt.subplots(nrows, ncols, squeeze=False,
                             figsize=(width_in, nrows * (pw * span_d / span_w + (0.36 if notes else 0.2))))
    for ax in axes.flat[len(times):]:
        ax.axis("off")
    for i, (ax, t) in enumerate(zip(axes.flat, times)):
        panel(ax, play, df, t, lateral, window, rings, down)
        ax.set_title(f"{i + 1}.  " + ("snap" if abs(t) < 1e-6 else f"{t:+.2f} s".rstrip("0")),
                     fontsize=8.5, color=style.INK_2, loc="left")
        if notes:
            ax.text(0.5, -0.03, notes[i], transform=ax.transAxes, ha="center", va="top",
                    fontsize=7.5, color=style.INK)
    if title:
        fig.suptitle(title, x=0.01, ha="left", fontsize=11, fontweight="bold", color=style.INK)
    fig.tight_layout(h_pad=1.3 if notes else 0.6, w_pad=0.6)
    return fig


def video(play, times, notes=None, lateral=(-12, 12), window=(-8, 13), rings=(("RB", style.THIRD),),
          down=None, width_in=5.6):
    """Web version of the strip: the same panel drawn at every frame, with the strip's notes as captions
    (each note shows from its frame's time on), the rings and the cut fades."""
    import shutil
    from matplotlib import animation
    from IPython.display import HTML, display
    df = tracking(play)
    span_w, span_d = lateral[1] - lateral[0], window[1] - window[0]
    fig, ax = plt.subplots(figsize=(width_in, width_in * span_d / span_w + 0.4))
    tmap = df.groupby("frameId")["time"].first()

    def update(fid):
        ax.clear()
        t = float(tmap[fid])
        panel(ax, play, df, t, lateral, window, rings, down)
        txt = ("snap" if abs(t) < 0.05 else f"{t:+.1f} s")
        if notes:
            cur = [n for tt, n in zip(times, notes) if tt <= t + 1e-6]
            txt += ("   " + cur[-1]) if cur else ""
        ax.set_title(txt, fontsize=9, color=style.INK, loc="left")
        return []

    anim = animation.FuncAnimation(fig, update, frames=sorted(df["frameId"].unique()), interval=100)
    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 zone_animation(play, times, notes=None, **kw):
    """Video on the website; a numbered, captioned frame strip in the PDF."""
    if pdf_build():
        strip(play, times, notes=notes, **kw)
        plt.show()
    else:
        video(play, times, notes=notes, **kw)

Second-and-7, early in the second quarter. The offense lines up with two tight ends, and at the snap all five offensive linemen take the same step to their right, in unison, like a chorus line. The running back takes the handoff on a tight path toward the right tight end, and for a moment it looks like he is going to be swallowed by a pile of bodies. Then he plants his foot, cuts back to the left, and runs through a hole near the center that was not there half a second earlier. Twelve yards. The announcer says “great vision.” He is right, but it is not the whole story. That hole was not luck and the cut was not improvised. The play was built to produce it. This chapter shows you how.

You’ll be able to:

NoteYou’ll need
  • The Language of the Run Game: gaps (A, B, C, D outward from the center), technique numbers for where a defensive lineman lines up (a 5-technique is on the tackle’s outside shoulder, a 3-technique on the guard’s outside shoulder, a 1-technique shaded on the center), covered and uncovered linemen, play-side and backside, and the core blocks: reach, cut-off, combo (double team) and kick-out.
  • Downs, Distance, and Field Position: EPA (expected points added: how much a play changed the offense’s expected score) and success rate (the share of plays with positive EPA). You need these only for the numbers section near the end.

How to read the diagrams. Offense is blue circles, defense orange squares. Left and right always mean the offense’s left and right. On offense, LT, LG, C, RG and RT are the five linemen, Q the quarterback and R the running back. Y is the main tight end, lined up on the line. U is a second tight end, on the left; zone teams love two-tight-end sets partly because the U gives the backside a blocker, as you will see. H is the “move” player from 02-02: a slot receiver in some pictures, an off-the-ball tight end (an H-back) in others, and each caption says which. X and Z are wide receivers. On defense, linemen are labelled by technique number, S, M and W are the Sam, Mike and Will linebackers, CB is a cornerback, and FS and SS are the safeties. Lines ending in a short bar are blocks, arrows are paths, and the thick dark arrow is the ball carrier.

Why block an area instead of a man?

Start with the problem zone blocking solves. On a classic “man” (or gap) blocking run, the coach draws the play against the front he expects: the right guard blocks that defensive tackle, the tight end blocks that end. That works beautifully until the defense moves. Defensive linemen do not stand still. They slant (step sideways into a different gap at the snap), they stunt (two linemen swap gaps), and linebackers blitz into gaps the play assumed would be empty. A blocker assigned to a man who has just left becomes a spectator, and the man who arrived in his place is unblocked.

Zone blocking flips the question. Instead of “which defender is mine?”, each lineman asks “who comes into my area?” Every lineman steps the same direction at the snap, and whoever enters the space he is responsible for is his man. If the defensive tackle slants away, the guard simply keeps moving and picks up whoever replaced him.

Notice what zone blocking is not. Linemen are not blocking “grass.” They block people, every time. What changes is how each lineman decides who that person is: by a rule applied after the snap, not by a name written on the play card.

That rule-based design has a second consequence that makes zone runs feel different to watch. Because nobody knows before the snap exactly where the hole will be, the running back has to find it. The line’s job is to create a moving wall and get the defense flowing sideways; the back’s job is to read where that wall cracks. A zone run is half a blocking scheme and half a running back’s decision. You will see both halves in this chapter.

ImportantWhy it exists

Zone blocking exists because defenses move. Assigning blockers to areas by rule means a slant, a stunt or a late shift does not leave a defender unblocked by surprise, the way it can when blockers are assigned to names. That is a promise about assignments, not about winning: a defender who moves fast enough can still beat his blocker physically, and you will see later which kinds of movement hurt zone most. The price of the scheme: zone blocks are rarely knock-down, drive-him-five-yards blocks. Zone teams accept “get in the way and keep moving” in exchange for never losing track of a defender. And because the hole is not fixed, the play depends on a running back who can read it.

Gap schemes (power, counter and their relatives) are the other great family of run plays and make the opposite trade, a fixed hole with extra blockers pulled to it. Most NFL teams run both; 03-03 covers when coaches choose which.

The three rules: step, covered or uncovered, climb

Every zone play, inside or outside, runs on the same three rules. Learn these and you can draw a zone play against any front.

Rule 1: everyone steps play-side. At the snap, all five linemen (and the tight ends) take their first step toward the side the play is going. On a broadcast this is the single clearest tell of a zone run: the whole line moves the same direction together. On a gap run, by contrast, linemen block in different directions and at least one usually pulls.

Rule 2: covered or uncovered decides your job. You met these words in 03-01; here is how zone teams count them. A lineman is covered if a defensive lineman is head-up on him or shaded to his play-side, that is, sitting in the gap he is stepping into. He blocks that man. A defender shaded to a lineman’s backside belongs to the neighbor on that side, not to him. A lineman with nobody head-up or play-side of him is uncovered. He does not stand around: his first step is still play-side, but his hands go to the defender in the gap on his backside, the man his covered neighbor is blocking, while his eyes find the linebacker behind that defender. Coaches count this in slightly different ways (some staffs call a lineman covered whenever anyone is shaded on him), but the pairs and the jobs come out the same.1

Rule 3: double-team to the second level. That help is the heart of zone blocking. When a covered and an uncovered lineman both have hands on the same defensive lineman, they form a combo block (a double team). Two men move one defensive lineman, and while they do it both keep their eyes on the linebacker behind him. When the linebacker commits to a gap, one of the two linemen comes off the double team and “climbs” to block him, leaving the other to finish the defensive lineman alone. The double team gets you movement; the climb gets you the second level (the linebackers).

Which of the two climbs? Usually the uncovered man, the one who started with his eyes on the linebacker; the covered man’s job is the defensive lineman, and he finishes him. When the climber leaves varies by coach: in one survey of line coaches, the largest group taught linemen to come off as soon as they saw the linebacker run over the top of the double team or underneath it.2 Come off too early and the defensive lineman splits the double team; too late and the linebacker is already in the hole.

Edge cases. Three situations the rules seem not to cover come up in this chapter’s pictures and drills:

  • Two uncovered linemen side by side. An uncovered lineman helps the covered man on his backside. If his backside neighbor is uncovered too, there is nobody to help, so he skips the double team and climbs straight to the nearest linebacker.
  • The last man on the play side, with a defender outside him (a tight end with an end lined up on his outside shoulder). He is covered, and there is no play-side neighbor to help him, so he has to block that man alone. That is the hardest block in zone, and it changes where the play hits.
  • The last man on the backside, with a defender outside him. Nobody needs to reach a backside defender; the job on the backside is to stop chasers. So the last backside blocker steps inside and protects the gap inside him (coaches call it hinging, swinging shut like a door), and the man outside him is left to the quarterback’s fake or read. That outside man is the “unblocked backside end” you will meet again and again.

The front in the next few pictures is a common four-man even front: four defensive linemen, none of them head-up on the center. Its name and its variations belong to the defense’s side of the book, in 05-02; here it is just a front to practise on.

Show the Python
off = [q for q in named_line(offense("singleback")) if q.key in OL_NAMES or q.key == "Y"]
p = Play(off, front7(+1), los=35, to_go=None, title="Zone rules: who is covered? (play going right)")
cov = {"LT": "covered", "LG": "uncovered", "C": "covered", "RG": "uncovered", "RT": "covered",
       "Y": "uncovered"}
fld = draw(p, lateral=(-8, 8.5), window=(-4.6, 8.8))
play_arrow(fld, p, 6.4, -4.5, 4.5, "first step: everyone goes right")
for k, v in cov.items():
    d = -1.9 if k in ("LT", "C", "RT") else -2.9
    say(fld, p, d, p.players[k].w, v, fontsize=7.5,
        color=style.DEFENSE_DARK if v == "covered" else ZONE_GREEN)
for (dw, tgt, txt) in [((2.6, -5.6), "BT", "in LT's\nplay-side gap"), ((2.6, -0.9), "PT", "in C's\nplay-side gap"),
                       ((2.6, 7.0), "PE", "in RT's\nplay-side gap")]:
    t = p.players[tgt]
    point_to(fld, p, dw, (t.d, t.w), txt, fontsize=6.6)
plt.show()
Figure 16.1: The zone rules against an even front, play going right. A lineman is covered if a defender is head-up on him or in the gap he is stepping into. The 3-technique lines up on the LG’s outside shoulder, but that is the LG’s backside, so the 3 belongs to the LT. Each uncovered lineman will help the covered man on his backside and look for a linebacker.

Work through Figure 16.1 from left to right, play going right. The left tackle’s play-side gap is the B gap between him and the left guard, and the 3-technique sits in it: the LT is covered. The left guard has nobody head-up on him and nobody in his play-side gap (the A gap to his right): he is uncovered, so he helps the LT on the 3-technique and looks for the Will linebacker. The center has the 1-technique in his play-side gap: covered. The right guard is uncovered, so he helps the center and looks for the Mike. The right tackle has the 5-technique in his play-side gap: covered. The tight end is uncovered, so he helps the right tackle on the 5-technique and looks for the Sam.

Two things are worth noticing. First, the rules found three natural double teams (LT and LG on the 3, C and RG on the 1, RT and Y on the 5) without the coach drawing them; a different front would produce different pairs from the same rules, which is exactly the point. Line coaches give these pairs short code names so two linemen can tell each other “we’re together on this one” before the snap; the names vary by staff. Second, the defender who lines up farthest from the play on the backside, the left 5-technique, is not on anyone’s list. Zone plays almost always leave someone unblocked on the backside. Much of this chapter is about how the offense deals with him.

Who decides all this? Before every snap the center usually identifies the front out loud and makes a “Mike” call: he points out one linebacker and names him the Mike for this play, so all five linemen count defenders from the same starting point and nobody disagrees about which linebacker is whose (how lines use that call in pass protection is in 04-02). The linemen then confirm their pairs with one-word calls. When a pair gets it wrong, two linemen block the same man, or nobody blocks one, and you see a defender in the backfield untouched at the snap.

CautionCommon misconception

“Zone linemen just block whoever is in front of them.” Not quite. A lineman whose man is directly in front of him but shaded to the backside is uncovered under zone rules, because what matters is the gap he is stepping into. That is why two linemen facing the same front can get different jobs depending on which way the play goes, and why zone teams spend hours of practice on “who’s covered?” against every front they might see.

The payoff: movement gets picked up

Now the claim this chapter opened with, in one picture. In Figure 16.2 the defense runs a simple pressure at the snap: the 1-technique slants from the center’s right shoulder into the gap on his left, and the Mike linebacker blitzes into the gap the 1-technique just left. On the left, the run is blocked by name: the center was told “block the 1,” the right guard “block the Mike.” On the right, the same run is blocked by zone rules.

Show the Python
def movement_play(zone):
    off = [q for q in named_line(offense("singleback")) if q.key in OL_NAMES or q.key in ("Y", "QB", "RB")]
    p = Play(off, front7(+1), los=35, to_go=None)
    go_to(p, "PT", (0.9, -0.8), "path", speed=2.2)                   # the 1 slants into the left A gap
    for k in ("LT", "RT", "Y"):
        go_to(p, k, (-0.3, p.players[k].w + 0.5), speed=1.5)         # everyone else: a step right
    if zone:
        go_to(p, "MIKE", (0.95, 0.8), "path", speed=5.0)             # the Mike blitzes the right A gap ...
        go_to(p, "LG", (0.05, -0.8), speed=2.0, via=[(-0.5, -1.2)])  # LG: the 1 came into his gap
        go_to(p, "C", (0.05, 0.75), speed=2.0, via=[(-0.5, 0.35)])   # C: the Mike came into his gap
        go_to(p, "RG", (2.6, 2.4), speed=3.0, via=[(-0.4, 2.0)])     # RG: nobody came, so he climbs
    else:
        go_to(p, "MIKE", (-2.0, 0.9), "path", speed=6.0)             # ... and runs through untouched
        go_to(p, "C", (0.1, -0.55), speed=2.0, via=[(-0.4, -0.1)])   # C chases "his" man left, late
        go_to(p, "RG", (3.2, 1.9), speed=3.6, via=[(-0.2, 1.8)])     # RG climbs to the Mike's old spot
        go_to(p, "LG", (2.6, -2.4), speed=3.0, via=[(-0.3, -1.6)])   # LG goes to the Will as drawn
    return p


fig, axes = plt.subplots(1, 2, figsize=(6.6, 3.6))
for ax, zone, ttl in [(axes[0], False, "Blocked by name"), (axes[1], True, "Blocked by zone rules")]:
    p = movement_play(zone)
    f = panel(ax, p, tracking(p), 1.05, lateral=(-6.0, 6.0), window=(-4.5, 6.5),
              rings=(("PT", style.DEFENSE), ("MIKE", style.DEFENSE)))
    if zone:
        point_to(f, p, (-3.2, -3.6), (0.05, -0.8), "LG: the 1 came\ninto my gap", color=ZONE_GREEN, fontsize=6.8)
        point_to(f, p, (-3.2, 3.4), (0.05, 0.75), "C: the Mike came\ninto my gap", color=ZONE_GREEN, fontsize=6.8)
        point_to(f, p, (4.6, 4.4), (2.6, 2.4), "RG: nobody came,\nso he climbs", fontsize=6.8)
    else:
        point_to(f, p, (-3.4, 3.6), (-2.0, 0.9), "Mike: unblocked", color=style.DEFENSE_DARK, fontsize=6.8)
        point_to(f, p, (-3.2, -3.6), (0.1, -0.55), "C chases\n\"his\" man", fontsize=6.8)
        point_to(f, p, (5.0, 4.0), (3.2, 1.9), "RG: to where the\nMike used to be", fontsize=6.8)
    ax.set_title(ttl + " (1 second after the snap)", fontsize=8.5, loc="left", color=style.INK, fontweight="bold")
fig.tight_layout(w_pad=0.6)
plt.show()
Figure 16.2: Why zone exists. The same defensive movement against two blocking plans, play going right, one second after the snap (faint lines are where each player came from; the two moving defenders are ringed). The 1-technique slants left and the Mike blitzes the gap he left. Left, blocking by name: the center chases his man across the formation, the right guard climbs to where the Mike used to be, and the Mike runs through untouched. Right, zone rules: every lineman steps right and blocks whoever enters his play-side gap, so the left guard picks up the slanting 1 and the center picks up the blitzing Mike.

The zone line did not guess the pressure; it did not have to. Each lineman’s question (“who enters my play-side gap?”) is answered after the snap, so whatever arrives gets blocked. One coaching manual describes exactly this case: when the defensive lineman slants into the uncovered lineman’s gap, the uncovered man simply takes him.3 That is the promise zone makes. It is not a promise to win every block, as you will see when the movement goes with the line instead of against it.

Inside zone: the downhill version

Inside zone is the zone play that attacks the middle of the line. The linemen take short, firm steps play-side (more forward than sideways), the double teams try to drive the defensive linemen backward, and the running back aims between the guard and tackle.

That target has a name. The aiming point is the spot the running back’s first steps point at. On inside zone it is usually the play-side guard’s outside hip, the B gap (some teams teach the A gap; it varies with the team and with whether the quarterback is under center or in the shotgun). The aiming point is not necessarily where the back will end up. It is where he starts, so that the defense has to respect the play-side gaps and the back can read the blocks from there.

Show the Python
off = named_line(offense("singleback"))
p = Play(off, even_front(+1), los=35, to_go=10, title="Inside zone right vs an even front")
p.block("C", pts=[(0.9, 0.5)])                        # C on the 1 ...
p.block("RG", pts=[(0.8, -0.8), (4.3, -0.4)])         # ... RG helps, then climbs to the Mike
p.block("LT", pts=[(0.9, 0.7)])                       # LT on the 3 ...
p.block("LG", pts=[(0.8, -0.6), (4.3, -0.8)])         # ... LG helps, then climbs to the Will
p.block("RT", pts=[(0.9, 0.6)])                       # RT on the 5 ...
p.block("Y", pts=[(0.6, -0.6), (3.6, 1.5)])           # ... Y helps, then climbs to the Sam
p.path("QB", [(-0.6, 0.6), (-1.9, 0.9)], speed=3.0)   # open and hand off ...
p.path("QB", [(-2.6, -5.5)], speed=4.0, delay=0.2)    # ... then fake a bootleg the other way
p.run("RB", [(3.0, 1.8), (7.0, 2.4), (13.0, 2.6)])
p.handoff("RB", t=0.75)
p.highlight("RB"); p.highlight("BE", color=style.DEFENSE)
fld = draw(p, width_in=6.2, lateral=(-12, 12), window=(-8, 13))
for d, w, wd in [(0.15, -2.4, 3.7), (0.15, 0.8, 3.7), (0.15, 4.0, 3.5)]:
    pair_oval(fld, p, d, w, wd, 3.2)
spot(fld, p, -1.7, 2.25)
say(fld, p, -3.0, 6.4, "aiming point:\nplay-side B gap", color=ZONE_GREEN, fontsize=7)
say(fld, p, 3.0, -8.4, "unblocked: the QB's\nfake tries to hold him", color=style.DEFENSE_DARK, fontsize=7)
say(fld, p, -4.2, -8.6, "QB: hand off,\nthen fake a boot", color=style.OFFENSE_DARK, fontsize=7)
say(fld, p, 8.0, -0.6, "double teams;\none man climbs to a LB", fontsize=7)
plt.show()
Figure 16.3: Inside zone right against the even front. The three green ovals are the double teams the rules produced (LT and LG on the 3, C and RG on the 1, RT and Y on the 5); in each, the uncovered man climbs to a linebacker (the T-bars at W, M and S). The back aims for the play-side B gap (green X). The left 5-technique (ringed) is unblocked. H is a slot receiver on the left, too wide to block that end; the wide receivers X and Z are outside the picture.

Why build a run this way? Because the double teams are where inside zone wins. Two 300-pound men on one defensive lineman can move him, and moving the defensive tackles off the line of scrimmage is what opens everything else. The linebackers then face an impossible choice. If a linebacker fills the play-side B gap early, the climbing lineman meets him there and walls him toward the sideline, and the back cuts just inside that block, into the gap the linebacker left. If he waits, the double team is still moving his teammate backward and the back gets downhill before anyone arrives.

What about the unblocked backside end? Count the box in Figure 16.3: six blockers (five linemen and the tight end) against seven defenders. One defender is always left over, and inside zone chooses the one with the longest way to go to the ball: the end farthest from the play. That does not make him harmless. If he simply chases down the line, he can tackle a back who cuts back toward him. After the handoff the quarterback fakes a bootleg (a rollout the other way, which you will meet properly near the end of the chapter) to make him hesitate; that is the only help plain inside zone gives against him. The H standing on that side in the picture is a slot receiver, too far out to block him. Later sections show the ways teams deal with him: a second tight end to block him (the U in the two-tight-end pictures), a crossing tight end to kick him out (split zone), or the quarterback reading him and keeping the ball, the zone read of 03-04.

What inside zone gives up: it is a grind-it-out play. It needs linemen strong enough to move a defensive tackle with help, and when the defense wins those double teams (a big, penetrating defensive tackle who splits the double team) the play dies in the backfield. Its average gain is modest; its virtue is that it is hard to make go badly, and it sets up everything else.

Outside zone: get the defense running sideways

Outside zone, also called wide zone, has the same rules and a different intent. Inside zone wants to move the defense backward; outside zone wants to move it sideways. The linemen take a lateral first step (some coaches teach a “bucket step,” opening the hips and stepping slightly back to gain width) and run, trying to get their heads across the play-side shoulder of the defender in front of them. “Head across” is literal, and it is the whole idea of outside zone: a blocker whose helmet and shoulders are on the play-side of a defender is standing between that defender and the ball, so the defender can only go inside, away from where the back is heading. A blocker whose head ends up on the inside has only got in the defender’s way; the defender can still run around him toward the ball. The running back’s aiming point moves out to the outside leg of the tight end (or of the tackle, if there is no tight end on that side).

That difference is the one you can see from the stands, and Figure 16.4 puts the two side by side.

Show the Python
fig, axes = plt.subplots(1, 2, figsize=(6.6, 3.1))
for ax, (ttl, step, track, aim, note) in zip(axes, [
        ("Inside zone: steps go up", (1.6, 0.7), [(-4.0, 1.8), (-1.0, 2.4)], (0.0, 2.4), "aims at the\nB gap"),
        ("Outside zone: steps go across", (0.5, 1.5), [(-4.3, 2.6), (-1.4, 5.1)], (-0.2, 5.5), "aims at the\nY's outside leg")]):
    off = [q for q in ace_condensed() if q.key not in ("X", "Z")]
    p = Play(off, None, los=35, to_go=None)
    go_to(p, "RB", track[-1], "run", via=track[:-1])
    p.highlight("RB")
    f = draw(p, ax=ax, lateral=(-7.5, 9.5), window=(-8, 3.8), title=False)
    for k in ("U", "LT", "LG", "C", "RG", "RT", "Y"):         # each lineman's first step, exaggerated
        q = p.players[k]
        (x0, y0), (x1, y1) = _P(f, p, 0.15, q.w), _P(f, p, 0.15 + step[0], q.w + step[1])
        ax.add_patch(FancyArrowPatch((float(x0), float(y0)), (float(x1), float(y1)), arrowstyle="-|>",
                                     mutation_scale=9, color=style.OFFENSE_DARK, lw=1.6, zorder=6))
    spot(f, p, *aim)
    say(f, p, -3.2, 6.4 if aim[1] < 3 else 7.6, note, color=ZONE_GREEN, fontsize=7)
    say(f, p, 2.9, -5.0, "first step", color=style.OFFENSE_DARK, fontsize=7)
    ax.set_title(ttl, fontsize=9, loc="left", color=style.INK, fontweight="bold")
fig.tight_layout(w_pad=0.6)
plt.show()
Figure 16.4: How to tell them apart in the first half-second. Inside zone (left): short, forward steps, and the back’s first steps point at the guard-tackle gap. Outside zone (right): flat, sideways steps, the whole line drifting toward one sideline, and the back running at the tight end’s outside leg. On the broadcast camera, watch the linemen’s helmets: up, or across.

Now look at all eleven jobs on outside zone in Figure 16.5 before watching the play move.

Show the Python
def oz_play():
    """Outside zone right, simulated for the frame strip and video."""
    p = Play(ace_condensed(), even_front(+1, cb_w=10.0), los=35, to_go=10)
    # the defense reacts: the play-side end fights to stay outside, linebackers flow
    go_to(p, "PE", (1.4, 6.5), "path", speed=2.0)
    go_to(p, "PT", (1.45, 1.55), "path", speed=1.6)
    go_to(p, "BT", (1.2, -1.6), "path", speed=1.4)
    go_to(p, "BE", (1.0, -3.0), "path", speed=1.6)
    go_to(p, "SAM", (3.6, 8.1), "path", speed=2.0)
    go_to(p, "MIKE", (3.1, 2.6), "path", speed=2.0, delay=0.3)
    go_to(p, "WILL", (3.4, 0.9), "path", speed=2.6, delay=0.2)
    go_to(p, "FS", (9.0, -2.5), "path", speed=4.0, delay=0.4)
    go_to(p, "SS", (7.5, 7.0), "path", speed=4.0, delay=0.4)
    go_to(p, "LCB", (12.0, -10.0), "path", speed=5.0)
    go_to(p, "RCB", (5.4, 9.6), "path", speed=1.5)
    go_to(p, "Y", (0.3, 5.3), speed=2.0, via=[(-0.2, 5.0)])     # hands on the 5 ...
    go_to(p, "Y", (2.8, 7.7), speed=3.0, delay=0.1)             # ... then climb to the Sam
    go_to(p, "RT", (0.9, 5.9), speed=2.2, via=[(-0.5, 4.0)])    # overtake the 5 and ride him wide
    go_to(p, "RG", (0.4, 1.9), speed=2.0)                       # hands on the 1 ...
    go_to(p, "RG", (2.6, 3.2), speed=2.6, delay=0.1)            # ... then wall off the Mike
    go_to(p, "C", (0.55, 2.3), speed=2.2, via=[(-0.4, 0.9)])    # overtake the 1, ending play-side of him
    go_to(p, "LG", (2.5, 0.6), speed=2.6, via=[(-0.4, -0.9)])   # climb to the Will
    go_to(p, "LT", (0.4, -2.2), speed=2.2, via=[(-0.6, -2.6)])  # cut off the 3
    go_to(p, "U", (0.2, -3.6), speed=2.2, via=[(-0.6, -4.2)])   # cut off the end
    go_to(p, "Z", (4.4, 9.4), speed=4.0, via=[(2.8, 9.8)])      # stalk the corner
    p.route("X", [(0, 0), (12, -0.5)])                          # run the corner off
    go_to(p, "QB", (-3.7, 1.7), "path", speed=2.8)              # reverse pivot to a deep mesh
    go_to(p, "QB", (-6.0, -4.5), "path", speed=4.0, delay=0.15)
    go_to(p, "RB", (6.6, 4.4), "run", speed=5.2,
          via=[(-4.4, 2.4), (-1.4, 5.1), (0.4, 4.4)])           # press the Y's outside leg, cut up
    p.handoff("RB", t=0.75)
    return p


p = Play(ace_condensed(), even_front(+1, cb_w=10.0), los=35, to_go=10,
         title="Outside zone right vs an even front: all 11 jobs")
go_to(p, "Y", (2.9, 6.8), via=[(0.1, 4.6)])            # hands on the 5, climb to the Sam
go_to(p, "RG", (3.5, 2.0), via=[(0.3, 1.25)])          # hands on the 1, climb to the Mike
go_to(p, "LG", (3.6, -1.9), via=[(-0.4, -0.9)])        # climb to the Will
go_to(p, "LT", (0.6, -1.7), via=[(-0.4, -2.6)])        # cut off the 3
go_to(p, "U", (0.6, -3.3), via=[(-0.4, -4.1)])         # cut off the end
go_to(p, "Z", (5.4, 10.0), via=[(3.0, 10.4)])          # stalk the corner
p.route("X", [(0, 0), (11, 0)])                        # run the corner off
go_to(p, "QB", (-3.6, 1.8), "path", speed=3.2)
go_to(p, "QB", (-6.0, -5.0), "path", speed=4.0, delay=0.15)
go_to(p, "RB", (2.5, 5.3), "run", via=[(-4.3, 2.6), (-1.3, 4.9)])
p.handoff("RB", t=0.7)
p.highlight("RB")
fld = draw(p, width_in=6.4, lateral=(-11, 11), window=(-8, 13.5))
overtake(fld, p, "RT", [(-0.4, 3.9), (0.1, 5.0)], (0.9, 5.6), lw=2.6)    # RT overtakes the 5
overtake(fld, p, "C", [(-0.4, 0.5), (0.1, 1.3)], (0.9, 1.8), lw=2.6)     # C overtakes the 1
spot(fld, p, -1.1, 5.4)
say(fld, p, -4.6, 7.4, "aiming point:\noutside leg of Y", color=ZONE_GREEN, fontsize=7)
say(fld, p, 8.6, 1.6, "dashed green = overtake: C takes\nover the 1, RT the 5, so RG and Y\ncan climb",
    color=ZONE_GREEN, fontsize=6.8)
point_to(fld, p, (-2.8, -7.4), (0.6, -3.3), "backside\ncut-offs", fontsize=6.8)
say(fld, p, -6.6, -6.2, "QB: fake the\nother way", fontsize=6.8, color=style.OFFENSE_DARK)
point_to(fld, p, (8.4, 7.4), (5.4, 10.0), "stalk", fontsize=6.6, color=style.OFFENSE_DARK)
point_to(fld, p, (6.4, -6.6), (6.4, -9.0), "run off", fontsize=6.6, color=style.OFFENSE_DARK)
plt.show()
Figure 16.5: Outside zone right vs an even front: all eleven jobs. Play-side, two reach-and-overtake pairs: the Y and the RG get their hands on the 5 and the 1 first, then climb to the Sam and Mike, while the RT and the C race flat and take those defenders over (dashed green, ending play-side of each defender). Backside, the LT and U cut off the 3 and the end, and the LG climbs to the Will. Z stalk-blocks his cornerback; X runs his cornerback off. The quarterback hands off and fakes the other way.

Two new ideas are hiding in that picture.

The receivers’ jobs. Z stalk-blocks his cornerback: he runs at him as if on a route, then breaks down, squares up and stays between the corner and the ball. X runs his cornerback off: he sprints straight downfield so the corner, who cannot know it is a run yet, has to turn and run with him, which takes him out of the play without a block.

Reach-and-overtake. On outside zone, a covered lineman wants to reach his defender: get his head and body to the play-side of the defender so the defender is sealed inside and the running back can get outside him. Physically, a reach is a long lateral first step to gain ground, then a second step aimed through the defender’s play-side leg, with the inside hand driving into his chest to stop him running.4 The trouble is that a defender sitting in your play-side gap is already a step closer to the play than you are, and he is moving the same way you are: he only has to take one step sideways to stay outside you. Reaching him alone is close to impossible. So zone teams do it in pairs: the reach-and-overtake. The pairs are the same ones the rules produced for inside zone; what changes is who touches the defender first. The uncovered man of the pair (here the Y beside the 5-technique, and the RG beside the 1-technique) is already outside the defender, so he gets his hands on him first, just enough to stop him running wide. The covered man (the RT, the C) races flat down the line and overtakes the block, getting in front of the defender from the inside. As soon as the overtake arrives, the first lineman lets go and climbs to the linebacker. The covered man still ends up with his own defender; his uncovered neighbor just got there first to hold him. It is the outside-zone cousin of the inside-zone double team: inside zone’s combo goes forward and splits; outside zone’s combo goes sideways and hands off.

The backside cut-off. Away from the play, the linemen are not trying to move anyone. Their job is the backside cut-off: step play-side and get in front of the defenders on their side, so those defenders cannot chase the play down from behind. A backside defender who is cut off is out of the play even if he is never knocked back an inch. Notice who cuts off the backside end here: the U. Against the even front in Figure 16.1, nobody had that man; a second tight end gives the backside a blocker for him, which is a big reason zone teams like two-tight-end sets. As you will see, the backside cut-off is also what makes the cutback possible.

Now watch it move. The animation (a numbered frame strip in the PDF) is simulated, not a real play, but every player’s path follows the rules above.

Show the Python
pa = oz_play()
zone_animation(pa, [0.0, 0.4, 0.9, 1.45, 1.95, 2.4],
               notes=["snap", "line steps play-side", "handoff; RT races flat",
                      "RT overtakes the end; Y climbs", "end widens: crease inside him",
                      "one cut, downhill"],
               rings=(("RB", style.THIRD), ("RT", PURPLE)),
               lateral=(-6.4, 10.0), window=(-7.7, 7.0))
Figure 16.6: Outside zone right, frame by frame (simulated play; positions in Big Data Bowl coordinates, generated by gridiron; faint lines are each player’s path so far). The whole line moves right together and the linebackers flow with it. The Y gets his hands on the end and climbs to the Sam; the right tackle (purple ring) overtakes the end and, because the end fights to stay outside, rides him wider. The back (green ring) presses the tight end’s outside leg, sees the crease open inside the right tackle’s block, and cuts up into it: bang.

Notice the timing. Under center, the quarterback turns and hands off several yards deep, and the back takes a second and a half or more to reach the line. That is by design: the line needs time to get the defense moving sideways, and the back needs time to see which way it moved. It is why a good outside-zone back can look slow for two steps and then very fast.

Why outside zone exists, and what it gives up

Outside zone was built to beat a defense that is bigger than you. You cannot drive a 320-pound defensive tackle backward, but you can make him run, and a running defensive lineman is a defensive lineman who is not holding his gap. Stretch the whole front laterally, and gaps open between defenders who are moving at different speeds. Linebackers, flowing fast to stay level with the back, over-run the play. The back only has to find one crease.

It gives up a few things in return:

  • It needs a particular kind of lineman. Outside zone favors lighter, quicker linemen who can run laterally and reach, over bigger, stronger linemen who can drive straight ahead. Teams built around outside zone have often gone smaller on the line; the scheme shapes the roster.
  • Fast movement with the line hurts it. Zone keeps every defender accounted for when the defense moves, but it cannot make movement harmless. A defensive lineman who slants hard toward the play at the snap is moving the same way as his blocker with a head start, and the blocker may never get his head in front of him. One who knifes straight upfield into the gap a lateral-stepping blocker just left is in the backfield before the block exists, and the back’s track is so wide that he is tackled for a loss. (Figure 16.13, later, draws it.)
  • It is patient by design, which means it can lose yards. The back runs sideways for a couple of yards before he turns upfield. When the crease never appears, the result is a loss.
NoteMadden vs. real life

In Madden you choose “HB Stretch,” a lane lights up, and you steer the back into it. On a real zone run, nobody knows where the lane is when the play is called. The play call tells the line which way to step and the back where to aim; the hole is created by the defense’s reaction, and the back has to see it at full speed. Two identical calls of outside zone can hit three different gaps. That is not the play failing; that is the play working. The same goes for inside zone, which is not Madden’s “HB Dive”: a dive goes to one numbered hole, while inside zone’s hole is wherever the double teams and the back’s read put it.

Stretch: the widest track

The word stretch causes confusion because teams use it differently. In many playbooks “stretch” is simply another name for outside zone. When coaches distinguish them, stretch is the widest member of the family: the aiming point moves outside the tight end, toward the numbers, and the back’s first intent is to get the edge (the outside boundary of the defense, where the last defender on the line stands). The blocking is the same lateral, reach-first zone blocking; the difference is how hard the back works to get outside before he even considers cutting up.

Why have it? Because some fronts invite it. When the defensive end lines up inside the tight end (a 7-technique, on the tight end’s inside shoulder), the tight end is already outside him before the snap: half the reach is done. By the rules the end belongs to the right tackle (he sits in the tackle’s play-side gap), so the uncovered tight end gets his hands on him, the tackle overtakes, and the pair can pin him inside and win the race to the sideline. An end lined up outside the tight end, as in the odd front below, is the opposite case: nobody can get outside him easily, and stretch becomes a bad bet. The Indianapolis Colts of the Peyton Manning era made “the stretch” a signature under line coach Howard Mudd, running it with Edgerrin James and later Joseph Addai.5 The cost is the same as outside zone’s, only more so: the wider the track, the more yards the back can lose if the edge is not there.

In this book, when a distinction matters we say inside zone (aimed inside), outside zone (aimed at the tight end, ready to cut up), and stretch (aimed outside the tight end, edge first). On a broadcast you will usually hear “outside zone” and “stretch” used interchangeably. That is fine. Watch the aiming point and you will know which one you are seeing.

Same play, different front: the rules re-pair

The most important thing about zone blocking is that the same call works against different fronts, because the rules re-pair the blockers after the defense shows its hand. Here is the same outside zone against an odd front, one with a nose tackle head-up on the center (a 0-technique), two 4i-techniques (on the inside shoulder of each tackle) and two outside linebackers on the line, each in a 9-technique (on the tight end’s outside shoulder). You will learn its name and logic in 05-03; for now it is “a different front.”

Apply the rules again (Figure 16.7). The Y is now covered (a 9-technique sits in his play-side gap), so he has to reach that man by himself, a hard block. The right tackle is uncovered: the 4i lines up on his inside shoulder, which is his backside, so that defender belongs to the right guard, whose play-side gap he sits in. So the RT and RG form the new reach-and-overtake pair: the RT gets his hands on the 4i first, the RG overtakes, and the RT climbs to the Mike. The center is covered by the nose head-up on him. The left guard is uncovered and right next to him, so he helps: the center works to the nose’s play-side half while the left guard hits the nose’s backside hip, and once the center has him, the guard climbs to the Will. The left tackle cuts off the backside 4i. The U is the last man on the backside with a defender outside him, the third edge case from the rules: he hinges, stepping inside to wall off anything that crashes down inside him, and the 9-technique outside him is left alone, as the backside end was on inside zone.

Show the Python
def odd_front(cb_w=10.0):
    return [
        D("POLB", "OLB", 1.0, 6.0, "9"),
        D("P4i", "DE", 1.0, technique("4i", 1), "4i"),
        D("NT", "NT", 1.0, 0.0, "0"),
        D("B4i", "DE", 1.0, technique("4i", -1), "4i"),
        D("BOLB", "OLB", 1.0, -6.0, "9"),
        D("MIKE", "ILB", 4.5, 2.4, "M"),
        D("WILL", "ILB", 4.5, -2.4, "W"),
    ] + secondary(cb_w)


p = Play([q for q in ace_condensed() if q.key not in ("X", "Z")], odd_front(), los=35, to_go=10,
         title="Same outside zone vs an odd front: the rules re-pair")
go_to(p, "Y", (0.4, 6.7), via=[(-0.4, 5.7)])            # reach the 9-tech alone
go_to(p, "RT", (3.4, 3.0), via=[(0.5, 2.4)])            # hands on the 4i, climb to the Mike
go_to(p, "LG", (3.6, -1.7), via=[(-0.3, -0.9), (0.4, -0.5)])  # hit the nose's backside hip, climb
go_to(p, "LT", (0.6, -1.9), via=[(-0.4, -2.4)])         # cut off the 4i
go_to(p, "U", (-1.1, -4.2), via=[(-0.9, -4.5)])         # hinge: wall off a crash inside
go_to(p, "QB", (-3.6, 1.8), "path", speed=3.2)
go_to(p, "QB", (-6.0, -5.0), "path", speed=4.0, delay=0.15)
go_to(p, "RB", (2.5, 5.0), "run", via=[(-4.3, 2.6), (-1.3, 4.9)])
p.handoff("RB", t=0.7)
p.highlight("RB")
p.highlight("NT", color=style.DEFENSE); p.highlight("POLB", color=style.DEFENSE)
fld = draw(p, width_in=5.6, lateral=(-11.5, 11.5), window=(-8, 9))
overtake(fld, p, "RG", [(-0.5, 2.0), (0.1, 2.8)], (0.9, 3.2))     # RG overtakes the 4i
overtake(fld, p, "C", [(-0.4, 0.3), (0.2, 0.8)], (0.9, 1.0))       # C works to the nose's play-side half
spot(fld, p, -0.2, 5.3)
say(fld, p, -3.0, 8.6, "Y must reach a\n9-tech alone", color=style.DEFENSE_DARK, fontsize=7)
point_to(fld, p, (-3.6, -3.0), (0.0, -0.9), "C + LG on the nose:\nthe hardest block", color=style.DEFENSE_DARK,
         fontsize=6.8)
point_to(fld, p, (7.4, 5.4), (3.4, 3.0), "RT: hands on the 4i,\nthen climbs to the Mike", fontsize=6.6)
point_to(fld, p, (-4.2, -8.6), (-1.1, -4.2), "U hinges: steps\ninside, guards the\ngap inside him", fontsize=6.6)
point_to(fld, p, (3.4, -8.8), (1.0, -6.0), "left alone; the\nQB fakes away", color=style.DEFENSE_DARK, fontsize=6.6)
plt.show()
Figure 16.7: The same outside zone right against an odd front (named in 05-03). Nothing in the call changed, but the rules re-pair: the RT gets his hands on the 4i and climbs while the RG overtakes (dashed green); the center works to the nose’s play-side half while the left guard hits his backside hip and then climbs; the Y must reach a 9-technique lined up outside him, alone. The two ringed defenders are where this play will be won or lost. On the backside the U hinges and the 9 outside him is left alone.

Compare the two pictures and you will see what coaches mean when they say “the front tells you where the play will hit.” Against the even front, the hardest block was the overtake on the 1-technique, and the edge was reachable. Against this odd front, the two hardest blocks are the center and left guard on a nose head-up on the center, and the tight end on a man lined up outside him. If the 9-technique cannot be reached, the back will not bounce. He will hit it up inside him, or cut back. The rules did not change. The likely hole did.

ImportantWhy it exists

A zone play is really a set of rules, not a drawing. Rules let one play call adapt to every front the defense can show, which is why zone teams can run a handful of plays all game without being predictable in the way that matters: the defense knows the call, but not where the ball will hit. Defenses fight back with fronts and movement that put the offense’s weakest blocker in the hardest job, a story you will pick up in Part 5.

Who picks inside or outside zone, and which way? The play-caller, from the sideline, as with every call (01-05). But the line of scrimmage still gets a vote. Many offenses let the quarterback flip a run to the other side (a kill call), or check out of it into a pass, when the defense’s alignment makes the called side a bad bet, for example when it shows more defenders in the box than the offense can block. How much freedom he has varies a great deal by team; the pre-snap chapter covers how checks work.

The runner’s half: bang, bend, bounce

Now the other half of the play. The zone back’s job is to take the handoff, press the aiming point (run at it hard enough that the defense believes the ball is going there), read the blocks, and choose. Coaches compress the choice into three words: bang-bend-bounce.

  • Bang: hit the designed gap and go straight upfield. The blocks went as drawn.
  • Bend: cut back against the flow, behind the double teams, usually into the backside A or B gap. The defense flowed too fast, and the space is behind them.
  • Bounce: take it outside. The edge defender got pinned inside, and the corner is open.
Show the Python
fig = plt.figure(figsize=(6.5, 4.2))
gs = fig.add_gridspec(1, 2, width_ratios=[1.0, 1.15], wspace=0.04)
ax1, ax2 = fig.add_subplot(gs[0]), fig.add_subplot(gs[1])
off = [q for q in named_line(offense("singleback")) if q.key in (*OL_NAMES, "Y", "RB")]
p = Play(off, front7(+1), los=35, to_go=None)
p.run("RB", [(3.0, 1.8), (5.8, 2.3)])
p.highlight("RB"); p.highlight("PT", color=style.THIRD)
fld = p.draw(ax=ax1, lateral=(-6.5, 9.5), window=(-8, 9.5), title=False)
clean(ax1)
(x0, y0), (x1, y1) = _P(fld, p, 1.6, 0.9), _P(fld, p, 2.3, 2.05)     # "if he flows over the top"
ax1.add_patch(FancyArrowPatch((float(x0), float(y0)), (float(x1), float(y1)), arrowstyle="-|>",
                              mutation_scale=10, color=style.DEFENSE, lw=1.8, zorder=9))
branch(fld, p, [(-1.2, 2.3), (6.6, 2.5)], color=ZONE_GREEN, label="1 bang", label_at=(7.6, 2.5))
branch(fld, p, [(-1.2, 2.3), (-1.9, 0.2), (-0.7, -0.8), (1.2, -1.1), (6.4, -1.6)], color=style.OFFENSE_DARK,
       label="2 bend", label_at=(7.4, -1.8))
branch(fld, p, [(-1.2, 2.3), (-1.8, 5.0), (-0.4, 6.7), (1.4, 7.9), (4.6, 8.5)], color=PURPLE,
       label="3 bounce", label_at=(5.8, 7.6))
say(fld, p, -4.8, -2.4, "press,\nread", color=style.INK, fontsize=7)
say(fld, p, 2.5, -0.5, "flows?", color=style.DEFENSE_DARK, fontsize=6.8)
ax1.set_title("One track, three answers", fontsize=9, loc="left", color=style.INK, fontweight="bold")

ax2.axis("off"); ax2.set_xlim(0, 1); ax2.set_ylim(0, 1)


def box(ax, y, h, text, fc, ec):
    ax.add_patch(FancyBboxPatch((0.01, y - h / 2), 0.98, h, fc=fc, ec=ec, lw=1.0,
                                boxstyle="round,pad=0.012,rounding_size=0.02"))
    ax.text(0.5, y, text, ha="center", va="center", fontsize=6.9, color=style.INK, linespacing=1.25)


def arrow(ax, y0, y1, text=None):
    ax.add_patch(FancyArrowPatch((0.5, y0), (0.5, y1), arrowstyle="-|>", mutation_scale=9,
                                 color=style.INK_2, lw=1.0))
    if text:
        ax.text(0.52, (y0 + y1) / 2, text, fontsize=6.8, color=style.INK_2, va="center")


box(ax2, 0.92, 0.12, "Press the aiming point, eyes on the first\ndefensive lineman play-side of the center",
    style.OFFENSE_TINT, style.OFFENSE)
box(ax2, 0.71, 0.12, "Is he walled off, with daylight beside him?\nBANG: hit the play-side gap, get vertical",
    "#e5f5ee", ZONE_GREEN)
box(ax2, 0.47, 0.14, "Did he (and the linebackers) flow over the top?\nBEND: cut back behind the double team,\n"
    "into the backside A or B gap", style.OFFENSE_TINT, style.OFFENSE_DARK)
box(ax2, 0.23, 0.14, "Everything inside clogged, and the edge\ndefender pinned inside? BOUNCE: take it\n"
    "outside (rare on inside zone)", "#e7e4f4", PURPLE)
arrow(ax2, 0.86, 0.775); arrow(ax2, 0.65, 0.54, "no"); arrow(ax2, 0.40, 0.30, "no")
ax2.text(0.02, 0.04, "Outside zone: first read the play-side end (reached? bounce),\nthen the next defensive "
         "lineman inside him (bang or bend?).", fontsize=6.8, color=style.INK_2, va="bottom")
plt.show()
Figure 16.8: The running back’s decision on inside zone. He presses the aiming point with his eyes on the first defensive lineman play-side of the center (the ringed 1-technique). If that man is walled off, bang through the B gap (green); if he flows over the top toward the play (the short orange arrow is his possible movement), bend back behind him between the center and left guard (blue); bounce (purple) only if everything inside is clogged and the edge is open. Outside zone uses the same three answers in a different order.

The order matters, and it is different for the two plays.

On inside zone the back thinks bang, bend, bounce. He reads the first defensive lineman play-side of the center, the man the first double team is working on. Why that man? Because he sits right next to the aiming point, and what happens to him answers both questions at once: if the double team is moving him, the play-side gap beside him is open; if he is sliding toward the play to get in front of it, he is taking the space behind him out of play for the defense, and the linebackers behind him usually flow the same way. One defender tells the back where the defense is going. If that defender is walled off and there is daylight beside him, bang. If he (and the linebackers behind him) flowed hard to the play-side, there is space behind them: bend. Bounce is the last resort on inside zone, because running outside on a play built to go inside usually means running away from your blockers. It is the right answer only when the play-side end has crashed inside and nobody has stayed outside to take his place.

On outside zone the order flips to bounce, bang, bend, and the back makes two reads in order. His first read is the play-side end, the first defensive lineman outside the tackle: is he reached? Remember who ends up with him: the reach-and-overtake pair, with the right tackle taking him over from the tight end. If the end is slow, or plays inside, and the tackle gets his head across him and pins him inside, the edge is open: bounce. That is uncommon against a good end lined up outside the tackle, which is why most outside-zone runs end up as bang or bend. If the end fights hard to stay outside, the tackle rides him wider and the back moves to his second read, the next defensive lineman inside, and asks where the hole is relative to him. If that man has been walled off, there is a crease between him and the end: bang, up inside the end. If he and the linebackers are racing to the sideline, the space is back the other way: bend, which on outside zone often becomes a full cutback (next section). The second read is the one to watch if you want to see a cutback coming.

Coaches teach this read in slightly different words and keys (some read a linebacker rather than a lineman), and you should expect that variety.6 The principle under all of them is the same: press, read, then make one cut.

For your own log, keep the boundary simple: bang if the back crosses the line in the play-side gaps, bounce if he goes outside the play-side end, bend if he comes back against the flow. Every bend is a cutback; the big ones that carry him outside the backside tackle are what broadcasters mean by “he found the cutback.”

That last phrase of the principle describes a style. A one-cut runner presses the aiming point with patience, plants one foot, and goes straight upfield; he does not dance, stutter or reverse field behind the line. Zone coaches prize this style above raw speed, because a zone run’s creases are open for a fraction of a second and close quickly. A back who hesitates or takes two cuts arrives after the hole has closed. It is why zone teams have often won with backs drafted in late rounds or signed off other teams’ rosters: the scheme rewards decisiveness and vision more than it rewards a top-10 pick’s raw talent. (The 1990s Broncos are the classic example; see below.)

The cutback and the backside

Here is the play from the chapter’s opening: second-and-7, two tight ends, the line steps right in unison, the back runs at the right tight end, plants, and comes back through a hole near the center.

A cutback is a cut against the flow of the play, back toward the side the line stepped away from. On outside zone it is not a desperation move. It is one of the three answers the play was designed to produce. Here is why it works. When eleven defenders see five linemen and a running back all racing to their right, they race to their right too. Linebackers who are taught to stay level with the ball carrier take aggressive angles, and a fast defense can over-run the play: everyone ends up play-side of the ball. The space behind them is empty, as long as the backside defenders cannot get there first.

That condition is what the backside cut-off is for. The backside linemen do not need to move anyone; they need the defensive linemen on their side to be on the ground, turned around, or walled away from the cutback lane. When they succeed, the cutback is the most explosive play in the zone family, because the back runs into space that the defense vacated on purpose.

Show the Python
p = Play(ace_condensed(), even_front(+1, cb_w=10.0), los=35, to_go=7)
go_to(p, "PE", (1.8, 6.2), "path", speed=2.0)
go_to(p, "PT", (1.2, 2.8), "path", speed=2.6)               # slants hard play-side
go_to(p, "BT", (0.9, -2.5), "path", speed=1.2)              # cut down by the LT
go_to(p, "BE", (0.9, -4.3), "path", speed=1.4)              # cut down by the U
go_to(p, "SAM", (3.2, 8.2), "path", speed=2.4)
go_to(p, "MIKE", (2.4, 5.4), "path", speed=3.4, delay=0.1)  # over-runs
go_to(p, "WILL", (2.8, 3.4), "path", speed=3.6, delay=0.1)  # over-runs
go_to(p, "FS", (7.6, -3.9), "path", speed=4.5, delay=0.5)
go_to(p, "SS", (7.0, 7.5), "path", speed=4.5, delay=0.4)
go_to(p, "LCB", (11.0, -10.0), "path", speed=4.0)
go_to(p, "RCB", (5.4, 9.6), "path", speed=1.5)
go_to(p, "Y", (1.0, 6.9), speed=2.4, via=[(0.0, 5.6)])
go_to(p, "RT", (0.5, 5.0), speed=2.0, via=[(-0.4, 4.2)])
go_to(p, "RG", (1.6, 3.6), speed=2.2, via=[(-0.2, 2.2)])
go_to(p, "C", (0.4, 1.8), speed=2.0, via=[(-0.5, 0.9)])
go_to(p, "LG", (2.2, 2.4), speed=2.4, via=[(-0.4, -0.7)])
go_to(p, "LT", (0.5, -2.4), speed=2.2, via=[(-0.6, -2.7)])   # cut block: forward, at the thighs
go_to(p, "U", (0.5, -4.2), speed=2.2, via=[(-0.6, -4.5)])    # cut block
go_to(p, "Z", (4.4, 9.4), speed=4.0, via=[(2.8, 9.8)])
p.route("X", [(0, 0), (11, -0.5)])
go_to(p, "QB", (-3.7, 1.7), "path", speed=2.8)
go_to(p, "QB", (-6.0, -4.5), "path", speed=4.0, delay=0.15)
go_to(p, "RB", (8.4, -3.6), "run", speed=5.6,
      via=[(-4.4, 2.4), (-1.9, 5.6), (-1.6, 5.2), (-0.7, 0.6), (1.2, -1.6)])
p.handoff("RB", t=0.75)
zone_animation(p, [0.0, 0.75, 1.25, 1.9, 2.45, 2.95],
               notes=["snap", "handoff; everyone flows right", "back presses: no room",
                      "plant, cut back behind the C", "through the backside A gap",
                      "the safety must make the tackle"],
               down={"BT": 0.7, "BE": 0.7},
               lateral=(-9.0, 9.0), window=(-7.7, 9.5))
Figure 16.9: The opening play: the cutback (simulated play). The linebackers and the play-side defensive tackle (the 1) over-run the outside zone. On the backside, the LT and the U cut their defenders to the ground (faded, tagged ‘cut’ from frame 2), so nobody is left to close the backside. The back (ringed) presses the tight end’s outside leg, sees no room, plants, and cuts back through the backside A gap, beside the center; only the deep safety is left to make the tackle.
CautionCommon misconception

“The cutback is the running back freelancing.” It is the opposite. The back is following the play’s own logic: press the aiming point to pull the defense one way, then take the space the defense left. Zone coaches often say the back should expect to cut back on outside zone, and coach the backside linemen as if the ball will come their way. A back who never cuts back makes outside zone easy to defend, because the defense can then over-pursue for free.

New block: the cut block

To clear a cutback lane quickly, backside linemen often do not try to stand a defender up. They cut him. A cut block is a block aimed at a defender’s thighs or lower legs, from the front, to put him on the ground. A defender on the ground cannot chase, and for a lighter zone lineman facing a heavier defensive tackle who is trying to run down the line, a cut is often the most reliable way to take him out of the play. “From the front” matters, because the backside defender is running sideways, chasing the play: the blocker’s play-side step puts him in front of that path, so the defender runs into the block instead of being hit from behind or the side.

It is also the most controversial block in football, because a block at the knees can end a career. The NFL has narrowed it again and again: low blocks are now legal only near the ball, inside the “tight end box” around the line; never from behind or from the side while moving back toward your own goal line (since 2013); and never combined with a high block by a teammate, the chop block, banned in every situation since 2016.7 The details are in 09-03. Mike Shanahan’s Denver lines were criticized for years for backside cuts; in 2004, after a Broncos lineman’s cut block broke a Bengals defensive tackle’s ankle on Monday Night Football, opposing head coaches and the broadcast crew criticized the team publicly.8 Defenders call it dirty; zone coaches call it legal technique that lets small linemen block big ones. With the rules this much tighter, how often a modern line cuts on the backside depends on its line coach. When you do see a backside defensive tackle go down at the snap on a zone run, you have probably just seen one.

Split zone: protecting the backside

Back to inside zone’s unblocked backside end, the man who can chase down a cutback. Split zone takes him away.

Show the Python
off = [q for q in named_line(offense("gun_2x2")) if q.key in (*OL_NAMES, "QB", "RB")] + [
    Player("Y", "TE", "off", -0.7, 4.8, label="Y"),
    Player("H", "TE", "off", -1.3, 6.4, label="H"),       # off-ball TE ("H-back") on the right
    Player("X", "WR", "off", -0.7, -11.0, label="X"),
    Player("Z", "WR", "off", -1.5, 11.0, label="Z"),
]
off = [q.moved(w=-1.6) if q.key == "RB" else q for q in off]
p = Play(off, even_front(+1, cb_w=11.5), los=35, to_go=10,
         title="Split zone: the H kicks out the backside end")
p.block("C", pts=[(0.9, 0.5)])
p.block("RG", pts=[(0.8, -0.8), (4.3, -0.4)])
p.block("LT", pts=[(0.9, 0.7)])
p.block("LG", pts=[(0.8, -0.6), (4.3, -0.8)])
p.block("RT", pts=[(0.9, 0.6)])
p.block("Y", pts=[(0.6, -0.6), (3.6, 1.5)])
go_to(p, "H", (0.3, -3.7), via=[(-1.8, 4.6), (-1.8, -2.6)])  # just behind the heels: kick out the end
go_to(p, "RB", (-1.4, 2.3), "run", via=[(-4.0, -0.2)])      # cross the QB's face to the B gap
go_to(p, "QB", (-5.5, -1.6), "path", speed=3.0)              # mesh, then fake a keep away
p.handoff("RB", t=0.7)
p.highlight("H"); p.highlight("BE", color=style.DEFENSE)
fld = draw(p, lateral=(-13, 13), window=(-8, 13))
spot(fld, p, 0.0, 2.4)
branch(fld, p, [(-1.4, 2.3), (-2.6, 0.6), (-1.9, -0.8), (0.6, -0.9), (2.6, -0.6), (6.6, 0.4)],
       color=ZONE_GREEN, label="bend", label_at=(7.6, 0.6))
say(fld, p, -3.6, -8.0, "H crosses just behind\nthe line, kicks out the end", fontsize=7)
say(fld, p, -6.8, 4.0, "back crosses\nthe QB's face", color=style.OFFENSE_DARK, fontsize=7)
plt.show()
Figure 16.10: Split zone from the shotgun. The line blocks inside zone right exactly as before, and the back, offset to the quarterback’s left, crosses his face toward the right B gap. The H (an off-the-ball tight end) runs the other way, just behind the linemen’s heels and in front of the handoff, and kicks out the backside end. With that end blocked, the back’s bend lane (dashed green) runs between the double team on the 1 and the left guard’s block on the Will.

The line blocks exactly as it would on inside zone. The difference is one man: an H-back or tight end, lined up off the ball on the play-side, who at the snap runs across the formation, just behind the linemen’s heels and in front of the handoff, and kicks out the backside end. The name comes from the picture: the play “splits,” with the line and the back going one way and the H going the other.

Under center or in the shotgun. Every picture before this one put the quarterback under center, where he turns his back to the defense, hands off and fakes the other way; turning away hides the ball and puts him in position to carry out the fake. From the shotgun, where most NFL snaps happen, the back usually lines up beside the quarterback and on inside zone runs across the quarterback’s face at the handoff: a back offset to the left usually runs inside zone to the right. That gives him a running start toward the aiming point and keeps the exchange (the mesh, the moment the ball changes hands; not the pass concept of the same name in 04-04) moving downhill. Defenses know this tendency, so offenses break it on purpose with same-side zone (the back runs to the side he lined up on) and with the pistol, where the back stands directly behind the quarterback and his alignment says nothing about direction.

Why it exists. Split zone solves three problems at once. It blocks the one defender plain inside zone leaves free. It protects the cutback, so the back can bend without an end waiting for him. And the H’s path is misdirection: a linebacker who keys the H (follows his movement to find the play) takes a false step the wrong way. It also builds a family. The same H motion across the formation is the action for bootlegs and for passes to the H in the flat (the short area near the sideline, within a few yards of the line), so the defense cannot simply crash on the H’s path.

What it costs. The H is no longer available to block play-side, so the play-side is one blocker lighter than it could be. If the defense brings an extra defender to the play-side, split zone can be outnumbered there. Every zone variation is this kind of trade: put a blocker where the threat is, and accept that he is not somewhere else.

Tags: insert, arc and bash

Zone teams rarely change the line’s rules. Instead they add a tag, a word added to the play call that changes one or two players’ jobs (you met tags in 01-04). Three zone tags are worth knowing, because you will see all three on Sundays.

Show the Python
fig, axes = plt.subplots(1, 2, figsize=(6.6, 3.7))

# insert
off = [q for q in named_line(offense("singleback")) if q.key in (*OL_NAMES, "Y", "QB", "RB")]
off.append(Player("H", "TE", "off", -4.4, -1.8, label="H"))            # offset fullback
p = Play(off, front7(), los=35, to_go=None)
p.block("C", pts=[(1.1, 0.6)]); p.block("RG", pts=[(1.0, -0.7)])      # the double stays on the 1
p.block("RT", pts=[(0.9, 0.6)]); p.block("Y", pts=[(0.6, -0.6), (3.6, 1.5)])
p.block("LT", pts=[(0.9, 0.7)]); p.block("LG", pts=[(0.8, -0.6), (4.3, -0.8)])
go_to(p, "H", (3.7, 1.8), via=[(-2.6, 0.6), (0.3, 2.3)])                 # insert on the Mike
p.run("RB", [(3.0, 1.0), (6.0, 2.7), (10.0, 3.0)], delay=0.25)
p.highlight("H")
f = draw(p, ax=axes[0], lateral=(-7.5, 8.5), window=(-8, 6.5), title=False)
point_to(f, p, (-6.2, -4.6), (-4.4, -1.8), "H: offset\nfullback", fontsize=6.8)
point_to(f, p, (-4.2, 5.4), (0.6, 1.0), "double team\nstays on the 1", fontsize=6.8, color=ZONE_GREEN)
axes[0].set_title("Insert: H leads up on the Mike", fontsize=9, loc="left", color=style.INK, fontweight="bold")

# arc
off = [q for q in named_line(offense("gun_2x2")) if q.key in (*OL_NAMES, "QB")]
off += [Player("H", "TE", "off", -1.5, -6.6, label="H"), Player("RB", "RB", "off", -5.0, -1.6, label="R")]
dfn = [q for q in front7() if q.key != "SAM"] + [D("SS", "SS", 5.0, -9.6, "SS")]
p = Play(off, dfn, los=35, to_go=None)
p.block("C", pts=[(0.9, 0.5)]); p.block("RG", pts=[(0.8, -0.8), (4.3, -0.4)])
p.block("RT", pts=[(0.9, 0.6)])
p.block("LT", pts=[(0.9, 0.7)]); p.block("LG", pts=[(0.8, -0.6), (4.3, -0.8)])
go_to(p, "H", (4.1, -9.3), via=[(0.4, -7.6), (2.6, -9.0)])               # arc past the end to the safety
go_to(p, "RB", (1.0, 2.6), "run", via=[(-4.0, -0.4), (-1.4, 2.3)])       # give: inside zone right
p.read("BE")
p.highlight("H"); p.highlight("BE", color=style.DEFENSE)
f = draw(p, ax=axes[1], lateral=(-12, 4.0), window=(-8, 6.5), title=False)
branch(f, p, [(-5.0, 0.0), (-4.4, -2.0), (-2.6, -4.4), (-0.4, -5.4), (4.0, -6.2)], label="keep",
       label_at=(5.4, -6.0), fontsize=7, color=style.OFFENSE_DARK)
point_to(f, p, (-3.4, 2.8), (-1.4, 2.3), "give", fontsize=7, color=style.OFFENSE_DARK)
point_to(f, p, (-6.6, -9.0), (1.0, -4.0), "read end:\nnot blocked", fontsize=6.8, color=style.DEFENSE_DARK)
axes[1].set_title("Arc: H runs past the end", fontsize=9, loc="left", color=style.INK, fontweight="bold")
fig.tight_layout(w_pad=0.6)
plt.show()
Figure 16.11: Two zone tags, both with inside-zone blocking to the right. Left, insert: the H (here an offset fullback) leads through the play-side B gap onto the Mike, a step ahead of the running back, so the double team on the 1 never has to climb. Right, arc: on the backside, the H (an H-back off the ball on the left) runs past the unblocked end without touching him and blocks the safety outside him. The quarterback reads that end (dashed line): if the end stays home, give; if he chases the back, keep and run behind the arc block.

Insert. On insert (or “zone insert”), a fullback, H-back or tight end leads up through a gap and blocks a linebacker, usually the play-side one (some staffs insert on the backside linebacker instead). That frees the play-side double team from having to climb: it can stay on the defensive lineman longer and move him farther. In effect, insert adds a blocker at the point of attack, which is how a zone team answers a defense that keeps one more defender in the box than the offense has blockers. The cost is the usual one: the inserting player is not available as a receiver, and his alignment (an offset fullback, or a tight end off the ball) can tip the play.

The other two tags borrow an idea from option football, which gets its own chapter: instead of blocking the unblocked backside end, the quarterback reads him (watches what he does after the snap) and decides whether to hand the ball off or keep it. For now, all you need is that idea; 03-04 builds it properly.

Arc. Arc happens on the backside, away from the line’s flow. The line zones right and the back runs inside zone to the right, while on the left a tight end or H-back makes an arc block: he releases outside the unblocked backside end, runs past him without touching him, and blocks the next defender out, the linebacker or safety responsible for the alley between the end and the sideline (the alley player of Part 5). The quarterback reads the end. If the end stays home, the quarterback gives and the back runs inside zone. If the end chases the running back down the line, the quarterback keeps, runs around the end the other way, and finds the arc block already waiting for the next man. Arc is why you sometimes see a tight end run right past a defensive end without touching him: he was never supposed to.

Bash needs one more step of background. On the standard zone read (03-04 draws it), the back runs the inside-zone track and the quarterback, reading the backside end, keeps the ball around that end if the end chases the back. Defenses learned an answer: the end crashes down hard at the back, inviting the keep, while a linebacker loops around behind him to meet the quarterback where he was about to run (a scrape exchange: the end and the linebacker swap jobs).9 The defense’s plan is a bet that the back will be inside and the quarterback outside.

Show the Python
fig, axes = plt.subplots(1, 2, figsize=(6.6, 3.5))
for ax, bash in [(axes[0], False), (axes[1], True)]:
    off = [q for q in named_line(offense("gun_2x2")) if q.key in (*OL_NAMES, "QB")]
    off += [Player("RB", "RB", "off", -5.0, 1.6 if bash else -1.6, label="R"),
            Player("Y", "TE", "off", -0.7, 4.8, label="Y")]
    p = Play(off, front7(), los=35, to_go=None)
    p.block("C", pts=[(0.9, 0.5)]); p.block("RG", pts=[(0.8, -0.8), (4.3, -0.4)])
    p.block("RT", pts=[(0.9, 0.6)]); p.block("Y", pts=[(0.6, -0.6), (3.6, 1.5)])
    p.block("LT", pts=[(0.9, 0.7)]); p.block("LG", pts=[(0.8, -0.6), (4.3, -0.8)])
    p.read("BE")
    p.highlight("BE", color=style.DEFENSE)
    f = draw(p, ax=ax, lateral=(-9.5, 7.0), window=(-8, 7), title=False)
    inside = [(-5.0, 0.0), (-3.6, 1.0), (-1.2, 2.3), (4.6, 2.7)]
    outside = [(-4.6, -1.0), (-3.6, -3.4), (-1.6, -6.2), (3.6, -7.6)]
    if bash:
        branch(f, p, [(-5.0, 1.6), (-4.8, 0.4)] + outside, color=style.OFFENSE_DARK,
               label="give (back)\nif the end squeezes", label_at=(-6.6, -5.6), fontsize=6.6)
        branch(f, p, inside, color=ZONE_GREEN, label="keep (QB) if the end\nwidens with the back",
               label_at=(6.2, 3.0), fontsize=6.6)
        ax.set_title("Bash: back outside, QB inside", fontsize=9, loc="left", color=style.INK, fontweight="bold")
    else:
        branch(f, p, [(-5.0, -1.6), (-3.8, 0.0)] + inside[2:], color=style.OFFENSE_DARK,
               label="give (back)", label_at=(6.0, 3.2), fontsize=6.6)
        branch(f, p, [(-5.0, 0.0)] + outside, color=ZONE_GREEN, label="keep (QB) if the\nend chases the back",
               label_at=(-6.6, -5.6), fontsize=6.6)
        ax.set_title("Zone read: back inside, QB outside", fontsize=9, loc="left", color=style.INK,
                     fontweight="bold")
fig.tight_layout(w_pad=0.6)
plt.show()
Figure 16.12: The zone read and bash, both with the line zoning right and the quarterback reading the same backside end (dashed line). Left, the zone read: the back takes the inside-zone track, and the quarterback keeps around the end if the end chases the back. Right, bash: the back goes the other way, wide around the end, and the quarterback, if he keeps, runs the inside-zone track. The runners have swapped lanes, so a defense planning for ‘back inside, quarterback outside’ has it backwards.

Bash. Bash is short for “back away”: the running back runs away from the direction the line is zoning, on a wide path around the read end, while the quarterback, if he keeps, runs the inside-zone track behind the line (Figure 16.12). It flips the usual roles: the running back threatens the edge and the quarterback becomes the inside runner. The read is the same end, with the answers reversed: if he squeezes (closes down the line toward the zone flow), the quarterback hands the ball to the back going around him; if he stays wide to take the back, the quarterback keeps and runs inside him.10 Against a scrape exchange, that matters: the end who crashes down to take the inside runner has crashed onto the quarterback’s fake, and the ball is going outside him with the running back. Bash is the offense’s reply to the defense’s reply, and the full back-and-forth belongs to option football.

All three tags share one logic: keep the zone rules for the line, and change one or two players to fix the specific problem the defense is creating. Watch for the extra player (the inserting back, the arcing tight end, the back running the “wrong” way) and you will usually know which tag you are watching.

How defenses fight zone

Zone’s rules guarantee that every defender is accounted for. They do not guarantee that every block is won, and defenses attack the places where zone is physically hardest. Figure 16.13 shows the two most common.

Show the Python
fig, axes = plt.subplots(1, 2, figsize=(6.6, 3.6))
# penetration: the 3-technique lines up on the play side this time (Sam still on the right)
dfn = [D("PE", "DE", 1.0, technique("5", 1), "5"), D("PT", "DT", 1.0, technique("3", 1), "3"),
       D("BT", "DT", 1.0, technique("1", -1), "1"), D("BE", "DE", 1.0, technique("5", -1), "5"),
       D("SAM", "SAM", 4.0, 6.6, "S"), D("MIKE", "MIKE", 4.5, 0.6, "M"), D("WILL", "WILL", 4.5, -3.0, "W")]
off = [q for q in ace_condensed() if q.key not in ("X", "Z")]
p = Play(off, dfn, los=35, to_go=None)
for k, st in [("LT", (0.1, 1.3)), ("LG", (0.1, 1.3)), ("C", (0.1, 1.2)), ("U", (0.1, 1.3)), ("Y", (0.2, 0.9))]:
    p.block(k, pts=[st])
p.block("RG", pts=[(-0.1, 1.1)]); p.block("RT", pts=[(0.0, 0.9)])
go_to(p, "PT", (-2.7, 3.0), "path")                       # the play-side 3-technique penetrates
go_to(p, "RB", (-2.8, 3.4), "run", via=[(-4.4, 2.4)])
go_to(p, "QB", (-3.6, 1.8), "path", speed=3.2)
p.highlight("PT", color=style.DEFENSE)
f = draw(p, ax=axes[0], lateral=(-7.5, 8.5), window=(-8, 6.5), title=False)
x, y = _P(f, p, -2.9, 3.5)
axes[0].plot([x], [y], marker="X", ms=11, color=style.DEFENSE_DARK, mec="white", mew=0.8, zorder=12)
say(f, p, -2.4, 6.4, "tackle\nfor loss", color=style.DEFENSE_DARK, fontsize=7)
point_to(f, p, (-5.8, 6.0), (1.0, 2.35), "3-tech knifes upfield\nbefore the reach", color=style.DEFENSE_DARK,
         fontsize=6.8)
axes[0].set_title("Penetration", fontsize=9, loc="left", color=style.INK, fontweight="bold")

# cutback player: the Will plays fast into the backside A gap before the LG can climb to him
# (the quarterback is left out of this panel so the bend lane behind the line stays visible)
p = Play([q for q in off if q.key != "QB"], front7(+1), los=35, to_go=None)
for k in ("LT", "C", "RG", "RT", "U", "Y"):
    p.block(k, pts=[(0.15, 1.3)])
go_to(p, "LG", (1.4, -0.3), via=[(-0.3, -0.9)])            # steps play-side to climb: late
go_to(p, "MIKE", (3.6, 4.6), "path"); go_to(p, "SAM", (3.4, 8.0), "path")
go_to(p, "WILL", (1.0, -1.1), "path", speed=4.0)           # downhill into the backside A gap
go_to(p, "RB", (-1.9, 4.8), "run", via=[(-4.4, 2.4)])
p.highlight("WILL", color=style.DEFENSE)
f = draw(p, ax=axes[1], lateral=(-7.5, 8.5), window=(-8, 6.5), title=False)
branch(f, p, [(-1.9, 4.8), (-2.1, 2.4), (-1.8, 0.2), (-0.6, -0.6), (-0.1, -0.75)], color=style.OFFENSE_DARK,
       label="bend", label_at=(-3.2, 0.6), fontsize=7)
x, y = _P(f, p, 0.25, -0.85)
axes[1].plot([x], [y], marker="X", ms=11, color=style.DEFENSE_DARK, mec="white", mew=0.8, zorder=12)
point_to(f, p, (-5.0, -4.6), (1.0, -1.1), "Will plays fast into\nthe backside A gap,\nbefore the LG can climb",
         color=style.DEFENSE_DARK, fontsize=6.6)
axes[1].set_title("The cutback player", fontsize=9, loc="left", color=style.INK, fontweight="bold")
fig.tight_layout(w_pad=0.6)
plt.show()
Figure 16.13: Two ways defenses kill outside zone right. Left: penetration. This time the 3-technique lines up on the play side; at the snap he knifes upfield through the B gap, before the lateral-stepping guard and tackle can get in front of him, and meets the back on his track. Right: a cutback player. Instead of flowing, the Will comes downhill into the backside A gap at the snap, faster than the left guard can climb to him, so when the back bends, the lane he expected is filled.

Penetration and movement. A defensive lineman who gets upfield at the snap, or slants hard toward the play, can beat a lateral-stepping blocker to the spot. Defenses that want to stop zone often play their linemen this way, attacking a gap instead of reading the man in front of them; how defensive linemen are taught to do either is the subject of 05-01.

The cutback player. Because outside zone’s biggest gains come from the cutback, defenses assign someone to stay home for it: usually the backside linebacker, sometimes a safety rotating down. You saw the deep safety arrive late in Figure 16.9; a defense that gets a defender there early takes away the play’s third answer.

Spill or squeeze. When a blocker comes at a defender, the defense chooses whether that defender fights inside the block to force the ball to bounce wide toward pursuit (spill) or holds the edge and squeezes the play back inside (squeeze). Against zone, either plan can work if all eleven players agree on it, which is the subject of run fits in 05-05.11

And when the defense simply puts more defenders in the box than the offense has blockers, a zone team answers with the tools you have already seen: an extra blocker (insert), a read of the unblocked man (arc, bash, the zone read), or a pass that looks like the run.

Why wide zone and the bootleg are married

Outside zone’s greatest weapon is not a run at all. It is the pass that looks exactly like it.

Think about what outside zone teaches a defense. Every snap, the line steps hard to one side, the back runs at the tight end, and the linebackers learn that if they do not flow fast and hard, they lose. The backside end learns that if he does not chase, the cutback beats him. After a few of these, the defense is trained to run with the line’s first step.

The bootleg cashes that in. It is a play-action pass (a pass that begins with a fake handoff) in which the quarterback fakes outside zone one way and rolls out the other, away from where the line went, with receivers crossing the field to meet him. In the “naked” version nobody blocks for him at all; in the protected version a lineman or a back is assigned to the backside end. Both are built in 04-05; here, what matters is why they pair with zone.

Show the Python
fig, axes = plt.subplots(1, 2, figsize=(6.6, 4.3))
for i, ax in enumerate(axes):
    p = Play(ace_condensed(), even_front(+1, cb_w=10.0), los=35, to_go=10)
    for k in ("LT", "LG", "C", "RG", "RT"):
        p.block(k, pts=[(0.15, 1.4)])                      # identical first steps
    go_to(p, "MIKE", (4.3, 4.4), "path"); go_to(p, "WILL", (4.3, 1.2), "path")
    go_to(p, "SAM", (3.8, 8.2), "path")
    if i == 0:
        go_to(p, "U", (0.4, -3.4), via=[(-0.5, -4.2)])     # cut off the end
        go_to(p, "BE", (1.0, -3.0), "path")
        go_to(p, "Y", (0.3, 5.9))
        go_to(p, "QB", (-3.6, 1.8), "path", speed=3.2)
        go_to(p, "RB", (2.5, 5.0), "run", via=[(-4.3, 2.6), (-1.3, 4.9)])
        p.route("X", [(0, 0), (9, 0)]); go_to(p, "Z", (4.0, 9.8))
        p.highlight("RB")
        f = draw(p, ax=ax, lateral=(-13, 12), window=(-9, 17.5), title=False)
        ax.set_title("Outside zone right", fontsize=9, loc="left", color=style.INK, fontweight="bold")
    else:
        go_to(p, "BE", (-2.2, 2.6), "path", via=[(0.4, -3.6), (-1.75, -2.6), (-2.0, 0.0)])  # chases the fake
        go_to(p, "QB", (-3.4, 1.6), "path", speed=3.2)                  # the same fake ...
        go_to(p, "QB", (-6.0, -7.5), "path", speed=4.5, delay=0.1)      # ... then roll the other way
        go_to(p, "RB", (1.0, 5.6), "path", via=[(-4.3, 2.6), (-1.3, 4.9)])
        p.route("U", [(0, 0), (1.5, 1.0), (4.5, 7.5)], delay=0.6)       # flat, boot side
        p.route("Y", [(0, 0), (1.2, -1.0), (4.5, -4.0), (7.0, -8.0), (7.5, -12.5)])  # inside the 5, then across
        p.route("X", [(0, 0), (14, 0.5)])                               # clear out
        p.route("Z", [(0, 0), (10, -1.0), (15, -10), (16, -17)])         # deep over, all the way across
        p.highlight("QB")
        f = draw(p, ax=ax, lateral=(-13, 12), window=(-9, 17.5), title=False)
        say(f, p, 2.4, -10.6, "flat", color=style.OFFENSE_DARK, fontsize=7)
        say(f, p, 8.6, -5.0, "cross", color=style.OFFENSE_DARK, fontsize=7)
        say(f, p, 16.2, -3.0, "over", color=style.OFFENSE_DARK, fontsize=7)
        point_to(f, p, (-7.6, 6.0), (-1.9, 0.6), "end chases\nthe fake", color=style.DEFENSE_DARK, fontsize=6.6)
        ax.set_title("Naked boot left, same first second", fontsize=9, loc="left", color=style.INK,
                     fontweight="bold")
    if i == 0:
        say(f, p, -6.8, -7.6, "first steps and linebacker\nflow: the same in both", color=style.MUTED, fontsize=6.6)
fig.tight_layout(w_pad=0.5)
plt.show()
Figure 16.14: The same first second. Left: outside zone right; the U cuts off the backside end. Right: a naked bootleg left off the same look. The line’s first steps, the back’s track and the linebackers’ flow are identical (grey note). What differs: on the boot, nobody blocks the backside end; if he chases the fake down the line onto the back’s track, he ends up behind a quarterback rolling away from him, who has three receivers at three depths on the boot side: the U in the flat, the Y on a crossing route (releasing inside the play-side end) and the Z on a deep over route.

The two plays look identical for the first second, which is the second that decides how the defense moves. (The “over” route is a deep crossing route: the receiver runs across the field 15 or more yards downfield, over the linebackers.) On a bootleg the backside end’s job is to contain the quarterback: stay outside him and force him back toward the pursuit. An end who chased the run fake (as outside zone has taught him to) is now behind a quarterback rolling away from him, and nobody is there to make the quarterback hurry. The linebackers who flowed with the line are a step or two the wrong way, and the crossing routes (receivers running across the field) come open behind them. The boot gives the quarterback three receivers at three depths on the same side: a short one in the flat, one crossing at linebacker depth, and one deep. That simple read is what makes the play so reliable.

Why the pair works. Each play protects the other. If the defense sits back and refuses to flow, outside zone gets the edge or the crease. If it flows hard, the bootleg punishes the flow. And because the two share the same first step, the defense cannot wait to find out which one it is facing. This is the backbone of the Shanahan-family offenses you will meet in 12-03: a run game and a play-action game built to be indistinguishable for as long as possible.

How to tell them apart after the snap. Three plays send a tight end or H-back at the backside end, and before the snap they can look the same. Watch what he does when he gets there:

  • He hits the end and drives him out: split zone.
  • He runs past the end without touching him and blocks the next man out (a linebacker or safety), while the quarterback rides the ball with the back and watches the end: arc.
  • He runs past the end into the flat and turns to look for the ball, while the quarterback pulls the ball and rolls the other way: bootleg.

The cost. A naked bootleg leaves the quarterback with nobody blocking the backside end. If that end does not bite on the fake (if he stays home), he is waiting for a quarterback who has turned his back to him. That is why the bootleg works only once outside zone has earned the defense’s respect.

Where zone came from

Running backs reading blocks is as old as football. Vince Lombardi’s Green Bay Packers of the 1960s ran their famous power sweep with a simple instruction to the ball carrier: run to daylight, wherever the blocks open it, a phrase that became the title of a 1963 book Lombardi wrote with W. C. Heinz.12 That sweep was a gap play with pulling guards, not a zone play, but its runner’s freedom to choose the hole is the same idea zone backs live by.

Who invented zone blocking is disputed, and nobody serious claims a single inventor. The best-documented claims put it in the NFL of the 1980s. Jim McNally, the Cincinnati Bengals’ offensive line coach, was one of the era’s most copied line coaches, and Cincinnati’s run game finished in the league’s top five every year from 1986 to 1990. McNally himself said, “I didn’t invent zone blocking, but we and the Cleveland Browns did it back in the ’80s,” and he described it as an answer to the rise of the 3-4 defense and its penetrating linemen. Cleveland’s line coach in those years was Howard Mudd, the same coach who later made the stretch a Colts signature.13 Coaches who credit older roots point to blocking ideas in earlier college offenses; treat any one-name “inventor” story with suspicion.

What is not in dispute is who made outside zone the identity of an NFL offense. Alex Gibbs, an offensive line coach with a famously blunt teaching style and a reputation as one of the best line coaches of his era, built the Denver Broncos’ running game under head coach Mike Shanahan from 1995.14 Denver had a specific problem to solve. Pittsburgh defensive coordinator Dom Capers had popularized the zone blitz, in which a linebacker blitzes and a lineman drops into coverage in his place, so the defenders a man-blocking line had assigned itself kept changing. “When you’re in a man scheme, you’re getting picked off and you look bad,” Gary Kubiak, then Denver’s offensive coordinator, later remembered.15 (In blocking, “picked off” means a blocker’s path is cut off by a defender he was not assigned, so his own man runs free: exactly the left side of Figure 16.2.) Blocking by area meant that whoever came was blocked.

Gibbs’s system was close to a religion: a small number of runs, repeated until the linemen could execute them against any front; light, quick linemen who could reach and run; backside cut blocks; and backs taught to press the aiming point and make one cut. His clinic tapes on zone running circulated widely among coaches and are still sold as coaching videos, and many of the phrases in this chapter descend from his teaching.16

Denver’s results became the advertisement. The Broncos won back-to-back Super Bowls after the 1997 and 1998 seasons, and running back Terrell Davis, a sixth-round draft pick, ran for 2,008 yards in 1998 and was named the league’s MVP.17 When injuries ended Davis’s peak, Denver kept producing 1,000-yard rushers with a string of other backs, several of them mid- or late-round picks, which convinced the league that the scheme was doing much of the work.18

The system spread through a coaching tree. Gary Kubiak carried it to Houston as head coach and back to Denver, where he won Super Bowl 50 after the 2015 season. Kyle Shanahan, Mike’s son, coached under Kubiak in Houston and under his father in Washington, then became the 49ers’ head coach in 2017. From Kyle Shanahan’s staffs came Sean McVay (Rams), Matt LaFleur (Packers) and others, and Kubiak’s son Klint called plays for the 2025 Seattle Seahawks before becoming the Raiders’ head coach for 2026.19 By late in the 2019 season, ESPN’s charting found zone blocking in use by all 32 teams and on at least half of the runs of most of them; LaFleur’s Packers led the league at 70.3% of runs (same ESPN study). The tree and its offense get a full case study in 12-03.

NoteFilm room: Denver Broncos, Super Bowl XXXII (1997 season)

The game: Super Bowl XXXII, January 25, 1998: Denver 31, Green Bay 24. Terrell Davis carried 30 times for 157 yards and three touchdowns and was named MVP, despite a migraine that blurred his vision and kept him out of part of the second quarter.20 Coaches’ film from the 1990s is hard to find, but Super Bowl broadcasts are the easiest games of the era to track down, and this one is dominated by Gibbs’s zone running (Denver mixed in other runs and play-action too).

What to notice:

  • The line’s first step. Every lineman moves laterally together; you will seldom see a Denver guard pull.
  • Davis’s patience. He runs at the tight end’s outside leg for two or three steps and does not cut until the end commits. Then he cuts once, hard, and is going north.
  • The backside. Watch the defensive linemen away from the play. Many end up on the ground in the first second: that is the backside cut, and it is why Davis’s cutbacks so often had nobody in them.
  • The bootleg. John Elway faking the stretch and rolling away is the other half of the same system.
NoteFilm room: San Francisco 49ers 2019

The game: the NFC Championship Game after the 2019 season, 49ers vs. Green Bay Packers, January 19, 2020. San Francisco won 37–20 and threw the ball only eight times; running back Raheem Mostert, a former undrafted free agent, ran for 220 yards and four touchdowns.21

What to notice:

  • How often the 49ers ran the wide-zone family, and how little they disguised it. They were not a pure zone team (the same ESPN charting had them using zone on 55% of their runs that season), so gap runs and tosses came off the same formations. Make it a drill: classify each run with this chapter’s Watch-for-it checklist (does the whole line step together, or does a guard pull?).
  • The linebackers. As the game goes on, watch them flow harder and harder to the play-side, and watch the cutbacks and the inside creases that opens.
  • Mostert’s runs: many of his biggest gains come on one cut, at full speed, into a crease that appeared only after the defense flowed.
NoteFilm room: Seattle Seahawks, Super Bowl LX (2025 season)

The game: Super Bowl LX, February 8, 2026: Seattle 29, New England 13, the end of Klint Kubiak’s single season as Seattle’s offensive coordinator (he became the Raiders’ head coach for 2026, so this is one season’s offense, not Seattle’s current one). Running back Kenneth Walker III carried 27 times for 135 yards and was named MVP.22 Kubiak’s offense descends directly from the Gibbs-Shanahan-Kubiak tree, built on outside zone from tight, two-tight-end formations and the bootlegs that pair with it.23

What to do: watch Walker’s 27 carries with this chapter’s checklist. For each one, call it zone or gap (does the whole line step together?), inside or outside (up or across?), and bang, bend or bounce. Then count the bootlegs and play-action passes that started with the same first step. It is the 2019 49ers’ film, a quarter-century after Denver.

One more modern example worth finding: Christian McCaffrey’s 2023 season in San Francisco, when he led the NFL with 1,459 rushing yards and was named Offensive Player of the Year.24 He is not a pure one-cut back (he will press, hop sideways and cut again), which makes him a good contrast with Davis and Mostert: watch how he uses the same aiming points with a different running style.

Does it work? Reading the numbers

You might expect a data source to tell us how well zone runs work. It cannot, directly, and the reason is worth understanding before looking at any chart.

The NFL’s play-by-play data (which nflverse packages for free) records where a run went, not what play was called. Each run gets a run location (left, middle or right) and, unless it went up the middle, a run gap (guard, tackle or end). These are charted by the league’s scorers from where the ball carrier crossed the line, and they are coarser than the gap letters of 03-01: roughly, “middle” is between the guards (the A gaps), “guard” is over or just outside a guard (the B gap), “tackle” is over or just outside a tackle (the C gap), and “end” is outside the last man on the line. There is no “zone” flag. So a zone run that cuts back is logged where the back ended up, not where the play was aimed. (Commercial charting services such as PFF, Pro Football Focus, do label run concepts by watching film. In the sample of their labels released with the 2025 Big Data Bowl (2022 season), outside zone was the single most common run concept.25 That is the most recent public count we know of; no league-wide zone share for 2025 has been published that we could check.)

So to study zone we need a proxy: a team we know runs a lot of zone. We use Kyle Shanahan’s 49ers. LaFleur’s Packers ran an even higher share of zone in ESPN’s 2019 count, and would also do; the 49ers are the root of the coaching tree and the subject of the 12-03 case study, and Shanahan was their head coach for every season in the chart. (The Packers’ number appears below too.)

One more thing before the chart: expect negative numbers. Across the league, the average running-back carry loses a little expected value, because a typical run gains less than the down and distance needs to keep the offense’s scoring chances where they were. So “good” on this chart means “less negative than the league,” and a run game is judged by how far above the league line it sits, not by whether it clears zero.

With those caveats, here is the 49ers’ efficiency by run location against the league average from 2019 to 2025. The measures are EPA per rush (how much each run changed the offense’s expected points, on average; above zero is good for the offense) and success rate (the share of runs with positive EPA). Only running back and fullback carries count, so quarterback runs and receivers’ jet sweeps and end-arounds, which are not zone runs, stay out.

Show the Python
from gridiron.data import pbp, nfl

style.apply()
SEASONS = list(range(2019, 2026))
cols = ["season", "season_type", "posteam", "play_type", "run_location", "run_gap", "epa",
        "success", "qb_scramble", "qb_kneel", "down", "rusher_player_id"]
plays = pbp(SEASONS, columns=cols)
rosters = nfl().load_rosters(SEASONS).to_pandas()
back_ids = set(rosters.loc[rosters["position"].isin(["RB", "FB"]), "gsis_id"].dropna())

runs = plays[(plays["season_type"] == "REG") & (plays["play_type"] == "run")
             & (plays["qb_scramble"] == 0) & (plays["qb_kneel"] == 0)
             & plays["epa"].notna() & plays["down"].notna() & plays["run_location"].notna()
             & plays["rusher_player_id"].isin(back_ids)].copy()
runs["lane"] = np.where(runs["run_location"] == "middle", "Middle", runs["run_gap"].str.title())
runs = runs[runs["lane"].isin(["Middle", "Guard", "Tackle", "End"])]
LANES = ["Middle", "Guard", "Tackle", "End"]

def by_lane(df):
    return df.groupby("lane").agg(n=("epa", "size"), epa=("epa", "mean"),
                                  sr=("success", "mean")).reindex(LANES)

lg, sf = by_lane(runs), by_lane(runs[runs["posteam"] == "SF"])
gap = sf["epa"] - lg["epa"]
team = runs.groupby("posteam")["epa"].mean().sort_values(ascending=False)
sf_rank = list(team.index).index("SF") + 1
gb_rank, gb_all = list(team.index).index("GB") + 1, team["GB"]
n_pos = int((team > 0).sum())
lg_all, sf_all = runs["epa"].mean(), runs.loc[runs["posteam"] == "SF", "epa"].mean()
ordinal = lambda n: f"{n}{'th' if 10 <= n % 100 <= 20 else {1: 'st', 2: 'nd', 3: 'rd'}.get(n % 10, 'th')}"
pct = lambda v: f"{100 * v:.0f}%"

fig, axes = plt.subplots(1, 2, figsize=(6.6, 3.3))
x = np.arange(len(LANES))
for ax, col, ttl, fmt in [(axes[0], "epa", "EPA per rush", "{:+.2f}"),
                          (axes[1], "sr", "Success rate (axis from 30%)", "{:.0%}")]:
    for frame, name, color in [(sf, "49ers", style.SERIES[0]), (lg, "League", style.SERIES[1])]:
        ax.plot(x, frame[col], color=color, lw=2, marker="o", ms=7, mec=style.SURFACE, mew=1.5,
                label=name, zorder=3)
        ax.annotate(f"{name} {fmt.format(frame[col].iloc[-1])}", (x[-1], frame[col].iloc[-1]),
                    xytext=(7, 0), textcoords="offset points", va="center", fontsize=7.5, color=style.INK_2)
    if col == "epa":
        ax.axhline(0, color=style.BASELINE, lw=1, zorder=1)
    else:
        ax.set_ylim(0.30, 0.48)
    ax.set_xticks(x, [f"{l}\n{lg.loc[l, 'n'] / 1000:.1f}k" for l in LANES], fontsize=7.5)
    ax.set_xlim(-0.3, 4.1)
    ax.set_title(ttl, fontsize=10)
    ax.tick_params(axis="y", labelsize=7.5)
    ax.grid(axis="x", visible=False)
axes[1].yaxis.set_major_formatter(plt.FuncFormatter(lambda v, _: f"{v:.0%}"))
axes[0].legend(loc="upper left", fontsize=7.5)
fig.supxlabel("Where the run went, from the middle out (league carries in each lane)", fontsize=8, color=style.INK_2)
fig.tight_layout()
plt.show()
Figure 16.15: Rushing efficiency by run location, 49ers vs. the league, 2019-2025 regular seasons (running back and fullback carries only; runs pooled across left and right). Nearly every value is below zero: the average carry loses a little expected value. Runs to the end look best for everyone, partly by selection (explained below). The 49ers beat the league average in every lane, by small margins. Note the success-rate axis starts at 30%, so its gaps look bigger than they are. Data: nflverse play-by-play and rosters via nflreadpy.

Four things to read from Figure 16.15.

Runs that reach the end are the least bad, for everyone. League-wide, running back carries logged at the end averaged -0.022 EPA per rush, against -0.083 up the middle. That does not mean “always run outside.” It means that when a run gets outside, it is usually because the edge was open, and the runs that tried to get outside and failed were often logged somewhere else (or as losses at the tackle). This is a selection effect (backs only go outside when the edge is open, so the runs that get there are the lucky ones), and it is why no coordinator reads this chart as a play-calling instruction.

The 49ers were a little better everywhere, most of all at the two ends of the chart. Their EPA edge over the league was +0.031 per carry at the end and +0.025 up the middle, against +0.015 at guard and +0.011 at tackle. That fits outside zone’s two big answers, the bounce (logged at the end) and the cutback (often logged up the middle), but the gaps are small, a few hundredths of a point per carry, and the chart cannot prove the scheme caused them.

Success rate tells a slightly different story. San Francisco’s success rate beat the league’s by 2.6 points at guard and 2.5 up the middle, but only 0.2 at tackle. Success rate rewards steady, positive gains; EPA also rewards big ones. A team can be consistent inside and explosive outside, and the two panels let you see both.

Overall, good, not magic. Across all seven seasons the 49ers’ running back carries averaged -0.043 EPA per rush against a league average of -0.064, ranking 9th of 32 teams; only one team averaged above zero. LaFleur’s Packers, the other famous zone offense of the period, averaged -0.010 and ranked 2nd. So two of the period’s best-known zone offenses landed in quite different places, both above the league average. That spread is the lesson: zone is one input to a run game, alongside the backs, the linemen, the quarterback and what the passing game makes defenses fear. Part of the 49ers’ edge is surely talent rather than scheme (McCaffrey, the 2023 Offensive Player of the Year, carried for them), and run-location data cannot separate the two; that would take play-level scheme labels and a model of player quality. Teams still run, even though the average carry loses a little expected value, because a run game does things a single carry’s EPA does not capture: it keeps the defense honest, it shortens third downs, and above all it sets up the play-action passes that look like it. You will see that argument tested with data in 13-02.

CautionCommon misconception

“Run location tells you which runs a team called.” It tells you where the ball carrier went. On zone runs especially, those are different things: an outside zone that cuts back is logged up the middle. Treat run-location splits as a picture of outcomes, and be suspicious of anyone who ranks “best run plays” from them.

TipWatch for it

On Sunday: bang, bend, bounce. You cannot watch everything in two seconds, so watch in this order.

Before the snap (you have time here)

  • Count the tight ends and find the running back. Two tight ends and a back directly behind the quarterback (or in the pistol) is a natural zone look. In the shotgun, an inside-zone back usually runs away from the side he lines up on, crossing the quarterback’s face. (How deep the back stands varies too much by team to be a reliable tell on its own.)
  • Find the backside end, the defender farthest from where you think the play is going. Remember where he is; you will check on him after the play.

The first half-second: watch the line, nothing else

  • Do all five linemen step the same way? Zone. Does a guard pull? Gap scheme (03-03). Double teams but no zone steps, and the back aiming straight at a linebacker? Probably duo, also in 03-03.
  • Are the linemen’s helmets going up (inside zone) or across (outside zone)? The high end-zone replay angle shows this best (01-06); on the live sideline angle, look for the whole line drifting toward one sideline.

Then: watch the back’s feet

  • Where is he aiming: the guard, or the tight end? Wider than the tight end is stretch.
  • Watch him press, plant and cut. Call it as it happens: bang (play-side gaps), bend (back against the flow) or bounce (outside the end).

After the play (on the replay)

  • Did a tight end or H-back go at the backside end? Hit him: split zone. Ran past him to the next man: arc. Slipped into the flat looking for the ball: bootleg. Did someone lead up into the line? Insert.
  • Where was the backside end when the back made his cut? On the ground (cut), chasing (and how close), or blocked?
  • If the defense has been flowing hard all game, start watching for the bootleg off the same look.

For your prediction log (01-06): before each zone run write I (inside), O (outside) or S (split) from the alignment; afterwards write which of bang, bend or bounce the back chose.

Predict the play

TipPredict the play

Drill 1. First-and-10 from your own 40. The offense is in the shotgun with one back and one tight end (11 personnel); the tight end is in-line on the right and the running back is offset to the quarterback’s left. The defense is in nickel with two deep safeties: six defenders in the box against six blockers. Its linemen are a 5 and a 1 on the left, and a 3 and a 7-technique (on the tight end’s inside shoulder) on the right. The offense calls inside zone. Which way is it most likely going, does the front change that, and why does the defense’s picture make a run attractive here?

Show the Python
off = named_line(offense("gun_2x2"))
off = [q.moved(d=-0.7, w=4.8) if q.key == "Y" else (q.moved(w=-2.0) if q.key == "RB" else
       (q.moved(d=-1.5) if q.key == "Z" else q)) for q in off]          # Z off the ball: 7 on the line
from gridiron import defense
DL_TECH = {"SDE": "7", "SDT": "3", "WDT": "1", "WDE": "5"}
dfn = []
for q in defense("nickel", "two_high", off):
    if q.key == "NB":
        q = q.moved(d=5.0, w=-8.5, label="NB")
    elif q.key in DL_TECH:
        q = q.moved(label=DL_TECH[q.key])
    elif q.pos == "CB":
        q = q.moved(label="CB")
    dfn.append(q)
p = Play(off, dfn, los=40, to_go=10, title="Drill 1: 1st and 10, gun, 11 personnel")
f = draw(p, lateral=(-17.5, 17.5), window=(-8, 13))
say(f, p, -6.9, -5.6, "RB offset to\nthe QB's left", fontsize=7)
plt.show()
Figure 16.16: Drill 1: gun, 11 personnel, back offset to the quarterback’s left, tight end in-line on the right; nickel defense (NB is the nickel back) with two deep safeties and six in the box. The 7 is a 7-technique, on the tight end’s inside shoulder.

Most likely to the right, toward the tight end. From the shotgun, inside zone usually has the back cross the quarterback’s face: he lines up on one side and runs to the other, which gives him a running start toward the aiming point and a downhill angle at the mesh. With the tight end on the right too, the right side is also where the offense has its extra blocker.

Does the front change it? Not the direction. Run the rules to the right: the RG is covered by the 3 and the RT by the 7, so the RG has no uncovered neighbor to help him and the 3-technique is the hardest block on the play side. That tells you where trouble is likely (a 3 who wins knocks the back off his track, and he bends), not which way the play is called. The back’s alignment is the stronger tell.

Why run here: two deep safeties and six in the box means six blockers for six defenders: “hat on a hat,” a fair fight up front, with both safeties starting 11–12 yards away. That is exactly the look zone teams want to run against, and it is a common look now: two-high shells rose from about a third of snaps in 2018 to 42% in 2025.26

The catch: good defenses know the “cross the face” tendency too, which is why offenses mix in same-side zone and the pistol. If you see a team do that a lot, that is why.

TipPredict the play

Drill 2. Outside zone to the right is called. The play-side end (on the offense’s right) is lined up wide, outside the tight end in a 9-technique, and the Sam linebacker lines up off the ball behind the right tackle. Before the snap, use the rules: who blocks the 9, who blocks the Sam, and where is the crease most likely to be? Which of bounce, bang or bend does that make the favorite?

Show the Python
dfn = even_front(+1, cb_w=10.0)
dfn = [q.moved(w=6.0, label="9") if q.key == "PE" else q for q in dfn]
dfn = [q.moved(d=4.5, w=3.4) if q.key == "SAM" else (q.moved(w=1.0) if q.key == "MIKE" else q) for q in dfn]
p = Play(ace_condensed(), dfn, los=40, to_go=10, title="Drill 2: outside zone right is called")
go_to(p, "RB", (-1.3, 4.9), "run", via=[(-4.3, 2.6)])
f = draw(p, width_in=5.4, lateral=(-12, 12), window=(-8, 12.5))
spot(f, p, -0.2, 5.3)
say(f, p, 2.9, 8.6, "end aligned\nwide (9-tech)", color=style.DEFENSE_DARK, fontsize=7)
plt.show()
Figure 16.17: Drill 2: outside zone right (the back’s track to the aiming point is shown), against a play-side end aligned wide in a 9-technique.

Most likely bang, inside the end. Run the rules. The tight end is covered by a man lined up outside him, the edge case with no help: he has to block the 9 alone, and reaching him (getting the tight end’s head across his outside shoulder) is close to impossible, so his job becomes “ride him wider.” The right tackle now has nobody on him and nobody in his play-side gap: uncovered. His backside neighbor, the right guard, is uncovered too (the 1 sits in the center’s play-side gap, so the RG helps the center), so the right tackle has nobody to double and climbs straight to the Sam stacked behind him. The back’s first read is the end: he will not be pinned inside, so bounce is off. But a wide end riding wider stretches the gap inside him, so the crease is likely to appear between the tight end and the tackle, in the Sam’s gap. If the right tackle gets to the Sam, bang.

What would make it bend: that is the second read. If the Sam beats the right tackle into that gap, or the Mike scrapes hard over the top to fill it, the back’s third answer is the cutback. A wide 9-technique is a defense saying “we will not let you have the edge”; outside zone’s answer is to stop trying for it and take what the alignment gives.

TipPredict the play

Drill 3. Third time this drive: the offense lines up in the same two-tight-end set it has run outside zone right from twice already. Both times the backside end (on the offense’s left) beat the U’s cut-off by crashing hard inside him at the snap, then flattened down the line and chased the back from behind (the orange arrow shows what he did; the faint dashed line is the back’s track on those runs). It is second-and-6. What call punishes him?

Show the Python
p = Play(ace_condensed(), even_front(+1, cb_w=10.0), los=40, to_go=6,
         title="Drill 3: the same look, third time this drive")
go_to(p, "BE", (-3.0, 1.4), "path", via=[(0.3, -4.0), (-1.3, -3.9), (-2.5, -1.6)])
f = draw(p, width_in=5.4, lateral=(-12, 12), window=(-8, 12.5))
branch(f, p, [(-7.0, 0.0), (-4.3, 2.6), (-1.3, 4.9), (1.5, 5.6)], color=style.MUTED, lw=1.3, dash=(0, (2, 2.5)))
say(f, p, -3.4, -7.2, "what this end did on\nthe last two zone runs", color=style.DEFENSE_DARK, fontsize=7)
plt.show()
Figure 16.18: Drill 3: the same two-tight-end look for the third time. The orange arrow shows what the backside (left) end did on the last two outside zone runs: crash inside the U at the snap, then flatten behind the line, chasing the back’s track (faint dashes).

A bootleg the other way (left), probably naked. An end who crashes hard on every outside-zone fake is the exact defender the bootleg is built to beat: the quarterback fakes outside zone right, the end chases the fake, and the quarterback rolls left behind him with the flat open and a crosser coming across. The end has been beating the U’s cut-off anyway, so the boot turns his speed into a liability: the harder he crashes, the farther behind the quarterback he ends up. Second-and-6 is a comfortable down for it, too: even a short completion in the flat keeps the offense on schedule.

A second good answer: split zone, with a tight end kicking out that end. If the end is going to crash, block him and let the back cut back behind him. Coaches choose between the two by asking whether they want to punish the end (the boot, for a potential big play) or neutralize him (split zone, for a safer run). Either way, his habit has become information, and that is how a zone offense talks to itself across a drive.

TipPredict the play

Drill 4. This one is after the snap. Shotgun, back offset to the quarterback’s left, an H-back off the ball on the left. Figure 66.12 shows the first second: everyone’s first steps and paths. Inside or outside zone? Which tag is this? What is the quarterback looking at, and what does he do if that man chases the back?

Show the Python
off = [q for q in named_line(offense("gun_2x2")) if q.key in (*OL_NAMES, "QB", "Y", "Z", "X")]
off = [q.moved(d=-0.7, w=4.8) if q.key == "Y" else (q.moved(d=-1.5) if q.key == "Z" else q) for q in off]
off += [Player("H", "TE", "off", -1.5, -6.6, label="H"), Player("RB", "RB", "off", -5.0, -1.6, label="R")]
dfn = [q for q in front7() if q.key != "SAM"] + [D("SS", "SS", 5.0, -9.6, "SS"), D("NB", "NB", 4.5, 8.0, "NB")]
p = Play(off, dfn, los=40, to_go=10, title="Drill 4: name the play and the tag")
p.block("C", pts=[(0.9, 0.5)]); p.block("RG", pts=[(0.8, -0.8), (4.3, -0.4)])
p.block("RT", pts=[(0.9, 0.6)]); p.block("Y", pts=[(0.6, -0.6), (3.6, 1.5)])
p.block("LT", pts=[(0.9, 0.7)]); p.block("LG", pts=[(0.8, -0.6), (4.3, -0.8)])
go_to(p, "H", (4.1, -9.3), via=[(0.4, -7.6), (2.6, -9.0)])
go_to(p, "RB", (-1.4, 2.3), "run", via=[(-4.0, -0.4)])
p.read("BE")
f = draw(p, width_in=5.6, lateral=(-12.5, 11), window=(-8, 9))
plt.show()
Figure 16.19: Drill 4: the first second after the snap. Lines ending in a bar are blocks (look at the direction of each lineman’s first step); the dashed line from the quarterback shows where his eyes are.

Inside zone right, with an arc tag. The linemen’s first steps go up, not across, and the back is crossing the quarterback’s face toward the right B gap: inside zone. The H runs past the backside end without touching him and heads for the safety outside him: that is an arc block, not split zone (he would hit the end) and not a bootleg (he would turn into the flat and look for the ball). The quarterback is reading the unblocked backside end. If the end stays home, he hands off. If the end chases the back down the line, he pulls the ball and runs around the end, behind the H’s block on the safety.

Takeaways

  • Zone blocking assigns blockers by rule, not by name: step play-side; block the man head-up on you or in your play-side gap; if nobody is, help the neighbor on your backside and climb to a linebacker. Because the rules are applied after the snap, slants and blitzes get picked up, and the same call re-pairs itself against every front.
  • Inside zone attacks the guard-tackle area with double teams that drive defenders backward; outside (wide) zone aims at the tight end’s outside leg and moves the defense sideways with reach-and-overtake blocks; stretch is the widest track, edge first; split zone adds a crossing H to kick the backside end. Tell them apart by the line’s first step (up or across) and the back’s aiming point.
  • The running back makes the play’s last decision: press the aiming point, then bang, bend or bounce, with one cut. On inside zone the order is bang-bend-bounce; on outside zone it is bounce-bang-bend.
  • The cutback is designed, not improvised: it works because the defense over-runs the play and the backside cut-off keeps the backside defenders out of the lane (in Gibbs’s Denver, often with a cut block, a legal but controversial low block that the rules have steadily narrowed).
  • Tags change one or two jobs to fix one problem: insert adds a lead blocker, arc runs past the unblocked end to block the next man while the quarterback reads the end, bash sends the back away and makes the quarterback the inside runner. Defenses fight back with penetration, a cutback player and coordinated run fits.
  • Outside zone’s biggest payoff is the bootleg that looks identical for the first second. The data shows zone running is efficient for a run game, not magic; its value is in what it sets up.

Connections

Builds on: The Language of the Run Game (gaps, techniques, covered and uncovered, the core blocks) and the EPA primer in Downs, Distance, and Field Position.

Sets up:

See also (case study): The Shanahan Tree: Wide Zone, Boots, and the Illusion of Complexity.

If you want to go deeper: Chris B. Brown’s The Art of Smart Football and his Smart Football writing on the inside and outside zone; Alex Gibbs’s zone-running clinic tapes, still widely circulated among coaches; and the Super Bowl XXXII broadcast and the 2019 49ers’ All-22, watched with nothing but the line’s first step and the running back’s feet in mind.

NoteGo deeper

Names you will hear. Zone vocabulary is a dialect map. Alex Gibbs called inside zone tight zone, and many coaches still do. Some analysts describe a mid zone between inside and outside zone, in which the play-side tackle pushes the end outward instead of trying to reach him, so the back’s read moves to the defensive tackles; one coach-analyst used the name for Sean McVay’s Rams’ base run.27 Split zone is also called zone slice, and bash is sometimes spelled out as back away. And duo, a two-back or one-back run with double teams that a casual viewer can mistake for inside zone, is not a zone play at all: the linemen do not take zone steps and the back reads a linebacker. It belongs to the gap family in 03-03.

NoteGo deeper

From diagrams to real tracking data. Every animation in this chapter is a gridiron simulation written in NFL Big Data Bowl (BDB) coordinates, the format of the league’s public tracking-data competition, so real tracking data drops into the same drawing code. The 2025 Big Data Bowl release (2022 season, weeks 1–9) includes pre-snap and post-snap frames for every player, and its plays.csv carries a run-concept label from PFF, so you can pull real outside-zone runs and watch the line step together. The data is hosted on Kaggle (a data-science competition site) and needs your own free login, so the code for this (in the web edition of this chapter, under “Show the Python”) is not run when this 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")
oz = plays[plays["pff_runConceptPrimary"].astype(str).str.upper().str.contains("OUTSIDE ZONE")]
print(len(oz), "outside zone runs")
g, pl = oz.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.0, 0.5, 1.0, 1.5, 2.0, 2.6])   # same call as the simulated plays

  1. The play-side-gap rule (“block the player in your play side gap”): Chris Haddad, “Inside Zone Install Guide,” vIQtory Sports (updated Jan 27, 2026): https://www.viqtorysports.com/complete-inside-zone-guide-tutorial/.↩︎

  2. Mike Kuchar, “Answering the 5 most common questions in zone combinations,” USA Football (Oct 15, 2015): https://blogs.usafootball.com/blog/1344/answering-the-5-most-common-questions-in-zone-combinations. In its coaches’ survey, 42.1% taught linemen to come off the double team when they see the linebacker work underneath or over the top of it, and 35.7% when the linebacker reaches the blocker’s level. The same article covers naming the combination blocks and how terminology varies by staff (one system calls the tight end-tackle, tackle-guard and center-guard pairs “Ted,” “Tag” and “Cage”).↩︎

  3. Mike Kuchar, “Strategies for blocking covered vs. uncovered in inside zone runs,” USA Football (Sep 24, 2015): “If the near hip slants to the backside gap – the uncovered lineman’s open gap – the uncovered offensive lineman will punch near number and the block will turn into a combination block”: https://blogs.usafootball.com/blog/590/strategies-for-blocking-covered-vs-uncovered-in-inside-zone-runs.↩︎

  4. Mark Staten, “The ins and outs of Michigan State’s outside zone play,” Coaches Insider (Mar 4, 2015): footwork “lateral lead to position, through the crotch of the defender, up the field,” with the inside hand driven “through his chest”: https://coachesinsider.com/football/the-ins-and-outs-of-michigan-states-outside-zone-play-article/.↩︎

  5. Doug Farrar, “Play of the Day: Stretching the Defense,” Sports Press Northwest, Nov 30, 2010 (Mudd “made this play the staple of the Indianapolis Colts running game through the last decade”): https://www.sportspressnw.com/2108372/2010/play-of-the-day-stretching-the-defense; X&O Labs on the Colts’ stretch with Manning under center and Edgerrin James and Joseph Addai: https://www.xandolabs.com/?p=5409. Mudd was the Colts’ line coach 1998–2009: https://en.wikipedia.org/wiki/Howard_Mudd.↩︎

  6. Chris B. Brown, The Art of Smart Football (2015), and his Smart Football posts on the inside zone (https://smartfootball.com/) describe the read and its variations. Terminology for the read differs by coach. On the “one-cut-and-go” runner Gibbs’s system demands, see Chris B. Brown, Grantland, Jan 10, 2012: https://grantland.com/features/chris-brown-gary-kubiak-houston-texans-running-game/.↩︎

  7. NFL Rulebook, Rule 12, Section 2 (blocks below the waist, chop blocks), at NFL Football Operations: https://operations.nfl.com/the-rules/nfl-rulebook/. Tight end box (2021: two yards outside each tackle, five yards either side of the line of scrimmage): ESPN, “How NFL rule changes for 2021 impact the game”: https://www.espn.com/nfl/story/_/id/32133796/how-nfl-rule-changes-2021-impact-game-fewer-low-blocks-expanded-review-balanced-holding-calls. Peel-back blocks banned everywhere (2013) and all chop blocks banned (2016): NFL, “Health and safety-related rules changes since 2002”: https://www.nfl.com/playerhealthandsafety/equipment-and-innovation/rules-changes/nfl-health-and-safety-related-rules-changes-since-2002; NFL.com, “NFL eliminates all chop-style blocks for 2016 season” (Mar 22, 2016): https://www.nfl.com/news/nfl-eliminates-all-chop-style-blocks-for-2016-season-0ap3000000646551.↩︎

  8. Associated Press, “Cutting remarks irk Shanahan,” Oct 29, 2004 (George Foster’s cut block on the Bengals’ Tony Williams; criticism from Marvin Lewis, Bill Cowher and ABC’s Al Michaels and John Madden): https://www.postbulletin.com/news/cutting-remarks-irk-shanahan. Chris B. Brown calls Gibbs’s backside cuts “sometimes controversial, but … legal” (Grantland, Jan 10, 2012: https://grantland.com/features/chris-brown-gary-kubiak-houston-texans-running-game/).↩︎

  9. “What Is: A Scrape Exchange,” MGoBlog: the end crashes down the line and a linebacker scrapes to the area he vacated, so a quarterback who keeps because he sees the end crash finds the linebacker where he meant to run: https://mgoblog.com/content/what-scrape-exchange.↩︎

  10. “Bash” = “back away”: the back runs away from the line’s zone flow and the quarterback becomes the inside runner. USA Football, “Utilizing the Bash Concept in the Run Game”: https://blogs.usafootball.com/blog/7772/utilizing-the-bash-concept-in-the-run-game; Buckeye Huddle, “Chalk Talk: The Zone Bash” (Feb 14, 2023): https://buckeyehuddle.com/2023/02/14/chalk-talk-the-zone-bash/. The name and the exact read vary by team.↩︎

  11. On spill and box (“squeeze”) techniques against a kick-out block on split zone, see Jon Svec, “Defending Split Zone,” Jan 12, 2022: https://jonsvec.substack.com/p/defending-split-zone.↩︎

  12. Vince Lombardi with W. C. Heinz, Run to Daylight! (Prentice-Hall, 1963). On the Packers’ power sweep, see the Pro Football Hall of Fame’s Lombardi biography: https://www.profootballhof.com/players/vince-lombardi/.↩︎

  13. Geoff Hobson, “The mouse that roared,” Bengals.com, Jan 14, 2008 (McNally’s quote; the Bengals “never finished below fifth and led the NFL twice” in rushing from 1986 to 1990; the scheme as “an antidote [to] the rise of the 3-4 defense and its ability to penetrate”): https://www.bengals.com/news/the-mouse-that-roared-399461. Mudd was the Browns’ offensive line coach 1983–1988: https://en.wikipedia.org/wiki/Howard_Mudd.↩︎

  14. Gibbs coached Denver’s line 1984–87 and again 1995–2003, and died July 12, 2021, aged 80: https://en.wikipedia.org/wiki/Alex_Gibbs_(American_football); ProFootballTalk, “Alex Gibbs dies at 80” (Jul 12, 2021): https://profootballtalk.nbcsports.com/2021/07/12/alex-gibbs-dies-at-80/.↩︎

  15. Kevin Seifert, “The secret to the NFL’s best rushing teams: Why zone blocking is here to stay,” ESPN, Dec 23, 2019 (Kubiak on Capers’s “zone dogs”; Packers 70.3% zone runs, league-leading; 49ers 55%; zone used by all 32 teams and at least half the time by a majority): https://www.espn.com/nfl/story/_/id/28353469/the-secret-nfl-best-rushing-teams-why-zone-blocking-here-stay.↩︎

  16. Gibbs’s clinic material is still sold to coaches, e.g. “Alex Gibbs: Outside Zone, Tight Zone, Boots and Thoughts on the Power” on CoachTube: https://coachtube.com/course/football/alex-gibbs-outside-zone-tight-zone-boots-and-thoughts-on-the-power/14602600. On his influence, see Chris B. Brown, Grantland, Jan 10, 2012: https://grantland.com/features/chris-brown-gary-kubiak-houston-texans-running-game/.↩︎

  17. Pro Football Hall of Fame, Terrell Davis (inducted 2017; sixth round, 196th overall, 1995): https://www.profootballhof.com/players/terrell-davis/; Pro Football Reference, Terrell Davis: https://www.pro-football-reference.com/players/D/DaviTe00.htm.↩︎

  18. After Davis, Denver’s 1,000-yard rushers under Shanahan were Olandis Gary (1999, fourth round), Mike Anderson (2000 and 2005, sixth round), Clinton Portis (2002–03, second round), Reuben Droughns (2004, third round, drafted by Detroit) and Tatum Bell (2006, second round). Pro Football Reference, Denver Broncos team pages: https://www.pro-football-reference.com/teams/den/; Westword, “Shanny’s spare parts”: https://www.westword.com/news/shannys-spare-parts-5084747/; https://en.wikipedia.org/wiki/Reuben_Droughns.↩︎

  19. Pro Football Reference coaching pages for Gary Kubiak, Kyle Shanahan, Sean McVay and Matt LaFleur (https://www.pro-football-reference.com/coaches/); https://en.wikipedia.org/wiki/Gary_Kubiak; https://en.wikipedia.org/wiki/Kyle_Shanahan; on the 2010–13 Washington staff (Kyle Shanahan OC, LaFleur quarterbacks, McVay tight ends): https://www.cbssports.com/nfl/news/dolphins-hiring-mike-mcdaniel-four-of-nfls-youngest-head-coaches-worked-together-on-same-staff-in-2013. Klint Kubiak’s 2025 Seattle role and 2026 Raiders hiring are in this book’s checked facts (planning/FACTS-current.md, §1 and §9).↩︎

  20. Super Bowl XXXII (Jan 25, 1998; Denver 31, Green Bay 24; Davis 30 carries, 157 yards, 3 TD, MVP; the second-quarter migraine): https://en.wikipedia.org/wiki/Super_Bowl_XXXII; Pro Football Hall of Fame, Terrell Davis: https://www.profootballhof.com/players/terrell-davis/.↩︎

  21. Pro Football Reference box score, NFC Championship, January 19, 2020: https://www.pro-football-reference.com/boxscores/202001190sfo.htm; ESPN, “49ers RB Raheem Mostert runs over Packers for 220 yards, 4 TDs” (Garoppolo 6 of 8 passing): https://www.espn.com/nfl/story/_/id/28519341/49ers-rb-raheem-mostert-runs-packers-220-yards-4-tds.↩︎

  22. Super Bowl LX, February 8, 2026: https://en.wikipedia.org/wiki/Super_Bowl_LX; staff per https://en.wikipedia.org/wiki/2026_Seattle_Seahawks_season.↩︎

  23. Kubiak’s “signature outside-zone scheme” and its bootleg and play-action pairing: Everett Herald, “Klint Kubiak completes install of new Seahawks offense” (Aug 13, 2025): https://www.heraldnet.com/2025/08/13/klint-kubiak-completes-install-of-new-seahawks-offense/. Seattle’s 2025 condensed formations (second-highest rate) and league-best 7.5 yards per play in 12 personnel: NFL.com Next Gen Stats trend watch: https://www.nfl.com/news/nfl-trend-watch-heavy-personnel-could-shape-super-bowl-lx-showdown-between-patriots-and-seahawks.↩︎

  24. Pro Football Reference, Christian McCaffrey: https://www.pro-football-reference.com/players/M/McCaCh01.htm; NFL.com, “Niners RB Christian McCaffrey named AP 2023 NFL Offensive Player of the Year”: https://www.nfl.com/news/niners-rb-christian-mccaffrey-named-ap-2023-nfl-offensive-player-of-the-year.↩︎

  25. The BDB 2025 plays.csv header includes pff_runConceptPrimary, pff_runConceptSecondary and pff_runPassOption; the most common primary value is OUTSIDE ZONE. See public solution repos, e.g. https://github.com/cadenweigel/NFLPreSnap (reports/basic_analysis.txt) and https://github.com/AlexJurcich/NFL_Optimization_Project (Zone_vs_Gap.py).↩︎

  26. NFL Next Gen Stats: split-safety coverage rate 32.9% in 2018, 42.0% in 2025, the highest since tracking began: https://www.nfl.com/news/the-coverage-that-turned-the-seahawks-into-super-bowl-winners-and-is-taking-the-nfl-by-storm.↩︎

  27. “Tight zone” as Gibbs’s term: the title of his clinic video, “Alex Gibbs: Outside Zone, Tight Zone, Boots and Thoughts on the Power” (CoachTube): https://coachtube.com/course/football/alex-gibbs-outside-zone-tight-zone-boots-and-thoughts-on-the-power/14602600; Chris B. Brown, Grantland, Jan 10, 2012: https://grantland.com/features/chris-brown-gary-kubiak-houston-texans-running-game/. “Mid zone”: Taylor Kolste (Riley-Kolste Football), “Overview of the Los Angeles Rams offense,” May 4, 2019 (“Because of the technique the Rams employ with their play-side tackle, I refer to this scheme as a ‘mid-zone’ play”): https://ramstalk.net/overview-of-the-los-angeles-rams-offense/. “Zone slice”: Jon Svec, “Defending Split Zone,” Jan 12, 2022: https://jonsvec.substack.com/p/defending-split-zone.↩︎