A chess opening repertoire study platform built with Next.js 15. Create and organize opening lines, study them with a visual board, train through repetition drills, and receive strategic commentary from an AI coach powered by Groq (Llama 3). Local position analysis is handled by Stockfish 16 NNUE running entirely in the browser. The web design and AI prompts are all in brazilian portuguese.
Live at: aichess.com.br
- Repertoire builder — Create opening repertoires for White or Black, organize lines into a move tree with full support for variations and transpositions
- Interactive study board — Navigate your repertoire moves, add annotations, and explore branches with a fully interactive chessboard
- Stockfish 16 NNUE analysis — Real-time position evaluation and best-line suggestions running locally in the browser via WebAssembly, with no server round-trip required
- AI commentary — Strategic explanations of any position generated by Groq (Llama 3.3-70b), adapting its analysis based on whether the engine is enabled or not
- Training drills — Flash-card-style training sessions that quiz you on your own repertoire moves and track correct answers over time
- AI hints — When stuck in a drill, request a subtle hint that guides you toward the correct move without revealing it directly
- Daily tip — A daily opening tip generated by the AI and cached in the database so it is computed only once per day
- Public repertoires — Mark any repertoire as public so other users can browse and study it from the explore page
- Authentication — Email/password and Google OAuth login via Supabase Auth
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Language | TypeScript |
| Frontend | React 19, Tailwind CSS, Framer Motion |
| Chess logic | chess.js |
| Chess engine | Stockfish 16 NNUE (WebAssembly, runs in browser) |
| AI / LLM | Groq SDK — Llama 3.3-70b-versatile |
| Database | Supabase (PostgreSQL) |
| Auth | Supabase Auth (email + Google OAuth) |
| Deployment | Vercel |
src/
app/
api/v1/ai/
comment/ POST — strategic commentary for a position
hint/ POST — subtle move hint for training drills
tip/ GET — daily opening tip (cached per day)
auth/
callback/ OAuth and email confirmation handler
login/ Login page
signup/ Signup page
signout/ Session termination
dashboard/ User home page (protected)
explore/ Browse public repertoires
repertoire/
new/ Create a new repertoire
[id]/ Study a specific repertoire
train/
[id]/ Training drill session for a repertoire
globals.css
layout.tsx
page.tsx Landing page
components/
chess/
CustomChessBoard.tsx Interactive board with piece rendering
ChessBoardDemo.tsx Animated demo board for the landing page
explore/
ExploreViewer.tsx Public repertoire listing
ExploreDetailClient.tsx Read-only detail view
landing/
HeroSection.tsx
FeaturesSection.tsx
HowItWorksSection.tsx
CtaSection.tsx
layout/
Navbar.tsx
Footer.tsx
repertoire/
StudyBoard.tsx Main study interface (board + tree + AI + engine)
AICommentary.tsx AI commentary panel
RepertoireDetail.tsx Repertoire metadata and controls
training/
TrainingSession.tsx Drill session component
hooks/
useStockfish.ts Web Worker wrapper for Stockfish 16
lib/
ai/
service.ts Centralized Groq client (generateText, generateJSON)
chess/
moveTree.ts Move tree data structure and utilities
openingDatabase.ts FEN-to-opening-name lookup using local JSON
puzzleService.ts Tactical puzzle fetching utilities
supabase/
client.ts Browser client
server.ts Server Component / API Route client
middleware.ts Session refresh and route protection
utils/
security.ts UUID validation before database queries
middleware.ts Global Next.js middleware (auth guard)
scripts/
fetchPuzzleIds.mjs Script to populate puzzle IDs from Lichess
types/
database.ts TypeScript types for all Supabase tables and enums
supabase/
migrations/
20240510000000_create_puzzles_table.sql Puzzles table structure
20260510214000_create_core_schema.sql Core tables and RLS policies
seed.sql Initial tactical puzzles data
public/
pieces/ 12 PNG chess piece images (wK, wQ, wR, wB, wN, wP, bK...)
openings.json Opening database indexed by FEN (used for opening detection)
stockfish-nnue-16.js Stockfish 16 compiled to WebAssembly
stockfish-nnue-16.wasm
nn-5af11540bbfe.nnue Stockfish NNUE neural network weights
profiles — One row per user, created automatically on signup.
| Column | Type | Notes |
|---|---|---|
| id | uuid | References auth.users |
| text | ||
| full_name | text | |
| chess_rating | integer | Self-reported rating |
| skill_level | enum | beginner / intermediate / advanced / expert |
| subscription_tier | enum | free / pro / elite |
| preferred_color | enum | white / black / both |
repertoires — Stores the opening lines a user has created.
| Column | Type | Notes |
|---|---|---|
| id | uuid | |
| user_id | uuid | References profiles |
| name | text | |
| color | enum | white / black — the side the user plays |
| moves | jsonb | Full move tree (see MoveTree structure below) |
| is_public | boolean | Visible on the explore page |
| opening_name | text | Auto-detected from the opening database |
| eco_code | text | ECO classification code |
| tags | text[] | |
| total_study_time | integer | Seconds |
| total_moves_studied | integer |
training_sessions — Records of each drill session.
| Column | Type | Notes |
|---|---|---|
| id | uuid | |
| user_id | uuid | References profiles |
| repertoire_id | uuid | Which repertoire was drilled |
| duration_seconds | integer | |
| moves_played | integer | |
| correct_moves | integer | |
| session_type | enum | drill / exploration / analysis |
daily_tips — AI-generated tips cached per calendar day. Not in types/database.ts but used in the tip API route.
| Column | Type | Notes |
|---|---|---|
| date | date | Primary key |
| title | text | Opening name or concept |
| content | text | 2–3 sentence explanation |
puzzles — Tactical puzzles from the Lichess database (migration in supabase/migrations/).
| Column | Type | Notes |
|---|---|---|
| id | text | Lichess puzzle ID |
| fen | text | Starting position |
| solution | text[] | Sequence of moves in UCI notation |
| rating | integer | Puzzle difficulty |
| themes | text[] | e.g. mateIn2, fork, backRankMate |
Repertoire lines are stored as a tree of MoveNode objects serialized to JSON inside the moves column. Each node represents one move.
interface MoveNode {
id: string; // UUID
san: string; // Move in Standard Algebraic Notation, e.g. "e4"
fen: string; // Board position after this move
parentId: string | null;
children: string[]; // IDs of child nodes (variations)
comments?: string;
}
interface ChessTree {
rootId: string;
nodes: Record<string, MoveNode>;
}Utility functions in lib/chess/moveTree.ts:
createEmptyTree(fen)— initializes a tree from any starting positionaddMoveToTree(tree, parentId, san, fen)— adds a move or returns the existing node if the move already exists at that branchgetPathToNode(tree, nodeId)— returns the sequence of SAN moves from root to a nodegetVariations(tree, nodeId)— returns all child nodes (alternative moves) from a given positiongetFullLineInfo(tree, nodeId)— returns the full path with sibling variations at each step
All routes require authentication. Requests without a valid session return 401 UNAUTHORIZED.
Generates a strategic commentary for a position.
Request body:
{
"fen": "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 1",
"history": ["e4", "e5"],
"opening": "Open Game",
"evaluation": "+0.3",
"bestLine": ["Nf3", "Nc6", "Bb5"],
"turn": "w",
"repertoireName": "Italian Game",
"repertoireDescription": "Control the center with pawns",
"engineEnabled": true,
"previousComments": []
}Response:
{
"status": "success",
"data": { "commentary": "..." },
"meta": { "timestamp": "2026-05-10T00:00:00.000Z" }
}Returns a subtle hint that guides the user toward the correct move without revealing it.
Request body:
{
"fen": "...",
"expectedMove": "Nf3",
"history": ["e4", "e5"],
"opening": "Open Game",
"repertoireName": "Italian Game",
"turn": "w"
}Response:
{
"status": "success",
"data": { "hint": "..." }
}Returns the daily opening tip. If a tip already exists for today in the database, it is returned from cache. Otherwise, a new one is generated and saved.
Response:
{
"status": "success",
"data": {
"date": "2026-05-10",
"title": "The Italian Game",
"content": "..."
}
}- Node.js 18 or later
- A Supabase project (free tier is sufficient)
- A Groq API key (free tier available at console.groq.com)
git clone https://github.com/fermneto/ChessAI.git
cd ChessAI
npm installCopy the example file and fill in your credentials:
cp .env.example .env.localNEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
NEXT_PUBLIC_SITE_URL=http://localhost:3000
GROQ_API_KEY=your_groq_api_keyNEXT_PUBLIC_ variables are exposed to the browser. SUPABASE_SERVICE_ROLE_KEY and GROQ_API_KEY are server-only and must never be committed to version control.
Run the migrations and seed data using the Supabase CLI:
# Sincronizar o esquema do banco de dados
npx supabase db push
# (Opcional) Resetar banco local com os dados de seed
npx supabase db resetAs tabelas profiles, repertoires, training_sessions e daily_tips agora são criadas automaticamente através das migrações em supabase/migrations/.
npm run devThe application will be available at http://localhost:3000.
npm run build
npm startThe project is configured for Vercel. Connect your GitHub repository to a Vercel project and set the same environment variables from .env.local in the Vercel dashboard under Settings > Environment Variables.
Every push to the main branch triggers an automatic deployment.
- Stockfish runs entirely in the browser via a Web Worker. No chess engine calls hit the server.
- The opening detection (
lib/chess/openingDatabase.ts) loadspublic/openings.jsononce and keeps it in memory for the duration of the session. It falls back to a small hardcoded list for the most common starting positions to provide instant responses. - The
debug_db.tsfile in the root is a development utility for testing the Supabase connection and is not part of the application.