Skip to content
Open

Fixes #300

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
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Auto-generated by Next.js — should not be linted or hand-edited
next-env.d.ts
.next/
1 change: 1 addition & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"endOfLine": "auto",
"plugins": ["prettier-plugin-tailwindcss"]
}
1 change: 1 addition & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
Binary file added public/assets/papers/maia3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/team/daniel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 14 additions & 6 deletions src/components/Common/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,38 @@ export const Footer: React.FC = () => {
title: 'Research',
links: [
{
href: 'https://arxiv.org/abs/2006.01855',
text: "Maia Paper (KDD '20)",
href: 'https://arxiv.org/abs/2605.19091',
text: "Maia-3 Paper (ICLR '26)",
},
{
href: 'https://www.cs.toronto.edu/~ashton/pubs/maia2-neurips2024.pdf',
text: "Maia-2 Paper (NeurIPS '24)",
},
{
href: 'https://arxiv.org/abs/2006.01855',
text: "Maia Paper (KDD '20)",
},
{
href: 'https://csslab.cs.toronto.edu/research/',
text: 'CSSLab Research',
},
],
},
{
title: 'Opensource',
title: 'Open-Source',
links: [
{
href: 'https://github.com/CSSLab/maia-chess',
text: 'Maia Model',
href: 'https://github.com/CSSLab/maia3',
text: 'Maia-3 Model',
},
{
href: 'https://github.com/CSSLab/maia2',
text: 'Maia-2 Model',
},
{
href: 'https://github.com/CSSLab/maia-chess',
text: 'Maia Model',
},
{
href: 'https://github.com/csslab/maia-platform-frontend',
text: 'Maia Web Platform',
Expand Down Expand Up @@ -153,7 +161,7 @@ export const Footer: React.FC = () => {
</div>
</div>
<p className="text-left text-sm text-secondary md:text-center md:text-xs">
© 2025 Maia Chess. All rights reserved.
© 2026 Maia Chess. All rights reserved.
</p>
</div>
</div>
Expand Down
90 changes: 47 additions & 43 deletions src/components/Home/AboutMaia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ const teamMembers = [
role: 'Model Developer',
github: 'lilv98',
},
{
image: '/assets/team/daniel.png',
name: 'Daniel Monroe',
website: 'https://daniel-monroe.github.io/',
institution: 'University of Toronto',
role: 'Model Developer',
github: 'daniel-monroe',
},
{
image: '/assets/team/kevin.jpg',
name: 'Kevin Thomas',
Expand Down Expand Up @@ -75,19 +83,44 @@ const teamMembers = [
},
]

const researchPapers = {
interface Paper {
title: string
link: string
description: string
image?: string
shortName?: string
}

const researchPapers: {
maia1: Paper
maia2: Paper
maia3: Paper
others: Paper[]
} = {
maia1: {
title:
'Aligning Superhuman AI with Human Behavior: Chess as a Model System',
link: 'https://www.cs.toronto.edu/~ashton/pubs/maia-kdd2020.pdf',
description:
'This paper introduces Maia, a chess engine trained to imitate real human moves at different rating levels. Instead of always picking the best move, Maia predicts what a human player of a given skill would actually play. This makes it ideal for training, game analysis, and even coaching, as it helps players learn from realistic decisions rather than computer perfection. It was the first AI to prioritize human-likeness over engine strength, making it a powerful tool for improvement.',
image: 'maia1',
shortName: 'Maia 1',
},
maia2: {
title: 'Maia‑2: A Unified Model for Human‑AI Alignment in Chess',
link: 'https://www.cs.toronto.edu/~ashton/pubs/maia2-neurips2024.pdf',
description:
"Maia‑2 is the evolution of Maia into a single model that can simulate any skill level in chess. Instead of using separate models for different ratings, it understands and adapts to your level in real time. Whether you're a beginner or a master, Maia‑2 predicts the moves players like you would actually make. It's built to feel human, teach naturally, and support personalized analysis without needing to toggle between bots.",
image: 'maia2',
shortName: 'Maia 2',
},
maia3: {
title: 'Chessformer: A Unified Architecture for Chess Modeling',
link: 'https://arxiv.org/abs/2605.19091',
description:
'Introduces Chessformer, a transformer-based architecture that unifies chess modeling to capture how human players make decisions across a wide range of skill levels.',
image: 'maia3',
shortName: 'Maia 3',
},
others: [
{
Expand Down Expand Up @@ -125,7 +158,7 @@ const PaperCard = ({
featured = false,
className = '',
}: {
paper: typeof researchPapers.maia1
paper: Paper
featured?: boolean
className?: string
}) => (
Expand All @@ -146,7 +179,7 @@ const PaperCard = ({
{featured && (
<div className="aspect-[4/3] w-full overflow-hidden">
<img
src={`/assets/papers/${paper.title.includes('Maia‑2') ? 'maia2' : 'maia1'}.jpg`}
src={`/assets/papers/${paper.image}.jpg`}
alt={`${paper.title} paper preview`}
className="h-full w-full object-cover object-top"
/>
Expand All @@ -172,7 +205,7 @@ const PaperCard = ({
rel="noreferrer"
className="inline-flex w-full items-center justify-center bg-human-4/80 px-5 py-3 font-medium text-primary transition duration-200 hover:bg-human-4"
>
Read {paper.title.includes('Maia‑2') ? 'Maia 2' : 'Maia 1'} Paper
Read {paper.shortName} Paper
</a>
)}
</div>
Expand Down Expand Up @@ -248,46 +281,17 @@ export const AboutMaia = () => {
</div>
</div>
<div className="mx-auto max-w-[95%] px-2 pt-16 md:max-w-[90%] md:px-4">
{/* Layout for screens < 1280px */}
<div className="xl:hidden">
{/* Featured papers in a row */}
<div className="mb-6 grid grid-rows-2 gap-6 md:grid-cols-2 md:grid-rows-none">
<PaperCard
paper={researchPapers.maia1}
featured={true}
className=""
/>
<PaperCard
paper={researchPapers.maia2}
featured={true}
className=""
/>
</div>
{/* Other papers in a row */}
<div className="grid grid-rows-2 gap-4 sm:grid-cols-4 sm:grid-rows-none">
{researchPapers.others.map((paper, index) => (
<PaperCard key={index} paper={paper} className="flex-1" />
))}
</div>
{/* Featured papers */}
<div className="mb-6 grid gap-6 md:grid-cols-3">
<PaperCard paper={researchPapers.maia1} featured={true} />
<PaperCard paper={researchPapers.maia2} featured={true} />
<PaperCard paper={researchPapers.maia3} featured={true} />
</div>

{/* Layout for screens >= 1280px (original layout) */}
<div className="hidden xl:grid xl:grid-cols-3 xl:gap-6">
<PaperCard
paper={researchPapers.maia1}
featured={true}
className=""
/>
<PaperCard
paper={researchPapers.maia2}
featured={true}
className=""
/>
<div className="flex flex-col gap-4">
{researchPapers.others.map((paper, index) => (
<PaperCard key={index} paper={paper} className="flex-1" />
))}
</div>
{/* Other papers in two columns */}
<div className="grid gap-4 sm:grid-cols-2">
{researchPapers.others.map((paper, index) => (
<PaperCard key={index} paper={paper} />
))}
</div>
</div>
</section>
Expand Down
7 changes: 5 additions & 2 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// The Maia model is only run at multiples of 200 Elo. The intermediate levels
// (200n + 100, e.g. 700, 900, ...) are not selectable; they only appear in the
// "Moves by Rating" graph, where they are linearly interpolated.
export const MAIA_MODELS = Array.from(
{ length: 21 },
(_, i) => `maia_kdd_${600 + i * 100}`,
{ length: 11 },
(_, i) => `maia_kdd_${600 + i * 200}`,
)

export const MAIA_RATINGS = MAIA_MODELS.map((m) =>
Expand Down
26 changes: 19 additions & 7 deletions src/hooks/useAnalysisController/useMoveRecommendations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
import { Chess } from 'chess.ts'
import { MAIA_MODELS } from 'src/constants/common'
import { MAIA_MODELS, MAIA_RATINGS } from 'src/constants/common'
import { GameNode, MaiaEvaluation, StockfishEvaluation } from 'src/types'
import { sortStockfishMoves } from './utils'

Expand Down Expand Up @@ -105,15 +105,27 @@ export const useMoveRecommendations = (
}
}

// Maia is only evaluated at multiples of 200 Elo (MAIA_MODELS). The graph is
// drawn at a finer 100-Elo resolution: evaluated levels use their real policy
// and the intermediate levels (200n + 100) are linearly interpolated from
// their two neighbours.
const probabilityAt = (rating: number, move: string): number =>
(maia[`maia_kdd_${rating}`]?.policy?.[move] || 0) * 100

const minRating = MAIA_RATINGS[0]
const maxRating = MAIA_RATINGS[MAIA_RATINGS.length - 1]

const data = []
for (const rating of MAIA_MODELS) {
const entry: { [key: string]: number } = {
rating: parseInt(rating.replace('maia_kdd_', '')),
}
for (let rating = minRating; rating <= maxRating; rating += 100) {
const entry: { [key: string]: number } = { rating }
const isEvaluated = rating % 200 === 0

for (const move of candidates) {
const probability = (maia[rating]?.policy?.[move[0]] || 0) * 100
entry[move[1]] = probability
entry[move[1]] = isEvaluated
? probabilityAt(rating, move[0])
: (probabilityAt(rating - 100, move[0]) +
probabilityAt(rating + 100, move[0])) /
2
}

data.push(entry)
Expand Down
4 changes: 2 additions & 2 deletions src/pages/candidates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ const PositionPill: React.FC<{
href={playHref}
className={`inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-medium text-primary shadow-[0_8px_24px_rgba(0,0,0,0.2)] transition ${
completed
? 'bg-emerald-500/30 hover:bg-emerald-500/34 border border-emerald-100/70 hover:border-emerald-50/80'
: 'bg-rose-500/30 hover:bg-rose-500/34 border border-rose-100/65 hover:border-rose-50/75'
? 'hover:bg-emerald-500/34 border border-emerald-100/70 bg-emerald-500/30 hover:border-emerald-50/80'
: 'hover:bg-rose-500/34 border border-rose-100/65 bg-rose-500/30 hover:border-rose-50/75'
}`}
>
<span className="material-symbols-outlined !text-[18px]">
Expand Down