Understanding and customizing the rCTF color system, including light/dark themes and semantic colors.
All colors in rCTF are defined using OKLCH. Colors are declared as CSS custom properties in apps/web/src/app.css, with :root containing light mode values and [data-theme='dark'] providing dark mode overrides. The theme is toggled via the data-theme attribute on <html>, persisted to localStorage, and respects prefers-color-scheme on first load.
The foundation of rCTF’s color system is an altered version of shadcn/ui’s system. We add nested lightness layers 0 through 5, where layer l0 represents the base (page background or primary text). Higher numbers progressively add emphasis (for backgrounds) or reduce prominence (for foregrounds).
Layer
Background (light)
Background (dark)
Foreground (light)
Foreground (dark)
l0
oklch(98% 0 0)
oklch(15% 0 0)
neutral-700
neutral-50
l1
oklch(95% 0 0)
oklch(18.5% 0 0)
neutral-600
neutral-200
l2
oklch(93% 0 0)
oklch(22% 0 0)
neutral-500
neutral-300
l3
oklch(91% 0 0)
oklch(26% 0 0)
oklch(60% 0 0)
neutral-400
l4
oklch(89% 0 0)
oklch(30% 0 0)
oklch(65% 0 0)
oklch(59.7% 0 0)
l5
oklch(84% 0 0)
oklch(40% 0 0)
oklch(70% 0 0)
neutral-500
These variables are mapped to Tailwind utilities via @theme inline in app.css, enabling classes like bg-background-l1 and text-foreground-l2 that we use throughout the application.
Leaderboard colors are reserved for visualizing rankings on scoreboards and podiums, as well as for highlighting first, second, and third bloods. Gold, silver, and bronze semantically denote the top three placements (see Wikipedia’s “Hierarchy of precious substances”), while “self” highlights the current user’s row. The “nth” color is applied to all other participants outside the top three, and is just mappings of our layered color system.