Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions components/PlayerNumber.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client";

import type { Card } from "@/lib/scoring/types";
import { Section } from "./ScoutReport";
import { resolveResultTheme } from "./finishTheme";

export default function PlayerNumber({ card }: { card: Card }) {
const theme = resolveResultTheme(card);
const accent = theme.ink;

return (
<Section title="SQUAD NUMBER" accent={accent} className="w-full mt-[14px]">
<div className="flex items-center justify-between pt-1 pb-[2px]">
<div
className="font-display text-center justify-center w-full text-[100px] font-black leading-none tabular-nums"
style={{ color: accent, filter: `drop-shadow(0 1px 8px ${accent}55)` }}
>
{card.squadNumber}
</div>
</div>
</Section>
);
}
5 changes: 4 additions & 1 deletion components/ResultView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import DistributionPanel from "./DistributionPanel";
import { confettiPalette, resolveResultTheme } from "./finishTheme";
import { useReveal } from "@/hooks/useReveal";
import { burstConfetti } from "@/lib/confetti";
import PlayerNumber from "./PlayerNumber";


const HowItWorksModal = dynamic(() => import("./HowItWorksModal"), { ssr: false });

Expand Down Expand Up @@ -183,11 +185,12 @@ export default function ResultView({
</div>
</div>

{/* right — scouting metrics + distribution */}
{/* right — scouting metrics + squad number + distribution */}
<div className="flex max-[980px]:order-3 max-[980px]:w-full max-[980px]:max-w-[420px] max-[980px]:justify-center">
<div className="flex w-full max-w-[360px] flex-col gap-[14px]">
<MetricsPanel card={card} />
<DistributionPanel card={card} />
<PlayerNumber card={card} />
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/ScoutReport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function AttributeRow({ label, children }: { label: string; children: React.Reac

// Editorial section: an accent dash + tracked label, then content — reads as a
// scouting-report section rather than a dashboard card.
function Section({
export function Section({
title,
accent,
className,
Expand Down
3 changes: 3 additions & 0 deletions lib/scoring/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { topLanguageLogo } from "../github/languages";
import { deriveMetrics, deriveSkillMoves, deriveStyle, deriveWeakFoot, deriveWorkRate } from "./attributes";
import { ATTACK_STATS, FINISH_LABELS, FOUNDER_OVERALL, FOUNDERS, K, STATS, WEIGHTS } from "./constants";
import { derivePlaystyles } from "./playstyles";
import { generateSquadNumber } from "./squadNumber";

import type {
Archetype,
Card,
Expand Down Expand Up @@ -212,6 +214,7 @@ export function buildCard(s: Signals): Card {
languageLogo,
...(founder ? { founder } : null),
legacy: { L },
squadNumber: generateSquadNumber(s.login, position, overall),
report: {
skillMoves: skill.value,
weakFoot: weak.value,
Expand Down
31 changes: 31 additions & 0 deletions lib/scoring/squadNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Position } from "./types";

export function generateSquadNumber(login: string, position: Position, overall: number): number {
//Create a hash from the username
let hash = 0;
for (let i = 0; i < login.length; i++) {
hash = login.charCodeAt(i) + ((hash << 5) - hash);
}

hash = Math.abs(hash);

//Iconic squad numbers grouped by football positions
const posNumbers: Record<Position, number[]> = {
ST: [7, 9, 10, 11, 19, 22, 18, 20, 14, 45, 99],
RW: [7, 10, 11, 17, 22, 21, 20, 23, 18, 10, 19],
CAM: [10, 8, 11, 20, 22, 18, 23, 42],
CM: [8, 6, 14, 16, 17, 22, 16, 15, 19, 20, 88],
CDM: [6, 4, 15, 16, 14, 28, 23, 8, 18, 25, 5],
CB: [4, 5, 2, 3, 6, 12, 15, 26, 33],
};

const pool = posNumbers[position]||[7, 9, 10, 11];

//Elite players (90+ OVR) always get the classic #1 choice for their position
if(overall >= 90){
return pool[0];
}

//Else use the hash to pick a varied, but consistent number
return pool[hash % pool.length];
}
1 change: 1 addition & 0 deletions lib/scoring/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,6 @@ export interface Card {
// Set only for gitfut founders — their bespoke card art/accent + hint metadata.
// Optional so every other card (and previously serialized ones) stay valid.
founder?: FounderMeta;
squadNumber: number; //Squad nnumber generated from login and position
report: Report;
}