Skip to content
Back to guides
Model checks

Pre-Snap Formation Features: A Bettable Walkthrough

Shark Snip Editorial 11 min read

Read the price, role, and market first

Engineer pre-snap formation features that move WR yardage props. Receiver alignment, motion-at-snap, RB depth, and the Brier-lift math.
16 sections
Pre-Snap Formation Features: A Bettable Walkthrough cover art

The pre-snap formation is the cheapest tracking-data feature you can compute. The football hasn’t moved yet, the play hasn’t happened, and the books haven’t fully priced what the offense is signaling. Every other tracking feature — separation, route trees, YAC — depends on the snap firing first. Pre-snap features just need x, y positions and the ball_snap event. This walkthrough shows the three formation features that lift WR prop Brier the most, the exact tracking-CSV columns they ride on, and how to wire them into a TF.js model running in /tinker.

What counts as “pre-snap”

In a Big Data Bowl tracking_week_.csv frame, the event column flags major moments. The pre-snap window for a single play is the contiguous block of frames between event == "line_set" and event == "ball_snap" minus one frame. The line_set marker fires when officials reset the chains and the play clock starts; ball_snap fires the instant the center’s hand begins moving the ball. Anything before line_set is dead time. Anything at or after ball_snap is post-snap and must be excluded from pre-snap features.

At 10 Hz that window is roughly 30 to 80 frames, averaging about 5 seconds of live setup. That’s plenty of data to fingerprint formation, detect motion, and compute alignment, but you do not need all of it. The most useful pre-snap features collapse to just two moments: line_set (the static setup) and ball_snap minus 1 (the dynamic moment-of-snap state).

Feature 1: receiver alignment width

The simplest, hardest-to-beat formation feature is just measuring how wide the offense lines up. Procedure:

  1. Filter the tracking frames to event == "ball_snap".
  2. Join players.csv on nflId to get position.
  3. Subset to offensive skill players (WR, TE, RB, FB) on the possession team.
  4. Find the football position (nflId is NaN, displayName "football") to anchor the y axis.
  5. For each skill player, compute abs(player.y minus football.y). Take the mean across players in the WR/TE subset only — that’s the alignment width feature.

Interpretation: a 4WR empty set tends to land at width 14 to 18 yards. A 2WR/2TE set lands closer to 8 to 11. The continuous version of this feature outperforms the categorical "SHOTGUN/EMPTY/PISTOL" indicator because it captures within-formation variation — an empty set with the slots 6 yards inside the numbers behaves very differently from an empty set with everyone splitting to the sideline.

One trap: the football’s y is not always centered on the field. Hashmark plays push the snap point left or right by about 6 yards. Always anchor on the football, never on the geometric field center.

Feature 2: motion-at-snap binary flag

The single most underpriced formation cue. Procedure:

  1. Find the frameId where event == "ball_snap" for the play.
  2. Filter all offensive non-OL players in that one frame.
  3. Check whether any player has s (speed in yards/sec) greater than 1.5.
  4. Set motion_at_snap = 1 if yes, 0 otherwise.

About 28% of NFL plays in the 2023 BDB sample had motion-at-snap on offense. On those plays the in-motion receiver gained an average of 0.4 yards of additional separation at pass_arrived versus a static baseline. Books understand this in the aggregate — the team’s pass-EPA over-expected baked into the spread captures most of it — but they consistently underprice the player-level impact on WR yardage props, especially for slot WRs against zone coverage.

Per our BDB cornerstone, the motion-flag alone lifts a WR-yards-prop Brier from 0.245 to 0.243 on a 2,000-player-week sample. Combined with the alignment feature it goes to 0.240. The features stack.

Why the 1.5 yards/sec threshold

You could use any cutoff between 1.0 and 2.0 yards/sec. We landed on 1.5 because:

  • Below 1.0: you catch noise frames where a WR is shuffling or recovering from a fake motion.
  • Above 2.0: you miss tight-end orbit motion that fires the moment the snap is called.
  • At 1.5 you’re selecting for players who are actually moving across the formation, not adjusting depth.

