Tempo
- 24 Devlogs
- 98 Total hours
A simple chess site to review games, play in person, or practice against an engine.
A simple chess site to review games, play in person, or practice against an engine.
Small devlog, I was about to do another ship after addressing the feedback from last time, but I noticed a small bug where brilliant moves did not show sometimes. It turns out the issue was much simpler than I was testing for and it was due to a small multiplication sign error when converting the mate evaluation to centipawns to check if a move was winning.
Hello again everybody! I know its been a long time since I last worked on this project, but I read the feedback on this project and addressed your suggestions.
Most of the feedback was on ui/ux improvements, so as a result I removed all mentions of infinity/nan on the site, as it looks rather unpolished and unprofessional.
I also changed the modal dialogs from the built in alert function to a less intrusive custom toast notification.
Lastly, a couple people said the engine took slightly long to make moves, so I slightly lowered the engine depth for games and also removed another delay I originally added to make the engine feel more human like in its thinking time.
In terms of the game review engine I decided to keep it the same as it works pretty quickly due to a worker pool being used, but I did change the dialog slightly to make it feel like something is happening in the background, which suprisingly actually makes it feel faster.
Anyways, to everyone that tried this project and gave feedback, thank you as it was much appreciated.
The site is now live. I actually had a lot of issues in deploying this site for some reason (mainly due to the large stockfish binaries stored in git lfs and the coi serviceworker) and my deployments just kept failing. I eventually got it straightened out now and I am ready to ship the project.
Another devlog here focusing on bug fixes, and I am happy to say that almost everything is pretty much complete. I’ve fixed pretty much every out of sync issue, and even got game reviews to load pretty much instantly. It literally took only around 5 seconds to load a 65 move game, so that is finally optimized. I think the issue was some web workers were not terminating properly and taking up too much memory.
Anyways I hope to finally have this project out very soon, and the only thing I might to is try to get the history tree working. Today I actually did kind of get it to work but it caused massive performance degradations for some reason and was causing some conflicts with other components as well.
More progress has been made adding features and fixing bugs. I’ll highlight the changes below.
The game chart has been updated to include custom dots and lines showing the move classifications and key points during the game (brilliant moves, great moves, mistake, blunder, and miss). You can also click on the chart to go to that move.
The history view has now been updated to show the classification icons next to the move, which should make it easier to find moves you are looking for
Data in the game chart has now been memoized. This prevents the chart from crashing the page due to trying to process data many times per second.
Game review evaluations now use an active worker pool to run multiple evaluations at once rather than just one at a time. Positions are also cached now so all evaluations share 1 chess instance. In practice, this has reduced the game review time for a 20 move game from over 1 minute to around 7 seconds, which is around a 90% decrease.
A few things in this devlog, I separated the game review panel into 2 sections containing the review report and engine analysis. I’ve also refined the classifications for great and brilliant.
After a long time, I’ve finally added brilliant moves. This was done by comparing a squares attackers and defenders to determine if the piece is hanging. If a move results in that piece being hanging/sacrificed, and is the top engine move, then the classification will return brilliant.
I’ve attached an example below in a game where GothamChess does what he does best and sacrifices both his rooks.
I’m going to post more frequently as this project gets wrapped up, and I’ve just finished caching the game review data so feedback is instant if you load in game to review. I also decided to add colors to the start and end squares based on classification because it looks nice.
I’ve attached a video below, I don’t know why my screen recorder records very laggy but I promise it’s not actually that laggy.
I’ve been working on the game review stats, and i’ve implemented a function to classify an entire game and tally up the classifications (which was actually harder than it looked, since i needed to rewrite my hooks since hooks cannot be called within functions). It now works pretty decently, but I do want to optimize performance a bit since it takes a while. Funnily enough there was an issue where if the worker resolved too early it would not terminate and create a memory leak and eat your entire system memory, but thats fixed now.
I really don’t like going this long without posting a devlog, but debugging move classifications was really painful.
I encountered an issue where if you went through many moves very quickly, it resulted in classifications not working properly since stockfish could only give evaluations for the current move. This is not ideal since most classifications require checking the evaluation drop, which requires 2+ points of evaluation.
I tried many things, first I tried running 3 different stockfish web workers inside the stockfish hook, which caused a couple issues and was not very performant. Next I tried using a single worker and passing in 3 positions, however since the web worker is single threaded it didn’t really work all that well. I also tried using a queue to run each instance one at a time, but that got complex quickly and still did not work.
I also wanted to merge the classification and evaluation hooks, which created a 500 line mess of a file which was a nightmare to maintain.
Finally, I decided to revert all my changes and keep the hooks separate and simple, and created 3 instances of evaluation hooks within my classification hook. This was much cleaner and actually worked really well, so I wasted 8 hours making things too complex.# Devlog 12
I really don’t like going this long without posting a devlog, but debugging move classifications was really painful.
I encountered an issue where if you went through many moves very quickly, it resulted in classifications not working properly since stockfish could only give evaluations for the current move. This is not ideal since most classifications require checking the evaluation drop, which requires 2+ points of evaluation.
I tried many things, first I tried running 3 different stockfish web workers inside the stockfish hook, which caused a couple issues and was not very performant. Next I tried using a single worker and passing in 3 positions, however since the web worker is single threaded it didn’t really work all that well. I also tried using a queue to run each instance one at a time, but that got complex quickly and still did not work.
I also wanted to merge the classification and evaluation hooks, which created a 500 line mess of a file which was a nightmare to maintain.
Finally, I decided to revert all my changes and keep the hooks separate and simple, and created 3 instances of evaluation hooks within my classification hook. This was much cleaner and actually worked really well, so I wasted 8 hours making things too complex.
I am finally back to this project, and this time did not wait 8 hours to post a devlog. Anyways, I added two major features today, custom position imports (which I forgot to do last time) and engine play.
You can now import a position into the custom position editor, which is great for things like loading puzzles and endgames to practice against the engine. You can also export positions by pressing the copy button to copy the position fen to the clipboard.
You can now play games against stockfish, and choose a difficulty level from 0-20. As mentioned above I believe this is a quite useful feature for things like just playing by yourself or practicing different endgames against the computer.
I finished work on in-person gameplay and custom position setups, all that is left now is to finish adding engine play, polish game review, and add brilliant moves.
You can now choose the piece you would like to promote to (no longer auto queen).
You can now create a game to be played in person between 2 people. Time controls are also availible.
You can now load custom positions via drag and drop, which is useful for practicing endgames or creating puzzles.
I tried to convert the history from a linear array into a tree, and it did not go well. I spent literal hours trying to get it to work and look at tutorials, but it just did not want to work. So for now i’ve decided to stop working on that feature, and just focus on the last few remaining tasks. I do have to fix a couple of things since a lot of features are currently in progress, but I will post another devlog later showing the updated features.
Sorry again for the long devlog, some things took a bit longer than I expected. Anyways, icons/glyphs have been added in this devlog. I’ve also fixed some issues with move backtracking. Additional classifications such as miss and great have been added, which took a while since I had to do a lot of refactors to store all the data in cache, and I also didn’t realize I sometimes was tracking the evaluations for the next moves, not the ones just played, which took a while
Miss: Miss is when the previous player makes a bad move, but the next player fails to capitalize on it causing the evaluation to drop back to near where it was before.
Great: Great moves are the only moves in the position that work, provided that the outcome is drawn or winning and you are not already winning had you not played the move. It compares 2 lines of stockfish to evaluate the evaluation difference and check for the conditions outlined above.
Lots of QOL features and fixes added today, i’ve added a basic view of move history, and added a settings page where you can change the theme of the website or board. Next, I do want to work on features that do not involve the game review, such as pass and play or engine play.
You can now properly go through a game’s moves and view all played moves in the side pane.
Website theming has been added, alongside being able to choose the colors you would like the board to be.
Second devlog today, this is more of an extension of the previous devlog since a lot of features were not fully polished yet. Since then move playback has been added and I also added a game review container. Most of the logic has now been implemented, all thats left now is a little polish and styling. The only logic thats left is trying to find a way to add proper move history and advanced classifications. I also attached a demo video this time since I forgot to last devlog.
It is now possible to use arrows to traverse forwards and backwards if a PGN file is imported.
I added a little side container which will be used to show the stats of the game review. Currently it only shows the opening and move feedback, but it will be expanded to show accuracies and a full breakdown of the analysis and position similar to chess.com.
Sorry for the long devlog, some things took longer than expected. First I decided to waste time trying to improve the UI until I remembered I suck at design and just decided to revert to the original design. Then I spent forever wondering why my input textbox would not work properly just for me to change e.target.value to e.currentTarget.value. Although I guess where would the fun be if there was no struggle. Anyways, here are the features I added.
It is now possible to flip the board and go forwards and backwards through moves.
This one took a bit of time, but now you can import games from Chess.com, or provide your own PGN/FEN. Later on I’ll probably also add Lichess as an import source as well.
Site styling has been added in this commit, and it also comes with light/dark mode. The evaluation bar has also been added, and is responsive based on the win probability formula.
Move classifications have finally been added. I thought it wouldn’t take this long but instead I spent hours trying to deal with react asynchronous state and trying to coordinate different hooks to play along nicely. Thankfully it works properly now (hopefully).
The classifications added are best, excellent, good, inaccuracy, mistake, blunder, and theory. Opening names have also been added as well.
Next, I’ll work on making the site actually look pretty and have functionality. Importing games should also come next after that. Towards the end i’ll add other classifications as well such as miss, great, and brilliant, however, I expect them to be more difficult as they have slightly stricter classifications.
There is now a playable UI to play Chess games. This was done using a mix of chess.js for the logic and react-chessboard for the UI. Most of the logic was handled by the board, however click/drag to move took some time to add. There is also positional evaluations and engine feedback now.
Next, I plan on creating the actual site design and controls. I also want to add a way to import games from sites like chess.com, and have the ability to load a full game rather than just a position. Move classification is also something that should be implemented soon.
I started work on Tempo, a chess analysis site to review your games. Chess engines such as Stockfish are easily self-hostable anyways, so there is no reason for sites like chess.com to limit game analysis to 1 per day.
Added move analysis using Stockfish, which is fully selfhosted. Figuring out web workers and UCI was pretty time consuming, but eventually I got the hang of it and figured it out.
Next, I plan to work on creating the chessboard and site UI. Later I’ll add move classifications such as “Blunder”, “Mistake”, “Excellent”, etc. Maybe i’ll add “Brilliant” moves, but there seems to be no clear definition of one other than “a good sacrifice”.