Lineara: built with AI, not generated by it.
Every fantasy tool shows you a ranked list and calls it advice. Lineara re-scores the entire board on every pick, tells you exactly why a player is worth taking right now, and adapts to your league format, your roster, and what your opponents are actually doing.
A live draft co-pilot that re-ranks the board on every single pick.
Real-time draft recommendations that know the board.
Every pick made by anyone in the draft triggers a full recalculation. Five prioritized recommendations update immediately, each with a plain-language explanation of why that player is worth taking right now: survival probability, tier cliff, positional scarcity, roster fit, value vs. ADP. Not a cached ranking list. Not generic advice. A read on this specific moment in this specific draft.
Connects to
Sleeper API, live draft polling
Signals per pick
6 scoring signals recalculated
Recommendations
5 ranked picks with written reasoning
Formats supported
Snake, Superflex, Best Ball, Guillotine, IDP, Dynasty, Auction
Full simulated draft against opponents that blend best-player-available and needs-based logic by round. Opponents roster-check before picking. Full AI Coach active throughout so you can practice with the same recommendations you'd see in a live draft.
Three demo states load with sample data before you connect Sleeper: Startup Draft (board mid-draft with AI Coach active), Rookie Draft, and Post-Draft Hub. So you can see the full experience before linking anything.
Team grade and projected points breakdown when the draft ends. Start/Sit, Waiver Wire, Trade Evaluator, and News pages extend the tool into the regular season. Pick grader shows letter grades on every selection in real time.
Draft page, live Sleeper draft, AI Coach open
Rankings show you who’s good. They don’t show you whether to take them at this pick.
The same player can be a must-take or completely safe to wait on depending entirely on board context: how many picks until you're up, whether teams between now and your next pick all need his position, and whether he's the last player in his tier before a quality drop. None of that is in the rank or the ADP.
Every existing fantasy tool has the same gap: a list sorted before the draft started that doesn't update based on what's happening in the room. Lineara recalculates the whole board on every pick using live board state, and explains the reasoning in plain language.
Three tools. Different jobs. None of it was one-shot.
The scoring engine started in conversations with ChatGPT and Claude before any code existed. ChatGPT for rapid ideation, throwing draft theories at something that could push back. Claude for stress-testing the logic, challenging edge cases, and working through why a resistance function was the right answer when multiple urgency signals fire at once. By the time the model went into Claude Code, the architecture was decided.
Claude Code's job was to build what was already designed. Every output got reviewed against the model. If survival probability was overcorrecting or need urgency fired at full strength on pick 1, that was a bug, not a design discovery. The logic came first.
Built over a few weeks of focused sessions. Format differentiation (dynasty, best ball, guillotine all have meaningfully different math) each required separate research passes before they could be specified for implementation. The dual ranking system (AI Rank, stable VORP, and Fit Rank, personalized and live-updating) came out of the same phase.
Claude Code session: implementing the scoring architecture
here's the scoring structure. base is VORP. multiply by survival urgency. need boost scales by how far behind you are vs. the rest of the draft, not just whether you're empty at a position. hard cap total context at +45%. build this out and show me the need urgency piece specifically
Built. The fill-gap approach means urgencyScale is 0 when everyone in the draft is equally empty (pick 1, round 1), and approaches 1.0 only when you're meaningfully behind the field at a position. That prevents full urgency from firing on your first pick just because you have zero RBs.
const myFill = (myPosCounts[pos] || 0) / Math.max(1, starterSlots) const fillGap = Math.max(0, sc.fillPct - myFill) const urgScale = Math.min(1.0, fillGap * 4 + (atRisk ? 0.35 : 0)) const baseBoost = urgency === 'critical' ? 0.18 : urgency === 'high' ? 0.10 : 0.04 score *= 1.0 + baseBoost * urgScale
verify the math: urgencyScale should actually return 0 on pick 1 when nobody has drafted anything yet
Confirmed. Pick 1, all teams equally empty: myFill = 0, sc.fillPct = 0, so fillGap = max(0, 0 - 0) = 0. atRisk is false. urgencyScale = min(1.0, 0 + 0) = 0. The boost collapses to 1.0 + (0.18 * 0) = 1.0. No adjustment applied. Matches the spec.
// Phase 1: VORP as the base quality signal. // Shift up so all top-80 players have a positive base. let score = Math.max(1, (proj.vorp ?? -(player.rank / 20)) + 15) // Dynasty / keeper: age curve + mileage + multi-year blend if (isDynastyMode(settings.leagueType)) { score *= dynastyAgeMult(player, seasonStats, prevSeasonStats, teamMode) } // Survival urgency: 1.0x (safe) up to 1.35x (almost gone) score *= 1.0 + 0.35 * (1 - pSurvive) // Need boost only when you're behind the field. // urgencyScale = 0 when everyone equally empty (pick 1). if (need) { const myFill = (myPosCounts[pos] || 0) / Math.max(1, starterSlots) const fillGap = Math.max(0, sc.fillPct - myFill) const urgScale = Math.min(1.0, fillGap * 4 + (atRisk ? 0.35 : 0)) const baseBoost = urgency === 'critical' ? 0.18 : urgency === 'high' ? 0.10 : 0.04 score *= 1.0 + baseBoost * urgScale } // Phase 3: saturation. Too many at one position. // Penalty scales with how rigid the roster format is. if (alreadyHave >= starterSlots + 2) score *= 1 - 0.65 * rigidity else if (alreadyHave >= starterSlots + 1) score *= 1 - 0.38 * rigidity else if (alreadyHave >= starterSlots) score *= 1 - 0.15 * rigidity
500+ lines. Three phases. Built to not lie to you.
All six signals could produce runaway recommendations unconstrained. A player might be last in his tier, in a positional run, with 25% survival, and behind on your roster. Every signal firing at once. Without a check, the engine recommends a mediocre player because circumstances feel urgent. The resistance function and ±45% hard cap prevent that: context tells you someone is urgent, not that someone bad is suddenly good.
Phase 1 (VORP) sets the floor. Phase 2 (context signals) adjusts within the cap, with resistance dampening boosts when projection lags behind best available. Phase 3 (saturation) penalizes overloading a position, scaled to how many flex slots the format allows.
How the engine changes by format
Best Ball rewards ceiling since optimal lineups are auto-set. Guillotine punishes inconsistency since one bad week eliminates you. Dynasty applies age curves: a 23-year-old and 28-year-old with identical projections are not worth the same capital. Auction replaces survival probability with Fair Market Value and VORP-per-dollar efficiency. The format grid below has the full breakdown.
The dual ranking system: AI Rank and Fit Rank
The board starts in pure AI Rank, a stable VORP-based ordering that doesn't change as picks happen. The moment you make your first pick, it switches to Fit Rank, reordering around what your roster actually needs, which positions are becoming scarce, and who gets harder to land as the draft progresses. Same engine, two outputs: one objective, one personalized.
Rookies show ★ instead of a fit rank. They're slotted where Sleeper's dynasty community ranks them since they have no stats to project from.
The six signals, built up one real problem at a time
The only starting point that makes sense
Raw points don't work: a 14-point WR2 is more valuable than a 14-point QB5 because replacement cost is completely different. VORP anchors every base score to how much better a player is than what you'd get off waivers. Everything else is a multiplier on this number.
A statistical model, not a guess
Normal distribution centered on consensus rank, with position-specific volatility coefficients: QB 1.22 (goes at wildly different points by league), TE 0.90 (premium or streamer, little in between), WR 1.00 as baseline. CDF computed inline via Abramowitz & Stegun polynomial with no library dependency. Opponent demand and position run pressure layer on top.
Who's actually pulling on the pool
The model reconstructs every roster from the draft log and estimates how many starter slots each team still needs per position. A team needing two RBs pulls harder than a team needing one. This separates survival probability from a simple ADP offset: it's the real pressure in this room, not a historical average.
12-pick window, recency-weighted
Tracks pick rate over the last 12 selections, with the most recent four counting 1.5x. Compared against baseline rates (RB: 0.28, WR: 0.34, QB: 0.13, TE: 0.13) to distinguish real momentum from normal clustering. When a position is being drafted above its baseline rate, urgency fires, catching things opponent demand and ADP miss entirely.
Being last in a tier is a different kind of risk
Players cluster into quality tiers with real drop-offs between them. The last player in a tier faces concentrated demand that generic survival probability doesn't capture. Everyone in the room sees the same cliff. When a player is last or second-to-last in his tier, the model fires a separate urgency signal.
Not just this player. The whole position at your next pick.
Survival asks "will this player be there?" Forward scarcity asks "if I pass, how many comparable options exist at my next pick?" The engine runs survival probability against every starter-quality player at the position and sums expected survivors. Fewer than 1.5 fires a moderate signal. Fewer than 0.5 fires a hard one.
The in-app "How the AI works" modal, verbatim
The app ships with a modal that explains the scoring logic per format. It opens from the setup screen before you connect your account. These are the exact points, pulled from the source.
The default format. Teams alternate pick direction each round. The largest player pool, the most balanced scoring signals.
VORP engine
Every player is scored by Value Over Replacement, measuring how much they outscore the last draftable starter at their position.
Survival probability
Predicts the chance a player is still available at your next pick using their ADP, positional volatility, and opponent demand.
Tier cliffs
When you're at the last player in a tier before a quality drop, urgency spikes so you don't miss the window.
Positional runs
Detects when a run is happening at a position in real time and adjusts urgency accordingly.
An extra starting slot that can be filled by any QB. Changes the value hierarchy of every position from pick one onward.
QB demand scaling
SFLEX leagues need ×1.82 the QBs of a standard league; 2QB leagues need ×2.08. Replacement level is recalibrated accordingly.
Dynamic urgency
QB urgency is critical with no QB, high once you're set, and medium with two solid starters. No irrational panic.
Hoarding limits
The engine suppresses QB picks after QB4 in SFLEX (QB5 in deep leagues) so elite skill players are never overshadowed by backup QBs.
Replacement collapse
Once the top 24 QBs are off the board in a 2QB league, value drops sharply. The engine knows this cliff is coming.
No weekly lineup decisions. Your best available starters are auto-set each week, so ceiling and variance are assets, not problems.
Ceiling contribution
Scores players by their average of top-8 weekly performances, reflecting what they contribute when auto-started in an optimal lineup.
Spike week rate
Players who score ≥120% of their average in a given week get a volatility bonus (up to ×1.14). Boom-bust is rewarded, not penalized.
Reduced depth penalty
Owning 5+ WRs is good, not wasteful. Saturation penalties are cut nearly in half vs. managed leagues.
Stack bonus
Drafting a QB's WR1 gets a ×1.08 correlation boost; WR2/TE from the same QB get ×1.05. Total stack boost capped at ×1.10.
The lowest-scoring team gets eliminated each week. One bad week, a bad injury, or a concentrated bye week can end your season.
Floor over ceiling
Consistency multipliers up to ×1.14 for stable volume players. High boom/bust gets penalized ×0.92. You can't afford a zero week.
Bye week penalty
2 starters sharing a bye: ×0.96. 3+ starters: ×0.90. The engine avoids building you a bye-week timebomb.
Stricter injury math
Out players get ×0.50 vs. ×0.60 standard, Doubtful gets ×0.68. Dead roster spots are more dangerous when you can't survive a low score.
Early-round reliability
Locked starters get a ×1.08 reliability boost in rounds 1 through 4, the weeks you're most likely to be eliminated.
Linebackers, linemen, and defensive backs score alongside your offense. Each position group has completely different value drivers.
Separate replacement levels
LBs, DLs, and DBs each get their own VORP baseline. A DB isn't competing for replacement value against a LB.
Position group volatility
LBs draft most predictably (tackle-floor, ×0.92). DL/EDGE are sack-volatile (×1.18). DBs are INT-boom (×1.12).
Opportunity confidence
Every-down starters get ×1.12. Rotation players get ×0.92. Uncertain roles get ×0.82. Snap share matters for IDP.
Depth-based timing
In shallow IDP leagues (1-2 spots), offense still dominates early. The engine applies a ×0.82 dampener to prevent premature IDP runs.
Rosters carry over year to year. A 23-year-old and a 28-year-old with the same current projection are not worth the same draft capital.
Age multiplier
Young players (21-24) get a significant VORP boost for long-term value. Veterans 30+ are penalized for aging curves.
Rookie modeling
Rookies are split into archetypes (immediate, upside, and situational) based on draft capital and depth chart slot.
Two-season stats
Projections blend 2025 stats (65%) and 2024 stats (35%) to stabilize volatile single-season samples.
Position scarcity
Dynasty replacement levels account for deeper rosters. The pool that matters isn't who's available this week, but who's available over years.
A fantasy app that shows a lot of information. That was always going to be true.
Each recommendation card shows projected PPG, floor, ceiling, VORP, ADP, position rank, survival probability, and a reason paragraph. Five of those, plus an intel feed with tier cliff warnings, position run alerts, handcuff flags, and stack opportunities. Dense by design. The job was making it navigable without reducing what matters.
Managing the density
Compact mode strips cards to name, position, points, reason. The AI Coach panel collapses entirely. Positions can be muted mid-draft, players dismissed individually. The intel feed sits below, secondary but always visible, never interrupting pick flow.
Three-panel desktop layout
Desktop: three columns with filters and team config on the left, player board in the center, and team panel on the right with AI Coach as an overlay. Mirrors ESPN and Sleeper so there's no learning curve. AI Coach sits alongside the board, not in place of it.
Mobile
Bottom tab nav: Players, Filters, My Team. Draft state persists across tabs. AI Coach shows as a banner above the player list.
Typography and visual system
Inter for body and UI. Space Grotesk for display (player names, headers). JetBrains Mono for all numerics, legible at small sizes and visually distinct from surrounding text. Position colors (QB red, RB emerald, WR blue, TE orange) run consistently across every surface so users build an unconscious map of the board.
Player profile modal, tap any player on the board to open
Projects 12.8 ppg drawing from a full season of 2025 data, with a realistic range of 10.4–15 ppg.
+3.6 VORP, clear starter value well above the typical waiver pickup at WR. Projecting more per game than any freely available replacement.
AI ranks WR17 · Sleeper has WR22. Model has him 5 spots higher than consensus, driven by stronger 2025 receiving production than the consensus has priced in.
What this actually was.
Using ChatGPT and Claude to design the scoring model before touching a codebase was the decision that made everything else possible. The logic had to be right before the implementation could be right.
What surprised me
Claude Code's output quality depended directly on the quality of what I brought in. Vague specs produced vague code. The more precisely I could describe what a signal should do at edge cases, the less revision it needed. Compact mode, mute controls, the intel feed, the three-panel layout: none of those came from Claude Code. All decided before any conversation started.
What I'd do differently
- Build the scoring engine as an isolated, testable module first. Calibration would've been faster without UI state in the way.
- Write a short spec for each signal before implementing it. The smoothest sessions were the ones with a well-defined problem going in.
- Ship one format completely before extending to others. Handling dynasty and best ball edge cases alongside the base snake format added early friction that didn't need to exist.
What's still in progress
The scoring logic is still being tuned. Edge cases surface during real drafts: signals that overcorrect in specific formats, urgency that fires slightly too early or too late. Each one gets addressed as it shows up. That calibration work doesn't really end, it just gets more precise.
Sleeper was the starting point because it has a strong API and a large dynasty community, but the plan is to extend support to other platforms. The core engine isn't Sleeper-specific. Adding ESPN or Yahoo is a data layer problem, not an architecture problem.