diff --git a/components/PlayerNumber.tsx b/components/PlayerNumber.tsx
new file mode 100644
index 0000000..66863fe
--- /dev/null
+++ b/components/PlayerNumber.tsx
@@ -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 (
+
+
+
+ {card.squadNumber}
+
+
+
+ );
+}
diff --git a/components/ResultView.tsx b/components/ResultView.tsx
index c2aeaa6..fa8e744 100644
--- a/components/ResultView.tsx
+++ b/components/ResultView.tsx
@@ -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 });
@@ -183,11 +185,12 @@ export default function ResultView({
- {/* right — scouting metrics + distribution */}
+ {/* right — scouting metrics + squad number + distribution */}
diff --git a/components/ScoutReport.tsx b/components/ScoutReport.tsx
index 3090e36..b3ba8fa 100644
--- a/components/ScoutReport.tsx
+++ b/components/ScoutReport.tsx
@@ -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,
diff --git a/lib/scoring/engine.ts b/lib/scoring/engine.ts
index 68ef9c5..e710199 100644
--- a/lib/scoring/engine.ts
+++ b/lib/scoring/engine.ts
@@ -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,
@@ -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,
diff --git a/lib/scoring/squadNumber.ts b/lib/scoring/squadNumber.ts
new file mode 100644
index 0000000..c160259
--- /dev/null
+++ b/lib/scoring/squadNumber.ts
@@ -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 = {
+ 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];
+}
\ No newline at end of file
diff --git a/lib/scoring/types.ts b/lib/scoring/types.ts
index 0efb058..4c79df6 100644
--- a/lib/scoring/types.ts
+++ b/lib/scoring/types.ts
@@ -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;
}