If you’re tuning the threshold per position, use 1.2 for TEs and 1.7 for WRs — TE motion tends to be slower (often glide motion) and WR motion tends to be at-speed.

Feature 3: RB depth and backfield structure

The third feature is RB depth: how far behind the QB the running back is at ball_snap.

  1. Filter to event == "ball_snap".
  2. Find the QB (position == "QB" on possession team).
  3. Find the RBs (position == "RB" or "FB" on possession team).
  4. If there is one RB, compute rb.x minus qb.x (sign flipped if playDirection == "left"). If zero RBs (empty), set to 0 and flag empty_backfield = 1. If multiple RBs, take the deepest.

RB depth correlates with run-game intent. A depth of 5+ yards typically signals downhill running. A depth of 0 to 2 yards (pistol or behind-QB) signals quicker action and often more pass options. A depth of -2 to 1 (offset alongside or in front) signals pass protection or screen action. The continuous variable beats the categorical "I_FORM/SHOTGUN/PISTOL" label because it captures the spectrum, including hybrid sets that are mislabeled in plays.csv.

Wiring the three features into TF.js

Once your feature transformer produces (alignment_width, motion_at_snap, rb_depth) per play, the player-week aggregate is just a mean (alignment, rb_depth) and an exposure rate (motion). Persist the per-player rolling 4-week values in IndexedDB. The training brick in /tinker takes them as three input features alongside the Vegas closing line, opponent defensive DVOA, and a base-rate yardage prior. The exact training loop:

  • Architecture: dense 8 → 4 → 1, sigmoid output.
  • Loss: binary cross-entropy for over/under, MSE for continuous yardage.
  • Sample: 1,500 to 2,500 player-weeks across 2 to 3 seasons.
  • Holdout: the most recent season, never random splits.
  • Convergence: 8 to 12 seconds on CPU, 1 to 2 seconds with WebGPU.

The whole training loop fits in the Tinker brick walkthrough with these features substituted in.

Validating the lift

Brier score on a holdout is the right primary metric. Two checks before you trust the lift:

  1. Calibration plot — bucket your predictions into deciles and check the realized hit rate. If your 60% prop calls hit 55%, the Brier improvement is calibration drift, not edge. See the CLV explainer for why this matters more than raw win rate.
  2. Permutation importance — shuffle each feature column one at a time and re-score. If permuting the motion flag drops Brier by only 0.0001, that feature isn’t doing real work for you.

The headline result on our internal 2024 holdout: alignment_width contributed 0.0024 Brier, motion_at_snap 0.0019, rb_depth 0.0011. The three together lifted 0.0061 (more than the sum because they interact — motion-with-wide-alignment is much more informative than either alone).

Watch-outs you’ll hit on real data

  • Pre-snap shifts vs motion: a shift is multiple players moving and then settling before the snap, while motion is a single player moving across the snap. Our flag captures motion-at-snap, not shifts that completed before ball_snap. Shifts are useful too but require frame-window analysis, not a single-frame check.
  • Trick formations: Wildcat, Wildcat-direct-snap, and similar plays break the QB anchor. Either set rb_depth to NaN and let the model learn the pattern, or filter these plays out.
  • Field flips: BDB plays move both directions on the field. Normalize x by playDirection: if playDirection == "left", set x = 120 - x and dir = dir - 180 before any of these features are computed.
  • Punt formations and Hail Marys: filter to plays.csv rows where playDescription doesn’t flag punt/kick/Hail Mary. About 8% of total snaps.
  • Season-to-season drift: motion rates in particular drift year over year as offenses copy from each other. Re-fit the feature transformer every season, not just the downstream model.

Where to use these features

