Skip to content

Add new Opening Page Drilling functionality + Improve codebase #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Jun 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f458371
chore: add initial iteration of openings modal
kevinjosethomas Jun 23, 2025
b9a9fd8
fix: bugs with play mode
kevinjosethomas Jun 23, 2025
0159477
chore: update with moves container + variations
kevinjosethomas Jun 24, 2025
5f2e0f1
feat: add initial working iteration of working opening drilling
kevinjosethomas Jun 24, 2025
6672199
feat: enhance OpeningDrillSidebar with reset functionality and integr…
kevinjosethomas Jun 24, 2025
70c1d7a
feat: enhance OpeningSelectionModal with improved styling and integra…
kevinjosethomas Jun 24, 2025
4e966f9
feat: refactor OpeningDrillAnalysis to use parent hover functions and…
kevinjosethomas Jun 24, 2025
e6384a6
feat: overhaul opening book modal
kevinjosethomas Jun 24, 2025
da0e8f4
feat: enhance opening drill functionality with new drill performance …
kevinjosethomas Jun 24, 2025
959f29d
feat: allow repeated openings for increased number of drills
kevinjosethomas Jun 25, 2025
f02dc33
feat: improve movemap to show all moves + improve movetooltip across …
kevinjosethomas Jun 25, 2025
6828b76
feat: update layout styles across multiple pages for consistent horiz…
kevinjosethomas Jun 25, 2025
25ad9de
feat: improve drill ending functionality
kevinjosethomas Jun 25, 2025
798c407
fix: opening drill sidebar
kevinjosethomas Jun 25, 2025
989e4a5
feat: enhance modal components with improved styling, layout adjustme…
kevinjosethomas Jun 26, 2025
ea115f9
fix: bug with duplicate get_move requests
kevinjosethomas Jun 26, 2025
7887b0b
feat: add view summary option after drills are complete
kevinjosethomas Jun 26, 2025
4ddc76e
feat: add functionality to update completed drills with new moves and…
kevinjosethomas Jun 26, 2025
b91e34f
fix: allow maia to continue opening after finish
kevinjosethomas Jun 26, 2025
d0fee62
fix: overwrite drills after reset
kevinjosethomas Jun 26, 2025
292426e
feat: improve opening modal
kevinjosethomas Jun 26, 2025
f30e1a2
feat: add initial iteration of drill performance confirmation
kevinjosethomas Jun 28, 2025
651b1a2
refactor: remove play/pause functionality and clean up evaluation cha…
kevinjosethomas Jun 28, 2025
3f34a88
refactor: remove ThemeButton component and update theme handling to s…
kevinjosethomas Jun 28, 2025
3b7dc5e
feat: make opening selection modal responsive for mobile
kevinjosethomas Jun 28, 2025
e3a73af
refactor: migrate scss to tailwind css
kevinjosethomas Jun 28, 2025
7270dd9
fix: update PGN generation to include headers
kevinjosethomas Jun 28, 2025
e4953e8
refactor: update BlunderMeter calculations to cap at 100%
kevinjosethomas Jun 28, 2025
1350b7a
feat: enhance DrillPerformanceModal with move classification and key …
kevinjosethomas Jun 28, 2025
1de35d5
feat: add MoveQualityDistribution component and enhance FinalCompleti…
kevinjosethomas Jun 28, 2025
5b429d2
feat: add research papers section with detailed descriptions and link…
kevinjosethomas Jun 28, 2025
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
Binary file added public/assets/papers/maia1.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/papers/maia2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 113 additions & 5 deletions src/components/Analysis/BlunderMeter.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import React, { useContext } from 'react'
import React, { useContext, useState } from 'react'
import { motion } from 'framer-motion'

import { BlunderMeterResult, ColorSanMapping } from 'src/types'
import { WindowSizeContext } from 'src/contexts'
import { MoveTooltip } from './MoveTooltip'

interface Props {
data: BlunderMeterResult
colorSanMapping: ColorSanMapping
hover: (move?: string) => void
makeMove: (move: string) => void
moveEvaluation?: {
maia?: { policy: { [key: string]: number } }
stockfish?: {
cp_vec: { [key: string]: number }
winrate_vec?: { [key: string]: number }
winrate_loss_vec?: { [key: string]: number }
}
} | null
}

