A Swift Package that wraps Stockfish for safe, high-quality chess analysis on iOS and macOS.
Existing Stockfish wrappers for Swift use dup2() to redirect stdout, which crashes SwiftUI. LucidEngine compiles Stockfish as a C library and communicates via direct function calls -- no stdout hijacking, no crashes. It delivers Stockfish-level analysis (~3500 ELO) through a clean async/await API.
- Single position evaluation -- FEN in, centipawn score + best move out
- Full game analysis -- analyze every move with accuracy percentages
- Move classification -- brilliant, great, good, book, inaccuracy, mistake, blunder
- Win probability -- per-move win/draw/loss percentages
- Game phase detection -- opening, middlegame, endgame boundaries
- Thread-safe -- actor-based API serializes all engine access
- No stdout redirect -- safe to use alongside SwiftUI and OSLog
Add LucidEngine as an SPM dependency:
// Package.swift
dependencies: [
.package(url: "https://github.com/CarlosDanielDev/lucid-engine", from: "1.0.0")
]Or in Xcode: File -> Add Package Dependencies -> enter the repository URL.
import LucidEngine
let engine = LucidEngine()
try await engine.start()
// Evaluate the starting position
let assessment = try await engine.evaluate(fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
print(assessment.score) // .centipawns(20) -- slight white advantage
print(assessment.bestMove.uci) // "e2e4"
// Or just get the best move directly
let move = try await engine.bestMove(fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
print(move.uci) // "e2e4"// Array of FEN positions from your game
let fens: [String] = gameViewModel.fenHistory
let analysis = try await engine.analyzeGame(fens: fens)
// Per-player accuracy
print("White: \(analysis.accuracy.white)%") // e.g., 87.3%
print("Black: \(analysis.accuracy.black)%") // e.g., 72.1%
// Walk through each move
for move in analysis.analyzedMoves {
print("Move \(move.moveNumber): \(move.classification)")
// .brilliant, .great, .good, .inaccuracy, .mistake, .blunder
}| Type | Description |
|---|---|
LucidEngine |
Actor -- main entry point; start(), shutdown(), evaluate(fen:depth:), bestMove(fen:depth:) |
PositionAssessment |
Score, best move, principal variation, depth, nodes -- returned by evaluate() |
Score |
.centipawns(Int) or .mate(Int) |
Move |
From/to squares, optional promotion piece, UCI notation |
EngineConfiguration |
defaultDepth (1...100), threadCount (1...64), hashSizeMB (1...4096), timeoutSeconds (>0, default 5.0) |
EngineError |
initializationFailed, engineNotRunning, invalidDepth(Int), invalidFEN(String), invalidConfiguration(String), evaluationTimeout, analysisInterrupted |
GameAnalysis |
[planned] Full game result: analyzed moves, accuracy, phases |
AnalyzedMove |
[planned] Per-move evaluation, classification, centipawn loss |
MoveClassification |
[planned] brilliant / great / good / book / inaccuracy / mistake / blunder |
Accuracy |
[planned] White and black accuracy percentages |
WinProbability |
[planned] Win / draw / loss probabilities |
GamePhases |
[planned] Opening / middlegame / endgame move ranges |
| Requirement | Version |
|---|---|
| Swift | 6.2+ |
| iOS | 17.0+ |
| macOS | 14.0+ |
| Xcode | 16.0+ |
LucidEngine uses two SPM targets:
- CStockfish -- Stockfish compiled as a C library with a bridging header
- LucidEngine -- Swift actor wrapping the C library with an async/await API
See docs/ARCHITECTURE.md for the full technical blueprint.
- Fork the repository
- Create a feature branch (
git checkout -b feat/my-feature) - Write tests first (TDD is mandatory)
- Make your changes
- Run
swift testto verify - Open a Pull Request
MIT License. See LICENSE for details.