Three places they pay off, ranked:

  1. WR yardage / receptions / longest-reception props. Best edge.
  2. Run-pass option (RPO) team total adjustments. Formation cohesion correlates with red-zone scoring efficiency.
  3. RB rushing-attempt props. RB depth + alignment width predicts run-rate within a quarter or two on either side.

The list of where they don’t pay off is just as important: do not use formation features alone for moneylines or spreads — Vegas captures team-level formation tendency in the closing line. Use them for player props, where the slower update cycle gives you room.

From feature to backtest in a real workflow

Engineering the features is half the work. Wiring them into a bet-by-bet workflow that doesn’t lie to you is the other half. The minimum honest backtest:

  1. Build the feature row at the exact moment you would have bet. For WR props this means using the most-recent-completed week’s tracking aggregates, never including data from the game-being-predicted. The temptation to peek at this week’s formation is the most common backtest leak in tracking work.
  2. Pull the actual prop line you could have bet, not the closing line. Edge against closing line tells you whether your model is sharp, but edge you can act on is against the price you actually saw at bet time. Both numbers matter and they answer different questions.
  3. Track CLV per bet in addition to win/loss. A 56% hit rate with -1.2% CLV is variance, not edge. A 51% hit rate with +3% CLV is real and will print over time. The /desk bet log captures both automatically when you log your tracking-data plays.
  4. Size in units, not dollars. Tracking models are fragile to scheme changes mid-season. Keep stake sizing modest until the in-season Brier confirms the holdout Brier.

How these features interact with coverage shells

The interaction between formation and defensive coverage is where the biggest residual edge lives. The presnap features we engineered are pure offense — they don’t know what the defense is showing. A second-stage feature that bins the defensive shell (single high, two high, tight zone, press man) and crosses it with the offensive formation produces multiplicative edge.

Reading the shell from tracking is a separate feature module, but the shortcut: at ball_snap, count safeties (FS, SS) more than 10 yards deep. One safety deep = single-high. Two safeties deep = two-high. Then look at the cornerbacks (CB): if both CB y-distance to nearest WR is under 2 yards at snap, it’s press. Combine the four-way cross-tab with the offensive formation features and the WR yardage Brier drops another 0.003 on the same 2,000-week sample.

This is the cleanest case for the “small, composable features stack” discipline we keep coming back to. Three offensive features alone get you the bulk of the lift. The defensive shell layer adds incremental value but only if your offensive features are already debugged.

Bottom line

Three columns, three features, ~30 lines of code, and a Brier lift big enough to clear vig on the WR prop board. Pre-snap formation features are the easiest first tracking-data win for a bettor, because they don’t require modeling routes or coverage and they run in a browser tab. Train them once, validate against a real Sunday on /picks, and let the model card on the BDB hub tell you whether to keep them or swap them.

Bet responsibly — set limits, never chase losses.

Props and DFS example board

For props, DFS, and PrizePicks-style decisions, the names should reveal the input. Jokic assists, Shai points, Wembanyama blocks, Josh Allen rushing, Ja'Marr Chase receptions, and Christian McCaffrey touchdown equity all require different checks. Treat each player as a role-and-price puzzle rather than a logo on a pick card.

  • Fixed-line check: compare the app line to sportsbook consensus before calling it an edge.
  • Correlation check: do not pair legs that require opposite game scripts.
  • DFS check: salary, ownership, and late-swap flexibility can matter as much as median projection.
  • Tracking check: grade closing value and result separately so a lucky hit does not hide a bad line.

Use PrizePicks basics, NFL player props, and correlation math as the internal loop from projection to price to risk control.

Model inputs worth naming

