brackt/app/routes/how-to-play.tsx
Chris Parsons e9798263b5
Add rules page, rewrite how-to-play, and fix scoring display (#20)
- Add new /rules route with official league rules covering rosters,
  scoring, major-based QP scoring, tiebreakers, draft, and season rules
- Rewrite how-to-play page with a tutorial/marketing tone, highlighting
  the Fischer increment draft clock as a novel feature
- Add Rules link to navbar (desktop and mobile)
- Align QP values in both pages with DEFAULT_QP_VALUES in code
- Fix tiebreaker description to match placement-count logic in code
- Update all fantasy point displays from toFixed(1) to toFixed(2) across
  StandingsTable, TeamScoreBreakdown, and PointProgressionChart
- Update tests to match new two-decimal-place point display format

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 21:58:51 -08:00

358 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Link } from "react-router";
export function meta() {
return [
{ title: "How To Play - Brackt" },
{
name: "description",
content:
"Learn how to play Brackt and compete in multi-sport fantasy leagues",
},
];
}
export default function HowToPlay() {
return (
<div className="container mx-auto px-4 py-8 max-w-4xl">
<h1 className="text-4xl font-bold mb-2">How To Play</h1>
<p className="text-lg text-muted-foreground mb-10">
Brackt is a multi-sport fantasy league where you draft athletes and
teams across dozens of sports, then watch your roster compete all year
long. Here's everything you need to know to get started.
</p>
<div className="space-y-10">
{/* The Big Picture */}
<section>
<h2 className="text-2xl font-semibold mb-3">The Big Picture</h2>
<p className="text-muted-foreground">
Before the season starts, every participant in your league holds a
draft — picking real athletes and teams across a set of sports
chosen by your commissioner. Over the following months, those picks
compete in their actual seasons. When it's all said and done,
whoever earned the most points from their picks wins.
</p>
</section>
{/* Building Your Roster */}
<section>
<h2 className="text-2xl font-semibold mb-3">Building Your Roster</h2>
<p className="text-muted-foreground mb-4">
Your league includes a set of sports selected by the commissioner
think NFL, NBA, golf, Formula 1, tennis, and more. Your roster has
one dedicated spot for each sport, so you need to draft at least
one pick from every sport in the league.
</p>
<p className="text-muted-foreground mb-4">
Extra draft rounds beyond the number of sports create{" "}
<span className="font-semibold text-foreground">flex spots</span>.
Flex picks can come from any sport great for grabbing a second
player in a sport where you see value, or doubling down on a safe
bet.
</p>
<div className="bg-muted rounded-lg p-4 text-sm text-muted-foreground">
<p>
<span className="font-semibold text-foreground">Example:</span>{" "}
Your league has 20 sports and 24 draft rounds. That means you
fill 20 dedicated sport spots and have 4 flex picks to use
however you like.
</p>
</div>
</section>
{/* How Points Work */}
<section>
<h2 className="text-2xl font-semibold mb-3">How Points Work</h2>
<p className="text-muted-foreground mb-4">
Points are awarded based on where your picks finish 1st through
8th. The better they finish, the more you earn. Your commissioner
can adjust point values before the draft, but here's what a typical
league looks like:
</p>
<div className="bg-muted rounded-lg overflow-hidden mb-4">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left p-3 font-semibold text-foreground">
Finish
</th>
<th className="text-right p-3 font-semibold text-foreground">
Points
</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="p-3">1st Place</td>
<td className="p-3 text-right font-semibold text-foreground">
100
</td>
</tr>
<tr>
<td className="p-3">2nd Place</td>
<td className="p-3 text-right font-semibold text-foreground">
70
</td>
</tr>
<tr>
<td className="p-3">3rd Place</td>
<td className="p-3 text-right font-semibold text-foreground">
50
</td>
</tr>
<tr>
<td className="p-3">4th Place</td>
<td className="p-3 text-right font-semibold text-foreground">
40
</td>
</tr>
<tr>
<td className="p-3">5th6th Place</td>
<td className="p-3 text-right font-semibold text-foreground">
25
</td>
</tr>
<tr>
<td className="p-3">7th8th Place</td>
<td className="p-3 text-right font-semibold text-foreground">
15
</td>
</tr>
</tbody>
</table>
</div>
<p className="text-sm text-muted-foreground">
If nobody in your league drafted a team that finishes in the top 8,
those points aren't awarded to anyone. Drafting rare picks can pay
off.
</p>
</section>
{/* Major-Based Sports */}
<section>
<h2 className="text-2xl font-semibold mb-3">
Golf, Tennis, CS2 Sports with Majors
</h2>
<p className="text-muted-foreground mb-4">
Some sports don't have a single championship — they have multiple
major tournaments spread throughout the year. For these sports,
players earn{" "}
<span className="font-semibold text-foreground">
qualifying points (QP)
</span>{" "}
at each major:
</p>
<div className="bg-muted rounded-lg overflow-hidden mb-4">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-border">
<th className="text-left p-3 font-semibold text-foreground">
Major Finish
</th>
<th className="text-right p-3 font-semibold text-foreground">
Qualifying Points
</th>
</tr>
</thead>
<tbody className="divide-y divide-border">
<tr>
<td className="p-3">1st</td>
<td className="p-3 text-right font-semibold text-foreground">
20 QP
</td>
</tr>
<tr>
<td className="p-3">2nd</td>
<td className="p-3 text-right font-semibold text-foreground">
14 QP
</td>
</tr>
<tr>
<td className="p-3">3rd</td>
<td className="p-3 text-right font-semibold text-foreground">
10 QP
</td>
</tr>
<tr>
<td className="p-3">4th</td>
<td className="p-3 text-right font-semibold text-foreground">
8 QP
</td>
</tr>
<tr>
<td className="p-3">5th6th</td>
<td className="p-3 text-right font-semibold text-foreground">
5 QP
</td>
</tr>
<tr>
<td className="p-3">7th8th</td>
<td className="p-3 text-right font-semibold text-foreground">
3 QP
</td>
</tr>
<tr>
<td className="p-3">9th12th</td>
<td className="p-3 text-right font-semibold text-foreground">
2 QP
</td>
</tr>
<tr>
<td className="p-3">13th16th</td>
<td className="p-3 text-right font-semibold text-foreground">
1 QP
</td>
</tr>
</tbody>
</table>
</div>
<p className="text-muted-foreground">
QP don't go straight to your score they determine the final
ranking within that sport. Once all the majors are done, total QP
are added up, and whoever's ranked 1st through 8th earns the
standard league points. Consistency across majors is the key.
</p>
</section>
{/* The Draft */}
<section>
<h2 className="text-2xl font-semibold mb-3">The Draft</h2>
<p className="text-muted-foreground mb-6">
The draft is a snake draft — pick order reverses every round. If
you pick last in round 1, you pick first in round 2. No trading
picks, and once you make a selection it's yours for the whole
season.
</p>
{/* Chess Clock */}
<div className="border rounded-lg p-5 mb-6 space-y-3">
<h3 className="text-lg font-semibold">
The Chess Clock A Brackt Original
</h3>
<p className="text-muted-foreground">
Most fantasy drafts use a simple countdown: you get X seconds per
pick and that's it. Brackt does it differently with a{" "}
<span className="font-semibold text-foreground">
Fischer increment timer
</span>
, borrowed from competitive chess.
</p>
<p className="text-muted-foreground">
Every participant starts the draft with a personal time bank.
Your clock counts down while it's your turn. When you make a
pick,{" "}
<span className="font-semibold text-foreground">
time is added back
</span>{" "}
to your bank. Any time you don't use carries over to your next
pick.
</p>
<p className="text-muted-foreground">
Pick quickly early on and you'll build up a bigger bank for the
later rounds when decisions get harder. Deliberate too long and
your bank shrinks. It rewards decisiveness without penalizing you
for taking a moment when you really need it.
</p>
<div className="bg-muted rounded-md p-3 text-sm text-muted-foreground">
<span className="font-semibold text-foreground">Example:</span>{" "}
On Standard speed, you start with 2 minutes. You make your first
pick in 30 seconds 15 seconds are added back, leaving you with
1 minute 45 seconds for your next turn. Keep picking fast and
that bank grows.
</div>
</div>
{/* Draft Queue & Autodraft */}
<div className="space-y-3">
<h3 className="text-lg font-semibold">Draft Queue & Autodraft</h3>
<p className="text-muted-foreground">
Before and during the draft you can build a{" "}
<span className="font-semibold text-foreground">draft queue</span>{" "}
an ordered list of picks you want to make. When it's your turn,
you can pick manually or let your queue guide you.
</p>
<p className="text-muted-foreground">
If your time bank runs out,{" "}
<span className="font-semibold text-foreground">autodraft</span>{" "}
kicks in automatically. It'll grab the first available pick from
your queue. If your queue is empty or everything in it has
already been taken, it'll grab from the top of the available player pool.
Keep your queue updated and you'll never get stuck with a random
pick.
</p>
</div>
</section>
{/* During the Season */}
<section>
<h2 className="text-2xl font-semibold mb-3">After the Draft</h2>
<p className="text-muted-foreground mb-4">
Once the draft ends, your roster is locked. No trades, no waivers,
no pickups. Just watch your picks compete across the year and see
how your draft decisions play out. Points accumulate as sports
seasons wrap up, and standings update in real time.
</p>
<p className="text-muted-foreground">
If there's a tie in the final standings, it's broken by who has
more 1st-place finishes. If that's still a tie, it goes to
2nd-place finishes, then 3rd, and so on.
</p>
</section>
{/* Tips */}
<section className="bg-primary/5 p-6 rounded-lg border border-primary/20">
<h2 className="text-xl font-semibold mb-4">Quick Tips</h2>
<ul className="space-y-3 text-muted-foreground">
<li>
<span className="font-semibold text-foreground">
Know your sports.
</span>{" "}
Understanding how each sport determines its top 8 (playoffs vs.
regular season vs. bracket) is the biggest edge you can have.
</li>
<li>
<span className="font-semibold text-foreground">
Build your queue early.
</span>{" "}
The draft moves fast. Having a ranked queue ready means you'll
always get a pick you're happy with, even if you step away.
</li>
<li>
<span className="font-semibold text-foreground">
Pick fast early on.
</span>{" "}
The chess clock rewards quick decisions. Bank extra time for the
tricky later rounds.
</li>
<li>
<span className="font-semibold text-foreground">
Flex spots are strategic.
</span>{" "}
Use them to double up on sports you feel confident about, not
just to fill the roster.
</li>
</ul>
</section>
{/* Links */}
<section className="flex flex-col sm:flex-row gap-4 items-center justify-between pt-2">
<p className="text-muted-foreground">
Want the full breakdown? Read the{" "}
<Link to="/rules" className="underline underline-offset-4 hover:text-foreground transition-colors">
official rules
</Link>
.
</p>
<Link
to="/leagues/new"
className="inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-11 px-8 text-base whitespace-nowrap"
>
Create a League
</Link>
</section>
</div>
</div>
);
}