export const BlunderMeter: React.FC<Props> = ({
data,
hover,
makeMove,
colorSanMapping,
moveEvaluation,
}: Props) => {
const { isMobile } = useContext(WindowSizeContext)

Expand All @@ -25,13 +35,15 @@ export const BlunderMeter: React.FC<Props> = ({
hover={hover}
makeMove={makeMove}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
) : (
<DesktopBlunderMeter
data={data}
hover={hover}
makeMove={makeMove}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
)
}
Expand All @@ -41,6 +53,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
hover,
makeMove,
colorSanMapping,
moveEvaluation,
}: Props) => {
return (
<div className="flex h-64 max-h-full w-full flex-col gap-2 overflow-hidden rounded bg-background-1/60 p-3 md:h-full md:w-auto md:min-w-[40%] md:max-w-[40%]">
Expand All @@ -56,6 +69,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
bgColor="bg-[#1a9850] rounded-t"
probability={data.goodMoves.probability}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
<Meter
hover={hover}
Expand All @@ -66,6 +80,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
textColor="text-[#fee08b]"
probability={data.okMoves.probability}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
<Meter
hover={hover}
Expand All @@ -76,6 +91,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
moves={data.blunderMoves.moves}
probability={data.blunderMoves.probability}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
</div>
</div>
Expand All @@ -88,6 +104,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
hover,
makeMove,
colorSanMapping,
moveEvaluation,
}: Props) => {
return (
<div className="flex w-full flex-col gap-2 overflow-hidden rounded bg-background-1/60 p-3">
Expand Down Expand Up @@ -135,6 +152,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
hover={hover}
makeMove={makeMove}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
<MovesList
title="Meh Moves"
Expand All @@ -143,6 +161,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
hover={hover}
makeMove={makeMove}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
<MovesList
title="Blunders"
Expand All @@ -151,6 +170,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
hover={hover}
makeMove={makeMove}
colorSanMapping={colorSanMapping}
moveEvaluation={moveEvaluation}
/>
</div>
</div>
Expand All @@ -165,18 +185,45 @@ function MovesList({
hover,
makeMove,
colorSanMapping,
moveEvaluation,
}: {
title: string
textColor: string
moves: { move: string; probability: number }[]
hover: (move?: string) => void
makeMove: (move: string) => void
colorSanMapping: ColorSanMapping
moveEvaluation?: {
maia?: { policy: { [key: string]: number } }
stockfish?: {
cp_vec: { [key: string]: number }
winrate_vec?: { [key: string]: number }
winrate_loss_vec?: { [key: string]: number }
}
} | null
}) {
const [tooltipData, setTooltipData] = useState<{
move: string
position: { x: number; y: number }
} | null>(null)

const filteredMoves = () => {
return moves.slice(0, 6).filter((move) => move.probability >= 8)
}

const handleMouseEnter = (move: string, event: React.MouseEvent) => {
hover(move)
setTooltipData({
move,
position: { x: event.clientX, y: event.clientY },
})
}

const handleMouseLeave = () => {
hover()
setTooltipData(null)
}

return (
<div className="flex flex-col">
<p className={`text-sm font-medium ${textColor}`}>{title}</p>
Expand All @@ -185,15 +232,32 @@ function MovesList({
<button
key={move.move}
className="text-left hover:underline"
onMouseLeave={() => hover()}
onMouseEnter={() => hover(move.move)}
onMouseLeave={handleMouseLeave}
onMouseEnter={(e) => handleMouseEnter(move.move, e)}
onClick={() => makeMove(move.move)}
>
{colorSanMapping[move.move]?.san || move.move} (
{Math.round(move.probability)}%)
</button>
))}
</div>

{/* Tooltip */}
{tooltipData && moveEvaluation && (
<MoveTooltip
move={tooltipData.move}
colorSanMapping={colorSanMapping}
maiaProb={moveEvaluation.maia?.policy[tooltipData.move]}
stockfishCp={moveEvaluation.stockfish?.cp_vec[tooltipData.move]}
stockfishWinrate={
moveEvaluation.stockfish?.winrate_vec?.[tooltipData.move]
}
stockfishLoss={
moveEvaluation.stockfish?.winrate_loss_vec?.[tooltipData.move]
}
position={tooltipData.position}
/>
)}
</div>
)
}
Expand Down Expand Up @@ -245,6 +309,7 @@ function Meter({
textColor,
probability,
colorSanMapping,
moveEvaluation,
}: {
title: string
textColor: string
Expand All @@ -254,11 +319,37 @@ function Meter({
makeMove: (move: string) => void
colorSanMapping: ColorSanMapping
moves: { move: string; probability: number }[]
moveEvaluation?: {
maia?: { policy: { [key: string]: number } }
stockfish?: {
cp_vec: { [key: string]: number }
winrate_vec?: { [key: string]: number }
winrate_loss_vec?: { [key: string]: number }
}
} | null
}) {
const [tooltipData, setTooltipData] = useState<{
move: string
position: { x: number; y: number }
} | null>(null)

const filteredMoves = () => {
return moves.slice(0, 6).filter((move) => move.probability >= 8)
}

const handleMouseEnter = (move: string, event: React.MouseEvent) => {
hover(move)
setTooltipData({
move,
position: { x: event.clientX, y: event.clientY },
})
}

const handleMouseLeave = () => {
hover()
setTooltipData(null)
}

return (
<motion.div
className="flex min-h-6 w-full flex-row items-start justify-start gap-2 overflow-hidden"
Expand All @@ -282,8 +373,8 @@ function Meter({
<button
key={move.move}
className="text-left hover:underline"
onMouseLeave={() => hover()}
onMouseEnter={() => hover(move.move)}
onMouseLeave={handleMouseLeave}
onMouseEnter={(e) => handleMouseEnter(move.move, e)}
onClick={() => makeMove(move.move)}
>
{colorSanMapping[move.move]?.san || move.move} (
Expand All @@ -292,6 +383,23 @@ function Meter({
))}
</div>
</div>

{/* Tooltip */}
{tooltipData && moveEvaluation && (
<MoveTooltip
move={tooltipData.move}
colorSanMapping={colorSanMapping}
maiaProb={moveEvaluation.maia?.policy[tooltipData.move]}
stockfishCp={moveEvaluation.stockfish?.cp_vec[tooltipData.move]}
stockfishWinrate={
moveEvaluation.stockfish?.winrate_vec?.[tooltipData.move]
}
stockfishLoss={
moveEvaluation.stockfish?.winrate_loss_vec?.[tooltipData.move]
}
position={tooltipData.position}
/>
)}
</motion.div>
)
}
Loading