The board had to teach, not just play.
I was the Creative Technologist on the original iOS team for Duolingo Chess. I joined at the start of production in August 2024 and architected, animated, and engineered the first working version of the chessboard alongside two product designers.
I built the board and motion system in Rive, and wrote the Swift that handled chess logic, move validation, and application state. After the first MVP, a product engineer joined as we hardened the system for launch.
Duolingo Chess was being designed for people who might not know where a knight can move, or why the move they just tried did not work. That meant the board had to do more than accept or reject moves. It had to show what was possible, make mistakes understandable, and give learners enough confidence to keep trying.
Every state needed to answer a few basic questions: What can I do? What just happened? What should I try next?
Today, Duolingo Chess is used by more than 8 million people every day.
- Role
- Creative Technologist
- Timeline
- August 2024 – Post-launch
- Team
- Two Product DesignersOne Product Engineer
- Responsibilities
- Product DesignInteraction DesignUXAnimationRiveSwift
- Impact
- 8M+ Daily Active Users
Chess is hard. The board shouldn't be.
Most chess interfaces are designed for people who already understand the game. Duolingo Chess was being built for people who might not know where a knight could move or why the move they just attempted did not work.
That changed the responsibility of the board. It could not simply accept valid moves and reject invalid ones. It needed to help learners understand what was possible, respond clearly when they made a mistake, and make every interaction feel encouraging enough to try again.
Every state needed to answer a learner's next question: What can I do? What just happened? What should I try next?
The board was not only where the lesson happened. It was part of the lesson.
We had to design it by building it.
When production started, there was no finished board or final engine-connected architecture to build against. But we still needed to answer product questions: Should pieces tap or drag? How should an invalid move recover? How much guidance should the board provide? What should a piece feel like under your finger?
So I built the first functional iOS version.
Rive handled the board, interaction states, and animation. Swift handled chess logic, validation, state, and eventually the chess engine.
That gave us something real to test. Instead of reviewing static screens, we could put the board in someone's hands, see where they hesitated, change the interaction, and try again.
I also built a lightweight chess representation layer with FEN parsing so we could jump directly into specific board states and test edge cases without playing through an entire game.
Building it was how we designed it.
A move begins as an intention.
A drag gesture should not rewrite the board simply because a piece crossed over another square. First, it expresses what the learner is trying to do.
I separated each interaction into five stages:
Selection → Intended move → Validation → State → Animation
The learner could tap or drag a piece. The interface interpreted the intended destination. Swift determined whether the move was valid and updated the authoritative board state. Rive then expressed the result through motion.
I designed and implemented the complete interaction language of the board, including tap and drag selection, legal-move guidance, invalid-move recovery, captures, promotion, castling, multi-piece movement, responsive resizing, piece animation rigs, and engine-controlled moves. The challenge was not building each of those as an isolated feature — it was making them feel like one coherent system.
A learner moving a piece and the chess engine moving a piece could not rely on two unrelated pathways. Castling could not be a one-off animation. Promotion could not break the selection state. Resizing could not change the meaning of a board coordinate. Every move needed to resolve through the same model.
Separating intention from state also made the experience more forgiving. Beginners could explore what a piece might do without every touch becoming an irreversible action.
Weight, without physics.
The pieces needed to feel more substantial than icons sliding between coordinates.
Real physics would have introduced the wrong kind of complexity. Chess is deterministic: when a piece moves, its destination cannot be approximate. The physicality needed to live in the animation without gaining control over the outcome.
I built a nested transform system in Rive. One transform preserved the piece's true board position. Another responded immediately to the learner's input. A delayed secondary transform introduced a small amount of rotation, lag, and follow-through.
During a drag, the piece appeared to carry weight. When released, the transforms settled back into an exact board coordinate. The result was expressive but predictable—physical enough to feel alive, precise enough to remain trustworthy.
Motion added feeling without gaining authority over the move.
The architecture evolved with the product.
The earliest version optimized for speed of iteration. Individual pieces could emit their own movement events, which worked well while the system was small.
As the board gained special moves, engine updates, and more coordinated behavior, that approach became harder to reason about. We moved toward a board-owned ViewModel and structured move events, giving us one authoritative representation of the board and a cleaner boundary between Swift and Rive.
A product engineer joined after the first iOS version, and we continued hardening and extending the system together.
After launch, the next problem was performance. On lower-end devices, the board could run at slower frame rates. For a direct-manipulation interface, that matters: if a piece lags behind your finger, the interaction immediately feels less trustworthy.
I have since been helping rethink the Swift-to-Rive architecture around Rive's newer Data Binding model, with the goal of reducing manual event plumbing and creating a more direct path between application state and the board.
Duolingo aims to make learning accessible regardless of what device someone owns. For Chess, that means the board should feel just as responsive on an older phone as it does on a new one.
More than 8 million people now use Duolingo Chess every day, but the experience still comes down to something small: a learner taps a knight, understands where it can go, and keeps playing.