Use names as evidence, not decoration. The useful SEO win is that Josh Allen, Ja'Marr Chase, Bijan Robinson and Puka Nacua and Chiefs, Bills, Eagles and Lions appear inside decisions, thresholds, and internal links instead of being dumped into a keyword list.

  • NFL model: route participation for Ja'Marr Chase, rushing attempts for Josh Allen, pressure rate allowed by the Bengals, and red-zone carry share for Jonathan Taylor should be separate features.
  • NBA model: usage, projected minutes, rest, and pace should move Nikola Jokic or Shai Gilgeous-Alexander props differently than a one-number power rating.
  • MLB model: Tarik Skubal strikeout projection, Coors Field park factor, lineup confirmation, and bullpen rest need their own columns.
  • Review loop: grade entry price, closing price, bet result, and model error separately so lucky results do not hide bad forecasts.

Build or audit the workflow in Tinker and review it with CLV.

Research note board

Use this model-audit board to keep features, validation, and bet sizing from collapsing into one confidence score.

Model layerWhat to inspectExample inputDowngrade when
FeatureWhether the variable maps to the sport and marketJosh Allen role data or Zero RB price movementThe feature is a proxy for something you can measure directly
ValidationOut-of-sample error, CLV, calibration, missing dataChiefs market movement after injury newsWins come without beating the close or improving calibration
SizingBankroll, confidence interval, correlation, market limitCLV exposure compared with related ticketsMultiple bets repeat the same thesis at full stake

Prop OVER hit rate vs line distance from median

Empirical hit rate of OVER bets as the prop line moves away from the player projection median, measured in standard deviations. A line set 1sd below the median hits ~84% of the time — but books price the juice to match.

Breakeven win % at common American odds

The win rate you need to break even at each price. Pick odds shorter than -150 and you must win >60% just to stay flat — a hurdle most casual handicappers never sustain.

Frequently asked questions

Do I have to use the offenseFormation column from plays.csv?
No, and you shouldn't for serious modeling. plays.csv offenseFormation is human-labeled and roughly 4 to 6 percent of rows mismatch what the tracking frames actually show at ball_snap. Compute formation from the tracking x, y positions yourself. The labeled column is fine as a sanity check.
What's the smallest meaningful pre-snap feature set?
Three features: receiver alignment width (mean y-distance from football for WR/TE), motion-at-snap binary flag (any offensive non-OL with speed > 1.5 yards/sec at the ball_snap frame), and RB depth (RB x-distance behind the QB). On 2,000 player-weeks these three lift WR yards-per-route Brier from 0.247 to 0.241.
Why do formation features matter more for WR props than spreads?
Vegas already prices team-level scheme tendency into spreads — the closing line for a 3WR-heavy offense reflects market knowledge. Player-level prop pricing leans more on season aggregates and is slower to react to week-specific formation deployment, especially against new defensive coordinators. That lag is the edge.
How do I avoid leaking post-snap information into a "pre-snap" feature?
Filter strictly to frames where frameId is less than the ball_snap frameId for that gameId+playId. Some BDB seasons have a 0.1-second clock-event ambiguity right at the snap; if in doubt, cut at ball_snap minus 2 frames. Pass result, target, and route labels live in plays.csv and player_play.csv post-snap fields — never join those into a pre-snap feature row.

Build a free model in 60 seconds →

Go →
11m read time
28 players/teams
8 key angles
Angles in this read 6 angles

Editorial example layer

Concrete examples make the page useful: tie player and team names to role, price, matchup, and timing so the content reads like analysis instead of glossary filler.
Patrick MahomesJosh AllenLamar JacksonJoe BurrowJalen HurtsJustin HerbertC.J. StroudTua TagovailoaChiefsBillsRavensEaglesLionsBengalsclosing line valuetarget shareair yardsred-zone roleroute participation
Pre-Snap Formation Features: A Bettable Walkthrough data infographic
Chart view of the article's core numbers. Source: inline-lib-propHitRateLadder-presnap-formation-feature-tutorial.

Get picks in your inbox

One email, every slate — ranked edges, no touts. Unsubscribe any time.

Start free — pick a sport

Go →

We use cookies for essential site functionality. With your consent, we also use cookies for analytics and performance monitoring. See our Privacy Policy.