PawnPilot is a macOS chess app that detects a board position from an image and lets you analyze variations, inspect best lines, or play against Stockfish.
This README reflects the current main branch implementation.
- Platform: macOS app (
SwiftUI+AppKitbridge), Apple Silicon. - Minimum deployment target: macOS
13.5. - Engine: bundled Stockfish binary at
PawnPilot/Engine/stockfish-macos-m1-apple-silicon. - Offline app: no network dependency for detection or analysis.
- Current app version settings in project:
MARKETING_VERSION:1.2CURRENT_PROJECT_VERSION(CFBundleVersion):3
The app uses a two-column layout:
- Left column: chessboard, overlays, and score strip.
- Right column: AppKit-backed tab view with three modes:
Analyze Variations(default on launch)Analyze Best LinesPlay Bot- Bottom section: output list (
Variations/Best Lines/ play-mode message).
Minimum window size is set to 1100 x 950 to avoid label wrapping in localized UI.
The Board group is split into two rows:
- Row A (state):
Next move(White/Black),Flip Board,Rotate(icon). - Row B (actions):
Open Image...,Reset,Undo,Redo.
Also supported:
- Drag and drop image onto board.
- Legal-move highlighting.
- Last-move highlighting.
- Animated piece movement.
- Keyboard/menu shortcuts via app commands for open/reset/undo/redo/rotate/flip.
Search Depthslider:4...30(default12).Strict depthtoggle: defaultON.
Strict depth applies to:
Analyze VariationsAnalyze Best Lines
It is not forced for bot-move generation.
Analysis Parameters:Alternatives/moveslider (1...10).- Action button:
Analyze. - Output list behavior:
- Shows a selectable tree-style variation list with line numbering for current children.
- Number labels are right-aligned to a fixed width so single and double digits align.
- Selected path is rendered as a single row of move tokens.
- Earlier tokens in that path are clickable to jump back.
- Current last token is not clickable and not visually emphasized as clickable.
- Previously discovered alternatives are kept and shown in a gray, indented history list.
- Colored current alternatives are displayed as the most-indented entries.
- Clicking the selected row again deselects and returns to the root variation view.
- Board arrows in this mode show immediate next-ply branches from current base path.
Tree expansion notes:
- Expansion is lazy and happens one ply at a time.
- Distinct first moves are deduplicated.
- Retries up to 3 times with wider
MultiPVif unique move count is below request. - If fewer unique moves exist, status reports reduced count.
- Engine loop now exits cleanly on
bestmoveeven when requestedMultiPVcannot be fully populated, avoiding stalls.
Analysis Parameters:Linesslider (1...10)Display pliesslider (2...10)- Action buttons:
AnalyzePlay Selected Moves- Output list:
- Each line is prefixed with
a,b,c, ... - Format is
scorefollowed by UCI move sequence. - Board arrows:
- Multi-line mode labels are
a1,a2, ... /b1,b2, ... - Selected single-line mode labels switch to
1,2,3, ...
Bot Parameters:Strength(1...5)Randomness(1...5)Keep playingtoggle- Action button:
Play Bot Move - In play mode, analysis line output is hidden in the bottom section.
For analysis modes, engine strength is effectively maxed (limitStrength = false).
For bot play, configured strength/elo limiting is used.
- Score strip under board shows
Score for whiteorScore for blackbased on board bottom orientation. - Variation-tree node scores are displayed from stored node perspective and adjusted for bottom side display.
- Threat map overlay rendering still exists internally (full-square red/blue overlays on white square base), but its UI toggle is currently removed from the visible interface.
Each group header has a question-mark icon:
BoardEngine ParametersAnalysis Parameters(both analysis tabs)Bot Parameters
Hovering for ~0.5s opens a popover with concise control explanations.
Project-localized languages currently configured:
- English (
en) - German (
de) - French (
fr) - Spanish (
es) - Italian (
it) - Chinese Simplified (
zh-Hans) - Japanese (
ja) - Korean (
ko) - Portuguese (Brazil) (
pt-BR)
Localization files are in PawnPilot/*.lproj/Localizable.strings.
Open in Xcode:
open /Users/felix/Documents/Programming/swift/PawnPilot/PawnPilot/PawnPilot.xcodeprojBuild from CLI:
xcodebuild -scheme PawnPilot -project /Users/felix/Documents/Programming/swift/PawnPilot/PawnPilot/PawnPilot.xcodeproj -configuration Debug buildTo test a language in Xcode:
Product > Scheme > Edit Scheme...- Select
Run > Options - Set
Application LanguageandApplication Region - Run
- App source:
PawnPilot/ - View + UI composition:
PawnPilot/ContentView.swift - App state and behaviors:
PawnPilot/AppViewModel.swift - Engine wrappers:
PawnPilot/NextMoveModels/Engine/ - Detection pipeline:
PawnPilot/FENDetector/ - Project settings:
PawnPilot.xcodeproj/project.pbxproj
- XCTest targets are mostly template scaffolding and do not yet cover current chess/engine workflows comprehensively.
- Recent images are kept in memory only (no persisted history).
- Threat-map feature is implemented but currently hidden from UI controls.