|
21103
|
Ritualia by @gabriel_ferreira | Stardance
|
gabriel_ferreira
|
1
|
148.7
|
2310
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-23T23:45:29Z", "hours": 148.0, "multiplier": 18.45, "payout": 2310, "blessing": "neutral", "text": "What did i made I made an complete music play system that will help users to learn while listening to musics! I used youtube, flask, python, mysql, js and hope to make this! What else Solved a lot of painful bugs that were stopping the project from working Finished and made the music queue work Added music description labels Improved a lot the performance Made the website responsive Added a keyboard based navigation Fixed so much errors at the cover-flow that now i forgot how many Added bug checks before the play of each video on the player Created an toast component to show errors or infos Added 54 musics to choose and listen Challenges The most painful code was the player and the cover-flow, they were with a lot of hidden bugs that i had to figure out, feats that i had to make and pain to suffer! Now i figured out that i love and HATE making a website responsive! What im proud of MutationObserver: An observer that loads / hides an image based on its position at the cover-flow, this system took a while and worked very well. Error checks at player: The system can handle the error that happen and dont crash! Keyboard navigation: Everyone can use the keyboard to navigate now! Oracle VM: For the first time i used an ssh and hosted an website in my own machine (oracle, not mine)! How to test Access http://ritualia.duckdns.org/ , when you join and the page loads you will find a screen to choose an genre, select which one you want, after you will see an emotion selector, select the emotion that you wanna feel! You will see the player screen and an audio explaining the music (The audio is in portuguese), after the audio the music will play. Notice: The github and the website are in portuguese, please use your browser built-in translator or any that you want to use the software properly! Follow the installation guides at github if you want to install", "repo": "https://github.com/GF-Silva/Ritualia", "demo": "https://ritualia.hackclub.app"}]...
|
[{"post_id": 73067, "ts": "202 [{"post_id": 73067, "ts": "2026-09-24T09:47:16Z", "hours": 0.6983, "text": "Added english readme I created an english readme, api and install Guide, so it will be easier to read and more accessible for worl-wide users"}, {"post_id": 72881, "ts": "2026-09-23T22:36:56Z", "hours": 0.3906, "text": "It is time to ship! Now the system is working perfectly fine running at a vm in oracle cloud with a public domain, and a dns with duckdns at http://ritualia.duckdns.org/ Warning: It is just HTTP!"}, {"post_id": 72810, "ts": "2026-09-23T19:36:13Z", "hours": 1.3461, "text": "Configuring an ssh server! I configured an oracle cloud vm with ubuntu to host my website 24/7, that was because nest wasnt working in a while. Im running it at a local IP with http only, i will configure https today and maybe an domain, the IP is http://164.152.55.252 , notice that some browsers may block you from accessing and http website. UPDATE AFTER THE DEVLOG: I put an domain using duck dns: http://ritualia.duckdns.org Hardwork I had absolutely not a single knowledge about oracle cloud vm, so configuring it was an hell. Sometime my internet stopped working so i had to use my smartphone, this lead me to configuring an invalid ssh key and i had do configure everything from scratch, i spent 5 hours configuring everything, but that was ssh and wasnt tracked. But now everything is working fine. Thx oracle This vm is a 24/7 entire OS (Virtual Machine) that has some good free plans, without any cold start. Thx stardance Stardance now will have one more mount!!!!!! I still has roughly 40 hours of deep development to do after this ship, i will love to finish that in stardance!"}, {"post_id": 70936, "ts": "2026-09-20T02:22:48Z", "hours": 2.9706, "text": "Added install guides Now there is guides to help the user install for ubuntu, arch and windows. Notice that im a linux user and my pc is weak, so i could not test it on another operational system. Also the guide is in portuguese (all of them), please use your browser built-in translator or any of them to read if u dont understands portuguese I could test it on another linux distro, but i would have to go through all the install steps. Also i cannot try installing windows because it normally wipe out another OS installed on the same disc (i know that it just replaces the bootloader) and using a VM was not possible due to the amount of RAM and the processor that i have."}, {"post_id": 69913, "ts": "2026-09-18T01:53:38Z", "hours": 0.3256, "text": "All done, it is time to ship Every metric at lighthouse it nearly perfect, im so exited to ship it!"}, {"post_id": 69904, "ts": "2026-09-18T01:19:42Z", "hours": 4.9561, "text": "The accessibility workings is done Features Now the system has a new navigation system that allow users to navigate with just the keyboard! (The video was with just the keyboard) Why Why not? It was meant to improve the accessibility for users without mouse, or any another problem and because i was tired of having to use the mouse to debug something. How it was made Again with a lot of pain, the feature itself was easy but i had to fix some errors that went unnoticed, so it took more time. The feature detects when the user press a key and do an action based on wich key was. The accessibility was easy to get 100, but the metrics at lighthouse dont give all what the users will need, i had to think about the website usage and how would be the easiest way for the user. Results The accessibility went from nearly 69 to 100! What next Now i will work on the best practices! Update after the devlog: Nearly every metric is already maxed out lol, i will ship it very soon!"}, {"post_id": 69444, "ts": "2026-09-17T02:13:13Z", "hours": 1.6906, "text": "The performance workings is finished and bug fix Fixes Now the logo z-index is lower, that is because the logo was ‘eating’ the click in more important elements. Also i did a small change at the cover-flow, that change fix the bug of the scroll at the element sudently stoping when at a certain position. The copa script had some old references to images that were leading to bugs, i changed it. Performance I already finished it in the past devlog, i was just checking if there was anything worth improving, but everything is working fine and now is time to improve acessibility. Most of the logged time was me trying to improve more some metrics at the lighthouse, but the work was too much for anything that is already good, so i decided to stop before i started focusing too much in it."}, {"post_id": 69395, "ts": "2026-09-16T23:43:00Z", "hours": 1.505, "text": "Fixing an error at the youtubeHelper Now the youtubeHelpers checks if the youtube API is ready before sending commands. Why Sometimes the API maybe is not finished yet, that was leaving an untreated error that was braking the entire website. How was made With a lot of pain and suffer. I thought “Oh hey, that will be a 15 minutes fix” - i spent 1 HOUR FIGHTING with the iframe itself, nothing was working and at some point i started thinking that even the API of YOUTUBE wasnt working, even the most basic function that should be triggered when the youtube finished the loading wasnt beeing activated, even the console.log(“Api READY!”) wasnt working, even when it worked it wasnt working well, the variable of the player was a promise and not the result. At the end i shut down my PC, defeated, without any energy left, with just hope that in the next day (this) that would be fixed (if not i was planning to ignore and make it a feature “Easter egg, if u dont join the website for a while it will not load!”. The problem here was just the position were the iframe api was in the HTML, it was being loaded before the helper script, so the helper was not there to check if it the iframe was ready or not, the fix was just move it a little down. Architecture It was just an promise, if the function checks that the iframe isnt available it await for it to be available. The check if it was available use the onYoutubeIframeAPIReady, easy easy (except for all the suffer that i went into)."}, {"post_id": 68896, "ts": "2026-09-15T23:59:43Z", "hours": 1.1389, "text": "The loading is done and working! Fix I fixed the error that were happening when the cover had a certain amount of elements. Problems The fix itself was very easy to do, but doing it in a readable or without using 10 lines of code (i want things concise) was way harder than i expected. So i spent this entire time trying different ways to do it, each of them making everything worse. Reasoning The bug were with less than 14 elements, the script were calculating the first and last element index, it happened that these elements were behind the screen focus. Why? Because the values that the system was using were leaving these values, so i had to fix the way it was calculating things."}, {"post_id": 68865, "ts": "2026-09-15T22:15:27Z", "hours": 1.3303, "text": "The loading is done Features Now the loading at the mutationObserver is finished, it finally loads or unloads the images that should be (or not) loaded! The new observer is way faster, because it can detect the image way before it enters the screen, loading it before and having more time to do it. Also the system loads just a maximum of images (with the configs that i put it is 13), so it will not fry an cellphone. Problems The loading part was easy to do, i already done it before in the past observer (intersectionObserver), so i just had to pass the old code to the new part. But when the cover-flow element dont got atleast 13 elements the mutationObserver code breaks completely! Im still pondering how to solve it, when i do i will post about! Results The performance went from 78 to 100! The system is way faster! The user does not see a blank image anymore! Why The old method was slow even with a good internet connection, because it was loading the images just when the element was already in the screen, leaving to a perceptive delay for the user and a blank image to the user. Also i thought about creating an observer from scratch (maybe i was a little off my ideas, because that was insane), but the browser already had exactly what i wanted (the mutationObserver) Videos The new features The performance of the new feats The old features Reasoning While i was trying to sleep i thought about a system that fill the cover-flow with a maximum of images (like 10, or 13, or the code decides) at the DOM, using less memory to run. That system will free a lot of memory based on how many cards the cover-flow have. But that will have noticeable effects just with a lot of elements and probably would be hard to develop, maybe i will do in next updates. What next Im leading to the shipping, so i will improve metrics about the lighthouse, improve the readme and post it."}, {"post_id": 68449, "ts": "2026-09-15T04:25:35Z", "hours": 7.2278, "text": "Adding a mutationObserver Now, instead of an intersectionObserver, the system use a mutationObserver that monitors the angle of the cylinder itself. With that the loading of the images will be insanely better, faster and user-friendly. Now the changes in the cover-flow is observed at the cylinder angle, not at each card. There was some problems in the journey like, for some reason, unexpected cards being loaded or not, the loading script at the observer dont triggering at all (that was caused by the speed of the observer) and an insane amount of cards being triggered at the same time (i still did not figured out why, but that isnt ‘harmful’). But man, i had to be creative here and remember about some concepts like concurrent programming, buffer / queue and apply some delays (because the mutationObserver is insanely fast and can trigger every millisecond). That all was meant to decrease the speed of the mutationObserver, because it was triggering with the most small change in the cylinder, so i made it trigger just when an expected amount of movement was made. The red/yellow collor is for me to visualize the loading state, it is just for debug The code isnt finished, i still need to implement the loading part, for now i just implemented the observer and basics of the loading part"}, {"post_id": 67841, "ts": "2026-09-14T03:19:48Z", "hours": 4.2825, "text": "The observer is finished (nearly) Now the cover-flow has an observer that checks the position of the images and changes it styles based on that, so the images that the user is seeing is loaded while the others is hide. It still has some bugs and space for improvements that im still figuring out how to solve, like the image loading too late on the screen or, in slow internet connections, the image takes too long to load. Most of these bugs are because the observer (an intersectionObserver ) was designed for 2d contexts, not 3d (that were and still is an giant problem to solve). For this reason i was thinking about creating an observer from scratch in C++ that can work better in my 3d element, but the overhead would be high so im trying to solve in other ways before that. The feature was made using fetchPriority, contentVisibility and src (the system add the source just when the image is near the screen). OBS: I found about MutationObserver after this post, maybe i will use that instead of insersectionObserver. Oh man, at least if had found about this before… Aaaaaahhhhh i spent 9 hours in that, but at least a Lot of the new logic will be used. Anyway, lets cook"}, {"post_id": 67151, "ts": "2026-09-13T06:53:12Z", "hours": 5.4219, "text": "Adding an observer Now the script observe the card elements at the cover-flow component, classify their position and changes it visibility based on that. Im using an IntersectionObserver to observe every card, but it was designed to observe the position of 2d elements, so i had to figure out how to make it work well in an 3d element. The way it works is when the observe activates (it basically means that some card is in the range to load) it get the card info (like position and angle) and changes it visibility state based on that. Simple, right? No, it was a headache for the start to the top, nearly 4 hours of what i did was to fix the fact that it was meant for 2d. The observer were activating for cards that were in the back of the element, so i had to classify the card position into back or front by using its angle. But if i tried to use the card angle without anything else the script would broke (and did for 3 hours until i realized how to fix), so i had to use an second angle which is 360 - cardAngle (the 360 is the angle of an circle), so this new angle is based on the circle end while the other is based on the circle start. But the system still broke, because at some point one of these values would become negative and makes the if that classify the elements fail. The fix was using the absolute value in the if (it took 1 hour until i figured that; oh i were so happy when it worked). Why To improve the performance, so the browser will just load what is really important and not 50 images that the user cant even see. What else All that work definitely improved a lot my logic thinking and for the first time i used the truth table well. Now i just need to use the new code to change more the style of the images that are not in the screen. I did not deleted the code that i wrote in the past devlog, it was used in the new code to select how many images should be loaded in the same time. ** The first video is the result, the others is some problems that i had **"}, {"post_id": 66316, "ts": "2026-09-12T02:31:12Z", "hours": 4.5481, "text": "Improving the loading performance Now the system selects some images that needs to be shown faster than the others and making them load with priority. It was made by selecting the images that the user is seeing and defining some params like fetchPriority = \"high\" and decoding=\"sync\" , the other images have the params: decoding=\"async\"; loading=\"lazy\"; contentVisibility=\"auto\"; . With that config the LCP went from 2.4s to 0.5s . Also it loads the image in the start and dont change that config again, so the browser will be lazy while downloading these images. The problem is: only the first images are chosen as high priority, but their positions will be changed while the configs stays the same, that makes the browser lazy while loading them and makes the runtime performance became worse. To fix that i found about IntersectionObserver, that are meant to solve the problem of updating the images position fast. It was not applied yet, i found about it like 1 hour ago. What else Now the perspective of the emotionDrum is based on the elements that it have, before it was based just in the screen and would broke if something changes. I did a little change in the way that the script checks for clicks in the screen, now it has more accuracy (I changed the round system)."}, {"post_id": 64533, "ts": "2026-09-09T00:41:52Z", "hours": 7.6869, "text": "Improving the LCP (Largest content paint) performance I am improving the way that the website create and downloads the images, the main reason is to make the user see something faster. Before the system were doing 2 main things: Go trough the entire list of images, creating the elements and placing them into the page. Position them. But the position of the items were being done after the creation of the images, in another function. Now they are in the same function: it create the element, position it and add it to the page. That does not seem like much, but the code got way faster with that, probably because it dont need to go item by item in an list twice just to create an element. I tested the time to load the first element and it went from 8.63s to 6.43s , the test was made with 2200 elements (Yeah ik, it is a lot and normally it isnt that much, but i had to see how they were holding with more than 22 items). Also i fixed a bug that passed unnoticed while improving the responsiveness: At some point of images the visibility of the elements broke, that was because the perspective (what makes the 3D perspective of the component, and makes it visible with 3D effects) was based on the screen size, not the elements itself. What was the problem in that: Each element takes a size in the screen ‘makes the circle that shows the element be more and more near of our point of view’ (i cant explain it any better, search what is ‘perspective in an 3d element at HTML’ ). While it was approaching our point of view (POV), our POV were exactly at the same position (based on the screen size), so at some point the circle perspective would pass the POV and we would be unable of seeing it well. Now it is based on the elements: The 3d elements were basically a circle, i just used the diameter to change the perspective based on it. TODO: Maybe i lowered the image quality too much… I will fix it in the next updates. Also i were trying to improve the font settings to improve the performance, but that wast working so i decided to move on to this because it was more critical (took a while for me to jump to this, maybe like 2 hours trying and trying values in the font settings). i am also working in a way to load the images in parallel, with that it will take way less time (I didnt known about LCP before so i spent a while figuring out the way it works)."}, {"post_id": 63656, "ts": "2026-09-07T16:11:33Z", "hours": 2.6633, "text": "Improving the performance After finishing the improvements in the responsiveness, now i decided to improve the performance. I used lighthouse to get insights (i learned about it in an tiktok video) and figured out that the images size were too high (were an png of 1280x1280px), so i saw more about that in the page: https://developer.chrome.com/docs/performance/insights/image-delivery (an link that google lighthouse gave). With that i saw how to decrease the size while staying with quality, i reached up to the sharp-cli tool, that makes the work of resize, convert and compress the image for me. The command used was that: npx sharp-cli -i * .png -o ./output resize 320 -f avif -q 50 --effort 6 --smartDeblock --preset photo The 320 is the size that i want it to be at the end, i got that value by seeing what was the computed value (the value that is being used in the website) in an high resolution pc (not the most higher one, the high but normal pc) with the resolution of 2500x1714px . With this simple changing the image went from 2mb to 40Kb! Nearly 100% decrease, and take in mind that there is more than one img, so the change were even higher. Also i created 5 different images: 320px, 480px, 640px, 960px e 1280px. With them the browser can choose which one is better for each device. With these changes i went from 35 points of performance to 59."}, {"post_id": 63459, "ts": "2026-09-07T10:10:31Z", "hours": 0.8717, "text": "The home is now fully responsive Ah that took a while, but finally it is fully responsive. Now the description at the player UI resizes based on the screen size and active a scroll behaviour when need, also i did some minor change at the emotionDrum perspective to make it show more emotions at the same time, removed the padding in the arrows at the emotionDrum so they will have more space and fixed an error in the genre drum that was making it perspective broke. After all these devlogs i improved how i make a code responsive."}, {"post_id": 63436, "ts": "2026-09-07T08:55:04Z", "hours": 2.5378, "text": "The emotionDrum is now responsive! Now the buttons that you use to select the emotion are in the same side as the div that displays the emotion, so they dont fight for space anymore. This change is meant to fix the low size of the items in screens that are too small, in the new way we have more free space to display the emotions, there is not much to say. What else I did some minor changes in the size of some items at the player area, now they are easier to read! (I increased the size of some items)"}, {"post_id": 63379, "ts": "2026-09-07T05:17:01Z", "hours": 6.6125, "text": "Im nearly finishing the workings on the responsiveness. Now the entire player screen is responsive and do not breaks the texts anymore (except for the description area), also the buttons that show you the next screen (the ones that displays ‘player’ and ‘generos’) are responsive too, the music queue is working perfectly fine, and the area that is used to select an emotion is nearly responsive too, it just needs some adjusts in the two buttons that change the current emotion because they become too small and uses a lot of space when the screen is too small, after that this screen will be finished. It is taking a really long time, the fact of how many different screen sizes exists makes it harder to finish, but now there is times that i even cannot see if i changed the resolution in some areas, because the system looks the same. I spent quite a while testing different resolutions and combinations of size, i didnt even noticed that i where 6 hours here, but now ik more about css (things like container-type + container based sizes and more ways to set the size of an text) The video shows how it is now, if u want to see the before just checks the past devlog."}, {"post_id": 62723, "ts": "2026-09-06T06:59:19Z", "hours": 0.7094, "text": "Finished the correction of the errors at the perspective and click in the cover-flow component. Now the perspective stays the same 150vw value (that is based on the screen width) and stays normal, with everything working. Oh man, that needed a lot of logic and out of box thinking finding another ways to check where the user clicked without using an normal click event listener (for those who lost the past devlog or didnt understood, i cannot use a normal eventListener in that because the clicks is detected in another element or in nothing, even with z-index or more in css, so the solution should be done entirely on javascript logic). The first video is the new way, the second is how it was before all changes in it"}, {"post_id": 62679, "ts": "2026-09-06T05:10:34Z", "hours": 5.5194, "text": "i finished the workings on the section of the home page that i where doing before, now has a good responsiveness for pc and a decent one for mobile. Now im working on the main area of the home page, the one where the user selects the desired genre for the music (second img). It may looks completely fine, but that same element already was a headache before and is here again. The given area is the cover-flow component, before i already fixed it (or so i thought), but it was looking bad (the 3d perspective where a bit strange) and would probably broken if i added new genres. I were trying to figure out a way to listen to the clicks in the card without any problems, that seems easy at first glance, but the 3d perspective in the element make other elements eat the click from one another, make the clicks dont be listened and so many problems that i nearly decided to erase it and write from scratch. I already found a way to do it by using the mouse position, the center of the screen and the card width (the genre img) to transform it in an value that can be used to select the exact card without any dependencies on the doom selector. It basically uses just some values, put in some calcs and get the difference between the current card (genre) index and the clicked. Im nearly finishing it, but i still need to figure out some values and more."}, {"post_id": 61879, "ts": "2026-09-05T01:17:53Z", "hours": 1.1772, "text": "Im improving the responsiveness at the home page (before was the player page), but for some reason that idk the emotion selection div is having a strange behavior, i will update what it is after i fix it. Take a look: (the item in the center should be centered)"}, {"post_id": 61218, "ts": "2026-09-04T01:30:11Z", "hours": 0.725, "text": "Hi again! Like said in the past devlog, im improving the responsiveness of the website, specifically in the player part. But it had some problems and where distorting when playing an video, now it resizes based on the screen size in a way that it stays ¨normal¨. The first video is the new way, the second is the old way. It still needs a lot of improvements, but it is going!"}, {"post_id": 60619, "ts": "2026-09-03T02:22:12Z", "hours": 1.4631, "text": "Making the website responsive Hi again! Like i said in some devlog, the website dont have support for mobile, that was because it was designed to be at kiosk mode and work just in desktops. but i decided to change that. First of all: the site where using a lot of absolute values of dimensions, so it where braking even in the desktops (it wasnt responsive at all). But i spent a while changing it, it is isnt ready and has some problems, but is better than before. (The mobile is still strange, i did not started fixing it yet). Credits: https://css-tricks.com/snippets/css/fluid-typography/ - This website shows about a way to make the texts become responsive for the screen using some calcs, it is worth seeing. The first video is how it was before, the second is how it is now"}, {"post_id": 60559, "ts": "2026-09-02T23:48:07Z", "hours": 0.7944, "text": "Creating a new helper Context: There was an class called youtubeFrameControls , this class basically where designed as an structure to help using the youtube iframe API, but with the time this class where becoming basically to hold just an function (and in a very inefficient way), because the methods that it had before (like the one that runs when the iframe is loaded) had to have more and more specific logic in the codes that used it, so they where useless (because the codes that where using it where rewriting it). What i did: I picked the only function that where being used and transformed it in an helpers (that can easily be customized). This function was the one that creates the player of the musics, and the function where called createPlayer . Also i removed the old class (youtubeFrameControls) and replaced it for this helper in every place that used it. It now is way more simple than before and can me more customized."}, {"post_id": 60001, "ts": "2026-09-02T02:58:53Z", "hours": 2.1603, "text": "Refactoring the copa script I where placing some scripts in a class. These scripts are related with the player functions of the copa script, so i pick all of them and placed in the same class. I did it to follow best practices, but i confess that i still got some doubts about when to create an class and when the variable or method should be static or private (#property), i will search and learn more about because maybe i will have to refactor some parts of the code following these rules of best practices. That was all for now, see ya!"}, {"post_id": 59339, "ts": "2026-09-01T02:28:57Z", "hours": 2.4744, "text": "Adding more bug checks I added some checks in the player class at the startExplication function that checks if the src (the url for the audio) is valid or not by doing an fetch with the HEAD method and checking if the return is an valid audio before trying anything in this function. Also i solved this error in the same function: Uncaught (in promise) AbortError: The play() request was interrupted because the media was removed from the document. https://goo.gl/LdLk22 This error was because the startExplication function where trying to play the audio before it was loaded, i solved it by making it play the audio just after it was load with the event listener canplaythrough . There was another error at the playMusic function where the code where trying to play the youtube video before it was loaded, i solved it by making it wait until it was CUED (Where the video isnt playing, but is loaded and showed). (The website was not created to be in mobile and dont has a lot of support, the video where recorded in my smartphone because i had to record the audio and the audio on my pc dont work. In the Future i Will add mobile suport, but right now im finishing the bugs and etc)"}, {"post_id": 58653, "ts": "2026-08-31T04:27:35Z", "hours": 2.7947, "text": "Adding a new description feature So basically there was an place where was designed to have the description about an music, but that was empty and where only finished today What it do It is petty simple, it just show an text about the music that is currently playing, also there is an audio that plays before the music starts playing, but this audios is played just one time before the music so if someone loses it or didnt listen well there was not a second chance to listen for that audio. Now there is this place that holds the same content, but in the format of an text that can be read whenever they want while the music is being played, that was what i added. Also that text can be hidden, so it will not stay using half of the screen every time (in the screenshot it is active) What this audios do This audio / text is part of the main purpose of the website, they give some fun facts about the music that may be useful someday in some kind of quiz or essay. Also the audio is played before the music and the music plays just after the audio finishes. That is to make whoever is listening listen to the entire audio before having what he (or she) wants, so they will not listen to the music and skip the audio."}, {"post_id": 58526, "ts": "2026-08-30T23:20:27Z", "hours": 1.3911, "text": "Studing about cache So basically i where studing about cache, the main ideia was to implement it in the sistem, but then i realized something: Theres is nearly no difference between cache and a normal request in an localhost project, adding the cache would not improve anything, sometimes it maybe even slow the website, because the page would need load more code. I realized it afther a while studing about it, but anyway lets focus on another thing. Also i where studing with google for devs: https://developer.chrome.com/docs/workbox/caching-strategies-overview"}, {"post_id": 56374, "ts": "2026-08-28T03:45:15Z", "hours": 1.0169, "text": "Toast applied and tested The toast notification component is now being used at the player class, i did some tests and it is working very nice, hopefully the user will not see it very often (because that would be a problem, the user must not see it unless there is an error playing the music). But why did i make it? It is used to show more about what is going on for the user, so they will not become anxious if it something is working or not. Why not use another notification system? Each notification system has its own use cases, the others would be very painful for the user. Imagine every time a simple error (that is simple for me) like the music fail to play there was an error that interrupt the use of the app with an popup or alert, that would be painful, dont it? That is why i used an toast notification, because it is temporary (disappears after some seconds) and dont stop the use of the website. Also there is a feature that i implemented for the same reason a few devlogs ago that add a fallback in the music search, so it wont show a message at every single combination. Lets calculate how many combinations we have: there is around 50 musics in the database, 22 genres and around 40 emotions, multiplying the genres and the music 880 combinations that the user can make. Now lets see how many musics we can get: each music have around 1.2 emotions and 1.2 genres, so we get 72 combinations that lead to an music . With that in mind, we can see that from 880 combinations, just 72 of them are useful combinations, so we get a 8.18% for getting a music, and 91,12% of not getting one. Consider that each failed attempt shows an error that stop the use flow of the website, but that was before the past devlog, now it tries again and again and only afther failing everything it shows an error, at that point it must really show an error. Thats all, sorry for the long boring text and thanks everyone that read, see yall later"}, {"post_id": 56331, "ts": "2026-08-28T01:58:42Z", "hours": 3.1336, "text": "The toast notification is finished So i finished it, it is a component that u adds in the code that u wants to use. I added 2 icons, 1 for infos and another for warnings. What i used and did The element that holds it all is an dialog , the icons are svg , the text is a span and the element that shows the time left is an progress . To update the time left i used an setInterval that runs at a 10ms delay and deduce 0.01 of the dialog value, so it will be smooth to see. Also there is an if inside that destroy the element and clear the interval when the value of the dialog reaches zero or less (In the past devlog i said about not using an if, but considering how low the cost for an if in that time is i decided to use it anyway). The function that creates the toast receives some params that will let it be customized by whoever is calling it: const icons = Object . freeze ({ INFO : infoIcon (), WARNING : warningIcon () }); function createToast ({ message , time = 5 , styles , icon = icons . INFO }) // the `message` is the displayed message // the `time` is the time until close // the `styles` is custom css styles for the element, it uses the dictionary format {} // the `icon` is the svg icon What else? I will apply it in some elements and post about. See you later!"}, {"post_id": 56188, "ts": "2026-08-27T20:27:52Z", "hours": 1.5956, "text": "Creating a toast notification system So rn im creating what i said in the past devlog about a toast navigation. This isnt finished yet, im still figuring out an way to check the end of the timer, i found some ways to do it, like using an simple if inside the countdown. I didnt comment but i am using an setInterval to decrease the time and an <progress> tag to show the value but that is a bad ideia, imagine doing 1 if every 50 ms? that dont cost a lot of processing power, but i still will search for other ways to do it just to check, if yall got any hints or ideas leave a comment. Also i will improve the design, the design is petty poor."}, {"post_id": 55334, "ts": "2026-08-27T02:23:29Z", "hours": 4.2383, "text": "Fixing errors and adding bug checks Hi everyone, so i were fixing some bugs that i saw that may broke the app, i fixed all of them (for now), here they are: There was a logic bug that a class (the one that controls the youtube iframe) where doing stuff that it wasnt supposed to do (not an unexpected behavior, but a logic that should be outside of it), it was an easy fix. There was a bug at the player class that when the provided sourceId (for the youtube iframe) where wrong or unable to use it crash and stopped doing anything else (like playing another musics). I tryied solving it in various ways, one was beffore the changes that i did in my last devlog, but i failed because the class that holds the player where hard to fix, this devlog fix it. I fixed it by adding some bug checks and, when some error ocurred, it play the next music. There was also a bug at the player class and youtube-iframe-controls class, that for a couple seconds in the start of the website it would broke if u tried to play a music. It was because in the start of the program the youtube API where unable to be used. To fix it i just made it wait until the API where ready using an ASYNC function. There was also a bug that, afther the past devlog, it was doing and request at the /api/songs with params at the wrong format. Afther the past devlog the API started using the params genre_id and emotion_id , but the frontend where passing with the incorrect name (genre, emotion). Something that i implemented I upgraded the mysql query that where being used to get more infos about the music, before it where just returning infos like name, author, sourceId, etc, but now it also returns the genre and emotion from that given music. I added a bug check at the player class, now if it fails it pass to the next music. Something that i want implement I want to implement a simple toast notification system that will apear when something fails, like the playing of some music. Others The youtube docs for the iframe where very helpful for this changes, check it out: https://developers.google.com/youtube/iframe_api_reference?hl=pt-br"}, {"post_id": 54690, "ts": "2026-08-25T19:06:05Z", "hours": 3.2633, "text": "Optimizating some piece of code So there was a certain part of the code responsible for the songs queue in the main route, that piece is a core function but where running a while true loop for no reason , here is the part: async start () { while ( true ) { // { emotion, genre, author, name, sourceId } const musicData = await this . #musicQueue . get (); this . createPlayer ( musicData [ ' sourceId ' ], null ); this . #showMusicInfos ( musicData [ ' name ' ], musicData [ ' author ' ]); this . #queueList . removeChild ( this . #queueList . children [ 0 ]); await this . #startExplication ( `/storage/ ${ musicData [ ' explicationSource ' ]} ` ); this . player . playVideo (); await this . #musicFinished . when ( true ); this . #musicFinished . set ( false ); } } Basically the code were calling it at the start and running it forever, but that code where a nightmare to maintain / implement, i tried to implement a safe check here for over 2 hours, but wasnt possible. I replaced it for a more efficient approach that do a loop in a different way, here it is: when adding a music, it checks if it is already playing, if no starts to play. when start to play it checks if there is a music in the queue for it to play, if no it stops playing, if yes it get it and play. When the music that is playing ends, it call the play function (from the above topic). That is just it, no while or constant loops, no overhead, it works by basically connecting all the codes in a way that they work together to maintain (or stop) the loop (notice how i said loop, it uses a loop but isnt a while or for loop, it connects the end of one code and the start of another, like a chain . I made it in the pull request #2, check it out: here"}, {"post_id": 54151, "ts": "2026-08-24T23:51:28Z", "hours": 5.8114, "text": "Fixing some forgoten code and more So at this devlog i were fixing some bugs in a specific ui / route called ¨copa¨, this is a special route added because a teacher asked our team to create them to use at some football games in our school. But since it was a hiddend route and mostly like a easter egg it hasnt been updated in a while and wasnt working anymore. What i fixed i was following a pattern where most of the images that each route used should be in a special foulder of storage (literally called /storage), but this mode (copa) where created before it and was following the old way Also there was some errors ocurred afther i changed the entire folder structure, so the copa mode where completely broken, i fixed it too. What i added I had a class about PHP + Laravel | API | Controlers in my course, afther that class i realized that the way the API (copa) where searching for data based on ID where wrong (was doing copa?id=…), i changed it to /copa/id There is a function that show the teams to the user to select one that he wants, but the teams list where hard coded and wasnt synced with the database. I made it use the database data instead of a hardcoded value ** That where all for that mode, but i didnt spent 5 hours just on it, i made more: ** Fixing (or making) some other bugs There is a script that controls the database that where holding and infinite single connection with the database, something like this conn = mysql . connector . connect ( ** configs ) cursor = conn . cursor ( Dictionary = True ) But all the codes where using the same connection and cursor, so i decided to apply a connecton pool and make each database call get a connection and a new cursor. Also i added some functions to abstrac the connection and query part: def __get_connection ( self ): conn = self . db_pool . get_connection () conn . ping ( reconnect = True , attempts = 3 , delay = 1 ) return conn def __execute_query ( self , query : str , params : list | None = None , dictionary = True , query_type : QueryTypes = QueryTypes . ALL ): conn = self . __get_connection () try : with conn . cursor ( dictionary = dictionary ) as cursor : cursor . execute ( query , ( params ) or ()) match query_type : case QueryTypes . ALL : return cursor . fetchall () case QueryTypes . ONE : return cursor . fetchone () case QueryTypes . EXECUTE : cursor . commit () return cursor . lastrowid or cursor . rowcount case _ : raise ValueError ( f \" Tipo de consulta não suportado: { query_type } \" ) If yall want to see it check here at my repo That was also the first time that i used a Enum (on code) and branchs (on github, but i didnt used them properly) Others There was also some other changes, check the repo GF-Silva/Ritualia What next Now i will add some bug checks on a piece of code that handle the video display using an youtube iframe."}, {"post_id": 52754, "ts": "2026-08-23T03:00:03Z", "hours": 4.8206, "text": "Changing some values to be relative I spent a while (more than i expected) changing some strange values that control some settings of a component called cover-flow (this component create and control the images that are displayed in the home screen). I spent more time figuring out what where each variable and lhe logic behind than acually writing.Before it had some hardcoded values that would probably broke if anything changes, i saw it and solved. I wasnt here for it, i was fixing another bug and fixed it before it broke. I also used some basic math of circles like angle of an arc. That is all for today"}, {"post_id": 52465, "ts": "2026-08-22T16:18:22Z", "hours": 3.1097, "text": "I spent some time correcting errors and logic problems, here they are: Error Correction Music playback would freeze when the music queue ended : This problem would break the app until you restarted it, but it was very simple to solve. I had simply made it remove the first instance of music from the HTML twice, which caused it to try to remove an element that didn’t exist, thus freezing the app. Removed an unnecessary loop : In the player section, there was a loop that iterated through all the elements (emotions) in a list to toggle the state of ONLY 1 ELEMENT. With the few elements it had (there were 3), this was minimal, but adding more could be detrimental to functionality. It only did this to toggle the state of the PREVIOUS element from active to inactive. I solved this simply by making it save the index of the last element and use that to access it. It took a while to work because javascript was treating 0 (the first indice / old indice when u start) as false in the if, but afther i figured out why it was simple to solve (if oldIndice != null) Implementations / Changes I separated the API/WEB routes : Previously, the routes exposed by the backend (such as /songs) were in the same file. This wasn’t a problem before, but with the addition of new functions, it could become difficult to maintain and prone to various errors, as the routes weren’t separated (a name could be the same). Therefore, I separated them into: /api (backend API codes) and / (frontend web codes). I put the genres in the database : Previously, the genres were in the frontend, and to add a new one, I would have to update both the backend and the frontend. To solve this, I simply added a route that retrieves the current genres (from the database) and uses the data (name / location) to load them into the frontend. I added the emotions to the database : The emotions had the same problem; although both (they and the genres) were in the database, the frontend wasn’t based on that data, so I did the same thing I did with the genres. I changed the name of where the music explanations were saved : I must have mentioned in a devlog that the folder inside storage was called /explication_source, and I also mentioned that the name was incorrect (because the audio source wasn’t there, nor would it be; the audio files themselves are there), so I changed it to /explication_audios"}, {"post_id": 48602, "ts": "2026-08-17T02:01:56Z", "hours": 3.6708, "text": "Updating the README I saw a post about how to structure a README, how to make it clear and etc. Afther i realized how wrong the old README was (it was confusing, and also was months out of date). So I chose some topics that would be interesting to include in and filled in a skeleton, spending some time learning what to do and what not to do. I also didn’t fill in some fields because they aren’t ready yet (they now are stored in my memory to add later). How it was before: https://github.com/GF-Silva/RitualIa/blob/9a2a7756c777a7042eca28309924e5a408bd561f/README.md How it is now: https://github.com/GF-Silva/RitualIa/blob/2dea5f80266f06e8633af1aa3c9430065cde9231/README.md There is a huge difference. Also i did some bugs and noticed how bad my commits are"}, {"post_id": 47776, "ts": "2026-08-15T22:55:35Z", "hours": 32.5314, "text": "After a development pause, here are the various changes made. Also, I never mentioned it, but this project was made by students focused on the school environment. (This time I finally got around to writing the devlog myself): Structure Moved main.py to the root Replaced mysql-connector with the official version : The added library was a version I didn’t recognize; I added the official one instead. Cleanup Removed some Code that wasnt being used. Backend Change the return value of the SQL cursor : Previously, the cursor returned an array, but for code readability and security, I opted to change it to an array. Structured Error 404 : The backend used abort in certain parts, but it returns HTML and certain parts of the frontend expected JSON, so I formatted the abort to JSON. This caused a headache, I hadn’t tested it (again lol) and when I saw it, it was time to present the project at school and I was having this error. frontend Fixed the CoverFlow component : An error went unnoticed in the creation of the component, this made the size and spacing of the images look strange, it was fixed to a certain extent. I implemented a new playback policy : The text about it got so long that I decided to open an extra topic. Playback Policy Now it search for the requested emotion + genre that the user choose, If It fails It search Just for the genre, if It fails again it search for anything. Now it falls into a fallback: This policy change was motivated by having to find a song to show in a presentation and failing. I reflected that if it was annoying for me, it would be for the end user (students) as well. Database Added new songs : I added 50 extras and their respective genres/emotions. (Also i wrote some helpers in python to help me categorize and search for the musics in youtube and get and structured sql output, that took quite a while) Saved the songs locally : Topic local saving Local saving But why would saving the songs in the cloud be a problem? Nothing comes for free, the server we were using to host the music had a monthly access limit, which was a silent problem that, thankfully, was noticed before it happened. My mistake, I didn’t even think about the possibility of saving locally and went straight to saving in the cloud, it must have been due to haste and inattention (always plan well what you are going to do before you do it, weigh the risks and benefits). Now, how it works The audios are saved inside the /storage folder. The database still saves the location, but this time it saves the relative path (e.g., /explication_audiis/fun_audio.extension). Why save the folder path as well? Won’t the audios always be there? Yes, but at some point the path might change (e.g., explication_source/youtube/audio_legal.extension). Future plans I’m going to improve my devlogs lol, this one got huge"}, {"post_id": 12818, "ts": "2026-06-20T23:46:13Z", "hours": 5.5386, "text": "RitualIa in Evolution: Refactoring, Optimization, and New Features 🎶 Hey everyone! I’m back with a cool update on what’s been happening here at RitualIa. After that commit where we transformed some scripts into helpers, things have evolved quite a bit. We’ve been doing a heavy refactoring of the project, focusing on organization, performance, and better code architecture . What’s changed: Structure & Organization: I removed legacy folders that weren’t being used, did a mega merge bringing everything from /frontend (the folder that where holding ALL the frontend logics) to the project root (with that the frontend and backend are in the same folder), and switched from FastAPI to Flask on the backend. Why the change of FastAPI to Flask: Because my supervisor or mentor (something like this) said and said again to, because there was other guys in the project (still is, but im the main developer, the others stopped doing anything like mounths Ago, and even while they where doing something i still was the main dev), these other guys where total starters and could not hold the learning curve of FastAPI (even with the fact that was Just me that where using It, because it was at the backend and i was the only developing at back). Code Quality: We made several methods private in the PlayerControls class, making the API cleaner and more secure. We also fixed the “enclosing class errors” that appeared. These small fixes make a huge difference in code reliability. UI/UX Improvements: We created a new CoverFlow component to replace GenreCylinder on the homepage – it’s much smoother and prettier now. We added support for async onClick, grab + touch in CoverFlow, and adjusted visual positioning to keep everything aligned. Oh, and we removed that unnecessary playerText that was cluttering the interface. New Features: A really cool feature that was added was the checking for duplicate songs in the queue . Nothing worse than accidentally playing the same song twice, right? Now that doesn’t happen anymore. Maintenance & Updates: We updated the fetches to call the new routes, moved the favicon to assets (because everything has its place), and focused on the details. What’s coming next: We are in a consolidation phase, laying a solid foundation for the upcoming features. The focus now is on ensuring that each component is doing exactly what it needs to do, nothing more, nothing less. Thanks for following along!"}, {"post_id": 11702, "ts": "2026-06-19T02:03:07Z", "hours": 1.0236, "text": "I’m transforming some duplicate code into helpers so they can be more easily used in new code."}, {"post_id": 11412, "ts": "2026-06-18T17:53:37Z", "hours": 1.2881, "text": "Introducing: The ‘Ritualia’ project is a project developed by me and some colleagues with the help of the school. In it, we have done and continue to do research and assembly with the aim of impacting the daily lives of students in our school and (in the future) other schools. It is an open-source project with an article soon to be published detailing the foundations used, etc. The readme is currently outdated because I am redoing part of the current architecture, but I will update it later to include information on how to assemble and create your own version. The project is divided into hardware and software. I, along with other members, am responsible for the software (which is usable on most computers), and the hardware is relatively simple (it only depends on a display + sound + a controller with an OS + the preparations for installation)."}]...
|
Title: Ritualia by @gabriel_ferreira | Stardance
Title: Ritualia by @gabriel_ferreira | Stardance
Devlogs:
Introducing: The ‘Ritualia’ project is a project developed by me and some colleagues with the help of the school. In it, we have done and continue to do research and assembly with the aim of impacting the daily lives of students in our school and (in the future) other schools. It is an open-source project with an article soon to be published detailing the foundations used, etc. The readme is currently outdated because I am redoing part of the current architecture, but I will update it later to include information on how to assemble and create your own version. The project is divided into hardware and software. I, along with other members, am responsible for the software (which is usable on most computers), and the hardware is relatively simple (it only depends on a display + sound + a controller with an OS + the preparations for installation).
I’m transforming some duplicate code into helpers so they can be more easily used in new code.
RitualIa in Evolution: Refactoring, Optimization, and New Features 🎶 Hey everyone! I’m back with a cool update on what’s been happening here at RitualIa. After that commit where we transformed some scripts into helpers, things have evolved quite a bit. We’ve been doing a heavy refactoring of the project, focusing on organization, performance, and better code architecture . What’s changed: Structure & Organization: I removed legacy folders that weren’t being used, did a mega merge bringing everything from /frontend (the folder that where holding ALL the frontend logics) to the project root (with that the frontend and backend are in the same folder), and switched from FastAPI to Flask on the backend. Why the change of FastAPI to Flask: Because my supervisor or mentor (something like this) said and said again to, because there was other guys in the project (still is, but im the main developer, the others stopped doing anything like mounths Ago, and even while they where doing something i still was the main dev), these other guys where total starters and could not hold the learning curve of FastAPI (even with the fact that was Just me that where using It, because it was at the backend and i was the only developing at back). Code Quality: We made several methods private in the PlayerControls class, making the API cleaner and more secure. We also fixed the “enclosing class errors” that appeared. These small fixes make a huge difference in code reliability. UI/UX Improvements: We created a new CoverFlow component to replace GenreCylinder on the homepage – it’s much smoother and prettier now. We added support for async onClick, grab + touch in CoverFlow, and adjusted visual positioning to keep everything aligned. Oh, and we removed that unnecessary playerText that was cluttering the interface. New Features: A really cool feature that was added was the checking for duplicate songs in the queue . Nothing worse than accidentally playing the same song twice, right? Now that doesn’t happen anymore. Maintenance & Updates: We updated the fetches to call the new routes, moved the favicon to assets (because everything has its place), and focused on the details. What’s coming next: We are in a consolidation phase, laying a solid foundation for the upcoming features. The focus now is on ensuring that each component is doing exactly what it needs to do, nothing more, nothing less. Thanks for following along!
After a development pause, here are the various changes made. Also, I never mentioned it, but this project was made by students focused on the school environment. (This time I finally got around to writing the devlog myself): Structure Moved main.py to the root Replaced mysql-connector with the official version : The added library was a version I didn’t recognize; I added the official one instead. Cleanup Removed some Code that wasnt being used. Backend Change the return value of the SQL cursor : Previously, the cursor returned an array, but for code readability and security, I opted to change it to an array. Structured Error 404 : The backend used abort in certain parts, but it returns HTML and certain parts of the frontend expected JSON, so I formatted the abort to JSON. This caused a headache, I hadn’t tested it (again lol) and when I saw it, it was time to present the project at school and I was having this error. frontend Fixed the CoverFlow component : An error went unnoticed in the creation of the component, this made the size and spacing of the images look strange, it was fixed to a certain extent. I implemented a new playback policy : The text about it got so long that I decided to open an extra topic. Playback Policy Now it search for the requested emotion + genre that the user choose, If It fails It search Just for the genre, if It fails again it search for anything. Now it falls into a fallback: This policy change was motivated by having to find a song to show in a presentation and failing. I reflected that if it was annoying for me, it would be for the end user (students) as well. Database Added new songs : I added 50 extras and their respective genres/emotions. (Also i wrote some helpers in python to help me categorize and search for the musics in youtube and get and structured sql output, that took quite a while) Saved the songs locally : Topic local saving Local saving But why would saving the songs in the cloud be a problem? Nothing comes for free, the server we were using to host the music had a monthly access limit, which was a silent problem that, thankfully, was noticed before it happened. My mistake, I didn’t even think about the possibility of saving locally and went straight to saving in the cloud, it must have been due to haste and inattention (always plan well what you are going to do before you do it, weigh the risks and benefits). Now, how it works The audios are saved inside the /storage folder. The database still saves the location, but this time it saves the relative path (e.g., /explication_audiis/fun_audio.extension). Why save the folder path as well? Won’t the audios always be there? Yes, but at some point the path might change (e.g., explication_source/youtube/audio_legal.extension). Future plans I’m going to improve my devlogs lol, this one got huge
Updating the README I saw a post about how to structure a README, how to make it clear and etc. Afther i realized how wrong the old README was (it was confusing, and also was months out of date). So I chose some topics that would be interesting to include in and filled in a skeleton, spending some time learning what to do and what not to do. I also didn’t fill in some fields because they aren’t ready yet (they now are stored in my memory to add later). How it was before: https://github.com/GF-Silva/RitualIa/blob/9a2a7756c777a7042eca28309924e5a408bd561f/README.md How it is now: https://github.com/GF-Silva/RitualIa/blob/2dea5f80266f06e8633af1aa3c9430065cde9231/README.md There is a huge difference. Also i did some bugs and noticed how bad my commits are
I spent some time correcting errors and logic problems, here they are: Error Correction Music playback would freeze when the music queue ended : This problem would break the app until you restarted it, but it was very simple to solve. I had simply made it remove the first instance of music from the HTML twice, which caused it to try to remove an element that didn’t exist, thus freezing the app. Removed an unnecessary loop : In the player section, there was a loop that iterated through all the elements (emotions) in a list to toggle the state of ONLY 1 ELEMENT. With the few elements it had (there were 3), this was minimal, but adding more could be detrimental to functionality. It only did this to toggle the state of the PREVIOUS element from active to inactive. I solved this simply by making it save the index of the last element and use that to access it. It took a while to work because javascript was treating 0 (the first indice / old indice when u start) as false in the if, but afther i figured out why it was simple to solve (if oldIndice != null) Implementations / Changes I separated the API/WEB routes : Previously, the routes exposed by the backend (such as /songs) were in the same file. This wasn’t a problem before, but with the addition of new functions, it could become difficult to maintain and prone to various errors, as the routes weren’t separated (a name could be the same). Therefore, I separated them into: /api (backend API codes) and / (frontend web codes). I put the genres in the database : Previously, the genres were in the frontend, and to add a new one, I would have to update both the backend and the frontend. To solve this, I simply added a route that retrieves the current genres (from the database) and uses the data (name / location) to load them into the frontend. I added the emotions to the database : The emotions had the same problem; although both (they and the genres) were in the database, the frontend wasn’t based on that data, so I did the same thing I did with the genres. I changed the name of where the music explanations were saved : I must have mentioned in a devlog that the folder inside storage was called /explication_source, and I also mentioned that the name was incorrect (because the audio source wasn’t there, nor would it be; the audio files themselves are there), so I changed it to /explication_audios
Changing some values to be relative I spent a while (more than i expected) changing some strange values that control some settings of a component called cover-flow (this component create and control the images that are displayed in the home screen). I spent more time figuring out what where each variable and lhe logic behind than acually writing.Before it had some hardcoded values that would probably broke if anything changes, i saw it and solved. I wasnt here for it, i was fixing another bug and fixed it before it broke. I also used some basic math of circles like angle of an arc. That is all for today
Fixing some forgoten code and more So at this devlog i were fixing some bugs in a specific ui / route called ¨copa¨, this is a special route added because a teacher asked our team to create them to use at some football games in our school. But since it was a hiddend route and mostly like a easter egg it hasnt been updated in a while and wasnt working anymore. What i fixed i was following a pattern where most of the images that each route used should be in a special foulder of storage (literally called /storage), but this mode (copa) where created before it and was following the old way Also there was some errors ocurred afther i changed the entire folder structure, so the copa mode where completely broken, i fixed it too. What i added I had a class about PHP + Laravel | API | Controlers in my course, afther that class i realized that the way the API (copa) where searching for data based on ID where wrong (was doing copa?id=…), i changed it to /copa/id There is a function that show the teams to the user to select one that he wants, but the teams list where hard coded and wasnt synced with the database. I made it use the database data instead of a hardcoded value ** That where all for that mode, but i didnt spent 5 hours just on it, i made more: ** Fixing (or making) some other bugs There is a script that controls the database that where holding and infinite single connection with the database, something like this conn = mysql . connector . connect ( ** configs ) cursor = conn . cursor ( Dictionary = True ) But all the codes where using the same connection and cursor, so i decided to apply a connecton pool and make each database call get a connection and a new cursor. Also i added some functions to abstrac the connection and query part: def __get_connection ( self ): conn = self . db_pool . get_connection () conn . ping ( reconnect = True , attempts = 3 , delay = 1 ) return conn def __execute_query ( self , query : str , params : list | None = None , dictionary = True , query_type : QueryTypes = QueryTypes . ALL ): conn = self . __get_connection () try : with conn . cursor ( dictionary = dictionary ) as cursor : cursor . execute ( query , ( params ) or ()) match query_type : case QueryTypes . ALL : return cursor . fetchall () case QueryTypes . ONE : return cursor . fetchone () case QueryTypes . EXECUTE : cursor . commit () return cursor . lastrowid or cursor . rowcount case _ : raise ValueError ( f " Tipo de consulta não suportado: { query_type } " ) If yall want to see it check here at my repo That was also the first time that i used a Enum (on code) and branchs (on github, but i didnt used them properly) Others There was also some other changes, check the repo GF-Silva/Ritualia What next Now i will add some bug checks on a piece of code that handle the video display using an youtube iframe.
Optimizating some piece of code So there was a certain part of the code responsible for the songs queue in the main route, that piece is a core function but where running a while true loop for no reason , here is the part: async start () { while ( true ) { // { emotion, genre, author, name, sourceId } const musicData = await this . #musicQueue . get (); this . createPlayer ( musicData [ ' sourceId ' ], null ); this . #showMusicInfos ( musicData [ ' name ' ], musicData [ ' author ' ]); this . #queueList . removeChild ( this . #queueList . children [ 0 ]); await this . #startExplication ( `/storage/ ${ musicData [ ' explicationSource ' ]} ` ); this . player . playVideo (); await this . #musicFinished . when ( true ); this . #musicFinished . set ( false ); } } Basically the code were calling it at the start and running it forever, but that code where a nightmare to maintain / implement, i tried to implement a safe check here for over 2 hours, but wasnt possible. I replaced it for a more efficient approach that do a loop in a different way, here it is: when adding a music, it checks if it is already playing, if no starts to play. when start to play it checks if there is a music in the queue for it to play, if no it stops playing, if yes it get it and play. When the music that is playing ends, it call the play function (from the above topic). That is just it, no while or constant loops, no overhead, it works by basically connecting all the codes in a way that they work together to maintain (or stop) the loop (notice how i said loop, it uses a loop but isnt a while or for loop, it connects the end of one code and the start of another, like a chain . I made it in the pull request #2, check it out: here
Fixing errors and adding bug checks Hi everyone, so i were fixing some bugs that i saw that may broke the app, i fixed all of them (for now), here they are: There was a logic bug that a class (the one that controls the youtube iframe) where doing stuff that it wasnt supposed to do (not an unexpected behavior, but a logic that should be outside of it), it was an easy fix. There was a bug at the player class that when the provided sourceId (for the youtube iframe) where wrong or unable to use it crash and stopped doing anything else (like playing another musics). I tryied solving it in various ways, one was beffore the changes that i did in my last devlog, but i failed because the class that holds the player where hard to fix, this devlog fix it. I fixed it by adding some bug checks and, when some error ocurred, it play the next music. There was also a bug at the player class and youtube-iframe-controls class, that for a couple seconds in the start of the website it would broke if u tried to play a music. It was because in the start of the program the youtube API where unable to be used. To fix it i just made it wait until the API where ready using an ASYNC function. There was also a bug that, afther the past devlog, it was doing and request at the /api/songs with params at the wrong format. Afther the past devlog the API started using the params genre_id and emotion_id , but the frontend where passing with the incorrect name (genre, emotion). Something that i implemented I upgraded the mysql query that where being used to get more infos about the music, before it where just returning infos like name, author, sourceId, etc, but now it also returns the genre and emotion from that given music. I added a bug check at the player class, now if it fails it pass to the next music. Something that i want implement I want to implement a simple toast notification system that will apear when something fails, like the playing of some music. Others The youtube docs for the iframe where very helpful for this changes, check it out: https://developers.google.com/youtube/iframe_api_reference?hl=pt-br
Creating a toast notification system So rn im creating what i said in the past devlog about a toast navigation. This isnt finished yet, im still figuring out an way to check the end of the timer, i found some ways to do it, like using an simple if inside the countdown. I didnt comment but i am using an setInterval to decrease the time and an <progress> tag to show the value but that is a bad ideia, imagine doing 1 if every 50 ms? that dont cost a lot of processing power, but i still will search for other ways to do it just to check, if yall got any hints or ideas leave a comment. Also i will improve the design, the design is petty poor.
The toast notification is finished So i finished it, it is a component that u adds in the code that u wants to use. I added 2 icons, 1 for infos and another for warnings. What i used and did The element that holds it all is an dialog , the icons are svg , the text is a span and the element that shows the time left is an progress . To update the time left i used an setInterval that runs at a 10ms delay and deduce 0.01 of the dialog value, so it will be smooth to see. Also there is an if inside that destroy the element and clear the interval when the value of the dialog reaches zero or less (In the past devlog i said about not using an if, but considering how low the cost for an if in that time is i decided to use it anyway). The function that creates the toast receives some params that will let it be customized by whoever is calling it: const icons = Object . freeze ({ INFO : infoIcon (), WARNING : warningIcon () }); function createToast ({ message , time = 5 , styles , icon = icons . INFO }) // the `message` is the displayed message // the `time` is the time until close // the `styles` is custom css styles for the element, it uses the dictionary format {} // the `icon` is the svg icon What else? I will apply it in some elements and post about. See you later!
Toast applied and tested The toast notification component is now being used at the player class, i did some tests and it is working very nice, hopefully the user will not see it very often (because that would be a problem, the user must not see it unless there is an error playing the music). But why did i make it? It is used to show more about what is going on for the user, so they will not become anxious if it something is working or not. Why not use another notification system? Each notification system has its own use cases, the others would be very painful for the user. Imagine every time a simple error (that is simple for me) like the music fail to play there was an error that interrupt the use of the app with an popup or alert, that would be painful, dont it? That is why i used an toast notification, because it is temporary (disappears after some seconds) and dont stop the use of the website. Also there is a feature that i implemented for the same reason a few devlogs ago that add a fallback in the music search, so it wont show a message at every single combination. Lets calculate how many combinations we have: there is around 50 musics in the database, 22 genres and around 40 emotions, multiplying the genres and the music 880 combinations that the user can make. Now lets see how many musics we can get: each music have around 1.2 emotions and 1.2 genres, so we get 72 combinations that lead to an music . With that in mind, we can see that from 880 combinations, just 72 of them are useful combinations, so we get a 8.18% for getting a music, and 91,12% of not getting one. Consider that each failed attempt shows an error that stop the use flow of the website, but that was before the past devlog, now it tries again and again and only afther failing everything it shows an error, at that point it must really show an error. Thats all, sorry for the long boring text and thanks everyone that read, see yall later
Studing about cache So basically i where studing about cache, the main ideia was to implement it in the sistem, but then i realized something: Theres is nearly no difference between cache and a normal request in an localhost project, adding the cache would not improve anything, sometimes it maybe even slow the website, because the page would need load more code. I realized it afther a while studing about it, but anyway lets focus on another thing. Also i where studing with google for devs: https://developer.chrome.com/docs/workbox/caching-strategies-overview
Adding a new description feature So basically there was an place where was designed to have the description about an music, but that was empty and where only finished today What it do It is petty simple, it just show an text about the music that is currently playing, also there is an audio that plays before the music starts playing, but this audios is played just one time before the music so if someone loses it or didnt listen well there was not a second chance to listen for that audio. Now there is this place that holds the same content, but in the format of an text that can be read whenever they want while the music is being played, that was what i added. Also that text can be hidden, so it will not stay using half of the screen every time (in the screenshot it is active) What this audios do This audio / text is part of the main purpose of the website, they give some fun facts about the music that may be useful someday in some kind of quiz or essay. Also the audio is played before the music and the music plays just after the audio finishes. That is to make whoever is listening listen to the entire audio before having what he (or she) wants, so they will not listen to the music and skip the audio.
Adding more bug checks I added some checks in the player class at the startExplication function that checks if the src (the url for the audio) is valid or not by doing an fetch with the HEAD method and checking if the return is an valid audio before trying anything in this function. Also i solved this error in the same function: Uncaught (in promise) AbortError: The play() request was interrupted because the media was removed from the document. https://goo.gl/LdLk22 This error was because the startExplication function where trying to play the audio before it was loaded, i solved it by making it play the audio just after it was load with the event listener canplaythrough . There was another error at the playMusic function where the code where trying to play the youtube video before it was loaded, i solved it by making it wait until it was CUED (Where the video isnt playing, but is loaded and showed). (The website was not created to be in mobile and dont has a lot of support, the video where recorded in my smartphone because i had to record the audio and the audio on my pc dont work. In the Future i Will add mobile suport, but right now im finishing the bugs and etc)
Refactoring the copa script I where placing some scripts in a class. These scripts are related with the player functions of the copa script, so i pick all of them and placed in the same class. I did it to follow best practices, but i confess that i still got some doubts about when to create an class and when the variable or method should be static or private (#property), i will search and learn more about because maybe i will have to refactor some parts of the code following these rules of best practices. That was all for now, see ya!
Creating a new helper Context: There was an class called youtubeFrameControls , this class basically where designed as an structure to help using the youtube iframe API, but with the time this class where becoming basically to hold just an function (and in a very inefficient way), because the methods that it had before (like the one that runs when the iframe is loaded) had to have more and more specific logic in the codes that used it, so they where useless (because the codes that where using it where rewriting it). What i did: I picked the only function that where being used and transformed it in an helpers (that can easily be customized). This function was the one that creates the player of the musics, and the function where called createPlayer . Also i removed the old class (youtubeFrameControls) and replaced it for this helper in every place that used it. It now is way more simple than before and can me more customized.
Making the website responsive Hi again! Like i said in some devlog, the website dont have support for mobile, that was because it was designed to be at kiosk mode and work just in desktops. but i decided to change that. First of all: the site where using a lot of absolute values of dimensions, so it where braking even in the desktops (it wasnt responsive at all). But i spent a while changing it, it is isnt ready and has some problems, but is better than before. (The mobile is still strange, i did not started fixing it yet). Credits: https://css-tricks.com/snippets/css/fluid-typography/ - This website shows about a way to make the texts become responsive for the screen using some calcs, it is worth seeing. The first video is how it was before, the second is how it is now
Hi again! Like said in the past devlog, im improving the responsiveness of the website, specifically in the player part. But it had some problems and where distorting when playing an video, now it resizes based on the screen size in a way that it stays ¨normal¨. The first video is the new way, the second is the old way. It still needs a lot of improvements, but it is going!
Im improving the responsiveness at the home page (before was the player page), but for some reason that idk the emotion selection div is having a strange behavior, i will update what it is after i fix it. Take a look: (the item in the center should be centered)
i finished the workings on the section of the home page that i where doing before, now has a good responsiveness for pc and a decent one for mobile. Now im working on the main area of the home page, the one where the user selects the desired genre for the music (second img). It may looks completely fine, but that same element already was a headache before and is here again. The given area is the cover-flow component, before i already fixed it (or so i thought), but it was looking bad (the 3d perspective where a bit strange) and would probably broken if i added new genres. I were trying to figure out a way to listen to the clicks in the card without any problems, that seems easy at first glance, but the 3d perspective in the element make other elements eat the click from one another, make the clicks dont be listened and so many problems that i nearly decided to erase it and write from scratch. I already found a way to do it by using the mouse position, the center of the screen and the card width (the genre img) to transform it in an value that can be used to select the exact card without any dependencies on the doom selector. It basically uses just some values, put in some calcs and get the difference between the current card (genre) index and the clicked. Im nearly finishing it, but i still need to figure out some values and more.
Finished the correction of the errors at the perspective and click in the cover-flow component. Now the perspective stays the same 150vw value (that is based on the screen width) and stays normal, with everything working. Oh man, that needed a lot of logic and out of box thinking finding another ways to check where the user clicked without using an normal click event listener (for those who lost the past devlog or didnt understood, i cannot use a normal eventListener in that because the clicks is detected in another element or in nothing, even with z-index or more in css, so the solution should be done entirely on javascript logic). The first video is the new way, the second is how it was before all changes in it
Im nearly finishing the workings on the responsiveness. Now the entire player screen is responsive and do not breaks the texts anymore (except for the description area), also the buttons that show you the next screen (the ones that displays ‘player’ and ‘generos’) are responsive too, the music queue is working perfectly fine, and the area that is used to select an emotion is nearly responsive too, it just needs some adjusts in the two buttons that change the current emotion because they become too small and uses a lot of space when the screen is too small, after that this screen will be finished. It is taking a really long time, the fact of how many different screen sizes exists makes it harder to finish, but now there is times that i even cannot see if i changed the resolution in some areas, because the system looks the same. I spent quite a while testing different resolutions and combinations of size, i didnt even noticed that i where 6 hours here, but now ik more about css (things like container-type + container based sizes and more ways to set the size of an text) The video shows how it is now, if u want to see the before just checks the past devlog.
The emotionDrum is now responsive! Now the buttons that you use to select the emotion are in the same side as the div that displays the emotion, so they dont fight for space anymore. This change is meant to fix the low size of the items in screens that are too small, in the new way we have more free space to display the emotions, there is not much to say. What else I did some minor changes in the size of some items at the player area, now they are easier to read! (I increased the size of some items)
The home is now fully responsive Ah that took a while, but finally it is fully responsive. Now the description at the player UI resizes based on the screen size and active a scroll behaviour when need, also i did some minor change at the emotionDrum perspective to make it show more emotions at the same time, removed the padding in the arrows at the emotionDrum so they will have more space and fixed an error in the genre drum that was making it perspective broke. After all these devlogs i improved how i make a code responsive.
Improving the performance After finishing the improvements in the responsiveness, now i decided to improve the performance. I used lighthouse to get insights (i learned about it in an tiktok video) and figured out that the images size were too high (were an png of 1280x1280px), so i saw more about that in the page: https://developer.chrome.com/docs/performance/insights/image-delivery (an link that google lighthouse gave). With that i saw how to decrease the size while staying with quality, i reached up to the sharp-cli tool, that makes the work of resize, convert and compress the image for me. The command used was that: npx sharp-cli -i * .png -o ./output resize 320 -f avif -q 50 --effort 6 --smartDeblock --preset photo The 320 is the size that i want it to be at the end, i got that value by seeing what was the computed value (the value that is being used in the website) in an high resolution pc (not the most higher one, the high but normal pc) with the resolution of 2500x1714px . With this simple changing the image went from 2mb to 40Kb! Nearly 100% decrease, and take in mind that there is more than one img, so the change were even higher. Also i created 5 different images: 320px, 480px, 640px, 960px e 1280px. With them the browser can choose which one is better for each device. With these changes i went from 35 points of performance to 59.
Improving the LCP (Largest content paint) performance I am improving the way that the website create and downloads the images, the main reason is to make the user see something faster. Before the system were doing 2 main things: Go trough the entire list of images, creating the elements and placing them into the page. Position them. But the position of the items were being done after the creation of the images, in another function. Now they are in the same function: it create the element, position it and add it to the page. That does not seem like much, but the code got way faster with that, probably because it dont need to go item by item in an list twice just to create an element. I tested the time to load the first element and it went from 8.63s to 6.43s , the test was made with 2200 elements (Yeah ik, it is a lot and normally it isnt that much, but i had to see how they were holding with more than 22 items). Also i fixed a bug that passed unnoticed while improving the responsiveness: At some point of images the visibility of the elements broke, that was because the perspective (what makes the 3D perspective of the component, and makes it visible with 3D effects) was based on the screen size, not the elements itself. What was the problem in that: Each element takes a size in the screen ‘makes the circle that shows the element be more and more near of our point of view’ (i cant explain it any better, search what is ‘perspective in an 3d element at HTML’ ). While it was approaching our point of view (POV), our POV were exactly at the same position (based on the screen size), so at some point the circle perspective would pass the POV and we would be unable of seeing it well. Now it is based on the elements: The 3d elements were basically a circle, i just used the diameter to change the perspective based on it. TODO: Maybe i lowered the image quality too much… I will fix it in the next updates. Also i were trying to improve the font settings to improve the performance, but that wast working so i decided to move on to this because it was more critical (took a while for me to jump to this, maybe like 2 hours trying and trying values in the font settings). i am also working in a way to load the images in parallel, with that it will take way less time (I didnt known about LCP before so i spent a while figuring out the way it works).
Improving the loading performance Now the system selects some images that needs to be shown faster than the others and making them load with priority. It was made by selecting the images that the user is seeing and defining some params like fetchPriority = "high" and decoding="sync" , the other images have the params: decoding="async"; loading="lazy"; contentVisibility="auto"; . With that config the LCP went from 2.4s to 0.5s . Also it loads the image in the start and dont change that config again, so the browser will be lazy while downloading these images. The problem is: only the first images are chosen as high priority, but their positions will be changed while the configs stays the same, that makes the browser lazy while loading them and makes the runtime performance became worse. To fix that i found about IntersectionObserver, that are meant to solve the problem of updating the images position fast. It was not applied yet, i found about it like 1 hour ago. What else Now the perspective of the emotionDrum is based on the elements that it have, before it was based just in the screen and would broke if something changes. I did a little change in the way that the script checks for clicks in the screen, now it has more accuracy (I changed the round system).
Adding an observer Now the script observe the card elements at the cover-flow component, classify their position and changes it visibility based on that. Im using an IntersectionObserver to observe every card, but it was designed to observe the position of 2d elements, so i had to figure out how to make it work well in an 3d element. The way it works is when the observe activates (it basically means that some card is in the range to load) it get the card info (like position and angle) and changes it visibility state based on that. Simple, right? No, it was a headache for the start to the top, nearly 4 hours of what i did was to fix the fact that it was meant for 2d. The observer were activating for cards that were in the back of the element, so i had to classify the card position into back or front by using its angle. But if i tried to use the card angle without anything else the script would broke (and did for 3 hours until i realized how to fix), so i had to use an second angle which is 360 - cardAngle (the 360 is the angle of an circle), so this new angle is based on the circle end while the other is based on the circle start. But the system still broke, because at some point one of these values would become negative and makes the if that classify the elements fail. The fix was using the absolute value in the if (it took 1 hour until i figured that; oh i were so happy when it worked). Why To improve the performance, so the browser will just load what is really important and not 50 images that the user cant even see. What else All that work definitely improved a lot my logic thinking and for the first time i used the truth table well. Now i just need to use the new code to change more the style of the images that are not in the screen. I did not deleted the code that i wrote in the past devlog, it was used in the new code to select how many images should be loaded in the same time. ** The first video is the result, the others is some problems that i had **
The observer is finished (nearly) Now the cover-flow has an observer that checks the position of the images and changes it styles based on that, so the images that the user is seeing is loaded while the others is hide. It still has some bugs and space for improvements that im still figuring out how to solve, like the image loading too late on the screen or, in slow internet connections, the image takes too long to load. Most of these bugs are because the observer (an intersectionObserver ) was designed for 2d contexts, not 3d (that were and still is an giant problem to solve). For this reason i was thinking about creating an observer from scratch in C++ that can work better in my 3d element, but the overhead would be high so im trying to solve in other ways before that. The feature was made using fetchPriority, contentVisibility and src (the system add the source just when the image is near the screen). OBS: I found about MutationObserver after this post, maybe i will use that instead of insersectionObserver. Oh man, at least if had found about this before… Aaaaaahhhhh i spent 9 hours in that, but at least a Lot of the new logic will be used. Anyway, lets cook
Adding a mutationObserver Now, instead of an intersectionObserver, the system use a mutationObserver that monitors the angle of the cylinder itself. With that the loading of the images will be insanely better, faster and user-friendly. Now the changes in the cover-flow is observed at the cylinder angle, not at each card. There was some problems in the journey like, for some reason, unexpected cards being loaded or not, the loading script at the observer dont triggering at all (that was caused by the speed of the observer) and an insane amount of cards being triggered at the same time (i still did not figured out why, but that isnt ‘harmful’). But man, i had to be creative here and remember about some concepts like concurrent programming, buffer / queue and apply some delays (because the mutationObserver is insanely fast and can trigger every millisecond). That all was meant to decrease the speed of the mutationObserver, because it was triggering with the most small change in the cylinder, so i made it trigger just when an expected amount of movement was made. The red/yellow collor is for me to visualize the loading state, it is just for debug The code isnt finished, i still need to implement the loading part, for now i just implemented the observer and basics of the loading part
The loading is done Features Now the loading at the mutationObserver is finished, it finally loads or unloads the images that should be (or not) loaded! The new observer is way faster, because it can detect the image way before it enters the screen, loading it before and having more time to do it. Also the system loads just a maximum of images (with the configs that i put it is 13), so it will not fry an cellphone. Problems The loading part was easy to do, i already done it before in the past observer (intersectionObserver), so i just had to pass the old code to the new part. But when the cover-flow element dont got atleast 13 elements the mutationObserver code breaks completely! Im still pondering how to solve it, when i do i will post about! Results The performance went from 78 to 100! The system is way faster! The user does not see a blank image anymore! Why The old method was slow even with a good internet connection, because it was loading the images just when the element was already in the screen, leaving to a perceptive delay for the user and a blank image to the user. Also i thought about creating an observer from scratch (maybe i was a little off my ideas, because that was insane), but the browser already had exactly what i wanted (the mutationObserver) Videos The new features The performance of the new feats The old features Reasoning While i was trying to sleep i thought about a system that fill the cover-flow with a maximum of images (like 10, or 13, or the code decides) at the DOM, using less memory to run. That system will free a lot of memory based on how many cards the cover-flow have. But that will have noticeable effects just with a lot of elements and probably would be hard to develop, maybe i will do in next updates. What next Im leading to the shipping, so i will improve metrics about the lighthouse, improve the readme and post it.
The loading is done and working! Fix I fixed the error that were happening when the cover had a certain amount of elements. Problems The fix itself was very easy to do, but doing it in a readable or without using 10 lines of code (i want things concise) was way harder than i expected. So i spent this entire time trying different ways to do it, each of them making everything worse. Reasoning The bug were with less than 14 elements, the script were calculating the first and last element index, it happened that these elements were behind the screen focus. Why? Because the values that the system was using were leaving these values, so i had to fix the way it was calculating things.
Fixing an error at the youtubeHelper Now the youtubeHelpers checks if the youtube API is ready before sending commands. Why Sometimes the API maybe is not finished yet, that was leaving an untreated error that was braking the entire website. How was made With a lot of pain and suffer. I thought “Oh hey, that will be a 15 minutes fix” - i spent 1 HOUR FIGHTING with the iframe itself, nothing was working and at some point i started thinking that even the API of YOUTUBE wasnt working, even the most basic function that should be triggered when the youtube finished the loading wasnt beeing activated, even the console.log(“Api READY!”) wasnt working, even when it worked it wasnt working well, the variable of the player was a promise and not the result. At the end i shut down my PC, defeated, without any energy left, with just hope that in the next day (this) that would be fixed (if not i was planning to ignore and make it a feature “Easter egg, if u dont join the website for a while it will not load!”. The problem here was just the position were the iframe api was in the HTML, it was being loaded before the helper script, so the helper was not there to check if it the iframe was ready or not, the fix was just move it a little down. Architecture It was just an promise, if the function checks that the iframe isnt available it await for it to be available. The check if it was available use the onYoutubeIframeAPIReady, easy easy (except for all the suffer that i went into).
The performance workings is finished and bug fix Fixes Now the logo z-index is lower, that is because the logo was ‘eating’ the click in more important elements. Also i did a small change at the cover-flow, that change fix the bug of the scroll at the element sudently stoping when at a certain position. The copa script had some old references to images that were leading to bugs, i changed it. Performance I already finished it in the past devlog, i was just checking if there was anything worth improving, but everything is working fine and now is time to improve acessibility. Most of the logged time was me trying to improve more some metrics at the lighthouse, but the work was too much for anything that is already good, so i decided to stop before i started focusing too much in it.
The accessibility workings is done Features Now the system has a new navigation system that allow users to navigate with just the keyboard! (The video was with just the keyboard) Why Why not? It was meant to improve the accessibility for users without mouse, or any another problem and because i was tired of having to use the mouse to debug something. How it was made Again with a lot of pain, the feature itself was easy but i had to fix some errors that went unnoticed, so it took more time. The feature detects when the user press a key and do an action based on wich key was. The accessibility was easy to get 100, but the metrics at lighthouse dont give all what the users will need, i had to think about the website usage and how would be the easiest way for the user. Results The accessibility went from nearly 69 to 100! What next Now i will work on the best practices! Update after the devlog: Nearly every metric is already maxed out lol, i will ship it very soon!
All done, it is time to ship Every metric at lighthouse it nearly perfect, im so exited to ship it!
Added install guides Now there is guides to help the user install for ubuntu, arch and windows. Notice that im a linux user and my pc is weak, so i could not test it on another operational system. Also the guide is in portuguese (all of them), please use your browser built-in translator or any of them to read if u dont understands portuguese I could test it on another linux distro, but i would have to go through all the install steps. Also i cannot try installing windows because it normally wipe out another OS installed on the same disc (i know that it just replaces the bootloader) and using a VM was not possible due to the amount of RAM and the processor that i have.
Configuring an ssh server! I configured an oracle cloud vm with ubuntu to host my website 24/7, that was because nest wasnt working in a while. Im running it at a local IP with http only, i will configure https today and maybe an domain, the IP is http://164.152.55.252 , notice that some browsers may block you from accessing and http website. UPDATE AFTER THE DEVLOG: I put an domain using duck dns: http://ritualia.duckdns.org Hardwork I had absolutely not a single knowledge about oracle cloud vm, so configuring it was an hell. Sometime my internet stopped working so i had to use my smartphone, this lead me to configuring an invalid ssh key and i had do configure everything from scratch, i spent 5 hours configuring everything, but that was ssh and wasnt tracked. But now everything is working fine. Thx oracle This vm is a 24/7 entire OS (Virtual Machine) that has some good free plans, without any cold start. Thx stardance Stardance now will have one more mount!!!!!! I still has roughly 40 hours of deep development to do after this ship, i will love to finish that in stardance!
It is time to ship! Now the system is working perfectly fine running at a vm in oracle cloud with a public domain, and a dns with duckdns at http://ritualia.duckdns.org/ Warning: It is just HTTP!
Added english readme I created an english readme, api and install Guide, so it will be easier to read and more accessible for worl-wide users
Ships:
What did i made I made an complete music play system that will help users to learn while listening to musics! I used youtube, flask, python, mysql, js and hope to make this! What else Solved a lot of painful bugs that were stopping the project from working Finished and made the music queue work Added music description labels Improved a lot the performance Made the website responsive Added a keyboard based navigation Fixed so much errors at the cover-flow that now i forgot how many Added bug checks before the play of each video on the player Created an toast component to show errors or infos Added 54 musics to choose and listen Challenges The most painful code was the player and the cover-flow, they were with a lot of hidden bugs that i had to figure out, feats that i had to make and pain to suffer! Now i figured out that i love and HATE making a website responsive! What im proud of MutationObserver: An observer that loads / hides an image based on its position at the cover-flow, this system took a while and worked very well. Error checks at player: The system can handle the error that happen and dont crash! Keyboard navigation: Everyone can use the keyboard to navigate now! Oracle VM: For the first time i used an ssh and hosted an website in my own machine (oracle, not mine)! How to test Access http://ritualia.duckdns.org/ , when you join and the page loads you will find a screen to choose an genre, select which one you want, after you will see an emotion selector, select the emotion that you wanna feel! You will see the player screen and an audio explaining the music (The audio is in portuguese), after the audio the music will play. Notice: The github and the website are in portuguese, please use your browser built-in translator or any that you want to use the software properly! Follow the installation guides at github if you want to install...
|
1793008144.3293169
|
1793094544.3293169
|
|
8298
|
Sephyr Magic mod for Minecraft by @Szczurek | Star Sephyr Magic mod for Minecraft by @Szczurek | Stardance...
|
Szczurek
|
0
|
147.82
|
0
|
[]
|
[{"post_id": 81656, "ts": "202 [{"post_id": 81656, "ts": "2026-10-21T22:33:18Z", "hours": 9.8467, "text": "Multiloader modding is pain Can’t NeoForge and Fabric just have one common api, for all the boring stuff like registration, networking and events? I’ve had enough, so I spent 2 hours porting my mod to Balm , which is a library providing exactly that. The result is beautiful - ~150 lines are gone, and the loader specific subprojects fit under 10 lines of code, as I was able to move everything to common. Now for the worst irony: I spent my time doing all of that and the next thing I’m gonna do is… disable fabric support 😭 Why, you may ask? I was forced into it by reality read on First VFX I made my first VFX, for the leap spell. You can see it in the attached video. It’s going to spawn under player’s legs. For now it’s a really simple one, as I’m rushing to add a bit more of content, than just a single spell, before Stardance ends. It is made using Photon Editor , which is a VFX editor for Minecraft. It has a lot of good stuff, like emitters, timeline and animation curves, which will be crucial in making more advanced effects. Only downside: It doesn’t support Fabric, which is why support for it is going to be disabled for now, until I manage to hopefully make a port it in the future. Reworking spell internals (again) After making the effect, I realized I have no way to run it from the spell code, because spell logic runs server side only, and VFX needs to be played on the client. So I wen’t back to the drawing board, and I’m going to change how spells run. They are going be entities now, but more on that next devlog, because it’s not done yet, as I ran into friction in the code, which triggered me to do the Balm refactor, and in the meantime the time counter hit 9,5h. Do NOT hardcode stuff please I had to do some work on my laptop today, which has NixOS. So I update my Sephyr clone, try to run it, and bada bing bada bum, it doesn’t work! What’s going on? After a hour of debugging, it turned out that NeoForge devs hardcoded their Gradle plugin to run one specific task using Java 21. The rest runs on Java 25 (the one used by Minecraft 26.1). So, be default, a NeoForge setup for Mc 26.1+ requires two java version. Normally the second one is autodownloaded, but that doesn’t work on NixOS, and that’s also bloat. I don’t want that! So I made a bug report . Fortunetely it isn’t really hardcoded, just dumb, and I was able to fix it with this line in build.gradle Update to Burn 0.22 Burn 0.22 was recently released, removing the Backend generic from most of it’s traits. I updated Sepple to work with that. I also had to regenerate the model code for the multipa model. I was hoping the update would provide some speedup to speech processing, but I wasn’t able to measure any difference. Replacing Multipa with Zipa I found a new speech-to-IPA model. It’s called Zipa , and it looks very promising. It’s around 4x smaller then multipa, which means faster processing and less to download for end users. Furthermore, according to it’s paper, and my few tests it has noticeable better accuracy! So I implemnted it. It was a little more trouble then multipa, because the model has a much richer pre-processing. The audio waveform is turned into a mel spectogram, Fourier Transform is done, and other stuff happens. Buuut there is a problem. It turns out the model is great at doing recognition on longer audio sequences, and doesn’t really work that well on short ones. For them it performed worse then multipa! That means it’s not suitable for doing recognition in realtime, at least when plugged in the same way multipa was. However I have a couple ideas to try, which might, hopefully, solve the issue. Until I do that, it is set aside on a separate branch."}, {"post_id": 79314, "ts": "2026-10-13T14:21:33Z", "hours": 10.1344, "text": "Debugging gui is (almost) done What is going on, why already 10 hours passed? This was menat to be a quick sidequest, where I built this gui tool for debugging how well detecting magic keywords is working BUUT given it is the third devlog about it That means it took over 30 hours! Well, happens. So, all of this devlog was spent building all the plumbing needed to capture all the data from the detection pipeline and sending it in realtime to the app. All of it is using done using channels. They are injected into the detection pipeline either as Tap<T> ‘s - a new pipeline element that clones data it sees, sends to channel, and passes it on, or using wrapper types around existing processors. The app then receives the data and displays in on the plot. I also encountered and fixed few bugs, that I didn’t expect. For example originally the zoom went to crazy values, because a timestamp used to determine where the data ends wasn’t converted to be relative to the timeline start. I also found an quite an issue introduced 3 months ago, where the timestamps attached to audio weren’t calculated properly, making entire audio chunks have identical stamps. It was minor enough that I never noticed till now, when the data landed on the plot and resulted in this funny thing you can see on the attached screenshot. Finally I added a simple scrolling animation, to amortize the jitter caused by bigger chunks of audio coming, so the plot doesn’t jump that much when going live, but it’s still not as smooth as I would like it to be. As mentioned before I was using AI assistance in strictly controlled manner (I carefully planned, revieved, cleaned up and adjusted to my liking all the code generated by it) to build this debugging tool faster, and by now I’m very tired of it. At the end of the work it started doing stupid things (possibly because some context was lost?), which made me question if it was making me faster or slower. Luckily the work is mostly over, and I can finally get to other, more interesting stuff, that will be fun to do, with no AI. Next I want to use the tool to improve the detection a bit, and spend more time working on the actual mod."}, {"post_id": 77831, "ts": "2026-10-08T13:13:43Z", "hours": 10.2597, "text": "Keyword detection UI is done Look as this! It’s so pretty! Seeing all the data visualised is quite mesmerizing. I know the image will probably attract more views, so lemme explain what you are looking at. I’m making a minecraft mod where you cast spells by saying custom made up words, and this is a tool for debugging the keyword detection system. It’s meant for me, to help me make the detection more accurate, and reliable. I’ve been building it for the last ~20 hours, and in the last two I built the rendering of all the 8 strips. Check previous devlog if you want to know what exactly they display. It was pretty smooth sailing. As said before, since this is just a debugging tool for me, that I want to have finished quickly for it I’m using AI assistence, by letting it do stuff in small, pre-planned steps, and unsloppifying all the code between them. It’s working well. What helps, is that entire app is built on the egui / eframe crates, which I used before, and are somewhat familiar with. I gotta give credit, where is due, their api is really intuitive for the most part, and simple to use. The entire chart is also zoomable, and scrollable, and making this work was a bit of pain. I wanted to limit the accesible range to only around the data (so you can’t scroll away to far from it), and egui_plot doesn’t really provide a way to do it, so some manual calculations had to be done. I wanted to have some breathing space by allowing 0.25x of the zoom after last audio sample to be visible. This was the worst part, as it’s kind of a recursive problem - the zoom value affects how much zoom is allowed. But after around two hours I manged to figure it out, but keeping the original zoom value independantly of the limit calculated from it. Worth noting - what you see is just a mockup data, and the gui isn’t actually hooked up to the detection system, as that’s what I’m going to do next. After that I can hopefully improve the detection, and the finally go back to minecraft coding."}, {"post_id": 76510, "ts": "2026-10-03T19:41:08Z", "hours": 11.5369, "text": "Visualizing the keyword detection pipeline I’m not happy with the accuracy of the magic words detection system. It work half of the time, sometimes better, sometimes worse depending on the word. This make casting longer spells quite troublesome. Debugging why a specific word wasn’t detected is hard, debug prints can only get you so far. So I decided to go on a crazy sidequest and build a gui tool, that will help me debug this. I spent over 2 hours designing the concept, and over 10 implementing it, and it’s around 40% ready. The tool will display 8 strips / plots, and each plot will display some data, all on a shared timeline on the bottom, that will update live as the audio is processed. Strips 1, 2, and 4 will display waveforms of the audio at different processing stages. Strip 3 will show Voice Activity Detection score (which is used to filter out non-speech). Strips 5, 6 and 7 will display detected IPA tokens, accumulated text buffer, and detected words respectively. Strip 8 will display latency stats, which will help in optimizing it. This way I will be able to easily see, “oh, this phoneme wasn’t detected” or “oh, VAD cut out this word” or “oh, some mess accumulated in the buffer” and tweak my algorithms. AI - it’s bad, or is it? Despite looking quite simple on the surface, the app is still quite an undertaking. And it’s just a debugging tool! A thing to help me get the main goal done! I don’t want to spend too much time on it. So I considered using AI as a tool ( NOT vibecoding ). I hate vibecod(ing, ers), and I’ve always steered off AI, because very often I wasn’t satisfied with the output quality. I take pride in writing good code. But recently I’ve been trying out OpenCode here and there (on free models), and was quite surprised with it’s capabilities. Sure, it’s still often slop, but a one you can quite quickly correct, and sometimes be more effective if used correctly. AI - is it helpful? So I decided to do an experiment - can carefully planned AI usage help me write the debugging tool quickly? I started off by designing the functionality of the tool - I described the idea in detail to MiMo-V2.6-Flash, and asked it to interrogate me about as many details as possible and needed. I had to answer 35 questions, some of which were quite observant, picking me on nooks and crannies. After that a markdown file describing the design was written, and then went through few corrections. Next up, in a new session I asked MiMo to create a bullet point outline of steps needed to be done to implement the tool specified in the design file. Then one by one I went over each bullet point, asking the just released LongCat 2.5 (which has a bigger ctx window) to ask me questions, and formulate an implementation plan of it, present it to me, I gave corrections, and the point in file was replaced. This way I ended up with a second markdown file - an implementation plan. This took way too long, and was really boring. So, finally coding time. I do it like this: Ask opencode to implement a step of the plan Review the diff in vscode Remove fluff and slop manually, make sure all new code is good quality. Give feedback if I something doesn’t work like expected, or also fix it manually. After it’s good - commit Repeat for the next step It’s still not super fun, but at least I’m touching the code now, so much better already. And it is efficient! I believe it definitely would take me longer, if I wasn’t using AI. So the morale is: If you want fun, or doing something important - do it manually. If you want to do something quickly and get it out of the way less important. Here is a screen of how it is looking now: the general shape is in place, but there is no plots yet."}, {"post_id": 72706, "ts": "2026-09-23T15:27:59Z", "hours": 6.3589, "text": "The Stack Overflow For some reason my mod broke and started crashing during startup, and it did so in the worst possible way - without any error message! All I got in the Intellij Idea, was a message that the process exited with the signal code 11. WHAT? That signal corresponds to SIGSEGV signal on Linux, which generally means you did something wrong with the memory. But this is Rust! There shouldn’t be any memory issues! I started searching, and I learned there is a tool called coredumpctl, which lets me access a special dump file generated in such cases, and analyze it in a debugger like GDB. So I did that, and what I found was even more bizzare! The debugger was pointing to a start of a function, before the first line. I added some debug prints, and to my disbelief, the print before calling that function ran, and the the second one, which was the first line inside the function didn’t! Fast forward a bit I managed to figure out the problem, with some help from a friend. It turned out I encountered an stack overflow! When the function was called, Rust tried to expand the stack, and crashed because the stack ran out! Why? Because the code was loaded in Java, and Java by default allocates less memory for the stack ! The solution was manually requesting a bigger stack size during thread creation in Java. I also discovered, why the problem appeared - in the Rust file download code I had allocated an array buffer of 1MB. It landed on the stack, and that was too much! The solution was using a Vec, which lives on the heap instead. Stupid problem, but took 3 hours of my time 😩 Mod init progress reporting Sephyr requires the IPA speech recognition model to work, which needs to be downloaded on the first run, and subsequently loaded from the disk. The logic was overhauled providing more corectness, and hooked up to a series of toasts. File download progress bar is shown, and the intialization state (or failure) is coummunicated to the user! See it in the video"}, {"post_id": 71471, "ts": "2026-09-20T21:50:14Z", "hours": 9.7653, "text": "Wind spells have sound now Using LMMS and ZynAddSubFx I made two wind sound effects, which now play when casting a wind spell. You can hear them in the attached video. Cross-Compiling is fun The speech recognition system is written in Rust, which compiles down to native code. This means that it needs to be compiled separately for each operating system, and processor architecture. Rust is more friendly to it, then C or C++ for example, but as always, compilation finds it own weird ways to break. I took the setup used by Sable as a base, with two Docker containers, one for Linux and Mac, and one for Windows. BUT: The Rust version installed in the docker image was not new enough for one of my dependencies - I had to update the rust toolchain in the container image. Compiling for linux required ALSA headers for audio access - I had to figure out, how to install them in a way, that works for both x86_64 and arm64, without breaking each other. The latest version of the base image has Mac cross compilation broken - I had to use a previous one. The image ships a MacOS SDK from 5 years ago - too old, doesn’t work, so it also had to be replaced. - the container is kinda becoming a Ship of Theseus xD My code was pulling openssl as a dependency, which was failing to compile - I had to spent over an hour, figuring out how to get rid of it from the dependency tree, discovering I can do so by updating a dependency to an unreleased version. Gradle obviously required some tweaks, who doesn’t love Gradle right? In the end I managed to get it working, which brings the mod closer to being usable by the public, outside dev environment. Downloading the model The mod works by running an IPA speech recognition model locally. The model weights around 1.2G, making it too large to be embedded in the mod jar. So I added automatic download support - the model can now be downloaded automatically on the first time an user runs the mod. There is even progress tracking, though it’s not hooked up to Minecraft yet. A Toast is also shown when the loading fails, making the mod more user friendly."}, {"post_id": 69097, "ts": "2026-09-16T11:23:50Z", "hours": 10.2308, "text": "SPELLCASTING WORKS! The main mechanic of the mod is working! YOU CAN CAST SPELLS WITH VOICE! Finally! It took soo long… After over two months of development, I finally have a proof, that my crazy idea actually works, and was worth trying out. As you can see (and hear) in the video I implemented a simple wind leap spell, as the first one in the mod. Note: There are no visuals or sounds yet, but they will be added, and this is just a proof of concept. The spell comes in three variants ʔalɪˈvɑn vɛɾtɛɾ ɛvi ˈonːdˌoː - wind launches you forward ʔalɪˈvɑn vɛɾtɛɾ ɛvi ãntikɔ - wind launches you backward ʔalɪˈvɑn vɛɾtɛɾ ɛvi fɒksɑm - wind launches you up (no matter where you are looking), not shown in the video Additionaly, it can be cast as just ʔalɪˈvɑn vɛɾtɛɾ ɛvi , which is a shortcut for the first variant. This can seen in the third attempt, where the system didin’t catch onːdˌoː , but the spell worked anyway. This flexibility is easily possible, thanks to Mojang’s brigadier library. Brigadier powers the / commands in vanilla, and now the spell syntax and execution in my mod. I settled on it after trying two alternative approaches and failing to make them work. After all, my spells are just sentences, with the only difference, is that you speak them instead of writing."}, {"post_id": 55219, "ts": "2026-08-26T20:03:24Z", "hours": 10.6233, "text": "Note: This one is kinda boring, mostly plumbing stuff to get things to work, feel free to skip it. Sephyr (the mod) I’m working on setting up the the logic for registering and casting spells. This is quite hard, as the design of the mod is far from complete, which means I don’t even know what exactly do I need. I created a registry of elements, which are a source of a color, and are going to have other effects in the future. The first word of a spell is its element. For example in the spell ʔalɪˈvɑn vɛɾtɛɾ ɛvi the word ʔalɪˈvɑn means wind. I also made a basic system for figuring out the spell the player is casting. For now its very simple and can’t handle more complex spells, for example, with optional words. The entirety is a big mess as I’m figuring things out, and the fact I’m making this mod for both Neo and Fabric doesn’t make it any easier. I also updated the mod to Minecraft 26.1.2, which means there is going to be no 1.21.1 release. Sepple (word detection system) I keep working on collecting data to finetine the speech to ipa ml model. After discovering a better way of getting the audio files while writing last devlog I scraped the download script, and instead replaced it with a new one to extract needed files from the 20GB Wiktinary audio dump tar. I also cleaned up the entire code, turning it back to human standards, after a bit of Opencode usage. (Since those are one-time scripts to extract data I decided using a bit of AI in this area won’t hurt. I don’t use AI for the rest of the project.). I also prepared a fourth script, that will use the existing multipa model, to generate IPA transcription of the files. Then files with generated IPA being too different from original IPA will be discarded, as a way to detect files, where the IPA doesn’t match the audio (because the audio contains more text for example)."}, {"post_id": 45897, "ts": "2026-08-12T17:21:05Z", "hours": 10.2356, "text": "Sephyr (the mod) A proper lifecycle of the detection system was added. The IPA model is loaded in background during game start, but the audio capture and processing start waits until you join a world, and stops once you leave it. The Rust code now has a logging hook, so that it can do civilized logging using the Java logger, instead of blatantly writing to stdout. Sepple (the voice casting detection system) I made the pipeline system cancellable, so that the mod can cleanly stop the detection, which was not possible before. Support for running the speech detection inference on GPU was added as a feature flag. For now it is not used by default, as it showed no measurable improvements over running on CPU on my PC, but it might be useful on other, weaker devices. Collecting data for training As I said too many times, the speech to IPA model used for magic speech detection is not quite the quality I would like it to be. I’m hoping to improve it by fine-tuning it on its weak areas, but for that I need some data. My idea is to use wiktionary as a data source. It is a free online dictionary run by the same people who run Wikipedia. Most words on it have the pronunciation attached both as an IPA and an audio file, which makes it ideal for the task. I downloaded a preprocessed jsonl dump file from kaikki and wrote a script to extract just words and ipa from it. Unfortunetely it was missing urls of the audio files. So I had to download a raw xml dump of the entire english wiktionary, and spend few hours writing a script to extract them. Then I used deepseek a generate a third script, to download all the audio files from a list. There is going to be almost 20k of them, and the script is running right now as I’m writing this, and it is going to take multiple hours as I can only download around 1 file per second to respect rate limits and not overburden wikimedia. And just now while writing I realized I’m an idiot, because kaikki provides a 20GB tar file with all the audio, downloading which would be more efficient."}, {"post_id": 41944, "ts": "2026-08-06T14:02:27Z", "hours": 9.6106, "text": "Integrating Rust IPA word detection with Minecraft With the IPA based magic keyword detection (which is written in Rust) working I spent all of this devlog integrating it into Minecraft. I created a new repo for the mod, using the Jared’s template. I decided to go with supporting both Fabric and Neoforge, and picked the 1.21.1 Minecraft version, though in the future I’m planning to move to 26.2 or later. I set up an additional gradle subproject and a rust package, that both together act as a Java to Rust bridge, using the j4rs crate. Using it I managed to initialize Sepple (the detection system), and get it running. The tricky part was going the other direction, to pass detected words from Rust to Java. For some reason Rust wasn’t detecting the JVM and was trying to spawn a new one! After a bit of experimentation I concluded, that I can only call Java from Rust only during the period when Java calls Rust, and only on the same thread. In the end I managed to get it working, by spawning a new thread on the Java side, and calling a blocking Rust function, that kept calling a Java callback passed to it. Originally I tried to use a static function as a callback, but for some reason (probably some kind of classloading isolation) the system was failing with some crazy null errors. I also had to adjust Sepple a bit, to not require a bunch of random json files at specific paths, and to provide an mpsc chanell directly outside its pipeline, for less boilerplate. With that I have a proof of concept working! Minecraft is receiving the detected words and printing them to chat. Note that those are all custom words, created by me specifically for this mod. This is why I had to create an entire new system for detecting them, and why they are written in the International Phonetic Language, which is also why they look a little weird in the minecraft’s font. The Java<->Rust setup is also not very good yet. For example the packaging of compiled Rust is very basic, and you can’t control the word detection from Java - no way to stop it or restart. There is also no good error handling, which means if a file is missing it will just crash everything. But it works, and I can continue working on the mod, and making it better!"}, {"post_id": 36043, "ts": "2026-07-27T21:21:56Z", "hours": 10.1719, "text": "About project Sephyr is a magic mod, with spell casting powered by speech live translated into International Phonetic Alphabet, to detecting custom-made spell words in it. Adding Voice Activity Detection - part 2 After the refactor I was able to finally add the VAD. But after few tests I noticed that the VAD was making things worse, not better! That was as a part of the previous devlog (which ran out of character limit). I added a pipeline part that writes every chunk of audio that passes through it to a file, so it can be inspected. With it I found the main problem: It took few hundred milliseconds before the VAD detected speech, so a small chunk was always cut off from the start. To fix this I added context keeping: A bunch of previous chunks are kept, and when speech is detected they are also taken into consideration. I also made the sliding window chunking aware of VAD - the VAD detector sends a signal when it detects an end of speech. The chunker then flushes its buffer into the pipeline, so that it doesn’t get stuck until next speech, and replaces it with precise amount of silenece. This way the start of next audio doesn’t get cut off later due to the sliding window mechanism. The author of the bunsen crate (providing the VAD model implementation) also released version 0.29.0, which fixed all the issues I encountered in the last devlog, and updated its API slighly, which meant that after adjusting my code I could stop using my own fork of it. Improving word detection from IPA My friend found a crate named phonetics-rs and suggested using it to improve the algorithm. This crate calculates the difference between two IPA strings, taking into account how similar they sound. This is much more accurate than just comparing strings on grapheme level. I modified my algorithm to use it, and it turned out to be a great idea, that significantly improved the detection rate of magic words. I also changed the dictionary to be sorted by longest words first, so that they take priority over short ones. So far, testing and improving the word detection algorithm has been the most fun out of the entire project. Looking at IPA strings, and figuring out why some speech has or hasn’t been classified as some word is quite fascinating. For example, I encountered a string pɾilifɛra which the model output after me saying prizim and fɛra , the two magic words that I made up for the spell system. Surprisingly, my algorithm said the string contained just prizim despite there being a literal fɛra in it. As I found out, pɾilif is closer then pɾili to prizim , and it fell under the threshold, so the algorithm took that part and left out ɛra in the buffer which was too far from fɛra . After seeing this, I made the algorithm scan the string for exact matches first, and then do fuzzy phonetic matching, also ensuring the order is preserved. I also tuned the thresholds, adding more and more tests (there is now 8 of them) to ensure the algorithm behaves well. Finally, I noticed the IPA output from the model changes based on audio’s offset in time. So I wrote a script that lets me test this, and see the effect of different offsets. What’s next There is a saying in data science: garbage in - garbage out. This is also true for my project. The detection works decently, but it also quite often outputs false positives during normal speech. I believe I did I all could to compensate for the unsatisfying quality of the speech to IPA translation model. Now I will be shifting to the Minecraft part of the project - creating a mod, integrating the detection system into it and creating spells. In paralell, I will be exploring the possibility of finetuning the model, to improve the accuracy of it and hopefully get better results. Watch the video with audio, that’s the part that matters right? :)"}, {"post_id": 27916, "ts": "2026-07-13T20:52:15Z", "hours": 30.4097, "text": "Finding words in long IPA strings For the magic system I need to find individual words in the ever accumulating string of IPA characters. To do that I hold a list of valid words in memory. When there is some text, I iterate over the dictionary, calculating a levenshtein distance between each word and start of the string. Then the word with the lowest score is taken and if the score is under a set threshold, the word is considered a match, and the matching part is remved from the buffer. To cover more cases different lengths of the string are checked. If no match is found, one character is removed from the string, and the process repeats, until all words are found. Fun fact: When comparing IPA and other non-ascii strings you need to make sure you are considering graphemes and not characters, because in UTF-8 what we perceive as one symbol, can be encoded as many characters in memory. So far this algorithm works quite well, though in the future it might need some performance optimization, or tuning, if it starts yelding too many false positives. Other misc changes: Migrated main fn to use clap for parsing arguments Added flake.nix with dev env so I can run this code on my NixOS laptop Added time information to the pipeline - Together with the audio from the mic, a timestamp is captured, and passed through entire pipeline up to the end, where it is used to discard text older then 200ms from the buffer, so that stale data doesn’t mess up new words. Adding VAD I noticed that the speech to IPA model likes to output random data when no one is talking, so I decided to add VAD - Voice Activity Detection - a system that detects if someone is talking, and only then passes the audio on. I estimated this to take me around 2 hours, and oh, how wrong I was? It took 10x that, which is why this devlog documents 3x the normal amount of time. And it still isn’t fully ready! So let me tell you what I did and why it took so long. In the Burn (ML/AI lib for Rust) discord I noticed a solution just dropped out of the sky: Merely few days before a Silero VAD model implementation was added to a library named bunsen . ML models take input as Tensor s - multidimensional arrays, which do not say in what form or shape the data is expected. So I had to figure that out myself. Fortunetely it was just 512 elements long chunks of 16khz audio with no additional pre-processing. Knowing that I fed the microphone input to the model and began to watch it output complete nonsense unrelated to whether I was speaking or not. So I started debugging - checked my code, wrote an equivalent in python using the official silero implementation to compare results - completely different. So I cloned the bunsen library, wrote an unit test there and ran off a Opencode agent. I also contacted the library author. He found one major issue, and the agent identified a second problem and wrote a solutuion - Silero VAD expects 64 samples of the previous chunk to be passed along the 512 to work correctly. I cleaned up the code, which was quite a pain because rust-analyzer was super slow on that repository, and made a PR, but it wasn’t merged because the author went with his own way of implementing it. The big refactor Coming back to my project I realized that my code strucutre makes it very hard to integrate VAD into it. So I spent the next 6 hours of so refactoring almost every file in the codebase into a new pipeline system. It lets you compose a pipeline out of a producer, many processors, and a consumer. It makes use of async, which saves on the amount of threads used. Static type checking ensures you can’t compose parts that wouldn’t work together, and all elements can also define contracts on the size of data chunks they produce and consume. I ran out of the character limit, so the rest of VAD story will be in next devlog."}, {"post_id": 11428, "ts": "2026-06-18T18:11:53Z", "hours": 4.8753, "text": "Live speech to IPA transcription in Rust using ML I finished my rough implementation of a live speech transcription pipeline. It captures my speech from the mic, and processes it with the Multipa model using the Burn framework. To make it work live I implemented a sliding window that chunks the audio into 2 second fragments, each of which is processed separately, and then assembled into a single string. The chunks overlap, and are then sliced, so that audio that was on the borders of a cut (which will reduce the quality) is thrown away, and the text for it is taken from the next chunk, for which it is at the center. The inference is running on cpu for simplicity and compatiblity, so by sacraficing a bit of pain I added threading (where each chunk is processed on a separate thread) to make sure the pipeline can keep up. I’m slightly worried about how the perfromance will be when this is going to run along Minecraft, but hopefully I will be able to make it as lightwieght and unintruisive as possible. Finally I reworked how the text is accumulated, switching from a vector of logits to a string. Since IPA has no concept of words, just phonemes, everything I say is appened to one long string. So I added a very simple silence detection, where if a captured chunk returns no text a space is added to the string. For easier teasting I also improved the main function, so that the program can: take a file and process it all at once take a file and process it using the pipeline run live mic capture on the pipeline What’s next - improving the detection In theory this is all I need, and I can start working on the Minecraft mod. However I’m not satisfied with the quality of the transcription, and at the level it currently is most spell detection will probably fail. The quality of the model itself is pretty bad. If the description on github of the Multipa model is correct, the model was trained on merely 9 hours of speech data, which probably explains it. The model is also sensitive to noise, and distractions like other people talking, and sometimes outputs garbage. So the next devlog I will be experimenting with various techinques of filtering and cleaning up the audio the model is receiving, and potentially even training a new model myself on a bigger dataset. Attached video Working demo of live capture and transcription of me talking."}, {"post_id": 9209, "ts": "2026-06-15T13:48:33Z", "hours": 3.7658, "text": "Sephyr - project overview Sephyr is an unique magic mod for Minecraft. It aims to differentiate itself by: Introducing a voice powered spell casting system , that’s both fun to use and intricate. You will be reading spells out loud into your mic in a magic language, and what will you say will affect the result of the spell. Having stunning, detailed visuals unique to each spell. This is going to be achieved by spending way too much effort on rendering. I want spell casting to be something satisfying, and the look is a key part of it. The project consits of two parts: Sephyr - The minecraft mod itself containing the spells, mechanics and visuals, written in kotlin. Sepple - Speech processing engine, responsible for transforming your babble into something Sephyr can work with and figure out what have you just said. Sepple overview Sepple is a foundation of the voice powered spell casting. It is an audio processing library written in rust, that Sephyr will depend on and embed. It captures your mic live and pre-processes the speech. Then it uses the Burn framework to locally and quickly run a speech recognition model called Multipa . The model transcribes speech into the International Phonetic Alphabet (IPA), a textual notation of various sounds that make up the spoken language. Finally it tries to match the result against a custom dictionary of magic words, which will form sentences - the spells you will be casting. This devlog Before Stardance launched I have written a rough skeleton for Sepple. With some trouble I managed to import the Multipa model to Burn via ONNX export from Pytorch, and implement the required post-processing to decode model’s output into IPA. I also started working on a pipeline for mic capture and sliding window processing, so that the audio can be transcribed live. After Stardance started I noticed that the same input audio file gives quite different result in Pytorch then in Rust. I spent few hours debugging why that is, and found a missing piece in my implemenation. For the Multipa model to work correctly the samples need to be normalized using a so-called z-score normalization. That means calculating the mean of the input and its standard deviation (a statistics measure), and applying a formula that rescales the data, so that it has a mean of 0 and standard deviation of 1. After implemenating that the model started to work correctly and give the same output for the same input on both sides. Picture: “Hello Stardance. Sepple is working now” translated to IPA using pytorch and the fixed Rust implementation. It is not veeery accurate, but it is good enough."}]...
|
Title: Sephyr Magic mod for Minecraft by @Szczurek Title: Sephyr Magic mod for Minecraft by @Szczurek | Stardance
Devlogs:
Sephyr - project overview Sephyr is an unique magic mod for Minecraft. It aims to differentiate itself by: Introducing a voice powered spell casting system , that’s both fun to use and intricate. You will be reading spells out loud into your mic in a magic language, and what will you say will affect the result of the spell. Having stunning, detailed visuals unique to each spell. This is going to be achieved by spending way too much effort on rendering. I want spell casting to be something satisfying, and the look is a key part of it. The project consits of two parts: Sephyr - The minecraft mod itself containing the spells, mechanics and visuals, written in kotlin. Sepple - Speech processing engine, responsible for transforming your babble into something Sephyr can work with and figure out what have you just said. Sepple overview Sepple is a foundation of the voice powered spell casting. It is an audio processing library written in rust, that Sephyr will depend on and embed. It captures your mic live and pre-processes the speech. Then it uses the Burn framework to locally and quickly run a speech recognition model called Multipa . The model transcribes speech into the International Phonetic Alphabet (IPA), a textual notation of various sounds that make up the spoken language. Finally it tries to match the result against a custom dictionary of magic words, which will form sentences - the spells you will be casting. This devlog Before Stardance launched I have written a rough skeleton for Sepple. With some trouble I managed to import the Multipa model to Burn via ONNX export from Pytorch, and implement the required post-processing to decode model’s output into IPA. I also started working on a pipeline for mic capture and sliding window processing, so that the audio can be transcribed live. After Stardance started I noticed that the same input audio file gives quite different result in Pytorch then in Rust. I spent few hours debugging why that is, and found a missing piece in my implemenation. For the Multipa model to work correctly the samples need to be normalized using a so-called z-score normalization. That means calculating the mean of the input and its standard deviation (a statistics measure), and applying a formula that rescales the data, so that it has a mean of 0 and standard deviation of 1. After implemenating that the model started to work correctly and give the same output for the same input on both sides. Picture: “Hello Stardance. Sepple is working now” translated to IPA using pytorch and the fixed Rust implementation. It is not veeery accurate, but it is good enough.
Live speech to IPA transcription in Rust using ML I finished my rough implementation of a live speech transcription pipeline. It captures my speech from the mic, and processes it with the Multipa model using the Burn framework. To make it work live I implemented a sliding window that chunks the audio into 2 second fragments, each of which is processed separately, and then assembled into a single string. The chunks overlap, and are then sliced, so that audio that was on the borders of a cut (which will reduce the quality) is thrown away, and the text for it is taken from the next chunk, for which it is at the center. The inference is running on cpu for simplicity and compatiblity, so by sacraficing a bit of pain I added threading (where each chunk is processed on a separate thread) to make sure the pipeline can keep up. I’m slightly worried about how the perfromance will be when this is going to run along Minecraft, but hopefully I will be able to make it as lightwieght and unintruisive as possible. Finally I reworked how the text is accumulated, switching from a vector of logits to a string. Since IPA has no concept of words, just phonemes, everything I say is appened to one long string. So I added a very simple silence detection, where if a captured chunk returns no text a space is added to the string. For easier teasting I also improved the main function, so that the program can: take a file and process it all at once take a file and process it using the pipeline run live mic capture on the pipeline What’s next - improving the detection In theory this is all I need, and I can start working on the Minecraft mod. However I’m not satisfied with the quality of the transcription, and at the level it currently is most spell detection will probably fail. The quality of the model itself is pretty bad. If the description on github of the Multipa model is correct, the model was trained on merely 9 hours of speech data, which probably explains it. The model is also sensitive to noise, and distractions like other people talking, and sometimes outputs garbage. So the next devlog I will be experimenting with various techinques of filtering and cleaning up the audio the model is receiving, and potentially even training a new model myself on a bigger dataset. Attached video Working demo of live capture and transcription of me talking.
Finding words in long IPA strings For the magic system I need to find individual words in the ever accumulating string of IPA characters. To do that I hold a list of valid words in memory. When there is some text, I iterate over the dictionary, calculating a levenshtein distance between each word and start of the string. Then the word with the lowest score is taken and if the score is under a set threshold, the word is considered a match, and the matching part is remved from the buffer. To cover more cases different lengths of the string are checked. If no match is found, one character is removed from the string, and the process repeats, until all words are found. Fun fact: When comparing IPA and other non-ascii strings you need to make sure you are considering graphemes and not characters, because in UTF-8 what we perceive as one symbol, can be encoded as many characters in memory. So far this algorithm works quite well, though in the future it might need some performance optimization, or tuning, if it starts yelding too many false positives. Other misc changes: Migrated main fn to use clap for parsing arguments Added flake.nix with dev env so I can run this code on my NixOS laptop Added time information to the pipeline - Together with the audio from the mic, a timestamp is captured, and passed through entire pipeline up to the end, where it is used to discard text older then 200ms from the buffer, so that stale data doesn’t mess up new words. Adding VAD I noticed that the speech to IPA model likes to output random data when no one is talking, so I decided to add VAD - Voice Activity Detection - a system that detects if someone is talking, and only then passes the audio on. I estimated this to take me around 2 hours, and oh, how wrong I was? It took 10x that, which is why this devlog documents 3x the normal amount of time. And it still isn’t fully ready! So let me tell you what I did and why it took so long. In the Burn (ML/AI lib for Rust) discord I noticed a solution just dropped out of the sky: Merely few days before a Silero VAD model implementation was added to a library named bunsen . ML models take input as Tensor s - multidimensional arrays, which do not say in what form or shape the data is expected. So I had to figure that out myself. Fortunetely it was just 512 elements long chunks of 16khz audio with no additional pre-processing. Knowing that I fed the microphone input to the model and began to watch it output complete nonsense unrelated to whether I was speaking or not. So I started debugging - checked my code, wrote an equivalent in python using the official silero implementation to compare results - completely different. So I cloned the bunsen library, wrote an unit test there and ran off a Opencode agent. I also contacted the library author. He found one major issue, and the agent identified a second problem and wrote a solutuion - Silero VAD expects 64 samples of the previous chunk to be passed along the 512 to work correctly. I cleaned up the code, which was quite a pain because rust-analyzer was super slow on that repository, and made a PR, but it wasn’t merged because the author went with his own way of implementing it. The big refactor Coming back to my project I realized that my code strucutre makes it very hard to integrate VAD into it. So I spent the next 6 hours of so refactoring almost every file in the codebase into a new pipeline system. It lets you compose a pipeline out of a producer, many processors, and a consumer. It makes use of async, which saves on the amount of threads used. Static type checking ensures you can’t compose parts that wouldn’t work together, and all elements can also define contracts on the size of data chunks they produce and consume. I ran out of the character limit, so the rest of VAD story will be in next devlog.
About project Sephyr is a magic mod, with spell casting powered by speech live translated into International Phonetic Alphabet, to detecting custom-made spell words in it. Adding Voice Activity Detection - part 2 After the refactor I was able to finally add the VAD. But after few tests I noticed that the VAD was making things worse, not better! That was as a part of the previous devlog (which ran out of character limit). I added a pipeline part that writes every chunk of audio that passes through it to a file, so it can be inspected. With it I found the main problem: It took few hundred milliseconds before the VAD detected speech, so a small chunk was always cut off from the start. To fix this I added context keeping: A bunch of previous chunks are kept, and when speech is detected they are also taken into consideration. I also made the sliding window chunking aware of VAD - the VAD detector sends a signal when it detects an end of speech. The chunker then flushes its buffer into the pipeline, so that it doesn’t get stuck until next speech, and replaces it with precise amount of silenece. This way the start of next audio doesn’t get cut off later due to the sliding window mechanism. The author of the bunsen crate (providing the VAD model implementation) also released version 0.29.0, which fixed all the issues I encountered in the last devlog, and updated its API slighly, which meant that after adjusting my code I could stop using my own fork of it. Improving word detection from IPA My friend found a crate named phonetics-rs and suggested using it to improve the algorithm. This crate calculates the difference between two IPA strings, taking into account how similar they sound. This is much more accurate than just comparing strings on grapheme level. I modified my algorithm to use it, and it turned out to be a great idea, that significantly improved the detection rate of magic words. I also changed the dictionary to be sorted by longest words first, so that they take priority over short ones. So far, testing and improving the word detection algorithm has been the most fun out of the entire project. Looking at IPA strings, and figuring out why some speech has or hasn’t been classified as some word is quite fascinating. For example, I encountered a string pɾilifɛra which the model output after me saying prizim and fɛra , the two magic words that I made up for the spell system. Surprisingly, my algorithm said the string contained just prizim despite there being a literal fɛra in it. As I found out, pɾilif is closer then pɾili to prizim , and it fell under the threshold, so the algorithm took that part and left out ɛra in the buffer which was too far from fɛra . After seeing this, I made the algorithm scan the string for exact matches first, and then do fuzzy phonetic matching, also ensuring the order is preserved. I also tuned the thresholds, adding more and more tests (there is now 8 of them) to ensure the algorithm behaves well. Finally, I noticed the IPA output from the model changes based on audio’s offset in time. So I wrote a script that lets me test this, and see the effect of different offsets. What’s next There is a saying in data science: garbage in - garbage out. This is also true for my project. The detection works decently, but it also quite often outputs false positives during normal speech. I believe I did I all could to compensate for the unsatisfying quality of the speech to IPA translation model. Now I will be shifting to the Minecraft part of the project - creating a mod, integrating the detection system into it and creating spells. In paralell, I will be exploring the possibility of finetuning the model, to improve the accuracy of it and hopefully get better results. Watch the video with audio, that’s the part that matters right? :)
Integrating Rust IPA word detection with Minecraft With the IPA based magic keyword detection (which is written in Rust) working I spent all of this devlog integrating it into Minecraft. I created a new repo for the mod, using the Jared’s template. I decided to go with supporting both Fabric and Neoforge, and picked the 1.21.1 Minecraft version, though in the future I’m planning to move to 26.2 or later. I set up an additional gradle subproject and a rust package, that both together act as a Java to Rust bridge, using the j4rs crate. Using it I managed to initialize Sepple (the detection system), and get it running. The tricky part was going the other direction, to pass detected words from Rust to Java. For some reason Rust wasn’t detecting the JVM and was trying to spawn a new one! After a bit of experimentation I concluded, that I can only call Java from Rust only during the period when Java calls Rust, and only on the same thread. In the end I managed to get it working, by spawning a new thread on the Java side, and calling a blocking Rust function, that kept calling a Java callback passed to it. Originally I tried to use a static function as a callback, but for some reason (probably some kind of classloading isolation) the system was failing with some crazy null errors. I also had to adjust Sepple a bit, to not require a bunch of random json files at specific paths, and to provide an mpsc chanell directly outside its pipeline, for less boilerplate. With that I have a proof of concept working! Minecraft is receiving the detected words and printing them to chat. Note that those are all custom words, created by me specifically for this mod. This is why I had to create an entire new system for detecting them, and why they are written in the International Phonetic Language, which is also why they look a little weird in the minecraft’s font. The Java<->Rust setup is also not very good yet. For example the packaging of compiled Rust is very basic, and you can’t control the word detection from Java - no way to stop it or restart. There is also no good error handling, which means if a file is missing it will just crash everything. But it works, and I can continue working on the mod, and making it better!
Sephyr (the mod) A proper lifecycle of the detection system was added. The IPA model is loaded in background during game start, but the audio capture and processing start waits until you join a world, and stops once you leave it. The Rust code now has a logging hook, so that it can do civilized logging using the Java logger, instead of blatantly writing to stdout. Sepple (the voice casting detection system) I made the pipeline system cancellable, so that the mod can cleanly stop the detection, which was not possible before. Support for running the speech detection inference on GPU was added as a feature flag. For now it is not used by default, as it showed no measurable improvements over running on CPU on my PC, but it might be useful on other, weaker devices. Collecting data for training As I said too many times, the speech to IPA model used for magic speech detection is not quite the quality I would like it to be. I’m hoping to improve it by fine-tuning it on its weak areas, but for that I need some data. My idea is to use wiktionary as a data source. It is a free online dictionary run by the same people who run Wikipedia. Most words on it have the pronunciation attached both as an IPA and an audio file, which makes it ideal for the task. I downloaded a preprocessed jsonl dump file from kaikki and wrote a script to extract just words and ipa from it. Unfortunetely it was missing urls of the audio files. So I had to download a raw xml dump of the entire english wiktionary, and spend few hours writing a script to extract them. Then I used deepseek a generate a third script, to download all the audio files from a list. There is going to be almost 20k of them, and the script is running right now as I’m writing this, and it is going to take multiple hours as I can only download around 1 file per second to respect rate limits and not overburden wikimedia. And just now while writing I realized I’m an idiot, because kaikki provides a 20GB tar file with all the audio, downloading which would be more efficient.
Note: This one is kinda boring, mostly plumbing stuff to get things to work, feel free to skip it. Sephyr (the mod) I’m working on setting up the the logic for registering and casting spells. This is quite hard, as the design of the mod is far from complete, which means I don’t even know what exactly do I need. I created a registry of elements, which are a source of a color, and are going to have other effects in the future. The first word of a spell is its element. For example in the spell ʔalɪˈvɑn vɛɾtɛɾ ɛvi the word ʔalɪˈvɑn means wind. I also made a basic system for figuring out the spell the player is casting. For now its very simple and can’t handle more complex spells, for example, with optional words. The entirety is a big mess as I’m figuring things out, and the fact I’m making this mod for both Neo and Fabric doesn’t make it any easier. I also updated the mod to Minecraft 26.1.2, which means there is going to be no 1.21.1 release. Sepple (word detection system) I keep working on collecting data to finetine the speech to ipa ml model. After discovering a better way of getting the audio files while writing last devlog I scraped the download script, and instead replaced it with a new one to extract needed files from the 20GB Wiktinary audio dump tar. I also cleaned up the entire code, turning it back to human standards, after a bit of Opencode usage. (Since those are one-time scripts to extract data I decided using a bit of AI in this area won’t hurt. I don’t use AI for the rest of the project.). I also prepared a fourth script, that will use the existing multipa model, to generate IPA transcription of the files. Then files with generated IPA being too different from original IPA will be discarded, as a way to detect files, where the IPA doesn’t match the audio (because the audio contains more text for example).
SPELLCASTING WORKS! The main mechanic of the mod is working! YOU CAN CAST SPELLS WITH VOICE! Finally! It took soo long… After over two months of development, I finally have a proof, that my crazy idea actually works, and was worth trying out. As you can see (and hear) in the video I implemented a simple wind leap spell, as the first one in the mod. Note: There are no visuals or sounds yet, but they will be added, and this is just a proof of concept. The spell comes in three variants ʔalɪˈvɑn vɛɾtɛɾ ɛvi ˈonːdˌoː - wind launches you forward ʔalɪˈvɑn vɛɾtɛɾ ɛvi ãntikɔ - wind launches you backward ʔalɪˈvɑn vɛɾtɛɾ ɛvi fɒksɑm - wind launches you up (no matter where you are looking), not shown in the video Additionaly, it can be cast as just ʔalɪˈvɑn vɛɾtɛɾ ɛvi , which is a shortcut for the first variant. This can seen in the third attempt, where the system didin’t catch onːdˌoː , but the spell worked anyway. This flexibility is easily possible, thanks to Mojang’s brigadier library. Brigadier powers the / commands in vanilla, and now the spell syntax and execution in my mod. I settled on it after trying two alternative approaches and failing to make them work. After all, my spells are just sentences, with the only difference, is that you speak them instead of writing.
Wind spells have sound now Using LMMS and ZynAddSubFx I made two wind sound effects, which now play when casting a wind spell. You can hear them in the attached video. Cross-Compiling is fun The speech recognition system is written in Rust, which compiles down to native code. This means that it needs to be compiled separately for each operating system, and processor architecture. Rust is more friendly to it, then C or C++ for example, but as always, compilation finds it own weird ways to break. I took the setup used by Sable as a base, with two Docker containers, one for Linux and Mac, and one for Windows. BUT: The Rust version installed in the docker image was not new enough for one of my dependencies - I had to update the rust toolchain in the container image. Compiling for linux required ALSA headers for audio access - I had to figure out, how to install them in a way, that works for both x86_64 and arm64, without breaking each other. The latest version of the base image has Mac cross compilation broken - I had to use a previous one. The image ships a MacOS SDK from 5 years ago - too old, doesn’t work, so it also had to be replaced. - the container is kinda becoming a Ship of Theseus xD My code was pulling openssl as a dependency, which was failing to compile - I had to spent over an hour, figuring out how to get rid of it from the dependency tree, discovering I can do so by updating a dependency to an unreleased version. Gradle obviously required some tweaks, who doesn’t love Gradle right? In the end I managed to get it working, which brings the mod closer to being usable by the public, outside dev environment. Downloading the model The mod works by running an IPA speech recognition model locally. The model weights around 1.2G, making it too large to be embedded in the mod jar. So I added automatic download support - the model can now be downloaded automatically on the first time an user runs the mod. There is even progress tracking, though it’s not hooked up to Minecraft yet. A Toast is also shown when the loading fails, making the mod more user friendly.
The Stack Overflow For some reason my mod broke and started crashing during startup, and it did so in the worst possible way - without any error message! All I got in the Intellij Idea, was a message that the process exited with the signal code 11. WHAT? That signal corresponds to SIGSEGV signal on Linux, which generally means you did something wrong with the memory. But this is Rust! There shouldn’t be any memory issues! I started searching, and I learned there is a tool called coredumpctl, which lets me access a special dump file generated in such cases, and analyze it in a debugger like GDB. So I did that, and what I found was even more bizzare! The debugger was pointing to a start of a function, before the first line. I added some debug prints, and to my disbelief, the print before calling that function ran, and the the second one, which was the first line inside the function didn’t! Fast forward a bit I managed to figure out the problem, with some help from a friend. It turned out I encountered an stack overflow! When the function was called, Rust tried to expand the stack, and crashed because the stack ran out! Why? Because the code was loaded in Java, and Java by default allocates less memory for the stack ! The solution was manually requesting a bigger stack size during thread creation in Java. I also discovered, why the problem appeared - in the Rust file download code I had allocated an array buffer of 1MB. It landed on the stack, and that was too much! The solution was using a Vec, which lives on the heap instead. Stupid problem, but took 3 hours of my time 😩 Mod init progress reporting Sephyr requires the IPA speech recognition model to work, which needs to be downloaded on the first run, and subsequently loaded from the disk. The logic was overhauled providing more corectness, and hooked up to a series of toasts. File download progress bar is shown, and the intialization state (or failure) is coummunicated to the user! See it in the video
Visualizing the keyword detection pipeline I’m not happy with the accuracy of the magic words detection system. It work half of the time, sometimes better, sometimes worse depending on the word. This make casting longer spells quite troublesome. Debugging why a specific word wasn’t detected is hard, debug prints can only get you so far. So I decided to go on a crazy sidequest and build a gui tool, that will help me debug this. I spent over 2 hours designing the concept, and over 10 implementing it, and it’s around 40% ready. The tool will display 8 strips / plots, and each plot will display some data, all on a shared timeline on the bottom, that will update live as the audio is processed. Strips 1, 2, and 4 will display waveforms of the audio at different processing stages. Strip 3 will show Voice Activity Detection score (which is used to filter out non-speech). Strips 5, 6 and 7 will display detected IPA tokens, accumulated text buffer, and detected words respectively. Strip 8 will display latency stats, which will help in optimizing it. This way I will be able to easily see, “oh, this phoneme wasn’t detected” or “oh, VAD cut out this word” or “oh, some mess accumulated in the buffer” and tweak my algorithms. AI - it’s bad, or is it? Despite looking quite simple on the surface, the app is still quite an undertaking. And it’s just a debugging tool! A thing to help me get the main goal done! I don’t want to spend too much time on it. So I considered using AI as a tool ( NOT vibecoding ). I hate vibecod(ing, ers), and I’ve always steered off AI, because very often I wasn’t satisfied with the output quality. I take pride in writing good code. But recently I’ve been trying out OpenCode here and there (on free models), and was quite surprised with it’s capabilities. Sure, it’s still often slop, but a one you can quite quickly correct, and sometimes be more effective if used correctly. AI - is it helpful? So I decided to do an experiment - can carefully planned AI usage help me write the debugging tool quickly? I started off by designing the functionality of the tool - I described the idea in detail to MiMo-V2.6-Flash, and asked it to interrogate me about as many details as possible and needed. I had to answer 35 questions, some of which were quite observant, picking me on nooks and crannies. After that a markdown file describing the design was written, and then went through few corrections. Next up, in a new session I asked MiMo to create a bullet point outline of steps needed to be done to implement the tool specified in the design file. Then one by one I went over each bullet point, asking the just released LongCat 2.5 (which has a bigger ctx window) to ask me questions, and formulate an implementation plan of it, present it to me, I gave corrections, and the point in file was replaced. This way I ended up with a second markdown file - an implementation plan. This took way too long, and was really boring. So, finally coding time. I do it like this: Ask opencode to implement a step of the plan Review the diff in vscode Remove fluff and slop manually, make sure all new code is good quality. Give feedback if I something doesn’t work like expected, or also fix it manually. After it’s good - commit Repeat for the next step It’s still not super fun, but at least I’m touching the code now, so much better already. And it is efficient! I believe it definitely would take me longer, if I wasn’t using AI. So the morale is: If you want fun, or doing something important - do it manually. If you want to do something quickly and get it out of the way less important. Here is a screen of how it is looking now: the general shape is in place, but there is no plots yet.
Keyword detection UI is done Look as this! It’s so pretty! Seeing all the data visualised is quite mesmerizing. I know the image will probably attract more views, so lemme explain what you are looking at. I’m making a minecraft mod where you cast spells by saying custom made up words, and this is a tool for debugging the keyword detection system. It’s meant for me, to help me make the detection more accurate, and reliable. I’ve been building it for the last ~20 hours, and in the last two I built the rendering of all the 8 strips. Check previous devlog if you want to know what exactly they display. It was pretty smooth sailing. As said before, since this is just a debugging tool for me, that I want to have finished quickly for it I’m using AI assistence, by letting it do stuff in small, pre-planned steps, and unsloppifying all the code between them. It’s working well. What helps, is that entire app is built on the egui / eframe crates, which I used before, and are somewhat familiar with. I gotta give credit, where is due, their api is really intuitive for the most part, and simple to use. The entire chart is also zoomable, and scrollable, and making this work was a bit of pain. I wanted to limit the accesible range to only around the data (so you can’t scroll away to far from it), and egui_plot doesn’t really provide a way to do it, so some manual calculations had to be done. I wanted to have some breathing space by allowing 0.25x of the zoom after last audio sample to be visible. This was the worst part, as it’s kind of a recursive problem - the zoom value affects how much zoom is allowed. But after around two hours I manged to figure it out, but keeping the original zoom value independantly of the limit calculated from it. Worth noting - what you see is just a mockup data, and the gui isn’t actually hooked up to the detection system, as that’s what I’m going to do next. After that I can hopefully improve the detection, and the finally go back to minecraft coding.
Debugging gui is (almost) done What is going on, why already 10 hours passed? This was menat to be a quick sidequest, where I built this gui tool for debugging how well detecting magic keywords is working BUUT given it is the third devlog about it That means it took over 30 hours! Well, happens. So, all of this devlog was spent building all the plumbing needed to capture all the data from the detection pipeline and sending it in realtime to the app. All of it is using done using channels. They are injected into the detection pipeline either as Tap<T> ‘s - a new pipeline element that clones data it sees, sends to channel, and passes it on, or using wrapper types around existing processors. The app then receives the data and displays in on the plot. I also encountered and fixed few bugs, that I didn’t expect. For example originally the zoom went to crazy values, because a timestamp used to determine where the data ends wasn’t converted to be relative to the timeline start. I also found an quite an issue introduced 3 months ago, where the timestamps attached to audio weren’t calculated properly, making entire audio chunks have identical stamps. It was minor enough that I never noticed till now, when the data landed on the plot and resulted in this funny thing you can see on the attached screenshot. Finally I added a simple scrolling animation, to amortize the jitter caused by bigger chunks of audio coming, so the plot doesn’t jump that much when going live, but it’s still not as smooth as I would like it to be. As mentioned before I was using AI assistance in strictly controlled manner (I carefully planned, revieved, cleaned up and adjusted to my liking all the code generated by it) to build this debugging tool faster, and by now I’m very tired of it. At the end of the work it started doing stupid things (possibly because some context was lost?), which made me question if it was making me faster or slower. Luckily the work is mostly over, and I can finally get to other, more interesting stuff, that will be fun to do, with no AI. Next I want to use the tool to improve the detection a bit, and spend more time working on the actual mod.
Multiloader modding is pain Can’t NeoForge and Fabric just have one common api, for all the boring stuff like registration, networking and events? I’ve had enough, so I spent 2 hours porting my mod to Balm , which is a library providing exactly that. The result is beautiful - ~150 lines are gone, and the loader specific subprojects fit under 10 lines of code, as I was able to move everything to common. Now for the worst irony: I spent my time doing all of that and the next thing I’m gonna do is… disable fabric support 😭 Why, you may ask? I was forced into it by reality read on First VFX I made my first VFX, for the leap spell. You can see it in the attached video. It’s going to spawn under player’s legs. For now it’s a really simple one, as I’m rushing to add a bit more of content, than just a single spell, before Stardance ends. It is made using Photon Editor , which is a VFX editor for Minecraft. It has a lot of good stuff, like emitters, timeline and animation curves, which will be crucial in making more advanced effects. Only downside: It doesn’t support Fabric, which is why support for it is going to be disabled for now, until I manage to hopefully make a port it in the future. Reworking spell internals (again) After making the effect, I realized I have no way to run it from the spell code, because spell logic runs server side only, and VFX needs to be played on the client. So I wen’t back to the drawing board, and I’m going to change how spells run. They are going be entities now, but more on that next devlog, because it’s not done yet, as I ran into friction in the code, which triggered me to do the Balm refactor, and in the meantime the time counter hit 9,5h. Do NOT hardcode stuff please I had to do some work on my laptop today, which has NixOS. So I update my Sephyr clone, try to run it, and bada bing bada bum, it doesn’t work! What’s going on? After a hour of debugging, it turned out that NeoForge devs hardcoded their Gradle plugin to run one specific task using Java 21. The rest runs on Java 25 (the one used by Minecraft 26.1). So, be default, a NeoForge setup for Mc 26.1+ requires two java version. Normally the second one is autodownloaded, but that doesn’t work on NixOS, and that’s also bloat. I don’t want that! So I made a bug report . Fortunetely it isn’t really hardcoded, just dumb, and I was able to fix it with this line in build.gradle Update to Burn 0.22 Burn 0.22 was recently released, removing the Backend generic from most of it’s traits. I updated Sepple to work with that. I also had to regenerate the model code for the multipa model. I was hoping the update would provide some speedup to speech processing, but I wasn’t able to measure any difference. Replacing Multipa with Zipa I found a new speech-to-IPA model. It’s called Zipa , and it looks very promising. It’s around 4x smaller then multipa, which means faster processing and less to download for end users. Furthermore, according to it’s paper, and my few tests it has noticeable better accuracy! So I implemnted it. It was a little more trouble then multipa, because the model has a much richer pre-processing. The audio waveform is turned into a mel spectogram, Fourier Transform is done, and other stuff happens. Buuut there is a problem. It turns out the model is great at doing recognition on longer audio sequences, and doesn’t really work that well on short ones. For them it performed worse then multipa! That means it’s not suitable for doing recognition in realtime, at least when plugged in the same way multipa was. However I have a couple ideas to try, which might, hopefully, solve the issue. Until I do that, it is set aside on a separate branch....
|
1792641292.6978648
|
1793246092.6978648
|
|
32004
|
FW 190 - RC Airplane by @BAUMAU | Stardance
|
BAUMAU
|
0
|
147.44
|
0
|
[]
|
[{"post_id": 79030, "ts": "202 [{"post_id": 79030, "ts": "2026-10-12T12:48:11Z", "hours": 10.0228, "text": "Just like last devlog, I didn’t do too much exciting stuff. I changed the attachment of the nose and inner parts-tray, so the nose is screwed to the main body, while the tray is just tucked in place. I reprinted some parts and cleaned them up. I cut the carbon tube that goes trough the wings and bent the springsteel wires for the front and back gear. The picture just shows all the sketches I drew during the entire design process, which I just think looks cool. See you on the next (and probably last) devlog =D"}, {"post_id": 76385, "ts": "2026-10-03T11:33:38Z", "hours": 9.4903, "text": "Since last devlog, I didn’t do much exciting stuff. I spent hours trying to solder everything, only to find out that the soldering irons tip was the problem all along. I cleaned up, tested tolerances on the printed parts, made small changes to the model and reprinted some parts so they would fit. Not very interesting, but it brings the project forward."}, {"post_id": 73923, "ts": "2026-09-26T10:30:23Z", "hours": 9.7311, "text": "Finally, after so much time, all the parts are there. I still need to solder some things and make sure everything fits nicely, but after that, the final assembly may begin : D"}, {"post_id": 71147, "ts": "2026-09-20T11:00:20Z", "hours": 10.0317, "text": "Hey guys, I am finally printing all the planes parts now! I‘m printing with ASA Aero which was an absolute nightmare before having the right settings, with strings everywhere and many failed prints. But now the settings work and the prints look great for the filament. Probably only one more devlog before shipping this project XD. See you on the next one."}, {"post_id": 68842, "ts": "2026-09-15T20:56:57Z", "hours": 10.7514, "text": "Welcome to devlog number 8. Most I did, was to design some gears for the back steering-mechanism. It now consists of one twirly gear on a small motor I took out of a servo, which slowly turns a chain of gears. I also made some small additions, mainly to stabilise the structural integrity after putting the different printed parts together."}, {"post_id": 66898, "ts": "2026-09-12T21:01:34Z", "hours": 9.3947, "text": "Welcome to my 7th devlog. Since the last devlog, I have worked on fixations for the cockpit, the back wheel, some irl hardware stuff and the steering mechanisms in the back of the plane. As it turns out, there is so little room in the back of the plane, that I could not fit a servo in there to deliver the needed form of motion. Because of that, I had to deconstruct a servo irl, so I can measure and fit the single parts (potentiometer, motor and the pcb) where I want them to be, kinda like a custom servo-version. The cockpit now has little springs in the back and some kind of nose in the front for a quick montage and removal. I also replaced the voltage step-down converter of the little electronics complex for reading and sending the controllers data I use to control the plane, because the old one wasn’t working. Sadly, it seems like the esp32 I was using to read the data, now has a short-circuit and completely overheats after a short time. Next I will integrate the core servo parts of the servo I demolished into Fusion 360 and hopefully make it work. And buy a new esp32 :( See you on the next devlog :)"}, {"post_id": 65071, "ts": "2026-09-09T22:40:40Z", "hours": 9.4864, "text": "I’m finally back to working on my project! The last days, I mostly worked on the internal arrangement of all the necessary parts like pcb, battery, servos etc. The mechanism for controlling the aileron/flaps now consists of two gears on top of each other at a 90° angle, so the servos wouldn’t have to be in the middle of the plane, creating a space problem. I put the battery, pcb and ESC controller onto a removable tray, so taking the battery out is easier. The tray will be fixed with screws in the back, and be connected to the removable front part of the plane for a semi-easy removal while also holding in place while flying. I also fixed a real-world issue with the gear, where in CAD it would fit perfectly, while being out of place irl. Now the only ramaining thing to do is to design the mechanism to steer the rudder, which is quite tricky, because there is pretty much no space at all to attach anything in the very back of the plane. See you on the next devlog :)"}, {"post_id": 42555, "ts": "2026-08-07T11:38:38Z", "hours": 9.3664, "text": "Hello guys, I am finally finished with the pcb design. Now all that is left to do is to finish the steering mechanism in the plane, adding a mount for the pcb and then assembling everything. Sadly I wont be able to work on this project for about a month or so, since im on vacation. See you on the next one!"}, {"post_id": 40446, "ts": "2026-08-03T23:27:21Z", "hours": 9.6944, "text": "Hey guys, this devlog I just fixed some problems with the 3D model of the aircraft and added a screw mount for the cockpit, so it holds onto the main body and is detachable. I also started to do some research on electronics and pcb design for a simple main pcb in the plane. I even started with the schematic but still have quite a lot to learn and do."}, {"post_id": 38458, "ts": "2026-07-31T20:45:20Z", "hours": 46.2483, "text": "Hi guys, it has been quite some time since my last devlog in which I promised to show the plane model. Now I am almost finished with it. Because this was my first time modeling something as complex and dynamic, it took me much time to figure things out. I also did the first test 3D print which pointed out some important issues I will need to fix. Heres a quick overview of how I intend the aircraft to function: -The main body will consist of multiple parts which get put together with glue -The wings will further be stabilised by a carbon pipe -It will have retractable gear -The flaps will be controlled by spinning rods connected to gears inside the main body -Everything will be connected to a main pcb and controlled by an esp32 which receives the data via an antenna See you on the next devlog!"}, {"post_id": 27809, "ts": "2026-07-13T18:10:01Z", "hours": 8.4608, "text": "Hello guys, this is my second devlog on my RC airplane. I’m finally finished with programming both the receiving and transmitting ESP32 boards which I use for this project. Heres a list of all the things I did/added and fixed since the last devlog: -I got the antennas working -The radio connection works and transmits the data I want -The receiving ESP32 now hands the signals down to servos -Fixed a problem with the servo library where attaching the servos to any pin would overwrite other attached servos -Added an easy kind of failsafe -Built a container for the electronics that goes on the back of my controller on the transmitting end–> still working on it but almost finished I will update you guys, when I have a decent 3D model of the plane to show."}, {"post_id": 25337, "ts": "2026-07-09T15:50:52Z", "hours": 4.7606, "text": "This is my first ever devlog so don‘t expect too much. Heres what I already did: -I set up my coding workspace -I connected the ESP32 to my controller and can read the data -I set up the Antennas and tested them Now I just need the Antennas to work together with the rest. After that I will start to design the plane in CAD. Thats it for the devlog, I‘ll post the next one, when i‘m finished with the main coding part."}]...
|
Title: FW 190 - RC Airplane by @BAUMAU | Stardance Title: FW 190 - RC Airplane by @BAUMAU | Stardance
Devlogs:
This is my first ever devlog so don‘t expect too much. Heres what I already did: -I set up my coding workspace -I connected the ESP32 to my controller and can read the data -I set up the Antennas and tested them Now I just need the Antennas to work together with the rest. After that I will start to design the plane in CAD. Thats it for the devlog, I‘ll post the next one, when i‘m finished with the main coding part.
Hello guys, this is my second devlog on my RC airplane. I’m finally finished with programming both the receiving and transmitting ESP32 boards which I use for this project. Heres a list of all the things I did/added and fixed since the last devlog: -I got the antennas working -The radio connection works and transmits the data I want -The receiving ESP32 now hands the signals down to servos -Fixed a problem with the servo library where attaching the servos to any pin would overwrite other attached servos -Added an easy kind of failsafe -Built a container for the electronics that goes on the back of my controller on the transmitting end–> still working on it but almost finished I will update you guys, when I have a decent 3D model of the plane to show.
Hi guys, it has been quite some time since my last devlog in which I promised to show the plane model. Now I am almost finished with it. Because this was my first time modeling something as complex and dynamic, it took me much time to figure things out. I also did the first test 3D print which pointed out some important issues I will need to fix. Heres a quick overview of how I intend the aircraft to function: -The main body will consist of multiple parts which get put together with glue -The wings will further be stabilised by a carbon pipe -It will have retractable gear -The flaps will be controlled by spinning rods connected to gears inside the main body -Everything will be connected to a main pcb and controlled by an esp32 which receives the data via an antenna See you on the next devlog!
Hey guys, this devlog I just fixed some problems with the 3D model of the aircraft and added a screw mount for the cockpit, so it holds onto the main body and is detachable. I also started to do some research on electronics and pcb design for a simple main pcb in the plane. I even started with the schematic but still have quite a lot to learn and do.
Hello guys, I am finally finished with the pcb design. Now all that is left to do is to finish the steering mechanism in the plane, adding a mount for the pcb and then assembling everything. Sadly I wont be able to work on this project for about a month or so, since im on vacation. See you on the next one!
I’m finally back to working on my project! The last days, I mostly worked on the internal arrangement of all the necessary parts like pcb, battery, servos etc. The mechanism for controlling the aileron/flaps now consists of two gears on top of each other at a 90° angle, so the servos wouldn’t have to be in the middle of the plane, creating a space problem. I put the battery, pcb and ESC controller onto a removable tray, so taking the battery out is easier. The tray will be fixed with screws in the back, and be connected to the removable front part of the plane for a semi-easy removal while also holding in place while flying. I also fixed a real-world issue with the gear, where in CAD it would fit perfectly, while being out of place irl. Now the only ramaining thing to do is to design the mechanism to steer the rudder, which is quite tricky, because there is pretty much no space at all to attach anything in the very back of the plane. See you on the next devlog :)
Welcome to my 7th devlog. Since the last devlog, I have worked on fixations for the cockpit, the back wheel, some irl hardware stuff and the steering mechanisms in the back of the plane. As it turns out, there is so little room in the back of the plane, that I could not fit a servo in there to deliver the needed form of motion. Because of that, I had to deconstruct a servo irl, so I can measure and fit the single parts (potentiometer, motor and the pcb) where I want them to be, kinda like a custom servo-version. The cockpit now has little springs in the back and some kind of nose in the front for a quick montage and removal. I also replaced the voltage step-down converter of the little electronics complex for reading and sending the controllers data I use to control the plane, because the old one wasn’t working. Sadly, it seems like the esp32 I was using to read the data, now has a short-circuit and completely overheats after a short time. Next I will integrate the core servo parts of the servo I demolished into Fusion 360 and hopefully make it work. And buy a new esp32 :( See you on the next devlog :)
Welcome to devlog number 8. Most I did, was to design some gears for the back steering-mechanism. It now consists of one twirly gear on a small motor I took out of a servo, which slowly turns a chain of gears. I also made some small additions, mainly to stabilise the structural integrity after putting the different printed parts together.
Hey guys, I am finally printing all the planes parts now! I‘m printing with ASA Aero which was an absolute nightmare before having the right settings, with strings everywhere and many failed prints. But now the settings work and the prints look great for the filament. Probably only one more devlog before shipping this project XD. See you on the next one.
Finally, after so much time, all the parts are there. I still need to solder some things and make sure everything fits nicely, but after that, the final assembly may begin : D
Since last devlog, I didn’t do much exciting stuff. I spent hours trying to solder everything, only to find out that the soldering irons tip was the problem all along. I cleaned up, tested tolerances on the printed parts, made small changes to the model and reprinted some parts so they would fit. Not very interesting, but it brings the project forward.
Just like last devlog, I didn’t do too much exciting stuff. I changed the attachment of the nose and inner parts-tray, so the nose is screwed to the main body, while the tray is just tucked in place. I reprinted some parts and cleaned them up. I cut the carbon tube that goes trough the wings and bent the springsteel wires for the front and back gear. The picture just shows all the sketches I drew during the entire design process, which I just think looks cool. See you on the next (and probably last) devlog =D...
|
1792518897.5662298
|
1793123697.5662298
|
|
56374
|
liteNgine by @AzzyAzimuth | Stardance
|
AzzyAzimuth
|
0
|
146.62
|
0
|
[]
|
[{"post_id": 65253, "ts": "202 [{"post_id": 65253, "ts": "2026-09-10T08:01:55Z", "hours": 7.1728, "text": "I’m cooking up a storm. The storm is leaking memory. Both sentences can be true without detracting from the skill I genuinely do not possess. My copy and paste Keys have been obliterated and my commits have become more and more loose with their terms due to the decreasing amounts of awareness I possess about what the heck I’m doing. Current progress indicates some developments in terms of plugin loading but at this point who knows anymore.Do not delete the vkDevice I beg"}, {"post_id": 58593, "ts": "2026-08-31T02:03:34Z", "hours": 139.4519, "text": "Out with the old, in with the new. A big gripe i had with the engine was it’s long compile times. Thus by compartmentalising it into multiple dll modules, it’s smaller and gets me faster build times! Besides, you can develop your own features using the ABI. Pic unrelated (Inverse kinematics demo)"}]...
|
Title: liteNgine by @AzzyAzimuth | Stardance
Devl Title: liteNgine by @AzzyAzimuth | Stardance
Devlogs:
Out with the old, in with the new. A big gripe i had with the engine was it’s long compile times. Thus by compartmentalising it into multiple dll modules, it’s smaller and gets me faster build times! Besides, you can develop your own features using the ABI. Pic unrelated (Inverse kinematics demo)
I’m cooking up a storm. The storm is leaking memory. Both sentences can be true without detracting from the skill I genuinely do not possess. My copy and paste Keys have been obliterated and my commits have become more and more loose with their terms due to the decreasing amounts of awareness I possess about what the heck I’m doing. Current progress indicates some developments in terms of plugin loading but at this point who knows anymore.Do not delete the vkDevice I beg...
|
1792659273.8753834
|
1793264073.8753834
|
|
22029
|
Sentinel: Autonomous Exploration Rover by @Sriyan Sentinel: Autonomous Exploration Rover by @Sriyan | Stardance...
|
Sriyan
|
1
|
146.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-30T03:15:27Z", "hours": 146.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a robot controller and the code responding for it although I couldn’t finish the robot itself I feel like this Is worth the effort I put into it thanks, Sriyan", "repo": "https://github.com/BigestBrainestbozo/Sentinal-robot-website-and-code", "demo": ""}]...
|
[{"post_id": 75433, "ts": "202 [{"post_id": 75433, "ts": "2026-09-30T02:29:18Z", "hours": 20.4072, "text": "Devlog — Motor Control System Time: ~7 Hours I wasn’t able to finish building the physical robot, so this year I’ve been focusing more on the coding side of the project. During these 7 hours, I worked on the robot’s motor control system, including movement, motor power, direction, and stopping. I also spent time testing and debugging the code so that when I return to the physical robot, I’ll already have a stronger software foundation ready. Next I’m going to keep developing and improving the code this year, and eventually return to finishing and integrating it with the physical robot."}, {"post_id": 55358, "ts": "2026-08-27T04:21:04Z", "hours": 5.8667, "text": "––Devlog 17–– Continuing Sentinel’s Retrace System Today I continued working on Sentinel’s autonomous retrace system. The goal of this system is to give it a way to recover when autonomous navigation leads it into a bad situation. Instead of stopping, it will eventually be able to remember its recent route, retrace it, look for another path, and only return control to the user if autonomous recovery fails. Recording Autonomous Movement I continued connecting it’s existing autonomous navigation to the movement-history system. it can store recent movements using: rememberMovement ()"}, {"post_id": 54250, "ts": "2026-08-25T04:19:16Z", "hours": 14.075, "text": "––Devlog 16–– Testing Sentinel in the Real World Yesterday I focused on just testing it over obstacles I’ve spent a lot of recent sessions improving the autonomous navigation system, failsafe logic, sensor handling, mission statistics, and the beginning of the retrace system. Physical Testing I spent the session working with Sentinel’s real hardware and observing how the different systems behave outside of the Arduino IDE. I focused on: Motor movement Servo movement Ultrasonic sensor behavior Sensor positioning Current wiring Rover movement Existing manual controls Existing autonomous behavior"}, {"post_id": 52469, "ts": "2026-08-22T16:24:33Z", "hours": 4.9, "text": "––Devlog 15–– Remembering its Path Today I started working on a much more advanced recovery system for the rover. Until now, FAILSAFE has mainly been designed to stop the rover when autonomous navigation runs into a serious problem. I don’t want stopping to always be the rovers first and only solution. Instead, I want Sentinel to eventually remember where it came from, retrace part of its path, and search for another route. The New Recovery Idea The recovery system I’m building is designed to eventually work like this: Dead End? I v FAILSAFE I v Retrace Recent Path I v Scan Surroundings Again I v Try Another Route I v No Safe Route? I v Switch to Manual Mode"}, {"post_id": 51305, "ts": "2026-08-20T21:38:39Z", "hours": 5.5142, "text": "—Devlog 14— Making it more reliable today I continue improving the autonomous navigation system work better by making a better failsafe. Sensor Failures I improved sentinels ultrasonic sensor failure handling/ the rover now treats different situations respectively not just backing up when sensor failsafe now it will retrace its path and go a different way if there is no other way the rover will automatically switch to manual mode and your device will do a cool animation change in the schedule since school started I am trying hard to balance 6 hours of school and 5 hours of work each day, so now physical and catch up days are on weekends due to having no school."}, {"post_id": 45366, "ts": "2026-08-11T19:31:55Z", "hours": 4.9944, "text": "–Devlog 13– Finishing Sentinel’s Failsafe System Today I continued working on Sentinel’s autonomous safety system. The main goal was to make FAILSAFE more useful instead of having it simply stop the rover without explaining what happened."}, {"post_id": 44450, "ts": "2026-08-10T06:23:59Z", "hours": 13.1775, "text": "––Devlog 12–– Making Sentinel Safer Today I focused on improving autonomous navigation and making the rover safer when something goes maybe might go wrong. A lot of today’s work was about making sure Sentinel doesn’t just assume that every sensor reading is correct or that every direction is safe. Smarter Path Decisions I added a minimum turning clearance to the rover’s settings. Before this, Sentinel could scan both directions and simply choose whichever side had more space. For example: left: 8 cm right: 12 cm the right side has more space, but 12 cm still isn’t enough room to safely turn. Now it checks whether a direction actually has enough clearance before choosing it. If both directions are clear, it chooses the side with more room. If only one direction is clear, it chooses that direction. If neither direction is clear, it knows that it needs to try something else. gn"}, {"post_id": 43773, "ts": "2026-08-09T06:19:22Z", "hours": 7.4453, "text": "———––Devlog 11———— I made it to Colorado yeah Failsafe I decided to make the autonomous mode safer rather than faster. the purpose of the failsafe is if something is to ever go wrong it will know what to do. Smart Path Decision well you heard the title, well basically what I did is that it can tell the difference between: A clear path A path that is too close to an obstacle A failed sensor reading Both paths being blocked I also added a minimum turning distance so it doesn’t choose one side for being like 1 cm better than the other. Example: left: 11cm right 12cm"}, {"post_id": 42656, "ts": "2026-08-07T14:31:52Z", "hours": 5.2392, "text": "———––Devlog 10———— Improving Sentinel’s Brain And Hardware Today I finally did a hardware and software day I spent the digital part fixing my devlogs and coding the place holder awareness. Software Progress I continued working on the autonomous navigation system like: Tracking servo current position Improved logic for left, center, and right Remembering sensor readings Physical Work My solder wire is leaded im cooked I didnt like my solder work so I tried again but this time I watched a video and it said leaded is dangerous so yeah but I connected 1 wire cut in half\\ Important Info im going to colorado today for 10 days but 3 of them Im going to be in mountain so no work Thanks for following Project Sentinel!"}, {"post_id": 41798, "ts": "2026-08-06T06:53:25Z", "hours": 7.4844, "text": "———––Devlog 09———— Sentinel’s Software Gets Smarter Today I focused mainly on improving Sentinel’s software and project documentation . The rover is not physically ready for full testing yet, so I used the digital work session to organize the code, fix errors, add useful debugging features, and improve how I present the project. Software Progress I expanded Sentinel’s Arduino Mega code with several new systems: Manual and autonomous driving modes Emergency stop command Configurable rover settings Obstacle detection and stopping Reverse-and-turn behavior Servo-based left, center, and right scanning Mission statistics Current rover status reporting Structured communication messages TB6612 motor-driver control functions The autonomous system is designed to follow this sequence: Drive forward Detect an obstacle Stop Reverse Scan left, center, and right Compare the available paths Choose the clearer direction Turn Continue driving Mission Statistics I added a command that can report information such as: Mission runtime Number of obstacles detected Number of left turns Number of right turns Number of successful distance readings I also added a current-status command so I can check Sentinel’s mode, state, movement command, and latest sensor reading while debugging. 📡 Communication Protocol I standardized the messages Sentinel sends through the Serial Monitor. Examples include: MODE:MANUAL MODE:AUTONOMOUS STATE:DRIVING STATE:REVERSING STATE:SCANNING_LEFT CMD:FORWARD CMD:STOP DIST:32.4"}, {"post_id": 40925, "ts": "2026-08-04T19:19:32Z", "hours": 14.7436, "text": "———––Devlog 08———— Making The Navigation Brain Toda I focused on the software for Sentinel. instead of working on hardware all day I switch to digital to make the user interface easy and intuitive for everyone(me) to use without any brain power. What I coded I added code for : The stop distance before obstacles Sensor-reading interval duration for turning and reversing and movement speed changes I got these from looking at my robot vac believe it or not. Preparations I began preparing for the motors because i have to solder them to the Arduino and im a noob at it so i made self drving mode and manual mode with placeholders What I Learned those little disks roaming around houses are hard to code kudos to the engineers, but I think that I learned that sensor awarness is hard and that anyways, Thanks for listening to my thing and following my project."}, {"post_id": 39172, "ts": "2026-08-01T23:01:50Z", "hours": 10.3956, "text": "———––Devlog 07———— Sentinel’s Web Controller Is Fixed Today I fixed a major part of the website which was the mobile part not being able to work properly Desktop Controls On a computer, sentinel can be controlled using the keyboard. The main controls are (for now): W - Forward A - Left S - Backward D - Right Mobile Controls For phones, I designed a different interface, instead of trying to use small buttons to control I made a joystick . Device Detection The website automatically provides better control method depending on what device you are using. Thanks for following Project Sentinel ! We’re getting closer to actually driving this thing."}, {"post_id": 37934, "ts": "2026-07-30T23:16:10Z", "hours": 9.9833, "text": "—————— Devlog 06 —————— Building Sentinel’s Eyes & Control Center Over the past few days, I worked on both the physical rover and its control system. What I Finished I completed the custom mount for Sentinel’s ultrasonic sensors. The mount holds the sensors securely and prepares them to be mounted on the servo, allowing Sentinel to scan left, center, and right while navigating. Website Progress I also spent time building Sentinel’s web controller. So far I have created: 🖥️ Desktop version Mobile version Both versions are coming together nicely. The only problem is that the mobile version isn’t displaying correctly on my phone yet, so I’ll show it off in the next devlog after I fix it. What I Learned This project is becoming much bigger than just building a rover. I’m now working on: CAD 3D printing Web development C++ Electronics Hardware integration It’s exciting seeing all of these skills come together in one project. Next Mission Fix the mobile website layout Finish the web controller Mount the ultrasonic sensor onto the servo Continue building Sentinel’s autonomous navigation system Thanks for following Project Sentinel ! Every update gets me one step closer to bringing Sentinel to life."}, {"post_id": 36717, "ts": "2026-07-28T23:13:11Z", "hours": 4.4978, "text": "———––Devlog 05———— Learning CAD - Day 2 Today I continued learning CAD so I eventually design custom parts for Sentinel . What I Learned Its hard. also refined my skills and made some medium difficulty items. Thanks for following Project Sentinel!"}, {"post_id": 36078, "ts": "2026-07-27T22:48:14Z", "hours": 11.8211, "text": "———––Devlog 04———— Learning CAD After being away for a while, I finally made it home! Now that I access to all my hardware again, I decided to make a mount for my servo and sensor and for the battery. Why I’m Learning CAD The rover needs some mount for: Ultrasonic Sensor Servo Battery Other electronics What I’m Working On My first goal is to design a bracket that can mount the ultrasonic sensor on top of the servo. That setup will allow Sentinel to: Look left Look forward Look right Compare distances Choose the best path What I’m Learning This is my first time trying a 3d modeling software, so Im going to start off with the basics. Target for tomorrow Make simple 3d shapes Build a servo mount Maybe print Thanks for following Project Sentinel!"}, {"post_id": 33733, "ts": "2026-07-23T21:42:37Z", "hours": 4.36, "text": "———––Devlog 03———— Information It’s definitely been longer than I planned since my last update . I was on vacation for a while, and I honestly lost more time than I wanted to. Instead of letting that stop the project, I decided to get back on track by focusing on something that will help Sentinel in the long run: learning C++ . What I’ve Been Doing While I haven’t been home to work on the hardware, I’ve been spending my time learning the fundamentals of C++. Some of the topics I’ve been working through includes: Variables Loops Functions Enums Classes General programming concepts I’ve attached a few screenshots showing what I’ve been learning. The Plan Since I lost some time during vacay, I going to have to do 4 hours and 32 minutes a day until I reach my goal. It won’t be easy, but I know it’ll be worth it when Sentinel finally comes together. Progress Even though there hasn’t been much hardware progress yet, I believe learning C++ now will save me a lot of time later because I’ll be writing and understanding my own rover software instead of relying on tutorials. Next Mission Continue learning C++ Return home Start assembling Sentinel Begin writing the rover’s software Thanks for following Project Sentinel. The build will finally start picking up speed soon!"}, {"post_id": 14189, "ts": "2026-06-23T05:44:45Z", "hours": 1.0669, "text": "———––Devlog 02———— Preparing For Sentinel Welcome back to another devlog! While I’m still waiting for the rest of Sentinel’s parts to arrive (they should be here by the end of June), I’ve decided to spend this time learning C++ . Instead of relying only on the Arduino examples and documentation, I want to understand how everything works so I can build different project by myself. Current Plan While waiting for the hardware, I’m focusing on learning: Variables Functions Loops Classes Enums General C++ programming My goal is to write as much of Sentinel’s software myself as possible instead of just copying code. Hardware Update As I said before Most of the remaining parts are expected to arrive near the end of June . Once everything arrives, I’ll be able to start assembling the rover and putting everything I’ve learned into practice. Target For Tomorrow -Continue learning C++ Wait for the remaining hardware Begin assembling Sentinel when the parts arrive Thanks so much for following Project Sentinel! Every bit of support motivates me to keep improving."}, {"post_id": 14046, "ts": "2026-06-23T00:51:47Z", "hours": 0.3708, "text": "———––Devlog 01———— Giving Sentinel Its Eyes Today I connect the ultrasonic sensors that will act as the eyes of Sentinel What I Added Ultrasonic distance sensors Front-facing sensor layout Very basic obstacle detection software Why Ultrasonic Sensors? I considered using cameras, but they were outside my budget and would have made the project more complicated. Target for tomorrow Test distance readings Connect the sensor to the Arduino Mega Start obstacle-avoidance log"}]...
|
Title: Sentinel: Autonomous Exploration Rover by @ Title: Sentinel: Autonomous Exploration Rover by @Sriyan | Stardance
Devlogs:
———––Devlog 01———— Giving Sentinel Its Eyes Today I connect the ultrasonic sensors that will act as the eyes of Sentinel What I Added Ultrasonic distance sensors Front-facing sensor layout Very basic obstacle detection software Why Ultrasonic Sensors? I considered using cameras, but they were outside my budget and would have made the project more complicated. Target for tomorrow Test distance readings Connect the sensor to the Arduino Mega Start obstacle-avoidance log
———––Devlog 02———— Preparing For Sentinel Welcome back to another devlog! While I’m still waiting for the rest of Sentinel’s parts to arrive (they should be here by the end of June), I’ve decided to spend this time learning C++ . Instead of relying only on the Arduino examples and documentation, I want to understand how everything works so I can build different project by myself. Current Plan While waiting for the hardware, I’m focusing on learning: Variables Functions Loops Classes Enums General C++ programming My goal is to write as much of Sentinel’s software myself as possible instead of just copying code. Hardware Update As I said before Most of the remaining parts are expected to arrive near the end of June . Once everything arrives, I’ll be able to start assembling the rover and putting everything I’ve learned into practice. Target For Tomorrow -Continue learning C++ Wait for the remaining hardware Begin assembling Sentinel when the parts arrive Thanks so much for following Project Sentinel! Every bit of support motivates me to keep improving.
———––Devlog 03———— Information It’s definitely been longer than I planned since my last update . I was on vacation for a while, and I honestly lost more time than I wanted to. Instead of letting that stop the project, I decided to get back on track by focusing on something that will help Sentinel in the long run: learning C++ . What I’ve Been Doing While I haven’t been home to work on the hardware, I’ve been spending my time learning the fundamentals of C++. Some of the topics I’ve been working through includes: Variables Loops Functions Enums Classes General programming concepts I’ve attached a few screenshots showing what I’ve been learning. The Plan Since I lost some time during vacay, I going to have to do 4 hours and 32 minutes a day until I reach my goal. It won’t be easy, but I know it’ll be worth it when Sentinel finally comes together. Progress Even though there hasn’t been much hardware progress yet, I believe learning C++ now will save me a lot of time later because I’ll be writing and understanding my own rover software instead of relying on tutorials. Next Mission Continue learning C++ Return home Start assembling Sentinel Begin writing the rover’s software Thanks for following Project Sentinel. The build will finally start picking up speed soon!
———––Devlog 04———— Learning CAD After being away for a while, I finally made it home! Now that I access to all my hardware again, I decided to make a mount for my servo and sensor and for the battery. Why I’m Learning CAD The rover needs some mount for: Ultrasonic Sensor Servo Battery Other electronics What I’m Working On My first goal is to design a bracket that can mount the ultrasonic sensor on top of the servo. That setup will allow Sentinel to: Look left Look forward Look right Compare distances Choose the best path What I’m Learning This is my first time trying a 3d modeling software, so Im going to start off with the basics. Target for tomorrow Make simple 3d shapes Build a servo mount Maybe print Thanks for following Project Sentinel!
———––Devlog 05———— Learning CAD - Day 2 Today I continued learning CAD so I eventually design custom parts for Sentinel . What I Learned Its hard. also refined my skills and made some medium difficulty items. Thanks for following Project Sentinel!
—————— Devlog 06 —————— Building Sentinel’s Eyes & Control Center Over the past few days, I worked on both the physical rover and its control system. What I Finished I completed the custom mount for Sentinel’s ultrasonic sensors. The mount holds the sensors securely and prepares them to be mounted on the servo, allowing Sentinel to scan left, center, and right while navigating. Website Progress I also spent time building Sentinel’s web controller. So far I have created: 🖥️ Desktop version Mobile version Both versions are coming together nicely. The only problem is that the mobile version isn’t displaying correctly on my phone yet, so I’ll show it off in the next devlog after I fix it. What I Learned This project is becoming much bigger than just building a rover. I’m now working on: CAD 3D printing Web development C++ Electronics Hardware integration It’s exciting seeing all of these skills come together in one project. Next Mission Fix the mobile website layout Finish the web controller Mount the ultrasonic sensor onto the servo Continue building Sentinel’s autonomous navigation system Thanks for following Project Sentinel ! Every update gets me one step closer to bringing Sentinel to life.
———––Devlog 07———— Sentinel’s Web Controller Is Fixed Today I fixed a major part of the website which was the mobile part not being able to work properly Desktop Controls On a computer, sentinel can be controlled using the keyboard. The main controls are (for now): W - Forward A - Left S - Backward D - Right Mobile Controls For phones, I designed a different interface, instead of trying to use small buttons to control I made a joystick . Device Detection The website automatically provides better control method depending on what device you are using. Thanks for following Project Sentinel ! We’re getting closer to actually driving this thing.
———––Devlog 08———— Making The Navigation Brain Toda I focused on the software for Sentinel. instead of working on hardware all day I switch to digital to make the user interface easy and intuitive for everyone(me) to use without any brain power. What I coded I added code for : The stop distance before obstacles Sensor-reading interval duration for turning and reversing and movement speed changes I got these from looking at my robot vac believe it or not. Preparations I began preparing for the motors because i have to solder them to the Arduino and im a noob at it so i made self drving mode and manual mode with placeholders What I Learned those little disks roaming around houses are hard to code kudos to the engineers, but I think that I learned that sensor awarness is hard and that anyways, Thanks for listening to my thing and following my project.
———––Devlog 09———— Sentinel’s Software Gets Smarter Today I focused mainly on improving Sentinel’s software and project documentation . The rover is not physically ready for full testing yet, so I used the digital work session to organize the code, fix errors, add useful debugging features, and improve how I present the project. Software Progress I expanded Sentinel’s Arduino Mega code with several new systems: Manual and autonomous driving modes Emergency stop command Configurable rover settings Obstacle detection and stopping Reverse-and-turn behavior Servo-based left, center, and right scanning Mission statistics Current rover status reporting Structured communication messages TB6612 motor-driver control functions The autonomous system is designed to follow this sequence: Drive forward Detect an obstacle Stop Reverse Scan left, center, and right Compare the available paths Choose the clearer direction Turn Continue driving Mission Statistics I added a command that can report information such as: Mission runtime Number of obstacles detected Number of left turns Number of right turns Number of successful distance readings I also added a current-status command so I can check Sentinel’s mode, state, movement command, and latest sensor reading while debugging. 📡 Communication Protocol I standardized the messages Sentinel sends through the Serial Monitor. Examples include: MODE:MANUAL MODE:AUTONOMOUS STATE:DRIVING STATE:REVERSING STATE:SCANNING_LEFT CMD:FORWARD CMD:STOP DIST:32.4
———––Devlog 10———— Improving Sentinel’s Brain And Hardware Today I finally did a hardware and software day I spent the digital part fixing my devlogs and coding the place holder awareness. Software Progress I continued working on the autonomous navigation system like: Tracking servo current position Improved logic for left, center, and right Remembering sensor readings Physical Work My solder wire is leaded im cooked I didnt like my solder work so I tried again but this time I watched a video and it said leaded is dangerous so yeah but I connected 1 wire cut in half\ Important Info im going to colorado today for 10 days but 3 of them Im going to be in mountain so no work Thanks for following Project Sentinel!
———––Devlog 11———— I made it to Colorado yeah Failsafe I decided to make the autonomous mode safer rather than faster. the purpose of the failsafe is if something is to ever go wrong it will know what to do. Smart Path Decision well you heard the title, well basically what I did is that it can tell the difference between: A clear path A path that is too close to an obstacle A failed sensor reading Both paths being blocked I also added a minimum turning distance so it doesn’t choose one side for being like 1 cm better than the other. Example: left: 11cm right 12cm
––Devlog 12–– Making Sentinel Safer Today I focused on improving autonomous navigation and making the rover safer when something goes maybe might go wrong. A lot of today’s work was about making sure Sentinel doesn’t just assume that every sensor reading is correct or that every direction is safe. Smarter Path Decisions I added a minimum turning clearance to the rover’s settings. Before this, Sentinel could scan both directions and simply choose whichever side had more space. For example: left: 8 cm right: 12 cm the right side has more space, but 12 cm still isn’t enough room to safely turn. Now it checks whether a direction actually has enough clearance before choosing it. If both directions are clear, it chooses the side with more room. If only one direction is clear, it chooses that direction. If neither direction is clear, it knows that it needs to try something else. gn
–Devlog 13– Finishing Sentinel’s Failsafe System Today I continued working on Sentinel’s autonomous safety system. The main goal was to make FAILSAFE more useful instead of having it simply stop the rover without explaining what happened.
—Devlog 14— Making it more reliable today I continue improving the autonomous navigation system work better by making a better failsafe. Sensor Failures I improved sentinels ultrasonic sensor failure handling/ the rover now treats different situations respectively not just backing up when sensor failsafe now it will retrace its path and go a different way if there is no other way the rover will automatically switch to manual mode and your device will do a cool animation change in the schedule since school started I am trying hard to balance 6 hours of school and 5 hours of work each day, so now physical and catch up days are on weekends due to having no school.
––Devlog 15–– Remembering its Path Today I started working on a much more advanced recovery system for the rover. Until now, FAILSAFE has mainly been designed to stop the rover when autonomous navigation runs into a serious problem. I don’t want stopping to always be the rovers first and only solution. Instead, I want Sentinel to eventually remember where it came from, retrace part of its path, and search for another route. The New Recovery Idea The recovery system I’m building is designed to eventually work like this: Dead End? I v FAILSAFE I v Retrace Recent Path I v Scan Surroundings Again I v Try Another Route I v No Safe Route? I v Switch to Manual Mode
––Devlog 16–– Testing Sentinel in the Real World Yesterday I focused on just testing it over obstacles I’ve spent a lot of recent sessions improving the autonomous navigation system, failsafe logic, sensor handling, mission statistics, and the beginning of the retrace system. Physical Testing I spent the session working with Sentinel’s real hardware and observing how the different systems behave outside of the Arduino IDE. I focused on: Motor movement Servo movement Ultrasonic sensor behavior Sensor positioning Current wiring Rover movement Existing manual controls Existing autonomous behavior
––Devlog 17–– Continuing Sentinel’s Retrace System Today I continued working on Sentinel’s autonomous retrace system. The goal of this system is to give it a way to recover when autonomous navigation leads it into a bad situation. Instead of stopping, it will eventually be able to remember its recent route, retrace it, look for another path, and only return control to the user if autonomous recovery fails. Recording Autonomous Movement I continued connecting it’s existing autonomous navigation to the movement-history system. it can store recent movements using: rememberMovement ()
Devlog — Motor Control System Time: ~7 Hours I wasn’t able to finish building the physical robot, so this year I’ve been focusing more on the coding side of the project. During these 7 hours, I worked on the robot’s motor control system, including movement, motor power, direction, and stopping. I also spent time testing and debugging the code so that when I return to the physical robot, I’ll already have a stronger software foundation ready. Next I’m going to keep developing and improving the code this year, and eventually return to finishing and integrating it with the physical robot.
Ships:
I made a robot controller and the code responding for it although I couldn’t finish the robot itself I feel like this Is worth the effort I put into it thanks, Sriyan...
|
1793004716.1833975
|
1793091116.1833975
|
|
46459
|
APStudyCanvas by @derek_chen | Stardance
|
derek_chen
|
2
|
146.0
|
1942
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-25T17:25:39Z", "hours": 13.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "An extension for Canvas. This works for other schools too, not just mine. Thank you all for your feedback. To install and use, please visit https://github.com/SimpleLemon/APStudyCanvas/releases and install the latest release.", "repo": "https://github.com/SimpleLemon/APStudyCanvas", "demo": "https://youtu.be/wb6AkZ6M4Q8"}, {"ship_num": 2, "ts": "2026-09-17T01:01:11Z", "hours": 133.0, "multiplier": 15.46, "payout": 1942, "blessing": "neutral", "text": "APStudyCanvas’s first beta release improves Canvas by improving the dashboard, a much richer To-Do experience, improved grades and course cards, synchronized streak tracking, smoother motion, and the first Google Calendar integration through Nest.APStudy. This extension adds onto CanvasRefined which similarly started due to dislike of BetterCampus’s high extension costs. Please note that this is still an early stage of the extension and bugs/optimization issues will be present. If you see any, please don’t hesitate to include comments in your feedback! They are greatly appreciated. The image below is a preview of the extension popup.", "repo": "https://github.com/SimpleLemon/APStudyCanvas", "demo": "https://youtu.be/wb6AkZ6M4Q8"}]...
|
[{"post_id": 82711, "ts": "202 [{"post_id": 82711, "ts": "2026-10-25T17:22:50Z", "hours": 5.7994, "text": "So many new features have been released since my last devlog that I forgot which was when. So for this devlog, I’ll announce a new solar system inspired progress bar where each ring represents a class. Each class orbits around a golden egg."}, {"post_id": 71578, "ts": "2026-09-21T02:45:37Z", "hours": 0.3953, "text": "Release: Beta 0.6 Link"}, {"post_id": 71562, "ts": "2026-09-21T02:00:02Z", "hours": 2.6711, "text": "Added a new orbital progress “bar” option that you can move around in 3d. I’m really happy with how it turned out."}, {"post_id": 70943, "ts": "2026-09-20T02:41:38Z", "hours": 3.76, "text": "Genuinely spent 2 hours on improving this 😭 Any design suggestions? I went with a compact streak button in the same line as the To-Do List instead of a large section above it to give more screen space to the assignments list. The large center is an egg surrounded by fire (because the extension is built under Nest.APStudy. So nests –> eggs) The motivational message also has a fun easter egg: one exclamation mark is rare and two exclamation mark messages are ultra rare. Just something to look forward to everyday."}, {"post_id": 69421, "ts": "2026-09-17T00:57:48Z", "hours": 2.2194, "text": "Still doesn’t look quite there yet, but more design UI will go into this including graphs and previous assignment history and how it affects your overall course grade."}, {"post_id": 68251, "ts": "2026-09-14T19:43:05Z", "hours": 8.8794, "text": "Improvement on the design! What do we think? Better rainbow, better sidebar, better assignment details, better streak, better due list, etc."}, {"post_id": 66008, "ts": "2026-09-11T15:02:04Z", "hours": 7.2456, "text": "Working on moving the 4 pages (Grades, Planner, Notes, and Study) to the popup UI and making it look nice."}, {"post_id": 64480, "ts": "2026-09-08T22:10:08Z", "hours": 3.4811, "text": "Settings design update! Went with an ios settings design"}, {"post_id": 63946, "ts": "2026-09-08T01:05:50Z", "hours": 8.5072, "text": "Looking better now! Now time to get some features to actually work properly (ie the 4 extension added pages)"}, {"post_id": 63211, "ts": "2026-09-06T21:51:20Z", "hours": 11.9767, "text": "Mildly messed up the settings page :("}, {"post_id": 61898, "ts": "2026-09-05T02:12:56Z", "hours": 9.4814, "text": "Heavily touched up that todo section & card appearance. Still got lots of issues to work on.As for new features, I’m working on adding canvas search, grade analytics, dashboard notes, local themes, planner tasks, and a better sidebar.Given that this project was initially a fork of CanvasRefined (though it has diverged by a large amount), I’m working on adding the new features/bug fixes to this extension as well."}, {"post_id": 60335, "ts": "2026-09-02T16:49:27Z", "hours": 9.1958, "text": "AYYY its coming together! The cards are now loading properly, the settings actually controls stuff, and the rings are coming together. Though, I can’t seem to figure out how to hide courses without active assignments from the ring design. After I finish all the UI changes I can think of, I’ll go through and completely revamp the settings popup (it’s mad ugly right now)."}, {"post_id": 58999, "ts": "2026-08-31T16:04:32Z", "hours": 12.4089, "text": "I may have broken the todo list section… But I’m still working on it and improving the design. I going for a rainbow style layout with a 3 column toggle for assignments and announcements"}, {"post_id": 55680, "ts": "2026-08-27T17:22:38Z", "hours": 8.4667, "text": "Sidebar is still coming together, but we’re getting closer to a nice design now!"}, {"post_id": 54401, "ts": "2026-08-25T12:19:14Z", "hours": 12.7903, "text": "Still working on improving the sidebar, which is suprisingly difficult to make look good. As for the todo list bar, I’m hoping to make it more like a rainbow and the tasks list to be easier to read."}, {"post_id": 49880, "ts": "2026-08-18T20:38:13Z", "hours": 9.9878, "text": "I’m trying to create a design similar to this… Still a work in progress though My Canvas page now looks broken with my WIP design, which is not good :("}, {"post_id": 46904, "ts": "2026-08-14T13:27:52Z", "hours": 10.6172, "text": "Almost done with my big change!"}, {"post_id": 46153, "ts": "2026-08-13T05:12:48Z", "hours": 8.9219, "text": "Many changes coming soon! Update in the DevLog above!"}, {"post_id": 45847, "ts": "2026-08-12T16:00:24Z", "hours": 9.2033, "text": "I am starting a project by forking CanvasRefined and connecting it to Nest.APStudy.org (my productivity project), as well as adding new features to make it easier to use myself. Improvements: Rebranded the extension (whilst keeping previous creator credit). Replaced the old settings screen with the new Edit Canvas workspace and compact-to-expanded navigation (essentially redesigned the popup and settings UI with clearer categories, spacing, focus states, and reduced-motion support) Added settings search with keyboard shortcuts and accessible live status updates. Improved course-card editing with previews, custom names, codes, images, visibility controls, saving, and reset actions. Added a settings-migration runbook for moving data from CanvasRefined to APStudyCanvas. Move changes to come!"}]...
|
Title: APStudyCanvas by @derek_chen | Stardance
D Title: APStudyCanvas by @derek_chen | Stardance
Devlogs:
I am starting a project by forking CanvasRefined and connecting it to Nest.APStudy.org (my productivity project), as well as adding new features to make it easier to use myself. Improvements: Rebranded the extension (whilst keeping previous creator credit). Replaced the old settings screen with the new Edit Canvas workspace and compact-to-expanded navigation (essentially redesigned the popup and settings UI with clearer categories, spacing, focus states, and reduced-motion support) Added settings search with keyboard shortcuts and accessible live status updates. Improved course-card editing with previews, custom names, codes, images, visibility controls, saving, and reset actions. Added a settings-migration runbook for moving data from CanvasRefined to APStudyCanvas. Move changes to come!
Many changes coming soon! Update in the DevLog above!
Almost done with my big change!
I’m trying to create a design similar to this… Still a work in progress though My Canvas page now looks broken with my WIP design, which is not good :(
Still working on improving the sidebar, which is suprisingly difficult to make look good. As for the todo list bar, I’m hoping to make it more like a rainbow and the tasks list to be easier to read.
Sidebar is still coming together, but we’re getting closer to a nice design now!
I may have broken the todo list section… But I’m still working on it and improving the design. I going for a rainbow style layout with a 3 column toggle for assignments and announcements
AYYY its coming together! The cards are now loading properly, the settings actually controls stuff, and the rings are coming together. Though, I can’t seem to figure out how to hide courses without active assignments from the ring design. After I finish all the UI changes I can think of, I’ll go through and completely revamp the settings popup (it’s mad ugly right now).
Heavily touched up that todo section & card appearance. Still got lots of issues to work on.As for new features, I’m working on adding canvas search, grade analytics, dashboard notes, local themes, planner tasks, and a better sidebar.Given that this project was initially a fork of CanvasRefined (though it has diverged by a large amount), I’m working on adding the new features/bug fixes to this extension as well.
Mildly messed up the settings page :(
Looking better now! Now time to get some features to actually work properly (ie the 4 extension added pages)
Settings design update! Went with an ios settings design
Working on moving the 4 pages (Grades, Planner, Notes, and Study) to the popup UI and making it look nice.
Improvement on the design! What do we think? Better rainbow, better sidebar, better assignment details, better streak, better due list, etc.
Still doesn’t look quite there yet, but more design UI will go into this including graphs and previous assignment history and how it affects your overall course grade.
Genuinely spent 2 hours on improving this 😭 Any design suggestions? I went with a compact streak button in the same line as the To-Do List instead of a large section above it to give more screen space to the assignments list. The large center is an egg surrounded by fire (because the extension is built under Nest.APStudy. So nests –> eggs) The motivational message also has a fun easter egg: one exclamation mark is rare and two exclamation mark messages are ultra rare. Just something to look forward to everyday.
Added a new orbital progress “bar” option that you can move around in 3d. I’m really happy with how it turned out.
Release: Beta 0.6 Link
So many new features have been released since my last devlog that I forgot which was when. So for this devlog, I’ll announce a new solar system inspired progress bar where each ring represents a class. Each class orbits around a golden egg.
Ships:
APStudyCanvas’s first beta release improves Canvas by improving the dashboard, a much richer To-Do experience, improved grades and course cards, synchronized streak tracking, smoother motion, and the first Google Calendar integration through Nest.APStudy. This extension adds onto CanvasRefined which similarly started due to dislike of BetterCampus’s high extension costs. Please note that this is still an early stage of the extension and bugs/optimization issues will be present. If you see any, please don’t hesitate to include comments in your feedback! They are greatly appreciated. The image below is a preview of the extension popup.
An extension for Canvas. This works for other schools too, not just mine. Thank you all for your feedback. To install and use, please visit https://github.com/SimpleLemon/APStudyCanvas/releases and install the latest release....
|
1793004863.894945
|
1793091263.894945
|
|
5067
|
Nest.APStudy by @derek_chen | Stardance
|
derek_chen
|
4
|
145.97
|
1964
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-14T17:33:45Z", "hours": 49.0, "multiplier": 14.1, "payout": 682, "blessing": "neutral", "text": "Thank you all for the feedback from my first three ships. I have focused more on the codebase and bug fixes. All the bug/issues from my last ship are addressed now! Shoutout to the people who put their time to bug find :) To those who review this ship, please share any issues you had with the website, whether it be a broken link or something simply looking bad.", "repo": "https://github.com/SimpleLemon/nest.apstudy", "demo": "https://nest.apstudy.org"}, {"ship_num": 2, "ts": "2026-07-28T20:25:20Z", "hours": 38.0, "multiplier": 17.18, "payout": 642, "blessing": "neutral", "text": "Thank you all for the feedback from my first two ships. I have focused more on detailed devlogs and small bug fixes. This ship’s focus was on general UI/UX improvements as well as a new /focus section. To those who review my 3rd ship, please share any issues you had with the website, whether it be a broken link or something simply looking bad.", "repo": "https://github.com/SimpleLemon/nest.apstudy", "demo": "https://nest.apstudy.org"}, {"ship_num": 3, "ts": "2026-07-01T18:50:16Z", "hours": 24.0, "multiplier": 15.16, "payout": 360, "blessing": "neutral", "text": "With this ship, I have drastically updated the Notes editor from a simple single-user editor into a writing workspace with block tools, rich paste normalization, and advanced features such as a print pipeline and expanded keyboard shortcuts. Sharing features such as public links, per-user shares, and a read-only view; performance optimization; accessibility (WCAG 2.2) compliance; and very, very extensive testing. Other minor fixes and admin panel changes were also included. https://nest.apstudy.org/join Let me know what you think! Please feel free to leave any suggestions and let me know of any bugs you find :)", "repo": "https://github.com/SimpleLemon/nest.apstudy", "demo": "https://nest.apstudy.org"}, {"ship_num": 4, "ts": "2026-06-16T03:46:40Z", "hours": 16.0, "multiplier": 18.6, "payout": 280, "blessing": "neutral", "text": "An Academic Command Center From now on, your day starts in one place! Features: central dashboard, calendar, tasks, notes, files, and a chat system. Course planning section specifically for Emory University students. Students can save courses, track seats, and simulate their course schedule. Build YOUR workspace today! https://nest.apstudy.org/join -# It solves my problems & reduces my stress. Hopefully it’ll solve yours too :)", "repo": "https://github.com/SimpleLemon/nest.apstudy", "demo": "https://nest.apstudy.org"}]...
|
[{"post_id": 57811, "ts": "202 [{"post_id": 57811, "ts": "2026-08-30T03:26:44Z", "hours": 9.0933, "text": "The calendar is currently still off, but I’m almost done with a fix by utilizing timezones properly. The status of each class isn’t completely accurate right now, but it should come together soon!"}, {"post_id": 56596, "ts": "2026-08-28T12:37:29Z", "hours": 9.88, "text": "I’m working on improving the calendar UI and adding .ics share features. It’s a long process, but I’m almost there for production release. The goal is to allow for .ics calendar link creation for simulated courses."}, {"post_id": 47049, "ts": "2026-08-14T17:27:53Z", "hours": 6.72, "text": "I’m beginning an extension that pairs with Nest! I’ve started porting features over to the extension to modify my school’s Canvas page. The Stardance extension project is here: https://stardance.hackclub.com/projects/46459"}, {"post_id": 44444, "ts": "2026-08-10T06:16:00Z", "hours": 6.28, "text": "REFACTOR + BUG FIXES COMPLETE! After ~40 hours, I completed a large application-wide refactor, added collaborative note review tools, and focused heavily on reliability :) Bug Fixes Fixed calendar feed validation (you can no longer add random links) and syncing issues with read-only collaborative notes. Fixed duplicate cookie-consent dialogs and the privacy-details link (shout out to the ones who caught it in ship #3!). Fixed Nest Announcements rendering errors. Fixed chat messages failing after the first send, leaking between rooms, or appearing only after a refresh. Fixed file uploads, including CSRF handling, error responses, and cleanup after failed uploads. Fixed task priority, deadline, recurrence, and floating-menu interactions becoming unresponsive (it was pretty annoying). Fixed logout behavior (thank you to the one who caught this!) Added profile length validation (thank you to the one who caught this in Ship 3!) Improved GitHub authentication diagnostics and callback/session handling (again thanks to the one who caught it in ship 3!!). Improvements Split large chat, notes, calendar, dashboard, file, onboarding, and admin systems into focused modules and services so they can be tested and changed independently. Reworked chat synchronization to be more stable. Reduced duplicate chat, presence, notification, and database work. Consolidated templates and shared frontend styling into a more consistent design (yay!). Major Features Added inline comments to shared notes, including ‘anchored’ discussions, editing and deletion, review events, and suggestions. Added administrative calendar-feed health reporting so broken or unsafe subscriptions are easier to diagnose (for admins). **Major architectural refactor across 200+ files!! https://nest.apstudy.org/ Thanks for reading!"}, {"post_id": 43490, "ts": "2026-08-08T19:48:13Z", "hours": 10.2058, "text": "Refactor continues…."}, {"post_id": 41258, "ts": "2026-08-05T11:15:47Z", "hours": 6.9658, "text": "Should be done in 4-5 days :) This will fix the bugs a lot of Ship 3’s reviewers mentioned"}, {"post_id": 39683, "ts": "2026-08-02T20:21:26Z", "hours": 9.7067, "text": "Still working! I’ll drop a more detailed summary later."}, {"post_id": 38452, "ts": "2026-07-31T20:28:56Z", "hours": 8.7231, "text": "Began a heavy code refactor today. I’ll give a very detailed refactor summary after it is complete!"}, {"post_id": 36601, "ts": "2026-07-28T20:22:34Z", "hours": 9.0275, "text": "Bug Fixes Fixed dashboard loading-grid alignment. Improved calendar week rendering for events that span multiple days or time slots. Refined course availability tracking controls. Improved invite redirects and management flows. Improvements Expanded Focus Mode with playlist composer improvements, routine selection, playlist gestures, resizable music panels, and better playback feedback. Deferred optional Focus Mode runtimes to improve loading performance. Added support for keeping completed Focus sessions visible. Improved invite-management cards and settings presentation. Major Feature* (only for myself) Added a gated Echo Show dashboard at /derek/echo for my newly jailbroken Echo! See 1st image below :)"}, {"post_id": 33263, "ts": "2026-07-23T01:14:11Z", "hours": 9.9094, "text": "This past couple days, I added Focus Mode (still a work in progress), improved navigation, and polished the frontend foundation (still got many more hours to go). Bug Fixes Fixed calendar event-editor and hidden-control behavior. Improved toast notifications and error states across the application. Improved calendar, dashboard, and notes interactions. Improvements Refined settings themes and notification controls. Added a global workspace search to the command palette with links across courses, files, calendar, and user content. Added dashboard layout editing and improved agenda/calendar interactions. Major Features Added Focus Mode with timed sessions, session history, completion sound, music playlist support (so fire since it uses less memory than Spotify), multiple playlists, Spotify playback controls, and customizable player preferences. https://nest.apstudy.org/focus"}, {"post_id": 30819, "ts": "2026-07-18T19:01:19Z", "hours": 9.5517, "text": "This past week, I focused on improving the website’s core systems, UX, and reliability. Bug Fixes Notes dragging was restored on tablets and laptops → It works again! Fixed notes page-setup popovers and improved keyboard shortcuts. Repaired browser notification subscriptions and delivery errors. Fixed settings tab visibility and improved cookie-consent controls. Hardened CSRF handling with silent token refresh for long-lived pages. Improved admin status polling and directory search. Improvements Replaced generic loaders with page-specific loading skeletons. Polished the shell, dashboard spacing, and settings layout. Improved chat profiles, member panels, composer interactions, and media previews. Added secure chat media sharing, GIF support, and attachment storage. Improved tier badge placement and presentation across the app. Major Features Users can now receive unified browser notifications, configure delivery preferences, and get reminders for individual calendar events and task deadlines!"}, {"post_id": 25606, "ts": "2026-07-09T23:46:06Z", "hours": 9.2494, "text": "My Progress Summary This past week (since my last devlog), I started with a visual and privacy redesign. Bug Fixes Note image uploads didn’t work => They work now! Calendar Validation previously would accept broken links => Fixed now! File uploads didn’t work => I can upload now! Safari kept signing me out => No more! I also improved the admin controls and security and resilience of the backend, especially with CSFR refresh handling. The loading UX was refined into page-specific skeletons (it was so cool seeing it work for the first time), but it took a few tries. The big change: Major release for tiers and quotas so that users can’t spam uploads and tier system skeleton for later. This includes admin tier controls (yay for me) and pixel assets generated by ChatGPT’s latest model 5.6 Try it here: https://nest.apstudy.org/join"}, {"post_id": 20171, "ts": "2026-07-01T18:34:05Z", "hours": 8.6836, "text": "Major Changes w/ Notes Page/Editor 1. Notes & Folder Sharing Users can now share their notes and even folders with multiple notes files with other Nest users. Public links can be generated to give everyone (even non-users) view-only access. 2. Simplified the Editor Less empty space! Now your whole screen on your laptop is the editor 3. Printing & Formatting Fixes/Updates Clicking Cmd/Ctrl + P now prints the notes page properly with appropriate colors and sizing! This actually took so many hours. Who knew modifying how a page looks for printing took this much time :( Grammarly is now more compatible and less RAM-hungry. I also optimized the notes page to reduce RAM consumption when moving between documents & website pages. Pasting now formats AI and messy text. Copy and pasting from Nest to another website looks cleaner now too (no more extra new lines for no reason like those AI websites). 4. Speed & Accessibility Changes Went with a WCAG 2.2 accessibility friendliness: people navigating can now easily run stuff through their keyboard (which is easy to open/close) Faster loading with lazy-loaded images. 5. Soon to Come: Real-Time Editing + Editor Sharing Access Who knows, it may just be more optimized than Google Docs (with fewer features, of course). It will have logic to view other people’s cursor positions & email invitations with roles (viewing, suggesting, editing). And a 30-day version history timeline. Try it yourself! https://nest.apstudy.org/notes"}, {"post_id": 15360, "ts": "2026-06-24T23:37:30Z", "hours": 4.1522, "text": "Admin Analytics Page I’m getting users! But who knew making an analytics page was so complex? I’m literally using Google Analytics API, which means I’m not hardcoding JavaScript tracking. Rather, I’m outputting the data into an interactive UI. Fun fact: 72% of users are high schoolers! https://nest.apstudy.org"}, {"post_id": 13971, "ts": "2026-06-22T22:38:21Z", "hours": 7.2628, "text": "Notes Page Design + UI You always see Google Docs and be like, “That’s a simple UI.” 😭 Or at least that’s what I thought until I tried creating a notes UI similar to both Notion & Google Docs. The goal was to make a lighter, simpler docs page that I can share easily. While, unfortunately, there are no share features yet, the toolbar and hover features are slowly coming together! 😄 Give it a try and let me know what you think: https://nest.apstudy.org/notes"}, {"post_id": 11099, "ts": "2026-06-18T04:43:46Z", "hours": 1.5686, "text": "Improved Course Search UI Changes: More results show now More filters and more details in the saved json Faster pings Seats display on the course preview Features: Simulate Courses Track courses that aren’t in your simulated schedule Recieve Emails when a class opens up Add as many courses to tracking as you wish Unfortunately, this is still limited to only Emory University students because the course pulling takes a lot of time and effort. https://nest.apstudy.org/courses"}, {"post_id": 10781, "ts": "2026-06-17T18:09:38Z", "hours": 2.69, "text": "Backend + Sidebar Fixes There were a good few small UI bugs that hurt the user experience. I went through and fixed a bunch, especially the sidebar issue that has been there for weeks. (The admin button is completely backend and won’t show for any of the other users) https://nest.apstudy.org/dashboard"}, {"post_id": 9697, "ts": "2026-06-16T03:26:14Z", "hours": 3.9828, "text": "Admin Backend & Basic Frontend Updates! I have offically gotten to a stage where I can finally start promoting and having people become early users. Nest.APStudy is a web platform for student course planning and productivity, combining local Emory course data with user accounts, dashboards, calendars, tasks, notes, chat, file sharing, and related admin tools. User data is stored in VPS-hosted SQLite databases, with Appwrite handling authentication and file storage. I spent a few more hours working on the backend changes and setting myself up to be in a position to quickly find and repair bugs by connecting the hosting VPS to my admin portal securely. Take a look and let me know what you think! :)"}, {"post_id": 8289, "ts": "2026-06-13T19:42:50Z", "hours": 0.9914, "text": "Backend Updates Updated the /admin page and transferred my database away from Appwrite towards a locally hosted SQLite on my VPS. Please take a look at https://nest.apstudy.org All the features are looking really solid now!"}, {"post_id": 7751, "ts": "2026-06-12T23:01:22Z", "hours": 2.7614, "text": "Created landing page for my Productivity Web Platform Added hero image, animations, showcases of all the website features, etc. I added some avengers easter eggs if you can find them ;) As for the actual platform, it is currently not fully functioning because I hit the database limits on my GitHub education plan. I may be locally hosting the database soon. Check out the website at https://nest.apstudy.org and feel free to leave me any comments/suggestions/hate! I appreciate all feedback :)"}, {"post_id": 2252, "ts": "2026-06-04T17:22:02Z", "hours": 0.9125, "text": "Calendar Page Creation & Polish! https://nest.apstudy.org/calendar Weekly view: 7-column time grid starting with Sunday 24 hour scrollable view that auto-scrolls to 7:30 AM Stickied all-day row (if all-day events are present) for multi-day/all-day events! Monthly View: 6-week grids with leading and trailing days from the adjacent months (less visible) Multi-day events are shown as spanning bars with row packing Options to share calendar (lots of configuration), calendar visibility, previous/next, and easy toggle between weekly and monthly views."}, {"post_id": 1587, "ts": "2026-06-03T18:22:11Z", "hours": 7.4042, "text": "Nest.APStudy is my summer coding project that I started right before AP testing. Yeah, I know… great timing. But I couldn’t wait to start working! 7 APs got nothing on me! Let me enjoy coding and discover the wonderful digital world of cyber, hardware, software, and AI :) Soon to be up at https://nest.apstudy.org"}]...
|
Title: Nest.APStudy by @derek_chen | Stardance
De Title: Nest.APStudy by @derek_chen | Stardance
Devlogs:
Nest.APStudy is my summer coding project that I started right before AP testing. Yeah, I know… great timing. But I couldn’t wait to start working! 7 APs got nothing on me! Let me enjoy coding and discover the wonderful digital world of cyber, hardware, software, and AI :) Soon to be up at https://nest.apstudy.org
Calendar Page Creation & Polish! https://nest.apstudy.org/calendar Weekly view: 7-column time grid starting with Sunday 24 hour scrollable view that auto-scrolls to 7:30 AM Stickied all-day row (if all-day events are present) for multi-day/all-day events! Monthly View: 6-week grids with leading and trailing days from the adjacent months (less visible) Multi-day events are shown as spanning bars with row packing Options to share calendar (lots of configuration), calendar visibility, previous/next, and easy toggle between weekly and monthly views.
Created landing page for my Productivity Web Platform Added hero image, animations, showcases of all the website features, etc. I added some avengers easter eggs if you can find them ;) As for the actual platform, it is currently not fully functioning because I hit the database limits on my GitHub education plan. I may be locally hosting the database soon. Check out the website at https://nest.apstudy.org and feel free to leave me any comments/suggestions/hate! I appreciate all feedback :)
Backend Updates Updated the /admin page and transferred my database away from Appwrite towards a locally hosted SQLite on my VPS. Please take a look at https://nest.apstudy.org All the features are looking really solid now!
Admin Backend & Basic Frontend Updates! I have offically gotten to a stage where I can finally start promoting and having people become early users. Nest.APStudy is a web platform for student course planning and productivity, combining local Emory course data with user accounts, dashboards, calendars, tasks, notes, chat, file sharing, and related admin tools. User data is stored in VPS-hosted SQLite databases, with Appwrite handling authentication and file storage. I spent a few more hours working on the backend changes and setting myself up to be in a position to quickly find and repair bugs by connecting the hosting VPS to my admin portal securely. Take a look and let me know what you think! :)
Backend + Sidebar Fixes There were a good few small UI bugs that hurt the user experience. I went through and fixed a bunch, especially the sidebar issue that has been there for weeks. (The admin button is completely backend and won’t show for any of the other users) https://nest.apstudy.org/dashboard
Improved Course Search UI Changes: More results show now More filters and more details in the saved json Faster pings Seats display on the course preview Features: Simulate Courses Track courses that aren’t in your simulated schedule Recieve Emails when a class opens up Add as many courses to tracking as you wish Unfortunately, this is still limited to only Emory University students because the course pulling takes a lot of time and effort. https://nest.apstudy.org/courses
Notes Page Design + UI You always see Google Docs and be like, “That’s a simple UI.” 😭 Or at least that’s what I thought until I tried creating a notes UI similar to both Notion & Google Docs. The goal was to make a lighter, simpler docs page that I can share easily. While, unfortunately, there are no share features yet, the toolbar and hover features are slowly coming together! 😄 Give it a try and let me know what you think: https://nest.apstudy.org/notes
Admin Analytics Page I’m getting users! But who knew making an analytics page was so complex? I’m literally using Google Analytics API, which means I’m not hardcoding JavaScript tracking. Rather, I’m outputting the data into an interactive UI. Fun fact: 72% of users are high schoolers! https://nest.apstudy.org
Major Changes w/ Notes Page/Editor 1. Notes & Folder Sharing Users can now share their notes and even folders with multiple notes files with other Nest users. Public links can be generated to give everyone (even non-users) view-only access. 2. Simplified the Editor Less empty space! Now your whole screen on your laptop is the editor 3. Printing & Formatting Fixes/Updates Clicking Cmd/Ctrl + P now prints the notes page properly with appropriate colors and sizing! This actually took so many hours. Who knew modifying how a page looks for printing took this much time :( Grammarly is now more compatible and less RAM-hungry. I also optimized the notes page to reduce RAM consumption when moving between documents & website pages. Pasting now formats AI and messy text. Copy and pasting from Nest to another website looks cleaner now too (no more extra new lines for no reason like those AI websites). 4. Speed & Accessibility Changes Went with a WCAG 2.2 accessibility friendliness: people navigating can now easily run stuff through their keyboard (which is easy to open/close) Faster loading with lazy-loaded images. 5. Soon to Come: Real-Time Editing + Editor Sharing Access Who knows, it may just be more optimized than Google Docs (with fewer features, of course). It will have logic to view other people’s cursor positions & email invitations with roles (viewing, suggesting, editing). And a 30-day version history timeline. Try it yourself! https://nest.apstudy.org/notes
My Progress Summary This past week (since my last devlog), I started with a visual and privacy redesign. Bug Fixes Note image uploads didn’t work => They work now! Calendar Validation previously would accept broken links => Fixed now! File uploads didn’t work => I can upload now! Safari kept signing me out => No more! I also improved the admin controls and security and resilience of the backend, especially with CSFR refresh handling. The loading UX was refined into page-specific skeletons (it was so cool seeing it work for the first time), but it took a few tries. The big change: Major release for tiers and quotas so that users can’t spam uploads and tier system skeleton for later. This includes admin tier controls (yay for me) and pixel assets generated by ChatGPT’s latest model 5.6 Try it here: https://nest.apstudy.org/join
This past week, I focused on improving the website’s core systems, UX, and reliability. Bug Fixes Notes dragging was restored on tablets and laptops → It works again! Fixed notes page-setup popovers and improved keyboard shortcuts. Repaired browser notification subscriptions and delivery errors. Fixed settings tab visibility and improved cookie-consent controls. Hardened CSRF handling with silent token refresh for long-lived pages. Improved admin status polling and directory search. Improvements Replaced generic loaders with page-specific loading skeletons. Polished the shell, dashboard spacing, and settings layout. Improved chat profiles, member panels, composer interactions, and media previews. Added secure chat media sharing, GIF support, and attachment storage. Improved tier badge placement and presentation across the app. Major Features Users can now receive unified browser notifications, configure delivery preferences, and get reminders for individual calendar events and task deadlines!
This past couple days, I added Focus Mode (still a work in progress), improved navigation, and polished the frontend foundation (still got many more hours to go). Bug Fixes Fixed calendar event-editor and hidden-control behavior. Improved toast notifications and error states across the application. Improved calendar, dashboard, and notes interactions. Improvements Refined settings themes and notification controls. Added a global workspace search to the command palette with links across courses, files, calendar, and user content. Added dashboard layout editing and improved agenda/calendar interactions. Major Features Added Focus Mode with timed sessions, session history, completion sound, music playlist support (so fire since it uses less memory than Spotify), multiple playlists, Spotify playback controls, and customizable player preferences. https://nest.apstudy.org/focus
Bug Fixes Fixed dashboard loading-grid alignment. Improved calendar week rendering for events that span multiple days or time slots. Refined course availability tracking controls. Improved invite redirects and management flows. Improvements Expanded Focus Mode with playlist composer improvements, routine selection, playlist gestures, resizable music panels, and better playback feedback. Deferred optional Focus Mode runtimes to improve loading performance. Added support for keeping completed Focus sessions visible. Improved invite-management cards and settings presentation. Major Feature* (only for myself) Added a gated Echo Show dashboard at /derek/echo for my newly jailbroken Echo! See 1st image below :)
Began a heavy code refactor today. I’ll give a very detailed refactor summary after it is complete!
Still working! I’ll drop a more detailed summary later.
Should be done in 4-5 days :) This will fix the bugs a lot of Ship 3’s reviewers mentioned
Refactor continues….
REFACTOR + BUG FIXES COMPLETE! After ~40 hours, I completed a large application-wide refactor, added collaborative note review tools, and focused heavily on reliability :) Bug Fixes Fixed calendar feed validation (you can no longer add random links) and syncing issues with read-only collaborative notes. Fixed duplicate cookie-consent dialogs and the privacy-details link (shout out to the ones who caught it in ship #3!). Fixed Nest Announcements rendering errors. Fixed chat messages failing after the first send, leaking between rooms, or appearing only after a refresh. Fixed file uploads, including CSRF handling, error responses, and cleanup after failed uploads. Fixed task priority, deadline, recurrence, and floating-menu interactions becoming unresponsive (it was pretty annoying). Fixed logout behavior (thank you to the one who caught this!) Added profile length validation (thank you to the one who caught this in Ship 3!) Improved GitHub authentication diagnostics and callback/session handling (again thanks to the one who caught it in ship 3!!). Improvements Split large chat, notes, calendar, dashboard, file, onboarding, and admin systems into focused modules and services so they can be tested and changed independently. Reworked chat synchronization to be more stable. Reduced duplicate chat, presence, notification, and database work. Consolidated templates and shared frontend styling into a more consistent design (yay!). Major Features Added inline comments to shared notes, including ‘anchored’ discussions, editing and deletion, review events, and suggestions. Added administrative calendar-feed health reporting so broken or unsafe subscriptions are easier to diagnose (for admins). **Major architectural refactor across 200+ files!! https://nest.apstudy.org/ Thanks for reading!
I’m beginning an extension that pairs with Nest! I’ve started porting features over to the extension to modify my school’s Canvas page. The Stardance extension project is here: https://stardance.hackclub.com/projects/46459
I’m working on improving the calendar UI and adding .ics share features. It’s a long process, but I’m almost there for production release. The goal is to allow for .ics calendar link creation for simulated courses.
The calendar is currently still off, but I’m almost done with a fix by utilizing timezones properly. The status of each class isn’t completely accurate right now, but it should come together soon!
Ships:
An Academic Command Center From now on, your day starts in one place! Features: central dashboard, calendar, tasks, notes, files, and a chat system. Course planning section specifically for Emory University students. Students can save courses, track seats, and simulate their course schedule. Build YOUR workspace today! https://nest.apstudy.org/join -# It solves my problems & reduces my stress. Hopefully it’ll solve yours too :)
With this ship, I have drastically updated the Notes editor from a simple single-user editor into a writing workspace with block tools, rich paste normalization, and advanced features such as a print pipeline and expanded keyboard shortcuts. Sharing features such as public links, per-user shares, and a read-only view; performance optimization; accessibility (WCAG 2.2) compliance; and very, very extensive testing. Other minor fixes and admin panel changes were also included. https://nest.apstudy.org/join Let me know what you think! Please feel free to leave any suggestions and let me know of any bugs you find :)
Thank you all for the feedback from my first two ships. I have focused more on detailed devlogs and small bug fixes. This ship’s focus was on general UI/UX improvements as well as a new /focus section. To those who review my 3rd ship, please share any issues you had with the website, whether it be a broken link or something simply looking bad.
Thank you all for the feedback from my first three ships. I have focused more on the codebase and bug fixes. All the bug/issues from my last ship are addressed now! Shoutout to the people who put their time to bug find :) To those who review this ship, please share any issues you had with the website, whether it be a broken link or something simply looking bad....
|
1792983135.514184
|
1793069535.514184
|
|
46051
|
Tic-Tac-Cube by @EthanCubes | Stardance
|
EthanCubes
|
1
|
145.0
|
0
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-18T21:33:24Z", "hours": 145.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a tic-tac-cube game where you can rotate the board like a Rubik’s cube! It was made in C++ with Raylib without a game engine, and only uses 2 libraries, Raylib, and Nlohmann-JSON. I’m really proud of the way I coded the entire GUI, buttons, board, and bot. Features Tic-Tac-Toe game on a Rubik’s cube Singleplayer mode against computer Local multiplayer against another player (or yourself) Main menu & help page. I coded the bot to be somewhat intelligent, and will actively try to block your attacks and create it’s own ones. It can turn the cube just like you, and will rotate the cube to get out of a pickle. This is my first C++ project, and my first experience with languages that have to be compiled before running. It was honestly really fun to make. I put a LOT of effort into this game, over 140 hours.", "repo": "https://github.com/EthanCubes/tic-tac-cube", "demo": "https://ethancubes.itch.io/tic-tac-cube"}]...
|
[{"post_id": 80806, "ts": "202 [{"post_id": 80806, "ts": "2026-10-18T20:46:55Z", "hours": 0.6053, "text": "Final Devlog Before Ship I’m done stalling. Every time I’ve shipped a project for Stardance, I’ve stalled for like a week trying to make sure it’s good enough. This time, I’ve stalled for more than a month. I’ve even shipped 2 separate projects to different Hack Club events in the time that this project has technically been “good enough”. Essentially, I just worked on the README a bit more. I did manage to fix a few errors. For example, I had a few spelling and grammar errors. I also added a bit more detail to the readme."}, {"post_id": 77976, "ts": "2026-10-09T02:51:47Z", "hours": 1.4722, "text": "Devlog #38 (25c796f): the beans aren’t going to know what hit them (regarding my 145 hours waiting to be shipped) I made a couple of changes, such as improving the readme and disabling the exit button, greying it out and making so that it can’t be pressed. For context, the game can only run on the web, and the exit button just doesn’t do anything useful on the web. I also customized the itch.io page (which hasn’t been released yet but you can access it here via secret url). It looks kinda decent (i just copied the game’s color scheme)"}, {"post_id": 76564, "ts": "2026-10-03T23:45:12Z", "hours": 2.1303, "text": "Devlog #37 (8b55316): I made a web build for the game! I took a break from Stardance to make something for Out to C, and when I was making a C game with Raylib I discovered that it is extremely hard to make a downloadable executable run well on Windows or MacOS, because on Windows you have to include DLL files, and on MacOS it’s just harder to install Raylib. In the end, I ended up making a web build, and since I wasn’t so bad, I decided to make a web build for this. I used Emscripten, and using the em++ tool with the asyncify option, manage to get most of the game logic working, with only one small frame generation bug, which I fixed by changing this_thread::sleep for to something that is easier for the browser to render. I also made some other QoL changes so that the bot feels less stagnant, hopefully."}, {"post_id": 71599, "ts": "2026-09-21T03:57:04Z", "hours": 2.0317, "text": "Devlog #36 (fcc4f2f): I made the first gameplay change in a while, and also changed the theming a bit more. The gameplay changes I noticed that the game was getting a bit… repetitive, so I changed the bot to have an element of randomness when there are multiple spots that provide similar advantage. This took me a long time, because my code is spaghetti, and also because random in JavaScript is so much better than in C++ The visual changes I changed the theming of the game because I didn’t think the discord-esque style looked very good. Now, it’s changed to match the “Arch” theme on Monkeytype. I also changed the font to Roboto Mono since that’s what my configuration of Monkeytype uses. Stuff to do Compile this for Windows and Mac, put this on Itch.io. Ship the project"}, {"post_id": 70648, "ts": "2026-09-19T14:52:27Z", "hours": 0.4536, "text": "Devlog #35 (b48efd0): I fixed most of the font scaling issues, and also updated the README at bit (as always). I did this by loading the same font 3 times, once at 20 font size, once at 40, and once at 80. I changed the code to use a either the 20, 40, or 80 version of the font according to the font size to make the text look smoother."}, {"post_id": 69944, "ts": "2026-09-18T03:21:41Z", "hours": 2.6569, "text": "Devlog #34 (4eec49b): I changed the font! And also updated the README. Fonts in raylib are REALLY hard. Since I’m using multiple different font sizes, the scaling is really screwed up and blurry sometimes. When I was trying to add the custom font, I may or may not have… lagged out my computer and had to restart. as for the readme upgrade, i added instructions to play i also removed some semicolons. took me like half and hour"}, {"post_id": 67849, "ts": "2026-09-14T03:57:37Z", "hours": 1.2122, "text": "Devlog #33 (d16d3b8): This time was used for trying to make the project work for webassembly, which i have decided to abandon. Therefore, this time should probably be deflated to account for the lack of progress. I probably picked the worst language for compiling for the web, and next time I want to make a web version of anything, I’m going to use a game engine. This just did not work out, and was too much effort to save maybe ~2 seconds of time. I’m sorry that this will cause any reviewers to have to download the game to play it, and to compensate I will be attaching a link to a YouTube video demoing the game either on the readme, on the itch.io page, or both. I feel like a failure for this, but maybe it’s the right choice for my mental health and academic… idk is health also the right word for this situation?"}, {"post_id": 67685, "ts": "2026-09-13T21:11:46Z", "hours": 2.8528, "text": "Devlog #32 (ca5f14e): I changed the theming yet again. I’m not really good at making programs look good, and even when I do, my designs are usually really basic. Yes, it’s inspired by discord. Please tell me how this looks in the comments, I really need feedback. I also finally added a little change in color to some of the buttons when selected, which was the entire reason I decided to rework buttons in the first place. I’ll also attach a beta design that’s more of a retro/terminal aesthetic, but contrasted too much with the cube and letters IMO"}, {"post_id": 66298, "ts": "2026-09-12T01:53:47Z", "hours": 1.1728, "text": "Devlog #31 (6639676): I fixed the code! Essentially, the code was breaking because the hover info for the code was undefined. I fixed it by setting the hover info to the regular button info if the hover info was not defined. Then I ran into another issue, which was that the buttons, upon hover, were being drawn from the center instead of the corner. It was a simple enough fix, I just changed like 2 values to use the calibrated values instead of the center coordinates. And yeah, the only real issue right now is that the text on the board is slightly offcentre, but that’s not really a big issue."}, {"post_id": 65739, "ts": "2026-09-11T02:41:43Z", "hours": 7.9714, "text": "Devlog #30 (b5f8085): The code is now compiling again, thanks to, as much as I hate to admit it, Visual Studio Code. I’m on Linux so I can’t use Visual Studio, CLion is kinda weird and the error messages are broken, and KDevelop doesn’t have a Wakatime/Hackatime plugin yet (maybe it does, but it isn’t in the Hackatime docs) I opened VSCode and was met with like a hundred errors. With a combination of VSCode’s functional error messages, DeepSeek telling me what those messages mean, and my pretty average brain, I managed to remove all the errors. But since I didn’t know how to use makefiles and stuff (still don’t ) I had to compile the program manually again. Apart from the fact that it crashes upon any user mouse input, it’s functional!"}, {"post_id": 63870, "ts": "2026-09-07T21:22:41Z", "hours": 0.4178, "text": "Devlog #29 (57bac36): Guess what I did: a: Made my code work again b: Add new features c: Complete the button rice d: Look up the GitHub Repo for DeepSeek because I got bored and discover how to add badges to my README. I had way to much fun doing this (it was d)"}, {"post_id": 63786, "ts": "2026-09-07T19:01:29Z", "hours": 9.4011, "text": "Devlog #28 (ac77900): I added an entire separate .cpp file for handling buttons because I wasn’t satisfied with how they were working (I love ricing). Yes, it did take 9 hours. I have a skill issue. There are 3 main things I improved on: The buttons are now more customizable, as they now accept JSON files as setup input instead of like only 4 parameters. A function was added to change the button upon hover It’s more organized since the files are separate. (I haven’t actually tested the code out yet, I feel pressured to get the devlog out ASAP)"}, {"post_id": 60009, "ts": "2026-09-02T03:12:55Z", "hours": 1.3197, "text": "Devlog #27 (a1b005f): I highkey have trouble keeping track of what I did between devlogs sometimes, so I’m adding the SHA of the Git commit to devlogs. So I tried to create a dedicated c++ file for handling buttons, since I wanted to have even more control over them, but ran into the issue of not having a way to share variables across different files. I know global variables are kinda bad, but I mean in this scenario they’re like config stuff that isn’t really going to be that harmful… Most of the time was spent creating the button.cpp and button.h files, and they’re not even in GitHub yet lol"}, {"post_id": 59291, "ts": "2026-09-01T00:20:03Z", "hours": 0.7611, "text": "Devlog #26: Pretty short devlog. I added some simple QoL changes: the main menu title is now centered, and the popup and some captions now have a margin around them so they aren’t stuck right on the edge. Also this was technically done a couple of devlogs ago, but I added shell scripts to compile and run the program so I don’t have to type g++ -std=c++17 -Wall -Wextra -Werror -pedantic -o build/tic-tac-cube src/main.cpp src/board.cpp src/bot.cpp src/logs.cpp -lraylib every single time I want to compile the program."}, {"post_id": 58538, "ts": "2026-08-30T23:41:22Z", "hours": 7.5928, "text": "Devlog #25: I tried to make the UI look good. It isn’t necessarily good, but it’s better than it used to be IMO. I just changed the color scheme, and now the text is round and the boxes are rounded. I also reworked the board position display system. Since the squares are just buttons, and the button class can display text, I just made the board display text by itself. For context I wrote the button class to draw and handle buttons. There might be a class for this or something but idc i just wrote it myself like 17 days ago."}, {"post_id": 57061, "ts": "2026-08-29T04:32:35Z", "hours": 7.4608, "text": "(How is it) Devlog #24 (Already): Lowkey, when I started this project I was expecting to take 1 week max, and it was supposed to be like practice for making a more advanced project. I’ve since decided to not make the more advanced project (for now). Now, it’s been more than 2 weeks since I’ve started it, and it’s still in rough shape and probably not ready for release. The UI still sucks, but I added like a popup system for displaying messages, such as telling the user why they won/lost without the win being visible due to the nature of the board being a cube. I was going to make a class to handle all the popups, but I settled for global variables and functions. Probably not the best practice, but it works, and if it ain’t broke don’t fix it. I also added a entire new menu, the help menu. It could probably use some improvements, so if you have anything you’re curious about or confused about, drop a comment. There’s like 8 people that have seen this project, so I’m really expecting anything, but it would be appreciated greatly. I lowkey forgot to add one break statement, so I spent like 30 minutes trying to figure out why it wasn’t working Still, how the hell did this take 7 hours? I swear I’m not inflating my time by any means."}, {"post_id": 56171, "ts": "2026-08-27T20:08:34Z", "hours": 2.4689, "text": "Devlog #23: “Minor” improvements that take like hours to do is literally my entire C++ learning experience so far. This time, I improved the “wild card” function that rotates the cube randomly. Before, it just actually rotated randomly, and now, I changed it to check and make sure that moves it makes does not cause the opponent to win on the very next move. fyi i DO write these devlogs myself without ai, I just literally need Vim keybinds to function as a person and therefore type all the devlogs inside of NeoVim before pasting them into the devlog. felt like writing this after i discovered that the “please write this yourself, humans read it” text at the bottom actually flashes red when you paste text."}, {"post_id": 55363, "ts": "2026-08-27T04:29:07Z", "hours": 3.4486, "text": "Devlog #22: I made the buttons look nicer by centering the text inside of them. It was much harder than it looked and I had to work with “Vector2” in Raylib. I may or may not have spent like half and hour trying to find documentation on it, only for me to discover that it’s a struct inside of Raylib. Still not entirely sure what a struct is. So I may or may not have spent another half and hour trying to declare the struct inside of the main.cpp file, before I finally gave up and asked DeepSeek. Turns out, it’s just Vector2 something{(float)x, (float)y} . It’s not exactly simple if you don’t have much experience with C++, but I started coding in C++ 16 days ago and I understand it just fine. Halfway through, while testing, I accidentally overrode the main file and had to restore it and re-add all the changes I make. I don’t like committing before the program doesn’t have that many bugs, so a lot of progress was lost. This is like the second time I’ve done this, and if you’re curious what I did, well… The command used to compile my program for testing is g++ -std=c++17 -o build/program src/main.cpp src/board.cpp src/bot.cpp src/logs.cpp -lrayib . This compiles the code for all the C++ files and the Raylib library, and creates and executable inside the build/ directory. Except I forgot to type build/program, and so GCC just overrode main.cpp. Honestly though, it didn’t do that much harm, thanks to the test.cpp file having a similar version of code as the code that was overridden, and also git. hackatime isn’t working so i can’t even post this devlog nvm it just worked nvm it broke again honestly this is one of the first times anything has broken in my experience as someone who joined hack club like 3 months ago. im sure everyone involved in fixing this is trying their absolute best."}, {"post_id": 55210, "ts": "2026-08-26T19:20:18Z", "hours": 2.4914, "text": "Devlog #21: I am very very very very bad at debugging code. Somehow I managed to fix the major rendering bug and also make the fork handling better within 2 hours. I don’t believe I’ve mentioned anything about it before, but there was a rendering glitch upon the bot winning the game right after the user has made a cube turn that allowed the bot to win the game. I’m still not sure wy that happened, but I fixed it by re-rendering the entire board before drawing the board position again. If that didn’t make sense to you, it doesn’t make much sense to me either. If it did, well good for you ig. I feel like the fork handling deserves and entire paragraph, so here: I changed the win blocking function to also log the direction that potential win is in, by logging “position 1” of that specific potential win. The possible neutralizing moves of the directional indicator value is then compared against the potential win location neutralizing move to try to find a match. If a match is found, that means that the move is guaranteed to neutralize the given threat. That paragraph did not make much sense, even to me. If you read my code, it’ll probably make more sense, as long as you do not get permanent brain damage from reading the it (I need to learn how to write better code)"}, {"post_id": 54902, "ts": "2026-08-26T03:54:05Z", "hours": 9.4122, "text": "Devlog #20: I abandoned searching for potential forks and stopping them from ever forming in favour of handling forks that have already been formed. After more than one win for the opponent is detected, the bot registers that it is a fork. It then calculates which moves are best to neutralize the threat. There are four ways for each single win to be neutralized, so I need to make one of these four moves, for each of the two cases. In some cases, one or more of the moves overlap, in which case the overlapped move will be immediately returned, but most of the time, the bot just picks from one of the 8 possible neutralization moves randomly. This is definitely less efficient than just figuring out how to prevent forks from ever forming, but I mean it’s a good implementation for the cube part of this game. (Sometimes it messes up and I just win instantly)"}, {"post_id": 54048, "ts": "2026-08-24T20:12:14Z", "hours": 5.1683, "text": "Devlog #19: In an effort to procrastinate fixing the bot fork bug while still doing something useful, I 1) took a 2 day break from this project to work (and ship) something else, and 2) fixed a very annoying bug where the user would be X every single time. I solved the issue by switching from older, more C-like rand() from cstdlib to the more modern #include <random> . I highkey copied the code from Stack Overflow , but at least it’s better than relying on AI. That solved like half of the problem, but then I discovered that I wasn’t actually resetting the board properly when manually exiting a game, since I was looking through the logs. I made the logs are procrastination, but they’re actually really nice. In case you were wondering btw, most of the time logged in this devlog was spent on trying to fix the fork bug, but I’ll make a dedicated devlog only when I’ve actually fixed the bug."}, {"post_id": 52065, "ts": "2026-08-22T03:58:57Z", "hours": 3.9525, "text": "Devlog #18: I worked on the logs even more, and now they are in separate files. You wouldn’t believe the amount of time this took me. Evidently, I’m not a very good C++ dev, and when I was searching on Stack Overflow and other sites, I kept running into things I don’t understand like & , auto , and probably many others. So of course, I resorted to coding my own functions at the most low level C++ possible without actually being totally backwards compatible with C. Essentially, every time the game starts, function runs that tries to generate a log file with the current time. There is a theoretically possible edge case where the user opens the project more than once in a single second, so I added some code to make absolute sure not to override any existing files. That took me like at least 15 minutes to half and hour, for an edge case that probably can only happen in testing, and that will not actually affect the game at all. Yay, what great decision making skills. I still haven’t fixed the fork detection and response function, but at least I can now have a way to find out what is going wrong. The only progress with finding out what is wrong is just narrowing the error location down to the function where I already knew there was going to be an error. Yay."}, {"post_id": 51891, "ts": "2026-08-21T19:50:23Z", "hours": 2.0631, "text": "Devlog #17: Guess what I did today: a) fixed the fork, b) optimized UI, c) hunted bugs, or d) added a random new c++ file for the sole purpose of logging information because I don’t want to use an IDE or configure NeoVim. The answer, of course, is D. I really need a way to figure out what is happening inside my code. Even though I wrote the code, it’s still kinda a black box to me, so I need to have some logs to figure out why the program is not working as expected. I have yet to actually implement the function or add out a way to have different logs files for different sessions though, I’m doing that next."}, {"post_id": 51427, "ts": "2026-08-21T03:58:41Z", "hours": 8.3636, "text": "Devlog #16: I added creating and defending against forks. One of my previous projects, Gomoku Balanced, had some decent defense and offense, which was even able to beat some people, according to the reviews on my ship. The one thing it was missing was the ability to detect potential forks and combat them, which was why I was able to beat it almost every single time. This bot, however, will not be the same. Mostly because the board is kinda small. I literally just added every single possibility of a fork to the to the bot. I just got notified that I have like 8 hours without a devlog, and since I am horrible at coding, the bot function I’m working on isn’t even working yet. I’m also just not getting it done within 2 hours. The function is supposed to block the fork, but it doesn’t work for some reason. DeepSeek (AI) gave me a list of 20 reasons it’s breaking, but I’m not about to blindly trust AI. I mean it doesn’t raise any errors, so that’s good. For me at least, I spend a lot of time just trying to get the code to compile properly. And in this case, even when the code compiles, half the time it just runs into a runtime error and crashes. The bot crashed like 20 times. They were all runtime errors, and I use C++, so I have absolutely no idea where the error occurs. Also, I want to be different, and therefore I use NeoVim, and since I don’t want to spend time that I could be building actually good projects for Stardance in the time it takes to configure NeoVim, and therefore I can’t see any warnings or errors. I did try using CLion and VSCode, but CLion takes up a lot of RAM and VSCode is made by Microsoft (and VSCodium and Code OSS don’t have that many plugins). Also, when I was using CLion, the errors didn’t really appear… and CLion also does a bunch of stuff and creates a bunch of mysterious files. I don’t really like doing stuff without knowing what they do, so I just ditched CLion altogether. Did I seriously go on a paragraph-long rant about how using NeoVim leads to not being able to know why my code sucks? Is the paragraph-long rant in question also probably longer than the entire rest of the devlog? (Yes and yes); Anyway you still can’t tell that I made any changes to the bot from a single screenshot, so I’m just going to attach one of my old ones."}, {"post_id": 50705, "ts": "2026-08-20T01:11:16Z", "hours": 2.1453, "text": "Devlog #15: I updated the bot to give it two of the most important features: winning the game, and trying to prevent your opponent from winning. This was done by saving every single possible way to have a two-in-a-row on the board, connected and disconnected, 24 possible combinations in total. And of course, because I’m not experienced enough to do it any other way, it was all written by hand. And since I don’t like using AI, and don’t really trust it, I wrote all of it myself, and used only used AI to check that I didn’t mess something up. Now how the hell do I make it detect forks…."}, {"post_id": 50618, "ts": "2026-08-19T20:57:50Z", "hours": 6.43, "text": "Devlog #14: In search of a better way to make a bot, I went on the world’s most reliable website: Wikipedia - and struck gold. The page on tic-tac-toe contains a strategy section, containing the optimal strategy that always leads to a draw. Of course, my game isn’t actually the same as Vanilla tic-tac-toe, so the player will probably still win most of the time. I haven’t actually implemented most of the rules, only the last few that are the least important. In my defense, they were the easiest to make. I did kinda struggle with the bot trying to mark a place that already has been placed, and it took like half and hour for me to figure that out. IDK what I should do for the screenshot, you can’t really tell that I changed anything."}, {"post_id": 49910, "ts": "2026-08-18T21:29:42Z", "hours": 6.7939, "text": "Devlog 13: I spent like 6 hours making the bot, and it’s absolutely stupid. I made two ways to get a move: scanning for 2-in-a-rows, and placing randomly. Even though the 2-in-a-row scan runs first, it still only plays randomly. As of right now, the bot has never won a single game against me and is always O for some reason. I probably messed up the setup code. but at least i made something that are somewhat functional….. (I was writing this devlog and trying to get a screenshot of the game, and somehow it actually worked and blocked my move somehow, IDK if it was a coincidence)"}, {"post_id": 49267, "ts": "2026-08-17T23:33:01Z", "hours": 2.055, "text": "Devlog #12: So I was going to implement the singleplayer mode, but turns out there was still a bunch of bugs and inconveniences that took me upwards of an hour to fix. Also, I lowkey put a break statement somewhere I shouldn’t have, and got the programming equivalent of a short-circuit. In the end, it did work fine, and now I actually will build the bot and singleplayer mode."}, {"post_id": 49122, "ts": "2026-08-17T19:10:00Z", "hours": 7.9347, "text": "Devlog #11: I was going to make a singleplayer mode for the game, but somewhere along the way I kinda messed my code up a lot, and had to undo nearly 6 hours of changes since the last devlog. I then spent like an hour fixing bugs and trying to organize code, mostly by moving code that could/should be reused. I’m going to start writing more functional code for singleplayer now :) Also I switched from Vim to NeoVim in case you care, and since not a lot of changes were actually implemented, Imma just attach a screenshot of a file opened in NVim"}, {"post_id": 48239, "ts": "2026-08-16T15:21:39Z", "hours": 1.3433, "text": "Devlog #10: I added an endscreen to the game. Before, when you won the game or lost the game, it would just go back to the main menu. Now, it displays a message according to which side won the game, and pauses for exactly one seconds before exiting back to the main menu. It probably still can be confusing since there’s no indication of where in the board the sequence that won the game is, and there is still a possibility that a cube rotation wins the game off the board, and I have no idea how to make more clear to the user what happened to win the game."}, {"post_id": 47846, "ts": "2026-08-16T02:15:52Z", "hours": 2.4331, "text": "Devlog #9: I added colors to the game. Colors are a crucial part in Rubik’s cubes, so it just makes sense to add it to this game, yknow. I basically just copied the code that rotates the board positions that I had to spend like 6 hours coding , and made it work with colors. Not actually that hard, but still almost made me go insane with how much mindless typing I had to do. It’s funny that when I am stuggling with things like using my brain and fixing broken code , I would like nothing more than some mindless coding, but now that I actually am doing this stuff, I am just wanting to do anything but. UI still looks ugly as hell, need to improve that later."}, {"post_id": 47741, "ts": "2026-08-15T21:13:06Z", "hours": 2.4297, "text": "Devlog 8: You can finally actually interact with the GUI. You can click the red squares to place an X or an O, or click on one of the white squares to rotate the cube. It’s kinda bad right now, and if you click one of the cube rotation things longer than 33 milliseconds, it will move several times. I mean, it’s good enough, I guess, apart from the fact that it looks… (I don’t know enough english to come up with a word that’s good enough, and my english grade in school is 95%)"}, {"post_id": 47618, "ts": "2026-08-15T16:56:17Z", "hours": 6.0747, "text": "Devlog #7: I got the GUI working for the game. I mean, technically, to be a GUI you have to be able to interact with it, and in it’s current state, uh you can’t really do anything and you’re just stuck there forever. I mean unless you decide to close the game window or press escape (which closes the game window). Ideally, I would like for the escape key to not close the window, but whatever at this stage it really does not matter. List of stuff I need to do: Make it so that the user can actually interact with the game. Make a bot or something Make the UI nicer Put in on Itch.io this actually looks kinda intimidating. what have i gotten myself in to"}, {"post_id": 46675, "ts": "2026-08-14T03:38:13Z", "hours": 4.9258, "text": "Devlog #6: I got a working GUI for the main menu! This is my first GUI that is actually like usable, but since the actual gameplay doesn’t have a GUI yet, it does nothing except closing when the exit button is pressed. I made the UI with Raylib, and apart from the occasional existential crisis, everything went pretty well. now how the hell do i make the actual game ui"}, {"post_id": 46051, "ts": "2026-08-12T23:59:49Z", "hours": 2.4667, "text": "Devlog #5: I added a main menu to the game. It’s still only Text UI, so it may not make sense why it took so long, but I moved all the functions inside a class, make a header file so that the class can be accessed in other C++ files, discovered that it doesn’t work, had an hour long conversation with deepseek about why this didn’t work, and finally got it working- just to implement one feature that would’ve taken like 5 minutes had I just made everything in one file. At least it’s going to be organized for when I add the GUI or other features."}, {"post_id": 45916, "ts": "2026-08-12T18:06:02Z", "hours": 3.4297, "text": "Devlog #4: You can now actually win the game! I wrote a function that scans all the possible ways to win on every face, with amounts to 6x8=48 possible combinations. So there’s a chance that you rotate a face of the cube, and win or lose instantly due to the face you rotated to already having like 2 in a row. Now, I just need to make the GUI, not sure how I’m even going to implement it. I know 2 of the options are Raylib and SDL2, but I honestly have no idea which one to pick."}, {"post_id": 44963, "ts": "2026-08-11T02:19:30Z", "hours": 3.5108, "text": "Devlog #3: I made the cube turning mechanic. Although I have made programs like this before (like my CubeTrainer ), I struggled a lot with making the code, especially the Z function, and the two functions that depend on it, L and R. This was entirely human error and typos though, and not really like intellectually challenging. So I added the ability to turn the cube finally. Most of the main features of the game are done now, I just need a GUI, main menu, bot, and… lowkey ran out of ideas so yeah. To be very honest, my experiences with GUIs in C++ is limited to drawing a single dot in sdl2, and that took me 3 hours to do. And I lowkey cannot find any tutorials on SDL2 that can satisfy my attention span. I am very much someone that learns by doing, and most SDL2 tutorials I found just tell me to copy and paste code word for word."}, {"post_id": 44443, "ts": "2026-08-10T06:12:06Z", "hours": 3.8533, "text": "Devlog #2: This is like my 3rd day of serious C++ coding, and I’ve already build a functional version of tic-tac-toe. That wasn’t really supposed to be impressive, but I am kinda surprised I managed to pull this off so quickly (by my standards, for context it took me like 3 year to make an actually decent Python project). So yeah, I made tic-tac-toe. So far it only works in the terminal as I have no idea how to make a functional GUI in C++. There are also safeguards in place to prevent placing where it’s already marked or out of bounds. I still need to implement rotating the cube, but that can’t be that hard…."}, {"post_id": 44282, "ts": "2026-08-09T22:49:28Z", "hours": 2.3694, "text": "Devlog #1: I suck at C++, so I decided to make tic-tac-toe on the different faces on a Rubik’s cube. Right now the program just prints out the default position (all blank), and you can’t change it or anything. Yes, this took me two hours. There were a lot of bugs and I have almost never used C++ before (I had to google how to output text like twice)"}]...
|
Title: Tic-Tac-Cube by @EthanCubes | Stardance
De Title: Tic-Tac-Cube by @EthanCubes | Stardance
Devlogs:
Devlog #1: I suck at C++, so I decided to make tic-tac-toe on the different faces on a Rubik’s cube. Right now the program just prints out the default position (all blank), and you can’t change it or anything. Yes, this took me two hours. There were a lot of bugs and I have almost never used C++ before (I had to google how to output text like twice)
Devlog #2: This is like my 3rd day of serious C++ coding, and I’ve already build a functional version of tic-tac-toe. That wasn’t really supposed to be impressive, but I am kinda surprised I managed to pull this off so quickly (by my standards, for context it took me like 3 year to make an actually decent Python project). So yeah, I made tic-tac-toe. So far it only works in the terminal as I have no idea how to make a functional GUI in C++. There are also safeguards in place to prevent placing where it’s already marked or out of bounds. I still need to implement rotating the cube, but that can’t be that hard….
Devlog #3: I made the cube turning mechanic. Although I have made programs like this before (like my CubeTrainer ), I struggled a lot with making the code, especially the Z function, and the two functions that depend on it, L and R. This was entirely human error and typos though, and not really like intellectually challenging. So I added the ability to turn the cube finally. Most of the main features of the game are done now, I just need a GUI, main menu, bot, and… lowkey ran out of ideas so yeah. To be very honest, my experiences with GUIs in C++ is limited to drawing a single dot in sdl2, and that took me 3 hours to do. And I lowkey cannot find any tutorials on SDL2 that can satisfy my attention span. I am very much someone that learns by doing, and most SDL2 tutorials I found just tell me to copy and paste code word for word.
Devlog #4: You can now actually win the game! I wrote a function that scans all the possible ways to win on every face, with amounts to 6x8=48 possible combinations. So there’s a chance that you rotate a face of the cube, and win or lose instantly due to the face you rotated to already having like 2 in a row. Now, I just need to make the GUI, not sure how I’m even going to implement it. I know 2 of the options are Raylib and SDL2, but I honestly have no idea which one to pick.
Devlog #5: I added a main menu to the game. It’s still only Text UI, so it may not make sense why it took so long, but I moved all the functions inside a class, make a header file so that the class can be accessed in other C++ files, discovered that it doesn’t work, had an hour long conversation with deepseek about why this didn’t work, and finally got it working- just to implement one feature that would’ve taken like 5 minutes had I just made everything in one file. At least it’s going to be organized for when I add the GUI or other features.
Devlog #6: I got a working GUI for the main menu! This is my first GUI that is actually like usable, but since the actual gameplay doesn’t have a GUI yet, it does nothing except closing when the exit button is pressed. I made the UI with Raylib, and apart from the occasional existential crisis, everything went pretty well. now how the hell do i make the actual game ui
Devlog #7: I got the GUI working for the game. I mean, technically, to be a GUI you have to be able to interact with it, and in it’s current state, uh you can’t really do anything and you’re just stuck there forever. I mean unless you decide to close the game window or press escape (which closes the game window). Ideally, I would like for the escape key to not close the window, but whatever at this stage it really does not matter. List of stuff I need to do: Make it so that the user can actually interact with the game. Make a bot or something Make the UI nicer Put in on Itch.io this actually looks kinda intimidating. what have i gotten myself in to
Devlog 8: You can finally actually interact with the GUI. You can click the red squares to place an X or an O, or click on one of the white squares to rotate the cube. It’s kinda bad right now, and if you click one of the cube rotation things longer than 33 milliseconds, it will move several times. I mean, it’s good enough, I guess, apart from the fact that it looks… (I don’t know enough english to come up with a word that’s good enough, and my english grade in school is 95%)
Devlog #9: I added colors to the game. Colors are a crucial part in Rubik’s cubes, so it just makes sense to add it to this game, yknow. I basically just copied the code that rotates the board positions that I had to spend like 6 hours coding , and made it work with colors. Not actually that hard, but still almost made me go insane with how much mindless typing I had to do. It’s funny that when I am stuggling with things like using my brain and fixing broken code , I would like nothing more than some mindless coding, but now that I actually am doing this stuff, I am just wanting to do anything but. UI still looks ugly as hell, need to improve that later.
Devlog #10: I added an endscreen to the game. Before, when you won the game or lost the game, it would just go back to the main menu. Now, it displays a message according to which side won the game, and pauses for exactly one seconds before exiting back to the main menu. It probably still can be confusing since there’s no indication of where in the board the sequence that won the game is, and there is still a possibility that a cube rotation wins the game off the board, and I have no idea how to make more clear to the user what happened to win the game.
Devlog #11: I was going to make a singleplayer mode for the game, but somewhere along the way I kinda messed my code up a lot, and had to undo nearly 6 hours of changes since the last devlog. I then spent like an hour fixing bugs and trying to organize code, mostly by moving code that could/should be reused. I’m going to start writing more functional code for singleplayer now :) Also I switched from Vim to NeoVim in case you care, and since not a lot of changes were actually implemented, Imma just attach a screenshot of a file opened in NVim
Devlog #12: So I was going to implement the singleplayer mode, but turns out there was still a bunch of bugs and inconveniences that took me upwards of an hour to fix. Also, I lowkey put a break statement somewhere I shouldn’t have, and got the programming equivalent of a short-circuit. In the end, it did work fine, and now I actually will build the bot and singleplayer mode.
Devlog 13: I spent like 6 hours making the bot, and it’s absolutely stupid. I made two ways to get a move: scanning for 2-in-a-rows, and placing randomly. Even though the 2-in-a-row scan runs first, it still only plays randomly. As of right now, the bot has never won a single game against me and is always O for some reason. I probably messed up the setup code. but at least i made something that are somewhat functional….. (I was writing this devlog and trying to get a screenshot of the game, and somehow it actually worked and blocked my move somehow, IDK if it was a coincidence)
Devlog #14: In search of a better way to make a bot, I went on the world’s most reliable website: Wikipedia - and struck gold. The page on tic-tac-toe contains a strategy section, containing the optimal strategy that always leads to a draw. Of course, my game isn’t actually the same as Vanilla tic-tac-toe, so the player will probably still win most of the time. I haven’t actually implemented most of the rules, only the last few that are the least important. In my defense, they were the easiest to make. I did kinda struggle with the bot trying to mark a place that already has been placed, and it took like half and hour for me to figure that out. IDK what I should do for the screenshot, you can’t really tell that I changed anything.
Devlog #15: I updated the bot to give it two of the most important features: winning the game, and trying to prevent your opponent from winning. This was done by saving every single possible way to have a two-in-a-row on the board, connected and disconnected, 24 possible combinations in total. And of course, because I’m not experienced enough to do it any other way, it was all written by hand. And since I don’t like using AI, and don’t really trust it, I wrote all of it myself, and used only used AI to check that I didn’t mess something up. Now how the hell do I make it detect forks….
Devlog #16: I added creating and defending against forks. One of my previous projects, Gomoku Balanced, had some decent defense and offense, which was even able to beat some people, according to the reviews on my ship. The one thing it was missing was the ability to detect potential forks and combat them, which was why I was able to beat it almost every single time. This bot, however, will not be the same. Mostly because the board is kinda small. I literally just added every single possibility of a fork to the to the bot. I just got notified that I have like 8 hours without a devlog, and since I am horrible at coding, the bot function I’m working on isn’t even working yet. I’m also just not getting it done within 2 hours. The function is supposed to block the fork, but it doesn’t work for some reason. DeepSeek (AI) gave me a list of 20 reasons it’s breaking, but I’m not about to blindly trust AI. I mean it doesn’t raise any errors, so that’s good. For me at least, I spend a lot of time just trying to get the code to compile properly. And in this case, even when the code compiles, half the time it just runs into a runtime error and crashes. The bot crashed like 20 times. They were all runtime errors, and I use C++, so I have absolutely no idea where the error occurs. Also, I want to be different, and therefore I use NeoVim, and since I don’t want to spend time that I could be building actually good projects for Stardance in the time it takes to configure NeoVim, and therefore I can’t see any warnings or errors. I did try using CLion and VSCode, but CLion takes up a lot of RAM and VSCode is made by Microsoft (and VSCodium and Code OSS don’t have that many plugins). Also, when I was using CLion, the errors didn’t really appear… and CLion also does a bunch of stuff and creates a bunch of mysterious files. I don’t really like doing stuff without knowing what they do, so I just ditched CLion altogether. Did I seriously go on a paragraph-long rant about how using NeoVim leads to not being able to know why my code sucks? Is the paragraph-long rant in question also probably longer than the entire rest of the devlog? (Yes and yes); Anyway you still can’t tell that I made any changes to the bot from a single screenshot, so I’m just going to attach one of my old ones.
Devlog #17: Guess what I did today: a) fixed the fork, b) optimized UI, c) hunted bugs, or d) added a random new c++ file for the sole purpose of logging information because I don’t want to use an IDE or configure NeoVim. The answer, of course, is D. I really need a way to figure out what is happening inside my code. Even though I wrote the code, it’s still kinda a black box to me, so I need to have some logs to figure out why the program is not working as expected. I have yet to actually implement the function or add out a way to have different logs files for different sessions though, I’m doing that next.
Devlog #18: I worked on the logs even more, and now they are in separate files. You wouldn’t believe the amount of time this took me. Evidently, I’m not a very good C++ dev, and when I was searching on Stack Overflow and other sites, I kept running into things I don’t understand like & , auto , and probably many others. So of course, I resorted to coding my own functions at the most low level C++ possible without actually being totally backwards compatible with C. Essentially, every time the game starts, function runs that tries to generate a log file with the current time. There is a theoretically possible edge case where the user opens the project more than once in a single second, so I added some code to make absolute sure not to override any existing files. That took me like at least 15 minutes to half and hour, for an edge case that probably can only happen in testing, and that will not actually affect the game at all. Yay, what great decision making skills. I still haven’t fixed the fork detection and response function, but at least I can now have a way to find out what is going wrong. The only progress with finding out what is wrong is just narrowing the error location down to the function where I already knew there was going to be an error. Yay.
Devlog #19: In an effort to procrastinate fixing the bot fork bug while still doing something useful, I 1) took a 2 day break from this project to work (and ship) something else, and 2) fixed a very annoying bug where the user would be X every single time. I solved the issue by switching from older, more C-like rand() from cstdlib to the more modern #include <random> . I highkey copied the code from Stack Overflow , but at least it’s better than relying on AI. That solved like half of the problem, but then I discovered that I wasn’t actually resetting the board properly when manually exiting a game, since I was looking through the logs. I made the logs are procrastination, but they’re actually really nice. In case you were wondering btw, most of the time logged in this devlog was spent on trying to fix the fork bug, but I’ll make a dedicated devlog only when I’ve actually fixed the bug.
Devlog #20: I abandoned searching for potential forks and stopping them from ever forming in favour of handling forks that have already been formed. After more than one win for the opponent is detected, the bot registers that it is a fork. It then calculates which moves are best to neutralize the threat. There are four ways for each single win to be neutralized, so I need to make one of these four moves, for each of the two cases. In some cases, one or more of the moves overlap, in which case the overlapped move will be immediately returned, but most of the time, the bot just picks from one of the 8 possible neutralization moves randomly. This is definitely less efficient than just figuring out how to prevent forks from ever forming, but I mean it’s a good implementation for the cube part of this game. (Sometimes it messes up and I just win instantly)
Devlog #21: I am very very very very bad at debugging code. Somehow I managed to fix the major rendering bug and also make the fork handling better within 2 hours. I don’t believe I’ve mentioned anything about it before, but there was a rendering glitch upon the bot winning the game right after the user has made a cube turn that allowed the bot to win the game. I’m still not sure wy that happened, but I fixed it by re-rendering the entire board before drawing the board position again. If that didn’t make sense to you, it doesn’t make much sense to me either. If it did, well good for you ig. I feel like the fork handling deserves and entire paragraph, so here: I changed the win blocking function to also log the direction that potential win is in, by logging “position 1” of that specific potential win. The possible neutralizing moves of the directional indicator value is then compared against the potential win location neutralizing move to try to find a match. If a match is found, that means that the move is guaranteed to neutralize the given threat. That paragraph did not make much sense, even to me. If you read my code, it’ll probably make more sense, as long as you do not get permanent brain damage from reading the it (I need to learn how to write better code)
Devlog #22: I made the buttons look nicer by centering the text inside of them. It was much harder than it looked and I had to work with “Vector2” in Raylib. I may or may not have spent like half and hour trying to find documentation on it, only for me to discover that it’s a struct inside of Raylib. Still not entirely sure what a struct is. So I may or may not have spent another half and hour trying to declare the struct inside of the main.cpp file, before I finally gave up and asked DeepSeek. Turns out, it’s just Vector2 something{(float)x, (float)y} . It’s not exactly simple if you don’t have much experience with C++, but I started coding in C++ 16 days ago and I understand it just fine. Halfway through, while testing, I accidentally overrode the main file and had to restore it and re-add all the changes I make. I don’t like committing before the program doesn’t have that many bugs, so a lot of progress was lost. This is like the second time I’ve done this, and if you’re curious what I did, well… The command used to compile my program for testing is g++ -std=c++17 -o build/program src/main.cpp src/board.cpp src/bot.cpp src/logs.cpp -lrayib . This compiles the code for all the C++ files and the Raylib library, and creates and executable inside the build/ directory. Except I forgot to type build/program, and so GCC just overrode main.cpp. Honestly though, it didn’t do that much harm, thanks to the test.cpp file having a similar version of code as the code that was overridden, and also git. hackatime isn’t working so i can’t even post this devlog nvm it just worked nvm it broke again honestly this is one of the first times anything has broken in my experience as someone who joined hack club like 3 months ago. im sure everyone involved in fixing this is trying their absolute best.
Devlog #23: “Minor” improvements that take like hours to do is literally my entire C++ learning experience so far. This time, I improved the “wild card” function that rotates the cube randomly. Before, it just actually rotated randomly, and now, I changed it to check and make sure that moves it makes does not cause the opponent to win on the very next move. fyi i DO write these devlogs myself without ai, I just literally need Vim keybinds to function as a person and therefore type all the devlogs inside of NeoVim before pasting them into the devlog. felt like writing this after i discovered that the “please write this yourself, humans read it” text at the bottom actually flashes red when you paste text.
(How is it) Devlog #24 (Already): Lowkey, when I started this project I was expecting to take 1 week max, and it was supposed to be like practice for making a more advanced project. I’ve since decided to not make the more advanced project (for now). Now, it’s been more than 2 weeks since I’ve started it, and it’s still in rough shape and probably not ready for release. The UI still sucks, but I added like a popup system for displaying messages, such as telling the user why they won/lost without the win being visible due to the nature of the board being a cube. I was going to make a class to handle all the popups, but I settled for global variables and functions. Probably not the best practice, but it works, and if it ain’t broke don’t fix it. I also added a entire new menu, the help menu. It could probably use some improvements, so if you have anything you’re curious about or confused about, drop a comment. There’s like 8 people that have seen this project, so I’m really expecting anything, but it would be appreciated greatly. I lowkey forgot to add one break statement, so I spent like 30 minutes trying to figure out why it wasn’t working Still, how the hell did this take 7 hours? I swear I’m not inflating my time by any means.
Devlog #25: I tried to make the UI look good. It isn’t necessarily good, but it’s better than it used to be IMO. I just changed the color scheme, and now the text is round and the boxes are rounded. I also reworked the board position display system. Since the squares are just buttons, and the button class can display text, I just made the board display text by itself. For context I wrote the button class to draw and handle buttons. There might be a class for this or something but idc i just wrote it myself like 17 days ago.
Devlog #26: Pretty short devlog. I added some simple QoL changes: the main menu title is now centered, and the popup and some captions now have a margin around them so they aren’t stuck right on the edge. Also this was technically done a couple of devlogs ago, but I added shell scripts to compile and run the program so I don’t have to type g++ -std=c++17 -Wall -Wextra -Werror -pedantic -o build/tic-tac-cube src/main.cpp src/board.cpp src/bot.cpp src/logs.cpp -lraylib every single time I want to compile the program.
Devlog #27 (a1b005f): I highkey have trouble keeping track of what I did between devlogs sometimes, so I’m adding the SHA of the Git commit to devlogs. So I tried to create a dedicated c++ file for handling buttons, since I wanted to have even more control over them, but ran into the issue of not having a way to share variables across different files. I know global variables are kinda bad, but I mean in this scenario they’re like config stuff that isn’t really going to be that harmful… Most of the time was spent creating the button.cpp and button.h files, and they’re not even in GitHub yet lol
Devlog #28 (ac77900): I added an entire separate .cpp file for handling buttons because I wasn’t satisfied with how they were working (I love ricing). Yes, it did take 9 hours. I have a skill issue. There are 3 main things I improved on: The buttons are now more customizable, as they now accept JSON files as setup input instead of like only 4 parameters. A function was added to change the button upon hover It’s more organized since the files are separate. (I haven’t actually tested the code out yet, I feel pressured to get the devlog out ASAP)
Devlog #29 (57bac36): Guess what I did: a: Made my code work again b: Add new features c: Complete the button rice d: Look up the GitHub Repo for DeepSeek because I got bored and discover how to add badges to my README. I had way to much fun doing this (it was d)
Devlog #30 (b5f8085): The code is now compiling again, thanks to, as much as I hate to admit it, Visual Studio Code. I’m on Linux so I can’t use Visual Studio, CLion is kinda weird and the error messages are broken, and KDevelop doesn’t have a Wakatime/Hackatime plugin yet (maybe it does, but it isn’t in the Hackatime docs) I opened VSCode and was met with like a hundred errors. With a combination of VSCode’s functional error messages, DeepSeek telling me what those messages mean, and my pretty average brain, I managed to remove all the errors. But since I didn’t know how to use makefiles and stuff (still don’t ) I had to compile the program manually again. Apart from the fact that it crashes upon any user mouse input, it’s functional!
Devlog #31 (6639676): I fixed the code! Essentially, the code was breaking because the hover info for the code was undefined. I fixed it by setting the hover info to the regular button info if the hover info was not defined. Then I ran into another issue, which was that the buttons, upon hover, were being drawn from the center instead of the corner. It was a simple enough fix, I just changed like 2 values to use the calibrated values instead of the center coordinates. And yeah, the only real issue right now is that the text on the board is slightly offcentre, but that’s not really a big issue.
Devlog #32 (ca5f14e): I changed the theming yet again. I’m not really good at making programs look good, and even when I do, my designs are usually really basic. Yes, it’s inspired by discord. Please tell me how this looks in the comments, I really need feedback. I also finally added a little change in color to some of the buttons when selected, which was the entire reason I decided to rework buttons in the first place. I’ll also attach a beta design that’s more of a retro/terminal aesthetic, but contrasted too much with the cube and letters IMO
Devlog #33 (d16d3b8): This time was used for trying to make the project work for webassembly, which i have decided to abandon. Therefore, this time should probably be deflated to account for the lack of progress. I probably picked the worst language for compiling for the web, and next time I want to make a web version of anything, I’m going to use a game engine. This just did not work out, and was too much effort to save maybe ~2 seconds of time. I’m sorry that this will cause any reviewers to have to download the game to play it, and to compensate I will be attaching a link to a YouTube video demoing the game either on the readme, on the itch.io page, or both. I feel like a failure for this, but maybe it’s the right choice for my mental health and academic… idk is health also the right word for this situation?
Devlog #34 (4eec49b): I changed the font! And also updated the README. Fonts in raylib are REALLY hard. Since I’m using multiple different font sizes, the scaling is really screwed up and blurry sometimes. When I was trying to add the custom font, I may or may not have… lagged out my computer and had to restart. as for the readme upgrade, i added instructions to play i also removed some semicolons. took me like half and hour
Devlog #35 (b48efd0): I fixed most of the font scaling issues, and also updated the README at bit (as always). I did this by loading the same font 3 times, once at 20 font size, once at 40, and once at 80. I changed the code to use a either the 20, 40, or 80 version of the font according to the font size to make the text look smoother.
Devlog #36 (fcc4f2f): I made the first gameplay change in a while, and also changed the theming a bit more. The gameplay changes I noticed that the game was getting a bit… repetitive, so I changed the bot to have an element of randomness when there are multiple spots that provide similar advantage. This took me a long time, because my code is spaghetti, and also because random in JavaScript is so much better than in C++ The visual changes I changed the theming of the game because I didn’t think the discord-esque style looked very good. Now, it’s changed to match the “Arch” theme on Monkeytype. I also changed the font to Roboto Mono since that’s what my configuration of Monkeytype uses. Stuff to do Compile this for Windows and Mac, put this on Itch.io. Ship the project
Devlog #37 (8b55316): I made a web build for the game! I took a break from Stardance to make something for Out to C, and when I was making a C game with Raylib I discovered that it is extremely hard to make a downloadable executable run well on Windows or MacOS, because on Windows you have to include DLL files, and on MacOS it’s just harder to install Raylib. In the end, I ended up making a web build, and since I wasn’t so bad, I decided to make a web build for this. I used Emscripten, and using the em++ tool with the asyncify option, manage to get most of the game logic working, with only one small frame generation bug, which I fixed by changing this_thread::sleep for to something that is easier for the browser to render. I also made some other QoL changes so that the bot feels less stagnant, hopefully.
Devlog #38 (25c796f): the beans aren’t going to know what hit them (regarding my 145 hours waiting to be shipped) I made a couple of changes, such as improving the readme and disabling the exit button, greying it out and making so that it can’t be pressed. For context, the game can only run on the web, and the exit button just doesn’t do anything useful on the web. I also customized the itch.io page (which hasn’t been released yet but you can access it here via secret url). It looks kinda decent (i just copied the game’s color scheme)
Final Devlog Before Ship I’m done stalling. Every time I’ve shipped a project for Stardance, I’ve stalled for like a week trying to make sure it’s good enough. This time, I’ve stalled for more than a month. I’ve even shipped 2 separate projects to different Hack Club events in the time that this project has technically been “good enough”. Essentially, I just worked on the README a bit more. I did manage to fix a few errors. For example, I had a few spelling and grammar errors. I also added a bit more detail to the readme.
Ships:
I made a tic-tac-cube game where you can rotate the board like a Rubik’s cube! It was made in C++ with Raylib without a game engine, and only uses 2 libraries, Raylib, and Nlohmann-JSON. I’m really proud of the way I coded the entire GUI, buttons, board, and bot. Features Tic-Tac-Toe game on a Rubik’s cube Singleplayer mode against computer Local multiplayer against another player (or yourself) Main menu & help page. I coded the bot to be somewhat intelligent, and will actively try to block your attacks and create it’s own ones. It can turn the cube just like you, and will rotate the cube to get out of a pickle. This is my first C++ project, and my first experience with languages that have to be compiled before running. It was honestly really fun to make. I put a LOT of effort into this game, over 140 hours....
|
1793047978.7932549
|
1793134378.7932549
|
|
53406
|
Iris by @Hamna | Stardance
|
Hamna
|
1
|
144.68
|
1521
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-18T22:02:27Z", "hours": 131.0, "multiplier": 13.36, "payout": 1521, "blessing": "neutral", "text": "This is my booking website for wellness (my family hotel). There’s a public site, online checkout, a Reception console and a Management console The most difficult part to stop double bookings btw the website and the front desk,I fixed this by making a hold time of 10 mints on suites I’m really so proud of this project as this was something I was planning to make for my family and it turned out to so amazing and I got to learn so much about security (P.S , This is my last project on Hackclub , I really had the cool experience here, This platform really motivated me to make this project)", "repo": "https://github.com/lilithCode/Iris_ChatBot", "demo": "https://iris-chat-bot-lac.vercel.app/"}]...
|
[{"post_id": 76064, "ts": "202 [{"post_id": 76064, "ts": "2026-10-02T07:21:18Z", "hours": 6.8922, "text": "Changed the UI a bit"}, {"post_id": 73916, "ts": "2026-09-26T09:52:32Z", "hours": 2.9411, "text": "There were some UI erros in the git pages file i made, so this is the last final verison for this project for the demo link: hope you’ll like this : )"}, {"post_id": 71239, "ts": "2026-09-20T14:41:31Z", "hours": 3.8447, "text": "Fixed it today! I replaced ChatInterface in the Space with a gr.Interface that takes the history as a JSON input, so the conversation actually reaches the model now. I also added a history count to the logs so I can see it arriving with every message. This fixes Amadeus too, since they share the same Space. Iris finally remembers what we’re talking about, and that feels like the right place to call this project complete"}, {"post_id": 70295, "ts": "2026-09-18T21:53:46Z", "hours": 4.7014, "text": "Spent today debugging the memory problem. The frontend was sending the chat history and the router was clearly using it, but the model was answering like every message was the first one. I asked “what did I just ask?” and got a totally random reply. Then I checked the Space’s API info and found the problem: Gradio 6’s ChatInterface hides the history from the API, so it was silently throwing the whole conversation away"}, {"post_id": 69607, "ts": "2026-09-17T12:20:33Z", "hours": 5.0708, "text": "Tested the new pipeline today. I asked “who won the last cricket world cup?” and it searched, found the facts and answered “Australia” correctly. Iris knowing current events feels like a huge upgrade. But while chatting normally I noticed something weird: it kept saying “Hai haii” to everything and had no idea what we’d been talking about"}, {"post_id": 69182, "ts": "2026-09-16T15:25:12Z", "hours": 4.86, "text": "Big backend day. I made Iris use the exact same backend as my other project, Amadeus: the same Hugging Face ZeroGPU Space, plus a RAG pipeline. Now a small router model on Hack Club AI rewrites the question, decides whether it needs a web search, and remembers facts about the user. If it needs current info, it searches the web with Exa and passes verified facts to the model. The UI stayed exactly the same"}, {"post_id": 67350, "ts": "2026-09-13T13:00:04Z", "hours": 8.9375, "text": "Tried Modal as another hosting option today, to compare it with ZeroGPU. I switched the route to call a Modal endpoint with an API key. It worked, but managing two setups for two projects (Iris and Amadeus) was getting messy, and I started thinking about putting both on the same backend"}, {"post_id": 66168, "ts": "2026-09-11T20:25:17Z", "hours": 11.0492, "text": "Came back to Iris after a while because responses were way too slow on free CPU hosting. Today I moved the model to Hugging Face ZeroGPU, so it actually runs on a GPU now. I rewrote the backend route to call the Space through the Gradio API, with retries and fallback messages in case something fail"}, {"post_id": 65771, "ts": "2026-09-11T04:17:48Z", "hours": 6.2706, "text": "Final UI touches today. I polished the About modal, updated the project links and rewrote the README with the whole training pipeline. Then I deployed it on Vercel. Iris is officially live and I shared the link with everyone"}, {"post_id": 65244, "ts": "2026-09-10T07:34:11Z", "hours": 8.7197, "text": "Today I connected the frontend to the real Hugging Face backend instead of the placeholder. Seeing Iris reply on my own website, in Senpai’s style, felt unreal. Responses were slow, but it was talking, and I spent way too long just chatting with it"}, {"post_id": 64336, "ts": "2026-09-08T17:12:01Z", "hours": 3.4358, "text": "I replaced the old playlist with songs that match the vibe better and made new covers for each track. Some of the song links broke right after, so I fixed those, and one mp3 was way too big, so I compressed it. Small stuff, but the radio station panel feels complete now"}, {"post_id": 64109, "ts": "2026-09-08T09:37:59Z", "hours": 4.6706, "text": "I didn’t like how the UI looked yesterday, so today I redesigned almost all of it. I went with a soft lavender pastel theme that feels more like Iris, removed the cyber cursor and added a cute Senpai avatar that pops up with little messages. I also made the whole thing responsive so it works on phones too"}, {"post_id": 63712, "ts": "2026-09-07T17:27:59Z", "hours": 9.7992, "text": "Started the frontend today with Next.js and Tailwind. I built the main layout: a chat panel in the middle, a music player on the left, and a side panel on the right. I also added a loading screen and little send/receive sound effects, because a chatbot without sounds feels lifeless. Pushed the first commit with the UI, routing and model connection all together"}, {"post_id": 62439, "ts": "2026-09-05T19:40:06Z", "hours": 11.1208, "text": "Training ran for 1000 steps today and I watched the loss drop from about 2.5 to 0.3. When I tested it, it replied with “Kk” and an eye roll emoji, and that’s literally how Senpai texts. I sent screenshots to my friends and they were all shocked. That was the best moment of the project so far"}, {"post_id": 61489, "ts": "2026-09-04T13:05:44Z", "hours": 22.205, "text": "Set up my Kaggle notebook today with Unsloth and Llama-3 8B as the base model. Most of the day went into fighting configs and memory errors on the T4 x2 GPUs. After a lot of trial and error I settled on a 2048 sequence length and a 5e-5 learning rate. It finally started training without crashing, and I almost cried"}, {"post_id": 59161, "ts": "2026-08-31T19:49:02Z", "hours": 12.4886, "text": "Today I turned the cleaned chats into proper training data. Senpai sends five short messages in a row instead of one long one, so I grouped consecutive messages together to keep that natural texting flow. I ended up with 12,613 dialogue samples. Seeing that number made it feel like a real project for the first time"}, {"post_id": 56717, "ts": "2026-08-28T16:11:34Z", "hours": 7.4811, "text": "Spent the whole day cleaning the WhatsApp export. It was around 81,000 lines of pure chaos: timestamps, “media omitted”, deleted messages, random links. I wrote a script to strip all the junk out and kept only the actual conversations. My eyes hurt, but the data finally looks usable"}, {"post_id": 54957, "ts": "2026-08-26T12:02:23Z", "hours": 9.8514, "text": "Today I finally started something I’d been thinking about for a while. Every AI chatbot I’ve used feels so polite and robotic, like it has zero aura. So I decided to make one that talks like a real person, specifically my friend “Senpai”. I exported our WhatsApp chats and just stared at them for a bit, wondering what I’d gotten myself into"}]...
|
Title: Iris by @Hamna | Stardance
Devlogs:
Today Title: Iris by @Hamna | Stardance
Devlogs:
Today I finally started something I’d been thinking about for a while. Every AI chatbot I’ve used feels so polite and robotic, like it has zero aura. So I decided to make one that talks like a real person, specifically my friend “Senpai”. I exported our WhatsApp chats and just stared at them for a bit, wondering what I’d gotten myself into
Spent the whole day cleaning the WhatsApp export. It was around 81,000 lines of pure chaos: timestamps, “media omitted”, deleted messages, random links. I wrote a script to strip all the junk out and kept only the actual conversations. My eyes hurt, but the data finally looks usable
Today I turned the cleaned chats into proper training data. Senpai sends five short messages in a row instead of one long one, so I grouped consecutive messages together to keep that natural texting flow. I ended up with 12,613 dialogue samples. Seeing that number made it feel like a real project for the first time
Set up my Kaggle notebook today with Unsloth and Llama-3 8B as the base model. Most of the day went into fighting configs and memory errors on the T4 x2 GPUs. After a lot of trial and error I settled on a 2048 sequence length and a 5e-5 learning rate. It finally started training without crashing, and I almost cried
Training ran for 1000 steps today and I watched the loss drop from about 2.5 to 0.3. When I tested it, it replied with “Kk” and an eye roll emoji, and that’s literally how Senpai texts. I sent screenshots to my friends and they were all shocked. That was the best moment of the project so far
Started the frontend today with Next.js and Tailwind. I built the main layout: a chat panel in the middle, a music player on the left, and a side panel on the right. I also added a loading screen and little send/receive sound effects, because a chatbot without sounds feels lifeless. Pushed the first commit with the UI, routing and model connection all together
I didn’t like how the UI looked yesterday, so today I redesigned almost all of it. I went with a soft lavender pastel theme that feels more like Iris, removed the cyber cursor and added a cute Senpai avatar that pops up with little messages. I also made the whole thing responsive so it works on phones too
I replaced the old playlist with songs that match the vibe better and made new covers for each track. Some of the song links broke right after, so I fixed those, and one mp3 was way too big, so I compressed it. Small stuff, but the radio station panel feels complete now
Today I connected the frontend to the real Hugging Face backend instead of the placeholder. Seeing Iris reply on my own website, in Senpai’s style, felt unreal. Responses were slow, but it was talking, and I spent way too long just chatting with it
Final UI touches today. I polished the About modal, updated the project links and rewrote the README with the whole training pipeline. Then I deployed it on Vercel. Iris is officially live and I shared the link with everyone
Came back to Iris after a while because responses were way too slow on free CPU hosting. Today I moved the model to Hugging Face ZeroGPU, so it actually runs on a GPU now. I rewrote the backend route to call the Space through the Gradio API, with retries and fallback messages in case something fail
Tried Modal as another hosting option today, to compare it with ZeroGPU. I switched the route to call a Modal endpoint with an API key. It worked, but managing two setups for two projects (Iris and Amadeus) was getting messy, and I started thinking about putting both on the same backend
Big backend day. I made Iris use the exact same backend as my other project, Amadeus: the same Hugging Face ZeroGPU Space, plus a RAG pipeline. Now a small router model on Hack Club AI rewrites the question, decides whether it needs a web search, and remembers facts about the user. If it needs current info, it searches the web with Exa and passes verified facts to the model. The UI stayed exactly the same
Tested the new pipeline today. I asked “who won the last cricket world cup?” and it searched, found the facts and answered “Australia” correctly. Iris knowing current events feels like a huge upgrade. But while chatting normally I noticed something weird: it kept saying “Hai haii” to everything and had no idea what we’d been talking about
Spent today debugging the memory problem. The frontend was sending the chat history and the router was clearly using it, but the model was answering like every message was the first one. I asked “what did I just ask?” and got a totally random reply. Then I checked the Space’s API info and found the problem: Gradio 6’s ChatInterface hides the history from the API, so it was silently throwing the whole conversation away
Fixed it today! I replaced ChatInterface in the Space with a gr.Interface that takes the history as a JSON input, so the conversation actually reaches the model now. I also added a history count to the logs so I can see it arriving with every message. This fixes Amadeus too, since they share the same Space. Iris finally remembers what we’re talking about, and that feels like the right place to call this project complete
There were some UI erros in the git pages file i made, so this is the last final verison for this project for the demo link: hope you’ll like this : )
Changed the UI a bit
Ships:
This is my booking website for wellness (my family hotel). There’s a public site, online checkout, a Reception console and a Management console The most difficult part to stop double bookings btw the website and the front desk,I fixed this by making a hold time of 10 mints on suites I’m really so proud of this project as this was something I was planning to make for my family and it turned out to so amazing and I got to learn so much about security (P.S , This is my last project on Hackclub , I really had the cool experience here, This platform really motivated me to make this project)...
|
1793008081.3630981
|
1793094481.3630981
|
|
34953
|
Ultimate Mob Farms by @OffsetMonkey538 | Stardance
|
OffsetMonkey538
|
1
|
144.43
|
2678
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-19T13:59:43Z", "hours": 125.0, "multiplier": 18.99, "payout": 2678, "blessing": "neutral", "text": "This is a Minecraft mod for making mob farms, something similar to for example Mob Grinding Utils. It features item and xp collection, entity movement, spawner relocation and crafting, single block mob farms and some other stuff. Honestly, I’m quite proud just over the fact that I finally did finish this project (or at least got it to the point of being comfortable releasing it publically) and it’s hard to choose any specific features, but here I go… I do really like how the particle effects for the soul fan turned out, they’re quite satisfying imo. This is kind of unrelated to the mod, but I’m also proud of having helped out with the development of RRV, the recipe viewer mod I added compat with. While adding support for it in this mod, I noticed some bugs and crashes and stuff, which I PRed fixes for. It’s a bigger project with many complex things, so coming up with a list of all the things I found hard or took a lot of time and explaining all of them would probably go over whatever character limit this text box has lol. One thing that was a big PITA was the compact mob farm inventory. The original implementation I wrote was just… completely wrong, so I had to rewrite it. Then later I realized I overlooked like the most important part of the item transfer api (transactions, which are used for rolling back changes and stuff) so I had to rewrite it again, and then after that I rewrote quite a bit of it one more time because, after the last rewrite, I had accidentally made it possible for other blocks to insert into the inventory, which isn’t something I wanted as that seems quite OP. Another thing that comes to mind is figuring out the code for the soul fan’s range based on upgrades and strength at a given distance. The problem was that the coordinate you have to increase/decrease depends on the orientation of the block, so as an example, the depth upgrade would need to increase the Y pos when the block is placed pointing up and decrease it when pointing down, the X pos when facing north/south and the Z pos when facing east/west. For pushing the entities, I had to find the coordinates of the middle of the face the block is pointing, and add/subtract the correct coordinate to get the range in the depth direction, and then find the distance between each entity currently in range and the fan in just that plane for calculating the strength. For people testing out the project, I definitely do recommend also installing the Reliable Recipe Viewer (RRV) and Item Description mods", "repo": "https://git.offsetmonkey538.top/OffsetMods538/Ultimate-Mob-Farms", "demo": "https://modrinth.com/mod/ultimate-mob-farms"}]...
|
[{"post_id": 82652, "ts": "202 [{"post_id": 82652, "ts": "2026-10-25T15:00:05Z", "hours": 5.1919, "text": "Set up empty pages for all the blocks and items, fought quite a bit with astro/typescript to get the PageTitle override to correctly display the icons. Turns out astro’s optimized Image stuff doesn’t support animated images, no matter how much you try to force it to, so I ended up having to use the basic img tag"}, {"post_id": 80728, "ts": "2026-10-18T17:03:06Z", "hours": 1.5967, "text": "Started working on setting up a docs page for the mod. Mainly want it for explaining the data driven configuration, but having full pages to give more detailed explanations of the different features is also probably a nice touch. Made a new icon for the mod as well, it’s pretty much the same but higher res because the 256x256 one looked weird on the docs page. The docs are done using Starlight like all my other docs pages (see those here ) and lives at https://ultimate-mob-farms.docs.cursedmods.com/ and on the docs/master branch in the repo Currently it’s just the landing page, but it’ll have more stuff soon enough"}, {"post_id": 79375, "ts": "2026-10-13T18:29:39Z", "hours": 3.9611, "text": "Added an RRV screen showing what items can be acquired from the Compact Mob Farm. Shows the entity, the items it drops and the required tier upgrade level. Hoping this also helps with confusion on how stuff works"}, {"post_id": 76204, "ts": "2026-10-02T17:34:45Z", "hours": 2.1567, "text": "Added a progress bar to the Compact Mob Farm GUI that hopefully makes it much easier to understand when it’ll damage the entity and it doesn’t look like it’s just doing nothing lol, especially with the 30 second default time"}, {"post_id": 75664, "ts": "2026-09-30T17:54:02Z", "hours": 6.5264, "text": "Waow that’s quite a bit of stardust 😅 Quite happy with this project and the ratings it got on the first ship :D (except the one that accused my devlogs of being written by ai… My writing is not that bad, right? ) I noticed in the shipwrights’ review video that how upgrades work is not very obvious, they were trying to put a tier upgrade into a soul fan, which only accepts width, height and depth upgrades. It was mentioned in ratings that stuff is a bit hard to figure out in the beginning as well. So to fix that, I added some silhouettes of the supported upgrades shown in the slots and also a hover tooltip saying what’s supported. Oh and i’ve also added 26.3 support now"}, {"post_id": 70575, "ts": "2026-09-19T11:52:49Z", "hours": 7.4719, "text": "School starting with september really hit my productivity on this mod like a truck I am realizing the deadline for stardance is getting real close, so I think this is probably the point where I’ll have to ship it. There are still some TODOs in the code and bugs that need to be squashed and porting to 26.3 (which released like this week, thanks mojang ) and so I haven’t been comfortable marking the latest release as 1.0.0 yet or making announcements elsewhere, but the mod is now perfectly usable and I like where it is. Changes since last devblog: 26.2 support Injecting some items into vanilla loot chests Advancements 26.2 wasn’t actually as painful as I thought it’d be, which was a nice surprise. Adding advancements was a bit more of a pain with 26.2 support though as I needed custom criteria for some of the advancements (one for putting a soul gem in the compact mob farm and another for using a soul gem on a spawner) and Mojang, in their infinite wisdom, decided to move a bunch of advancement stuff around in 26.2."}, {"post_id": 62252, "ts": "2026-09-05T15:04:19Z", "hours": 6.3956, "text": "Getting closer and closer to the actual release… could this be the last devblog before that? Still not quite 100% about if the required kills for each mob are balanced, but it’s probably good enough. Definitely better than everything being 10 kills tho. Felt very off-balance when withers, which are hard to spawn and hard to kill, and pigs, which are just everywhere, required the same amount of kills to capture. Notable changes: Show soul capturing recipe in rrv when checking usages of spawn eggs Show tooltip with entity name when hovering entity in soul capturing rrv recipe Add item descriptions Fix being able to insert items into the compact mob farm inventory Make amount of kills required for capturing an entity different per entity. Update compact mob farm recipe (now uses soul spikes in the middle instead of stone bricks) Store soul gem colors as hex strings in entity tiers config. Much more understandable and easier to manually change the overrides config or whatever Make built-in packs use the mod icon using a mixin instead of copying the icon into the packs. This shaves like 80kb off the final jar which is quite a bit of unnecessary duplicate crap Remove some log spam that was for debugging"}, {"post_id": 59802, "ts": "2026-09-01T19:04:17Z", "hours": 2.5989, "text": "checking the recipe for a specific soul gem now only shows that specific entity instead of all soul capturing recipes soul capturing recipe now shows up before the duplication recipe soul gems can now be searched by the name of the entity they contain fix compact mob farm gui not rendering vanilla background overlay allow filling soul gem when held in the main hand fix dedicated server crashing Running in a dedicated server would crash because there are quite a few places where I referenced client-only classes in places that the jvm will load on the dedicated server as well. Mostly in the different block entity classes, where I had a clientTick method that had ClientLevel as one of it’s parameters. Even though that method would never get called on the dedicated server, java still wants it to exist when loading the class because it’s part of a method’s definition. My current solution is very very awful… I moved those things into methods in the client initializer and… well… yeah… it just looks and is awful: https://git.offsetmonkey538.top/OffsetMods538/Ultimate-Mob-Farms/src/commit/0.0.7/modded/src/main/java/top/offsetmonkey538/ultimatemobfarms/modded/UltimateMobFarmsModdedClient.java#L65 The real, foolproof solution would be using the split sources feature of loom, which creates a second source set and makes the main source set unable to access client classes. Only problem is that it’d be a bit annoying to fully get set up in my multiloader-version gradle system and would most definitely need many changes on MonkeyLib538 as well and I just am not up for doing that atm."}, {"post_id": 58874, "ts": "2026-08-31T13:27:24Z", "hours": 8.6083, "text": "Fixed compact mob farm inventory not working correctly and being incompatible with other mods’ item movement stuff. The whole point of the transfer API on both fabric and neoforge is the transaction system, where each change must store a snapshot that can be returned to if needed; Turns out ignoring the TransactionContext and not saving any snapshots is a bad idea 😅 I’ve tested and it’s compatible with create fly (see screenshot where a compact mob farm with a blaze is being used to feed a blaze burner for a steam engine) and most probably other mods as well. Added Reliable Recipe Viewer integration that explains soul capturing"}, {"post_id": 54946, "ts": "2026-08-26T11:20:57Z", "hours": 7.2406, "text": "Bunch of refactoring, bug fixes, balancing, etc. Release notes can be seen on the forgejo release or on modrinth, I’m not gonna copy paste em here (this is version 0.0.5 right now) It is now actually reviewed on Modrinth, took two weeks for that to happen (Gosh I remember when review times were like less than 24 hours ). I’m still keeping it unlisted until I get a 1.0.0 release out, but if anyone wants to check it out and share feedback or anything, then it’s right over here: https://modrinth.com/mod/ultimate-mob-farms Before a v1, I still need better rrv and item descriptions integration, some more balancing changes, advancements, quite a few bugfixes and probably some other stuff I’m forgetting at the moment."}, {"post_id": 50153, "ts": "2026-08-19T08:08:41Z", "hours": 2.3531, "text": "Made soul fans placed at different locations use a different starting frame offset, so they don’t all look the same (see before and after videos). The way this is implemented is a bit interesting… There’s no easy “use this model but offset any texture’s animation by 1 frame” as afaik the frame index is global per texture. What Minecraft does allow is each block state variant actually being an array of variants that the game will choose between using afaik a hash derived from the block position. This is used in vanilla for things like stone and deepslate, which have mirrored and rotated variants so caves look less repetitive or whatever. As each texture has a global frame index, I am duplicating the soul fan texture and just changing the order of the frames in the accompanying animation metadata file and creating separate models which point to the different textures and then those models are used as variants in the blockstate. What’s even more fun is I am using datagen for duplicating the texture and creating the animation metadata files, which definitely isn’t concerning at all. This also required me to make a pull request to fabric api because the FabricCodecDataProvider assumes all files it generates are .json files, but animation metadata is .mcmeta. (The PR isn’t yet merged so I resorted to…. injecting a mixin into fabric api, definitely not cursed at all I swear)"}, {"post_id": 49673, "ts": "2026-08-18T15:46:30Z", "hours": 4.43, "text": "Added particle effects for soul fan. Figuring out where to spawn em was quite fun actually, though I did have to add a custom particle (reuses the vanilla “small gust” texture) because turns out most particles won’t obey the velocity you give them and just do their own thing, which was a bit annoying."}, {"post_id": 49138, "ts": "2026-08-17T19:28:11Z", "hours": 3.7422, "text": "Added range upgrades for the fan and collector blocks. It was a bit challenging figuring out actually extending the bounding box in the correct directions based on the block is facing, but I did get it working"}, {"post_id": 48767, "ts": "2026-08-17T09:17:16Z", "hours": 4.6397, "text": "Implemented functionality of the soul fan, getting the strength to scale based on distance was a bit of a pain cause i needed to get the position of the center of the face that the fan’s pointing in and only calculate the distance to the entity based on the correct axis cause otherwise giving it a larger range would make the farther to the side entities get pushed less and uhh yeah, took quite a bit of experimenting with stuff to get it to work correctly"}, {"post_id": 47706, "ts": "2026-08-15T19:55:20Z", "hours": 0.9575, "text": "Spent the last hour and a half faffing about with my loader abstraction in monkeylib (stardance only recorded an hour cause that’s technically a separate project) for creative tabs. All that just cause I really wanted the RRV stack group for the filled soul gems to show up next to the empty soul gem, instead of at the end of the list where it did previously"}, {"post_id": 47530, "ts": "2026-08-15T14:35:38Z", "hours": 3.0928, "text": "Spent a bunch of time on cleaning up some code and abstracting some things out of collector block classes to make it easier to add functionality of the soul fan later on, speaking of which! the soul fan is a block that exists in game now"}, {"post_id": 46880, "ts": "2026-08-14T12:46:12Z", "hours": 0.2881, "text": "Spent some time thinking about what I’m gonna do for the block that moves mobs around. I think I’ve decided on going with a basic “fan” type block and now started working on what it could look like. I’m imagining the souls kinda like escaping from the soul sand and also particles spawning and moving in the direction it’s pushing. As always I’m pretty bad at drawing textures, so the beginning here looks a bit crude, but it’s definitely a start. It’d be really nice if aseprite had a wakatime plugin…"}, {"post_id": 46845, "ts": "2026-08-14T11:27:58Z", "hours": 3.8683, "text": "Added the experience collector block, which obviously picks up xp orbs and turns em into bottles of enchanting. Kind of got so focused I forgot about making more detailed devlogs 😅"}, {"post_id": 46238, "ts": "2026-08-13T10:39:10Z", "hours": 3.695, "text": "Made the soul spikes actually deal extra fall damage when fell on. Current fall damage multiplier is at 5, not sure if that is too much or too little. The damage is done by a FakePlayer, so the mob will also drop loot that only drops from player kills, including experience orbs. (Seems like I need to add an XP Collector block in the future to deal with those). Oh and also did some boilerplate-ish things to soul spikes like adding a recipe, translation, etc Turns out minecraft decides that the block you fall on is the one that’s 0.2 blocks below you…. The model of the soul spikes (which i don’t really wanna change anymore) has the base at 3 pixels high, which makes it… 0.1875 block high 😮💨 Nothing that can’t be solved with a mixin to Entity#getOnPosLegacy that changes the BlockPos it returns if the the block above the “correct” block is soul spikes"}, {"post_id": 45189, "ts": "2026-08-11T14:44:28Z", "hours": 0.2731, "text": "Made an okay-ish texture for the soul spikes block (many of em at once looks kinda noisy but oh well, it’ll do. Hopefully it’ll be locked up in a farm killing chamber room anyway). Had to change the UV mapping again because for whatever reasons, minecraft decides to render a sliver of the neighboring pixel as well which looks super bad with two very contrasty colors next to each other. Solution was to move the blue parts to the bottom of the texture where there was room to have it separated by a row of blank pixels."}, {"post_id": 45107, "ts": "2026-08-11T11:51:36Z", "hours": 0.7186, "text": "Finished UV mapping the spikes…. this literally took like over an hour haha, sadly time spent in blockbench doesn’t count as it doesn’t have a plugin for wakatime or whatever :/ (the 43min this devlog logs was actually setting up oxipng to automatically run on every commit to optimize the png files) Next i guess will be to make an actual texture for it, yay. Here’s the super very interesting texture that currently just has all the different mapped sides in different colors"}, {"post_id": 44754, "ts": "2026-08-10T18:48:32Z", "hours": 2.0067, "text": "Started working on the soul spikes. First made a model for it, not sure if it’ll look good once I make a texture for the actual spikes part of it as well"}, {"post_id": 41521, "ts": "2026-08-05T19:39:30Z", "hours": 1.7181, "text": "Been doing some boring things like writing a description and making an icon and some miscellaneous fixes and whatnot as I actually think I want to get this in a state where I could send it in for review on modrinth. Otherwise if I sent it in once I was actually finished with the project, it probably wouldn’t get reviewed before stardance ends and then i’d have to tell people to download the mod from my git releases and that wouldn’t automatically tell em where to get dependencies and whatnot so yeah, want to get it in the queue asap. Here’s the icon I came up with btw"}, {"post_id": 40668, "ts": "2026-08-04T11:02:42Z", "hours": 2.4575, "text": "Added a texture and recipe to item collector, made it possible to disable it using redstone, made the sample collector only pick up items every 10 ticks."}, {"post_id": 39730, "ts": "2026-08-02T21:36:20Z", "hours": 1.855, "text": "Shift-right-clicking an item collector with an empty hand now shows its range. Drawing lines of particles between the correct corners for the outline took a bit of trial and error, also added a screenshot where it doesn’t look quite correct Also I’m not sure if the video from the previous devlog got uploaded correctly (my browser at least isn’t able to play it) so here it is again"}, {"post_id": 39564, "ts": "2026-08-02T16:40:59Z", "hours": 2.9042, "text": "Made item collector spawn a line of particles when picking up items Oh and also added compatibility to item collector with container blocks from other mods that use the fabric or neoforge transfer api instead of vanilla containers, more loader specific stuff, yay!"}, {"post_id": 38906, "ts": "2026-08-01T14:21:22Z", "hours": 1.0933, "text": "Implemented basic functionality of the item collector. Currently has a range of 2 blocks that it will pick things up from and put em straight into a connected inventory"}, {"post_id": 38761, "ts": "2026-08-01T10:08:52Z", "hours": 3.6756, "text": "Started work on adding the item collector, currently just got done with adding the block itself with some boilerplate stuff and a model. As the name suggests, it’ll be for picking up items in some range of it. Not quite sure if I want it to be a range all around the block, or maybe going outwards from the direction it’s facing? Also not yet quite sure if I want it to just put stuff into an internal inventory and require a hopper or something modded to pull out of it, or if it should act like a hopper pushing things out from the side it’s attached on"}, {"post_id": 37603, "ts": "2026-07-30T13:35:05Z", "hours": 1.1933, "text": "Received new textures and spent some time messing around in the mcmeta file for the animation timing. Looks quite good now. Also made the empty soul gem use the same texture, just with a soul light blue colors."}, {"post_id": 37190, "ts": "2026-07-29T18:31:37Z", "hours": 5.0456, "text": "Past while has been spent on fighting with gradle to extend my overly complicated setup ( monkeylogic, my gradle convention plugin ) and make it even more complicated allow adding dependencies from modrinth to projects. After that I could easily add RRV (Reliable Recipe Viewer) as a dependency and now lastly add integration with it. Currently I’ve got integration to the point of showing the custom duplication recipe, which is great"}, {"post_id": 35160, "ts": "2026-07-26T12:28:59Z", "hours": 2.7197, "text": "Finally fixed the soul gem duplication recipe, which was a bit of a pain to deal with… I initially went down a dumb rabbit hole of overcomplicating the matcher system when turns out having multiple of the same item in the recipe can easily be solved by storing a count for each ingredient instead of having multiple entries for them 😝"}, {"post_id": 34287, "ts": "2026-07-24T21:18:42Z", "hours": 2.5044, "text": "Made spawners craftable, made interacting with spawners using a filled soul gem set the entity in the spawner. Still not quite sure what to call the “filled” soul gem. One idea i had was to call it just a soul gem and call the not filled one an “Empty Soul Gem”, which is honestly a pretty good idea, but I’m not sure what to do when it’s in the process of being filled. Technically at that point it’s not empty , but maybe it’d be fine to call it that"}, {"post_id": 32839, "ts": "2026-07-22T07:47:33Z", "hours": 3.5317, "text": "Lots of fun stuff between this and the last devlog: Creative tab for filled soul gems now only contains supported ones (had to make creative tabs refresh when data is reloaded cause datapacks can change what’s supported) Removed the old SampleTakerItem and FilledSampleTakerItem classes and moved most logic to custom components or mixins. Soul gems can be filled by holding them in the off hand when killing the target entity ( https://imgur.com/a/Lz6PjZs ) Some optimizations"}, {"post_id": 32407, "ts": "2026-07-21T16:00:26Z", "hours": 1.9203, "text": "Optimized the EntityTiers lookup (which I mentioned I messed up last devlog) by using a map instead of a list, and it’s also now storing a reference to the Identifier instead of EntityType, so there’s less work converting between them for the packet codec (has to be sent as an Identifier (or, well, string) over the network) and also when doing some of the lookups (like from the tint provider, which has just the id by itself) Not sure what to put as the screenshot it requires me to add…. I guess have some prototypes of the new soul gem texture a person’s working on (the final shape will probably not be a perfectly round pearl)"}, {"post_id": 32271, "ts": "2026-07-21T10:39:38Z", "hours": 3.1261, "text": "Made “filled” soul gems have colors based on the entity they contain! (and also switched to a different (and probably even worse lmao) texture) The colors are the same as what spawn eggs used to have, thankfully the minecraft wiki has a list of what they all were before that was removed. Sadly I can’t steal the entity colors from vanilla anymore as that was removed in 1.21.5, so I had to add color fields to the entity tiers config and that messed with a lot of stuff and is a bit of a hit on performance when it’s not looping over stuff in weird ways as it’s a list of entries when it really should probably be a map… I’ll fix that i guess Also I know this texture is ass and someone a bit more talented in drawing is cooking up a new one which I’ll probably be able to show off in a few days. Question is… do I want the current one to show up when the vanilla programmer art pack is enabled or is that too embarrassing to show off?"}, {"post_id": 31810, "ts": "2026-07-20T14:25:41Z", "hours": 0.9456, "text": "Added recipes, translations, etc for soul essence and gem, removed spirit bottle, added recipe for spawner, made spawners drop with silk touch. Thanks to neoforge there have to be separate mixins for fabric and neo for disabling the xp drop when a spawner is broken with silk touch (would lead to infinite xp otherwise lol)…. if only neoforge was just fabric"}, {"post_id": 31751, "ts": "2026-07-20T12:04:50Z", "hours": 1.2917, "text": "Made soul essence drop from mobs killed on soul sand/soil. Also spawns fun particles! https://imgur.com/a/Qt5XxUI"}, {"post_id": 31695, "ts": "2026-07-20T09:44:19Z", "hours": 0.3378, "text": "So I’ve been doing some brainstorming and writing things down on paper (like a caveman) and have at least redesigned some of the features that already exist. Instead of a bottle of spirits that you get by right clicking a spawner, there’s going to be Soul Essence that you get by killing a mob while they’re standing on soul sand/soil. Instead of the Sample taker, there’s gonna be a soul gem crafted from a diamond and 4 soul essence that will be filled by holding it in your offhand while killing x amount of the target mob. Also thought of some recipes that I’m not gonna explain here rn. Sadly (or thankfully) I haven’t found a wakatime plugin for Aseprite, so nobody will know just how many hours I spent on the absolute trash textures I made for the soul gem and soul essence (I promise they’ll be better at some point maybe idk if I can do any better 😭 ). Soul essence just looks off somehow, and the soul gem looks like a duck spawn egg 😭 😭 😭 😭"}, {"post_id": 31122, "ts": "2026-07-19T08:32:28Z", "hours": 6.5108, "text": "It is now working on NeoForge as well! Getting the inventory to work with the neoforge transfer api was a bit of a pain, but I managed to get it to work! (Don’t mind the debug upgrades in the screenshot, they make it easier to test but dont have textures) Next up is uhh… some brainstorming and rethinking how the whole mod works and thinking about what’s in scope for this and what’s not: One thing I definitely want to add is a crafting recipe for spawners and making the sample takers (which will probably be renamed to something relating to souls and gems) usable as spawn eggs on spawners. I’m not quite sure if upgradeable spawners should be a part of this though as there’s already apotheosis for neoforge (and a port in the works for fabric) that does that and probably other mods as well. I also really wanted to add things for moving and killing mobs in the world, for which there are also already mods like Dark Utilities (got quite inspired by that) which afaik also is updated to the latest version and is for both fabric and neoforge…. Though it seems to have more random things unrelated to mob farming, and maybe it’d be fine if I really differentiate from it and other similar mods with the theme of this? Yeahhh this’ll need quite a bit more thinking."}, {"post_id": 28545, "ts": "2026-07-14T21:20:48Z", "hours": 2.0633, "text": "Finished getting everything out of :loader:fabric and into :modded that makes sense to move. The fabric subproject now only has 4 files, two of which are just the entrypoints that invoke the common initializer and the other two are using fabric api specific things and can’t be moved out without a lot of headache!"}, {"post_id": 28177, "ts": "2026-07-14T09:44:23Z", "hours": 0.2531, "text": "(the 15m were spent working on getting MenuProvider stuff out from fabric specific code and into the common modded subproject, butttt I’m making a post cause I wanna share…) Some funny screenshots from when I was porting from 1.21.1 to 26.1 (rendering changes here are a pain lol)"}, {"post_id": 28170, "ts": "2026-07-14T09:24:59Z", "hours": 17.9675, "text": "Just realized this is probably something I could submit to stardance as well 😅 Basically the initial idea was to have a mob farm contained in a single block. You craft a sample taker and have to click on 10 separate instances of an entity to get a filled sample of that entity. Then you put that into a Compact Mob Farm, turn it on, maybe give it some upgrades and a sword, and it’ll start farming the drops of the entity you took samples of. Here are some screenshots of what stuff looks like"}]...
|
Title: Ultimate Mob Farms by @OffsetMonkey538 | St Title: Ultimate Mob Farms by @OffsetMonkey538 | Stardance
Devlogs:
Just realized this is probably something I could submit to stardance as well 😅 Basically the initial idea was to have a mob farm contained in a single block. You craft a sample taker and have to click on 10 separate instances of an entity to get a filled sample of that entity. Then you put that into a Compact Mob Farm, turn it on, maybe give it some upgrades and a sword, and it’ll start farming the drops of the entity you took samples of. Here are some screenshots of what stuff looks like
(the 15m were spent working on getting MenuProvider stuff out from fabric specific code and into the common modded subproject, butttt I’m making a post cause I wanna share…) Some funny screenshots from when I was porting from 1.21.1 to 26.1 (rendering changes here are a pain lol)
Finished getting everything out of :loader:fabric and into :modded that makes sense to move. The fabric subproject now only has 4 files, two of which are just the entrypoints that invoke the common initializer and the other two are using fabric api specific things and can’t be moved out without a lot of headache!
It is now working on NeoForge as well! Getting the inventory to work with the neoforge transfer api was a bit of a pain, but I managed to get it to work! (Don’t mind the debug upgrades in the screenshot, they make it easier to test but dont have textures) Next up is uhh… some brainstorming and rethinking how the whole mod works and thinking about what’s in scope for this and what’s not: One thing I definitely want to add is a crafting recipe for spawners and making the sample takers (which will probably be renamed to something relating to souls and gems) usable as spawn eggs on spawners. I’m not quite sure if upgradeable spawners should be a part of this though as there’s already apotheosis for neoforge (and a port in the works for fabric) that does that and probably other mods as well. I also really wanted to add things for moving and killing mobs in the world, for which there are also already mods like Dark Utilities (got quite inspired by that) which afaik also is updated to the latest version and is for both fabric and neoforge…. Though it seems to have more random things unrelated to mob farming, and maybe it’d be fine if I really differentiate from it and other similar mods with the theme of this? Yeahhh this’ll need quite a bit more thinking.
So I’ve been doing some brainstorming and writing things down on paper (like a caveman) and have at least redesigned some of the features that already exist. Instead of a bottle of spirits that you get by right clicking a spawner, there’s going to be Soul Essence that you get by killing a mob while they’re standing on soul sand/soil. Instead of the Sample taker, there’s gonna be a soul gem crafted from a diamond and 4 soul essence that will be filled by holding it in your offhand while killing x amount of the target mob. Also thought of some recipes that I’m not gonna explain here rn. Sadly (or thankfully) I haven’t found a wakatime plugin for Aseprite, so nobody will know just how many hours I spent on the absolute trash textures I made for the soul gem and soul essence (I promise they’ll be better at some point maybe idk if I can do any better 😭 ). Soul essence just looks off somehow, and the soul gem looks like a duck spawn egg 😭 😭 😭 😭
Made soul essence drop from mobs killed on soul sand/soil. Also spawns fun particles! https://imgur.com/a/Qt5XxUI
Added recipes, translations, etc for soul essence and gem, removed spirit bottle, added recipe for spawner, made spawners drop with silk touch. Thanks to neoforge there have to be separate mixins for fabric and neo for disabling the xp drop when a spawner is broken with silk touch (would lead to infinite xp otherwise lol)…. if only neoforge was just fabric
Made “filled” soul gems have colors based on the entity they contain! (and also switched to a different (and probably even worse lmao) texture) The colors are the same as what spawn eggs used to have, thankfully the minecraft wiki has a list of what they all were before that was removed. Sadly I can’t steal the entity colors from vanilla anymore as that was removed in 1.21.5, so I had to add color fields to the entity tiers config and that messed with a lot of stuff and is a bit of a hit on performance when it’s not looping over stuff in weird ways as it’s a list of entries when it really should probably be a map… I’ll fix that i guess Also I know this texture is ass and someone a bit more talented in drawing is cooking up a new one which I’ll probably be able to show off in a few days. Question is… do I want the current one to show up when the vanilla programmer art pack is enabled or is that too embarrassing to show off?
Optimized the EntityTiers lookup (which I mentioned I messed up last devlog) by using a map instead of a list, and it’s also now storing a reference to the Identifier instead of EntityType, so there’s less work converting between them for the packet codec (has to be sent as an Identifier (or, well, string) over the network) and also when doing some of the lookups (like from the tint provider, which has just the id by itself) Not sure what to put as the screenshot it requires me to add…. I guess have some prototypes of the new soul gem texture a person’s working on (the final shape will probably not be a perfectly round pearl)
Lots of fun stuff between this and the last devlog: Creative tab for filled soul gems now only contains supported ones (had to make creative tabs refresh when data is reloaded cause datapacks can change what’s supported) Removed the old SampleTakerItem and FilledSampleTakerItem classes and moved most logic to custom components or mixins. Soul gems can be filled by holding them in the off hand when killing the target entity ( https://imgur.com/a/Lz6PjZs ) Some optimizations
Made spawners craftable, made interacting with spawners using a filled soul gem set the entity in the spawner. Still not quite sure what to call the “filled” soul gem. One idea i had was to call it just a soul gem and call the not filled one an “Empty Soul Gem”, which is honestly a pretty good idea, but I’m not sure what to do when it’s in the process of being filled. Technically at that point it’s not empty , but maybe it’d be fine to call it that
Finally fixed the soul gem duplication recipe, which was a bit of a pain to deal with… I initially went down a dumb rabbit hole of overcomplicating the matcher system when turns out having multiple of the same item in the recipe can easily be solved by storing a count for each ingredient instead of having multiple entries for them 😝
Past while has been spent on fighting with gradle to extend my overly complicated setup ( monkeylogic, my gradle convention plugin ) and make it even more complicated allow adding dependencies from modrinth to projects. After that I could easily add RRV (Reliable Recipe Viewer) as a dependency and now lastly add integration with it. Currently I’ve got integration to the point of showing the custom duplication recipe, which is great
Received new textures and spent some time messing around in the mcmeta file for the animation timing. Looks quite good now. Also made the empty soul gem use the same texture, just with a soul light blue colors.
Started work on adding the item collector, currently just got done with adding the block itself with some boilerplate stuff and a model. As the name suggests, it’ll be for picking up items in some range of it. Not quite sure if I want it to be a range all around the block, or maybe going outwards from the direction it’s facing? Also not yet quite sure if I want it to just put stuff into an internal inventory and require a hopper or something modded to pull out of it, or if it should act like a hopper pushing things out from the side it’s attached on
Implemented basic functionality of the item collector. Currently has a range of 2 blocks that it will pick things up from and put em straight into a connected inventory
Made item collector spawn a line of particles when picking up items Oh and also added compatibility to item collector with container blocks from other mods that use the fabric or neoforge transfer api instead of vanilla containers, more loader specific stuff, yay!
Shift-right-clicking an item collector with an empty hand now shows its range. Drawing lines of particles between the correct corners for the outline took a bit of trial and error, also added a screenshot where it doesn’t look quite correct Also I’m not sure if the video from the previous devlog got uploaded correctly (my browser at least isn’t able to play it) so here it is again
Added a texture and recipe to item collector, made it possible to disable it using redstone, made the sample collector only pick up items every 10 ticks.
Been doing some boring things like writing a description and making an icon and some miscellaneous fixes and whatnot as I actually think I want to get this in a state where I could send it in for review on modrinth. Otherwise if I sent it in once I was actually finished with the project, it probably wouldn’t get reviewed before stardance ends and then i’d have to tell people to download the mod from my git releases and that wouldn’t automatically tell em where to get dependencies and whatnot so yeah, want to get it in the queue asap. Here’s the icon I came up with btw
Started working on the soul spikes. First made a model for it, not sure if it’ll look good once I make a texture for the actual spikes part of it as well
Finished UV mapping the spikes…. this literally took like over an hour haha, sadly time spent in blockbench doesn’t count as it doesn’t have a plugin for wakatime or whatever :/ (the 43min this devlog logs was actually setting up oxipng to automatically run on every commit to optimize the png files) Next i guess will be to make an actual texture for it, yay. Here’s the super very interesting texture that currently just has all the different mapped sides in different colors
Made an okay-ish texture for the soul spikes block (many of em at once looks kinda noisy but oh well, it’ll do. Hopefully it’ll be locked up in a farm killing chamber room anyway). Had to change the UV mapping again because for whatever reasons, minecraft decides to render a sliver of the neighboring pixel as well which looks super bad with two very contrasty colors next to each other. Solution was to move the blue parts to the bottom of the texture where there was room to have it separated by a row of blank pixels.
Made the soul spikes actually deal extra fall damage when fell on. Current fall damage multiplier is at 5, not sure if that is too much or too little. The damage is done by a FakePlayer, so the mob will also drop loot that only drops from player kills, including experience orbs. (Seems like I need to add an XP Collector block in the future to deal with those). Oh and also did some boilerplate-ish things to soul spikes like adding a recipe, translation, etc Turns out minecraft decides that the block you fall on is the one that’s 0.2 blocks below you…. The model of the soul spikes (which i don’t really wanna change anymore) has the base at 3 pixels high, which makes it… 0.1875 block high 😮💨 Nothing that can’t be solved with a mixin to Entity#getOnPosLegacy that changes the BlockPos it returns if the the block above the “correct” block is soul spikes
Added the experience collector block, which obviously picks up xp orbs and turns em into bottles of enchanting. Kind of got so focused I forgot about making more detailed devlogs 😅
Spent some time thinking about what I’m gonna do for the block that moves mobs around. I think I’ve decided on going with a basic “fan” type block and now started working on what it could look like. I’m imagining the souls kinda like escaping from the soul sand and also particles spawning and moving in the direction it’s pushing. As always I’m pretty bad at drawing textures, so the beginning here looks a bit crude, but it’s definitely a start. It’d be really nice if aseprite had a wakatime plugin…
Spent a bunch of time on cleaning up some code and abstracting some things out of collector block classes to make it easier to add functionality of the soul fan later on, speaking of which! the soul fan is a block that exists in game now
Spent the last hour and a half faffing about with my loader abstraction in monkeylib (stardance only recorded an hour cause that’s technically a separate project) for creative tabs. All that just cause I really wanted the RRV stack group for the filled soul gems to show up next to the empty soul gem, instead of at the end of the list where it did previously
Implemented functionality of the soul fan, getting the strength to scale based on distance was a bit of a pain cause i needed to get the position of the center of the face that the fan’s pointing in and only calculate the distance to the entity based on the correct axis cause otherwise giving it a larger range would make the farther to the side entities get pushed less and uhh yeah, took quite a bit of experimenting with stuff to get it to work correctly
Added range upgrades for the fan and collector blocks. It was a bit challenging figuring out actually extending the bounding box in the correct directions based on the block is facing, but I did get it working
Added particle effects for soul fan. Figuring out where to spawn em was quite fun actually, though I did have to add a custom particle (reuses the vanilla “small gust” texture) because turns out most particles won’t obey the velocity you give them and just do their own thing, which was a bit annoying.
Made soul fans placed at different locations use a different starting frame offset, so they don’t all look the same (see before and after videos). The way this is implemented is a bit interesting… There’s no easy “use this model but offset any texture’s animation by 1 frame” as afaik the frame index is global per texture. What Minecraft does allow is each block state variant actually being an array of variants that the game will choose between using afaik a hash derived from the block position. This is used in vanilla for things like stone and deepslate, which have mirrored and rotated variants so caves look less repetitive or whatever. As each texture has a global frame index, I am duplicating the soul fan texture and just changing the order of the frames in the accompanying animation metadata file and creating separate models which point to the different textures and then those models are used as variants in the blockstate. What’s even more fun is I am using datagen for duplicating the texture and creating the animation metadata files, which definitely isn’t concerning at all. This also required me to make a pull request to fabric api because the FabricCodecDataProvider assumes all files it generates are .json files, but animation metadata is .mcmeta. (The PR isn’t yet merged so I resorted to…. injecting a mixin into fabric api, definitely not cursed at all I swear)
Bunch of refactoring, bug fixes, balancing, etc. Release notes can be seen on the forgejo release or on modrinth, I’m not gonna copy paste em here (this is version 0.0.5 right now) It is now actually reviewed on Modrinth, took two weeks for that to happen (Gosh I remember when review times were like less than 24 hours ). I’m still keeping it unlisted until I get a 1.0.0 release out, but if anyone wants to check it out and share feedback or anything, then it’s right over here: https://modrinth.com/mod/ultimate-mob-farms Before a v1, I still need better rrv and item descriptions integration, some more balancing changes, advancements, quite a few bugfixes and probably some other stuff I’m forgetting at the moment.
Fixed compact mob farm inventory not working correctly and being incompatible with other mods’ item movement stuff. The whole point of the transfer API on both fabric and neoforge is the transaction system, where each change must store a snapshot that can be returned to if needed; Turns out ignoring the TransactionContext and not saving any snapshots is a bad idea 😅 I’ve tested and it’s compatible with create fly (see screenshot where a compact mob farm with a blaze is being used to feed a blaze burner for a steam engine) and most probably other mods as well. Added Reliable Recipe Viewer integration that explains soul capturing
checking the recipe for a specific soul gem now only shows that specific entity instead of all soul capturing recipes soul capturing recipe now shows up before the duplication recipe soul gems can now be searched by the name of the entity they contain fix compact mob farm gui not rendering vanilla background overlay allow filling soul gem when held in the main hand fix dedicated server crashing Running in a dedicated server would crash because there are quite a few places where I referenced client-only classes in places that the jvm will load on the dedicated server as well. Mostly in the different block entity classes, where I had a clientTick method that had ClientLevel as one of it’s parameters. Even though that method would never get called on the dedicated server, java still wants it to exist when loading the class because it’s part of a method’s definition. My current solution is very very awful… I moved those things into methods in the client initializer and… well… yeah… it just looks and is awful: https://git.offsetmonkey538.top/OffsetMods538/Ultimate-Mob-Farms/src/commit/0.0.7/modded/src/main/java/top/offsetmonkey538/ultimatemobfarms/modded/UltimateMobFarmsModdedClient.java#L65 The real, foolproof solution would be using the split sources feature of loom, which creates a second source set and makes the main source set unable to access client classes. Only problem is that it’d be a bit annoying to fully get set up in my multiloader-version gradle system and would most definitely need many changes on MonkeyLib538 as well and I just am not up for doing that atm.
Getting closer and closer to the actual release… could this be the last devblog before that? Still not quite 100% about if the required kills for each mob are balanced, but it’s probably good enough. Definitely better than everything being 10 kills tho. Felt very off-balance when withers, which are hard to spawn and hard to kill, and pigs, which are just everywhere, required the same amount of kills to capture. Notable changes: Show soul capturing recipe in rrv when checking usages of spawn eggs Show tooltip with entity name when hovering entity in soul capturing rrv recipe Add item descriptions Fix being able to insert items into the compact mob farm inventory Make amount of kills required for capturing an entity different per entity. Update compact mob farm recipe (now uses soul spikes in the middle instead of stone bricks) Store soul gem colors as hex strings in entity tiers config. Much more understandable and easier to manually change the overrides config or whatever Make built-in packs use the mod icon using a mixin instead of copying the icon into the packs. This shaves like 80kb off the final jar which is quite a bit of unnecessary duplicate crap Remove some log spam that was for debugging
School starting with september really hit my productivity on this mod like a truck I am realizing the deadline for stardance is getting real close, so I think this is probably the point where I’ll have to ship it. There are still some TODOs in the code and bugs that need to be squashed and porting to 26.3 (which released like this week, thanks mojang ) and so I haven’t been comfortable marking the latest release as 1.0.0 yet or making announcements elsewhere, but the mod is now perfectly usable and I like where it is. Changes since last devblog: 26.2 support Injecting some items into vanilla loot chests Advancements 26.2 wasn’t actually as painful as I thought it’d be, which was a nice surprise. Adding advancements was a bit more of a pain with 26.2 support though as I needed custom criteria for some of the advancements (one for putting a soul gem in the compact mob farm and another for using a soul gem on a spawner) and Mojang, in their infinite wisdom, decided to move a bunch of advancement stuff around in 26.2.
Waow that’s quite a bit of stardust 😅 Quite happy with this project and the ratings it got on the first ship :D (except the one that accused my devlogs of being written by ai… My writing is not that bad, right? ) I noticed in the shipwrights’ review video that how upgrades work is not very obvious, they were trying to put a tier upgrade into a soul fan, which only accepts width, height and depth upgrades. It was mentioned in ratings that stuff is a bit hard to figure out in the beginning as well. So to fix that, I added some silhouettes of the supported upgrades shown in the slots and also a hover tooltip saying what’s supported. Oh and i’ve also added 26.3 support now
Added a progress bar to the Compact Mob Farm GUI that hopefully makes it much easier to understand when it’ll damage the entity and it doesn’t look like it’s just doing nothing lol, especially with the 30 second default time
Added an RRV screen showing what items can be acquired from the Compact Mob Farm. Shows the entity, the items it drops and the required tier upgrade level. Hoping this also helps with confusion on how stuff works
Started working on setting up a docs page for the mod. Mainly want it for explaining the data driven configuration, but having full pages to give more detailed explanations of the different features is also probably a nice touch. Made a new icon for the mod as well, it’s pretty much the same but higher res because the 256x256 one looked weird on the docs page. The docs are done using Starlight like all my other docs pages (see those here ) and lives at https://ultimate-mob-farms.docs.cursedmods.com/ and on the docs/master branch in the repo Currently it’s just the landing page, but it’ll have more stuff soon enough
Set up empty pages for all the blocks and items, fought quite a bit with astro/typescript to get the PageTitle override to correctly display the icons. Turns out astro’s optimized Image stuff doesn’t support animated images, no matter how much you try to force it to, so I ended up having to use the basic img tag
Ships:
This is a Minecraft mod for making mob farms, something similar to for example Mob Grinding Utils. It features item and xp collection, entity movement, spawner relocation and crafting, single block mob farms and some other stuff. Honestly, I’m quite proud just over the fact that I finally did finish this project (or at least got it to the point of being comfortable releasing it publically) and it’s hard to choose any specific features, but here I go… I do really like how the particle effects for the soul fan turned out, they’re quite satisfying imo. This is kind of unrelated to the mod, but I’m also proud of having helped out with the development of RRV, the recipe viewer mod I added compat with. While adding support for it in this mod, I noticed some bugs and crashes and stuff, which I PRed fixes for. It’s a bigger project with many complex things, so coming up with a list of all the things I found hard or took a lot of time and explaining all of them would probably go over whatever character limit this text box has lol. One thing that was a big PITA was the compact mob farm inventory. The original implementation I wrote was just… completely wrong, so I had to rewrite it. Then later I realized I overlooked like the most important part of the item transfer api (transactions, which are used for rolling back changes and stuff) so I had to rewrite it again, and then after that I rewrote quite a bit of it one more time because, after the last rewrite, I had accidentally made it possible for other blocks to insert into the inventory, which isn’t something I wanted as that seems quite OP. Another thing that comes to mind is figuring out the code for the soul fan’s range based on upgrades and strength at a given distance. The problem was that the coordinate you have to increase/decrease depends on the orientation of the block, so as an example, the depth upgrade would need to increase the Y pos when the block is placed pointing up and decrease it when pointing down, the X pos when facing north/south and the Z pos when facing east/west. For pushing the entities, I had to find the coordinates of the middle of the face the block is pointing, and add/subtract the correct coordinate to get the range in the depth direction, and then find the distance between each entity currently in range and the fan in just that plane for calculating the strength. For people testing out the project, I definitely do recommend also installing the Reliable Recipe Viewer (RRV) and Item Description mods...
|
1793004599.9761665
|
1793090999.9761665
|
|
36348
|
Chess Bot by @GunRattler28 | Stardance
|
GunRattler28
|
1
|
143.67
|
2096
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-21T06:00:32Z", "hours": 127.0, "multiplier": 16.58, "payout": 2096, "blessing": "neutral", "text": "I’m finally shipping the chess bot! So excited to see what people think of it :) . Before you try my project I highly suggest reading the README (on my github page https://github.com/GunRattler28/Chess-Bot ). It has a full list of all controls which will help you understand how to play. Anways, can’t wait to see what you guys think of it!", "repo": "https://github.com/GunRattler28/Chess-Bot", "demo": "https://github.com/GunRattler28/Chess-Bot/releases"}]...
|
[{"post_id": 80354, "ts": "202 [{"post_id": 80354, "ts": "2026-10-17T11:49:41Z", "hours": 0.8044, "text": "So, I’ve actually decided to work on making my bot playable on a website since that was one of the main things people said they would have wanted last ship and stardance is ending soon. But thats not why I’m posting. I’m posting because I spent the last 40 minutes rooting out a bug that caused my premoves to not be played. My first step was playing the release version that can be downloaded to see if the bug was there as well. Luckily it wasn’t so I went to my current commit on my main branch and kepy undoing commits (and saving them with git stash ) until the bug was gone. I then found that the bug only became a thing after I merged my commenting branch. Because of this I did the same thing of undoing commits and saving them on the commenting branch til I found the commit that caused the bug. I then went through all the changes until I found the problem. Then I fixed the bug, merged the fix to main then merged main into my other branches so that they would have the bug fix as well. I’ve already done some research and have found that pygbag seems to fit my needs for turning my pygame program into a website pretty well. Due to this I will probably use pygbag to get a website version of my chess bot up and running! Attached is a screenshot of the commit that caused the bug. Before the commit is on the left and after the commit is on the right. Try to find what caused the bug! If you can’t check the comments of the post as I am gonna say what the problem was there. I also attached a photo of how my git tree looks now and… it looks sooo messy lol."}, {"post_id": 79553, "ts": "2026-10-14T16:01:16Z", "hours": 2.835, "text": "I started getting bored of just commenting my code so I created a new branch in which I am trying to make my bot be able to play other bots. After some research, I found that the engine needs to be able to take in moves in the form of algebraic notation (a type of shorthand notation for moves. for example: Be4). Because of this I read a Wikipedia page on algebraic notation and made a function to convert between it and the parameters my makeMove() takes, that being: startRow , startColumn , endRow and endColumn . I have done this by first checking if the move is a castle (notated by O-O or O-O-O) then forming the full start and end coordinates by hardcoding the column values and finding the row based off the colour that is castling. Then I find what piece is moving (shown by the first letter) and if there is a promotion (shown by ‘=’ sign). Algebraic also has characters to show captures (x), checkmates (#) and checks (+), however the engine does not need these and so they are removed in 3 separate while loops. At this point I am left with just the end coordinates and maybe a combination of start coordinates. To find the full start coordinates (as they are all I am missing) I loop through the specific bitboard for the piece and whenever I find a square where there is a piece, I check whether it matches with the start coordinates I have, and if it does whether it can legally reach the end square. If it can then that is my piece and I return its start coordinates and the end coordinates it moves to (which is given in the input string). Currently, this function lives inside a random file in my project folder but my next step will be to properly integrate it into the rest of the code."}, {"post_id": 78191, "ts": "2026-10-09T22:40:08Z", "hours": 7.2036, "text": "Yup! I did what I said I would last time, and finished commenting ALL of logic.py . I don’t think I can describe how long this took and how annoying it was to have to go through 750+ lines of code and add comments explaining things. And then I realise that there’s just random stuff that I don’t even need. Anyway, I’m pretty satisfied that I managed to comment so much. This is definitely the largest file and so I’m happy I’ve gotten it out of the way. There’s not really much I can’t say like explaining and stuff because all I’ve done for the last 5 hours is explain stuff. Anyway once I’ve commented everything, I’ll probably make another devlog and then go and work on something else."}, {"post_id": 72816, "ts": "2026-09-23T19:46:37Z", "hours": 5.8231, "text": "Thanks for all the positive feedback and constructive criticism on my ship! Working to improve where people said and I am starting by trying to add comments to my code to explain what is happening. So far I’ve fully commented 3 / 7 files and am around 30% through commenting logic.py which contains most of the complicated code. Its taking a while but I really hope that this will help people understand what I am doing and that they will like my project more because of this. Next I am going to continue adding comments to logic.py and will probably have to make a devlog after just that since the file is pretty big and has slightly complicated stuff in it. Once again thanks to all the people who rated the project or gave feedback!"}, {"post_id": 71494, "ts": "2026-09-20T22:33:25Z", "hours": 2.5339, "text": "I’ve made a few small changes that help slightly speed the bot up. I stopped checking whether I have surpassed the time limit every move I search and instead every 2048 moves I search. This is better as it removes thousands of unnecessary library calls which each add a small amount of time to how long each move takes to search. Since computers are very fast 2048 doesn’t actually take long at all but it massively reduces the amount of times the pygame library is called. I also changed my move ordering to sort manually instead of with in a lambda function since this lambda functions are more inefficient. I am next going to ship the project!!!"}, {"post_id": 69354, "ts": "2026-09-16T21:16:32Z", "hours": 3.3497, "text": "Premoves finished! My premoves are now fully implemented and the branch is merged. Making the move with middle click removes that specific premove. Middle clicking a random square clears all premoves and arrows. I also added principal variation search (pvs) which is just searching moves that aren’t the previous best move with a tight move score boundary then researching them normally if they are better than expected. I am probably going to ship soon and so will start polishing the project up now."}, {"post_id": 63850, "ts": "2026-09-07T20:35:48Z", "hours": 6.9336, "text": "Way better premoves. I’ve updated my premove system to store multiple premoves. I did this by storing eaach premove as a tuple of ( startRow , startColumn , endRow , endColumn ). These tuples contain all the data I need to know and can be easily appended into an array. To clear a premove you can either do the same move again which removes that specific premove or tap the middle mouse button anywhere which clears all premoves and arrows. I also render a translucent version of the piece that I’ve moved to its premove destination and remove the texture for where it was originally. This helps you keep track of what your premoves are actually doing. I do this by drawing the board normally then looping through each move in the premoves array and drawing that piece at its correct destination in reduced alpha. Next I am going to try to improve my bot further so that I can push to a depth of around 10 during midgame."}, {"post_id": 59871, "ts": "2026-09-01T21:01:21Z", "hours": 5.3678, "text": "I’ve added FEN strings! FEN strings (Forsyth-Edwards Notation) are a way to store positions of chess games. They are used by many chess engines to allow players to start from different positions or midway through games. Adding these wasn’t too difficult as the strings are formatted in a nice way. I simply split up the FEN string into its 6 parts and set my variables to the value in the FEN string. To test if it worked I inputted the FEN string 4kb1r/p2n1ppp/4q3/4p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 1 16 which gives the position of the famous opera game directly before the queen sacrifice. I then set the bot colour to white and was glad to see that it immediately found the best move (the queen sacrifice). I also added premoves so that I can choose my move in advance. I did this by just storing the move I make when it is the bot’s turn and playing it as soon as the bot plays. However I can only premove 1 move ahead. Next I will try to allow the user to premove multiple moves ahead."}, {"post_id": 52243, "ts": "2026-08-22T10:35:52Z", "hours": 2.8078, "text": "Quiescent search is amazing! After adding it my bot instantly became better. A quiescent search just means that when evaluating a board state to a certain depth even if you reach that depth you need to evaluate until a quiet move (a move that isn’t a capture). This means that even if the bot reaches the max depth in the middle of a piece trade it won’t just think the move is amazing since all it can see it won a piece. Since I added the bot, when tested against other bots it has made 0 blunders! In fact it beat Li, a bot rated 2000 on chess.com ! I’m really proud of this and think it is really cool to say that my bot has beaten a 2000 rated bot. However, it only beat the bot once and so it could just be lucky. I was going to test it in 2 more games against the same bot but found myself getting bored of manually inputting moves into chess.com and my bot to get them to play each other. Therefore, I’m planning on making my bot able to play other bots on its own. To do this I will need to download the other bots and make my bot give properly formatted inputs and outputs."}, {"post_id": 51300, "ts": "2026-08-20T21:17:05Z", "hours": 3.5539, "text": "Massive improvements in depth! I added 2 changes: null move pruning and late move reduction. Null move pruning is when the bot ‘passes its turn’, when searching for the best move. The bot then evaluates the board at a reduced depth after letting the opponent play twice in a row. If it is still in a winning position then that means it is winning by a lot. This means that it can prune this branch since the opponent wouldn’t let the game get to this state and would make a better decision earlier in the tree. Since the opponent wouldn’t let the game get to this it means that further analysis isn’t necessary. Late move reduction works on the basis that I have good move ordering, which I just worked on so I would hope I do. Late move reduction means that I search the later moves at a reduced depth since the best moves are at the start and so later moves are likely bad. If they turn out to be good after the reduced evaluation depth then they are researched at the full depth. This helps reduce the amount of moves which need to be evaluated by a lot. Together null move pruning and late move reduction have taken my depth from around 6 - 7 in midgame to around depth 7 - 10 in midgame! In endgame this is even more. When I tested it in endgame it got to a depth of 13! My next change is something called quiescent search which will boost the bot’s elo by massive amounts as it should mostly stop the bot from making blunders."}, {"post_id": 50191, "ts": "2026-08-19T10:05:52Z", "hours": 1.9161, "text": "Move ordering improved! I’ve merged my SCRUM-29/move-ordering branch with main and now have my improved move ordering in main. This has let me go from a depth of 5 to almost always a depth of at least 6. I then merged main into SCRUM-42/improve-maintainability so that I could add comments to the code I added from the move ordering branch. Next I am going to add some comments explaining what things do."}, {"post_id": 48364, "ts": "2026-08-16T17:56:17Z", "hours": 4.4589, "text": "I’ve massively improved my organisation! I’m now properly utilising branches which is allowing me to work on multiple changes at the same time. Currently I am working on 2 branches. One is about improving my maintainability by adding comments so that other people can understand what I am doing and why. This also has the added benefit of me being able to make some small improvements and bug fixes as I am reading through all of my code. The second branch is about move ordering which is super important as it makes my alpha beta pruning more effective. Working on these changes on branches is useful because it not only keeps it organised and easy to see what each commit is for but also means that if I decide I don’t want the change anymore it is easy to remove as it isn’t mixed in with all the other changes. To help with this I’ve also created a Jira board which helps me keep my ideas organised. My branches are called SCRUM-NUMBER/NAME . The scrum number is given to me by Jira. As well as improving my organisation I also further improved my zobrist hashing by replacing using modulo on the hash to get the index of the transposition with using an and gate between my hash and the table size - 1 (which is just all 1s and a single 0 on the left most digit since the table size is a power of 2). I also stored my castle rights as a single 4 digit binary digit where each digit represents whether a certain rook has castling rights or not. My logic with this was since the point of bitboards is 12 integer is better than 64 integers, a single 4 digit integer is better than a dictionary of 4 values but I am not actually sure if this is true or not. On the maintainability branch so far I have added comments to all of main.py . On the move ordering branch I have improved my sorting from just sorting by most valuable capture and least valuable attacker which is only good for captures to also scoring promotions very highly. I also instantly push the previous best move to the front of the queue and score moves which cutoff branches in alpha beta pruning highly as well. Next I will try to add comments to one of my other files and improve my move ordering by not using lambda functions."}, {"post_id": 47220, "ts": "2026-08-15T00:10:15Z", "hours": 4.5128, "text": "I’ve improved my endgame condition. When testing the bot I found that during endgame it would sometimes move its king to the corners of the board. I realised that this was because it saw a queen on the board and due to the poor endgame condition it thought this meant that it wasn’t endgame and instead used the early / mid game position bonus table which rewards staying safe in the corners. However in endgame moving the king to the corner isn’t good as it makes checkmates easier for the opponent and means that the king isn’t used to help checkmate the opponent, which is crucial in certain endgames such as a king and queen against just a king. In situations like this the king is necessary in achieving a checkmate. I changed it to being if there is less than (2 black queens and 2 white queens and less than 16 pieces) or if there is less than 5 pieces not including pawns. This is more accurate and ensures the king actually helps win and tries to stop a checkmate on itself. I also improved my zobrist hashing by fully incrementing it. Previously I incremented it for everything except castling and en passant however now these are implemented as well. I also noticed that the bot would walk its king towards the centre of the board during the opening which puzzled me until I read through my code and realised its because I set totalPieces to 0, asked if it was endgame, and afterwards set totalPieces to the true value. This was pretty difficult to find as I couldn’t see it by just seeing if it thought it was endgame at the end of a move. This makes sure I can actually get my hashes in O(1) time. Next I am going to try and make my arrows darker when over each other."}, {"post_id": 46626, "ts": "2026-08-14T00:35:40Z", "hours": 3.7133, "text": "I’ve added a better endgame condition! Now endgame is determined if (there are no queens and less than 16 pieces on the board) or if there is less than 8 pieces on the board. This is better because it means when pawns promote the king doesn’t run to the corners or use the other position bonus table. I also improved my bot’s 3 fold repetition check when searching for moves by using a dictionary with hashes as keys and number of times they have appeared as values. This lets me check if I have been in the position 3 times before in O(1) instead of O(n) . I also improved my makeMove() and previousMove() functions by checking if its the bot searching for moves and if it is then only storing the key information instead of everything. To help simplify previousMove() I instead created a seperate function called unmakeMove() (clearly related to makeMove() ) to undo moves when the bot is searching. I also changed the time the bot has to move from 3 seconds to 1.5 seconds so that it feels snappier. Probably cos I have 0 patience when I want to test if the bot works :). Next I am going to try and make my bot faster by improving the move ordering so that alpha beta pruning can be more effective."}, {"post_id": 46469, "ts": "2026-08-13T18:10:03Z", "hours": 6.67, "text": "Iterative deepening! The bot now searches depths in an ascending order instead of descending. This is only possible thanks to my transposition tables but means that I can give the bot a time limit. Once the time limit is reached it just return the best move of the highest depth its fully searched. This means that I can search to different depths in different positions whilst making sure I always play within the time limit. This is good as it means I can have a high depth during the opening and endgame whilst having a medium depth during mid game instead of having a medium depth everywhere to ensure moves at midgame don’t take too long. Midgame usually has a lower depth due to the high number or possible moves that can be played. I can also easily change the time limit with just a single variable. This means I can get my bot to play faster but also worse or take longer but play better. I added incremental evaluation. This means that for each move, instead of looping through all 12 bitboards and recalculating the evaluation score from scratch I instead update it from the current evaluation score. So when I move a piece I subtract its old it’s material value and then add the material value if it still exists. The same happens for the position bonuses. This takes my time complexity from O(n) to O(1) which is a massive upgrade. These changes lets my depth in early game and endgame almost always stay at 7 whilst during midgame hover between depth 6 and depth 7. Currently I determine if I am in endgame if both queens are gone and the total amount of pieces is below 16 however I feel that this isn’t a good measure and I should improve this. Next I will try to improve efficiency by improving my move ordering so that the alpha beta pruning is more efficient."}, {"post_id": 45212, "ts": "2026-08-11T15:18:18Z", "hours": 7.8964, "text": "Transposition tables! I’ve added zobrist hashing so that I can create a dictionary that contains all of the board states I have already evaluated. Since many different moves can lead to the same position it means that I can save computing power by just getting the score of that board state instead of having to re-evaluate the board again. Zobrist hashes are just a way to represent the board in hash. This is useful as I can use them as the keys in my dictionary and quickly see if the current board state has been evaluated yet. I also fixed a bug that let the bot play illegal moves as there wasn’t a legality check after the aspiration window failed. An abort flag was also added that is set to True when the user undos or redos a move. This lets me instantly stop that thread’s search for the best move ensuring it doesn’t use unneccessary computing power. Next I am going to try and implement iterative deepening so that I can force the bot to move within a certain amount of time. This would let me make the bot play different ‘time controls’ by altering how long it has to think about what move it should play. I tested it against some bots from chess.com and it managed to beat Wally (a 1800 bot) but lost to Li (a 2000 bot)"}, {"post_id": 43276, "ts": "2026-08-08T13:19:50Z", "hours": 9.4272, "text": "Improved efficiency! I’ve improved the efficiency of the bot by sorting the possible moves better. This is useful as it means when the alpha beta pruning goes over everything it searches the best trees first. This means that it can prune more branches. I also removed some random integer conversions on my bitboards as they did nothing, since the bitboards are already integers. I also removed a restriction that didn’t let the player do anything on the bot’s turn. Now the player can draw during the bot’s turn. I also went across all of my code and changed it to use (row, column) instead of (column, row). This helps keep things cleaner. I then also changed the bot calculations from from using the fullyLegalMoves() function to the movementLegalMoves function(). fullyLegalMoves() just makes sure that the king isnt in check after the move. If it is then it undoes the move. By insteading doing this in my bot.py it means I can just not undo the move and immediately remove that move. This means that I don’t need to undo the move more times than needed. This is very helful as undoing a move takes up computing power. I also completely replaced the piece names with integers as this would be slightly better and I could use bit operations with integers. As well as this I also added a timer that shows how long the bot took to make its move. By adding all of these changes the bot reduced its time on the first move as white from ~4 seconds (with depth 4) to 3 seconds (with depth 5). This shows that it is much more efficient as, time taken increases exponentially as depth increases. As well as this 3 seconds is the earliest the bot can move and so the true speed is likely much less."}, {"post_id": 40993, "ts": "2026-08-04T21:24:23Z", "hours": 1.4964, "text": "Better arrows! I don’t remember where but there is one place where drawing arrows in a knights movement creates an L shaped arrow instead of just a normal arrow. I love this and so implemented it into my program. I also added aspiration windows. Aspiration windows work on the basis that moves don’t usually swing the score by a lot. This means that when going down paths we can set the lower and upper bounds to previous score ± window size. This helps prune more paths. If we find that the score is actually higher than we expect we search again but without the aspiration window. This helps remove lots of the obviously bad paths which makes the program much more efficient. Next I am going to add zobrist hashing so that I can use transposition tables."}, {"post_id": 40821, "ts": "2026-08-04T16:15:52Z", "hours": 2.5794, "text": "Colour randomisation! The colour you play as is chosen at random at the start of the game. The board is also automatically rotated so that you are at the bottom and the bot is at the top. This also helps to show which colour you are playing as. I also show the last move by making the starting square #97C997 and the ending square #8DCE8D. I did this as when I asked I watched someone play it I noticed that they would often undo the move, to see what the bot just did, then redo the move again. This helps make everything feel more polished. I like the ending square colour ( #8DCE8D ) but I’m not sure if I like the starting square colour ( #97C997 ). These colours are very easy to change though and so I can quickly edit them to test out different colours. I also realised that when I eventually ship the project most people who download it won’t have the font I use ( dynapuff ) installed. I tested it out to see what it is like without it and found that it crashed. To fix this, I implemented a try - except statement which sees if dynapuff exists on the user’s computer. If it does then it uses dynapuff which is how it is supposed to be played but if they don’t have the font it uses arial instead. Due to the strange spacing of dynapuff I used double spaces between the words on the game over messages, but when using arial the double spaces look quite strange. I also tweaked some of the position bonus values to further encourage castling. Next I am going to try to add a file to reward moves which keep keep the king safe."}, {"post_id": 40296, "ts": "2026-08-03T18:45:17Z", "hours": 10.2542, "text": "I’ve added position bonuses! I created a new file which rewards moves which place certain pieces in certain areas. For example pawns are rewarded for controlling the centre and pushing to the 7th rank (so that they can promote). The bot now tries to control squares and this means it now has proper openings. I also completely updated the file structure to split the responsibilities more clearly. I also updated main.py and logic.py and made them classes. Making logic.py a class means that I can use it for both the player actions and bot actions without them interfering. This also makes my previousMove() much cleaner as it means when the bot uses it, it doesn’t interfere with when the player uses it. Due to the new file structure it means that I can easily change the weights of each of the different modules to change how the bot plays easily. Later I will add a slider or at least a setting that lets the player control these modules. As well as this I also changed it so that drawing the same arrow again removes the arrow. Next I am going to try add another module that rewards moves which keep the king safe."}, {"post_id": 37668, "ts": "2026-07-30T15:47:33Z", "hours": 7.4286, "text": "I’ve added a bot! The main point of this was to link the new file I made ( bot.py ) to main.py . The bot currently just chooses moves based off of what would result in the best material difference between white (player) and black (bot). It calculates these moves with a depth of 4. Since the main point wasn’t to actually make a bot in one go the bot isn’t very good currently. However I still added alpha beta pruning. Alpha beta pruning works by storing the best guaranteed outcome for you (alpha) and the best guaranteed outcome for the opponent (beta). Whenever it finds a path where the opponent can force a move that is worse than the alpha, it immediately stops going down that path. The same happens for beta. I also removed some duplicated code in main.py and fixed the undo and redo move logic as I forgot to check if it still worked properly after switching from tkinter to pygame. Currently you can only tap the buttons and but can’t hold to go back multiple moves. Undoing and redoing moves with a bot was a bit confusing for me and so I decided to make it so that when undoing and redoing there is 3 seconds before the bot moves. During these 3 seconds you can go forwards or backwards to reset the timer. I used threading so that the bot starts to calculate what move it would make at the same time as the 3 seconds are passing. This means that if you decide to stay on the turn you don’t need to wait as long. I also blurred the background of the the promotion GUI so that it is grabs the players attention. Next I am going to try and add a better bot by assigning each possible move a score that is based off of the squares it controls, offensive and defensive opportunities and potentials for forks (when 2 pieces are being attacked by 1 piece so only one piece can move out of danger)."}, {"post_id": 36896, "ts": "2026-07-29T08:41:59Z", "hours": 1.9431, "text": "I’ve split my file into 5 now. There is moveGeneration.py which calculates all the legal moves, moveExecution.py which actually moves the pieces, updateBoard.py which updates the board, gui.py which handles graphics (like arrows, promotion page and clicks) and main.py which says what functions should happen when an input is given and has a while loop for while the game is running (as is needed by pygame). Splitting the file makes it much easier to debug, keep track and add features instead of just having one ~1000 line file where everything is jumbled up. Next I am going to start work on the actual bot."}, {"post_id": 36538, "ts": "2026-07-28T18:38:30Z", "hours": 1.1517, "text": "Insufficient material and 50 move rule! These were the last things I needed to add before step 1 was complete. Now the next step is to actually add the bot! I’ve got everything I need down for a game of chess before 2 players. I added insufficient material by creating a new insufficientMaterial() . Inside the function are some if statements that determine whether winning is still possible (not assisted by opponent going into the corner). I also added the 50 move rule by checking moves since last pawn advancement or capture and if it exceeds 50 then end the game. I also made it so that once the game ends you can go undo moves and continue playing instead of just having the game end. Next I am going to try to clean up my code, split the code into multiple files and optimise it."}, {"post_id": 36025, "ts": "2026-07-27T20:54:24Z", "hours": 1.3014, "text": "En passant has been added. I find if it is legal by making sure the pawn capturing is on its fifth rank and the pawn being captured is moved 2 forward. Thats all I need for en passant (also only available for the first go it is there). I also made my program more efficient by ensuring I only rely on an array for finding what piece is on an index and drawing. Everything else uses bitboards which helps me fully utilise bitboards. I now have 2 things left: 50 move rule and Insufficient Material. Both of these end in a draw and are the last things I need for my program to have all the rules of chess! Next I will add the 50 move rule"}, {"post_id": 34600, "ts": "2026-07-25T13:43:51Z", "hours": 2.65, "text": "I was so unimpressed by how my old arrows looked I just completely switched libraries! I now use pygame instead of tkinter. It offers much more graphical customisability and now I can draw arrows (and other shapes) with true transparency instead of just stipples. One of the main downsides of pygame is that it constantly redraws each frame. This takes computing power and drains battery. To stop this I created a redraw boolean which tells my script when to redraw. This means instead of redrawing every single frame I redraw whenever something actually changes. Due to pygame I also customised the arrows so that the tails are rounded. This means that multiple arrows from the same point looks much cleaner. I also get true translucency instead of stipples and I added an icon!"}, {"post_id": 34132, "ts": "2026-07-24T17:06:08Z", "hours": 4.1839, "text": "Need to get your strategies into something you can see? Lines let you do just that. Right clicking and dragging draws a line that follows your cursor around. Right clicking again places the line. The lines are automatically centred so that they snap to the centre of the squares. If you line starts and ends at the same place it creates a circle instead. I also spent lots of time making sure my bitboards are used properly as when I created the array last time I used it for more than I intended and lost most of the arrays of bitboards. I also noticed that the promotion GUI wasn’t properly centred and so fixed that. I don’t really like the lines as they use stipples instead of a solid colour and overall don’t look nice but tkinter doesn’t offer transparency apart from stipples and doesn’t allow lots of customisation of the arrows. Next I will likely try to add en passant."}, {"post_id": 33646, "ts": "2026-07-23T18:39:22Z", "hours": 4.0794, "text": "Finally, promotions! This was the last major part of chess that I didn’t have. I added it by finding the row of the piece when I move something. I hardcoded it so that it knows when the pawn is at the last row. When at the last row, it runs a choosePromotion() function. That function then creates a frame inside of my window. I then loop for each of the choices of the pieces I can choose. For each of these pieces I create a button with the piece (in the correct colour) in the centre. The frame waits until I pick a choice before adding a 1 on that piece’s bitboard at the correct location and removes the 1 on the pawn bitboard. Thats all I need to do to register a promotion! The rest of the time I spent optimising my code and realising that I didn’t have to use just a bitboard or an array, I could use both. Knowing that, I removed my getPiece() function and instead used an array to find the piece at a row and column. This is more efficient as arrays have a lookup time of O(1) whereas the getPiece() function has a lookup time of O(n) in the worst case. This is because my getPiece() function worked by cycling through each bitboard to find what piece was at a certain coordinate. This meant that I could also remove my totalPieces bitboard since this was only used in the getPiece() function to avoid cycling through all 12 bitboards if there was nothing there. Overall I’m really happy with how everything is going as I have all I really need for a proper game of 2 player chess. Next I am going to try and add the small things I am still missing such as En passant and the 50 move rule."}, {"post_id": 33388, "ts": "2026-07-23T09:22:55Z", "hours": 1.5583, "text": "Stalemates and three-fold repetition have now been added. Stalemates are calculated if legalMoves(turnColour) returns none but the king is not in check. I find if there is three-fold repetition by storing a hash of the board every move. This is stored in a dictionary as dictionaries are much better than arrays for lookups. After each move I see if that board state is in the dictionary. If it is I increase its value by 1. If not I set its value to 1. I then see how many times its reached that board state and if it is 3 times I end the game and show bright red text saying ‘Three-fold Repetition! Nobody wins!’. The hash includes piece positions, turn colour and castling rights as these are 3 of the 4 criteria that FIDE use. The fourth is en passant however that has not been added yet. Next I will add pawn promotions as this is the last major thing I don’t have."}, {"post_id": 33184, "ts": "2026-07-22T21:11:59Z", "hours": 2.3886, "text": "Castling! I’ve actually added castling this time. The castling also works with undo / redo move so that it undoes and redoes the move correctly. I’m starting to think my python file is getting a bit big now so I also created a few helper functions to help reduce code duplication. Its 572 lines currently. Luckily I am quite close to finishing the actual board and getting everything ready for a 2 person game of chess. This was my first goal so that the bot just becomes one of the players. Once I’m ready for a 2 person game of chess I’ll try to create another python file for the bot. This will help me keep track of what is doing what. Next I am going to add pawn promotion as that’s one of the biggest things that I don’t have yet. It is essential in late game and so is one of my priorities."}, {"post_id": 32902, "ts": "2026-07-22T11:18:43Z", "hours": 2.9108, "text": "Ever misclick and sell the game? Well not anymore! You can now undo moves by tapping the left arrow on the keybord and also redo those same moves if you change your mind by tapping the right arrow ! I did this by adding a saveMove() function which I run after every move I make. This saves the details of the last move to the moveHistory array: Piece Moved Start Position End Position Piece Captured (Just “” if None) Turn Colour Moves so far In my undoMove() function I remove the last move done and add it to an array called redoHistory . I then set all the details to the last entry in moveHistory . I do the same in my redoMove() function excpet I use the last entry in redoHistory instead. I’ve allowed undos after checkmate so that you can look for what went wrong and try other moves that might’ve stopped it. I also added sound! You’ll be able to see / hear all of this if the video uploads instead of just a screenshot. Next I am going to add castling (for real this time)."}, {"post_id": 32585, "ts": "2026-07-21T21:11:56Z", "hours": 2.6961, "text": "The game can now end! I have added a check to see if it is checkmate. When it is checkmate bright red text appears on the screen that says “Checkmate! WINNER wins!” (it says the colour which won not WINNER). I have also changed it so that when a player is in check they are forced to make a move that stops them from being in check. The only circles that come up are ones which would block the check to make it a bit easier for players. I’ve also made it so that my new function blockCheck() takes the calculations made by calculateLegalMoves() and uses it to display and allow only legal moves. As well as this anywhere that used to call calculateLegalMoves() now calls blockCheck instead. By making sure each function does 1 task it makes debugging easier ( not that anything would ever go wrong… ). Next I am going to try and add castling as this is a crucial mechanic that is used often."}, {"post_id": 32399, "ts": "2026-07-21T15:39:28Z", "hours": 2.8764, "text": "I’ve added better red and green overlays that are translucent so that you can see through them an easily know what piece you are taking. But most importantly, I’ve added check detection. I created a few new functions to do this. The first function I created was the isSquareAttacked(row, column, atkColour) function. It works by cycling through the bitboards and checking if they are atkColour or not. If they are find the type of piece and those pieces could attack the king. I think this will be helpful when I start to actually make the bot. I also created a simple findKing(colour) function to see where the king is so that I can parse that information into the isSquareAttacked() function. I then get a boolean. If it is true (the king is in check) I add the red overlay to the king so that the player easily knows they are in check but I don’t actually force them to block the attack yet. I think the overlay should be different but am not sure what to make it (gimme some ideas). I also created a slidingMoves() function as in my calculateLegalMoves() function I had ~40 lines of almost fully repeated code. Next I am going to force the player to block the check and end the game if it is checkmate."}, {"post_id": 32072, "ts": "2026-07-20T23:45:34Z", "hours": 0.9622, "text": "Finally took the time to change the piece textures so that black has an actual piece colour and you don’t get confused about whose pieces are whose"}, {"post_id": 31762, "ts": "2026-07-20T12:27:13Z", "hours": 3.4017, "text": "I’ve added dots to show where you can move when you click on a piece. If the position you want to move the piece to the dot is green but if it has an enemy piece the dot is red. Sadly, tkinter (the library I’m using) doesn’t support transparency. Because of this the dot takes up some of piece you want to capture. I can fix this by instead of drawing a circle drawing a translucent image… but tbh i rly cba. I will eventually do it to make it look better and actually add black pieces but i want to focus on getting things to actually work for now. The reason why this took me so long to implement is because as I was making the function to draw the dots I found that it was doing something very similar to my validMove() function but it was MUCH more efficient. In the old function I went through every square on the board and looked if the piece selected could get there. This is very inefficient and would build up quickly when I call the function 1000s of times per second (when I eventually add the bot). In my new function I look at the selected piece and have an array of each of the places it can move relative to its position. I then add the dots to those places if they are able to move there. This ended up with me just completely removing the old function and knowing its a valid move if there is a dot there. Next I am going to add something to see if the king is in check and maybe add some text when it is checkmate."}, {"post_id": 31082, "ts": "2026-07-19T06:07:07Z", "hours": 2.55, "text": "I’ve implemented bitboards instead of an array to store my board. At first I didn’t understand why bitboards were so good but after an amazing youtube video ( here ) I understand them and love them. I use them by having a 64 bit long integer (wow thats long) that represents the 8 by 8 board. Each bit can either be a 0 or 1 and represent whether there is a piece there or not. But you might think then how do you know what type of piece each 1 is? Thats why I use 12 bitboards (technically theres 1 more I added for extra efficiency but I don’t need that). Each of these 12 bitboards represents a type of piece in a specific colour (for example: white pawns and black pawns have 2 different bitboards). Then when I want to move pieces I create a position integer which is just 63 zeroes and a single 1 where the piece should be. I then invert this and use an AND statement so that all of the results for the AND are true where there are pieces apart from where I set the 1 at the start (though it is now a 0)."}, {"post_id": 30753, "ts": "2026-07-18T16:10:19Z", "hours": 3.6586, "text": "Added move legality. You can now mostly only make legal moves however I have not added something to checks if the king is in check. I made sure the move was legal by taking the startRow startColumn and endRow endColumn. I then look at what piece is being moved and ensure it is ok. If it isn’t nothing happens when you try to click and you have to make another move. I made sure that the correct colour moves as well. I also haven’t added pawn promotions, castling or en passant (tbh im not 100% certain on the rules of en passant). I couldn’t add castling as I don’t have a move history so would have no way of knowing if the king or rook have moved before. I’m now working on converting my current way of storing the board (a 2D array) into bitboards. After some research I found that bitboards are more than 5 times more efficient than arrays!"}, {"post_id": 30312, "ts": "2026-07-17T19:23:30Z", "hours": 2.0086, "text": "I can now move pieces! But there is no legality check yet. I also added a green outline if you select a piece. It works by listening for a click. Then when it gets a click it takes mouseX and mouseY and divides by positionSize to find which row and column it is on. It then checks against the board to see what is on that position. If it is a piece then it creates an outline and sets that as the active square. If it is empty AND active square has a value, it moves the piece."}, {"post_id": 30018, "ts": "2026-07-17T08:18:30Z", "hours": 1.4367, "text": "I’ve finally decided to actually making a chess bot and stick to it! So far I’ve set up the chess board for just visuals. Everything right now is purely visual. I am using python and the tkinter library."}]...
|
Title: Chess Bot by @GunRattler28 | Stardance
Dev Title: Chess Bot by @GunRattler28 | Stardance
Devlogs:
I’ve finally decided to actually making a chess bot and stick to it! So far I’ve set up the chess board for just visuals. Everything right now is purely visual. I am using python and the tkinter library.
I can now move pieces! But there is no legality check yet. I also added a green outline if you select a piece. It works by listening for a click. Then when it gets a click it takes mouseX and mouseY and divides by positionSize to find which row and column it is on. It then checks against the board to see what is on that position. If it is a piece then it creates an outline and sets that as the active square. If it is empty AND active square has a value, it moves the piece.
Added move legality. You can now mostly only make legal moves however I have not added something to checks if the king is in check. I made sure the move was legal by taking the startRow startColumn and endRow endColumn. I then look at what piece is being moved and ensure it is ok. If it isn’t nothing happens when you try to click and you have to make another move. I made sure that the correct colour moves as well. I also haven’t added pawn promotions, castling or en passant (tbh im not 100% certain on the rules of en passant). I couldn’t add castling as I don’t have a move history so would have no way of knowing if the king or rook have moved before. I’m now working on converting my current way of storing the board (a 2D array) into bitboards. After some research I found that bitboards are more than 5 times more efficient than arrays!
I’ve implemented bitboards instead of an array to store my board. At first I didn’t understand why bitboards were so good but after an amazing youtube video ( here ) I understand them and love them. I use them by having a 64 bit long integer (wow thats long) that represents the 8 by 8 board. Each bit can either be a 0 or 1 and represent whether there is a piece there or not. But you might think then how do you know what type of piece each 1 is? Thats why I use 12 bitboards (technically theres 1 more I added for extra efficiency but I don’t need that). Each of these 12 bitboards represents a type of piece in a specific colour (for example: white pawns and black pawns have 2 different bitboards). Then when I want to move pieces I create a position integer which is just 63 zeroes and a single 1 where the piece should be. I then invert this and use an AND statement so that all of the results for the AND are true where there are pieces apart from where I set the 1 at the start (though it is now a 0).
I’ve added dots to show where you can move when you click on a piece. If the position you want to move the piece to the dot is green but if it has an enemy piece the dot is red. Sadly, tkinter (the library I’m using) doesn’t support transparency. Because of this the dot takes up some of piece you want to capture. I can fix this by instead of drawing a circle drawing a translucent image… but tbh i rly cba. I will eventually do it to make it look better and actually add black pieces but i want to focus on getting things to actually work for now. The reason why this took me so long to implement is because as I was making the function to draw the dots I found that it was doing something very similar to my validMove() function but it was MUCH more efficient. In the old function I went through every square on the board and looked if the piece selected could get there. This is very inefficient and would build up quickly when I call the function 1000s of times per second (when I eventually add the bot). In my new function I look at the selected piece and have an array of each of the places it can move relative to its position. I then add the dots to those places if they are able to move there. This ended up with me just completely removing the old function and knowing its a valid move if there is a dot there. Next I am going to add something to see if the king is in check and maybe add some text when it is checkmate.
Finally took the time to change the piece textures so that black has an actual piece colour and you don’t get confused about whose pieces are whose
I’ve added better red and green overlays that are translucent so that you can see through them an easily know what piece you are taking. But most importantly, I’ve added check detection. I created a few new functions to do this. The first function I created was the isSquareAttacked(row, column, atkColour) function. It works by cycling through the bitboards and checking if they are atkColour or not. If they are find the type of piece and those pieces could attack the king. I think this will be helpful when I start to actually make the bot. I also created a simple findKing(colour) function to see where the king is so that I can parse that information into the isSquareAttacked() function. I then get a boolean. If it is true (the king is in check) I add the red overlay to the king so that the player easily knows they are in check but I don’t actually force them to block the attack yet. I think the overlay should be different but am not sure what to make it (gimme some ideas). I also created a slidingMoves() function as in my calculateLegalMoves() function I had ~40 lines of almost fully repeated code. Next I am going to force the player to block the check and end the game if it is checkmate.
The game can now end! I have added a check to see if it is checkmate. When it is checkmate bright red text appears on the screen that says “Checkmate! WINNER wins!” (it says the colour which won not WINNER). I have also changed it so that when a player is in check they are forced to make a move that stops them from being in check. The only circles that come up are ones which would block the check to make it a bit easier for players. I’ve also made it so that my new function blockCheck() takes the calculations made by calculateLegalMoves() and uses it to display and allow only legal moves. As well as this anywhere that used to call calculateLegalMoves() now calls blockCheck instead. By making sure each function does 1 task it makes debugging easier ( not that anything would ever go wrong… ). Next I am going to try and add castling as this is a crucial mechanic that is used often.
Ever misclick and sell the game? Well not anymore! You can now undo moves by tapping the left arrow on the keybord and also redo those same moves if you change your mind by tapping the right arrow ! I did this by adding a saveMove() function which I run after every move I make. This saves the details of the last move to the moveHistory array: Piece Moved Start Position End Position Piece Captured (Just “” if None) Turn Colour Moves so far In my undoMove() function I remove the last move done and add it to an array called redoHistory . I then set all the details to the last entry in moveHistory . I do the same in my redoMove() function excpet I use the last entry in redoHistory instead. I’ve allowed undos after checkmate so that you can look for what went wrong and try other moves that might’ve stopped it. I also added sound! You’ll be able to see / hear all of this if the video uploads instead of just a screenshot. Next I am going to add castling (for real this time).
Castling! I’ve actually added castling this time. The castling also works with undo / redo move so that it undoes and redoes the move correctly. I’m starting to think my python file is getting a bit big now so I also created a few helper functions to help reduce code duplication. Its 572 lines currently. Luckily I am quite close to finishing the actual board and getting everything ready for a 2 person game of chess. This was my first goal so that the bot just becomes one of the players. Once I’m ready for a 2 person game of chess I’ll try to create another python file for the bot. This will help me keep track of what is doing what. Next I am going to add pawn promotion as that’s one of the biggest things that I don’t have yet. It is essential in late game and so is one of my priorities.
Stalemates and three-fold repetition have now been added. Stalemates are calculated if legalMoves(turnColour) returns none but the king is not in check. I find if there is three-fold repetition by storing a hash of the board every move. This is stored in a dictionary as dictionaries are much better than arrays for lookups. After each move I see if that board state is in the dictionary. If it is I increase its value by 1. If not I set its value to 1. I then see how many times its reached that board state and if it is 3 times I end the game and show bright red text saying ‘Three-fold Repetition! Nobody wins!’. The hash includes piece positions, turn colour and castling rights as these are 3 of the 4 criteria that FIDE use. The fourth is en passant however that has not been added yet. Next I will add pawn promotions as this is the last major thing I don’t have.
Finally, promotions! This was the last major part of chess that I didn’t have. I added it by finding the row of the piece when I move something. I hardcoded it so that it knows when the pawn is at the last row. When at the last row, it runs a choosePromotion() function. That function then creates a frame inside of my window. I then loop for each of the choices of the pieces I can choose. For each of these pieces I create a button with the piece (in the correct colour) in the centre. The frame waits until I pick a choice before adding a 1 on that piece’s bitboard at the correct location and removes the 1 on the pawn bitboard. Thats all I need to do to register a promotion! The rest of the time I spent optimising my code and realising that I didn’t have to use just a bitboard or an array, I could use both. Knowing that, I removed my getPiece() function and instead used an array to find the piece at a row and column. This is more efficient as arrays have a lookup time of O(1) whereas the getPiece() function has a lookup time of O(n) in the worst case. This is because my getPiece() function worked by cycling through each bitboard to find what piece was at a certain coordinate. This meant that I could also remove my totalPieces bitboard since this was only used in the getPiece() function to avoid cycling through all 12 bitboards if there was nothing there. Overall I’m really happy with how everything is going as I have all I really need for a proper game of 2 player chess. Next I am going to try and add the small things I am still missing such as En passant and the 50 move rule.
Need to get your strategies into something you can see? Lines let you do just that. Right clicking and dragging draws a line that follows your cursor around. Right clicking again places the line. The lines are automatically centred so that they snap to the centre of the squares. If you line starts and ends at the same place it creates a circle instead. I also spent lots of time making sure my bitboards are used properly as when I created the array last time I used it for more than I intended and lost most of the arrays of bitboards. I also noticed that the promotion GUI wasn’t properly centred and so fixed that. I don’t really like the lines as they use stipples instead of a solid colour and overall don’t look nice but tkinter doesn’t offer transparency apart from stipples and doesn’t allow lots of customisation of the arrows. Next I will likely try to add en passant.
I was so unimpressed by how my old arrows looked I just completely switched libraries! I now use pygame instead of tkinter. It offers much more graphical customisability and now I can draw arrows (and other shapes) with true transparency instead of just stipples. One of the main downsides of pygame is that it constantly redraws each frame. This takes computing power and drains battery. To stop this I created a redraw boolean which tells my script when to redraw. This means instead of redrawing every single frame I redraw whenever something actually changes. Due to pygame I also customised the arrows so that the tails are rounded. This means that multiple arrows from the same point looks much cleaner. I also get true translucency instead of stipples and I added an icon!
En passant has been added. I find if it is legal by making sure the pawn capturing is on its fifth rank and the pawn being captured is moved 2 forward. Thats all I need for en passant (also only available for the first go it is there). I also made my program more efficient by ensuring I only rely on an array for finding what piece is on an index and drawing. Everything else uses bitboards which helps me fully utilise bitboards. I now have 2 things left: 50 move rule and Insufficient Material. Both of these end in a draw and are the last things I need for my program to have all the rules of chess! Next I will add the 50 move rule
Insufficient material and 50 move rule! These were the last things I needed to add before step 1 was complete. Now the next step is to actually add the bot! I’ve got everything I need down for a game of chess before 2 players. I added insufficient material by creating a new insufficientMaterial() . Inside the function are some if statements that determine whether winning is still possible (not assisted by opponent going into the corner). I also added the 50 move rule by checking moves since last pawn advancement or capture and if it exceeds 50 then end the game. I also made it so that once the game ends you can go undo moves and continue playing instead of just having the game end. Next I am going to try to clean up my code, split the code into multiple files and optimise it.
I’ve split my file into 5 now. There is moveGeneration.py which calculates all the legal moves, moveExecution.py which actually moves the pieces, updateBoard.py which updates the board, gui.py which handles graphics (like arrows, promotion page and clicks) and main.py which says what functions should happen when an input is given and has a while loop for while the game is running (as is needed by pygame). Splitting the file makes it much easier to debug, keep track and add features instead of just having one ~1000 line file where everything is jumbled up. Next I am going to start work on the actual bot.
I’ve added a bot! The main point of this was to link the new file I made ( bot.py ) to main.py . The bot currently just chooses moves based off of what would result in the best material difference between white (player) and black (bot). It calculates these moves with a depth of 4. Since the main point wasn’t to actually make a bot in one go the bot isn’t very good currently. However I still added alpha beta pruning. Alpha beta pruning works by storing the best guaranteed outcome for you (alpha) and the best guaranteed outcome for the opponent (beta). Whenever it finds a path where the opponent can force a move that is worse than the alpha, it immediately stops going down that path. The same happens for beta. I also removed some duplicated code in main.py and fixed the undo and redo move logic as I forgot to check if it still worked properly after switching from tkinter to pygame. Currently you can only tap the buttons and but can’t hold to go back multiple moves. Undoing and redoing moves with a bot was a bit confusing for me and so I decided to make it so that when undoing and redoing there is 3 seconds before the bot moves. During these 3 seconds you can go forwards or backwards to reset the timer. I used threading so that the bot starts to calculate what move it would make at the same time as the 3 seconds are passing. This means that if you decide to stay on the turn you don’t need to wait as long. I also blurred the background of the the promotion GUI so that it is grabs the players attention. Next I am going to try and add a better bot by assigning each possible move a score that is based off of the squares it controls, offensive and defensive opportunities and potentials for forks (when 2 pieces are being attacked by 1 piece so only one piece can move out of danger).
I’ve added position bonuses! I created a new file which rewards moves which place certain pieces in certain areas. For example pawns are rewarded for controlling the centre and pushing to the 7th rank (so that they can promote). The bot now tries to control squares and this means it now has proper openings. I also completely updated the file structure to split the responsibilities more clearly. I also updated main.py and logic.py and made them classes. Making logic.py a class means that I can use it for both the player actions and bot actions without them interfering. This also makes my previousMove() much cleaner as it means when the bot uses it, it doesn’t interfere with when the player uses it. Due to the new file structure it means that I can easily change the weights of each of the different modules to change how the bot plays easily. Later I will add a slider or at least a setting that lets the player control these modules. As well as this I also changed it so that drawing the same arrow again removes the arrow. Next I am going to try add another module that rewards moves which keep the king safe.
Colour randomisation! The colour you play as is chosen at random at the start of the game. The board is also automatically rotated so that you are at the bottom and the bot is at the top. This also helps to show which colour you are playing as. I also show the last move by making the starting square #97C997 and the ending square #8DCE8D. I did this as when I asked I watched someone play it I noticed that they would often undo the move, to see what the bot just did, then redo the move again. This helps make everything feel more polished. I like the ending square colour ( #8DCE8D ) but I’m not sure if I like the starting square colour ( #97C997 ). These colours are very easy to change though and so I can quickly edit them to test out different colours. I also realised that when I eventually ship the project most people who download it won’t have the font I use ( dynapuff ) installed. I tested it out to see what it is like without it and found that it crashed. To fix this, I implemented a try - except statement which sees if dynapuff exists on the user’s computer. If it does then it uses dynapuff which is how it is supposed to be played but if they don’t have the font it uses arial instead. Due to the strange spacing of dynapuff I used double spaces between the words on the game over messages, but when using arial the double spaces look quite strange. I also tweaked some of the position bonus values to further encourage castling. Next I am going to try to add a file to reward moves which keep keep the king safe.
Better arrows! I don’t remember where but there is one place where drawing arrows in a knights movement creates an L shaped arrow instead of just a normal arrow. I love this and so implemented it into my program. I also added aspiration windows. Aspiration windows work on the basis that moves don’t usually swing the score by a lot. This means that when going down paths we can set the lower and upper bounds to previous score ± window size. This helps prune more paths. If we find that the score is actually higher than we expect we search again but without the aspiration window. This helps remove lots of the obviously bad paths which makes the program much more efficient. Next I am going to add zobrist hashing so that I can use transposition tables.
Improved efficiency! I’ve improved the efficiency of the bot by sorting the possible moves better. This is useful as it means when the alpha beta pruning goes over everything it searches the best trees first. This means that it can prune more branches. I also removed some random integer conversions on my bitboards as they did nothing, since the bitboards are already integers. I also removed a restriction that didn’t let the player do anything on the bot’s turn. Now the player can draw during the bot’s turn. I also went across all of my code and changed it to use (row, column) instead of (column, row). This helps keep things cleaner. I then also changed the bot calculations from from using the fullyLegalMoves() function to the movementLegalMoves function(). fullyLegalMoves() just makes sure that the king isnt in check after the move. If it is then it undoes the move. By insteading doing this in my bot.py it means I can just not undo the move and immediately remove that move. This means that I don’t need to undo the move more times than needed. This is very helful as undoing a move takes up computing power. I also completely replaced the piece names with integers as this would be slightly better and I could use bit operations with integers. As well as this I also added a timer that shows how long the bot took to make its move. By adding all of these changes the bot reduced its time on the first move as white from ~4 seconds (with depth 4) to 3 seconds (with depth 5). This shows that it is much more efficient as, time taken increases exponentially as depth increases. As well as this 3 seconds is the earliest the bot can move and so the true speed is likely much less.
Transposition tables! I’ve added zobrist hashing so that I can create a dictionary that contains all of the board states I have already evaluated. Since many different moves can lead to the same position it means that I can save computing power by just getting the score of that board state instead of having to re-evaluate the board again. Zobrist hashes are just a way to represent the board in hash. This is useful as I can use them as the keys in my dictionary and quickly see if the current board state has been evaluated yet. I also fixed a bug that let the bot play illegal moves as there wasn’t a legality check after the aspiration window failed. An abort flag was also added that is set to True when the user undos or redos a move. This lets me instantly stop that thread’s search for the best move ensuring it doesn’t use unneccessary computing power. Next I am going to try and implement iterative deepening so that I can force the bot to move within a certain amount of time. This would let me make the bot play different ‘time controls’ by altering how long it has to think about what move it should play. I tested it against some bots from chess.com and it managed to beat Wally (a 1800 bot) but lost to Li (a 2000 bot)
Iterative deepening! The bot now searches depths in an ascending order instead of descending. This is only possible thanks to my transposition tables but means that I can give the bot a time limit. Once the time limit is reached it just return the best move of the highest depth its fully searched. This means that I can search to different depths in different positions whilst making sure I always play within the time limit. This is good as it means I can have a high depth during the opening and endgame whilst having a medium depth during mid game instead of having a medium depth everywhere to ensure moves at midgame don’t take too long. Midgame usually has a lower depth due to the high number or possible moves that can be played. I can also easily change the time limit with just a single variable. This means I can get my bot to play faster but also worse or take longer but play better. I added incremental evaluation. This means that for each move, instead of looping through all 12 bitboards and recalculating the evaluation score from scratch I instead update it from the current evaluation score. So when I move a piece I subtract its old it’s material value and then add the material value if it still exists. The same happens for the position bonuses. This takes my time complexity from O(n) to O(1) which is a massive upgrade. These changes lets my depth in early game and endgame almost always stay at 7 whilst during midgame hover between depth 6 and depth 7. Currently I determine if I am in endgame if both queens are gone and the total amount of pieces is below 16 however I feel that this isn’t a good measure and I should improve this. Next I will try to improve efficiency by improving my move ordering so that the alpha beta pruning is more efficient.
I’ve added a better endgame condition! Now endgame is determined if (there are no queens and less than 16 pieces on the board) or if there is less than 8 pieces on the board. This is better because it means when pawns promote the king doesn’t run to the corners or use the other position bonus table. I also improved my bot’s 3 fold repetition check when searching for moves by using a dictionary with hashes as keys and number of times they have appeared as values. This lets me check if I have been in the position 3 times before in O(1) instead of O(n) . I also improved my makeMove() and previousMove() functions by checking if its the bot searching for moves and if it is then only storing the key information instead of everything. To help simplify previousMove() I instead created a seperate function called unmakeMove() (clearly related to makeMove() ) to undo moves when the bot is searching. I also changed the time the bot has to move from 3 seconds to 1.5 seconds so that it feels snappier. Probably cos I have 0 patience when I want to test if the bot works :). Next I am going to try and make my bot faster by improving the move ordering so that alpha beta pruning can be more effective.
I’ve improved my endgame condition. When testing the bot I found that during endgame it would sometimes move its king to the corners of the board. I realised that this was because it saw a queen on the board and due to the poor endgame condition it thought this meant that it wasn’t endgame and instead used the early / mid game position bonus table which rewards staying safe in the corners. However in endgame moving the king to the corner isn’t good as it makes checkmates easier for the opponent and means that the king isn’t used to help checkmate the opponent, which is crucial in certain endgames such as a king and queen against just a king. In situations like this the king is necessary in achieving a checkmate. I changed it to being if there is less than (2 black queens and 2 white queens and less than 16 pieces) or if there is less than 5 pieces not including pawns. This is more accurate and ensures the king actually helps win and tries to stop a checkmate on itself. I also improved my zobrist hashing by fully incrementing it. Previously I incremented it for everything except castling and en passant however now these are implemented as well. I also noticed that the bot would walk its king towards the centre of the board during the opening which puzzled me until I read through my code and realised its because I set totalPieces to 0, asked if it was endgame, and afterwards set totalPieces to the true value. This was pretty difficult to find as I couldn’t see it by just seeing if it thought it was endgame at the end of a move. This makes sure I can actually get my hashes in O(1) time. Next I am going to try and make my arrows darker when over each other.
I’ve massively improved my organisation! I’m now properly utilising branches which is allowing me to work on multiple changes at the same time. Currently I am working on 2 branches. One is about improving my maintainability by adding comments so that other people can understand what I am doing and why. This also has the added benefit of me being able to make some small improvements and bug fixes as I am reading through all of my code. The second branch is about move ordering which is super important as it makes my alpha beta pruning more effective. Working on these changes on branches is useful because it not only keeps it organised and easy to see what each commit is for but also means that if I decide I don’t want the change anymore it is easy to remove as it isn’t mixed in with all the other changes. To help with this I’ve also created a Jira board which helps me keep my ideas organised. My branches are called SCRUM-NUMBER/NAME . The scrum number is given to me by Jira. As well as improving my organisation I also further improved my zobrist hashing by replacing using modulo on the hash to get the index of the transposition with using an and gate between my hash and the table size - 1 (which is just all 1s and a single 0 on the left most digit since the table size is a power of 2). I also stored my castle rights as a single 4 digit binary digit where each digit represents whether a certain rook has castling rights or not. My logic with this was since the point of bitboards is 12 integer is better than 64 integers, a single 4 digit integer is better than a dictionary of 4 values but I am not actually sure if this is true or not. On the maintainability branch so far I have added comments to all of main.py . On the move ordering branch I have improved my sorting from just sorting by most valuable capture and least valuable attacker which is only good for captures to also scoring promotions very highly. I also instantly push the previous best move to the front of the queue and score moves which cutoff branches in alpha beta pruning highly as well. Next I will try to add comments to one of my other files and improve my move ordering by not using lambda functions.
Move ordering improved! I’ve merged my SCRUM-29/move-ordering branch with main and now have my improved move ordering in main. This has let me go from a depth of 5 to almost always a depth of at least 6. I then merged main into SCRUM-42/improve-maintainability so that I could add comments to the code I added from the move ordering branch. Next I am going to add some comments explaining what things do.
Massive improvements in depth! I added 2 changes: null move pruning and late move reduction. Null move pruning is when the bot ‘passes its turn’, when searching for the best move. The bot then evaluates the board at a reduced depth after letting the opponent play twice in a row. If it is still in a winning position then that means it is winning by a lot. This means that it can prune this branch since the opponent wouldn’t let the game get to this state and would make a better decision earlier in the tree. Since the opponent wouldn’t let the game get to this it means that further analysis isn’t necessary. Late move reduction works on the basis that I have good move ordering, which I just worked on so I would hope I do. Late move reduction means that I search the later moves at a reduced depth since the best moves are at the start and so later moves are likely bad. If they turn out to be good after the reduced evaluation depth then they are researched at the full depth. This helps reduce the amount of moves which need to be evaluated by a lot. Together null move pruning and late move reduction have taken my depth from around 6 - 7 in midgame to around depth 7 - 10 in midgame! In endgame this is even more. When I tested it in endgame it got to a depth of 13! My next change is something called quiescent search which will boost the bot’s elo by massive amounts as it should mostly stop the bot from making blunders.
Quiescent search is amazing! After adding it my bot instantly became better. A quiescent search just means that when evaluating a board state to a certain depth even if you reach that depth you need to evaluate until a quiet move (a move that isn’t a capture). This means that even if the bot reaches the max depth in the middle of a piece trade it won’t just think the move is amazing since all it can see it won a piece. Since I added the bot, when tested against other bots it has made 0 blunders! In fact it beat Li, a bot rated 2000 on chess.com ! I’m really proud of this and think it is really cool to say that my bot has beaten a 2000 rated bot. However, it only beat the bot once and so it could just be lucky. I was going to test it in 2 more games against the same bot but found myself getting bored of manually inputting moves into chess.com and my bot to get them to play each other. Therefore, I’m planning on making my bot able to play other bots on its own. To do this I will need to download the other bots and make my bot give properly formatted inputs and outputs.
I’ve added FEN strings! FEN strings (Forsyth-Edwards Notation) are a way to store positions of chess games. They are used by many chess engines to allow players to start from different positions or midway through games. Adding these wasn’t too difficult as the strings are formatted in a nice way. I simply split up the FEN string into its 6 parts and set my variables to the value in the FEN string. To test if it worked I inputted the FEN string 4kb1r/p2n1ppp/4q3/4p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 1 16 which gives the position of the famous opera game directly before the queen sacrifice. I then set the bot colour to white and was glad to see that it immediately found the best move (the queen sacrifice). I also added premoves so that I can choose my move in advance. I did this by just storing the move I make when it is the bot’s turn and playing it as soon as the bot plays. However I can only premove 1 move ahead. Next I will try to allow the user to premove multiple moves ahead.
Way better premoves. I’ve updated my premove system to store multiple premoves. I did this by storing eaach premove as a tuple of ( startRow , startColumn , endRow , endColumn ). These tuples contain all the data I need to know and can be easily appended into an array. To clear a premove you can either do the same move again which removes that specific premove or tap the middle mouse button anywhere which clears all premoves and arrows. I also render a translucent version of the piece that I’ve moved to its premove destination and remove the texture for where it was originally. This helps you keep track of what your premoves are actually doing. I do this by drawing the board normally then looping through each move in the premoves array and drawing that piece at its correct destination in reduced alpha. Next I am going to try to improve my bot further so that I can push to a depth of around 10 during midgame.
Premoves finished! My premoves are now fully implemented and the branch is merged. Making the move with middle click removes that specific premove. Middle clicking a random square clears all premoves and arrows. I also added principal variation search (pvs) which is just searching moves that aren’t the previous best move with a tight move score boundary then researching them normally if they are better than expected. I am probably going to ship soon and so will start polishing the project up now.
I’ve made a few small changes that help slightly speed the bot up. I stopped checking whether I have surpassed the time limit every move I search and instead every 2048 moves I search. This is better as it removes thousands of unnecessary library calls which each add a small amount of time to how long each move takes to search. Since computers are very fast 2048 doesn’t actually take long at all but it massively reduces the amount of times the pygame library is called. I also changed my move ordering to sort manually instead of with in a lambda function since this lambda functions are more inefficient. I am next going to ship the project!!!
Thanks for all the positive feedback and constructive criticism on my ship! Working to improve where people said and I am starting by trying to add comments to my code to explain what is happening. So far I’ve fully commented 3 / 7 files and am around 30% through commenting logic.py which contains most of the complicated code. Its taking a while but I really hope that this will help people understand what I am doing and that they will like my project more because of this. Next I am going to continue adding comments to logic.py and will probably have to make a devlog after just that since the file is pretty big and has slightly complicated stuff in it. Once again thanks to all the people who rated the project or gave feedback!
Yup! I did what I said I would last time, and finished commenting ALL of logic.py . I don’t think I can describe how long this took and how annoying it was to have to go through 750+ lines of code and add comments explaining things. And then I realise that there’s just random stuff that I don’t even need. Anyway, I’m pretty satisfied that I managed to comment so much. This is definitely the largest file and so I’m happy I’ve gotten it out of the way. There’s not really much I can’t say like explaining and stuff because all I’ve done for the last 5 hours is explain stuff. Anyway once I’ve commented everything, I’ll probably make another devlog and then go and work on something else.
I started getting bored of just commenting my code so I created a new branch in which I am trying to make my bot be able to play other bots. After some research, I found that the engine needs to be able to take in moves in the form of algebraic notation (a type of shorthand notation for moves. for example: Be4). Because of this I read a Wikipedia page on algebraic notation and made a function to convert between it and the parameters my makeMove() takes, that being: startRow , startColumn , endRow and endColumn . I have done this by first checking if the move is a castle (notated by O-O or O-O-O) then forming the full start and end coordinates by hardcoding the column values and finding the row based off the colour that is castling. Then I find what piece is moving (shown by the first letter) and if there is a promotion (shown by ‘=’ sign). Algebraic also has characters to show captures (x), checkmates (#) and checks (+), however the engine does not need these and so they are removed in 3 separate while loops. At this point I am left with just the end coordinates and maybe a combination of start coordinates. To find the full start coordinates (as they are all I am missing) I loop through the specific bitboard for the piece and whenever I find a square where there is a piece, I check whether it matches with the start coordinates I have, and if it does whether it can legally reach the end square. If it can then that is my piece and I return its start coordinates and the end coordinates it moves to (which is given in the input string). Currently, this function lives inside a random file in my project folder but my next step will be to properly integrate it into the rest of the code.
So, I’ve actually decided to work on making my bot playable on a website since that was one of the main things people said they would have wanted last ship and stardance is ending soon. But thats not why I’m posting. I’m posting because I spent the last 40 minutes rooting out a bug that caused my premoves to not be played. My first step was playing the release version that can be downloaded to see if the bug was there as well. Luckily it wasn’t so I went to my current commit on my main branch and kepy undoing commits (and saving them with git stash ) until the bug was gone. I then found that the bug only became a thing after I merged my commenting branch. Because of this I did the same thing of undoing commits and saving them on the commenting branch til I found the commit that caused the bug. I then went through all the changes until I found the problem. Then I fixed the bug, merged the fix to main then merged main into my other branches so that they would have the bug fix as well. I’ve already done some research and have found that pygbag seems to fit my needs for turning my pygame program into a website pretty well. Due to this I will probably use pygbag to get a website version of my chess bot up and running! Attached is a screenshot of the commit that caused the bug. Before the commit is on the left and after the commit is on the right. Try to find what caused the bug! If you can’t check the comments of the post as I am gonna say what the problem was there. I also attached a photo of how my git tree looks now and… it looks sooo messy lol.
Ships:
I’m finally shipping the chess bot! So excited to see what people think of it :) . Before you try my project I highly suggest reading the README (on my github page https://github.com/GunRattler28/Chess-Bot ). It has a full list of all controls which will help you understand how to play. Anways, can’t wait to see what you guys think of it!...
|
1792856898.3795884
|
1793720898.3795884
|
|
7574
|
Kolori by @nikooo | Stardance
|
nikooo
|
1
|
142.69
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-19T21:34:34Z", "hours": 100.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "Kolori is a desktop application that lets you create beautiful pieces of art from mathematical expressions. Kolori features a custom hand-written recursive descent parser to parse mathematical expressions–which it then uses to transpile your input down to low-level shader instructions to render images to the screen on the GPU. Kolori also supports rendering not only images, but animations using the “ t ” variable in the input expression, which grows linearly with time elapsed–the speed at which is adjustable. Kolori offers four coloring modes that can generate different images based on your input: HSL : Uses the HSL color space to generate pixel colors HSLuv : Uses the HSLuv color space, a perceptually uniform alternative to HSL, to generate pixel colors Custom Palette Generation : Input 4 colors of your choosing so Kolori can generate a custom color palette based on them, to determine pixel colors Use an Image : Select an image using your file manager, or just drag and drop one onto the window for Kolori to sample pixel colors from the input image to determine pixel colors. Making this project was a bit of an adventure, as I had never worked with libraries such as ImGui, SDL, and OpenGL before. The biggest challenge when creating the program was managing memory correctly–which makes me appreciate languages like Nim even more–and code organization.", "repo": "https://github.com/neroist/kolori", "demo": "https://github.com/neroist/kolori/releases/latest"}]...
|
[{"post_id": 18957, "ts": "202 [{"post_id": 18957, "ts": "2026-06-30T04:15:45Z", "hours": 3.4697, "text": "Managed to get everything working <3 The main issue was not assigning texture units to the sampler uniforms whenever the shaders were rebuilt 🤦. Either way, the feature works fully now. The rest that’s left before making a release is chasing some bugs that are left: e.g. crashes on Windows on startup and access violation errors when making a screenshot on fullscreen (also specifically on Windows). Below is the Joukowski function, as I briefly mentioned before in the prior devlog."}, {"post_id": 18224, "ts": "2026-06-29T09:17:52Z", "hours": 16.4414, "text": "After much, much longer than I’d like to admit, I finally got “sliced” coloring to work! Naturally we need a better name, but that can wait. A bit on implementation So, for Kolori, we use OpenGL to render scenes on the GPU. Specifically, we target at minimum desktop OpenGL 3.3, and the GLSL shaders are written for GL ES 3.0 (we plan to target WebGL in the future, maybe moving to WebGPU later. Maybe.). We implement the “slices” coloring mode as follows: The user inputs a list of colors We store these colors as a variable-length array (VLA) which can grow dynamically but, instead of giving these values to the GPU as an array, we instead upload the color data onto the GPU as a one-dimensional texture , since GLSL doesnt support VLAs (and I didn’t want to limit the amount of colors one can add). Though, I did still do that inadvertently. Slice colors are managed by color edit widgets. Each widget’s ID (which must be unique) is generated using the index of the slice color it controls, casted to a byte. Thus, the number of colors cannot exceed 256. Something I hope to fix in the future. Also, an interesting note: GLSL for GLES 3.0 doesn’t support the sampler1D type (which literally represents a 1D texture), so one would have to use the type that represents a 2D texture, but set the height of the texture to 1, to emulate the same behavior and structure. This means that there are now two textures we handle in the shaders: the image texture that holds a user-uploaded image for the “Use an Image” coloring mode, and the slices texture that holds the selected colors for the “(Pizza) Slices” coloring mode. OK, but why’d you take so long? The major obstacle that was ran into was texture data mix-up: the data for the image texture would always overwrite the data for the slices texture, and it would even seem that the two textures were pointing to the same data, even though I assigned separate texture units to each one, and made sure to set the active texture each time before binding textures. OK, can I see it? See the demo below :) They don’t really start to look like “pizza slices” until you have 5+ slices. There are some really interesting graphs you can create using this, such as the graph of the Joukowski function , defined as: f(z)=(z+1/z)/2 (unfortunately not pictured below)."}, {"post_id": 16041, "ts": "2026-06-26T02:00:22Z", "hours": 22.7831, "text": "Progress on 0.4.0 Mainly, two new features/fixes: AppImage builds for Linux (we may add .deb files in releases in the future aswell) Image aspect ratio persistence AppImage builds In past releases, only an executable was published for Linux platforms. This is not a proper solution for distribution–different Linux systems may differ in ABI, available shared libraries, and packages. For instance, on WSL in my Windows machine, SDL3 is not available in the default repository, leaving me unable to build or even run the application. AppImage builds bundle the executable and everything needed for running the application into one file–perfect for distributing. “One app = one file”, or whatever those nerds say. To run on a Linux system, users will only need to do the following: Give the .AppImage file executable permissions Run the app! Its that easy. Image aspect ratio persistence Before, when you put in an image, it would be squished down into a square, distorting the image along its longest dimension. For images with a 1:1 aspect ratio, this is fine. For other images? Not so fine. We now apply proper scaling in the vertex shader pass to textures so that image aspect ratio is preserved in the canvas. Future changes Expect a new coloring mode: “Slices” . This will split the canvas into a number of “slices”–similar to how the four quadrants of the cartesian plane split it up into four slices itself"}, {"post_id": 11476, "ts": "2026-06-18T19:13:22Z", "hours": 5.6697, "text": "I’ve finally added image coloring to Kolori! Kolori can now take an image as input, by either selecting a image file using a native file dialog or dragging and dropping a image onto the window! The image below was created using the feature–using one of the gallery images as the input image. The hard part about this was, not actually loading the image file, reading the pixel data, uploading that into the GPU, and rendering it, but instead managing the file dialog by which a user can upload an image into the application. We use SDL3 for windowing and make use of the SDL_ShowOpenFileDialog function to, well, show an open file dialog. I initially put all of the image loading and OpenGL calls into the dialog callback, but something strange happened then. All of my OpenGL calls were triggering an GL_INVALID_OPERATION error–and specifically on Windows–but why? All of my OpenGL calls were fine, no invalid arguments passed in (or in the wrong order), so everything should’ve been fine. The answer lies in the SDL_ShowOpenFileDialog and how OpenGL works with multiple threads. SDL_ShowOpenFileDialog is an asynchronous function–it will return immediately, and the result of the dialog will be passed on to the callback. However, the callback function may be called on a different thread depending on the operating system, which explains the difference in effect on Windows, and the GL_INVALID_OPERATION errors were caused by the absence of an active OpenGL context on the new thread. SDL3 does not provide an API for setting the current thread’s OpenGL context, so I had to cope. I moved most of the business logic out of the callback function, only keeping the image loading logic, and instead performed the texture uploading into the UI rendering logic, where we check if there is any new image data that happened to be uploaded, upload the data onto the GPU as a texture and show it on screen."}, {"post_id": 11058, "ts": "2026-06-18T02:57:25Z", "hours": 13.5519, "text": "Bumped version from 0.1.0 to 0.2.0! See it here: https://github.com/neroist/kolori/releases/tag/0.2.0 . Some interesting changes are that there is now a VSync toggle + a frame rate slider with support for unlimited frame rate (as much as your GPU can handle), build system improvements–so that Kolori is one make release away on all platforms that have make , and the UI is now DPI-aware and will scale based on the monitor’s DPI (we do not change scaling however if the monitor were to change–something to fix in a future release). We also changed our color input sliders to display RGB colors in their integral components from 0 to 255–what you would expect, rather than a decimal display. See it below!"}, {"post_id": 10217, "ts": "2026-06-16T20:45:34Z", "hours": 5.3461, "text": "Wrote a full-length devlog about a core feature of Kolori and its implementation, but it got deleted for being “too long”. Lets try again then, with a piece that only demands a bit of your time. Kolori offers users three (at the moment) coloring modes: HSL, HSLuv, and custom palette generation. How do these work? Custom palette generation Unlike HSL and HSLuv, using a custom palette to color the complex plane is much more simple. Kolori lets the user input four arbitrary RGB colors. We then use Inigo Quilez’s cosine-based formula for procedural palette generation to determine the color of a pixel. An article of his that describes it is here: https://iquilezles.org/articles/palettes/ . The shader code that does it all: // From https://iquilezles.org/articles/palettes/ vec4 palette ( float t , vec3 a , vec3 b , vec3 c , vec3 d ) { return vec4 ( a + b * cos ( TAU * ( c * t + d )), 1 ); } Our a , b , c , and d are the colors the user has selected, and t is an input variable to vary. However, one would notice that t is a scalar, while we work in the complex numbers. How would we map the plane onto the real line in order to get a valid t to input into palette ? The answer we chose is simple: we take the projection onto the real axis–i.e. just taking the real part of the complex number This is an answer that a user would expect and is pointed out in the user guide. Furthermore, by not choosing ahead of time for the user, we allow the user to exert more control over what they wish to generate."}, {"post_id": 9714, "ts": "2026-06-16T04:10:17Z", "hours": 12.3725, "text": "Was preparing for first our ship, but then discovered that my application was leaking memory–badly. Memory usage would climb by a gigabyte in <2 minutes. Worse than any browser you’ve ever seen. To start, I use Odin, which has a tracking allocator that lets you see where you didn’t free up memory, or perhaps made bad frees. On program exit, it prints out how many bytes you leaked, and where you made the allocations. I had been using this allocator, and it had not reported anything . Furthermore, upon, admittedly, a very cursory look into my code, I couldn’t find anything that would’ve caused any leaks either–all allocations were eventually freed: whether that be manually or via Odin’s temporary allocator (a really nice feature of the language). LSan hadn’t pointed out anything, and Valgrind didn’t report anything scary, only ~200KiB of memory usage. I had even patched myself a custom allocator, which would print to stdout whenever an allocation was made with it, and I saw nothing concerning at all . Only small allocations were made which were, again, eventually freed. My application uses SDL3 for windowing and ImGui for GUI, so perhaps one of those has a memory leak in it? I’m not sure. For such a large library, I doubt that’s the case. Though, when running valgrind with --leak-check=full --show-leak-kinds=all I did keep seeing SDL pop up, but it didn’t report any outright leaks. Upon researching potential external sources for this memory leak, I found https://github.com/libsdl-org/SDL/issues/15192 , which describes my issue exactly. It seems that there is no memory leak in SDL, ImGui, or whatever I’m doing, but instead a driver issue, which is interesting. The example that was given to reproduce the leak is quite minimal, so I wonder how that got past their testing. Furthermore, if this is indeed a driver-level issue, why is it that no other applications running on this device leak memory this egregiously? In any case, the leak is not my fault, and out of my hands."}, {"post_id": 8767, "ts": "2026-06-14T16:04:51Z", "hours": 3.8556, "text": "Learned how cool rubberducking is. I was having a problem fixing a bug with the parser (as described below), and I went to write a devlog about it. As I was describing the bug, I immediately had an idea about how to fix it, and lo and behold, it worked. The original post was going to be as follows: Fixed a bug where trailing input after the parser successfully completes is not disallowed. This most commonly occurs, as I’ve found, after the use of a comma character. The parser simply does not see it, and instead only parses the expression it sees before it. Internally, a comma character is used to delimit function arguments, so this kind of behavior is not totally useless. However, for situations like picrel, it just seems strange. doesn’t it? This usually would be an easy bug to fix. We currently use a recursive descent parser (considering moving to a pratt parser) for parsing mathematical expression. All that honestly would’ve needed to be done was adding a check at the procedure that parses the top level grammar rule: “OK, are we at the end of our input? We should be. If not, return an error.” (Here, I realized that if we literally call this procedure while parsing function calls, it really isn’t too wise to immediately ask “are we done yet?” if we very much aren’t done yet. I then added the check into a procedure that isn’t called by the parser and we should definitely be done by the time that check is ran.)"}, {"post_id": 7892, "ts": "2026-06-13T05:13:05Z", "hours": 13.1858, "text": "(excuse the amount of time, i’m doing general refactors + debugging as well as working on other features) Implemented adjusting the gamma correction amount. Normally, with the gamma correction, areas close to zero would appear black, and areas that have large magnitudes would appear white. However, you might not always want this, and instead would prefer only pure hue . Set the gamma correction amount to zero to reduce the amount that colors’ lightness values are altered. An example is shown where we use this feature to produce a colorful, moving spiral. Note that when gamma correction is not zero, as demonstrated, the effect does not work as well."}, {"post_id": 7005, "ts": "2026-06-11T19:13:46Z", "hours": 32.8386, "text": "The project has come a long way (see the 30 hours of work that went into this). We now support: arbitrary function input on-the-fly graphing and error checking a “t” time variable, allowing you to animate graphs being able to speed up, slow down, and pause animations screenshots (not imaged below) zoom in/out panning As well as being multiplatform for both Linux and Windows (you can go build and run this, right now ). What to expect: the ability to change coloring method (hsl, hsluv, palette generation) the ability to use an image for coloring WASM web builds coordinate inspector to see where exactly in the complex plane you are Check it out on github: https://github.com/neroist/kolori"}, {"post_id": 3571, "ts": "2026-06-06T15:51:37Z", "hours": 12.8247, "text": "Finally! SDL3 & the GPU shaders are working. FWIW – this is the graph of f(z)=z, the identity transformation. I will make a devlog on how these images are generated later."}]...
|
Title: Kolori by @nikooo | Stardance
Devlogs:
Fin Title: Kolori by @nikooo | Stardance
Devlogs:
Finally! SDL3 & the GPU shaders are working. FWIW – this is the graph of f(z)=z, the identity transformation. I will make a devlog on how these images are generated later.
The project has come a long way (see the 30 hours of work that went into this). We now support: arbitrary function input on-the-fly graphing and error checking a “t” time variable, allowing you to animate graphs being able to speed up, slow down, and pause animations screenshots (not imaged below) zoom in/out panning As well as being multiplatform for both Linux and Windows (you can go build and run this, right now ). What to expect: the ability to change coloring method (hsl, hsluv, palette generation) the ability to use an image for coloring WASM web builds coordinate inspector to see where exactly in the complex plane you are Check it out on github: https://github.com/neroist/kolori
(excuse the amount of time, i’m doing general refactors + debugging as well as working on other features) Implemented adjusting the gamma correction amount. Normally, with the gamma correction, areas close to zero would appear black, and areas that have large magnitudes would appear white. However, you might not always want this, and instead would prefer only pure hue . Set the gamma correction amount to zero to reduce the amount that colors’ lightness values are altered. An example is shown where we use this feature to produce a colorful, moving spiral. Note that when gamma correction is not zero, as demonstrated, the effect does not work as well.
Learned how cool rubberducking is. I was having a problem fixing a bug with the parser (as described below), and I went to write a devlog about it. As I was describing the bug, I immediately had an idea about how to fix it, and lo and behold, it worked. The original post was going to be as follows: Fixed a bug where trailing input after the parser successfully completes is not disallowed. This most commonly occurs, as I’ve found, after the use of a comma character. The parser simply does not see it, and instead only parses the expression it sees before it. Internally, a comma character is used to delimit function arguments, so this kind of behavior is not totally useless. However, for situations like picrel, it just seems strange. doesn’t it? This usually would be an easy bug to fix. We currently use a recursive descent parser (considering moving to a pratt parser) for parsing mathematical expression. All that honestly would’ve needed to be done was adding a check at the procedure that parses the top level grammar rule: “OK, are we at the end of our input? We should be. If not, return an error.” (Here, I realized that if we literally call this procedure while parsing function calls, it really isn’t too wise to immediately ask “are we done yet?” if we very much aren’t done yet. I then added the check into a procedure that isn’t called by the parser and we should definitely be done by the time that check is ran.)
Was preparing for first our ship, but then discovered that my application was leaking memory–badly. Memory usage would climb by a gigabyte in <2 minutes. Worse than any browser you’ve ever seen. To start, I use Odin, which has a tracking allocator that lets you see where you didn’t free up memory, or perhaps made bad frees. On program exit, it prints out how many bytes you leaked, and where you made the allocations. I had been using this allocator, and it had not reported anything . Furthermore, upon, admittedly, a very cursory look into my code, I couldn’t find anything that would’ve caused any leaks either–all allocations were eventually freed: whether that be manually or via Odin’s temporary allocator (a really nice feature of the language). LSan hadn’t pointed out anything, and Valgrind didn’t report anything scary, only ~200KiB of memory usage. I had even patched myself a custom allocator, which would print to stdout whenever an allocation was made with it, and I saw nothing concerning at all . Only small allocations were made which were, again, eventually freed. My application uses SDL3 for windowing and ImGui for GUI, so perhaps one of those has a memory leak in it? I’m not sure. For such a large library, I doubt that’s the case. Though, when running valgrind with --leak-check=full --show-leak-kinds=all I did keep seeing SDL pop up, but it didn’t report any outright leaks. Upon researching potential external sources for this memory leak, I found https://github.com/libsdl-org/SDL/issues/15192 , which describes my issue exactly. It seems that there is no memory leak in SDL, ImGui, or whatever I’m doing, but instead a driver issue, which is interesting. The example that was given to reproduce the leak is quite minimal, so I wonder how that got past their testing. Furthermore, if this is indeed a driver-level issue, why is it that no other applications running on this device leak memory this egregiously? In any case, the leak is not my fault, and out of my hands.
Wrote a full-length devlog about a core feature of Kolori and its implementation, but it got deleted for being “too long”. Lets try again then, with a piece that only demands a bit of your time. Kolori offers users three (at the moment) coloring modes: HSL, HSLuv, and custom palette generation. How do these work? Custom palette generation Unlike HSL and HSLuv, using a custom palette to color the complex plane is much more simple. Kolori lets the user input four arbitrary RGB colors. We then use Inigo Quilez’s cosine-based formula for procedural palette generation to determine the color of a pixel. An article of his that describes it is here: https://iquilezles.org/articles/palettes/ . The shader code that does it all: // From https://iquilezles.org/articles/palettes/ vec4 palette ( float t , vec3 a , vec3 b , vec3 c , vec3 d ) { return vec4 ( a + b * cos ( TAU * ( c * t + d )), 1 ); } Our a , b , c , and d are the colors the user has selected, and t is an input variable to vary. However, one would notice that t is a scalar, while we work in the complex numbers. How would we map the plane onto the real line in order to get a valid t to input into palette ? The answer we chose is simple: we take the projection onto the real axis–i.e. just taking the real part of the complex number This is an answer that a user would expect and is pointed out in the user guide. Furthermore, by not choosing ahead of time for the user, we allow the user to exert more control over what they wish to generate.
Bumped version from 0.1.0 to 0.2.0! See it here: https://github.com/neroist/kolori/releases/tag/0.2.0 . Some interesting changes are that there is now a VSync toggle + a frame rate slider with support for unlimited frame rate (as much as your GPU can handle), build system improvements–so that Kolori is one make release away on all platforms that have make , and the UI is now DPI-aware and will scale based on the monitor’s DPI (we do not change scaling however if the monitor were to change–something to fix in a future release). We also changed our color input sliders to display RGB colors in their integral components from 0 to 255–what you would expect, rather than a decimal display. See it below!
I’ve finally added image coloring to Kolori! Kolori can now take an image as input, by either selecting a image file using a native file dialog or dragging and dropping a image onto the window! The image below was created using the feature–using one of the gallery images as the input image. The hard part about this was, not actually loading the image file, reading the pixel data, uploading that into the GPU, and rendering it, but instead managing the file dialog by which a user can upload an image into the application. We use SDL3 for windowing and make use of the SDL_ShowOpenFileDialog function to, well, show an open file dialog. I initially put all of the image loading and OpenGL calls into the dialog callback, but something strange happened then. All of my OpenGL calls were triggering an GL_INVALID_OPERATION error–and specifically on Windows–but why? All of my OpenGL calls were fine, no invalid arguments passed in (or in the wrong order), so everything should’ve been fine. The answer lies in the SDL_ShowOpenFileDialog and how OpenGL works with multiple threads. SDL_ShowOpenFileDialog is an asynchronous function–it will return immediately, and the result of the dialog will be passed on to the callback. However, the callback function may be called on a different thread depending on the operating system, which explains the difference in effect on Windows, and the GL_INVALID_OPERATION errors were caused by the absence of an active OpenGL context on the new thread. SDL3 does not provide an API for setting the current thread’s OpenGL context, so I had to cope. I moved most of the business logic out of the callback function, only keeping the image loading logic, and instead performed the texture uploading into the UI rendering logic, where we check if there is any new image data that happened to be uploaded, upload the data onto the GPU as a texture and show it on screen.
Progress on 0.4.0 Mainly, two new features/fixes: AppImage builds for Linux (we may add .deb files in releases in the future aswell) Image aspect ratio persistence AppImage builds In past releases, only an executable was published for Linux platforms. This is not a proper solution for distribution–different Linux systems may differ in ABI, available shared libraries, and packages. For instance, on WSL in my Windows machine, SDL3 is not available in the default repository, leaving me unable to build or even run the application. AppImage builds bundle the executable and everything needed for running the application into one file–perfect for distributing. “One app = one file”, or whatever those nerds say. To run on a Linux system, users will only need to do the following: Give the .AppImage file executable permissions Run the app! Its that easy. Image aspect ratio persistence Before, when you put in an image, it would be squished down into a square, distorting the image along its longest dimension. For images with a 1:1 aspect ratio, this is fine. For other images? Not so fine. We now apply proper scaling in the vertex shader pass to textures so that image aspect ratio is preserved in the canvas. Future changes Expect a new coloring mode: “Slices” . This will split the canvas into a number of “slices”–similar to how the four quadrants of the cartesian plane split it up into four slices itself
After much, much longer than I’d like to admit, I finally got “sliced” coloring to work! Naturally we need a better name, but that can wait. A bit on implementation So, for Kolori, we use OpenGL to render scenes on the GPU. Specifically, we target at minimum desktop OpenGL 3.3, and the GLSL shaders are written for GL ES 3.0 (we plan to target WebGL in the future, maybe moving to WebGPU later. Maybe.). We implement the “slices” coloring mode as follows: The user inputs a list of colors We store these colors as a variable-length array (VLA) which can grow dynamically but, instead of giving these values to the GPU as an array, we instead upload the color data onto the GPU as a one-dimensional texture , since GLSL doesnt support VLAs (and I didn’t want to limit the amount of colors one can add). Though, I did still do that inadvertently. Slice colors are managed by color edit widgets. Each widget’s ID (which must be unique) is generated using the index of the slice color it controls, casted to a byte. Thus, the number of colors cannot exceed 256. Something I hope to fix in the future. Also, an interesting note: GLSL for GLES 3.0 doesn’t support the sampler1D type (which literally represents a 1D texture), so one would have to use the type that represents a 2D texture, but set the height of the texture to 1, to emulate the same behavior and structure. This means that there are now two textures we handle in the shaders: the image texture that holds a user-uploaded image for the “Use an Image” coloring mode, and the slices texture that holds the selected colors for the “(Pizza) Slices” coloring mode. OK, but why’d you take so long? The major obstacle that was ran into was texture data mix-up: the data for the image texture would always overwrite the data for the slices texture, and it would even seem that the two textures were pointing to the same data, even though I assigned separate texture units to each one, and made sure to set the active texture each time before binding textures. OK, can I see it? See the demo below :) They don’t really start to look like “pizza slices” until you have 5+ slices. There are some really interesting graphs you can create using this, such as the graph of the Joukowski function , defined as: f(z)=(z+1/z)/2 (unfortunately not pictured below).
Managed to get everything working <3 The main issue was not assigning texture units to the sampler uniforms whenever the shaders were rebuilt 🤦. Either way, the feature works fully now. The rest that’s left before making a release is chasing some bugs that are left: e.g. crashes on Windows on startup and access violation errors when making a screenshot on fullscreen (also specifically on Windows). Below is the Joukowski function, as I briefly mentioned before in the prior devlog.
Ships:
Kolori is a desktop application that lets you create beautiful pieces of art from mathematical expressions. Kolori features a custom hand-written recursive descent parser to parse mathematical expressions–which it then uses to transpile your input down to low-level shader instructions to render images to the screen on the GPU. Kolori also supports rendering not only images, but animations using the “ t ” variable in the input expression, which grows linearly with time elapsed–the speed at which is adjustable. Kolori offers four coloring modes that can generate different images based on your input: HSL : Uses the HSL color space to generate pixel colors HSLuv : Uses the HSLuv color space, a perceptually uniform alternative to HSL, to generate pixel colors Custom Palette Generation : Input 4 colors of your choosing so Kolori can generate a custom color palette based on them, to determine pixel colors Use an Image : Select an image using your file manager, or just drag and drop one onto the window for Kolori to sample pixel colors from the input image to determine pixel colors. Making this project was a bit of an adventure, as I had never worked with libraries such as ImGui, SDL, and OpenGL before. The biggest challenge when creating the program was managing memory correctly–which makes me appreciate languages like Nim even more–and code organization....
|
1792983191.248482
|
1793069591.248482
|
|
16233
|
See-TreePiO by @Aryana | Stardance
|
Aryana
|
1
|
142.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-18T06:32:43Z", "hours": 142.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I made a project that can detect tree/plant species and temperature to determine whether it is dead or not. It displays the result on an LCD in the back, and will start the process of scanning a tree/plant once a button is pressed. The wiring is enclosed in a 3D printed prototype. The most difficult thing I did in this project was likely trying to fit it all in the enclosure. There were a lot of wires here and there, and the button was also quite difficult to fit in, as I needed to solder it on. However, this project was really fun to do, as it helped me gain knowledge about the environment around me, and I got to practice my software and hardware skills. I am really proud of myself, as I completed this project from start to finish, and didn’t give up. To test my project, all you have to do is plug in the battery pack, wait for a minute or so, point the prototype at the tree you want to scan, press the button, and wait for the results. Sometimes, it will take a little longer to get the results, resulting from a difficulty figuring out either the temperature or species of that particular plant/tree.", "repo": "https://github.com/dawinner395/tree-health-scanner", "demo": ""}]...
|
[{"post_id": 69981, "ts": "202 [{"post_id": 69981, "ts": "2026-09-18T05:40:56Z", "hours": 0.35, "text": "I completed the prototype by combining the enclosure with the prototype. I encased the sensors and the LCD. The prototype is finally complete!"}, {"post_id": 69965, "ts": "2026-09-18T04:18:13Z", "hours": 1.5167, "text": "I combined the parts in the bottom half of the prototype, and fit it in the encolsure."}, {"post_id": 67575, "ts": "2026-09-13T18:30:05Z", "hours": 1.3167, "text": "I researched the different types of prevalent trees in California and their temperatures during different seasons. I plan to add this to my database, as I hadn’t previously done this. I used many websites, but Our City Forest was the most helpful."}, {"post_id": 66887, "ts": "2026-09-12T20:45:05Z", "hours": 0.9333, "text": "I fixed the issues that the prototype was facing. I also added a button. The main thing I did was make the prototype able to function without the computer nearby, which can make it so that anyone in the world can use it with a battery pack."}, {"post_id": 64447, "ts": "2026-09-08T20:39:44Z", "hours": 12.0014, "text": "I 3D printed the top half of the housing for the prototype. Next, I will print the bottom half."}, {"post_id": 48288, "ts": "2026-08-16T16:26:44Z", "hours": 10.6833, "text": "I build a CAD of the structure that will house the prototype. I left holes for all the different parts, and will print it later today."}, {"post_id": 36195, "ts": "2026-07-28T03:59:06Z", "hours": 1.7667, "text": "I connected the database to the Raspberry Pi, and tested it out using a house plant. It worked really well, and the next step is to test it outside with a real tree."}, {"post_id": 35375, "ts": "2026-07-26T18:41:48Z", "hours": 1.8333, "text": "I researched about how to use the specific PlantNet API database with the Raspberry Pi and hook that database to a Machine Learning algorthim. I am finally ready to actually make the Machine Learning algorithm and get my hands dirty now that I have the information I need to continue on with the project."}, {"post_id": 32105, "ts": "2026-07-21T01:22:30Z", "hours": 0.3333, "text": "I researched more about the tree datasets, and I found one that has plenty of accurate information: PlantNet API."}, {"post_id": 31560, "ts": "2026-07-20T02:06:06Z", "hours": 0.6333, "text": "I researched the different datasets I can use for the project, as well as the amount of tree data each have in them. I still need to do some more research, but as of now, creating a dataset is the best option if I want to get a wide, accurate range of data. I haven’t found any datasets that match the amount of data I can collect by myself in my neighborhood."}, {"post_id": 29878, "ts": "2026-07-17T01:24:55Z", "hours": 0.6, "text": "I tested the camera and battery pack that came. They both worked really well. Now, I can start inputting the ML algrothm."}, {"post_id": 28665, "ts": "2026-07-15T01:45:42Z", "hours": 3.7747, "text": "I fiinshed the Machine Learning book."}, {"post_id": 28079, "ts": "2026-07-14T03:24:59Z", "hours": 1.0333, "text": "I read Chapters 14 and 15 of the Machine Learning book. The parts will come tomorrow."}, {"post_id": 27961, "ts": "2026-07-13T22:13:23Z", "hours": 0.6833, "text": "I read Chapter 13 of the Machine Learning book."}, {"post_id": 27279, "ts": "2026-07-12T18:33:41Z", "hours": 1.65, "text": "I planned the way I am going to connect the ArduCam to the Raspberry Pi with the thermal sensor. I realized I might have to solder some wires together so that more than one wire can fit on one pin on the Pi. I planned the way the wires are going to connect to the Pi and how I am going to integrate ML into the Pi using the camera and thermal sensor."}, {"post_id": 26242, "ts": "2026-07-10T22:09:55Z", "hours": 1.7667, "text": "I researched more about using the ArduCam with the Raspberry Pi 5. I found troubleshooting techniques and what I need to do after I get the camera (the setup)."}, {"post_id": 25652, "ts": "2026-07-10T02:04:39Z", "hours": 1.6847, "text": "I read Chapters 11 and 12 of the Machine Learning book."}, {"post_id": 25543, "ts": "2026-07-09T21:16:12Z", "hours": 1.5167, "text": "I watched a video about using the ArduCam with the Raspberry Pi 5."}, {"post_id": 25481, "ts": "2026-07-09T19:38:18Z", "hours": 1.2369, "text": "I read Chapters 9 and 10 of the Machine Learning book."}, {"post_id": 25077, "ts": "2026-07-09T01:30:27Z", "hours": 0.4, "text": "I read Chapter 8 of the Machine Learning book. I will stop watching the AI on the Edge videos because they are not accessible on YouTube after Lesson 31. The parts will come day after tomorrow, so I plan to finish reading this book by then."}, {"post_id": 24895, "ts": "2026-07-08T19:02:48Z", "hours": 2.1167, "text": "I watched Lesson 31 of the AI on the Edge videos."}, {"post_id": 24517, "ts": "2026-07-08T03:43:40Z", "hours": 2.1914, "text": "I watched Lesson 30 of the AI on the Edge videos."}, {"post_id": 24471, "ts": "2026-07-08T01:31:47Z", "hours": 1.9167, "text": "I watched Lesson 29 of the AI on the Edge videos."}, {"post_id": 24422, "ts": "2026-07-07T23:28:04Z", "hours": 3.2, "text": "I watched Lesson 28 of the AI on the Edge videos."}, {"post_id": 24308, "ts": "2026-07-07T19:58:17Z", "hours": 2.1003, "text": "I watched Lesson 27 of the AI on the Edge videos."}, {"post_id": 23795, "ts": "2026-07-06T23:03:10Z", "hours": 2.7667, "text": "I watched Lesson 26 of the AI on the Edge videos."}, {"post_id": 23280, "ts": "2026-07-06T04:18:00Z", "hours": 2.3625, "text": "I watched Lesson 25 of the AI on the Edge videos."}, {"post_id": 23236, "ts": "2026-07-06T01:55:59Z", "hours": 3.1667, "text": "I watched Lesson 24 of the AI on the Edge videos."}, {"post_id": 23150, "ts": "2026-07-05T22:46:20Z", "hours": 0.9167, "text": "I read chapters 6 and 7 of the Machine Learning book. I’m just reading and watching the videos until the parts arrive in three or four days. Then, I will work on the technical aspect of the prototype. I have some free time now, so I thought I would learn about Machine Learning and using the Raspberry Pi in the time I have instead of wasting it."}, {"post_id": 22461, "ts": "2026-07-04T22:37:08Z", "hours": 2.0494, "text": "I watched Lesson 23 of the AI on the Edge videos."}, {"post_id": 22380, "ts": "2026-07-04T20:34:29Z", "hours": 3.2, "text": "I watched Lesson 22 of the AI on the Edge videos."}, {"post_id": 21779, "ts": "2026-07-03T21:41:25Z", "hours": 1.5, "text": "I watched Lesson 21 of the AI on the Edge videos."}, {"post_id": 21716, "ts": "2026-07-03T20:11:28Z", "hours": 1.9, "text": "I watched Lesson 20 of the AI on the Edge videos."}, {"post_id": 21285, "ts": "2026-07-03T04:02:15Z", "hours": 2.8383, "text": "I watched Lesson 19 of the AI on the Edge videos."}, {"post_id": 21215, "ts": "2026-07-03T01:11:38Z", "hours": 2.3, "text": "I watched Lesson 18 of the AI on the Edge videos."}, {"post_id": 21101, "ts": "2026-07-02T21:55:09Z", "hours": 3.7, "text": "I watched Lesson 17 of the AI on the Edge videos."}, {"post_id": 20495, "ts": "2026-07-02T03:07:09Z", "hours": 1.9072, "text": "I watched Lesson 16 of the AI on the Edge videos."}, {"post_id": 20442, "ts": "2026-07-02T01:11:45Z", "hours": 2.3333, "text": "I watched Lesson 15 of the AI on the Edge videos."}, {"post_id": 20318, "ts": "2026-07-01T21:43:50Z", "hours": 3.6667, "text": "I watched Lesson 14 of the AI on the Edge videos."}, {"post_id": 19770, "ts": "2026-07-01T04:50:30Z", "hours": 2.7167, "text": "I watched Lesson 13 of the AI on the Edge videos."}, {"post_id": 19679, "ts": "2026-07-01T02:07:59Z", "hours": 1.4167, "text": "I watched Lesson 12 of the AI on the Edge videos."}, {"post_id": 19634, "ts": "2026-07-01T00:35:15Z", "hours": 1.6167, "text": "I read chapters 5 and 6 of the Machine Learning book."}, {"post_id": 19586, "ts": "2026-06-30T22:40:26Z", "hours": 1.6167, "text": "I watched Lesson 11 of the AI on the Edge videos."}, {"post_id": 19523, "ts": "2026-06-30T21:02:23Z", "hours": 1.0494, "text": "I watched Lesson 10 of the AI on the Edge videos."}, {"post_id": 19468, "ts": "2026-06-30T19:58:25Z", "hours": 2.1, "text": "I watched Lesson 9 of the AI on the Edge videos."}, {"post_id": 19018, "ts": "2026-06-30T05:48:49Z", "hours": 2.7, "text": "I watched Lesson 8 of the AI on the Edge videos."}, {"post_id": 18914, "ts": "2026-06-30T03:06:50Z", "hours": 0.75, "text": "I finished reading Chapter 4 of the Machine Learning book. I am also taking more notes on the book now."}, {"post_id": 18878, "ts": "2026-06-30T02:18:01Z", "hours": 0.9, "text": "I sent an email to Ms. Mint (the one I met previosuly) asking if we could meet again for some feedback on my project idea. I also converted my paper plan onto a document and calendar so I can keep track of any deadlines I might have for the project."}, {"post_id": 18760, "ts": "2026-06-29T23:18:51Z", "hours": 4.0, "text": "I watched Lesson 7 of the AI on the Edge videos."}, {"post_id": 17910, "ts": "2026-06-28T20:55:18Z", "hours": 1.2, "text": "I watched Lesson 6 of the AI on the Edge videos."}, {"post_id": 17840, "ts": "2026-06-28T19:40:59Z", "hours": 1.0667, "text": "I watched Lesson 5 of AI on the Edge. In the previous DevLog about the AI on the Edge videos, I actually watched Lesson 4, not Lesson 3."}, {"post_id": 17786, "ts": "2026-06-28T18:35:28Z", "hours": 1.7667, "text": "I made a plan on how to spend my time during this summer, as a lot of time will be dedicated to the ML aspect of my project."}, {"post_id": 17345, "ts": "2026-06-28T02:58:04Z", "hours": 2.0833, "text": "I watched Lesson 3 of the AI on the Edge videos."}, {"post_id": 17217, "ts": "2026-06-27T22:37:39Z", "hours": 3.05, "text": "I finished the 3rd lesson of the AI on the Edge."}, {"post_id": 17106, "ts": "2026-06-27T19:33:57Z", "hours": 1.5667, "text": "I watched the Lesson 2 of the AI on the Edge Raspberry Pi videos."}, {"post_id": 16603, "ts": "2026-06-27T00:34:57Z", "hours": 1.5, "text": "I watched a video about using the Raspberry Pi 5 with ML. Though the Machine Learning book is helpful (and I will keep reading it), I felt that it was not enough to help me with this specific project."}, {"post_id": 16000, "ts": "2026-06-25T23:50:46Z", "hours": 0.9333, "text": "I researched exactly what camera and battery pack to buy (to power the Raspberry Pi). I added them to the cart and will buy it as soon as possible to further develop the prototype. I can’t wait to see how it works with the thermal sensor!"}, {"post_id": 15917, "ts": "2026-06-25T21:22:07Z", "hours": 1.0667, "text": "I just researched about how to combine a thermal sensor with a camera. I found a helpful video and took notes on that video. I also found the specific type of camera I can use, which is a standard Raspberry Pi Camera Module, as well as the connector."}, {"post_id": 15877, "ts": "2026-06-25T20:08:12Z", "hours": 0.6167, "text": "Instead of physically testing the prototypes out (because my dog accidentally stepped on the ultrasonic sensor prototype), I just researched a bit more about the two sensors. I researched the benefits and downsides of each sensor, as well as how accurae they are at specifcally detecting dead trees. I found that people have used ultrasonic sensors before to detect dead trees, but no one has used thermal sensors in the way that I am before to do so. Therefore, I will stick with using a thermal sensor for this prototype. I will have to do more research about the actual pairing between a thermal sensor, a camera, and ML, but the book will help me a lot in the coding of the ML portion."}, {"post_id": 15231, "ts": "2026-06-24T18:49:08Z", "hours": 0.5333, "text": "I compared the 2 prototypes to see which sensor is more accurate (with research, not actual testing). I found that the thermal sensor is more accurate, especially when paired with a camera and an ML algorithm. However, the pairing will be new to me because of the Raspberry Pi. I am more used to working with Aruinos, but through research and practice, I will be able to implement ML. Also, the book I am reading is going to help increase my knowledge on ML. In a future DevLog, I might just test this research just to be sure the thermal sensor is the right choice."}, {"post_id": 14069, "ts": "2026-06-23T01:29:08Z", "hours": 2.3667, "text": "I created the new prototype using the ultrasonic sensor. I coded it, and it successfully functions properly. However, when I tested it with a tree, it didn’t detect it correctly (it said it was dead, not healthy). When I tested it a few more times, it showed accurate readings. I still need to compare the two prototypes together."}, {"post_id": 13982, "ts": "2026-06-22T23:01:27Z", "hours": 0.7219, "text": "I started taking notes on how to work with a thermal sensor, a camera, and ML. I found that it might be hard to integrate all 3 of these things, so I started looking in a different path. I found that I could use ultrasonic distance sensors to detect the unique ultrasonic waves emitted from trees. Therefore, I will start creating a prototype using the ultrasonic sensor and compare the 2 prototypes together."}, {"post_id": 13915, "ts": "2026-06-22T20:24:35Z", "hours": 1.6833, "text": "I copied the code from Command Prompt to GitHub so I have a way to store it somewhere safe. I also double-checkked that the code was correct, and fixed any errors."}, {"post_id": 13555, "ts": "2026-06-22T06:01:12Z", "hours": 3.0333, "text": "I interviewed a tree expert, Ms. Mint, who works at a local farm. She brought up some interesting points, and helped me narrow down what sensors I want to use for my project. She said that using a thermal sensor would be a good idea becuase of its accuracy and easy use. However, when I interviewed her, I had to record the video on my phone instead of on this Hackatime. Therefore, I screen recorded the video and that is the video shown here on this Devlog. I was also with a few other people interested in Ms. Mint’s work, so it wasn’t a one-on-one session, more of a broader overview with a lot of Q-and-A. Overall, this experience was really nice because I got to meet a curator of a nature center, feel the nature all around me, see the difference between dead and healthy trees, and get feedback on my idea."}, {"post_id": 13494, "ts": "2026-06-22T02:51:43Z", "hours": 1.1878, "text": "I wired the thermal sensor, the LCD, the Raspberry Pi, and the LCD backpack. At first, the wiring was not working, so I switched to planning the wiring on paper. Once I finished that, I used a soldering iron to combine two wires to fit in one slot. This is the completed wiring."}, {"post_id": 13467, "ts": "2026-06-22T01:34:43Z", "hours": 0.4833, "text": "I continued reading the Machine Learning book and got to Chapter 4. The book is really interesting and I already feel like I have some knowledge (not a lot, but some) about ML."}, {"post_id": 13450, "ts": "2026-06-22T01:01:41Z", "hours": 2.55, "text": "I continued reading the Machine Learning book and got to Chapter 4. The book is really interesting and I already feel like I have some knowledge (not a lot, but some) about ML."}, {"post_id": 13342, "ts": "2026-06-21T21:15:14Z", "hours": 0.4833, "text": "I have started reading a book about Machine Learning, its history, and how to train/use it to the best of my ability. I have been taking some notes and answering some questions presented in the book. I have gotten through the first 2 chapters so far and plan to finish the book in the next few weeks. This book will really help me use ML in my project, as well as use it in other projects that I may decide to pursue."}, {"post_id": 12793, "ts": "2026-06-20T22:25:53Z", "hours": 0.8169, "text": "I created the code for the basic part of the prototype. The code makes the prototype able to detect the thermal signature of a Redwood Tree and determine whether it is dead or healthy. In the future, I wil re-make the code to incorporate a camera and a Machine Learning algorithm that can be used for more accurate and broader readings, not just for Redwood trees."}, {"post_id": 12756, "ts": "2026-06-20T21:19:55Z", "hours": 1.4667, "text": "Researched about the different techniques and sensors I could use for this project. I found that using a thermal sensor with Machine Learning algorithms and a camera would be the best for my project."}, {"post_id": 12708, "ts": "2026-06-20T19:07:36Z", "hours": 0.6164, "text": "Testing and editing the code and the wiring of the prototype"}]...
|
Title: See-TreePiO by @Aryana | Stardance
Devlogs Title: See-TreePiO by @Aryana | Stardance
Devlogs:
Testing and editing the code and the wiring of the prototype
Researched about the different techniques and sensors I could use for this project. I found that using a thermal sensor with Machine Learning algorithms and a camera would be the best for my project.
I created the code for the basic part of the prototype. The code makes the prototype able to detect the thermal signature of a Redwood Tree and determine whether it is dead or healthy. In the future, I wil re-make the code to incorporate a camera and a Machine Learning algorithm that can be used for more accurate and broader readings, not just for Redwood trees.
I have started reading a book about Machine Learning, its history, and how to train/use it to the best of my ability. I have been taking some notes and answering some questions presented in the book. I have gotten through the first 2 chapters so far and plan to finish the book in the next few weeks. This book will really help me use ML in my project, as well as use it in other projects that I may decide to pursue.
I continued reading the Machine Learning book and got to Chapter 4. The book is really interesting and I already feel like I have some knowledge (not a lot, but some) about ML.
I continued reading the Machine Learning book and got to Chapter 4. The book is really interesting and I already feel like I have some knowledge (not a lot, but some) about ML.
I wired the thermal sensor, the LCD, the Raspberry Pi, and the LCD backpack. At first, the wiring was not working, so I switched to planning the wiring on paper. Once I finished that, I used a soldering iron to combine two wires to fit in one slot. This is the completed wiring.
I interviewed a tree expert, Ms. Mint, who works at a local farm. She brought up some interesting points, and helped me narrow down what sensors I want to use for my project. She said that using a thermal sensor would be a good idea becuase of its accuracy and easy use. However, when I interviewed her, I had to record the video on my phone instead of on this Hackatime. Therefore, I screen recorded the video and that is the video shown here on this Devlog. I was also with a few other people interested in Ms. Mint’s work, so it wasn’t a one-on-one session, more of a broader overview with a lot of Q-and-A. Overall, this experience was really nice because I got to meet a curator of a nature center, feel the nature all around me, see the difference between dead and healthy trees, and get feedback on my idea.
I copied the code from Command Prompt to GitHub so I have a way to store it somewhere safe. I also double-checkked that the code was correct, and fixed any errors.
I started taking notes on how to work with a thermal sensor, a camera, and ML. I found that it might be hard to integrate all 3 of these things, so I started looking in a different path. I found that I could use ultrasonic distance sensors to detect the unique ultrasonic waves emitted from trees. Therefore, I will start creating a prototype using the ultrasonic sensor and compare the 2 prototypes together.
I created the new prototype using the ultrasonic sensor. I coded it, and it successfully functions properly. However, when I tested it with a tree, it didn’t detect it correctly (it said it was dead, not healthy). When I tested it a few more times, it showed accurate readings. I still need to compare the two prototypes together.
I compared the 2 prototypes to see which sensor is more accurate (with research, not actual testing). I found that the thermal sensor is more accurate, especially when paired with a camera and an ML algorithm. However, the pairing will be new to me because of the Raspberry Pi. I am more used to working with Aruinos, but through research and practice, I will be able to implement ML. Also, the book I am reading is going to help increase my knowledge on ML. In a future DevLog, I might just test this research just to be sure the thermal sensor is the right choice.
Instead of physically testing the prototypes out (because my dog accidentally stepped on the ultrasonic sensor prototype), I just researched a bit more about the two sensors. I researched the benefits and downsides of each sensor, as well as how accurae they are at specifcally detecting dead trees. I found that people have used ultrasonic sensors before to detect dead trees, but no one has used thermal sensors in the way that I am before to do so. Therefore, I will stick with using a thermal sensor for this prototype. I will have to do more research about the actual pairing between a thermal sensor, a camera, and ML, but the book will help me a lot in the coding of the ML portion.
I just researched about how to combine a thermal sensor with a camera. I found a helpful video and took notes on that video. I also found the specific type of camera I can use, which is a standard Raspberry Pi Camera Module, as well as the connector.
I researched exactly what camera and battery pack to buy (to power the Raspberry Pi). I added them to the cart and will buy it as soon as possible to further develop the prototype. I can’t wait to see how it works with the thermal sensor!
I watched a video about using the Raspberry Pi 5 with ML. Though the Machine Learning book is helpful (and I will keep reading it), I felt that it was not enough to help me with this specific project.
I watched the Lesson 2 of the AI on the Edge Raspberry Pi videos.
I finished the 3rd lesson of the AI on the Edge.
I watched Lesson 3 of the AI on the Edge videos.
I made a plan on how to spend my time during this summer, as a lot of time will be dedicated to the ML aspect of my project.
I watched Lesson 5 of AI on the Edge. In the previous DevLog about the AI on the Edge videos, I actually watched Lesson 4, not Lesson 3.
I watched Lesson 6 of the AI on the Edge videos.
I watched Lesson 7 of the AI on the Edge videos.
I sent an email to Ms. Mint (the one I met previosuly) asking if we could meet again for some feedback on my project idea. I also converted my paper plan onto a document and calendar so I can keep track of any deadlines I might have for the project.
I finished reading Chapter 4 of the Machine Learning book. I am also taking more notes on the book now.
I watched Lesson 8 of the AI on the Edge videos.
I watched Lesson 9 of the AI on the Edge videos.
I watched Lesson 10 of the AI on the Edge videos.
I watched Lesson 11 of the AI on the Edge videos.
I read chapters 5 and 6 of the Machine Learning book.
I watched Lesson 12 of the AI on the Edge videos.
I watched Lesson 13 of the AI on the Edge videos.
I watched Lesson 14 of the AI on the Edge videos.
I watched Lesson 15 of the AI on the Edge videos.
I watched Lesson 16 of the AI on the Edge videos.
I watched Lesson 17 of the AI on the Edge videos.
I watched Lesson 18 of the AI on the Edge videos.
I watched Lesson 19 of the AI on the Edge videos.
I watched Lesson 20 of the AI on the Edge videos.
I watched Lesson 21 of the AI on the Edge videos.
I watched Lesson 22 of the AI on the Edge videos.
I watched Lesson 23 of the AI on the Edge videos.
I read chapters 6 and 7 of the Machine Learning book. I’m just reading and watching the videos until the parts arrive in three or four days. Then, I will work on the technical aspect of the prototype. I have some free time now, so I thought I would learn about Machine Learning and using the Raspberry Pi in the time I have instead of wasting it.
I watched Lesson 24 of the AI on the Edge videos.
I watched Lesson 25 of the AI on the Edge videos.
I watched Lesson 26 of the AI on the Edge videos.
I watched Lesson 27 of the AI on the Edge videos.
I watched Lesson 28 of the AI on the Edge videos.
I watched Lesson 29 of the AI on the Edge videos.
I watched Lesson 30 of the AI on the Edge videos.
I watched Lesson 31 of the AI on the Edge videos.
I read Chapter 8 of the Machine Learning book. I will stop watching the AI on the Edge videos because they are not accessible on YouTube after Lesson 31. The parts will come day after tomorrow, so I plan to finish reading this book by then.
I read Chapters 9 and 10 of the Machine Learning book.
I watched a video about using the ArduCam with the Raspberry Pi 5.
I read Chapters 11 and 12 of the Machine Learning book.
I researched more about using the ArduCam with the Raspberry Pi 5. I found troubleshooting techniques and what I need to do after I get the camera (the setup).
I planned the way I am going to connect the ArduCam to the Raspberry Pi with the thermal sensor. I realized I might have to solder some wires together so that more than one wire can fit on one pin on the Pi. I planned the way the wires are going to connect to the Pi and how I am going to integrate ML into the Pi using the camera and thermal sensor.
I read Chapter 13 of the Machine Learning book.
I read Chapters 14 and 15 of the Machine Learning book. The parts will come tomorrow.
I fiinshed the Machine Learning book.
I tested the camera and battery pack that came. They both worked really well. Now, I can start inputting the ML algrothm.
I researched the different datasets I can use for the project, as well as the amount of tree data each have in them. I still need to do some more research, but as of now, creating a dataset is the best option if I want to get a wide, accurate range of data. I haven’t found any datasets that match the amount of data I can collect by myself in my neighborhood.
I researched more about the tree datasets, and I found one that has plenty of accurate information: PlantNet API.
I researched about how to use the specific PlantNet API database with the Raspberry Pi and hook that database to a Machine Learning algorthim. I am finally ready to actually make the Machine Learning algorithm and get my hands dirty now that I have the information I need to continue on with the project.
I connected the database to the Raspberry Pi, and tested it out using a house plant. It worked really well, and the next step is to test it outside with a real tree.
I build a CAD of the structure that will house the prototype. I left holes for all the different parts, and will print it later today.
I 3D printed the top half of the housing for the prototype. Next, I will print the bottom half.
I fixed the issues that the prototype was facing. I also added a button. The main thing I did was make the prototype able to function without the computer nearby, which can make it so that anyone in the world can use it with a battery pack.
I researched the different types of prevalent trees in California and their temperatures during different seasons. I plan to add this to my database, as I hadn’t previously done this. I used many websites, but Our City Forest was the most helpful.
I combined the parts in the bottom half of the prototype, and fit it in the encolsure.
I completed the prototype by combining the enclosure with the prototype. I encased the sensors and the LCD. The prototype is finally complete!
Ships:
I made a project that can detect tree/plant species and temperature to determine whether it is dead or not. It displays the result on an LCD in the back, and will start the process of scanning a tree/plant once a button is pressed. The wiring is enclosed in a 3D printed prototype. The most difficult thing I did in this project was likely trying to fit it all in the enclosure. There were a lot of wires here and there, and the button was also quite difficult to fit in, as I needed to solder it on. However, this project was really fun to do, as it helped me gain knowledge about the environment around me, and I got to practice my software and hardware skills. I am really proud of myself, as I completed this project from start to finish, and didn’t give up. To test my project, all you have to do is plug in the battery pack, wait for a minute or so, point the prototype at the tree you want to scan, press the button, and wait for the results. Sometimes, it will take a little longer to get the results, resulting from a difficulty figuring out either the temperature or species of that particular plant/tree....
|
1793004568.6503468
|
1793090968.6503468
|
|
50622
|
Quary by @Veert | Stardance
|
Veert
|
1
|
141.33
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-20T12:28:09Z", "hours": 14.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "Working on improving the bot behavior aswell as mastering the gravity effects", "repo": "https://github.com/VrSchool11/Quary", "demo": "https://vrschool11.github.io/Quary/"}]...
|
[{"post_id": 67746, "ts": "202 [{"post_id": 67746, "ts": "2026-09-13T23:58:49Z", "hours": 5.4667, "text": "Rewrote Text and captions to sound more human"}, {"post_id": 66299, "ts": "2026-09-12T01:54:14Z", "hours": 13.8675, "text": "Making the game less ai by rewriting the affected parts"}, {"post_id": 65056, "ts": "2026-09-09T21:55:44Z", "hours": 8.4336, "text": "Adding some new features and improving on gameplay and improving the performance of the game on low-end devices"}, {"post_id": 64787, "ts": "2026-09-09T13:29:53Z", "hours": 4.6419, "text": "Working one some gameplay fixed and fixing some bugs"}, {"post_id": 64540, "ts": "2026-09-09T01:07:14Z", "hours": 1.0333, "text": "Completely Rewrote my code as when i shipped it the reviewer said it was over 30% ai now fixed it and its now below 30% ai"}, {"post_id": 64193, "ts": "2026-09-08T12:50:07Z", "hours": 7.6981, "text": "Fixing General Bugs and Fixing The boss fight"}, {"post_id": 63477, "ts": "2026-09-07T11:09:45Z", "hours": 8.8664, "text": "Working On Fixing The readability of the captions and fixing the tips and the tutorial for the game along with improving the layout of the game"}, {"post_id": 62152, "ts": "2026-09-05T12:26:37Z", "hours": 9.0681, "text": "Guns are in. You take one off the first guard you kill, and firing it wakes the whole zone so you build a silencer out of a sleeve, a spring and an oily rag. The king’s an actual fight now too, he winds up before every move so you can dodge it and one of them rips a limb off you and chucks it on the floor. He used to one-shot you if you’d gone full animal, so that’s gone. Checkpoints on every zone now, plus a pile of daft bugs fixed."}, {"post_id": 61860, "ts": "2026-09-04T23:59:57Z", "hours": 4.2339, "text": "Binned the black hole game after about a day and started Quarry instead. You’re a scientist who got kidnapped for something you built, they took your limbs, and you escape by tearing limbs off whatever you can find. Animal ones jump higher and hit harder, but the guards can see you’re not human anymore, which is basically the whole game. First playable version was rubbish. Every gap was too wide to clear, so you couldn’t actually finish it. Since then I’ve added five zones, a king to fight at the end, guns you loot off dead guards, and a silencer you build out of a sleeve, a spring and an oiled rag. Also spent way too long moving the gun sprite up four pixels because at hip height it looked like something else."}, {"post_id": 61283, "ts": "2026-09-04T04:06:54Z", "hours": 2.9639, "text": "Changed the Game Completely and moved onto another game idea as the other one didn’t seem to be working out heres a sneak peek below"}, {"post_id": 59498, "ts": "2026-09-01T11:27:27Z", "hours": 6.7897, "text": "1 September Today i completely redesigned the UI and also added two new features Different Type of foods A SpeedRun mode On top of that cleaned up the repo and fixed some minor issues here and there"}, {"post_id": 57370, "ts": "2026-08-29T14:27:55Z", "hours": 12.195, "text": "aug 29 completely remade the banner today — scrapped the old one and rebuilt it from scratch so it actually holds together. after that i cleaned up the code, tidying things up and cutting out the rough bits, and did some general improvements across the game while i was in there. more features coming soon."}, {"post_id": 54428, "ts": "2026-08-25T13:07:06Z", "hours": 9.8839, "text": "Fixed the big bug where growing your hole past a certain size would whiteout the entire screen — turned out the camera and the glow effects were both scaling wrong at high mass. While I was in there I added a bunch of new stuff: kill cam replays when you die, comets and binary planets that mess with gravity, a tracker that shows when a rogue hole is hunting you, and permanent achievements on top of the regular quests. Hosts can also now tweak gravity strength, arena size, and bot count before opening a station. Caught and fixed a couple of sneaky bugs along the way too, like eat sounds losing their punch on big absorbs. It’s all live on the GitHub Pages link now."}, {"post_id": 52329, "ts": "2026-08-22T13:13:51Z", "hours": 7.4672, "text": "Turned out if you’d already played a round and went back to the menu, you’d hear every bot in the background eating dust at full volume — the sound code treated “nobody’s watching” as “max volume” instead of silent. Fixed.Also added a pile of new stuff to actually do out there: dash (E key, quick burst forward, costs mass), wormholes that teleport you across the map, random supernova blasts that shove everything outward, a gravity slingshot off planets for a free speed boost, slow mass decay if you’re running away with the lead, a shockwave when you eat something way smaller than you, and a token bounty on whoever’s currently #1."}, {"post_id": 52060, "ts": "2026-08-22T03:27:35Z", "hours": 14.3667, "text": "Spent this session on polish and cleanup. Reworked the UI and CSS myself — set up a color palette with variables so the whole game re-themes from one place, and simplified a lot of the styling. Also fixed a performance bug: the game ran fine in Safari but lagged in Chrome. Turned out canvas shadow-blur is way slower in Chromium, so I cut it off the small stuff (dust, particles) and leaned on the additive glow instead. Runs smooth now. Still fixing the plinko bonus round and cleaning things up. More soon."}, {"post_id": 51642, "ts": "2026-08-21T12:55:44Z", "hours": 4.9736, "text": "Big redesign + feature passRepainted the whole UI — it was reading way too “safe dark-mode template,” so it’s now themed around eclipse observation expeditions instead: brass, khaki, oxide colors, stencil title font, manifest-style panels. Gameplay’s untouched, just the look changed.Also shipped a bunch of stuff that had been on the list:personal best (mass + survival time) on the menusettings: quality toggle, volume slider, minimap on/offkill streak popup when you’re on a rollfree color picker for your holefirst-time tutorial popupauto-lowers quality if your fps tankspower-ups: speed, magnet, shieldtimed matches and last-hole-standing modeteams (red vs blue), no friendly firedaily challenge — same seeded world for everyone each dayFound and fixed two real bugs while testing: the shop wasn’t updating your token count after a purchase, and timed matches were miscalculating rank when multiple people hit the clock at once."}, {"post_id": 51436, "ts": "2026-08-21T04:27:59Z", "hours": 3.7672, "text": "UPDATE — CSS rebuild + progression system. Review sent it back saying my CSS looked too AI-made, so I rebuilt the styling myself and actually learned how it works — set up a color palette with variables and re-themed the whole game in one line to prove it. While I was in there I added a progression system: tokens you earn each run and keep between games, side quests for bonus tokens, a cosmetics shop (colors and orbiting shapes, no pay-to-win), and an end-of-run plinko round that multiplies your run tokens (minimum 1x, so you can never lose them), plus arrow-key/WASD movement and a pause button. Biggest headache was the plinko ball not landing in a slot — the physics were using the display size instead of the canvas’s real size — fixed once I matched them."}, {"post_id": 50987, "ts": "2026-08-20T14:02:44Z", "hours": 1.6131, "text": "UPDATE — Multiplayer is live (online, with room codes) Summary Blackhole.io is now real online multiplayer. Create a room, share the code, and someone on another device joins and you can actually eat each other. Not bots — real people. Breakdown moved the whole game simulation onto a server so it’s authoritative (server decides what’s real, clients can’t cheat) clients now only send their mouse target; the server sends back everyone’s positions create/join a room with a short code, each room is its own isolated game added interpolation so other players move smoothly instead of teleporting between updates bots still fill empty rooms so it’s never a dead lobby deployed the server to Render and the game page to GitHub Pages, wired together over WebSockets What fought me The networking logic wasn’t even the hard part — deploying it was. Getting the GitHub Pages page to actually talk to the Render server took forever. The site kept opening my README instead of the game, the WebSocket wouldn’t connect because it was still pointing at localhost, and it had to be wss:// not ws:// or the browser silently blocked it. Bunch of small things that each looked like the whole thing was broken. Once the client finally connected to the live server and I saw a second black hole move on my screen, that was the moment. Note: Server May Take some time to start up"}, {"post_id": 50934, "ts": "2026-08-20T12:25:40Z", "hours": 6.6444, "text": "Working On fixing the lag caused by the advance gravity effects"}, {"post_id": 50512, "ts": "2026-08-19T18:02:36Z", "hours": 7.405, "text": "Spent today getting Blackhole.io off the ground. You’re a black hole — you eat dust, grow, and start pulling in bigger stuff. Got the core loop working: move toward the mouse, swallow anything smaller, get bigger. Made growth area-based so it doesn’t snowball out of control in ten seconds. The part that ate my time was gravity. I didn’t want stuff to just slide toward me — I wanted it to actually orbit and spiral in. Took a lot of fiddling with the numbers before it felt right instead of floaty. About 7.5 hours in so far. Next up: making the other black holes smarter so it’s not just me alone out there aswell as a multiplayer version so you can play with your friends"}]...
|
Title: Quary by @Veert | Stardance
Devlogs:
Spent Title: Quary by @Veert | Stardance
Devlogs:
Spent today getting Blackhole.io off the ground. You’re a black hole — you eat dust, grow, and start pulling in bigger stuff. Got the core loop working: move toward the mouse, swallow anything smaller, get bigger. Made growth area-based so it doesn’t snowball out of control in ten seconds. The part that ate my time was gravity. I didn’t want stuff to just slide toward me — I wanted it to actually orbit and spiral in. Took a lot of fiddling with the numbers before it felt right instead of floaty. About 7.5 hours in so far. Next up: making the other black holes smarter so it’s not just me alone out there aswell as a multiplayer version so you can play with your friends
Working On fixing the lag caused by the advance gravity effects
UPDATE — Multiplayer is live (online, with room codes) Summary Blackhole.io is now real online multiplayer. Create a room, share the code, and someone on another device joins and you can actually eat each other. Not bots — real people. Breakdown moved the whole game simulation onto a server so it’s authoritative (server decides what’s real, clients can’t cheat) clients now only send their mouse target; the server sends back everyone’s positions create/join a room with a short code, each room is its own isolated game added interpolation so other players move smoothly instead of teleporting between updates bots still fill empty rooms so it’s never a dead lobby deployed the server to Render and the game page to GitHub Pages, wired together over WebSockets What fought me The networking logic wasn’t even the hard part — deploying it was. Getting the GitHub Pages page to actually talk to the Render server took forever. The site kept opening my README instead of the game, the WebSocket wouldn’t connect because it was still pointing at localhost, and it had to be wss:// not ws:// or the browser silently blocked it. Bunch of small things that each looked like the whole thing was broken. Once the client finally connected to the live server and I saw a second black hole move on my screen, that was the moment. Note: Server May Take some time to start up
UPDATE — CSS rebuild + progression system. Review sent it back saying my CSS looked too AI-made, so I rebuilt the styling myself and actually learned how it works — set up a color palette with variables and re-themed the whole game in one line to prove it. While I was in there I added a progression system: tokens you earn each run and keep between games, side quests for bonus tokens, a cosmetics shop (colors and orbiting shapes, no pay-to-win), and an end-of-run plinko round that multiplies your run tokens (minimum 1x, so you can never lose them), plus arrow-key/WASD movement and a pause button. Biggest headache was the plinko ball not landing in a slot — the physics were using the display size instead of the canvas’s real size — fixed once I matched them.
Big redesign + feature passRepainted the whole UI — it was reading way too “safe dark-mode template,” so it’s now themed around eclipse observation expeditions instead: brass, khaki, oxide colors, stencil title font, manifest-style panels. Gameplay’s untouched, just the look changed.Also shipped a bunch of stuff that had been on the list:personal best (mass + survival time) on the menusettings: quality toggle, volume slider, minimap on/offkill streak popup when you’re on a rollfree color picker for your holefirst-time tutorial popupauto-lowers quality if your fps tankspower-ups: speed, magnet, shieldtimed matches and last-hole-standing modeteams (red vs blue), no friendly firedaily challenge — same seeded world for everyone each dayFound and fixed two real bugs while testing: the shop wasn’t updating your token count after a purchase, and timed matches were miscalculating rank when multiple people hit the clock at once.
Spent this session on polish and cleanup. Reworked the UI and CSS myself — set up a color palette with variables so the whole game re-themes from one place, and simplified a lot of the styling. Also fixed a performance bug: the game ran fine in Safari but lagged in Chrome. Turned out canvas shadow-blur is way slower in Chromium, so I cut it off the small stuff (dust, particles) and leaned on the additive glow instead. Runs smooth now. Still fixing the plinko bonus round and cleaning things up. More soon.
Turned out if you’d already played a round and went back to the menu, you’d hear every bot in the background eating dust at full volume — the sound code treated “nobody’s watching” as “max volume” instead of silent. Fixed.Also added a pile of new stuff to actually do out there: dash (E key, quick burst forward, costs mass), wormholes that teleport you across the map, random supernova blasts that shove everything outward, a gravity slingshot off planets for a free speed boost, slow mass decay if you’re running away with the lead, a shockwave when you eat something way smaller than you, and a token bounty on whoever’s currently #1.
Fixed the big bug where growing your hole past a certain size would whiteout the entire screen — turned out the camera and the glow effects were both scaling wrong at high mass. While I was in there I added a bunch of new stuff: kill cam replays when you die, comets and binary planets that mess with gravity, a tracker that shows when a rogue hole is hunting you, and permanent achievements on top of the regular quests. Hosts can also now tweak gravity strength, arena size, and bot count before opening a station. Caught and fixed a couple of sneaky bugs along the way too, like eat sounds losing their punch on big absorbs. It’s all live on the GitHub Pages link now.
aug 29 completely remade the banner today — scrapped the old one and rebuilt it from scratch so it actually holds together. after that i cleaned up the code, tidying things up and cutting out the rough bits, and did some general improvements across the game while i was in there. more features coming soon.
1 September Today i completely redesigned the UI and also added two new features Different Type of foods A SpeedRun mode On top of that cleaned up the repo and fixed some minor issues here and there
Changed the Game Completely and moved onto another game idea as the other one didn’t seem to be working out heres a sneak peek below
Binned the black hole game after about a day and started Quarry instead. You’re a scientist who got kidnapped for something you built, they took your limbs, and you escape by tearing limbs off whatever you can find. Animal ones jump higher and hit harder, but the guards can see you’re not human anymore, which is basically the whole game. First playable version was rubbish. Every gap was too wide to clear, so you couldn’t actually finish it. Since then I’ve added five zones, a king to fight at the end, guns you loot off dead guards, and a silencer you build out of a sleeve, a spring and an oiled rag. Also spent way too long moving the gun sprite up four pixels because at hip height it looked like something else.
Guns are in. You take one off the first guard you kill, and firing it wakes the whole zone so you build a silencer out of a sleeve, a spring and an oily rag. The king’s an actual fight now too, he winds up before every move so you can dodge it and one of them rips a limb off you and chucks it on the floor. He used to one-shot you if you’d gone full animal, so that’s gone. Checkpoints on every zone now, plus a pile of daft bugs fixed.
Working On Fixing The readability of the captions and fixing the tips and the tutorial for the game along with improving the layout of the game
Fixing General Bugs and Fixing The boss fight
Completely Rewrote my code as when i shipped it the reviewer said it was over 30% ai now fixed it and its now below 30% ai
Working one some gameplay fixed and fixing some bugs
Adding some new features and improving on gameplay and improving the performance of the game on low-end devices
Making the game less ai by rewriting the affected parts
Rewrote Text and captions to sound more human
Ships:
Working on improving the bot behavior aswell as mastering the gravity effects...
|
1792993946.4456816
|
1793080346.4456816
|
|
16179
|
Robotics RoboLens by @mira_j_maroni | Stardance
|
mira_j_maroni
|
2
|
140.27
|
26
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T22:22:22Z", "hours": 124.0, "multiplier": 16.83, "payout": 0, "blessing": "neutral", "text": "What did I make? Since Ship #1, RoboLens grew from one AI scanner into four connected tools. I added a rules checker that reads the actual FRC game manual (2024–2026) alongside your robot photo so it’s grounded in real rules instead of guessing. I built out a full shared battery tracker. I added a guided camera that walks you through lighting/tilt/framing and auto-captures once the angle looks right. And the biggest addition: a Team Stats & Match Center with four tabs (My Team, Stats, Events, Sim) pulling live data from The Blue Alliance and the FRC Events API, including a season-wide “World Rating,” a matchup simulator with win probabilities, and bookmarking teams to get real push notifications before their matches. I also spent a lot of time on stuff that doesn’t show up as a “feature” but makes the app actually usable: a queue + exponential backoff + retry system so the shared free-tier Gemini key doesn’t randomly fail scans under load, a report button that feeds recurring AI mistakes back into future scans, offline detection so scans fail fast instead of hanging, and a new instant-loading splash screen. What was challenging for me? The AI usage limits were the most persistent problem. Everyone shares one free-tier Gemini key, so scans would fail with no clear pattern whenever enough people hit it at once. I fixed it in stages: first a queue limiting in-flight requests, then automatic retries with backoff (and respecting the retry-after header when Gemini gave one), then finally surfacing that retry status to the user (“High demand. Retrying (2/3)…”) instead of just showing a dead spinner. The guided camera and push notifications both turned into whole rabbit holes of browser-specific pain (iOS Safari blocking camera/notification permissions unless triggered by a direct tap, no live frame streaming on web so I had to build a custom JS-interop layer from scratch, and push not working on iOS at all unless the site’s added to the home screen firs)t. My favorite bug story: the Match Center’s Events tab would spin forever with zero errors. I burned time adding timeouts and retries that did nothing before realizing the real issue. The spinner wasn’t stuck waiting on the network, it was stuck because nothing ever tried. What am I the most proud of? Going from a single-purpose AI scanner to four genuinely useful, connected tools without the codebase turning into spaghetti. I’m also proud that scans now degrade gracefully under load instead of just failing, and that notifications work reliably even though I had zero experience with service workers or VAPID keys before this. And honestly, just sticking with it. 21 devlogs and three months of real iteration based on actual user feedback instead of giving up. What should people know so they can test your project? Live app: https://mirage54321.github.io/RoboLens/ You can log in as a guest for team 4388 to browse batteries without needing an account. Push notifications currently work reliably on desktop browsers and Android (iOS Safari requires the site to be added to your home screen as a bookmark). You can test this by logging into -4388 (Yes, a negative. I needed a number that wouldn’t have a real team). The AI scan/rules tools need a robot photo to test against; if you don’t have one handy, any well-lit photo of mechanical/electrical components will still show you how the flow works.", "repo": "https://github.com/mirage54321/RoboLens", "demo": "https://mirage54321.github.io/RoboLens/"}, {"ship_num": 2, "ts": "2026-06-22T18:39:59Z", "hours": 5.0, "multiplier": 5.73, "payout": 26, "blessing": "neutral", "text": "I made an app for specifically robotics teams (although this could be used for other things too). This is still a work in progress because there is so much more I want to add. I did this project so that I could make something with an AI model and I’m really proud of myself because Flutter was really hard to work with!", "repo": "https://github.com/mirage54321/RoboLens", "demo": "https://mirage54321.github.io/RoboLens/"}]...
|
[{"post_id": 65393, "ts": "202 [{"post_id": 65393, "ts": "2026-09-10T14:37:50Z", "hours": 6.5575, "text": "Devlog #23 -> Fixed the camera disconnect crash from the feedback. Turns out the camera plugin doesn’t actually throw an error when the hardware gets yanked mid-session, it just quietly flips an internal hasError flag and keeps going. Which is why the app was crashing somewhere random instead of failing cleanly. Nothing in my code was listening for that flag, so it just kept trying to read frames and capture photos off a dead controller. Fixed it by adding a listener that actually watches for that error state, cleans everything up, and drops the user onto a proper “Camera disconnected, try again” screen instead of freezing or throwing. Also fixed the retry logic after a failed capture so it doesn’t try to restart a stream on a controller that’s already dead. Next up: the cursor. Someone pointed that out, because every button on web just shows the default arrow. Live app: https://mirage54321.github.io/RoboLens/a"}, {"post_id": 64602, "ts": "2026-09-09T03:43:12Z", "hours": 4.7133, "text": "Devlog #22 -> I was looking at the comments people left me from my ship and the first thing I noticed that I should work on is the load-in page. It is definitely kind of plain. To be honest, I used Claude to help a lot with this one. Making the spinning circle was pretty easy but I had some complex ideas I wanted to put to work and I just didn’t know how to do it. It has a huge radar that has the colors pop up and says “scounting __ teams”. Overall, I am so happy about this new design! Let me know what you guys think! I also added a folder for the photos so it looks more organized! The next thing I plan to work on “loop crashes if the camera disconnects” comment. Live app: https://mirage54321.github.io/RoboLens/"}, {"post_id": 63881, "ts": "2026-09-07T21:41:15Z", "hours": 2.065, "text": "Updates!!! Basically, I’ve been checking to see how many users and views I have. I have google analytics on my project to keep an eye on it. Right now I have 52 users and 163 views. Which honestly, I am pretty dang happy about. (1) I haven’t really been advertising (2) I literally thought it was gonna be like 20 views Woop woop! Okay, now on these past few days I have been working on getting as many hours as possible. I don’t have a personal computer so I am really aiming for literally any of the laptops. Now, programatically I have been working on removing the 3 burst messages for iPhone (it wouldn’t compact itself on the Apple homescreen). FYI: 90% of the time for this was spent removing the 3 burst messages for iPhone and writing Ship #2… so you better be ready for Ship 2! View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 63811, "ts": "2026-09-07T19:35:43Z", "hours": 0.7911, "text": "Notifications are working again! Basically, the rebuilding of Render helped fix the issue which is kind of ragebait. I’m getting a little nervous though because I wonder what happens if someone doesn’t reopen the bookmark (because that is how it resets). Would they still get the messages? Will it update automatically? Overall, it works great. I just worry there may be an error that arises (that is a risk with any project honestly). View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 63771, "ts": "2026-09-07T18:47:23Z", "hours": 5.1583, "text": "Devlog #19 -> I know I just committed a bunch the last few days. I guess I realized there is only a few days left and I found how to be way more efficent in getting hours. If I just keep this open and something else on another computer and work with them kinda being different windows then I get a lot more time because the switching of windows in the same computer made me keep forgetting to come back and work on the project (and I’m guessing was cutting the time too). Anywho! The most recent changes I have made is removing the ? mark button. I think I was going for a like “about me” thing but I think it was a little redundant and kind of unneccessary to say the least. I added a report button instead (it’s just in the home page). I got this idea from lovable which was something I worked with during my internship. I highkey have been working so much on this project (you can see by all my hours) that I didn’t want to connect it to the backend. It is just a popout that takes you to an gmail link and you can click send. Maybe if I run out of ideas I can add it as a backend. Now, if I am going to be so honest. I have worked a lot on this project and I want to ship but I also want to just crank out some more hours. I’m extremely proud of this project and I need to get it out to the world so that I can get some users! My issues to work on are: Low MongoDB storage for free account Professionalizing (now just looking back over and seeing if there is anything I wanna fix before putting on chief delphi) View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 63405, "ts": "2026-09-07T07:05:48Z", "hours": 8.2653, "text": "Devlog #18 -> Okay, super short devlog just to explain what I am doing. Basically all my hours are spent on fixing the notifications. It is super annoying right now because I am trying to finalize my project and the notifications randomly stop working. I tried clearing out mongoDB and checking on my cron-job and those seem to be working just fine. I’m not sure what to do. I pushed the hours up (for the practice day so I can check it earlier) and redeployed with Render. I shall see tomorrow if it works. View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 62347, "ts": "2026-09-05T17:45:39Z", "hours": 8.4539, "text": "Devlog #17 -> Part 3, wrapping this one up Last piece was making the retrying actually visible instead of just quietly happening in the background. Before, if a scan was retrying you’d just stare at a spinner with no idea what was going on. Now the loading screen updates to say something like “High demand. Retrying (2/3)…” so people know the app hasn’t frozen, it’s just waiting its turn. Between the queueing, the backoff retries on both ends, and this messaging, this should turn a lot of what used to be “scan failed, try again” moments into just a few extra seconds of waiting instead. Doesn’t make the free tier limit go away entirely, but it’s a big improvement over what I had. Current problems / what’s next: Low MongoDB storage for free account Professionalizing (before putting on Chief Delphi)"}, {"post_id": 61646, "ts": "2026-09-04T17:29:48Z", "hours": 9.4403, "text": "Devlog #16 -> Part 2, continuing from #15 Got retries working on top of the queue from last time. If Gemini comes back with a 429 (rate limited) or 503 (overloaded) instead of an actual answer, the backend now waits and tries again automatically, using exponential backoff (2s, then 4s, then 8s) instead of hammering it again right away, up to a few attempts before it actually gives up and reports failure. It also checks for a retry-after header first and uses that instead of the backoff timer if Gemini actually tells us how long to wait. Then I mirrored the same idea on the Flutter side, so if the backend’s retries still aren’t enough, the app itself will retry the whole request a couple more times before showing the user an error."}, {"post_id": 60875, "ts": "2026-09-03T14:59:25Z", "hours": 12.3994, "text": "Devlog #15 -> Part 1 (still working on this one!) Finally started actually tackling the AI usage limit problem from devlog #2. Since everyone using the app shares the same free-tier Gemini key, scans would just randomly fail with no real pattern whenever enough people were hitting it at once. Started on the backend side first: instead of letting every incoming scan hit Gemini immediately, I added a little queue that only lets 2 requests be in-flight to Gemini at a time, and everything else waits its turn. Next step is getting it to actually retry instead of just failing after the wait, but that’s for the next devlog."}, {"post_id": 60344, "ts": "2026-09-02T16:57:27Z", "hours": 7.4197, "text": "Devlog #14 -> Part 5 of 5 Finally! This final devlog is about the small tweaks I made in the app. I made it have a new photo Small one, just swapped out one of the app’s images for something more current since the old one was from way back in devlog #1 and didn’t really represent what the app looks like anymore. Nothing technical here, just housekeeping. It kinda works offline I say “kinda” because this isn’t a real offline mode where you can browse cached data with no internet, it’s more like the app now knows when it’s offline and fails fast instead of just hanging. Basically, I added a ConnectivityCheck helper that on web reads navigator.onLine (a free, instant, synchronous browser check for whether the device has a network interface up) so if you’re in airplane mode or your wifi is off, the AI scan screens can immediately say “can’t use this when offline” instead of sitting there for a full request timeout before failing. On native platforms there’s no real equivalent without pulling in a whole new plugin like connectivity_plus, so I just made the stub always report “online” there — an actually-offline phone still gets caught by the AI request’s own timeout/retry handling, just without the instant fail I get on web. One thing worth noting: this only checks if the device thinks it has a network connection, not whether that network actually has working internet behind it. So a wifi network that’s connected but dead will still say “online” here. That case still gets caught eventually, just the slower way through the request timeout instead of instantly. Good enough for now though, this was mostly about killing the most common case of someone trying to scan with their phone in airplane mode and just watching the app hang. I changed the load in screen Went back and reworked the loading screen from devlog #5. It’s now a plain CSS screen sitting directly in index.html instead of living inside the Flutter app itself, which means it can actually paint the instant the page loads, before Flutter has even finished downloading and booting up. That was the whole point: the old version technically only appeared once Flutter itself was far enough along to render it, so there was still a blank/white flash before it. Now there’s a little animated wordmark and spinner (the spinner’s colored arc cycles through the same colors as the logo letters) that fades out and removes itself once Flutter fires its first real frame. While I was in there I also fixed something unrelated but annoying: Flutter’s web service worker by default waits to activate a new version until every open instance of the app is fully closed, which for something people add to their home screen basically never happens naturally. So people could keep opening an old cached version of the app for a long time after I’d pushed updates. Added a bit of JS to force any newly installed service worker to skip that wait and take over immediately (reloading the page once it does), so the next time someone opens the app after I ship something, they actually get it. And that’s it, I’m all caught up! Five devlogs in one sitting was a lot, but future updates should go back to being posted as I actually build them instead of in one giant backlog dump. Current problems / what’s next: Low MongoDB storage for free account Releasing the app (onto chief delphi to get feedback)!! Making it ready to release (working on the ? and report button) Future ideas: team tracker, public chat for teams, judging/interview prep tool, callout tool, round robin generator View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 59335, "ts": "2026-09-01T02:11:53Z", "hours": 9.7772, "text": "Devlog #13 -> Part 4 of 5 Continuing from #12: more on the match center, mostly the stuff that actually broke on me. Biggest bug of the bunch: on the Events tab, tapping into an event was supposed to show “scheduled to attend” info and the competing teams list, but both of those sections would just spin forever, no error, nothing. I assumed it was a network timing issue at first and went down a whole rabbit hole adding timeouts and retry logic that did absolutely nothing. Turns out the actual problem was way dumber: when I pushed the EventDetailScreen with Navigator.push, that screen gets placed in the Overlay as a sibling of the tab tree, not a child of it, meaning it’s NOT under my MatchScope anymore. So the second that screen tried to call MatchScope.of(context), it threw an assertion error immediately, before initState even got the chance to call setState and load anything. The spinner wasn’t stuck because of a slow network, it was stuck because the load call never even ran. Fixed it by just re-wrapping the pushed route in its own MatchScope using the same controller instance. Felt very silly once I found it, but also weirdly satisfying to finally understand. Next was the matchup simulator and win probabilities. On the schedule screen I show a rough “Red 45% / Blue 55%” prediction for each match. My first instinct was to use each event’s own OPR for this, but that falls apart for upcoming events since OPR doesn’t exist until a team has actually played a match there. So instead I based predictions on the season-wide World Rating from the Stats tab (average points across every event a team’s played all season), which actually gives predictions even for a event that hasn’t started yet. Also went back and hooked the push notification bell (from devlog #11) directly into the match center’s top bar now that there’s finally a “your team” + “your event” to actually attach a subscription to. There’s a little pulsing glow animation on the bell the first time you land on a screen where you could enable alerts, just so people notice it’s there instead of it blending into the top bar. Took way too many attempts to get the glow animation timing feeling smooth and not epileptic-seizure-inducing, but I think I landed on something decent. Genuinely didn’t expect the 4th app to take this many devlogs but here we are. One more to wrap up some small stuff and then I think I’m caught up! View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 58655, "ts": "2026-08-31T04:34:12Z", "hours": 9.4486, "text": "Devlog #12 -> Part 3 of 5 Okay, actual 4th app time: Team Stats & Match Center (internally I’ve just been calling it “match” in the code, so if you dig around the file names that’s why). I started by mocking everything out before touching any real API, just so I could get the UI feeling right first. Made an intro screen (basically pitching the three features: match alerts, team stats, matchup simulator) and a fake mockTeams list with made-up EPA numbers just so I had something to look at while building. Once the layout felt right, I started swapping the fake data for real stuff from The Blue Alliance’s API, proxied through my backend the same way I already had set up for the FRC Events API (so I’m not spamming TBA directly from a bunch of client apps and to keep my API key private). Architecture-wise, I did something different from my other three apps: instead of passing state down through a million constructor params, I made a MatchDataController (basically one class holding all the team/event/match data + loading state) and wrapped the whole feature in a MatchScope, which is just an InheritedNotifier. So anywhere in the match center I can just call MatchScope.of(context) and get the controller without threading it through every single widget. Probably overkill for how big this feature ended up being, but once I had 4 tabs and a handful of sub-screens all needing the same data, I was really glad I did it this way instead of my usual pass-everything-into-the-constructor approach. Speaking of tabs, I split it into 4: My Team -> your team’s own info/next match Stats -> a season-wide “World Rating” I calculate from aggregating TBA’s OPR data across events (this was its own whole thing, might do a separate devlog on it someday) Events -> browse every FRC event, filter by time or location, see who’s live right now Sim -> the matchup simulator I keep promising Getting match data to actually parse right from TBA’s JSON took a minute (comp levels like qm/qf/sf/f needed their own label logic, predicted_time vs actual_time needed fallback logic since actual_time barely ever gets posted until after the match is already over, that kind of thing) but nothing too crazy, just tedious model-writing. Devlog #13 is basically a straight continuation of this one, mostly bug stories and the simulator, so be ready for that. View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 55760, "ts": "2026-08-27T19:05:53Z", "hours": 4.8611, "text": "Devlog #11 -> Part 2 of 5 Now for the second devlog, I am going to talk about how I got notifications to work. This is the one that ate my week. So the goal: when a match is coming up for a team you bookmarked, get a push notification even if the app/tab isn’t open. That last part is the whole problem, because it means I can’t just pop a normal in-app alert, I actually need real browser push notifications, which meant learning a whole new stack: service workers, VAPID keys, and the Push API. Here’s roughly how it works now ->Subscribe -> user picks a team number + event key, the app asks the browser for notification permission, and if granted it registers a push subscription through the service worker using my VAPID public key. Send to backend -> that subscription (plus team number/event key) gets sent to my Express backend and stored in MongoDB. Actually sending them -> the backend uses the web-push npm package to send the push whenever it detects a match coming up for that team. Getting the Flutter side to talk to any of this was its own adventure, since none of this exists as a nice Dart package, so I had to write a JS interop layer (basically a matchPush object in plain JS that Dart calls into) and wire it up through the same conditional-export trick I used for the guided camera: one file for web, one stub file that just says “unsupported” for native, so the app doesn’t explode on phone builds while I haven’t built native push yet. Problems I ran into (there were many) ->iOS Safari straight up does not support web push at all unless the site has been added to the home screen first. So right now notifications basically only work reliably on desktop browsers and Android, and I have to eventually explain that to iOS users somehow. Permission requests have the same “must be triggered by a direct tap” rule I fought with on the guided camera, so subscribing has to happen from an actual button press, no auto-subscribing on load. Debugging this was rough because half the errors happen silently in the service worker, not in the normal Flutter console, so I was stuck adding console.logs into push.js and checking devtools like a caveman for a while.It works now though! Bookmark a team, subscribe, and you’ll get pinged. Native (phone-installed) push notifications are still a “later” problem since that needs a totally different setup (probably Firebase Cloud Messaging), so for now the stub just returns unsupported on native and I’m keeping my scope to web. Two devlogs about the 4th app itself coming up next, promise. View it here: https://mirage54321.github.io/RoboLens/ P.S. For right now there are 3 notifications that send for iOS I plan to change that though!"}, {"post_id": 54198, "ts": "2026-08-25T02:42:40Z", "hours": 8.6025, "text": "Devlog #10 -> Part 1 of 5 Please don’t hurt me, but I have to post multiple devlogs because I worked on so many things in all this time. It’s a lot of stuff to talk about and I don’t want to write it all into one because it will be super unorganized and hard for me to find in the future. In this first devlog, I am going to talk about how I got bookmarks to work. The idea came from thinking ahead to the match notifier. If someone wants alerts for a match, they need a way to say “these are the teams I care about” without having to retype a team number every single time. So I added a bookmark system using shared_preferences (just storing a list of team numbers locally on the device/browser). You can now star a team from a few places in the app and it’ll save to your bookmarks list, which I’m planning to hook the notifier into so it can just loop through your saved teams instead of asking you every time. This one was honestly pretty painless compared to my usual chaos. The only annoying part was making sure the bookmarked list actually persisted correctly on web (learned my lesson from the MongoDB flutter-web thing, so I tested this one on both platforms before moving on lol). Turns out shared_preferences just works with local storage under the hood on web, so no weird surprises this time. Short devlog, I know, but wait till you see what devlog #11 turned into. View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 49268, "ts": "2026-08-17T23:33:09Z", "hours": 6.1139, "text": "Devlog #9 -> Okay, so getting the report button to work was a little finicky. I wasn’t sure what approach to take: I could make it easy by just sending me the reported things and I could look at them and just change the prompt, or I could make it difficult by just feeding every single reported issue back into the AI model so that the AI tries to not make the same mistake (which might be a problem because someone could report something that was actually right), or make it VERY difficult make it feed back into the AI if a similar issues were coming up again and again. Guess which one I chose? Yup, the third. Basically, I decided to store the reports in MongoDB and look for recurring mistakes instead of letting a single report change the AI. That way, if one person reports something incorrectly, it doesn’t immediately affect everyone else’s scans. If the same type of mistake keeps getting reported, I can investigate it and use those reports to improve the AI.This seems really complex, and it was. It took me 4 hours (it says 6 on the devlog but 2 of them was working on the 4th app). Alright, ready for my fourth widget idea………. a match notifier!! Now don’t get too excited. I have more to tell. So, every FRC kid knows that there’s a website called Nexus that sends messages for when your game is going to start so you can get in queue, and it works really well. There’s also this thing I came across called statbotics, and it calculates many things like EPA, and more (I didn’t really stay on that website for too long). So, what I plan to do is combine them. Hopefully, I’m not getting myself into too much of a challenge. This will most definitely be the hardest thing I have ever done on this app. Wish me luck! P.S. I started making the fourth widget before the report button then switched to finish the report button halfway so if you see my commits in a confusing order that’s why. View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 43541, "ts": "2026-08-08T21:26:06Z", "hours": 0.3608, "text": "Devlog #8 -> Part 2/2 (part 2 of this devlog) I also posted my app onto reddit (r/FRC) and got some feedback. From the feedback, I got the message that an AI scanner can’t be all that reliable/useful without a user-end customization. I totally agree with this. The problem is that I’m not sure if it is worth it to spend time on adding in customization tools for the AI as there is not a lot of return from it. Therefore, I think that right now the AI’s are at the best product they can be as of now (besides adding functionality to the report button). So, my time would be better spent adding in more apps into the app. On the bright side, there were lots of positive reviews about the battery section! I am now going to work on the report button for the UI because I think it will take less time to add than adding a fourth app. In my next post, I will have a confirmed idea for the fourth app! Things to work on: Low MongoDB storage for free account Report button on the UI needs to feed into the AI ⭐ (Going to do this first because it is easier) Find solution for Render (takes a long time to power on and first time you try to do anything it always fails) Adding fourth ‘app’ ⭐⭐ View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 43529, "ts": "2026-08-08T21:02:52Z", "hours": 6.3211, "text": "Devlog #7 -> Part 2/2 (but part 1 of this devlog) Okay. This was very annoying to work on because every single time I would edit the code, I would have to recommit in order to see it on the github pages (because the permissions wouldn’t work on the flutter web-server). So, getting the guided camera working on web brought a whole lot of browser-specific issues that don’t show up on native mobile. First, the app would hang on a black loading screen because permission_handler and frame streaming aren’t supported in browsers. I then fixed that by branching on kIsWeb to skip those native-only calls and let the browser’s own getUserMedia prompt handle camera access instead.Next, iOS Safari blocked the camera request outright because it requires permission calls to fire directly from a user tap with no delay -> solved by gating the whole flow behind an explicit “Enable Camera” button instead of auto-starting on page load. Since camera_web doesn’t support live frame streaming and sensors_plus doesn’t handle iOS’s motion permission prompt, live guidance (tilt, brightness, sharpness) had to be rebuilt from scratch for web: a custom JS-interop layer (WebProbe) draws each video frame onto a hidden canvas to sample brightness/sharpness, and separately requests iOS’s DeviceMotionEvent permission to read tilt.That introduced two more subtle bugs (a Dart generics issue causing a null-cast crash in the interop code, and a timing issue where the element wasn’t in the DOM yet when we went looking for it) both fixed with explicit type arguments and a retry loop. With all of that sorted, the guided camera now works consistently across native and web, with live tilt/lighting/sharpness feedback and autocapture. View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 37868, "ts": "2026-07-30T20:50:16Z", "hours": 4.4522, "text": "Devlog #6 -> Part 1/2 Hey! I know it has been awhile since I worked on my project (adding the guided camera has been taking a lot of will power), but I have a new update. I have added the guided camera to the scan screen (which I will add to the rules screen too after it is finished). The process that the guided camera uses is: Startup -> requests camera permission immediately for phone usage (permission_handler) or waits for a tap on “Enable Camera” first for browser usage. Camera setup -> fetches available cameras (from Flutter’s camera plugin), picks the back-facing one (falls back to the first available camera on the device if no back camera is found), sets resolution to high on phone or medium on browser (since browsers often reject high-res requests), then calls initialize() to start the live preview. Manual fallback for taking photos -> the shutter button is always available to captures the photo; this is the primary method right now. Capture -> stops the frame stream (phone only), takes the picture, reads the bytes, then returns them to the previous screen via Navigator.pop(context, bytes). An issue I ran into was camera permissions on iPhone Safari. It worked fine on my laptop but wouldn’t work on my phone. I eventually figured out that iPhones are notorious for always requiring explicit permission prompts, so I solved it by requiring the camera request to be triggered by a direct user tap. Basically, I added an “Enable Camera” button on web that only calls the camera setup when tapped, since iOS Safari silently blocks getUserMedia (instead of showing an error) if there’s any delay between the tap and the request. Now I am working on the flutter comments (“too dark”, “focus”, etc.) because right now those aren’t working. Once I get the live guidance to work, then I will be able to implement an auto-capture (that way the photo is taken when at a good angle). View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 29717, "ts": "2026-07-16T20:11:47Z", "hours": 4.3139, "text": "Devlog #5 -> My app now has a load in screen! Yay! I figured it was necessary just to make my whole app look more professional. It was pretty easy (took lots of time though) to add and I didn’t fall into any huge difficulties. Only a mini one because I tried to make the animation in the home screen class and it got chaotic. Once it was its own file it was quite easy because then I just needed to fix up the UI. Look here if you want to learn more about how to do animations in your own project (if using Flutter): https://docs.flutter.dev/ui/animations I also added a very tiny change to the error message for logging in. Instead of saying “Team already registered”, it tells you to contact my email if you cannot access your team. I guess I got really nervous that someone would try to access their team, and if they couldn’t, they would go and put another team’s number and so on indefinitely. Right now, I think this is a good way to fix the issue, but I’ll add a way to report it in the app; that way, the issue can be solved quicker, and you won’t have to send an email to someone. I did have the idea to make it so there is identification of some sort for each team; however, that would just make the app complex, and my whole goal was to have a simple solution to problems. So, if this app actually does really well in the FRC world, I will add some sort of verification; that way lost accounts can be found, and it would just give all-around easier access. Next, I am going to focus on my long put off task: photo to video. I am not sure how I am going to do this, if I am going to be so honest. My idea for it came fom the Smile Doctors invisalign app where it opens up your camera and tells you things like “go to better lighting” or “move to the left”. However, I think that will be super complex and difficult to implement so I might have to start a lot smaller. Best of luck to myself, I guess! List of current tasks: Low MongoDB storage for free account Report button on the UI needs to feed into the AI ⭐ Find solution for Render (takes a long time to power on and first time you try to do anything it always fails) Photo to video (that way it can help you find the right orientation for the AI to scan with the best feedback possible) ⭐⭐ View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 28023, "ts": "2026-07-14T00:50:11Z", "hours": 4.6822, "text": "Devlog #4 -> Hey! I have been working on the issues I talked about in my last devlog. So far I have successfully solved one: How I solved “Connenction to MongoDB working for flutter web but not github?” -> The issue was that GitHub Pages is a static hosting service and couldn’t connect directly to MongoDB. Therefore I had to update the application so the GitHub Pages frontend communicates with the Express backend on Render. Basically, I just modified some of the backend configuration like changing (in very very simple terms): fetch(‘/battery’) to something like fetch(‘ https://ridgeboticsapp.onrender.com/battery ’). I also added a ? mark button so that if clicked on it can tell you a little more about the app. Right now, it is just saying some basic things but I plan to show this app to my friends and see what they think I should add to that text in order to help people figure out what is going on if they just found my app. Finally, I fixed an error I wasn’t even aware of: the name finder for each teams batteries. I made it so when you sign up your team, it will try to search up the team name with that FRC number. However, there would be times where I would sign in as my team and it would show up with some random name like “Robo-Knights” or something weird. I think this was related to the Gemini model because I had used it while testing, soincorrect team names could have been stored and reused instead of being verified. To fix this, I connected my backend to the official FRC Events API. Now, the app sends the team’s FRC number to FIRST to retrieve the official team information to then save the verified team name. This prevents teams from accidentally being assigned another team’s name and makes sure the battery data is connected to the correct FRC team. It was never too big of an issue because I could always just edit the names in MongoDB but having it so it says the name right 100% of the time is just much easier for me. Now my new top things to work on are: If team is signed up but you don’t have access to your team Photo to video (that way it can help you find the right orientation for the AI to scan with the best feedback possible) Report button working better to fix the AI’s findings View it here: https://mirage54321.github.io/RoboLens/ P.S. If you are trying things out you can sign in as a guest for 4388 and see my teams batteries"}, {"post_id": 24928, "ts": "2026-07-08T20:05:31Z", "hours": 1.5633, "text": "Devlog #3 -> In the past few days I have been working on adding a battery tracker because I believe that it has the potential to be very helpful to FRC teams. Tracking batteries is always a pain for my team, and other teams I’ve connected with can probably agree with that statement. Batteries can randomly fail by not charging or just full-on dying in two minutes. Although one might assume that keeping track of all this is easy, it truly is not. Having a system to hold records and data, I believe, can be very helpful to teams! I’ve added the third tool to the app: a shared battery tracker where a team can log in with a team number and passcode, add batteries, and mark each one as charging, in use, or available. It also lets you flag a battery as weak or unreliable with a note, so if a battery dies mid-match, the whole team can see that history the next time they’re deciding which one to grab. I even added an option for the AI to recommend which battery to use next based on how long it’s been charged and whether it’s been flagged before. My new challenge for this tool has been working with MongoDB. It stores the data fine, but it wasn’t letting me log in (it kept throwing an error). What confused me more is that when I ran it in Flutter web, it worked just fine. This is what I plan to work on for the next few days. To fix my last problem, which was with the AI saying it had spikes in usage, I changed the message to ask the user to try again because it usually works on the try right after. Right now, this is just a temporary solution until I can find a new AI model. List of things to work on: Low MongoDB storage for free account Report button on the UI needs to feed into the AI Find permanant solution for the AI usage Connenction to MongoDB working for flutter web but not github? Photo to video (that way it can help you find the right orientation for the AI to scan with the best feedback possible) View it here: https://mirage54321.github.io/RoboLens/ Log in as guest for team 4388 if you just want to view it. P.S. My logged time is glitching out a bunch and I would love if someone could help me in the #stardance-help on slack."}, {"post_id": 23707, "ts": "2026-07-06T20:19:01Z", "hours": 9.0781, "text": "Devlog #2-> Now that I’ve finished the foundation of my project, I can keep adding tools! On my last ship, I realized I should keep more documentation. So be ready for more devlogs going forward! To get a little more comfortable with what I’m doing, I decided to add another AI scanning tool that I have been thinking about: a rules checker. The general scanner already looked for physical problems like wiring and cracks, but I wanted something that could actually check a robot against the official FRC rulebook. So I added the actual PDFs of past FRC game manuals (2024, 2025, and 2026) and let the user pick which season’s rules to check against. That PDF gets fed into the AI alongside the photo, so instead of relying on whatever general FRC knowledge the model already has (which could be outdated or made up), it’s reading the exact rulebook for that year while it looks at the image. Getting the PDF into the AI request in the first place took some figuring out. I had to load it from the app’s assets, converting it into a format the API would actually accept, and making sure it got sent alongside the image without breaking anything. Once it worked though, the difference was noticeable (the AI’s answers started actually referencing real rules instead of guesses). The bigger challenge was AI usage limits. Not “too many messages” though. Instead, it was more that other people using the same free model at the same time meant my requests were competing with everyone else’s. Half the time a scan would go through fine, and the other half it just wouldn’t, with no real pattern I could find. To fix this I… haven’t yet, honestly. Still an open problem :(. Hoping to hear from you guys for some ideas! I’m a little nervous because AI kind of has a negative connotation in FRC. To address that issue, I’m planning to make the whole app not centered around AI so I’ll be adding more tools. Excited to keep going though, because I just started programming my new idea: adding a battery tracker! View it here: https://mirage54321.github.io/RoboLens/"}, {"post_id": 13860, "ts": "2026-06-22T18:21:53Z", "hours": 4.63, "text": "Devlog #1-> I’ve finished the foundation of my project! The app currently has a simple UI and one AI tool that takes in a photo and tells you what’s wrong with it — whether it’s frayed wiring, loose screws, cracked/bent frames, or corrosion. Goal of my project: cut down the time it takes to find an issue so an FRC team has more time to actually fix the problem, and flag problems a human might miss during a rushed pit-stop check. Working with Flutter to program the UI wasn’t too bad. I’ve always been used to Java and JavaScript, so although Dart isn’t exactly the same, I picked it up pretty fast. I had the most difficulty implementing the AI. I started with an Ollama model, but it was way too slow — it would time out before it ever finished telling me what it noticed in the photo. I then found out Google lets you use a free Gemini model, so I got an API key for that and added it in. The new problem: every time I published my app as a GitHub Page, the API key would get disabled because it wasn’t safe sitting in client-side code. I finally learned the key needs to live on a backend to actually be secure, so I set one up using Render. I’m so proud of how my project is looking so far! Next up, I plan to add more tools, like a rules scanner."}]...
|
Title: Robotics RoboLens by @mira_j_maroni | Stard Title: Robotics RoboLens by @mira_j_maroni | Stardance
Devlogs:
Devlog #1-> I’ve finished the foundation of my project! The app currently has a simple UI and one AI tool that takes in a photo and tells you what’s wrong with it — whether it’s frayed wiring, loose screws, cracked/bent frames, or corrosion. Goal of my project: cut down the time it takes to find an issue so an FRC team has more time to actually fix the problem, and flag problems a human might miss during a rushed pit-stop check. Working with Flutter to program the UI wasn’t too bad. I’ve always been used to Java and JavaScript, so although Dart isn’t exactly the same, I picked it up pretty fast. I had the most difficulty implementing the AI. I started with an Ollama model, but it was way too slow — it would time out before it ever finished telling me what it noticed in the photo. I then found out Google lets you use a free Gemini model, so I got an API key for that and added it in. The new problem: every time I published my app as a GitHub Page, the API key would get disabled because it wasn’t safe sitting in client-side code. I finally learned the key needs to live on a backend to actually be secure, so I set one up using Render. I’m so proud of how my project is looking so far! Next up, I plan to add more tools, like a rules scanner.
Devlog #2-> Now that I’ve finished the foundation of my project, I can keep adding tools! On my last ship, I realized I should keep more documentation. So be ready for more devlogs going forward! To get a little more comfortable with what I’m doing, I decided to add another AI scanning tool that I have been thinking about: a rules checker. The general scanner already looked for physical problems like wiring and cracks, but I wanted something that could actually check a robot against the official FRC rulebook. So I added the actual PDFs of past FRC game manuals (2024, 2025, and 2026) and let the user pick which season’s rules to check against. That PDF gets fed into the AI alongside the photo, so instead of relying on whatever general FRC knowledge the model already has (which could be outdated or made up), it’s reading the exact rulebook for that year while it looks at the image. Getting the PDF into the AI request in the first place took some figuring out. I had to load it from the app’s assets, converting it into a format the API would actually accept, and making sure it got sent alongside the image without breaking anything. Once it worked though, the difference was noticeable (the AI’s answers started actually referencing real rules instead of guesses). The bigger challenge was AI usage limits. Not “too many messages” though. Instead, it was more that other people using the same free model at the same time meant my requests were competing with everyone else’s. Half the time a scan would go through fine, and the other half it just wouldn’t, with no real pattern I could find. To fix this I… haven’t yet, honestly. Still an open problem :(. Hoping to hear from you guys for some ideas! I’m a little nervous because AI kind of has a negative connotation in FRC. To address that issue, I’m planning to make the whole app not centered around AI so I’ll be adding more tools. Excited to keep going though, because I just started programming my new idea: adding a battery tracker! View it here: https://mirage54321.github.io/RoboLens/
Devlog #3 -> In the past few days I have been working on adding a battery tracker because I believe that it has the potential to be very helpful to FRC teams. Tracking batteries is always a pain for my team, and other teams I’ve connected with can probably agree with that statement. Batteries can randomly fail by not charging or just full-on dying in two minutes. Although one might assume that keeping track of all this is easy, it truly is not. Having a system to hold records and data, I believe, can be very helpful to teams! I’ve added the third tool to the app: a shared battery tracker where a team can log in with a team number and passcode, add batteries, and mark each one as charging, in use, or available. It also lets you flag a battery as weak or unreliable with a note, so if a battery dies mid-match, the whole team can see that history the next time they’re deciding which one to grab. I even added an option for the AI to recommend which battery to use next based on how long it’s been charged and whether it’s been flagged before. My new challenge for this tool has been working with MongoDB. It stores the data fine, but it wasn’t letting me log in (it kept throwing an error). What confused me more is that when I ran it in Flutter web, it worked just fine. This is what I plan to work on for the next few days. To fix my last problem, which was with the AI saying it had spikes in usage, I changed the message to ask the user to try again because it usually works on the try right after. Right now, this is just a temporary solution until I can find a new AI model. List of things to work on: Low MongoDB storage for free account Report button on the UI needs to feed into the AI Find permanant solution for the AI usage Connenction to MongoDB working for flutter web but not github? Photo to video (that way it can help you find the right orientation for the AI to scan with the best feedback possible) View it here: https://mirage54321.github.io/RoboLens/ Log in as guest for team 4388 if you just want to view it. P.S. My logged time is glitching out a bunch and I would love if someone could help me in the #stardance-help on slack.
Devlog #4 -> Hey! I have been working on the issues I talked about in my last devlog. So far I have successfully solved one: How I solved “Connenction to MongoDB working for flutter web but not github?” -> The issue was that GitHub Pages is a static hosting service and couldn’t connect directly to MongoDB. Therefore I had to update the application so the GitHub Pages frontend communicates with the Express backend on Render. Basically, I just modified some of the backend configuration like changing (in very very simple terms): fetch(‘/battery’) to something like fetch(‘ https://ridgeboticsapp.onrender.com/battery ’). I also added a ? mark button so that if clicked on it can tell you a little more about the app. Right now, it is just saying some basic things but I plan to show this app to my friends and see what they think I should add to that text in order to help people figure out what is going on if they just found my app. Finally, I fixed an error I wasn’t even aware of: the name finder for each teams batteries. I made it so when you sign up your team, it will try to search up the team name with that FRC number. However, there would be times where I would sign in as my team and it would show up with some random name like “Robo-Knights” or something weird. I think this was related to the Gemini model because I had used it while testing, soincorrect team names could have been stored and reused instead of being verified. To fix this, I connected my backend to the official FRC Events API. Now, the app sends the team’s FRC number to FIRST to retrieve the official team information to then save the verified team name. This prevents teams from accidentally being assigned another team’s name and makes sure the battery data is connected to the correct FRC team. It was never too big of an issue because I could always just edit the names in MongoDB but having it so it says the name right 100% of the time is just much easier for me. Now my new top things to work on are: If team is signed up but you don’t have access to your team Photo to video (that way it can help you find the right orientation for the AI to scan with the best feedback possible) Report button working better to fix the AI’s findings View it here: https://mirage54321.github.io/RoboLens/ P.S. If you are trying things out you can sign in as a guest for 4388 and see my teams batteries
Devlog #5 -> My app now has a load in screen! Yay! I figured it was necessary just to make my whole app look more professional. It was pretty easy (took lots of time though) to add and I didn’t fall into any huge difficulties. Only a mini one because I tried to make the animation in the home screen class and it got chaotic. Once it was its own file it was quite easy because then I just needed to fix up the UI. Look here if you want to learn more about how to do animations in your own project (if using Flutter): https://docs.flutter.dev/ui/animations I also added a very tiny change to the error message for logging in. Instead of saying “Team already registered”, it tells you to contact my email if you cannot access your team. I guess I got really nervous that someone would try to access their team, and if they couldn’t, they would go and put another team’s number and so on indefinitely. Right now, I think this is a good way to fix the issue, but I’ll add a way to report it in the app; that way, the issue can be solved quicker, and you won’t have to send an email to someone. I did have the idea to make it so there is identification of some sort for each team; however, that would just make the app complex, and my whole goal was to have a simple solution to problems. So, if this app actually does really well in the FRC world, I will add some sort of verification; that way lost accounts can be found, and it would just give all-around easier access. Next, I am going to focus on my long put off task: photo to video. I am not sure how I am going to do this, if I am going to be so honest. My idea for it came fom the Smile Doctors invisalign app where it opens up your camera and tells you things like “go to better lighting” or “move to the left”. However, I think that will be super complex and difficult to implement so I might have to start a lot smaller. Best of luck to myself, I guess! List of current tasks: Low MongoDB storage for free account Report button on the UI needs to feed into the AI ⭐ Find solution for Render (takes a long time to power on and first time you try to do anything it always fails) Photo to video (that way it can help you find the right orientation for the AI to scan with the best feedback possible) ⭐⭐ View it here: https://mirage54321.github.io/RoboLens/
Devlog #6 -> Part 1/2 Hey! I know it has been awhile since I worked on my project (adding the guided camera has been taking a lot of will power), but I have a new update. I have added the guided camera to the scan screen (which I will add to the rules screen too after it is finished). The process that the guided camera uses is: Startup -> requests camera permission immediately for phone usage (permission_handler) or waits for a tap on “Enable Camera” first for browser usage. Camera setup -> fetches available cameras (from Flutter’s camera plugin), picks the back-facing one (falls back to the first available camera on the device if no back camera is found), sets resolution to high on phone or medium on browser (since browsers often reject high-res requests), then calls initialize() to start the live preview. Manual fallback for taking photos -> the shutter button is always available to captures the photo; this is the primary method right now. Capture -> stops the frame stream (phone only), takes the picture, reads the bytes, then returns them to the previous screen via Navigator.pop(context, bytes). An issue I ran into was camera permissions on iPhone Safari. It worked fine on my laptop but wouldn’t work on my phone. I eventually figured out that iPhones are notorious for always requiring explicit permission prompts, so I solved it by requiring the camera request to be triggered by a direct user tap. Basically, I added an “Enable Camera” button on web that only calls the camera setup when tapped, since iOS Safari silently blocks getUserMedia (instead of showing an error) if there’s any delay between the tap and the request. Now I am working on the flutter comments (“too dark”, “focus”, etc.) because right now those aren’t working. Once I get the live guidance to work, then I will be able to implement an auto-capture (that way the photo is taken when at a good angle). View it here: https://mirage54321.github.io/RoboLens/
Devlog #7 -> Part 2/2 (but part 1 of this devlog) Okay. This was very annoying to work on because every single time I would edit the code, I would have to recommit in order to see it on the github pages (because the permissions wouldn’t work on the flutter web-server). So, getting the guided camera working on web brought a whole lot of browser-specific issues that don’t show up on native mobile. First, the app would hang on a black loading screen because permission_handler and frame streaming aren’t supported in browsers. I then fixed that by branching on kIsWeb to skip those native-only calls and let the browser’s own getUserMedia prompt handle camera access instead.Next, iOS Safari blocked the camera request outright because it requires permission calls to fire directly from a user tap with no delay -> solved by gating the whole flow behind an explicit “Enable Camera” button instead of auto-starting on page load. Since camera_web doesn’t support live frame streaming and sensors_plus doesn’t handle iOS’s motion permission prompt, live guidance (tilt, brightness, sharpness) had to be rebuilt from scratch for web: a custom JS-interop layer (WebProbe) draws each video frame onto a hidden canvas to sample brightness/sharpness, and separately requests iOS’s DeviceMotionEvent permission to read tilt.That introduced two more subtle bugs (a Dart generics issue causing a null-cast crash in the interop code, and a timing issue where the element wasn’t in the DOM yet when we went looking for it) both fixed with explicit type arguments and a retry loop. With all of that sorted, the guided camera now works consistently across native and web, with live tilt/lighting/sharpness feedback and autocapture. View it here: https://mirage54321.github.io/RoboLens/
Devlog #8 -> Part 2/2 (part 2 of this devlog) I also posted my app onto reddit (r/FRC) and got some feedback. From the feedback, I got the message that an AI scanner can’t be all that reliable/useful without a user-end customization. I totally agree with this. The problem is that I’m not sure if it is worth it to spend time on adding in customization tools for the AI as there is not a lot of return from it. Therefore, I think that right now the AI’s are at the best product they can be as of now (besides adding functionality to the report button). So, my time would be better spent adding in more apps into the app. On the bright side, there were lots of positive reviews about the battery section! I am now going to work on the report button for the UI because I think it will take less time to add than adding a fourth app. In my next post, I will have a confirmed idea for the fourth app! Things to work on: Low MongoDB storage for free account Report button on the UI needs to feed into the AI ⭐ (Going to do this first because it is easier) Find solution for Render (takes a long time to power on and first time you try to do anything it always fails) Adding fourth ‘app’ ⭐⭐ View it here: https://mirage54321.github.io/RoboLens/
Devlog #9 -> Okay, so getting the report button to work was a little finicky. I wasn’t sure what approach to take: I could make it easy by just sending me the reported things and I could look at them and just change the prompt, or I could make it difficult by just feeding every single reported issue back into the AI model so that the AI tries to not make the same mistake (which might be a problem because someone could report something that was actually right), or make it VERY difficult make it feed back into the AI if a similar issues were coming up again and again. Guess which one I chose? Yup, the third. Basically, I decided to store the reports in MongoDB and look for recurring mistakes instead of letting a single report change the AI. That way, if one person reports something incorrectly, it doesn’t immediately affect everyone else’s scans. If the same type of mistake keeps getting reported, I can investigate it and use those reports to improve the AI.This seems really complex, and it was. It took me 4 hours (it says 6 on the devlog but 2 of them was working on the 4th app). Alright, ready for my fourth widget idea………. a match notifier!! Now don’t get too excited. I have more to tell. So, every FRC kid knows that there’s a website called Nexus that sends messages for when your game is going to start so you can get in queue, and it works really well. There’s also this thing I came across called statbotics, and it calculates many things like EPA, and more (I didn’t really stay on that website for too long). So, what I plan to do is combine them. Hopefully, I’m not getting myself into too much of a challenge. This will most definitely be the hardest thing I have ever done on this app. Wish me luck! P.S. I started making the fourth widget before the report button then switched to finish the report button halfway so if you see my commits in a confusing order that’s why. View it here: https://mirage54321.github.io/RoboLens/
Devlog #10 -> Part 1 of 5 Please don’t hurt me, but I have to post multiple devlogs because I worked on so many things in all this time. It’s a lot of stuff to talk about and I don’t want to write it all into one because it will be super unorganized and hard for me to find in the future. In this first devlog, I am going to talk about how I got bookmarks to work. The idea came from thinking ahead to the match notifier. If someone wants alerts for a match, they need a way to say “these are the teams I care about” without having to retype a team number every single time. So I added a bookmark system using shared_preferences (just storing a list of team numbers locally on the device/browser). You can now star a team from a few places in the app and it’ll save to your bookmarks list, which I’m planning to hook the notifier into so it can just loop through your saved teams instead of asking you every time. This one was honestly pretty painless compared to my usual chaos. The only annoying part was making sure the bookmarked list actually persisted correctly on web (learned my lesson from the MongoDB flutter-web thing, so I tested this one on both platforms before moving on lol). Turns out shared_preferences just works with local storage under the hood on web, so no weird surprises this time. Short devlog, I know, but wait till you see what devlog #11 turned into. View it here: https://mirage54321.github.io/RoboLens/
Devlog #11 -> Part 2 of 5 Now for the second devlog, I am going to talk about how I got notifications to work. This is the one that ate my week. So the goal: when a match is coming up for a team you bookmarked, get a push notification even if the app/tab isn’t open. That last part is the whole problem, because it means I can’t just pop a normal in-app alert, I actually need real browser push notifications, which meant learning a whole new stack: service workers, VAPID keys, and the Push API. Here’s roughly how it works now ->Subscribe -> user picks a team number + event key, the app asks the browser for notification permission, and if granted it registers a push subscription through the service worker using my VAPID public key. Send to backend -> that subscription (plus team number/event key) gets sent to my Express backend and stored in MongoDB. Actually sending them -> the backend uses the web-push npm package to send the push whenever it detects a match coming up for that team. Getting the Flutter side to talk to any of this was its own adventure, since none of this exists as a nice Dart package, so I had to write a JS interop layer (basically a matchPush object in plain JS that Dart calls into) and wire it up through the same conditional-export trick I used for the guided camera: one file for web, one stub file that just says “unsupported” for native, so the app doesn’t explode on phone builds while I haven’t built native push yet. Problems I ran into (there were many) ->iOS Safari straight up does not support web push at all unless the site has been added to the home screen first. So right now notifications basically only work reliably on desktop browsers and Android, and I have to eventually explain that to iOS users somehow. Permission requests have the same “must be triggered by a direct tap” rule I fought with on the guided camera, so subscribing has to happen from an actual button press, no auto-subscribing on load. Debugging this was rough because half the errors happen silently in the service worker, not in the normal Flutter console, so I was stuck adding console.logs into push.js and checking devtools like a caveman for a while.It works now though! Bookmark a team, subscribe, and you’ll get pinged. Native (phone-installed) push notifications are still a “later” problem since that needs a totally different setup (probably Firebase Cloud Messaging), so for now the stub just returns unsupported on native and I’m keeping my scope to web. Two devlogs about the 4th app itself coming up next, promise. View it here: https://mirage54321.github.io/RoboLens/ P.S. For right now there are 3 notifications that send for iOS I plan to change that though!
Devlog #12 -> Part 3 of 5 Okay, actual 4th app time: Team Stats & Match Center (internally I’ve just been calling it “match” in the code, so if you dig around the file names that’s why). I started by mocking everything out before touching any real API, just so I could get the UI feeling right first. Made an intro screen (basically pitching the three features: match alerts, team stats, matchup simulator) and a fake mockTeams list with made-up EPA numbers just so I had something to look at while building. Once the layout felt right, I started swapping the fake data for real stuff from The Blue Alliance’s API, proxied through my backend the same way I already had set up for the FRC Events API (so I’m not spamming TBA directly from a bunch of client apps and to keep my API key private). Architecture-wise, I did something different from my other three apps: instead of passing state down through a million constructor params, I made a MatchDataController (basically one class holding all the team/event/match data + loading state) and wrapped the whole feature in a MatchScope, which is just an InheritedNotifier. So anywhere in the match center I can just call MatchScope.of(context) and get the controller without threading it through every single widget. Probably overkill for how big this feature ended up being, but once I had 4 tabs and a handful of sub-screens all needing the same data, I was really glad I did it this way instead of my usual pass-everything-into-the-constructor approach. Speaking of tabs, I split it into 4: My Team -> your team’s own info/next match Stats -> a season-wide “World Rating” I calculate from aggregating TBA’s OPR data across events (this was its own whole thing, might do a separate devlog on it someday) Events -> browse every FRC event, filter by time or location, see who’s live right now Sim -> the matchup simulator I keep promising Getting match data to actually parse right from TBA’s JSON took a minute (comp levels like qm/qf/sf/f needed their own label logic, predicted_time vs actual_time needed fallback logic since actual_time barely ever gets posted until after the match is already over, that kind of thing) but nothing too crazy, just tedious model-writing. Devlog #13 is basically a straight continuation of this one, mostly bug stories and the simulator, so be ready for that. View it here: https://mirage54321.github.io/RoboLens/
Devlog #13 -> Part 4 of 5 Continuing from #12: more on the match center, mostly the stuff that actually broke on me. Biggest bug of the bunch: on the Events tab, tapping into an event was supposed to show “scheduled to attend” info and the competing teams list, but both of those sections would just spin forever, no error, nothing. I assumed it was a network timing issue at first and went down a whole rabbit hole adding timeouts and retry logic that did absolutely nothing. Turns out the actual problem was way dumber: when I pushed the EventDetailScreen with Navigator.push, that screen gets placed in the Overlay as a sibling of the tab tree, not a child of it, meaning it’s NOT under my MatchScope anymore. So the second that screen tried to call MatchScope.of(context), it threw an assertion error immediately, before initState even got the chance to call setState and load anything. The spinner wasn’t stuck because of a slow network, it was stuck because the load call never even ran. Fixed it by just re-wrapping the pushed route in its own MatchScope using the same controller instance. Felt very silly once I found it, but also weirdly satisfying to finally understand. Next was the matchup simulator and win probabilities. On the schedule screen I show a rough “Red 45% / Blue 55%” prediction for each match. My first instinct was to use each event’s own OPR for this, but that falls apart for upcoming events since OPR doesn’t exist until a team has actually played a match there. So instead I based predictions on the season-wide World Rating from the Stats tab (average points across every event a team’s played all season), which actually gives predictions even for a event that hasn’t started yet. Also went back and hooked the push notification bell (from devlog #11) directly into the match center’s top bar now that there’s finally a “your team” + “your event” to actually attach a subscription to. There’s a little pulsing glow animation on the bell the first time you land on a screen where you could enable alerts, just so people notice it’s there instead of it blending into the top bar. Took way too many attempts to get the glow animation timing feeling smooth and not epileptic-seizure-inducing, but I think I landed on something decent. Genuinely didn’t expect the 4th app to take this many devlogs but here we are. One more to wrap up some small stuff and then I think I’m caught up! View it here: https://mirage54321.github.io/RoboLens/
Devlog #14 -> Part 5 of 5 Finally! This final devlog is about the small tweaks I made in the app. I made it have a new photo Small one, just swapped out one of the app’s images for something more current since the old one was from way back in devlog #1 and didn’t really represent what the app looks like anymore. Nothing technical here, just housekeeping. It kinda works offline I say “kinda” because this isn’t a real offline mode where you can browse cached data with no internet, it’s more like the app now knows when it’s offline and fails fast instead of just hanging. Basically, I added a ConnectivityCheck helper that on web reads navigator.onLine (a free, instant, synchronous browser check for whether the device has a network interface up) so if you’re in airplane mode or your wifi is off, the AI scan screens can immediately say “can’t use this when offline” instead of sitting there for a full request timeout before failing. On native platforms there’s no real equivalent without pulling in a whole new plugin like connectivity_plus, so I just made the stub always report “online” there — an actually-offline phone still gets caught by the AI request’s own timeout/retry handling, just without the instant fail I get on web. One thing worth noting: this only checks if the device thinks it has a network connection, not whether that network actually has working internet behind it. So a wifi network that’s connected but dead will still say “online” here. That case still gets caught eventually, just the slower way through the request timeout instead of instantly. Good enough for now though, this was mostly about killing the most common case of someone trying to scan with their phone in airplane mode and just watching the app hang. I changed the load in screen Went back and reworked the loading screen from devlog #5. It’s now a plain CSS screen sitting directly in index.html instead of living inside the Flutter app itself, which means it can actually paint the instant the page loads, before Flutter has even finished downloading and booting up. That was the whole point: the old version technically only appeared once Flutter itself was far enough along to render it, so there was still a blank/white flash before it. Now there’s a little animated wordmark and spinner (the spinner’s colored arc cycles through the same colors as the logo letters) that fades out and removes itself once Flutter fires its first real frame. While I was in there I also fixed something unrelated but annoying: Flutter’s web service worker by default waits to activate a new version until every open instance of the app is fully closed, which for something people add to their home screen basically never happens naturally. So people could keep opening an old cached version of the app for a long time after I’d pushed updates. Added a bit of JS to force any newly installed service worker to skip that wait and take over immediately (reloading the page once it does), so the next time someone opens the app after I ship something, they actually get it. And that’s it, I’m all caught up! Five devlogs in one sitting was a lot, but future updates should go back to being posted as I actually build them instead of in one giant backlog dump. Current problems / what’s next: Low MongoDB storage for free account Releasing the app (onto chief delphi to get feedback)!! Making it ready to release (working on the ? and report button) Future ideas: team tracker, public chat for teams, judging/interview prep tool, callout tool, round robin generator View it here: https://mirage54321.github.io/RoboLens/
Devlog #15 -> Part 1 (still working on this one!) Finally started actually tackling the AI usage limit problem from devlog #2. Since everyone using the app shares the same free-tier Gemini key, scans would just randomly fail with no real pattern whenever enough people were hitting it at once. Started on the backend side first: instead of letting every incoming scan hit Gemini immediately, I added a little queue that only lets 2 requests be in-flight to Gemini at a time, and everything else waits its turn. Next step is getting it to actually retry instead of just failing after the wait, but that’s for the next devlog.
Devlog #16 -> Part 2, continuing from #15 Got retries working on top of the queue from last time. If Gemini comes back with a 429 (rate limited) or 503 (overloaded) instead of an actual answer, the backend now waits and tries again automatically, using exponential backoff (2s, then 4s, then 8s) instead of hammering it again right away, up to a few attempts before it actually gives up and reports failure. It also checks for a retry-after header first and uses that instead of the backoff timer if Gemini actually tells us how long to wait. Then I mirrored the same idea on the Flutter side, so if the backend’s retries still aren’t enough, the app itself will retry the whole request a couple more times before showing the user an error.
Devlog #17 -> Part 3, wrapping this one up Last piece was making the retrying actually visible instead of just quietly happening in the background. Before, if a scan was retrying you’d just stare at a spinner with no idea what was going on. Now the loading screen updates to say something like “High demand. Retrying (2/3)…” so people know the app hasn’t frozen, it’s just waiting its turn. Between the queueing, the backoff retries on both ends, and this messaging, this should turn a lot of what used to be “scan failed, try again” moments into just a few extra seconds of waiting instead. Doesn’t make the free tier limit go away entirely, but it’s a big improvement over what I had. Current problems / what’s next: Low MongoDB storage for free account Professionalizing (before putting on Chief Delphi)
Devlog #18 -> Okay, super short devlog just to explain what I am doing. Basically all my hours are spent on fixing the notifications. It is super annoying right now because I am trying to finalize my project and the notifications randomly stop working. I tried clearing out mongoDB and checking on my cron-job and those seem to be working just fine. I’m not sure what to do. I pushed the hours up (for the practice day so I can check it earlier) and redeployed with Render. I shall see tomorrow if it works. View it here: https://mirage54321.github.io/RoboLens/
Devlog #19 -> I know I just committed a bunch the last few days. I guess I realized there is only a few days left and I found how to be way more efficent in getting hours. If I just keep this open and something else on another computer and work with them kinda being different windows then I get a lot more time because the switching of windows in the same computer made me keep forgetting to come back and work on the project (and I’m guessing was cutting the time too). Anywho! The most recent changes I have made is removing the ? mark button. I think I was going for a like “about me” thing but I think it was a little redundant and kind of unneccessary to say the least. I added a report button instead (it’s just in the home page). I got this idea from lovable which was something I worked with during my internship. I highkey have been working so much on this project (you can see by all my hours) that I didn’t want to connect it to the backend. It is just a popout that takes you to an gmail link and you can click send. Maybe if I run out of ideas I can add it as a backend. Now, if I am going to be so honest. I have worked a lot on this project and I want to ship but I also want to just crank out some more hours. I’m extremely proud of this project and I need to get it out to the world so that I can get some users! My issues to work on are: Low MongoDB storage for free account Professionalizing (now just looking back over and seeing if there is anything I wanna fix before putting on chief delphi) View it here: https://mirage54321.github.io/RoboLens/
Notifications are working again! Basically, the rebuilding of Render helped fix the issue which is kind of ragebait. I’m getting a little nervous though because I wonder what happens if someone doesn’t reopen the bookmark (because that is how it resets). Would they still get the messages? Will it update automatically? Overall, it works great. I just worry there may be an error that arises (that is a risk with any project honestly). View it here: https://mirage54321.github.io/RoboLens/
Updates!!! Basically, I’ve been checking to see how many users and views I have. I have google analytics on my project to keep an eye on it. Right now I have 52 users and 163 views. Which honestly, I am pretty dang happy about. (1) I haven’t really been advertising (2) I literally thought it was gonna be like 20 views Woop woop! Okay, now on these past few days I have been working on getting as many hours as possible. I don’t have a personal computer so I am really aiming for literally any of the laptops. Now, programatically I have been working on removing the 3 burst messages for iPhone (it wouldn’t compact itself on the Apple homescreen). FYI: 90% of the time for this was spent removing the 3 burst messages for iPhone and writing Ship #2… so you better be ready for Ship 2! View it here: https://mirage54321.github.io/RoboLens/
Devlog #22 -> I was looking at the comments people left me from my ship and the first thing I noticed that I should work on is the load-in page. It is definitely kind of plain. To be honest, I used Claude to help a lot with this one. Making the spinning circle was pretty easy but I had some complex ideas I wanted to put to work and I just didn’t know how to do it. It has a huge radar that has the colors pop up and says “scounting __ teams”. Overall, I am so happy about this new design! Let me know what you guys think! I also added a folder for the photos so it looks more organized! The next thing I plan to work on “loop crashes if the camera disconnects” comment. Live app: https://mirage54321.github.io/RoboLens/
Devlog #23 -> Fixed the camera disconnect crash from the feedback. Turns out the camera plugin doesn’t actually throw an error when the hardware gets yanked mid-session, it just quietly flips an internal hasError flag and keeps going. Which is why the app was crashing somewhere random instead of failing cleanly. Nothing in my code was listening for that flag, so it just kept trying to read frames and capture photos off a dead controller. Fixed it by adding a listener that actually watches for that error state, cleans everything up, and drops the user onto a proper “Camera disconnected, try again” screen instead of freezing or throwing. Also fixed the retry logic after a failed capture so it doesn’t try to restart a stream on a controller that’s already dead. Next up: the cursor. Someone pointed that out, because every button on web just shows the default arrow. Live app: https://mirage54321.github.io/RoboLens/a
Ships:
I made an app for specifically robotics teams (although this could be used for other things too). This is still a work in progress because there is so much more I want to add. I did this project so that I could make something with an AI model and I’m really proud of myself because Flutter was really hard to work with!
What did I make? Since Ship #1, RoboLens grew from one AI scanner into four connected tools. I added a rules checker that reads the actual FRC game manual (2024–2026) alongside your robot photo so it’s grounded in real rules instead of guessing. I built out a full shared battery tracker. I added a guided camera that walks you through lighting/tilt/framing and auto-captures once the angle looks right. And the biggest addition: a Team Stats & Match Center with four tabs (My Team, Stats, Events, Sim) pulling live data from The Blue Alliance and the FRC Events API, including a season-wide “World Rating,” a matchup simulator with win probabilities, and bookmarking teams to get real push notifications before their matches. I also spent a lot of time on stuff that doesn’t show up as a “feature” but makes the app actually usable: a queue + exponential backoff + retry system so the shared free-tier Gemini key doesn’t randomly fail scans under load, a report button that feeds recurring AI mistakes back into future scans, offline detection so scans fail fast instead of hanging, and a new instant-loading splash screen. What was challenging for me? The AI usage limits were the most persistent problem. Everyone shares one free-tier Gemini key, so scans would fail with no clear pattern whenever enough people hit it at once. I fixed it in stages: first a queue limiting in-flight requests, then automatic retries with backoff (and respecting the retry-after header when Gemini gave one), then finally surfacing that retry status to the user (“High demand. Retrying (2/3)…”) instead of just showing a dead spinner. The guided camera and push notifications both turned into whole rabbit holes of browser-specific pain (iOS Safari blocking camera/notification permissions unless triggered by a direct tap, no live frame streaming on web so I had to build a custom JS-interop layer from scratch, and push not working on iOS at all unless the site’s added to the home screen firs)t. My favorite bug story: the Match Center’s Events tab would spin forever with zero errors. I burned time adding timeouts and retries that did nothing before realizing the real issue. The spinner wasn’t stuck waiting on the network, it was stuck because nothing ever tried. What am I the most proud of? Going from a single-purpose AI scanner to four genuinely useful, connected tools without the codebase turning into spaghetti. I’m also proud that scans now degrade gracefully under load instead of just failing, and that notifications work reliably even though I had zero experience with service workers or VAPID keys before this. And honestly, just sticking with it. 21 devlogs and three months of real iteration based on actual user feedback instead of giving up. What should people know so they can test your project? Live app: https://mirage54321.github.io/RoboLens/ You can log in as a guest for team 4388 to browse batteries without needing an account. Push notifications currently work reliably on desktop browsers and Android (iOS Safari requires the site to be added to your home screen as a bookmark). You can test this by logging into -4388 (Yes, a negative. I needed a number that wouldn’t have a real team). The AI scan/rules tools need a robot photo to test against; if you don’t have one handy, any well-lit photo of mechanical/electrical components will still show you how the flow works....
|
1792875207.636436
|
1793739207.636436
|
|
1172
|
Unity Motion Matching System by @NintedoAsh12 | St Unity Motion Matching System by @NintedoAsh12 | Stardance...
|
NintedoAsh12
|
0
|
140.12
|
0
|
[]
|
[{"post_id": 81951, "ts": "202 [{"post_id": 81951, "ts": "2026-10-23T04:55:45Z", "hours": 4.4681, "text": "I finished all the code comments. I know. WOW 4 HOURS OF CODE COMMENTS yeah but I was also cleaning some other parts of it up and fixing some of the indentations. anyways that’s done now only a few more things till we get to ship! but also a note to other devs like me… please comment your code while writing it because I have gotten in the habit of not doing that and as seeing here by 4 hours logged of code comments PLEASE JUST DO IT WHILE WRITING IT BECUASE THIS SUCKS"}, {"post_id": 81124, "ts": "2026-10-19T23:48:27Z", "hours": 3.2969, "text": "Not much changed I made an Itch.io for the demo. I also started adding comments to all of my code yeah its hard to remember what does what but I also got the dataset editor done or almost done. then its onto the matcher and then the trajectory maker then we are done there and then onto a tutorial of how to use it then we are done"}, {"post_id": 80294, "ts": "2026-10-17T05:11:06Z", "hours": 4.6256, "text": "OK its fixed now but first test build didn’t go so well (see video) the problem was unity wasn’t saving any of my data running in the background because it wasn’t serialized. I also organized project files plus removing unneeded scripts (I reuse code a lot and sometimes things get replaced and just left there) I also if you can’t tell from the video a dropped frame counter to show matches that where canceled because the current frame was good enough to meet the cost threshold. anyways I think now most of what I have to do it package everything up into… well a package then send it off into the world for you the hack clubbers to mess around with. EDIT: I added a demo for Windows to the github if you want to try it early"}, {"post_id": 79321, "ts": "2026-10-13T14:51:10Z", "hours": 2.2531, "text": "The demo UI has been finished and it works quite well! I have a few more things to add like a looping map so that the Character doesn’t just walk off the end of the world and die plus some more main menu stuff I think too. anyways progress has been fast so far so expect more soon!"}, {"post_id": 78971, "ts": "2026-10-12T06:56:58Z", "hours": 5.7781, "text": "LOTS OF DEBUG UI COMEING YOUR WAY! I have added lots of UI stuff to display internal values such as costs as stuff. I have also added the ability to adjust motion matching settings from in the demo so when I upload it to itch.io all of you can play with the system as much as you want and tell me how bad you broke it. to do wise its a bit more UI (some of it doesn’t work or I want it to look better) and then the data points kinda like the unity gizmo stuff I have been showing you here on star dance. anyways its like 1 AM I should have gone to bed HOURS AGO so I’mma go brush my teeth and work some more tomorrow…. my keyboard is starting to fail :-< Goodnight y’all. or good morning to the folk around the world like in Norway or something"}, {"post_id": 78190, "ts": "2026-10-09T22:29:56Z", "hours": 1.3486, "text": "I finally made a git hub repository. I also made a new unity project and moved everything into it to clean everything up for the demo I am starting to work on. I also made Bone Rotation matching but it doesn’t contribute all that match. I should be ready to ship/ Have a demo ready soon"}, {"post_id": 77746, "ts": "2026-10-08T04:44:35Z", "hours": 6.5831, "text": "OK OK IT WORKS ENOUGH OK DONT TOUCH IT I’m a fraud you guys. I couldn’t figure out the velocity thing so I…. I USED AI! I SWARE I HAVENT BEEN THIS ENTIRE TIME…. ok heres what happened I couldn’t figure it out so I had some AI going through some Motion Matching related thesis stuff and explaining it to me and then I ended up giving it a small chunk of my matcher code use to generate the cost and it pointed out my problems….. so 1. The way I was calculating local position was wrong which is funny because when I do it the other way it also breaks but then that leads into the second part. 2. I was inverting data and that was what was keeping the system working for some reason awhile back and even when I tried removing it a bit ago it broke which was really weird. anyways if you change both of them they fix each other so YAY I guess… sorry for the AI usage. it didn’t re write my code for me though I hand fixed my problem which I can proudly say all of the code is all hand typed…. (other then stuff I copy and pasted and or reused from other code I wrote… TRUST ME I NEVER WANT TO REWRITE UI SYSTEMS please unity fix the uitoolkit its bad)"}, {"post_id": 75040, "ts": "2026-09-28T23:29:30Z", "hours": 4.0911, "text": "Working on velocity matching. its kinda working now better then it was but its really weird that it slows the character down so much but its better then random snapping poses"}, {"post_id": 72963, "ts": "2026-09-24T03:42:38Z", "hours": 3.4628, "text": "HOLY CRAP IT WALKS!!! I can’t believe it. I am so FLIIPING happy ITS MOTION MATCHING! THAT IS ACTAUL REAL MOVEMENT AND NOT JUST WIGGLES!!!!! AAAAAAHHHHHH!!!!!! HECK YEAH!!!!!!! ok so in reality its still not fully working. I had to disable bone velocity matching completely to get it to work but I think I figured out why it doesn’t work. for trajectory matching I realized that the character is scaled to 1.83 instead of just 1 so that will affect the matching and I have to implement an offset (and I did it for the bone positions too but I never did it to the velocities) anyways I think I will fiddle with it till that work epeshly since STARDANCE WAS EXETENDED UNTILL OCTOBER 30TH THANK YOU HACK CLUB!!!! Video is of it working, not working and me playing with settings."}, {"post_id": 70896, "ts": "2026-09-19T23:38:42Z", "hours": 9.4997, "text": "WE HAVE HIT 100 HOURS LOGGED!!!! wow the amount of time I spent on this is CRAZY! anyways we have had little improvements on the matcher I have been trying to get it to give me a full animation but it refuses instead kinda just wiggling its arms up and down pretending to be a bird OR snapping between poses that have NOTHING to do with walking. I have spent the last few hours attempting to calibrate it to work as well as writing a better dataset debug script so then it will be easier to visualize what every frame of animation contains Data-wise so then I can attempt to manually match frames and see what the matcher ranks them vs what it normally matches so the I can maybe weight it or bias it a bit. we only have a week and bit left LET LOCK IN!!!!!!!!!!!!!!!!!!!!"}, {"post_id": 67146, "ts": "2026-09-13T06:34:17Z", "hours": 6.7892, "text": "we have done it! MOTION MATCHING FROM SCRATCH! the last week has been crazy. I have found more data from a unity demo of a long discontinued motion matching asset and I have retargeted the animation in blender and brought it into unity with proper root motion. since this was my first time using more then one animation clip with EVERYTHING I expected bugs and errors AND THAT I GOT. I had to go in and rewrite a really small chunk of how the dataset maker compiles the trajectory data. I had to make the matcher actually handle more then one clip as well as dig into a null reference error it was giving me so I had to dig into it more and learn that the dataset was still flawed and go back and do more to the editor AND THEN ONCE the data was good now the matcher scales the character to like 300% or something and I never even told it to touch scale so now I have to properly set up multi-animation unity playables since before I didn’t know that you couldn’t just set all the blend weights to one and hope for the best. now finally after all of that. it appears to match and hold onto a frame. I have a few last features to implement into it that being velocity matching so then it wont just hold a frame but understand that arms move and swing. as well as debug info for both me while testing as well as for you my dear hackclubbers so when I ship you all can see a bit into the inner workings of it. thank you for coming with me on this journey I never expected it to go this long but it feels good to have at least one person interested in what I’m working on for once and not just get shrugged off. - Ash ❤️ Video is of the matcher working photos are of the scaling issue"}, {"post_id": 63393, "ts": "2026-09-07T06:09:06Z", "hours": 5.9814, "text": "sheesh I’ve done a bit in the last week. So we have added the ability to match bones in the matcher got the matcher to handle multiple animation clips and I guess that’s it… I honestly thought I did more… on paper it doesn’t actually seem like that much.. huh. OH WELL! I also found a MASIVE collection of animation from a unreal engine demo project so I’m probably going to extract that and retarget TONS of that over the next few days because imma say it the problem with the matcher is the lack of good data at this point. Pink/Purple - Animation frame data position Red/green - predicted trajectory"}, {"post_id": 60036, "ts": "2026-09-02T04:33:58Z", "hours": 1.2344, "text": "OK OK OK IT WORKS!!!!! so we got bone positions to work. I’m done for the day. anyways I literally just had to flip my subtraction around… yes… its stupid…. anyways went from this: RootPositions[i][j] - BoneTransform.position to this: BoneTransform.position - RootPositions[i][j]. ok mic drop… I did say I would ship by the end of the month of august and clearly that didn’t happen but it will (hopefully) be this week Pink sphere is the foot pos from data set Blue is the other models foot pos not from dataset then red is root position (Also 2 devlogs in one day! I’m on fire!)"}, {"post_id": 59736, "ts": "2026-09-01T17:45:26Z", "hours": 8.6739, "text": "IM SO CLOSE!!!!!!!!! LIKE LATER TODAY (maybe can’t promise anything or the programing gods will kill me) I WILL HAVE MOTION MATCHING IN A GOOD DEMOABLE STATE FOR ME TO SHIP! I have got the bone data to work and actually spit out something useful by changing my whole approach and instead of sampling curves (which could work I just gotta deal with all the weird problems) I have created a unity scene in memory it spawns in the rig samples all the bone transform.positrons making unity do all the math and hard work before it returns me world positions of all of the bones I told it to track. the only problem I am having now is that I got to convert those world positions back into local position so that they can work anywhere (and yes I just converted them from local position to world position and this might sound counter intuitive but I need to change the parent of the local position) I remember this being easy for trajectory matching but maybe since this is WAYY more sensitive to rotation I need to try a different approach. the final stretch is approaching us dear hack clubbers. I got the rest of today then school starts tomorrow. LETS! LOCK! IN! YEAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!! btw the pink sphere is the foot potion… or what should be the foot position. Blue is the actual foot position. Red is root Position"}, {"post_id": 54275, "ts": "2026-08-25T05:45:45Z", "hours": 8.4231, "text": "Note to self… don’t freehand code… plan everything out on paper because I’m just experiencing Murphey’s law at this point :-< so…. the data that I didn’t know if it was right or not was incorrect… VERY incorrect (kinda) so that data was in local space I need it in world space but to convert it you either need to do the conversion through a transform (which requires a transform to reference) or do what I am doing (since I don’t have a easily accessible transform (unless I’m stupid and don’t know of one)) so I am going up the paths and for each object extracting their position and transforms (in local position) then adding it up until I eventually hit the root which would be in world space so now its converted (I’m doing the same for rotation too with more math) anyways my code for this entire project was never pre planned and I never normally pre plan but this is one of the times where once it works I’m going to figure out how it works (because who am I kidding I don’t really know) then I’m writing all of it down on paper and optimizing the loops and everything before jumping back into the editor to re-write the bake() function from scratch leading to MUCH BETTER READABILTY and hopefully speed because it takes a good 5 seconds from my for loops and brute force. anyways if you cant tell this is VERY BORING WORK and I really just want it to work SO BADLY because once I get everything in world position the next steps should be really easy but I shouldn’t say that because at this point if I do I might jinx myself"}, {"post_id": 46135, "ts": "2026-08-13T04:38:45Z", "hours": 3.9642, "text": "WOW JUST WOW!!! So I toured the Vicon Set-up at my local univercity and it was amazing. I loved every moment of it. they even put markers on me and captured some data (not any I can use for motion matching but still WOW THAT TECH IS COOL) In more on topic news I got the dataset maker to output bone data into the database. is it the correct data… idk but I will figure that out! (Photo of me standing forward is just a general photo with the markers. photo of me looking away from camera with hand in air is me showing off all the retroreflective markers (and EMGs) then there is a photo of the compiled dataset)"}, {"post_id": 43104, "ts": "2026-08-08T06:02:03Z", "hours": 2.9892, "text": "THERE WE GO! finally we can select what bones we want to track from a nested dropdown. now I just need to implement it into the baking logic so I can get a finished dataset out of dataset maker. perfect timing too. I have gotten a few emails back from the university and they are willing to give me a tour of the Vicon system and there may be a chance one day to capture data on it so hopefully everything works out and I can capture on the same tech that AAA game studios use which would be a dream come true and would blow my mind."}, {"post_id": 40564, "ts": "2026-08-04T06:14:32Z", "hours": 3.9083, "text": "There we go. I think I finally got it working. JEEZ UNITY NEEDS BETTER DOCUMENTATION ON THE UI TOOLKIT LIKE WOW ITS THAT BAD…. anyway I got the custom lists working now I just gotta add the actual bone selections then write in the logic to add everything to the datasets. if you look at the photo that’s roughly how it will look to use the dataset maker. not sure if I mentioned this in the last devlog but I finally messaged my local university to see if they will let me either tour or use their vicon system so I’m hoping something comes of that because that would be really cool. anyways its really late I pulled another programmer and stayed up till midnight working. see yall later."}, {"post_id": 38041, "ts": "2026-07-31T06:49:07Z", "hours": 7.1853, "text": "Pretty boring stuff happening right now. I have been working to implement bone positional and velocity tracking into the dataset builder but since I wanted to use a custom class to do it the unity UI Toolkit decided to pick a fight and be really annoying to do it in. if anyone wants to write a custom class in unity and have it show up in a list view use this: link I also am working on processing some mocap data but its not going so well right now and I am getting pretty tired with dealing with these markerless systems so we will see if my local university will let me use or even tour their 10 cam Vicon setup (cross your fingers for me) anyways I still have one mocap session to prosses so I will probably do that tomorrow since I can just let it run while I am doing other things. also I just watched these videos where this guy is building open sourced optical mocap cameras and I think I might just funnel all my hack club hours into pcb credits to build a few of them. part 1 vid: https://youtu.be/kYVqL_DqBis?si=CPKxKiLa8cxf3M1t Part 2 vid: https://youtu.be/WJ13C_1hDIA?si=hMlQ8u5ofEBf-cFS"}, {"post_id": 34122, "ts": "2026-07-24T16:47:29Z", "hours": 8.3331, "text": "#MOTION MATCHING SYSTEM V1 DEVLOG ok its been a few days and we have gotten a few things done including started work on feet and hand bone tracking (the secret sause to motion matching) I finished making the large Charuco Board so I can calibrate FreeMoCap. so its coming along… slowly but that’s ok. the hardest part of all of this is the motion capture though since my setup is really bad (I wish my city had a capture studio somewhere even if it was small)"}, {"post_id": 29976, "ts": "2026-07-17T06:02:22Z", "hours": 10.1758, "text": "sheesh its been awhile since I last posted a devlog. MOTION MATCHING SYSTEM V1 - HIP Better matching Change Log/Updates Matching changed from world space to local space started work on recording motion capture I got more consistent matching now thanks to changing how it store the data in the dataset and how it matches to it. originally the future trajectory positions where stored as world space values in the dataset and the matcher would match it to the players world space values. if you know how transform systems work in game engines or blender you might know that because of that I had to be in the EXACT same position in the world that the data was recorded (you can see this in my last devlog where I kinda wiggle around in a few areas and get flurries of matches) in which… doesn’t work very well for this because if you had to record your self walking forwards backwards and side to side for ever single value in the game world that would take you FOREVER! so I switched it to local space which is basically where you are in the world based off of something. so like instead of 0, 0, 0 being the root of the world it would be where the character is so the trajectory positions are based around the character transform… do you know what I mean? I hope so because I cant think of a better way to explain it at the moment. Right now the biggest thing holding me back is the actual motion capture data that I am feeding into this thing because the recording I downloaded… is really bad. so I have been experimenting with a free open sourced software called FreeMoCap which is a marker less triangulation based motion capture software. I will report back when I get some good results out of it (hopefully soon) TODO hand and feet position and velocity matching 6 to 8 camera motion capture data finish Charuco board for FreeMoCap camera calibration Video is of the new matching in action the red (and 1 green) points are the players future predicted trajectory the pinkish purple points are the animation fames current trajectory. they should be aligned most of the time"}, {"post_id": 19015, "ts": "2026-06-30T05:40:05Z", "hours": 2.9392, "text": "FIRST MATCH!!! WE DID IT! This past week I started working on code to compare and chose a frame to play (the actual matcher) and it works… Kind of? YES IT MACHES… Is it a good match? HECK NO!!!! BUT IT MATCHES!!!! AND THAT JUST MADE 9 MONTHS OF WORK WORTH IT AS I HYPERVENTILATE WATCHING MY MATCHER STUGGLE BADLY LAGING EVERYTHING BUT IT WORKS! now the next step is making it work… properly. the video is of it trying to match. i kinda move around a bit to get it changing data but you can tell when it finds… something because the character will lock onto a frame or start playing the animation."}, {"post_id": 15199, "ts": "2026-06-24T18:20:54Z", "hours": 10.0492, "text": "WE HAVE A WORKING DATASET! Hello hack club! Didja miss me? NO?! WELL TOO BAD!!!!! I now got my motion capture data outputting a dataset with trajectory samples and root positions which is a VERY big step forwards. so as I have mentioned in the past motion matching is literally what MOTION MATCHING is doing. Matching the motion. I have had player predicted trajectory working since before stardance even started but only recently have we started to make progress on the motion capture data that we can MATCH to the players predicted trajectory. the set up I have going on for running the motion data extraction is really cool if I do say so myself. I have a custom editor menu where I can add animation clips and tell it what times in the future I want the trajectory to sampled from then it will compile everything into a scriptable object. plus I also added cool loading bars! anyways we are getting very close to having actual motion matching made from scratch. wow. 9 months this has took so far. its been fun. well… technically not done yet so lets keep up the good work and build the matching algorithm"}, {"post_id": 8844, "ts": "2026-06-14T18:22:33Z", "hours": 7.4806, "text": "DataSet Baker V1 Alpha - HIP is in the works!!!!! Now you might be asking why it’s named HIP, and unless you are from Canada you will most likely not know who I am going to talk about, but the motion matching editor versions are going to be named after Tragically Hip album names (the first one is self titled so HIP). Anyways, in the last week I have gotten a lot done. I started work on actually figuring out the logic to get the trajectory out of the animation (and I don’t remember if I talked about this before but there were 2 ideas I had. 1 is I put the animation’s root motion through a lot more math to get a proper predicted trajectory just like how the input trajectory works. Or just sample the actual future, but then you would get problems like a 90 degree turn where the animation isn’t even anticipating it yet but the trajectory says it should be.) I actually got really confused and stuck so I emailed someone. That someone is Daniel Holden, the creator of Learned Motion Matching (and he runs the website where I learned the first input trajectory math). And WOW!!!! HE RESPONDED: Hi Asher, Sorry for the late reply, I have been travelling the last couple of days. First of all I just wanted to say that it is awesome that you are looking into advanced animation techniques like these already. (email removed for space) (i might put it in the comments if you want to read it) I hope that helps! All the best, Dan LIKE HOLY COW!!! I am talking to a LEGEND!!!! Normal motion matching works as such: you got 2 trajectories, a predicted one from the input then a true trajectory from the animation, then you load all that animation into RAM and use a matcher to play the correct frame. But what he made was use a neural network instead of the matcher and database WHICH SHRUNK RAM USAGE LIKE CRAZY (and I might have to get working on something like that sometime soon because RAM prices don’t appear to be dropping anytime soon). Anyways, in the email he said that my second idea was actually right. The idea that I thought was wrong, but he says is just a sad limitation of it and nobody has figured it out yet (yet…). So that will make life easier because I WILL BE ABLE TO FINISH THE DATASET STUFF HOPEFULLY IN A WEEK!!!!!!! And to make that dataset I started messing around with Unity’s UI Toolkit and custom editors. So now I have several custom drop downs and then you can open the MOTION MATCHING DATASET EDITOR where you can define all of your animation clips and once I write the rest, be able to press the bake button. It will process every frame and then spit out a Scriptable Object or database. Now hopefully writing the rest will be easier than writing the UI code because the UI stuff is powerful but not like normal runtime coding."}, {"post_id": 5233, "ts": "2026-06-08T22:55:23Z", "hours": 1.5761, "text": "HELLO STARDANCE!!!!!! I THINK I FIXED IT!!! Now I am not going to even mention that root motion is working this time because if you have been following along you know that the second “IT WORKS!” comes out of my mouth something breaks. So last devlog I said I thought it was working but… my character was half way in the floor. after a bit of fiddling around and some google I discovered that the problem was that I had put the root bone in the hips of the character. And apparently in unity that’s a big no no. So one hour and eight minutes of blender B.S later I Fixed it (hopefully). I ended up using a blender addon called RootMaker to create a proper root bone at the feet where unity wants it. then I used the addon to transfer all of the root motion data from the hips into the new dedicated root bone. so now hopefully unity will be happy that it has a proper root bone to work with and wont try to shove my character into the earths mantle. The crazy part of all of this is that I have been doing more of blender and fighting animation during Stardance than actually working on the motion matching so if this continues to work I can get to work on what I am supposed to be doing; working on the actual motion matching. since I am the music variety of nerd I spend most of my time coding jamming to music and I think I started measuring my programing time in albums rather then hours XD. Over the course of just this weekend I have listened front to back to: 21st Century Breakdown - Green Day American Idiot - Green Day Back in Black - AC/DC Black Holes and Revelations - Muse The Black Parade - My Chemical Romance and if you add all of the runtimes of those albums up it matches very close to the time logged in Stardance so it might work XD. anyways I am going to go stretch my legs then maybe play some of The Last of Us Part 2 (which is very appropriate since it too uses motion matching as its animation system)"}, {"post_id": 5031, "ts": "2026-06-08T18:06:54Z", "hours": 1.1372, "text": "at this point I should stop saying that I have root motion working because every time I say that I jinx it and something falls apart. so I set everything up wrong (of course) so I need to pull all of the rigs apart once more to fix some errors that I made there and how I set up the root bone (its set at the hips not at the feet). so its been a fun ride (not) plus my laptop keeps trying to update my graphics drivers and every time it crashes unity, blender, plus all of the audio drivers with it. XD. I hope after today I can start work back up on motion matching and not dealing with blender and its shenanigans."}, {"post_id": 4545, "ts": "2026-06-07T21:49:20Z", "hours": 0.8836, "text": "Ok. I may have celebrated a little bit early. but I think I finally got root motion working for real this time. the problem was a combination of blender being blender, transformation offsets, weird scaling and just the names of objects/bones being wrong. though I did get an awesome video from when I was testing and comparing two animations together and root motion sent one of them into the floor so we got a beautiful video of one guy riding the other guys head. anyways lets hope that this keeps working because I just want to get my math mathing and dataset datasetting"}, {"post_id": 4362, "ts": "2026-06-07T17:35:54Z", "hours": 1.3164, "text": "This morning I got root motion finally set up in unity. since that now works I can begin working on a data set for the motion matching. I guess I never really explained how motion matching works in any of my other devlogs so I am going to do that right now: Motion matching is a animating technique where instead of using classic state machines that go if walking play walking animation they go this is your current position, velocity, trajectory, and a lot more and try to MATCH that MOTION to a large database of motion captured animations. so what I will be working on next is building that database/dataset of animations and the code to pull the current position, velocity, trajectory out of the animations then store each frame in a dataset for the matching code to search though to find one that matches what the character is currently doing on screen. its sounds kinda easy but trust me unless you are a big math/physics person (which I am not) its quite difficult to figure out how it al l works (plus you also need to know animations and blender which SUCKSSSS!) Also the video is of root motion NOT WORKING!"}, {"post_id": 1659, "ts": "2026-06-03T19:53:43Z", "hours": 1.2667, "text": "fighting unity and blender animation systems"}, {"post_id": 335, "ts": "2026-06-01T17:11:13Z", "hours": 0.4014, "text": "I got input trajectory working. The reason it wasn’t before was that movement and the prediction where in different update types (one was in fixed update and one was in regular update) so that works really well now. Now I am setting stuff up to make a animation dataset which involve me modifying my trajectory code to make it work with PRE RECORDED animations Devlogs From flavortown: Devlog 1: Lots of research and trial and error. I have spent all this time looking for an algorithm that works to generate a predicted trajectory from an input. I think I found the right one (I haven’t tested it yet) but if not then I know that I am looking in the right place at Daniel Holden’s articles on spring dampers check it out here: https://theorangeduck.com/page/spring-roll-call#controllers Devlog 2: I got the Trajectory prediction working!!!! after all of that math, research, and pain. it works! I wish I could truly express in words how happy I am. everything is based off of the work of Daniel Holden you can find it here: https://theorangeduck.com/page/spring-roll-call#controllers Devlog 3: Fixed jittering issue by adding a lerp to desired trajectory."}]...
|
Title: Unity Motion Matching System by @NintedoAsh Title: Unity Motion Matching System by @NintedoAsh12 | Stardance
Devlogs:
I got input trajectory working. The reason it wasn’t before was that movement and the prediction where in different update types (one was in fixed update and one was in regular update) so that works really well now. Now I am setting stuff up to make a animation dataset which involve me modifying my trajectory code to make it work with PRE RECORDED animations Devlogs From flavortown: Devlog 1: Lots of research and trial and error. I have spent all this time looking for an algorithm that works to generate a predicted trajectory from an input. I think I found the right one (I haven’t tested it yet) but if not then I know that I am looking in the right place at Daniel Holden’s articles on spring dampers check it out here: https://theorangeduck.com/page/spring-roll-call#controllers Devlog 2: I got the Trajectory prediction working!!!! after all of that math, research, and pain. it works! I wish I could truly express in words how happy I am. everything is based off of the work of Daniel Holden you can find it here: https://theorangeduck.com/page/spring-roll-call#controllers Devlog 3: Fixed jittering issue by adding a lerp to desired trajectory.
fighting unity and blender animation systems
This morning I got root motion finally set up in unity. since that now works I can begin working on a data set for the motion matching. I guess I never really explained how motion matching works in any of my other devlogs so I am going to do that right now: Motion matching is a animating technique where instead of using classic state machines that go if walking play walking animation they go this is your current position, velocity, trajectory, and a lot more and try to MATCH that MOTION to a large database of motion captured animations. so what I will be working on next is building that database/dataset of animations and the code to pull the current position, velocity, trajectory out of the animations then store each frame in a dataset for the matching code to search though to find one that matches what the character is currently doing on screen. its sounds kinda easy but trust me unless you are a big math/physics person (which I am not) its quite difficult to figure out how it al l works (plus you also need to know animations and blender which SUCKSSSS!) Also the video is of root motion NOT WORKING!
Ok. I may have celebrated a little bit early. but I think I finally got root motion working for real this time. the problem was a combination of blender being blender, transformation offsets, weird scaling and just the names of objects/bones being wrong. though I did get an awesome video from when I was testing and comparing two animations together and root motion sent one of them into the floor so we got a beautiful video of one guy riding the other guys head. anyways lets hope that this keeps working because I just want to get my math mathing and dataset datasetting
at this point I should stop saying that I have root motion working because every time I say that I jinx it and something falls apart. so I set everything up wrong (of course) so I need to pull all of the rigs apart once more to fix some errors that I made there and how I set up the root bone (its set at the hips not at the feet). so its been a fun ride (not) plus my laptop keeps trying to update my graphics drivers and every time it crashes unity, blender, plus all of the audio drivers with it. XD. I hope after today I can start work back up on motion matching and not dealing with blender and its shenanigans.
HELLO STARDANCE!!!!!! I THINK I FIXED IT!!! Now I am not going to even mention that root motion is working this time because if you have been following along you know that the second “IT WORKS!” comes out of my mouth something breaks. So last devlog I said I thought it was working but… my character was half way in the floor. after a bit of fiddling around and some google I discovered that the problem was that I had put the root bone in the hips of the character. And apparently in unity that’s a big no no. So one hour and eight minutes of blender B.S later I Fixed it (hopefully). I ended up using a blender addon called RootMaker to create a proper root bone at the feet where unity wants it. then I used the addon to transfer all of the root motion data from the hips into the new dedicated root bone. so now hopefully unity will be happy that it has a proper root bone to work with and wont try to shove my character into the earths mantle. The crazy part of all of this is that I have been doing more of blender and fighting animation during Stardance than actually working on the motion matching so if this continues to work I can get to work on what I am supposed to be doing; working on the actual motion matching. since I am the music variety of nerd I spend most of my time coding jamming to music and I think I started measuring my programing time in albums rather then hours XD. Over the course of just this weekend I have listened front to back to: 21st Century Breakdown - Green Day American Idiot - Green Day Back in Black - AC/DC Black Holes and Revelations - Muse The Black Parade - My Chemical Romance and if you add all of the runtimes of those albums up it matches very close to the time logged in Stardance so it might work XD. anyways I am going to go stretch my legs then maybe play some of The Last of Us Part 2 (which is very appropriate since it too uses motion matching as its animation system)
DataSet Baker V1 Alpha - HIP is in the works!!!!! Now you might be asking why it’s named HIP, and unless you are from Canada you will most likely not know who I am going to talk about, but the motion matching editor versions are going to be named after Tragically Hip album names (the first one is self titled so HIP). Anyways, in the last week I have gotten a lot done. I started work on actually figuring out the logic to get the trajectory out of the animation (and I don’t remember if I talked about this before but there were 2 ideas I had. 1 is I put the animation’s root motion through a lot more math to get a proper predicted trajectory just like how the input trajectory works. Or just sample the actual future, but then you would get problems like a 90 degree turn where the animation isn’t even anticipating it yet but the trajectory says it should be.) I actually got really confused and stuck so I emailed someone. That someone is Daniel Holden, the creator of Learned Motion Matching (and he runs the website where I learned the first input trajectory math). And WOW!!!! HE RESPONDED: Hi Asher, Sorry for the late reply, I have been travelling the last couple of days. First of all I just wanted to say that it is awesome that you are looking into advanced animation techniques like these already. (email removed for space) (i might put it in the comments if you want to read it) I hope that helps! All the best, Dan LIKE HOLY COW!!! I am talking to a LEGEND!!!! Normal motion matching works as such: you got 2 trajectories, a predicted one from the input then a true trajectory from the animation, then you load all that animation into RAM and use a matcher to play the correct frame. But what he made was use a neural network instead of the matcher and database WHICH SHRUNK RAM USAGE LIKE CRAZY (and I might have to get working on something like that sometime soon because RAM prices don’t appear to be dropping anytime soon). Anyways, in the email he said that my second idea was actually right. The idea that I thought was wrong, but he says is just a sad limitation of it and nobody has figured it out yet (yet…). So that will make life easier because I WILL BE ABLE TO FINISH THE DATASET STUFF HOPEFULLY IN A WEEK!!!!!!! And to make that dataset I started messing around with Unity’s UI Toolkit and custom editors. So now I have several custom drop downs and then you can open the MOTION MATCHING DATASET EDITOR where you can define all of your animation clips and once I write the rest, be able to press the bake button. It will process every frame and then spit out a Scriptable Object or database. Now hopefully writing the rest will be easier than writing the UI code because the UI stuff is powerful but not like normal runtime coding.
WE HAVE A WORKING DATASET! Hello hack club! Didja miss me? NO?! WELL TOO BAD!!!!! I now got my motion capture data outputting a dataset with trajectory samples and root positions which is a VERY big step forwards. so as I have mentioned in the past motion matching is literally what MOTION MATCHING is doing. Matching the motion. I have had player predicted trajectory working since before stardance even started but only recently have we started to make progress on the motion capture data that we can MATCH to the players predicted trajectory. the set up I have going on for running the motion data extraction is really cool if I do say so myself. I have a custom editor menu where I can add animation clips and tell it what times in the future I want the trajectory to sampled from then it will compile everything into a scriptable object. plus I also added cool loading bars! anyways we are getting very close to having actual motion matching made from scratch. wow. 9 months this has took so far. its been fun. well… technically not done yet so lets keep up the good work and build the matching algorithm
FIRST MATCH!!! WE DID IT! This past week I started working on code to compare and chose a frame to play (the actual matcher) and it works… Kind of? YES IT MACHES… Is it a good match? HECK NO!!!! BUT IT MATCHES!!!! AND THAT JUST MADE 9 MONTHS OF WORK WORTH IT AS I HYPERVENTILATE WATCHING MY MATCHER STUGGLE BADLY LAGING EVERYTHING BUT IT WORKS! now the next step is making it work… properly. the video is of it trying to match. i kinda move around a bit to get it changing data but you can tell when it finds… something because the character will lock onto a frame or start playing the animation.
sheesh its been awhile since I last posted a devlog. MOTION MATCHING SYSTEM V1 - HIP Better matching Change Log/Updates Matching changed from world space to local space started work on recording motion capture I got more consistent matching now thanks to changing how it store the data in the dataset and how it matches to it. originally the future trajectory positions where stored as world space values in the dataset and the matcher would match it to the players world space values. if you know how transform systems work in game engines or blender you might know that because of that I had to be in the EXACT same position in the world that the data was recorded (you can see this in my last devlog where I kinda wiggle around in a few areas and get flurries of matches) in which… doesn’t work very well for this because if you had to record your self walking forwards backwards and side to side for ever single value in the game world that would take you FOREVER! so I switched it to local space which is basically where you are in the world based off of something. so like instead of 0, 0, 0 being the root of the world it would be where the character is so the trajectory positions are based around the character transform… do you know what I mean? I hope so because I cant think of a better way to explain it at the moment. Right now the biggest thing holding me back is the actual motion capture data that I am feeding into this thing because the recording I downloaded… is really bad. so I have been experimenting with a free open sourced software called FreeMoCap which is a marker less triangulation based motion capture software. I will report back when I get some good results out of it (hopefully soon) TODO hand and feet position and velocity matching 6 to 8 camera motion capture data finish Charuco board for FreeMoCap camera calibration Video is of the new matching in action the red (and 1 green) points are the players future predicted trajectory the pinkish purple points are the animation fames current trajectory. they should be aligned most of the time
#MOTION MATCHING SYSTEM V1 DEVLOG ok its been a few days and we have gotten a few things done including started work on feet and hand bone tracking (the secret sause to motion matching) I finished making the large Charuco Board so I can calibrate FreeMoCap. so its coming along… slowly but that’s ok. the hardest part of all of this is the motion capture though since my setup is really bad (I wish my city had a capture studio somewhere even if it was small)
Pretty boring stuff happening right now. I have been working to implement bone positional and velocity tracking into the dataset builder but since I wanted to use a custom class to do it the unity UI Toolkit decided to pick a fight and be really annoying to do it in. if anyone wants to write a custom class in unity and have it show up in a list view use this: link I also am working on processing some mocap data but its not going so well right now and I am getting pretty tired with dealing with these markerless systems so we will see if my local university will let me use or even tour their 10 cam Vicon setup (cross your fingers for me) anyways I still have one mocap session to prosses so I will probably do that tomorrow since I can just let it run while I am doing other things. also I just watched these videos where this guy is building open sourced optical mocap cameras and I think I might just funnel all my hack club hours into pcb credits to build a few of them. part 1 vid: https://youtu.be/kYVqL_DqBis?si=CPKxKiLa8cxf3M1t Part 2 vid: https://youtu.be/WJ13C_1hDIA?si=hMlQ8u5ofEBf-cFS
There we go. I think I finally got it working. JEEZ UNITY NEEDS BETTER DOCUMENTATION ON THE UI TOOLKIT LIKE WOW ITS THAT BAD…. anyway I got the custom lists working now I just gotta add the actual bone selections then write in the logic to add everything to the datasets. if you look at the photo that’s roughly how it will look to use the dataset maker. not sure if I mentioned this in the last devlog but I finally messaged my local university to see if they will let me either tour or use their vicon system so I’m hoping something comes of that because that would be really cool. anyways its really late I pulled another programmer and stayed up till midnight working. see yall later.
THERE WE GO! finally we can select what bones we want to track from a nested dropdown. now I just need to implement it into the baking logic so I can get a finished dataset out of dataset maker. perfect timing too. I have gotten a few emails back from the university and they are willing to give me a tour of the Vicon system and there may be a chance one day to capture data on it so hopefully everything works out and I can capture on the same tech that AAA game studios use which would be a dream come true and would blow my mind.
WOW JUST WOW!!! So I toured the Vicon Set-up at my local univercity and it was amazing. I loved every moment of it. they even put markers on me and captured some data (not any I can use for motion matching but still WOW THAT TECH IS COOL) In more on topic news I got the dataset maker to output bone data into the database. is it the correct data… idk but I will figure that out! (Photo of me standing forward is just a general photo with the markers. photo of me looking away from camera with hand in air is me showing off all the retroreflective markers (and EMGs) then there is a photo of the compiled dataset)
Note to self… don’t freehand code… plan everything out on paper because I’m just experiencing Murphey’s law at this point :-< so…. the data that I didn’t know if it was right or not was incorrect… VERY incorrect (kinda) so that data was in local space I need it in world space but to convert it you either need to do the conversion through a transform (which requires a transform to reference) or do what I am doing (since I don’t have a easily accessible transform (unless I’m stupid and don’t know of one)) so I am going up the paths and for each object extracting their position and transforms (in local position) then adding it up until I eventually hit the root which would be in world space so now its converted (I’m doing the same for rotation too with more math) anyways my code for this entire project was never pre planned and I never normally pre plan but this is one of the times where once it works I’m going to figure out how it works (because who am I kidding I don’t really know) then I’m writing all of it down on paper and optimizing the loops and everything before jumping back into the editor to re-write the bake() function from scratch leading to MUCH BETTER READABILTY and hopefully speed because it takes a good 5 seconds from my for loops and brute force. anyways if you cant tell this is VERY BORING WORK and I really just want it to work SO BADLY because once I get everything in world position the next steps should be really easy but I shouldn’t say that because at this point if I do I might jinx myself
IM SO CLOSE!!!!!!!!! LIKE LATER TODAY (maybe can’t promise anything or the programing gods will kill me) I WILL HAVE MOTION MATCHING IN A GOOD DEMOABLE STATE FOR ME TO SHIP! I have got the bone data to work and actually spit out something useful by changing my whole approach and instead of sampling curves (which could work I just gotta deal with all the weird problems) I have created a unity scene in memory it spawns in the rig samples all the bone transform.positrons making unity do all the math and hard work before it returns me world positions of all of the bones I told it to track. the only problem I am having now is that I got to convert those world positions back into local position so that they can work anywhere (and yes I just converted them from local position to world position and this might sound counter intuitive but I need to change the parent of the local position) I remember this being easy for trajectory matching but maybe since this is WAYY more sensitive to rotation I need to try a different approach. the final stretch is approaching us dear hack clubbers. I got the rest of today then school starts tomorrow. LETS! LOCK! IN! YEAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!! btw the pink sphere is the foot potion… or what should be the foot position. Blue is the actual foot position. Red is root Position
OK OK OK IT WORKS!!!!! so we got bone positions to work. I’m done for the day. anyways I literally just had to flip my subtraction around… yes… its stupid…. anyways went from this: RootPositions[i][j] - BoneTransform.position to this: BoneTransform.position - RootPositions[i][j]. ok mic drop… I did say I would ship by the end of the month of august and clearly that didn’t happen but it will (hopefully) be this week Pink sphere is the foot pos from data set Blue is the other models foot pos not from dataset then red is root position (Also 2 devlogs in one day! I’m on fire!)
sheesh I’ve done a bit in the last week. So we have added the ability to match bones in the matcher got the matcher to handle multiple animation clips and I guess that’s it… I honestly thought I did more… on paper it doesn’t actually seem like that much.. huh. OH WELL! I also found a MASIVE collection of animation from a unreal engine demo project so I’m probably going to extract that and retarget TONS of that over the next few days because imma say it the problem with the matcher is the lack of good data at this point. Pink/Purple - Animation frame data position Red/green - predicted trajectory
we have done it! MOTION MATCHING FROM SCRATCH! the last week has been crazy. I have found more data from a unity demo of a long discontinued motion matching asset and I have retargeted the animation in blender and brought it into unity with proper root motion. since this was my first time using more then one animation clip with EVERYTHING I expected bugs and errors AND THAT I GOT. I had to go in and rewrite a really small chunk of how the dataset maker compiles the trajectory data. I had to make the matcher actually handle more then one clip as well as dig into a null reference error it was giving me so I had to dig into it more and learn that the dataset was still flawed and go back and do more to the editor AND THEN ONCE the data was good now the matcher scales the character to like 300% or something and I never even told it to touch scale so now I have to properly set up multi-animation unity playables since before I didn’t know that you couldn’t just set all the blend weights to one and hope for the best. now finally after all of that. it appears to match and hold onto a frame. I have a few last features to implement into it that being velocity matching so then it wont just hold a frame but understand that arms move and swing. as well as debug info for both me while testing as well as for you my dear hackclubbers so when I ship you all can see a bit into the inner workings of it. thank you for coming with me on this journey I never expected it to go this long but it feels good to have at least one person interested in what I’m working on for once and not just get shrugged off. - Ash ❤️ Video is of the matcher working photos are of the scaling issue
WE HAVE HIT 100 HOURS LOGGED!!!! wow the amount of time I spent on this is CRAZY! anyways we have had little improvements on the matcher I have been trying to get it to give me a full animation but it refuses instead kinda just wiggling its arms up and down pretending to be a bird OR snapping between poses that have NOTHING to do with walking. I have spent the last few hours attempting to calibrate it to work as well as writing a better dataset debug script so then it will be easier to visualize what every frame of animation contains Data-wise so then I can attempt to manually match frames and see what the matcher ranks them vs what it normally matches so the I can maybe weight it or bias it a bit. we only have a week and bit left LET LOCK IN!!!!!!!!!!!!!!!!!!!!
HOLY CRAP IT WALKS!!! I can’t believe it. I am so FLIIPING happy ITS MOTION MATCHING! THAT IS ACTAUL REAL MOVEMENT AND NOT JUST WIGGLES!!!!! AAAAAAHHHHHH!!!!!! HECK YEAH!!!!!!! ok so in reality its still not fully working. I had to disable bone velocity matching completely to get it to work but I think I figured out why it doesn’t work. for trajectory matching I realized that the character is scaled to 1.83 instead of just 1 so that will affect the matching and I have to implement an offset (and I did it for the bone positions too but I never did it to the velocities) anyways I think I will fiddle with it till that work epeshly since STARDANCE WAS EXETENDED UNTILL OCTOBER 30TH THANK YOU HACK CLUB!!!! Video is of it working, not working and me playing with settings.
Working on velocity matching. its kinda working now better then it was but its really weird that it slows the character down so much but its better then random snapping poses
OK OK IT WORKS ENOUGH OK DONT TOUCH IT I’m a fraud you guys. I couldn’t figure out the velocity thing so I…. I USED AI! I SWARE I HAVENT BEEN THIS ENTIRE TIME…. ok heres what happened I couldn’t figure it out so I had some AI going through some Motion Matching related thesis stuff and explaining it to me and then I ended up giving it a small chunk of my matcher code use to generate the cost and it pointed out my problems….. so 1. The way I was calculating local position was wrong which is funny because when I do it the other way it also breaks but then that leads into the second part. 2. I was inverting data and that was what was keeping the system working for some reason awhile back and even when I tried removing it a bit ago it broke which was really weird. anyways if you change both of them they fix each other so YAY I guess… sorry for the AI usage. it didn’t re write my code for me though I hand fixed my problem which I can proudly say all of the code is all hand typed…. (other then stuff I copy and pasted and or reused from other code I wrote… TRUST ME I NEVER WANT TO REWRITE UI SYSTEMS please unity fix the uitoolkit its bad)
I finally made a git hub repository. I also made a new unity project and moved everything into it to clean everything up for the demo I am starting to work on. I also made Bone Rotation matching but it doesn’t contribute all that match. I should be ready to ship/ Have a demo ready soon
LOTS OF DEBUG UI COMEING YOUR WAY! I have added lots of UI stuff to display internal values such as costs as stuff. I have also added the ability to adjust motion matching settings from in the demo so when I upload it to itch.io all of you can play with the system as much as you want and tell me how bad you broke it. to do wise its a bit more UI (some of it doesn’t work or I want it to look better) and then the data points kinda like the unity gizmo stuff I have been showing you here on star dance. anyways its like 1 AM I should have gone to bed HOURS AGO so I’mma go brush my teeth and work some more tomorrow…. my keyboard is starting to fail :-< Goodnight y’all. or good morning to the folk around the world like in Norway or something
The demo UI has been finished and it works quite well! I have a few more things to add like a looping map so that the Character doesn’t just walk off the end of the world and die plus some more main menu stuff I think too. anyways progress has been fast so far so expect more soon!
OK its fixed now but first test build didn’t go so well (see video) the problem was unity wasn’t saving any of my data running in the background because it wasn’t serialized. I also organized project files plus removing unneeded scripts (I reuse code a lot and sometimes things get replaced and just left there) I also if you can’t tell from the video a dropped frame counter to show matches that where canceled because the current frame was good enough to meet the cost threshold. anyways I think now most of what I have to do it package everything up into… well a package then send it off into the world for you the hack clubbers to mess around with. EDIT: I added a demo for Windows to the github if you want to try it early
Not much changed I made an Itch.io for the demo. I also started adding comments to all of my code yeah its hard to remember what does what but I also got the dataset editor done or almost done. then its onto the matcher and then the trajectory maker then we are done there and then onto a tutorial of how to use it then we are done
I finished all the code comments. I know. WOW 4 HOURS OF CODE COMMENTS yeah but I was also cleaning some other parts of it up and fixing some of the indentations. anyways that’s done now only a few more things till we get to ship! but also a note to other devs like me… please comment your code while writing it because I have gotten in the habit of not doing that and as seeing here by 4 hours logged of code comments PLEASE JUST DO IT WHILE WRITING IT BECUASE THIS SUCKS...
|
1792760004.6095197
|
1793364804.6095197
|
|
7968
|
Chess Now! by @AngelCMHxD | Stardance
|
AngelCMHxD
|
1
|
140.11
|
1509
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-30T15:00:21Z", "hours": 137.0, "multiplier": 18.82, "payout": 1509, "blessing": "neutral", "text": "This is Chess Now! A real-time chess API with challenges handling, matches, friends, and much more! The idea is for anyone to be able to make a custom client, bot or integration with the platform, thus it’s as open as it can possibly be while trying to also stay secure. One of the biggest parts of the proyect was doing that many clients, especially the TUI client. While I learned Vue doing the TUI client, I found it’s behaviour kinda… unintuitive in some way I can’t really explain. Though at the end I felt that Vue is better than React by a mile (now I only have to try out Svelte) I am proud of how well structured the API is, and while I’m sure it can be improved, the bases feel pretty solid. I’m also proud of how much I learned doing this. I mean, I tried a lot of things I’ve been meaning to try for some time already: Vue, Better Auth, Drizzle ORM, actually deploying a Next.js app, React mail + Resend, Elysia, and Fumadocs. And probably something else I already forgot about hehe Would I do something different if I started right now? Probably, but mostly just to try out even more things, which is the main reason why I do most of my projects. If you want to try out the project, you should probably just check the instance hosted at https://chessnow.angelcmh.com/ , create an account and play against a bot. You should also check out the docs, or the npm package over at https://www.npmjs.com/package/@chess-now/api if you are interested. Thanks for reading till the end, have a great day! ;P", "repo": "https://github.com/AngelCMHxD/chess-now", "demo": "https://chessnow.angelcmh.com/"}]...
|
[{"post_id": 62578, "ts": "202 [{"post_id": 62578, "ts": "2026-09-06T01:20:34Z", "hours": 3.1125, "text": "aaaa, so… long time no see! also, super star!!! So, I’ve began doing some things that I’ve meant to do before, but completely forgot as I got quite busy… lol I fixed an error which made the TUI not work on Linux, it works now! It was an issue as I was building on NixOS, and the linker path was on my /nix/store folder instead of the usual /lib one. that means it also broke for me after an update lol You can now configure challenges! This needed to be implemented on all clients, hence why it took a little while lol Select whether you want to start with white, black or random. The opponent will be able to see which color you selected before accepting the challenge though! :P Also, meet unrankeds! You can now also mark a match as unranked so it doesn’t affect your ELO ratings at all . Take into account that there is decay though! so if you don’t play ranked for a while, your next match ELO diffs might be a little bit different Fun fact: The starting color option has been available on the API for a while already, even documented. so, if you did API calls directly, you could have selected a starting color and the opponent would not have been able to notice! as none of the clients showed it. except for the Discord bot… I think… or if you requested the match through the API too ;D"}, {"post_id": 37641, "ts": "2026-07-30T14:59:49Z", "hours": 0.8269, "text": "Hewo! This devlog was unexpected. I prepared a small video/trailer so I had something to upload when shipping the project, and when I tried to upload it I realized that you can only upload images when shipping a project :/ So here is that video as it won’t go to waste. I tried my best, hope my voice doesn’t sound awkward, I’m not a native speaker Also, check out the shipped project! As I probably shipped it right after this devlog"}, {"post_id": 37305, "ts": "2026-07-29T22:23:23Z", "hours": 3.36, "text": "Well, I set up the domain + reverse proxy and all kind of problems arose. I changed the package so you only need to instantiate the class without any arguments to use the default server over at https://chessnow.angelcmh.com though you can still pass an optional baseUrl in case you selfhost your own instance at first nothing worked, but then i noticed that I had a port conflict on my VPS with two things trying to use the same port lol i also tried to improve SEO on the main page as much as I could, though im not an expert on that. i also added an official bots section so you can challenge some bots without having to look at any docs to find them shipping in some minutes!"}, {"post_id": 36858, "ts": "2026-07-29T05:39:21Z", "hours": 6.6392, "text": "Hewo! Last devlog till ship here (i think) I didn’t think I’d add anything else, but you can now forfeit matches or ask the opponent for a draw! They just seemed like something that should exist on the shipped project… Each player can request only one draw per match, so you think before you do it. why did i do it like that? well, asking for a draw pauses the whole match, an neither player can do any moves until the draw request is answered. in order to prevent one of the users spamming draws, i simply limited to only one per match. also, ending the match in a draw doesn’t mean that your ELO isn’t affected, it is affected. depending on the elo of your opponent, you’ll lose/earn elo on a draw, just as you’d do on a stalemate. I also added a piece promotion selector. i forgot i made it so it always chose the queen by default, but in some matches that might not be wanted, so now you get a popup to select the piece you want to promote to well, i don’t really know if i’m missing any other things, as that was all that was i had on my TODO list, so i guess i’ll start setting up the prod environment below is a video showing the forfeit and draw flows, along with the promotion popup. don’t worry about the first match being a valid checkmate but the match continued being active, i already fixed that bug but it didn’t apply to already affected matches :P i also sped up (is that the correct way to say it?) and cutted out some parts of the video to prevent it from being 6 minutes of me playing the match lol"}, {"post_id": 34658, "ts": "2026-07-25T15:44:56Z", "hours": 9.5286, "text": "Well, that took way longer than expected. The docs are way more polished now! All endpoints have example responses so you know exactly what each one will return, along with a small description. HTTP endpoints that trigger a WebSocket event for any user (like friend requests, challenges, match moves, etc), mention it on their descriptions. I also added some headers to the PGN strings, as they were previously filled with “?“s. This mostly took this long due to a LOT of issues with the account deletion process, but it works perfectly now. When you delete your account, your user is replaced in all the matches you’ve played to @deleted_user . This is to keep the match data available even after any user deletes it. After that, your account is deleted from the DB. Due to how the DB is configured with cascade deletes, that will delete all other rows that reference the user (friendships, friend requests, pending challenges, etc.) except for matches, as they no longer reference the user that is being deleted. I’m am quite close to the ship, which I’m kinda nervous about. I want the project to be in the best state and as polished as possible, without any bugs (well, any known bugs lol). Which is mostly the reason this project as a whole has taken soo long :/ Below is a small video showing the docs with the example data. At the end is the delete account flow, which have lot’s of confirmations as it currently doesn’t send an email. I’m thinking it probably should send one lol See you in the next (and probably last) devlog! (I fixed my OBS settings, the video should look a bit better than the previous ones :P)"}, {"post_id": 33878, "ts": "2026-07-24T04:38:40Z", "hours": 5.6958, "text": "ELO system! let’s go!! At the end, I did add an ELO system. Well, it’s not really ELO, it’s Glicko . I used the glicko2-lite library, which is stateless unlike other glicko implementations I found. I wanted a stateless one because I’m saving the data on the DB anyways, so making it stateful would only make it use more resources (primarly RAM). You start with a rating of 1500. After every match your rating will go up/down depending on whether you win or lose. How much you win or lose depends on how many matches you have played (the first one are worth a bit more to get you to the optimal points), and depending on the rating of your oponent. If you win against someone with a bigger rating than yours, you’ll gain way more points than if you win agains someone around your rating or less. I also added a settings page so you can change your name and username, along with a page to change your password. Below is a small video showing how the ELO Glicko system works: What remains is just to also add the name/username change for bots and improve the docs. I also made a Stockfish bot which you can try to play against. (Keyword: try , because it’s probably almost impossible)"}, {"post_id": 33281, "ts": "2026-07-23T02:11:49Z", "hours": 2.855, "text": "User page done! You can now see all of the matches and friends of other people, along with a small list of stats. I’m thinking about implementing the ELO system. While I previously said that I wouldn’t be able to moderate people artificially inflating it (by selfbotting), having it without a leaderboard wouldn’t really make it that enticing to abuse. And personally, if there isn’t a leaderboard, I don’t think moderating it would be that important, what would the user gain more than having a bigger number on their profile? Still thinking about it though I’m not sure about adding custom profile pictures or really any other user generated content. It would be nice to have, but it also involves moderation in order to prevent anything inappropriate from being uploaded (i mean, we all know how the internet works :/) Below is a small video showing the user page, along with the bot auto accepting any new friend requests :P"}, {"post_id": 32786, "ts": "2026-07-22T05:22:14Z", "hours": 6.9678, "text": "Well, the web client is done!! I used react-chessboard and it’s a pretty good library. I didn’t add click-to-move pieces as it makes the logic a LOT more complex, so I didn’t want to do it for now I also used the API package from before, so we can use the websocket connection and listen for any changes. I also added it onto the matches page so any updates on the boards are reflected in real-time (which would probably look amazing if you have multiple automated matches running lol), and any new matches are added to the list without needing to refresh the page. I also want to add it onto the friends page, so it also updates in real-time I had to change the icons on the discord bot as I realized they were Chess.com’s icons, and they aren’t free to use, so I removed them and replaced them with a pack named Caliente , which look amazing. It’s the same one I use on the web client I think I should add a popup once the match is over as the current result feels quite plain. I also gotta add another page where you can spectate the match of other people, as the current one has too many logic already I prefer to duplicate it and remove the need of handling input and what not. I also haven’t added a profiles page yet, so that’s still on the TODO list hahah Below is a small video of me playing a match against a bot. Two disclaimers: I used AI to fix some issues I had with the CSS on the page, though it didn’t change anything other than fix some class names, and the whole logic was made by me. I played horribly against the bot, as the difficulty is set quite low lol Additional disclaimer: Ignore the -55s duration on one of the matches, it was an old bug but I’ve gotten lazy and haven’t fixed the match on the DB yet .-."}, {"post_id": 32426, "ts": "2026-07-21T16:34:43Z", "hours": 0.685, "text": "The TUI is 100% done! (I think…) There is no longer any mock data and it works with the actual API. You can send and receive challenges and friend requests, and you can see/play your running matches. I think that, for the account management, I’ll remove email signups and only allow social OAuth2 (currently Google and Discord). As with email/password signups I need to handle email verification and password reset, and while Resend (what I use right now) is REALLY good and it’s free tier is great (3000 mails a month, 100 daily), if someone tries to spam the endpoints, it’s gonna eat up the limit. Though I might just put a rate limiter in place, and with Cloudflare Turnstile I already combat at least some botting, still thinking about it… I’ll probably start with the web client for now, which might be the last thing to do Below is a little video showing the TUI in action, while playing a match: (I took quite a bit of time thinking about the move I should make till I remembered I was just recording a test video lol)"}, {"post_id": 32210, "ts": "2026-07-21T07:10:56Z", "hours": 0.5875, "text": "And… This devlog is just to show the web dashboard, which I have forgotten to do a devlog for it all this time, which is why the logged time is so low lol I used the Next.js framework to build the web dashboard (well, the whole dashboard + welcome page and just the whole web thing). I also used the shadcn/ui components library, as I’m not that good making frontend stuff, so that helped a lot. The dashboard layout is actually a template you can find on the shadcn site, I love the huge amount of things they have I didn’t know what else to put as a welcome to the dashboard, so I left a little welcome message as seen at the beginning of the video And I also forgot to show (mostly because there wasn’t any) the notifications button, where you can find any incoming challenges and friend requests. The whole bot creation process works, at the end it gives you a token that you can use as if it were a user auth token, but you have all the scopes by default, so you can do anything you want with the account What remains to do on this web part is to be able to see the profile of other users, along with their recent matches. And also a web client so you can play without downloading the TUI client or needing to use the discord bot"}, {"post_id": 32193, "ts": "2026-07-21T06:11:10Z", "hours": 5.3728, "text": "Edit: I realized right after posting this devlog: 100 hours! This has taken me more time than what I expected and gone quite big at this point hahah Welp, the bots are done, and now I’ve tested the Discord integration. I made the bots using the js-chess-engine package. Why that instead of something like stockfish? it simply was way easier to do as it’s a full js/ts engine lol Though, that doesn’t mean that the stockfish engine wouldn’t be posible to integrate! as anyone can create bots, that also means that anyone could create a stockfish bot if they wanted to. In case you don’t know what Stockfish is: It’s a really powerful and popular chess engine written in C++. Also, while writing this devlog, I found this package , which could be used to make a stockfish bot really easily. Though the ELO of the stockfish bot is really high, so I don’t really regret choosing js-chess-engine as a simpler engine means people can at least win against it lol Here is a small video showing a match running on the discord bot. There are some small coordinates on the image so writing the SAN/LAN notation is easier, though it’s quire hard to see them on the video due to compression. While it has support for everything (friend requests, send challenges, accept challenges, etc), I kinda forgot to record the rest :P"}, {"post_id": 31519, "ts": "2026-07-20T00:11:39Z", "hours": 9.0231, "text": "Well, making the TUI has gone quite well. While I initially thought that Vue seemed weird for doing TUIs, it’s actually not that bad. No wonder Ink is so popular. (Though I’m liking Vue more than I like React, and Ink felt kinda clunky at times when I first tried it) If you want to do TUIs with TypeScript/JavaScript, I’d recommend you give Vue TermUI a try. It also supports the Vue Router, so it’s easy to make a lot of pages and then navigate through them. The data show in the video is just mock data. So it still doesn’t use the actual API, though progress have gone quite well without many hiccups. The send friend request button, and the accept/reject challenge buttons do use the actual API, but they just throw an error because it tries to accept/reject a challenge that doesn’t actually exist, as it’s just mock data. The app doesn’t crash on error though, it displays the error message right below the button, that way the user can see what went wrong without having the whole app crash or any other unexpected behavior. What remains now is making some bots, that way I can make the whole “Playing a game” page, as having mock data for the WHOLE game state is not very… easy? I mean, I’ll have to do some bots anyway, so why not do them now instead of creating some weird mock functions hahah I also think that the icons on the authorization page feel weird. I dont know if maybe they are too big or if I should just change them to other ones. I also have to change the card after approval or denial instead of just showing the toast at the bottom, as it doesnt give feedback to the user Below is a small video of the TUI in action: (Disclaimer: Some AI was used, primarily to create the mock data so I could focus on the TUI itself)"}, {"post_id": 30506, "ts": "2026-07-18T04:16:32Z", "hours": 8.6408, "text": "Welp, designing how to do the TUI was kinda… complex. I mostly know JS/TS, so I wanted to use that. And that made everything way more complex, as there aren’t so many options as you might have with something like how good Bubble Tea is on Go. So these were the options I considered: Ink : Which didn’t have mouse support and uses React, which I’ve felt kinda clunky while doing the webpage, so I wanted try something else. Rezi : Which, at first, was AMAZING. But it had some bugs where focus didn’t work at all and I couldn’t interact with the TUI, or just started getting weird. OpenTUI : tbf, I didn’t test it out that much, couldn’t really understand it’s TS bindings So what I ended up going with? Something not listed above: I ended up going with Vue TermUI ( for now ). Why? Well, I’ve wanted to try out Vue for some time now, and it uses OpenTUI under the hood, so it’s backend is probably pretty stable, or so I think, i don’t really know. It does handles mouse input and focus management, making it quite easy to use. Will I stay with Vue TermUI? I don’t really know yet. I’m just beginning to try it out, and I’m curious to see how it ends up. Especially because Vue for TUI sounds pretty weird lol I actually really liked Rezi and you should check it out, as the issues I had were probably because I was doing something wrong hahah"}, {"post_id": 24535, "ts": "2026-07-08T04:57:03Z", "hours": 62.6878, "text": "Welp, I’ve been working for quite a while and this is quite a long devlog. If this seems interesting to you, leave a comment with suggestions! Maybe I could do some of them depending on their difficulty I now have a pretty good API structure. It has normal HTTP endpoints and also a subscription system using WebSockets so you can get event-based messages, all of it working already. I also did a JS/TS package so it’s easier to implement it on your proyects. (Still not published to npm) I currently have the following systems working: Account, Friends, Challenges, Matches, Bot management and Device auth (the thing where the app can show you an 8 character code to login). I also did a scopes system, that way you can know exactly what data the app will have access to and what actions it’d be able to do on your behalf I made the backend using Elysia , while the whole storage is a PostgreSQL database that I interface with using Drizzle . The doc pages were done using Fumadocs , I love the way they look :D A secondary DB, using Redis (or Redis-compatible DB) is also optional, quite useful as some thing like board movements might be done by players quite fast on low timers (like 1 min) and should be replied to as fast as possible to prevent the DB write speeds and reply time from counting against a player’s timer or affecting the match playability, though I still haven’t implemented timers lol If the secondary Redis DB isn’t setup, then that data will be stored on RAM in order to keep it fast. Things like match status is kept there until the match ends, that means if the API server restarts, the matches that are currently being played are restarted too. I thought this isn’t as bad of a tradeoff in order to have a fast API reply, especially because you can solve it by setting up the Redis DB, and then you can restart the API server without worry, as the data is stored on the Redis server. While the whole API is done, the account dashboard still requires some work to do, and I’m planning to do some integrations to make it easy to test, like a Discord bot (which is already done), a TUI, or maybe a web interface, though frontend interactivity isn’t something I’m really good at, and still haven’t gotten used to doing things “the React way” :P I also added some bot management endpoints. That way someone can create a bot account under their user and be able to create any “bot opponent” to play against, something that I also want to do so anyone trying out the API or implementations can test it without requiring another available opponent Don’t know if I should make an ELO/Leaderboard system, as those could be easily cheated and can’t really moderate them, and doing skill based match making wouldn’t work with a small user base."}, {"post_id": 7750, "ts": "2026-06-12T22:58:59Z", "hours": 14.0508, "text": "This is Chess Now! An open-source (soon!) API to control chess games. The idea is for anyone to be able to create and integrate their apps and be able to control the games from there. This also means that you could be playing on App1 while your opponent can be playing on App2, as the server-side is shared between them. I’ve added the whole auth flow and database integration. Better Auth really helped a lot in this regard, the docs were awesome. I used some templates for the hero and login/signup flow as I don’t have almost any experience with frontend development (and a side-goal for me is to not use AI for codegen while making this project), though I’ve been learning a LOT about frontend doing this. I’ll begin planning the whole API structure, I still don’t know where to begin hahah"}]...
|
Title: Chess Now! by @AngelCMHxD | Stardance
Devl Title: Chess Now! by @AngelCMHxD | Stardance
Devlogs:
This is Chess Now! An open-source (soon!) API to control chess games. The idea is for anyone to be able to create and integrate their apps and be able to control the games from there. This also means that you could be playing on App1 while your opponent can be playing on App2, as the server-side is shared between them. I’ve added the whole auth flow and database integration. Better Auth really helped a lot in this regard, the docs were awesome. I used some templates for the hero and login/signup flow as I don’t have almost any experience with frontend development (and a side-goal for me is to not use AI for codegen while making this project), though I’ve been learning a LOT about frontend doing this. I’ll begin planning the whole API structure, I still don’t know where to begin hahah
Welp, I’ve been working for quite a while and this is quite a long devlog. If this seems interesting to you, leave a comment with suggestions! Maybe I could do some of them depending on their difficulty I now have a pretty good API structure. It has normal HTTP endpoints and also a subscription system using WebSockets so you can get event-based messages, all of it working already. I also did a JS/TS package so it’s easier to implement it on your proyects. (Still not published to npm) I currently have the following systems working: Account, Friends, Challenges, Matches, Bot management and Device auth (the thing where the app can show you an 8 character code to login). I also did a scopes system, that way you can know exactly what data the app will have access to and what actions it’d be able to do on your behalf I made the backend using Elysia , while the whole storage is a PostgreSQL database that I interface with using Drizzle . The doc pages were done using Fumadocs , I love the way they look :D A secondary DB, using Redis (or Redis-compatible DB) is also optional, quite useful as some thing like board movements might be done by players quite fast on low timers (like 1 min) and should be replied to as fast as possible to prevent the DB write speeds and reply time from counting against a player’s timer or affecting the match playability, though I still haven’t implemented timers lol If the secondary Redis DB isn’t setup, then that data will be stored on RAM in order to keep it fast. Things like match status is kept there until the match ends, that means if the API server restarts, the matches that are currently being played are restarted too. I thought this isn’t as bad of a tradeoff in order to have a fast API reply, especially because you can solve it by setting up the Redis DB, and then you can restart the API server without worry, as the data is stored on the Redis server. While the whole API is done, the account dashboard still requires some work to do, and I’m planning to do some integrations to make it easy to test, like a Discord bot (which is already done), a TUI, or maybe a web interface, though frontend interactivity isn’t something I’m really good at, and still haven’t gotten used to doing things “the React way” :P I also added some bot management endpoints. That way someone can create a bot account under their user and be able to create any “bot opponent” to play against, something that I also want to do so anyone trying out the API or implementations can test it without requiring another available opponent Don’t know if I should make an ELO/Leaderboard system, as those could be easily cheated and can’t really moderate them, and doing skill based match making wouldn’t work with a small user base.
Welp, designing how to do the TUI was kinda… complex. I mostly know JS/TS, so I wanted to use that. And that made everything way more complex, as there aren’t so many options as you might have with something like how good Bubble Tea is on Go. So these were the options I considered: Ink : Which didn’t have mouse support and uses React, which I’ve felt kinda clunky while doing the webpage, so I wanted try something else. Rezi : Which, at first, was AMAZING. But it had some bugs where focus didn’t work at all and I couldn’t interact with the TUI, or just started getting weird. OpenTUI : tbf, I didn’t test it out that much, couldn’t really understand it’s TS bindings So what I ended up going with? Something not listed above: I ended up going with Vue TermUI ( for now ). Why? Well, I’ve wanted to try out Vue for some time now, and it uses OpenTUI under the hood, so it’s backend is probably pretty stable, or so I think, i don’t really know. It does handles mouse input and focus management, making it quite easy to use. Will I stay with Vue TermUI? I don’t really know yet. I’m just beginning to try it out, and I’m curious to see how it ends up. Especially because Vue for TUI sounds pretty weird lol I actually really liked Rezi and you should check it out, as the issues I had were probably because I was doing something wrong hahah
Well, making the TUI has gone quite well. While I initially thought that Vue seemed weird for doing TUIs, it’s actually not that bad. No wonder Ink is so popular. (Though I’m liking Vue more than I like React, and Ink felt kinda clunky at times when I first tried it) If you want to do TUIs with TypeScript/JavaScript, I’d recommend you give Vue TermUI a try. It also supports the Vue Router, so it’s easy to make a lot of pages and then navigate through them. The data show in the video is just mock data. So it still doesn’t use the actual API, though progress have gone quite well without many hiccups. The send friend request button, and the accept/reject challenge buttons do use the actual API, but they just throw an error because it tries to accept/reject a challenge that doesn’t actually exist, as it’s just mock data. The app doesn’t crash on error though, it displays the error message right below the button, that way the user can see what went wrong without having the whole app crash or any other unexpected behavior. What remains now is making some bots, that way I can make the whole “Playing a game” page, as having mock data for the WHOLE game state is not very… easy? I mean, I’ll have to do some bots anyway, so why not do them now instead of creating some weird mock functions hahah I also think that the icons on the authorization page feel weird. I dont know if maybe they are too big or if I should just change them to other ones. I also have to change the card after approval or denial instead of just showing the toast at the bottom, as it doesnt give feedback to the user Below is a small video of the TUI in action: (Disclaimer: Some AI was used, primarily to create the mock data so I could focus on the TUI itself)
Edit: I realized right after posting this devlog: 100 hours! This has taken me more time than what I expected and gone quite big at this point hahah Welp, the bots are done, and now I’ve tested the Discord integration. I made the bots using the js-chess-engine package. Why that instead of something like stockfish? it simply was way easier to do as it’s a full js/ts engine lol Though, that doesn’t mean that the stockfish engine wouldn’t be posible to integrate! as anyone can create bots, that also means that anyone could create a stockfish bot if they wanted to. In case you don’t know what Stockfish is: It’s a really powerful and popular chess engine written in C++. Also, while writing this devlog, I found this package , which could be used to make a stockfish bot really easily. Though the ELO of the stockfish bot is really high, so I don’t really regret choosing js-chess-engine as a simpler engine means people can at least win against it lol Here is a small video showing a match running on the discord bot. There are some small coordinates on the image so writing the SAN/LAN notation is easier, though it’s quire hard to see them on the video due to compression. While it has support for everything (friend requests, send challenges, accept challenges, etc), I kinda forgot to record the rest :P
And… This devlog is just to show the web dashboard, which I have forgotten to do a devlog for it all this time, which is why the logged time is so low lol I used the Next.js framework to build the web dashboard (well, the whole dashboard + welcome page and just the whole web thing). I also used the shadcn/ui components library, as I’m not that good making frontend stuff, so that helped a lot. The dashboard layout is actually a template you can find on the shadcn site, I love the huge amount of things they have I didn’t know what else to put as a welcome to the dashboard, so I left a little welcome message as seen at the beginning of the video And I also forgot to show (mostly because there wasn’t any) the notifications button, where you can find any incoming challenges and friend requests. The whole bot creation process works, at the end it gives you a token that you can use as if it were a user auth token, but you have all the scopes by default, so you can do anything you want with the account What remains to do on this web part is to be able to see the profile of other users, along with their recent matches. And also a web client so you can play without downloading the TUI client or needing to use the discord bot
The TUI is 100% done! (I think…) There is no longer any mock data and it works with the actual API. You can send and receive challenges and friend requests, and you can see/play your running matches. I think that, for the account management, I’ll remove email signups and only allow social OAuth2 (currently Google and Discord). As with email/password signups I need to handle email verification and password reset, and while Resend (what I use right now) is REALLY good and it’s free tier is great (3000 mails a month, 100 daily), if someone tries to spam the endpoints, it’s gonna eat up the limit. Though I might just put a rate limiter in place, and with Cloudflare Turnstile I already combat at least some botting, still thinking about it… I’ll probably start with the web client for now, which might be the last thing to do Below is a little video showing the TUI in action, while playing a match: (I took quite a bit of time thinking about the move I should make till I remembered I was just recording a test video lol)
Well, the web client is done!! I used react-chessboard and it’s a pretty good library. I didn’t add click-to-move pieces as it makes the logic a LOT more complex, so I didn’t want to do it for now I also used the API package from before, so we can use the websocket connection and listen for any changes. I also added it onto the matches page so any updates on the boards are reflected in real-time (which would probably look amazing if you have multiple automated matches running lol), and any new matches are added to the list without needing to refresh the page. I also want to add it onto the friends page, so it also updates in real-time I had to change the icons on the discord bot as I realized they were Chess.com’s icons, and they aren’t free to use, so I removed them and replaced them with a pack named Caliente , which look amazing. It’s the same one I use on the web client I think I should add a popup once the match is over as the current result feels quite plain. I also gotta add another page where you can spectate the match of other people, as the current one has too many logic already I prefer to duplicate it and remove the need of handling input and what not. I also haven’t added a profiles page yet, so that’s still on the TODO list hahah Below is a small video of me playing a match against a bot. Two disclaimers: I used AI to fix some issues I had with the CSS on the page, though it didn’t change anything other than fix some class names, and the whole logic was made by me. I played horribly against the bot, as the difficulty is set quite low lol Additional disclaimer: Ignore the -55s duration on one of the matches, it was an old bug but I’ve gotten lazy and haven’t fixed the match on the DB yet .-.
User page done! You can now see all of the matches and friends of other people, along with a small list of stats. I’m thinking about implementing the ELO system. While I previously said that I wouldn’t be able to moderate people artificially inflating it (by selfbotting), having it without a leaderboard wouldn’t really make it that enticing to abuse. And personally, if there isn’t a leaderboard, I don’t think moderating it would be that important, what would the user gain more than having a bigger number on their profile? Still thinking about it though I’m not sure about adding custom profile pictures or really any other user generated content. It would be nice to have, but it also involves moderation in order to prevent anything inappropriate from being uploaded (i mean, we all know how the internet works :/) Below is a small video showing the user page, along with the bot auto accepting any new friend requests :P
ELO system! let’s go!! At the end, I did add an ELO system. Well, it’s not really ELO, it’s Glicko . I used the glicko2-lite library, which is stateless unlike other glicko implementations I found. I wanted a stateless one because I’m saving the data on the DB anyways, so making it stateful would only make it use more resources (primarly RAM). You start with a rating of 1500. After every match your rating will go up/down depending on whether you win or lose. How much you win or lose depends on how many matches you have played (the first one are worth a bit more to get you to the optimal points), and depending on the rating of your oponent. If you win against someone with a bigger rating than yours, you’ll gain way more points than if you win agains someone around your rating or less. I also added a settings page so you can change your name and username, along with a page to change your password. Below is a small video showing how the ELO Glicko system works: What remains is just to also add the name/username change for bots and improve the docs. I also made a Stockfish bot which you can try to play against. (Keyword: try , because it’s probably almost impossible)
Well, that took way longer than expected. The docs are way more polished now! All endpoints have example responses so you know exactly what each one will return, along with a small description. HTTP endpoints that trigger a WebSocket event for any user (like friend requests, challenges, match moves, etc), mention it on their descriptions. I also added some headers to the PGN strings, as they were previously filled with “?“s. This mostly took this long due to a LOT of issues with the account deletion process, but it works perfectly now. When you delete your account, your user is replaced in all the matches you’ve played to @deleted_user . This is to keep the match data available even after any user deletes it. After that, your account is deleted from the DB. Due to how the DB is configured with cascade deletes, that will delete all other rows that reference the user (friendships, friend requests, pending challenges, etc.) except for matches, as they no longer reference the user that is being deleted. I’m am quite close to the ship, which I’m kinda nervous about. I want the project to be in the best state and as polished as possible, without any bugs (well, any known bugs lol). Which is mostly the reason this project as a whole has taken soo long :/ Below is a small video showing the docs with the example data. At the end is the delete account flow, which have lot’s of confirmations as it currently doesn’t send an email. I’m thinking it probably should send one lol See you in the next (and probably last) devlog! (I fixed my OBS settings, the video should look a bit better than the previous ones :P)
Hewo! Last devlog till ship here (i think) I didn’t think I’d add anything else, but you can now forfeit matches or ask the opponent for a draw! They just seemed like something that should exist on the shipped project… Each player can request only one draw per match, so you think before you do it. why did i do it like that? well, asking for a draw pauses the whole match, an neither player can do any moves until the draw request is answered. in order to prevent one of the users spamming draws, i simply limited to only one per match. also, ending the match in a draw doesn’t mean that your ELO isn’t affected, it is affected. depending on the elo of your opponent, you’ll lose/earn elo on a draw, just as you’d do on a stalemate. I also added a piece promotion selector. i forgot i made it so it always chose the queen by default, but in some matches that might not be wanted, so now you get a popup to select the piece you want to promote to well, i don’t really know if i’m missing any other things, as that was all that was i had on my TODO list, so i guess i’ll start setting up the prod environment below is a video showing the forfeit and draw flows, along with the promotion popup. don’t worry about the first match being a valid checkmate but the match continued being active, i already fixed that bug but it didn’t apply to already affected matches :P i also sped up (is that the correct way to say it?) and cutted out some parts of the video to prevent it from being 6 minutes of me playing the match lol
Well, I set up the domain + reverse proxy and all kind of problems arose. I changed the package so you only need to instantiate the class without any arguments to use the default server over at https://chessnow.angelcmh.com though you can still pass an optional baseUrl in case you selfhost your own instance at first nothing worked, but then i noticed that I had a port conflict on my VPS with two things trying to use the same port lol i also tried to improve SEO on the main page as much as I could, though im not an expert on that. i also added an official bots section so you can challenge some bots without having to look at any docs to find them shipping in some minutes!
Hewo! This devlog was unexpected. I prepared a small video/trailer so I had something to upload when shipping the project, and when I tried to upload it I realized that you can only upload images when shipping a project :/ So here is that video as it won’t go to waste. I tried my best, hope my voice doesn’t sound awkward, I’m not a native speaker Also, check out the shipped project! As I probably shipped it right after this devlog
aaaa, so… long time no see! also, super star!!! So, I’ve began doing some things that I’ve meant to do before, but completely forgot as I got quite busy… lol I fixed an error which made the TUI not work on Linux, it works now! It was an issue as I was building on NixOS, and the linker path was on my /nix/store folder instead of the usual /lib one. that means it also broke for me after an update lol You can now configure challenges! This needed to be implemented on all clients, hence why it took a little while lol Select whether you want to start with white, black or random. The opponent will be able to see which color you selected before accepting the challenge though! :P Also, meet unrankeds! You can now also mark a match as unranked so it doesn’t affect your ELO ratings at all . Take into account that there is decay though! so if you don’t play ranked for a while, your next match ELO diffs might be a little bit different Fun fact: The starting color option has been available on the API for a while already, even documented. so, if you did API calls directly, you could have selected a starting color and the opponent would not have been able to notice! as none of the clients showed it. except for the Discord bot… I think… or if you requested the match through the API too ;D
Ships:
This is Chess Now! A real-time chess API with challenges handling, matches, friends, and much more! The idea is for anyone to be able to make a custom client, bot or integration with the platform, thus it’s as open as it can possibly be while trying to also stay secure. One of the biggest parts of the proyect was doing that many clients, especially the TUI client. While I learned Vue doing the TUI client, I found it’s behaviour kinda… unintuitive in some way I can’t really explain. Though at the end I felt that Vue is better than React by a mile (now I only have to try out Svelte) I am proud of how well structured the API is, and while I’m sure it can be improved, the bases feel pretty solid. I’m also proud of how much I learned doing this. I mean, I tried a lot of things I’ve been meaning to try for some time already: Vue, Better Auth, Drizzle ORM, actually deploying a Next.js app, React mail + Resend, Elysia, and Fumadocs. And probably something else I already forgot about hehe Would I do something different if I started right now? Probably, but mostly just to try out even more things, which is the main reason why I do most of my projects. If you want to try out the project, you should probably just check the instance hosted at https://chessnow.angelcmh.com/ , create an account and play against a bot. You should also check out the docs, or the npm package over at https://www.npmjs.com/package/@chess-now/api if you are interested. Thanks for reading till the end, have a great day! ;P...
|
1792986608.2230716
|
1793073008.2230716
|
|
6517
|
swarmtrace by @raviiiibro | Stardance
|
raviiiibro
|
1
|
140.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T14:12:02Z", "hours": 140.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "the marketing was challenging and i think now it is ready and i get more suggestion if people will use it and i hope i ccan buy a domain by the star dust", "repo": "https://github.com/ravi3594444/swarmtrace", "demo": "https://swarmtrace.vercel.app/"}]...
|
[{"post_id": 57987, "ts": "202 [{"post_id": 57987, "ts": "2026-08-30T10:07:47Z", "hours": 3.3442, "text": "half work done"}, {"post_id": 45694, "ts": "2026-08-12T10:51:40Z", "hours": 14.5639, "text": "starting work"}, {"post_id": 38796, "ts": "2026-08-01T11:14:26Z", "hours": 10.8114, "text": "today i know there is so much work left on this project then i think i added a floating side bar added some more now features for backend optimization guys working on a i3 sucks please help me to buy an macbook byyy"}, {"post_id": 34749, "ts": "2026-07-25T18:41:00Z", "hours": 9.1911, "text": "adding agent graph this is mvp only i will polish it byee"}, {"post_id": 31855, "ts": "2026-07-20T15:58:43Z", "hours": 8.5708, "text": "added many features like day and night light take a tour and adjust icons sizes to a bit smaller and fixed some backend issues and run many real tests like rag agent and hermes agent and again applied for google search console ——————————————————————————————————— i need to buy a domain but i do not have money i will start marketing after buying domain byee guyss please like"}, {"post_id": 29572, "ts": "2026-07-16T16:32:50Z", "hours": 10.4061, "text": "does a full audit by ai agent found some production bugs working on prd section 1 because it is main it conation python package updtaes because the whole project is up to sdk byee meet in next vlog"}, {"post_id": 27112, "ts": "2026-07-12T11:44:54Z", "hours": 11.8228, "text": "all test are passing"}, {"post_id": 25197, "ts": "2026-07-09T08:46:20Z", "hours": 13.8544, "text": "added new features"}, {"post_id": 20965, "ts": "2026-07-02T18:13:39Z", "hours": 22.3356, "text": "Ahh infinite .tsx bug fixing"}, {"post_id": 12234, "ts": "2026-06-19T23:39:44Z", "hours": 9.5261, "text": "dev vlog#7today i worked on research on my project about similar projects because i cant get a .com domain hi have to buy a .ai domain and i worked on dashboard today because it was so simple then guys please suggest any improvement."}, {"post_id": 9898, "ts": "2026-06-16T11:58:18Z", "hours": 5.4533, "text": "Dev Vlog #6Finally, the landing page work is officially done! The platform is ready for users, and you can check it out here: swarmtrace.vercel.app.Right now, I don’t have the budget to buy a custom domain, so I have set it up on Google Search Console for now. I know that having a domain like swarmtrace.ai would help it perform much better in Google Search, since Google tends to rank subdomains poorly.That being said, the platform is still very much in the building phase. I am already working on adding some exciting new features.Stay tuned, and bye for now!"}, {"post_id": 7404, "ts": "2026-06-12T10:32:32Z", "hours": 8.6239, "text": "finally live on vercel but still in deployment you can check it guys go on swarmtrace.vercel.app"}, {"post_id": 5009, "ts": "2026-06-08T17:33:24Z", "hours": 0.6333, "text": "dev vlog #4 builders just finished the backend work for today / rest work tomorrow i will make the frontend connected to clerk for auth and neon for database . byee👍"}, {"post_id": 4889, "ts": "2026-06-08T13:38:09Z", "hours": 5.7483, "text": "dev vlog 3”What’s up, builders! Today we are fundamentally changing how SwarmTrace works. We’re tearing out the local SQLite restrictions and turning this project into a distributed, multi-tenant AI agent monitoring platform. The goal? Anyone can install our package, drop in an API key, and instantly view their agent’s execution traces on a sleek, hosted Next.js dashboard powered by Clerk and Supabase—without hosting a single thing themselves.” What We’re Solving Today: The “Localhost” Trap: Right now, the FastAPI backend expects to live on the same machine as the SQLite database. If a user runs an agent on their machine, they can’t easily see it on a globally hosted dashboard. Multi-Tenancy: We need to make sure User A never sees User B’s logs. Every single trace must be bound to an organization or user ID. Zero-Infra for the User: The developer using tracely should only have to pip-install it, provide a SWARMTRACE_API_KEY, and let our remote backend handle the rest. 📐 The SaaS Architecture Blueprint Here is how data will flow across the internet from your user’s local python script straight to your Vercel-hosted frontend dashboard: [ User’s Local Machine ] └── Running AI Agent (LangChain/CrewAI/AutoGen) └── Tracely SDK (Decorators) │ ▼ (Async Background HTTP POST /ingest) [ Vercel Serverless / API Gateway ] ─── (Validates SWARMTRACE_API_KEY) │ ▼ (Writes Log Payload) [ Hosted Database: Supabase / Postgres ] └── traces table (Schema: id, user_id, execution_time, trace_payload) ▲ │ (Fetches user-specific traces via Clerk JWT auth) [ Vercel Frontend: Next.js + Clerk ] └── Protected Dashboard View (Only shows rows matching user_id) 🗂️ The Technical Roadmap To pull this off, we have to transform four key elements of your repository: The SDK (tracely/scraper.py & tracer.py) Current: Writes to a local SQLite database via storage.py. SaaS Modification: Introduce a background background-worker thread or async pool. When a trace finishes, it sends an HTTP POST request to https://api.swarmtrace.dev/v1/ingest carrying the payload and an Authorization: Bearer st_live_… header. The Backend Engine (api.py) Current: Reads from local SQLite. SaaS Modification: Drop SQLite. Migrate to a hosted Postgres instance (Supabase is perfect here). Add an /ingest route for incoming agent metrics. Add middleware to validate incoming user requests from the frontend using Clerk JWT tokens. The Authentication Layer (Clerk) Wrap your frontend-next/ layout inside a . Set up a pipeline where a user logs in, generates an “Agent API Key” from their settings dashboard, and pastes that key into their Python .env file. also tracely is maded by me it is the part of swarm trace."}, {"post_id": 3574, "ts": "2026-06-06T15:55:13Z", "hours": 1.6264, "text": "🐝 SwarmTrace DevLog #3 — Wiring the Dashboard to Real Data June 6, 2026 /////////////////////////////////////////////////////// Today was all plumbing. No new features, no design work — just making the two halves of this project actually talk to each other. /////////////////////////////////////////////////////// Where Things Stood I had two things running independently. On one side, the FastAPI server — started it up this morning, it boots clean, the @observe decorator has been collecting real traces into SQLite every time an agent function runs. The data is there. It’s been there. On the other side, the dashboard UI — five pages, looks exactly like the design mockups, dark theme, all the charts and tables and drawers. Finished that yesterday. The problem is they had never spoken to each other. The UI was showing hardcoded numbers I typed in by hand. The API was sitting there with real data and nothing asking for it. The Work Spent today closing that gap. First thing I did was map out what each page actually needs from the backend. Overview needs health stats and an activity feed. Traces needs the full call list. Agents needs a registry of everything that’s been observed. Metrics needs cost and token breakdowns. Settings needs API key management and integration status. Then I went into the API and built those endpoints out one by one. The good news — all the underlying data was already in the database from the decorator. I wasn’t inventing anything, just exposing it in the right shape. The annoying part was that the frontend and backend had grown slightly different vocabularies. The UI expected fields named one way, the API had them named another. Duration in milliseconds vs latency in seconds. function_name vs function. Small things, but they all had to be aligned or every fetch would silently return nothing. CORS was the other thing that caught me — frontend on one port, backend on another, browser refuses to talk between them without the right middleware. Quick fix once I remembered that’s what was happening. The Moment it Clicked Started both servers. Opened the dashboard. Traces page loaded with real function names — execute_task, plan_steps, fetch_data — things I’d actually run this week. Real latencies. Real token counts. Real errors with the actual error messages. Turned on Live Mode. Ran an agent task in a separate terminal. Watched the row appear in the table a couple seconds later. That’s the thing you build toward. What’s Still Hardcoded A few things I haven’t gotten to yet. The Overview stat cards are still static numbers — need to write proper aggregation logic for those. The per-agent token sparklines are placeholder data because I’m storing traces, not time-bucketed token history per agent. Something to fix this week. Tomorrow Get the Overview cards pulling from real DB aggregations. Then figure out deployment — right now this whole thing requires running two local servers which isn’t great for a demo. Want a single public URL before the submission deadline. /////////////////////////////////////////////////////// SwarmTrace — open-source observability for multi-agent AI systems. Built for AMD Hackathon 2026."}, {"post_id": 3416, "ts": "2026-06-06T10:35:54Z", "hours": 3.8981, "text": "🐝 SwarmTrace — Developer Log 1 Project: SwarmTrace Version: 0.1.7 Built for: AMD Hackathon Author: Ravi Kumar What is it? SwarmTrace is a tracing and observability library for LLM-based multi-agent systems — essentially “pytest for AI agents.” The core idea: AI swarms are unpredictable, and existing tools give you no visibility into what happened, where it broke, or whether a prompt change caused a regression. SwarmTrace fixes that. What it does Tracing — wrap any Python function (sync or async) with @observe and every call is automatically recorded: inputs, outputs, latency, token usage, cost, errors, and parent–child relationships between nested agent calls. Token Budget — the @budget decorator tracks cumulative token usage across calls and warns you (or hard-stops) before an agent blows past its limit. Regression Detection — the compare() function runs two prompt versions against the same inputs and uses an LLM to score output similarity, flagging regressions automatically. Tool Attention (ISO Scoring) — implements the technique from arXiv:2604.21816. Instead of injecting all tool schemas into every prompt, it uses FAISS + sentence embeddings to select only the top-k relevant tools per query — reducing tool token overhead by up to 95%. Web Scraping Traces — scraper.scrape(url) wraps Scrapling with full trace recording so scrape calls show up in the call tree like any other agent action. CLI — swarmtrace prints a rich call tree with costs and statuses. swarmtrace-replay replays any individual trace. swarmtrace-export dumps everything to JSON or CSV. Frontend Dashboard A React + TanStack Router frontend visualises live traces from the FastAPI backend: Stat bar — total traces, cumulative tokens, total cost, error count at a glance Call Tree — hierarchical view of parent→child agent calls for a full run Waterfall — timeline view showing which agents ran in parallel vs sequentially Token Chart — per-trace token usage over time Failures page — isolated view of every errored trace with its call chain and error message Detail Drawer — click any trace to inspect its full args, output, latency, and lineage Live Mode — polls the backend every 2 seconds for real-time trace updates Storage All traces land in a local SQLite database (~/.tracely.db) with WAL mode enabled. Auto-purges oldest rows beyond 10,000 to stay bounded. Indexed on timestamp for fast ordered reads. Export to JSON/CSV available via CLI. Stack LayerTechnologyCore libraryPython 3.8+, SQLite, contextvarsRegression LLMClaude Haiku via litaiTool selectionFAISS + sentence-transformersAPIFastAPI + PydanticFrontendReact, TanStack Router/Start, Tailwind, RechartsCLI displayrichPackagingsetuptools, pip-installable Key design decisions contextvars for parent tracking — parent IDs propagate automatically through async and threaded code without any manual wiring. Nested @observe calls build the tree on their own. SQLite over a hosted DB — zero setup for the user; works offline; the auto-purge keeps it from growing unboundedly. Graceful degradation everywhere — if sentence-transformers/FAISS aren’t installed, Tool Attention falls back to returning the first k tools. If tiktoken isn’t installed, budget tracking falls back to len // 4. Storage errors never crash the agent being traced. Current limitations Failures page still uses static demo data instead of the live API swarm_module_0–4.py are five identical placeholder files (to be collapsed into one) No authentication on the API (development only) pyproject.toml is incomplete; setup.py not yet migrated. i have to complete ui first now then i will do other api work because it will be connected to ui because it was originally built a python frame work.byee"}]...
|
Title: swarmtrace by @raviiiibro | Stardance
Devl Title: swarmtrace by @raviiiibro | Stardance
Devlogs:
🐝 SwarmTrace — Developer Log 1 Project: SwarmTrace Version: 0.1.7 Built for: AMD Hackathon Author: Ravi Kumar What is it? SwarmTrace is a tracing and observability library for LLM-based multi-agent systems — essentially “pytest for AI agents.” The core idea: AI swarms are unpredictable, and existing tools give you no visibility into what happened, where it broke, or whether a prompt change caused a regression. SwarmTrace fixes that. What it does Tracing — wrap any Python function (sync or async) with @observe and every call is automatically recorded: inputs, outputs, latency, token usage, cost, errors, and parent–child relationships between nested agent calls. Token Budget — the @budget decorator tracks cumulative token usage across calls and warns you (or hard-stops) before an agent blows past its limit. Regression Detection — the compare() function runs two prompt versions against the same inputs and uses an LLM to score output similarity, flagging regressions automatically. Tool Attention (ISO Scoring) — implements the technique from arXiv:2604.21816. Instead of injecting all tool schemas into every prompt, it uses FAISS + sentence embeddings to select only the top-k relevant tools per query — reducing tool token overhead by up to 95%. Web Scraping Traces — scraper.scrape(url) wraps Scrapling with full trace recording so scrape calls show up in the call tree like any other agent action. CLI — swarmtrace prints a rich call tree with costs and statuses. swarmtrace-replay replays any individual trace. swarmtrace-export dumps everything to JSON or CSV. Frontend Dashboard A React + TanStack Router frontend visualises live traces from the FastAPI backend: Stat bar — total traces, cumulative tokens, total cost, error count at a glance Call Tree — hierarchical view of parent→child agent calls for a full run Waterfall — timeline view showing which agents ran in parallel vs sequentially Token Chart — per-trace token usage over time Failures page — isolated view of every errored trace with its call chain and error message Detail Drawer — click any trace to inspect its full args, output, latency, and lineage Live Mode — polls the backend every 2 seconds for real-time trace updates Storage All traces land in a local SQLite database (~/.tracely.db) with WAL mode enabled. Auto-purges oldest rows beyond 10,000 to stay bounded. Indexed on timestamp for fast ordered reads. Export to JSON/CSV available via CLI. Stack LayerTechnologyCore libraryPython 3.8+, SQLite, contextvarsRegression LLMClaude Haiku via litaiTool selectionFAISS + sentence-transformersAPIFastAPI + PydanticFrontendReact, TanStack Router/Start, Tailwind, RechartsCLI displayrichPackagingsetuptools, pip-installable Key design decisions contextvars for parent tracking — parent IDs propagate automatically through async and threaded code without any manual wiring. Nested @observe calls build the tree on their own. SQLite over a hosted DB — zero setup for the user; works offline; the auto-purge keeps it from growing unboundedly. Graceful degradation everywhere — if sentence-transformers/FAISS aren’t installed, Tool Attention falls back to returning the first k tools. If tiktoken isn’t installed, budget tracking falls back to len // 4. Storage errors never crash the agent being traced. Current limitations Failures page still uses static demo data instead of the live API swarm_module_0–4.py are five identical placeholder files (to be collapsed into one) No authentication on the API (development only) pyproject.toml is incomplete; setup.py not yet migrated. i have to complete ui first now then i will do other api work because it will be connected to ui because it was originally built a python frame work.byee
🐝 SwarmTrace DevLog #3 — Wiring the Dashboard to Real Data June 6, 2026 /////////////////////////////////////////////////////// Today was all plumbing. No new features, no design work — just making the two halves of this project actually talk to each other. /////////////////////////////////////////////////////// Where Things Stood I had two things running independently. On one side, the FastAPI server — started it up this morning, it boots clean, the @observe decorator has been collecting real traces into SQLite every time an agent function runs. The data is there. It’s been there. On the other side, the dashboard UI — five pages, looks exactly like the design mockups, dark theme, all the charts and tables and drawers. Finished that yesterday. The problem is they had never spoken to each other. The UI was showing hardcoded numbers I typed in by hand. The API was sitting there with real data and nothing asking for it. The Work Spent today closing that gap. First thing I did was map out what each page actually needs from the backend. Overview needs health stats and an activity feed. Traces needs the full call list. Agents needs a registry of everything that’s been observed. Metrics needs cost and token breakdowns. Settings needs API key management and integration status. Then I went into the API and built those endpoints out one by one. The good news — all the underlying data was already in the database from the decorator. I wasn’t inventing anything, just exposing it in the right shape. The annoying part was that the frontend and backend had grown slightly different vocabularies. The UI expected fields named one way, the API had them named another. Duration in milliseconds vs latency in seconds. function_name vs function. Small things, but they all had to be aligned or every fetch would silently return nothing. CORS was the other thing that caught me — frontend on one port, backend on another, browser refuses to talk between them without the right middleware. Quick fix once I remembered that’s what was happening. The Moment it Clicked Started both servers. Opened the dashboard. Traces page loaded with real function names — execute_task, plan_steps, fetch_data — things I’d actually run this week. Real latencies. Real token counts. Real errors with the actual error messages. Turned on Live Mode. Ran an agent task in a separate terminal. Watched the row appear in the table a couple seconds later. That’s the thing you build toward. What’s Still Hardcoded A few things I haven’t gotten to yet. The Overview stat cards are still static numbers — need to write proper aggregation logic for those. The per-agent token sparklines are placeholder data because I’m storing traces, not time-bucketed token history per agent. Something to fix this week. Tomorrow Get the Overview cards pulling from real DB aggregations. Then figure out deployment — right now this whole thing requires running two local servers which isn’t great for a demo. Want a single public URL before the submission deadline. /////////////////////////////////////////////////////// SwarmTrace — open-source observability for multi-agent AI systems. Built for AMD Hackathon 2026.
dev vlog 3”What’s up, builders! Today we are fundamentally changing how SwarmTrace works. We’re tearing out the local SQLite restrictions and turning this project into a distributed, multi-tenant AI agent monitoring platform. The goal? Anyone can install our package, drop in an API key, and instantly view their agent’s execution traces on a sleek, hosted Next.js dashboard powered by Clerk and Supabase—without hosting a single thing themselves.” What We’re Solving Today: The “Localhost” Trap: Right now, the FastAPI backend expects to live on the same machine as the SQLite database. If a user runs an agent on their machine, they can’t easily see it on a globally hosted dashboard. Multi-Tenancy: We need to make sure User A never sees User B’s logs. Every single trace must be bound to an organization or user ID. Zero-Infra for the User: The developer using tracely should only have to pip-install it, provide a SWARMTRACE_API_KEY, and let our remote backend handle the rest. 📐 The SaaS Architecture Blueprint Here is how data will flow across the internet from your user’s local python script straight to your Vercel-hosted frontend dashboard: [ User’s Local Machine ] └── Running AI Agent (LangChain/CrewAI/AutoGen) └── Tracely SDK (Decorators) │ ▼ (Async Background HTTP POST /ingest) [ Vercel Serverless / API Gateway ] ─── (Validates SWARMTRACE_API_KEY) │ ▼ (Writes Log Payload) [ Hosted Database: Supabase / Postgres ] └── traces table (Schema: id, user_id, execution_time, trace_payload) ▲ │ (Fetches user-specific traces via Clerk JWT auth) [ Vercel Frontend: Next.js + Clerk ] └── Protected Dashboard View (Only shows rows matching user_id) 🗂️ The Technical Roadmap To pull this off, we have to transform four key elements of your repository: The SDK (tracely/scraper.py & tracer.py) Current: Writes to a local SQLite database via storage.py. SaaS Modification: Introduce a background background-worker thread or async pool. When a trace finishes, it sends an HTTP POST request to https://api.swarmtrace.dev/v1/ingest carrying the payload and an Authorization: Bearer st_live_… header. The Backend Engine (api.py) Current: Reads from local SQLite. SaaS Modification: Drop SQLite. Migrate to a hosted Postgres instance (Supabase is perfect here). Add an /ingest route for incoming agent metrics. Add middleware to validate incoming user requests from the frontend using Clerk JWT tokens. The Authentication Layer (Clerk) Wrap your frontend-next/ layout inside a . Set up a pipeline where a user logs in, generates an “Agent API Key” from their settings dashboard, and pastes that key into their Python .env file. also tracely is maded by me it is the part of swarm trace.
dev vlog #4 builders just finished the backend work for today / rest work tomorrow i will make the frontend connected to clerk for auth and neon for database . byee👍
finally live on vercel but still in deployment you can check it guys go on swarmtrace.vercel.app
Dev Vlog #6Finally, the landing page work is officially done! The platform is ready for users, and you can check it out here: swarmtrace.vercel.app.Right now, I don’t have the budget to buy a custom domain, so I have set it up on Google Search Console for now. I know that having a domain like swarmtrace.ai would help it perform much better in Google Search, since Google tends to rank subdomains poorly.That being said, the platform is still very much in the building phase. I am already working on adding some exciting new features.Stay tuned, and bye for now!
dev vlog#7today i worked on research on my project about similar projects because i cant get a .com domain hi have to buy a .ai domain and i worked on dashboard today because it was so simple then guys please suggest any improvement.
Ahh infinite .tsx bug fixing
added new features
all test are passing
does a full audit by ai agent found some production bugs working on prd section 1 because it is main it conation python package updtaes because the whole project is up to sdk byee meet in next vlog
added many features like day and night light take a tour and adjust icons sizes to a bit smaller and fixed some backend issues and run many real tests like rag agent and hermes agent and again applied for google search console ——————————————————————————————————— i need to buy a domain but i do not have money i will start marketing after buying domain byee guyss please like
adding agent graph this is mvp only i will polish it byee
today i know there is so much work left on this project then i think i added a floating side bar added some more now features for backend optimization guys working on a i3 sucks please help me to buy an macbook byyy
starting work
half work done
Ships:
the marketing was challenging and i think now it is ready and i get more suggestion if people will use it and i hope i ccan buy a domain by the star dust...
|
1792983406.4024994
|
1793069806.4024994
|
|
26398
|
200 MPH Drone RTOS by @Guagyyy | Stardance
|
Guagyyy
|
2
|
139.02
|
2267
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-22T00:49:05Z", "hours": 106.0, "multiplier": 19.18, "payout": 2024, "blessing": "neutral", "text": "200 MPH Drone RTOS: How it went Simulation to Silicon! When I published the first major update for this project at the 15-hour mark, I essentially had a proof-of-concept. I had managed to write a custom hybrid cooperative/preemptive scheduler and get an ARM Cortex-M7 (on the STM32f756VGTx) assembly context switcher functioning inside the Renode simulator. Although this looked like a massive leap, the project had barely started. Over 100 hours of development have gone into this project since then. The transition from a simulated kernel to a bare-metal flight controller capable of keeping a 200 MPH drone in the air required stripping the system down to its bare components, rewriting the memory architecture, and debugging some of the most frustrating hardware faults I have ever encountered-especially whenever the project just crashed, leaving me no traces as to what went wrong. Software Limitations The biggest turning point was realizing that software simulation can only take you so far. Renode is an amazing tool, but it hid a massive amount of race conditions and timing flaws that only exposed themselves when I finally flashed the code to physical STM32F756 Nucleo board. Sometimes, the MCU would have to reboot every 2 seconds. I spent dozens of hours tracking down massive architectural bugs. One of the worst was a context-switching fault where floating-point math was corrupting the return address in the CPU registers, causing the processor to execute raw garbage data. To fix this, I had to completely restructure the boot sequence and overhaul the memory management. I moved away from static arrays to a dynamic per-task stack allocation system, and implemented a dual-guard memory system. Arguably, this was the most important change as it allowed me to debug tasks way quicker as I instantly could know when the canary values were corrupted. Overhauling the Data Pipelines In order to avoid the 10ms delay of my original blocking pipline (for data transfer), I entirely rewrote the hardware data pipelines multiple times to use a semi-blocking, circular Direct Memory Access (DMA) architecture. Instead of the processor handling the data transfer, the hardware itself moves the bytes from the sensors directly into memory in the background. The DMA streams now trigger precise interrupts at the halfway and full-transfer points, allowing the RTOS to safely parse incoming radio packets and sensor reads without ever risking data overwrites or blocking the main flight loop. Building a Flight Controller I integrated Betaflight’s Actual Rates algorithm with custom expo curves, ensuring that physical stick inputs map perfectly to target velocities. I built a custom SPI driver to pull 24-bit raw pressure and temperature data from a BMP390 barometer, passing it through hypsometric formulas to calculate altitude. For video and telemetry, I moved away from raw UART strings and implemented native MSP DisplayPort communication (for true digital Walksnail Avatar connection). I also built an interactive USB command-line interface. Instead of having to recompile and re-flash the firmware every time a PID value needs to be adjusted, I can plug into the board, pull up a terminal, and manually tune gains, remap CRSF radio channels, or adjust IMU orientation offsets in real time. Final Version The last few weeks have been about refinement and consistency, removing race conditions and overall polishing the code. Now that the RTOS is fully functional, the only things to add are extra features, like a permanent + more expanded CLI, as well as finishing the external RM and linking the ESC drivers. As these are pretty insignificant, I have linked the source of this shipment to the Github project rather than a specific release so that I can update these during review!", "repo": "https://github.com/Guag914/200-MPH-Drone-RTOS/", "demo": "https://github.com/Guag914/200-MPH-Drone-RTOS#interactive--simulation-demo"}, {"ship_num": 2, "ts": "2026-07-15T04:02:12Z", "hours": 15.0, "multiplier": 16.44, "payout": 243, "blessing": "neutral", "text": "Phase 1 (The Custom RTOS Kernel) I am building a custom FPV drone from scratch with my friend in an attempt to achieve 200 mph . At those speeds, standard super loops are far too slow, as a single microsecond of lag means the drone travels feet before making a PID correction. To solve this, I built a custom, hybrid cooperative/preemptive Real-Time Operating System (RTOS) from scratch for the ARM Cortex-M7 (STM32F7)! What Was Challenging? The absolute hardest part of this phase was writing the low-level assembly context switcher ( PendSV_Handler.S ). Hacking the ARM Cortex-M7 registers to physically hot-swap stack pointers ( PSP ) mid-execution without crashing the CPU or corrupting the program state was a massive headache. I had to ensure that when an asynchronous preemption event fires, the assembly code perfectly preserves the execution registers ( R4-R11 plus the hardware-stacked registers), jumps to the high-priority task, and then seamlessly restores the background task right where it left off. Getting the compiler-enforced task overloading working so the kernel cleanly separates periodic tasks from raw interrupts was another huge hurdle, but it makes the whole codebase infinitely more robust. Want to Test It or Write Your Own Tasks? You don’t need physical hardware to watch this run! I’ve packaged the entire project with a Renode simulation script. You can run the interactive emulator with a single command to see the preemption scheduler hijack our counter task live, or you can jump into the user sandbox file and write your own custom tasks. Check out the GitHub Repository to Run the Demo! The README has a quick 5-minute setup guide to get you compiling and simulating your own code in no time.", "repo": "https://github.com/Guag914/200-MPH-Drone-RTOS/", "demo": "https://github.com/Guag914/200-MPH-Drone-RTOS#interactive--simulation-demo"}]...
|
[{"post_id": 82549, "ts": "202 [{"post_id": 82549, "ts": "2026-10-25T06:23:47Z", "hours": 9.7414, "text": "I spent the past week fixing timing issues on the hardware and getting the simulation environment back into a usable state. Although it isn’t 100% yet, I managed to fix a lot of underlying bugs causing the program to fail on actual hardware. Serial Communication and DMA The biggest issue was that manual USART transfers were completely blocking the system. Printing alone was taking around 95 percent of the total execution time. This was destroying the preempt speed and causing weird timing bugs across the board. I rewrote the USART printing logic to offload everything to a background circular DMA task instead. While I was working on the serial connections, I also fixed the UART mapping bugs and moved all logging over to UART4 so it stops fighting with the GPS module on USART3. I also went through stm32f7xx_it.c and fixed the rest of the extern “C” methods. They were previously commented out, which was silently causing their respective DMA HALs to fail. Moving them to the correct user code sections fixed the issue entirely. Simulation Environment and Tooling On the software side, the simulation startup in the HAL was broken and preventing the virtual boards from properly configuring and running. I fixed the initialization sequence so the simulations actually boot correctly now. To make starting the environment even easier for new users, I updated both the run.sh and run.bat scripts with installers that automatically download Renode. This skips the manual installation step completely and gets the simulation running much faster."}, {"post_id": 78931, "ts": "2026-10-12T02:34:08Z", "hours": 8.2783, "text": "Although I haven’t been able to make much progress on the project due to school over the past weeks I did manage to make some substantial project mostly with the scheduler, allowing for fairly good performance on my STM Nucleo boards, rather than it just crashing instantly. 1. Issues with the Old Design The flight controller’s RTOS scheduler wasn’t working under real hardware timing because global variables like currTaskIndex, topOfStack, and excReturn were being modified from multiple entry points simultaneously. Yield calls, interrupt handlers, and the main task-selection logic were all making independent writes to the same shared task control blocks. Whenever a hardware interrupt fired mid-write, stack pointers and exception return values were saved into the wrong taskControlBlocks slot. This created edge cases where preempted tasks were silently double-queued, state tracking completely desynchronized, and time-critical hardware events were dropped during flight. 2. Centralizing Context Switches in PendSV To eliminate these race conditions, all state-selection decisions were moved out of individual execution contexts and consolidated into decideNextTask(), which now runs exclusively inside the PendSV assembly handler. Functions like yieldCurrentTask(), decideNextInterruptTask(), and decideNextScheduledTask() no longer touch global scheduler state or choose which task runs next; they simply update local status flags like TaskState::BLOCKED or TaskState::READY inside brief __disable_irq() critical sections and trigger PendSV using SCB_ICSR_PENDSVSET_Msk. When PendSV fires, decideNextTask() saves outgoingSP and outgoingExcReturn to the active block, sets RUNNING tasks to READY, and runs a two-pass check over taskControlBlocks[]—evaluating high-priority TaskType::INTERRUPT tasks first, then TaskType::SCHEDULED tasks, and falling back to index 0 for idle. Since PendSV is the only place allowed to modify currTaskIndex, concurrent state corruption is structurally impossible."}, {"post_id": 71997, "ts": "2026-09-21T23:26:43Z", "hours": 7.2761, "text": "For the past couple weeks I have been mostly refining small bugs, which were originally rendering the RTOS usless, as well as refactoring the code for simplicity rather than elegancy. 1. Transition to Actual Hardware Renode is great for simulation, but it ended up hiding a bunch of race conditions in the population methods and the main scheduler that led to no code actually running during the IRQ handler calls. I spent a lot of time securing those resources and finally got the scheduler mostly finished up. Also, I decided to just take out the double preempts entirely since they were adding way too much complexity for absolutely zero speed benefits in practice (plus they were creating detrimental but rare race conditions). 2. Code Refactor To make things run a bit more consistent, I restructured how the control loops operate. I ended up merging the dShotGeneration task with the parent IMU control loop, so now everything from reading the sensors to pushing motor commands happens in one clean sequence (rather than including an unnecessary preempt). I also built out a brand new CRSF control loop to handle all the radio parsing and state machine updates in its own dedicated space (just for consistency). Lastly, while doing a final pass on the code, I realized that in my dShotGeneration helper, I had forgot to scale the values by a factor of 1/2000, as the inputs require the value to be between 0 and 1 (not 0 and 2000). 3. Final DMA Iteration The biggest relief was finally getting rid of the old blocking USART system. I finally transitioned away from manually handling the streaming by polling flags in a loop, which was tying up the processor way more than it should have. Everything has been converted over to a blocking DMA system, so the hardware can just handle all the memory transfers in the background while the CPU focuses on actually keeping the drone in the air. Overall, I think that this will be the final iteration of the RTOS DMA pipeline, as now that it is solid and works with all the edge cases, theres no need to change it. 4. Timeline With almost all the major bugs fixed, I am going to ship the project! While it is not 100% done, it will likely be as close as it will get during the timeframe of the Stardance hackathon, and with it so close, theres no reason not to ship. Anyway, I will keep the source as the main project rather than a release, so if I do end up fixing any major bugs, they will get patched either before or during project review (besides most of these bugs are only detectable on actual hardware). I will most likely finish the RTOS in the next couple weeks (by the end of October), and will finish the drivers for the ESC and RM by latest end of November (for more timing refer to the README). Thanks to everyone who supported me throughout this project (hopefully me and my friend can get this drone flying in another Hack Club Hackathon!)."}, {"post_id": 63202, "ts": "2026-09-06T21:25:57Z", "hours": 9.6606, "text": "1. Scheduler Hardening and Task Discovery Spent part of this session making the RTOS scheduler itself more robust. I added a findTaskByName() function so interrupt-driven task lookups happen dynamically instead of relying on hardcoded task indices, which was a fragile setup just waiting to break the moment task registration order changed. Alongside that, I wrapped every one of those lookups with lambdas that throw a proper warning if a task can’t be found, so a missing task fails loudly instead of silently dereferencing a null pointer somewhere downstream. 2. Blocking vs Non-Blocking Scheduled Tasks After a lot of painful debugging, I traced a string of issues (including interrupt tasks silently failing to fire and scheduled tasks stepping on each other) back to non-blocking statements I’d introduced inside scheduled tasks in the previous devlog. I ended up taking those out and reverting scheduled tasks fully back to blocking, which is genuinely what the scheduled zone was designed for in the first place: tasks that don’t need to run in polynomial time and can safely block without putting the drone at risk of crashing. Once that was sorted, I converted the raw USART byte-pushing into a blocking DMA system instead, so streaming is handled by DMA hardware rather than manually pushed byte-by-byte over USART. 3. Flight Loop Refactor and VTX Communication On the flight logic side, I refactored flightLoop() to use lambdas and a state machine so I would never have to yield in the middle of my tasks (which was used previousely for zeroing motor outputs). I also converted the error handling into a proper state machine, so different types of warnings can be caught and handled distinctly instead of lumping every issue into one path, and turned on full debug printing whenever the system is running. Last but not least, I built out a dedicated injector for respondToVTX so I can properly test and simulate VTX communication going forward. 4. Real Hardware Testing Since, I am almost 100% done with the RTOS I bought two NUCLEO-F756ZG’s which will serve as testing the 100% production code rather than the simulation version. I bought two so that one of the boards will be running the real RTOS code, testing DMA reading from USART, SPI, and emitting real motor signals, while the second will be emulating all of my peripherals. When the boards come, if the code does work, it will also mean that the real PCB’s will also work when my friend finishes with them. 5. Next Steps As of now there are a few issues with the double preempt system (for the interrupt tasks) I designed a while back, so I will need to debug that before they arrive. Right now before the boards arrive, I will be finishing up the RTOS blocking DMA pipelines (stripping out IRQ, removing NVIC etc. for scheduled tasks), and performing a bunch of baseline testing in order to prove that the RTOS is capable of flying an actual drone!"}, {"post_id": 52761, "ts": "2026-08-23T03:11:04Z", "hours": 9.6356, "text": "1. CLI Upgrades and Channel Mapping Over the past 5 days, I knocked out some major quality-of-life upgrades for the flight controller. I added customizable channel mapping for CRSF directly through the CLI. By utilizing a combination of references and pointers, I was able to point a volatile alias to certain channel mappings, allowing for completely customizable CRSF channels. While I was in the CLI logic, I also added the ability to configure custom IMU orientations around the z-axis, making it way easier to mount the board in different directions without having to recompile the firmware. 2. DMA Pipeline Fixes and Baro Optimization A big chunk of this session went into debugging and refactoring the hardware data pipelines. I adjusted the ADC population pipeline in order to fix some stream parsing issues, and gave the barometer a massive overhaul. The baro now uses a non-blocking, non-circular DMA setup that relies on a semi-interrupt-driven task call rather than a continuous loop. This enabled me to yield in the middle of the function, and call back later as soon as DMA is finished transferring. I also fixed a massive bug in the DMA setup: the DMA_SxCR_HTIE and DMA_SxCR_TCIE flags were accidentally enabled for the GPS and OSD ring buffers, which would have crashed the whole RTOS by firing unhandled interrupts, causing default HAL and IRQ handlers to run. 3. Walksnail Two-Way Communication Finally, I built out the respondToVTX task to get the drone properly communicating with the Walksnail VTX. Instead of just blindly sending video data out, this sets up true two-way communication over asynchronous UART. By writing a persistent byte-by-byte state machine, the flight controller can now safely parse incoming requests from the VTX without dropping half-packets, allowing me to send back live stick positions and armed status for the OSD menus. The only thing left to do now is handle persistent CLI storage, the logToBlackBox task, integrating the semi-interrupt pipeline with telemetryTX and the OSD, and a few other system tweaks. After that the RTOS will be 100% ready to fly the actual drone."}, {"post_id": 49360, "ts": "2026-08-18T04:16:35Z", "hours": 4.0211, "text": "Complete RTOS Overhaul, Circular DMA Pipelines, and CPU Abort Fixes This update focuses on fine-tuning the RTOS, organizing the scheduler, and rewriting microcontroller memory handling. Renode’s simulated DMA restrictions make software-only pipeline testing nearly impossible, so I plan to buy a physical dev board and Raspberry Pi to validate on silicon. While the Git diff might not look massive, the architecture has evolved from a blocking system to a true preemptive RTOS with precise polynomial timing. 1. Reworking DMA Flow & Standardizing Ring Buffers Sensor and receiver data pipelines are now driven by circular DMA, enabling non-blocking, high-frequency transfers with response times as fast as 0.3 ms (without printToUSART enabled). Everything now relies on ring buffers. Instead of generating complete packets instantly, mock injectors stream bytes directly into the buffers while updating the simulated NDTR register to mirror hardware behavior. if ( byteIdx >= frameLen ) { byteIdx = 0 ; } crsfRingBuffer [ head ] = frameBuf [ byteIdx ++ ]; head = ( head + 1 ) % CRSF_RING_BUFFER_SIZE ; currentBoardConfig . crsf_dma_stream -> NDTR = CRSF_RING_BUFFER_SIZE - head ; Feeding bytes incrementally moves the write head gradually, ensuring the simulation mimics a physical UART and allowing population functions to safely pull data within interrupt locks. 2. DMA Interrupts for Safe Parsing To prevent data overwrites, DMA streams trigger interrupts at the halfway (HTIE) and full-transfer (TCIE) points to queue tasks. Because registers like LISR are read-only in hardware, I implemented a software mock flag system (mock_LISR) for simulation: extern \"C\" void DMA1_Stream0_IRQHandler ( void ) { #ifdef SIMULATION uint32_t flags = mock_LISR ; mock_LISR = 0 ; #else uint32_t flags = DMA1 -> LISR ; #endif if ( flags & DMA_LISR_HTIF0 ) { DMA1 -> LIFCR = DMA_LIFCR_CHTIF0 ; decideNextInterruptTask ( & taskControlBlocks [ 1 ]); } } Functions safely extract data with interrupts disabled, ensuring the CPU never blocks waiting for peripheral transfers. 3. Assembly Bugs & CPU Aborts Debugging nested hardware interrupts exposed massive faults: The context-switching bug: FPU usage or large stack frames corrupted the return address, causing the CPU to execute BX LR with garbage data. Fixed in PendSV_Handler.S by explicitly storing excReturn inside the TaskControlBlock rather than relying on stacked registers. Second, a 0x00000000 Null Return Crash: Scheduled tasks attempted to return natively, popping 0x00000000 from the zero-initialized Link Register and causing a fetch fault. Every task now runs inside an infinite while(true) loop calling yieldCurrentTask() . 4. Clock PLLs & Hardware Re-routing After configuring the STM32CubeMX PLL for a 25 MHz HSE clock, the MCU runs at its full 216 MHz. I added a standardized initSystemGPIOClocks() function to enable peripheral clocks consistently. I also moved motor 3 from TIM1 to TIM4, synchronizing it with the 216MHz clock and freeing up a TIM1 DMA stream exclusively for the upcoming BlackBox logging. Future Updates With the core RTOS stabilized, development shifts to flight-facing systems: hooking the SPI pipeline to the video overlay for live OSD goggle telemetry, adding permanent flash storage for PID tunes/configs, exposing MCU controls via CLI, supporting programmable transmitter bind buttons, building a desktop GUI, and using the freed TIM1 DMA for BlackBox logging. Below, I have attached a screenshot of every single task working, and outputting values in the simulation, something that wasn’t possible for the interrupt tasks until now."}, {"post_id": 48647, "ts": "2026-08-17T03:57:01Z", "hours": 9.6761, "text": "1. Reworking the DMA Flow for Speed So, a lot has been going on lately, starting with a massive rework of the entire DMA flow. The functions are now entirely populated by circular DMA, which is a huge upgrade for the system’s overall performance. This architectural change allows for completely non-blocking, high-frequency calls, hitting response times as fast as 0.03 milliseconds. It basically means the whole data pipeline is significantly faster, and much more responsive than it was in previous versions. 2. Standardizing Ring Buffers and Mock Injectors To make everything more reliable, the DMA now follows a very specific and predictable pattern for both scheduled and interrupt tasks. Everything relies on ring buffers now, whether they are being injected by actual hardware (or simulated) DMA or by my custom simulation scripts. I also reworked the mock injectors so they no longer just return a pre-formatted packet. Instead, they write directly into the ring buffer, which lets me test the exact same parsing pipeline in software, simulating the hardware flow almost exactly like Renode (if only they would ever fix that USART DMA bug…). 3. Assembly BX LR Bug + STMCubeMX Clock PLL I also finally solved the long term BX LR return bug that I literally spent over 20 hours trying to find. Whenever tasks used the FPU or had slightly larger stacks, the return address in the r0 register would just get completely corrupted by the extra data. I fixed this by storing the return address in a dedicated uint value instead of blindly trusting the registers to hold it. That fix alone allowed me to safely re-add telemetryTX and make a bunch of other function logic much more robust. On top of that, I went into STM32CubeMX and reworked the clock PLL manually (it took over 3 hours to solve by hand). By feeding in a 25 MHz HSE clock, I managed to unlock the MCU’s internal clocks to run at their full 216 MHz.I also took some time to clean up the codebase to improve overall readability and commenting. 4. DMA Interrupts for Safe Parsing Another feature is that DMA now triggers interrupts when the ring buffers hit exactly halfway and when they are fully populated. This gives me the time to parse all the incoming values safely without having the risk about data getting overwritten by the next DMA pass before I am done reading it. I set up the IRQ handlers in the code to call the interrupt methods automatically, which ensures the CPU stays completely unblocked and free to handle other flight control tasks almost all the time (overall decreasing headroom). 5. Current Status: NVIC Bug Sadly, the code is actually not functional right now because the NVIC and IRQ pipeline is malfunctioning and just refusing to call the interrupts for reasons I cannot figure out yet. Because of this, I am holding off on pushing the code until I can track down the bug, give everything a final polish, and run some benchmark testing (since I don’t want to commit broken code). Also, sorry for promising a commit a day or two after my last devlog. I got super busy, especially with vacation, but I will try my best to get this sorted. Depending on how long it takes to figure out this NVIC issue, the next commit might drop anywhere from tomorrow to a few weeks from now."}, {"post_id": 41654, "ts": "2026-08-06T00:44:12Z", "hours": 9.5336, "text": "This week was heavily focused on the fine tuning and organization of the RTOS. I spent numerous hours of research and untangling environment setups. I originally tried to build out a complete framework for the drone code without relying on any simulation code, but Renode’s restrictions, specifically with its ability to perform DMA requests, quickly made it clear that path was impossible. To fix this I’m looking into picking up a dev board and a Raspberry Pi so I can test and debug everything on an actual MCU before finally moving the codebase over to the drone. Even though the git won’t look a whole lot different and not a lot of actual code changed, getting these configs finalized (especially in STM32CubeMX) in was a huge step forward for the project. I expect to commit the next version of the code either today or tomorrow, with improvements specifically in TelemetryTX, BlackBoxLogging, and a few other minor changes!"}, {"post_id": 37983, "ts": "2026-07-31T02:30:16Z", "hours": 8.6756, "text": "Major Architecture Upgrade : OSD, Betaflight Rates & Build System Refactor 1. OSD, DMA + SYS First off on the hardware side, I added native MSP-based OSD support for Walksnail video transmitters, built the SPI barometer driver for altitude tracking, and spun up a low-level health task that constantly monitors MPU registers and stack usage in the background. On top of that, I finally fixed the DMA stream conflicts (mainly in STMCubeMX) between TIM1 DShot motor outputs , ADC1, and SPI peripherals, so everything runs without collisions now. 2. SYS Health + Debugging I also implemented a few other low level tasks, allowing me to monitor system health, based upon ram usage and storage used. This task prints out the amount at which each tasks stack is being used, allowing me to effectively debug whether a task was actually overflowing, vs an unrestricted read/write. Furthermore, the original canary values that I used, were completely replaced as they in fact were causing some of the “stack overflow” bugs (via unrestricted reads/write every 1 ms in SysTick_Handler ). 3. Betaflight Rates + CLI Update For flight feel, I implemented Betaflight’s Actual Rates algorithm with custom expo curves, so stick inputs map to target angular velocities with center-stick precision. I also completely separated serial communications by moving the interactive CLI to USART1 (accessible via nc -C localhost 1234 in terminal) and pushing system logs to USART3. Additionally, I removed the old telemetryTX task because its unauthorized reads/writes were completely breaking the RTOS scheduler, and expanded the CLI with a ton of commands for live sensor readings and more PID tuning. Speaking of which, I am planning to create a persistent file in /bin/ , allowing for rates to be stored between runs, rather than being reset each during runtime, and having to be manually configured through the CLI. 4. Overhauled Building Workflow Finally, I overhauled the whole developer workflow and build automation setup. The build.sh and build.bat scripts now auto-configure custom CMake profiles and generate a full disassembly file in /bin/ after every build for fast low-level debugging, while run.sh and run.bat automatically launch the right terminal windows on launch. 5. Future Additions: I’m planning to build a closed-loop Renode simulation matrix to stream hardware data into every peripheral externally, letting me run 100% real production code during SIL testing! For this, I will utilize the currently blank simulate.py as well as certain commands in simulate.resc to create properly formatted dynamic buffers(which are not directly injected into the code), allowing me to properly test the DMA drivers, and many of the memory management helpers."}, {"post_id": 35605, "ts": "2026-07-27T04:22:30Z", "hours": 9.44, "text": "Over the last few days, I wrapped up two major tasks for the flight controller’s core sensor and telemetry stack: the on-screen display (OSD) renderer and the BMP390 barometer subsystem. The OSD engine is now fully hooked up to the state system, giving real-time visual downlinks for critical metrics like flight battery voltage, active flight modes, and height statistics over UART. To keep the execution completely non-blocking, all frame updates are dispatched asynchronously, preventing rendering delays from hindering the performance of the high-frequency control loops. On the barometer side, I implemented altitude tracking using Bosch’s BMP390 sensor over SPI with non-blocking DMA burst transfers. In the 50Hz task loop, incoming 24-bit raw pressure and temperature bytes are assembled and passed through the hypsometric formula to calculate smooth, relative height above ground level (AGL). Although the barometer task is a bit flawed due to floating point register stack errors with the header and end canary values, they don’t seem to be affecting the system in anyway (nor is any data being corrupted). I will find a way to fix these issues before the next commit, as well as the race condition in the interrupt tasks in the next Github commit. After that, it is just system polish and extensive testing before the RTOS will be complete!"}, {"post_id": 33865, "ts": "2026-07-24T04:03:21Z", "hours": 7.1808, "text": "1. Fixing the Stack Overflows at Boot After an entire 25-hour debugging period across 4 days, the RTOS kernel is finally done (for the scheduled tasks). I tracked down a silent bug where several critical scheduled tasks—like powerManagement , lowLevelFailSafe , and telemetryTX —were crashing the MCU on boot. The issue came down to a boot-time dependency lock: tasks were trying to poll hardware registers (like UART TX flags) and read shared drone state variables before the peripherals or producer tasks had time to initialize on Tick 0. By adding an initial yieldCurrentTask() right at the top of these methods, Task Phase Alignment was officially added. This gives the hardware a full cycle to stabilize, preventing buffer overflows and eliminating the cascading task state corruptions that were locking up the scheduler. 2. Custom Stack Sizing & Real-Time Guard Checks Alongside the scheduler fix, I pushed major upgrades to memory safety and task management. Instead of assigning a static stack array to every task, I transitioned to dynamic per-task stack allocations during initialization ( new (std::nothrow) ). Heavy string-parsing and math tasks get larger stacks, while simple toggle tasks stay lightweight. To catch memory issues before they corrupt the heap, I implemented a custom dual guarding system: 0xDEADBEEF is appended at the bottom of the stack to catch standard stack overflows, while a new 0xBEEFCAFE canary value is written to the very top index ( stackSizeWords ) to instantly flag memory breaches in the SysTick_Handler . Furthermore, I refactored powerManagement to use ADC2 in Circular DMA Mode, writing battery telemetry directly to RAM in the background for zero CPU overhead. 3. Transitioning to Walksnail Avatar HD Looking ahead, my and my friend are officially transitioning our existing analog video setup over to a fully integrated Walksnail Avatar HD digital ecosystem. Rather than keeping my custom telemetry task ( telemetryTX ) with heavy string formatting over raw UART, Walksnail allows me to stream standard MSP (MultiWii Serial Protocol) DisplayPort frames straight to the VTX. The Walksnail system will serve as our primary onboard logging source, giving us full OSD telemetry, high-framerate HD video, and precise blackbox data logging. With the RTOS core now stable and non-blocking, our next focus shifts toward “premium” flight controller features, e.g. including custom RC stick expo curves, an expanded USB CLI, and an integrated simulator interface."}, {"post_id": 32665, "ts": "2026-07-21T23:24:15Z", "hours": 9.0794, "text": "I just finished expanding the RTOS architecture, filling out all of the scheduled background tasks to handle real-time flight telemetry, peripheral hardware, and terminal configuration. On the telemetry side, I built out telemetryTX to package battery, status, and GPS data into standard CRSF frames over UART, alongside an NMEA gpsParser that decodes $GNGGA and $GNRMC sentences for live location fixes. I also made powerManagement into its own standalone task so ADC voltage and current metrics can feed into the failsafe logic and telemetry concurrently. To make bench testing and tuning significantly easier, I added usbCLI over USART1, giving me a full interactive shell to tweak PID gains (Kp, Ki, Kd), dump raw IMU data, and inspect hardware states on the fly without needing to reflash firmware. To keep the physical quad safe and responsive during flight, I added updatePeripherals for LED status patterns and buzzer warnings, along with a dedicated Independent Watchdog (IWDG) task running as a low-priority fail-safe to trigger hardware MCU resets if the scheduler ever freezes. On the project structure side, CMake now routes all output binaries straight into a clean ./bin/ directory so nobody has to compile the source manually just to run the .elf target in Renode. I also introduced a -DENABLE_DEBUG flag, allowing me to cleanly toggle between complete USART log prints across every loop or a blank terminal environment meant purely for the CLI shell. While all the background subsystems and scheduled task priorities are fully mapped out, I’m currently figuring out a few lingering RTOS bugs—specifically around stack allocation, causing stack overflow flags on certain scheduled tasks, along with scheduling starvation where context switching isn’t releasing task blocks properly. Because I want to ensure the scheduler kernel is 100% complete before pushing broken stack frames to the main branch, the GitHub repository will be updated with the complete, bug-fixed code later today. Everything is moving in the right direction, and getting these background tasks finalized brings me one step closer to full flight hardware deployment!"}, {"post_id": 31067, "ts": "2026-07-19T04:58:26Z", "hours": 2.5139, "text": "I’ve spent the last 20 hours of coding basically staring at bare-metal memory allocations and tracking down why the drone’s context switcher was triggering CPU drops under the Renode simulation environment. Moving away from manual Python injection scripts to a cleaner C++ conditional compilation framework using CMake was supposed to simplify the testing layout, but instead, it exposed structural design flaws in how the scheduler kernel boots up. Running a multi-sample sensorCalibration() routine at cold boot was forcing hidden task yields before the OS kernel was fully mapped out, which was throwing unmapped register address errors and wiping out index-0 entries. To solve this, I decoupled the entire state machine sequence so that hardware allocations, peripheral registers, and core tracking counters now clear before any operational loops drop into the registry. I also added a critical rtosStarted gatekeeper flag to yieldCurrentTask() so calibration math runs cleanly in sequence without triggering early PendSV handler switches. On top of that, the task stack pointers are completely realigned. The assembly context swapper now maps a precise 32-word boundary allocation utilizing 0xFFFFFFFD as a basic exception return code, which completely eliminates the data corruption that was misaligning our Process Stack Pointer. With the fundamental kernel stabilized, I shifted entirely into clean architecture organization. The massive, cluttered code blocks have been split up into independent tracking files (BufferPopulation.cpp, Tasks.cpp, and SimInjector.cpp). High-speed SPI reads for the IMU, UART ring buffers for decoding CRSF radio channel frames, battery ADC sampling, and DShot600 motor output mixers are now fully broken out and functional. There is still a nagging preemption lockout issue inside the simulator where a single interrupt task attempts to starve out the other concurrent loops during a millisecond window, but the baseline operating system is locked in, meaning I can confidently verify the PID flight mixing tables and safety code blocks safely before the code ever touches a physical quadcopter. If you would like to run your own tasks, I also added support in the .bat and .sh files to build code for the simulation (flag=sim), user task code (flag=user), and actual drone upload code (no flags). Example MacOS Commands: ./build.sh sim ./build.sh user ./build.sh This makes it so that I don’t have to constantly modify code to run either the user tasks or simulation code, instead using a flag. Overall, this RTOS is not done yet, however, I plan to add the rest of the scheduled tasks later today, and fixing the sole bug keeping this simulation back! I expect a full ship to be comming out in the next week or so, along with all ESC, RM, and TM code complete!"}, {"post_id": 30963, "ts": "2026-07-18T23:42:07Z", "hours": 9.2461, "text": "I’ve been doing a lot of debugging for the RTOS scheduler inside the simulation environment, and it’s been very difficult for me to identify many bugs in teh core architecture of my tasks. Moving away from Python scripts to a cleaner C++ conditional compilation framework using CMake was supposed to simplify things, but instead, it exposed some nasty architectural bugs in how tasks and context switching interact. There has also been a massive priority inversion and preemption lockup where the CRSF parsing loop completely starves out the lower-priority threads. Also, running a raw sensor calibration loop at boot was forcing thread switches before the OS kernel was even fully initialized, completely corrupting task indexes, throwing null pointer warnings, and leaving half of my PID calculations at zero. Still working on many fixes, but it has been a lot of work (9 hours), but I hope to get the full RTOS with at least bare minimum flight tasks out by tomorrow! The GitHub repo still won’t be fully up-to-date until these structural bugs are figured out, but I plan to push the corrected scheduler files and mock drivers very soon. The screenshot below shows an image of the CRSF task completely dominating, without any processes interrupting it."}, {"post_id": 30245, "ts": "2026-07-17T17:45:35Z", "hours": 9.5911, "text": "I just wrapped up the core architecture of the drone’s flight controller, including mapping out all 7 interrupt methods into a far more optimized RTOS scheduler. The updated version makes use of a FIFO stack, to keep track of nested interrupts. I also protected the main code from data corruption during pendSV switches by enabling and disabling irq in certain areas of vulnerable code. Other small changes to the assembly to save floating point registers as well as better memory allocation was also done in this update. From high-speed IMU sensor integration and state estimation calculations to CRSF packet decoding and DShot motor generation, the essential tasks are fully written and compiled. I’ve officially shifted gears into the testing phase, working on simulated environments to debug DMA transfers, registers, and the flight state machine’s arming sequences. As of now, I am writing python scripts by hand, in order to inject “dummy” values into the GPIO, SPI, and USART registers in order to populate the buffers, and simulate the calculations. As the code is becoming longer and longer, I will try to refactor a lot of the files into smaller more organized portions, to increase readability (often I have a hard time traversing everything). Note: The current code pushed to GitHub isn’t quite the latest since I’m in the middle of troubleshooting a few simulation-specific register bugs, but I wanted to get this update out to meet the 10-hour devlog requirement on Stardance. Everything is moving in the right direction, and having a virtual environment all working means I can safely verify the PID mixer and safety flags before this code ever touches a physical quad. This officially marks the end of both phases 2 and 3, and now its a matter of finishing extra scheduled telemetry tasks (e.g. OSD and EdgeTX logging), but I estimate that the flight controller portion of the code (around 60% of all logic in the drone) will be done between now and Sunday, July 19th! I will also post a much more in depth devlog about how the methods work, as well as an updated README.md on Github ASAP."}, {"post_id": 28703, "ts": "2026-07-15T03:44:43Z", "hours": 1.4603, "text": "To make my hybrid RTOS accessible and easy to test, I designed a modular sandbox task registry system that isolates the core kernel from custom user code. Developers can write standard non-returning tasks in an isolated file ( User_Tasks/user_tasks.cpp ), while the kernel exposes a registration hook that allocates a dedicated 1024-word stack space. This decoupling means anyone can plug in their own cooperative or preemptive tasks, set execution periods or trigger bounds, and run them instantly on our virtual STM32F7 without risking memory corruption or touching the underlying context-switching assembly. For more information on how to make your own tasks refer to the README.md ."}, {"post_id": 28651, "ts": "2026-07-15T01:05:47Z", "hours": 1.0922, "text": "I just updated a few build files and restructured the project, so code and simulation separation would be better. I also added a few executable files (build.sh, run.bat, and run.sh) to easily compile and run the project."}, {"post_id": 28615, "ts": "2026-07-14T23:38:20Z", "hours": 5.5942, "text": "I finally reached a massive milestone with the kernel architecture and got the scheduler firing exactly how it needs to. Even though I thought the RTOS portion was completely wrapped up a bit ago, now it is officially done. I ended up doing a massive revamp on how scheduled tasks execute, routing them through PendSV so that the background worker states get completely backed up and saved by my assembly code just like the preemptive ones. I also cleaned up the initialization API by throwing in an overloaded function to separate timed loops from raw hardware events (the interrupt tasks). Overall most of the testing logic is now gone, and now the system is being more and more focused on the actual drone tasks. On the hardware side of things, I built out the actual drone tasks and the underlying SPI and UART DMA drivers that populate my local data packets. Even though they are not in use right now as all the tasks (which are not fully completed) require the support of each other for full testing. With the core OS completely checked off, the focus is shifting entirely over to the actual flight control logic. Over the next couple of days, I’m going to wrap up the final flight controller tasks, and get the core stabilization algorithms running. Once the flight controller application layer is fully put together, I’m moving straight onto building out complete simulations for the receiver, transmitter, and finally the ESC modules to get the whole drone network interacting together!"}, {"post_id": 27365, "ts": "2026-07-12T21:17:48Z", "hours": 3.8289, "text": "I finally finished the most difficult part of the project so far and got a hybrid cooperative/preemptive scheduler running from scratch. After a ton of debugging with the assembly memory layout, the core RTOS kernel shell is officially stable, verified inside the Renode simulator, and completely ready to handle flight data. The architecture divides the CPU’s brain into two execution pathways to maximize calculation speeds while keeping latency near zero. Standard background tasks, like handling low-priority peripheral updates, run sequentially inside a cooperative loop based on their relative priority. They execute and then drop out without wasting an overhead time. But for high-priority hardware event such as a critical radio packet arriving over UART or raw sensor data from the IMU, the system completely bypasses the standard queue. It pulls a physical hardware lever (PendSV) that forces an instant stack swap. When an interrupt task fires through PendSV, the CPU pauses the background scheduled loop, and my assembly code packs up the core registers, saves that exact memory address to RAM, and hot-swaps the Process Stack Pointer to launch the interrupt task. Right now, there is just a dummy delay loop inside the interrupt task to visually show the execution break in the console logs. Once it finishes printing, it hits a yield function that throws the assembly switch backward, pops the background registers, and hands control straight back to the flight loop. The repository currenly has a lot of diagnostic test code because I needed to prove the pointer indirection and stack-faking logic worked without blowing up the memory alignment. Now that the plumbing is completely verified, the next step is to strip out the test code and start writing the actual flight infrastructure. I am moving straight into coding the PID control loops, signal mixers, Kalman filters, and live motor generation."}, {"post_id": 26996, "ts": "2026-07-12T03:54:25Z", "hours": 2.8228, "text": "I finally added minimum task scheduling for the RTOS. I had originally designed a simple kernel to create a buffer of scheduled tasks in QEMU, but after learning that the simulation didn’t actually support the specific MCU that my friend and I are using for the real drone, I had to pivot. I switched over to using STM32CubeMX for the actual bare-metal configuration and Renode to handle running the emulation. Right now, the kernel just executes a task based on a basic timing loop and priority, waits for it to completely finish, and then moves on to the next task. To be honest, it isn’t super useful yet because it only covers tasks in what I call the “scheduled zone” of the drone. This includes background stuff like blackbox flight data management, but it leaves out the most critical parts like the PID control loops and streaming real-time UART data from the IMU. Those features need to fire their own asynchronous interrupt signals at the highest possible hardware priority so they can instantly pause the optional background tasks and execute the critical code that actually keeps the drone stable and flying. Next up, I need to write a short piece of assembly to handle saving the current CPU state and registers of whatever task is currently running when an interrupt hits. It shouldn’t be too bad since it will only take about 30 lines of code. I know I haven’t been posting devlogs for the past couple of weeks even though I’ve been grinding on this, but that’s mostly because we spent a ton of time initially planning out the architecture of the drone. We wanted to map out the software boundaries early so my friend and I could go our separate ways working on different systems without having massive merge conflicts later on."}]...
|
Title: 200 MPH Drone RTOS by @Guagyyy | Stardance
Title: 200 MPH Drone RTOS by @Guagyyy | Stardance
Devlogs:
I finally added minimum task scheduling for the RTOS. I had originally designed a simple kernel to create a buffer of scheduled tasks in QEMU, but after learning that the simulation didn’t actually support the specific MCU that my friend and I are using for the real drone, I had to pivot. I switched over to using STM32CubeMX for the actual bare-metal configuration and Renode to handle running the emulation. Right now, the kernel just executes a task based on a basic timing loop and priority, waits for it to completely finish, and then moves on to the next task. To be honest, it isn’t super useful yet because it only covers tasks in what I call the “scheduled zone” of the drone. This includes background stuff like blackbox flight data management, but it leaves out the most critical parts like the PID control loops and streaming real-time UART data from the IMU. Those features need to fire their own asynchronous interrupt signals at the highest possible hardware priority so they can instantly pause the optional background tasks and execute the critical code that actually keeps the drone stable and flying. Next up, I need to write a short piece of assembly to handle saving the current CPU state and registers of whatever task is currently running when an interrupt hits. It shouldn’t be too bad since it will only take about 30 lines of code. I know I haven’t been posting devlogs for the past couple of weeks even though I’ve been grinding on this, but that’s mostly because we spent a ton of time initially planning out the architecture of the drone. We wanted to map out the software boundaries early so my friend and I could go our separate ways working on different systems without having massive merge conflicts later on.
I finally finished the most difficult part of the project so far and got a hybrid cooperative/preemptive scheduler running from scratch. After a ton of debugging with the assembly memory layout, the core RTOS kernel shell is officially stable, verified inside the Renode simulator, and completely ready to handle flight data. The architecture divides the CPU’s brain into two execution pathways to maximize calculation speeds while keeping latency near zero. Standard background tasks, like handling low-priority peripheral updates, run sequentially inside a cooperative loop based on their relative priority. They execute and then drop out without wasting an overhead time. But for high-priority hardware event such as a critical radio packet arriving over UART or raw sensor data from the IMU, the system completely bypasses the standard queue. It pulls a physical hardware lever (PendSV) that forces an instant stack swap. When an interrupt task fires through PendSV, the CPU pauses the background scheduled loop, and my assembly code packs up the core registers, saves that exact memory address to RAM, and hot-swaps the Process Stack Pointer to launch the interrupt task. Right now, there is just a dummy delay loop inside the interrupt task to visually show the execution break in the console logs. Once it finishes printing, it hits a yield function that throws the assembly switch backward, pops the background registers, and hands control straight back to the flight loop. The repository currenly has a lot of diagnostic test code because I needed to prove the pointer indirection and stack-faking logic worked without blowing up the memory alignment. Now that the plumbing is completely verified, the next step is to strip out the test code and start writing the actual flight infrastructure. I am moving straight into coding the PID control loops, signal mixers, Kalman filters, and live motor generation.
I finally reached a massive milestone with the kernel architecture and got the scheduler firing exactly how it needs to. Even though I thought the RTOS portion was completely wrapped up a bit ago, now it is officially done. I ended up doing a massive revamp on how scheduled tasks execute, routing them through PendSV so that the background worker states get completely backed up and saved by my assembly code just like the preemptive ones. I also cleaned up the initialization API by throwing in an overloaded function to separate timed loops from raw hardware events (the interrupt tasks). Overall most of the testing logic is now gone, and now the system is being more and more focused on the actual drone tasks. On the hardware side of things, I built out the actual drone tasks and the underlying SPI and UART DMA drivers that populate my local data packets. Even though they are not in use right now as all the tasks (which are not fully completed) require the support of each other for full testing. With the core OS completely checked off, the focus is shifting entirely over to the actual flight control logic. Over the next couple of days, I’m going to wrap up the final flight controller tasks, and get the core stabilization algorithms running. Once the flight controller application layer is fully put together, I’m moving straight onto building out complete simulations for the receiver, transmitter, and finally the ESC modules to get the whole drone network interacting together!
I just updated a few build files and restructured the project, so code and simulation separation would be better. I also added a few executable files (build.sh, run.bat, and run.sh) to easily compile and run the project.
To make my hybrid RTOS accessible and easy to test, I designed a modular sandbox task registry system that isolates the core kernel from custom user code. Developers can write standard non-returning tasks in an isolated file ( User_Tasks/user_tasks.cpp ), while the kernel exposes a registration hook that allocates a dedicated 1024-word stack space. This decoupling means anyone can plug in their own cooperative or preemptive tasks, set execution periods or trigger bounds, and run them instantly on our virtual STM32F7 without risking memory corruption or touching the underlying context-switching assembly. For more information on how to make your own tasks refer to the README.md .
I just wrapped up the core architecture of the drone’s flight controller, including mapping out all 7 interrupt methods into a far more optimized RTOS scheduler. The updated version makes use of a FIFO stack, to keep track of nested interrupts. I also protected the main code from data corruption during pendSV switches by enabling and disabling irq in certain areas of vulnerable code. Other small changes to the assembly to save floating point registers as well as better memory allocation was also done in this update. From high-speed IMU sensor integration and state estimation calculations to CRSF packet decoding and DShot motor generation, the essential tasks are fully written and compiled. I’ve officially shifted gears into the testing phase, working on simulated environments to debug DMA transfers, registers, and the flight state machine’s arming sequences. As of now, I am writing python scripts by hand, in order to inject “dummy” values into the GPIO, SPI, and USART registers in order to populate the buffers, and simulate the calculations. As the code is becoming longer and longer, I will try to refactor a lot of the files into smaller more organized portions, to increase readability (often I have a hard time traversing everything). Note: The current code pushed to GitHub isn’t quite the latest since I’m in the middle of troubleshooting a few simulation-specific register bugs, but I wanted to get this update out to meet the 10-hour devlog requirement on Stardance. Everything is moving in the right direction, and having a virtual environment all working means I can safely verify the PID mixer and safety flags before this code ever touches a physical quad. This officially marks the end of both phases 2 and 3, and now its a matter of finishing extra scheduled telemetry tasks (e.g. OSD and EdgeTX logging), but I estimate that the flight controller portion of the code (around 60% of all logic in the drone) will be done between now and Sunday, July 19th! I will also post a much more in depth devlog about how the methods work, as well as an updated README.md on Github ASAP.
I’ve been doing a lot of debugging for the RTOS scheduler inside the simulation environment, and it’s been very difficult for me to identify many bugs in teh core architecture of my tasks. Moving away from Python scripts to a cleaner C++ conditional compilation framework using CMake was supposed to simplify things, but instead, it exposed some nasty architectural bugs in how tasks and context switching interact. There has also been a massive priority inversion and preemption lockup where the CRSF parsing loop completely starves out the lower-priority threads. Also, running a raw sensor calibration loop at boot was forcing thread switches before the OS kernel was even fully initialized, completely corrupting task indexes, throwing null pointer warnings, and leaving half of my PID calculations at zero. Still working on many fixes, but it has been a lot of work (9 hours), but I hope to get the full RTOS with at least bare minimum flight tasks out by tomorrow! The GitHub repo still won’t be fully up-to-date until these structural bugs are figured out, but I plan to push the corrected scheduler files and mock drivers very soon. The screenshot below shows an image of the CRSF task completely dominating, without any processes interrupting it.
I’ve spent the last 20 hours of coding basically staring at bare-metal memory allocations and tracking down why the drone’s context switcher was triggering CPU drops under the Renode simulation environment. Moving away from manual Python injection scripts to a cleaner C++ conditional compilation framework using CMake was supposed to simplify the testing layout, but instead, it exposed structural design flaws in how the scheduler kernel boots up. Running a multi-sample sensorCalibration() routine at cold boot was forcing hidden task yields before the OS kernel was fully mapped out, which was throwing unmapped register address errors and wiping out index-0 entries. To solve this, I decoupled the entire state machine sequence so that hardware allocations, peripheral registers, and core tracking counters now clear before any operational loops drop into the registry. I also added a critical rtosStarted gatekeeper flag to yieldCurrentTask() so calibration math runs cleanly in sequence without triggering early PendSV handler switches. On top of that, the task stack pointers are completely realigned. The assembly context swapper now maps a precise 32-word boundary allocation utilizing 0xFFFFFFFD as a basic exception return code, which completely eliminates the data corruption that was misaligning our Process Stack Pointer. With the fundamental kernel stabilized, I shifted entirely into clean architecture organization. The massive, cluttered code blocks have been split up into independent tracking files (BufferPopulation.cpp, Tasks.cpp, and SimInjector.cpp). High-speed SPI reads for the IMU, UART ring buffers for decoding CRSF radio channel frames, battery ADC sampling, and DShot600 motor output mixers are now fully broken out and functional. There is still a nagging preemption lockout issue inside the simulator where a single interrupt task attempts to starve out the other concurrent loops during a millisecond window, but the baseline operating system is locked in, meaning I can confidently verify the PID flight mixing tables and safety code blocks safely before the code ever touches a physical quadcopter. If you would like to run your own tasks, I also added support in the .bat and .sh files to build code for the simulation (flag=sim), user task code (flag=user), and actual drone upload code (no flags). Example MacOS Commands: ./build.sh sim ./build.sh user ./build.sh This makes it so that I don’t have to constantly modify code to run either the user tasks or simulation code, instead using a flag. Overall, this RTOS is not done yet, however, I plan to add the rest of the scheduled tasks later today, and fixing the sole bug keeping this simulation back! I expect a full ship to be comming out in the next week or so, along with all ESC, RM, and TM code complete!
I just finished expanding the RTOS architecture, filling out all of the scheduled background tasks to handle real-time flight telemetry, peripheral hardware, and terminal configuration. On the telemetry side, I built out telemetryTX to package battery, status, and GPS data into standard CRSF frames over UART, alongside an NMEA gpsParser that decodes $GNGGA and $GNRMC sentences for live location fixes. I also made powerManagement into its own standalone task so ADC voltage and current metrics can feed into the failsafe logic and telemetry concurrently. To make bench testing and tuning significantly easier, I added usbCLI over USART1, giving me a full interactive shell to tweak PID gains (Kp, Ki, Kd), dump raw IMU data, and inspect hardware states on the fly without needing to reflash firmware. To keep the physical quad safe and responsive during flight, I added updatePeripherals for LED status patterns and buzzer warnings, along with a dedicated Independent Watchdog (IWDG) task running as a low-priority fail-safe to trigger hardware MCU resets if the scheduler ever freezes. On the project structure side, CMake now routes all output binaries straight into a clean ./bin/ directory so nobody has to compile the source manually just to run the .elf target in Renode. I also introduced a -DENABLE_DEBUG flag, allowing me to cleanly toggle between complete USART log prints across every loop or a blank terminal environment meant purely for the CLI shell. While all the background subsystems and scheduled task priorities are fully mapped out, I’m currently figuring out a few lingering RTOS bugs—specifically around stack allocation, causing stack overflow flags on certain scheduled tasks, along with scheduling starvation where context switching isn’t releasing task blocks properly. Because I want to ensure the scheduler kernel is 100% complete before pushing broken stack frames to the main branch, the GitHub repository will be updated with the complete, bug-fixed code later today. Everything is moving in the right direction, and getting these background tasks finalized brings me one step closer to full flight hardware deployment!
1. Fixing the Stack Overflows at Boot After an entire 25-hour debugging period across 4 days, the RTOS kernel is finally done (for the scheduled tasks). I tracked down a silent bug where several critical scheduled tasks—like powerManagement , lowLevelFailSafe , and telemetryTX —were crashing the MCU on boot. The issue came down to a boot-time dependency lock: tasks were trying to poll hardware registers (like UART TX flags) and read shared drone state variables before the peripherals or producer tasks had time to initialize on Tick 0. By adding an initial yieldCurrentTask() right at the top of these methods, Task Phase Alignment was officially added. This gives the hardware a full cycle to stabilize, preventing buffer overflows and eliminating the cascading task state corruptions that were locking up the scheduler. 2. Custom Stack Sizing & Real-Time Guard Checks Alongside the scheduler fix, I pushed major upgrades to memory safety and task management. Instead of assigning a static stack array to every task, I transitioned to dynamic per-task stack allocations during initialization ( new (std::nothrow) ). Heavy string-parsing and math tasks get larger stacks, while simple toggle tasks stay lightweight. To catch memory issues before they corrupt the heap, I implemented a custom dual guarding system: 0xDEADBEEF is appended at the bottom of the stack to catch standard stack overflows, while a new 0xBEEFCAFE canary value is written to the very top index ( stackSizeWords ) to instantly flag memory breaches in the SysTick_Handler . Furthermore, I refactored powerManagement to use ADC2 in Circular DMA Mode, writing battery telemetry directly to RAM in the background for zero CPU overhead. 3. Transitioning to Walksnail Avatar HD Looking ahead, my and my friend are officially transitioning our existing analog video setup over to a fully integrated Walksnail Avatar HD digital ecosystem. Rather than keeping my custom telemetry task ( telemetryTX ) with heavy string formatting over raw UART, Walksnail allows me to stream standard MSP (MultiWii Serial Protocol) DisplayPort frames straight to the VTX. The Walksnail system will serve as our primary onboard logging source, giving us full OSD telemetry, high-framerate HD video, and precise blackbox data logging. With the RTOS core now stable and non-blocking, our next focus shifts toward “premium” flight controller features, e.g. including custom RC stick expo curves, an expanded USB CLI, and an integrated simulator interface.
Over the last few days, I wrapped up two major tasks for the flight controller’s core sensor and telemetry stack: the on-screen display (OSD) renderer and the BMP390 barometer subsystem. The OSD engine is now fully hooked up to the state system, giving real-time visual downlinks for critical metrics like flight battery voltage, active flight modes, and height statistics over UART. To keep the execution completely non-blocking, all frame updates are dispatched asynchronously, preventing rendering delays from hindering the performance of the high-frequency control loops. On the barometer side, I implemented altitude tracking using Bosch’s BMP390 sensor over SPI with non-blocking DMA burst transfers. In the 50Hz task loop, incoming 24-bit raw pressure and temperature bytes are assembled and passed through the hypsometric formula to calculate smooth, relative height above ground level (AGL). Although the barometer task is a bit flawed due to floating point register stack errors with the header and end canary values, they don’t seem to be affecting the system in anyway (nor is any data being corrupted). I will find a way to fix these issues before the next commit, as well as the race condition in the interrupt tasks in the next Github commit. After that, it is just system polish and extensive testing before the RTOS will be complete!
Major Architecture Upgrade : OSD, Betaflight Rates & Build System Refactor 1. OSD, DMA + SYS First off on the hardware side, I added native MSP-based OSD support for Walksnail video transmitters, built the SPI barometer driver for altitude tracking, and spun up a low-level health task that constantly monitors MPU registers and stack usage in the background. On top of that, I finally fixed the DMA stream conflicts (mainly in STMCubeMX) between TIM1 DShot motor outputs , ADC1, and SPI peripherals, so everything runs without collisions now. 2. SYS Health + Debugging I also implemented a few other low level tasks, allowing me to monitor system health, based upon ram usage and storage used. This task prints out the amount at which each tasks stack is being used, allowing me to effectively debug whether a task was actually overflowing, vs an unrestricted read/write. Furthermore, the original canary values that I used, were completely replaced as they in fact were causing some of the “stack overflow” bugs (via unrestricted reads/write every 1 ms in SysTick_Handler ). 3. Betaflight Rates + CLI Update For flight feel, I implemented Betaflight’s Actual Rates algorithm with custom expo curves, so stick inputs map to target angular velocities with center-stick precision. I also completely separated serial communications by moving the interactive CLI to USART1 (accessible via nc -C localhost 1234 in terminal) and pushing system logs to USART3. Additionally, I removed the old telemetryTX task because its unauthorized reads/writes were completely breaking the RTOS scheduler, and expanded the CLI with a ton of commands for live sensor readings and more PID tuning. Speaking of which, I am planning to create a persistent file in /bin/ , allowing for rates to be stored between runs, rather than being reset each during runtime, and having to be manually configured through the CLI. 4. Overhauled Building Workflow Finally, I overhauled the whole developer workflow and build automation setup. The build.sh and build.bat scripts now auto-configure custom CMake profiles and generate a full disassembly file in /bin/ after every build for fast low-level debugging, while run.sh and run.bat automatically launch the right terminal windows on launch. 5. Future Additions: I’m planning to build a closed-loop Renode simulation matrix to stream hardware data into every peripheral externally, letting me run 100% real production code during SIL testing! For this, I will utilize the currently blank simulate.py as well as certain commands in simulate.resc to create properly formatted dynamic buffers(which are not directly injected into the code), allowing me to properly test the DMA drivers, and many of the memory management helpers.
This week was heavily focused on the fine tuning and organization of the RTOS. I spent numerous hours of research and untangling environment setups. I originally tried to build out a complete framework for the drone code without relying on any simulation code, but Renode’s restrictions, specifically with its ability to perform DMA requests, quickly made it clear that path was impossible. To fix this I’m looking into picking up a dev board and a Raspberry Pi so I can test and debug everything on an actual MCU before finally moving the codebase over to the drone. Even though the git won’t look a whole lot different and not a lot of actual code changed, getting these configs finalized (especially in STM32CubeMX) in was a huge step forward for the project. I expect to commit the next version of the code either today or tomorrow, with improvements specifically in TelemetryTX, BlackBoxLogging, and a few other minor changes!
1. Reworking the DMA Flow for Speed So, a lot has been going on lately, starting with a massive rework of the entire DMA flow. The functions are now entirely populated by circular DMA, which is a huge upgrade for the system’s overall performance. This architectural change allows for completely non-blocking, high-frequency calls, hitting response times as fast as 0.03 milliseconds. It basically means the whole data pipeline is significantly faster, and much more responsive than it was in previous versions. 2. Standardizing Ring Buffers and Mock Injectors To make everything more reliable, the DMA now follows a very specific and predictable pattern for both scheduled and interrupt tasks. Everything relies on ring buffers now, whether they are being injected by actual hardware (or simulated) DMA or by my custom simulation scripts. I also reworked the mock injectors so they no longer just return a pre-formatted packet. Instead, they write directly into the ring buffer, which lets me test the exact same parsing pipeline in software, simulating the hardware flow almost exactly like Renode (if only they would ever fix that USART DMA bug…). 3. Assembly BX LR Bug + STMCubeMX Clock PLL I also finally solved the long term BX LR return bug that I literally spent over 20 hours trying to find. Whenever tasks used the FPU or had slightly larger stacks, the return address in the r0 register would just get completely corrupted by the extra data. I fixed this by storing the return address in a dedicated uint value instead of blindly trusting the registers to hold it. That fix alone allowed me to safely re-add telemetryTX and make a bunch of other function logic much more robust. On top of that, I went into STM32CubeMX and reworked the clock PLL manually (it took over 3 hours to solve by hand). By feeding in a 25 MHz HSE clock, I managed to unlock the MCU’s internal clocks to run at their full 216 MHz.I also took some time to clean up the codebase to improve overall readability and commenting. 4. DMA Interrupts for Safe Parsing Another feature is that DMA now triggers interrupts when the ring buffers hit exactly halfway and when they are fully populated. This gives me the time to parse all the incoming values safely without having the risk about data getting overwritten by the next DMA pass before I am done reading it. I set up the IRQ handlers in the code to call the interrupt methods automatically, which ensures the CPU stays completely unblocked and free to handle other flight control tasks almost all the time (overall decreasing headroom). 5. Current Status: NVIC Bug Sadly, the code is actually not functional right now because the NVIC and IRQ pipeline is malfunctioning and just refusing to call the interrupts for reasons I cannot figure out yet. Because of this, I am holding off on pushing the code until I can track down the bug, give everything a final polish, and run some benchmark testing (since I don’t want to commit broken code). Also, sorry for promising a commit a day or two after my last devlog. I got super busy, especially with vacation, but I will try my best to get this sorted. Depending on how long it takes to figure out this NVIC issue, the next commit might drop anywhere from tomorrow to a few weeks from now.
Complete RTOS Overhaul, Circular DMA Pipelines, and CPU Abort Fixes This update focuses on fine-tuning the RTOS, organizing the scheduler, and rewriting microcontroller memory handling. Renode’s simulated DMA restrictions make software-only pipeline testing nearly impossible, so I plan to buy a physical dev board and Raspberry Pi to validate on silicon. While the Git diff might not look massive, the architecture has evolved from a blocking system to a true preemptive RTOS with precise polynomial timing. 1. Reworking DMA Flow & Standardizing Ring Buffers Sensor and receiver data pipelines are now driven by circular DMA, enabling non-blocking, high-frequency transfers with response times as fast as 0.3 ms (without printToUSART enabled). Everything now relies on ring buffers. Instead of generating complete packets instantly, mock injectors stream bytes directly into the buffers while updating the simulated NDTR register to mirror hardware behavior. if ( byteIdx >= frameLen ) { byteIdx = 0 ; } crsfRingBuffer [ head ] = frameBuf [ byteIdx ++ ]; head = ( head + 1 ) % CRSF_RING_BUFFER_SIZE ; currentBoardConfig . crsf_dma_stream -> NDTR = CRSF_RING_BUFFER_SIZE - head ; Feeding bytes incrementally moves the write head gradually, ensuring the simulation mimics a physical UART and allowing population functions to safely pull data within interrupt locks. 2. DMA Interrupts for Safe Parsing To prevent data overwrites, DMA streams trigger interrupts at the halfway (HTIE) and full-transfer (TCIE) points to queue tasks. Because registers like LISR are read-only in hardware, I implemented a software mock flag system (mock_LISR) for simulation: extern "C" void DMA1_Stream0_IRQHandler ( void ) { #ifdef SIMULATION uint32_t flags = mock_LISR ; mock_LISR = 0 ; #else uint32_t flags = DMA1 -> LISR ; #endif if ( flags & DMA_LISR_HTIF0 ) { DMA1 -> LIFCR = DMA_LIFCR_CHTIF0 ; decideNextInterruptTask ( & taskControlBlocks [ 1 ]); } } Functions safely extract data with interrupts disabled, ensuring the CPU never blocks waiting for peripheral transfers. 3. Assembly Bugs & CPU Aborts Debugging nested hardware interrupts exposed massive faults: The context-switching bug: FPU usage or large stack frames corrupted the return address, causing the CPU to execute BX LR with garbage data. Fixed in PendSV_Handler.S by explicitly storing excReturn inside the TaskControlBlock rather than relying on stacked registers. Second, a 0x00000000 Null Return Crash: Scheduled tasks attempted to return natively, popping 0x00000000 from the zero-initialized Link Register and causing a fetch fault. Every task now runs inside an infinite while(true) loop calling yieldCurrentTask() . 4. Clock PLLs & Hardware Re-routing After configuring the STM32CubeMX PLL for a 25 MHz HSE clock, the MCU runs at its full 216 MHz. I added a standardized initSystemGPIOClocks() function to enable peripheral clocks consistently. I also moved motor 3 from TIM1 to TIM4, synchronizing it with the 216MHz clock and freeing up a TIM1 DMA stream exclusively for the upcoming BlackBox logging. Future Updates With the core RTOS stabilized, development shifts to flight-facing systems: hooking the SPI pipeline to the video overlay for live OSD goggle telemetry, adding permanent flash storage for PID tunes/configs, exposing MCU controls via CLI, supporting programmable transmitter bind buttons, building a desktop GUI, and using the freed TIM1 DMA for BlackBox logging. Below, I have attached a screenshot of every single task working, and outputting values in the simulation, something that wasn’t possible for the interrupt tasks until now.
1. CLI Upgrades and Channel Mapping Over the past 5 days, I knocked out some major quality-of-life upgrades for the flight controller. I added customizable channel mapping for CRSF directly through the CLI. By utilizing a combination of references and pointers, I was able to point a volatile alias to certain channel mappings, allowing for completely customizable CRSF channels. While I was in the CLI logic, I also added the ability to configure custom IMU orientations around the z-axis, making it way easier to mount the board in different directions without having to recompile the firmware. 2. DMA Pipeline Fixes and Baro Optimization A big chunk of this session went into debugging and refactoring the hardware data pipelines. I adjusted the ADC population pipeline in order to fix some stream parsing issues, and gave the barometer a massive overhaul. The baro now uses a non-blocking, non-circular DMA setup that relies on a semi-interrupt-driven task call rather than a continuous loop. This enabled me to yield in the middle of the function, and call back later as soon as DMA is finished transferring. I also fixed a massive bug in the DMA setup: the DMA_SxCR_HTIE and DMA_SxCR_TCIE flags were accidentally enabled for the GPS and OSD ring buffers, which would have crashed the whole RTOS by firing unhandled interrupts, causing default HAL and IRQ handlers to run. 3. Walksnail Two-Way Communication Finally, I built out the respondToVTX task to get the drone properly communicating with the Walksnail VTX. Instead of just blindly sending video data out, this sets up true two-way communication over asynchronous UART. By writing a persistent byte-by-byte state machine, the flight controller can now safely parse incoming requests from the VTX without dropping half-packets, allowing me to send back live stick positions and armed status for the OSD menus. The only thing left to do now is handle persistent CLI storage, the logToBlackBox task, integrating the semi-interrupt pipeline with telemetryTX and the OSD, and a few other system tweaks. After that the RTOS will be 100% ready to fly the actual drone.
1. Scheduler Hardening and Task Discovery Spent part of this session making the RTOS scheduler itself more robust. I added a findTaskByName() function so interrupt-driven task lookups happen dynamically instead of relying on hardcoded task indices, which was a fragile setup just waiting to break the moment task registration order changed. Alongside that, I wrapped every one of those lookups with lambdas that throw a proper warning if a task can’t be found, so a missing task fails loudly instead of silently dereferencing a null pointer somewhere downstream. 2. Blocking vs Non-Blocking Scheduled Tasks After a lot of painful debugging, I traced a string of issues (including interrupt tasks silently failing to fire and scheduled tasks stepping on each other) back to non-blocking statements I’d introduced inside scheduled tasks in the previous devlog. I ended up taking those out and reverting scheduled tasks fully back to blocking, which is genuinely what the scheduled zone was designed for in the first place: tasks that don’t need to run in polynomial time and can safely block without putting the drone at risk of crashing. Once that was sorted, I converted the raw USART byte-pushing into a blocking DMA system instead, so streaming is handled by DMA hardware rather than manually pushed byte-by-byte over USART. 3. Flight Loop Refactor and VTX Communication On the flight logic side, I refactored flightLoop() to use lambdas and a state machine so I would never have to yield in the middle of my tasks (which was used previousely for zeroing motor outputs). I also converted the error handling into a proper state machine, so different types of warnings can be caught and handled distinctly instead of lumping every issue into one path, and turned on full debug printing whenever the system is running. Last but not least, I built out a dedicated injector for respondToVTX so I can properly test and simulate VTX communication going forward. 4. Real Hardware Testing Since, I am almost 100% done with the RTOS I bought two NUCLEO-F756ZG’s which will serve as testing the 100% production code rather than the simulation version. I bought two so that one of the boards will be running the real RTOS code, testing DMA reading from USART, SPI, and emitting real motor signals, while the second will be emulating all of my peripherals. When the boards come, if the code does work, it will also mean that the real PCB’s will also work when my friend finishes with them. 5. Next Steps As of now there are a few issues with the double preempt system (for the interrupt tasks) I designed a while back, so I will need to debug that before they arrive. Right now before the boards arrive, I will be finishing up the RTOS blocking DMA pipelines (stripping out IRQ, removing NVIC etc. for scheduled tasks), and performing a bunch of baseline testing in order to prove that the RTOS is capable of flying an actual drone!
For the past couple weeks I have been mostly refining small bugs, which were originally rendering the RTOS usless, as well as refactoring the code for simplicity rather than elegancy. 1. Transition to Actual Hardware Renode is great for simulation, but it ended up hiding a bunch of race conditions in the population methods and the main scheduler that led to no code actually running during the IRQ handler calls. I spent a lot of time securing those resources and finally got the scheduler mostly finished up. Also, I decided to just take out the double preempts entirely since they were adding way too much complexity for absolutely zero speed benefits in practice (plus they were creating detrimental but rare race conditions). 2. Code Refactor To make things run a bit more consistent, I restructured how the control loops operate. I ended up merging the dShotGeneration task with the parent IMU control loop, so now everything from reading the sensors to pushing motor commands happens in one clean sequence (rather than including an unnecessary preempt). I also built out a brand new CRSF control loop to handle all the radio parsing and state machine updates in its own dedicated space (just for consistency). Lastly, while doing a final pass on the code, I realized that in my dShotGeneration helper, I had forgot to scale the values by a factor of 1/2000, as the inputs require the value to be between 0 and 1 (not 0 and 2000). 3. Final DMA Iteration The biggest relief was finally getting rid of the old blocking USART system. I finally transitioned away from manually handling the streaming by polling flags in a loop, which was tying up the processor way more than it should have. Everything has been converted over to a blocking DMA system, so the hardware can just handle all the memory transfers in the background while the CPU focuses on actually keeping the drone in the air. Overall, I think that this will be the final iteration of the RTOS DMA pipeline, as now that it is solid and works with all the edge cases, theres no need to change it. 4. Timeline With almost all the major bugs fixed, I am going to ship the project! While it is not 100% done, it will likely be as close as it will get during the timeframe of the Stardance hackathon, and with it so close, theres no reason not to ship. Anyway, I will keep the source as the main project rather than a release, so if I do end up fixing any major bugs, they will get patched either before or during project review (besides most of these bugs are only detectable on actual hardware). I will most likely finish the RTOS in the next couple weeks (by the end of October), and will finish the drivers for the ESC and RM by latest end of November (for more timing refer to the README). Thanks to everyone who supported me throughout this project (hopefully me and my friend can get this drone flying in another Hack Club Hackathon!).
Although I haven’t been able to make much progress on the project due to school over the past weeks I did manage to make some substantial project mostly with the scheduler, allowing for fairly good performance on my STM Nucleo boards, rather than it just crashing instantly. 1. Issues with the Old Design The flight controller’s RTOS scheduler wasn’t working under real hardware timing because global variables like currTaskIndex, topOfStack, and excReturn were being modified from multiple entry points simultaneously. Yield calls, interrupt handlers, and the main task-selection logic were all making independent writes to the same shared task control blocks. Whenever a hardware interrupt fired mid-write, stack pointers and exception return values were saved into the wrong taskControlBlocks slot. This created edge cases where preempted tasks were silently double-queued, state tracking completely desynchronized, and time-critical hardware events were dropped during flight. 2. Centralizing Context Switches in PendSV To eliminate these race conditions, all state-selection decisions were moved out of individual execution contexts and consolidated into decideNextTask(), which now runs exclusively inside the PendSV assembly handler. Functions like yieldCurrentTask(), decideNextInterruptTask(), and decideNextScheduledTask() no longer touch global scheduler state or choose which task runs next; they simply update local status flags like TaskState::BLOCKED or TaskState::READY inside brief __disable_irq() critical sections and trigger PendSV using SCB_ICSR_PENDSVSET_Msk. When PendSV fires, decideNextTask() saves outgoingSP and outgoingExcReturn to the active block, sets RUNNING tasks to READY, and runs a two-pass check over taskControlBlocks[]—evaluating high-priority TaskType::INTERRUPT tasks first, then TaskType::SCHEDULED tasks, and falling back to index 0 for idle. Since PendSV is the only place allowed to modify currTaskIndex, concurrent state corruption is structurally impossible.
I spent the past week fixing timing issues on the hardware and getting the simulation environment back into a usable state. Although it isn’t 100% yet, I managed to fix a lot of underlying bugs causing the program to fail on actual hardware. Serial Communication and DMA The biggest issue was that manual USART transfers were completely blocking the system. Printing alone was taking around 95 percent of the total execution time. This was destroying the preempt speed and causing weird timing bugs across the board. I rewrote the USART printing logic to offload everything to a background circular DMA task instead. While I was working on the serial connections, I also fixed the UART mapping bugs and moved all logging over to UART4 so it stops fighting with the GPS module on USART3. I also went through stm32f7xx_it.c and fixed the rest of the extern “C” methods. They were previously commented out, which was silently causing their respective DMA HALs to fail. Moving them to the correct user code sections fixed the issue entirely. Simulation Environment and Tooling On the software side, the simulation startup in the HAL was broken and preventing the virtual boards from properly configuring and running. I fixed the initialization sequence so the simulations actually boot correctly now. To make starting the environment even easier for new users, I updated both the run.sh and run.bat scripts with installers that automatically download Renode. This skips the manual installation step completely and gets the simulation running much faster.
Ships:
Phase 1 (The Custom RTOS Kernel) I am building a custom FPV drone from scratch with my friend in an attempt to achieve 200 mph . At those speeds, standard super loops are far too slow, as a single microsecond of lag means the drone travels feet before making a PID correction. To solve this, I built a custom, hybrid cooperative/preemptive Real-Time Operating System (RTOS) from scratch for the ARM Cortex-M7 (STM32F7)! What Was Challenging? The absolute hardest part of this phase was writing the low-level assembly context switcher ( PendSV_Handler.S ). Hacking the ARM Cortex-M7 registers to physically hot-swap stack pointers ( PSP ) mid-execution without crashing the CPU or corrupting the program state was a massive headache. I had to ensure that when an asynchronous preemption event fires, the assembly code perfectly preserves the execution registers ( R4-R11 plus the hardware-stacked registers), jumps to the high-priority task, and then seamlessly restores the background task right where it left off. Getting the compiler-enforced task overloading working so the kernel cleanly separates periodic tasks from raw interrupts was another huge hurdle, but it makes the whole codebase infinitely more robust. Want to Test It or Write Your Own Tasks? You don’t need physical hardware to watch this run! I’ve packaged the entire project with a Renode simulation script. You can run the interactive emulator with a single command to see the preemption scheduler hijack our counter task live, or you can jump into the user sandbox file and write your own custom tasks. Check out the GitHub Repository to Run the Demo! The README has a quick 5-minute setup guide to get you compiling and simulating your own code in no time.
200 MPH Drone RTOS: How it went Simulation to Silicon! When I published the first major update for this project at the 15-hour mark, I essentially had a proof-of-concept. I had managed to write a custom hybrid cooperative/preemptive scheduler and get an ARM Cortex-M7 (on the STM32f756VGTx) assembly context switcher functioning inside the Renode simulator. Although this looked like a massive leap, the project had barely started. Over 100 hours of development have gone into this project since then. The transition from a simulated kernel to a bare-metal flight controller capable of keeping a 200 MPH drone in the air required stripping the system down to its bare components, rewriting the memory architecture, and debugging some of the most frustrating hardware faults I have ever encountered-especially whenever the project just crashed, leaving me no traces as to what went wrong. Software Limitations The biggest turning point was realizing that software simulation can only take you so far. Renode is an amazing tool, but it hid a massive amount of race conditions and timing flaws that only exposed themselves when I finally flashed the code to physical STM32F756 Nucleo board. Sometimes, the MCU would have to reboot every 2 seconds. I spent dozens of hours tracking down massive architectural bugs. One of the worst was a context-switching fault where floating-point math was corrupting the return address in the CPU registers, causing the processor to execute raw garbage data. To fix this, I had to completely restructure the boot sequence and overhaul the memory management. I moved away from static arrays to a dynamic per-task stack allocation system, and implemented a dual-guard memory system. Arguably, this was the most important change as it allowed me to debug tasks way quicker as I instantly could know when the canary values were corrupted. Overhauling the Data Pipelines In order to avoid the 10ms delay of my original blocking pipline (for data transfer), I entirely rewrote the hardware data pipelines multiple times to use a semi-blocking, circular Direct Memory Access (DMA) architecture. Instead of the processor handling the data transfer, the hardware itself moves the bytes from the sensors directly into memory in the background. The DMA streams now trigger precise interrupts at the halfway and full-transfer points, allowing the RTOS to safely parse incoming radio packets and sensor reads without ever risking data overwrites or blocking the main flight loop. Building a Flight Controller I integrated Betaflight’s Actual Rates algorithm with custom expo curves, ensuring that physical stick inputs map perfectly to target velocities. I built a custom SPI driver to pull 24-bit raw pressure and temperature data from a BMP390 barometer, passing it through hypsometric formulas to calculate altitude. For video and telemetry, I moved away from raw UART strings and implemented native MSP DisplayPort communication (for true digital Walksnail Avatar connection). I also built an interactive USB command-line interface. Instead of having to recompile and re-flash the firmware every time a PID value needs to be adjusted, I can plug into the board, pull up a terminal, and manually tune gains, remap CRSF radio channels, or adjust IMU orientation offsets in real time. Final Version The last few weeks have been about refinement and consistency, removing race conditions and overall polishing the code. Now that the RTOS is fully functional, the only things to add are extra features, like a permanent + more expanded CLI, as well as finishing the external RM and linking the ESC drivers. As these are pretty insignificant, I have linked the source of this shipment to the Github project rather than a specific release so that I can update these during review!...
|
1792993800.8647993
|
1793080200.8647993
|
|
5322
|
Kopuz by @temidaradev | Stardance
|
temidaradev
|
5
|
139.0
|
2306
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-14T16:31:49Z", "hours": 29.0, "multiplier": 19.98, "payout": 572, "blessing": "neutral", "text": "Two parts of the player stop lying to you: Recently Added lists what you actually added, and shuffle and repeat go dark when you switch them off. Apple Music takes any storefront, and Kopuz is now EUPL-1.2. Highlights Recently Added means recently added. The row was the alphabetical album list read backwards, so it showed the tail of your alphabet forever. Albums now rank by when their music arrived, stamped per file from the filesystem while the library is scanned, and the library’s own date added sort reads the same stamp. Rescan once after upgrading to fill it in. Shuffle and repeat clear their highlight. Dioxus merges an inline style instead of replacing it, so the empty “off” style could never unset the accent color and the button stayed lit for the rest of the session, with only the tooltip telling the truth. Both toggles carry their state in the class attribute now. Apple Music takes any storefront. Pick one or type the country code yourself, validated before it saves. Apple serves far more regions than the shortlist, and the storefront API is gated behind a developer account. EUPL-1.2. Kopuz was MIT, and is now licensed under the European Union Public Licence 1.2. Fixes Unsynced albums asked Subsonic for the wrong cover and fell back to an uncached request, so covers came back soft, and the three dots menu opened in the wrong place. Brave’s newer packaging ships the browser as brave-origin , which cookie import could not find. Windows with an app-drawn titlebar resize from any edge or corner on Linux. Flathub and Google Play badges on the README.", "repo": "https://github.com/Kopuz-org/kopuz", "demo": "https://github.com/Kopuz-org/kopuz/releases"}, {"ship_num": 2, "ts": "2026-08-24T14:51:45Z", "hours": 25.0, "multiplier": 17.59, "payout": 352, "blessing": "neutral", "text": "We released v0.16.0!!! Android is back and shippable, two new sources (Apple Music, Nextcloud), lyrics grew depth blur and instrumental breaks, and remote tracks start faster. The app identity finished its move to moe.kopuz.kopuz , so your data directory moves with it on macOS and Windows. Highlights Android builds again. arm64 APK on the releases page (API 24+), signed release job that fails a tagged build rather than shipping unsigned, F-Droid recipe, just android-release . Phone UI too: two line track rows, swipe gestures (up for fullscreen, left/right for next/prev), notification shuffle and repeat buttons, media permission flow, a keepalive waker so the player task keeps turning while hidden, WebView based YouTube deciphering, and an AMOLED theme (#634). Apple Music. Browser sign in, catalog and library browsing, favorites, playlists, downloads, word timed lyrics, per server storefront and language. Playback is hand rolled Widevine using a CDM borrowed from a browser you already have installed (never shipped with Kopuz); Android goes through MediaDrm . Streams decrypt progressively instead of pulling the whole file first (#455, closes #404). Nextcloud over WebDAV. App password auth. No music API there, so the library is read off the tree: folder is album, level above is artist. Listings carry no duration, so the scanner range requests the file head. Per server library folders with a PROPFIND picker and autodetect. Covers go embedded, then sidecar, then the preview endpoint. Use the Subsonic source if your instance runs the Music app (#629). Lyrics. Depth of field blur with a strength slider, synthesized instrumental breaks that fill left to right, the active line stays centered, changing songs no longer reads as a scroll, tab switches no longer desync, and a manual offset that auto fills from the backend’s reported output latency (#643, #647, #648). Remote tracks start faster. HTTP clients are pooled across tracks instead of one handshake per song, and the next 512 KiB window prefetches once reading passes the middle of the current one (#634). Radio uses the server’s analysis. OpenSubsonic sonicSimilarity (AudioMuse on Navidrome) when advertised, song seeded getSimilarSongs otherwise, seed at the head of the queue, and a 90s budget since cold metadata agent lookups were timing out silently (#647, 15615f36). Untrusted paths. Offline filenames are SHA-256 derived, extensions restricted, downloads staged before publication. Deletion only touches direct children of the offline cache or canonical files under a configured library root. Cancellation tombstones close the race where a worker finishing after a cancel re-registered the track (#650).", "repo": "https://github.com/Kopuz-org/kopuz", "demo": "https://github.com/Kopuz-org/kopuz/releases"}, {"ship_num": 3, "ts": "2026-08-04T16:26:49Z", "hours": 10.0, "multiplier": 19.86, "payout": 207, "blessing": "neutral", "text": "v0.14.0 is here!!! Now we are using automated builds with github actions! This one is mostly playlists and looks. Radio can start from a whole playlist now, the settings screen got rebuilt (prefer using top bar view in settings menu rather than cd if you are a linux user), and Kopuz can follow your wallpaper’s colors live. Releases finally ship proper packages for all three desktops. Highlights Radio from playlists: Sources can now seed a mix from an entire playlist instead of one track. YouTube Music does it first, and the button shows up on the playlist grid and the playlist page wherever a source supports it. YouTube liked music is also listed as a playlist of its own, so it gets the same treatment (#591, #592, #593). Matugen and pywal, live: Pick Matugen / Pywal (live) in Settings > Appearance and Kopuz recolors itself about half a second after the palette is regenerated. No restart. pywal needs nothing configured, matugen needs a small template. (#572). Settings rebuilt: The page is split up properly and there are now two layouts to choose from, CD (default) and top bar (#588). Helium for Spotify: Helium joins Chrome, Edge, Brave, Chromium, Vivaldi and Safari as a Web Playback SDK host. It needs Widevine pointed at manually; the README has the config (#574). Track numbers from tags: Album lists use the real metadata track number when there is one, instead of just counting rows (#581). Search in favorites: The favorites list filters as you type, with a proper no-results state (#587). Real release packages: One workflow now builds AppImage, DEB and RPM for Linux, a DMG for macOS, and EXE and MSI for Windows, with checksums. (probably no space will left for macos but eh) Fixes Selection bar was unreadable on light accents like Ayu Dark and Mirage (#599). Long album titles pushed the entire song list off screen (#580). Dots menus were getting clipped inside scrolling containers (#586). Fullscreen forgot the active tab when you hid and unhid the tabs panel (#585).", "repo": "https://github.com/Kopuz-org/kopuz", "demo": "https://github.com/Kopuz-org/kopuz/releases"}, {"ship_num": 4, "ts": "2026-07-24T21:24:05Z", "hours": 42.0, "multiplier": 19.65, "payout": 772, "blessing": "neutral", "text": "kopuz v0.12.0 is out. this one’s got some solid stuff. added isolated local music libraries so separate folders stay separate instead of all blending into one big pile. settings page got a full revision, it needed it. the cover art loading is a lot faster now since we defer cover indexing until after the metadata scan, so big libraries scan way quicker. also local artwork scales properly per view so no more blurry thumbnails. trickiest part was keeping the library scan from lagging everything, that’s sorted now. to test: point it at a couple different music folders and watch them stay isolated, covers should load smooth and settings should feel cleaner. (warning, parallelization: so uhh if you have a big lib, when you scroll in album page it will hurt your cpu a little because of the rendering but dont worry its a one time thing .d)", "repo": "https://github.com/Kopuz-org/kopuz", "demo": "https://github.com/Kopuz-org/kopuz/releases"}, {"ship_num": 5, "ts": "2026-06-27T18:33:59Z", "hours": 33.0, "multiplier": 15.36, "payout": 403, "blessing": "neutral", "text": "I made kopuz music player with the maintainers!! I submitted this project last event too! It got waaay better than first time also i will ship everytime we publish new version from now on! This release is mostly cleanup and refactor work: a big code split across server, utils, sources, and the playback controller, native Windows cookie decryption for sign-in, assets baked into the binary, and a bunch of new translations. Highlights Native Windows cookie decryption. YouTube Music and SoundCloud sign-in now read browser cookies natively on Windows instead of going through the rookie crate (which is now off on Windows). Sign-in works without the third-party cookie reader. Assets are baked into the binary. CSS, fonts, and the favicon now ship inside the kopuz binary, so it doesn’t need any external files at runtime. Big refactor. Server and utils are split up, the source model, page runtimes, backend modules, and playback controller are all broken out, and audio init, playback parsing, and config views got reworked. Dependencies are deduplicated through a virtual manifest to get ready for publishing on crates.io. Features yt-music showcase refactor. Focus indicators on interactive elements that didn’t have them. Matroska audio content-types now map to the mka decode hint. CSS, fonts, and favicon embedded into the binary. Dropped panicky .unwrap() calls, added crate docs, and moved eprintln! over to tracing . Deduplicated shared deps via a virtual manifest to prep for publish. Added contributing guidelines. New locales: Dutch, Malayalam, Tamil, Filipino, and European Portuguese (pt-PT), plus an updated Indonesian one. Fixes ytdlp : give yt-dlp a valid stdin so downloads work on Windows. queue : don’t split the queue when shuffling. server : gate the rookie browser-cookie import to non-Windows. db : tolerate line-ending-only migration checksum differences. lyrics : drop negative cache TTL from 7 days to 1 day. styles : stop the console warnings from re-diffing the stylesheet.", "repo": "https://github.com/Kopuz-org/kopuz", "demo": "https://github.com/Kopuz-org/kopuz/releases"}]...
|
[{"post_id": 68150, "ts": "202 [{"post_id": 68150, "ts": "2026-09-14T16:30:19Z", "hours": 9.9761, "text": "Eh i fixed some little bugs and reviewed prs, all these hours is just because i worked on daemon-frontend split i deployed the bugs fixed version for now, daemon is way harder than i expected thats why its taking sooooo long and too much effort. Fixed bugs are shuffle and repeat button werent updating their states but they now update .d"}, {"post_id": 60743, "ts": "2026-09-03T09:44:44Z", "hours": 10.7572, "text": "All right, so we got accepted to flathub and properly setted up our page, also now it releases on google play store properly too!!! I fixed some bugs and worked a lot for splitting daemon and frontend, hopefully it will be implemented soon. Lastly we switched to EUPL v1.2 license from MIT because i want to protect the daemon…"}, {"post_id": 54324, "ts": "2026-08-25T08:43:21Z", "hours": 8.6461, "text": "All right im in the middle of splitting the daemon from frontend, get ready for the holy kopuzd, we may release an official tui version too!!"}, {"post_id": 53815, "ts": "2026-08-24T14:49:03Z", "hours": 15.3031, "text": "I finally released android version again!! even its on google play store, also we did some improvements to the app. I started split daemon from the frontend, which will allow custom frontends soon, I dont have much photos to show and no long descrips because im too busy atm sorry .d we are mostly working on the backend currently."}, {"post_id": 49105, "ts": "2026-08-17T18:48:25Z", "hours": 10.1075, "text": "All right new log is here, so i was really busy with my job but i def worked on kopuz besides that. Firstly i added version and commit id to general settings, added progress stuff like in youtube progress bar to http streamed musics. Did a little bit of codebase cleanup, fixed a lot of RTL issues and now i splitted configs from db and now they are toml configable (hjem supported)."}, {"post_id": 40678, "ts": "2026-08-04T11:25:14Z", "hours": 3.0694, "text": "all right so i partially migrated CI/CD to self hosted ones because github actions SUCKS, also now Linux and Windows builds are made with github actions. Also added favorite, and 3 dots menu to fullscreen multimedia controller .d added search bar to favorites page, and i also made when listen from youtube music, discord presence will directly get the youtube music photo and doesnt fetch form musicbrainz, lastly some little bug fixes has made :3"}, {"post_id": 39386, "ts": "2026-08-02T10:23:53Z", "hours": 1.6589, "text": "I was so busy last 5 days for interview project but, good news i passed it! I wasnt able to develop kopuz at that time but its over, right after interview arc i redesigned the settings menu for better visibility and this is not the only option you can make it constant topbar but the default is cd selector so cope with it .d"}, {"post_id": 36306, "ts": "2026-07-28T10:21:27Z", "hours": 5.7181, "text": "so uhhh spotify integration is finally in master branch, people were just asking me when spotify when spotify and yeah its here, but for avoiding lawsuits i had to use public api which will give users some bad experience, but eh this can be used as “download your own music” propaganda, besides this i did some codebase cleanup and lil bug fixes"}, {"post_id": 34279, "ts": "2026-07-24T21:02:07Z", "hours": 7.8978, "text": "all right, so i was like super bored and randomly started add stuff, so uhh we now have isolated local music libraries, so like if you have 2 different folders which contains different kinds of music and you dont want to mix it with your main library, i had that issue so added this option, also people were complaining about settings menu so i made exactly how they wanted, also when i woke up this morning i saw a discussion opened in the repo which said, “kopuz individually takes images of flac files” which is true, i didnt expect anyone with 5k songs to use this app .d Anyways i fixed that issue and the app got faster (i was so stupid while i was enabling individual image scanning)."}, {"post_id": 32862, "ts": "2026-07-22T09:32:47Z", "hours": 8.7542, "text": "spotify support is postponed to v0.12.0, but uhh we got some solid stuff for v0.11.0 fullscreen got reworked, now with cover art backgrounds and a general cleanup pass added quick search so you can actually find your stuff fast custom UI font support, use whatever font you want redesigned the normal radio page radio-browser.info search, ICY now-playing metadata, and playlist resolution EQ now has 10 bands instead of the old setup auto-scroll pauses when you scroll manually, plus a sync button added Helium browser for browser sign-in app now checks if the media server is actually reachable instead of assuming it is added Swedish locale"}, {"post_id": 30196, "ts": "2026-07-17T16:06:51Z", "hours": 5.7239, "text": "I added spotify support with Public API, since this is a big app, im afraid of using the illegal way, so for using the spotify integration there MUST be a browser which has widevine capability… Is it annoying? yes. But is it working? yes."}, {"post_id": 28454, "ts": "2026-07-14T18:23:33Z", "hours": 8.9486, "text": "Okay so, firstly i added list view to album and artist menu, its kinda a cheat for better performance since the images are getting smaller, users always complain about bad performance on higher resolutions so its a step against it, also i added highly customazible sorting options because it was a pr back then and the author of that pr couldnt reach to his pc so i took over his task, also not MPRIS and darwin now playing integration supports seeking, lastly i started on TIDAL integration because vaxry requested it .d"}, {"post_id": 23726, "ts": "2026-07-06T20:51:28Z", "hours": 2.9472, "text": "Revised settings page for better understandability for users. Yeah so vaxry told me that settings menu sucks. So i made the components like this in the photo, easily understandable (idiotproofing)"}, {"post_id": 22262, "ts": "2026-07-04T17:15:09Z", "hours": 3.3267, "text": "I reinforced ListenBrainz scrobbling because vaxry reported that it sucks, so apperantly it was half my issue and half LB’s issue because BTS listeners migrated to libre.fm and listenbrainz from last.fm. So scrobbling was a bit wrong in my side, so fixed that. Also im waiting for a contributor to add offline scrobbling ability which will fully fix this issue since it will cache listening and when the LB server is awake again it will dump scrobbles… Ah also now playing was a bit broken so i fully fixed it too, now the app has great logs for scrobble stuff…"}, {"post_id": 20754, "ts": "2026-07-02T13:28:30Z", "hours": 4.5308, "text": "Added enhanced discord presence which now has the option to show the source of your music, also i added clear image cache and rescan buttons for easier image handling."}, {"post_id": 17070, "ts": "2026-06-27T18:31:27Z", "hours": 1.8081, "text": "fixed source selector part styling and with contributors we fixed login issue on windows, established ai policy, and a lot more!!"}, {"post_id": 15158, "ts": "2026-06-24T16:58:45Z", "hours": 4.4406, "text": "worked on adding librespot backend (kinda), since spotify isnt giving us any music or music data bytes we cant decode anything, so i made librespot to fetch the stuff in logged in profile and play via anon yt music backend with metadata matching, its still a pr but eh hopefully it will be good"}, {"post_id": 13216, "ts": "2026-06-21T17:24:11Z", "hours": 2.4389, "text": "better album view in yt music, fixed search for yt music, discover menu is now better, any album available can now viewable. Also we have migrated to sqlite from json so the app became waaay faster and now there is no seperation between local and server now everything is in one place."}, {"post_id": 12648, "ts": "2026-06-20T17:42:21Z", "hours": 0.8142, "text": "made last touches with the contributor and made it ready to release! hopefully first release in stardance will be v0.7.0, who knows kopuz may become stable in stardance…"}, {"post_id": 12101, "ts": "2026-06-19T19:09:14Z", "hours": 1.3692, "text": "fixed fullscreen view, it was really poor and multimedia controls were so bad, i took the audio control to top right corner so it looks like apple music now."}, {"post_id": 11511, "ts": "2026-06-18T20:02:54Z", "hours": 3.7036, "text": "i added mini player and tray implementation for users!!"}, {"post_id": 9168, "ts": "2026-06-15T11:15:59Z", "hours": 10.3256, "text": "I worked on adding spotify but failed, same for apple music too but at least i added soundcloud to kopuz!!! This music player will be the best music player ever created for every platform user!"}, {"post_id": 5936, "ts": "2026-06-09T22:34:46Z", "hours": 1.9461, "text": "local metadata viewer and editor added"}, {"post_id": 4334, "ts": "2026-06-07T16:45:21Z", "hours": 4.0619, "text": "we got youtube music support now!! with a lot of bug fixes"}, {"post_id": 942, "ts": "2026-06-02T18:20:14Z", "hours": 1.8019, "text": "Making kopuz better this time huh?"}]...
|
Title: Kopuz by @temidaradev | Stardance
Devlogs: Title: Kopuz by @temidaradev | Stardance
Devlogs:
Making kopuz better this time huh?
we got youtube music support now!! with a lot of bug fixes
local metadata viewer and editor added
I worked on adding spotify but failed, same for apple music too but at least i added soundcloud to kopuz!!! This music player will be the best music player ever created for every platform user!
i added mini player and tray implementation for users!!
fixed fullscreen view, it was really poor and multimedia controls were so bad, i took the audio control to top right corner so it looks like apple music now.
made last touches with the contributor and made it ready to release! hopefully first release in stardance will be v0.7.0, who knows kopuz may become stable in stardance…
better album view in yt music, fixed search for yt music, discover menu is now better, any album available can now viewable. Also we have migrated to sqlite from json so the app became waaay faster and now there is no seperation between local and server now everything is in one place.
worked on adding librespot backend (kinda), since spotify isnt giving us any music or music data bytes we cant decode anything, so i made librespot to fetch the stuff in logged in profile and play via anon yt music backend with metadata matching, its still a pr but eh hopefully it will be good
fixed source selector part styling and with contributors we fixed login issue on windows, established ai policy, and a lot more!!
Added enhanced discord presence which now has the option to show the source of your music, also i added clear image cache and rescan buttons for easier image handling.
I reinforced ListenBrainz scrobbling because vaxry reported that it sucks, so apperantly it was half my issue and half LB’s issue because BTS listeners migrated to libre.fm and listenbrainz from last.fm. So scrobbling was a bit wrong in my side, so fixed that. Also im waiting for a contributor to add offline scrobbling ability which will fully fix this issue since it will cache listening and when the LB server is awake again it will dump scrobbles… Ah also now playing was a bit broken so i fully fixed it too, now the app has great logs for scrobble stuff…
Revised settings page for better understandability for users. Yeah so vaxry told me that settings menu sucks. So i made the components like this in the photo, easily understandable (idiotproofing)
Okay so, firstly i added list view to album and artist menu, its kinda a cheat for better performance since the images are getting smaller, users always complain about bad performance on higher resolutions so its a step against it, also i added highly customazible sorting options because it was a pr back then and the author of that pr couldnt reach to his pc so i took over his task, also not MPRIS and darwin now playing integration supports seeking, lastly i started on TIDAL integration because vaxry requested it .d
I added spotify support with Public API, since this is a big app, im afraid of using the illegal way, so for using the spotify integration there MUST be a browser which has widevine capability… Is it annoying? yes. But is it working? yes.
spotify support is postponed to v0.12.0, but uhh we got some solid stuff for v0.11.0 fullscreen got reworked, now with cover art backgrounds and a general cleanup pass added quick search so you can actually find your stuff fast custom UI font support, use whatever font you want redesigned the normal radio page radio-browser.info search, ICY now-playing metadata, and playlist resolution EQ now has 10 bands instead of the old setup auto-scroll pauses when you scroll manually, plus a sync button added Helium browser for browser sign-in app now checks if the media server is actually reachable instead of assuming it is added Swedish locale
all right, so i was like super bored and randomly started add stuff, so uhh we now have isolated local music libraries, so like if you have 2 different folders which contains different kinds of music and you dont want to mix it with your main library, i had that issue so added this option, also people were complaining about settings menu so i made exactly how they wanted, also when i woke up this morning i saw a discussion opened in the repo which said, “kopuz individually takes images of flac files” which is true, i didnt expect anyone with 5k songs to use this app .d Anyways i fixed that issue and the app got faster (i was so stupid while i was enabling individual image scanning).
so uhhh spotify integration is finally in master branch, people were just asking me when spotify when spotify and yeah its here, but for avoiding lawsuits i had to use public api which will give users some bad experience, but eh this can be used as “download your own music” propaganda, besides this i did some codebase cleanup and lil bug fixes
I was so busy last 5 days for interview project but, good news i passed it! I wasnt able to develop kopuz at that time but its over, right after interview arc i redesigned the settings menu for better visibility and this is not the only option you can make it constant topbar but the default is cd selector so cope with it .d
all right so i partially migrated CI/CD to self hosted ones because github actions SUCKS, also now Linux and Windows builds are made with github actions. Also added favorite, and 3 dots menu to fullscreen multimedia controller .d added search bar to favorites page, and i also made when listen from youtube music, discord presence will directly get the youtube music photo and doesnt fetch form musicbrainz, lastly some little bug fixes has made :3
All right new log is here, so i was really busy with my job but i def worked on kopuz besides that. Firstly i added version and commit id to general settings, added progress stuff like in youtube progress bar to http streamed musics. Did a little bit of codebase cleanup, fixed a lot of RTL issues and now i splitted configs from db and now they are toml configable (hjem supported).
I finally released android version again!! even its on google play store, also we did some improvements to the app. I started split daemon from the frontend, which will allow custom frontends soon, I dont have much photos to show and no long descrips because im too busy atm sorry .d we are mostly working on the backend currently.
All right im in the middle of splitting the daemon from frontend, get ready for the holy kopuzd, we may release an official tui version too!!
All right, so we got accepted to flathub and properly setted up our page, also now it releases on google play store properly too!!! I fixed some bugs and worked a lot for splitting daemon and frontend, hopefully it will be implemented soon. Lastly we switched to EUPL v1.2 license from MIT because i want to protect the daemon…
Eh i fixed some little bugs and reviewed prs, all these hours is just because i worked on daemon-frontend split i deployed the bugs fixed version for now, daemon is way harder than i expected thats why its taking sooooo long and too much effort. Fixed bugs are shuffle and repeat button werent updating their states but they now update .d
Ships:
I made kopuz music player with the maintainers!! I submitted this project last event too! It got waaay better than first time also i will ship everytime we publish new version from now on! This release is mostly cleanup and refactor work: a big code split across server, utils, sources, and the playback controller, native Windows cookie decryption for sign-in, assets baked into the binary, and a bunch of new translations. Highlights Native Windows cookie decryption. YouTube Music and SoundCloud sign-in now read browser cookies natively on Windows instead of going through the rookie crate (which is now off on Windows). Sign-in works without the third-party cookie reader. Assets are baked into the binary. CSS, fonts, and the favicon now ship inside the kopuz binary, so it doesn’t need any external files at runtime. Big refactor. Server and utils are split up, the source model, page runtimes, backend modules, and playback controller are all broken out, and audio init, playback parsing, and config views got reworked. Dependencies are deduplicated through a virtual manifest to get ready for publishing on crates.io. Features yt-music showcase refactor. Focus indicators on interactive elements that didn’t have them. Matroska audio content-types now map to the mka decode hint. CSS, fonts, and favicon embedded into the binary. Dropped panicky .unwrap() calls, added crate docs, and moved eprintln! over to tracing . Deduplicated shared deps via a virtual manifest to prep for publish. Added contributing guidelines. New locales: Dutch, Malayalam, Tamil, Filipino, and European Portuguese (pt-PT), plus an updated Indonesian one. Fixes ytdlp : give yt-dlp a valid stdin so downloads work on Windows. queue : don’t split the queue when shuffling. server : gate the rookie browser-cookie import to non-Windows. db : tolerate line-ending-only migration checksum differences. lyrics : drop negative cache TTL from 7 days to 1 day. styles : stop the console warnings from re-diffing the stylesheet.
kopuz v0.12.0 is out. this one’s got some solid stuff. added isolated local music libraries so separate folders stay separate instead of all blending into one big pile. settings page got a full revision, it needed it. the cover art loading is a lot faster now since we defer cover indexing until after the metadata scan, so big libraries scan way quicker. also local artwork scales properly per view so no more blurry thumbnails. trickiest part was keeping the library scan from lagging everything, that’s sorted now. to test: point it at a couple different music folders and watch them stay isolated, covers should load smooth and settings should feel cleaner. (warning, parallelization: so uhh if you have a big lib, when you scroll in album page it will hurt your cpu a little because of the rendering but dont worry its a one time thing .d)
v0.14.0 is here!!! Now we are using automated builds with github actions! This one is mostly playlists and looks. Radio can start from a whole playlist now, the settings screen got rebuilt (prefer using top bar view in settings menu rather than cd if you are a linux user), and Kopuz can follow your wallpaper’s colors live. Releases finally ship proper packages for all three desktops. Highlights Radio from playlists: Sources can now seed a mix from an entire playlist instead of one track. YouTube Music does it first, and the button shows up on the playlist grid and the playlist page wherever a source supports it. YouTube liked music is also listed as a playlist of its own, so it gets the same treatment (#591, #592, #593). Matugen and pywal, live: Pick Matugen / Pywal (live) in Settings > Appearance and Kopuz recolors itself about half a second after the palette is regenerated. No restart. pywal needs nothing configured, matugen needs a small template. (#572). Settings rebuilt: The page is split up properly and there are now two layouts to choose from, CD (default) and top bar (#588). Helium for Spotify: Helium joins Chrome, Edge, Brave, Chromium, Vivaldi and Safari as a Web Playback SDK host. It needs Widevine pointed at manually; the README has the config (#574). Track numbers from tags: Album lists use the real metadata track number when there is one, instead of just counting rows (#581). Search in favorites: The favorites list filters as you type, with a proper no-results state (#587). Real release packages: One workflow now builds AppImage, DEB and RPM for Linux, a DMG for macOS, and EXE and MSI for Windows, with checksums. (probably no space will left for macos but eh) Fixes Selection bar was unreadable on light accents like Ayu Dark and Mirage (#599). Long album titles pushed the entire song list off screen (#580). Dots menus were getting clipped inside scrolling containers (#586). Fullscreen forgot the active tab when you hid and unhid the tabs panel (#585).
We released v0.16.0!!! Android is back and shippable, two new sources (Apple Music, Nextcloud), lyrics grew depth blur and instrumental breaks, and remote tracks start faster. The app identity finished its move to moe.kopuz.kopuz , so your data directory moves with it on macOS and Windows. Highlights Android builds again. arm64 APK on the releases page (API 24+), signed release job that fails a tagged build rather than shipping unsigned, F-Droid recipe, just android-release . Phone UI too: two line track rows, swipe gestures (up for fullscreen, left/right for next/prev), notification shuffle and repeat buttons, media permission flow, a keepalive waker so the player task keeps turning while hidden, WebView based YouTube deciphering, and an AMOLED theme (#634). Apple Music. Browser sign in, catalog and library browsing, favorites, playlists, downloads, word timed lyrics, per server storefront and language. Playback is hand rolled Widevine using a CDM borrowed from a browser you already have installed (never shipped with Kopuz); Android goes through MediaDrm . Streams decrypt progressively instead of pulling the whole file first (#455, closes #404). Nextcloud over WebDAV. App password auth. No music API there, so the library is read off the tree: folder is album, level above is artist. Listings carry no duration, so the scanner range requests the file head. Per server library folders with a PROPFIND picker and autodetect. Covers go embedded, then sidecar, then the preview endpoint. Use the Subsonic source if your instance runs the Music app (#629). Lyrics. Depth of field blur with a strength slider, synthesized instrumental breaks that fill left to right, the active line stays centered, changing songs no longer reads as a scroll, tab switches no longer desync, and a manual offset that auto fills from the backend’s reported output latency (#643, #647, #648). Remote tracks start faster. HTTP clients are pooled across tracks instead of one handshake per song, and the next 512 KiB window prefetches once reading passes the middle of the current one (#634). Radio uses the server’s analysis. OpenSubsonic sonicSimilarity (AudioMuse on Navidrome) when advertised, song seeded getSimilarSongs otherwise, seed at the head of the queue, and a 90s budget since cold metadata agent lookups were timing out silently (#647, 15615f36). Untrusted paths. Offline filenames are SHA-256 derived, extensions restricted, downloads staged before publication. Deletion only touches direct children of the offline cache or canonical files under a configured library root. Cancellation tombstones close the race where a worker finishing after a cancel re-registered the track (#650).
Two parts of the player stop lying to you: Recently Added lists what you actually added, and shuffle and repeat go dark when you switch them off. Apple Music takes any storefront, and Kopuz is now EUPL-1.2. Highlights Recently Added means recently added. The row was the alphabetical album list read backwards, so it showed the tail of your alphabet forever. Albums now rank by when their music arrived, stamped per file from the filesystem while the library is scanned, and the library’s own date added sort reads the same stamp. Rescan once after upgrading to fill it in. Shuffle and repeat clear their highlight. Dioxus merges an inline style instead of replacing it, so the empty “off” style could never unset the accent color and the button stayed lit for the rest of the session, with only the tooltip telling the truth. Both toggles carry their state in the class attribute now. Apple Music takes any storefront. Pick one or type the country code yourself, validated before it saves. Apple serves far more regions than the shortlist, and the storefront API is gated behind a developer account. EUPL-1.2. Kopuz was MIT, and is now licensed under the European Union Public Licence 1.2. Fixes Unsynced albums asked Subsonic for the wrong cover and fell back to an uncached request, so covers came back soft, and the three dots menu opened in the wrong place. Brave’s newer packaging ships the browser as brave-origin , which cookie import could not find. Windows with an app-drawn titlebar resize from any edge or corner on Linux. Flathub and Google Play badges on the README....
|
1792990555.9965124
|
1793076955.9965124
|
|
19478
|
Searchuse 1.4.4 by @ai_zamden | Stardance
|
ai_zamden
|
3
|
135.0
|
1486
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T22:47:37Z", "hours": 33.0, "multiplier": 11.36, "payout": 340, "blessing": "neutral", "text": "Hey guys, this is my third ship for my turn-based strategy game Searchuse. A lot of you guys suggested to add a tutorial, so I made one, and now it’s a lot easier to figure out how to play the game! I hope you enjoy.", "repo": "https://github.com/aidenzma/Searchuse", "demo": "https://ai-zamden.itch.io/searchuse"}, {"ship_num": 2, "ts": "2026-07-17T01:35:02Z", "hours": 77.0, "multiplier": 14.75, "payout": 853, "blessing": "neutral", "text": "I’ve listened to the people and have tried to make as many improvements as I could. UI has been improved Art has been pixel-adjusted Controls are specified in the README Main Menu button has been added Searchuse is now available on Linux AND Searchuse is now available on BROWSER (itch.io, the demo link) So now everyone is theoretically able to try it! A large portion of my time was spent creating a neural network for the bot (that can only be experienced in Train Bot, there’s a hardcoded bot and a neural network bot.) (The neural network bot is still very inexperienced currently.) (Admittedly, Gemini helped me a lot with setting up that portion of the game.) For specific help in downloading the zips, visit the README.", "repo": "https://github.com/aidenzma/Searchuse", "demo": "https://ai-zamden.itch.io/searchuse"}, {"ship_num": 3, "ts": "2026-06-25T04:03:09Z", "hours": 25.0, "multiplier": 12.05, "payout": 293, "blessing": "neutral", "text": "I made a turn-based strategy game called Searchuse, where you search for and then use various items with different mechanics. A challenge in the process was getting all of the turn-based logic right. (For cooldowns and lasting effects, the timing can be surprisingly complicated to get down.) I’m proud that there aren’t any glaring bugs in the game right now. To play, move around using arrow keys, and press the buttons search or use. There are deeper mechanics you can learn, but the surface-level controls should be intuitive! Here’s the trailer: https://youtu.be/wL6j5aslFXA Join the Discord: https://discord.gg/NpBV6vHc7", "repo": "https://github.com/aidenzma/Searchuse", "demo": "https://ai-zamden.itch.io/searchuse"}]...
|
[{"post_id": 63898, "ts": "202 [{"post_id": 63898, "ts": "2026-09-07T22:44:08Z", "hours": 3.3097, "text": "I’m finished with the tutorial, so now you guys can easily learn how to play Searchuse!"}, {"post_id": 63059, "ts": "2026-09-06T17:21:51Z", "hours": 9.2094, "text": "I’m making a tutorial to teach new users how to play the game, as requested by feedback for my latest ship."}, {"post_id": 36775, "ts": "2026-07-29T01:24:16Z", "hours": 12.9503, "text": "I did a massive overhaul of the inner workings of the inventory system, changing the data tracking from only ints representing the itemIDs to structs which provide a container for data of items. I did this because I had to add individual item durability."}, {"post_id": 34389, "ts": "2026-07-25T02:19:17Z", "hours": 7.4644, "text": "After a long while, some new content is finally added to Searchuse. Introducing: Armor Piercing Rounds: Use with certain weapons to allow damage to be done as if the opponent were wearing no armor! Beretta+: An upgraded version of the Beretta, this weapon allows you to do damage the the enemy’s max health, a groundbreaking new mechanic added in this update. Fixed: Energy Orb edge bug: Now, the Energy Orb and other explosives will explode when hitting the edge of the map instead of not doing anything! Smoke vision bug: A small error in FOV rendering while in a smoked area was fixed. Factory edge bug: A visual glitch that resulted in Factory tiles peeking out from under the greyed out vision area was fixed."}, {"post_id": 29881, "ts": "2026-07-17T01:27:03Z", "hours": 1.3161, "text": "Searchuse is now available on Linux and Browser!"}, {"post_id": 29302, "ts": "2026-07-16T04:03:09Z", "hours": 7.9944, "text": "I’ve made major UI improvements to the game!"}, {"post_id": 26990, "ts": "2026-07-12T03:45:34Z", "hours": 10.4197, "text": "I’ve set up the system so that my hardcoded bot can train the neural network bot. This is gonna be fun!"}, {"post_id": 26063, "ts": "2026-07-10T17:29:06Z", "hours": 8.1575, "text": "I started building a neural network for the bot so that I can train it and it can learn. This is what the data file looks like for all of the weights and nodes."}, {"post_id": 24880, "ts": "2026-07-08T18:45:45Z", "hours": 2.7314, "text": "I coded an algorithm that allows the bot to scan the map, and the resulting data lists are represented here by colors! Red = near mountains & hills Green = near cover (caves & trees) Blue = near loot (buildings)"}, {"post_id": 24522, "ts": "2026-07-08T03:50:22Z", "hours": 15.1186, "text": "I added a world map to Searchuse!"}, {"post_id": 21711, "ts": "2026-07-03T20:06:43Z", "hours": 7.6906, "text": "I’ve upgraded the bot’s intelligence. Instead of only being aware of the enemy when they are in its immediate vision, the bot now remembers where it previously saw the enemy, keeps track of how many opportunities to move the enemy had since then, and precisely calculates all the squares the enemy could be on using a flood fill algorithm, based on how many moves the bot thinks the enemy had. (The eye icons represent what the bot thinks are the possible positions of my player based on where it last saw my player. (Sometimes the player can “escape” the eyes by having more moves than what the bot thinks the player has.) (Otherwise, if the bot is right about how many moves the player has, the player should not be able to move to a square without an eye icon.))"}, {"post_id": 20077, "ts": "2026-07-01T16:24:44Z", "hours": 23.2564, "text": "I worked on the enemy AI for my turn-based game Searchuse. The enemy can now use tools, such as invisibility potions, binoculars, radars, UAVs, and traps like landmines or C4s, and can also get airdrops."}, {"post_id": 15456, "ts": "2026-06-25T03:54:38Z", "hours": 4.6358, "text": "I added a few final features to match my turn-based strategy on Unity to its Scratch predecessor. Added: Hitmarker: When you’re hit with an unsuppressed weapon or bomb, a red arrow appears, telling you in which direction on your player’s character’s body you felt the impact. Cooldown visualiser: When you press c, a visual will show up that will show you all the items you have on cooldown and how many turns it is before you can use them next. 4 turn heavy weapons rule: In the first 4 turns, it is now impossible to find any weapon that totals a damage greater than 25 per turn. 3 weapon limit: You can only carry 3 weapons at a time. (By weapons I mean those that stay in your inventory, so something like Grenade doesn’t count.) If you find another weapon while you’re at your limit, you can choose to switch. Turns text: You can now press t to show the turns text, which is below the moves text and shows how many turns it’s been. Turn indicator: On the bottom of your screen, you’ll now find a green or blue landscape that indicates whose turn it is. (Green meaning your turn, blue meaning the enemy’s turn.)"}, {"post_id": 14868, "ts": "2026-06-24T04:17:21Z", "hours": 2.3808, "text": "Added: Message in a Floating Bottle: Like a book, it gives you a random powerup, but its rarity is lower than that of a book. However, its upside is that it is granted immediately after searching. Can only be found in water. AK-47: The world’s most iconic rifle is now in Searchuse! With 2 shots of 20 damage each, this addition provides more mid-tier weapon choices. AK-74: An upgrade of the AK-47, this gun matches the damage done by the M4A1, but it has a lesser cooldown, making it the more desirable option. Meat Stick: This item provides a solid mid-tier healing option, giving you 40 health in one bite. Spikes: This item gives you three more moves, but takes up an armor slot and provides 0 armor. (my beautiful art below)"}, {"post_id": 14567, "ts": "2026-06-23T18:50:46Z", "hours": 10.5353, "text": "I added a bunch of features, a new item, and fixed some bugs for my turn-based strategy game Searchuse. Added: Replay for when Vital Signs run out Replay for when Binoculars runs out Book: when read, gives you a random skill. These skills range from increasing moves to getting 2 searches per turn, so put on your reading glasses and pick up a book! You can also now press b to see your book inventory. Use arrow keys to navigate. Roll Chances Information: press L to open Roll Chances Information, which will tell you the chances of getting each rarity on each tile when you press search. Use arrow keys to navigate. Changed: Sound when picking up Thermal Vision Goggles Fixed: Not being able to start your turn on bot mode glitch Normalized speeds for UAV animation, texts, and movement"}, {"post_id": 11694, "ts": "2026-06-19T01:46:35Z", "hours": 7.0461, "text": "I added an airdrop to my turn-based strategy game Searchuse, which, instead of one, gives you three options to choose from when you press search."}, {"post_id": 9970, "ts": "2026-06-16T14:36:33Z", "hours": 0.32, "text": "I added a UAV to my turn-based strategy game Searchuse, which tracks down the enemy."}]...
|
Title: Searchuse 1.4.4 by @ai_zamden | Stardance
Title: Searchuse 1.4.4 by @ai_zamden | Stardance
Devlogs:
I added a UAV to my turn-based strategy game Searchuse, which tracks down the enemy.
I added an airdrop to my turn-based strategy game Searchuse, which, instead of one, gives you three options to choose from when you press search.
I added a bunch of features, a new item, and fixed some bugs for my turn-based strategy game Searchuse. Added: Replay for when Vital Signs run out Replay for when Binoculars runs out Book: when read, gives you a random skill. These skills range from increasing moves to getting 2 searches per turn, so put on your reading glasses and pick up a book! You can also now press b to see your book inventory. Use arrow keys to navigate. Roll Chances Information: press L to open Roll Chances Information, which will tell you the chances of getting each rarity on each tile when you press search. Use arrow keys to navigate. Changed: Sound when picking up Thermal Vision Goggles Fixed: Not being able to start your turn on bot mode glitch Normalized speeds for UAV animation, texts, and movement
Added: Message in a Floating Bottle: Like a book, it gives you a random powerup, but its rarity is lower than that of a book. However, its upside is that it is granted immediately after searching. Can only be found in water. AK-47: The world’s most iconic rifle is now in Searchuse! With 2 shots of 20 damage each, this addition provides more mid-tier weapon choices. AK-74: An upgrade of the AK-47, this gun matches the damage done by the M4A1, but it has a lesser cooldown, making it the more desirable option. Meat Stick: This item provides a solid mid-tier healing option, giving you 40 health in one bite. Spikes: This item gives you three more moves, but takes up an armor slot and provides 0 armor. (my beautiful art below)
I added a few final features to match my turn-based strategy on Unity to its Scratch predecessor. Added: Hitmarker: When you’re hit with an unsuppressed weapon or bomb, a red arrow appears, telling you in which direction on your player’s character’s body you felt the impact. Cooldown visualiser: When you press c, a visual will show up that will show you all the items you have on cooldown and how many turns it is before you can use them next. 4 turn heavy weapons rule: In the first 4 turns, it is now impossible to find any weapon that totals a damage greater than 25 per turn. 3 weapon limit: You can only carry 3 weapons at a time. (By weapons I mean those that stay in your inventory, so something like Grenade doesn’t count.) If you find another weapon while you’re at your limit, you can choose to switch. Turns text: You can now press t to show the turns text, which is below the moves text and shows how many turns it’s been. Turn indicator: On the bottom of your screen, you’ll now find a green or blue landscape that indicates whose turn it is. (Green meaning your turn, blue meaning the enemy’s turn.)
I worked on the enemy AI for my turn-based game Searchuse. The enemy can now use tools, such as invisibility potions, binoculars, radars, UAVs, and traps like landmines or C4s, and can also get airdrops.
I’ve upgraded the bot’s intelligence. Instead of only being aware of the enemy when they are in its immediate vision, the bot now remembers where it previously saw the enemy, keeps track of how many opportunities to move the enemy had since then, and precisely calculates all the squares the enemy could be on using a flood fill algorithm, based on how many moves the bot thinks the enemy had. (The eye icons represent what the bot thinks are the possible positions of my player based on where it last saw my player. (Sometimes the player can “escape” the eyes by having more moves than what the bot thinks the player has.) (Otherwise, if the bot is right about how many moves the player has, the player should not be able to move to a square without an eye icon.))
I added a world map to Searchuse!
I coded an algorithm that allows the bot to scan the map, and the resulting data lists are represented here by colors! Red = near mountains & hills Green = near cover (caves & trees) Blue = near loot (buildings)
I started building a neural network for the bot so that I can train it and it can learn. This is what the data file looks like for all of the weights and nodes.
I’ve set up the system so that my hardcoded bot can train the neural network bot. This is gonna be fun!
I’ve made major UI improvements to the game!
Searchuse is now available on Linux and Browser!
After a long while, some new content is finally added to Searchuse. Introducing: Armor Piercing Rounds: Use with certain weapons to allow damage to be done as if the opponent were wearing no armor! Beretta+: An upgraded version of the Beretta, this weapon allows you to do damage the the enemy’s max health, a groundbreaking new mechanic added in this update. Fixed: Energy Orb edge bug: Now, the Energy Orb and other explosives will explode when hitting the edge of the map instead of not doing anything! Smoke vision bug: A small error in FOV rendering while in a smoked area was fixed. Factory edge bug: A visual glitch that resulted in Factory tiles peeking out from under the greyed out vision area was fixed.
I did a massive overhaul of the inner workings of the inventory system, changing the data tracking from only ints representing the itemIDs to structs which provide a container for data of items. I did this because I had to add individual item durability.
I’m making a tutorial to teach new users how to play the game, as requested by feedback for my latest ship.
I’m finished with the tutorial, so now you guys can easily learn how to play Searchuse!
Ships:
I made a turn-based strategy game called Searchuse, where you search for and then use various items with different mechanics. A challenge in the process was getting all of the turn-based logic right. (For cooldowns and lasting effects, the timing can be surprisingly complicated to get down.) I’m proud that there aren’t any glaring bugs in the game right now. To play, move around using arrow keys, and press the buttons search or use. There are deeper mechanics you can learn, but the surface-level controls should be intuitive! Here’s the trailer: https://youtu.be/wL6j5aslFXA Join the Discord: https://discord.gg/NpBV6vHc7
I’ve listened to the people and have tried to make as many improvements as I could. UI has been improved Art has been pixel-adjusted Controls are specified in the README Main Menu button has been added Searchuse is now available on Linux AND Searchuse is now available on BROWSER (itch.io, the demo link) So now everyone is theoretically able to try it! A large portion of my time was spent creating a neural network for the bot (that can only be experienced in Train Bot, there’s a hardcoded bot and a neural network bot.) (The neural network bot is still very inexperienced currently.) (Admittedly, Gemini helped me a lot with setting up that portion of the game.) For specific help in downloading the zips, visit the README.
Hey guys, this is my third ship for my turn-based strategy game Searchuse. A lot of you guys suggested to add a tutorial, so I made one, and now it’s a lot easier to figure out how to play the game! I hope you enjoy....
|
1792994080.973617
|
1793080480.973617
|
|
26626
|
Grapefruit by @tsunami014 | Stardance
|
tsunami014
|
2
|
135.0
|
2180
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-12T22:08:50Z", "hours": 25.0, "multiplier": 16.69, "payout": 421, "blessing": "neutral", "text": "FIXED THE UI with dynamic colours and themes! Fixed some layouts Improved how tasks are made (including a not overwhelming amount of qualities and changed the ambiguous “reasoning” into a much less so “goals” As well as many minor also cool things! (See the devlogs after ship 1 for the full account)", "repo": "https://github.com/Tsunami014/Grapefruit/tree/v2.0", "demo": "https://github.com/Tsunami014/Grapefruit/releases/tag/v2.0"}, {"ship_num": 2, "ts": "2026-08-20T11:10:17Z", "hours": 110.0, "multiplier": 15.99, "payout": 1759, "blessing": "neutral", "text": "I finally decided I had done enough and it was really good! This app contains the conversation, a scene with Grapefruit in it, a basic settings page with not much in it, a tasks manager with categories (including a today category) and tasks with importance, reasoning, qualities, items! Also has a great bottom bar for easier text editing and has everything layed out in a mobile-friendly manner! Installation instructions are in the README", "repo": "https://github.com/Tsunami014/Grapefruit/tree/v2.0", "demo": "https://github.com/Tsunami014/Grapefruit/releases/tag/v2.0"}]...
|
[{"post_id": 66920, "ts": "202 [{"post_id": 66920, "ts": "2026-09-12T21:50:02Z", "hours": 2.17, "text": "I improved how tasks are made, making the task overlay centred instead of to the side, changed “reasoning” into “goals” which is easier to understand and still useful, reduced the number of qualities and added some new ones similar to the old reasoning (e.g. ‘obligation’ & ‘reward’), came up with MUCH better sample tasks and fixed a small issue with the bottom bar!"}, {"post_id": 65770, "ts": "2026-09-11T04:14:17Z", "hours": 6.3225, "text": "I did a bunch of work on the settings and added a “theme”! (Different variations of the base colour - which is now changeable in the settings!) I also used HSLuv instead of just HSL (which I tried before and thought it didn’t do much but now I realise it did help make everything nicer). I also added an effect so when you press on buttons it decreases the border radius a bit! And lastly I thought I’d fix some issues super quick due to the increased layout diversity from the settings but ended up spending much longer on them than expected, those being the jumpyness of the settings dropdowns (so I removed the animations and fixed it up a bit more and also fixed the flowlayout because it turns out everything is broken), fixed scrollbars inside other scrollbars, and probably more I forgot."}, {"post_id": 65060, "ts": "2026-09-09T22:07:39Z", "hours": 4.7747, "text": "Tweaked the colours lots and I’m now quite happy with how it’s at! Added auto generating colours for everything I didn’t before (the calendar, settings, importance and some buttons in overlays) Saved the dark/light theme to a settings file And fixed a bug with the confirm and move overlays being a strange fixed width!"}, {"post_id": 64549, "ts": "2026-09-09T01:39:01Z", "hours": 7.5414, "text": "Added dynamic colours! Don’t worry that it looks kinda bad right now, I had to learn UI design from scratch for this, and I will improve it soon. Made all the colours (well, most of them for now) generate based on a base colour and added a light and dark theme! I also made the Android navigation icons and the svgs change between light and dark properly. I spent quite some time trying to implement HSLuv or HCT in the hopes it would improve the colours but ended up scrapping that due to many reasons, including too much extra stuff, wasn’t making much (or any) difference, and my HCT implementation was just so broken and I wasn’t bothered to try and fix it. Also some parts are now extra broken, I’ll fix them soon too don’t worry! I had to devlog this in case I went over 10h by accident, hopefully will be resolved before the next one"}, {"post_id": 62540, "ts": "2026-09-05T23:38:38Z", "hours": 4.4194, "text": "Improved some UI layouts, clarified a sentence or two in the conversation, reordered the tasks page, made selecting the title in the task overlay hide the buttons (to make it easier to see), fixed some visual bugs (maybe?), improved some icons, changed ‘today’ to ‘starred’ (and made it not clear at the end of the day; I wanted to plan for the future) and last but not least I made the grey background for some of the overlays reach past the navigation AT LAST! So now the title bar doesn’t look off when the overlays are open!"}, {"post_id": 50885, "ts": "2026-08-20T10:54:28Z", "hours": 3.4444, "text": "Added an app icon and FINALLY got around to actually drawing the Grapefruit character! Also improved some parts of the conversation a bit more, improved the default tasks, improved the date importance calculations a smidge and fixed many tiny issues. It should now be DONE!"}, {"post_id": 47411, "ts": "2026-08-15T10:28:21Z", "hours": 0.8222, "text": "I thought I was done but turns out I forgot to add scrolling to the tasks list, so it would cause large issues if there were many tasks (or if the screen height was very low, as it does get on mobile when the keyboard is up)"}, {"post_id": 47355, "ts": "2026-08-15T07:43:42Z", "hours": 1.3553, "text": "Improved the “X weeks away” text (which was just wrong before) and added a today toggle and category button!"}, {"post_id": 46825, "ts": "2026-08-14T10:57:19Z", "hours": 6.6328, "text": "Did various small improvements, including: Many many bugfixes, rearranging the task and settings display to have buttons on the bottom (from user feedback), a help screen, a ‘move task to another category’ button and dialogue (which I cannot believe I forgot about until now) and added another purpose in the conversation for the user designated reason (so it actually gets shown sometimes)!"}, {"post_id": 42346, "ts": "2026-08-07T00:53:14Z", "hours": 5.9806, "text": "Added all sorts of cool things, including info in the settings page, bullet points to the text edits, changed the preset times and tasks, extra conversation features (failsafes and external functions), and improved the conversation some more (because it was fun)!"}, {"post_id": 41181, "ts": "2026-08-05T07:11:58Z", "hours": 8.2414, "text": "Finished the conversation! (It may change/get improved more later, but for now I’m happy with it!) I made many changes to some terrible phrasing choices I made previously (e.g. “But why won’t you do xyz? It’s super fun!” -> “You don’t have to do it if you don’t want to”), rewriting huge chunks of it and adding other huge chunks. (I hope you appreciate the dialogue, I’ve apparently spent 20 hours by now JUST on that, not even the code behind it) Also changed times to use +...m as well as +...h and included a preset range of times which are more on the short side to incentavise shorter tasks."}, {"post_id": 39244, "ts": "2026-08-02T02:43:56Z", "hours": 1.5244, "text": "Added buttons to insert new lines above/below, saving information to an external file automatically and trimming whitespace off of some things (a small convenience when on mobile)"}, {"post_id": 38611, "ts": "2026-08-01T02:54:26Z", "hours": 7.6272, "text": "Finalised the connection between the task engine and the conversation including adding variety, conversation suggestions knowing about the qualities and reasons, a significantly improved conversation (that’s almost done!!), a lot of conversation backend (including a custom parser for recursive synonym choices) and heaps more!"}, {"post_id": 36925, "ts": "2026-07-29T10:13:07Z", "hours": 6.4594, "text": "Spent pretty much the entire time working on the conversation choices and options (yes it’s that difficult). Also made some improvements to the backend (extra features making it easier/possible to do some things, fixed bugs). Still not done the conversation, will be another long stretch until I finish it but it’s nearly there!"}, {"post_id": 35517, "ts": "2026-07-27T00:18:06Z", "hours": 4.7739, "text": "Worked on the conversation, improving the quality of texts and options, and added some new options and features! Also added some cool mathy functions for determining task urgency/load!"}, {"post_id": 33452, "ts": "2026-07-23T12:45:03Z", "hours": 3.1211, "text": "Added the beginnings to the task importance system and implemented a cool task bottom text including progress, and also included that task progress in the task overlay popup at the bottom!"}, {"post_id": 33268, "ts": "2026-07-23T01:41:19Z", "hours": 1.11, "text": "Implemented a bunch of small improvements and fixes to the calendar popup and date highlight!"}, {"post_id": 32915, "ts": "2026-07-22T11:46:31Z", "hours": 4.1114, "text": "Spent the whole time working on a date selector! Also added text about the due date, e.g. “was due yesterday”, “due next Monday (in 5 days)”, etc."}, {"post_id": 32801, "ts": "2026-07-22T05:52:27Z", "hours": 1.6331, "text": "Implemented many extremely minor things brought up from user feedback, including: adding titles to the category and task list, using e.g. +2.5h instead of #E for counting time, improved the importance selection layout, ordering tasks, improving done task formatting (with tick and strikethrough) and other even more minor things!"}, {"post_id": 32262, "ts": "2026-07-21T10:09:04Z", "hours": 4.2289, "text": "Added a qualities screen to add qualities to tasks by clicking on the buttons and a lot of backend work to make everything run smoother and easier to code!"}, {"post_id": 31592, "ts": "2026-07-20T03:27:25Z", "hours": 3.4722, "text": "Added an importance slider, an info text and some minor things to the task overlay"}, {"post_id": 31054, "ts": "2026-07-19T04:15:30Z", "hours": 3.5669, "text": "Fixed a lot of bugs in the tasks area; including resizing issues, inability to scroll, and wrapping problems."}, {"post_id": 30597, "ts": "2026-07-18T09:33:18Z", "hours": 6.4275, "text": "Added task groups and an add, rename, and delete task group button that do things! Deleting, naming collisions and other problems are also handled with dialogues! Also added a slightly better colour scheme"}, {"post_id": 30005, "ts": "2026-07-17T07:38:26Z", "hours": 3.5383, "text": "Added a basic scene!!"}, {"post_id": 23344, "ts": "2026-07-06T07:27:06Z", "hours": 5.0297, "text": "Dramatically improved the backend for the conversation, adding many new features!"}, {"post_id": 23221, "ts": "2026-07-06T01:25:52Z", "hours": 5.4508, "text": "Added a parser for conversation backend data and an options list and text box to display it in!"}, {"post_id": 20674, "ts": "2026-07-02T10:21:27Z", "hours": 4.2228, "text": "Added a bottom bar to the task input including some utility functions like move up and down, a sample highlight that can get modified with the + and - timer buttons and a scrollbar!"}, {"post_id": 20454, "ts": "2026-07-02T01:36:55Z", "hours": 7.5497, "text": "Added an item input field with a bottom bar with utilities in it!"}, {"post_id": 19643, "ts": "2026-07-01T00:49:45Z", "hours": 4.1286, "text": "Added more to the UI layout, including a settings (with accordian sections) and new tasks (currently empty) page!"}, {"post_id": 19012, "ts": "2026-06-30T05:31:27Z", "hours": 5.6044, "text": "Added the very basic interface! The reason it took so long was because I had zero idea how to compile anything and took way too long figuring that out. But it can compile for desktop or mobile now! (although desktop is only for testing)"}]...
|
Title: Grapefruit by @tsunami014 | Stardance
Devl Title: Grapefruit by @tsunami014 | Stardance
Devlogs:
Added the very basic interface! The reason it took so long was because I had zero idea how to compile anything and took way too long figuring that out. But it can compile for desktop or mobile now! (although desktop is only for testing)
Added more to the UI layout, including a settings (with accordian sections) and new tasks (currently empty) page!
Added an item input field with a bottom bar with utilities in it!
Added a bottom bar to the task input including some utility functions like move up and down, a sample highlight that can get modified with the + and - timer buttons and a scrollbar!
Added a parser for conversation backend data and an options list and text box to display it in!
Dramatically improved the backend for the conversation, adding many new features!
Added a basic scene!!
Added task groups and an add, rename, and delete task group button that do things! Deleting, naming collisions and other problems are also handled with dialogues! Also added a slightly better colour scheme
Fixed a lot of bugs in the tasks area; including resizing issues, inability to scroll, and wrapping problems.
Added an importance slider, an info text and some minor things to the task overlay
Added a qualities screen to add qualities to tasks by clicking on the buttons and a lot of backend work to make everything run smoother and easier to code!
Implemented many extremely minor things brought up from user feedback, including: adding titles to the category and task list, using e.g. +2.5h instead of #E for counting time, improved the importance selection layout, ordering tasks, improving done task formatting (with tick and strikethrough) and other even more minor things!
Spent the whole time working on a date selector! Also added text about the due date, e.g. “was due yesterday”, “due next Monday (in 5 days)”, etc.
Implemented a bunch of small improvements and fixes to the calendar popup and date highlight!
Added the beginnings to the task importance system and implemented a cool task bottom text including progress, and also included that task progress in the task overlay popup at the bottom!
Worked on the conversation, improving the quality of texts and options, and added some new options and features! Also added some cool mathy functions for determining task urgency/load!
Spent pretty much the entire time working on the conversation choices and options (yes it’s that difficult). Also made some improvements to the backend (extra features making it easier/possible to do some things, fixed bugs). Still not done the conversation, will be another long stretch until I finish it but it’s nearly there!
Finalised the connection between the task engine and the conversation including adding variety, conversation suggestions knowing about the qualities and reasons, a significantly improved conversation (that’s almost done!!), a lot of conversation backend (including a custom parser for recursive synonym choices) and heaps more!
Added buttons to insert new lines above/below, saving information to an external file automatically and trimming whitespace off of some things (a small convenience when on mobile)
Finished the conversation! (It may change/get improved more later, but for now I’m happy with it!) I made many changes to some terrible phrasing choices I made previously (e.g. “But why won’t you do xyz? It’s super fun!” -> “You don’t have to do it if you don’t want to”), rewriting huge chunks of it and adding other huge chunks. (I hope you appreciate the dialogue, I’ve apparently spent 20 hours by now JUST on that, not even the code behind it) Also changed times to use +...m as well as +...h and included a preset range of times which are more on the short side to incentavise shorter tasks.
Added all sorts of cool things, including info in the settings page, bullet points to the text edits, changed the preset times and tasks, extra conversation features (failsafes and external functions), and improved the conversation some more (because it was fun)!
Did various small improvements, including: Many many bugfixes, rearranging the task and settings display to have buttons on the bottom (from user feedback), a help screen, a ‘move task to another category’ button and dialogue (which I cannot believe I forgot about until now) and added another purpose in the conversation for the user designated reason (so it actually gets shown sometimes)!
Improved the “X weeks away” text (which was just wrong before) and added a today toggle and category button!
I thought I was done but turns out I forgot to add scrolling to the tasks list, so it would cause large issues if there were many tasks (or if the screen height was very low, as it does get on mobile when the keyboard is up)
Added an app icon and FINALLY got around to actually drawing the Grapefruit character! Also improved some parts of the conversation a bit more, improved the default tasks, improved the date importance calculations a smidge and fixed many tiny issues. It should now be DONE!
Improved some UI layouts, clarified a sentence or two in the conversation, reordered the tasks page, made selecting the title in the task overlay hide the buttons (to make it easier to see), fixed some visual bugs (maybe?), improved some icons, changed ‘today’ to ‘starred’ (and made it not clear at the end of the day; I wanted to plan for the future) and last but not least I made the grey background for some of the overlays reach past the navigation AT LAST! So now the title bar doesn’t look off when the overlays are open!
Added dynamic colours! Don’t worry that it looks kinda bad right now, I had to learn UI design from scratch for this, and I will improve it soon. Made all the colours (well, most of them for now) generate based on a base colour and added a light and dark theme! I also made the Android navigation icons and the svgs change between light and dark properly. I spent quite some time trying to implement HSLuv or HCT in the hopes it would improve the colours but ended up scrapping that due to many reasons, including too much extra stuff, wasn’t making much (or any) difference, and my HCT implementation was just so broken and I wasn’t bothered to try and fix it. Also some parts are now extra broken, I’ll fix them soon too don’t worry! I had to devlog this in case I went over 10h by accident, hopefully will be resolved before the next one
Tweaked the colours lots and I’m now quite happy with how it’s at! Added auto generating colours for everything I didn’t before (the calendar, settings, importance and some buttons in overlays) Saved the dark/light theme to a settings file And fixed a bug with the confirm and move overlays being a strange fixed width!
I did a bunch of work on the settings and added a “theme”! (Different variations of the base colour - which is now changeable in the settings!) I also used HSLuv instead of just HSL (which I tried before and thought it didn’t do much but now I realise it did help make everything nicer). I also added an effect so when you press on buttons it decreases the border radius a bit! And lastly I thought I’d fix some issues super quick due to the increased layout diversity from the settings but ended up spending much longer on them than expected, those being the jumpyness of the settings dropdowns (so I removed the animations and fixed it up a bit more and also fixed the flowlayout because it turns out everything is broken), fixed scrollbars inside other scrollbars, and probably more I forgot.
I improved how tasks are made, making the task overlay centred instead of to the side, changed “reasoning” into “goals” which is easier to understand and still useful, reduced the number of qualities and added some new ones similar to the old reasoning (e.g. ‘obligation’ & ‘reward’), came up with MUCH better sample tasks and fixed a small issue with the bottom bar!
Ships:
I finally decided I had done enough and it was really good! This app contains the conversation, a scene with Grapefruit in it, a basic settings page with not much in it, a tasks manager with categories (including a today category) and tasks with importance, reasoning, qualities, items! Also has a great bottom bar for easier text editing and has everything layed out in a mobile-friendly manner! Installation instructions are in the README
FIXED THE UI with dynamic colours and themes! Fixed some layouts Improved how tasks are made (including a not overwhelming amount of qualities and changed the ambiguous “reasoning” into a much less so “goals” As well as many minor also cool things! (See the devlogs after ship 1 for the full account)...
|
1792997630.288298
|
1793084030.288298
|
|
29121
|
hivemind by @justin0711 | Stardance
|
justin0711
|
0
|
134.77
|
0
|
[]
|
[{"post_id": 46864, "ts": "202 [{"post_id": 46864, "ts": "2026-08-14T12:22:31Z", "hours": 20.5064, "text": "We’re developing a Rust sandbox, adding a bunch of features to make it function like a programming language."}, {"post_id": 45532, "ts": "2026-08-12T02:26:01Z", "hours": 15.4608, "text": "I wrote a detailed document for the official website and also wrote a sandbox executor in Rust, which I think has excellent performance and usability."}, {"post_id": 37401, "ts": "2026-07-30T02:49:53Z", "hours": 9.3197, "text": "The previous front-end was merged, and a preliminary sandbox interpreter was written, which has the functions of conditional variable function operations and conditional judgment .."}, {"post_id": 33256, "ts": "2026-07-23T00:50:53Z", "hours": 15.6447, "text": "Fixed the issue where the master could not view logs correctly, deployed nodepool and VPN services, and included the VPN client in the installation package."}, {"post_id": 29339, "ts": "2026-07-16T06:51:50Z", "hours": 2.1697, "text": "write the official website and fixed some previous architectural issues. changed the task ID to UUID."}, {"post_id": 29289, "ts": "2026-07-16T03:14:02Z", "hours": 71.6733, "text": "The entire system has been refactored using Rust, and the underlying sandbox has been replaced."}]...
|
Title: hivemind by @justin0711 | Stardance
Devlog Title: hivemind by @justin0711 | Stardance
Devlogs:
The entire system has been refactored using Rust, and the underlying sandbox has been replaced.
write the official website and fixed some previous architectural issues. changed the task ID to UUID.
Fixed the issue where the master could not view logs correctly, deployed nodepool and VPN services, and included the VPN client in the installation package.
The previous front-end was merged, and a preliminary sandbox interpreter was written, which has the functions of conditional variable function operations and conditional judgment ..
I wrote a detailed document for the official website and also wrote a sandbox executor in Rust, which I think has excellent performance and usability.
We’re developing a Rust sandbox, adding a bunch of features to make it function like a programming language....
|
1792540213.9539003
|
1793145013.9539003
|
|
9616
|
revo by @ratmuds | Stardance
|
ratmuds
|
1
|
134.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-21T01:26:40Z", "hours": 134.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I wanted to make a robot arm that punched above it’s weight. The price is pretty similar to smaller robot arms on Amazon that may not include cameras, which would need to be purchased seperately. The way this is achieved by using cheap servos, servos that are 100% NOT made for this purpose, and adding most of the functionality of a smart servo back by using a TON of PCBs. It was a lot of soldering. I just wanted to make something that had more features for less money :) This project was SUPER difficult for me, and pushed my limits a bit. The amount of tolerences especially for the stupid custom motor case and magnet and PCBs and the crazy mainboard and generally having everything play well together took so long, I had many days where I quit frustrated. I’m very happy about how it turned out though, even seeing the lots of shortcomings it has.", "repo": "https://github.com/ratmuds/revo", "demo": ""}]...
|
[{"post_id": 71545, "ts": "202 [{"post_id": 71545, "ts": "2026-09-21T01:17:14Z", "hours": 1.7336, "text": "Finish Project Up :) I wrote a ton in the repository im tired :( https://github.com/ratmuds/revo"}, {"post_id": 71258, "ts": "2026-09-20T15:14:42Z", "hours": 3.1572, "text": "Setup VR and Gripper, Robot Rapidly Disassembles my robot arm is broken I setup VR and fixed some more IK when I go into VR and try playing around, it instantly flies out and throws itself off the table and breaks into pieces. This is going to be fun to fix."}, {"post_id": 70809, "ts": "2026-09-19T19:55:52Z", "hours": 3.8861, "text": "Integration Hell I’ve just been like trying to get this stupid project to work. Screws keep falling out, the IK keeps failing, things are hitting each other and wires are being strained I’m in integration hell. Everything works fine on its own, but combining everything is horrible. I’ve been reassembling and trying to fix this stupid thing for so long. Anyway I’ve went through a few more revisions of some CAD and some more refinements and the gripper and camera is now mounted but this is just incredibly incredibly annoying :(((("}, {"post_id": 69881, "ts": "2026-09-18T00:05:17Z", "hours": 3.8311, "text": "Fixed Broken Magnet, Redoing all IK joint data and offsets, Stereo depth test An encoder magnet broke off, so I had to disassemble and reassemble the top half of the arm to get to the encoder magnet and glue it back on. I also started properly punching in the IK joint data, before it was mostly just random data but now almost all of the data is mostly correct, and I’m waiting for a print to complete that will flip a motor to finally get the IK simulation matching with real life and have the IK endpoint be tracked at the tip of the gripper. It was a lot of trial and error and measurements. I also started experimenting with adding depth estimation. Eventually this could add collision avoidance IK pathfinding, which would be really cool but it’s just a pointcloud in the render right now. But the robot arm is slowly coming together finally! I’ll be able to grab something soon I think."}, {"post_id": 68903, "ts": "2026-09-16T00:31:34Z", "hours": 2.8461, "text": "Assembled Full Arm (not all motors active yet for safety) and Basic Interpolation for Control I assembled the new full arm assembly minus the end effector and didn’t plug in the first two motors as they have the highest chance of doing something really bad. I also made some general changes to the code and also added a flag to some motors to interpolate their movement slowly to not explode the robot arm while controlling it."}, {"post_id": 68352, "ts": "2026-09-15T00:17:44Z", "hours": 2.5044, "text": "Significantly Better Motor Control and Gripper CAD The motor code was getting a bit messy, so I rewrote it. I separated the motor code from the main control code which cleaned it up a bit. LADRC I’m using LADRC now. It’s kind of like PID, but advanced. I took the implementation from online. I feed it the motor current, encoder value, and the target and it goes. The algorithm or whatever somehow calculates the velocity of the motor and how much “effort” it’s using and then gives an effort to put to the motor. It somehow cancels out like disturbances like gravity, backlash, the general physics, etc. As you can see, the motor control is so so so much better than before. It cleanly decelerates. It handles load and dynamically increases effort. Before there was some oscillation because it just couldn’t figure out how to get to the target, this one is just so much better and so hands off. There’s basically like no calibration as it does it over time :)))"}, {"post_id": 67779, "ts": "2026-09-14T00:57:25Z", "hours": 1.4489, "text": "Assembled last 4 DoF for Integrated Test I assembled the MG996R servos in a test piece that will represent the full regular arm segment to test if everything worked. With some fiddling it worked. As you can see there’s more transparent pieces. The pieces that connect the previous joint are transparent to show the Neopixel below it a lot better as before the LED was almost completely occluded. The bright green LEDs power status ones are too bright but I can cover them later."}, {"post_id": 67735, "ts": "2026-09-13T23:20:04Z", "hours": 6.6769, "text": "Dashboard Revamp WIP, Tons of CAD changes, Code Updates, Tolerances I’ve just been refining everything and it’s just going really slowly. Many problems. Magnets shorting out stuff. Magnet too far and not being detected. Wires breaking. I’ve also redesigned the dashboard UI to hopefully look better. I’m still working on it, hopefully it will look more polished later. The dashboard It shows a load speedometer type thing, with the load (max current from a motor out of 500mA) and the temp on the right (for now just dummy value) The motors have cool little animations now too and look less cluttered. I’ve just been working on it a lot. Just everything in general tbh."}, {"post_id": 65061, "ts": "2026-09-09T22:13:56Z", "hours": 5.7644, "text": "Debugging and Fixing Is Killing Me and the Mainboard Exploded :( I have spent SO many hours trying to get this to work. It’s so annoying. This isn’t near how many hours I spent, I’ve been too frustrated to log it. The case is incredibly annoying. Getting the initial case works fine. Doing all of this stuff makes it complicated and break and jam up. The RS485 busses just randomly stop working. The servo output is wiggly and not stable. A PCB header snapped and I didn’t have replacements so I had to bodge solder it back on. The mainboard voltage regulator literally exploded. It was a cheap part but yeah that literally just broke stuff. Fixes to everything. CAD. Firmware. bruh"}, {"post_id": 60577, "ts": "2026-09-03T00:49:54Z", "hours": 6.7731, "text": "MG996Rs Finally Working The servos finally work. I don’t even think this amount of hours logged is equal to how long this took, because I just got tired of it. I think I printed like 20 new revisions of the case and servo mount. It was just so so annoying. While the general case worked, getting a reliable magnet output shaft was impossible. From tolerances, to my own errors to binding to hot glue getting everywhere, or superglue binding random gears, or my getting my fingers stuck to the actual case from superglue (was not fun and hurt) The case finally works. And the prototype code somewhat works too. It basically rotates until the sensor hits zero, it resets the “ticks”. A tick is a raw output from the AS5600. Because this magnet shaft spins faster than the output shaft, like 10x faster, the MCU needs to poll the sensor super quickly, which also needed some optimizations to clear the blocking bus communication wait that would let the magnet skip multiple full turns. The sensor doesn’t internally count turns so we just need to count manually and detect when it jumps from 4096-0 or the other way around. It then spins around until the sensor is hit AGAIN to calculate tick to degrees, assuming the sensor was zeroed before, and then the current ticks would equal 360 degrees. Another problem was the servo needs a PWM signal to move. The threshold from stop to go is pretty garbage on these cheap servos, leading it to spin quite fast already when at the lowest PWM value. Instead when far from the value it increases the PWM signal, closer it brings to minimum and starts linearly flickering the PWM signal from 0 to the speed, with the closer it is the more ratio of time stopped to inch it closer to the target. It actually surprisingly works. It’s very fragile though, any skipped reads, from potentially slow bus transfers would completely throw it off, so all the code running locally on the weak 8 bit MCU needs to be extremely lightweight. Yeah this was super super painful. I’ve been sitting here redoing superglue and code for hours."}, {"post_id": 58979, "ts": "2026-08-31T15:36:35Z", "hours": 3.4036, "text": "Servo Code I did some slight refining to the servo case again, making the tolerances tighter to keep the gears from wobbling. It’s still sort of loose, so I need to just keep trying over and over again. I’m also still writing the servo code. It’s already much more organized than before. I’m also learning Vim keybinds and stuff to try and code faster. The RS485 bus communication works now, and it’s just sending dummy telemetry data back right now. It can also control the servo fine. I’ve just been doing like the lower level architecting I guess, or not really I’m not sure. Before everything was crammed into a single file and now there’s actually header files and multiple source files and it’s actually somewhat readable. I had an issue with LED control for a second but that’s fixed now :)"}, {"post_id": 58467, "ts": "2026-08-30T21:44:37Z", "hours": 2.4922, "text": "V2 Servo Case Working; Servo Code Revamp WIP After around 10 more revisions, the new servo case is fully working with the magnetic extender. The V2 is significantly better designed and higher efficiency than the last, more guess and check result. I’ve also started to rewrite the servo code. Right now, its really messy and just kind of snowballed over time as I’ve slapped on patches and features to a fundamentally weak base. I’m in the progress of writing that now, hopefully it will be done soon. It will also include the new auto calibration and encoder usage and PID (and potentially advanced auto tuned curve to combat motor acceleration overshoot and backlash)"}, {"post_id": 57778, "ts": "2026-08-30T02:16:49Z", "hours": 3.8514, "text": "Working on IK System & Resoldered Joints Again Bruh so my robot arm after finally being assembled by the way exceeded it’s limits and tore its wires out. I had to take apart the mainboard assembly again, which just is SO TEDIOUS. I just dumped solder and hot glue again and fixed a short caused from another wire being sheared off. Also I’m working on the IK system, but it’s not really going well right now. I need to add offsets and config to each of the motors to get them to work correctly. The motors hooked up right now started crashing into my table sadly. Hopefully it will work soon. I also continued working on the servo case. I still haven’t added the code to calibrate and get closed loop control on the MG996R servos. The DS5180 encoders should be easier though."}, {"post_id": 57272, "ts": "2026-08-29T11:42:11Z", "hours": 3.1006, "text": "Reprinted Arm Segments; Added Segment Cover; Servo Mount Working; Working on Web UI I reprinted the arm segments, hopefully for one of the last times, I’ve went through so much filament already. It now allows the mainboard to be neatly packed inside, hiding most of it while still allowing wires to come out. Due to the design of the mainboard, the wires do have to stick out the front like that sadly. To avoid crushing wires, the servo mount has been expanded to allow more clearance for wires and general electronics. The servo mount works now with a new design. I remeasured and adjusted the sketches and added proper hole sizes and a little chamfer to allow the insert to slot in before using a soldering iron to melt it in to help align much better than before. The web UI now shows a representation of the arm. It’s not tuned yet, so the angles are wrong but I’ll fix it soon. I had to move everything from Fusion to Onshape to create the assemblies, and then use a Python library to convert the Onshape assembly into a URDF file that can be rendered with the correct joints inside ThreeJS. Next, I’ll be adding IK and general arm control."}, {"post_id": 56800, "ts": "2026-08-28T18:32:28Z", "hours": 3.1978, "text": "Heatset Inserts Working; Fixing Faulty Motor Power Connections; Internal Fan Power Connectors I verified that the servo cover works, and it’s much much better than the last version. The tolerances are much better this time, leading to less stress on the gears. The same amount of turning uses around 100mA compared to 300mA before, almost reaching it’s limit without any load. Some motor power connectors disconnected, so I found it with a multimeter and added hot glue to some connectors to secure them. I soldered the fan power things inside the PCB, but realized that the JST connectors I’m using are different from the fans. I might have to make a sort of adapter or something by crimping more wires. And the heatset inserts finally work after some tweaking, before the inserts would get misaligned when put in, now with a aligning lip thing it can be slotted in and melted in more accurately."}, {"post_id": 56316, "ts": "2026-08-28T01:34:32Z", "hours": 4.6306, "text": "New Mainboard Cover, Wiring, Bearing Revamp, Heatset Inserts, Servo Cover I added space for the mainboard segment, now it has clearance to actually fit, I redid the cover for this segment, and now it can allow the wires to come out The servo mount now has heatset inserts, because the previous screw in print kept slipping out, but this time the screws just would not go into the inserts through the mount for some reason? The screws went in normally, but with the tolerances, when multiple screws go in they just fight and push against the edge of the insert instead of going in. The MG996R servo housing now has been redesigned, based off of picture references and calipers to attempt to be more accurate than the last one to try and reduce the amount of bad tolerances affecting the gears and making them misaligned, reducing torque output. And just general wiring and CAD work."}, {"post_id": 55294, "ts": "2026-08-27T01:14:32Z", "hours": 2.9064, "text": "Assembled Basic Arm Parts and Packaged Main Board Assembly; Reprogrammed servo MCUs & worked on web UI I redid some soldering on the mainboard PCB, secured connections, and secured everything with tape for now. I’ll likely have to reprint the first arm segment to fit everything in flush because as you can see there are wires and things bulging out of the segment itself right now. I also redesigned the CAD to include heat set inserts. I did programming and a bunch of bug testing and fixing too. An hour of time was lost because Lapse errored out :((((( very sad about that :( I also had an issue with data corruption on the RS485 bus but that is fixed now, and it works like it should."}, {"post_id": 54840, "ts": "2026-08-26T00:29:08Z", "hours": 4.3236, "text": "Mainboard Stack Redo & Firmware Updates and Test Web UI I had to take the electronics out, and redo some of the wiring. The screw terminals are pretty cheap and suck, which makes it incredibly annoying to use as it’s impossible to fit these thicker AWG wires in and they sometimes slide out of the terminals. When I’m done I’m probably going to hot glue the wires. The incredibly fragile flexible extension jumpers for data transfer between the stack is also super fragile, and especially doesn’t grip. Sometimes the data wires just slip out. I took apart the arm, as during testing the motor stripped some screws. I’ve ordered some heat set inserts to prevent that from happening again, which will require me to reprint all the arm segments again. I also added a simple web UI for moving the joints. There is an empty ThreeJS sidebar and the right has some graphs (real data) from the mainboard sensors. The smaller MG996R servos haven’t been mounted yet due to a power delivery issue from the mainboard but hopefully that will be fixed soon."}, {"post_id": 28657, "ts": "2026-07-15T01:25:27Z", "hours": 4.0167, "text": "Test assembly and fitting of robot arm I am mostly done with the core functionality of the mainboard, so i packed everything together and double checked eerything works including power Then I started assembling most of the servos The smaller servo casing doesn’t fit very well, and the transparent window doesn’t fit either But the magnetic cover for the arm segments works great :) It was a lot of fitting, screwing, testing with multimeter, etc"}, {"post_id": 28409, "ts": "2026-07-14T17:26:49Z", "hours": 5.1303, "text": "Finalizing hardware I crimped and soldered almost the remaining wires, I’ve made some last redesigns to the arm CAD and I’m now fitting everything into the new prints and assembling. I’ve also had a ton of trouble with my servo PCBs lately, but I found out a lot of the issue was my programmer is actually fried somehow, so I’m now using an old RPi Pico to act as a UPDI adapter so PlatformIO can now successfully program the ATtinys much better now. A lot of the CAD was slightly tweaked so that everything fits better"}, {"post_id": 26853, "ts": "2026-07-11T21:36:43Z", "hours": 1.175, "text": "Servo firmware almost done The servo firmware now (with the mainboard) sends validation data back and forth so both the servo and mainboard can verify that the data was sent successfully and can ignore corrupted packets because my wiring can be flaky sometimes The firmware now sends real data again and is much more robust, with a proper stateful LED that shows useful information, like offline, online and driving motor, homing, error (fast flashing of LED as red), and the error state is also triggered in the case of corrupted packets (I tried it and it works :)) I’m also still printing out the pieces to assemble the arm. I actually have more hours working on it, I just forgot to log :((((((("}, {"post_id": 26218, "ts": "2026-07-10T21:40:32Z", "hours": 8.1217, "text": "Rewrote all firmware; Fixing Servo Cover and a ton of other CAD; Almost fried everything For the CAD, it doesn’t look like much changed, but I’ve basically redesigned a bunch of things and fixed tolerances and now it should move really smoothly. With the bearings added, everything moves incredibly smoothly now Especially the servo cover was annoying. I needed to attach a magnet to the shaft which was really annoying. I haven’t logged that well, I’ve done more like 15 hours of work instead of just 5 but whatever Most of those hours was the painful debugging. RS-485 busses, JSON not communcating with the PC, dropped connections, corrupted data, disconnected jumpers, FTDI programmer becoming flaky for some reason It’s just been pain :((( Now the PC (screenshot) recieves all the data and sends all the data You can see a lot (not all) of the telemetry being received. Ignore the volts though my math is wrong. Realtime connecting now works smoothly, as you can see the other RS485 servos are offline."}, {"post_id": 24091, "ts": "2026-07-07T13:11:08Z", "hours": 5.9586, "text": "Bidirectional Communication To PC/RPi 5 with LeRobot & More CAD changes I setup a basic class for my robot in LeRobot (which was a little confusing) and then I also got communication between the Pico and my PC working. Originally I have SPI pins exposed on my mainboard PCB to connect to the RPi 5’s GPIO pins, but for some reason after lots of debugging, even running it at super low speeds it just would not work. So I switched to just using serial over USB, and using the SerialTransfer library to send data more reliably. The script on the PC now can send target joint angles, and receive a lot of data back, like if the joint is online, temp, current, angle, homing sensor, home status, LED, firmware version, voltage, etc I also iterated on the CAD for everything, and it should be done soon. It’s just a bunch of tolerance fixes to make everything fit at this point and some new things like mounts for encoders and DC buck modules and fixing the CAD for the custom MG996R case."}, {"post_id": 23468, "ts": "2026-07-06T13:46:37Z", "hours": 1.9767, "text": "Mainboard and other CAD I got the mainboard to stack on top of each other with a weird jumper and two piece jumper holder and some screws setup which required some revisions and trying to get everything to fit. I’ve squeezed one of the DC buck modules into between the mainboard, and the second arm segment will hold the two remaining DC buck modules. The bottom mainboard PCB also has 2 smaller buck modules. There’s a lot of things going on with the voltages in this project due to the servos peak current draw being so large. I also refined the arm segment CAD by some reprints and made the DS5180 servo fit better. I’ve also made one of the buck module mounts for the second arm segment to fit more cleanly."}, {"post_id": 22393, "ts": "2026-07-04T21:03:02Z", "hours": 4.3272, "text": "Servo Control Working, More CAD and 3D Printing I got the mainboard to be able to control the servo on the servo PCBs. I also tested a bunch of the functions, like the magnetic sensor, neopixel LED, etc The communication now sends the PCB ID, and the target speed and the servo PCB echos it back and moves the servo. I also worked on the CAD (and refined) for the mainboard connector that will make connecting the two mainboards not a total pain. I also soldered the connectors on the mainboard PCBs for them to connect to each other."}, {"post_id": 21568, "ts": "2026-07-03T16:23:00Z", "hours": 0.4833, "text": "Servo PCB Daisy Chaining Working I plugged in the JST VH and JST 1.25mm wires into the PCBs, and they seem to work! I adjusted the message struct to hold a desired PCB sort of address or ID. When the MCU detects that the ID matches the PCB (by using the solder jumpers at the bottom of each PCB to program the PCB ID), only then it lights up the LED and replies to the main board. The mainboard now loops through IDs and sends a message and waits for a response. I’m very very happy this worked without any really big problems."}, {"post_id": 21540, "ts": "2026-07-03T15:45:12Z", "hours": 3.4667, "text": "Crimped JST VH wires, Connected JST 1.25mm wires, Soldered more PCB connectors Crimping JST VH wires is a ton easier than JST 1.25mm, and after a bunch of failed attempts still, I got some okay crimps that work finally. It took me a long time because I didn’t know that I had to rotate the wire for the hook on the terminal to go into the housing hole, and then also that the box shape part on the terminal actually has to stick out of the crimper or the crimper will crush the whole terminal into bits"}, {"post_id": 21185, "ts": "2026-07-03T00:14:50Z", "hours": 4.7722, "text": "Finished Soldering all Smaller PCBs & Got RS-485 communication working from main board to servo PCBs First, I finished soldering the PCBs. I added the connectors for power and the small data connectors. I also finished the servo expansion boards that hold the magnetic encoder and sensor. I also finished soldering the joint encoder PCBs that will track shoulder and elbow lift servo positions. I also got the bus communication to work. It was really really painful and I was really scared it wouldn’t work. First, the PCBs wouldn’t communicate at all. But eventually, I realized that it was because I wasn’t supplying 3.3V to the main board. This is when I realized that I haven’t adjusted the buck converters on the main board to supply the correct voltage, so I was about to unsolder the buck converter when I realized that I could just set the power supply to 5V (which the ICs on the mainboard can handle luckily), and then adjust the voltage down to 3.3V. But after a really long time of debugging, it still wasn’t working. The connection would sometimes work but was really flaky. Eventually, I soldered on the RPi Pico 2 onto the board completely and then found out the reason, it was because the ATtiny3216 was set to clock at a slow speed that would mess with the communication. I made them use the SerialTransfer library to send data more reliably and it now can communicate properly :)"}, {"post_id": 20354, "ts": "2026-07-01T22:40:54Z", "hours": 5.5597, "text": "Done Soldering Most PCBs, Crimped JST wires kind of I’m pretty much done soldering, I just have like 3 more tiny PCBs and I should be done. The big main board PCBs are pretty much done, I just need to make some botched tall headers since the clearance of regular headers are too small, and the servo PCBs are almost done, with just some connectors left to solder. Soldering JST 1.25mm wires ARE THE WORST EVER THING TO EVER EXIST I spent 2 hours crimping terminals on multiple wires and its so so so annoying. I can barely hold the terminal itself and they are so easy to bend. I couldn’t afford the real tool to crimp them, so I have cheap crimpers that are the wrong size and can’t technically crimp these. If crimping the metal things wasn’t bad enough, inserting the terminals into the housing was even worse. The housing would bend, or I would accidentally somehow insert it where it shorts the pin next to it??? Also while soldering a JST 1.25mm connector on a PCB, I ripped the pads clean off the PCB. I guess that one just will be missing the daisy chain feature because it only has one connector for data now and all the components and MCU are already soldered on, which really sucks. The rest of the servo PCB (4 in total for now) went fine though, and I’m getting faster at it."}, {"post_id": 18843, "ts": "2026-06-30T01:27:03Z", "hours": 4.7572, "text": "Worked on firmware & CAD & Soldered Second PCB I got the PCB and ATtiny3216 to power a servo. I soldered on the remaining components on it, like the custom LED (which just turns on when the motor is spinning for now) and the 100uF capacitor and also the RS485 bus IC. I also changed the CAD of the arm to use a bearing and changed the servo horn to fit inside of the bearing. I’ve ordered right angle headers and the bearing and metal servo horn already. I also added some transparent parts to the arm design to make it look more interesting hopefully. I also am almost done soldering the second servo PCB. Now that I have all the parts ready and I actually got better at soldering ICs I can do it faster now."}, {"post_id": 17022, "ts": "2026-06-27T17:00:47Z", "hours": 4.0433, "text": "Finally got ATtiny3216 on PCB Working This took so so long. Basically, I spent hours trying to get it to work. First, the 3.3V rail wasn’t getting power and the LED wasn’t lighting so I had to resolder the voltage regulator and then both green LEDs lit up, meaning everything was working. Then I got my FTDI programmer, and plugged it into my PCB. Because I have a FTDI programmer and the ATtiny3216 has a UPDI programming interface, there is a resistor on the board to combine the two pins into one. Even just getting megaTinyCore installed in Arduino IDE was a pain. The website that hosted the package info was down again, with an expired certificate. Apparently, this happens very often with it but I found an alternative mirror. Then I tried flashing code, and it didn’t work. Then I realized that the board type I was using was the Optiboot version, and I couldn’t find the non Optiboot version so I had to flash Optiboot onto the MCU. I did not realize that doing this would cause problems later on. I also had to switch the programmer from the one that programs Arduinos to the UPDI programmer. But I STILL couldn’t get any GPIO to work. I just tried things for hours. I switched to PlatformIO. I tried switching from C to Arduino in PlatformIO. I tried unplugging the programmer because I saw some voltage leaking from it. I tried emptying the caps and trying again. I probed every single pin to see if I wrote the wrong pin. Then after all of that, when I switched to non Optiboot (having to find online that I have to downgrade megaTinyCore), and flashing that, it works. I think it was because flashing a bootloader burns some fuses to expect a bootloader, but when I flash my code it actually overwrites the bootloader code because I don’t have access to the TX and RX pins typically used to flash when Optiboot is installed, and that just caused the code to not run."}, {"post_id": 14058, "ts": "2026-06-23T01:15:22Z", "hours": 2.3747, "text": "Soldered Smaller PCBs, Ordered Missing Parts, Continued CAD work I soldered most of the small PCBs, but now I need to order the parts I missed from the first order I placed. I’m also running out of 0.1uF caps, which sucks. I added a spot and holes for a fan on the camera mount and also some arm segment CAD improvements and back plating to hold the metal rods in. I printed out a test and it works fine. As for the PCBs, I’m still waiting for a few parts."}, {"post_id": 13444, "ts": "2026-06-22T00:49:23Z", "hours": 2.6311, "text": "Continued Soldering PCB (Diodes/LEDs, power circuitry, etc) and worked on arm CAD. For the PCB, after some time, I got the power switching circuit to output power. It’s a collection of things that I hope will make it safer, with a some diodes and a fuse, some MOSFETs, so the main MCU can command to send power, and also another stage that requires the E-STOP to not be pressed to actually be able to send power through with two MOSFETs (one main power, another switch the main MOSFET). I added a fan to the global shutter main wrist camera since it gets hot, and added a new “head” to the arm segment CAD (the heads are swappable depending on what you need to print) for the smaller motor for the last DOFs in the arm. It fits my custom daisy chaining two part PCB hat for the MG996R to give it current, temp, power sensing, and daisy chaining power and data via a RS485 bus with an onboard MCU to provide communication and control. I added some holes for airflow for this PCB. I also added some screw holes to actually connect the halves of the arm together."}, {"post_id": 12830, "ts": "2026-06-21T00:22:41Z", "hours": 1.6036, "text": "Continued Soldering and Working on CAD I snapped some headers and soldered on some more ICs on the PCBs. I did also mess up and ordered a wrong footprint for a part, so now I have to delay that too. It’s so tiny I can barely see the pins. I also worked on the CAD, where I designed the stereo camera holder, added a spot for the RPi 5 to go on top, and maybe a display. I also made a V2 of my grabber since the old one didn’t work well. It also seems that Stardance isn’t syncing my time properly, and it’s missing a few hours so that’s annoying :("}, {"post_id": 12281, "ts": "2026-06-20T01:43:23Z", "hours": 5.3406, "text": "I soldered some parts on the PCB, and worked on the CAD files some more I did realize that I forgot some parts, so I ordered them on DigiKey. I’ll continue soldering the rest tomorrow. One of the parts was the LDO, which I only found out because I soldered the parts and realized that the voltage being put on the 3.3V rail is 5V My project needs both versions of the same LDO and I only bought the 5V one I also bought the wrong resistors. I’ve ordered them and they should arrive in a week or so. My design of stacking the PCBs and then adding the buck modules in the middle might be very challenging, and I might need to stack multiple headers on top of each other to fit the modules inside. Hopefully it will still fit inside my arm segment and not short anything. There also needs to be sufficient airflow, which is def a challenge"}, {"post_id": 10584, "ts": "2026-06-17T12:06:26Z", "hours": 1.8508, "text": "Added Bottom Reinforcements with holes for magnets and wiring Added Fans and airflow holes And just fixed and refined the CAD, like adding spots for magnetic attached front and back plates and more"}]...
|
Title: revo by @ratmuds | Stardance
Devlogs:
Adde Title: revo by @ratmuds | Stardance
Devlogs:
Added Bottom Reinforcements with holes for magnets and wiring Added Fans and airflow holes And just fixed and refined the CAD, like adding spots for magnetic attached front and back plates and more
I soldered some parts on the PCB, and worked on the CAD files some more I did realize that I forgot some parts, so I ordered them on DigiKey. I’ll continue soldering the rest tomorrow. One of the parts was the LDO, which I only found out because I soldered the parts and realized that the voltage being put on the 3.3V rail is 5V My project needs both versions of the same LDO and I only bought the 5V one I also bought the wrong resistors. I’ve ordered them and they should arrive in a week or so. My design of stacking the PCBs and then adding the buck modules in the middle might be very challenging, and I might need to stack multiple headers on top of each other to fit the modules inside. Hopefully it will still fit inside my arm segment and not short anything. There also needs to be sufficient airflow, which is def a challenge
Continued Soldering and Working on CAD I snapped some headers and soldered on some more ICs on the PCBs. I did also mess up and ordered a wrong footprint for a part, so now I have to delay that too. It’s so tiny I can barely see the pins. I also worked on the CAD, where I designed the stereo camera holder, added a spot for the RPi 5 to go on top, and maybe a display. I also made a V2 of my grabber since the old one didn’t work well. It also seems that Stardance isn’t syncing my time properly, and it’s missing a few hours so that’s annoying :(
Continued Soldering PCB (Diodes/LEDs, power circuitry, etc) and worked on arm CAD. For the PCB, after some time, I got the power switching circuit to output power. It’s a collection of things that I hope will make it safer, with a some diodes and a fuse, some MOSFETs, so the main MCU can command to send power, and also another stage that requires the E-STOP to not be pressed to actually be able to send power through with two MOSFETs (one main power, another switch the main MOSFET). I added a fan to the global shutter main wrist camera since it gets hot, and added a new “head” to the arm segment CAD (the heads are swappable depending on what you need to print) for the smaller motor for the last DOFs in the arm. It fits my custom daisy chaining two part PCB hat for the MG996R to give it current, temp, power sensing, and daisy chaining power and data via a RS485 bus with an onboard MCU to provide communication and control. I added some holes for airflow for this PCB. I also added some screw holes to actually connect the halves of the arm together.
Soldered Smaller PCBs, Ordered Missing Parts, Continued CAD work I soldered most of the small PCBs, but now I need to order the parts I missed from the first order I placed. I’m also running out of 0.1uF caps, which sucks. I added a spot and holes for a fan on the camera mount and also some arm segment CAD improvements and back plating to hold the metal rods in. I printed out a test and it works fine. As for the PCBs, I’m still waiting for a few parts.
Finally got ATtiny3216 on PCB Working This took so so long. Basically, I spent hours trying to get it to work. First, the 3.3V rail wasn’t getting power and the LED wasn’t lighting so I had to resolder the voltage regulator and then both green LEDs lit up, meaning everything was working. Then I got my FTDI programmer, and plugged it into my PCB. Because I have a FTDI programmer and the ATtiny3216 has a UPDI programming interface, there is a resistor on the board to combine the two pins into one. Even just getting megaTinyCore installed in Arduino IDE was a pain. The website that hosted the package info was down again, with an expired certificate. Apparently, this happens very often with it but I found an alternative mirror. Then I tried flashing code, and it didn’t work. Then I realized that the board type I was using was the Optiboot version, and I couldn’t find the non Optiboot version so I had to flash Optiboot onto the MCU. I did not realize that doing this would cause problems later on. I also had to switch the programmer from the one that programs Arduinos to the UPDI programmer. But I STILL couldn’t get any GPIO to work. I just tried things for hours. I switched to PlatformIO. I tried switching from C to Arduino in PlatformIO. I tried unplugging the programmer because I saw some voltage leaking from it. I tried emptying the caps and trying again. I probed every single pin to see if I wrote the wrong pin. Then after all of that, when I switched to non Optiboot (having to find online that I have to downgrade megaTinyCore), and flashing that, it works. I think it was because flashing a bootloader burns some fuses to expect a bootloader, but when I flash my code it actually overwrites the bootloader code because I don’t have access to the TX and RX pins typically used to flash when Optiboot is installed, and that just caused the code to not run.
Worked on firmware & CAD & Soldered Second PCB I got the PCB and ATtiny3216 to power a servo. I soldered on the remaining components on it, like the custom LED (which just turns on when the motor is spinning for now) and the 100uF capacitor and also the RS485 bus IC. I also changed the CAD of the arm to use a bearing and changed the servo horn to fit inside of the bearing. I’ve ordered right angle headers and the bearing and metal servo horn already. I also added some transparent parts to the arm design to make it look more interesting hopefully. I also am almost done soldering the second servo PCB. Now that I have all the parts ready and I actually got better at soldering ICs I can do it faster now.
Done Soldering Most PCBs, Crimped JST wires kind of I’m pretty much done soldering, I just have like 3 more tiny PCBs and I should be done. The big main board PCBs are pretty much done, I just need to make some botched tall headers since the clearance of regular headers are too small, and the servo PCBs are almost done, with just some connectors left to solder. Soldering JST 1.25mm wires ARE THE WORST EVER THING TO EVER EXIST I spent 2 hours crimping terminals on multiple wires and its so so so annoying. I can barely hold the terminal itself and they are so easy to bend. I couldn’t afford the real tool to crimp them, so I have cheap crimpers that are the wrong size and can’t technically crimp these. If crimping the metal things wasn’t bad enough, inserting the terminals into the housing was even worse. The housing would bend, or I would accidentally somehow insert it where it shorts the pin next to it??? Also while soldering a JST 1.25mm connector on a PCB, I ripped the pads clean off the PCB. I guess that one just will be missing the daisy chain feature because it only has one connector for data now and all the components and MCU are already soldered on, which really sucks. The rest of the servo PCB (4 in total for now) went fine though, and I’m getting faster at it.
Finished Soldering all Smaller PCBs & Got RS-485 communication working from main board to servo PCBs First, I finished soldering the PCBs. I added the connectors for power and the small data connectors. I also finished the servo expansion boards that hold the magnetic encoder and sensor. I also finished soldering the joint encoder PCBs that will track shoulder and elbow lift servo positions. I also got the bus communication to work. It was really really painful and I was really scared it wouldn’t work. First, the PCBs wouldn’t communicate at all. But eventually, I realized that it was because I wasn’t supplying 3.3V to the main board. This is when I realized that I haven’t adjusted the buck converters on the main board to supply the correct voltage, so I was about to unsolder the buck converter when I realized that I could just set the power supply to 5V (which the ICs on the mainboard can handle luckily), and then adjust the voltage down to 3.3V. But after a really long time of debugging, it still wasn’t working. The connection would sometimes work but was really flaky. Eventually, I soldered on the RPi Pico 2 onto the board completely and then found out the reason, it was because the ATtiny3216 was set to clock at a slow speed that would mess with the communication. I made them use the SerialTransfer library to send data more reliably and it now can communicate properly :)
Crimped JST VH wires, Connected JST 1.25mm wires, Soldered more PCB connectors Crimping JST VH wires is a ton easier than JST 1.25mm, and after a bunch of failed attempts still, I got some okay crimps that work finally. It took me a long time because I didn’t know that I had to rotate the wire for the hook on the terminal to go into the housing hole, and then also that the box shape part on the terminal actually has to stick out of the crimper or the crimper will crush the whole terminal into bits
Servo PCB Daisy Chaining Working I plugged in the JST VH and JST 1.25mm wires into the PCBs, and they seem to work! I adjusted the message struct to hold a desired PCB sort of address or ID. When the MCU detects that the ID matches the PCB (by using the solder jumpers at the bottom of each PCB to program the PCB ID), only then it lights up the LED and replies to the main board. The mainboard now loops through IDs and sends a message and waits for a response. I’m very very happy this worked without any really big problems.
Servo Control Working, More CAD and 3D Printing I got the mainboard to be able to control the servo on the servo PCBs. I also tested a bunch of the functions, like the magnetic sensor, neopixel LED, etc The communication now sends the PCB ID, and the target speed and the servo PCB echos it back and moves the servo. I also worked on the CAD (and refined) for the mainboard connector that will make connecting the two mainboards not a total pain. I also soldered the connectors on the mainboard PCBs for them to connect to each other.
Mainboard and other CAD I got the mainboard to stack on top of each other with a weird jumper and two piece jumper holder and some screws setup which required some revisions and trying to get everything to fit. I’ve squeezed one of the DC buck modules into between the mainboard, and the second arm segment will hold the two remaining DC buck modules. The bottom mainboard PCB also has 2 smaller buck modules. There’s a lot of things going on with the voltages in this project due to the servos peak current draw being so large. I also refined the arm segment CAD by some reprints and made the DS5180 servo fit better. I’ve also made one of the buck module mounts for the second arm segment to fit more cleanly.
Bidirectional Communication To PC/RPi 5 with LeRobot & More CAD changes I setup a basic class for my robot in LeRobot (which was a little confusing) and then I also got communication between the Pico and my PC working. Originally I have SPI pins exposed on my mainboard PCB to connect to the RPi 5’s GPIO pins, but for some reason after lots of debugging, even running it at super low speeds it just would not work. So I switched to just using serial over USB, and using the SerialTransfer library to send data more reliably. The script on the PC now can send target joint angles, and receive a lot of data back, like if the joint is online, temp, current, angle, homing sensor, home status, LED, firmware version, voltage, etc I also iterated on the CAD for everything, and it should be done soon. It’s just a bunch of tolerance fixes to make everything fit at this point and some new things like mounts for encoders and DC buck modules and fixing the CAD for the custom MG996R case.
Rewrote all firmware; Fixing Servo Cover and a ton of other CAD; Almost fried everything For the CAD, it doesn’t look like much changed, but I’ve basically redesigned a bunch of things and fixed tolerances and now it should move really smoothly. With the bearings added, everything moves incredibly smoothly now Especially the servo cover was annoying. I needed to attach a magnet to the shaft which was really annoying. I haven’t logged that well, I’ve done more like 15 hours of work instead of just 5 but whatever Most of those hours was the painful debugging. RS-485 busses, JSON not communcating with the PC, dropped connections, corrupted data, disconnected jumpers, FTDI programmer becoming flaky for some reason It’s just been pain :((( Now the PC (screenshot) recieves all the data and sends all the data You can see a lot (not all) of the telemetry being received. Ignore the volts though my math is wrong. Realtime connecting now works smoothly, as you can see the other RS485 servos are offline.
Servo firmware almost done The servo firmware now (with the mainboard) sends validation data back and forth so both the servo and mainboard can verify that the data was sent successfully and can ignore corrupted packets because my wiring can be flaky sometimes The firmware now sends real data again and is much more robust, with a proper stateful LED that shows useful information, like offline, online and driving motor, homing, error (fast flashing of LED as red), and the error state is also triggered in the case of corrupted packets (I tried it and it works :)) I’m also still printing out the pieces to assemble the arm. I actually have more hours working on it, I just forgot to log :(((((((
Finalizing hardware I crimped and soldered almost the remaining wires, I’ve made some last redesigns to the arm CAD and I’m now fitting everything into the new prints and assembling. I’ve also had a ton of trouble with my servo PCBs lately, but I found out a lot of the issue was my programmer is actually fried somehow, so I’m now using an old RPi Pico to act as a UPDI adapter so PlatformIO can now successfully program the ATtinys much better now. A lot of the CAD was slightly tweaked so that everything fits better
Test assembly and fitting of robot arm I am mostly done with the core functionality of the mainboard, so i packed everything together and double checked eerything works including power Then I started assembling most of the servos The smaller servo casing doesn’t fit very well, and the transparent window doesn’t fit either But the magnetic cover for the arm segments works great :) It was a lot of fitting, screwing, testing with multimeter, etc
Mainboard Stack Redo & Firmware Updates and Test Web UI I had to take the electronics out, and redo some of the wiring. The screw terminals are pretty cheap and suck, which makes it incredibly annoying to use as it’s impossible to fit these thicker AWG wires in and they sometimes slide out of the terminals. When I’m done I’m probably going to hot glue the wires. The incredibly fragile flexible extension jumpers for data transfer between the stack is also super fragile, and especially doesn’t grip. Sometimes the data wires just slip out. I took apart the arm, as during testing the motor stripped some screws. I’ve ordered some heat set inserts to prevent that from happening again, which will require me to reprint all the arm segments again. I also added a simple web UI for moving the joints. There is an empty ThreeJS sidebar and the right has some graphs (real data) from the mainboard sensors. The smaller MG996R servos haven’t been mounted yet due to a power delivery issue from the mainboard but hopefully that will be fixed soon.
Assembled Basic Arm Parts and Packaged Main Board Assembly; Reprogrammed servo MCUs & worked on web UI I redid some soldering on the mainboard PCB, secured connections, and secured everything with tape for now. I’ll likely have to reprint the first arm segment to fit everything in flush because as you can see there are wires and things bulging out of the segment itself right now. I also redesigned the CAD to include heat set inserts. I did programming and a bunch of bug testing and fixing too. An hour of time was lost because Lapse errored out :((((( very sad about that :( I also had an issue with data corruption on the RS485 bus but that is fixed now, and it works like it should.
New Mainboard Cover, Wiring, Bearing Revamp, Heatset Inserts, Servo Cover I added space for the mainboard segment, now it has clearance to actually fit, I redid the cover for this segment, and now it can allow the wires to come out The servo mount now has heatset inserts, because the previous screw in print kept slipping out, but this time the screws just would not go into the inserts through the mount for some reason? The screws went in normally, but with the tolerances, when multiple screws go in they just fight and push against the edge of the insert instead of going in. The MG996R servo housing now has been redesigned, based off of picture references and calipers to attempt to be more accurate than the last one to try and reduce the amount of bad tolerances affecting the gears and making them misaligned, reducing torque output. And just general wiring and CAD work.
Heatset Inserts Working; Fixing Faulty Motor Power Connections; Internal Fan Power Connectors I verified that the servo cover works, and it’s much much better than the last version. The tolerances are much better this time, leading to less stress on the gears. The same amount of turning uses around 100mA compared to 300mA before, almost reaching it’s limit without any load. Some motor power connectors disconnected, so I found it with a multimeter and added hot glue to some connectors to secure them. I soldered the fan power things inside the PCB, but realized that the JST connectors I’m using are different from the fans. I might have to make a sort of adapter or something by crimping more wires. And the heatset inserts finally work after some tweaking, before the inserts would get misaligned when put in, now with a aligning lip thing it can be slotted in and melted in more accurately.
Reprinted Arm Segments; Added Segment Cover; Servo Mount Working; Working on Web UI I reprinted the arm segments, hopefully for one of the last times, I’ve went through so much filament already. It now allows the mainboard to be neatly packed inside, hiding most of it while still allowing wires to come out. Due to the design of the mainboard, the wires do have to stick out the front like that sadly. To avoid crushing wires, the servo mount has been expanded to allow more clearance for wires and general electronics. The servo mount works now with a new design. I remeasured and adjusted the sketches and added proper hole sizes and a little chamfer to allow the insert to slot in before using a soldering iron to melt it in to help align much better than before. The web UI now shows a representation of the arm. It’s not tuned yet, so the angles are wrong but I’ll fix it soon. I had to move everything from Fusion to Onshape to create the assemblies, and then use a Python library to convert the Onshape assembly into a URDF file that can be rendered with the correct joints inside ThreeJS. Next, I’ll be adding IK and general arm control.
Working on IK System & Resoldered Joints Again Bruh so my robot arm after finally being assembled by the way exceeded it’s limits and tore its wires out. I had to take apart the mainboard assembly again, which just is SO TEDIOUS. I just dumped solder and hot glue again and fixed a short caused from another wire being sheared off. Also I’m working on the IK system, but it’s not really going well right now. I need to add offsets and config to each of the motors to get them to work correctly. The motors hooked up right now started crashing into my table sadly. Hopefully it will work soon. I also continued working on the servo case. I still haven’t added the code to calibrate and get closed loop control on the MG996R servos. The DS5180 encoders should be easier though.
V2 Servo Case Working; Servo Code Revamp WIP After around 10 more revisions, the new servo case is fully working with the magnetic extender. The V2 is significantly better designed and higher efficiency than the last, more guess and check result. I’ve also started to rewrite the servo code. Right now, its really messy and just kind of snowballed over time as I’ve slapped on patches and features to a fundamentally weak base. I’m in the progress of writing that now, hopefully it will be done soon. It will also include the new auto calibration and encoder usage and PID (and potentially advanced auto tuned curve to combat motor acceleration overshoot and backlash)
Servo Code I did some slight refining to the servo case again, making the tolerances tighter to keep the gears from wobbling. It’s still sort of loose, so I need to just keep trying over and over again. I’m also still writing the servo code. It’s already much more organized than before. I’m also learning Vim keybinds and stuff to try and code faster. The RS485 bus communication works now, and it’s just sending dummy telemetry data back right now. It can also control the servo fine. I’ve just been doing like the lower level architecting I guess, or not really I’m not sure. Before everything was crammed into a single file and now there’s actually header files and multiple source files and it’s actually somewhat readable. I had an issue with LED control for a second but that’s fixed now :)
MG996Rs Finally Working The servos finally work. I don’t even think this amount of hours logged is equal to how long this took, because I just got tired of it. I think I printed like 20 new revisions of the case and servo mount. It was just so so annoying. While the general case worked, getting a reliable magnet output shaft was impossible. From tolerances, to my own errors to binding to hot glue getting everywhere, or superglue binding random gears, or my getting my fingers stuck to the actual case from superglue (was not fun and hurt) The case finally works. And the prototype code somewhat works too. It basically rotates until the sensor hits zero, it resets the “ticks”. A tick is a raw output from the AS5600. Because this magnet shaft spins faster than the output shaft, like 10x faster, the MCU needs to poll the sensor super quickly, which also needed some optimizations to clear the blocking bus communication wait that would let the magnet skip multiple full turns. The sensor doesn’t internally count turns so we just need to count manually and detect when it jumps from 4096-0 or the other way around. It then spins around until the sensor is hit AGAIN to calculate tick to degrees, assuming the sensor was zeroed before, and then the current ticks would equal 360 degrees. Another problem was the servo needs a PWM signal to move. The threshold from stop to go is pretty garbage on these cheap servos, leading it to spin quite fast already when at the lowest PWM value. Instead when far from the value it increases the PWM signal, closer it brings to minimum and starts linearly flickering the PWM signal from 0 to the speed, with the closer it is the more ratio of time stopped to inch it closer to the target. It actually surprisingly works. It’s very fragile though, any skipped reads, from potentially slow bus transfers would completely throw it off, so all the code running locally on the weak 8 bit MCU needs to be extremely lightweight. Yeah this was super super painful. I’ve been sitting here redoing superglue and code for hours.
Debugging and Fixing Is Killing Me and the Mainboard Exploded :( I have spent SO many hours trying to get this to work. It’s so annoying. This isn’t near how many hours I spent, I’ve been too frustrated to log it. The case is incredibly annoying. Getting the initial case works fine. Doing all of this stuff makes it complicated and break and jam up. The RS485 busses just randomly stop working. The servo output is wiggly and not stable. A PCB header snapped and I didn’t have replacements so I had to bodge solder it back on. The mainboard voltage regulator literally exploded. It was a cheap part but yeah that literally just broke stuff. Fixes to everything. CAD. Firmware. bruh
Dashboard Revamp WIP, Tons of CAD changes, Code Updates, Tolerances I’ve just been refining everything and it’s just going really slowly. Many problems. Magnets shorting out stuff. Magnet too far and not being detected. Wires breaking. I’ve also redesigned the dashboard UI to hopefully look better. I’m still working on it, hopefully it will look more polished later. The dashboard It shows a load speedometer type thing, with the load (max current from a motor out of 500mA) and the temp on the right (for now just dummy value) The motors have cool little animations now too and look less cluttered. I’ve just been working on it a lot. Just everything in general tbh.
Assembled last 4 DoF for Integrated Test I assembled the MG996R servos in a test piece that will represent the full regular arm segment to test if everything worked. With some fiddling it worked. As you can see there’s more transparent pieces. The pieces that connect the previous joint are transparent to show the Neopixel below it a lot better as before the LED was almost completely occluded. The bright green LEDs power status ones are too bright but I can cover them later.
Significantly Better Motor Control and Gripper CAD The motor code was getting a bit messy, so I rewrote it. I separated the motor code from the main control code which cleaned it up a bit. LADRC I’m using LADRC now. It’s kind of like PID, but advanced. I took the implementation from online. I feed it the motor current, encoder value, and the target and it goes. The algorithm or whatever somehow calculates the velocity of the motor and how much “effort” it’s using and then gives an effort to put to the motor. It somehow cancels out like disturbances like gravity, backlash, the general physics, etc. As you can see, the motor control is so so so much better than before. It cleanly decelerates. It handles load and dynamically increases effort. Before there was some oscillation because it just couldn’t figure out how to get to the target, this one is just so much better and so hands off. There’s basically like no calibration as it does it over time :)))
Assembled Full Arm (not all motors active yet for safety) and Basic Interpolation for Control I assembled the new full arm assembly minus the end effector and didn’t plug in the first two motors as they have the highest chance of doing something really bad. I also made some general changes to the code and also added a flag to some motors to interpolate their movement slowly to not explode the robot arm while controlling it.
Fixed Broken Magnet, Redoing all IK joint data and offsets, Stereo depth test An encoder magnet broke off, so I had to disassemble and reassemble the top half of the arm to get to the encoder magnet and glue it back on. I also started properly punching in the IK joint data, before it was mostly just random data but now almost all of the data is mostly correct, and I’m waiting for a print to complete that will flip a motor to finally get the IK simulation matching with real life and have the IK endpoint be tracked at the tip of the gripper. It was a lot of trial and error and measurements. I also started experimenting with adding depth estimation. Eventually this could add collision avoidance IK pathfinding, which would be really cool but it’s just a pointcloud in the render right now. But the robot arm is slowly coming together finally! I’ll be able to grab something soon I think.
Integration Hell I’ve just been like trying to get this stupid project to work. Screws keep falling out, the IK keeps failing, things are hitting each other and wires are being strained I’m in integration hell. Everything works fine on its own, but combining everything is horrible. I’ve been reassembling and trying to fix this stupid thing for so long. Anyway I’ve went through a few more revisions of some CAD and some more refinements and the gripper and camera is now mounted but this is just incredibly incredibly annoying :((((
Setup VR and Gripper, Robot Rapidly Disassembles my robot arm is broken I setup VR and fixed some more IK when I go into VR and try playing around, it instantly flies out and throws itself off the table and breaks into pieces. This is going to be fun to fix.
Finish Project Up :) I wrote a ton in the repository im tired :( https://github.com/ratmuds/revo
Ships:
I wanted to make a robot arm that punched above it’s weight. The price is pretty similar to smaller robot arms on Amazon that may not include cameras, which would need to be purchased seperately. The way this is achieved by using cheap servos, servos that are 100% NOT made for this purpose, and adding most of the functionality of a smart servo back by using a TON of PCBs. It was a lot of soldering. I just wanted to make something that had more features for less money :) This project was SUPER difficult for me, and pushed my limits a bit. The amount of tolerences especially for the stupid custom motor case and magnet and PCBs and the crazy mainboard and generally having everything play well together took so long, I had many days where I quit frustrated. I’m very happy about how it turned out though, even seeing the lots of shortcomings it has....
|
1793005016.299186
|
1793091416.299186
|
|
41548
|
Market Lab by @GoldenClarinet | Stardance
|
GoldenClarinet
|
1
|
132.14
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-20T13:44:17Z", "hours": 130.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "MarketLab is a python tool to exploring BINANCE financial data. With MarketLab, you can create and manage database of market data such as the OHLCV, calculated indicators such as SMA, RSI etc… The most challenging part was to rebuilt the core of the project. I am very proud of MarketLab because it is my very first and my most complex python project yet.", "repo": "https://github.com/Cla1tra2algo/Market-Lab", "demo": "https://pypi.org/project/the-marketlab-project/"}]...
|
[{"post_id": 74089, "ts": "202 [{"post_id": 74089, "ts": "2026-09-26T17:22:31Z", "hours": 0.6122, "text": "After Ship DevLog #2: I changed manually the README to reduce the part of AI code"}, {"post_id": 72266, "ts": "2026-09-22T15:30:09Z", "hours": 1.5233, "text": "After DevLog #1 : I have edited parts of the README and fixed a bug when window selection. Thanks for reading 😄"}, {"post_id": 71199, "ts": "2026-09-20T13:09:32Z", "hours": 6.0994, "text": "Final DevLog (#33) : Great Great Great New !! The first version of MarketLab is finished !! You can now install it, if you have python with a simple pip install the-marketlab-project and import it under the name of marketlab ! Thanks for reading ad for all the support you gave me 😄 ✌️ ! Special thanks to @dapsvi , @jinjin , @preyas_21 and @MathBty for liking DevLog #33 !"}, {"post_id": 64930, "ts": "2026-09-09T17:27:42Z", "hours": 1.0522, "text": "DevLog #32 : Newfeature ! : I finally fixed the bug that misplaced and made calcultation over wrong data to update indicators. Thes next step is to add the update for the events. Thanks for reading 😄 PS : Special thanks to @kingkev for liking DevLog #31 and following and thank to @No1Michael for liking DevLog #30 !"}, {"post_id": 63039, "ts": "2026-09-06T16:40:05Z", "hours": 0.3269, "text": "DevLog #31 : New feature (not perfect yet) ! I am fixing the issues on the indicator update (see DevLog #30). The indicator is now updated over te whole set of new data and a misplacement has been corrected. But some problems remains: the indicator is updated with what seems to be the first value of the whole set of data and it is also calculated with the very first values (that normally cannot be done: if you are calculating a SMA100, the 99 firsts values cannot be calculated) Thanks for reading 😄"}, {"post_id": 62995, "ts": "2026-09-06T15:44:46Z", "hours": 1.2817, "text": "DevLog #30 : New feature (not perfect yet) ! You can now update the calculated indicators, but an issue just showed up: there are three misplacement of the new values of the indicator. I am working on fixing that. Thanks for reading 🫡 PS : Special thanks to @bali0531 , @lakshaykhatri780 and @jinjin for liking DevLog #29 !"}, {"post_id": 62088, "ts": "2026-09-05T10:32:14Z", "hours": 4.7581, "text": "DevLog #29 : New feature ! You can now update the data available on Binance API. I am also working on calculating indicators and avents over these new data. Thanks for reading 😄 PS: If you know how the 3D Printing Credits available in the shop can be used, I will be grateful if you tell me in the comments!"}, {"post_id": 58871, "ts": "2026-08-31T13:24:47Z", "hours": 8.6258, "text": "DevLog #28 : I finalized the sync of all the part of the system that manage events calculation with the new core of MarketLab. I also started the README. I am currently working on updating all the data after a break in your work on MarketLab. Thanks for reading ✌️! PS: Special thanks again to @bali0531 for liking DevLog #27 ! PS 2: I do not have special image to illustrate the work I have donne these last 8 hours, sorry 🙇♂️"}, {"post_id": 57267, "ts": "2026-08-29T11:33:25Z", "hours": 2.5878, "text": "DevLog #27 : I finalized the sync of all the part of the system that manage indicators calculation with the new core of MarketLab. The next step is to do the same with the events part. Thanks for reading 😆 PS: Special thanks to @bali0531 for liking DevLog #26 !"}, {"post_id": 56754, "ts": "2026-08-28T17:15:42Z", "hours": 10.6694, "text": "DevLog #26 : I keep on modifying the core of MarketLab. I do not have anything special but I need to do this DevLog to log my hours. Thanks fore reading 😄"}, {"post_id": 54023, "ts": "2026-08-24T19:26:44Z", "hours": 8.7467, "text": "DevLog #25 : New feature ! While trying to calculate an indicator, if an existing one has the same name, MaketLab will ask if you want to replace the existing one, rename the indicator you want to calculate or simply cancel the calculations. I am working on the same system but with MarketLab looking on the parameters of calculated indicators. Thanks for reading ✌️!"}, {"post_id": 53139, "ts": "2026-08-23T16:00:46Z", "hours": 8.6025, "text": "DevLog #24 : I standardized indicator definition and metadata to set the rules the user must follow to create indicator that can be accepted by MarkLab. The user must define these metadata to use its own custom indicators : the name of the indicator, the number of parameters nb that the user can choose, the recommended parameters r , the function of the indicator f , the type t of the indicator ( general_app or custom ) and the forced parameters fp . The next step is to do the same with the events. Thanks for reading 🙌!"}, {"post_id": 51812, "ts": "2026-08-21T17:32:26Z", "hours": 8.0319, "text": "DevLog #23 : I keep on working on redefining the structure of the code. All the sqlite3 operations are now performed by the class MarketLabDataBase . Redefining the structure af the code will take a long time (8 hours for one step) but it is one of the final steps of the project and it will hopefully improve the complexity grade of my project. Thanks for reading 😆!"}, {"post_id": 51280, "ts": "2026-08-20T20:27:26Z", "hours": 3.5481, "text": "DevLog #22 : I started working on redefining the structure of the code to strengthen robustness and clarify the architecture. I asked Codex to make me a check list of all the modifications to operate. Thanks for reading 😁 PS : Special thanks to @Aaravkatiyar for liking and commenting DevLog #21 and following ! (You are the GOAT!)"}, {"post_id": 51044, "ts": "2026-08-20T15:07:02Z", "hours": 8.0183, "text": "DevLog #21 : New functionality ! You can now download data from a specific date range. I added this feature to prevent long downloads ( ~ 5 minutes for the whole history with a time frame of 15m and 15 times longer for a timeframe of 1m ). I am now working on computing series with incompatible indicators with general_application . Thanks for reading ✌️! PS : Special thanks to @alyaanmughal for liking DevLog #18, @Aaravkatiyar for liking DevLog #20 and @Sreeni for following me !"}, {"post_id": 49474, "ts": "2026-08-18T10:20:12Z", "hours": 3.0044, "text": "DevLog #20 : New design ! I redesign the main menu by moving 🧩 Manage Custom Indicators and Events , 🗑️ Delete a Column and 📁 Open or Create a Database in the ⚙️ Settings . Small change but it improves the user experience and the understanding of the main menu. Thanks for reading 😄!"}, {"post_id": 48927, "ts": "2026-08-17T14:20:06Z", "hours": 2.0031, "text": "DevLog #19 : New functionality ! You can now compute series of the same indicator but with different windows (EMA 20; EMA 30; EMA 40 …). It only work for the functions compatible with general_application for now but I am working to extend this feature to the custom indicator functions. Thanks for reading 🙌!"}, {"post_id": 48352, "ts": "2026-08-16T17:43:53Z", "hours": 4.1689, "text": "DevLog #18 : New indicator and new event ! The filter_savgol applies a Savitzky-Golay filter (filter that works on polynomial regression) and peak_detection . This led me to add a system that allows the use of indicators and events functions that do not comply with the functions general_application and general_event_application (functions that simplify the création of custom indicators and events). The next steps are the packaging and the writing of the README. Thanks for reading 🙌!"}, {"post_id": 47705, "ts": "2026-08-15T19:53:16Z", "hours": 7.8397, "text": "DevLog #17 : New functionality ! You can now create a file containing your own custom indicators and events . I also created a function called general_event_application which simplifies the creation of new events. Thanks for reading 😄 PS : Special thanks to @bali0531 for liking DevLog #16 !"}, {"post_id": 44678, "ts": "2026-08-10T16:24:41Z", "hours": 3.4011, "text": "DevLog #16 : New functionality ! You can now calculate statistics of an event to show up in function of two parameters. In The example, the event is a cross between the close and the SMA 100 in function of the volume and the the volume of the quote. I am coming to the end of the project, the next steps are to allowing the user create its own indicators and events. Thanks for reading 🙌 ! PS : Special thanks to @MathBty and @dhruvalya for liking DevLog #15 !"}, {"post_id": 43280, "ts": "2026-08-08T13:27:43Z", "hours": 2.3211, "text": "DevLog #15 : New functionality ! You can now search a file already created to make returning to work easier on an existing file. Thank for reading 😄 ! PS : Special thanks to @Gerafftes for liking DevLog #14 !"}, {"post_id": 42185, "ts": "2026-08-06T20:01:07Z", "hours": 1.8761, "text": "DevLog #14 : New fonctionality ! You can now plot a Status with indicators directly with the interface. In the example, Close, SMA 100, SMA 50 and Cross(SMA 100, SMA 50) are plotted on the same graph. The next step is to calculate Stats and plot it too. Thanks for reading 🫡"}, {"post_id": 41992, "ts": "2026-08-06T15:11:05Z", "hours": 5.2839, "text": "DevLog #13 : New functionalities ! You can now plot any indicators already calculated directly with the interface. The next step is to plot status (like “cross”) and stats. I also added 4 functional indicators in the indicator dict of the interface (ATR, VWMA, Amplitude and Relative). The Indicator Dict is able to contain recommended parameters for each indicator and they are printed when entering parameters to calculate indicators. Thanks for reading 🫡. PS : Special thanks to @Jinan (again!), @CoolDuck and @MathBty for liking DevLog #12, @PAPER_01 for liking my first DevLog. Thanks again to @jinan for the amazing comment about DevLog #12 and @yeshwingadde for following !"}, {"post_id": 41322, "ts": "2026-08-05T13:45:46Z", "hours": 2.9131, "text": "DevLog #12 : Bugs fixed ! I added in the code verifications for each user entry to prevent incorrect type of entries and reduce program crash. I also added the option Continue after an action. Hope you like the new logo. Thanks for reading 🙌! PS: Special thanks to @shi , @Jinan and @f for liking DevLog #11. Thank again to @f for the nice comment about DevLog #11!"}, {"post_id": 41198, "ts": "2026-08-05T08:37:29Z", "hours": 4.0861, "text": "DevLog #11 : New functionality ! You can now calculate indicators directly with the interface and delete it. I also added an History to remember the actions that have been done. Hope you like the new design with emojis. I am still taking ideas from you. Thanks for reading 😁"}, {"post_id": 40775, "ts": "2026-08-04T14:59:09Z", "hours": 1.1947, "text": "DevLog #10 : New functionality ! I have started to build a terminal-based user interface to make Market Lab much easier to use. Here is a preview of the first functionality : Download Data to download every candles of the selected symbol and interval. I am also continuing to work on the heat map feature (look at DevLog #9). If you have advice about the design or whatever of the interface, I will be very happy to listen to it. Thanks for reading 🫶 !"}, {"post_id": 40616, "ts": "2026-08-04T08:41:34Z", "hours": 1.0947, "text": "DevLog #9 : New functionality ! The probability for an event occurring can now be calculated and plotted. In the example, the probability of a crossover/crossunder based on trading volume is shown in red or in blue. The next step is to calculate the probability of an event to show up based on two variables and visualize the results using heatmaps. Thanks for reading 🙌. PS : Special thanks to @jinan , @logannavaia and @Epicninja3 for liking the DevLog #8. Thanks again to @Epicninja3 and @logannavaia for following this project !"}, {"post_id": 40386, "ts": "2026-08-03T21:08:16Z", "hours": 1.6072, "text": "DevLog #8 : New event ! The event “under_over” allows us to detect a moment in time where a variable is under or over another. Here the example shows the moment when the SMA 50 is either under or over the SMA 100. I keep on working on the function that allows to compute the probability of an event to show up based on different variables. Thanks for reading 🤠 PS : special thanks to @f for liking the DevLog #7 and the very encouraging comment !"}, {"post_id": 40269, "ts": "2026-08-03T18:04:16Z", "hours": 0.4303, "text": "DevLog #7 : Following the DevLog #6. Triangular labels can now be plotted on the graph at the location of each event. In the example, the event is the crossover between two EMAs. The next step is to compute the probability for an event to show up based on different variables such as the volume, the number of trades etc. Thanks for reading ✌️ ! PS : special thanks to @benvelzul for following this project !"}, {"post_id": 40182, "ts": "2026-08-03T16:13:51Z", "hours": 1.2819, "text": "DevLog #6 : New event ! The event « cross » allows us to detect a moment in time when two values cross each other. Here, the example shows the moment when two SMAs cross one another. This event is shown by the second graph which ocilliates between 1 and -1 for a crossover and a crossunder. The next step is to plot labels directly on the graph for each « cross ». Thanks for reading 😄"}, {"post_id": 39966, "ts": "2026-08-03T09:35:00Z", "hours": 0.3058, "text": "DevLog #5 : New indicator ! I have juste finished implementing the Commodity Chanel Index (cci). This indicator show how much the deviation of the price form its average (SMA) is important relatively to the mean deviation of the price (MD). The math formula is a bit complexe so I joined it below. The typical price (TP) is the average of the high (H), low (L) and close (C) of the same candle. Thanks for reading this DevLog 🫡"}, {"post_id": 39947, "ts": "2026-08-03T08:48:30Z", "hours": 0.485, "text": "DevLog #4 : New indicator ! I have just finished implementing the Stochastic Oscillator (or %K). It is a simple indicator which calculate the “position” of the close of the the last candle over n candles. Here is the math formula: %K = 100 * (Close-Low)/(High-Low) with Close the close of the last candle ; Low the lowest point over n candles ; High the highest point over n candles. The timeframe is still 12h because the calculations are much more faster than those for a 1h timeframe ( logically 12 time faster). Thanks for reading this DevLog 🙌"}, {"post_id": 39921, "ts": "2026-08-03T07:32:41Z", "hours": 1.06, "text": "DevLog #3 : I have just finished implementing the RSI calculation. This is the RSI 14 close of the BTC on a 12h timeframe. I have more than 10 indicators now !"}, {"post_id": 39612, "ts": "2026-08-02T18:27:40Z", "hours": 0.6106, "text": "DevLog #2 : New Indicator ! Here is the ATR 14 of BTC since the 17/08/2017 computed on a 12h time frame. Thanks for reading 😆!"}, {"post_id": 39559, "ts": "2026-08-02T16:27:33Z", "hours": 12.2767, "text": "DevLog #1 : Very first DevLog ! I started Market Lab one week ago and heard about StarDance Challenge one month ago. But I got the idea to participate only yesterday so I have about ten hour that won’t count 😥. I already established the data extraction from BINANCE API. I keep on tracking errors and creating new functions to calculate indicators. Thanks for reading 🫡!"}]...
|
Title: Market Lab by @GoldenClarinet | Stardance
Title: Market Lab by @GoldenClarinet | Stardance
Devlogs:
DevLog #1 : Very first DevLog ! I started Market Lab one week ago and heard about StarDance Challenge one month ago. But I got the idea to participate only yesterday so I have about ten hour that won’t count 😥. I already established the data extraction from BINANCE API. I keep on tracking errors and creating new functions to calculate indicators. Thanks for reading 🫡!
DevLog #2 : New Indicator ! Here is the ATR 14 of BTC since the 17/08/2017 computed on a 12h time frame. Thanks for reading 😆!
DevLog #3 : I have just finished implementing the RSI calculation. This is the RSI 14 close of the BTC on a 12h timeframe. I have more than 10 indicators now !
DevLog #4 : New indicator ! I have just finished implementing the Stochastic Oscillator (or %K). It is a simple indicator which calculate the “position” of the close of the the last candle over n candles. Here is the math formula: %K = 100 * (Close-Low)/(High-Low) with Close the close of the last candle ; Low the lowest point over n candles ; High the highest point over n candles. The timeframe is still 12h because the calculations are much more faster than those for a 1h timeframe ( logically 12 time faster). Thanks for reading this DevLog 🙌
DevLog #5 : New indicator ! I have juste finished implementing the Commodity Chanel Index (cci). This indicator show how much the deviation of the price form its average (SMA) is important relatively to the mean deviation of the price (MD). The math formula is a bit complexe so I joined it below. The typical price (TP) is the average of the high (H), low (L) and close (C) of the same candle. Thanks for reading this DevLog 🫡
DevLog #6 : New event ! The event « cross » allows us to detect a moment in time when two values cross each other. Here, the example shows the moment when two SMAs cross one another. This event is shown by the second graph which ocilliates between 1 and -1 for a crossover and a crossunder. The next step is to plot labels directly on the graph for each « cross ». Thanks for reading 😄
DevLog #7 : Following the DevLog #6. Triangular labels can now be plotted on the graph at the location of each event. In the example, the event is the crossover between two EMAs. The next step is to compute the probability for an event to show up based on different variables such as the volume, the number of trades etc. Thanks for reading ✌️ ! PS : special thanks to @benvelzul for following this project !
DevLog #8 : New event ! The event “under_over” allows us to detect a moment in time where a variable is under or over another. Here the example shows the moment when the SMA 50 is either under or over the SMA 100. I keep on working on the function that allows to compute the probability of an event to show up based on different variables. Thanks for reading 🤠 PS : special thanks to @f for liking the DevLog #7 and the very encouraging comment !
DevLog #9 : New functionality ! The probability for an event occurring can now be calculated and plotted. In the example, the probability of a crossover/crossunder based on trading volume is shown in red or in blue. The next step is to calculate the probability of an event to show up based on two variables and visualize the results using heatmaps. Thanks for reading 🙌. PS : Special thanks to @jinan , @logannavaia and @Epicninja3 for liking the DevLog #8. Thanks again to @Epicninja3 and @logannavaia for following this project !
DevLog #10 : New functionality ! I have started to build a terminal-based user interface to make Market Lab much easier to use. Here is a preview of the first functionality : Download Data to download every candles of the selected symbol and interval. I am also continuing to work on the heat map feature (look at DevLog #9). If you have advice about the design or whatever of the interface, I will be very happy to listen to it. Thanks for reading 🫶 !
DevLog #11 : New functionality ! You can now calculate indicators directly with the interface and delete it. I also added an History to remember the actions that have been done. Hope you like the new design with emojis. I am still taking ideas from you. Thanks for reading 😁
DevLog #12 : Bugs fixed ! I added in the code verifications for each user entry to prevent incorrect type of entries and reduce program crash. I also added the option Continue after an action. Hope you like the new logo. Thanks for reading 🙌! PS: Special thanks to @shi , @Jinan and @f for liking DevLog #11. Thank again to @f for the nice comment about DevLog #11!
DevLog #13 : New functionalities ! You can now plot any indicators already calculated directly with the interface. The next step is to plot status (like “cross”) and stats. I also added 4 functional indicators in the indicator dict of the interface (ATR, VWMA, Amplitude and Relative). The Indicator Dict is able to contain recommended parameters for each indicator and they are printed when entering parameters to calculate indicators. Thanks for reading 🫡. PS : Special thanks to @Jinan (again!), @CoolDuck and @MathBty for liking DevLog #12, @PAPER_01 for liking my first DevLog. Thanks again to @jinan for the amazing comment about DevLog #12 and @yeshwingadde for following !
DevLog #14 : New fonctionality ! You can now plot a Status with indicators directly with the interface. In the example, Close, SMA 100, SMA 50 and Cross(SMA 100, SMA 50) are plotted on the same graph. The next step is to calculate Stats and plot it too. Thanks for reading 🫡
DevLog #15 : New functionality ! You can now search a file already created to make returning to work easier on an existing file. Thank for reading 😄 ! PS : Special thanks to @Gerafftes for liking DevLog #14 !
DevLog #16 : New functionality ! You can now calculate statistics of an event to show up in function of two parameters. In The example, the event is a cross between the close and the SMA 100 in function of the volume and the the volume of the quote. I am coming to the end of the project, the next steps are to allowing the user create its own indicators and events. Thanks for reading 🙌 ! PS : Special thanks to @MathBty and @dhruvalya for liking DevLog #15 !
DevLog #17 : New functionality ! You can now create a file containing your own custom indicators and events . I also created a function called general_event_application which simplifies the creation of new events. Thanks for reading 😄 PS : Special thanks to @bali0531 for liking DevLog #16 !
DevLog #18 : New indicator and new event ! The filter_savgol applies a Savitzky-Golay filter (filter that works on polynomial regression) and peak_detection . This led me to add a system that allows the use of indicators and events functions that do not comply with the functions general_application and general_event_application (functions that simplify the création of custom indicators and events). The next steps are the packaging and the writing of the README. Thanks for reading 🙌!
DevLog #19 : New functionality ! You can now compute series of the same indicator but with different windows (EMA 20; EMA 30; EMA 40 …). It only work for the functions compatible with general_application for now but I am working to extend this feature to the custom indicator functions. Thanks for reading 🙌!
DevLog #20 : New design ! I redesign the main menu by moving 🧩 Manage Custom Indicators and Events , 🗑️ Delete a Column and 📁 Open or Create a Database in the ⚙️ Settings . Small change but it improves the user experience and the understanding of the main menu. Thanks for reading 😄!
DevLog #21 : New functionality ! You can now download data from a specific date range. I added this feature to prevent long downloads ( ~ 5 minutes for the whole history with a time frame of 15m and 15 times longer for a timeframe of 1m ). I am now working on computing series with incompatible indicators with general_application . Thanks for reading ✌️! PS : Special thanks to @alyaanmughal for liking DevLog #18, @Aaravkatiyar for liking DevLog #20 and @Sreeni for following me !
DevLog #22 : I started working on redefining the structure of the code to strengthen robustness and clarify the architecture. I asked Codex to make me a check list of all the modifications to operate. Thanks for reading 😁 PS : Special thanks to @Aaravkatiyar for liking and commenting DevLog #21 and following ! (You are the GOAT!)
DevLog #23 : I keep on working on redefining the structure of the code. All the sqlite3 operations are now performed by the class MarketLabDataBase . Redefining the structure af the code will take a long time (8 hours for one step) but it is one of the final steps of the project and it will hopefully improve the complexity grade of my project. Thanks for reading 😆!
DevLog #24 : I standardized indicator definition and metadata to set the rules the user must follow to create indicator that can be accepted by MarkLab. The user must define these metadata to use its own custom indicators : the name of the indicator, the number of parameters nb that the user can choose, the recommended parameters r , the function of the indicator f , the type t of the indicator ( general_app or custom ) and the forced parameters fp . The next step is to do the same with the events. Thanks for reading 🙌!
DevLog #25 : New feature ! While trying to calculate an indicator, if an existing one has the same name, MaketLab will ask if you want to replace the existing one, rename the indicator you want to calculate or simply cancel the calculations. I am working on the same system but with MarketLab looking on the parameters of calculated indicators. Thanks for reading ✌️!
DevLog #26 : I keep on modifying the core of MarketLab. I do not have anything special but I need to do this DevLog to log my hours. Thanks fore reading 😄
DevLog #27 : I finalized the sync of all the part of the system that manage indicators calculation with the new core of MarketLab. The next step is to do the same with the events part. Thanks for reading 😆 PS: Special thanks to @bali0531 for liking DevLog #26 !
DevLog #28 : I finalized the sync of all the part of the system that manage events calculation with the new core of MarketLab. I also started the README. I am currently working on updating all the data after a break in your work on MarketLab. Thanks for reading ✌️! PS: Special thanks again to @bali0531 for liking DevLog #27 ! PS 2: I do not have special image to illustrate the work I have donne these last 8 hours, sorry 🙇♂️
DevLog #29 : New feature ! You can now update the data available on Binance API. I am also working on calculating indicators and avents over these new data. Thanks for reading 😄 PS: If you know how the 3D Printing Credits available in the shop can be used, I will be grateful if you tell me in the comments!
DevLog #30 : New feature (not perfect yet) ! You can now update the calculated indicators, but an issue just showed up: there are three misplacement of the new values of the indicator. I am working on fixing that. Thanks for reading 🫡 PS : Special thanks to @bali0531 , @lakshaykhatri780 and @jinjin for liking DevLog #29 !
DevLog #31 : New feature (not perfect yet) ! I am fixing the issues on the indicator update (see DevLog #30). The indicator is now updated over te whole set of new data and a misplacement has been corrected. But some problems remains: the indicator is updated with what seems to be the first value of the whole set of data and it is also calculated with the very first values (that normally cannot be done: if you are calculating a SMA100, the 99 firsts values cannot be calculated) Thanks for reading 😄
DevLog #32 : Newfeature ! : I finally fixed the bug that misplaced and made calcultation over wrong data to update indicators. Thes next step is to add the update for the events. Thanks for reading 😄 PS : Special thanks to @kingkev for liking DevLog #31 and following and thank to @No1Michael for liking DevLog #30 !
Final DevLog (#33) : Great Great Great New !! The first version of MarketLab is finished !! You can now install it, if you have python with a simple pip install the-marketlab-project and import it under the name of marketlab ! Thanks for reading ad for all the support you gave me 😄 ✌️ ! Special thanks to @dapsvi , @jinjin , @preyas_21 and @MathBty for liking DevLog #33 !
After DevLog #1 : I have edited parts of the README and fixed a bug when window selection. Thanks for reading 😄
After Ship DevLog #2: I changed manually the README to reduce the part of AI code
Ships:
MarketLab is a python tool to exploring BINANCE financial data. With MarketLab, you can create and manage database of market data such as the OHLCV, calculated indicators such as SMA, RSI etc… The most challenging part was to rebuilt the core of the project. I am very proud of MarketLab because it is my very first and my most complex python project yet....
|
1793008228.350848
|
1793094628.350848
|
|
21719
|
bs-odin by @Ankush | Stardance
|
Ankush
|
0
|
132.0
|
0
|
[]
|
[{"post_id": 31805, "ts": "202 [{"post_id": 31805, "ts": "2026-07-20T14:10:21Z", "hours": 6.0, "text": "Preformance Checkup + Audio System Things I did: I stress tested my game to work with 512 & 1024 entities. Ran under 3ms and 5ms . The difference maker was the number of entities currently in the screen (rendering). Profiled all the “slow” parts Implemented sound system , for menu and game Recorded the sounds myself!! (both in-game and ui)! Performance I tried my best to find ways to increase speed in my game. Unfortunately, all the things that I thought were “slow” weren’t actually slow. Orui UI build was like under 50micro seconds . Orui Rendering was under 250micro seconds . Animation system ran under 50micro for all entities combined iirc So, for now, there has been done no performance improvements this devlog Sound System First I made the sound system simple, for the menu. It worked and I was happy. I made 6 different similar sounds for the hover and click actions, and I play one of them randomly when clicked. menu_hover_sounds : [ 6 ] rl . Sound loadMenuSounds :: proc () { for i in 0 ..< len ( menu_hover_sounds ) { path : = fmt . ctprintf ( \"res/audio/menu/menu_click_%d.wav\" , i + 1 ) menu_click_sounds [ i ] = rl . LoadSound ( path ) } } playMenuHoveredSound :: proc () { i : = rand . int_max ( len ( menu_hover_sounds )) rl . PlaySound ( menu_hover_sounds [ i ]) } When I went on to make the Player sounds, I noticed that I am unable to the same sound twice simultaneously. I needed that so that I can simulate multiple enemies and other stuff. So I googled a bit, found this raylib example. And implemented it. For both menu and entities. TOTAL_ALIASES :: 4 Sound :: struct { aliases : [ TOTAL_ALIASES ] rl . Sound , index : int , } loadSound :: proc ( path : cstring ) -> Sound { sound : Sound sound . aliases [ 0 ] = rl . LoadSound ( path ) for i in 1 ..< TOTAL_ALIASES { sound . aliases [ i ] = rl . LoadSoundAlias ( sound . aliases [ 0 ]) } sound . index = 0 return sound } playSound :: proc ( sound : ^ Sound ) { rl . PlaySound ( sound . aliases [ sound . index ]) sound . index = ( sound . index + 1 ) % TOTAL_ALIASES } playMenuClickedSound :: proc () { i : = rand . int_max ( len ( menu_click_sounds )) playSound ( & menu_click_sounds [ i ]) } I also stole borrowed this really great background music from raylib source."}, {"post_id": 30071, "ts": "2026-07-17T11:13:28Z", "hours": 5.0, "text": "Health System, Enemy Attack, 15 new Skin! Summary of Features added: Player/Enemy Attacks Health System (Damage/Heal) Health Bar shown 15 new Skins! Avatar Menu “Set” Selector Avatar Set Selector This took a lot of time than I would like. I first had to scourge through 100s of directories for each Skin (each skin has 3 “tiers”) and get the 0th “idle” animation sprite. The next part was pretty straight forward owing to the time I took to make the architecture great :3 Health Bar This wasn’t hard as per say. But it is mad slow. I realised it earlier but never mentioned it. orui library is slow. UI libraries aren’t meant to be this slow. Probably it is due to the rendering that makes it this much slower. How slow? My renderer could render 50 entities under 1ms, now it takes ~5ms to render 20 entities. Future Todos: Performance. I will track down where orui is slow. If it is in the logic part, we can’t do anything as I am not smart enough to fix logic so complex. But if it is related to rendering, we can work with that. Performance. It’s been a while since I diagnosed the slow parts in my code. I will deep dive into the code. Find out what is slow and try to fix them The next few days, I will work on to squeeze as much performance as I can from this game."}, {"post_id": 29321, "ts": "2026-07-16T05:20:06Z", "hours": 9.0, "text": "Enemy AI done + Tons more! Other things done this time around: Fix: WASM build fixes Feature: Added the back button in Avatar Menu (finally) Fix: The character scale and position in Main/Avatar Menu acted funny in extreme dimentions (when too small) Fix: Physics renderer didn’t render polygons with 4 vertices Feature: Added physics colliders for all enemies! Feature: Y-Sorting enabled Performance: Pushed Data Oriented Design for max performance Architecture: Moved the files around, where they make more sense Feature: Implemented Attacking Feature: Player & Enemy State machine Feature: Enemy AI (super basic tbh) Performance All of these changes were made keeping performance in mind. As of right now the state machines need work to make them even faster! Obstacles State machine logic is very mind numbing, I won’t want to do that…. a lot of edge case problems. A lot of problems I never thought existed. Y-Sorting was also in the harder side because I wanted a fast sort while also not needing to change the whole array of entities. I finally decided to use another array render_list of type []int this essentially sorts the id (or index in this case) of the entities by entity.pos.y . When rendering use the ids to render. This proved to be a more efficient way to do it, than sorting the entire array of entities. Future Todos Implement Enemy attacking Implement health system (with regenability?) Draw the health bar Implement death After these things are done. We I will think of further things like game win/game end amongst many others like game pause."}, {"post_id": 28209, "ts": "2026-07-14T11:03:33Z", "hours": 5.0, "text": "Dozens of small features implemented! Migrated the End screen UI to the new UI library Brought back the physics collider with water from previously deleted code. Removed a rouge sleep call in loading phase. (Which was put there for testing ) Instead of drawing rectangles in when playing. We now draw the characters! With randomly generated skins!! Migrated Playing and loading UI to the new library Code cleanup and refactored for better architecture Culling #bd56fa When adding Culling to player rendering, I got an optimisation of 5ms->2ms. Animation while playing The initial phase was very easy. What I did struggle with was flipping the image. First, I tried flipping the texture themselves. It did work but the offset of the bones were not in place. It was fine when going right, but when I turn left. It all turns bad, the 2nd video is a demonstration of that. It took a lot of tweaks and black magic to find out that I had to also flip the anchor position and angle too 😭 Now it is working as intented :)"}, {"post_id": 26655, "ts": "2026-07-11T16:23:47Z", "hours": 4.0, "text": "Player Customisation Screen!! RAAH, this is really done! TBH this was easier than expected. I had an idea of how this will work out, and implemented just that. The menu includes some smart and fancy mathematics too // gettin the index current_index : = ( int ( curr_type ) * num_tiers ) + int ( curr_tier ) // applying the changes, Lets say user pressed right arrow. new_index : = ( current_index + 1 ) % total_options setPartType ( group , anim . CharacterType ( new_index / num_tiers )) setPartTier ( group , anim . CharacterTier ( new_index % num_tiers )) I am really proud of the UI. Looks great. Honestly I was really lucky with the great reference images I found in the internet :) hosted here"}, {"post_id": 25955, "ts": "2026-07-10T14:06:12Z", "hours": 7.0, "text": "UI Overhaul - Done! So I changed the entire UI , game UI is tough, even more so when you have a lot of moving components. I never had ever use any library like orui so it was fun, but at the same time - confusing at times. Like for example: there are only 2 components for drawing ( container and label ). I mean there’s also element, but that is just an empty container. Also I’ve tried everything but you can’t just get hover information for the container element. I need some color suggestions for the buttons in options menu, they look kinda dull… All the colors are taken from pallets at coolors.co ! Icons!! So while at it, I wanted to add icons. This was hell. A very bad idea. Let me tell you why - orui doesn’t support icons by default, so you’ve got to load another font to draw the icons. Now, Raylib can’t draw icon fonts, until you specify all the individual codepoints…here’s the code required to load a font with 3 icons: icon_codepoints : = [?] rune { 0xe048 , // ICON_LUCIDE_ARROW_LEFT 0xe049 , // ICON_LUCIDE_ARROW_RIGHT 0xe14d , // ICON_LUCIDE_SAVE 0xe18e , // ICON_LUCIDE_TRASH_2 } icon_font = rl . LoadFontEx ( \"./res/fonts/lucide.ttf\" , 32 , & icon_codepoints [ 0 ], len ( icon_codepoints ), ) Animation Blending Made the animation transition buttery smooth!! Look at the video!!"}, {"post_id": 25292, "ts": "2026-07-09T14:18:18Z", "hours": 8.0, "text": "Implemented Animation blending + UI library changed I wanted the player to be rendered in the main_menu and in the avatar menu . But also wanted the animations to be looping randomly. When I implemented random looping I found out that, the animations wouldn’t behave properly due to snapping . So I implemented animation blending . It was not at all easy , had to implement another angle_lerp function specifically for blending angles. Character customisation Due to me working hard earlier, changing character sprites is a cakewalk. In the attatched video. The head sprite is of tier 2 while the rest is from tier 1 GUI I really wanted to like raygui, but it was really bad. A lot of maths required for very simple things! I didn’t like it at all. So in search of a new UI library I found this niche library orui ! This fits my needs perfectly: Immediate mode Super fast (Not what I was looking for but a plus) Uses raylib Doesn’t depend on me to do the maths Actually customisable You can see the updated GUI in the video, looks good right :) it also supports animations and transitions!"}, {"post_id": 24692, "ts": "2026-07-08T13:28:51Z", "hours": 11.0, "text": "Fully functional animation parser and engine! The entire thing started by me searching for assets to use for my game, then I found these super cute chibi characters that too FOR FREE!! I downloaded one of the free ones and saw that they use .scml file for animations. They do have pre-rendered png images in sequence too, but that is too easy, not fun and doesn’t look good! So, I planned to make a .scml parser, my own animation engine. And see how it goes. In the added video there’s the working part and the non-working part, which I found pretty funny. 1. Image loader First I made a image loader that dynamically loads all the sprites that are in use. Later I will add the abitily to drop the sprites from memory when not in use. 2. Mapping the data This was, tough. Very, very tough that I had originally anticipated. Making this parser included me staring at a file with 9k lines for hours. Trying to figure out what each elements do and how to use them interconnectedly. I first made a scml_data.odin where I one by one mapped all the required data to odin structs. 3. .scml parser I created a new file scml_parser.odin and in it I loaded the .scml file with Odin’s built in xml parser. The parsing took a big chunk of time too, as there are not good docs or examples available out here. But there was one single forum post that got me going and I never had any problems thereafter. I parse the file and save the values in my global private data variable defined in scml_data.odin . I read each elements and added all the necessary ones. I observed all the attributes, data and values very carefully earlier so I had an idea of some repetitive values that I could skip. I think almost 50% of the file was repetition, which ofc I didn’t save. 4. The engine Now that I had all the data with me in, the only thing I had to do was use that. With a given time t I have to find the timeline that it lands on and interpolate the time, linearly lerp the values and issue a draw command for the single sprite. I was unable to do two specific things and had to take help from AI: Lerping Angle: angle lerping is different as there can be a case where we have to learp from 350 to 10, normal lerp functions would just lerp it 350->200->10 instead of 350->360->10 Using the parent bones to calculate the final position of the child node. The particular function ai generated is here . Debugging After making the engine, we got to fix the engine. It had bugs, I debugged for a long time and then fixed them. Pretty stupid things like not pushing the timeline keys after initialising them, flipped y-axis, and angle clockwise order. Final thoughts Finally the thing is working now, I still have to polish it and make it play nicely with my entire game. There are other optimisation opportunities available but I’ll put that for later. I will now work on the avatar menu, so user can mix different things."}, {"post_id": 23439, "ts": "2026-07-06T12:29:30Z", "hours": 6.0, "text": "Nothing much this time. Added options menu Added physics collider to the player (finally, phew..) Notify mobile users to play in landscape mode. That’s about it. All of them were relatively easy. What I did try and haven’t pushed to upstream is a failed attempt to detect entry and exit from water bodies by the entities in an economical way."}, {"post_id": 22204, "ts": "2026-07-04T15:44:46Z", "hours": 6.0, "text": "Drops and drops together make an ocean. Did nothing major just some small stuff Added buttons (RayGUI) for navigation #7608e9 Added Loading Screen before match starts. #76c086 , #26ddc4 Made the game fully self-contained. The game executable requires no dlls, no other libraries or assets either. Everything is bundled together in a single executable! For this to work, I used #load(\"file_source\") function. It returns []u8 or in C terms *uint8_t . But this won’t work with the raygui style loader function rl.GuiLoadStyle() that requires the ‘filename’ and not the data. So for that reason. I read the source code of raygui an d implemented their function in Odin since they don’t expose the function to the user. That’s about it tho!"}, {"post_id": 20936, "ts": "2026-07-02T17:49:13Z", "hours": 8.0, "text": "From bare metals to web. A rough road. My game is now available to play in bs-odin.onkush.dev I built my application for the Web and it works. Probably the most dirty work I had to do in this project overall. I probably have read all available Odin / WASM templates. Setting the Sail I knew what WASM is, I once to compile one of my C++ games to WASM too, but seeing more than 500+ errors in the first try took a big toll on me and I didn’t bother. I don’t want this project to end up like that. I didn’t have to search much to find a template that builds Odin + raylib in WASM . So I started to implement ‘ Offline Mode ’ for my game. Didn’t take much time tbh, easy work. So I went to sleep and assigned WASM implementation to future me. Thunderstorm Next morning, I looked at how the {template]( https://github.com/karl-zylinski/odin-raylib-web/ ) works - really simple and straightforward. I copied their code with proper attribution ofc. After fixing some build bugs, I ran my build.sh and…It didn’t work. But nothing works the first time… Spoiler, it didn’t work in the 69th time either. Tsunami By evening, I was able to make it compile, I won’t get into the specifics but it had to do with multiple definition of functions within Odin core libraries. So, after it compiled. I had a huge sigh of relief, I ran it in my browser and bam! A fully dark screen! Wait…What? NOO I opened up the console… and Alas! Errors, not 500 errors, only one error Uncaught (in promise) InternalError: too much recursion I couldn’t find what caused this error, how to fix it, how to narrow it down. Lastly I gave up and went to sleep. After I woke up! I one by one tested each file and their dependency. Lastly I found the culprit…it was Box2D After I dug deeper I found the fix, but it was concerned with changing the source code of Odin…so virtually no one can compile my game to WASM but me… I’ll try to find a workaround for it, till then - if it works, it works. The arrival to the forbidden Island After a lot of hardwork, I got the fruits of my labour. This journey was not as much fun, but seeing my game run in my browser is so much worth it! I fixed few visual glitches and frame time capture fixes. And then I pushed it into my domain :)"}, {"post_id": 19190, "ts": "2026-06-30T13:37:42Z", "hours": 10.0, "text": "Implemented Physics, generated islands form the terrain + Server side Seed generation. Performance Performance is out of the window, the algorithm that generates the islands is O(n^3) !! This disgusts me, but I wasn’t even able to come up with this solution! AI made the entire function…unfortunately I was not able to come up with the solution by myself… I understand how the function works, but I don’t know how I could improve it anyway. The one upside to this is that, this function will only run once - during the game start. My beloved physics engine Box2D can easily handle all these complex islands with no problem at all! So that helps :) Time What took 10hrs? Most of the time was trying to generate the islands, another huge chunk of time was spent making the renderer for Box2D #510535 . IDK how, but the server side seed generation that I though would take less time took about 2hrs… #4bac51 My state of mind I am currently disappointed in myself, multiplayer is hard. Server side seed generation taking so much time destroyed my confidence. Not being able to generate the islands broke me… I am having doubts of being competent enough to complete this project. My current plan is to focus on single player - offline mode. I will handle multiplayer with server later. Currently I will focus on things that are fun and actually have meaning. First I’ll make it work fully in web, then I will do character…"}, {"post_id": 17458, "ts": "2026-06-28T07:42:10Z", "hours": 5.0, "text": "Frame Time so low, we’re drawing the future. Last devlog I said Raylib was slow. It is on me, I am dumb. I didn’t have to look more into it, DrawMesh did the exact thing I required! Currently, the frame renders in my laptop under 0.9ms instead of 3-4ms earlier and in this devlog I document the changes I made. Batch Rendering Earlier I iterated over all the vertices and rendered them. for v in vertices { rlgl . Color4ub ( v . color . r , v . color . g , v . color . b , v . color . a ) rlgl . Vertex2f ( v . pos . x , v . pos . y ) } That was very slow, when I profiled it I saw that just iterating over the vertices took about 1.4ms . Drawing took another 1.5ms . So I changed the vertices data: // old vertex :: struct { pos : rl . Vector2 , color : rl . Color , } vertices : [ dynamic ] vertex // new vertices_pos : [ dynamic ] rl . Vector3 vertices_col : [ dynamic ] rl . Color Then I generate a terrain_mesh using these arrays in this function. And use that to render everything at once! if mesh_initialised && terrain_mesh . vaoId != 0 { rl . DrawMesh ( terrain_mesh , default_material , default_transform ) } Results Went from 3-4ms to 0.5ms . But when we move we have to generate the vertices at each frame! So if we don’ t move it is 0.5ms but if we move it is 4.0+ms !!! Chunking Since our terrain doesn’t change, we can store the results in GPU memory and render them at will. But if we try to render a texture of size 5120x5120 , our gpu will suffer really bad. So we chunk. We divide the terrain in chunks, load them into gpu and show only the parts that are visible currently. Sounds easy. But for stupid ppl like me it is hard, took me a long while to fight the memory, logic and silly mistakes. But finally, it did work. Results It renders about 0.8ms avg and 1ms in high load, sometimes goes down to 0.6ms too! That too while moving!"}, {"post_id": 16739, "ts": "2026-06-27T06:14:54Z", "hours": 6.0, "text": "Reworked my entire Rendering and Windowing System… Raylib - The unfortunate switch I wanted to make a game accessible to many people. And the most accessible platform is Web. So I had to compile my application in WASM . While my previous renderer, SDL_Renderer was able to render in Web it was not meant to be used intensively, it doesn’t support shaders among many other flaws. So I looked for other rendering libraries to use for my game. bgfx - no bindings for Odin sokol - I never used it, I had to ask myself if the complexity it brings with it is worth it. Very sweet option otherwise. Vulkan - No WASM SDL_GPU - No WASM Raylib comes with it’s own downsides tho - It is slow, just changing to it added 2ms to my render time, it was 1ms with SDL Renderer. But it’s simplicity keeps me in awe. Right now I’ve decided to settle with my slower Raylib and focus on important stuff like offline mode , bots , characters ."}, {"post_id": 15624, "ts": "2026-06-25T12:36:30Z", "hours": 7.0, "text": "A massive overhaul of game architecture. Architecture I think it’s safe to say that this time I unscrambled the spaghetti code that I have been writing. These things are hard but very important for a project of this scale. Else, the developer burden piles up and motivation to complete the game is dead. #883172 . Performance I implemented a simple performance hack to my terrain generation. This fix gives almost 100% faster terrain generation and rendering! I’ve documented the fix in the comments of the code here . #f2a07a Camera Till now the camera didn’t follow the player, but now it does. The math again, wasn’t easy. I introduced another bug that I caught days later. #393da8 Others Added a feature to ping server at any moment #da64b7 Enforced naming convention Out of bounds array access fix"}, {"post_id": 14192, "ts": "2026-06-23T05:49:53Z", "hours": 3.0, "text": "Implemented Marching Squares! Brief intro to marching squares This is a technique commonly used in 2d terrain generation models. It converts the rigid ‘blocky’ tiling of squares to smth more organic by adding triangles to the mix. The end result is even more good looking when you add linear interpolation! The implementation Took everything from me. I feel exhausted and tired, I need sleep. The implementation took a lot of hand written logic, here and here . But idk how but the lookup table was perfect, and required no changes! Sure took some time to make it but the results speak for themselves I think. What was indeed the problem… this code in github _bl : = bl > threshold ? 0b0010 : 0 _br : = br > threshold ? 0b0001 : 0 The fix? _bl : = bl > threshold ? 0b0001 : 0 _br : = br > threshold ? 0b0010 : 0 I had these two swapped from what the standard says! Oh my gawd, this took forever to debug. Performance The current implementation is using Painter's Algorithm , this works but there is a heck ton of overdraw! I hate it and probably will try to find a fix to it soon!"}, {"post_id": 13224, "ts": "2026-06-21T17:36:10Z", "hours": 3.0, "text": "Made rendering more than 4000% faster ! Premature optimisation is the root… So initially my renderer drew all the cells, even when not in view. There were only 64x64 cells so it was no problem for my lappy at all! But when I increased it to 512x512 my laptop took huge load (45ms rendering time)! Currently after implementing a camera thingy it is now not an issue. The terrain is generated once and only the visible part (80x45 cells) is rendered in the screen! This change lead to render times go below 1ms again :) The maths behind camera thing was really logical error prone, and took a lot of time + I had a rough time working with dynamic arrays of Odin. Apparently you got to use raw_data(array) function to get the underlying data from the array. This is not documented anywhere neither did LSP find me this function when I did try to find it! Other stuff I also changed the colours of the terrain. Added background to the fps and frame_time texts"}, {"post_id": 12636, "ts": "2026-06-20T17:10:25Z", "hours": 5.0, "text": "Procedural Terrain Generation is working now! Maths I kinda learnt a lot of maths for Perlin and simplex noise generations! Watched a lot of tutorials to get an idea of how it is generally implemented to generate terrain. It is very easy when you don’t have to code the noise functions yourselves… Resources: 1 , 2 Opensource helping while at it I also added imgui as a dependency. When imgui was building I saw a two big libraries (the actual imgui and sdl3 repos) clone. They were more than 100mb each. I made some simple code changes build.py of the original repo which brought it down to 1-2mb each. I made an issue in the original bindings repo. Let’s hope it goes well. Rendering I changed the rendering technique of the tiles of the generated terrain twice. It was real hard work. This probably took most of the time. There were many errors in maths and logic during the making of terrain renderer."}, {"post_id": 11783, "ts": "2026-06-19T05:28:23Z", "hours": 18.0, "text": "Multiplayer setup done! Server and client work flawlessly! This devlog is bigger than my normal work, because I started this project not knowing about Stardance tldr; This is a 9 day blog of my game I am making from scratch using odin lang, sdl3 for window and rendering(will switch to vulkan later on), and ENet for networking. During the 18hrs and 9 days I made functional multiplayer, rendering, game states, input handling and profiling. I spent a lot my time in the architecture and infra, in the later days, I will focus on features itself. When done, I will improve architecture and performance I spent more than 2-3 hours writing and editing the devlog, but it became too long and stardance website didn’t allow me to post it here (stardance has a limit of 4k characters and my devlog was about 6k ). So I had to upload it in my own site here . I am so sorry for the inconveniences caused 🙏"}]...
|
Title: bs-odin by @Ankush | Stardance
Devlogs:
Mu Title: bs-odin by @Ankush | Stardance
Devlogs:
Multiplayer setup done! Server and client work flawlessly! This devlog is bigger than my normal work, because I started this project not knowing about Stardance tldr; This is a 9 day blog of my game I am making from scratch using odin lang, sdl3 for window and rendering(will switch to vulkan later on), and ENet for networking. During the 18hrs and 9 days I made functional multiplayer, rendering, game states, input handling and profiling. I spent a lot my time in the architecture and infra, in the later days, I will focus on features itself. When done, I will improve architecture and performance I spent more than 2-3 hours writing and editing the devlog, but it became too long and stardance website didn’t allow me to post it here (stardance has a limit of 4k characters and my devlog was about 6k ). So I had to upload it in my own site here . I am so sorry for the inconveniences caused 🙏
Procedural Terrain Generation is working now! Maths I kinda learnt a lot of maths for Perlin and simplex noise generations! Watched a lot of tutorials to get an idea of how it is generally implemented to generate terrain. It is very easy when you don’t have to code the noise functions yourselves… Resources: 1 , 2 Opensource helping while at it I also added imgui as a dependency. When imgui was building I saw a two big libraries (the actual imgui and sdl3 repos) clone. They were more than 100mb each. I made some simple code changes build.py of the original repo which brought it down to 1-2mb each. I made an issue in the original bindings repo. Let’s hope it goes well. Rendering I changed the rendering technique of the tiles of the generated terrain twice. It was real hard work. This probably took most of the time. There were many errors in maths and logic during the making of terrain renderer.
Made rendering more than 4000% faster ! Premature optimisation is the root… So initially my renderer drew all the cells, even when not in view. There were only 64x64 cells so it was no problem for my lappy at all! But when I increased it to 512x512 my laptop took huge load (45ms rendering time)! Currently after implementing a camera thingy it is now not an issue. The terrain is generated once and only the visible part (80x45 cells) is rendered in the screen! This change lead to render times go below 1ms again :) The maths behind camera thing was really logical error prone, and took a lot of time + I had a rough time working with dynamic arrays of Odin. Apparently you got to use raw_data(array) function to get the underlying data from the array. This is not documented anywhere neither did LSP find me this function when I did try to find it! Other stuff I also changed the colours of the terrain. Added background to the fps and frame_time texts
Implemented Marching Squares! Brief intro to marching squares This is a technique commonly used in 2d terrain generation models. It converts the rigid ‘blocky’ tiling of squares to smth more organic by adding triangles to the mix. The end result is even more good looking when you add linear interpolation! The implementation Took everything from me. I feel exhausted and tired, I need sleep. The implementation took a lot of hand written logic, here and here . But idk how but the lookup table was perfect, and required no changes! Sure took some time to make it but the results speak for themselves I think. What was indeed the problem… this code in github _bl : = bl > threshold ? 0b0010 : 0 _br : = br > threshold ? 0b0001 : 0 The fix? _bl : = bl > threshold ? 0b0001 : 0 _br : = br > threshold ? 0b0010 : 0 I had these two swapped from what the standard says! Oh my gawd, this took forever to debug. Performance The current implementation is using Painter's Algorithm , this works but there is a heck ton of overdraw! I hate it and probably will try to find a fix to it soon!
A massive overhaul of game architecture. Architecture I think it’s safe to say that this time I unscrambled the spaghetti code that I have been writing. These things are hard but very important for a project of this scale. Else, the developer burden piles up and motivation to complete the game is dead. #883172 . Performance I implemented a simple performance hack to my terrain generation. This fix gives almost 100% faster terrain generation and rendering! I’ve documented the fix in the comments of the code here . #f2a07a Camera Till now the camera didn’t follow the player, but now it does. The math again, wasn’t easy. I introduced another bug that I caught days later. #393da8 Others Added a feature to ping server at any moment #da64b7 Enforced naming convention Out of bounds array access fix
Reworked my entire Rendering and Windowing System… Raylib - The unfortunate switch I wanted to make a game accessible to many people. And the most accessible platform is Web. So I had to compile my application in WASM . While my previous renderer, SDL_Renderer was able to render in Web it was not meant to be used intensively, it doesn’t support shaders among many other flaws. So I looked for other rendering libraries to use for my game. bgfx - no bindings for Odin sokol - I never used it, I had to ask myself if the complexity it brings with it is worth it. Very sweet option otherwise. Vulkan - No WASM SDL_GPU - No WASM Raylib comes with it’s own downsides tho - It is slow, just changing to it added 2ms to my render time, it was 1ms with SDL Renderer. But it’s simplicity keeps me in awe. Right now I’ve decided to settle with my slower Raylib and focus on important stuff like offline mode , bots , characters .
Frame Time so low, we’re drawing the future. Last devlog I said Raylib was slow. It is on me, I am dumb. I didn’t have to look more into it, DrawMesh did the exact thing I required! Currently, the frame renders in my laptop under 0.9ms instead of 3-4ms earlier and in this devlog I document the changes I made. Batch Rendering Earlier I iterated over all the vertices and rendered them. for v in vertices { rlgl . Color4ub ( v . color . r , v . color . g , v . color . b , v . color . a ) rlgl . Vertex2f ( v . pos . x , v . pos . y ) } That was very slow, when I profiled it I saw that just iterating over the vertices took about 1.4ms . Drawing took another 1.5ms . So I changed the vertices data: // old vertex :: struct { pos : rl . Vector2 , color : rl . Color , } vertices : [ dynamic ] vertex // new vertices_pos : [ dynamic ] rl . Vector3 vertices_col : [ dynamic ] rl . Color Then I generate a terrain_mesh using these arrays in this function. And use that to render everything at once! if mesh_initialised && terrain_mesh . vaoId != 0 { rl . DrawMesh ( terrain_mesh , default_material , default_transform ) } Results Went from 3-4ms to 0.5ms . But when we move we have to generate the vertices at each frame! So if we don’ t move it is 0.5ms but if we move it is 4.0+ms !!! Chunking Since our terrain doesn’t change, we can store the results in GPU memory and render them at will. But if we try to render a texture of size 5120x5120 , our gpu will suffer really bad. So we chunk. We divide the terrain in chunks, load them into gpu and show only the parts that are visible currently. Sounds easy. But for stupid ppl like me it is hard, took me a long while to fight the memory, logic and silly mistakes. But finally, it did work. Results It renders about 0.8ms avg and 1ms in high load, sometimes goes down to 0.6ms too! That too while moving!
Implemented Physics, generated islands form the terrain + Server side Seed generation. Performance Performance is out of the window, the algorithm that generates the islands is O(n^3) !! This disgusts me, but I wasn’t even able to come up with this solution! AI made the entire function…unfortunately I was not able to come up with the solution by myself… I understand how the function works, but I don’t know how I could improve it anyway. The one upside to this is that, this function will only run once - during the game start. My beloved physics engine Box2D can easily handle all these complex islands with no problem at all! So that helps :) Time What took 10hrs? Most of the time was trying to generate the islands, another huge chunk of time was spent making the renderer for Box2D #510535 . IDK how, but the server side seed generation that I though would take less time took about 2hrs… #4bac51 My state of mind I am currently disappointed in myself, multiplayer is hard. Server side seed generation taking so much time destroyed my confidence. Not being able to generate the islands broke me… I am having doubts of being competent enough to complete this project. My current plan is to focus on single player - offline mode. I will handle multiplayer with server later. Currently I will focus on things that are fun and actually have meaning. First I’ll make it work fully in web, then I will do character…
From bare metals to web. A rough road. My game is now available to play in bs-odin.onkush.dev I built my application for the Web and it works. Probably the most dirty work I had to do in this project overall. I probably have read all available Odin / WASM templates. Setting the Sail I knew what WASM is, I once to compile one of my C++ games to WASM too, but seeing more than 500+ errors in the first try took a big toll on me and I didn’t bother. I don’t want this project to end up like that. I didn’t have to search much to find a template that builds Odin + raylib in WASM . So I started to implement ‘ Offline Mode ’ for my game. Didn’t take much time tbh, easy work. So I went to sleep and assigned WASM implementation to future me. Thunderstorm Next morning, I looked at how the {template]( https://github.com/karl-zylinski/odin-raylib-web/ ) works - really simple and straightforward. I copied their code with proper attribution ofc. After fixing some build bugs, I ran my build.sh and…It didn’t work. But nothing works the first time… Spoiler, it didn’t work in the 69th time either. Tsunami By evening, I was able to make it compile, I won’t get into the specifics but it had to do with multiple definition of functions within Odin core libraries. So, after it compiled. I had a huge sigh of relief, I ran it in my browser and bam! A fully dark screen! Wait…What? NOO I opened up the console… and Alas! Errors, not 500 errors, only one error Uncaught (in promise) InternalError: too much recursion I couldn’t find what caused this error, how to fix it, how to narrow it down. Lastly I gave up and went to sleep. After I woke up! I one by one tested each file and their dependency. Lastly I found the culprit…it was Box2D After I dug deeper I found the fix, but it was concerned with changing the source code of Odin…so virtually no one can compile my game to WASM but me… I’ll try to find a workaround for it, till then - if it works, it works. The arrival to the forbidden Island After a lot of hardwork, I got the fruits of my labour. This journey was not as much fun, but seeing my game run in my browser is so much worth it! I fixed few visual glitches and frame time capture fixes. And then I pushed it into my domain :)
Drops and drops together make an ocean. Did nothing major just some small stuff Added buttons (RayGUI) for navigation #7608e9 Added Loading Screen before match starts. #76c086 , #26ddc4 Made the game fully self-contained. The game executable requires no dlls, no other libraries or assets either. Everything is bundled together in a single executable! For this to work, I used #load("file_source") function. It returns []u8 or in C terms *uint8_t . But this won’t work with the raygui style loader function rl.GuiLoadStyle() that requires the ‘filename’ and not the data. So for that reason. I read the source code of raygui an d implemented their function in Odin since they don’t expose the function to the user. That’s about it tho!
Nothing much this time. Added options menu Added physics collider to the player (finally, phew..) Notify mobile users to play in landscape mode. That’s about it. All of them were relatively easy. What I did try and haven’t pushed to upstream is a failed attempt to detect entry and exit from water bodies by the entities in an economical way.
Fully functional animation parser and engine! The entire thing started by me searching for assets to use for my game, then I found these super cute chibi characters that too FOR FREE!! I downloaded one of the free ones and saw that they use .scml file for animations. They do have pre-rendered png images in sequence too, but that is too easy, not fun and doesn’t look good! So, I planned to make a .scml parser, my own animation engine. And see how it goes. In the added video there’s the working part and the non-working part, which I found pretty funny. 1. Image loader First I made a image loader that dynamically loads all the sprites that are in use. Later I will add the abitily to drop the sprites from memory when not in use. 2. Mapping the data This was, tough. Very, very tough that I had originally anticipated. Making this parser included me staring at a file with 9k lines for hours. Trying to figure out what each elements do and how to use them interconnectedly. I first made a scml_data.odin where I one by one mapped all the required data to odin structs. 3. .scml parser I created a new file scml_parser.odin and in it I loaded the .scml file with Odin’s built in xml parser. The parsing took a big chunk of time too, as there are not good docs or examples available out here. But there was one single forum post that got me going and I never had any problems thereafter. I parse the file and save the values in my global private data variable defined in scml_data.odin . I read each elements and added all the necessary ones. I observed all the attributes, data and values very carefully earlier so I had an idea of some repetitive values that I could skip. I think almost 50% of the file was repetition, which ofc I didn’t save. 4. The engine Now that I had all the data with me in, the only thing I had to do was use that. With a given time t I have to find the timeline that it lands on and interpolate the time, linearly lerp the values and issue a draw command for the single sprite. I was unable to do two specific things and had to take help from AI: Lerping Angle: angle lerping is different as there can be a case where we have to learp from 350 to 10, normal lerp functions would just lerp it 350->200->10 instead of 350->360->10 Using the parent bones to calculate the final position of the child node. The particular function ai generated is here . Debugging After making the engine, we got to fix the engine. It had bugs, I debugged for a long time and then fixed them. Pretty stupid things like not pushing the timeline keys after initialising them, flipped y-axis, and angle clockwise order. Final thoughts Finally the thing is working now, I still have to polish it and make it play nicely with my entire game. There are other optimisation opportunities available but I’ll put that for later. I will now work on the avatar menu, so user can mix different things.
Implemented Animation blending + UI library changed I wanted the player to be rendered in the main_menu and in the avatar menu . But also wanted the animations to be looping randomly. When I implemented random looping I found out that, the animations wouldn’t behave properly due to snapping . So I implemented animation blending . It was not at all easy , had to implement another angle_lerp function specifically for blending angles. Character customisation Due to me working hard earlier, changing character sprites is a cakewalk. In the attatched video. The head sprite is of tier 2 while the rest is from tier 1 GUI I really wanted to like raygui, but it was really bad. A lot of maths required for very simple things! I didn’t like it at all. So in search of a new UI library I found this niche library orui ! This fits my needs perfectly: Immediate mode Super fast (Not what I was looking for but a plus) Uses raylib Doesn’t depend on me to do the maths Actually customisable You can see the updated GUI in the video, looks good right :) it also supports animations and transitions!
UI Overhaul - Done! So I changed the entire UI , game UI is tough, even more so when you have a lot of moving components. I never had ever use any library like orui so it was fun, but at the same time - confusing at times. Like for example: there are only 2 components for drawing ( container and label ). I mean there’s also element, but that is just an empty container. Also I’ve tried everything but you can’t just get hover information for the container element. I need some color suggestions for the buttons in options menu, they look kinda dull… All the colors are taken from pallets at coolors.co ! Icons!! So while at it, I wanted to add icons. This was hell. A very bad idea. Let me tell you why - orui doesn’t support icons by default, so you’ve got to load another font to draw the icons. Now, Raylib can’t draw icon fonts, until you specify all the individual codepoints…here’s the code required to load a font with 3 icons: icon_codepoints : = [?] rune { 0xe048 , // ICON_LUCIDE_ARROW_LEFT 0xe049 , // ICON_LUCIDE_ARROW_RIGHT 0xe14d , // ICON_LUCIDE_SAVE 0xe18e , // ICON_LUCIDE_TRASH_2 } icon_font = rl . LoadFontEx ( "./res/fonts/lucide.ttf" , 32 , & icon_codepoints [ 0 ], len ( icon_codepoints ), ) Animation Blending Made the animation transition buttery smooth!! Look at the video!!
Player Customisation Screen!! RAAH, this is really done! TBH this was easier than expected. I had an idea of how this will work out, and implemented just that. The menu includes some smart and fancy mathematics too // gettin the index current_index : = ( int ( curr_type ) * num_tiers ) + int ( curr_tier ) // applying the changes, Lets say user pressed right arrow. new_index : = ( current_index + 1 ) % total_options setPartType ( group , anim . CharacterType ( new_index / num_tiers )) setPartTier ( group , anim . CharacterTier ( new_index % num_tiers )) I am really proud of the UI. Looks great. Honestly I was really lucky with the great reference images I found in the internet :) hosted here
Dozens of small features implemented! Migrated the End screen UI to the new UI library Brought back the physics collider with water from previously deleted code. Removed a rouge sleep call in loading phase. (Which was put there for testing ) Instead of drawing rectangles in when playing. We now draw the characters! With randomly generated skins!! Migrated Playing and loading UI to the new library Code cleanup and refactored for better architecture Culling #bd56fa When adding Culling to player rendering, I got an optimisation of 5ms->2ms. Animation while playing The initial phase was very easy. What I did struggle with was flipping the image. First, I tried flipping the texture themselves. It did work but the offset of the bones were not in place. It was fine when going right, but when I turn left. It all turns bad, the 2nd video is a demonstration of that. It took a lot of tweaks and black magic to find out that I had to also flip the anchor position and angle too 😭 Now it is working as intented :)
Enemy AI done + Tons more! Other things done this time around: Fix: WASM build fixes Feature: Added the back button in Avatar Menu (finally) Fix: The character scale and position in Main/Avatar Menu acted funny in extreme dimentions (when too small) Fix: Physics renderer didn’t render polygons with 4 vertices Feature: Added physics colliders for all enemies! Feature: Y-Sorting enabled Performance: Pushed Data Oriented Design for max performance Architecture: Moved the files around, where they make more sense Feature: Implemented Attacking Feature: Player & Enemy State machine Feature: Enemy AI (super basic tbh) Performance All of these changes were made keeping performance in mind. As of right now the state machines need work to make them even faster! Obstacles State machine logic is very mind numbing, I won’t want to do that…. a lot of edge case problems. A lot of problems I never thought existed. Y-Sorting was also in the harder side because I wanted a fast sort while also not needing to change the whole array of entities. I finally decided to use another array render_list of type []int this essentially sorts the id (or index in this case) of the entities by entity.pos.y . When rendering use the ids to render. This proved to be a more efficient way to do it, than sorting the entire array of entities. Future Todos Implement Enemy attacking Implement health system (with regenability?) Draw the health bar Implement death After these things are done. We I will think of further things like game win/game end amongst many others like game pause.
Health System, Enemy Attack, 15 new Skin! Summary of Features added: Player/Enemy Attacks Health System (Damage/Heal) Health Bar shown 15 new Skins! Avatar Menu “Set” Selector Avatar Set Selector This took a lot of time than I would like. I first had to scourge through 100s of directories for each Skin (each skin has 3 “tiers”) and get the 0th “idle” animation sprite. The next part was pretty straight forward owing to the time I took to make the architecture great :3 Health Bar This wasn’t hard as per say. But it is mad slow. I realised it earlier but never mentioned it. orui library is slow. UI libraries aren’t meant to be this slow. Probably it is due to the rendering that makes it this much slower. How slow? My renderer could render 50 entities under 1ms, now it takes ~5ms to render 20 entities. Future Todos: Performance. I will track down where orui is slow. If it is in the logic part, we can’t do anything as I am not smart enough to fix logic so complex. But if it is related to rendering, we can work with that. Performance. It’s been a while since I diagnosed the slow parts in my code. I will deep dive into the code. Find out what is slow and try to fix them The next few days, I will work on to squeeze as much performance as I can from this game.
Preformance Checkup + Audio System Things I did: I stress tested my game to work with 512 & 1024 entities. Ran under 3ms and 5ms . The difference maker was the number of entities currently in the screen (rendering). Profiled all the “slow” parts Implemented sound system , for menu and game Recorded the sounds myself!! (both in-game and ui)! Performance I tried my best to find ways to increase speed in my game. Unfortunately, all the things that I thought were “slow” weren’t actually slow. Orui UI build was like under 50micro seconds . Orui Rendering was under 250micro seconds . Animation system ran under 50micro for all entities combined iirc So, for now, there has been done no performance improvements this devlog Sound System First I made the sound system simple, for the menu. It worked and I was happy. I made 6 different similar sounds for the hover and click actions, and I play one of them randomly when clicked. menu_hover_sounds : [ 6 ] rl . Sound loadMenuSounds :: proc () { for i in 0 ..< len ( menu_hover_sounds ) { path : = fmt . ctprintf ( "res/audio/menu/menu_click_%d.wav" , i + 1 ) menu_click_sounds [ i ] = rl . LoadSound ( path ) } } playMenuHoveredSound :: proc () { i : = rand . int_max ( len ( menu_hover_sounds )) rl . PlaySound ( menu_hover_sounds [ i ]) } When I went on to make the Player sounds, I noticed that I am unable to the same sound twice simultaneously. I needed that so that I can simulate multiple enemies and other stuff. So I googled a bit, found this raylib example. And implemented it. For both menu and entities. TOTAL_ALIASES :: 4 Sound :: struct { aliases : [ TOTAL_ALIASES ] rl . Sound , index : int , } loadSound :: proc ( path : cstring ) -> Sound { sound : Sound sound . aliases [ 0 ] = rl . LoadSound ( path ) for i in 1 ..< TOTAL_ALIASES { sound . aliases [ i ] = rl . LoadSoundAlias ( sound . aliases [ 0 ]) } sound . index = 0 return sound } playSound :: proc ( sound : ^ Sound ) { rl . PlaySound ( sound . aliases [ sound . index ]) sound . index = ( sound . index + 1 ) % TOTAL_ALIASES } playMenuClickedSound :: proc () { i : = rand . int_max ( len ( menu_click_sounds )) playSound ( & menu_click_sounds [ i ]) } I also stole borrowed this really great background music from raylib source....
|
1792943262.175508
|
1793807262.175508
|
|
950
|
Volvo API playground by @Kl | Stardance
|
Kl
|
1
|
130.69
|
2165
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-06T20:19:02Z", "hours": 113.0, "multiplier": 19.09, "payout": 2165, "blessing": "neutral", "text": "A Milestone Welcome everybody to the first ship of this project. What is this project? This project simulates how the Volvo API works. Why was this project created in the first place? So it’s easier to create and test your app that uses the Volvo API without using ready-made libraries. I can’t find the features you mentioned in the devlog? Check the scope branch or the upcoming dev branch. What I’m proud of: I learned a lot of things (this is my first big public project): Tailwind Python stuff (I started with C++) Writing documentation (Markdown) I also learned the basics of OAuth2 and how APIs work. Making a project with all the features needed to get started. I created an additional document for you, Stardancers: Stardance PATH What is still on the TODO list? More APIs Scopes docker image See the roadmap . What to see? error logger recreated endpoints dashboard web socket realtime changes internal endpints interactivity of the car", "repo": "https://github.com/klswar0/Volvo-API-playground", "demo": "https://playground.kls.hackclub.app/"}]...
|
[{"post_id": 79861, "ts": "202 [{"post_id": 79861, "ts": "2026-10-15T17:17:04Z", "hours": 7.1881, "text": "Devlog A very long time no see. I have made a lot of progress on adding an SQL database. Testing on MySQL The backup server provider gives me access to one. SQL changes A lot of BIG changes. The reason why I haven’t posted for so long is that I didn’t want to post about something that doesn’t work. Created new classes to intercept data changes, both in case of direct dict changes and when going through the SQL model library. (I didn’t change much in the code, just imported it under the same name as the old database.) And it works! At the start, only reading data worked, but now it can send data back to the database. Added a regen function to make sure built-in API keys are always the same after a restart. Fixed the car creation function (but when I started storing the additional data in SQL, it broke AGAIN). Added configuration attributes. At first, just the database type, but then all the information needed to connect to a MySQL database. Fixed the scenario readconfig (wasn’t it updated in the past?). A really small number of things I added? Yes, but the amount of debugging and changing built-in functions in classes took me so long. (Could be because of school and not having time to do everything in one sitting.) But I learned how to make a dummy dict with a class, as I called it in the commit: proxy . Problems The SQL database can’t create new cars. Need to check all internal endpoints to make sure they work. Still haven’t merged the DEV branch (TODO). All information is stored in one column as JSON. It works, buuuut I don’t like it that way. Need to clean up the proxy classes. updating docs What failed this time? The second photo attached shows it. Have a look before reading more. _contains__ If you see it, congrats! But if you have a screen full of code, it’s harder to spot. It should be __contains__ , and I spent, I think, two days debugging why all in statements just didn’t work. I was so happy when I finally found it! XAMPP and Apple Silicon The manager app doesn’t open after a restart, so after consulting Google and AI, I found a command that I use: sudo /Applications/XAMPP/xamppfiles/xampp start xampp If someone is asking why I didn’t use the server provided one it just wasn’t practical for now."}, {"post_id": 73730, "ts": "2026-09-25T19:56:38Z", "hours": 4.9217, "text": "Devlog A lot of breaking changes later and getting closer to PR and going to 2 ship Token lifetime WORKS made time when token is expired is rounded to int endpoint for invalidating token possibility for enabling expiring token for a specific token when it’s disabled for all in config file misc pytest for location and energy API fix the url for the enrgy API (it started with connectivity url not wi the energy api) cleanup import created new files to make the code more readable dashboard added location values added capabilities and values auto token generation and expiration in dashboard"}, {"post_id": 69307, "ts": "2026-09-16T19:32:57Z", "hours": 5.58, "text": "Read till the end PLEASE 🥺 Devlog A lot of changes from the last devlog only 5 hrs Mostly bc I add stuff on top of but I will suffer in the future (See dev branch for these changes) Change all connectivity API to start with /connected-vehicle/v2/ to make room for different APIs After that I fixed pytest to reflect that I added a location API with a ONE endpoint There were few iterations Added scopes for this API location:read If I remember correctly Unique error responses (because location error look like old (v1) connectivity API Fixed that operationID could be a constant Added a config option to use longer API keys About here I Fixed the url for location api because it used the connectivity scheme Started working on energy API I added all data from it to this project In short one endpoints says what this car is capable of And the other says the values TODO: add its unique error its half done Scopes corresponding to energy API Fixed that some values and capabilities had the same name (bc of that some bool values where number so a it was important) WIP Oauth2 update: JWT tokens for access tokens WIP token can expire! what are JWT token? There consist of three parts header payload and signature The two first is important for my project the 3 isn’t . They store info about issuer, when token is active, scopes… A lot of useless data for this project or useful? We will see Life Bc of school I didn’t have a lot of time to write devlog (and write code) but I try to do my best before the end of stardance The next ship is planned for 28 September BIRTHDAY TODAY (16 September) Im celebrating my birthday 😄 If you write me a few good words It would be motivating for me."}, {"post_id": 63130, "ts": "2026-09-06T19:20:58Z", "hours": 1.6042, "text": "Devlog MAIN added a startup baner fixed snapshots not saving if website was used scope If you didn’t follow from start this branch contains the experimental scope support which is mostly done but I can guarantee stability that’s why it isn’t pushed to main in fist ship made the scope page work added a back button added button to scope on main page fixed snapshots loading/saving"}, {"post_id": 61052, "ts": "2026-09-03T19:22:00Z", "hours": 2.8836, "text": "Long time no see… The school started aaand I didn’t have time I had low motivation The only thing to do before first ship is docs but I could find time to finish them. Buut I back now. AND I promise to ship it before 7 of September. If you are voting on this project PLEASE do not skip. I have my birthday coming and if the shipwrights doesn’t have a long list it could mean this project payout could be my birthday gift. If I ofc ship it 😅 devlog Small marketing changes everywhere to say that this project doesn’t have any ready code to use Added info about error logger on the landing page Scopes A long way from last devlog Fixed pytest ( A second time) TEMPORARY FIX added so the scope error doesn’t - throw just internal error FIXed the Oauth2 endpoint at least 3 times Added a WIP endpoint to edit scope data from API Fixed how cars are created so they work with both - Oauth and scopes stuff Only looking dashboard page for scopes compare I think I forgot to say something in last devlog config file if you would like to use different instance Toml oillevel to oilLever AI disclaimer that I used this project to learn tailwind Make the doors have different statuses in mean time Untracked WIKI Redo the home page Started working on stardance path A lot of misc that I don’t remember other I created a small modified volvo example app to show that my app works like the real one"}, {"post_id": 55226, "ts": "2026-08-26T20:27:11Z", "hours": 4.2503, "text": "Devlog Error logger added colors to the terminal print out using: \\033[31m \\033[0m Good to know that it is so easy to add colors to text added timestamps to log file and - between errors Changes how it reads body once again and fixed url encoded requests logging My additional information I put in detail in the json response (the real API can send it like that buttty I didn’t see it. info from docs ) additional changes: New scenarios mostly about service warnings You can add notes to the website thru config files Scopes I started working on scopes. What are they? They are really permissions (you can know them from discord bots or if you login thru GitHub etc.) I don’t want to put them in this first ship but I needed to work on something (while I work on wiki) and I CAN’T guarantee every thing works after adding them. You can see it in the scopes branch. what is done: I have made preparation so the additional database (dict) I use for OAuth can store more data have updated website func to work with changes and also pytest added all possible conve (connectivity API) scopes WIKI when I add everything to them I will finally try making a ship added the error logger page updated the sidebar scenario and snapshots page a lot of misc Bonus photos from vacation on baltic sea"}, {"post_id": 49931, "ts": "2026-08-18T21:59:53Z", "hours": 3.1292, "text": "Devlog There was a small (or big) problem in my playground. If an error was returned in the response, you could only see it if your app handled it or by printing the response. That’s why I added an error logger. It can show errors in two ways: Terminal Log file How it works There were two ways of doing it (from what I learned): Middleware that captures all responses (this could be helpful in the future). Exception handlers (this is what I chose). I use two handlers: @app.exception_handler(RequestValidationError) @app.exception_handler(HTTPException) It was a horrible time searching for why it didn’t work. At first, I worked in a separate file, but I couldn’t get the (fastapi) app variable into those functions. So I copied them into main file to make them work first. I had to change some JSON responses to HTTPException to make the second handler work. After I captured the first request and printed it, I worked on one function that writes a log and another that prints to the terminal. I also created a class to store useful data. It works like this: Exception handler-> ->Put data into class -> ->Create response -> ->Return response ->Create a background task that logs the error I create a background task so the response doesn’t wait or even worse fails In the end I found that I can wrap these func with this simple func to make them work in different file def setup_error_logging(app: FastAPI): Added a config option: To disable it completely. To disable only the log file. It also bypasses all internal endpoints to make the logs more readable. The best fail… 😅 I returned an exception instead of raising it. I spent a good 15 minutes wondering why the response had status code 200 with a JSON body saying status code 400 . response changes I also checked how the authorization errors look and added two new ones: Missing Authorization header. Invalid vcc-api-key header. WIKI (not counted) I focus on making a GitHub wiki (new docs) After ending them and the error logger. Its time for the first ship !!!!!!! Nest instability: I made a backup server : https://frog01-21185.wykr.es/ Its not ideal one, bc some asian countries are blocked but its shouldn’t have any downtime (I hope so) If an Admin read it why I must copy enter from different text input 😭"}, {"post_id": 48444, "ts": "2026-08-16T19:51:20Z", "hours": 2.4822, "text": "Devlog SITE changes I found that some number inputs didn’t use the utility classes. I gave them inputText because they are really the same; the only difference is the HTML type . I also forgot to update the reloadable fuel section. It now uses the shorter utility class. Made sure that all text in the header is the same size (they weren’t). I copied all changes back to the main branch. config changes Then I added a config file using the configparser library. also added an option to disable the FastAPI docs. I started working on Wiki: reworking docs.md into a GitHub Wiki with up to date information. Error logger, so you can see what’s wrong without printing the API response in your code. I had some problems with catching the fastapi automatic response but I will leave it for next devlog"}, {"post_id": 46236, "ts": "2026-08-13T10:31:45Z", "hours": 4.6175, "text": "Devlog I forgot to add that I worked on the tests in the test branch, not the main one. OAuth2 PKCE testing. Helped me find an error where, if the code was used (it was reset to \"\" ), it was accepted as \"\" . Now it correctly returns an error. OAuth2 flow testing. Warnings and diagnostics now have some simple checks too. And I merged it into main . Then I started cleaning up the Tailwind CSS. NOTE: they are in new branch dashboard/cleanup Why? Because I used the Play CDN in the past, so I couldn’t create utility classes in a CSS file. Soooo I didn’t. Andddd there were a lot of Tailwind classes that didn’t fit on my screen. Now that I started precompiling it, I could add them. I added 5 unique utility classes. All of them combined are used around ~120 times across all HTMLs. The longest one: @utility inputSelection { @apply w-full px-4 py-2 .5 bg-zinc-950 border border-zinc-800 rounded-xl text-zinc-100 focus : outline-none focus : ring-2 focus : ring-blue-300 focus : border-transparent transition-all appearance-none text-center [ text-align-last : center ] cursor-pointer ; } I also minified the CSS file. If I understand it, it removes anything the browser doesn’t need to understand the CSS (new lines, unnecessary spaces…). It’s better because those characters are still sent over the network, and fewer bytes mean less traffic. While using the new utility classes, I tried to preserve the layout, so everything should look the same as before."}, {"post_id": 44802, "ts": "2026-08-10T20:28:29Z", "hours": 3.7639, "text": "Devlog Working hard on pytest tests. I learn how assert works and how to name . I never used or created test in any language so I think they aren’t perfect (not like they should),but they work😄. I looked like AI made few and how other people and read some stuff online Tests created for these endpoints Around 25 of them List cars About car Engine info Engine start/stop Climate start/stop Windows Doors Lock/Unlock Reduced Guard Lock Flash, Honk, and Combination Tyres Statistics Fuel Odometer Engine diagnostics Brakes Command accessibility Still to do Warnings and diagnostics Commands More changes The tests helped me find and clean up several issues: Documentation updates. The honk endpoint was ../horn but should be /honk . Some values ( odometer , fuel ) are int , just like in the OpenAPI specification, not as described in the official docs. Fixed spelling mistakes: - oillevel to oilLevel - coolantLever to coolantLevel Want to help and has access to volvo with active VOC I need to test engine and climate endpoints but I don’t have an access to a car with it. Soooo if you can contact me on slack"}, {"post_id": 42512, "ts": "2026-08-07T09:41:54Z", "hours": 4.2411, "text": "Devlog Tracking headers implemented : There are two vcc-api-operationId - UUID traceparent - W3C traceparent (for now only sends it back) dashboard should look good on small screen (its very long but I don’t want to redesign it now) This is the reason why I there is much time in this devlog. It was a lot of try and error before something looked good both on mobile and desktop and I liked it . But at least it works know 🙃. some small cleanup of comments I worked again on internal updates endpoint (hopefully works now) started working on pytests (but I will talk about in next devlog (I gave my self 2 days for it) I really want to get the first ship out, so it isn’t going to be perfect. I still have a lot of features and improvements I’d like to add."}, {"post_id": 40711, "ts": "2026-08-04T12:41:43Z", "hours": 4.4231, "text": "Devlog I had a problem when I wanted to rewrite the scenario system. It only changed the local version of the Car (It means it really didn’t update anything). I wanted to update a backup version first, and only if everything was correct, replace the original with the backup. In the end, I used an already created function to first test and then apply to the car . Main PKCE misspelling fixed. Added a landing page with an option to disable it and redirect directly to the login screen (like in the last devlog I have photos of making it). Worked on the lights section. Fixed the docs URLs. Dashboard and WebSocket toggles now work. Rewrote and enabled the updates endpoint. Validation now catches values that can’t be converted to int . Scenario loading into a car instance should now be more consistent with the other functions. Improved mobile responsiveness (and then fixed the desktop one). Some elements were outside the screen on mobile (nothing important, but it didn’t look good). NOTE: the dashboard with car attributes still needs to be adapted. Added windows (because I forgot to 😅) to the dashboard and organised the lighting section. OAuth2 and Snapshots buttons should now always be centred. TODO Debug and tracing headers (from the real API). Additional instructions. Then I think it’s finally ready for the first ship. There are still a lot of things I want to add, but I can’t work indefinitely. Compare The compare app now has the Content-Type fix enabled (like the official API). Compiled the Tailwind CSS for the compare app. NOTE: I will add here more screenshots as link later Also thinking about adding it frictionless mission but I’m not sure."}, {"post_id": 39642, "ts": "2026-08-02T19:24:37Z", "hours": 3.62, "text": "Devlog Snapshots loading page (screenshots while I worked. I had more but the limit was 4). As suggested by the Tailwind CSS tools, changed some classes to more canonical ones. You can now delete cars through both the API and the dashboard. Snapshot corruption (when the app is force quit) should be fixed. Started working on the landing page, but I’ll leave it for the next devlog (mostly because I have on my other laptop). Fixes to do Sometimes the new OAuth2 and Snapshots buttons are off-center. Compare app needs fixing (need to enable the Content-Type fix from the official API). PKCE spelling in the internal API."}, {"post_id": 37827, "ts": "2026-07-30T19:39:54Z", "hours": 4.1028, "text": "Devlog The Content-Type problem is SOLVED …… What was the problem? (My reading skills? ) there are two headers with application/json : Content-Type (POST) Accept (GET) The Accept header isn’t required ( can be */* , application/* or application/json ). So the Content-Type mystery is mostly FIXED but I still need to check with a real Volvo car if Content-Type is actually required. (I’ll do it tomorrow.) Changes: Accept is now handled by my API like in the official API. Added Content-Type checks (like the docs say, meaning it’s required). While proofreading the docs, I found that PKCE is written as PCKE in one internal endpoint. (Not fixed yet.) Small README update (I try to keep it up to date). Scenario page: You can now load a scenario using the GUI. Recompiled the Tailwind CSS. I attached screenshots showing it (you can also see snapshot button but its not implemented YET)"}, {"post_id": 36608, "ts": "2026-07-28T20:31:07Z", "hours": 0.5122, "text": "The comparison app is now online! Comparison app: https://compareplay.kls.hackclub.app/ I also updated the main app with the new dashboard design: https://playground.kls.hackclub.app/internal/welcome devlog Tailwind CSS is no longer loaded from the CDN. I think its now precompiled. Note to others: Remember to update your banner to feature your app (see #stardance on Slack). Otherwise, your ship will be rejected. EDIT: A lot of bots try to connect to my apps do you think I should make a honeypot?"}, {"post_id": 36297, "ts": "2026-07-28T09:47:40Z", "hours": 3.2881, "text": "Devlog I found another way to hide the fuel stat when it isn’t useful for a particular type of car: the HTML hidden attribute. At first, I thought I should add or remove the element hidden, but that turned out to be more complicated than I expected. I think using hidden is still a cleaner solution but I still using templates files. While working on the dashboard, I wanted to add units like km , L , and % to some values. Instead of handling that in Python, I added another div with some margins and, in a few places, used flex so everything stays on the same line without adding more backend logic. Added more page changes thru HTMX (nearly all pages use it). Creating a new car now refreshes the page. when an error occurs, I use HX-Reswap and the HX-Retarget response header (when creating new car as proof of concept). Added HTMX transitions to the OAuth2 settings page.(all pages have transitions) What to do before the first release (Mostly a checklist for myself 😅) Content-Type checks. Scenario and snapshot system support in the dashboard. Main showcase page. Finish the remaining documentation. Two READMEs: one for the main repository and one for the companion app repository. I’m thinking about having one technical README and another one that’s easier to understand for people who don’t code. Better error handling in the dashboard. Right now, most errors are just displayed as plain text instead of being part of the page. deploy updated version on nest I wanted to add a video but MacOS made me a half gig and I don’t think stardance would handle"}, {"post_id": 35043, "ts": "2026-07-26T06:29:01Z", "hours": 5.5947, "text": "Devlog Most of my time was spent working on the dashboard with Tailwind CSS. It took a lot of experimenting to find a design I actually like. I also changed how HTMX updates the dashboard through WebSockets. Before: A dedicated template was rendered every time to update that part of the dashboard. Now: Only the text containing the updated value is replaced. That said, in the future it won’t always be just text. For example, if the fuel type changes from hybrid to electric , the fuel level should disappear from the dashboard instead of just changing its value. While working on this, I found a bug caused by HTMX sending boolean values as strings. This caused climate settings to be marked as invalid. I need to distinguish between an invalid value and an invalid attribute instead of always treating the entire attribute as invalid. Note to myself Add transitions. Make all HTML pages use the same CSS file from now on. Update the version on nest server and make a public companion instance Aaand that’s all. Making websites is painfully slow."}, {"post_id": 33472, "ts": "2026-07-23T13:34:25Z", "hours": 4.2786, "text": "Devlog I don’t know if I mentioned it before, but for now the Content-Type checks are disabled. I need to learn more about them and implement better validation. Created an updated OAuth2 settings page and a car selection screen (with Tailwind CSS, of course). Started experimenting with a new dashboard. It’s still a work in progress, but it will most likely become the main design. I’m also thinking about adding a second dashboard style, although I’m not sure if I’ll do that before the first release. I definitely want to clean up the HTML/Tailwind code by moving repeated styles into reusable classes or something similar. I’m also thinking about using more HTMX so that more pages can update data without needing a full page reload. Wrote more documentation. I still need to verify the fuel endpoint because I don’t remember whether it handles different engine types correctly. ( The new OAuth2 settings page and the car selection screen. For next develop I think I will make a video of how everything works)"}, {"post_id": 32303, "ts": "2026-07-21T11:58:32Z", "hours": 2.6278, "text": "Devlog Companion app I said it was finished for now, but I forgot to add one more thing (the one on the left in the screenshots): a dashboard redirect. Main app I’m still investigating the Content-Type problem. I verified that the official Volvo API behaves correctly, so I’m working on matching that behavior. Added work-in-progress Content-Type checks. Started reworking the CSS using Tailwind CSS. It’s still mixed with some plain CSS for now. Enabled support for the reduced guard lock command. You have to manually mark it as supported, and for now it behaves the same as the normal lock command. Let me know which design you like more: the new one (center) or the old one (right)."}, {"post_id": 31979, "ts": "2026-07-20T20:18:13Z", "hours": 3.7667, "text": "Devlog I’m mainly focused on finishing the companion app. I started working on the CSS. Most of my time was spent learning Tailwind CSS (so I didn’t track it). I think it’s a better fit for me than writing plain CSS. Added Tailwind CSS to all pages of the companion app. (I think I need to redo the main app now. 😅) Added a small README with information about the main app. I think it done now but I will come back to it before first ship Main app While working on the companion app, I found another issue. The Content-Type: application/json behavior doesn’t match the official API. I verified that the official API works as expected, checks for it mine doesn’t (I think)"}, {"post_id": 30890, "ts": "2026-07-18T21:12:58Z", "hours": 3.2169, "text": "Devlog Companion app Added manual mode for comparison. Engine start/stop now works in normal mode. Before pushing, I forgot to fix one thing: { \"error\" : \"Failed to retrieve data from unofficial API.\" , \"detail\" :{ \"detail\" :[{ \"type\" : \"dict_type\" , \"loc\" :[ \"body\" ], \"msg\" : \"Input should be a valid dictionary\" , \"input\" : \"{ \\\" runtimeMinutes \\\" : 10}\" }]}} The fix was simple: I forgot to use json.loads() . I pushed a quick fix commit right after. The photo shows the manual comparison page. I’m still working on the comparison logic, which is why it doesn’t have any CSS yet. Sorry for not adding Volvo API keys so you can see the differences between both APIs, but that would have taken too much time today. Its also the reason why Im creating this app Main app Worked on the documentation. The notifier now supports more than one updated attribute at the same time. It’s not the best implementation, but I’ll improve it after the first ship. Fixed snapshot loading and added exception handling. Scenario loading now reports malformed JSON files. Fixed a dashboard bug where tire information was shown three times. I think I planned to add more data there… and then forgot. I should probably test everything before making a devlog or committing, but I also don’t want my devlogs to have to much time."}, {"post_id": 29435, "ts": "2026-07-16T11:46:44Z", "hours": 0.5936, "text": "A public online demo!!!!! The project is finally available online! https://playground.kls.hackclub.app/internal/welcome Please don’t be the bad guy and fight with other people over access. ❤️ That’s all I wanted to say because this is a really big milestone for me. There will also be another commit today to make sure everyone can run their own instance of the project. I found a few issues that only appeared outside of my local environment: Some WebSocket features break when using HTTPS. The dashboard had problems when the instance wasn’t running on the same computer. Those should be fixed in today’s commit. If you find any errors please comment or contact me on slack Also thanks to nest hackclub for hosting"}, {"post_id": 29164, "ts": "2026-07-15T21:37:24Z", "hours": 2.8483, "text": "Devlog Authorization was my mistake. It should have been accessToken , not Authorization . Why I thought that? I have no idea. No it was good before I was sleepy I think when I did that The snapshots system now works. Why it didn’t work as expected: I forgot to use copy(deep=True) . One of the small dictionaries was written incorrectly. Added saving and loading snapshots from a file. The scenarios system now works and has been tested. Difference between snapshots and scenarios Snapshots copy all data about a car. They are persistent and can be saved to a file. Scenarios only change selected attributes. They are designed to be created and edited manually in a JSON file. Main app The main app is mostly ready. Before the first release, I still need to: Finish the documentation. Add a roadmap with future updates. Verify error responses against the real API. Finish the comparison feature in the companion app. Add more ready-to-use scenarios and API keys. Companion app Manual login now works, so only the comparison logic is left. I found a bug where api_key_p was None because one endpoint redirected using api_key instead. Started working on the comparison feature. PS: A photo of why the api_key_p was none"}, {"post_id": 27883, "ts": "2026-07-13T19:57:06Z", "hours": 3.8994, "text": "Devlog Writing documentation is a good way to check whether the code you wrote actually works. I already found four bugs while documenting the project. For example, I forgot to pass the redirect URI in a function in main.py , even though it was already implemented in internal.py . I also fixed a bug where notifications could sometimes contain an older value. The dashboard has been moved into a separate file. Snapshots currently have a problem. They are very similar to the Car class, so I’ll debug it and explain what the issue was in the next devlog. Companion app The companion app is meant to showcase the differences between my implementation and the official Volvo Demo Car Sandbox. It also makes testing easier, since you don’t have to write your own application just to try the API. I had a problem with the built-in LibreSSL because one of the dependencies didn’t support it. I had to reinstall Python so that uv would detect the new OpenSSL installation. After that, I was finally able to start the app and get it working. Auto-login and automatic creation of a test car are now working. There’s is no css but I will do it after logic works One more thing: the reason the devlogs have been quieter recently is that I’ve been dealing with some administrative paperwork. I’ll get back to posting them more regularly once that’s sorted out."}, {"post_id": 25868, "ts": "2026-07-10T10:58:56Z", "hours": 4.3936, "text": "Devlog How I don’t like web development… did I already say that? I’ll say it again. I’m working on the OAuth2 settings, and I had a problem where one of the query parameters wasn’t reaching the backend. I still don’t know what actually fixed it. Then I had another problem. I have a function that changes values in the backend, but only one button worked while everything else didn’t. It turned out to be because I debugged the first problem with AI. Always trust your own mind before trusting AI. The problem was hx-trigger . I also had problems applying CSS through HTMX. In the end, I solved it by using hx-redirect . But in the end everything works (you can see it one the phtoto) I also worked on the scenario system, which loads scenarios from a JSON file. It isn’t tested yet, and I still need to work on state snapshots. The idea is that you’ll be able to save a moment in time and restore it later, so you can test the same scenario as many times as you want without setting up all the data again. I also started working on a companion app to showcase the differences between my implementation and the official demo car sandbox. I’ll write more about it in the next devlog."}, {"post_id": 24338, "ts": "2026-07-07T20:58:43Z", "hours": 3.7069, "text": "Devlog A small error from the last devlog: it’s PKCE , not PCKE . I had to rename a lot of variables because of that. More customizable data Gearbox Model year More diagnostic data for lights (hazard, fog, brake, high beam, low beam, and more) Other additions Added a new default API key with 3 cars, each having different values. Wrote more docs. Started working on scenarios (templates for new or existing cars to make setup faster). I’m thinking about loading them from a file so users can create their own. Started working on setting up OAuth2 through the dashboard. Fixed most command responses because when I first created them, I forgot to wrap everything inside { \"data\": {} } . Added light options to the dashboard. Working: PKCE How does it work? The application generates a random secret. Before redirecting the user to the login page, it sends only a hashed version of that secret. After the user logs in, the application receives an authorization code. When exchanging the code for tokens, it sends the original secret. The server checks whether it matches the previously received hash. If it does, the tokens are issued. It normally protects from having the tokens stolen New promoting picture I made in canva have a look"}, {"post_id": 23100, "ts": "2026-07-05T20:54:08Z", "hours": 3.3289, "text": "Devlog Small additions to the new documentation. changes how the api handles errors BIG ADDITION OAuth2 without PKCE. I started working on PKCE, but I thought I should write a devlog before adding it. Added a login website (I know I mentioned it last time). Added a way to enable and disable OAuth2. Authentication now checks whether OAuth2 is enabled. If it is, requests are authenticated using OAuth2. Tokens don’t expire yet, but that will be added soon. Added endpoints for refreshing tokens and exchanging an authorization code for tokens. How does OAuth2 work? The app redirects the user to a login page. After logging in, the website redirects the user back to the callback URL provided by the app. The app receives an authorization code, which it exchanges for two tokens: a long-lived refresh token and a short-lived access token. When the access token expires, the app can use the refresh endpoint to obtain a new access token. What is PKCE? I’ll write more about it once it’s added to the project. In short, PKCE protects the authorization flow by ensuring that only the application that started the login process can exchange the authorization code for tokens. The application first generates a random secret (called a code verifier). Before the login request is sent, a hashed version of that secret (the code challenge) is sent to the server. Later, when exchanging the authorization code for tokens, the application sends the original secret. The server verifies that it matches the previously received hash before issuing any tokens. I’ll explain the complete flow in the next devlog."}, {"post_id": 20221, "ts": "2026-07-01T19:28:27Z", "hours": 5.3022, "text": "Devlog This devlog will be a short one because I’ve been focusing on implementing OAuth 2.0. I’ll cover that in more detail in the next update but I will add photo of a “login” screen that I created for it (it looks bad on purpose). What’s new The terminal now works with more than one static car. The dashboard can (once again) create new cars. The codebase has been split into multiple files instead of a single large file: main still contains the public API endpoints. internal contains the dashboard logic and internal API endpoints. database will contain multiple predefined car scenarios. I also started writing a new manual that documents the quirks of the Volvo API and my implementation ( and edge cases). I will write more about in next 2 devlogs What’s left before the first ship An example application demonstrating the differences between the official Volvo Sandbox and this project. OAuth 2.0 with PKCE (it would be great to have before the first ship). Documentation. A major code cleanup and refactoring."}, {"post_id": 17924, "ts": "2026-06-28T21:18:15Z", "hours": 2.7358, "text": "Devlog I added two static (for now) endpoints: statistics and warning . The statistics endpoint mostly returns data, so there isn’t much to test. The warning endpoint has a very large response that would require a lot of new code, and for now I don’t want to implement all of it. I started working on adding cars through the dashboard (you could already see part of it in the last devlog), but I found out it doesn’t work, so I need to fix it before the next devlog. Climate and engine STOP commands now respond correctly. In the last invoice update, they incorrectly returned RUNNING . Added checks for the new command endpoints to verify whether the car supports a given command. Added a small terminal page that outputs changes. In the future, you’ll be able to choose whether to display only Volvo changes, all changes, or all information (for example, if you checked whether the windows status). I also used it to verify that the normal WebSocket status works. Added the foundations for disabling WebSockets on startup. Only a configuration file is left to implement. Added UNAVAILABLE reason invoice logic mostly something like this: If the reason is NO_INTERNET , the invoice becomes CONNECTION_FAILURE . If the reason is POWER_SAVING_MODE , the invoice becomes VEHICLE_IN_SLEEP . Made some improvements to the dashboard’s appearance."}, {"post_id": 15774, "ts": "2026-06-25T17:19:10Z", "hours": 7.1422, "text": "Devlog A funny story: I built the invoice system but didn’t always assign values correctly, so the values got mixed up. I spent a long time debugging before realizing that was the cause. { \"error\" : { \"message\" : \"VALUE_ERROR\" , \"description\" : \" \\\" Car \\\" object has no field \\\" 123 \\\" \" } } I also spent a lot of time on CSS. Most of that time went into learning: classes IDs box shadows CSS Grid The reason it took so long since the last devlog is CSS. As I said before, I don’t really like web development, so my motivation was pretty low. I used some AI, but I worked hard to remove most of the generated code. At this point, most of the site’s design looks the way I want it to and will probably stay that way until the end of the project. Made invoices have some logic instead of always sending the same value. That means: If no invoice status is set, it sends COMPLETED or RUNNING depending on whether the engine or climate is running. Loc like actions can’t have a RUNNING invoice status. Added a distinction between successful and failed invoices. PS: Always remember to stop the server with Ctrl+C , not Ctrl+Z , because Ctrl+Z can leave the process running and keep the port blocked."}, {"post_id": 14241, "ts": "2026-06-23T07:56:55Z", "hours": 6.0522, "text": "Devlog It has been a long time since my last devlog, but I was more focused on learning than adding new stuff. Right now, I am focusing on learning HTML, htmx, and Jinja. The welcome page logic is mostly working. I had some problems with it because I used htmx to add new code, but the JavaScript from the is not reloaded with that. Now, I use the HX-Redirect response. I also learned how WebSockets work with FastAPI and htmx. I also designed how the dashboard will look (I attached my drawings. Good luck reading them!)."}, {"post_id": 11274, "ts": "2026-06-18T13:16:22Z", "hours": 3.5742, "text": "Devlog centralLock is called carLocked in the docs. The docs seem to be outdated. I think the OpenAPI specification is more accurate and contains fewer errors. I added a way to validate data using class functions. Implemented timestamps. Using datetime function from python Added tyre endpoints. Added a way to generate new API keys and create new cars (I used python secrets). (getting ready to make first public running version) Roadmap.md file with status of this project What is next to do Start using the updated method for changing data. Update the dashboard to reflect and modify the new data. Add WebSocket support. Add the remaining 2 vehicle and warning endpoints. Create an example app for testers. Redesign dashboard. It looks awful I had a 2 days off because I was on school trip but I back. Next thing on my list is an updated dashboard"}, {"post_id": 9202, "ts": "2026-06-15T13:28:28Z", "hours": 1.9225, "text": "Devlog You can edit data through the dashboard now. It’s not the best solution, and I want to change how it works (probably start from scratch), but not now. Diagnostics endpoints. I had a very good time with them today. Why? Because of the “/diagnostics” docs. I attached a screenshot showing an example from the official website and data from a real car (left: real API, right: docs). If you look at them, you can see two errors and one very small issue that you would only notice if you read the whole documentation: In serviceWarning, you can see the value is NORMAL, but NORMAL is not a valid value for it. It should be NO_WARNING. This is the small one. In engineHoursToService, the API response contains a unit, but the docs don’t mention it at all. And the worst one (and the only real error): there is no information about washerFluidLevelWarning in the docs, but it appears in the data from the car. What do you think I should do? Should I write to them about it? I think you can comment on the post, so let me know what you think."}, {"post_id": 8961, "ts": "2026-06-14T22:15:21Z", "hours": 1.7606, "text": "Devlog Added odometer and fuel endpoints. Funny thing is that Volvo sends in what unit the data is, but the docs say that only metric units are valid, so it really sends always the same unit. Most likely they wanted to add imperial later, or they left it like this for simplicity. Added first version of dashboard. For now, it’s using polling every 5 seconds (I have planned to change it to WebSocket). It only displays some information and can’t edit anything. Also, I wrote some HTML and JavaScript. I never liked web development, so I don’t know a lot (I’m learning while I code 😅). It could be that it will look very rough till the end because I don’t have any patience for HTML and CSS. I “will” do it when I have a very good day, or AI will do it? I would like not to use AI in this way, but I will see. Edit: Forgot to push the updated version to GitHub I will do it tomorrow because it’s late (it’s tomorrow )"}, {"post_id": 8322, "ts": "2026-06-13T20:45:50Z", "hours": 2.8264, "text": "Devlog Added a command accessibility endpoint (it tells if the car can receive commands). I refactored duplicate code in the climate endpoint. Added engine endpoints (they aren’t perfect, but this isn’t the final code). It was also a frustrating day because I repeatedly forgot to save my code before testing (my bad). A photo of the error that cost me way too much time today. (I changed it to “/vehicles/{VIN}/engine-status”, but I didn’t save the file.)"}, {"post_id": 7410, "ts": "2026-06-12T10:41:57Z", "hours": 0.9136, "text": "I setup my codespace and started working on first few endpoints. Additionally I looked how most of Volvos apis looks that gave me direction to go. That was all time I had today. Also I could add screenshot here because of macOS :("}]...
|
Title: Volvo API playground by @Kl | Stardance
De Title: Volvo API playground by @Kl | Stardance
Devlogs:
I setup my codespace and started working on first few endpoints. Additionally I looked how most of Volvos apis looks that gave me direction to go. That was all time I had today. Also I could add screenshot here because of macOS :(
Devlog Added a command accessibility endpoint (it tells if the car can receive commands). I refactored duplicate code in the climate endpoint. Added engine endpoints (they aren’t perfect, but this isn’t the final code). It was also a frustrating day because I repeatedly forgot to save my code before testing (my bad). A photo of the error that cost me way too much time today. (I changed it to “/vehicles/{VIN}/engine-status”, but I didn’t save the file.)
Devlog Added odometer and fuel endpoints. Funny thing is that Volvo sends in what unit the data is, but the docs say that only metric units are valid, so it really sends always the same unit. Most likely they wanted to add imperial later, or they left it like this for simplicity. Added first version of dashboard. For now, it’s using polling every 5 seconds (I have planned to change it to WebSocket). It only displays some information and can’t edit anything. Also, I wrote some HTML and JavaScript. I never liked web development, so I don’t know a lot (I’m learning while I code 😅). It could be that it will look very rough till the end because I don’t have any patience for HTML and CSS. I “will” do it when I have a very good day, or AI will do it? I would like not to use AI in this way, but I will see. Edit: Forgot to push the updated version to GitHub I will do it tomorrow because it’s late (it’s tomorrow )
Devlog You can edit data through the dashboard now. It’s not the best solution, and I want to change how it works (probably start from scratch), but not now. Diagnostics endpoints. I had a very good time with them today. Why? Because of the “/diagnostics” docs. I attached a screenshot showing an example from the official website and data from a real car (left: real API, right: docs). If you look at them, you can see two errors and one very small issue that you would only notice if you read the whole documentation: In serviceWarning, you can see the value is NORMAL, but NORMAL is not a valid value for it. It should be NO_WARNING. This is the small one. In engineHoursToService, the API response contains a unit, but the docs don’t mention it at all. And the worst one (and the only real error): there is no information about washerFluidLevelWarning in the docs, but it appears in the data from the car. What do you think I should do? Should I write to them about it? I think you can comment on the post, so let me know what you think.
Devlog centralLock is called carLocked in the docs. The docs seem to be outdated. I think the OpenAPI specification is more accurate and contains fewer errors. I added a way to validate data using class functions. Implemented timestamps. Using datetime function from python Added tyre endpoints. Added a way to generate new API keys and create new cars (I used python secrets). (getting ready to make first public running version) Roadmap.md file with status of this project What is next to do Start using the updated method for changing data. Update the dashboard to reflect and modify the new data. Add WebSocket support. Add the remaining 2 vehicle and warning endpoints. Create an example app for testers. Redesign dashboard. It looks awful I had a 2 days off because I was on school trip but I back. Next thing on my list is an updated dashboard
Devlog It has been a long time since my last devlog, but I was more focused on learning than adding new stuff. Right now, I am focusing on learning HTML, htmx, and Jinja. The welcome page logic is mostly working. I had some problems with it because I used htmx to add new code, but the JavaScript from the is not reloaded with that. Now, I use the HX-Redirect response. I also learned how WebSockets work with FastAPI and htmx. I also designed how the dashboard will look (I attached my drawings. Good luck reading them!).
Devlog A funny story: I built the invoice system but didn’t always assign values correctly, so the values got mixed up. I spent a long time debugging before realizing that was the cause. { "error" : { "message" : "VALUE_ERROR" , "description" : " \" Car \" object has no field \" 123 \" " } } I also spent a lot of time on CSS. Most of that time went into learning: classes IDs box shadows CSS Grid The reason it took so long since the last devlog is CSS. As I said before, I don’t really like web development, so my motivation was pretty low. I used some AI, but I worked hard to remove most of the generated code. At this point, most of the site’s design looks the way I want it to and will probably stay that way until the end of the project. Made invoices have some logic instead of always sending the same value. That means: If no invoice status is set, it sends COMPLETED or RUNNING depending on whether the engine or climate is running. Loc like actions can’t have a RUNNING invoice status. Added a distinction between successful and failed invoices. PS: Always remember to stop the server with Ctrl+C , not Ctrl+Z , because Ctrl+Z can leave the process running and keep the port blocked.
Devlog I added two static (for now) endpoints: statistics and warning . The statistics endpoint mostly returns data, so there isn’t much to test. The warning endpoint has a very large response that would require a lot of new code, and for now I don’t want to implement all of it. I started working on adding cars through the dashboard (you could already see part of it in the last devlog), but I found out it doesn’t work, so I need to fix it before the next devlog. Climate and engine STOP commands now respond correctly. In the last invoice update, they incorrectly returned RUNNING . Added checks for the new command endpoints to verify whether the car supports a given command. Added a small terminal page that outputs changes. In the future, you’ll be able to choose whether to display only Volvo changes, all changes, or all information (for example, if you checked whether the windows status). I also used it to verify that the normal WebSocket status works. Added the foundations for disabling WebSockets on startup. Only a configuration file is left to implement. Added UNAVAILABLE reason invoice logic mostly something like this: If the reason is NO_INTERNET , the invoice becomes CONNECTION_FAILURE . If the reason is POWER_SAVING_MODE , the invoice becomes VEHICLE_IN_SLEEP . Made some improvements to the dashboard’s appearance.
Devlog This devlog will be a short one because I’ve been focusing on implementing OAuth 2.0. I’ll cover that in more detail in the next update but I will add photo of a “login” screen that I created for it (it looks bad on purpose). What’s new The terminal now works with more than one static car. The dashboard can (once again) create new cars. The codebase has been split into multiple files instead of a single large file: main still contains the public API endpoints. internal contains the dashboard logic and internal API endpoints. database will contain multiple predefined car scenarios. I also started writing a new manual that documents the quirks of the Volvo API and my implementation ( and edge cases). I will write more about in next 2 devlogs What’s left before the first ship An example application demonstrating the differences between the official Volvo Sandbox and this project. OAuth 2.0 with PKCE (it would be great to have before the first ship). Documentation. A major code cleanup and refactoring.
Devlog Small additions to the new documentation. changes how the api handles errors BIG ADDITION OAuth2 without PKCE. I started working on PKCE, but I thought I should write a devlog before adding it. Added a login website (I know I mentioned it last time). Added a way to enable and disable OAuth2. Authentication now checks whether OAuth2 is enabled. If it is, requests are authenticated using OAuth2. Tokens don’t expire yet, but that will be added soon. Added endpoints for refreshing tokens and exchanging an authorization code for tokens. How does OAuth2 work? The app redirects the user to a login page. After logging in, the website redirects the user back to the callback URL provided by the app. The app receives an authorization code, which it exchanges for two tokens: a long-lived refresh token and a short-lived access token. When the access token expires, the app can use the refresh endpoint to obtain a new access token. What is PKCE? I’ll write more about it once it’s added to the project. In short, PKCE protects the authorization flow by ensuring that only the application that started the login process can exchange the authorization code for tokens. The application first generates a random secret (called a code verifier). Before the login request is sent, a hashed version of that secret (the code challenge) is sent to the server. Later, when exchanging the authorization code for tokens, the application sends the original secret. The server verifies that it matches the previously received hash before issuing any tokens. I’ll explain the complete flow in the next devlog.
Devlog A small error from the last devlog: it’s PKCE , not PCKE . I had to rename a lot of variables because of that. More customizable data Gearbox Model year More diagnostic data for lights (hazard, fog, brake, high beam, low beam, and more) Other additions Added a new default API key with 3 cars, each having different values. Wrote more docs. Started working on scenarios (templates for new or existing cars to make setup faster). I’m thinking about loading them from a file so users can create their own. Started working on setting up OAuth2 through the dashboard. Fixed most command responses because when I first created them, I forgot to wrap everything inside { "data": {} } . Added light options to the dashboard. Working: PKCE How does it work? The application generates a random secret. Before redirecting the user to the login page, it sends only a hashed version of that secret. After the user logs in, the application receives an authorization code. When exchanging the code for tokens, it sends the original secret. The server checks whether it matches the previously received hash. If it does, the tokens are issued. It normally protects from having the tokens stolen New promoting picture I made in canva have a look
Devlog How I don’t like web development… did I already say that? I’ll say it again. I’m working on the OAuth2 settings, and I had a problem where one of the query parameters wasn’t reaching the backend. I still don’t know what actually fixed it. Then I had another problem. I have a function that changes values in the backend, but only one button worked while everything else didn’t. It turned out to be because I debugged the first problem with AI. Always trust your own mind before trusting AI. The problem was hx-trigger . I also had problems applying CSS through HTMX. In the end, I solved it by using hx-redirect . But in the end everything works (you can see it one the phtoto) I also worked on the scenario system, which loads scenarios from a JSON file. It isn’t tested yet, and I still need to work on state snapshots. The idea is that you’ll be able to save a moment in time and restore it later, so you can test the same scenario as many times as you want without setting up all the data again. I also started working on a companion app to showcase the differences between my implementation and the official demo car sandbox. I’ll write more about it in the next devlog.
Devlog Writing documentation is a good way to check whether the code you wrote actually works. I already found four bugs while documenting the project. For example, I forgot to pass the redirect URI in a function in main.py , even though it was already implemented in internal.py . I also fixed a bug where notifications could sometimes contain an older value. The dashboard has been moved into a separate file. Snapshots currently have a problem. They are very similar to the Car class, so I’ll debug it and explain what the issue was in the next devlog. Companion app The companion app is meant to showcase the differences between my implementation and the official Volvo Demo Car Sandbox. It also makes testing easier, since you don’t have to write your own application just to try the API. I had a problem with the built-in LibreSSL because one of the dependencies didn’t support it. I had to reinstall Python so that uv would detect the new OpenSSL installation. After that, I was finally able to start the app and get it working. Auto-login and automatic creation of a test car are now working. There’s is no css but I will do it after logic works One more thing: the reason the devlogs have been quieter recently is that I’ve been dealing with some administrative paperwork. I’ll get back to posting them more regularly once that’s sorted out.
Devlog Authorization was my mistake. It should have been accessToken , not Authorization . Why I thought that? I have no idea. No it was good before I was sleepy I think when I did that The snapshots system now works. Why it didn’t work as expected: I forgot to use copy(deep=True) . One of the small dictionaries was written incorrectly. Added saving and loading snapshots from a file. The scenarios system now works and has been tested. Difference between snapshots and scenarios Snapshots copy all data about a car. They are persistent and can be saved to a file. Scenarios only change selected attributes. They are designed to be created and edited manually in a JSON file. Main app The main app is mostly ready. Before the first release, I still need to: Finish the documentation. Add a roadmap with future updates. Verify error responses against the real API. Finish the comparison feature in the companion app. Add more ready-to-use scenarios and API keys. Companion app Manual login now works, so only the comparison logic is left. I found a bug where api_key_p was None because one endpoint redirected using api_key instead. Started working on the comparison feature. PS: A photo of why the api_key_p was none
A public online demo!!!!! The project is finally available online! https://playground.kls.hackclub.app/internal/welcome Please don’t be the bad guy and fight with other people over access. ❤️ That’s all I wanted to say because this is a really big milestone for me. There will also be another commit today to make sure everyone can run their own instance of the project. I found a few issues that only appeared outside of my local environment: Some WebSocket features break when using HTTPS. The dashboard had problems when the instance wasn’t running on the same computer. Those should be fixed in today’s commit. If you find any errors please comment or contact me on slack Also thanks to nest hackclub for hosting
Devlog Companion app Added manual mode for comparison. Engine start/stop now works in normal mode. Before pushing, I forgot to fix one thing: { "error" : "Failed to retrieve data from unofficial API." , "detail" :{ "detail" :[{ "type" : "dict_type" , "loc" :[ "body" ], "msg" : "Input should be a valid dictionary" , "input" : "{ \" runtimeMinutes \" : 10}" }]}} The fix was simple: I forgot to use json.loads() . I pushed a quick fix commit right after. The photo shows the manual comparison page. I’m still working on the comparison logic, which is why it doesn’t have any CSS yet. Sorry for not adding Volvo API keys so you can see the differences between both APIs, but that would have taken too much time today. Its also the reason why Im creating this app Main app Worked on the documentation. The notifier now supports more than one updated attribute at the same time. It’s not the best implementation, but I’ll improve it after the first ship. Fixed snapshot loading and added exception handling. Scenario loading now reports malformed JSON files. Fixed a dashboard bug where tire information was shown three times. I think I planned to add more data there… and then forgot. I should probably test everything before making a devlog or committing, but I also don’t want my devlogs to have to much time.
Devlog I’m mainly focused on finishing the companion app. I started working on the CSS. Most of my time was spent learning Tailwind CSS (so I didn’t track it). I think it’s a better fit for me than writing plain CSS. Added Tailwind CSS to all pages of the companion app. (I think I need to redo the main app now. 😅) Added a small README with information about the main app. I think it done now but I will come back to it before first ship Main app While working on the companion app, I found another issue. The Content-Type: application/json behavior doesn’t match the official API. I verified that the official API works as expected, checks for it mine doesn’t (I think)
Devlog Companion app I said it was finished for now, but I forgot to add one more thing (the one on the left in the screenshots): a dashboard redirect. Main app I’m still investigating the Content-Type problem. I verified that the official Volvo API behaves correctly, so I’m working on matching that behavior. Added work-in-progress Content-Type checks. Started reworking the CSS using Tailwind CSS. It’s still mixed with some plain CSS for now. Enabled support for the reduced guard lock command. You have to manually mark it as supported, and for now it behaves the same as the normal lock command. Let me know which design you like more: the new one (center) or the old one (right).
Devlog I don’t know if I mentioned it before, but for now the Content-Type checks are disabled. I need to learn more about them and implement better validation. Created an updated OAuth2 settings page and a car selection screen (with Tailwind CSS, of course). Started experimenting with a new dashboard. It’s still a work in progress, but it will most likely become the main design. I’m also thinking about adding a second dashboard style, although I’m not sure if I’ll do that before the first release. I definitely want to clean up the HTML/Tailwind code by moving repeated styles into reusable classes or something similar. I’m also thinking about using more HTMX so that more pages can update data without needing a full page reload. Wrote more documentation. I still need to verify the fuel endpoint because I don’t remember whether it handles different engine types correctly. ( The new OAuth2 settings page and the car selection screen. For next develop I think I will make a video of how everything works)
Devlog Most of my time was spent working on the dashboard with Tailwind CSS. It took a lot of experimenting to find a design I actually like. I also changed how HTMX updates the dashboard through WebSockets. Before: A dedicated template was rendered every time to update that part of the dashboard. Now: Only the text containing the updated value is replaced. That said, in the future it won’t always be just text. For example, if the fuel type changes from hybrid to electric , the fuel level should disappear from the dashboard instead of just changing its value. While working on this, I found a bug caused by HTMX sending boolean values as strings. This caused climate settings to be marked as invalid. I need to distinguish between an invalid value and an invalid attribute instead of always treating the entire attribute as invalid. Note to myself Add transitions. Make all HTML pages use the same CSS file from now on. Update the version on nest server and make a public companion instance Aaand that’s all. Making websites is painfully slow.
Devlog I found another way to hide the fuel stat when it isn’t useful for a particular type of car: the HTML hidden attribute. At first, I thought I should add or remove the element hidden, but that turned out to be more complicated than I expected. I think using hidden is still a cleaner solution but I still using templates files. While working on the dashboard, I wanted to add units like km , L , and % to some values. Instead of handling that in Python, I added another div with some margins and, in a few places, used flex so everything stays on the same line without adding more backend logic. Added more page changes thru HTMX (nearly all pages use it). Creating a new car now refreshes the page. when an error occurs, I use HX-Reswap and the HX-Retarget response header (when creating new car as proof of concept). Added HTMX transitions to the OAuth2 settings page.(all pages have transitions) What to do before the first release (Mostly a checklist for myself 😅) Content-Type checks. Scenario and snapshot system support in the dashboard. Main showcase page. Finish the remaining documentation. Two READMEs: one for the main repository and one for the companion app repository. I’m thinking about having one technical README and another one that’s easier to understand for people who don’t code. Better error handling in the dashboard. Right now, most errors are just displayed as plain text instead of being part of the page. deploy updated version on nest I wanted to add a video but MacOS made me a half gig and I don’t think stardance would handle
The comparison app is now online! Comparison app: https://compareplay.kls.hackclub.app/ I also updated the main app with the new dashboard design: https://playground.kls.hackclub.app/internal/welcome devlog Tailwind CSS is no longer loaded from the CDN. I think its now precompiled. Note to others: Remember to update your banner to feature your app (see #stardance on Slack). Otherwise, your ship will be rejected. EDIT: A lot of bots try to connect to my apps do you think I should make a honeypot?
Devlog The Content-Type problem is SOLVED …… What was the problem? (My reading skills? ) there are two headers with application/json : Content-Type (POST) Accept (GET) The Accept header isn’t required ( can be */* , application/* or application/json ). So the Content-Type mystery is mostly FIXED but I still need to check with a real Volvo car if Content-Type is actually required. (I’ll do it tomorrow.) Changes: Accept is now handled by my API like in the official API. Added Content-Type checks (like the docs say, meaning it’s required). While proofreading the docs, I found that PKCE is written as PCKE in one internal endpoint. (Not fixed yet.) Small README update (I try to keep it up to date). Scenario page: You can now load a scenario using the GUI. Recompiled the Tailwind CSS. I attached screenshots showing it (you can also see snapshot button but its not implemented YET)
Devlog Snapshots loading page (screenshots while I worked. I had more but the limit was 4). As suggested by the Tailwind CSS tools, changed some classes to more canonical ones. You can now delete cars through both the API and the dashboard. Snapshot corruption (when the app is force quit) should be fixed. Started working on the landing page, but I’ll leave it for the next devlog (mostly because I have on my other laptop). Fixes to do Sometimes the new OAuth2 and Snapshots buttons are off-center. Compare app needs fixing (need to enable the Content-Type fix from the official API). PKCE spelling in the internal API.
Devlog I had a problem when I wanted to rewrite the scenario system. It only changed the local version of the Car (It means it really didn’t update anything). I wanted to update a backup version first, and only if everything was correct, replace the original with the backup. In the end, I used an already created function to first test and then apply to the car . Main PKCE misspelling fixed. Added a landing page with an option to disable it and redirect directly to the login screen (like in the last devlog I have photos of making it). Worked on the lights section. Fixed the docs URLs. Dashboard and WebSocket toggles now work. Rewrote and enabled the updates endpoint. Validation now catches values that can’t be converted to int . Scenario loading into a car instance should now be more consistent with the other functions. Improved mobile responsiveness (and then fixed the desktop one). Some elements were outside the screen on mobile (nothing important, but it didn’t look good). NOTE: the dashboard with car attributes still needs to be adapted. Added windows (because I forgot to 😅) to the dashboard and organised the lighting section. OAuth2 and Snapshots buttons should now always be centred. TODO Debug and tracing headers (from the real API). Additional instructions. Then I think it’s finally ready for the first ship. There are still a lot of things I want to add, but I can’t work indefinitely. Compare The compare app now has the Content-Type fix enabled (like the official API). Compiled the Tailwind CSS for the compare app. NOTE: I will add here more screenshots as link later Also thinking about adding it frictionless mission but I’m not sure.
Devlog Tracking headers implemented : There are two vcc-api-operationId - UUID traceparent - W3C traceparent (for now only sends it back) dashboard should look good on small screen (its very long but I don’t want to redesign it now) This is the reason why I there is much time in this devlog. It was a lot of try and error before something looked good both on mobile and desktop and I liked it . But at least it works know 🙃. some small cleanup of comments I worked again on internal updates endpoint (hopefully works now) started working on pytests (but I will talk about in next devlog (I gave my self 2 days for it) I really want to get the first ship out, so it isn’t going to be perfect. I still have a lot of features and improvements I’d like to add.
Devlog Working hard on pytest tests. I learn how assert works and how to name . I never used or created test in any language so I think they aren’t perfect (not like they should),but they work😄. I looked like AI made few and how other people and read some stuff online Tests created for these endpoints Around 25 of them List cars About car Engine info Engine start/stop Climate start/stop Windows Doors Lock/Unlock Reduced Guard Lock Flash, Honk, and Combination Tyres Statistics Fuel Odometer Engine diagnostics Brakes Command accessibility Still to do Warnings and diagnostics Commands More changes The tests helped me find and clean up several issues: Documentation updates. The honk endpoint was ../horn but should be /honk . Some values ( odometer , fuel ) are int , just like in the OpenAPI specification, not as described in the official docs. Fixed spelling mistakes: - oillevel to oilLevel - coolantLever to coolantLevel Want to help and has access to volvo with active VOC I need to test engine and climate endpoints but I don’t have an access to a car with it. Soooo if you can contact me on slack
Devlog I forgot to add that I worked on the tests in the test branch, not the main one. OAuth2 PKCE testing. Helped me find an error where, if the code was used (it was reset to "" ), it was accepted as "" . Now it correctly returns an error. OAuth2 flow testing. Warnings and diagnostics now have some simple checks too. And I merged it into main . Then I started cleaning up the Tailwind CSS. NOTE: they are in new branch dashboard/cleanup Why? Because I used the Play CDN in the past, so I couldn’t create utility classes in a CSS file. Soooo I didn’t. Andddd there were a lot of Tailwind classes that didn’t fit on my screen. Now that I started precompiling it, I could add them. I added 5 unique utility classes. All of them combined are used around ~120 times across all HTMLs. The longest one: @utility inputSelection { @apply w-full px-4 py-2 .5 bg-zinc-950 border border-zinc-800 rounded-xl text-zinc-100 focus : outline-none focus : ring-2 focus : ring-blue-300 focus : border-transparent transition-all appearance-none text-center [ text-align-last : center ] cursor-pointer ; } I also minified the CSS file. If I understand it, it removes anything the browser doesn’t need to understand the CSS (new lines, unnecessary spaces…). It’s better because those characters are still sent over the network, and fewer bytes mean less traffic. While using the new utility classes, I tried to preserve the layout, so everything should look the same as before.
Devlog SITE changes I found that some number inputs didn’t use the utility classes. I gave them inputText because they are really the same; the only difference is the HTML type . I also forgot to update the reloadable fuel section. It now uses the shorter utility class. Made sure that all text in the header is the same size (they weren’t). I copied all changes back to the main branch. config changes Then I added a config file using the configparser library. also added an option to disable the FastAPI docs. I started working on Wiki: reworking docs.md into a GitHub Wiki with up to date information. Error logger, so you can see what’s wrong without printing the API response in your code. I had some problems with catching the fastapi automatic response but I will leave it for next devlog
Devlog There was a small (or big) problem in my playground. If an error was returned in the response, you could only see it if your app handled it or by printing the response. That’s why I added an error logger. It can show errors in two ways: Terminal Log file How it works There were two ways of doing it (from what I learned): Middleware that captures all responses (this could be helpful in the future). Exception handlers (this is what I chose). I use two handlers: @app.exception_handler(RequestValidationError) @app.exception_handler(HTTPException) It was a horrible time searching for why it didn’t work. At first, I worked in a separate file, but I couldn’t get the (fastapi) app variable into those functions. So I copied them into main file to make them work first. I had to change some JSON responses to HTTPException to make the second handler work. After I captured the first request and printed it, I worked on one function that writes a log and another that prints to the terminal. I also created a class to store useful data. It works like this: Exception handler-> ->Put data into class -> ->Create response -> ->Return response ->Create a background task that logs the error I create a background task so the response doesn’t wait or even worse fails In the end I found that I can wrap these func with this simple func to make them work in different file def setup_error_logging(app: FastAPI): Added a config option: To disable it completely. To disable only the log file. It also bypasses all internal endpoints to make the logs more readable. The best fail… 😅 I returned an exception instead of raising it. I spent a good 15 minutes wondering why the response had status code 200 with a JSON body saying status code 400 . response changes I also checked how the authorization errors look and added two new ones: Missing Authorization header. Invalid vcc-api-key header. WIKI (not counted) I focus on making a GitHub wiki (new docs) After ending them and the error logger. Its time for the first ship !!!!!!! Nest instability: I made a backup server : https://frog01-21185.wykr.es/ Its not ideal one, bc some asian countries are blocked but its shouldn’t have any downtime (I hope so) If an Admin read it why I must copy enter from different text input 😭
Devlog Error logger added colors to the terminal print out using: \033[31m \033[0m Good to know that it is so easy to add colors to text added timestamps to log file and - between errors Changes how it reads body once again and fixed url encoded requests logging My additional information I put in detail in the json response (the real API can send it like that buttty I didn’t see it. info from docs ) additional changes: New scenarios mostly about service warnings You can add notes to the website thru config files Scopes I started working on scopes. What are they? They are really permissions (you can know them from discord bots or if you login thru GitHub etc.) I don’t want to put them in this first ship but I needed to work on something (while I work on wiki) and I CAN’T guarantee every thing works after adding them. You can see it in the scopes branch. what is done: I have made preparation so the additional database (dict) I use for OAuth can store more data have updated website func to work with changes and also pytest added all possible conve (connectivity API) scopes WIKI when I add everything to them I will finally try making a ship added the error logger page updated the sidebar scenario and snapshots page a lot of misc Bonus photos from vacation on baltic sea
Long time no see… The school started aaand I didn’t have time I had low motivation The only thing to do before first ship is docs but I could find time to finish them. Buut I back now. AND I promise to ship it before 7 of September. If you are voting on this project PLEASE do not skip. I have my birthday coming and if the shipwrights doesn’t have a long list it could mean this project payout could be my birthday gift. If I ofc ship it 😅 devlog Small marketing changes everywhere to say that this project doesn’t have any ready code to use Added info about error logger on the landing page Scopes A long way from last devlog Fixed pytest ( A second time) TEMPORARY FIX added so the scope error doesn’t - throw just internal error FIXed the Oauth2 endpoint at least 3 times Added a WIP endpoint to edit scope data from API Fixed how cars are created so they work with both - Oauth and scopes stuff Only looking dashboard page for scopes compare I think I forgot to say something in last devlog config file if you would like to use different instance Toml oillevel to oilLever AI disclaimer that I used this project to learn tailwind Make the doors have different statuses in mean time Untracked WIKI Redo the home page Started working on stardance path A lot of misc that I don’t remember other I created a small modified volvo example app to show that my app works like the real one
Devlog MAIN added a startup baner fixed snapshots not saving if website was used scope If you didn’t follow from start this branch contains the experimental scope support which is mostly done but I can guarantee stability that’s why it isn’t pushed to main in fist ship made the scope page work added a back button added button to scope on main page fixed snapshots loading/saving
Read till the end PLEASE 🥺 Devlog A lot of changes from the last devlog only 5 hrs Mostly bc I add stuff on top of but I will suffer in the future (See dev branch for these changes) Change all connectivity API to start with /connected-vehicle/v2/ to make room for different APIs After that I fixed pytest to reflect that I added a location API with a ONE endpoint There were few iterations Added scopes for this API location:read If I remember correctly Unique error responses (because location error look like old (v1) connectivity API Fixed that operationID could be a constant Added a config option to use longer API keys About here I Fixed the url for location api because it used the connectivity scheme Started working on energy API I added all data from it to this project In short one endpoints says what this car is capable of And the other says the values TODO: add its unique error its half done Scopes corresponding to energy API Fixed that some values and capabilities had the same name (bc of that some bool values where number so a it was important) WIP Oauth2 update: JWT tokens for access tokens WIP token can expire! what are JWT token? There consist of three parts header payload and signature The two first is important for my project the 3 isn’t . They store info about issuer, when token is active, scopes… A lot of useless data for this project or useful? We will see Life Bc of school I didn’t have a lot of time to write devlog (and write code) but I try to do my best before the end of stardance The next ship is planned for 28 September BIRTHDAY TODAY (16 September) Im celebrating my birthday 😄 If you write me a few good words It would be motivating for me.
Devlog A lot of breaking changes later and getting closer to PR and going to 2 ship Token lifetime WORKS made time when token is expired is rounded to int endpoint for invalidating token possibility for enabling expiring token for a specific token when it’s disabled for all in config file misc pytest for location and energy API fix the url for the enrgy API (it started with connectivity url not wi the energy api) cleanup import created new files to make the code more readable dashboard added location values added capabilities and values auto token generation and expiration in dashboard
Devlog A very long time no see. I have made a lot of progress on adding an SQL database. Testing on MySQL The backup server provider gives me access to one. SQL changes A lot of BIG changes. The reason why I haven’t posted for so long is that I didn’t want to post about something that doesn’t work. Created new classes to intercept data changes, both in case of direct dict changes and when going through the SQL model library. (I didn’t change much in the code, just imported it under the same name as the old database.) And it works! At the start, only reading data worked, but now it can send data back to the database. Added a regen function to make sure built-in API keys are always the same after a restart. Fixed the car creation function (but when I started storing the additional data in SQL, it broke AGAIN). Added configuration attributes. At first, just the database type, but then all the information needed to connect to a MySQL database. Fixed the scenario readconfig (wasn’t it updated in the past?). A really small number of things I added? Yes, but the amount of debugging and changing built-in functions in classes took me so long. (Could be because of school and not having time to do everything in one sitting.) But I learned how to make a dummy dict with a class, as I called it in the commit: proxy . Problems The SQL database can’t create new cars. Need to check all internal endpoints to make sure they work. Still haven’t merged the DEV branch (TODO). All information is stored in one column as JSON. It works, buuuut I don’t like it that way. Need to clean up the proxy classes. updating docs What failed this time? The second photo attached shows it. Have a look before reading more. _contains__ If you see it, congrats! But if you have a screen full of code, it’s harder to spot. It should be __contains__ , and I spent, I think, two days debugging why all in statements just didn’t work. I was so happy when I finally found it! XAMPP and Apple Silicon The manager app doesn’t open after a restart, so after consulting Google and AI, I found a command that I use: sudo /Applications/XAMPP/xamppfiles/xampp start xampp If someone is asking why I didn’t use the server provided one it just wasn’t practical for now.
Ships:
A Milestone Welcome everybody to the first ship of this project. What is this project? This project simulates how the Volvo API works. Why was this project created in the first place? So it’s easier to create and test your app that uses the Volvo API without using ready-made libraries. I can’t find the features you mentioned in the devlog? Check the scope branch or the upcoming dev branch. What I’m proud of: I learned a lot of things (this is my first big public project): Tailwind Python stuff (I started with C++) Writing documentation (Markdown) I also learned the basics of OAuth2 and how APIs work. Making a project with all the features needed to get started. I created an additional document for you, Stardancers: Stardance PATH What is still on the TODO list? More APIs Scopes docker image See the roadmap . What to see? error logger recreated endpoints dashboard web socket realtime changes internal endpints interactivity of the car...
|
1793004616.137251
|
1793091016.137251
|
|
25672
|
NeoOS by @WilGulf | Stardance
|
WilGulf
|
1
|
130.63
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-07T16:36:40Z", "hours": 118.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "So I made my own os “NeoOS”, this project was started not long after the release of the macbook neo and cause of that the os got it’s name. Testing is pretty easy, just make sure you have qemu installed with the correct cpu architecture. The project has become much bigger than I thought when I started it, I just could not stop implementing more features. And the most challenging part must be the hardware interaction, like reading from a disk by sending commands in hex. The documentation found for how cpus/ata disks/ram and all works are so hard to understand but that may be because it is not a simple thing. So when testing I want you to know that even though there aren’t many commands the kernel is still doing so much work not seen and the kernel is also what took most hours on this project. Lastly I hope that someone with all documentation provided writes their own program for NeoOS, I would love to see what other people could do with my OS.", "repo": "https://github.com/WilGulf/NeoOS", "demo": "https://github.com/WilGulf/NeoOS/releases/tag/1.1.0"}]...
|
[{"post_id": 74057, "ts": "202 [{"post_id": 74057, "ts": "2026-09-26T16:34:52Z", "hours": 9.7725, "text": "Devblog 22 The review of NeoOS found some problems with the filesystem commands and I took some time to fix them. Now the commands know where they are run and you can move around with cd. The second thing for this devblog is that I got multi disk support so now you can have up to 4 harddrives attached with writing/reading working on all of them , and that took some interractions with the ata ports but I finally got it working. –WilGulf"}, {"post_id": 69740, "ts": "2026-09-17T18:05:34Z", "hours": 2.8608, "text": "Devblog 21 The review is taking ages, and I couldn’t leave NeoOS. So I of course continued with fixes and features. The big new thing in this devblog is the filesystem: NeoFS, I have done major changes to the design like how a free block is found which greatly improves performance. And many safeguards were added to reading/writing to the filesystem. I also updated the host fstools used to create the filesystem on a drive to support arguments with options, easier to use now. – WilGulf"}, {"post_id": 63661, "ts": "2026-09-07T16:18:42Z", "hours": 1.5858, "text": "Devblog 20 Final touches and logging the remaining time before shipping. I hope I have fixed all small bugs and made the libraries easy to use in new C programs. I also created some small new programs to show all functions in the kernel. Thats all for now and I hope to get to ship soon. –WilGulf"}, {"post_id": 63163, "ts": "2026-09-06T20:16:36Z", "hours": 1.6142, "text": "Devblog 19 Not as big of a update now, but I just wanted to show of my new readdir implementation. That is then used by list with some coloring, all are green cause there is only executables in /execs. – WilGulf"}, {"post_id": 63079, "ts": "2026-09-06T17:50:19Z", "hours": 9.9825, "text": "Devblog 18 So close to going over 10h however I managed to fix the bug. So a missing feature has been writing to the disk and not only read it. But the current file system was fat16 and the attempts I have made to implement writing has failed. What is the logical thing to do in this scenario, well I wrote my own filesystem: NeoFS. It is not feature rich compared to fat16 but that was why I could make it write. And the performance may be horibble when having larger files. But if it works I will keep it! So the test just shows writing/reading of a file. – WilGulf"}, {"post_id": 60414, "ts": "2026-09-02T18:32:35Z", "hours": 3.4125, "text": "Devblog 17 I have developed my own ramfs. The old filesystem only supported fat16 with only reading capabilities which maded it feel very limited with what you could do with it. So the first step I dicided to do with adding reading was to implement filesystem that lives in ram which is really easy to write to. Now the D: drive is used for the ramfs (D as in dev used by linux). In the screenshot test.elf creates a file: D:/test.txt and writes HELLO FROM RAMFS to it. Then read.elf (linux cat) can read that file. – WilGulf"}, {"post_id": 58085, "ts": "2026-08-30T13:12:46Z", "hours": 7.1003, "text": "Devblog 16 I wanted more programs for NeoOS but I felt really limited to just the print and getkey functions. So I rewrite ncurses (not with all ncurses functions) into my own curses for NeoOS. This allowed me to write programs that update the terminal like a screen. Here I shouw the NeoOS logo being displayed with a CRT-screen effect. Now I am In the decision of what game to make with this new library. – WilGulf"}, {"post_id": 56739, "ts": "2026-08-28T16:47:26Z", "hours": 4.86, "text": "Devblog 15 I have now added colored printing that I showcase here in the fetch program. The printing made me redo how the writer works to support the decoding of the default ascii sequence used to change color: \\033[xxm , where xx is the color. It follows the standard C way which makes it pretty easy to use colored printing. – WilGulf"}, {"post_id": 53943, "ts": "2026-08-24T17:27:07Z", "hours": 13.1097, "text": "Devblog 14 I have worked on multiple commands for the shell but the one that i want to showcase now is the process management. Running.elf lists all running processes (including itself) with their name, pid and privilege level. Then I execute kill.elf with “1” as a argument which is the id of the shell. That kills the shell which leaves the os with just the blinking underscore cause there is no longer a shell running. Other commands are the sysinfo (uname) and updating fetch.elf with some new info."}, {"post_id": 49143, "ts": "2026-08-17T19:33:20Z", "hours": 9.0397, "text": "Devblog 13 Not much to show on the screen, however in the background i have worked on a security feature. So it is kind of like the pledge feature in open-bsd: so the kernel first need to know from the program what it wants to do, like print to the screen. Not until it has told what it will do it won’t be able to do anything. And if the program ever does anything it hasn’t told it would do the kernel will just kill the process. The program promise to not use any other functions except the one it has specified. And the kernel won’t let it break it’s promise. That is why the c function is called promise. –WilGulf"}, {"post_id": 48037, "ts": "2026-08-16T10:16:51Z", "hours": 9.1672, "text": "Devblog 12 A shell This is the first shell for NeoOS, it only has the clear command and a fetch program to display the logo. It took some time implementing all syscalls it needed, i needed to make many kernel functions available in the userprogram and that took most my time. I have yet to implement a way to terminate the program so now when fetch is called it never ends and you never get back to the shell again. – WilGulf"}, {"post_id": 46769, "ts": "2026-08-14T08:19:44Z", "hours": 4.0228, "text": "Devblog 11 NeoOS has now got ps2 keyboard drivers! So now I have implemented a driver for the US layout on ps2 keyboards. I am also looking into changing it to support my keyboards (Swedish layout), but that would take some time to map the right keys to the right number when the US layout can be found right on the os dev wiki. So this keyboard writing is also done the real way, the kernel boots, the kernel starts a program, that program asks for keyboard input, when it gets a input it asks the kernel to print that input. Now you can see how this could later change into a shell: you write the name of a command and it runs it. –WilGulf"}, {"post_id": 44096, "ts": "2026-08-09T17:04:23Z", "hours": 7.8719, "text": "Devblog 10 Now a binary file is able to be loaded AND executed. So from that qemu picture you can see the “Hello from a binary program” message, that message is printed by that print.s code. This is a huge milestone. There are still some functions to implement. But after that it is just writing all the userland programs. I must say none of this was easy, and choosing to develop a OS for stardance has so far been a really big challange. And now I need to push through coding the last bit so i can get this shipped before the end of stardance. –WilGulf"}, {"post_id": 43351, "ts": "2026-08-08T15:42:07Z", "hours": 7.6778, "text": "Devblog 9 I found a course for os development to follow and it really helped me with this. With the course explaining, I got my kernel to read a fat16 disk and print the content of hello.txt. This was a lot of debugging, first the file did open but couldn’t be read, then later the file was read but the data was just wierd characters. Now this is a huge step, the reading is done and now I only need it to be able to understand executables and read them. – WilGulf"}, {"post_id": 42494, "ts": "2026-08-07T08:16:16Z", "hours": 3.1131, "text": "Devblog 8 The real malloc and free is implemented. And if you know C you may understand what is going on in the image. All ptr are allocated using malloc and the first one is free’d before allocating ptr4, that is why their values are the same: ptr4 reuses ptr1 because ptr1 is free’d. Now that I don’t only have the allocation but also freeing which means I can safely implement a filesystem driver without worrying about the memory overflowing. – WilGulf"}, {"post_id": 42122, "ts": "2026-08-06T18:15:14Z", "hours": 4.8756, "text": "Devblog 7 I got to usermode, there I could run all the programs like a shell. But when jumping to usermode you need somewhere to land, some address where the cpu can start executing code. I don’t have that. So the next thing would be to implement a filesystem driver to read a disk and execute an executable. But my memory management is to simple to do it in a good way, I can only allocate and never delocate. So now I am going to revamp my memory management. –WilGulf"}, {"post_id": 26450, "ts": "2026-07-11T08:03:23Z", "hours": 11.1347, "text": "10h I don’t have anything to show right now, but as you can see i have 11 more hours on this project. I have both been working on fixes and some new things needed for the next big thing being: getting to ring 3/usermode. –WilGulf"}, {"post_id": 24029, "ts": "2026-07-07T09:45:52Z", "hours": 4.8494, "text": "Now we got progress! The kernel now has my implementation of paging working. If you don’t know what paging is, it is basically a way of managing the memory that is used by most x86 operating systems. The paging implementation took some C files and some updates to the assembly files but now it is done! Now I have many ways to go with what to implement next. We’ll see what i choose. –WilGulf"}, {"post_id": 19092, "ts": "2026-06-30T09:33:07Z", "hours": 7.1717, "text": "IDT Done! Now I got the IDT working. You can see it is working cause when that “Divide By Zero” message appears the kernel does a division with a zero. Normally that would make the kernel start bootlooping but now the interrupt handler handles the divide by zero and stops the kernel instead. Interrupt handling does not only stop crashes but also allow keyboards or syscalls to invoke interrupts that the kernel can process. Next step may be to use that interrupt handler to implement syscalls. – WilGulf"}, {"post_id": 18225, "ts": "2026-06-29T09:29:17Z", "hours": 2.5817, "text": "Hello Yes we got it, hello world on the screen. Turns out the loading of the kernel set up the stack wrong. One line of assembly was in the wrong section. I also continued with the GDT. It isnt something you can see but in the background the GDT has been initialized. That is my progress so far, now after GDT comes some interrupt handling. –WilGulf"}, {"post_id": 17849, "ts": "2026-06-28T19:51:48Z", "hours": 3.3697, "text": "HELP What is wrong? Well as I said, I would continue with getting Hello World on the screen. Well that wasn’t hard to do the “simple” way, just pasting several lines for each letter. But I wanted to do it the real way, implement a writer function. I started with making a function to clear the framebuffer from that “Booting…” message. And also moving the cursor to the start. Then I continued with the writer. The writer took two parameters: (char *buf, unsigned int len). Both arguments needed. The function i began testing with calling it from kmain like this: writer(“hello”, 5) . Then in the function i processed it like this: unsigned char *bytes = (unsigned char *)buf; for (unsigned int i = 0; i < len; i++) { fb_write_cell(pos * 2, bytes[i], 0x0F, 0x00); pos++; } But thats where it went wrong. When compiling and booting after adding that function content it wouldn’t boot. And that is wierd cause when i removed the bytes[i] line it booted. Somehow my kernel cant handle it. I don’t know what could currently be causing this. What now? Well i will of course try to solve this myself or find a way to make the writer work. And if you have any knowledge in C and os development please help me. The projects current code can be found on my github. – WilGulf"}, {"post_id": 15860, "ts": "2026-06-25T19:46:32Z", "hours": 1.8089, "text": "I got my OS booting without entering a bootloop!!! I wanted to leave assembly and start to use C. But to do that I need to call the main function in C from assembly. Much googling and testing later I got it to actually use the main functions while loop to keep itself from bootlooping. Never thought i would be so happy about completing the first and easiest task in os development. I will comeback with another post when i get ‘hello world’ on the screen."}]...
|
Title: NeoOS by @WilGulf | Stardance
Devlogs:
I g Title: NeoOS by @WilGulf | Stardance
Devlogs:
I got my OS booting without entering a bootloop!!! I wanted to leave assembly and start to use C. But to do that I need to call the main function in C from assembly. Much googling and testing later I got it to actually use the main functions while loop to keep itself from bootlooping. Never thought i would be so happy about completing the first and easiest task in os development. I will comeback with another post when i get ‘hello world’ on the screen.
HELP What is wrong? Well as I said, I would continue with getting Hello World on the screen. Well that wasn’t hard to do the “simple” way, just pasting several lines for each letter. But I wanted to do it the real way, implement a writer function. I started with making a function to clear the framebuffer from that “Booting…” message. And also moving the cursor to the start. Then I continued with the writer. The writer took two parameters: (char *buf, unsigned int len). Both arguments needed. The function i began testing with calling it from kmain like this: writer(“hello”, 5) . Then in the function i processed it like this: unsigned char *bytes = (unsigned char *)buf; for (unsigned int i = 0; i < len; i++) { fb_write_cell(pos * 2, bytes[i], 0x0F, 0x00); pos++; } But thats where it went wrong. When compiling and booting after adding that function content it wouldn’t boot. And that is wierd cause when i removed the bytes[i] line it booted. Somehow my kernel cant handle it. I don’t know what could currently be causing this. What now? Well i will of course try to solve this myself or find a way to make the writer work. And if you have any knowledge in C and os development please help me. The projects current code can be found on my github. – WilGulf
Hello Yes we got it, hello world on the screen. Turns out the loading of the kernel set up the stack wrong. One line of assembly was in the wrong section. I also continued with the GDT. It isnt something you can see but in the background the GDT has been initialized. That is my progress so far, now after GDT comes some interrupt handling. –WilGulf
IDT Done! Now I got the IDT working. You can see it is working cause when that “Divide By Zero” message appears the kernel does a division with a zero. Normally that would make the kernel start bootlooping but now the interrupt handler handles the divide by zero and stops the kernel instead. Interrupt handling does not only stop crashes but also allow keyboards or syscalls to invoke interrupts that the kernel can process. Next step may be to use that interrupt handler to implement syscalls. – WilGulf
Now we got progress! The kernel now has my implementation of paging working. If you don’t know what paging is, it is basically a way of managing the memory that is used by most x86 operating systems. The paging implementation took some C files and some updates to the assembly files but now it is done! Now I have many ways to go with what to implement next. We’ll see what i choose. –WilGulf
10h I don’t have anything to show right now, but as you can see i have 11 more hours on this project. I have both been working on fixes and some new things needed for the next big thing being: getting to ring 3/usermode. –WilGulf
Devblog 7 I got to usermode, there I could run all the programs like a shell. But when jumping to usermode you need somewhere to land, some address where the cpu can start executing code. I don’t have that. So the next thing would be to implement a filesystem driver to read a disk and execute an executable. But my memory management is to simple to do it in a good way, I can only allocate and never delocate. So now I am going to revamp my memory management. –WilGulf
Devblog 8 The real malloc and free is implemented. And if you know C you may understand what is going on in the image. All ptr are allocated using malloc and the first one is free’d before allocating ptr4, that is why their values are the same: ptr4 reuses ptr1 because ptr1 is free’d. Now that I don’t only have the allocation but also freeing which means I can safely implement a filesystem driver without worrying about the memory overflowing. – WilGulf
Devblog 9 I found a course for os development to follow and it really helped me with this. With the course explaining, I got my kernel to read a fat16 disk and print the content of hello.txt. This was a lot of debugging, first the file did open but couldn’t be read, then later the file was read but the data was just wierd characters. Now this is a huge step, the reading is done and now I only need it to be able to understand executables and read them. – WilGulf
Devblog 10 Now a binary file is able to be loaded AND executed. So from that qemu picture you can see the “Hello from a binary program” message, that message is printed by that print.s code. This is a huge milestone. There are still some functions to implement. But after that it is just writing all the userland programs. I must say none of this was easy, and choosing to develop a OS for stardance has so far been a really big challange. And now I need to push through coding the last bit so i can get this shipped before the end of stardance. –WilGulf
Devblog 11 NeoOS has now got ps2 keyboard drivers! So now I have implemented a driver for the US layout on ps2 keyboards. I am also looking into changing it to support my keyboards (Swedish layout), but that would take some time to map the right keys to the right number when the US layout can be found right on the os dev wiki. So this keyboard writing is also done the real way, the kernel boots, the kernel starts a program, that program asks for keyboard input, when it gets a input it asks the kernel to print that input. Now you can see how this could later change into a shell: you write the name of a command and it runs it. –WilGulf
Devblog 12 A shell This is the first shell for NeoOS, it only has the clear command and a fetch program to display the logo. It took some time implementing all syscalls it needed, i needed to make many kernel functions available in the userprogram and that took most my time. I have yet to implement a way to terminate the program so now when fetch is called it never ends and you never get back to the shell again. – WilGulf
Devblog 13 Not much to show on the screen, however in the background i have worked on a security feature. So it is kind of like the pledge feature in open-bsd: so the kernel first need to know from the program what it wants to do, like print to the screen. Not until it has told what it will do it won’t be able to do anything. And if the program ever does anything it hasn’t told it would do the kernel will just kill the process. The program promise to not use any other functions except the one it has specified. And the kernel won’t let it break it’s promise. That is why the c function is called promise. –WilGulf
Devblog 14 I have worked on multiple commands for the shell but the one that i want to showcase now is the process management. Running.elf lists all running processes (including itself) with their name, pid and privilege level. Then I execute kill.elf with “1” as a argument which is the id of the shell. That kills the shell which leaves the os with just the blinking underscore cause there is no longer a shell running. Other commands are the sysinfo (uname) and updating fetch.elf with some new info.
Devblog 15 I have now added colored printing that I showcase here in the fetch program. The printing made me redo how the writer works to support the decoding of the default ascii sequence used to change color: \033[xxm , where xx is the color. It follows the standard C way which makes it pretty easy to use colored printing. – WilGulf
Devblog 16 I wanted more programs for NeoOS but I felt really limited to just the print and getkey functions. So I rewrite ncurses (not with all ncurses functions) into my own curses for NeoOS. This allowed me to write programs that update the terminal like a screen. Here I shouw the NeoOS logo being displayed with a CRT-screen effect. Now I am In the decision of what game to make with this new library. – WilGulf
Devblog 17 I have developed my own ramfs. The old filesystem only supported fat16 with only reading capabilities which maded it feel very limited with what you could do with it. So the first step I dicided to do with adding reading was to implement filesystem that lives in ram which is really easy to write to. Now the D: drive is used for the ramfs (D as in dev used by linux). In the screenshot test.elf creates a file: D:/test.txt and writes HELLO FROM RAMFS to it. Then read.elf (linux cat) can read that file. – WilGulf
Devblog 18 So close to going over 10h however I managed to fix the bug. So a missing feature has been writing to the disk and not only read it. But the current file system was fat16 and the attempts I have made to implement writing has failed. What is the logical thing to do in this scenario, well I wrote my own filesystem: NeoFS. It is not feature rich compared to fat16 but that was why I could make it write. And the performance may be horibble when having larger files. But if it works I will keep it! So the test just shows writing/reading of a file. – WilGulf
Devblog 19 Not as big of a update now, but I just wanted to show of my new readdir implementation. That is then used by list with some coloring, all are green cause there is only executables in /execs. – WilGulf
Devblog 20 Final touches and logging the remaining time before shipping. I hope I have fixed all small bugs and made the libraries easy to use in new C programs. I also created some small new programs to show all functions in the kernel. Thats all for now and I hope to get to ship soon. –WilGulf
Devblog 21 The review is taking ages, and I couldn’t leave NeoOS. So I of course continued with fixes and features. The big new thing in this devblog is the filesystem: NeoFS, I have done major changes to the design like how a free block is found which greatly improves performance. And many safeguards were added to reading/writing to the filesystem. I also updated the host fstools used to create the filesystem on a drive to support arguments with options, easier to use now. – WilGulf
Devblog 22 The review of NeoOS found some problems with the filesystem commands and I took some time to fix them. Now the commands know where they are run and you can move around with cd. The second thing for this devblog is that I got multi disk support so now you can have up to 4 harddrives attached with writing/reading working on all of them , and that took some interractions with the ata ports but I finally got it working. –WilGulf
Ships:
So I made my own os “NeoOS”, this project was started not long after the release of the macbook neo and cause of that the os got it’s name. Testing is pretty easy, just make sure you have qemu installed with the correct cpu architecture. The project has become much bigger than I thought when I started it, I just could not stop implementing more features. And the most challenging part must be the hardware interaction, like reading from a disk by sending commands in hex. The documentation found for how cpus/ata disks/ram and all works are so hard to understand but that may be because it is not a simple thing. So when testing I want you to know that even though there aren’t many commands the kernel is still doing so much work not seen and the kernel is also what took most hours on this project. Lastly I hope that someone with all documentation provided writes their own program for NeoOS, I would love to see what other people could do with my OS....
|
1793004659.32004
|
1793091059.32004
|
|
836
|
meow auth by @moon | Stardance
|
moon
|
0
|
129.27
|
0
|
[]
|
[{"post_id": 76283, "ts": "202 [{"post_id": 76283, "ts": "2026-10-03T02:33:15Z", "hours": 10.1333, "text": "pew pew cabosh, wawah space birb is very sleepy. BREAKING NEWS, i added and changed a lot of things so i could make a delicious soup of changes that changed my old changed code that i yes. minimal frontend work called making the passkey section button go crazy with colors, authenticator icon (just search “aaguid explorer”, its not crazy work) and having a dialog telling “hi do you want to rename this, no? okay”. I also have collapsibles that hide info from your lil nonfluffy face when its useless. Now my crappy server knows from where you are connecting (who would have known that a server could know that) and where you live (oh no [its approximated from your ip]). THe latter only works when the instance is proxied under cloudflare (it even gets mad if a request doesnt have the headers it wants when you have enabled the “under cloudflare” mode). the audit log single method to do everything™ has been swapped with a builder (i love this), AND its info now includes that same ip and location (actor related [who did it]). all fields are now obligatory for… audit log purposes, because before i just pushed null on the db for things i didnt want to show the user MAKING a pretty stinker audit log that does not show who did what. i really dont know whata past me thought, because you can keep everything on the db and just show what you want to the user. idk, past me thinking in uhm not portals (yes). okay, more slurry of things. mah beautiful fix so the JWKS (signing keys used to… sign a jwt! [important for OpenID]) update when the database JWKS changed, spammed the hell out of the db and log as it polled instead of waiting for the db (or an instance) to say “I UPDATED IT GUYSS!1”!1”. This comes from the instances cache’ing JWKS instead of saying “could you repeat that” to the db (too many requests = blue elephant cry and explosions), so they need to know when the db changes or THEY WILL BE out of sync!! mr past me also thought that it was a good idea to store the oauth token code (used to get an access token) in plaintext in the muffing db, SMTH YOU SHOULDNT AT ALL DO. now its just hashed via hmac just like everything else. man i am GOOOD at this job of so called programming, having to go back to edit a thing i called done AND then HAVINGTO edit and edit and edit. this is so fun that I WILL BURST into FLAMES because of how stoopid i am meanwhile, you also have me deserving to be cooked with rice because I made a condition in the oauth token exchange that when SOMEONE somehow miss types or gets access to the oauth token code but has the wrong client_id, the temporary code gets deleted… and you know what i forgot? i forgot to commit the changes to the db, so the code never was deleted lol. i love these kind of stupid goofy pain errors that arent even errors. AALSO I reprettyfied the oauth helpers because after working on them a long time ago, i didnt know what were they doing and it wasnt fun nor funny >:( [i was mad {i am still mad, with that space birb… i want to sentence past moon to sad corner jail for 12 seconds}]. NOW teeny tiny additions!“1 the ratelimiter now exposes a “Retry-After” per a hacker news old moldy article i found, plus exposes its headers on cors. the audit log now does its job even in more parts! now it also tracks the totp recovery code usage [i frankly forgot about it :(].Changing your email or name now requires sudo minus the name on register. AND the app startup has now a beautiful banner saying “meow auth” in cursive. its pretty :3, makes it stylishinning. I also moved and added to the service manager (the watcher) a way to have service names and to launch services from inside of it (for some reason i used a method that was outof place for ages lol). oh no my time has come nnonono, i give you permission to see my trashy work in screenshot format (so modern)… yet i shall push towards completion of this meowing meow meow authing meow auth server:"}, {"post_id": 65650, "ts": "2026-09-10T22:39:28Z", "hours": 11.2656, "text": "hi hello hiiii, stupid space birb back from long bed sleep break. CATCHING UP, i have swapped to resident passkeys, fixed jwk refresh feature not working, beautified toml settings, added 2fa replay protection and audit log beautification. alright.. prepare for a long boring devlog as always. I finally swapped to resident passkeys after thinking about it for days (hours)! That means.. NO MORE user enumeration problemo with passkeys, yippie. it wasnt really a pain in the feathered buttocks, like it was just enabling a crate flag and boomy boom (and it even works on the frontend!). also, i patched with scotch tape a stupid buggy bug about the email templates, becuase I used a lazylock to store the email templater engine stuffy, when SOME random goofy template or data was wrong for whatever reason, it would poison the lazylock and the next time it was used it would just say “oh noes, i am broken, poisoned my childs. GO HECK YOUR SELF”… i just fixed the template part by checking if tera likes them in the global state creation. i love scotch tape, it smells great. while doing that, i finally addressed the beautiful jwks not updating on all instances because in MY JOB QUEUE only one running server instance can eat the job. that means, if you have 2 instances running, the one that is the unfortunate one that didnt eat the job will have stale jwks until the next time it is restarted. fixed it with some beautiful blue elephant database screaming “HEY GUYS, THE JWKS HAVE BEEN UPDATED” and the other instances will be like “oh, okay, i will update my beautiful jwks now”. finally, 2fa, or as i like to call it, TOTP, has been taken cared like a baby and then thrown again to the battle field after giving it the power up of replay protection. That means, if you use a code, it will be marked as used and you cant use it again (this only works with valid codes). makes you wait more smh. THE SETTINGS got a layer of microscopic makeup because i was like “man, these setting name are weired? what if the settings file had comments to know what the heck is this beautiful knob named ‘do_not_touch_this’”. yes i did that. it was a big red booty pain as i had rerereremember how to do proc_macros and how the heck did i even update the toml files with new entries without making them implode with gibrish. AND WE ALL KNOW NOW that ‘do_not_touch_this’ is a setting that if you set it to true, it will make this space birb implode in flames and become dust (yes, like a real firework going CHIRPAAAAAAAAAAAH pop ). and the final thing given some body work spray was the audit log. no more caveman moonbeeper style ‘log’ method with a thousand things. now we have the SAME thing but as a builder with a ‘save’ method. it just makes the code easier to read and understand. also, the audit log now has a “what resource¿” and “what ip?” and i removed the audit entry making from inside the auth helpers to outside. it was just an inconvenient place to put it, i dont evne know why would moonbeeper put it there… oh right i am moonbeeper. I DID IT BECAUSE it was a great place in those times. alright, HERE’s your typical bad screenshots that are trashign and god i am sleepy:"}, {"post_id": 53541, "ts": "2026-08-24T04:13:41Z", "hours": 9.2344, "text": "hi hello this is space bird. i have eaten 9h hours of real world time in just making the dialog component. I mean, IT WAS for making the 2FA prompts for when you wanted to enable it or disable and bleh bluh.. atleast it does look great… and i still need to add icons. the prompt is just the typical 2fa enable that gives you a qr or the 2fa secret if you cant scan the qr. The dialog component was pretty much made in nothing, in air time (free :D). the thing that took a bit was just the styling BUT WAHT did take a BIG LOOOT of time was just making the 2FA dialogs. lik gha damn hecking “2FA prompt” and “beep boop enabling dialogs”.. why?! becuase they are PACKED like a lasagna with forms, tanstack fetching, dialog steps and other stupid stuff to make it atleast not confusing for the user to navigate with tree sized buttons that dont work (becuase you are on the wrong step!!!!1 or already did everything lol). i mean, besides that custom stuff, it just reuses components like the pin or qr svg and… for now, also uses the spinner icon on the buttons you click to manage 2fa as i couldnt be asked to add real icons for now (leaving them for lasts). next up working work is more dialogs (for the passkey setup [so it isnt just a spinner without any “magic guideance”]), a collapsible comp to wrap the info items to show EVENTUALLY some metadata like, in the session items, browser, ip, what user was that did that thing and etc. Its just so i dont balloon the “info items” BECaUSE they are supposed to be some kind of “quick info”. broom brroom, i love wasting time on these stupid things (and wiring them!) >:3. LEAVING that tiny goofy work that apparently took hours to do. I am thinking and WILL be doing a beautiful swap into using resident passkeys (the ones that dont require me to know the user’s email in advance). yes, i know i said before that i dont wanted and ew ew resident. but man, its just easier for the end user to click a magical button to login directly. AND AND this even protects me from someone slapping the meowbackend with the email fish to see who is registered (with a passkey) by checking if the user’s email makes the selector appear. still, some part of me still thinks this is really bad idea but i want to do it tho… what could go wrong hah! i might aswell go to the cooking pot already and make some uhh chicken soup made of space birb. that’s it, i still feel like i havent done anything. Here’s your beautiful video of showing the beautiful dialog going “hi” “goodbye” (the video shows me enabling 2fa, viewing recovery codes and disabling it [with a recovery code]):"}, {"post_id": 47860, "ts": "2026-08-16T02:59:32Z", "hours": 10.5872, "text": "would you look at that, 10h… i love wasting time. Now THIS thing fetches some bits of data like the audit log, my passkeys, adding those and even modifying the username (you are forced to do it)! BUT big buty, i had to add the mr /signup/complete where you set your prefered username, like moon (its a me!), or else the backend will straight up refuse anything you want to do. AFTER changing it, you can do everything else a normal user can [by Default the username is just the user’s email AND THAT IS NOT PRETTY AT ALL >:(] FIRST OF all i grabbed my magic cup for tea and made the audit log page (it does not even have anything special)! .. oh right, for that i needed to know how the heck you even send requests with tanstack. so uhh,, blah bleh bluh wawa BOOM i now know how to call a method and get my data back AAnd even make infinite fetchers (IT kinda hates my way of giving data [its wrapped in {3} onion layers {request.data.data.data}, the ones that make you cry a bit]). i also synced my auth state with the tanstack client so it doesnt do two trips every time. okay now. TO make the audit log thingy, i did some beautiful matching so the type, creation and guy who did the action (probably the user) are actually human readable with a limit of 8 items (or else the /me page would be as long as this project’s crappy devlogs). When there’s more, a beautiful “view more” button appears (separate page). For this, so called “view more” page, i used the infinite queries. while at first i just puuushed the data into the dom with the #each (svelte thingy), chrome do be VERY very mad when there’s a lot of entries in there (The audit log, because it logs actions in your account, can get very huge. Because actions like the baddie Session action logs each time you log in or log out), SOO i did what someone whose browser is eating more than 10gb does, using a virtual list to render the it! (IT only renders items when they are visible, hidding [removing from the dom] non visible ones. this fixes the “OH gosh THOSE 200 things THAT I CANT EVEN SEE, ARE EATING MY precious ram”). OHh and you can press ESC to leave the page because i made a cool component that lets me plug in a callback for specific keyboard events :D. SECOND, the passkey stuff. yeah, pretty easy thanks to libraries like SimpleWebAuthn that do the hard work of telling the browser “hey, authenticate this guy please” or “hiya, registrate this passkey please”. its just querying what passkys you have to know… hwat passkeys you have and that’s it. BUT sadly, an actually sadly, my passkeys are non resident (I cant have a simple button to just login, I need you email before i can use the passkey). Thaaat means I havea teeny big tiny small user enumaration problemo becuase the backend can reveal that an user has a passkey registered and, in turn, we know that user is registered. a bad guy can just atack with “oh noes, your passkey has been stolen. pls give a undecillion of moneys”. third, i had to add the sudo page. It does what you think, reauthenticate to do sensitive operations like adding a passkey. Pretty simple, it redirects directly to an email code if the user does not have a passkey or totp enabled (email code is always enabled), if they have those, it just shows a selection screen. fourth, i had to fix up some stupid things with the api schema of the backend becuase I either forgot to put a body on the responses (like the passkey/webauthn routes) or just fix up a teeeeeny tiny setting thing that wasnt correct (its the webauthn/passkey rp_origin [allowed pages to register/use a passkey} becuase it jsut used the backend url and THAT is not correct). so tahat’s it, shall you see some stupid screenshots and not even a video because i havent even finished everything:"}, {"post_id": 44382, "ts": "2026-08-10T02:59:15Z", "hours": 6.0403, "text": "well hello again. space birb presents you the next devlog. I cleaned up the forms a bit (they are a still bit TOO messy ugly but they do work), REDID the ugly flags class to be a more EEEASIER TO WROK WITH (i dont even know how it worked before lol) and FINALIZED the auth pages! RIGHT right, first frontend. I finally finalized the most basic and empty and everything pages of the frontend! wahoo mee :). these pages practically include the otp one and the 2fa one (+ recovery).. and i just realized that i forgot about the passkey one, great so now it isnt finished (fried space bird thingy). Redid the pin component so it works with my Input form component AND also fixed some weired quicks of the pin component in phones (for some reason, my phone, didnt respect the max lenght of the input. i just sliced the value of the input on my max length lol). And finally, the frontend now has the most precious bit of any… i dont know. i just added the typical dropdown componetn for the avatars (yes, this was important for me). while on the backend, because mr past moon made some weired decisions, the 2FA recovery code generator and giver of the code the state was a messy mess that I frankly dont know if I even tested it, because it accepted wrong codes? i dont even remember if it worked haha in the past BUT now it works as it should and its at least better readable with normal method names (not plainly “recovery” [… what does that mean anyway!?? you would need to look at the code to understand it! and that’s bad]). ah, the typical moment has arrived, the one i always repeat. HERE’s your happily working auth pages for once, plus the “want to retry the email sending?”, the passkey one is still missing but that’s just slapping some paint (and painting my self) and boom (whhile this is practically the same as the past devlog, it just works better than the past devlog lol):"}, {"post_id": 43668, "ts": "2026-08-09T01:58:51Z", "hours": 10.3242, "text": "would you look at that! Finnaly some functional pages with forms, ALmost finalized components… oh they are just the login pages….. and its not even all of the auth pages, just selected ones so the auth flow barely works. BUT, THIS fLuffy (not fluffy) space bird has finalllizated converting (or thinks) the classes i had as global styles into beautiful svelte components with all those stars and happy things. happily, i am longer limited by having evertyhign in global space.. oh right, RIGHT. i wasnt even limited :). AND the coolest compponent of all of them is the spinner one because it spins. The first pages have been plugged into an outlet called SuperForms (not really super, mostly helping to validate)! thanks to that, we now have working forms that post to the backend! with all those classic things, red colors and form validation. but, how I THE unfluffy space bird is pushing envelopes with the form inside of it? by talking to my backend obviously! but not manually (doign every step each time manually), by using a library like the trusty openapi-fetch that eats the openapi schema of the server i used in the past iteration. BUT i trashed it into the.. trash because I was fed up by having to repeat a thousand times the same snippet of code in each form or even page (I could have used a service like class to make it easier tho!). it was swapped by Orval! Orval works with the same openapi schema BUT gives methods! No more repeating the same things, just use the method and boom. and also that openapi-fetch was mad that i used a more recent typescript version. ANND, finally, the auth context was upgraded with a leg made of clay so it can now parse the BITENUM flags of, for example, the user (UserFlags) that tell what is enabled and what is not, if you didnt remember. Its practically a generic class with everything that i considered necessary that must be extended to be able to use it. and that’s it. you may watch the shittiest video ever that just shows that it kinda works with the forms and logging in and that’s it with still mocked things:"}, {"post_id": 36040, "ts": "2026-07-27T21:16:15Z", "hours": 6.8131, "text": "haha 10 days later. no progress just me rambling and going in circles. I am a bad space birb. RIGHT! I just were converting the css stuff into svelte components using the style tag (and the preprocessor duh). That’s actually it, quite literally. No progress at all. Wasted time on, still, falling on the loop of trying to get something that “looks good”, but i dont reall know what i want in reality. ofc i try to get “inspiratainionion” from other websites and try to mix them together to then dislike the result, undo and rinse and repeat (at this point my fur and feather soaked hard on water). YOu may imagine it as thinking that you ahve a finish line when you done even know where it is. i will just try to make the frontend work first without thinking about the design… AND i cant even promise THAT! because i will probbaly spiral into the same loop once again (saying oh this looks bad blah bleh bleh). god i am bad at making frontends or evne design or everything, but thats how people learn haha. it is a lesson that i should learn from now on.. i keep judging my work too harsly but i dont know. frontend is just harder for me. here’s the useless non functional three pages that atleast have something layout:"}, {"post_id": 30020, "ts": "2026-07-17T08:27:04Z", "hours": 1.9356, "text": "in the end i gave up in the design or well… can you even call it “design” when it was ugly even at teh start? yes, i tried my best at making it look “good” in my own eyes but i could not for the love of birds. it was bad anyways, like actually bad. I, to make it easy for my self and be able to copy how other people do it because i am a lazy bastard (stupid space birb that klanks its keyboard for nothing), will be using the typical two columns for each section. One for “what the heck is this section for” and the other for the actual content (wow). man, i hate how the frontend is where i struggle the most when the backend should be where i should have struggled the most, not with this dude. agh. I also hate HOW i thought the layout i wanted initially was the best one and that i look great when in reality it was an aberration that didnt even look good and it really threw to the trash the unused space bruh. it just wasnt for this job, maybe for something else.. idk haha, what I know is that I think it already looks better with the simple sutff ive done lol [that’s sad btw :)]. as you may see int eh screen shooting, the audit log section instead of having a table it uses a… placeholder for a button with the same content it has currently because I frankly i am scared of making tables because of the probable difficulty i will have (because I am already struggling with teh simplest of things!). ALSO, i need to stop making .scss files, compounded into a single css file using @layer and @use , to just use svelte components that use the style tag. it really doesnt change anything, but atleast i wont be doing “class=‘meow’” each time i want something, just using “” is half better lol (doesnt really fix anything, I just want to give use the svelte components). finally, i am planning to use “services”.. they arent really services but more about wrappers around the openapi client. less manual labor for some shitty stuff that i wont need to do anymore. Still, its just a wrapper with nicer method names and namespaces. (also, ill be adding profile pictures. didnt think i would be adding them tho) here’s the typical dumb screenshot of what i think that looks “good” without doing that much work:"}, {"post_id": 28705, "ts": "2026-07-15T03:47:05Z", "hours": 8.9958, "text": "i am ashamed. i am that bad or… well ive gotten to the point of real badness and what some call “skill issue” because I CANT make this hecking frontend. its just too hard, i am just way more slower than before and what i though i was. i hate that i am not usign tailwindcss and isntead I am building my own scss styles IN @layer when i could have been using svelte components with the style tag but ugh bad decisions that can be still reverted i guess. For the layout of the settings, i even tried copying how I did it in the last iteration of this frontend (past server, not named meow auth).. i just did not like it because using a sidebar for this teeny tiny amount of information is wasteful (like this tiny [not really tiny] space birb). Like the content is just the typical name, email, auditlog, 2fa, passkeys, sessions, oauth authorizations and user created oauth apps AND lets not forget about the admin panel. i am practically suffering with mundane crap that anyone can have done in probably 10 minutes by asking mr claude or even chatgpt OR even just copying an already made layout, but here i am suffering trying to make stuff my own way, telling my self that this was the worst decision i’ve made goddamit… at this point i will really become a hotpot space birb soup.. i just need one layout made and then it should be an easy job to then copy and paste to other tabs. then the enxt step is to wire it up the forms and have it communicate to the backend which should be an easy task (i think [… oh god please be easy])… i know this entries of the frontend will make my project go into deflation mode and stuff, and i even broken a promise that ive made my self to not make devlogs that are more than 5h long because of a review someone made of my project when i submitted it unfinished to flavourtown (yes, flavortown) which is sad but it is what is. you cant be perfect, that’s why i have a shit hecking design. i am just bad, a bad space bird i guess. i already rambled too much in this suppossedly simple devlog. here’s your half crap “inspiration” that I used to (quite literally did a C&P of the page) of my past proyect using a sidebar (not what i want with this iteration) and the current state of art of my REALLY REALLY SHITTY curernt state page:"}, {"post_id": 25277, "ts": "2026-07-09T13:32:20Z", "hours": 10.9092, "text": "hi hello. oh, ive been 10 hours doing the same thing!!1 god. So, I was doing the frontend design without using figma and uhh yes. And also removed the ability to use your login to.. login to the app. You just use your email (otp, and passkeys). First, I forgot how to use figma, I only remember some shortcuts. I was going to use it (for frontend and logos) but seeing how struggled to make simple things, I only used it to swap the colors of the logo of MEOW AUTH, hmm yes, very meow. . The frontend stuff… I frankly ALSO do not remember anything.. or well I do now remember some things thanks to me fighting to uncenter a div hah. The stack is practically svelte, as always, client rendered and scss (sassy :o) for the styling. In the start I was just going to use the same styling and structure of my first iteration of this project, beepauth (ew), and after doing all of that I thought “god, this looks pretty bad”, soo I then tried to make it look a bit better WITHOUT starting from zero again. And I did style it a bit better but I didn’t even like it. Like it felt like I hadnt even advanced at all, like if the same shitty fricking backend was the same from the past (probably noone would care because probably uhh noone cares.) [brains a weired and even more mine i guess, wawa]. So, naturally, i did the less sane thing, REDOING EVERYTHING again. Had to watch tutorials to relearn how use sass and picked up also some new css stuff that I wont even use (minus the layers! that pretty cool!!). And from that css stuff I discovered Oklch.. yes i swapped my whole color palette to that using their harmonizer that uses the equivalent of WCAG, APCA (contrast bg to text!). At least the frontend now looks decent (or the first blocks fo the website). sadly the only frcking shitting heckign parts ive made are the login (and register BUT THATS THE SAME). AWIT WAIT WAWA, I also swapped some gears in the BACKEND! I removed the login (username) entirely, now its just demoted to a non unique display name (for openid!). you must be asking why, because I changed it to use the login not long ago. Well, because I don’t have to force a user to give me a username AND their email on signup. Its easier to just give the email. And if you already have an account and hit, without knowing (our typical autopilot mode), the signup page, I can silently make a AuthChallenge for login instead of signup because both handlers return the same result. Then, after registering, I just force you to set a display name (by default its just the email, i could leave it like that but currently I want it to force you set a custom display name for OPENID). By doing that, I practically removed the “vectors” (ooh hackiry stuffiry) for user enumeration [those vectors were the endpoints to see if a login (username) or email was already taken] (I also made so the login endpoint gives you a fake challenge id when the email doesnt exist {This works thanks to having the auth exchange handlers return “invalid code” even if the challenge doesnt even exist}). here’s your screenshot of a login page that looks exactly like very other login page, maybe even shittier (sorry i am bad doing these kinds of things.) [also you have the logo colors, i went with purple because it looks cool and its a cool color] {the “Psst, over here” its just a random greeting, just like the ones i have in the emails} [[sorry for wasting 10 hours doing nothing]]:"}, {"post_id": 23063, "ts": "2026-07-05T20:02:59Z", "hours": 0.3025, "text": "a. hi there mr svelte! I was wondering if I should be drafting first a design in figma but meh. I like to suffer and make bad designs that progress very slowly to look mediocre at best! yay!1!! anyways, ill be using scss as always (i frankly done even remember anything about it lol) and sveltekit. HERE’S YOUR stupid “hello world” from slevetkt (reaaly useful devlog):"}, {"post_id": 22522, "ts": "2026-07-05T01:24:44Z", "hours": 0.3122, "text": "oopsy. shoooort one, sorry. I added the forgotten oauth error StatusCodes and Descriptions. there’s not much to it lol, I just forgot about it. as always, here’s your even uselesser screenshot with code taht you can already see in the guthub:"}, {"post_id": 22514, "ts": "2026-07-05T00:59:48Z", "hours": 1.7131, "text": "right, its a me! the teeny tiny waist sized space birb that is here to tell you that I added the ratelimiter! It works just as i’ve explained in the last entry, it uses the IP of the user to limit the amount of requests via a ticket bucket. THe bucket is stored in memory, as again said before, so if the instance is restarted, goodbye ratelimits. EAch request eats 1 ticket AND the bucket tickets and refill rate can be set via the… middleware. who would have known wow. It always adds the typical “x-ratelimit-limit” bleh bleh bleh with all the info you can like that is useless BUT hey, its there for you. I like making my own stuffies because its cool. THe root has a limit of 500 requests, refilling after 1 second. While the auth routes have a limit of 10 (sudo) and 20 (auth flows) requests, refilling after 1 minute. The other routes are just uhh protected under the umbrella of the root ratelimiter lol, no need for having to add a ratelimiter to every single route (god). that’s it. there’s no more devlog. Now what i gotta start doing is the frontend. I will cry a bit because I am VERY very VEEERY rustified in the typescript department like I never touch it but meh I MUST do a frontend or else this is incomplete… and i will do be crying if i send it off in a incomplete state. THE frontend will be in svelte kit, because its cool and ive already used it in the last iteration and it left me with a good taste in my forked tongue (hahaha, i am space birb) AND thanks that Ive been using from the start utoipa to add an openapi schema, I can use it easily to make requests from the frontend! and i didnt need to suffer adding them after everything was done just like in the past iteration! here’s your useless screenshot showing teh ratelimiter working and the headers and stuffies… god i am a mediocre at best writting long hecking devlogs for nothing:"}, {"post_id": 22325, "ts": "2026-07-04T18:52:19Z", "hours": 1.4481, "text": "wow. that’s a long time doing nothing. I just updated the deps, tera had a change on its templating because it was rewritten from the ground up. pretty cool, now it kinda looks like jsx and at the same time not. I also tried or well… I am thinking about making my own ratelimiter but was like, ugh. I was practically mega blocked on the idea of wanting a ratelimiter that used the IP + UserId. Both are easy but for some goddamn reason I kept going circles and circles and honestly I dont even remember why anymore, like huh!? In the end I will only be doing ratelimits via IP because they are the easiest AND THEY DO NOT NEED TO be stored in the database. yes database, you read it right. IN this version of my backend I wanted to use the least things AAANd the oNly thing required is just the database to make everything. Adding redis would be waste (and waste of ram) for just storing the ratelimiter. Redis would be required if I wanted to run more than 1 instance of my application AND IF i wanted to distribute the info about “oh this guy is grounded, no entering the meow auth realm for 5 minutes” to all other running instances. BUTTT, as you might not see, I dont want to run more than instance nor want to distribute it to more instances if it were the case that I wnted to run more than 1 instance. Soo, I went in circles in my crapppy bird brain because to add ratelimits via the user id I would have to store the info somewhere that wouldnt be erased (like in the in-memmory storing that i will be using) or else the ratelimits would be useless because… THEY WOULD BE ERASED from this whole realm when the instance is restarted (memory goes boom to the void, so does the ratelimiter). That’s why I want to just implement the Ip based one, its the easiest one and the only one that I don’t care about loosing the information about the ratelimits when the instance is restarted. Also, i need to implement it yet lol i was just scrambling my head nuts and bolts hearing them clank while trying to ratchet them. ALSO², i need to redo the email stuff because my brain has came up with a cool design lol but first gotta do the frontend to make it uhh look good before suffering making the email components. I also started to hate the tera zed language extension. its crap. bad crap the worst one. ALSO, here’s your really useless screenshot this time showing code that you can already see on the github page (yay!1):"}, {"post_id": 20456, "ts": "2026-07-02T01:37:49Z", "hours": 5.1653, "text": "hello again, its a me, a random space birb that is here to tell you that I completly forgot about the ratelimiting stuff. BUUT, I added the admin methods and UserFlags to be able to set… flags. not much rodeo this time. had to think how i wanted the audit logs to work for the admin stuff. I first though about just having a bool saying “ah yeah admin” but meh, I think its better to have also an “actor_id”, the who did it user id, and boom. In the user side handlers for the audit log I just return the typical plain response of “yeah this was changed” (not sql joins, cheaper [?]) but in the admin side, I return the actor_id with some other things like the user login of the actor AND the user login of the user that was changed (cause why not!? its jsut another join statement in sql). Works wonderfully and even better now because before I had setup the user audit log to fetch AAAL the entries form the db and pee pee poo poo no, now that i have my paginated stuff, no way! SOO, the admin methods are just the typical ones, see what the user has changed or an admin changed from an user via its audit logs, the oauth applications and authorizations management and that’s it. I will probably also add a way to know globally what the heck is being changed but idk about that, seems a big sql query (that is tiny but very costly in db terms) and I frankly want to avoid that… and even more avoid using redis because i hate it and that SOMEHOW i have better some beautiful organized code vs the first version of this backend where I used the typical DB+redis aaand it was ugly . i hate that. I also added the UserFlags to be able to set flags like “is the user an admin?” or “is this user allowed to manage its oauth applications?” and so on. Pretty cool. BUUT as always, I had to C&P some code (almost all of it) from past handlers to make the admin handlers work lol. I would really want to make a central place to put all the common handler code but meh. IT WORKS! and that’s what matters. THe next things are just making the ratelimiting WHICCHC probably will be only inside the instance the user is reaching and that’s it. I would like to have global ratelimiting using the IP of the user or its account id but that would (i think) require redis… I really need to think about this because someone with a crappy toaster can make explode my poor baby vps. ps. god do I really take that much time doing stuff? god i am slow at coding. i am bad goddamit. that’s it. shallllll you see my shiitty api docs with the admin stuff and admin auditlogs becuase why not:"}, {"post_id": 16949, "ts": "2026-06-27T14:57:54Z", "hours": 2.2208, "text": "hi and welcome to my unreadable journals. I added those oauth authorized applications management handlers that I forgot to add yesterday, like the typical “oh let me see what scopes does this thing use… OH GOD IT CAN SEE MY fur color I MUST revoke it NOW!11”. Then I moved AAAL the handlers that touched ME user data to the.. obvious /me route so its prettier and doesnt pollute the air of the real auth related things. and did some cleanup in the http error department by merging some repeated errors. god this is one of the shorter entries i’ve made i think. next up is doing ratelimting, probably roles or just an admin api and the “hey your account has been locked because of repeated tries to login”. i dont even know what will it take to make tests work god. here’s your shitty screenshot showing my only progress, the oauth management bleh bleh bleh:"}, {"post_id": 16427, "ts": "2026-06-26T18:44:11Z", "hours": 3.4175, "text": "hi, hello i am space birb in the sad corner and i am here to tell you that i added the the typical oauth management handlers that everything has. I also added a generic paginated database thingy to be able to make… pages when there’s more than 20 items (rows). firstly, everything was easy. yes, no rocks not nothing that could set me on fire… minus that I HAD TO MAKE a paginated database thingy. WHY did i make it? idk man, i wanted because my bad coder brain thought that maybe someone could have more than 1 oauth application created (like a thousand) and that’s pretty bad for mr blue elephant database becuase that means eating 1000 rows in one go (and blue elephant doesnt like that, AND EVEN less if my vps has 1vcore and not really that much ram). SO, the best course of action was to make pagination to be able to cut in pieces the data and make it easier to load and handle.. even though the loaded rows are hardcoded (its 20 plus 1). The pagination practically works by seeing if there’s more data after 20 items (that’s why it has a “plus 1”!), if so, we take the LAST item’s id (using a trait to access it, because you can’t really know in what form or what id will be used in any database model) in those same 20 items to set the ‘next’ param. That ‘next’ param is used to.. quite literally say “hi, uh could you give me the next rows after this id pretty please?” and boom works and i didnt set my self on fire but i did ruffle my feathers a bit because of. Ill probably implement it to more places because the only places that use it are the oauth applications and user sessions because i am a bit lazy haha (i mean, its just C&P the current find_many* and use the pagination stuff and caboosh). oh god, i forgot about the oauth consent management. great job me, NOW IT ISNT COMPLETE “everything” great coder i am great big bird brain. My next plans are just to do some general cleanup with the openapi schema, add comments to the code and then start doing the frontend in mr sveltekit.. although i am too rusty in ts land and i will have to learn some stuff again and touch again scss and stuffies and god, i am going to get cooked in the sun and roasted like the space birb i am because of me no longer touching anything javascript. here’s your really useless screenshots showing the INCOMPLETE oauth management handlers and the pagination thingy working:"}, {"post_id": 15504, "ts": "2026-06-25T06:20:57Z", "hours": 1.2603, "text": "I made the User Info handler for the open id stuff. that’s the end of it. It works, wahoo my self yay good job, even though you had pretty much bad scrambled code, you did it hahaha. It practically, as the openid spec says, returns the claims used also on the id_token. Soo, because its sooo close to the id_token, i’ve decided to just eat the that same id_token but spit out a converted version with things I want. I also added the typical OauthManager and RequiresOauth. the latter one not having a param to decide what scopes you want because, whhy would you want that?! its just a one liner and it may change for each hecking endpoint or even the data the endpoint returns. its just over complicating it with wrapped trash. … and about my devlogs, i realized that mine are pretty bad and not interesting like other people’s devlogs. i simply write weird and long ones. but i don’t want to write a simple “I did this, commits, hardness of implementing, whatever” in bullet points like other people do. i dunno it feels flat like this devlog. Here’s you typical SINGLE screenshot showing that the user info works, that’s it:"}, {"post_id": 15052, "ts": "2026-06-24T13:25:06Z", "hours": 6.1178, "text": "oh hi, did not know that you are really reading this. I added the openid stuff! Well not all of it, I still need to do the ‘userinfo’ endpoint but meh, it works as it should. I also added the cool JWK (the secret key [ES256] that is used to sign the JWTs) rotation stuff, which I can say that I tried at first over complicating it to then end up simplifying it because it was A HELL to use like you had to call a thousand hecking things or in one method give a thousand arguments (its an overestimation, probs not real [shy of 5, it wasnt generic, it was attached to the token flow] :3), it was a pain to use and IT EVEN GAVE ME a burn mark. As I said, I just redo’d everything and boom, simplified thigny you just call from the global state and boom, we do be working! The JWKs are rotated every 2 months, and the old one is retired at the same time. After 1 month, the retired one is deleted. So, at any given time, there’s a maximum of 2 keys, the current one and the retired one. The retired one, as the name implies, is not used to sign new tokens but is still valid to verify old token. And all of this is fetched at startup and then via a scheduled job it is updated. AND as you might have (NOT) guessed the JWKs are stored in the database, so if you have multiple instances of mah meow meow server running, they all share the same JWKs and rotate… OH GOD THEY DO NOT ROTATE THEM AT THE SAME TIME GODDAMIT AAAGH.. the intention was there okay? I did that to, in one part, give more use to my job manager and, to let all isntances update at the same time but big brain me did not think that a job is always locked to the instance that picks it up. also the token endpoint now supports using openid and spitting out a ‘id_token’ with the user info (some claims are gatekeept behind the scopes [like ‘profile’ or ‘email’ duh]). that’s it actually, like i started really pulling my hair, fluff, feathers whatever because I was trying to overcomplicate it a lot and i really dunno why. like, for another example, i kept swapping from the ‘jsonwebtokens’ and ‘compact_jwt’ crates because I wanted to use ES256 but didnt want the other because i never used it but then ended up using the latter because it was easier, and then that I wanted to use EC25519 which is apparently not really talked about in the rfcs (that’s why i ended up with ES256! [also supported on compact_jwt]). AH! and also in the job queue, for the JWK rotation, I wanted first to add cron job for that but… why tho, I don’t really need it, I just need a way to NOT run a job until a specific time and then reschedule it inside the same worker. here’s the shitty screenshots showing the oh wow ‘openid configuration’, oh wowie ‘it does output tokens and id_token’, oh thats nice ‘it does give out a valid jwt with valid claims that the programmer didn’t even do themselves because they used a library called compact_jwt’ and wow ‘it does have a job that tries to autorotate if the current key is older than two months’:"}, {"post_id": 13022, "ts": "2026-06-21T09:21:29Z", "hours": 1.6031, "text": "you know? i love debugging my code when the error was the entire time in the db. great job me!!!! I’ve made the token handler. again, as other devlogs, that’s all folks. Stupid me couldnt figure out why client secret was always bad, why the mr code verifier was always bad when it was the same as the stored one aaand why the heck scopes werent showing. i really do love that my code, practically, worked first try (MY CODE >:3). But did NOT love that i am still stupid and forgot that i had a database that works as the house for the data that my app ingests. god i am smart. time to go suffer with openid i guess. i have to touch jwt and stuff, eugh.. i like my opaque tokens more than jwts, because IF you want to revoke one of them you still HAVE TO STORE A LIST OF IDS… that defeats the whole hecking purpose dude, not worth it (or that’s what i think for now, smh i am just a space birb claking at keys). here’s your video that shows that it does work and gives the bearer opaque token and creates the db entry:"}, {"post_id": 12940, "ts": "2026-06-21T05:37:44Z", "hours": 4.6994, "text": "yayy! the first step of making oauth2 alive has been made. I rewrote the tiny part of the authorization handler of the oauth2 flow… there’s not much to it! It did took a while to reunderstand it because of how long I wrote it (2 months ago) and that I wrote it in a rush (and didn’t even make it work). Basically, the same as always, traceback to try to understand what past me wanted to do, to then rework everything (or at least try) to unspaghettify those radiative peaces of code. So, practically it only the authorization method was half done and ugly, it was a big BIG monolithic method that did everything in a way that either past me or current me like at all because it takes a whole lotta things to work (8 to 9 argumentos lol). In the end i just splitted the big MONOLITHIC (thick) method into two of the same kind but with at least clear and defined and bleh jobs. One when the user has already authorized the client and the other when he has never touched it in its life. I also did some qol for my self (or i think i did, probs not because it was already bad and rushed and stuff… i already said it at the start) with the oauth helpers and stuff by also prettifying them and simplying parts that I really don’t know why I added. Like I added mr “OauthResponse” which, as the name implies, makes the oauth response (redirect, plain error, error with redirect) instead of the 3 different methods I had to use to do the same thing, easier is better (and even understandable!). Ah, and i even tried to use strum but nope, it do not cut the job (it tries to cut the wall instead of the thing i want). NOW, sHALl the work continue to make the token making handler and then the OpenID stuff that may be a bit difficult because, with my shitty reading, i think ill have to juggle making jwks and stuffies to server correctly the food for the picky openid. here’s the video that shows, confusingly, that indeed the handler works (It does a “hi, oh you want to authenticate with ‘poop’, let me create a pending authentication. Oh! you accepted the consent, let me delete the pending one and create the actual lasting consent for ‘poop’.). god, i am so bad at coding or whatever the this is:"}, {"post_id": 11753, "ts": "2026-06-19T04:14:50Z", "hours": 2.2278, "text": "AAAH, sorry, did i startle you? I added audit logs, a health handler (a simple “OK YES i am alive ) and a root info thingy that tells you “okay, so my name is this, mmh yes, and this is my version and my build stuffies…). the audit log thing was not really a pain to add. At first i was thinking of using my job queue (because ITS only use is for emails… and i put my sweat and tears to making it pretty to then not being used lol) but.. why tho, like IF you see how was the code before the audit log adavancement (yes, cement) you can se HOW every action runs already a postgresql transaction. So, why not bundle the audit log adding magic into that same transaction? and so i did. Now, we don’t have to track our selves with pencil (i dont like pens) and paper the actions we do, we just let the application do it for us… leaving a paper trail of our desastrous actions. yay… now that i said that, i should add a random chance of also adding another audit log entry that is just a random “hi, i am your audit log talking”. hah that would be funny. btw, strum is not cool. I thought i could use hte EnumString thingy to make it implement automagaicallytationally the Display trait to snake_case but NOPE, it is used backwards. You give it a string and it gives out the enum variant. what a pee pee poo poo dude, imagine having a big monstrous enum and having to implement Display for each variant… just like the monolithic error enum of the http site… ew. to use it you just sprinkle the audit::log() and boom, done. AAAAAAH, did i scare you again, no? yay. I almost forgot (<- totally) to say that… i think THIS IS really the last thingyes before the oauth stuff. i really think i am going to burst into flames and become a cooked space birb… kfa (i hope you get it [its a acronym of a whole word {also, hi and thank you for reading this long journals that may be very boring or unnecessary to read}])"}, {"post_id": 11100, "ts": "2026-06-18T04:45:50Z", "hours": 4.8661, "text": "ah, beautiful api docs. I reworked the api docs (because they were a messy mess because of my past laziness [not understandable!!]) and now they are organized in pretty folders (tags) with correct descriptions and titles. now its even helpful to read the api docs to understand how to use a api handler, not having to dig into the code [noone does that :(] right, I DID THE EMAIL CHANGE THING and LOGIN tooo wohooo…. yeah it isn’t that amazing lol. at the start i was just thinking about using the typical chacha encryption that ive used for the TOTP stuff but for a random token nanoid’d… you just don’t, hMAc is fine. Ended up with a dual like verification flow where both the old email AND the new email get a token link (well, now it just the token string because, ahem, i dont have a frontend). both have to be verified before the change goes through. sooo, no more “oh noes, not again, someone got into my account and changed the mail to their own, smh”. then you just get the notif saying “hey, your email has been changed”. SEEECOND, login (your username) changing magic that is way simpler because I just check if you have sudo enabled and that you havent changed it in the last 24 days (why not). Just like with the email stuff, you get a notification saying “yay, you changed it!”. and I think that’s the last of the tiny stuff i wanted to do before the BIG and PAINFUL oauth stuff. i think i am going to burst into flames and go boom and the floor is covered with dust and feathers. OH wait, i sitll need to do account deletion… whatever its just a simple “hya you need sudo”, “are you sure about this”, “ok, bye” flow. meh. i also need profile pictures… heh backblaze or maybe cloudflare idk i like backblaze more but uhh I GOTTA RESEARCH OKAY!?! shall you see the probabaly useless screenshots that atleast show the tiny progress that i always do. great"}, {"post_id": 3935, "ts": "2026-06-07T02:04:58Z", "hours": 3.2119, "text": "beep bwap. firstly, what a waste of argon2. I was using it for encrypting the otp codes and.. dude, that’s like its just 6 characters. I just swapped to the typical hmac256. I also made a common cookies helper method to not have 2 (or more) instances of the same cookie making method. uhh, also I adde dhte forgotten passkey management handlers… and that’s it. OH WAIT, i also added validation! I mean, its pretty rough and very bad but it works for what I want! I, in theory, was going to use Garde for the validation with axum-valid to provide me with the base stuff. I DID NOT WORK, like I had (and still have) to make a wrapper around their sutff so I can send out my own error messages and not some plaintext like before i handled them. right, it did not work because of something called the “Context” … I tried everything to make it work, but I just could not, not even doing workarounds and C&P examples directly and stuffies, it just would not work like it wanted the global context to have a trait implemented, which I did, but it still would not work. I guess its because to use my global context inside axum, i wrap it around an Arc and maybe it didnt like that? or whatever meh wa. I just swapped to using Validate, and ta-da works as it should. HERE’s your badly made screenshot showing the crappy validation messages (they just say: “this field is bad :(”)"}, {"post_id": 3560, "ts": "2026-06-06T15:40:12Z", "hours": 0.8356, "text": "added a better way to handle required authentication!… middleware. yup, i am very creative. it’s practically a qol improvement in the development side, making code look a bit nicer without seeing in every single protected route the same 3 lines to check if the user is authenticated. now i can “enforce” it when I want the user to be reallly unauthenticated to use a route. to use it, you just “add the middleware and maybe move one flag” and that’s it… goddamit I should have had that before to not write a heck ton of “if not authenticated or if authenticated…”. i am trying to delay the inevitable.. the need of making the oauth side and the frontend ;D"}, {"post_id": 3518, "ts": "2026-06-06T14:25:42Z", "hours": 3.6319, "text": "I started using a master key for everything and fixed the server returning a plain text message when parsing goes wrong. FIRST, I have seen the future and the future says that I WILL be suffering if I have more than 2 secret keys to manage when I can just derivate them from a single master key. AND EVEN rails does that! its just blake3’s key derivation with a xor to fill the remaining bytes that some libraries require. it works pretty great. neat. SECOND, this was a problemo that one of the flavourtown (yes flavour not flavor) reviewers made me notice. When you send a malformed json body, like a new line on a field that really doesn’t expect a new line, the server would plainly return a error message in plain text, which is really bad for the client to handle and even for looks. Sooo, I tried fixing it trying to strap a error handler to axum… yes I dont even know if that even exists bruh. In the end i just created a newtype that wraps the original Json extractor from axum to catch its errors and THEN and only then wrap those with my own error messages. And bob’s your dad, the server now return a json error message like every other route error. shall you see the useless screen recording (its cropped by stardance’s ui, great)"}]...
|
Title: meow auth by @moon | Stardance
Devlogs:
I Title: meow auth by @moon | Stardance
Devlogs:
I started using a master key for everything and fixed the server returning a plain text message when parsing goes wrong. FIRST, I have seen the future and the future says that I WILL be suffering if I have more than 2 secret keys to manage when I can just derivate them from a single master key. AND EVEN rails does that! its just blake3’s key derivation with a xor to fill the remaining bytes that some libraries require. it works pretty great. neat. SECOND, this was a problemo that one of the flavourtown (yes flavour not flavor) reviewers made me notice. When you send a malformed json body, like a new line on a field that really doesn’t expect a new line, the server would plainly return a error message in plain text, which is really bad for the client to handle and even for looks. Sooo, I tried fixing it trying to strap a error handler to axum… yes I dont even know if that even exists bruh. In the end i just created a newtype that wraps the original Json extractor from axum to catch its errors and THEN and only then wrap those with my own error messages. And bob’s your dad, the server now return a json error message like every other route error. shall you see the useless screen recording (its cropped by stardance’s ui, great)
added a better way to handle required authentication!… middleware. yup, i am very creative. it’s practically a qol improvement in the development side, making code look a bit nicer without seeing in every single protected route the same 3 lines to check if the user is authenticated. now i can “enforce” it when I want the user to be reallly unauthenticated to use a route. to use it, you just “add the middleware and maybe move one flag” and that’s it… goddamit I should have had that before to not write a heck ton of “if not authenticated or if authenticated…”. i am trying to delay the inevitable.. the need of making the oauth side and the frontend ;D
beep bwap. firstly, what a waste of argon2. I was using it for encrypting the otp codes and.. dude, that’s like its just 6 characters. I just swapped to the typical hmac256. I also made a common cookies helper method to not have 2 (or more) instances of the same cookie making method. uhh, also I adde dhte forgotten passkey management handlers… and that’s it. OH WAIT, i also added validation! I mean, its pretty rough and very bad but it works for what I want! I, in theory, was going to use Garde for the validation with axum-valid to provide me with the base stuff. I DID NOT WORK, like I had (and still have) to make a wrapper around their sutff so I can send out my own error messages and not some plaintext like before i handled them. right, it did not work because of something called the “Context” … I tried everything to make it work, but I just could not, not even doing workarounds and C&P examples directly and stuffies, it just would not work like it wanted the global context to have a trait implemented, which I did, but it still would not work. I guess its because to use my global context inside axum, i wrap it around an Arc and maybe it didnt like that? or whatever meh wa. I just swapped to using Validate, and ta-da works as it should. HERE’s your badly made screenshot showing the crappy validation messages (they just say: “this field is bad :(”)
ah, beautiful api docs. I reworked the api docs (because they were a messy mess because of my past laziness [not understandable!!]) and now they are organized in pretty folders (tags) with correct descriptions and titles. now its even helpful to read the api docs to understand how to use a api handler, not having to dig into the code [noone does that :(] right, I DID THE EMAIL CHANGE THING and LOGIN tooo wohooo…. yeah it isn’t that amazing lol. at the start i was just thinking about using the typical chacha encryption that ive used for the TOTP stuff but for a random token nanoid’d… you just don’t, hMAc is fine. Ended up with a dual like verification flow where both the old email AND the new email get a token link (well, now it just the token string because, ahem, i dont have a frontend). both have to be verified before the change goes through. sooo, no more “oh noes, not again, someone got into my account and changed the mail to their own, smh”. then you just get the notif saying “hey, your email has been changed”. SEEECOND, login (your username) changing magic that is way simpler because I just check if you have sudo enabled and that you havent changed it in the last 24 days (why not). Just like with the email stuff, you get a notification saying “yay, you changed it!”. and I think that’s the last of the tiny stuff i wanted to do before the BIG and PAINFUL oauth stuff. i think i am going to burst into flames and go boom and the floor is covered with dust and feathers. OH wait, i sitll need to do account deletion… whatever its just a simple “hya you need sudo”, “are you sure about this”, “ok, bye” flow. meh. i also need profile pictures… heh backblaze or maybe cloudflare idk i like backblaze more but uhh I GOTTA RESEARCH OKAY!?! shall you see the probabaly useless screenshots that atleast show the tiny progress that i always do. great
AAAH, sorry, did i startle you? I added audit logs, a health handler (a simple “OK YES i am alive ) and a root info thingy that tells you “okay, so my name is this, mmh yes, and this is my version and my build stuffies…). the audit log thing was not really a pain to add. At first i was thinking of using my job queue (because ITS only use is for emails… and i put my sweat and tears to making it pretty to then not being used lol) but.. why tho, like IF you see how was the code before the audit log adavancement (yes, cement) you can se HOW every action runs already a postgresql transaction. So, why not bundle the audit log adding magic into that same transaction? and so i did. Now, we don’t have to track our selves with pencil (i dont like pens) and paper the actions we do, we just let the application do it for us… leaving a paper trail of our desastrous actions. yay… now that i said that, i should add a random chance of also adding another audit log entry that is just a random “hi, i am your audit log talking”. hah that would be funny. btw, strum is not cool. I thought i could use hte EnumString thingy to make it implement automagaicallytationally the Display trait to snake_case but NOPE, it is used backwards. You give it a string and it gives out the enum variant. what a pee pee poo poo dude, imagine having a big monstrous enum and having to implement Display for each variant… just like the monolithic error enum of the http site… ew. to use it you just sprinkle the audit::log() and boom, done. AAAAAAH, did i scare you again, no? yay. I almost forgot (<- totally) to say that… i think THIS IS really the last thingyes before the oauth stuff. i really think i am going to burst into flames and become a cooked space birb… kfa (i hope you get it [its a acronym of a whole word {also, hi and thank you for reading this long journals that may be very boring or unnecessary to read}])
yayy! the first step of making oauth2 alive has been made. I rewrote the tiny part of the authorization handler of the oauth2 flow… there’s not much to it! It did took a while to reunderstand it because of how long I wrote it (2 months ago) and that I wrote it in a rush (and didn’t even make it work). Basically, the same as always, traceback to try to understand what past me wanted to do, to then rework everything (or at least try) to unspaghettify those radiative peaces of code. So, practically it only the authorization method was half done and ugly, it was a big BIG monolithic method that did everything in a way that either past me or current me like at all because it takes a whole lotta things to work (8 to 9 argumentos lol). In the end i just splitted the big MONOLITHIC (thick) method into two of the same kind but with at least clear and defined and bleh jobs. One when the user has already authorized the client and the other when he has never touched it in its life. I also did some qol for my self (or i think i did, probs not because it was already bad and rushed and stuff… i already said it at the start) with the oauth helpers and stuff by also prettifying them and simplying parts that I really don’t know why I added. Like I added mr “OauthResponse” which, as the name implies, makes the oauth response (redirect, plain error, error with redirect) instead of the 3 different methods I had to use to do the same thing, easier is better (and even understandable!). Ah, and i even tried to use strum but nope, it do not cut the job (it tries to cut the wall instead of the thing i want). NOW, sHALl the work continue to make the token making handler and then the OpenID stuff that may be a bit difficult because, with my shitty reading, i think ill have to juggle making jwks and stuffies to server correctly the food for the picky openid. here’s the video that shows, confusingly, that indeed the handler works (It does a “hi, oh you want to authenticate with ‘poop’, let me create a pending authentication. Oh! you accepted the consent, let me delete the pending one and create the actual lasting consent for ‘poop’.). god, i am so bad at coding or whatever the this is:
you know? i love debugging my code when the error was the entire time in the db. great job me!!!! I’ve made the token handler. again, as other devlogs, that’s all folks. Stupid me couldnt figure out why client secret was always bad, why the mr code verifier was always bad when it was the same as the stored one aaand why the heck scopes werent showing. i really do love that my code, practically, worked first try (MY CODE >:3). But did NOT love that i am still stupid and forgot that i had a database that works as the house for the data that my app ingests. god i am smart. time to go suffer with openid i guess. i have to touch jwt and stuff, eugh.. i like my opaque tokens more than jwts, because IF you want to revoke one of them you still HAVE TO STORE A LIST OF IDS… that defeats the whole hecking purpose dude, not worth it (or that’s what i think for now, smh i am just a space birb claking at keys). here’s your video that shows that it does work and gives the bearer opaque token and creates the db entry:
oh hi, did not know that you are really reading this. I added the openid stuff! Well not all of it, I still need to do the ‘userinfo’ endpoint but meh, it works as it should. I also added the cool JWK (the secret key [ES256] that is used to sign the JWTs) rotation stuff, which I can say that I tried at first over complicating it to then end up simplifying it because it was A HELL to use like you had to call a thousand hecking things or in one method give a thousand arguments (its an overestimation, probs not real [shy of 5, it wasnt generic, it was attached to the token flow] :3), it was a pain to use and IT EVEN GAVE ME a burn mark. As I said, I just redo’d everything and boom, simplified thigny you just call from the global state and boom, we do be working! The JWKs are rotated every 2 months, and the old one is retired at the same time. After 1 month, the retired one is deleted. So, at any given time, there’s a maximum of 2 keys, the current one and the retired one. The retired one, as the name implies, is not used to sign new tokens but is still valid to verify old token. And all of this is fetched at startup and then via a scheduled job it is updated. AND as you might have (NOT) guessed the JWKs are stored in the database, so if you have multiple instances of mah meow meow server running, they all share the same JWKs and rotate… OH GOD THEY DO NOT ROTATE THEM AT THE SAME TIME GODDAMIT AAAGH.. the intention was there okay? I did that to, in one part, give more use to my job manager and, to let all isntances update at the same time but big brain me did not think that a job is always locked to the instance that picks it up. also the token endpoint now supports using openid and spitting out a ‘id_token’ with the user info (some claims are gatekeept behind the scopes [like ‘profile’ or ‘email’ duh]). that’s it actually, like i started really pulling my hair, fluff, feathers whatever because I was trying to overcomplicate it a lot and i really dunno why. like, for another example, i kept swapping from the ‘jsonwebtokens’ and ‘compact_jwt’ crates because I wanted to use ES256 but didnt want the other because i never used it but then ended up using the latter because it was easier, and then that I wanted to use EC25519 which is apparently not really talked about in the rfcs (that’s why i ended up with ES256! [also supported on compact_jwt]). AH! and also in the job queue, for the JWK rotation, I wanted first to add cron job for that but… why tho, I don’t really need it, I just need a way to NOT run a job until a specific time and then reschedule it inside the same worker. here’s the shitty screenshots showing the oh wow ‘openid configuration’, oh wowie ‘it does output tokens and id_token’, oh thats nice ‘it does give out a valid jwt with valid claims that the programmer didn’t even do themselves because they used a library called compact_jwt’ and wow ‘it does have a job that tries to autorotate if the current key is older than two months’:
I made the User Info handler for the open id stuff. that’s the end of it. It works, wahoo my self yay good job, even though you had pretty much bad scrambled code, you did it hahaha. It practically, as the openid spec says, returns the claims used also on the id_token. Soo, because its sooo close to the id_token, i’ve decided to just eat the that same id_token but spit out a converted version with things I want. I also added the typical OauthManager and RequiresOauth. the latter one not having a param to decide what scopes you want because, whhy would you want that?! its just a one liner and it may change for each hecking endpoint or even the data the endpoint returns. its just over complicating it with wrapped trash. … and about my devlogs, i realized that mine are pretty bad and not interesting like other people’s devlogs. i simply write weird and long ones. but i don’t want to write a simple “I did this, commits, hardness of implementing, whatever” in bullet points like other people do. i dunno it feels flat like this devlog. Here’s you typical SINGLE screenshot showing that the user info works, that’s it:
hi, hello i am space birb in the sad corner and i am here to tell you that i added the the typical oauth management handlers that everything has. I also added a generic paginated database thingy to be able to make… pages when there’s more than 20 items (rows). firstly, everything was easy. yes, no rocks not nothing that could set me on fire… minus that I HAD TO MAKE a paginated database thingy. WHY did i make it? idk man, i wanted because my bad coder brain thought that maybe someone could have more than 1 oauth application created (like a thousand) and that’s pretty bad for mr blue elephant database becuase that means eating 1000 rows in one go (and blue elephant doesnt like that, AND EVEN less if my vps has 1vcore and not really that much ram). SO, the best course of action was to make pagination to be able to cut in pieces the data and make it easier to load and handle.. even though the loaded rows are hardcoded (its 20 plus 1). The pagination practically works by seeing if there’s more data after 20 items (that’s why it has a “plus 1”!), if so, we take the LAST item’s id (using a trait to access it, because you can’t really know in what form or what id will be used in any database model) in those same 20 items to set the ‘next’ param. That ‘next’ param is used to.. quite literally say “hi, uh could you give me the next rows after this id pretty please?” and boom works and i didnt set my self on fire but i did ruffle my feathers a bit because of. Ill probably implement it to more places because the only places that use it are the oauth applications and user sessions because i am a bit lazy haha (i mean, its just C&P the current find_many* and use the pagination stuff and caboosh). oh god, i forgot about the oauth consent management. great job me, NOW IT ISNT COMPLETE “everything” great coder i am great big bird brain. My next plans are just to do some general cleanup with the openapi schema, add comments to the code and then start doing the frontend in mr sveltekit.. although i am too rusty in ts land and i will have to learn some stuff again and touch again scss and stuffies and god, i am going to get cooked in the sun and roasted like the space birb i am because of me no longer touching anything javascript. here’s your really useless screenshots showing the INCOMPLETE oauth management handlers and the pagination thingy working:
hi and welcome to my unreadable journals. I added those oauth authorized applications management handlers that I forgot to add yesterday, like the typical “oh let me see what scopes does this thing use… OH GOD IT CAN SEE MY fur color I MUST revoke it NOW!11”. Then I moved AAAL the handlers that touched ME user data to the.. obvious /me route so its prettier and doesnt pollute the air of the real auth related things. and did some cleanup in the http error department by merging some repeated errors. god this is one of the shorter entries i’ve made i think. next up is doing ratelimting, probably roles or just an admin api and the “hey your account has been locked because of repeated tries to login”. i dont even know what will it take to make tests work god. here’s your shitty screenshot showing my only progress, the oauth management bleh bleh bleh:
hello again, its a me, a random space birb that is here to tell you that I completly forgot about the ratelimiting stuff. BUUT, I added the admin methods and UserFlags to be able to set… flags. not much rodeo this time. had to think how i wanted the audit logs to work for the admin stuff. I first though about just having a bool saying “ah yeah admin” but meh, I think its better to have also an “actor_id”, the who did it user id, and boom. In the user side handlers for the audit log I just return the typical plain response of “yeah this was changed” (not sql joins, cheaper [?]) but in the admin side, I return the actor_id with some other things like the user login of the actor AND the user login of the user that was changed (cause why not!? its jsut another join statement in sql). Works wonderfully and even better now because before I had setup the user audit log to fetch AAAL the entries form the db and pee pee poo poo no, now that i have my paginated stuff, no way! SOO, the admin methods are just the typical ones, see what the user has changed or an admin changed from an user via its audit logs, the oauth applications and authorizations management and that’s it. I will probably also add a way to know globally what the heck is being changed but idk about that, seems a big sql query (that is tiny but very costly in db terms) and I frankly want to avoid that… and even more avoid using redis because i hate it and that SOMEHOW i have better some beautiful organized code vs the first version of this backend where I used the typical DB+redis aaand it was ugly . i hate that. I also added the UserFlags to be able to set flags like “is the user an admin?” or “is this user allowed to manage its oauth applications?” and so on. Pretty cool. BUUT as always, I had to C&P some code (almost all of it) from past handlers to make the admin handlers work lol. I would really want to make a central place to put all the common handler code but meh. IT WORKS! and that’s what matters. THe next things are just making the ratelimiting WHICCHC probably will be only inside the instance the user is reaching and that’s it. I would like to have global ratelimiting using the IP of the user or its account id but that would (i think) require redis… I really need to think about this because someone with a crappy toaster can make explode my poor baby vps. ps. god do I really take that much time doing stuff? god i am slow at coding. i am bad goddamit. that’s it. shallllll you see my shiitty api docs with the admin stuff and admin auditlogs becuase why not:
wow. that’s a long time doing nothing. I just updated the deps, tera had a change on its templating because it was rewritten from the ground up. pretty cool, now it kinda looks like jsx and at the same time not. I also tried or well… I am thinking about making my own ratelimiter but was like, ugh. I was practically mega blocked on the idea of wanting a ratelimiter that used the IP + UserId. Both are easy but for some goddamn reason I kept going circles and circles and honestly I dont even remember why anymore, like huh!? In the end I will only be doing ratelimits via IP because they are the easiest AND THEY DO NOT NEED TO be stored in the database. yes database, you read it right. IN this version of my backend I wanted to use the least things AAANd the oNly thing required is just the database to make everything. Adding redis would be waste (and waste of ram) for just storing the ratelimiter. Redis would be required if I wanted to run more than 1 instance of my application AND IF i wanted to distribute the info about “oh this guy is grounded, no entering the meow auth realm for 5 minutes” to all other running instances. BUTTT, as you might not see, I dont want to run more than instance nor want to distribute it to more instances if it were the case that I wnted to run more than 1 instance. Soo, I went in circles in my crapppy bird brain because to add ratelimits via the user id I would have to store the info somewhere that wouldnt be erased (like in the in-memmory storing that i will be using) or else the ratelimits would be useless because… THEY WOULD BE ERASED from this whole realm when the instance is restarted (memory goes boom to the void, so does the ratelimiter). That’s why I want to just implement the Ip based one, its the easiest one and the only one that I don’t care about loosing the information about the ratelimits when the instance is restarted. Also, i need to implement it yet lol i was just scrambling my head nuts and bolts hearing them clank while trying to ratchet them. ALSO², i need to redo the email stuff because my brain has came up with a cool design lol but first gotta do the frontend to make it uhh look good before suffering making the email components. I also started to hate the tera zed language extension. its crap. bad crap the worst one. ALSO, here’s your really useless screenshot this time showing code that you can already see on the github page (yay!1):
right, its a me! the teeny tiny waist sized space birb that is here to tell you that I added the ratelimiter! It works just as i’ve explained in the last entry, it uses the IP of the user to limit the amount of requests via a ticket bucket. THe bucket is stored in memory, as again said before, so if the instance is restarted, goodbye ratelimits. EAch request eats 1 ticket AND the bucket tickets and refill rate can be set via the… middleware. who would have known wow. It always adds the typical “x-ratelimit-limit” bleh bleh bleh with all the info you can like that is useless BUT hey, its there for you. I like making my own stuffies because its cool. THe root has a limit of 500 requests, refilling after 1 second. While the auth routes have a limit of 10 (sudo) and 20 (auth flows) requests, refilling after 1 minute. The other routes are just uhh protected under the umbrella of the root ratelimiter lol, no need for having to add a ratelimiter to every single route (god). that’s it. there’s no more devlog. Now what i gotta start doing is the frontend. I will cry a bit because I am VERY very VEEERY rustified in the typescript department like I never touch it but meh I MUST do a frontend or else this is incomplete… and i will do be crying if i send it off in a incomplete state. THE frontend will be in svelte kit, because its cool and ive already used it in the last iteration and it left me with a good taste in my forked tongue (hahaha, i am space birb) AND thanks that Ive been using from the start utoipa to add an openapi schema, I can use it easily to make requests from the frontend! and i didnt need to suffer adding them after everything was done just like in the past iteration! here’s your useless screenshot showing teh ratelimiter working and the headers and stuffies… god i am a mediocre at best writting long hecking devlogs for nothing:
oopsy. shoooort one, sorry. I added the forgotten oauth error StatusCodes and Descriptions. there’s not much to it lol, I just forgot about it. as always, here’s your even uselesser screenshot with code taht you can already see in the guthub:
a. hi there mr svelte! I was wondering if I should be drafting first a design in figma but meh. I like to suffer and make bad designs that progress very slowly to look mediocre at best! yay!1!! anyways, ill be using scss as always (i frankly done even remember anything about it lol) and sveltekit. HERE’S YOUR stupid “hello world” from slevetkt (reaaly useful devlog):
hi hello. oh, ive been 10 hours doing the same thing!!1 god. So, I was doing the frontend design without using figma and uhh yes. And also removed the ability to use your login to.. login to the app. You just use your email (otp, and passkeys). First, I forgot how to use figma, I only remember some shortcuts. I was going to use it (for frontend and logos) but seeing how struggled to make simple things, I only used it to swap the colors of the logo of MEOW AUTH, hmm yes, very meow. . The frontend stuff… I frankly ALSO do not remember anything.. or well I do now remember some things thanks to me fighting to uncenter a div hah. The stack is practically svelte, as always, client rendered and scss (sassy :o) for the styling. In the start I was just going to use the same styling and structure of my first iteration of this project, beepauth (ew), and after doing all of that I thought “god, this looks pretty bad”, soo I then tried to make it look a bit better WITHOUT starting from zero again. And I did style it a bit better but I didn’t even like it. Like it felt like I hadnt even advanced at all, like if the same shitty fricking backend was the same from the past (probably noone would care because probably uhh noone cares.) [brains a weired and even more mine i guess, wawa]. So, naturally, i did the less sane thing, REDOING EVERYTHING again. Had to watch tutorials to relearn how use sass and picked up also some new css stuff that I wont even use (minus the layers! that pretty cool!!). And from that css stuff I discovered Oklch.. yes i swapped my whole color palette to that using their harmonizer that uses the equivalent of WCAG, APCA (contrast bg to text!). At least the frontend now looks decent (or the first blocks fo the website). sadly the only frcking shitting heckign parts ive made are the login (and register BUT THATS THE SAME). AWIT WAIT WAWA, I also swapped some gears in the BACKEND! I removed the login (username) entirely, now its just demoted to a non unique display name (for openid!). you must be asking why, because I changed it to use the login not long ago. Well, because I don’t have to force a user to give me a username AND their email on signup. Its easier to just give the email. And if you already have an account and hit, without knowing (our typical autopilot mode), the signup page, I can silently make a AuthChallenge for login instead of signup because both handlers return the same result. Then, after registering, I just force you to set a display name (by default its just the email, i could leave it like that but currently I want it to force you set a custom display name for OPENID). By doing that, I practically removed the “vectors” (ooh hackiry stuffiry) for user enumeration [those vectors were the endpoints to see if a login (username) or email was already taken] (I also made so the login endpoint gives you a fake challenge id when the email doesnt exist {This works thanks to having the auth exchange handlers return “invalid code” even if the challenge doesnt even exist}). here’s your screenshot of a login page that looks exactly like very other login page, maybe even shittier (sorry i am bad doing these kinds of things.) [also you have the logo colors, i went with purple because it looks cool and its a cool color] {the “Psst, over here” its just a random greeting, just like the ones i have in the emails} [[sorry for wasting 10 hours doing nothing]]:
i am ashamed. i am that bad or… well ive gotten to the point of real badness and what some call “skill issue” because I CANT make this hecking frontend. its just too hard, i am just way more slower than before and what i though i was. i hate that i am not usign tailwindcss and isntead I am building my own scss styles IN @layer when i could have been using svelte components with the style tag but ugh bad decisions that can be still reverted i guess. For the layout of the settings, i even tried copying how I did it in the last iteration of this frontend (past server, not named meow auth).. i just did not like it because using a sidebar for this teeny tiny amount of information is wasteful (like this tiny [not really tiny] space birb). Like the content is just the typical name, email, auditlog, 2fa, passkeys, sessions, oauth authorizations and user created oauth apps AND lets not forget about the admin panel. i am practically suffering with mundane crap that anyone can have done in probably 10 minutes by asking mr claude or even chatgpt OR even just copying an already made layout, but here i am suffering trying to make stuff my own way, telling my self that this was the worst decision i’ve made goddamit… at this point i will really become a hotpot space birb soup.. i just need one layout made and then it should be an easy job to then copy and paste to other tabs. then the enxt step is to wire it up the forms and have it communicate to the backend which should be an easy task (i think [… oh god please be easy])… i know this entries of the frontend will make my project go into deflation mode and stuff, and i even broken a promise that ive made my self to not make devlogs that are more than 5h long because of a review someone made of my project when i submitted it unfinished to flavourtown (yes, flavortown) which is sad but it is what is. you cant be perfect, that’s why i have a shit hecking design. i am just bad, a bad space bird i guess. i already rambled too much in this suppossedly simple devlog. here’s your half crap “inspiration” that I used to (quite literally did a C&P of the page) of my past proyect using a sidebar (not what i want with this iteration) and the current state of art of my REALLY REALLY SHITTY curernt state page:
in the end i gave up in the design or well… can you even call it “design” when it was ugly even at teh start? yes, i tried my best at making it look “good” in my own eyes but i could not for the love of birds. it was bad anyways, like actually bad. I, to make it easy for my self and be able to copy how other people do it because i am a lazy bastard (stupid space birb that klanks its keyboard for nothing), will be using the typical two columns for each section. One for “what the heck is this section for” and the other for the actual content (wow). man, i hate how the frontend is where i struggle the most when the backend should be where i should have struggled the most, not with this dude. agh. I also hate HOW i thought the layout i wanted initially was the best one and that i look great when in reality it was an aberration that didnt even look good and it really threw to the trash the unused space bruh. it just wasnt for this job, maybe for something else.. idk haha, what I know is that I think it already looks better with the simple sutff ive done lol [that’s sad btw :)]. as you may see int eh screen shooting, the audit log section instead of having a table it uses a… placeholder for a button with the same content it has currently because I frankly i am scared of making tables because of the probable difficulty i will have (because I am already struggling with teh simplest of things!). ALSO, i need to stop making .scss files, compounded into a single css file using @layer and @use , to just use svelte components that use the style tag. it really doesnt change anything, but atleast i wont be doing “class=‘meow’” each time i want something, just using “” is half better lol (doesnt really fix anything, I just want to give use the svelte components). finally, i am planning to use “services”.. they arent really services but more about wrappers around the openapi client. less manual labor for some shitty stuff that i wont need to do anymore. Still, its just a wrapper with nicer method names and namespaces. (also, ill be adding profile pictures. didnt think i would be adding them tho) here’s the typical dumb screenshot of what i think that looks “good” without doing that much work:
haha 10 days later. no progress just me rambling and going in circles. I am a bad space birb. RIGHT! I just were converting the css stuff into svelte components using the style tag (and the preprocessor duh). That’s actually it, quite literally. No progress at all. Wasted time on, still, falling on the loop of trying to get something that “looks good”, but i dont reall know what i want in reality. ofc i try to get “inspiratainionion” from other websites and try to mix them together to then dislike the result, undo and rinse and repeat (at this point my fur and feather soaked hard on water). YOu may imagine it as thinking that you ahve a finish line when you done even know where it is. i will just try to make the frontend work first without thinking about the design… AND i cant even promise THAT! because i will probbaly spiral into the same loop once again (saying oh this looks bad blah bleh bleh). god i am bad at making frontends or evne design or everything, but thats how people learn haha. it is a lesson that i should learn from now on.. i keep judging my work too harsly but i dont know. frontend is just harder for me. here’s the useless non functional three pages that atleast have something layout:
would you look at that! Finnaly some functional pages with forms, ALmost finalized components… oh they are just the login pages….. and its not even all of the auth pages, just selected ones so the auth flow barely works. BUT, THIS fLuffy (not fluffy) space bird has finalllizated converting (or thinks) the classes i had as global styles into beautiful svelte components with all those stars and happy things. happily, i am longer limited by having evertyhign in global space.. oh right, RIGHT. i wasnt even limited :). AND the coolest compponent of all of them is the spinner one because it spins. The first pages have been plugged into an outlet called SuperForms (not really super, mostly helping to validate)! thanks to that, we now have working forms that post to the backend! with all those classic things, red colors and form validation. but, how I THE unfluffy space bird is pushing envelopes with the form inside of it? by talking to my backend obviously! but not manually (doign every step each time manually), by using a library like the trusty openapi-fetch that eats the openapi schema of the server i used in the past iteration. BUT i trashed it into the.. trash because I was fed up by having to repeat a thousand times the same snippet of code in each form or even page (I could have used a service like class to make it easier tho!). it was swapped by Orval! Orval works with the same openapi schema BUT gives methods! No more repeating the same things, just use the method and boom. and also that openapi-fetch was mad that i used a more recent typescript version. ANND, finally, the auth context was upgraded with a leg made of clay so it can now parse the BITENUM flags of, for example, the user (UserFlags) that tell what is enabled and what is not, if you didnt remember. Its practically a generic class with everything that i considered necessary that must be extended to be able to use it. and that’s it. you may watch the shittiest video ever that just shows that it kinda works with the forms and logging in and that’s it with still mocked things:
well hello again. space birb presents you the next devlog. I cleaned up the forms a bit (they are a still bit TOO messy ugly but they do work), REDID the ugly flags class to be a more EEEASIER TO WROK WITH (i dont even know how it worked before lol) and FINALIZED the auth pages! RIGHT right, first frontend. I finally finalized the most basic and empty and everything pages of the frontend! wahoo mee :). these pages practically include the otp one and the 2fa one (+ recovery).. and i just realized that i forgot about the passkey one, great so now it isnt finished (fried space bird thingy). Redid the pin component so it works with my Input form component AND also fixed some weired quicks of the pin component in phones (for some reason, my phone, didnt respect the max lenght of the input. i just sliced the value of the input on my max length lol). And finally, the frontend now has the most precious bit of any… i dont know. i just added the typical dropdown componetn for the avatars (yes, this was important for me). while on the backend, because mr past moon made some weired decisions, the 2FA recovery code generator and giver of the code the state was a messy mess that I frankly dont know if I even tested it, because it accepted wrong codes? i dont even remember if it worked haha in the past BUT now it works as it should and its at least better readable with normal method names (not plainly “recovery” [… what does that mean anyway!?? you would need to look at the code to understand it! and that’s bad]). ah, the typical moment has arrived, the one i always repeat. HERE’s your happily working auth pages for once, plus the “want to retry the email sending?”, the passkey one is still missing but that’s just slapping some paint (and painting my self) and boom (whhile this is practically the same as the past devlog, it just works better than the past devlog lol):
would you look at that, 10h… i love wasting time. Now THIS thing fetches some bits of data like the audit log, my passkeys, adding those and even modifying the username (you are forced to do it)! BUT big buty, i had to add the mr /signup/complete where you set your prefered username, like moon (its a me!), or else the backend will straight up refuse anything you want to do. AFTER changing it, you can do everything else a normal user can [by Default the username is just the user’s email AND THAT IS NOT PRETTY AT ALL >:(] FIRST OF all i grabbed my magic cup for tea and made the audit log page (it does not even have anything special)! .. oh right, for that i needed to know how the heck you even send requests with tanstack. so uhh,, blah bleh bluh wawa BOOM i now know how to call a method and get my data back AAnd even make infinite fetchers (IT kinda hates my way of giving data [its wrapped in {3} onion layers {request.data.data.data}, the ones that make you cry a bit]). i also synced my auth state with the tanstack client so it doesnt do two trips every time. okay now. TO make the audit log thingy, i did some beautiful matching so the type, creation and guy who did the action (probably the user) are actually human readable with a limit of 8 items (or else the /me page would be as long as this project’s crappy devlogs). When there’s more, a beautiful “view more” button appears (separate page). For this, so called “view more” page, i used the infinite queries. while at first i just puuushed the data into the dom with the #each (svelte thingy), chrome do be VERY very mad when there’s a lot of entries in there (The audit log, because it logs actions in your account, can get very huge. Because actions like the baddie Session action logs each time you log in or log out), SOO i did what someone whose browser is eating more than 10gb does, using a virtual list to render the it! (IT only renders items when they are visible, hidding [removing from the dom] non visible ones. this fixes the “OH gosh THOSE 200 things THAT I CANT EVEN SEE, ARE EATING MY precious ram”). OHh and you can press ESC to leave the page because i made a cool component that lets me plug in a callback for specific keyboard events :D. SECOND, the passkey stuff. yeah, pretty easy thanks to libraries like SimpleWebAuthn that do the hard work of telling the browser “hey, authenticate this guy please” or “hiya, registrate this passkey please”. its just querying what passkys you have to know… hwat passkeys you have and that’s it. BUT sadly, an actually sadly, my passkeys are non resident (I cant have a simple button to just login, I need you email before i can use the passkey). Thaaat means I havea teeny big tiny small user enumaration problemo becuase the backend can reveal that an user has a passkey registered and, in turn, we know that user is registered. a bad guy can just atack with “oh noes, your passkey has been stolen. pls give a undecillion of moneys”. third, i had to add the sudo page. It does what you think, reauthenticate to do sensitive operations like adding a passkey. Pretty simple, it redirects directly to an email code if the user does not have a passkey or totp enabled (email code is always enabled), if they have those, it just shows a selection screen. fourth, i had to fix up some stupid things with the api schema of the backend becuase I either forgot to put a body on the responses (like the passkey/webauthn routes) or just fix up a teeeeeny tiny setting thing that wasnt correct (its the webauthn/passkey rp_origin [allowed pages to register/use a passkey} becuase it jsut used the backend url and THAT is not correct). so tahat’s it, shall you see some stupid screenshots and not even a video because i havent even finished everything:
hi hello this is space bird. i have eaten 9h hours of real world time in just making the dialog component. I mean, IT WAS for making the 2FA prompts for when you wanted to enable it or disable and bleh bluh.. atleast it does look great… and i still need to add icons. the prompt is just the typical 2fa enable that gives you a qr or the 2fa secret if you cant scan the qr. The dialog component was pretty much made in nothing, in air time (free :D). the thing that took a bit was just the styling BUT WAHT did take a BIG LOOOT of time was just making the 2FA dialogs. lik gha damn hecking “2FA prompt” and “beep boop enabling dialogs”.. why?! becuase they are PACKED like a lasagna with forms, tanstack fetching, dialog steps and other stupid stuff to make it atleast not confusing for the user to navigate with tree sized buttons that dont work (becuase you are on the wrong step!!!!1 or already did everything lol). i mean, besides that custom stuff, it just reuses components like the pin or qr svg and… for now, also uses the spinner icon on the buttons you click to manage 2fa as i couldnt be asked to add real icons for now (leaving them for lasts). next up working work is more dialogs (for the passkey setup [so it isnt just a spinner without any “magic guideance”]), a collapsible comp to wrap the info items to show EVENTUALLY some metadata like, in the session items, browser, ip, what user was that did that thing and etc. Its just so i dont balloon the “info items” BECaUSE they are supposed to be some kind of “quick info”. broom brroom, i love wasting time on these stupid things (and wiring them!) >:3. LEAVING that tiny goofy work that apparently took hours to do. I am thinking and WILL be doing a beautiful swap into using resident passkeys (the ones that dont require me to know the user’s email in advance). yes, i know i said before that i dont wanted and ew ew resident. but man, its just easier for the end user to click a magical button to login directly. AND AND this even protects me from someone slapping the meowbackend with the email fish to see who is registered (with a passkey) by checking if the user’s email makes the selector appear. still, some part of me still thinks this is really bad idea but i want to do it tho… what could go wrong hah! i might aswell go to the cooking pot already and make some uhh chicken soup made of space birb. that’s it, i still feel like i havent done anything. Here’s your beautiful video of showing the beautiful dialog going “hi” “goodbye” (the video shows me enabling 2fa, viewing recovery codes and disabling it [with a recovery code]):
hi hello hiiii, stupid space birb back from long bed sleep break. CATCHING UP, i have swapped to resident passkeys, fixed jwk refresh feature not working, beautified toml settings, added 2fa replay protection and audit log beautification. alright.. prepare for a long boring devlog as always. I finally swapped to resident passkeys after thinking about it for days (hours)! That means.. NO MORE user enumeration problemo with passkeys, yippie. it wasnt really a pain in the feathered buttocks, like it was just enabling a crate flag and boomy boom (and it even works on the frontend!). also, i patched with scotch tape a stupid buggy bug about the email templates, becuase I used a lazylock to store the email templater engine stuffy, when SOME random goofy template or data was wrong for whatever reason, it would poison the lazylock and the next time it was used it would just say “oh noes, i am broken, poisoned my childs. GO HECK YOUR SELF”… i just fixed the template part by checking if tera likes them in the global state creation. i love scotch tape, it smells great. while doing that, i finally addressed the beautiful jwks not updating on all instances because in MY JOB QUEUE only one running server instance can eat the job. that means, if you have 2 instances running, the one that is the unfortunate one that didnt eat the job will have stale jwks until the next time it is restarted. fixed it with some beautiful blue elephant database screaming “HEY GUYS, THE JWKS HAVE BEEN UPDATED” and the other instances will be like “oh, okay, i will update my beautiful jwks now”. finally, 2fa, or as i like to call it, TOTP, has been taken cared like a baby and then thrown again to the battle field after giving it the power up of replay protection. That means, if you use a code, it will be marked as used and you cant use it again (this only works with valid codes). makes you wait more smh. THE SETTINGS got a layer of microscopic makeup because i was like “man, these setting name are weired? what if the settings file had comments to know what the heck is this beautiful knob named ‘do_not_touch_this’”. yes i did that. it was a big red booty pain as i had rerereremember how to do proc_macros and how the heck did i even update the toml files with new entries without making them implode with gibrish. AND WE ALL KNOW NOW that ‘do_not_touch_this’ is a setting that if you set it to true, it will make this space birb implode in flames and become dust (yes, like a real firework going CHIRPAAAAAAAAAAAH pop ). and the final thing given some body work spray was the audit log. no more caveman moonbeeper style ‘log’ method with a thousand things. now we have the SAME thing but as a builder with a ‘save’ method. it just makes the code easier to read and understand. also, the audit log now has a “what resource¿” and “what ip?” and i removed the audit entry making from inside the auth helpers to outside. it was just an inconvenient place to put it, i dont evne know why would moonbeeper put it there… oh right i am moonbeeper. I DID IT BECAUSE it was a great place in those times. alright, HERE’s your typical bad screenshots that are trashign and god i am sleepy:
pew pew cabosh, wawah space birb is very sleepy. BREAKING NEWS, i added and changed a lot of things so i could make a delicious soup of changes that changed my old changed code that i yes. minimal frontend work called making the passkey section button go crazy with colors, authenticator icon (just search “aaguid explorer”, its not crazy work) and having a dialog telling “hi do you want to rename this, no? okay”. I also have collapsibles that hide info from your lil nonfluffy face when its useless. Now my crappy server knows from where you are connecting (who would have known that a server could know that) and where you live (oh no [its approximated from your ip]). THe latter only works when the instance is proxied under cloudflare (it even gets mad if a request doesnt have the headers it wants when you have enabled the “under cloudflare” mode). the audit log single method to do everything™ has been swapped with a builder (i love this), AND its info now includes that same ip and location (actor related [who did it]). all fields are now obligatory for… audit log purposes, because before i just pushed null on the db for things i didnt want to show the user MAKING a pretty stinker audit log that does not show who did what. i really dont know whata past me thought, because you can keep everything on the db and just show what you want to the user. idk, past me thinking in uhm not portals (yes). okay, more slurry of things. mah beautiful fix so the JWKS (signing keys used to… sign a jwt! [important for OpenID]) update when the database JWKS changed, spammed the hell out of the db and log as it polled instead of waiting for the db (or an instance) to say “I UPDATED IT GUYSS!1”!1”. This comes from the instances cache’ing JWKS instead of saying “could you repeat that” to the db (too many requests = blue elephant cry and explosions), so they need to know when the db changes or THEY WILL BE out of sync!! mr past me also thought that it was a good idea to store the oauth token code (used to get an access token) in plaintext in the muffing db, SMTH YOU SHOULDNT AT ALL DO. now its just hashed via hmac just like everything else. man i am GOOOD at this job of so called programming, having to go back to edit a thing i called done AND then HAVINGTO edit and edit and edit. this is so fun that I WILL BURST into FLAMES because of how stoopid i am meanwhile, you also have me deserving to be cooked with rice because I made a condition in the oauth token exchange that when SOMEONE somehow miss types or gets access to the oauth token code but has the wrong client_id, the temporary code gets deleted… and you know what i forgot? i forgot to commit the changes to the db, so the code never was deleted lol. i love these kind of stupid goofy pain errors that arent even errors. AALSO I reprettyfied the oauth helpers because after working on them a long time ago, i didnt know what were they doing and it wasnt fun nor funny >:( [i was mad {i am still mad, with that space birb… i want to sentence past moon to sad corner jail for 12 seconds}]. NOW teeny tiny additions!“1 the ratelimiter now exposes a “Retry-After” per a hacker news old moldy article i found, plus exposes its headers on cors. the audit log now does its job even in more parts! now it also tracks the totp recovery code usage [i frankly forgot about it :(].Changing your email or name now requires sudo minus the name on register. AND the app startup has now a beautiful banner saying “meow auth” in cursive. its pretty :3, makes it stylishinning. I also moved and added to the service manager (the watcher) a way to have service names and to launch services from inside of it (for some reason i used a method that was outof place for ages lol). oh no my time has come nnonono, i give you permission to see my trashy work in screenshot format (so modern)… yet i shall push towards completion of this meowing meow meow authing meow auth server:...
|
1792738089.8583465
|
1793342889.8583465
|
|
20497
|
ScreenExtend by @epiccodewizard | Stardance
|
epiccodewizard
|
1
|
129.27
|
158
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-01T23:47:06Z", "hours": 55.0, "multiplier": 15.76, "payout": 158, "blessing": "neutral", "text": "Initial release for ScreenExtend! Please give feedback and read the initial devlog (shorter one here, longer one at https://github.com/ScreenExtend/ScreenExtend/blob/main/DEVLOG.md ) for detailed information.", "repo": "https://github.com/ScreenExtend/ScreenExtend", "demo": "https://screenextend.app/"}]...
|
[{"post_id": 60703, "ts": "202 [{"post_id": 60703, "ts": "2026-09-03T08:05:38Z", "hours": 9.5622, "text": "One step closer to finally shipping…or so I hope. I speedran shipping this next feature, so it took a lot of time. This feature is mainly for myself. I have an old Mac (running 10.13 from 2017, really old I get itttt). I want my app to run on there, but it currently only supports 10.15+. Hence, I went down a funny rabbit hole in an attempt to add support. 33. Cleaning up dylib signature lookups at run time One of the key challenges I faced throughout development was how to have a unified codebase for multiple API versions. I decided that instead of version-gating APIs and guessing which beta/normal versions they would be accessible on, I’d test for APIs at run time. I changed VideoToolbox to use this logic: it would attempt to set/use APIs and variables available at higher runtimes, but would work fine without them and have fallbacks. This ensured both legacy and modern systems functioned well. 34. Airplay automations…? As I was doing competitor research, I noticed many of the other apps supported Mac 10.13-10.15 as well as 10.15+, while mainly only supported 10.15+. Essentially, they started a fake Airplay server, had the Mac connect it, and set the display mode to “Use as separate display”. This would create a virtual display that the app would then use for its own functions. As ScreenExtend requires its own display on older machines, similar to this, where CGVirtualDisplay isn’t an option, I decided to use this method. I had my app automate opening the Airplay menu and connecting as well, in addition to running the fake server. Most of the process was straightforward, especially due to the abundance of fake Airplay server implementations online and my own experience with apps like LonelyScreen. The one issue of this approach is that only one display can be connected at a time, so any tertiary devices wanting to connect have to wait their turn. I guess the only option is to by a new mac then… 35. Client UI update cleanliness fixes Due to the one device restriction, I implemented a separate page that would be served if the display slot was being used up. It would be coupled with a short message explaining the consequences of the older Mac version. There were also bugs related to session teardown (keyboard still being locked, video stream still active in the background, etc) that I quickly squashed after finding them. Soooo in hindsight, I prolly should’ve bumped this up to 0.6.0, but I left it at 0.5.4. Oh well, I’ll increment the version by next release. Only a few more features to go on the feature list before hitting v1 and shipping!!!"}, {"post_id": 58576, "ts": "2026-08-31T01:22:07Z", "hours": 12.0222, "text": "Oh my lord, I keep forgetting to write devlogs every 10 hours and am losing hours on each one. Nevertheless, I finally finished audio work! Plus some other things like running claude security agents on the code base and patching stupid vulnerabilities. Here’s how the week went: 28. HiDPI and Mac Issues Whenever I use my Mac with ScreenExtend, the stream looks blurry due to Macs having HiDPI screens. I fixed this by adding basic HiDPI scaling on Windows. The UI has a DPR slider based on autodetected values. This DPR is multiplied by the screen resolution for a shaper display. One issue that arose with the new displays was the fact that the display would randomly not scale properly, so the task bar and apps would appear tiny. To mitigate this, I reapplied all display settings after resolution changes and a timeout. 29. AUDIO WORKS!!!! For the longest time, I tried getting audio to work. On Windows, the process was straightforward: a WASAPI loopback system audio capture session. I wanted to build my own custom driver to capture audio faster, but this would be too expensive to deploy. I read other Rust implementations and quickly wrote the code. On the other hand, Mac was a whole different issue. On older versions of Mac, system audio recording is not supported. Hence, for Macs below 13.0, I wrote a custom audio driver. I didn’t have a clue about implementing an AudioServerPlugIn on Mac, but worked out the specifics by looking at the Blackhole audio driver. I did have to proxy physical volume buttons to work (i.e. I listen for taps and change the audio level within the driver). For older Macs, I used ScreenCaptureKit with an extra audio flag. This was a simple fix to capture audio. On even newer Macs, there’s a Process Tap API to record system audio with low latency. Once again, I didn’t have much difficulties implementing these due to the abundance of documentation. 30. Streaming Audio over WebRTC (with A/V sync) When sending video and audio separately, the two are prone to fall out of sync, so watching movies or videos is difficult. To mitigate these issues, I wrote an A/V sync host clock. This packages the time on the host clock to audio samples and video frames, such that they can be reconstructed and coupled on the receiving end. On the browser side, I began by implementing a basic audio streamer with an audio element. However, similar to video, there’s always a faster method possible. I used the AudioDecoder class from WebCodecs to implement a worklet class and jitterbuffer. In simple terms, this would decode audio on a separate thread, like WebCodecs prefers, and send the audio back to be played to the user. 31. Windows Video Encoding Speedups I made a few encoding speedups on Windows targets: The NVENC capture encode system uses a texture ring implementation: a pool of 3-5 encoder instances paired with a frame queue, allowing multiple frames to be encoded concurrently BGRA encoding is done directly in the library instead of using a third-party implementation Unchanged frames in DXGI capture are not encoded again, reducing CPU load 32. Mac Video Encoding Speedups I made a few encoding speedups on Mac targets: Request LatencyCritical activity for the session to ensure App Nap and other sleep measures don’t affect the thread Analogous to DXGI, skip encoding when CGDisplayStream reports no dirty rects Not an encoding speedup, but preferring 5 GHz for Mac hosted networks to ensure higher speeds Lotta stuff done this week, am I right? I made lots of progress and finished the bulk of my features, although Linux support is still in the works. I’ll make the 1.0.0 release soon and start a Stardance ship as well. I’ll likely add Linux support after 1.0.0, as I need to research EVDI and the WSL display compositor, as well as other minor tweaks for Windows/Mac. See y’all in the next devlog!"}, {"post_id": 54119, "ts": "2026-08-24T22:53:29Z", "hours": 12.6531, "text": "I speedran shipping a buncha features…in the span of a few days. I logged a copious amount of hours on Hackatime building random stuff. I tried some things with recording system audio and building a driver…those didn’t go the best, but I’ll cover that in the next devlog. Here are the main changes this week: 24. Even more quality of life changes Compared to last time, I wanted the user experience to improve even more. Specifically, for the Windows client, a custom display driver is required. On Macs, the functionality I need is built in, so none is required. However, uninstalling this display driver used to be a pain for users. Now, I bundled it as part of the uninstall script. I wasn’t sure how to do this, but Tauri has many useful guides and issues opened regarding custom WiX/NSIS code. When the window isn’t focused, join and leave notifications are toasted. This allows the user to stay informed even when the app isn’t open. Basic feature but very useful. I’d often get annoyed that I needed to keep re-entering the password to log in to a previously connected device. Hence, I added auto-join for devices based on their IP. This ensures that commonly connected devices can save time when reconnecting. 25. Onboarding screens The app is intuitive to use…or so I thought? Some of my beta testers were confused as to the various features and how to use the interface. Hence, I used NextStepjs to add onboarding components. This would dim the UI and only highlight the component being displayed, along with a message next to it. I liked the styles of NextStepjs a lot, so I chose it. There were some issues regarding window resize, so I made the onboarding exit and reopen to the last step when the window is resized. This way, the positioning of elements was forcefully recalculated. 26. Random security fixes My app had various vulnerabilities scattered throughout, so I ran a vulnerability Claude skill and patched some holes. The main issues fixed were: Checksums of bundled DLLs and resources are checked before being pushed to GitHub Actions Tauri CSP and allow list are actually enforced instead of being set to allow all TLS cert used for hosting the HTTPS domain has more secure file system permissions to reduce unwanted tampering of files Devices are trusted by a uniquely generated token, not by IP, to decrease the chance of impersonators 27. Command-line interface A majority of the time on this devlog was spent on the CLI. It wasn’t that hard (from a technical perspective), mainly just translating a lot of the UI code into Tauri CLI commands and mapping them correctly in the generated JSON file. One of the harder things to figure out was setting up cross-thread AppState, when the app wasn’t exactly running…turned out I just had to move the initialization command to before the window is created, so it would run inside both CLI and GUI modes. To present the QR codes better. I used qr2term to display the QR codes. By default, all logging is hidden. This turns ScreenExtend into a clean CLI mimicking the GUI. Hoorah! That’s it for this devlog. Not much to conclude, but plenty more features coming. Stay tuned!"}, {"post_id": 51902, "ts": "2026-08-21T20:12:46Z", "hours": 10.3639, "text": "Oh my lord…I crammed a lot of features into this week. I have yet to do proper audits of the codebase as a whole, specifically related to latency optimizations. I added a lot more code that affects the WebRTC pipeline, but I at least got the core features working. 20. Automatic updates For a while, the app relied on manual updating. It would check the latest version on Github, but users would have to go to the website, download the installer, uninstall the current version, and reinstall the newer version. This also messed up config and was a huge pain. Hence, I generated my own signing keys and used the Tauri updater plugin to automatically update apps. When the app is first launched and if an update is available, it automatically downloads and installs it without any user action. To make this more robust, I added a progress bar while downloading the update. On Windows specifically, the app must be shut down and restarted, so a blocking modal prevents devices from joining till this is done. I originally made this modal manually, but switched to using AlertDialog from ShadCN. Another issue I faced was the latest.json manifest. As I used custom filenames when downloading and installing updates, I had to manually patch the JSON. I learned a lot about the Tauri updater Github action through this, as I had to figure out how Tauri generated build filenames and how I could safely update them. 21. Quality of life for client devices I finished QOL fixes on the client side: Remember past devices to quickly import preferences or ban devices (all config saving is IP-based) Warn if the user is attempting to connect from the same device (this app is a remote control tool, but you can’t exactly remote control yourself) If the screen orientation changes, the virtual display is updated accordingly using CSS media queries to ensure a seamless experience A no fullscreen mode was added so users could quickly switch apps and maintain productivity 22. Quality of life for host devices I converted all in-app modals and error messages to JSON. This allowed me to add i18n language support, so I could easily translate my app to other languages. To detect and ensure only a single instance of the app was running, I previously used a file lock. However, there was an issue with MSI builds falsely detecting a file lock and not opening. I switched to a basic TCP model for IPC so that multiple processes running can figure out which was there first and shut down the others. 23. More more more Mac features! I’ve always felt a bit sad for my Mac users. I don’t have a Mac to test on, so I keep borrowing my dad’s Mac, which results in insanely slow development times. Nevertheless, I made some serious progress this week. The biggest thing was a simpler installation process. Many users would complain that they didn’t remember if they’re on Intel or Apple Silicon, so I now distribute a universal DMG. In terms of the app itself, I added a permissions check for screen recording and input injection. It would run a live test of screen capture or key input to see if the app actually had permissions; therefore, down the road it wouldn’t cause issues. I initially tried to do a soft check without an actual test (i.e., read the settings app), but this didn’t work. The only foolproof way was to call the API itself. The biggest feature by far was adding Mac input injection. Using accessibility APIs and a charmap similar to Windows, it would inject input onto the Mac screen. I could remotely log in from my Chromebook and get a lot of work done. I mirrored the structure and code on the Windows input injection pipeline, so no major difficulties here. That’s it for this week! Lotta stuff added, especially for the Mac users. I have a long list of features to continue building, specifically regarding easier Windows uninstall processes, onboarding, and an overall better UX. See you soon!"}, {"post_id": 39065, "ts": "2026-08-01T19:07:47Z", "hours": 9.8208, "text": "I had so much fun at the conference in San Francisco! I met a lot of cool people who gave me advice on the app, although I didn’t see the downloads spike 😭. I primarily began working on a SW encoder and other miscellaneous changes: 17. Remote control toggle Sometimes, the user doesn’t want a client to have remote control access. Although the purpose of the app is to have remote control, it is useful to disable this feature. On the frontend, I added a toggle switch that enables or disables the remote control backend. I was debating whether WebRTC negotiation was required as well, but decided to do so in the end. The remote control used data channels, so an unused data channel would result in slightly lower latency. Renegotiation ensured the stream stayed as efficient as possible without sending redundant data. 18. Update checking In order for current users to access newer versions, I wanted to add an update functionality. I’m not using Tauri’s update plugin just yet, so I run a simple check. The app, on startup, checks the latest release tag on GitHub. If it’s not equal to the current version (rollback or higher version), the user is prompted to download the newer version. Automatic updates will come next. 19. The big boy: software encoding This one’s been a long time coming. A lot of machines like VMs or computers with a weird setup just don’t have a working hardware encoder (Intel/AMD/Nvidia), and until now that meant the app straight up didn’t work there. So I built a full CPU-only x264 fallback. For the pipeline, the frames come as raw BGRA bytes that the other supporters already encoded. They must be converted to I420 before going to libx264, whose build I pulled from OBS. As a side note, the DLL is bundled with the app at runtime to ensure no missing dependencies. As with any encoder, the rate control is ABR with a tight VBV, as well as an infinite GOP. Besides the technical jargon, this just means latency is the north star and nothing else matters. The whole software variant is added to the encoder vendor enum, and wired into the fallback chain: if NVENC fails, try Intel; if Intel fails, fall back to software before giving up entirely. There’s also a manual override if someone really prefers software encoding, but this is not the default. There’s a big CPU cost compared to hardware encoding, so it’s very much a last resort and only kicks in if absolutely no GPU encoders are available. But “last resort that works” beats “doesn’t work at all.” That’s it for this week! I plan to have some smaller quality-of-life changes and better updates coming soon…"}, {"post_id": 34237, "ts": "2026-07-24T19:29:18Z", "hours": 9.1139, "text": "Sooooo this devlog is mostly comprised of website changes. I have a conference in San Francisco and wanted to polish up the app before publishing. Here are the main changes I made: 13. Random chores and updating the website I absolutely love shadcn-ui, but so do AI models. In past reviews by stardance raters, as well as family and friends, they pointed out the website looked AI-generated. Hence, I decreased the number of gradients and added basic animations to make the site feel more alive. This was a first for me to implement animations, but the Tailwind docs made it quite simple. I used a specific code-like font instead of the generic fonts I had and tidied up CSS classes. The biggest change was adding a blurred-geometric background for a nicer feel. 14. Redesigning the website completely I felt it was better to update the website as a whole, so I changed up the user interface. When I tested the app with real users, they complained that they didn’t know how to actually use the app. I changed the hero design to have clearer text and added an SVG-animation component showing how the site actually works. The feature section stayed the same, but there was a highlights grid (inspo https://cider.sh/ ) to highlight the main features. The FAQ was shortened to my liking, and I pulled some utilities from Tailwind for animations. In terms of images, I updated the images of the app featured on the website and cleaned up some of the dimensions related to that CSS. The old homepage still lives inside OldHome() but isn’t used anymore. 15. Tidying up the README and build workflows I edited the README to remove redundant information and make it more developer-focused. I also updated some information regarding GPU builds. For the build workflow, I ensured it would only run if the commit ended in “rebuild”. This ensures unnecessary build minutes are not spent on small changes not requiring a full rebuild. 16. Wake lock API fallback This app aims to support all devices, but older devices have…funny APIs to say the least. For WebRTC, I implemented the legacy encoded streams API. However, the device would still turn off for seemingly no reason while the video was playing. On older devices, the wake lock API is not supported. However, there’s a unique workaround for this: any video element playing on the webpage will keep the screen from dimming. Hence, I used the NoSleep library to create an off-screen 1-second video element that keeps looping, ensuring the display doesn’t go dark. Some very fun stuff with browsers. That’s it for this devlog! Mostly minor changes, but the next one will have better SW encoding support among other changes. Stay tuned…"}, {"post_id": 28772, "ts": "2026-07-15T08:02:33Z", "hours": 10.7358, "text": "I met with some friends to discuss my app…and realized I gotta lock in with the features. Among the various topics we discussed like the difficult UI or lack of automatic updates, they really wanted remote control features. So, I set out to make the remote display something I can actually touch, click, and type into. And patching some other bugs along the way. 9. Remote input This is the main headline feature. Streaming pixels one way was solved; now the client had to send input back up the wire and have the host replay it as if it came from real hardware. Host side (Windows). A new input backend injects events through a synthetic pointer device , so mouse, touch, and pen all seem real as opposed to faked mouse moves. The synthetic device can execute touch or mouse movements from the tablet client. macOS and Linux backends are stubbed and will come later (trust me bro). The wire. This side had to be optimized for dead-low latency like the rest of the project. Instead of passing strings or using some wrapper library, I made my own binary protocol (a dedicated protocol module) serialized over WebRTC data channels , not the media path. Client-side input.js captures keyboard, mouse, pointer (touch/pen), wheel, clipboard, and drag-drop and ships them across. The code basically catches every single frontend input event and forwards all those events (20+)! The routing is latency-first, same as everything else, with three different paths. fast-path events (pointer moves, wheel) take an unreliable channel , where a dropped packet is cheaper than a late one, while clicks, keys, and clipboard take the reliable channel where every event must land exactly once. It’s not that big of a deal if one small mouse delta doesn’t go through, but it definitely is a big deal if a click doesn’t go through. 10. Browser compatibility detections Not every browser can do WebCodecs, secure contexts, or the input paths above. Rather than fail silently, I added a compatibility check on both the browser and client up front. It shows compatibility modals with per-feature lists to ensure the user knows what’s going on. 11. Some more small fixes I added two quality-of-life additions: avatars (upload custom profile pictures) and zoom controls (ctrl/cmd +/-). 12. Encoders that don’t explode when funny stuff happens Oh my god…one of the biggest issues by far. When I ran the NVIDIA encoder at high FPS, it didn’t crash. However, the Intel Quick Sync encoder would arbitrarily crash at high FPS and wouldn’t give a reason why. I audited a buncha different parts of my code and eventually found that FPS was the issue, not resolution or low-latency flags. Hence, I added a binary search that probes the hardware for its true maximum supported fps and clamps to it before the encoder can choke. Essentially, I ask the encoder “can you do 1920x1080 at 240 fps?” –> “no” –> “what about 120 fps?” –> “yes” –> “what about 180 fps?”. This keeps repeating till the max FPS is found and streamed to the client. Rounding out the release, I made a variety of different UI fixes like the modal fixes , backdrop overlap, a stray uninstall-modal backdrop, and cloud reconfig errors . More progress to come!"}, {"post_id": 20389, "ts": "2026-07-01T23:35:58Z", "hours": 54.7942, "text": "ScreenExtend Devlog: Building the Rust Engine Under a Wireless Second Monitor TL;DR ScreenExtend turns any device with a browser into a real, wireless extended monitor for a Windows host, no client app and no cables (it began so my brother could use his iPad for notes at debate tournaments). Scan a QR code and the host spins up a real virtual display, streamed over WebRTC with hardware H.264. The React/TS control UI existed before; everything else (Rust core, GPU pipeline, WebCodecs client, cloud relay) was built from scratch , always latency-first, quality-second. 1. The spine: Tauri + a typed Rust↔TS bridge tauri-specta exports a fully-typed src/lib/bindings.ts for commands (TS→Rust) plus typed events (Rust→TS): devices, network, cloud status, logs. A code-generated bridge beats maintaining one by hand. Let the code write itself! 2. Virtual displays: faking a real monitor Each client gets its own virtual display the OS treats as real hardware, a true second screen, not mirroring. On join the host creates one sized to the client , forces extend topology, then captures it once attached. On Windows a signed IDD driver installs at runtime (via nefconc + certutil ), and it tears down cleanly on leave. 3. First light: WebRTC + WHEP + H.264 The media path is WebRTC (real-time, in every browser). Signaling is WHEP : the client POSTs an SDP offer, the host answers in-response, no signaling server. Codec is H.264 , universal hardware decode on clients and encode (NVENC/QSV/AMF) on hosts. The first release streamed NVENC to a plain <video> ; it worked but was laggy. It binds HTTP + HTTPS (self-signed via rcgen ) , since WebCodecs needs a secure context. 4. The pipeline: capture → encode → broadcast Capture is Windows Graphics Capture (later a custom fork; DXGI Desktop Duplication fallback), with a repeater thread for idle keepalive/IDRs and transient-stall tolerance. 5. Going vendor-specific: the part that made it fast Generic capture→CPU-copy→encode is slow everywhere; the win: keep the frame on the GPU from capture to bitstream. Per vendor: NVENC (NVIDIA): no SDK linked (API dynamically loaded ); zero-copy writes capture into a shared D3D11 texture behind a keyed mutex, else a CPU bridge. Intel QSV/oneVPL: same-adapter capture+encode fuses the downscale into the VPP pass (BGRA→NV12 + resize in one shot). macOS (VideoToolbox): ScreenCaptureKit (12.3+, CGDisplayStream fallback) via objc2 runtime interop only , so one binary loads on every macOS version, same IOSurface zero-copy. 6. The client: WebCodecs over <video> Fast path: an RTCRtpScriptTransform feeds a worker VideoDecoder ( optimizeForLatency: true ) onto an OffscreenCanvas , latency hints zeroed. A <video> fallback covers missing WebCodecs or stalls. It also feels like a monitor: fullscreen + input/wake locks, /leave beacon on exit. 7. Adaptive bitrate, sessions & security A BWE driver reads getStats every 250ms, pushing a smoothed bitrate into the encoder. Changing settings triggers in-place renegotiation (a reconfig/kick epoch the client polls) with no display teardown. Each host is gated by a session ID + 6-digit OTP ( OtpLimiter lockout); every device is isolated, over HTTPS + DTLS/SRTP. 8. Networking + status (v0.2.3) Same-network is direct, no servers. Offline mode stands up an ad-hoc hosted network , no infrastructure needed. Cross-network adds a cloud relay (WebSocket to session.screenextend.app ) tunneling signaling while media stays P2P; a self-hosted TURN server covers hard NATs. A logbus feeds an in-app terminal. Working today: Windows/macOS hosts, per-vendor GPU encode, per-device displays, adaptive bitrate, OTP sessions, offline mode, and cloud relay."}]...
|
Title: ScreenExtend by @epiccodewizard | Stardance Title: ScreenExtend by @epiccodewizard | Stardance
Devlogs:
ScreenExtend Devlog: Building the Rust Engine Under a Wireless Second Monitor TL;DR ScreenExtend turns any device with a browser into a real, wireless extended monitor for a Windows host, no client app and no cables (it began so my brother could use his iPad for notes at debate tournaments). Scan a QR code and the host spins up a real virtual display, streamed over WebRTC with hardware H.264. The React/TS control UI existed before; everything else (Rust core, GPU pipeline, WebCodecs client, cloud relay) was built from scratch , always latency-first, quality-second. 1. The spine: Tauri + a typed Rust↔TS bridge tauri-specta exports a fully-typed src/lib/bindings.ts for commands (TS→Rust) plus typed events (Rust→TS): devices, network, cloud status, logs. A code-generated bridge beats maintaining one by hand. Let the code write itself! 2. Virtual displays: faking a real monitor Each client gets its own virtual display the OS treats as real hardware, a true second screen, not mirroring. On join the host creates one sized to the client , forces extend topology, then captures it once attached. On Windows a signed IDD driver installs at runtime (via nefconc + certutil ), and it tears down cleanly on leave. 3. First light: WebRTC + WHEP + H.264 The media path is WebRTC (real-time, in every browser). Signaling is WHEP : the client POSTs an SDP offer, the host answers in-response, no signaling server. Codec is H.264 , universal hardware decode on clients and encode (NVENC/QSV/AMF) on hosts. The first release streamed NVENC to a plain <video> ; it worked but was laggy. It binds HTTP + HTTPS (self-signed via rcgen ) , since WebCodecs needs a secure context. 4. The pipeline: capture → encode → broadcast Capture is Windows Graphics Capture (later a custom fork; DXGI Desktop Duplication fallback), with a repeater thread for idle keepalive/IDRs and transient-stall tolerance. 5. Going vendor-specific: the part that made it fast Generic capture→CPU-copy→encode is slow everywhere; the win: keep the frame on the GPU from capture to bitstream. Per vendor: NVENC (NVIDIA): no SDK linked (API dynamically loaded ); zero-copy writes capture into a shared D3D11 texture behind a keyed mutex, else a CPU bridge. Intel QSV/oneVPL: same-adapter capture+encode fuses the downscale into the VPP pass (BGRA→NV12 + resize in one shot). macOS (VideoToolbox): ScreenCaptureKit (12.3+, CGDisplayStream fallback) via objc2 runtime interop only , so one binary loads on every macOS version, same IOSurface zero-copy. 6. The client: WebCodecs over <video> Fast path: an RTCRtpScriptTransform feeds a worker VideoDecoder ( optimizeForLatency: true ) onto an OffscreenCanvas , latency hints zeroed. A <video> fallback covers missing WebCodecs or stalls. It also feels like a monitor: fullscreen + input/wake locks, /leave beacon on exit. 7. Adaptive bitrate, sessions & security A BWE driver reads getStats every 250ms, pushing a smoothed bitrate into the encoder. Changing settings triggers in-place renegotiation (a reconfig/kick epoch the client polls) with no display teardown. Each host is gated by a session ID + 6-digit OTP ( OtpLimiter lockout); every device is isolated, over HTTPS + DTLS/SRTP. 8. Networking + status (v0.2.3) Same-network is direct, no servers. Offline mode stands up an ad-hoc hosted network , no infrastructure needed. Cross-network adds a cloud relay (WebSocket to session.screenextend.app ) tunneling signaling while media stays P2P; a self-hosted TURN server covers hard NATs. A logbus feeds an in-app terminal. Working today: Windows/macOS hosts, per-vendor GPU encode, per-device displays, adaptive bitrate, OTP sessions, offline mode, and cloud relay.
I met with some friends to discuss my app…and realized I gotta lock in with the features. Among the various topics we discussed like the difficult UI or lack of automatic updates, they really wanted remote control features. So, I set out to make the remote display something I can actually touch, click, and type into. And patching some other bugs along the way. 9. Remote input This is the main headline feature. Streaming pixels one way was solved; now the client had to send input back up the wire and have the host replay it as if it came from real hardware. Host side (Windows). A new input backend injects events through a synthetic pointer device , so mouse, touch, and pen all seem real as opposed to faked mouse moves. The synthetic device can execute touch or mouse movements from the tablet client. macOS and Linux backends are stubbed and will come later (trust me bro). The wire. This side had to be optimized for dead-low latency like the rest of the project. Instead of passing strings or using some wrapper library, I made my own binary protocol (a dedicated protocol module) serialized over WebRTC data channels , not the media path. Client-side input.js captures keyboard, mouse, pointer (touch/pen), wheel, clipboard, and drag-drop and ships them across. The code basically catches every single frontend input event and forwards all those events (20+)! The routing is latency-first, same as everything else, with three different paths. fast-path events (pointer moves, wheel) take an unreliable channel , where a dropped packet is cheaper than a late one, while clicks, keys, and clipboard take the reliable channel where every event must land exactly once. It’s not that big of a deal if one small mouse delta doesn’t go through, but it definitely is a big deal if a click doesn’t go through. 10. Browser compatibility detections Not every browser can do WebCodecs, secure contexts, or the input paths above. Rather than fail silently, I added a compatibility check on both the browser and client up front. It shows compatibility modals with per-feature lists to ensure the user knows what’s going on. 11. Some more small fixes I added two quality-of-life additions: avatars (upload custom profile pictures) and zoom controls (ctrl/cmd +/-). 12. Encoders that don’t explode when funny stuff happens Oh my god…one of the biggest issues by far. When I ran the NVIDIA encoder at high FPS, it didn’t crash. However, the Intel Quick Sync encoder would arbitrarily crash at high FPS and wouldn’t give a reason why. I audited a buncha different parts of my code and eventually found that FPS was the issue, not resolution or low-latency flags. Hence, I added a binary search that probes the hardware for its true maximum supported fps and clamps to it before the encoder can choke. Essentially, I ask the encoder “can you do 1920x1080 at 240 fps?” –> “no” –> “what about 120 fps?” –> “yes” –> “what about 180 fps?”. This keeps repeating till the max FPS is found and streamed to the client. Rounding out the release, I made a variety of different UI fixes like the modal fixes , backdrop overlap, a stray uninstall-modal backdrop, and cloud reconfig errors . More progress to come!
Sooooo this devlog is mostly comprised of website changes. I have a conference in San Francisco and wanted to polish up the app before publishing. Here are the main changes I made: 13. Random chores and updating the website I absolutely love shadcn-ui, but so do AI models. In past reviews by stardance raters, as well as family and friends, they pointed out the website looked AI-generated. Hence, I decreased the number of gradients and added basic animations to make the site feel more alive. This was a first for me to implement animations, but the Tailwind docs made it quite simple. I used a specific code-like font instead of the generic fonts I had and tidied up CSS classes. The biggest change was adding a blurred-geometric background for a nicer feel. 14. Redesigning the website completely I felt it was better to update the website as a whole, so I changed up the user interface. When I tested the app with real users, they complained that they didn’t know how to actually use the app. I changed the hero design to have clearer text and added an SVG-animation component showing how the site actually works. The feature section stayed the same, but there was a highlights grid (inspo https://cider.sh/ ) to highlight the main features. The FAQ was shortened to my liking, and I pulled some utilities from Tailwind for animations. In terms of images, I updated the images of the app featured on the website and cleaned up some of the dimensions related to that CSS. The old homepage still lives inside OldHome() but isn’t used anymore. 15. Tidying up the README and build workflows I edited the README to remove redundant information and make it more developer-focused. I also updated some information regarding GPU builds. For the build workflow, I ensured it would only run if the commit ended in “rebuild”. This ensures unnecessary build minutes are not spent on small changes not requiring a full rebuild. 16. Wake lock API fallback This app aims to support all devices, but older devices have…funny APIs to say the least. For WebRTC, I implemented the legacy encoded streams API. However, the device would still turn off for seemingly no reason while the video was playing. On older devices, the wake lock API is not supported. However, there’s a unique workaround for this: any video element playing on the webpage will keep the screen from dimming. Hence, I used the NoSleep library to create an off-screen 1-second video element that keeps looping, ensuring the display doesn’t go dark. Some very fun stuff with browsers. That’s it for this devlog! Mostly minor changes, but the next one will have better SW encoding support among other changes. Stay tuned…
I had so much fun at the conference in San Francisco! I met a lot of cool people who gave me advice on the app, although I didn’t see the downloads spike 😭. I primarily began working on a SW encoder and other miscellaneous changes: 17. Remote control toggle Sometimes, the user doesn’t want a client to have remote control access. Although the purpose of the app is to have remote control, it is useful to disable this feature. On the frontend, I added a toggle switch that enables or disables the remote control backend. I was debating whether WebRTC negotiation was required as well, but decided to do so in the end. The remote control used data channels, so an unused data channel would result in slightly lower latency. Renegotiation ensured the stream stayed as efficient as possible without sending redundant data. 18. Update checking In order for current users to access newer versions, I wanted to add an update functionality. I’m not using Tauri’s update plugin just yet, so I run a simple check. The app, on startup, checks the latest release tag on GitHub. If it’s not equal to the current version (rollback or higher version), the user is prompted to download the newer version. Automatic updates will come next. 19. The big boy: software encoding This one’s been a long time coming. A lot of machines like VMs or computers with a weird setup just don’t have a working hardware encoder (Intel/AMD/Nvidia), and until now that meant the app straight up didn’t work there. So I built a full CPU-only x264 fallback. For the pipeline, the frames come as raw BGRA bytes that the other supporters already encoded. They must be converted to I420 before going to libx264, whose build I pulled from OBS. As a side note, the DLL is bundled with the app at runtime to ensure no missing dependencies. As with any encoder, the rate control is ABR with a tight VBV, as well as an infinite GOP. Besides the technical jargon, this just means latency is the north star and nothing else matters. The whole software variant is added to the encoder vendor enum, and wired into the fallback chain: if NVENC fails, try Intel; if Intel fails, fall back to software before giving up entirely. There’s also a manual override if someone really prefers software encoding, but this is not the default. There’s a big CPU cost compared to hardware encoding, so it’s very much a last resort and only kicks in if absolutely no GPU encoders are available. But “last resort that works” beats “doesn’t work at all.” That’s it for this week! I plan to have some smaller quality-of-life changes and better updates coming soon…
Oh my lord…I crammed a lot of features into this week. I have yet to do proper audits of the codebase as a whole, specifically related to latency optimizations. I added a lot more code that affects the WebRTC pipeline, but I at least got the core features working. 20. Automatic updates For a while, the app relied on manual updating. It would check the latest version on Github, but users would have to go to the website, download the installer, uninstall the current version, and reinstall the newer version. This also messed up config and was a huge pain. Hence, I generated my own signing keys and used the Tauri updater plugin to automatically update apps. When the app is first launched and if an update is available, it automatically downloads and installs it without any user action. To make this more robust, I added a progress bar while downloading the update. On Windows specifically, the app must be shut down and restarted, so a blocking modal prevents devices from joining till this is done. I originally made this modal manually, but switched to using AlertDialog from ShadCN. Another issue I faced was the latest.json manifest. As I used custom filenames when downloading and installing updates, I had to manually patch the JSON. I learned a lot about the Tauri updater Github action through this, as I had to figure out how Tauri generated build filenames and how I could safely update them. 21. Quality of life for client devices I finished QOL fixes on the client side: Remember past devices to quickly import preferences or ban devices (all config saving is IP-based) Warn if the user is attempting to connect from the same device (this app is a remote control tool, but you can’t exactly remote control yourself) If the screen orientation changes, the virtual display is updated accordingly using CSS media queries to ensure a seamless experience A no fullscreen mode was added so users could quickly switch apps and maintain productivity 22. Quality of life for host devices I converted all in-app modals and error messages to JSON. This allowed me to add i18n language support, so I could easily translate my app to other languages. To detect and ensure only a single instance of the app was running, I previously used a file lock. However, there was an issue with MSI builds falsely detecting a file lock and not opening. I switched to a basic TCP model for IPC so that multiple processes running can figure out which was there first and shut down the others. 23. More more more Mac features! I’ve always felt a bit sad for my Mac users. I don’t have a Mac to test on, so I keep borrowing my dad’s Mac, which results in insanely slow development times. Nevertheless, I made some serious progress this week. The biggest thing was a simpler installation process. Many users would complain that they didn’t remember if they’re on Intel or Apple Silicon, so I now distribute a universal DMG. In terms of the app itself, I added a permissions check for screen recording and input injection. It would run a live test of screen capture or key input to see if the app actually had permissions; therefore, down the road it wouldn’t cause issues. I initially tried to do a soft check without an actual test (i.e., read the settings app), but this didn’t work. The only foolproof way was to call the API itself. The biggest feature by far was adding Mac input injection. Using accessibility APIs and a charmap similar to Windows, it would inject input onto the Mac screen. I could remotely log in from my Chromebook and get a lot of work done. I mirrored the structure and code on the Windows input injection pipeline, so no major difficulties here. That’s it for this week! Lotta stuff added, especially for the Mac users. I have a long list of features to continue building, specifically regarding easier Windows uninstall processes, onboarding, and an overall better UX. See you soon!
I speedran shipping a buncha features…in the span of a few days. I logged a copious amount of hours on Hackatime building random stuff. I tried some things with recording system audio and building a driver…those didn’t go the best, but I’ll cover that in the next devlog. Here are the main changes this week: 24. Even more quality of life changes Compared to last time, I wanted the user experience to improve even more. Specifically, for the Windows client, a custom display driver is required. On Macs, the functionality I need is built in, so none is required. However, uninstalling this display driver used to be a pain for users. Now, I bundled it as part of the uninstall script. I wasn’t sure how to do this, but Tauri has many useful guides and issues opened regarding custom WiX/NSIS code. When the window isn’t focused, join and leave notifications are toasted. This allows the user to stay informed even when the app isn’t open. Basic feature but very useful. I’d often get annoyed that I needed to keep re-entering the password to log in to a previously connected device. Hence, I added auto-join for devices based on their IP. This ensures that commonly connected devices can save time when reconnecting. 25. Onboarding screens The app is intuitive to use…or so I thought? Some of my beta testers were confused as to the various features and how to use the interface. Hence, I used NextStepjs to add onboarding components. This would dim the UI and only highlight the component being displayed, along with a message next to it. I liked the styles of NextStepjs a lot, so I chose it. There were some issues regarding window resize, so I made the onboarding exit and reopen to the last step when the window is resized. This way, the positioning of elements was forcefully recalculated. 26. Random security fixes My app had various vulnerabilities scattered throughout, so I ran a vulnerability Claude skill and patched some holes. The main issues fixed were: Checksums of bundled DLLs and resources are checked before being pushed to GitHub Actions Tauri CSP and allow list are actually enforced instead of being set to allow all TLS cert used for hosting the HTTPS domain has more secure file system permissions to reduce unwanted tampering of files Devices are trusted by a uniquely generated token, not by IP, to decrease the chance of impersonators 27. Command-line interface A majority of the time on this devlog was spent on the CLI. It wasn’t that hard (from a technical perspective), mainly just translating a lot of the UI code into Tauri CLI commands and mapping them correctly in the generated JSON file. One of the harder things to figure out was setting up cross-thread AppState, when the app wasn’t exactly running…turned out I just had to move the initialization command to before the window is created, so it would run inside both CLI and GUI modes. To present the QR codes better. I used qr2term to display the QR codes. By default, all logging is hidden. This turns ScreenExtend into a clean CLI mimicking the GUI. Hoorah! That’s it for this devlog. Not much to conclude, but plenty more features coming. Stay tuned!
Oh my lord, I keep forgetting to write devlogs every 10 hours and am losing hours on each one. Nevertheless, I finally finished audio work! Plus some other things like running claude security agents on the code base and patching stupid vulnerabilities. Here’s how the week went: 28. HiDPI and Mac Issues Whenever I use my Mac with ScreenExtend, the stream looks blurry due to Macs having HiDPI screens. I fixed this by adding basic HiDPI scaling on Windows. The UI has a DPR slider based on autodetected values. This DPR is multiplied by the screen resolution for a shaper display. One issue that arose with the new displays was the fact that the display would randomly not scale properly, so the task bar and apps would appear tiny. To mitigate this, I reapplied all display settings after resolution changes and a timeout. 29. AUDIO WORKS!!!! For the longest time, I tried getting audio to work. On Windows, the process was straightforward: a WASAPI loopback system audio capture session. I wanted to build my own custom driver to capture audio faster, but this would be too expensive to deploy. I read other Rust implementations and quickly wrote the code. On the other hand, Mac was a whole different issue. On older versions of Mac, system audio recording is not supported. Hence, for Macs below 13.0, I wrote a custom audio driver. I didn’t have a clue about implementing an AudioServerPlugIn on Mac, but worked out the specifics by looking at the Blackhole audio driver. I did have to proxy physical volume buttons to work (i.e. I listen for taps and change the audio level within the driver). For older Macs, I used ScreenCaptureKit with an extra audio flag. This was a simple fix to capture audio. On even newer Macs, there’s a Process Tap API to record system audio with low latency. Once again, I didn’t have much difficulties implementing these due to the abundance of documentation. 30. Streaming Audio over WebRTC (with A/V sync) When sending video and audio separately, the two are prone to fall out of sync, so watching movies or videos is difficult. To mitigate these issues, I wrote an A/V sync host clock. This packages the time on the host clock to audio samples and video frames, such that they can be reconstructed and coupled on the receiving end. On the browser side, I began by implementing a basic audio streamer with an audio element. However, similar to video, there’s always a faster method possible. I used the AudioDecoder class from WebCodecs to implement a worklet class and jitterbuffer. In simple terms, this would decode audio on a separate thread, like WebCodecs prefers, and send the audio back to be played to the user. 31. Windows Video Encoding Speedups I made a few encoding speedups on Windows targets: The NVENC capture encode system uses a texture ring implementation: a pool of 3-5 encoder instances paired with a frame queue, allowing multiple frames to be encoded concurrently BGRA encoding is done directly in the library instead of using a third-party implementation Unchanged frames in DXGI capture are not encoded again, reducing CPU load 32. Mac Video Encoding Speedups I made a few encoding speedups on Mac targets: Request LatencyCritical activity for the session to ensure App Nap and other sleep measures don’t affect the thread Analogous to DXGI, skip encoding when CGDisplayStream reports no dirty rects Not an encoding speedup, but preferring 5 GHz for Mac hosted networks to ensure higher speeds Lotta stuff done this week, am I right? I made lots of progress and finished the bulk of my features, although Linux support is still in the works. I’ll make the 1.0.0 release soon and start a Stardance ship as well. I’ll likely add Linux support after 1.0.0, as I need to research EVDI and the WSL display compositor, as well as other minor tweaks for Windows/Mac. See y’all in the next devlog!
One step closer to finally shipping…or so I hope. I speedran shipping this next feature, so it took a lot of time. This feature is mainly for myself. I have an old Mac (running 10.13 from 2017, really old I get itttt). I want my app to run on there, but it currently only supports 10.15+. Hence, I went down a funny rabbit hole in an attempt to add support. 33. Cleaning up dylib signature lookups at run time One of the key challenges I faced throughout development was how to have a unified codebase for multiple API versions. I decided that instead of version-gating APIs and guessing which beta/normal versions they would be accessible on, I’d test for APIs at run time. I changed VideoToolbox to use this logic: it would attempt to set/use APIs and variables available at higher runtimes, but would work fine without them and have fallbacks. This ensured both legacy and modern systems functioned well. 34. Airplay automations…? As I was doing competitor research, I noticed many of the other apps supported Mac 10.13-10.15 as well as 10.15+, while mainly only supported 10.15+. Essentially, they started a fake Airplay server, had the Mac connect it, and set the display mode to “Use as separate display”. This would create a virtual display that the app would then use for its own functions. As ScreenExtend requires its own display on older machines, similar to this, where CGVirtualDisplay isn’t an option, I decided to use this method. I had my app automate opening the Airplay menu and connecting as well, in addition to running the fake server. Most of the process was straightforward, especially due to the abundance of fake Airplay server implementations online and my own experience with apps like LonelyScreen. The one issue of this approach is that only one display can be connected at a time, so any tertiary devices wanting to connect have to wait their turn. I guess the only option is to by a new mac then… 35. Client UI update cleanliness fixes Due to the one device restriction, I implemented a separate page that would be served if the display slot was being used up. It would be coupled with a short message explaining the consequences of the older Mac version. There were also bugs related to session teardown (keyboard still being locked, video stream still active in the background, etc) that I quickly squashed after finding them. Soooo in hindsight, I prolly should’ve bumped this up to 0.6.0, but I left it at 0.5.4. Oh well, I’ll increment the version by next release. Only a few more features to go on the feature list before hitting v1 and shipping!!!
Ships:
Initial release for ScreenExtend! Please give feedback and read the initial devlog (shorter one here, longer one at https://github.com/ScreenExtend/ScreenExtend/blob/main/DEVLOG.md ) for detailed information....
|
1792993902.9684305
|
1793080302.9684305
|
|
61015
|
MischiefOS by @arshadpathan | Stardance
|
arshadpathan
|
2
|
128.84
|
1255
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-23T10:44:02Z", "hours": 105.0, "multiplier": 12.18, "payout": 1255, "blessing": "neutral", "text": "As the Policy of Stardance for Review - Please look at all devlogs, readme and exprience the Real look by reviewing demo. Message to Reviewer Please Look at all devlogs and review code before judging as stardance asks reviewer So basically the idea is: i watched loki series for multiple times and always inspired by TVA aesthetics and loki mischief behaviour. (also i was also very admired by Retro Tech) so thought to build a- Retro Futurism interface that doesn’t feel heavy and bold. Just a unique art direction that differentiate ongoing Tech Trend. So I started Brainstorming and made some amazing design decisions and a copy of all things in my mind. This whole project was challenging So first of all explaining all project related challenges, i have to mention one- I had no device for to code, so i brought friend’s laptop for most of time but want to know something exciting, when i does not friend’s laptop too, i starts coding in my android mobile through Acode mobile app - the more exciting part is that it also features wakatime extension so i do not have to worry about time and to do code changes at all. so the github and acode apps were become very helpful for me. Challenges in code , btw all the OS was challenging but there are some elements who took me to build long hours and concerned me: timer weather widget visitor counter widget setting wallpaper functionality toggle on off buttons in setting journal app inspiration and guide book mygame app, animations and states of elements music app and lots BTW, I am proud of myself that i made it succefully. i was challenged to build something unique i was challenged to make it cool i was challenged to just make functionalities work i was challenged to make it to be real and feel real i was challenged to build this along my very rough college schedules and deadlines And I’M Proud of myself that i completed all very neatly as i always expected (btw except college all other challenges are my goals to satisfy my creativity.) To exprience this crazy built OS [ ] just have some excitement. [ ] get some fresh water. [ ] look or search for some lowki keywords and aesthetic in pinterest. [ ] Give some time to load all images and assets for best exprience. [ ] after in OS, read guide book on desktop page to know features. [ ] open intro app and read inspiration book to be get inspired and know how i got inspired.", "repo": "https://github.com/Arshad-Pathan/MischiefOS", "demo": "https://mischief-os.vercel.app/"}, {"ship_num": 2, "ts": "2026-09-18T11:13:31Z", "hours": 21.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "MischiefOS A Retro - Futuristic themed OS inspired by MARVEL TV SERIES “LOKI” Everything You’ll see on the interface is ideat and coded by myself. Used AI just for debugging. The mistakes and even wrong logic(which also mine) was resolved by me by apply understanding problem. So consider AI just used for finding what causing errors, not to solve that errors. What my idea is: Retro Futurism interface that doesn’t feel heavy and bold. Just a unique art direction that differentiate ongoing Tech Trend. So I started Brainstorming and come to conclusion: I can’t think to go againts the choice of LOKI What you will experience during review is pure retro futuristc world - an enviroment - a timeline where things gone beyond current technology sorry because not adding a proper reference or image, and you will find all you find in readme and in website", "repo": "https://github.com/Arshad-Pathan/MischiefOS", "demo": "https://mischief-os.vercel.app/"}]...
|
[{"post_id": 82382, "ts": "202 [{"post_id": 82382, "ts": "2026-10-24T17:39:41Z", "hours": 2.8417, "text": "Thank You to all Reviewers i am very thankful to reviewer who pointed out mistakes, faults and responsive feedback. Now i changed some functions, some way of workings and compressed maximum of assets files. Removed all key press functionality except Apps browsing, changed app key with micrsoft key. also added new wallpaper and updated readme with walkthrough video. I removed my previous boot animation with something new, Go check out."}, {"post_id": 81976, "ts": "2026-10-23T09:32:58Z", "hours": 0.8108, "text": "Devlog 41, Forget to update Readme ew, Forget to to update readme. so updated it."}, {"post_id": 81964, "ts": "2026-10-23T07:04:32Z", "hours": 3.0506, "text": "Devlog 40. Thank you, pl read entire devlog Finished this OS Project now going to submit it. Last changes- added booting animation or whatever u say. made window to change into fullscreen also added one more wallpaper small chnages fully inspiration (in intro app) and guide book apps Thank u all the stardancers who supported me along this amazing building journey. this may be my First and last project in stardance(even ma be last devlog), because i got projects deadlines, assignment deadlines and mid sem exams and lot of things. Thank you - @r2shergill , @253_Mathilde_IYKYK , @Zhanik , @reshiiiram , @Saif_Yousuf , @spearedrice , @subzeroditto , @Anvith , @ojasthakur , @eyosafit , @akshay369 , @madzia , @MathBty . AGAIN THANK YOU, VERY VERY MUCH"}, {"post_id": 81825, "ts": "2026-10-22T17:18:44Z", "hours": 4.5478, "text": "Devlog 39 Last remainings haha, built almost all things, just remaining things are a guide assets, images of guide app. there are lot of things i chnaged to just submit this before tomorrow(because i got deadlines for assignements and school projects)"}, {"post_id": 81722, "ts": "2026-10-22T07:01:28Z", "hours": 0.5275, "text": "Devlog 38 making some scrapbooks for intro app that tells what inspired to create different and amazing elements. now using canva to make it."}, {"post_id": 81566, "ts": "2026-10-21T18:20:03Z", "hours": 2.6203, "text": "Devlog 37 Ahhhhhhhhh, i’m tired of reviewing and testing each components again and again. but in this process, i’m very obessed with my own design. to show something here from bundle small changes, i can show this journal app. i chnaged background and styling."}, {"post_id": 81495, "ts": "2026-10-21T14:21:20Z", "hours": 2.0767, "text": "devlog 36 I dont know how i am working, just noticing each detail and wasting all time fixing each design, functionalities and details. what changes Basically Changed lots of things which even i dont remember, some oh them were: apps icons container, transition, position and almost all details. grid underlying details like changed content of each grid element. Finalized Library App but there are even lots of things i have to final so byeeeeeeeeeee. let me finish this project"}, {"post_id": 81302, "ts": "2026-10-20T18:46:07Z", "hours": 0.6472, "text": "Devlog 35 this time devlogging time is low but i have given like 2 or 2.5 hours designing assest. all that stuffs are created by me with bare hands Im not exprienced designer that can create impressive designs, but this is what i can create. BTW i’m using affinity here."}, {"post_id": 81272, "ts": "2026-10-20T15:58:07Z", "hours": 12.0831, "text": "Devlog 34 Finalizing windows styles. Worked on Lockscreen. Very long day though. Playing. Testing. Reviewing. modifying and debugging functions and frontend elements."}, {"post_id": 80457, "ts": "2026-10-17T18:01:21Z", "hours": 1.6408, "text": "Devlog 33 Made this amazing interface for navbar and added the clock. the tuff part was the clock and its hands. Designing and Testing with User interface again and again was very time consuming and frustrating. But loved the Process!"}, {"post_id": 80360, "ts": "2026-10-17T12:31:23Z", "hours": 3.1975, "text": "Devlog 32 I’m proud of my creativeness Now this is time for finalizing and polishing the design. And may be adding some little what impressive elements in this final phase. now im covering this all and going to ship in next 1-2 days. Here i tried to give navbar a visuals like it is a real gadged or some tool display. Here, i added a cool effect to timer’s button. Visit and enjoy"}, {"post_id": 80190, "ts": "2026-10-16T17:11:26Z", "hours": 2.2172, "text": "Devlog 31 Finally made the actual game with all the functionalities that makes a game A Game. How to play start the game and find all the saviors(Lokis). once you find all the lokis, congrats in advance you will won. whats differents in game from normal flow is at 7th step when u find 7th loki, a message will appear saying “you are looser and always, but when you find the lasts you will won. what was challenging The most challenging part is not part about the game but it is about me and my creative thinking. It was the UI Design it was the User Experience Design it was animations and bugs They were all parts i made in my mind, and i want to add at any way by myself"}, {"post_id": 80140, "ts": "2026-10-16T11:20:57Z", "hours": 4.3492, "text": "Devlog 30 Made Amaaazzzzzzzzzzzzzzzzzzziiiiiiiiiiiiiinnnnnnnnnnnnnnnnnnggggggggggggggg Animationsss. one thing i would say: Go check it out mygame app in myos, give some patience to finish animation jussssssssssssssssssssst have to add winning condition. But rather than game starting loading animation was very smooth from my vision and to audience who watched loki series."}, {"post_id": 79608, "ts": "2026-10-14T18:08:48Z", "hours": 2.3717, "text": "Devlog 29 Made this tiny character animation then adding it in game. The game is now not fully functional but it is on the way to finally being build. the os is just few days way from available to all"}, {"post_id": 79351, "ts": "2026-10-13T16:31:24Z", "hours": 3.2297, "text": "Devlog 28 Trying to make a game. for now i added placeholder images but will add actual real objects images. Trying to make a portal that opens up and takes and hides all the objects when found or game ends"}, {"post_id": 78839, "ts": "2026-10-11T18:53:15Z", "hours": 3.035, "text": "Devlog 27 Please See all images to be thrilled! lets go from small to big! made small interaction functionalities in setting(lots of time went in solving mini mistake that are just at front but not seemed) made a wikipedia app successfully – go read articles about tva, apocalypses in history and hunters made a general setting that toggle clock widget to display and hide. – it also remembers that last time u hided it or displayed"}, {"post_id": 78698, "ts": "2026-10-11T10:45:15Z", "hours": 0.4153, "text": "Devlog 26 See both pictures made clock exactly like i thought and in series. it just needs styling and polishing. making all it together was little what hard so i made it in my way."}, {"post_id": 78694, "ts": "2026-10-11T10:08:41Z", "hours": 2.7456, "text": "Devlog 25 made whether and clock widgets i was not able make these widgets without youtube tutorials. So absolute these widgets needs improvments in styling. and yeah i want to make clock widget like this below image, and i just having a logic idea that might works."}, {"post_id": 78404, "ts": "2026-10-10T17:32:02Z", "hours": 4.4456, "text": "Devlog 24 Built some components and also made changes that looks very little but gives very much impression added visitor counter widget Firstly, Because some days before i commented about my project on someone reel on instagram and also added project link in bio, and guess what! people visited my project. added or fixed mini functionalities such as navbar, app maximize. made visitor Counter with app script and spreadsheet – before this, i also worked on IoT projects in college and worked with app script and spreadsheet – so i thought why not apply exactly that here – i also took suggestions and idea from ai’s chatbots but its ai and ai always give perfection in each work and i was not intented to go with any backend like node.js or supabase, etc. fixed nav and app as apps are going under the navbar adjustments in maximize and alignments changed simple single key press close and maximize to work with Alt key"}, {"post_id": 77646, "ts": "2026-10-07T18:54:59Z", "hours": 1.0092, "text": "Debugged, found and solved bugs Debug and solved bugs such as functions that are called without need or at wrong time. also added key press for closing and maximizing apps"}, {"post_id": 77617, "ts": "2026-10-07T17:22:18Z", "hours": 0.4208, "text": "Added Key Press Functionality on Timer How u can interact: Press “T” or “t” to start and stop Timer Press “S” or “s” to select Timer time"}, {"post_id": 77607, "ts": "2026-10-07T16:38:07Z", "hours": 2.5664, "text": "so i added a on key press functionality on musicApp. Functionalities added: now user can play music when space bar is clicked made navigation bar static so app does not go underneath of it."}, {"post_id": 77497, "ts": "2026-10-07T07:58:56Z", "hours": 2.4944, "text": "finally made fully functional gallery app successfully For now i have limited numbers of images, so i placed them as placeholders, will add much more later. Now my next goal is to make a special widgets for my purpose in this site : Site Visit Counter and yeah will also make other widgets"}, {"post_id": 77379, "ts": "2026-10-06T18:30:57Z", "hours": 1.1006, "text": "Working on Gallery app despite some personal challenges I facing some logical problems, but what i tried to execute is : I made a Gallery that features two tabs: Recent, where all images are dispayed Albums, Where images are classified and displayed in categories will be feature images categories in next devlog"}, {"post_id": 77333, "ts": "2026-10-06T15:50:10Z", "hours": 2.4372, "text": "made a fully functional library/file manager app. I got sick while making this app! i just thinking that the logic or code was that tough to make me sick or just was my deep thinking that made me sick ⚠️the app works like when you click any document icon it let you see that document in very interactive and wonderful way. for now i placed placeholder images and will add real once when all my creative ideas are executed"}, {"post_id": 76926, "ts": "2026-10-05T03:15:15Z", "hours": 1.8492, "text": "Finally made music player Features play & pause buttons forward & backward buttons a music player cd rounds when playing can play whatever song want to and whenever just select song from selection or go forward or backward if creativity gives me more time then then ill add volume buttons yeah i’ll polish the design and will make it look exactly as it has to"}, {"post_id": 76473, "ts": "2026-10-03T17:07:25Z", "hours": 2.7617, "text": "made and executed main essential music player functionality! and yeah also found how to write these emojies Whats done: Music plays when selected play - pause working but there is something unusual is happening idk why other visuals r just visuals and just structure, i have to make it work. also see codes snippets, i written all code and logic myself and yeah all the logic i learn from youtube tutorials, chatgpt and w3school."}, {"post_id": 76114, "ts": "2026-10-02T10:44:50Z", "hours": 2.8067, "text": "Devlogging after some long days, because i went on college trip As Readers will know i was working on music player, i just decided what logic & code flow i have to apply. I watched some tutorials, asked chatgpt for different suggestions and how to execute, but none of them was seems to work for me and my idea. so i now i’m going to apply the logic what my mind created and let me go for it for a test. this the song disk i am thinking to place in music player"}, {"post_id": 74936, "ts": "2026-09-28T17:06:03Z", "hours": 8.8092, "text": "My laptop crashed - devlog with combinig 2 days work My laptop crashed and i don’t know why but it was just heating up without much load. when i start the laptop the gpu fan just abnormally very fast and then it just increaisingly heats. so my whole yesterday was went into this, and now it just at service center and i don’t know when i get it to continue on it. So it was a situation made by fate but i’m not the guy who just stop at that problem So this is devlog for 2 days combined work done what i made: BTW There are some crazzzy interactions i’ve build, but it is surprise. just test yourself!, go visit project. sorry because of sone styling and same icon use, im just making it work now! A fully working terminal app with just couple of personalized commands Currently working on Music Player So not whole terminal app but some complex syntax and minimal logic was done by watching youtube tutorials and chatgpt at conclusion and to ensure if i learnt right thing. also as i said not whole app just learning logic of how to make my own music player btw just learnt how to apply logic and how to serve different solutions to different ideas"}, {"post_id": 73892, "ts": "2026-09-26T08:42:06Z", "hours": 2.5753, "text": "Here’s my OS timer just made it, proud of myself that it was made and executed very well and working as expected. still lots of creativity remaining to apply still lots of concepts are not explored and yeah lot of visual elements are not made & remaining not shown. I’m now just making things real using figma, canva, etc. and then will be add to project in future"}, {"post_id": 73701, "ts": "2026-09-25T18:48:44Z", "hours": 6.2942, "text": "just made a countdown or timer whatever everyone say. it steal lacks connection between the countdown options and button. I don’t know why its not fetching and displaying custom timer input box, so i pushed code to github and if there anyone who suggest what wrong thing i’m doing. consider that all other duplicate html, css and js files are created for practicing and setup of basic components and styling and learning how to execute certain wokloads efficiently. and yeah if u have any suggestions, please kindly reach to me and asks for features and recommendations. see ya next time !"}, {"post_id": 72985, "ts": "2026-09-24T05:15:18Z", "hours": 0.6367, "text": "This is very important for me and my projects in Stardance. Here i came to tell about how i made functionalities and projects. First of all, when i started in stardance i didn’t have a laptop, in fact during my diploma study till 3 years - i can’t bought one. but at this time when i shipped webos1 project, I bought a second hand laptop(after 2.5 year in diploma). Before that i was coding in my friend’s laptop. And during my college hours, when i got some free time i start coding in my Android Device via Acode Editor. So the laptop or windows is maximumly used for entire project creation but i also used android for micro-mini functionalities and adjustments So i’m very thankfull and pleasure to have things like: !Github - who secure my code and give me acceess on the go. !Acode - which allows me to code in every language i learnt, use terminal and yeah importantly the preview feature. I litteraly used bluetooth mouse in android and audited all the visual designs and code in Android and acode preview."}, {"post_id": 72771, "ts": "2026-09-23T18:31:55Z", "hours": 0.7667, "text": "I m now very proud of my self that i can take very good design decisions. and even more proud of on designs. if u see design something off or irrelevent, please suggest me to improve because this is my first time design interfaces and even interfaces that are unique and visually creative. please please please react on this because i dont know if i’m going in right direction or not!!"}, {"post_id": 72686, "ts": "2026-09-23T14:35:09Z", "hours": 0.9881, "text": "Hurray! The selected Background image is now being saved and loaded on website. Meaning in simple term is like i just cooked and added personalization. And Yeah, it is ready for personal use Let me finish I also made the navbar some smaller for to look ui good and also made the windows to be relative in position when maximized, So the navbar content doesn’t hide when maximized"}, {"post_id": 72647, "ts": "2026-09-23T12:43:24Z", "hours": 4.0639, "text": "What i achieved: The First of all The Preview Setting works. The Second Achievment, The Wallpaper are loaded as background when selected. What Still need: Is just a background setting like making it fit in background and not repeat. And in the final I would say that the UI is still not accurate as what i wanted and it embrassing me. So just one request i want is a honest feedback on UI and design."}, {"post_id": 72175, "ts": "2026-09-22T11:44:59Z", "hours": 6.1939, "text": "What i achieved: Just added a maximize functionality in my apps. also added a micro interaction like when you try to drag a maximized window, the window minimize just a little. when u again click the maximize button after dragging from max, it changes it to real height and width. What are difficulties: while trying to apply different sizes for different events and interactions, it was very difficult make a window to at it actual coordinates. Frustrated? Very much i was trying to make a setting app and a wallpaer setting that previews and set the wallpaper of the OS, but the the logic was very confusing and i’m now just finding the way just how to make it works with my own logic(even it was broken, just have to be work) BTW, The maximize functionality is not my first priority when i started this session, it was the setting app"}, {"post_id": 71692, "ts": "2026-09-21T10:03:01Z", "hours": 3.3331, "text": "Tested , played and made some minor Ui and css style changes such as ** Windowxs header, buttpns and navigatipn bar **, whuch must be new well maintained and"}, {"post_id": 70048, "ts": "2026-09-18T11:08:32Z", "hours": 2.1733, "text": "Done well, polished for production. Just sorry for not adding a screen shot here. Very tired."}, {"post_id": 69741, "ts": "2026-09-17T18:05:37Z", "hours": 4.1122, "text": "Made the design very good and added visuals that make you excited.What i’m feeling after completing this:"}, {"post_id": 69237, "ts": "2026-09-16T17:06:07Z", "hours": 7.7225, "text": "added dynamic content loading in journal app, i don’t know what say. i’m very very exhausted of errors and bad login implementation. don’t even knowing what im writing. i just have to say that its works and its works and the logic is right. and yeah i also made it live."}, {"post_id": 68576, "ts": "2026-09-15T10:44:15Z", "hours": 1.6561, "text": "phw solved the error that causing multiple icons activating at once. yeah there is way more details that i cant’t explain here, so read readme. now im on the way to apply css"}, {"post_id": 68488, "ts": "2026-09-15T06:41:20Z", "hours": 5.2372, "text": "So this is my first devlog for My MischiefOS Project. just now i’ve finished part 4 of os guide and made two windows with all the primary capabilities it must have. for now i just made static visuals of my screen. not hard visuals, just executed pure code. 1st-main screen 2nd-apps"}]...
|
Title: MischiefOS by @arshadpathan | Stardance
De Title: MischiefOS by @arshadpathan | Stardance
Devlogs:
So this is my first devlog for My MischiefOS Project. just now i’ve finished part 4 of os guide and made two windows with all the primary capabilities it must have. for now i just made static visuals of my screen. not hard visuals, just executed pure code. 1st-main screen 2nd-apps
phw solved the error that causing multiple icons activating at once. yeah there is way more details that i cant’t explain here, so read readme. now im on the way to apply css
added dynamic content loading in journal app, i don’t know what say. i’m very very exhausted of errors and bad login implementation. don’t even knowing what im writing. i just have to say that its works and its works and the logic is right. and yeah i also made it live.
Made the design very good and added visuals that make you excited.What i’m feeling after completing this:
Done well, polished for production. Just sorry for not adding a screen shot here. Very tired.
Tested , played and made some minor Ui and css style changes such as ** Windowxs header, buttpns and navigatipn bar **, whuch must be new well maintained and
What i achieved: Just added a maximize functionality in my apps. also added a micro interaction like when you try to drag a maximized window, the window minimize just a little. when u again click the maximize button after dragging from max, it changes it to real height and width. What are difficulties: while trying to apply different sizes for different events and interactions, it was very difficult make a window to at it actual coordinates. Frustrated? Very much i was trying to make a setting app and a wallpaer setting that previews and set the wallpaper of the OS, but the the logic was very confusing and i’m now just finding the way just how to make it works with my own logic(even it was broken, just have to be work) BTW, The maximize functionality is not my first priority when i started this session, it was the setting app
What i achieved: The First of all The Preview Setting works. The Second Achievment, The Wallpaper are loaded as background when selected. What Still need: Is just a background setting like making it fit in background and not repeat. And in the final I would say that the UI is still not accurate as what i wanted and it embrassing me. So just one request i want is a honest feedback on UI and design.
Hurray! The selected Background image is now being saved and loaded on website. Meaning in simple term is like i just cooked and added personalization. And Yeah, it is ready for personal use Let me finish I also made the navbar some smaller for to look ui good and also made the windows to be relative in position when maximized, So the navbar content doesn’t hide when maximized
I m now very proud of my self that i can take very good design decisions. and even more proud of on designs. if u see design something off or irrelevent, please suggest me to improve because this is my first time design interfaces and even interfaces that are unique and visually creative. please please please react on this because i dont know if i’m going in right direction or not!!
This is very important for me and my projects in Stardance. Here i came to tell about how i made functionalities and projects. First of all, when i started in stardance i didn’t have a laptop, in fact during my diploma study till 3 years - i can’t bought one. but at this time when i shipped webos1 project, I bought a second hand laptop(after 2.5 year in diploma). Before that i was coding in my friend’s laptop. And during my college hours, when i got some free time i start coding in my Android Device via Acode Editor. So the laptop or windows is maximumly used for entire project creation but i also used android for micro-mini functionalities and adjustments So i’m very thankfull and pleasure to have things like: !Github - who secure my code and give me acceess on the go. !Acode - which allows me to code in every language i learnt, use terminal and yeah importantly the preview feature. I litteraly used bluetooth mouse in android and audited all the visual designs and code in Android and acode preview.
just made a countdown or timer whatever everyone say. it steal lacks connection between the countdown options and button. I don’t know why its not fetching and displaying custom timer input box, so i pushed code to github and if there anyone who suggest what wrong thing i’m doing. consider that all other duplicate html, css and js files are created for practicing and setup of basic components and styling and learning how to execute certain wokloads efficiently. and yeah if u have any suggestions, please kindly reach to me and asks for features and recommendations. see ya next time !
Here’s my OS timer just made it, proud of myself that it was made and executed very well and working as expected. still lots of creativity remaining to apply still lots of concepts are not explored and yeah lot of visual elements are not made & remaining not shown. I’m now just making things real using figma, canva, etc. and then will be add to project in future
My laptop crashed - devlog with combinig 2 days work My laptop crashed and i don’t know why but it was just heating up without much load. when i start the laptop the gpu fan just abnormally very fast and then it just increaisingly heats. so my whole yesterday was went into this, and now it just at service center and i don’t know when i get it to continue on it. So it was a situation made by fate but i’m not the guy who just stop at that problem So this is devlog for 2 days combined work done what i made: BTW There are some crazzzy interactions i’ve build, but it is surprise. just test yourself!, go visit project. sorry because of sone styling and same icon use, im just making it work now! A fully working terminal app with just couple of personalized commands Currently working on Music Player So not whole terminal app but some complex syntax and minimal logic was done by watching youtube tutorials and chatgpt at conclusion and to ensure if i learnt right thing. also as i said not whole app just learning logic of how to make my own music player btw just learnt how to apply logic and how to serve different solutions to different ideas
Devlogging after some long days, because i went on college trip As Readers will know i was working on music player, i just decided what logic & code flow i have to apply. I watched some tutorials, asked chatgpt for different suggestions and how to execute, but none of them was seems to work for me and my idea. so i now i’m going to apply the logic what my mind created and let me go for it for a test. this the song disk i am thinking to place in music player
made and executed main essential music player functionality! and yeah also found how to write these emojies Whats done: Music plays when selected play - pause working but there is something unusual is happening idk why other visuals r just visuals and just structure, i have to make it work. also see codes snippets, i written all code and logic myself and yeah all the logic i learn from youtube tutorials, chatgpt and w3school.
Finally made music player Features play & pause buttons forward & backward buttons a music player cd rounds when playing can play whatever song want to and whenever just select song from selection or go forward or backward if creativity gives me more time then then ill add volume buttons yeah i’ll polish the design and will make it look exactly as it has to
made a fully functional library/file manager app. I got sick while making this app! i just thinking that the logic or code was that tough to make me sick or just was my deep thinking that made me sick ⚠️the app works like when you click any document icon it let you see that document in very interactive and wonderful way. for now i placed placeholder images and will add real once when all my creative ideas are executed
Working on Gallery app despite some personal challenges I facing some logical problems, but what i tried to execute is : I made a Gallery that features two tabs: Recent, where all images are dispayed Albums, Where images are classified and displayed in categories will be feature images categories in next devlog
finally made fully functional gallery app successfully For now i have limited numbers of images, so i placed them as placeholders, will add much more later. Now my next goal is to make a special widgets for my purpose in this site : Site Visit Counter and yeah will also make other widgets
so i added a on key press functionality on musicApp. Functionalities added: now user can play music when space bar is clicked made navigation bar static so app does not go underneath of it.
Added Key Press Functionality on Timer How u can interact: Press “T” or “t” to start and stop Timer Press “S” or “s” to select Timer time
Debugged, found and solved bugs Debug and solved bugs such as functions that are called without need or at wrong time. also added key press for closing and maximizing apps
Devlog 24 Built some components and also made changes that looks very little but gives very much impression added visitor counter widget Firstly, Because some days before i commented about my project on someone reel on instagram and also added project link in bio, and guess what! people visited my project. added or fixed mini functionalities such as navbar, app maximize. made visitor Counter with app script and spreadsheet – before this, i also worked on IoT projects in college and worked with app script and spreadsheet – so i thought why not apply exactly that here – i also took suggestions and idea from ai’s chatbots but its ai and ai always give perfection in each work and i was not intented to go with any backend like node.js or supabase, etc. fixed nav and app as apps are going under the navbar adjustments in maximize and alignments changed simple single key press close and maximize to work with Alt key
Devlog 25 made whether and clock widgets i was not able make these widgets without youtube tutorials. So absolute these widgets needs improvments in styling. and yeah i want to make clock widget like this below image, and i just having a logic idea that might works.
Devlog 26 See both pictures made clock exactly like i thought and in series. it just needs styling and polishing. making all it together was little what hard so i made it in my way.
Devlog 27 Please See all images to be thrilled! lets go from small to big! made small interaction functionalities in setting(lots of time went in solving mini mistake that are just at front but not seemed) made a wikipedia app successfully – go read articles about tva, apocalypses in history and hunters made a general setting that toggle clock widget to display and hide. – it also remembers that last time u hided it or displayed
Devlog 28 Trying to make a game. for now i added placeholder images but will add actual real objects images. Trying to make a portal that opens up and takes and hides all the objects when found or game ends
Devlog 29 Made this tiny character animation then adding it in game. The game is now not fully functional but it is on the way to finally being build. the os is just few days way from available to all
Devlog 30 Made Amaaazzzzzzzzzzzzzzzzzzziiiiiiiiiiiiiinnnnnnnnnnnnnnnnnnggggggggggggggg Animationsss. one thing i would say: Go check it out mygame app in myos, give some patience to finish animation jussssssssssssssssssssst have to add winning condition. But rather than game starting loading animation was very smooth from my vision and to audience who watched loki series.
Devlog 31 Finally made the actual game with all the functionalities that makes a game A Game. How to play start the game and find all the saviors(Lokis). once you find all the lokis, congrats in advance you will won. whats differents in game from normal flow is at 7th step when u find 7th loki, a message will appear saying “you are looser and always, but when you find the lasts you will won. what was challenging The most challenging part is not part about the game but it is about me and my creative thinking. It was the UI Design it was the User Experience Design it was animations and bugs They were all parts i made in my mind, and i want to add at any way by myself
Devlog 32 I’m proud of my creativeness Now this is time for finalizing and polishing the design. And may be adding some little what impressive elements in this final phase. now im covering this all and going to ship in next 1-2 days. Here i tried to give navbar a visuals like it is a real gadged or some tool display. Here, i added a cool effect to timer’s button. Visit and enjoy
Devlog 33 Made this amazing interface for navbar and added the clock. the tuff part was the clock and its hands. Designing and Testing with User interface again and again was very time consuming and frustrating. But loved the Process!
Devlog 34 Finalizing windows styles. Worked on Lockscreen. Very long day though. Playing. Testing. Reviewing. modifying and debugging functions and frontend elements.
Devlog 35 this time devlogging time is low but i have given like 2 or 2.5 hours designing assest. all that stuffs are created by me with bare hands Im not exprienced designer that can create impressive designs, but this is what i can create. BTW i’m using affinity here.
devlog 36 I dont know how i am working, just noticing each detail and wasting all time fixing each design, functionalities and details. what changes Basically Changed lots of things which even i dont remember, some oh them were: apps icons container, transition, position and almost all details. grid underlying details like changed content of each grid element. Finalized Library App but there are even lots of things i have to final so byeeeeeeeeeee. let me finish this project
Devlog 37 Ahhhhhhhhh, i’m tired of reviewing and testing each components again and again. but in this process, i’m very obessed with my own design. to show something here from bundle small changes, i can show this journal app. i chnaged background and styling.
Devlog 38 making some scrapbooks for intro app that tells what inspired to create different and amazing elements. now using canva to make it.
Devlog 39 Last remainings haha, built almost all things, just remaining things are a guide assets, images of guide app. there are lot of things i chnaged to just submit this before tomorrow(because i got deadlines for assignements and school projects)
Devlog 40. Thank you, pl read entire devlog Finished this OS Project now going to submit it. Last changes- added booting animation or whatever u say. made window to change into fullscreen also added one more wallpaper small chnages fully inspiration (in intro app) and guide book apps Thank u all the stardancers who supported me along this amazing building journey. this may be my First and last project in stardance(even ma be last devlog), because i got projects deadlines, assignment deadlines and mid sem exams and lot of things. Thank you - @r2shergill , @253_Mathilde_IYKYK , @Zhanik , @reshiiiram , @Saif_Yousuf , @spearedrice , @subzeroditto , @Anvith , @ojasthakur , @eyosafit , @akshay369 , @madzia , @MathBty . AGAIN THANK YOU, VERY VERY MUCH
Devlog 41, Forget to update Readme ew, Forget to to update readme. so updated it.
Thank You to all Reviewers i am very thankful to reviewer who pointed out mistakes, faults and responsive feedback. Now i changed some functions, some way of workings and compressed maximum of assets files. Removed all key press functionality except Apps browsing, changed app key with micrsoft key. also added new wallpaper and updated readme with walkthrough video. I removed my previous boot animation with something new, Go check out.
Ships:
MischiefOS A Retro - Futuristic themed OS inspired by MARVEL TV SERIES “LOKI” Everything You’ll see on the interface is ideat and coded by myself. Used AI just for debugging. The mistakes and even wrong logic(which also mine) was resolved by me by apply understanding problem. So consider AI just used for finding what causing errors, not to solve that errors. What my idea is: Retro Futurism interface that doesn’t feel heavy and bold. Just a unique art direction that differentiate ongoing Tech Trend. So I started Brainstorming and come to conclusion: I can’t think to go againts the choice of LOKI What you will experience during review is pure retro futuristc world - an enviroment - a timeline where things gone beyond current technology sorry because not adding a proper reference or image, and you will find all you find in readme and in website
As the Policy of Stardance for Review - Please look at all devlogs, readme and exprience the Real look by reviewing demo. Message to Reviewer Please Look at all devlogs and review code before judging as stardance asks reviewer So basically the idea is: i watched loki series for multiple times and always inspired by TVA aesthetics and loki mischief behaviour. (also i was also very admired by Retro Tech) so thought to build a- Retro Futurism interface that doesn’t feel heavy and bold. Just a unique art direction that differentiate ongoing Tech Trend. So I started Brainstorming and made some amazing design decisions and a copy of all things in my mind. This whole project was challenging So first of all explaining all project related challenges, i have to mention one- I had no device for to code, so i brought friend’s laptop for most of time but want to know something exciting, when i does not friend’s laptop too, i starts coding in my android mobile through Acode mobile app - the more exciting part is that it also features wakatime extension so i do not have to worry about time and to do code changes at all. so the github and acode apps were become very helpful for me. Challenges in code , btw all the OS was challenging but there are some elements who took me to build long hours and concerned me: timer weather widget visitor counter widget setting wallpaper functionality toggle on off buttons in setting journal app inspiration and guide book mygame app, animations and states of elements music app and lots BTW, I am proud of myself that i made it succefully. i was challenged to build something unique i was challenged to make it cool i was challenged to just make functionalities work i was challenged to make it to be real and feel real i was challenged to build this along my very rough college schedules and deadlines And I’M Proud of myself that i completed all very neatly as i always expected (btw except college all other challenges are my goals to satisfy my creativity.) To exprience this crazy built OS [ ] just have some excitement. [ ] get some fresh water. [ ] look or search for some lowki keywords and aesthetic in pinterest. [ ] Give some time to load all images and assets for best exprience. [ ] after in OS, read guide book on desktop page to know features. [ ] open intro app and read inspiration book to be get inspired and know how i got inspired....
|
1793055288.0528977
|
1793141688.0528977
|
|
50858
|
OpenDAW by @saisrihari | Stardance
|
saisrihari
|
0
|
128.54
|
0
|
[]
|
[{"post_id": 63592, "ts": "202 [{"post_id": 63592, "ts": "2026-09-07T14:48:48Z", "hours": 7.7333, "text": "I’VE ADDED TWO HUGE FEATURES!!!: 1)Full Mixer- So now we’ve got a dedicated mixer screen with volume faders, pan, mute/solo and a master channel. The colour of the tracks correspond with the mixer track colours. 2)Fixed Timeline Zoom- The zoom is now visible on the left panel. It changes the timeline width. The zoom is also saved with projects."}, {"post_id": 62627, "ts": "2026-09-06T02:58:38Z", "hours": 8.6619, "text": "I’ve fixed some major bugs with the drum machine. I added a startup window which appears when the application is opened. It appears with entries where you can set your project name, BPM, Make a new project, Open an existing project or even settings. I made a new logo which is displayed at the top. I’ve also added a zoom in timeline feature for better viewing in the timeline."}, {"post_id": 62171, "ts": "2026-09-05T13:08:13Z", "hours": 6.3, "text": "I’ve added a settings window. You can now select your preferred microphone, MIDI and you can refresh devices if you’ve connected a new one. Also the keyboard shortcut list is displayed here. Settings is accessible from both the toolbar or the File dropdown"}, {"post_id": 61937, "ts": "2026-09-05T03:36:26Z", "hours": 5.3333, "text": "I removed the fullscreen arrangement feature cause it kept bugging out and I wasn’t able to fix it. I’ll probably add it back on a future date. I also improved the vocals. You can now select your microphone from the input dropdown. You can record vocals when the instrument is playing. I’ve also added a vocal preset to the fx rack. The project is near completion (I’ll say around 3/4th way through)."}, {"post_id": 60964, "ts": "2026-09-03T17:23:11Z", "hours": 5.7111, "text": "I added a fullscreen arangement view. When you click f11 or the arrangement button in the top the daw expands into the timeline. It’s not perfect yet and it’s very buggy so I might remove it later (or fix it). The feature is inspired from ableton live."}, {"post_id": 59690, "ts": "2026-09-01T16:44:27Z", "hours": 8.5333, "text": "I added markers (they get placed at your playheads position). I added Auto-save which is togglable currently but I’ll probably change that soon. I added clip fades which can be set after clicking the fade in or fade out button. A dialogue box appears asking you at what time you need the track to fade in and out. I also expanded the undo/redo to 100 states which now includes fades and the markers. The project is close to completion!"}, {"post_id": 59000, "ts": "2026-08-31T16:06:50Z", "hours": 8.3353, "text": "I added a drum beat maker ! (It shows up with an error tho whenever I try to play more than two drum tracks). It has a 16 step sequencer, A kick, snare, Hi-hats, clap. You can add cells by clicking them (they’re togglable). It uses your current BPM and is added to the timeline using the “Add to timeline” button. The code works by having separate parts for the tracks, audio engine, and GUI, which work together to load."}, {"post_id": 57853, "ts": "2026-08-30T05:04:15Z", "hours": 7.1, "text": "So I added undo and redo buttons (finally) in the top toolbar you can use ctrl+z and ctrl+y as shortcut keys. I’ve also added a looping feature. You can now enable the loop from the on/off button on the transport bar. Set A sets the loop start at current playhead. Set B sets the loop end at current playhead. “L” toggles looping and playback cycles continuously between Set A and Set B."}, {"post_id": 56752, "ts": "2026-08-28T17:15:33Z", "hours": 8.2692, "text": "I finally added an effects rack. The effects I included were: Gain, Delay, Delay Time, Reverb, Distortion, Compressor, High-pass and low-pass filters. Each track now has an “fx” button or you can use the open effects rack on the left panel. The effects are added both to playback and export and you can use the “f” key to open the rack."}, {"post_id": 55580, "ts": "2026-08-27T15:04:58Z", "hours": 8.3667, "text": "I finally found a purpose for the panel on the left. You can now see the current bpm, track count, track length, selected track, position and length. You can also rename your track, change its colour or split the track here. You can also split a track by moving the playhead and clicking “D” or split at a particular section of the track."}, {"post_id": 55109, "ts": "2026-08-26T15:55:11Z", "hours": 5.6667, "text": "Ok! I added some core features that I was supposed to add before. You can now move your tracks in the timeline. Your supposed to click and drag the waveforms horizontally. I also added settable BPM. Now your BPM is visible in the top toolbar and I set the range from 40bpm to 240 (By default it’s 120). Also your bpm is saved and loaded with projects."}, {"post_id": 54901, "ts": "2026-08-26T03:51:31Z", "hours": 3.4381, "text": "I finally added another instrument in the piano roll. You can now select between an acoustic guitar and a piano. I’ll add more in the coming days."}, {"post_id": 54612, "ts": "2026-08-25T17:09:21Z", "hours": 6.9333, "text": "You can now rename and recolor all your tracks! I also fixed the importing from the piano roll to the timeline. When you click the recolour button it randomly picks a colour. I’ll add particular colour pickers in the near future."}, {"post_id": 53907, "ts": "2026-08-24T16:44:13Z", "hours": 1.2, "text": "Added these keyboard commands"}, {"post_id": 53836, "ts": "2026-08-24T15:09:08Z", "hours": 8.3119, "text": "-I FINALLY FIXED THE RECORD BUTTON. -I added a piano roll which can be switched to using the button on the top left (Probably might switch it’s location later). -It’s a 4 octave piano you can left-click cells to add notes and click them again to remove. -For now there’s only one instrument (Rhodes Piano). I’ll add more soon!"}, {"post_id": 53055, "ts": "2026-08-23T13:31:43Z", "hours": 2.4144, "text": "Tried to fix the record button cus it kept bugging out for some reason and I screwed everything up. I GIVE UP FOR TODAY. I’ll think abt this tmrw."}, {"post_id": 52840, "ts": "2026-08-23T06:13:19Z", "hours": 9.7575, "text": "Had a bit of a longer session this time. The last 3 days have been highly productive for me but now my holidays are over :( . I’ve made some big changes: -Added a record button. (Took me wayyy to long to make) -Added partitions so now all the sections are clearly divided. -Added a timeline. -Added a panel on the left (Still don’t know what I’m gonna do with it) -Added Save, Load, Export and Import features -Now you can trim your audio clips -Moved the add track button to the top left"}, {"post_id": 52371, "ts": "2026-08-22T14:14:53Z", "hours": 8.0044, "text": "Ok… I’ve got some huge changes. The DAW is starting to take shape now. You can now see the waveform of your audio track. I improved the audio quality drastically. I formatted so now everything is centered. I implemented a dark grey theme with neon blue accents. I’ve come up with the name… I think I’ll call it OpenDAW. I still don’t know what I’ll do with the space on the left but I know I’ll come up with something. My passion for this project is increasing every second I work on it."}, {"post_id": 51720, "ts": "2026-08-21T15:35:14Z", "hours": 8.4694, "text": "FINALLY…After 8 hrs smth mins of scripting and debugging I have this….You can add many tracks, change their individual volumes and play it as a whole. My plan is to make an opensource DAW which can easily be modded. I have holidays where I live so I’ll try putting atleast 8hrs a day. I need to format it because it feels pretty barebones rn AND I NEED THAT LAPTOP (i have a 4gb ram rn). Ty all!!"}]...
|
Title: OpenDAW by @saisrihari | Stardance
Devlogs Title: OpenDAW by @saisrihari | Stardance
Devlogs:
FINALLY…After 8 hrs smth mins of scripting and debugging I have this….You can add many tracks, change their individual volumes and play it as a whole. My plan is to make an opensource DAW which can easily be modded. I have holidays where I live so I’ll try putting atleast 8hrs a day. I need to format it because it feels pretty barebones rn AND I NEED THAT LAPTOP (i have a 4gb ram rn). Ty all!!
Ok… I’ve got some huge changes. The DAW is starting to take shape now. You can now see the waveform of your audio track. I improved the audio quality drastically. I formatted so now everything is centered. I implemented a dark grey theme with neon blue accents. I’ve come up with the name… I think I’ll call it OpenDAW. I still don’t know what I’ll do with the space on the left but I know I’ll come up with something. My passion for this project is increasing every second I work on it.
Had a bit of a longer session this time. The last 3 days have been highly productive for me but now my holidays are over :( . I’ve made some big changes: -Added a record button. (Took me wayyy to long to make) -Added partitions so now all the sections are clearly divided. -Added a timeline. -Added a panel on the left (Still don’t know what I’m gonna do with it) -Added Save, Load, Export and Import features -Now you can trim your audio clips -Moved the add track button to the top left
Tried to fix the record button cus it kept bugging out for some reason and I screwed everything up. I GIVE UP FOR TODAY. I’ll think abt this tmrw.
-I FINALLY FIXED THE RECORD BUTTON. -I added a piano roll which can be switched to using the button on the top left (Probably might switch it’s location later). -It’s a 4 octave piano you can left-click cells to add notes and click them again to remove. -For now there’s only one instrument (Rhodes Piano). I’ll add more soon!
Added these keyboard commands
You can now rename and recolor all your tracks! I also fixed the importing from the piano roll to the timeline. When you click the recolour button it randomly picks a colour. I’ll add particular colour pickers in the near future.
I finally added another instrument in the piano roll. You can now select between an acoustic guitar and a piano. I’ll add more in the coming days.
Ok! I added some core features that I was supposed to add before. You can now move your tracks in the timeline. Your supposed to click and drag the waveforms horizontally. I also added settable BPM. Now your BPM is visible in the top toolbar and I set the range from 40bpm to 240 (By default it’s 120). Also your bpm is saved and loaded with projects.
I finally found a purpose for the panel on the left. You can now see the current bpm, track count, track length, selected track, position and length. You can also rename your track, change its colour or split the track here. You can also split a track by moving the playhead and clicking “D” or split at a particular section of the track.
I finally added an effects rack. The effects I included were: Gain, Delay, Delay Time, Reverb, Distortion, Compressor, High-pass and low-pass filters. Each track now has an “fx” button or you can use the open effects rack on the left panel. The effects are added both to playback and export and you can use the “f” key to open the rack.
So I added undo and redo buttons (finally) in the top toolbar you can use ctrl+z and ctrl+y as shortcut keys. I’ve also added a looping feature. You can now enable the loop from the on/off button on the transport bar. Set A sets the loop start at current playhead. Set B sets the loop end at current playhead. “L” toggles looping and playback cycles continuously between Set A and Set B.
I added a drum beat maker ! (It shows up with an error tho whenever I try to play more than two drum tracks). It has a 16 step sequencer, A kick, snare, Hi-hats, clap. You can add cells by clicking them (they’re togglable). It uses your current BPM and is added to the timeline using the “Add to timeline” button. The code works by having separate parts for the tracks, audio engine, and GUI, which work together to load.
I added markers (they get placed at your playheads position). I added Auto-save which is togglable currently but I’ll probably change that soon. I added clip fades which can be set after clicking the fade in or fade out button. A dialogue box appears asking you at what time you need the track to fade in and out. I also expanded the undo/redo to 100 states which now includes fades and the markers. The project is close to completion!
I added a fullscreen arangement view. When you click f11 or the arrangement button in the top the daw expands into the timeline. It’s not perfect yet and it’s very buggy so I might remove it later (or fix it). The feature is inspired from ableton live.
I removed the fullscreen arrangement feature cause it kept bugging out and I wasn’t able to fix it. I’ll probably add it back on a future date. I also improved the vocals. You can now select your microphone from the input dropdown. You can record vocals when the instrument is playing. I’ve also added a vocal preset to the fx rack. The project is near completion (I’ll say around 3/4th way through).
I’ve added a settings window. You can now select your preferred microphone, MIDI and you can refresh devices if you’ve connected a new one. Also the keyboard shortcut list is displayed here. Settings is accessible from both the toolbar or the File dropdown
I’ve fixed some major bugs with the drum machine. I added a startup window which appears when the application is opened. It appears with entries where you can set your project name, BPM, Make a new project, Open an existing project or even settings. I made a new logo which is displayed at the top. I’ve also added a zoom in timeline feature for better viewing in the timeline.
I’VE ADDED TWO HUGE FEATURES!!!: 1)Full Mixer- So now we’ve got a dedicated mixer screen with volume faders, pan, mute/solo and a master channel. The colour of the tracks correspond with the mixer track colours. 2)Fixed Timeline Zoom- The zoom is now visible on the left panel. It changes the timeline width. The zoom is also saved with projects....
|
1792918400.532229
|
1793782400.532229
|
|
51767
|
Friction less by @jinjin | Stardance
|
jinjin
|
1
|
128.53
|
110
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-31T12:30:11Z", "hours": 39.0, "multiplier": 3.55, "payout": 110, "blessing": "neutral", "text": "I built TidyPaste, a client-side web workbench designed to clean messy text, reformat data structures, and track session productivity - all inside a single browser tab.", "repo": "https://github.com/jinjintt89-cmyk/Friction-less-copy-and-paste", "demo": "https://copyandpaste2.vercel.app/"}]...
|
[{"post_id": 65982, "ts": "202 [{"post_id": 65982, "ts": "2026-09-11T14:14:33Z", "hours": 4.6333, "text": "Polishing the Desktop VersionI’ve continued working on the desktop version of Frictionless and focused on making it feel more like a proper standalone application.A big part of this work has been testing the Mac build, fixing issues that appeared during packaging, and making sure the desktop version still has the same core functionality as the web version.I also spent time improving the overall reliability of the project after moving more of the code into the Electron setup. This included checking that the app opens correctly, that the different tools continue to work, and that the project can still be built and packaged when changes are made.The desktop version is getting much closer to feeling like a complete second version of Frictionless rather than just a website running inside a window.What I worked onTested the Mac desktop buildImproved Electron integrationChecked existing Frictionless toolsFixed packaging-related issuesImproved desktop reliabilityContinued preparing the app for distributionKept the web and desktop versions working together"}, {"post_id": 65868, "ts": "2026-09-11T09:28:32Z", "hours": 9.1667, "text": "Fixing the Mac App and Improving DistributionI’ve been continuing work on the desktop version of Frictionless and focusing on making the Mac app easier to distribute.After successfully building the Electron version, I ran into an issue where macOS showed a “damaged” message when the app was downloaded. I investigated the problem and found that it was related to macOS security and the app being unsigned.I’ve now been working on ad-hoc signing the application and testing the build again. This has been useful because it showed me that building an application and actually distributing it are two different challenges.I also made sure the desktop-app changes were properly pushed to the Frictionless GitHub repository, so the project now contains both the original web version and the Electron desktop version.The main focus right now is making the desktop version as reliable as the web version while keeping the project simple and easy to access.What I worked onInvestigated the macOS “damaged app” issueTested ad-hoc code signingContinued improving the Electron buildPushed the desktop-app code to GitHubWorked on making the Mac version easier to distributeKept the web version available as an alternative"}, {"post_id": 65613, "ts": "2026-09-10T21:07:53Z", "hours": 9.8333, "text": "Making Frictionless a Desktop AppI’ve been working on turning Frictionless into more than just a web app by creating a proper desktop version for macOS.I set up Electron and Electron Forge to package the existing Frictionless code into a standalone Mac application. The app now runs in its own window and keeps the same tools and features from the web version.I also configured the project for Apple Silicon Macs and successfully built the application into a distributable .zip file. I connected all of the new Electron files to the GitHub repository as well, so the desktop version is now part of the main project.One issue I ran into was macOS showing a “damaged” warning when opening the downloaded application. After investigating, I found that this is related to macOS security checks for unsigned applications rather than the app itself being broken. I’m now testing ad-hoc signing while keeping the web version available as the easiest way to use Frictionless.This was a big milestone for the project because Frictionless can now work as both a web application and a standalone desktop application.What I worked onAdded ElectronAdded Electron ForgeCreated the desktop app windowBuilt an Apple Silicon Mac versionCreated a distributable ZIPAdded the desktop files to GitHubTested macOS app signingKept the web version working alongside the desktop version"}, {"post_id": 65305, "ts": "2026-09-10T11:16:42Z", "hours": 8.9792, "text": "Turning Frictionless Into a Desktop AppI’ve been working on taking Frictionless beyond just being a web app and turning it into a proper desktop application.I used Electron to package the existing HTML, CSS, and JavaScript version into a native-style macOS app. This means Frictionless can now run in its own window instead of requiring a browser tab.I also set up Electron Forge so the project can be packaged into a distributable Mac application. The app successfully builds for Apple Silicon, which means it works with Macs using Apple Silicon processors.I connected the desktop version back to the same GitHub repository as the web version, so both versions can continue to be developed together.I also spent some time dealing with macOS security and app signing. The app itself was working, but macOS can show a “damaged” warning for unsigned applications downloaded from the internet. I’m now testing free ad-hoc signing for local use while keeping the web version available as the easiest way to try Frictionless.This is a pretty big step for the project because Frictionless is no longer just a simple website. It can now exist as both a web tool and a standalone desktop application.What I addedElectron desktop appmacOS Apple Silicon buildElectron Forge packagingDesktop app entry pointGitHub integration for the desktop sourcemacOS signing testingKept the original web version workingThe goal is to make Frictionless feel like a real, complete tool that can be used wherever it is most convenient."}, {"post_id": 65091, "ts": "2026-09-09T23:47:56Z", "hours": 8.4333, "text": "Connecting Everything TogetherToday I spent around 8 hours and 50 minutes working on Frictionless and connecting the new tools together more smoothly.With the number of features growing, I focused on making sure everything still feels like one application instead of a collection of separate tools. I cleaned up interactions between the different text tools, improved how results are displayed, and fixed smaller issues I found while testing everything.I also spent time testing different types of input, including messy text, repeated lines, formatted data, and larger pieces of content. This helped me find and fix a few edge cases that weren’t obvious when testing with simple examples.The project is getting much closer to the version I want to ship. At this point I’m focusing less on just adding features and more on making sure the features I already built actually feel polished and useful."}, {"post_id": 64807, "ts": "2026-09-09T14:14:11Z", "hours": 5.6, "text": "Expanding FrictionlessToday I worked on expanding Frictionless from a simple text-cleaning tool into a much more complete text and data workbench.I added a bunch of new tools for different situations, including duplicate line removal, sorting, case conversion, text statistics, JSON formatting and validation, CSV tools, Markdown tools, and Diff/Compare.I also worked on features like Undo/Redo and Saved Presets so users can perform multiple transformations without worrying about losing their original text, and save workflows they use regularly.The main goal with these changes was to make Frictionless something that could actually be useful in everyday projects instead of only being a basic copy-and-paste cleaner.There is still plenty I want to polish, but the project is starting to feel much more like a complete productivity tool."}, {"post_id": 64679, "ts": "2026-09-09T08:36:55Z", "hours": 8.3781, "text": "Today I worked on adding a proper Find & Replace feature to Frictionless.The goal was to make it easier to quickly change specific words or phrases without having to manually search through a large amount of text. I added separate find and replace inputs, along with options that give more control over how searches work.I also made sure the feature fits into the existing workflow instead of feeling like a separate tool. Users can search through their text, see how many matches were found, and replace individual matches or all matching text at once.This is one of the bigger improvements I’ve made recently because it makes Frictionless more useful for actually working with messy or repetitive text, rather than only cleaning and converting it."}, {"post_id": 64458, "ts": "2026-09-08T21:13:08Z", "hours": 11.2139, "text": "Today I spent some time improving a few smaller parts of Frictionless that aren’t necessarily big features, but make the app nicer to use.I adjusted some of the interactions around the text tools so they give clearer feedback when an action is completed. I also cleaned up a few small inconsistencies between different buttons and controls.These changes were mostly about the little details. Frictionless has quite a few different tools now, so making sure everything behaves consistently is becoming more important as the project grows.Nothing huge was added today, but the overall experience feels a bit more polished and predictable."}, {"post_id": 64116, "ts": "2026-09-08T09:52:57Z", "hours": 4.1708, "text": "Timer & Calendar Improvements Today I worked on two parts of Frictionless: the timer and the calendar. I added a timer so I can keep track of how long I’m spending on a task while working in the app. I also went through the calendar and fixed several issues with how it behaved and displayed information. The calendar needed some extra attention because small problems with dates and interactions made it less reliable to use. I cleaned those areas up and made the experience smoother. These features aren’t the main text-cleaning tools, but they fit the idea of Frictionless being a small productivity workbench rather than just a place to paste and format text. There are still some improvements I’d like to make, but both features are now working much more reliably."}, {"post_id": 63902, "ts": "2026-09-07T22:47:41Z", "hours": 10.9, "text": "Timer & Calendar Improvements Today I added a timer to the project to make it more useful and interactive. I also spent some time fixing issues with the calendar and making sure it works properly. The timer should make it easier to keep track of time while using the app, while the calendar fixes should make scheduling and viewing events smoother. There are still a few things I want to improve, but the core features are now working much better."}, {"post_id": 63495, "ts": "2026-09-07T11:51:38Z", "hours": 6.5144, "text": "Background & Calendar Improvements Today I added a green background to give the UI a cleaner and more consistent look. I also continued working on the calendar, making improvements to how it looks and functions. These changes help make the project feel more polished and easier to use. I’m happy with how the new background fits with the rest of the interface, and I’ll keep improving the calendar as I work on the project."}, {"post_id": 61875, "ts": "2026-09-05T01:06:44Z", "hours": 1.7117, "text": "Code Improvements Today I worked on improving and cleaning up the code to make it more organised and easier to understand. I went through different parts of the project, made some sections simpler, and fixed small issues along the way. The goal was to make the code feel more natural and readable while keeping everything working properly. This should also make it easier to continue adding features and fixing bugs in the future."}, {"post_id": 52825, "ts": "2026-08-23T05:39:34Z", "hours": 5.8, "text": "Today I spent a long session finishing up the main parts of Frictionless. I worked through the remaining code, fixed issues as I found them, and made sure the different parts of the project were working together properly. A lot of the work was focused on getting everything into a usable state rather than adding one specific feature. I went back through parts that weren’t quite working as expected and cleaned them up. This was a big step toward getting the project ready to use properly, and it gave me a much better base to build the next features on."}, {"post_id": 52691, "ts": "2026-08-22T23:34:53Z", "hours": 12.1053, "text": "Today I continued working on the main code for Frictionless. I ran into an error that stopped part of the project from working correctly, so I spent time tracking down what was causing it and fixing the problem. After getting it working again, I tested the affected parts to make sure the fix didn’t break anything else. I also made a few small adjustments while going through the code. This was mainly a debugging session, but fixing these problems helped make the project more stable and gave me a better understanding of how the different parts of the app connect."}, {"post_id": 52254, "ts": "2026-08-22T10:59:09Z", "hours": 5.1794, "text": "Today I continued building Frictionless and spent most of the session working through the code and debugging issues as they came up. I tested different parts of the project while developing and fixed problems that were preventing certain features from working properly. I also made small changes to improve how the different parts of the app worked together. Most of the progress today came from fixing problems rather than adding a single large feature. Each issue I solved made the project more stable and brought it closer to being a complete, usable workbench."}, {"post_id": 52008, "ts": "2026-08-22T01:13:23Z", "hours": 15.5908, "text": "Today I continued building the core of Frictionless, focusing on writing and connecting the main parts of the application. I worked through the structure of the project and started putting the different features together so they could work as one consistent experience. Along the way, I tested what I had built and made adjustments where things weren’t working as expected. At this stage, I was mainly focused on getting a solid foundation in place. This gave me something reliable to build on as I started adding more features and improving the overall UI."}]...
|
Title: Friction less by @jinjin | Stardance
Devlo Title: Friction less by @jinjin | Stardance
Devlogs:
Today I continued building the core of Frictionless, focusing on writing and connecting the main parts of the application. I worked through the structure of the project and started putting the different features together so they could work as one consistent experience. Along the way, I tested what I had built and made adjustments where things weren’t working as expected. At this stage, I was mainly focused on getting a solid foundation in place. This gave me something reliable to build on as I started adding more features and improving the overall UI.
Today I continued building Frictionless and spent most of the session working through the code and debugging issues as they came up. I tested different parts of the project while developing and fixed problems that were preventing certain features from working properly. I also made small changes to improve how the different parts of the app worked together. Most of the progress today came from fixing problems rather than adding a single large feature. Each issue I solved made the project more stable and brought it closer to being a complete, usable workbench.
Today I continued working on the main code for Frictionless. I ran into an error that stopped part of the project from working correctly, so I spent time tracking down what was causing it and fixing the problem. After getting it working again, I tested the affected parts to make sure the fix didn’t break anything else. I also made a few small adjustments while going through the code. This was mainly a debugging session, but fixing these problems helped make the project more stable and gave me a better understanding of how the different parts of the app connect.
Today I spent a long session finishing up the main parts of Frictionless. I worked through the remaining code, fixed issues as I found them, and made sure the different parts of the project were working together properly. A lot of the work was focused on getting everything into a usable state rather than adding one specific feature. I went back through parts that weren’t quite working as expected and cleaned them up. This was a big step toward getting the project ready to use properly, and it gave me a much better base to build the next features on.
Code Improvements Today I worked on improving and cleaning up the code to make it more organised and easier to understand. I went through different parts of the project, made some sections simpler, and fixed small issues along the way. The goal was to make the code feel more natural and readable while keeping everything working properly. This should also make it easier to continue adding features and fixing bugs in the future.
Background & Calendar Improvements Today I added a green background to give the UI a cleaner and more consistent look. I also continued working on the calendar, making improvements to how it looks and functions. These changes help make the project feel more polished and easier to use. I’m happy with how the new background fits with the rest of the interface, and I’ll keep improving the calendar as I work on the project.
Timer & Calendar Improvements Today I added a timer to the project to make it more useful and interactive. I also spent some time fixing issues with the calendar and making sure it works properly. The timer should make it easier to keep track of time while using the app, while the calendar fixes should make scheduling and viewing events smoother. There are still a few things I want to improve, but the core features are now working much better.
Timer & Calendar Improvements Today I worked on two parts of Frictionless: the timer and the calendar. I added a timer so I can keep track of how long I’m spending on a task while working in the app. I also went through the calendar and fixed several issues with how it behaved and displayed information. The calendar needed some extra attention because small problems with dates and interactions made it less reliable to use. I cleaned those areas up and made the experience smoother. These features aren’t the main text-cleaning tools, but they fit the idea of Frictionless being a small productivity workbench rather than just a place to paste and format text. There are still some improvements I’d like to make, but both features are now working much more reliably.
Today I spent some time improving a few smaller parts of Frictionless that aren’t necessarily big features, but make the app nicer to use.I adjusted some of the interactions around the text tools so they give clearer feedback when an action is completed. I also cleaned up a few small inconsistencies between different buttons and controls.These changes were mostly about the little details. Frictionless has quite a few different tools now, so making sure everything behaves consistently is becoming more important as the project grows.Nothing huge was added today, but the overall experience feels a bit more polished and predictable.
Today I worked on adding a proper Find & Replace feature to Frictionless.The goal was to make it easier to quickly change specific words or phrases without having to manually search through a large amount of text. I added separate find and replace inputs, along with options that give more control over how searches work.I also made sure the feature fits into the existing workflow instead of feeling like a separate tool. Users can search through their text, see how many matches were found, and replace individual matches or all matching text at once.This is one of the bigger improvements I’ve made recently because it makes Frictionless more useful for actually working with messy or repetitive text, rather than only cleaning and converting it.
Expanding FrictionlessToday I worked on expanding Frictionless from a simple text-cleaning tool into a much more complete text and data workbench.I added a bunch of new tools for different situations, including duplicate line removal, sorting, case conversion, text statistics, JSON formatting and validation, CSV tools, Markdown tools, and Diff/Compare.I also worked on features like Undo/Redo and Saved Presets so users can perform multiple transformations without worrying about losing their original text, and save workflows they use regularly.The main goal with these changes was to make Frictionless something that could actually be useful in everyday projects instead of only being a basic copy-and-paste cleaner.There is still plenty I want to polish, but the project is starting to feel much more like a complete productivity tool.
Connecting Everything TogetherToday I spent around 8 hours and 50 minutes working on Frictionless and connecting the new tools together more smoothly.With the number of features growing, I focused on making sure everything still feels like one application instead of a collection of separate tools. I cleaned up interactions between the different text tools, improved how results are displayed, and fixed smaller issues I found while testing everything.I also spent time testing different types of input, including messy text, repeated lines, formatted data, and larger pieces of content. This helped me find and fix a few edge cases that weren’t obvious when testing with simple examples.The project is getting much closer to the version I want to ship. At this point I’m focusing less on just adding features and more on making sure the features I already built actually feel polished and useful.
Turning Frictionless Into a Desktop AppI’ve been working on taking Frictionless beyond just being a web app and turning it into a proper desktop application.I used Electron to package the existing HTML, CSS, and JavaScript version into a native-style macOS app. This means Frictionless can now run in its own window instead of requiring a browser tab.I also set up Electron Forge so the project can be packaged into a distributable Mac application. The app successfully builds for Apple Silicon, which means it works with Macs using Apple Silicon processors.I connected the desktop version back to the same GitHub repository as the web version, so both versions can continue to be developed together.I also spent some time dealing with macOS security and app signing. The app itself was working, but macOS can show a “damaged” warning for unsigned applications downloaded from the internet. I’m now testing free ad-hoc signing for local use while keeping the web version available as the easiest way to try Frictionless.This is a pretty big step for the project because Frictionless is no longer just a simple website. It can now exist as both a web tool and a standalone desktop application.What I addedElectron desktop appmacOS Apple Silicon buildElectron Forge packagingDesktop app entry pointGitHub integration for the desktop sourcemacOS signing testingKept the original web version workingThe goal is to make Frictionless feel like a real, complete tool that can be used wherever it is most convenient.
Making Frictionless a Desktop AppI’ve been working on turning Frictionless into more than just a web app by creating a proper desktop version for macOS.I set up Electron and Electron Forge to package the existing Frictionless code into a standalone Mac application. The app now runs in its own window and keeps the same tools and features from the web version.I also configured the project for Apple Silicon Macs and successfully built the application into a distributable .zip file. I connected all of the new Electron files to the GitHub repository as well, so the desktop version is now part of the main project.One issue I ran into was macOS showing a “damaged” warning when opening the downloaded application. After investigating, I found that this is related to macOS security checks for unsigned applications rather than the app itself being broken. I’m now testing ad-hoc signing while keeping the web version available as the easiest way to use Frictionless.This was a big milestone for the project because Frictionless can now work as both a web application and a standalone desktop application.What I worked onAdded ElectronAdded Electron ForgeCreated the desktop app windowBuilt an Apple Silicon Mac versionCreated a distributable ZIPAdded the desktop files to GitHubTested macOS app signingKept the web version working alongside the desktop version
Fixing the Mac App and Improving DistributionI’ve been continuing work on the desktop version of Frictionless and focusing on making the Mac app easier to distribute.After successfully building the Electron version, I ran into an issue where macOS showed a “damaged” message when the app was downloaded. I investigated the problem and found that it was related to macOS security and the app being unsigned.I’ve now been working on ad-hoc signing the application and testing the build again. This has been useful because it showed me that building an application and actually distributing it are two different challenges.I also made sure the desktop-app changes were properly pushed to the Frictionless GitHub repository, so the project now contains both the original web version and the Electron desktop version.The main focus right now is making the desktop version as reliable as the web version while keeping the project simple and easy to access.What I worked onInvestigated the macOS “damaged app” issueTested ad-hoc code signingContinued improving the Electron buildPushed the desktop-app code to GitHubWorked on making the Mac version easier to distributeKept the web version available as an alternative
Polishing the Desktop VersionI’ve continued working on the desktop version of Frictionless and focused on making it feel more like a proper standalone application.A big part of this work has been testing the Mac build, fixing issues that appeared during packaging, and making sure the desktop version still has the same core functionality as the web version.I also spent time improving the overall reliability of the project after moving more of the code into the Electron setup. This included checking that the app opens correctly, that the different tools continue to work, and that the project can still be built and packaged when changes are made.The desktop version is getting much closer to feeling like a complete second version of Frictionless rather than just a website running inside a window.What I worked onTested the Mac desktop buildImproved Electron integrationChecked existing Frictionless toolsFixed packaging-related issuesImproved desktop reliabilityContinued preparing the app for distributionKept the web and desktop versions working together
Ships:
I built TidyPaste, a client-side web workbench designed to clean messy text, reformat data structures, and track session productivity - all inside a single browser tab....
|
1792878589.8854256
|
1793742589.8854256
|
|
35760
|
Algora by @diputs | Stardance
|
diputs
|
1
|
127.84
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-13T06:59:44Z", "hours": 95.0, "multiplier": 18.72, "payout": 0, "blessing": "neutral", "text": "Algora 1.0 Ship An attempt to put everything I wish I had when learning algorithms into one place. This project started when a friend asked me for help with USACO. While helping them, I started thinking back to my own path of learning algorithms and the things I wished I had when I was learning them. I wanted one place where I could not only read about an algorithm, but actually see it work, understand what is happening at each step, compare it with other algorithms, and look at both a teaching implementation and a more practical implementation. That idea eventually became Algora. What’s Included The first release currently includes: 15 sorting algorithms 17 searching algorithms Interactive algorithm visualizations Step by step execution and playback controls Algorithm specific workspaces for more complex algorithms Quick facts and complexity information Detailed algorithm explanations Pseudocode Teaching implementations in C, C++, Java, and Python Production style implementations in C, C++, Java, and Python Sorting algorithm comparison Searching algorithm comparison Comparison information including time complexity, space complexity, requirements, strengths, and weaknesses Warnings when algorithms are not directly comparable Individual pages for every algorithm The goal was to make each algorithm more than just a page of code. I wanted to be able to go from: What is this? → How does it work? → Can I see it happen? → Can I understand each step? → What does the code look like? → How does it compare to other approaches? Why I Built It I built Algora because I kept thinking about how much easier learning algorithms could have been if I had all of these things in one place when I was going through USACO. I’ve gone through the USACO training path myself and reached Platinum, and helping my friend brought me back to the way I learned all of this in the first place. So instead of making another collection of algorithm implementations, I wanted to make the resource I wish I had back then. Algora is an attempt to put everything I wish I had when learning algorithms into one place. The Making of Algora I also recorded a large part of the development process while building the project. The video below is a 1000× speed timelapse made from roughly 70 hours of raw development footage. I lost some footage along the way, so it does not contain absolutely everything, but most of the development process is there. Apparently Stands saw the size of the video and decided it simply did not exist D: If you really want to watch the video, the link is here: https://github.com/diputs-sudo/algora/tree/main/video you might have to download it :( Thank You Thank you to everyone who supported me while I was building Algora. Thank you to everyone who tested things, gave feedback, helped me figure things out, listened to me ramble about algorithms, or simply encouraged me to keep working on it. This project ended up becoming much bigger than the original idea, and I’m really happy that I finally get to share it.", "repo": "https://github.com/diputs-sudo/algora", "demo": "https://diputs-sudo.github.io/algora/"}]...
|
[{"post_id": 52833, "ts": "202 [{"post_id": 52833, "ts": "2026-08-23T05:58:16Z", "hours": 3.8481, "text": "algora dev log #68 Implemented the page for Dijkstra. Finished the algorithm workspace, Both the advanced and teaching version of the algorithm in all 4 languages including python, c, java and c++"}, {"post_id": 52724, "ts": "2026-08-23T01:25:57Z", "hours": 0.5294, "text": "I got my latest project reviews back today, and first of all thank you so much to everyone who took the time to look through the project! A lot of the feedback genuinely made me really happy. Some people pointed out bugs I hadn’t noticed, some gave me ideas for things I could improve, and a few of you even said you wanted to bookmark the project or use it for studying algorithms, which honestly means a lot to me. There were also some questions about the tech stack and how different parts of the project were built, which I’m happy to answer. Review #1: “what is this stack? html, typescript, c, c++ and java?” The website itself is built primarily with HTML, CSS, and TypeScript. The additional languages: C, C++, Java, and Python are there because the project includes implementations of the algorithms in multiple languages. Review #5: “Dijkstra doesn’t work, I get a 404” The Ship is mainly about sorting and searching algorithms. I think by the time you visited the pathfinding page, I had already started working on the new pathfinding section but hadn’t finished implementing it yet, which is why Dijkstra gave you a 404. I’m actively working on the Dijkstra right now tho! Review #8: “the amount of time to type out your project at 70 words per minute is around 200 hours” This assumes every character was typed manually. I use tab completion and copy/paste repetitive code. For example, most of the TypeScript engine API is basically the same across algorithms, so I’m obviously not going to retype the same thing every time Review #8: “make no mention of struggles or frustrations, inspirations or ideas” I personally don’t like putting my frustration into project logs. I usually just keep my devlogs focused on what I made, changed, or learned. Review #8: “You type out rgba and hexadecimals by hand without a tool” I sketched the website layout on my iPad and used it as a reference while coding. I can’t exactly copy/paste an RGB value from my iPad onto my computer, so I just typed it Review #8: “you type out entire svg lines” The SVGs are actually copy/pasted. They’re reused assets and basically the same every time. The timelapse is around 1000x speed, so a paste just looks like the SVG suddenly appeared. Review #8: “You never delete any lines in your timelapses” I cut most of the boring debugging out because who wants to watch that. That’s also why sometimes the timelapse jumps from broken code to fixed code. I wanted the videos to stay short and watchable. Review #8: “Show us your second monitor” There is no second monitor. You assumed there was one because I wasn’t recording my full screen. I intentionally only record the part of my screen relevant to the project because the rest is my privacy. I also look through a lot of references, documentation, and other pages while working, and I don’t think anyone wants all of that flashing across a 1000x timelapse anyway. I don’t mind people questioning my work or asking how I did something, but I do think there’s a difference between asking and immediately assuming someone faked their work. Some of the comments also became pretty personal, which was honestly disappointing to see. Review #9: “Don’t bring it down pls” don’t worry, I’m planning to keep the website up I’m really happy that you actually want to use it though, that’s basically the whole reason I made this project And to everyone else who left a review, thank you so much!! I didn’t want to respond to every review with just “thank you” over and over again, but I read all of them and really appreciate all the feedback Seeing people say they actually want to use the website for learning, revision, or even USACO genuinely made me really happy. That’s basically why I wanted to build this project in the first place"}, {"post_id": 52049, "ts": "2026-08-22T02:52:45Z", "hours": 3.9061, "text": "algora dev log #68 Implemented Python C++ Java and C for D* Lite. Both the advanced and teaching implementation is finished."}, {"post_id": 51461, "ts": "2026-08-21T05:51:58Z", "hours": 4.48, "text": "algora dev log #67 Implemented the page for D* Lite . Finished the algorithm workspace, this one is hard and the TypeScript is behaving weirdly, Gotta rewrite a lot of times for the engine to render correctly with the different heuristic implemented and clicking to change the board while the algorithm runs But it works now. Really proud of it."}, {"post_id": 50795, "ts": "2026-08-20T05:54:40Z", "hours": 2.8314, "text": "algora dev log #66 Implemented the page for Bidirectional BFS. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 50111, "ts": "2026-08-19T05:36:14Z", "hours": 3.2497, "text": "algora dev log #65 Implemented the page for BFS. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 49389, "ts": "2026-08-18T05:43:00Z", "hours": 3.0567, "text": "algora dev log #64 Implemented the page for Bellman-Ford. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 49313, "ts": "2026-08-18T01:54:06Z", "hours": 2.8961, "text": "algora dev log #63 Implemented the page for A* pathfinding. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 47858, "ts": "2026-08-16T02:52:38Z", "hours": 2.9633, "text": "algora dev log #62 Implemented the page for 0-1 BFS. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 47341, "ts": "2026-08-15T07:02:41Z", "hours": 1.1183, "text": "algora dev log # 61 Finished both standard and advanced DFS implementations. Standard version keeps the algorithm clean. Advanced version adds a more optimized/practical implementation with deeper control over traversal"}, {"post_id": 47310, "ts": "2026-08-15T05:48:18Z", "hours": 2.6106, "text": "algora dev log # 60 Built the reusable grid search engine for graph/search algorithms. Finished DFS as the first full test of the engine traversal, animation, visited states, and path reconstruction all working. Added randomized maze generation with start/target. Built and integrated the full DFS algorithm page + interactive workspace. Engine is now ready to reuse for the rest of the search algorithms"}, {"post_id": 46709, "ts": "2026-08-14T04:49:55Z", "hours": 1.3528, "text": "Algora dev log #59 Apparently shipping 1.0 means I can add more things now. Started building out graph algorithms, new index, filters, learning paths, complexity info, and the foundation for the graph workspaces."}, {"post_id": 46178, "ts": "2026-08-13T06:31:08Z", "hours": 0.3875, "text": "#algora dev log #58 Update Readme for the shipping :D The Making of Algora Below is a 1000× speed timelapse of me building the project. I lost some footage along the way, so this isn’t every single thing that happened, but most of the development is here. Altogether, it represents roughly 70 hours of raw development footage condensed into this video. It is kind of crazy to look back at all of that work and see it compressed into a few minutes."}, {"post_id": 46128, "ts": "2026-08-13T04:14:50Z", "hours": 2.1542, "text": "#algora dev log # 57 Finally finished the Algorithm Comparison page for searching algorithm class, Compelted the HTML and TypeScript implementations. Added some details like warnings. Finished with the Search Class of Algorithms 🎉"}, {"post_id": 45583, "ts": "2026-08-12T05:26:59Z", "hours": 3.4308, "text": "algora dev log #55 Upgraded the Exponential Search, Galloping Search, and Jump Search workspace so they are more intuitive. :D and the most time consuming part of upgrading the css"}, {"post_id": 45017, "ts": "2026-08-11T04:52:47Z", "hours": 1.8975, "text": "algora dev log #55 Implemented the page for Rotated Sorted Array Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 44389, "ts": "2026-08-10T03:07:03Z", "hours": 2.0311, "text": "algora dev log #54 Implemented the page for Quickselect. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 43681, "ts": "2026-08-09T02:42:06Z", "hours": 2.0572, "text": "algora dev log #53 Implemented the page for Parametric Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 43072, "ts": "2026-08-08T04:32:03Z", "hours": 1.9503, "text": "algora dev log #52 Implemented the page for Hash Table Lookup. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 42979, "ts": "2026-08-07T23:56:59Z", "hours": 2.6147, "text": "algora dev log #51 Implemented the page for Fractional Cascading. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 42364, "ts": "2026-08-07T01:26:27Z", "hours": 1.7836, "text": "algora dev log #50 Finishes and upgrade the page for Bitonic Array Search, added custom workspace for the search"}, {"post_id": 41689, "ts": "2026-08-06T02:07:07Z", "hours": 2.0547, "text": "algora dev log #49 Implemented the page for Uniform Binary Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 41642, "ts": "2026-08-05T23:59:03Z", "hours": 1.9908, "text": "algora dev log #48 Implemented the page for Ternary Linear Search. Finished both easy and advanced versions, Finished implementations in C, C++, Java, and Python."}, {"post_id": 41070, "ts": "2026-08-05T01:06:29Z", "hours": 2.38, "text": "algora dev log #47 Implemented the page for Sentinel Linear Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 40527, "ts": "2026-08-04T03:32:57Z", "hours": 2.4717, "text": "algora dev log #46 Implemented the page for Meta Binary Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python."}, {"post_id": 40459, "ts": "2026-08-04T00:04:15Z", "hours": 1.4769, "text": "algora dev log #45 Implemented the page for Linear Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 40392, "ts": "2026-08-03T21:13:25Z", "hours": 2.0106, "text": "algora dev log #44 Implemented the page for Jump Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 39836, "ts": "2026-08-03T02:50:53Z", "hours": 1.525, "text": "algora dev log #43 Thought the interpolation search lab was done until I actually used it. It turned out it showed the result, but not the reasoning. Added a new visualization that explains how the probe is estimated instead of just where it lands."}, {"post_id": 39804, "ts": "2026-08-03T01:17:01Z", "hours": 1.9919, "text": "algora dev log #42 Implemented the page for Interpolation Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 39276, "ts": "2026-08-02T04:32:36Z", "hours": 2.2861, "text": "algora dev log #41 Implemented the page for Galloping Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python."}, {"post_id": 39212, "ts": "2026-08-02T01:01:41Z", "hours": 2.2714, "text": "algora dev log #40 Implemented the page for Fibonacci Search. Finished both easy and advanced version of Fibonacci search implementations in C, C++, Java, and Python. Together with the engine"}, {"post_id": 39161, "ts": "2026-08-01T22:06:30Z", "hours": 0.7069, "text": "algora dev log #39 Spent some time implementing the advanced version of Exponential Search. Finished implementations in C, C++, Java, and Python."}, {"post_id": 39123, "ts": "2026-08-01T20:38:05Z", "hours": 0.9406, "text": "algora dev log #38 Spent some time implementing the advanced version of Bitonic Array Search. Finished implementations in C, C++, Java, and Python."}, {"post_id": 39070, "ts": "2026-08-01T19:16:21Z", "hours": 0.6119, "text": "algora dev log #37 Spent some time implementing the advanced version of Binary Search . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38591, "ts": "2026-08-01T02:15:08Z", "hours": 0.6681, "text": "algora dev log #36 Spent some time implementing the advanced version of Tournament Sort . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38566, "ts": "2026-08-01T01:29:13Z", "hours": 0.7253, "text": "algora dev log #35 Spent some time implementing the advanced version of Tim Sort . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38545, "ts": "2026-08-01T00:38:44Z", "hours": 0.6617, "text": "algora dev log #34 Spent some time implementing the advanced version of Shell Sort . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38500, "ts": "2026-07-31T22:30:21Z", "hours": 0.5581, "text": "algora dev log #33 Spent some time implementing the advanced version of Selection Sort . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38484, "ts": "2026-07-31T21:52:30Z", "hours": 0.6564, "text": "algora dev log #32 Spent some time implementing the advanced version of Radix Sort . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38467, "ts": "2026-07-31T21:09:48Z", "hours": 0.8247, "text": "algora dev log #31 Spent some time implementing the advanced version of Quick Sort . Finished implementations in C, C++, Java, and Python."}, {"post_id": 38379, "ts": "2026-07-31T18:44:07Z", "hours": 1.1031, "text": "algora dev log #30 Spent some time implementing the advanced version of Merge Sort (in place) today. Finished implementations in C, C++, Java, and Python. honestly this one is pretty hard to get it right"}, {"post_id": 37976, "ts": "2026-07-31T01:43:35Z", "hours": 0.7942, "text": "algora dev log #29 Spent some time implementing the advanced version of Merge Sort today. Finished implementations in C, C++, Java, and Python."}, {"post_id": 37957, "ts": "2026-07-31T00:38:05Z", "hours": 2.0833, "text": "algora dev log #28 Spent some time implementing the advanced version of Insertion and Intro Sort today. Finished implementations in C, C++, Java, and Python."}, {"post_id": 37430, "ts": "2026-07-30T04:53:22Z", "hours": 0.6233, "text": "#algora dev log #27 Spent some time implementing the advanced version of Heap Sort today. Finished implementations in C, C++, Java, and Python."}, {"post_id": 37420, "ts": "2026-07-30T03:54:46Z", "hours": 0.6931, "text": "algora dev log #26 Spent some time implementing the advanced version of Counting Sort today. Finished implementations in C, C++, Java, and Python."}, {"post_id": 37336, "ts": "2026-07-30T00:02:09Z", "hours": 0.8036, "text": "algora dev log #25 Spent some time implementing the advanced version of Bucket Sort today. Finished implementations in C, C++, Java, and Python."}, {"post_id": 37323, "ts": "2026-07-29T23:10:28Z", "hours": 0.6233, "text": "algora dev log #24 Spent some time implementing the advanced version of Bubble Sort today. Finished implementations in C, C++, Java, and Python."}, {"post_id": 36788, "ts": "2026-07-29T01:59:30Z", "hours": 1.8864, "text": "algora dev log #23 Changed my mind on this one. I want each algorithm page to include a production style implementation so readers can compare a simplified, educational version with a more advanced version that’s closer to what you might actually see in production. Because of that, I went back and started adding Bitonic Sort implementations in all four supported languages."}, {"post_id": 36704, "ts": "2026-07-28T22:39:27Z", "hours": 1.6408, "text": "algora dev log #22 Spent some time building the Exponential Search page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Fibonacci Search!"}, {"post_id": 36567, "ts": "2026-07-28T19:30:18Z", "hours": 2.3331, "text": "algora dev log #22 Spent some time building the Bitonic Array Search page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Exponential Search!"}, {"post_id": 36167, "ts": "2026-07-28T02:34:39Z", "hours": 2.0194, "text": "algora dev log #21 Spent some time building the Binary Search page today! Added the frontend and TypeScript. will finished the python, c, hava, and c++ implementation later!"}, {"post_id": 36125, "ts": "2026-07-28T00:26:15Z", "hours": 0.2853, "text": "algora dev log #20 Adding the missing main page TypeScript, now the animation is working in the main page."}, {"post_id": 36108, "ts": "2026-07-28T00:02:00Z", "hours": 1.3203, "text": "algora dev log #19 Adding the main page for searching algorithms layout, finishing the HTML and TypeScript for the page"}, {"post_id": 35571, "ts": "2026-07-27T03:12:16Z", "hours": 2.0331, "text": "algora dev log #18 Worked on the new algorithm comparison page. You can now compare two sorting algorithms side by side, view their information, watch the visualizations together, and browse the implementations in C, C++, Java, and Python. This ended up being one of the larger frontend pages in Algora so far and took a long time to write the typescript engine."}, {"post_id": 35498, "ts": "2026-07-26T23:37:19Z", "hours": 1.0839, "text": "algora dev log #17 Finished Tournament Sort page today! Added the TypeScript, then finish implementing the algorithm in C, C++, Java, and Python."}, {"post_id": 34950, "ts": "2026-07-26T02:13:55Z", "hours": 0.5944, "text": "algora dev log #16 don’t have much time today but build the html page for the Tournament Sort page today! Later on will Added the TypeScript, then finish implementing the algorithm in C, C++, Java, and Python."}, {"post_id": 34392, "ts": "2026-07-25T02:28:24Z", "hours": 1.7706, "text": "algora dev log #15 Spent some time building the Tim Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Tournament Sort!"}, {"post_id": 33831, "ts": "2026-07-24T02:12:45Z", "hours": 1.135, "text": "algora dev log #14 Spent some time building the Shell Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Tim Sort!"}, {"post_id": 33801, "ts": "2026-07-24T00:59:13Z", "hours": 1.1319, "text": "algora dev log #13 Spent some time building the Selection Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Shell Sort!"}, {"post_id": 33277, "ts": "2026-07-23T02:07:28Z", "hours": 1.3489, "text": "algora dev log #12 Spent some time building the Radix Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Selection Sort!"}, {"post_id": 33173, "ts": "2026-07-22T20:46:04Z", "hours": 1.49, "text": "algora dev log #11 Spent some time building the Quick Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Radix Sort!"}, {"post_id": 32730, "ts": "2026-07-22T02:16:03Z", "hours": 1.4678, "text": "algora dev log #10 Spent some time building the Merge Sort (in place) page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Quick Sort!"}, {"post_id": 32695, "ts": "2026-07-22T00:35:59Z", "hours": 1.7364, "text": "algora dev log #9 Spent some time building the Merge Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python.Next up: Merge (in place) Sort!"}, {"post_id": 32136, "ts": "2026-07-21T02:57:42Z", "hours": 1.9833, "text": "algora dev log #9 Spent some time building the Intro Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Merge Sort!"}, {"post_id": 32097, "ts": "2026-07-21T00:52:09Z", "hours": 1.195, "text": "algora dev log #8 Spent some time building the Insertion Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Intro Sort!"}, {"post_id": 31515, "ts": "2026-07-19T23:55:04Z", "hours": 1.6153, "text": "algora dev log #7 Spent some time building the Heap Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python.Next up: insertion Sort!"}, {"post_id": 31020, "ts": "2026-07-19T02:32:46Z", "hours": 1.5067, "text": "algora dev log #6 Spent some time building the Counting Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Heap Sort!"}, {"post_id": 30422, "ts": "2026-07-17T23:05:03Z", "hours": 1.6528, "text": "algora dev log #5 Spent some time building the Bucket Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Counting Sort!"}, {"post_id": 30350, "ts": "2026-07-17T20:27:56Z", "hours": 1.4964, "text": "algora dev log #4 Spent some time building the Bubble Sort page today! Added the frontend and TypeScript then finished implementations in C, C++, Java, and Python. Next up: Bucket Sort !"}, {"post_id": 29857, "ts": "2026-07-17T00:36:27Z", "hours": 5.5211, "text": "#Algora dev Log #3 Today’s goal was simple: Get Bitonic Sort fully working from end to end. Turns out that meant building a lot more than just Bitonic Sort. The day started with finishing the Bitonic Sort page itself. The visualizer, controls, explanations, pseudocode section, code viewer, and all the usual algorithm page stuff are now in place. At this point the page finally feels like a real part of the site instead of a placeholder. Most of the work ended up happening behind the scenes. I spent a good chunk of time building out the animation system that powers the visualizer. The goal was to make algorithms describe what they’re doing (compare, swap, finished, etc.) and let the frontend handle the actual animation. It took a bit of trial and error, but the system is finally working and feels flexible enough to support future algorithms. I also ended up writing way more TypeScript than expected. What started as “I just need Bitonic Sort working” somehow turned into multiple files handling animation control, code loading, documentation parsing, syntax highlighting, copy-to-clipboard functionality, and a bunch of other supporting systems. After that came the real test: implementing Bitonic Sort in all four supported languages. Python C++ Java C The actual algorithm wasn’t the hard part. The important part was making sure everything worked together and that the platform could properly support multiple language implementations for the same algorithm. Thankfully, it worked. By the end of the day I had: Finished the Bitonic Sort page Finished the animation engine Added playback controls Built the code loading system Added documentation parsing Implemented Bitonic Sort in C, C++, Python, and Java Connected everything together The biggest win isn’t really Bitonic Sort itself. The biggest win is that the system now works. Future sorting algorithms should be significantly easier to add because most of the annoying infrastructure work is finally out of the way. Current Status Bitonic Sort page complete Animation system working Multi-language code viewer working Bitonic Sort implemented in C, C++, Python, and Java First sorting algorithm fully integrated into Algora Next up: more algorithms !!"}, {"post_id": 29279, "ts": "2026-07-16T02:56:46Z", "hours": 3.0047, "text": "Algora dev log #2! Spent another session focused on building the Sorting Algorithm Index for Algora. The goal was to create a dedicated hub where users can browse algorithms, compare characteristics, and quickly find the right visualization to explore. Most of the work went into designing the overall layout, building algorithm cards, organizing metadata, and creating filtering and discovery systems. A large portion of the work has gone into creating the Sorting Algorithm Index, a central hub where users can browse, discover, and eventually compare different sorting algorithms. Most of this process involved designing and implementing the interface using HTML and CSS, with a focus on creating a clean layout that can scale as more algorithms and features are added. The page now includes searchable algorithm cards, filtering options, learning path recommendations, and categorized algorithm metadata to help users quickly find relevant topics. While the visual design makes up the majority of the implementation, a small amount of TypeScript has also been introduced to support interactive features such as search and filtering. Progress Continued work on the Algora frontend Improved the landing page and overall UI Fixed various styling and layout issues Continued polishing the user experience Next Steps Implement Python versions of all sorting algorithms Implement C++ versions of all sorting algorithms Implement Java versions of all sorting algorithms Implement C versions of all sorting algorithms Connect code implementations to algorithm pages Continue work on visualization and comparison tools Planned Sorting Algorithms Bitonic Sort Bubble Sort Bucket Sort Counting Sort Heap Sort Insertion Sort Intro Sort Merge Sort Merge Sort (In Place) Quick Sort Radix Sort Selection Sort Shell Sort Tim Sort Tournament Sort"}, {"post_id": 29208, "ts": "2026-07-15T23:03:45Z", "hours": 1.8942, "text": "Working on Algora Spent most of today working on the frontend for Algora , a project I’m building to help learn algorithms through interactive visualizations and comparisons. A lot of my time went into building the main landing page and polishing the overall look of the site. Surprisingly, the hardest part wasn’t the algorithms themselves which ofc it was CSS. I ended up spending way longer than expected trying to get layouts, spacing, responsiveness, and animations to behave the way I wanted. At this point my wrist is probably filing complaints against me. Not everything is working yet either. Some parts of the site are still unfinished, and a few features (including parts of the preview and visualization system) are still being actively worked on. There were definitely a lot of moments where something looked fine in my head and then completely broke the second I opened it in the browser. Even though progress felt slower than I expected, it’s starting to come together. The homepage is beginning to feel like something real instead of a collection of random components, and the overall direction of the project is becoming much clearer. Today’s Progress Continued building the Algora frontend Worked on the main landing page Improved layout and styling across multiple sections Fixed various UI issues Continued work on algorithm visualizations Recorded a development timelapse Still a long way to go, but seeing everything slowly come together has been pretty motivating."}]...
|
Title: Algora by @diputs | Stardance
Devlogs:
Wor Title: Algora by @diputs | Stardance
Devlogs:
Working on Algora Spent most of today working on the frontend for Algora , a project I’m building to help learn algorithms through interactive visualizations and comparisons. A lot of my time went into building the main landing page and polishing the overall look of the site. Surprisingly, the hardest part wasn’t the algorithms themselves which ofc it was CSS. I ended up spending way longer than expected trying to get layouts, spacing, responsiveness, and animations to behave the way I wanted. At this point my wrist is probably filing complaints against me. Not everything is working yet either. Some parts of the site are still unfinished, and a few features (including parts of the preview and visualization system) are still being actively worked on. There were definitely a lot of moments where something looked fine in my head and then completely broke the second I opened it in the browser. Even though progress felt slower than I expected, it’s starting to come together. The homepage is beginning to feel like something real instead of a collection of random components, and the overall direction of the project is becoming much clearer. Today’s Progress Continued building the Algora frontend Worked on the main landing page Improved layout and styling across multiple sections Fixed various UI issues Continued work on algorithm visualizations Recorded a development timelapse Still a long way to go, but seeing everything slowly come together has been pretty motivating.
Algora dev log #2! Spent another session focused on building the Sorting Algorithm Index for Algora. The goal was to create a dedicated hub where users can browse algorithms, compare characteristics, and quickly find the right visualization to explore. Most of the work went into designing the overall layout, building algorithm cards, organizing metadata, and creating filtering and discovery systems. A large portion of the work has gone into creating the Sorting Algorithm Index, a central hub where users can browse, discover, and eventually compare different sorting algorithms. Most of this process involved designing and implementing the interface using HTML and CSS, with a focus on creating a clean layout that can scale as more algorithms and features are added. The page now includes searchable algorithm cards, filtering options, learning path recommendations, and categorized algorithm metadata to help users quickly find relevant topics. While the visual design makes up the majority of the implementation, a small amount of TypeScript has also been introduced to support interactive features such as search and filtering. Progress Continued work on the Algora frontend Improved the landing page and overall UI Fixed various styling and layout issues Continued polishing the user experience Next Steps Implement Python versions of all sorting algorithms Implement C++ versions of all sorting algorithms Implement Java versions of all sorting algorithms Implement C versions of all sorting algorithms Connect code implementations to algorithm pages Continue work on visualization and comparison tools Planned Sorting Algorithms Bitonic Sort Bubble Sort Bucket Sort Counting Sort Heap Sort Insertion Sort Intro Sort Merge Sort Merge Sort (In Place) Quick Sort Radix Sort Selection Sort Shell Sort Tim Sort Tournament Sort
#Algora dev Log #3 Today’s goal was simple: Get Bitonic Sort fully working from end to end. Turns out that meant building a lot more than just Bitonic Sort. The day started with finishing the Bitonic Sort page itself. The visualizer, controls, explanations, pseudocode section, code viewer, and all the usual algorithm page stuff are now in place. At this point the page finally feels like a real part of the site instead of a placeholder. Most of the work ended up happening behind the scenes. I spent a good chunk of time building out the animation system that powers the visualizer. The goal was to make algorithms describe what they’re doing (compare, swap, finished, etc.) and let the frontend handle the actual animation. It took a bit of trial and error, but the system is finally working and feels flexible enough to support future algorithms. I also ended up writing way more TypeScript than expected. What started as “I just need Bitonic Sort working” somehow turned into multiple files handling animation control, code loading, documentation parsing, syntax highlighting, copy-to-clipboard functionality, and a bunch of other supporting systems. After that came the real test: implementing Bitonic Sort in all four supported languages. Python C++ Java C The actual algorithm wasn’t the hard part. The important part was making sure everything worked together and that the platform could properly support multiple language implementations for the same algorithm. Thankfully, it worked. By the end of the day I had: Finished the Bitonic Sort page Finished the animation engine Added playback controls Built the code loading system Added documentation parsing Implemented Bitonic Sort in C, C++, Python, and Java Connected everything together The biggest win isn’t really Bitonic Sort itself. The biggest win is that the system now works. Future sorting algorithms should be significantly easier to add because most of the annoying infrastructure work is finally out of the way. Current Status Bitonic Sort page complete Animation system working Multi-language code viewer working Bitonic Sort implemented in C, C++, Python, and Java First sorting algorithm fully integrated into Algora Next up: more algorithms !!
algora dev log #4 Spent some time building the Bubble Sort page today! Added the frontend and TypeScript then finished implementations in C, C++, Java, and Python. Next up: Bucket Sort !
algora dev log #5 Spent some time building the Bucket Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Counting Sort!
algora dev log #6 Spent some time building the Counting Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Heap Sort!
algora dev log #7 Spent some time building the Heap Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python.Next up: insertion Sort!
algora dev log #8 Spent some time building the Insertion Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Intro Sort!
algora dev log #9 Spent some time building the Intro Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Merge Sort!
algora dev log #9 Spent some time building the Merge Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python.Next up: Merge (in place) Sort!
algora dev log #10 Spent some time building the Merge Sort (in place) page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Quick Sort!
algora dev log #11 Spent some time building the Quick Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Radix Sort!
algora dev log #12 Spent some time building the Radix Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Selection Sort!
algora dev log #13 Spent some time building the Selection Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Shell Sort!
algora dev log #14 Spent some time building the Shell Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Tim Sort!
algora dev log #15 Spent some time building the Tim Sort page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Tournament Sort!
algora dev log #16 don’t have much time today but build the html page for the Tournament Sort page today! Later on will Added the TypeScript, then finish implementing the algorithm in C, C++, Java, and Python.
algora dev log #17 Finished Tournament Sort page today! Added the TypeScript, then finish implementing the algorithm in C, C++, Java, and Python.
algora dev log #18 Worked on the new algorithm comparison page. You can now compare two sorting algorithms side by side, view their information, watch the visualizations together, and browse the implementations in C, C++, Java, and Python. This ended up being one of the larger frontend pages in Algora so far and took a long time to write the typescript engine.
algora dev log #19 Adding the main page for searching algorithms layout, finishing the HTML and TypeScript for the page
algora dev log #20 Adding the missing main page TypeScript, now the animation is working in the main page.
algora dev log #21 Spent some time building the Binary Search page today! Added the frontend and TypeScript. will finished the python, c, hava, and c++ implementation later!
algora dev log #22 Spent some time building the Bitonic Array Search page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Exponential Search!
algora dev log #22 Spent some time building the Exponential Search page today! Added the frontend and TypeScript, then finished implementations in C, C++, Java, and Python. Next up: Fibonacci Search!
algora dev log #23 Changed my mind on this one. I want each algorithm page to include a production style implementation so readers can compare a simplified, educational version with a more advanced version that’s closer to what you might actually see in production. Because of that, I went back and started adding Bitonic Sort implementations in all four supported languages.
algora dev log #24 Spent some time implementing the advanced version of Bubble Sort today. Finished implementations in C, C++, Java, and Python.
algora dev log #25 Spent some time implementing the advanced version of Bucket Sort today. Finished implementations in C, C++, Java, and Python.
algora dev log #26 Spent some time implementing the advanced version of Counting Sort today. Finished implementations in C, C++, Java, and Python.
#algora dev log #27 Spent some time implementing the advanced version of Heap Sort today. Finished implementations in C, C++, Java, and Python.
algora dev log #28 Spent some time implementing the advanced version of Insertion and Intro Sort today. Finished implementations in C, C++, Java, and Python.
algora dev log #29 Spent some time implementing the advanced version of Merge Sort today. Finished implementations in C, C++, Java, and Python.
algora dev log #30 Spent some time implementing the advanced version of Merge Sort (in place) today. Finished implementations in C, C++, Java, and Python. honestly this one is pretty hard to get it right
algora dev log #31 Spent some time implementing the advanced version of Quick Sort . Finished implementations in C, C++, Java, and Python.
algora dev log #32 Spent some time implementing the advanced version of Radix Sort . Finished implementations in C, C++, Java, and Python.
algora dev log #33 Spent some time implementing the advanced version of Selection Sort . Finished implementations in C, C++, Java, and Python.
algora dev log #34 Spent some time implementing the advanced version of Shell Sort . Finished implementations in C, C++, Java, and Python.
algora dev log #35 Spent some time implementing the advanced version of Tim Sort . Finished implementations in C, C++, Java, and Python.
algora dev log #36 Spent some time implementing the advanced version of Tournament Sort . Finished implementations in C, C++, Java, and Python.
algora dev log #37 Spent some time implementing the advanced version of Binary Search . Finished implementations in C, C++, Java, and Python.
algora dev log #38 Spent some time implementing the advanced version of Bitonic Array Search. Finished implementations in C, C++, Java, and Python.
algora dev log #39 Spent some time implementing the advanced version of Exponential Search. Finished implementations in C, C++, Java, and Python.
algora dev log #40 Implemented the page for Fibonacci Search. Finished both easy and advanced version of Fibonacci search implementations in C, C++, Java, and Python. Together with the engine
algora dev log #41 Implemented the page for Galloping Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #42 Implemented the page for Interpolation Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #43 Thought the interpolation search lab was done until I actually used it. It turned out it showed the result, but not the reasoning. Added a new visualization that explains how the probe is estimated instead of just where it lands.
algora dev log #44 Implemented the page for Jump Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #45 Implemented the page for Linear Search. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #46 Implemented the page for Meta Binary Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #47 Implemented the page for Sentinel Linear Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #48 Implemented the page for Ternary Linear Search. Finished both easy and advanced versions, Finished implementations in C, C++, Java, and Python.
algora dev log #49 Implemented the page for Uniform Binary Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #50 Finishes and upgrade the page for Bitonic Array Search, added custom workspace for the search
algora dev log #51 Implemented the page for Fractional Cascading. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #52 Implemented the page for Hash Table Lookup. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #53 Implemented the page for Parametric Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #54 Implemented the page for Quickselect. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #55 Implemented the page for Rotated Sorted Array Search. Finished both easy and advanced versions, Made it’s own custom workspace. Finished implementations in C, C++, Java, and Python.
algora dev log #55 Upgraded the Exponential Search, Galloping Search, and Jump Search workspace so they are more intuitive. :D and the most time consuming part of upgrading the css
#algora dev log # 57 Finally finished the Algorithm Comparison page for searching algorithm class, Compelted the HTML and TypeScript implementations. Added some details like warnings. Finished with the Search Class of Algorithms 🎉
#algora dev log #58 Update Readme for the shipping :D The Making of Algora Below is a 1000× speed timelapse of me building the project. I lost some footage along the way, so this isn’t every single thing that happened, but most of the development is here. Altogether, it represents roughly 70 hours of raw development footage condensed into this video. It is kind of crazy to look back at all of that work and see it compressed into a few minutes.
Algora dev log #59 Apparently shipping 1.0 means I can add more things now. Started building out graph algorithms, new index, filters, learning paths, complexity info, and the foundation for the graph workspaces.
algora dev log # 60 Built the reusable grid search engine for graph/search algorithms. Finished DFS as the first full test of the engine traversal, animation, visited states, and path reconstruction all working. Added randomized maze generation with start/target. Built and integrated the full DFS algorithm page + interactive workspace. Engine is now ready to reuse for the rest of the search algorithms
algora dev log # 61 Finished both standard and advanced DFS implementations. Standard version keeps the algorithm clean. Advanced version adds a more optimized/practical implementation with deeper control over traversal
algora dev log #62 Implemented the page for 0-1 BFS. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #63 Implemented the page for A* pathfinding. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #64 Implemented the page for Bellman-Ford. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #65 Implemented the page for BFS. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #66 Implemented the page for Bidirectional BFS. Finished both easy and advanced versions, finished implementations in C, C++, Java, and Python.
algora dev log #67 Implemented the page for D* Lite . Finished the algorithm workspace, this one is hard and the TypeScript is behaving weirdly, Gotta rewrite a lot of times for the engine to render correctly with the different heuristic implemented and clicking to change the board while the algorithm runs But it works now. Really proud of it.
algora dev log #68 Implemented Python C++ Java and C for D* Lite. Both the advanced and teaching implementation is finished.
I got my latest project reviews back today, and first of all thank you so much to everyone who took the time to look through the project! A lot of the feedback genuinely made me really happy. Some people pointed out bugs I hadn’t noticed, some gave me ideas for things I could improve, and a few of you even said you wanted to bookmark the project or use it for studying algorithms, which honestly means a lot to me. There were also some questions about the tech stack and how different parts of the project were built, which I’m happy to answer. Review #1: “what is this stack? html, typescript, c, c++ and java?” The website itself is built primarily with HTML, CSS, and TypeScript. The additional languages: C, C++, Java, and Python are there because the project includes implementations of the algorithms in multiple languages. Review #5: “Dijkstra doesn’t work, I get a 404” The Ship is mainly about sorting and searching algorithms. I think by the time you visited the pathfinding page, I had already started working on the new pathfinding section but hadn’t finished implementing it yet, which is why Dijkstra gave you a 404. I’m actively working on the Dijkstra right now tho! Review #8: “the amount of time to type out your project at 70 words per minute is around 200 hours” This assumes every character was typed manually. I use tab completion and copy/paste repetitive code. For example, most of the TypeScript engine API is basically the same across algorithms, so I’m obviously not going to retype the same thing every time Review #8: “make no mention of struggles or frustrations, inspirations or ideas” I personally don’t like putting my frustration into project logs. I usually just keep my devlogs focused on what I made, changed, or learned. Review #8: “You type out rgba and hexadecimals by hand without a tool” I sketched the website layout on my iPad and used it as a reference while coding. I can’t exactly copy/paste an RGB value from my iPad onto my computer, so I just typed it Review #8: “you type out entire svg lines” The SVGs are actually copy/pasted. They’re reused assets and basically the same every time. The timelapse is around 1000x speed, so a paste just looks like the SVG suddenly appeared. Review #8: “You never delete any lines in your timelapses” I cut most of the boring debugging out because who wants to watch that. That’s also why sometimes the timelapse jumps from broken code to fixed code. I wanted the videos to stay short and watchable. Review #8: “Show us your second monitor” There is no second monitor. You assumed there was one because I wasn’t recording my full screen. I intentionally only record the part of my screen relevant to the project because the rest is my privacy. I also look through a lot of references, documentation, and other pages while working, and I don’t think anyone wants all of that flashing across a 1000x timelapse anyway. I don’t mind people questioning my work or asking how I did something, but I do think there’s a difference between asking and immediately assuming someone faked their work. Some of the comments also became pretty personal, which was honestly disappointing to see. Review #9: “Don’t bring it down pls” don’t worry, I’m planning to keep the website up I’m really happy that you actually want to use it though, that’s basically the whole reason I made this project And to everyone else who left a review, thank you so much!! I didn’t want to respond to every review with just “thank you” over and over again, but I read all of them and really appreciate all the feedback Seeing people say they actually want to use the website for learning, revision, or even USACO genuinely made me really happy. That’s basically why I wanted to build this project in the first place
algora dev log #68 Implemented the page for Dijkstra. Finished the algorithm workspace, Both the advanced and teaching version of the algorithm in all 4 languages including python, c, java and c++
Ships:
Algora 1.0 Ship An attempt to put everything I wish I had when learning algorithms into one place. This project started when a friend asked me for help with USACO. While helping them, I started thinking back to my own path of learning algorithms and the things I wished I had when I was learning them. I wanted one place where I could not only read about an algorithm, but actually see it work, understand what is happening at each step, compare it with other algorithms, and look at both a teaching implementation and a more practical implementation. That idea eventually became Algora. What’s Included The first release currently includes: 15 sorting algorithms 17 searching algorithms Interactive algorithm visualizations Step by step execution and playback controls Algorithm specific workspaces for more complex algorithms Quick facts and complexity information Detailed algorithm explanations Pseudocode Teaching implementations in C, C++, Java, and Python Production style implementations in C, C++, Java, and Python Sorting algorithm comparison Searching algorithm comparison Comparison information including time complexity, space complexity, requirements, strengths, and weaknesses Warnings when algorithms are not directly comparable Individual pages for every algorithm The goal was to make each algorithm more than just a page of code. I wanted to be able to go from: What is this? → How does it work? → Can I see it happen? → Can I understand each step? → What does the code look like? → How does it compare to other approaches? Why I Built It I built Algora because I kept thinking about how much easier learning algorithms could have been if I had all of these things in one place when I was going through USACO. I’ve gone through the USACO training path myself and reached Platinum, and helping my friend brought me back to the way I learned all of this in the first place. So instead of making another collection of algorithm implementations, I wanted to make the resource I wish I had back then. Algora is an attempt to put everything I wish I had when learning algorithms into one place. The Making of Algora I also recorded a large part of the development process while building the project. The video below is a 1000× speed timelapse made from roughly 70 hours of raw development footage. I lost some footage along the way, so it does not contain absolutely everything, but most of the development process is there. Apparently Stands saw the size of the video and decided it simply did not exist D: If you really want to watch the video, the link is here: https://github.com/diputs-sudo/algora/tree/main/video you might have to download it :( Thank You Thank you to everyone who supported me while I was building Algora. Thank you to everyone who tested things, gave feedback, helped me figure things out, listened to me ramble about algorithms, or simply encouraged me to keep working on it. This project ended up becoming much bigger than the original idea, and I’m really happy that I finally get to share it....
|
1792878745.069722
|
1793742745.069722
|
|
59861
|
Cirkuit by @spectra | Stardance
|
spectra
|
1
|
127.4
|
1802
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-27T22:09:45Z", "hours": 95.0, "multiplier": 18.99, "payout": 1802, "blessing": "neutral", "text": "Hi! I’m really happy to introduce you to my biggest project so far. It’s called Cirkuit, and it’s a logic circuit sandbox simulator… but with pixel art! That means you can basically build anything using just pixels. Why pixels? You may ask. Well, many logic simulators already exist, but the issue is that most of them aren’t very accessible to the average user. That’s why I wanted Cirkuit to be as easy to use as possible. I’m already quite familiar with TypeScript and React, which I used for this project. So the most difficult part was actually figuring out how to implement features without having 100 nested loops :D I had a hard time figuring out how to build the core engine (obviously), as well as the annotation system. I’m quite proud of how it looks and how well it works. This project was a perfect opportunity for me to improve my design skills. I worked hard to reduce friction between the interface and the user (aka you, dear shipwriters). One piece of advice: try it on a computer with a mouse. Phones and trackpads are supported, but it’s not the best experience. Hope you’ll like this project!", "repo": "https://github.com/NaFo44/Cirkuit", "demo": "https://nafo44.github.io/Cirkuit/"}]...
|
[{"post_id": 83044, "ts": "202 [{"post_id": 83044, "ts": "2026-10-26T17:30:29Z", "hours": 4.7797, "text": "Devlog 42 : Integrated circuits (almost done!) It wasn’t easy! The UX part is actually really challenging. I had to rely on AI more than usual because Stardance is ending really soon, and I’m honestly a bit scared of not having enough time to ship :/ I’ll still try to polish the UI as much as possible! The screenshot below shows what it currently looks like. I added a new section for modules in the sidebar, where you can see all the modules you’ve created, edit them, or create new ones. When creating a new module, you can set its name, preview the footprint, add or remove inputs/outputs, and place them directly on the footprint. It’s almost ready tho! I’m just polishing the UX now. Next steps: finish this feature, polish the UI/UX, ship!"}, {"post_id": 82831, "ts": "2026-10-25T23:44:06Z", "hours": 2.5764, "text": "Devlog 41 : Integrated Circuits I’m working on the UI! The picture below shows what it currently looks like. I’m still not sure about the colors, so they might change. I still have the hardest part to figure out: How will users create and modify a module, UX-wise? Will it have its own sub-editor? How will users assign pins, name them, and define the module’s size and name? As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: Keep working on the UI, polish the UX/UI, and ship!"}, {"post_id": 82612, "ts": "2026-10-25T12:50:30Z", "hours": 2.0128, "text": "Devlog #40 : Integrated circuits I’m (again) still working on this feature! Since my last devlog, I’ve updated the project document format to serialize the new modules. And that’s basically it! Next step: integrate them into the UI, polish the UX, and ship!"}, {"post_id": 82446, "ts": "2026-10-24T20:32:14Z", "hours": 3.4561, "text": "Devlog #39 : Integrated circuits (again) I’m still working on this feature! I’m not at the frontend part yet, still adapting the engine. More details if you’re curious: A module has a definition that includes its name, public pins, and internal circuit. It can be used multiple times (it’s called an instance in the code). And all modules are listed in a catalog (that I’ll probably integrate in the frontend later). Instances can be selected, moved, copied and pasted, across the layers… The picture bellow shows how this feature could be used. It will make things much easier if you want to build more complex circuits like an 8 bit adder. You’ll just have to stack 8x 1-bit full adder modules! As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: finish the backend side, then integrate everything into the frontend, polish the UI, and ship!"}, {"post_id": 81890, "ts": "2026-10-22T21:14:45Z", "hours": 1.7631, "text": "Devlog #38 : Integrated circuits Some of you have requested this, so I’m working on it! It’s not out yet, as it’s a pretty big feature. Integrated circuits will basically be custom components (most likely rectangles) with multiple inputs and outputs, all defined by the user. It’s literally a footprint, kinda like what you’d find in KiCad. I’ve started modifying the engine’s internals so it can handle these new types of connections (alongside the classic 1-pixel components). The real challenge here is keeping everything simple on the UX side, even though this feature targets more advanced users. The image below only shows what it might look like, this will probably change over time. As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: keep working on this feature, polish the UI/UX, ship it, and sadly… the end of stardance :("}, {"post_id": 80656, "ts": "2026-10-18T12:34:55Z", "hours": 0.6414, "text": "Devlog #37 : Probe tool is out! You can now inspect your circuits with this new tool. It highlights equipotential wires. I also added small circles to every connected ports. Next steps: UI polish, and maybe a “challenge” or “community circuits” tab."}, {"post_id": 80469, "ts": "2026-10-17T19:03:13Z", "hours": 1.3664, "text": "Devlog #36 : Probe tool and 4-bit calculator. While I was working on improving my 7-segment display, I had quite a hard time simplifying the circuit. Then I thought it could be really useful to have a tool that shows all the equipotential wires. So I’m currently working on it! It’s working, but I still have to improve its style before publishing it. Aside from that, I actually spent way too many hours improving the 4-bit calculator. And it’s now finished! It’s available in the demo circuit if you want to try it. I’ll see if I can build a keyboard later so users don’t have to enter numbers in binary. As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: finish the Probe tool, polish the UI, add a “challenge” tab."}, {"post_id": 79615, "ts": "2026-10-14T18:37:38Z", "hours": 1.4939, "text": "Devlog #35 : UI cleanup and (another) demo circuit The sidebar was getting a bit too crowded, so I added a small button to show/hide the more advanced components. The idea is to make things a little less overwhelming for new users, instead of throwing everything at them right away. I also worked on a 4-bit adder and wired it up to my 7-segment decoder! I’m going to try making it a 4-bit decoder instead of a 3-bit one, but things are going to get a lot more complicated (more numbers = more logic gates). One small issue with the adder for now: the most significant bit is on the right, so the input is basically reversed. I’ll fix that soon. In the meantime, you can already try it out in the live demo project! As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: more UI/UX improvements, adding challenges, and continuing to waste way too much of my time messing around with circuits xd"}, {"post_id": 79427, "ts": "2026-10-13T22:49:03Z", "hours": 0.4678, "text": "Devlog #34 : New component: Memory! This is one step up in difficulty! It has two inputs: a clock input (at the top) and a signal input (on the left). The output signal is provided on the right. This component can store a 1-bit value, which is updated on every rising edge of the clock signal. You can basically build anything with the component available: calculator, more advanced display (e.g. a 7-segment decoder that can go from 0 to 9). I added a 3-bit binary counter that I wired up to my 7-segment decoder! (demo bellow). It’s also included in the demo project file. Next steps: cleanup UI and improve UX (the sidebar is really really crowded right now)"}, {"post_id": 79113, "ts": "2026-10-12T18:33:18Z", "hours": 1.6869, "text": "Devlog #33 : Docs update and 1-bit memory! I added the clock to the docs page, along with some new tests for it. I’m also almost done with the 1-bit memory (basically a simplified D flip-flop). I’ll share it in the next devlog! Also, if you like this project, you can leave a star on the project’s GitHub page if you wish! Next steps: finish the 1-bit memory and clean up the UI/UX"}, {"post_id": 77284, "ts": "2026-10-06T12:57:02Z", "hours": 1.4464, "text": "Devlog #32 : New component: CLOCK (finally) This one was relatively easy to implement! The tick system was already there, but it was only triggered by user interactions. Now, your circuits run at 10 ticks/s, and the clock has a constant 1 Hz square signal (the recording below is choppy, but yes it is indeed a 1 Hz periodic signal) This component only has one output. I thought it would make building complex circuits easier if the other sides were isolated. Next steps: 1-bit memory, and then a lot of UX/UI improvements!"}, {"post_id": 76710, "ts": "2026-10-04T11:58:04Z", "hours": 1.9281, "text": "Devlog #31 : UI improvement! I replaced the old “main shortcuts” section in the sidebar with simple links. It frees up some space, makes the interface feel cleaner, and should make it much easier to add a proper “Challenge” tab later. Next steps: add a clock and a 1-bit memory."}, {"post_id": 76242, "ts": "2026-10-02T20:30:28Z", "hours": 2.1839, "text": "Devlog #30 : Component documentation! I’ve added a new page in the sidebar that shows a description and preview image for every component. A few people asked for this in the reviews of my first ship, so it felt like a good addition. Also, if you have any idea of how I could integrate the new more advanced features without overwhelming new users, I’m all ears! The sidebar is starting to get pretty crowded, so I need to find a cleaner way to organize everything and keep navigation smooth. Also, huge thanks to the Stardance staff for awarding this project Superstar ❤️ Next steps: code cleanup, UX improvements, 1-bit memory support, and FINALLY the clock."}, {"post_id": 75958, "ts": "2026-10-01T18:50:05Z", "hours": 4.13, "text": "Devlog #29 : New feature: Multi-layer! You can now build circuits across two layers! I added vias, so you can connect the two layers together (obviously). When you place a via, it’s added on both layers, it basically works like a wire. I also finished the 7-segment decoder: 3bit input, supporting only 0-4 for now. The other values are just don’t-cares. Next steps: polish the code and UI, then add some documentation."}, {"post_id": 75590, "ts": "2026-09-30T14:38:26Z", "hours": 2.4681, "text": "Devlog #28 : Multi-layer (and thank you!!) First of all, thank you so much for all the support on this project! The Stardancers who reviewed my first ship got some really great advices. I’ll be following up on a lot of it. So, I’m planning to add: a simple component documentation some challenges (e.g. 7-segment decoder, XOR gate) more advanced features (clock, 1-bit memory) and what I’m working on right now: a second layer! (currently, wires can’t cross each other, which becomes a real issue with more complex circuits) and, if I have enough time, a place where people can share circuit snippets and showcase their projects! The real challenge will be integrating all of this while keeping the UI clean and the UX intuitive. The screenshot below shows what the circuit viewport could look like with the second layer."}, {"post_id": 74661, "ts": "2026-09-27T21:50:30Z", "hours": 1.2256, "text": "Devlog #27 : Some optimization, code cleanup, and brand new readme! That’s the last devlog for this project before I ship!"}, {"post_id": 74620, "ts": "2026-09-27T19:48:58Z", "hours": 2.7119, "text": "Devlog #26 : I’ve done many small improvements, such as: ability to move annotations undo/redo buttons custom favicon Next step: SHIP!"}, {"post_id": 74207, "ts": "2026-09-26T22:21:43Z", "hours": 2.4531, "text": "Devlog #25 : UI/UX improvements! I improved the component selection outline. Now the outline is around the whole selected group of pixels, instead of around each individual pixel. You can also now delete selected components by pressing Del on your keyboard. And I added a little preview showing the pixel currently targeted by the cursor. Next steps: keep working on the UI/UX, and ship!"}, {"post_id": 74006, "ts": "2026-09-26T14:48:02Z", "hours": 2.2353, "text": "Devlog #24 : New feature (kinda): the camera position and zoom are now stored in the project file, and loaded when you open the project. That means you can setup any point of view in your project, and the viewport will be right where you left it when you open it again! I also fixed a bunch of UI inconsistencies: the hover label position is now responsive to the workspace sidebar (before, it was getting hidden behind it) unified border colors fixed the phone workspace responsiveness made the sidebar on the right a little bit smaller I also continued working on the 7-segment display, but ran into some issues since wires can’t cross each other. So I thought about having circuits on two different layers. What do you think about this? Next steps: I’ll probably polish the UX a little bit more, and then ship the project. But I’m planning to keep working on it!"}, {"post_id": 73755, "ts": "2026-09-25T21:20:35Z", "hours": 5.3378, "text": "Devlog #23 : New feature: Undo/Redo! You can now undo and redo things you’ve done in the editor. This works with both components and annotations. I had to implement a project history system. Basically, every time an action modifies the project, the previous project state is added to the past history stack. When you undo, the latest state from past becomes the current state, while the previous current state is moved to the future stack. When you redo, the next state from future becomes the current state and the previous current state is moved back to past. Yeah it’s messy 😂 I’m also still working on the 7-segment decoder. I switched to a 3-bit one, I’ll probably include it in the demo. Next steps: mostly UI and code improvements, and then I’ll probably ship it. I’ll keep working on it!"}, {"post_id": 73252, "ts": "2026-09-24T17:56:14Z", "hours": 4.5872, "text": "Devlog #22 : New feature: selection and copy/paste! You just have to press “S” and drag your mouse/pad while holding the left click. You can then copy, paste, or move the selected pixels around. Probably the most difficult feature I’ve worked on so far. I had to get some help from ChatGPT :’) I think this will be my last devlog before shipping, since one of my other projects has been pending for 18 days now, so yeah… I’ll still keep working on this project though!"}, {"post_id": 72869, "ts": "2026-09-23T21:59:41Z", "hours": 4.2722, "text": "Devlog #21 : Some UI/UX improvements and started working on selection! I’m currently working on the selection system. It works like this: Press S, then while holding it, drag the selection area with the left click. Once selected, you can copy, paste or move the selected block of pixels. It’s not committed yet! It still requires some work. Next steps: finish the selection feature, then add the clock. I also want to improve the UX as much as possible."}, {"post_id": 72417, "ts": "2026-09-22T21:44:45Z", "hours": 3.6344, "text": "Devlog #20 : demo project and UI/UX update! I added a demo project with a basic light/switch circuit, an OR and XOR gate, and a few annotations. I also (and mostly) removed the old “Quick start” section. It was becoming kinda useless since pretty much everything was already covered by the demo project. So I replaced it with a little intro to the project, along with a table of the shortcuts. I also added a little decoration to the bottom-left corner of the sidebar. I think it looks pretty dope! Next steps: copy/paste and selection, THEN add a clock."}, {"post_id": 71977, "ts": "2026-09-21T21:47:46Z", "hours": 2.3336, "text": "Devlog #19 : A little code cleanup! I refactored the App.tsx file because it was handling too many different things. Now each hook has its own dedicated file. Small refactor, but definitely a needed one! Next steps: add a demo project, improve the UI/UX and laptop pad support, add copy/paste and selection, and finally add a clock (eventually, at this point 😂)"}, {"post_id": 71454, "ts": "2026-09-20T21:12:46Z", "hours": 7.6194, "text": "Devlog #18 : You can save your work now! There are now two buttons in the bottom-left corner: Open and Save. Your projects are downloaded as .cirkuit files. This part was actually quite challenging, mostly because of the file format validation and all the tests around it. Next steps: clean up the code, cleanup the UI (it feels a bit messy right now), add a demo project, add copy/paste and selection, and add a clock"}, {"post_id": 70868, "ts": "2026-09-19T21:55:45Z", "hours": 4.9169, "text": "Devlog #17 : New feature: Annotations! You can now add labels, lines and rectangles to your circuits! I developed this feature so I can better explain what’s going on in the demo project when I’ll ship this project. But you can also use it to explain your craziest circuits! Next step: upload/download projects."}, {"post_id": 70240, "ts": "2026-09-18T19:31:51Z", "hours": 4.5228, "text": "Devlog #16 : Annotation feature (WIP) It’s not finished yet, but I’m currently working on a new annotation feature. Why? Because I’ll need it to explain the circuits in the demo! I’m adding this before the project download/upload system, because otherwise I’d have to refactor quite a bit of the system later. Also, I’m starting to build a 4-bit 7-segment decoder in Cirkuit! (I started with the two easier segments lmao) Next steps: continue working on the annotation system, then implement project download/upload."}, {"post_id": 69732, "ts": "2026-09-17T17:45:12Z", "hours": 4.5497, "text": "Devlog #15 : I added a little guide! The goal of this small guide is to explain a few things that might not be obvious to new users. You can close and reopen it whenever you want, so it doesn’t get in the way while you’re playing. It’s still available on the GitHub page if you want to give it a try! Next step: add a minimal circuit loading system (so I can add a default demo circuit), and THEN I’ll add the clock 😂😭"}, {"post_id": 69345, "ts": "2026-09-16T21:00:55Z", "hours": 4.0622, "text": "Devlog #14 : New component: AND gate! Now the two main gates are available (NOT & AND), so you can basically build anything with them! In the screenshot below, I built a working XOR logic gate, both in a large and a condensed version. A few changes since last time, apart from the new component: The old NOT gate wasn’t working properly because the circuit actually handles 3 states (low, floating, high), while the NOT component only supported low and high. So now, “floating” is considered as “low”. Also, there’s no longer real-time simulation, sadly. I had some issues with the logic gates: if you built them the wrong way, it could crash the entire webpage. So now you have to click on “Run simulation” to see the magic happen. It’s a bit less cool than real-time simulation, but at least it doesn’t nuke the whole page anymore lol. Next steps: UI/UX improvements, clock, and 1-bit memory later on"}, {"post_id": 68867, "ts": "2026-09-15T22:24:51Z", "hours": 5.5678, "text": "Devlog #13 : New component: NOT gate! This component returns the opposite signal you give it: low becomes high, high becomes low. I also improved the UI/UX. There’s now a new label in the bottom-left corner of the page that shows which component you’re hovering over with your mouse, and what its current state is. For example: “Wire | Low”, “Switch | Open”. I also fixed the pixel rendering, because before there were some really thin lines between them. And now the sidebar is responsive! Next steps: code cleanup, AND gate, clock"}, {"post_id": 68303, "ts": "2026-09-14T21:50:03Z", "hours": 2.3831, "text": "Devlog #12 : Wire states are now visually apparent! In the example below, on the first circuit, the first segment is high because it is powered by the source, while the second segment (connected to the lamp) is floating because the switch is open. I’ve also fixed a whole bunch of UI issues. You can try out this project on my GitHub page! Next step (for real this time): adding a NOT gate (the clock will come later)"}, {"post_id": 67690, "ts": "2026-09-13T21:26:19Z", "hours": 0.8703, "text": "Devlog #11 : I did some UI improvements, but before I commit, I’d like to have your opinion for the light component; which glow do you prefere?"}, {"post_id": 67626, "ts": "2026-09-13T19:32:41Z", "hours": 0.7378, "text": "Devlog #10: I added some tooltips so it’s easier to understand for you guys! Next steps: Start writting an actual documentation, add new components"}, {"post_id": 67547, "ts": "2026-09-13T17:58:10Z", "hours": 4.0528, "text": "Devlog #9 : New component: Switch This new component come with a new “simulation” mode, where you can interact with the components. Next step: add small tooltips to the sidebar elements, add new components (clock, memory…) It’s deployed so you can try it (see the project page)! I’d love to get some feedbacks."}, {"post_id": 67325, "ts": "2026-09-13T12:07:15Z", "hours": 0.7281, "text": "Devlog #8 : UI update! Changes: checkerboard background texture instead of the old grid custom selector on the component palette pixel art icons Next step: new components (switch, clock, memory…)"}, {"post_id": 67277, "ts": "2026-09-13T10:52:18Z", "hours": 2.2756, "text": "Devlog #7 : Now power and light can be connected from all sides! Also, since the old arrows are no longer necessary (at least for these components), I improved the UX by displaying the actual component icon instead. The icons on the circuit are also hidden by default now, and only appear when you hover over them. Oh and there’s an eraser now. I also deployed the website: nafo44.github.io/Cirkuit/ Next step: add new components (switch, clock, logic gates, memory)"}, {"post_id": 66878, "ts": "2026-09-12T20:32:38Z", "hours": 3.0808, "text": "Devlog #6: I wired up the simulation engine to the UI! It’s working really well, even tho there’s only 3 components right now (source, wire, light). I added arrows so you can easily rotate the components. I want this project to be really intuitive, so if you guys have some ideas to simplify this, I’m all ears! Next step: let a source and light to power/be powered through all sides, add new components (switch, clock, memory)"}, {"post_id": 66549, "ts": "2026-09-12T12:01:35Z", "hours": 4.5847, "text": "Devlog #5 : Now the component placement UI side is wired to our circuit layout! It probably don’t make much sens for you right now. Next step: modify visually the component grid according to the simulation."}, {"post_id": 65649, "ts": "2026-09-10T22:37:33Z", "hours": 5.8197, "text": "Devlog #4: The other half of the engine is done! It can now compute components state (low, high, floating, conflict) based on the connections between each other. Next step: wiring the engine to the UI."}, {"post_id": 65057, "ts": "2026-09-09T21:57:21Z", "hours": 6.5794, "text": "Devlog #3: I’ve finished half of the engine of my website, made to let you create circuits using pixel art. It wasn’t easy! I came up with a simplified netlist algorithm, to represent how a component (pixel) is oriented, how many are wired, to what, and through which side of the pixel. Components states aren’t handled yet, but that’s what I’m going to work on next."}, {"post_id": 64452, "ts": "2026-09-08T20:55:25Z", "hours": 2.1144, "text": "Devlog #2: I improved the UI, added mouse wheel support (to zoom and move the map). Now it’s time to work on the actual engine."}, {"post_id": 64381, "ts": "2026-09-08T18:22:49Z", "hours": 1.6267, "text": "Devlog #1: Hi! I just started making a website where you will be able to create circuits… with pixel art! The idea is to add different pixels: wire (gray), power (green), light (yellow), logic gates (AND, OR, …), memory (simple true/false state storage). I want to keep this as simple as possible to use."}]...
|
Title: Cirkuit by @spectra | Stardance
Devlogs:
D Title: Cirkuit by @spectra | Stardance
Devlogs:
Devlog #1: Hi! I just started making a website where you will be able to create circuits… with pixel art! The idea is to add different pixels: wire (gray), power (green), light (yellow), logic gates (AND, OR, …), memory (simple true/false state storage). I want to keep this as simple as possible to use.
Devlog #2: I improved the UI, added mouse wheel support (to zoom and move the map). Now it’s time to work on the actual engine.
Devlog #3: I’ve finished half of the engine of my website, made to let you create circuits using pixel art. It wasn’t easy! I came up with a simplified netlist algorithm, to represent how a component (pixel) is oriented, how many are wired, to what, and through which side of the pixel. Components states aren’t handled yet, but that’s what I’m going to work on next.
Devlog #4: The other half of the engine is done! It can now compute components state (low, high, floating, conflict) based on the connections between each other. Next step: wiring the engine to the UI.
Devlog #5 : Now the component placement UI side is wired to our circuit layout! It probably don’t make much sens for you right now. Next step: modify visually the component grid according to the simulation.
Devlog #6: I wired up the simulation engine to the UI! It’s working really well, even tho there’s only 3 components right now (source, wire, light). I added arrows so you can easily rotate the components. I want this project to be really intuitive, so if you guys have some ideas to simplify this, I’m all ears! Next step: let a source and light to power/be powered through all sides, add new components (switch, clock, memory)
Devlog #7 : Now power and light can be connected from all sides! Also, since the old arrows are no longer necessary (at least for these components), I improved the UX by displaying the actual component icon instead. The icons on the circuit are also hidden by default now, and only appear when you hover over them. Oh and there’s an eraser now. I also deployed the website: nafo44.github.io/Cirkuit/ Next step: add new components (switch, clock, logic gates, memory)
Devlog #8 : UI update! Changes: checkerboard background texture instead of the old grid custom selector on the component palette pixel art icons Next step: new components (switch, clock, memory…)
Devlog #9 : New component: Switch This new component come with a new “simulation” mode, where you can interact with the components. Next step: add small tooltips to the sidebar elements, add new components (clock, memory…) It’s deployed so you can try it (see the project page)! I’d love to get some feedbacks.
Devlog #10: I added some tooltips so it’s easier to understand for you guys! Next steps: Start writting an actual documentation, add new components
Devlog #11 : I did some UI improvements, but before I commit, I’d like to have your opinion for the light component; which glow do you prefere?
Devlog #12 : Wire states are now visually apparent! In the example below, on the first circuit, the first segment is high because it is powered by the source, while the second segment (connected to the lamp) is floating because the switch is open. I’ve also fixed a whole bunch of UI issues. You can try out this project on my GitHub page! Next step (for real this time): adding a NOT gate (the clock will come later)
Devlog #13 : New component: NOT gate! This component returns the opposite signal you give it: low becomes high, high becomes low. I also improved the UI/UX. There’s now a new label in the bottom-left corner of the page that shows which component you’re hovering over with your mouse, and what its current state is. For example: “Wire | Low”, “Switch | Open”. I also fixed the pixel rendering, because before there were some really thin lines between them. And now the sidebar is responsive! Next steps: code cleanup, AND gate, clock
Devlog #14 : New component: AND gate! Now the two main gates are available (NOT & AND), so you can basically build anything with them! In the screenshot below, I built a working XOR logic gate, both in a large and a condensed version. A few changes since last time, apart from the new component: The old NOT gate wasn’t working properly because the circuit actually handles 3 states (low, floating, high), while the NOT component only supported low and high. So now, “floating” is considered as “low”. Also, there’s no longer real-time simulation, sadly. I had some issues with the logic gates: if you built them the wrong way, it could crash the entire webpage. So now you have to click on “Run simulation” to see the magic happen. It’s a bit less cool than real-time simulation, but at least it doesn’t nuke the whole page anymore lol. Next steps: UI/UX improvements, clock, and 1-bit memory later on
Devlog #15 : I added a little guide! The goal of this small guide is to explain a few things that might not be obvious to new users. You can close and reopen it whenever you want, so it doesn’t get in the way while you’re playing. It’s still available on the GitHub page if you want to give it a try! Next step: add a minimal circuit loading system (so I can add a default demo circuit), and THEN I’ll add the clock 😂😭
Devlog #16 : Annotation feature (WIP) It’s not finished yet, but I’m currently working on a new annotation feature. Why? Because I’ll need it to explain the circuits in the demo! I’m adding this before the project download/upload system, because otherwise I’d have to refactor quite a bit of the system later. Also, I’m starting to build a 4-bit 7-segment decoder in Cirkuit! (I started with the two easier segments lmao) Next steps: continue working on the annotation system, then implement project download/upload.
Devlog #17 : New feature: Annotations! You can now add labels, lines and rectangles to your circuits! I developed this feature so I can better explain what’s going on in the demo project when I’ll ship this project. But you can also use it to explain your craziest circuits! Next step: upload/download projects.
Devlog #18 : You can save your work now! There are now two buttons in the bottom-left corner: Open and Save. Your projects are downloaded as .cirkuit files. This part was actually quite challenging, mostly because of the file format validation and all the tests around it. Next steps: clean up the code, cleanup the UI (it feels a bit messy right now), add a demo project, add copy/paste and selection, and add a clock
Devlog #19 : A little code cleanup! I refactored the App.tsx file because it was handling too many different things. Now each hook has its own dedicated file. Small refactor, but definitely a needed one! Next steps: add a demo project, improve the UI/UX and laptop pad support, add copy/paste and selection, and finally add a clock (eventually, at this point 😂)
Devlog #20 : demo project and UI/UX update! I added a demo project with a basic light/switch circuit, an OR and XOR gate, and a few annotations. I also (and mostly) removed the old “Quick start” section. It was becoming kinda useless since pretty much everything was already covered by the demo project. So I replaced it with a little intro to the project, along with a table of the shortcuts. I also added a little decoration to the bottom-left corner of the sidebar. I think it looks pretty dope! Next steps: copy/paste and selection, THEN add a clock.
Devlog #21 : Some UI/UX improvements and started working on selection! I’m currently working on the selection system. It works like this: Press S, then while holding it, drag the selection area with the left click. Once selected, you can copy, paste or move the selected block of pixels. It’s not committed yet! It still requires some work. Next steps: finish the selection feature, then add the clock. I also want to improve the UX as much as possible.
Devlog #22 : New feature: selection and copy/paste! You just have to press “S” and drag your mouse/pad while holding the left click. You can then copy, paste, or move the selected pixels around. Probably the most difficult feature I’ve worked on so far. I had to get some help from ChatGPT :’) I think this will be my last devlog before shipping, since one of my other projects has been pending for 18 days now, so yeah… I’ll still keep working on this project though!
Devlog #23 : New feature: Undo/Redo! You can now undo and redo things you’ve done in the editor. This works with both components and annotations. I had to implement a project history system. Basically, every time an action modifies the project, the previous project state is added to the past history stack. When you undo, the latest state from past becomes the current state, while the previous current state is moved to the future stack. When you redo, the next state from future becomes the current state and the previous current state is moved back to past. Yeah it’s messy 😂 I’m also still working on the 7-segment decoder. I switched to a 3-bit one, I’ll probably include it in the demo. Next steps: mostly UI and code improvements, and then I’ll probably ship it. I’ll keep working on it!
Devlog #24 : New feature (kinda): the camera position and zoom are now stored in the project file, and loaded when you open the project. That means you can setup any point of view in your project, and the viewport will be right where you left it when you open it again! I also fixed a bunch of UI inconsistencies: the hover label position is now responsive to the workspace sidebar (before, it was getting hidden behind it) unified border colors fixed the phone workspace responsiveness made the sidebar on the right a little bit smaller I also continued working on the 7-segment display, but ran into some issues since wires can’t cross each other. So I thought about having circuits on two different layers. What do you think about this? Next steps: I’ll probably polish the UX a little bit more, and then ship the project. But I’m planning to keep working on it!
Devlog #25 : UI/UX improvements! I improved the component selection outline. Now the outline is around the whole selected group of pixels, instead of around each individual pixel. You can also now delete selected components by pressing Del on your keyboard. And I added a little preview showing the pixel currently targeted by the cursor. Next steps: keep working on the UI/UX, and ship!
Devlog #26 : I’ve done many small improvements, such as: ability to move annotations undo/redo buttons custom favicon Next step: SHIP!
Devlog #27 : Some optimization, code cleanup, and brand new readme! That’s the last devlog for this project before I ship!
Devlog #28 : Multi-layer (and thank you!!) First of all, thank you so much for all the support on this project! The Stardancers who reviewed my first ship got some really great advices. I’ll be following up on a lot of it. So, I’m planning to add: a simple component documentation some challenges (e.g. 7-segment decoder, XOR gate) more advanced features (clock, 1-bit memory) and what I’m working on right now: a second layer! (currently, wires can’t cross each other, which becomes a real issue with more complex circuits) and, if I have enough time, a place where people can share circuit snippets and showcase their projects! The real challenge will be integrating all of this while keeping the UI clean and the UX intuitive. The screenshot below shows what the circuit viewport could look like with the second layer.
Devlog #29 : New feature: Multi-layer! You can now build circuits across two layers! I added vias, so you can connect the two layers together (obviously). When you place a via, it’s added on both layers, it basically works like a wire. I also finished the 7-segment decoder: 3bit input, supporting only 0-4 for now. The other values are just don’t-cares. Next steps: polish the code and UI, then add some documentation.
Devlog #30 : Component documentation! I’ve added a new page in the sidebar that shows a description and preview image for every component. A few people asked for this in the reviews of my first ship, so it felt like a good addition. Also, if you have any idea of how I could integrate the new more advanced features without overwhelming new users, I’m all ears! The sidebar is starting to get pretty crowded, so I need to find a cleaner way to organize everything and keep navigation smooth. Also, huge thanks to the Stardance staff for awarding this project Superstar ❤️ Next steps: code cleanup, UX improvements, 1-bit memory support, and FINALLY the clock.
Devlog #31 : UI improvement! I replaced the old “main shortcuts” section in the sidebar with simple links. It frees up some space, makes the interface feel cleaner, and should make it much easier to add a proper “Challenge” tab later. Next steps: add a clock and a 1-bit memory.
Devlog #32 : New component: CLOCK (finally) This one was relatively easy to implement! The tick system was already there, but it was only triggered by user interactions. Now, your circuits run at 10 ticks/s, and the clock has a constant 1 Hz square signal (the recording below is choppy, but yes it is indeed a 1 Hz periodic signal) This component only has one output. I thought it would make building complex circuits easier if the other sides were isolated. Next steps: 1-bit memory, and then a lot of UX/UI improvements!
Devlog #33 : Docs update and 1-bit memory! I added the clock to the docs page, along with some new tests for it. I’m also almost done with the 1-bit memory (basically a simplified D flip-flop). I’ll share it in the next devlog! Also, if you like this project, you can leave a star on the project’s GitHub page if you wish! Next steps: finish the 1-bit memory and clean up the UI/UX
Devlog #34 : New component: Memory! This is one step up in difficulty! It has two inputs: a clock input (at the top) and a signal input (on the left). The output signal is provided on the right. This component can store a 1-bit value, which is updated on every rising edge of the clock signal. You can basically build anything with the component available: calculator, more advanced display (e.g. a 7-segment decoder that can go from 0 to 9). I added a 3-bit binary counter that I wired up to my 7-segment decoder! (demo bellow). It’s also included in the demo project file. Next steps: cleanup UI and improve UX (the sidebar is really really crowded right now)
Devlog #35 : UI cleanup and (another) demo circuit The sidebar was getting a bit too crowded, so I added a small button to show/hide the more advanced components. The idea is to make things a little less overwhelming for new users, instead of throwing everything at them right away. I also worked on a 4-bit adder and wired it up to my 7-segment decoder! I’m going to try making it a 4-bit decoder instead of a 3-bit one, but things are going to get a lot more complicated (more numbers = more logic gates). One small issue with the adder for now: the most significant bit is on the right, so the input is basically reversed. I’ll fix that soon. In the meantime, you can already try it out in the live demo project! As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: more UI/UX improvements, adding challenges, and continuing to waste way too much of my time messing around with circuits xd
Devlog #36 : Probe tool and 4-bit calculator. While I was working on improving my 7-segment display, I had quite a hard time simplifying the circuit. Then I thought it could be really useful to have a tool that shows all the equipotential wires. So I’m currently working on it! It’s working, but I still have to improve its style before publishing it. Aside from that, I actually spent way too many hours improving the 4-bit calculator. And it’s now finished! It’s available in the demo circuit if you want to try it. I’ll see if I can build a keyboard later so users don’t have to enter numbers in binary. As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: finish the Probe tool, polish the UI, add a “challenge” tab.
Devlog #37 : Probe tool is out! You can now inspect your circuits with this new tool. It highlights equipotential wires. I also added small circles to every connected ports. Next steps: UI polish, and maybe a “challenge” or “community circuits” tab.
Devlog #38 : Integrated circuits Some of you have requested this, so I’m working on it! It’s not out yet, as it’s a pretty big feature. Integrated circuits will basically be custom components (most likely rectangles) with multiple inputs and outputs, all defined by the user. It’s literally a footprint, kinda like what you’d find in KiCad. I’ve started modifying the engine’s internals so it can handle these new types of connections (alongside the classic 1-pixel components). The real challenge here is keeping everything simple on the UX side, even though this feature targets more advanced users. The image below only shows what it might look like, this will probably change over time. As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: keep working on this feature, polish the UI/UX, ship it, and sadly… the end of stardance :(
Devlog #39 : Integrated circuits (again) I’m still working on this feature! I’m not at the frontend part yet, still adapting the engine. More details if you’re curious: A module has a definition that includes its name, public pins, and internal circuit. It can be used multiple times (it’s called an instance in the code). And all modules are listed in a catalog (that I’ll probably integrate in the frontend later). Instances can be selected, moved, copied and pasted, across the layers… The picture bellow shows how this feature could be used. It will make things much easier if you want to build more complex circuits like an 8 bit adder. You’ll just have to stack 8x 1-bit full adder modules! As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: finish the backend side, then integrate everything into the frontend, polish the UI, and ship!
Devlog #40 : Integrated circuits I’m (again) still working on this feature! Since my last devlog, I’ve updated the project document format to serialize the new modules. And that’s basically it! Next step: integrate them into the UI, polish the UX, and ship!
Devlog 41 : Integrated Circuits I’m working on the UI! The picture below shows what it currently looks like. I’m still not sure about the colors, so they might change. I still have the hardest part to figure out: How will users create and modify a module, UX-wise? Will it have its own sub-editor? How will users assign pins, name them, and define the module’s size and name? As always, if you enjoy the project, feel free to leave a star on GitHub! Repo: https://github.com/NaFo44/Cirkuit Next steps: Keep working on the UI, polish the UX/UI, and ship!
Devlog 42 : Integrated circuits (almost done!) It wasn’t easy! The UX part is actually really challenging. I had to rely on AI more than usual because Stardance is ending really soon, and I’m honestly a bit scared of not having enough time to ship :/ I’ll still try to polish the UI as much as possible! The screenshot below shows what it currently looks like. I added a new section for modules in the sidebar, where you can see all the modules you’ve created, edit them, or create new ones. When creating a new module, you can set its name, preview the footprint, add or remove inputs/outputs, and place them directly on the footprint. It’s almost ready tho! I’m just polishing the UX now. Next steps: finish this feature, polish the UI/UX, ship!
Ships:
Hi! I’m really happy to introduce you to my biggest project so far. It’s called Cirkuit, and it’s a logic circuit sandbox simulator… but with pixel art! That means you can basically build anything using just pixels. Why pixels? You may ask. Well, many logic simulators already exist, but the issue is that most of them aren’t very accessible to the average user. That’s why I wanted Cirkuit to be as easy to use as possible. I’m already quite familiar with TypeScript and React, which I used for this project. So the most difficult part was actually figuring out how to implement features without having 100 nested loops :D I had a hard time figuring out how to build the core engine (obviously), as well as the annotation system. I’m quite proud of how it looks and how well it works. This project was a perfect opportunity for me to improve my design skills. I worked hard to reduce friction between the interface and the user (aka you, dear shipwriters). One piece of advice: try it on a computer with a mouse. Phones and trackpads are supported, but it’s not the best experience. Hope you’ll like this project!...
|
1793055099.1470068
|
1793141499.1470068
|
|
62095
|
violin by @amiterlich05 | Stardance
|
amiterlich05
|
1
|
127.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-23T11:38:13Z", "hours": 127.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I designed and modeled a complete 3D violin from scratch using Onshape. The most challenging part was getting the curved body geometry and intricate details of the violin correct. I am really proud of how the final assembly turned out, and you can test it by opening the public Onshape CAD link.", "repo": "https://github.com/amiterlichpico-beep/violin-onshape", "demo": ""}]...
|
[{"post_id": 72618, "ts": "202 [{"post_id": 72618, "ts": "2026-09-23T11:15:34Z", "hours": 5.5556, "text": "DevLog 9 I’ve finished everything; I’m publishing it now."}, {"post_id": 72520, "ts": "2026-09-23T03:49:08Z", "hours": 9.995, "text": "Devlog 7 I’ve just about finished the final touches; all that’s left is to build the stand and add the very last details. I’ll be releasing it in the next devlog."}, {"post_id": 72324, "ts": "2026-09-22T17:47:09Z", "hours": 4.1386, "text": "Dev Vlog 7 So… I’ve solved the color issue and handled the final touches. I’ll work a bit more on the finishing details, then build a stand to mount it on—and that’s it. It should be ready very soon; I think maybe two more updates from now. Hopefully, it’ll be finished sometime tomorrow."}, {"post_id": 72198, "ts": "2026-09-22T13:14:42Z", "hours": 27.7378, "text": "Developer Vlog 6 I’m almost done; I really just have a few final touches left and need to make it stand upright. I probably won’t have time to add an arch, since I really need to wrap up this project and get back to studying. I don’t know why—I didn’t do anything to it—but it decided to turn purple; I’ll check everything over and then close out the file and the project. So… this is what it looks like right now."}, {"post_id": 71653, "ts": "2026-09-21T07:46:48Z", "hours": 22.2042, "text": "Devlog #5? I’ve more or less put all the parts together; all that’s left is to add textures, finishing touches, and a stand. I’m not sure if I’ll make a violin bow, too—I tried, but I really couldn’t get the hair right; if I do make one, it’ll probably be without the hair."}, {"post_id": 70493, "ts": "2026-09-19T08:50:26Z", "hours": 19.0517, "text": "Developer Vlog #4 I’ve finished making most of the violin parts; now I need to assemble everything and add textures and finishing touches."}, {"post_id": 69477, "ts": "2026-09-17T04:20:07Z", "hours": 10.4853, "text": "devlod#3 I’ve just finished assembling some of the parts and the bottom section of the violin; now, all that’s left is the top section and the final finishing touches."}, {"post_id": 68956, "ts": "2026-09-16T03:29:22Z", "hours": 16.5075, "text": "I continued working on the violin; I had already crafted almost the entire lower half and the ornamentation for the middle section."}, {"post_id": 68483, "ts": "2026-09-15T06:25:07Z", "hours": 11.0475, "text": "Hi, I want to say upfront that this will probably be pretty bad, since it’s the first time I’m writing a dev log like this… Anyway, for this project, I chose to work on a violin model using the web-based software Onshape. I’m roughly halfway through—or maybe just at the beginning… I mean, I have the structure down, but the hard part is still ahead. I need to do the finishing touches to make it look good and check that it’s properly converted into a printable file… uh… Yeah, I don’t have much else to say about it right now. So, sorry."}]...
|
Title: violin by @amiterlich05 | Stardance
Devlog Title: violin by @amiterlich05 | Stardance
Devlogs:
Hi, I want to say upfront that this will probably be pretty bad, since it’s the first time I’m writing a dev log like this… Anyway, for this project, I chose to work on a violin model using the web-based software Onshape. I’m roughly halfway through—or maybe just at the beginning… I mean, I have the structure down, but the hard part is still ahead. I need to do the finishing touches to make it look good and check that it’s properly converted into a printable file… uh… Yeah, I don’t have much else to say about it right now. So, sorry.
I continued working on the violin; I had already crafted almost the entire lower half and the ornamentation for the middle section.
devlod#3 I’ve just finished assembling some of the parts and the bottom section of the violin; now, all that’s left is the top section and the final finishing touches.
Developer Vlog #4 I’ve finished making most of the violin parts; now I need to assemble everything and add textures and finishing touches.
Devlog #5? I’ve more or less put all the parts together; all that’s left is to add textures, finishing touches, and a stand. I’m not sure if I’ll make a violin bow, too—I tried, but I really couldn’t get the hair right; if I do make one, it’ll probably be without the hair.
Developer Vlog 6 I’m almost done; I really just have a few final touches left and need to make it stand upright. I probably won’t have time to add an arch, since I really need to wrap up this project and get back to studying. I don’t know why—I didn’t do anything to it—but it decided to turn purple; I’ll check everything over and then close out the file and the project. So… this is what it looks like right now.
Dev Vlog 7 So… I’ve solved the color issue and handled the final touches. I’ll work a bit more on the finishing details, then build a stand to mount it on—and that’s it. It should be ready very soon; I think maybe two more updates from now. Hopefully, it’ll be finished sometime tomorrow.
Devlog 7 I’ve just about finished the final touches; all that’s left is to build the stand and add the very last details. I’ll be releasing it in the next devlog.
DevLog 9 I’ve finished everything; I’m publishing it now.
Ships:
I designed and modeled a complete 3D violin from scratch using Onshape. The most challenging part was getting the curved body geometry and intricate details of the violin correct. I am really proud of how the final assembly turned out, and you can test it by opening the public Onshape CAD link....
|
1793058538.4602268
|
1793144938.4602268
|
|
16683
|
Blur Stuff by @AbdurRehman | Stardance
|
AbdurRehman
|
1
|
126.53
|
826
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-15T15:46:55Z", "hours": 118.0, "multiplier": 14.02, "payout": 826, "blessing": "neutral", "text": "I made Blur Stuff, a privacy focused tool for safely sharing images, videos, GIFs, and documents. It automatically detects sensitive information such as faces, license plates, text, and PII, then lets you anonymize the detected areas with different anonymization effects. It also removes EXIF metadata so other sensitive information isn’t left hidden inside the file. The goal of this project is to make sharing media safely as easy as uploading it. Instead of manually searching through a file like a document or photo and manually covering stuff you don’t want others to see, Blur Stuff does this work for you. The hardest part of making this project was making anonymization work reliably across different types of media. Images were relatively simple, but videos and GIFs require frame by frame processing while keeping detections consistent over time. And to make things efficient and fast I also had to deal with things like tracking which were really tricky. Connecting the frontend and backend was also another challenge and then hosting everything also brought it’s problems with dependency conflicts which took quite a while to solve. The thing I am most proud of is that this became a real working and professional looking application rather than just a prototype type thing. It supports most of the commonly used media formats, has multiple customization options among other neat functionalities. Also I like how this project is privacy focused. Like it doesn’t store the user’s files ever. It just processes them, removing EXIF, and gives the result. Blur Stuff can be tested by uploading an image containing faces, text, or a license plate and let it detect the sensitive regions and then select what you want anonymized, and run the anonymization. The current deployment has limited memory and resources since I’m on a free plan, so larger videos and documents can take a while to process, and very large files may run into resource limitations. The app is also deployed using Railway’s serverless option, so the server may need a few seconds to start up if it hasn’t received a request recently. Also the selected region anonymization for videos is still a bit buggy but mostly it works. These are areas I will improve in the future.", "repo": "https://github.com/RealAbdurRehman/blur-stuff", "demo": "https://blurstuff.up.railway.app"}]...
|
[{"post_id": 50269, "ts": "202 [{"post_id": 50269, "ts": "2026-08-19T13:00:35Z", "hours": 8.5269, "text": "Since shipping Blur Stuff, I got feedback that the frontend felt too generic so I completely revamped the UI to give it a more intentional and fun style. I redesigned everything from colors to typography and everything else. Now the app has a more personal feel. I also cleaned up some small things here and there."}, {"post_id": 47548, "ts": "2026-08-15T14:59:59Z", "hours": 6.7497, "text": "Since the previous dev log, I have been focused on getting Blur Stuff ready for deployment. This ended up being much more painful than I expected. The biggest part was dealing with dependency issues. The project worked locally, but moving everything to a production environment exposed a bunch of problems with Python versions, PaddlePaddle, PaddleOCR, PaddleX, PyYAML, spaCy, OpenCV and other dependencies. I spent a lot of time testing different configurations, fixing dependency conflicts, debugging the production container, and figuring out why things that seemed to work okay locally were breaking during deployment. The biggest headache was PaddleOCR. I had to deal with missing system libraries, model downloading, Paddle initialization issues and eventually a oneDNN runtime error that was causing OCR requests to return 503s. After a lot of debugging and testing different configurations, I eventually got the OCR pipeline working properly in production. That was probably the one of the most frustrating parts of the entire project, but it is finally done. I also switched the spaCy model from en_core_web_lg to en_core_web_sm. The larger model was unnecessarily heavy for what Blur Stuff needs and was making deployments take way longer. Switching to the smaller model made deployment faster and also improved performance without having a noticeable impact on the PII detection quality. After successful deployment I finished the README and added the final assets, screenshots, logo and documentation. I added the MIT license, favicon, deployment related changes and generally cleaned up the entire repository. At this point, I think Blur Stuff is ready to ship. There are definitely still improvements I could make, especially improving performance, making video anonymization more reliable and efficient, and polishing various parts of the application but I don’t want to spend more time trying to make everything perfect. The current deployment is also running on Railway’s free plan, so there are some resource and memory limitations since Blur Stuff runs several machine learning models in the same process. For now, I’m okay with that rather than spending more time optimizing around the limitations of a free deployment. For now, I’m calling it finished and shipping it since the core functionality is working and the project is deployed. I’ll definitely come back to Blur Stuff later to improve it, but I think it’s time to move on to something new."}, {"post_id": 46326, "ts": "2026-08-13T13:59:24Z", "hours": 10.0189, "text": "Since the previous dev log, I worked on fixing the remaining issues in the anonymization workflow and finishing the frontend around the application. The biggest thing I worked on was selected video anonymization. There were still some problems where selected areas could stop being anonymized correctly or the anonymization could move away from the actual object as it moved through the video or retracking when something like a face was lost. I spent quite a lot of time testing different things, tracking down where the problems were coming from, and making the selected anonymization much more reliable across video frames. This ended up taking a lot more work than I initially expected, but the selected video workflow is now working much better. It still isn’t perfect and there are still some bugs and I think I probably need a lot more time to find and fix them but right now it is in a decent working state so I don’t plan to spend more time on achieving perfection because debugging and stuff is boring as hell. I also made some improvements to the overall frontend and added the remaining main pages. I added the about, arivacy, documentation pages and also did some other improvents around the frontend. The documentation now explains the available endpoints, detection targets, anonymization modes and other features. At this point, I feel like the main application is in a really good place. The core functionality is implemented, the main frontend workflow is complete, and the remaining work is mostly getting this thing hosted and stuff. Next, I plan to write the README file, host the application, and do a final round of testing and cleanup. After that, I think I’ll consider this project finished for a while (I will work on improving it further later) and move on to building something new."}, {"post_id": 45041, "ts": "2026-08-11T08:51:50Z", "hours": 10.0544, "text": "Since the previous dev log, I continued building the application workflow and have almost completed the anonymization process. I first worked on the anonymization routes and updated the backend so that the frontend can send detected regions back to the API and have them anonymized. This allows the user to choose which detections they want to anonymize instead of always having to process everything. I also added support for passing dynamic padding (and also made it so that other dynamic stuff is easy to add later) through the request so that the effects can be customized based on what the user wants. I also added client side file handling required for the results page. The original and processed files are kept available in the browser so they can be previewed and downloaded without needing to be stored on the server. Everything also handles missing files and stuff without breaking and I also added error handling with notifications which are displayed to the user. I also made a bunch of smaller UI improvements while connecting everything together. At this point, the main frontend workflow is coming together. Next I will fix small remaining issues and improve reliability rather than adding any major change. The next things I plan to work on are to mainly fix bugs in the code. Like GIFs still need some additional handling to make sure detections are applied across the animation rather than being treated like a normal image and the existing video tracking system is able to follow detections across frames, but during testing I noticed that the anonymization can drift away from the actual detected regions in videos. This is the major thing I need to fix. And I also plan to do some small changes to the UI and stuff and fix some bugs there before adding the remaining pages like the API and documentation pages."}, {"post_id": 44018, "ts": "2026-08-09T14:49:05Z", "hours": 8.77, "text": "Since the previous dev log, I continued building the application workflow and moved beyond the initial upload interface into review/customization functionality. I first worked on the file preview system so that uploaded files can be displayed correctly even when the browser cannot natively display them. Now a preview is generated for unsupported images and documents while keeping browser previews for files that are already supported. After that, I built the results page, which is where the user can review the detections found in their uploaded file and also customise stuff for anonymisation. The biggest addition was the detection review panel. Instead of simply processing everything automatically, the interface now shows the detected content which will allow users to review individual detections and choose which ones they want to work with. A lot of the work also went into the smaller UI/UX improvements. I also fixed a ton of issues that came up while connecting the different pieces together and handling the detection data and working with different file formats. At this point, the frontend is starting to really come together and look like a real app. The next step is to connect stuff to my anonymization API. The user will be able to to select specific detections, choose how they want them anonymized, and add other customizations."}, {"post_id": 43070, "ts": "2026-08-08T04:16:11Z", "hours": 7.8842, "text": "Since the previous dev log, I continued working on the frontend and have now finished the main landing page as well as the initial anonymize/file upload page. I first started by completing the remaining parts of the landing page by adding the footer, API description section, and some final component layout and CSS improvements. After that, I started building the anonymize page, which is where the actual application workflow begins. I implemented the complete upload interface with both file selection and drag and drop feature. I also added client side file handling so uploaded files can be passed from the landing page to the anonymize page without having to upload them to the server first. To do this, I implemented a small IndexedDB based file storage system in the browser. Uploaded files are temporarily stored locally with a timestamp allowing the anonymize page to retrieve the file when the user arrives there. The stored file automatically expires after a short period and is also removed once it has been retrieved. This keeps the upload flow client side and also avoids putting the file data into the URL or sending it to the backend before processing when not needed. The anonymize page now also handles different file types correctly and displays a preview based on their type. I also added different anonymization options making it straightforward to pass the processing preferences to the backend. I too spent time fixing bugs and adding small UX improvements across the new frontend functionality. Next I am going to connect the interface to the backend API and build the actual processing experience. Rather than anonymizing everything automatically, I will create a processing page where the user will be able to decide what to anonymize and I will probably add more customization."}, {"post_id": 41878, "ts": "2026-08-06T11:22:26Z", "hours": 9.1442, "text": "Since the previous dev log I’ve been completely focused on the frontend. I first set up the frontend stack by integrating Tailwind CSS for styles and Alpine.js for lightweight interactivity. I also created a reusable layout with shared components such as the header that future pages can be built consistently and easily. With that foundation in place, I began implementing the landing page. I designed and built the hero section, which consists of a cool drag and drop upload area, and an interactive before/after comparison slider that allows users to visually compare original and anonymized images, which makes the landing page looks awesome. Besides frontend work, I made a few backend improvements as well, including cleaning up temporary video files after processing to avoid leaving unnecessary files behind as originally they weren’t properly disposed of. Next I plan to continue working on the landing page for a bit by adding a footer and maybe some other useful section before connecting everything to the existing API and implementing the upload and processing workflow and building the remaining pages needed."}, {"post_id": 40707, "ts": "2026-08-04T12:12:59Z", "hours": 5.1222, "text": "I focused on preparing everything for the frontend rather than adding new features. I reorganized the API by moving all routes into a dedicated package and grouping every endpoint under /api/v1. This gives everything a much cleaner structure and makes everything look professional. I also added detection endpoints for all supported files. Before the project was primarily focused on anonymization, and even though I had a detection endpoint, it only supported images and was buggy. These new endpoints allows receiving detection results directly without applying any effects and serve as a foundation for selective anonymization that I will implement later. While implementing these endpoints, I refactored how detection IDs are handled across the application. Before they too were buggy but I got them to work. I not only worked on the backend but also worked on the frontend by laying out it’s initial structure that I will build upon. I also spent some time cleaning up the codebase by removing unused imports and simplifying parts of the project. Now I plan to really start working on building the frontend. Now that the API structure is in place, I want to focus on creating a professional looking interface that allows users to interact with all of the functionality that has been implemented so far plus more."}, {"post_id": 40104, "ts": "2026-08-03T14:28:55Z", "hours": 7.8764, "text": "I expanded the range of file types that the application supports. Image support now includes TIFF/TIF, HEIC/HEIF, and GIF files. HEIC/HEIF images are automatically converted to PNG after processing since they are not widely supported for encoding. I also added support for documents which include PDF, DOCX, PPTX, and XLSX files. Rather than building separate anonymization logic for every Office file format, they are first converted to PDF and then are annonymized the same way as PDFs which keeps the implementation much simpler. While working on adding support for these files, I noticed that I had a bunch of duplicated code. So I spent some time refactoring stuff and removing duplicated stuff. I also found that GIF processing was slow so I worked on making it faster by treating it the same as a video and using trackers on it rather than running detection on every frame. I also made few smaller improvements, including adjusting the confidence thresholds for some of the detectors since I was noticing a bunch of false positives and fixing several bugs that came along the way. The next thing I plan to work on are cleaning up the code by finding and removing unused stuff, and then building the frontend for the application."}, {"post_id": 39358, "ts": "2026-08-02T09:02:20Z", "hours": 4.3503, "text": "I focused on improving the performance and maintainability of the anonymization system rather than adding new features. The biggest change was a refactor of the video anonymization system. Instead of repeatedly creating new anonymization masks for every frame, the tracker now caches and reuses them wherever possible. This reduces unnecessary work during video processing and also makes it easier in the future to add further performance improvements. I also improved the applications behavior by preventing both full text anonymization and PII anonymization to be selected at the same time since these targets overlap and would produce redundant processing. I also cleaned up several parts of the codebase by removing unused code and making the everything a bit easier to maintain. I also spent a lot of time experimenting with more aggressive optimization techniques but after testing, I decided to postpone those changes because they added complexity without providing the improvement I was looking for (and they were kind of buggy and it would take a lot more time to fix them). Instead, I decided to focus on optimizations that are simpler. Right now I don’t plan to work on improving the performance (even though there probably are tons of improvements to be made) because that stuff is boring and difficult as hell. Instead I’m going to add support for more file types like PDF."}, {"post_id": 38921, "ts": "2026-08-01T14:49:34Z", "hours": 4.2206, "text": "I expanded the anonymization system by adding multiple anonymization modes instead of having only the pixelization effect. The application can now switch between anonymizing regions using blur, solid fill, noise, emoji overlay, and inpainting. The emoji overlay right now is pretty basic but I plan on improving it later. I also improved the quality of face anonymization by replacing rectangular masks with elliptical masks (for some of the effects), producing better looking results. I also refactored the anonymization pipeline to separate anonymization effects from overlay rendering making future additions even easier and also cleaned up and reorganized the existing image effect implementations to improve readability and consistency across the project. Next, I plan to improve the performance of the anonymization system by trying to reuse detection targets and effect masks wherever possible."}, {"post_id": 38713, "ts": "2026-08-01T08:01:59Z", "hours": 2.0572, "text": "I improved the overall quality and efficiency of the video anonymization system. I updated detection intervals to use the video’s frame rate instead of relying on a hard coded number of frames. This allows the system to adapt well to videos with different frame rates. I also evaluated several object tracking algorithms, including DaSiamRPN, to find a good one that balances accuracy and speed. After comparing the performance of a bunch of them, I switched to Nano Tracker which was faster than my original KCF and CSRT trackers while being more accurate. I made additional improvements to privacy by removing metadata from exported videos. I am now also applying EXIF orientation before processing ensuring that images taken from different devices are processed in their correct orientation. Next, I plan to introduce different anonymization modes like blur and solid black boxes."}, {"post_id": 38633, "ts": "2026-08-01T04:05:36Z", "hours": 6.9461, "text": "I focused on adding support for videos. I first implemented a basic video anonymization system so uploaded videos could be processed the same way as images. I also made sure that the audio for the video is preserved so that it carries over to the anonymized video being unchanged. After getting the basic system working, I improved how videos are processed by adding object tracking and scene change detection. Instead of running detections on every frame, the system can now follow previously detected objects across frames and automatically run detections again when needed (when a tracker is lost, or the scene changes drastically, or periodically after a set amount of frames). This provides a great performance boost while the result stays reliable. Next, I want to continue improving video processing by optimizing it further and making it more accurate."}, {"post_id": 37518, "ts": "2026-07-30T10:23:19Z", "hours": 3.8147, "text": "I focused on improving the entire OCR system, as the previous approach with EasyOCR was missing too much text and reducing the accuracy of the entire system. After spending quite a bit of time trying to improve it, I decided to replace it with PaddleOCR. Now more accurate text detections are being produced making the entire program more robust. After, I expanded the regex based detectors to also account for URLs in addition to emails, etc. I also improved the phone number detection logic to reduce false positives and improve overall accuracy. Then, I adjusted padding around blurred regions so that stuff is covered more consistently and without blurring unnecessary content. The last thing I did was optimizing PaddleOCR as it was much slower than EasyOCR. After a lot of tinkering I was able to significantly reduce its processing time. For some files it now performs at roughly the same speed as EasyOCR while being way more accurate. Next, I probably want to add support for more file types and ultimately videos. And later also support for multiple languages."}, {"post_id": 36966, "ts": "2026-07-29T12:14:19Z", "hours": 3.4994, "text": "I added a new way for the app to detect personal information by using named entity recognition. Previously, the app could only find structured information like emails and phone numbers, but it could not detect things like names. So I integrated Presidio to identify such information from the text extracted from images. These extractions are then combined with the existing PII detections done using regex for the structured stuff. This improves the accuracy of the entire system by combining multiple detection methods instead of relying on one single approach. Next, I will improve the detection process further as right now it isn’t too accurate, mostly because I think the OCR is missing some stuff from the text. So I might try replacing it or find some other way."}, {"post_id": 36365, "ts": "2026-07-28T13:10:24Z", "hours": 6.6581, "text": "I implemented PII detection, allowing the app to identify and blur sensitive information within the text extracted from images instead of blurring everything blindly. First I used regular expressions to detect structured data such as email addresses, phone numbers, etc. But OCR frequently omitted punctuation, causing many valid emails to be missed. To fix this, I redesigned the everything around an OCR token graph. Each token stores its bounding box, neighboring tokens, and line information, allowing the detections to be more accurate. I might switch to PaddleOCR again or someother ocr so that I get more accurate detections. I also spent time improving the overall design of the PII detection system. These changes make it easier to extend in the future while improving the accuracy of the detected regions that are blurred. Next, I will implement NER based detection to identify unstructured personal information such as names."}, {"post_id": 21527, "ts": "2026-07-03T15:19:19Z", "hours": 5.6331, "text": "I implemented OCR-based text detection, allowing the application to detect text within uploaded images. I initially used PaddleOCR, but found that it took over 30 seconds to process a single image. After spending a lot of time trying to optimize its performance, I decided to switch to EasyOCR, which reduced the processing time to around one second while maintaining the same detection quality. Switching the OCR engines was well worth it. I also tried to keep the OCR implementation consistent with the face and license plate detectors and also optimized them too. Next, I will implement detection of sensitive information within the extracted text using regular expressions and NER. This will allow the application to distinguish ordinary text from personal information such as names, emails, phone numbers, etc, and allow me to blur only the relevant regions (right now the the entirety of the detected text is blurred)."}, {"post_id": 20974, "ts": "2026-07-02T18:27:02Z", "hours": 3.4869, "text": "I expanded the application by adding support for license plate detection and blurring. The app can now detect both faces and license plates in an image and blur them. I also made the API more flexible by allowing users to choose what they want to anonymize. Instead of always processing everything, they can now select whether to detect faces, license plates, or both. This makes the application more efficient and easier to extend with new features in the future. I also improved the structure of the project so that adding new types of detections will require much less work. I also added unique ids to each detection, which will be useful for future features that let users blur individual detections. Next, I will implement detection of sensitive text within images. This will allow the app to identify information such as email addresses, phone numbers, and other personal details, then blur them."}, {"post_id": 20600, "ts": "2026-07-02T07:10:58Z", "hours": 1.7692, "text": "I focused on improving the backend rather than adding new features. I reorganized the API by splitting it into smaller, more focused endpoints. For example, there’s now a dedicated endpoint that only detects faces and returns their locations, while separate endpoints handle image anonymization and API health checks. This makes the API easier to use and gives me more flexibility as I add new features. I also reorganized the detection system so that all object detection goes through a single service. At the moment it only detects faces, but it’s now much easier to add support for other types, such as license plates, without having to redesign the rest of the application. Health check endpoints let the application report whether it’s running correctly and whether the AI models have loaded successfully. Next I’m going to add detection beyond faces by adding license plate detection. These changes are gonna make it much easier for me to do so."}, {"post_id": 20144, "ts": "2026-07-01T18:06:28Z", "hours": 2.2011, "text": "I spent some time refining the face anonymization system. The pixelation effect was completely reworked to produce smoother, better looking results while blurring the faces more accurately (using the previous blur you could sometimes make out the features of the people). I also cleaned up the implementation, making the blur functionality much simpler and easier to maintain and most importantly I made it more reusable for ease of use in the future for more features. Behind the scenes, I also reorganized the project’s Python environment by removing unused libraries and recreating the virtual environment. Next I am planning to either add support for videos or make the API better by creating more focused routes such as one that only detects faces and other that returns the blur image. I also want to add functionality where the user can select which people to anonymize instead of blurring everybody detected. After that, I’ll expand beyond simple face anonymization by adding support for automatically detecting and anonymizing other sensitive information, such as license plates, documents, and other personally identifiable content."}, {"post_id": 19929, "ts": "2026-07-01T11:30:11Z", "hours": 4.4158, "text": "Replaced the temporary grayscale filter with automatic face anonymization. Uploaded images are now scanned for faces, and every detected face is pixelated. I also improved detection accuracy to reduce missed faces by tweaking a bunch of stuff for a while and adding more functionality to my face detection like running the image at multiple sizes. A lot of my time was also spent making the pixelated effect look good. I first went for only blurring the faces but now the face is pixelated along with a smooth transition into the surrounding image making the effect look pretty good. Right now images with large crowds are correctly blurred, including people who are far away or appear very small in the image."}, {"post_id": 19370, "ts": "2026-06-30T17:34:05Z", "hours": 1.9744, "text": "Integrated OpenCV so uploaded images are now decoded, processed, and returned to the client. I also introduced modularity into the code by creating separate modules for each step. The grayscale filter is only a temporary placeholder before I implement functionality such as blurring faces."}, {"post_id": 19094, "ts": "2026-06-30T09:42:15Z", "hours": 0.4869, "text": "Added image upload functionality with validation for missing files and non image uploads. The API right now only returns basic metadata about the upload. Next I’ll integrate OpenCV to begin the image processing stage."}, {"post_id": 19079, "ts": "2026-06-30T08:42:18Z", "hours": 0.6667, "text": "Set up the project’s foundation by creating Flask application structure, initializing Git, creating a virtual environment, and organizing the codebase for future features. I also got the development server running to verify everything is wired up correctly. Next, I’ll implement image uploads."}]...
|
Title: Blur Stuff by @AbdurRehman | Stardance
Dev Title: Blur Stuff by @AbdurRehman | Stardance
Devlogs:
Set up the project’s foundation by creating Flask application structure, initializing Git, creating a virtual environment, and organizing the codebase for future features. I also got the development server running to verify everything is wired up correctly. Next, I’ll implement image uploads.
Added image upload functionality with validation for missing files and non image uploads. The API right now only returns basic metadata about the upload. Next I’ll integrate OpenCV to begin the image processing stage.
Integrated OpenCV so uploaded images are now decoded, processed, and returned to the client. I also introduced modularity into the code by creating separate modules for each step. The grayscale filter is only a temporary placeholder before I implement functionality such as blurring faces.
Replaced the temporary grayscale filter with automatic face anonymization. Uploaded images are now scanned for faces, and every detected face is pixelated. I also improved detection accuracy to reduce missed faces by tweaking a bunch of stuff for a while and adding more functionality to my face detection like running the image at multiple sizes. A lot of my time was also spent making the pixelated effect look good. I first went for only blurring the faces but now the face is pixelated along with a smooth transition into the surrounding image making the effect look pretty good. Right now images with large crowds are correctly blurred, including people who are far away or appear very small in the image.
I spent some time refining the face anonymization system. The pixelation effect was completely reworked to produce smoother, better looking results while blurring the faces more accurately (using the previous blur you could sometimes make out the features of the people). I also cleaned up the implementation, making the blur functionality much simpler and easier to maintain and most importantly I made it more reusable for ease of use in the future for more features. Behind the scenes, I also reorganized the project’s Python environment by removing unused libraries and recreating the virtual environment. Next I am planning to either add support for videos or make the API better by creating more focused routes such as one that only detects faces and other that returns the blur image. I also want to add functionality where the user can select which people to anonymize instead of blurring everybody detected. After that, I’ll expand beyond simple face anonymization by adding support for automatically detecting and anonymizing other sensitive information, such as license plates, documents, and other personally identifiable content.
I focused on improving the backend rather than adding new features. I reorganized the API by splitting it into smaller, more focused endpoints. For example, there’s now a dedicated endpoint that only detects faces and returns their locations, while separate endpoints handle image anonymization and API health checks. This makes the API easier to use and gives me more flexibility as I add new features. I also reorganized the detection system so that all object detection goes through a single service. At the moment it only detects faces, but it’s now much easier to add support for other types, such as license plates, without having to redesign the rest of the application. Health check endpoints let the application report whether it’s running correctly and whether the AI models have loaded successfully. Next I’m going to add detection beyond faces by adding license plate detection. These changes are gonna make it much easier for me to do so.
I expanded the application by adding support for license plate detection and blurring. The app can now detect both faces and license plates in an image and blur them. I also made the API more flexible by allowing users to choose what they want to anonymize. Instead of always processing everything, they can now select whether to detect faces, license plates, or both. This makes the application more efficient and easier to extend with new features in the future. I also improved the structure of the project so that adding new types of detections will require much less work. I also added unique ids to each detection, which will be useful for future features that let users blur individual detections. Next, I will implement detection of sensitive text within images. This will allow the app to identify information such as email addresses, phone numbers, and other personal details, then blur them.
I implemented OCR-based text detection, allowing the application to detect text within uploaded images. I initially used PaddleOCR, but found that it took over 30 seconds to process a single image. After spending a lot of time trying to optimize its performance, I decided to switch to EasyOCR, which reduced the processing time to around one second while maintaining the same detection quality. Switching the OCR engines was well worth it. I also tried to keep the OCR implementation consistent with the face and license plate detectors and also optimized them too. Next, I will implement detection of sensitive information within the extracted text using regular expressions and NER. This will allow the application to distinguish ordinary text from personal information such as names, emails, phone numbers, etc, and allow me to blur only the relevant regions (right now the the entirety of the detected text is blurred).
I implemented PII detection, allowing the app to identify and blur sensitive information within the text extracted from images instead of blurring everything blindly. First I used regular expressions to detect structured data such as email addresses, phone numbers, etc. But OCR frequently omitted punctuation, causing many valid emails to be missed. To fix this, I redesigned the everything around an OCR token graph. Each token stores its bounding box, neighboring tokens, and line information, allowing the detections to be more accurate. I might switch to PaddleOCR again or someother ocr so that I get more accurate detections. I also spent time improving the overall design of the PII detection system. These changes make it easier to extend in the future while improving the accuracy of the detected regions that are blurred. Next, I will implement NER based detection to identify unstructured personal information such as names.
I added a new way for the app to detect personal information by using named entity recognition. Previously, the app could only find structured information like emails and phone numbers, but it could not detect things like names. So I integrated Presidio to identify such information from the text extracted from images. These extractions are then combined with the existing PII detections done using regex for the structured stuff. This improves the accuracy of the entire system by combining multiple detection methods instead of relying on one single approach. Next, I will improve the detection process further as right now it isn’t too accurate, mostly because I think the OCR is missing some stuff from the text. So I might try replacing it or find some other way.
I focused on improving the entire OCR system, as the previous approach with EasyOCR was missing too much text and reducing the accuracy of the entire system. After spending quite a bit of time trying to improve it, I decided to replace it with PaddleOCR. Now more accurate text detections are being produced making the entire program more robust. After, I expanded the regex based detectors to also account for URLs in addition to emails, etc. I also improved the phone number detection logic to reduce false positives and improve overall accuracy. Then, I adjusted padding around blurred regions so that stuff is covered more consistently and without blurring unnecessary content. The last thing I did was optimizing PaddleOCR as it was much slower than EasyOCR. After a lot of tinkering I was able to significantly reduce its processing time. For some files it now performs at roughly the same speed as EasyOCR while being way more accurate. Next, I probably want to add support for more file types and ultimately videos. And later also support for multiple languages.
I focused on adding support for videos. I first implemented a basic video anonymization system so uploaded videos could be processed the same way as images. I also made sure that the audio for the video is preserved so that it carries over to the anonymized video being unchanged. After getting the basic system working, I improved how videos are processed by adding object tracking and scene change detection. Instead of running detections on every frame, the system can now follow previously detected objects across frames and automatically run detections again when needed (when a tracker is lost, or the scene changes drastically, or periodically after a set amount of frames). This provides a great performance boost while the result stays reliable. Next, I want to continue improving video processing by optimizing it further and making it more accurate.
I improved the overall quality and efficiency of the video anonymization system. I updated detection intervals to use the video’s frame rate instead of relying on a hard coded number of frames. This allows the system to adapt well to videos with different frame rates. I also evaluated several object tracking algorithms, including DaSiamRPN, to find a good one that balances accuracy and speed. After comparing the performance of a bunch of them, I switched to Nano Tracker which was faster than my original KCF and CSRT trackers while being more accurate. I made additional improvements to privacy by removing metadata from exported videos. I am now also applying EXIF orientation before processing ensuring that images taken from different devices are processed in their correct orientation. Next, I plan to introduce different anonymization modes like blur and solid black boxes.
I expanded the anonymization system by adding multiple anonymization modes instead of having only the pixelization effect. The application can now switch between anonymizing regions using blur, solid fill, noise, emoji overlay, and inpainting. The emoji overlay right now is pretty basic but I plan on improving it later. I also improved the quality of face anonymization by replacing rectangular masks with elliptical masks (for some of the effects), producing better looking results. I also refactored the anonymization pipeline to separate anonymization effects from overlay rendering making future additions even easier and also cleaned up and reorganized the existing image effect implementations to improve readability and consistency across the project. Next, I plan to improve the performance of the anonymization system by trying to reuse detection targets and effect masks wherever possible.
I focused on improving the performance and maintainability of the anonymization system rather than adding new features. The biggest change was a refactor of the video anonymization system. Instead of repeatedly creating new anonymization masks for every frame, the tracker now caches and reuses them wherever possible. This reduces unnecessary work during video processing and also makes it easier in the future to add further performance improvements. I also improved the applications behavior by preventing both full text anonymization and PII anonymization to be selected at the same time since these targets overlap and would produce redundant processing. I also cleaned up several parts of the codebase by removing unused code and making the everything a bit easier to maintain. I also spent a lot of time experimenting with more aggressive optimization techniques but after testing, I decided to postpone those changes because they added complexity without providing the improvement I was looking for (and they were kind of buggy and it would take a lot more time to fix them). Instead, I decided to focus on optimizations that are simpler. Right now I don’t plan to work on improving the performance (even though there probably are tons of improvements to be made) because that stuff is boring and difficult as hell. Instead I’m going to add support for more file types like PDF.
I expanded the range of file types that the application supports. Image support now includes TIFF/TIF, HEIC/HEIF, and GIF files. HEIC/HEIF images are automatically converted to PNG after processing since they are not widely supported for encoding. I also added support for documents which include PDF, DOCX, PPTX, and XLSX files. Rather than building separate anonymization logic for every Office file format, they are first converted to PDF and then are annonymized the same way as PDFs which keeps the implementation much simpler. While working on adding support for these files, I noticed that I had a bunch of duplicated code. So I spent some time refactoring stuff and removing duplicated stuff. I also found that GIF processing was slow so I worked on making it faster by treating it the same as a video and using trackers on it rather than running detection on every frame. I also made few smaller improvements, including adjusting the confidence thresholds for some of the detectors since I was noticing a bunch of false positives and fixing several bugs that came along the way. The next thing I plan to work on are cleaning up the code by finding and removing unused stuff, and then building the frontend for the application.
I focused on preparing everything for the frontend rather than adding new features. I reorganized the API by moving all routes into a dedicated package and grouping every endpoint under /api/v1. This gives everything a much cleaner structure and makes everything look professional. I also added detection endpoints for all supported files. Before the project was primarily focused on anonymization, and even though I had a detection endpoint, it only supported images and was buggy. These new endpoints allows receiving detection results directly without applying any effects and serve as a foundation for selective anonymization that I will implement later. While implementing these endpoints, I refactored how detection IDs are handled across the application. Before they too were buggy but I got them to work. I not only worked on the backend but also worked on the frontend by laying out it’s initial structure that I will build upon. I also spent some time cleaning up the codebase by removing unused imports and simplifying parts of the project. Now I plan to really start working on building the frontend. Now that the API structure is in place, I want to focus on creating a professional looking interface that allows users to interact with all of the functionality that has been implemented so far plus more.
Since the previous dev log I’ve been completely focused on the frontend. I first set up the frontend stack by integrating Tailwind CSS for styles and Alpine.js for lightweight interactivity. I also created a reusable layout with shared components such as the header that future pages can be built consistently and easily. With that foundation in place, I began implementing the landing page. I designed and built the hero section, which consists of a cool drag and drop upload area, and an interactive before/after comparison slider that allows users to visually compare original and anonymized images, which makes the landing page looks awesome. Besides frontend work, I made a few backend improvements as well, including cleaning up temporary video files after processing to avoid leaving unnecessary files behind as originally they weren’t properly disposed of. Next I plan to continue working on the landing page for a bit by adding a footer and maybe some other useful section before connecting everything to the existing API and implementing the upload and processing workflow and building the remaining pages needed.
Since the previous dev log, I continued working on the frontend and have now finished the main landing page as well as the initial anonymize/file upload page. I first started by completing the remaining parts of the landing page by adding the footer, API description section, and some final component layout and CSS improvements. After that, I started building the anonymize page, which is where the actual application workflow begins. I implemented the complete upload interface with both file selection and drag and drop feature. I also added client side file handling so uploaded files can be passed from the landing page to the anonymize page without having to upload them to the server first. To do this, I implemented a small IndexedDB based file storage system in the browser. Uploaded files are temporarily stored locally with a timestamp allowing the anonymize page to retrieve the file when the user arrives there. The stored file automatically expires after a short period and is also removed once it has been retrieved. This keeps the upload flow client side and also avoids putting the file data into the URL or sending it to the backend before processing when not needed. The anonymize page now also handles different file types correctly and displays a preview based on their type. I also added different anonymization options making it straightforward to pass the processing preferences to the backend. I too spent time fixing bugs and adding small UX improvements across the new frontend functionality. Next I am going to connect the interface to the backend API and build the actual processing experience. Rather than anonymizing everything automatically, I will create a processing page where the user will be able to decide what to anonymize and I will probably add more customization.
Since the previous dev log, I continued building the application workflow and moved beyond the initial upload interface into review/customization functionality. I first worked on the file preview system so that uploaded files can be displayed correctly even when the browser cannot natively display them. Now a preview is generated for unsupported images and documents while keeping browser previews for files that are already supported. After that, I built the results page, which is where the user can review the detections found in their uploaded file and also customise stuff for anonymisation. The biggest addition was the detection review panel. Instead of simply processing everything automatically, the interface now shows the detected content which will allow users to review individual detections and choose which ones they want to work with. A lot of the work also went into the smaller UI/UX improvements. I also fixed a ton of issues that came up while connecting the different pieces together and handling the detection data and working with different file formats. At this point, the frontend is starting to really come together and look like a real app. The next step is to connect stuff to my anonymization API. The user will be able to to select specific detections, choose how they want them anonymized, and add other customizations.
Since the previous dev log, I continued building the application workflow and have almost completed the anonymization process. I first worked on the anonymization routes and updated the backend so that the frontend can send detected regions back to the API and have them anonymized. This allows the user to choose which detections they want to anonymize instead of always having to process everything. I also added support for passing dynamic padding (and also made it so that other dynamic stuff is easy to add later) through the request so that the effects can be customized based on what the user wants. I also added client side file handling required for the results page. The original and processed files are kept available in the browser so they can be previewed and downloaded without needing to be stored on the server. Everything also handles missing files and stuff without breaking and I also added error handling with notifications which are displayed to the user. I also made a bunch of smaller UI improvements while connecting everything together. At this point, the main frontend workflow is coming together. Next I will fix small remaining issues and improve reliability rather than adding any major change. The next things I plan to work on are to mainly fix bugs in the code. Like GIFs still need some additional handling to make sure detections are applied across the animation rather than being treated like a normal image and the existing video tracking system is able to follow detections across frames, but during testing I noticed that the anonymization can drift away from the actual detected regions in videos. This is the major thing I need to fix. And I also plan to do some small changes to the UI and stuff and fix some bugs there before adding the remaining pages like the API and documentation pages.
Since the previous dev log, I worked on fixing the remaining issues in the anonymization workflow and finishing the frontend around the application. The biggest thing I worked on was selected video anonymization. There were still some problems where selected areas could stop being anonymized correctly or the anonymization could move away from the actual object as it moved through the video or retracking when something like a face was lost. I spent quite a lot of time testing different things, tracking down where the problems were coming from, and making the selected anonymization much more reliable across video frames. This ended up taking a lot more work than I initially expected, but the selected video workflow is now working much better. It still isn’t perfect and there are still some bugs and I think I probably need a lot more time to find and fix them but right now it is in a decent working state so I don’t plan to spend more time on achieving perfection because debugging and stuff is boring as hell. I also made some improvements to the overall frontend and added the remaining main pages. I added the about, arivacy, documentation pages and also did some other improvents around the frontend. The documentation now explains the available endpoints, detection targets, anonymization modes and other features. At this point, I feel like the main application is in a really good place. The core functionality is implemented, the main frontend workflow is complete, and the remaining work is mostly getting this thing hosted and stuff. Next, I plan to write the README file, host the application, and do a final round of testing and cleanup. After that, I think I’ll consider this project finished for a while (I will work on improving it further later) and move on to building something new.
Since the previous dev log, I have been focused on getting Blur Stuff ready for deployment. This ended up being much more painful than I expected. The biggest part was dealing with dependency issues. The project worked locally, but moving everything to a production environment exposed a bunch of problems with Python versions, PaddlePaddle, PaddleOCR, PaddleX, PyYAML, spaCy, OpenCV and other dependencies. I spent a lot of time testing different configurations, fixing dependency conflicts, debugging the production container, and figuring out why things that seemed to work okay locally were breaking during deployment. The biggest headache was PaddleOCR. I had to deal with missing system libraries, model downloading, Paddle initialization issues and eventually a oneDNN runtime error that was causing OCR requests to return 503s. After a lot of debugging and testing different configurations, I eventually got the OCR pipeline working properly in production. That was probably the one of the most frustrating parts of the entire project, but it is finally done. I also switched the spaCy model from en_core_web_lg to en_core_web_sm. The larger model was unnecessarily heavy for what Blur Stuff needs and was making deployments take way longer. Switching to the smaller model made deployment faster and also improved performance without having a noticeable impact on the PII detection quality. After successful deployment I finished the README and added the final assets, screenshots, logo and documentation. I added the MIT license, favicon, deployment related changes and generally cleaned up the entire repository. At this point, I think Blur Stuff is ready to ship. There are definitely still improvements I could make, especially improving performance, making video anonymization more reliable and efficient, and polishing various parts of the application but I don’t want to spend more time trying to make everything perfect. The current deployment is also running on Railway’s free plan, so there are some resource and memory limitations since Blur Stuff runs several machine learning models in the same process. For now, I’m okay with that rather than spending more time optimizing around the limitations of a free deployment. For now, I’m calling it finished and shipping it since the core functionality is working and the project is deployed. I’ll definitely come back to Blur Stuff later to improve it, but I think it’s time to move on to something new.
Since shipping Blur Stuff, I got feedback that the frontend felt too generic so I completely revamped the UI to give it a more intentional and fun style. I redesigned everything from colors to typography and everything else. Now the app has a more personal feel. I also cleaned up some small things here and there.
Ships:
I made Blur Stuff, a privacy focused tool for safely sharing images, videos, GIFs, and documents. It automatically detects sensitive information such as faces, license plates, text, and PII, then lets you anonymize the detected areas with different anonymization effects. It also removes EXIF metadata so other sensitive information isn’t left hidden inside the file. The goal of this project is to make sharing media safely as easy as uploading it. Instead of manually searching through a file like a document or photo and manually covering stuff you don’t want others to see, Blur Stuff does this work for you. The hardest part of making this project was making anonymization work reliably across different types of media. Images were relatively simple, but videos and GIFs require frame by frame processing while keeping detections consistent over time. And to make things efficient and fast I also had to deal with things like tracking which were really tricky. Connecting the frontend and backend was also another challenge and then hosting everything also brought it’s problems with dependency conflicts which took quite a while to solve. The thing I am most proud of is that this became a real working and professional looking application rather than just a prototype type thing. It supports most of the commonly used media formats, has multiple customization options among other neat functionalities. Also I like how this project is privacy focused. Like it doesn’t store the user’s files ever. It just processes them, removing EXIF, and gives the result. Blur Stuff can be tested by uploading an image containing faces, text, or a license plate and let it detect the sensitive regions and then select what you want anonymized, and run the anonymization. The current deployment has limited memory and resources since I’m on a free plan, so larger videos and documents can take a while to process, and very large files may run into resource limitations. The app is also deployed using Railway’s serverless option, so the server may need a few seconds to start up if it hasn’t received a request recently. Also the selected region anonymization for videos is still a bit buggy but mostly it works. These are areas I will improve in the future....
|
1793000835.739663
|
1793087235.739663
|
|
15442
|
Cornilieus by @Falling10fruit | Stardance
|
Falling10fruit
|
0
|
126.33
|
0
|
[]
|
[{"post_id": 80316, "ts": "202 [{"post_id": 80316, "ts": "2026-10-17T08:24:29Z", "hours": 27.3931, "text": "Ah a bit of work here and there amidst A levels. what a shame for those 17 hours. whoops :) made another vite folder within the repositories so I can test out shaders without the other parts of the project getting in the way."}, {"post_id": 48774, "ts": "2026-08-17T09:44:53Z", "hours": 1.9389, "text": "So remember when last time I thought “oh no how to do private prefix arrays”? Well, an hour later and I discovered “Oh, my 2^24 entities can be divided by 256 and then 256 again so I’ll just have to do 3 prefix sums layered one on top of each other on the thread level” I don’t know what happened but my brand new 8 bit radix pass takes 460+ms. Yay"}, {"post_id": 48316, "ts": "2026-08-16T16:59:36Z", "hours": 7.4489, "text": "So I’ve hit a brick wall. gogle told me that to improve my 4 bit radix shader is to do 8 bits at a time to halve the number of passes (and that a byte is industry standard) but I can’t figure out how to like create a private histogram for each of the 256 digits also I got a 72 on math AS levels :P"}, {"post_id": 41934, "ts": "2026-08-06T13:43:28Z", "hours": 15.7667, "text": "Hey guys so I reduced the chunk size so that joints don’t have to hope that there’s at most 16 entities within 16 tiles Also I was reading the dev time of my other project and I accrued almost 6 hours over the limit, whoops :P"}, {"post_id": 31103, "ts": "2026-07-19T07:12:44Z", "hours": 1.75, "text": "I made a pool of unmapped buffers so I can continuously record the time taken so I can clearly see how much worse my changes to the algorithm are."}, {"post_id": 30643, "ts": "2026-07-18T11:47:17Z", "hours": 1.6572, "text": "I tried to optimize sorting by reducing the memory footprint of every thread so they could fit more threads. Mid-bitpacking, I decided to test the pipeline and viola. I’ve doubled execution time. Also rerolls only add like 10% or less of what you initially rolled. Absolute scams"}, {"post_id": 30186, "ts": "2026-07-17T15:37:17Z", "hours": 1.0831, "text": "So by bitpacking I was able to make the array longer while fitting within the shared memory limit. That means that more threads can work on the kogge stone -> larger workgroup size -> less iterations per thread. school’s back btw"}, {"post_id": 29380, "ts": "2026-07-16T09:26:18Z", "hours": 7.0303, "text": "So the sorting system is taking a bit too long, ah well I’ll figure it out. Google says it’s possible to get it fast enough"}, {"post_id": 26708, "ts": "2026-07-11T17:33:06Z", "hours": 8.0044, "text": "So I was trying to visualize the buffer on a helper static website so I can eyedrop data since reading a 16384 length array isn’t efficient but apparently chromium dropped an update that prevents mouse interactions the moment you use their builtin eyedropper so here’s my replacement (not what all 8 hours was spent on pls believe me)"}, {"post_id": 25985, "ts": "2026-07-10T15:13:37Z", "hours": 13.3789, "text": "So I forgot to add rotations to the collision thing. Also I got my first ever Device Lost error yay. No one told me that not posting for over 10 hours will deduct me of my precious work."}, {"post_id": 24278, "ts": "2026-07-07T18:55:34Z", "hours": 8.4122, "text": "some stufff so collisions taking their sweet time with gjk are seperated and moved to the entities_buffer_meta so the gpu can focus on resolving those stubborn collisions look, after several parallel friendly paradigms the last step of my code is this sequential and divergent code"}, {"post_id": 22349, "ts": "2026-07-04T19:39:15Z", "hours": 8.0772, "text": "Man I made a lot of mistakes earlier whoop. Anyways here’s a naive implementation of the support function for the gjk algo. I’m going to move the entity_nodes buffer into shared memory (or at least the collision pair’s colliding mesh nodes into private memory) tomorrow"}, {"post_id": 18412, "ts": "2026-06-29T15:34:11Z", "hours": 1.4953, "text": "Yay yesterday’s issue is fixed, in theory. Man, I haven’t actually like tested any of this code. Should I just print the data from the buffer and eye it or actually try to render it… Cause I’m definitely am going to spend a while getting the render to work in the first place."}, {"post_id": 17822, "ts": "2026-06-28T19:12:22Z", "hours": 2.5992, "text": "I’m almost done with the algo that finds the memory offsets to fit colliding data but uh, I just realized I don’t have space anymore :) I think I’m going to revert last update’s progress. fun"}, {"post_id": 17120, "ts": "2026-06-27T20:03:53Z", "hours": 4.5011, "text": "After doodling a bit, I decided that the collision handling should deal with 8 collision pairs at a time. I forgot how to implement kogge stone which we will need and oh boy do I not know where to put the gjk phase. I’m already taking up 0.8 GiB vram at best. Also, here’s a histogram with nit picking bit packing."}, {"post_id": 13503, "ts": "2026-06-22T03:01:42Z", "hours": 1.6019, "text": "Shuffled buffers around and created a cos sin look up table since entities only have 2^13 possible rotations. Although I am using a 13-bit floating point for rotation velocity but it’s fine. That’s future me’s specifications to implement"}, {"post_id": 10483, "ts": "2026-06-17T07:07:50Z", "hours": 5.5903, "text": "So apparently changing the href attribute of a link means that the website has to request for the css file and wait while the component is loaded instantly causing FOUC So I just copy pasted every css file into the header so the stylesheets are always loaded. And to retain the ability to just id an element as “sidebar” without worrying about conflicts I just wrapped every stylesheet with the id of the main element. I was also optimizing bit unpacking and casting position and restructuring layouts. I swear I didn’t spend all 5 hours just writing 20 lines of code."}, {"post_id": 8293, "ts": "2026-06-13T19:45:11Z", "hours": 0.4575, "text": "Simple readjustment of the velocity precision. Previously the smallest value of the 10-bit float, we’re not going to implement subnormal values, accumulates to shift entities when idle."}, {"post_id": 8229, "ts": "2026-06-13T18:03:46Z", "hours": 1.5025, "text": "Wow I spent eternity making 10 boxes. And still tsx doesn’t like that I imported a png file, I should Google that up one day."}, {"post_id": 7617, "ts": "2026-06-12T18:52:34Z", "hours": 1.9397, "text": "Menu expands with little code. I’m going to run out of functional UI to work on and eventually will have to either fix the aesthetics or make the physics engine."}, {"post_id": 6932, "ts": "2026-06-11T16:52:13Z", "hours": 4.7031, "text": "I’ve been avoiding debugging WGSL learning Solid JS. Incredible UI design I know thank you :)"}]...
|
Title: Cornilieus by @Falling10fruit | Stardance
Title: Cornilieus by @Falling10fruit | Stardance
Devlogs:
I’ve been avoiding debugging WGSL learning Solid JS. Incredible UI design I know thank you :)
Menu expands with little code. I’m going to run out of functional UI to work on and eventually will have to either fix the aesthetics or make the physics engine.
Wow I spent eternity making 10 boxes. And still tsx doesn’t like that I imported a png file, I should Google that up one day.
Simple readjustment of the velocity precision. Previously the smallest value of the 10-bit float, we’re not going to implement subnormal values, accumulates to shift entities when idle.
So apparently changing the href attribute of a link means that the website has to request for the css file and wait while the component is loaded instantly causing FOUC So I just copy pasted every css file into the header so the stylesheets are always loaded. And to retain the ability to just id an element as “sidebar” without worrying about conflicts I just wrapped every stylesheet with the id of the main element. I was also optimizing bit unpacking and casting position and restructuring layouts. I swear I didn’t spend all 5 hours just writing 20 lines of code.
Shuffled buffers around and created a cos sin look up table since entities only have 2^13 possible rotations. Although I am using a 13-bit floating point for rotation velocity but it’s fine. That’s future me’s specifications to implement
After doodling a bit, I decided that the collision handling should deal with 8 collision pairs at a time. I forgot how to implement kogge stone which we will need and oh boy do I not know where to put the gjk phase. I’m already taking up 0.8 GiB vram at best. Also, here’s a histogram with nit picking bit packing.
I’m almost done with the algo that finds the memory offsets to fit colliding data but uh, I just realized I don’t have space anymore :) I think I’m going to revert last update’s progress. fun
Yay yesterday’s issue is fixed, in theory. Man, I haven’t actually like tested any of this code. Should I just print the data from the buffer and eye it or actually try to render it… Cause I’m definitely am going to spend a while getting the render to work in the first place.
Man I made a lot of mistakes earlier whoop. Anyways here’s a naive implementation of the support function for the gjk algo. I’m going to move the entity_nodes buffer into shared memory (or at least the collision pair’s colliding mesh nodes into private memory) tomorrow
some stufff so collisions taking their sweet time with gjk are seperated and moved to the entities_buffer_meta so the gpu can focus on resolving those stubborn collisions look, after several parallel friendly paradigms the last step of my code is this sequential and divergent code
So I forgot to add rotations to the collision thing. Also I got my first ever Device Lost error yay. No one told me that not posting for over 10 hours will deduct me of my precious work.
So I was trying to visualize the buffer on a helper static website so I can eyedrop data since reading a 16384 length array isn’t efficient but apparently chromium dropped an update that prevents mouse interactions the moment you use their builtin eyedropper so here’s my replacement (not what all 8 hours was spent on pls believe me)
So the sorting system is taking a bit too long, ah well I’ll figure it out. Google says it’s possible to get it fast enough
So by bitpacking I was able to make the array longer while fitting within the shared memory limit. That means that more threads can work on the kogge stone -> larger workgroup size -> less iterations per thread. school’s back btw
I tried to optimize sorting by reducing the memory footprint of every thread so they could fit more threads. Mid-bitpacking, I decided to test the pipeline and viola. I’ve doubled execution time. Also rerolls only add like 10% or less of what you initially rolled. Absolute scams
I made a pool of unmapped buffers so I can continuously record the time taken so I can clearly see how much worse my changes to the algorithm are.
Hey guys so I reduced the chunk size so that joints don’t have to hope that there’s at most 16 entities within 16 tiles Also I was reading the dev time of my other project and I accrued almost 6 hours over the limit, whoops :P
So I’ve hit a brick wall. gogle told me that to improve my 4 bit radix shader is to do 8 bits at a time to halve the number of passes (and that a byte is industry standard) but I can’t figure out how to like create a private histogram for each of the 256 digits also I got a 72 on math AS levels :P
So remember when last time I thought “oh no how to do private prefix arrays”? Well, an hour later and I discovered “Oh, my 2^24 entities can be divided by 256 and then 256 again so I’ll just have to do 3 prefix sums layered one on top of each other on the thread level” I don’t know what happened but my brand new 8 bit radix pass takes 460+ms. Yay
Ah a bit of work here and there amidst A levels. what a shame for those 17 hours. whoops :) made another vite folder within the repositories so I can test out shaders without the other parts of the project getting in the way....
|
1792684346.9161808
|
1793289146.9161808
|
|
15452
|
VeritasAI by @rianchad | Stardance
|
rianchad
|
0
|
125.09
|
0
|
[]
|
[{"post_id": 12443, "ts": "202 [{"post_id": 12443, "ts": "2026-06-20T09:35:49Z", "hours": 15.3708, "text": "i was on vacaiton so i forgot to write"}, {"post_id": 10921, "ts": "2026-06-17T21:57:35Z", "hours": 7.4081, "text": "wll do later"}, {"post_id": 10169, "ts": "2026-06-16T19:41:43Z", "hours": 7.7919, "text": "Will update later"}, {"post_id": 9834, "ts": "2026-06-16T09:03:20Z", "hours": 13.9131, "text": "long day will update later"}, {"post_id": 9332, "ts": "2026-06-15T17:31:25Z", "hours": 7.2622, "text": "devlog will update later"}, {"post_id": 9127, "ts": "2026-06-15T08:33:38Z", "hours": 4.0861, "text": "devlog will update later"}, {"post_id": 8973, "ts": "2026-06-14T22:45:55Z", "hours": 7.7925, "text": "Devlog will update later"}, {"post_id": 8722, "ts": "2026-06-14T14:19:55Z", "hours": 7.8492, "text": "devpost will update later"}, {"post_id": 7977, "ts": "2026-06-13T09:32:44Z", "hours": 8.2808, "text": "did some work"}, {"post_id": 7770, "ts": "2026-06-12T23:58:26Z", "hours": 6.6164, "text": "refactoring some logic"}, {"post_id": 7482, "ts": "2026-06-12T14:16:38Z", "hours": 1.225, "text": "I did a cleanup session today: moved hardcoded API keys from config.js into .env , added a startup check that exits immediately with a clear message if any required key is missing, and split a 650-line index.js into pipeline.js , cli.js , and utils.js . The tool runs cleanly on my machine and I have been using it on articles I read this past week, but it requires setting up two API keys to run so nobody else can actually use it yet, and figuring out distribution is probably the next real question."}, {"post_id": 7455, "ts": "2026-06-12T12:54:32Z", "hours": 7.1053, "text": "This session was supposed to take two hours and took seven because I assumed fetching and parsing a news article from a URL would be straightforward. It is not: axios plus cheerio works fine for AP and Reuters, NYT and WaPo render their bodies client-side so the raw HTML comes back nearly empty, Puppeteer solved that but added 5 seconds of headless Chrome startup time to every run, and @mozilla/readability worked better across most sites but choked on paywalls. I ended up with a three-layer fallback that tries readability first, then the longest <article> tag, then the largest div by text length, which covers about 70% of sites. The session ended with a clean formatted terminal report using chalk for color-coded confidence labels, which was the first time the tool looked like something a person would actually use."}, {"post_id": 7308, "ts": "2026-06-12T05:30:45Z", "hours": 3.5261, "text": "I rewrote the whole pipeline in Node.js and parallelized all the agents because the Python sequential version was timing a 7-claim article at 68 seconds, which is not usable. The rewrite took about 90 minutes and the rest of the session was debugging differences between the Python and Node versions, mostly around how I had structured the retry logic. Running 14 concurrent API requests at once got me rate-limited immediately, so I added a concurrency queue capped at 4 simultaneous calls, and the same article that took 68 seconds dropped to 14 seconds."}, {"post_id": 7185, "ts": "2026-06-12T00:04:43Z", "hours": 0.9936, "text": "Two things kept crashing longer test runs so I fixed them both today. Claude was returning malformed JSON about one in fifteen runs despite explicit instructions, either wrapping output in backticks or adding a trailing comma, so I added a cleanup step before JSON.parse and a retry that sends the raw response back with “this was not valid JSON, return only the array with no other text.” The second issue was unverifiable claims burning three full search iterations and returning nothing, so I added a classification step upfront where subjective claims skip the loop entirely and return a subjective_claim flag instead."}, {"post_id": 7012, "ts": "2026-06-11T19:22:43Z", "hours": 3.5992, "text": "I added the divergence layer today, which surfaces how outlets with different political leans frame the same underlying fact rather than just whether the fact is accurate. I first tried scraping lean ratings from AllSides at runtime but scrapped it after 45 minutes because it was fragile, probably against their ToS, and too slow for a per-request lookup. I replaced it with a hardcoded lookup table sourced from Ad Fontes Media data covering about 40 major outlets, where anything not in the table returns “Unknown” rather than a guess. Testing it on a border crossings story came back with CNN describing the encounter numbers as a humanitarian crisis, Fox describing the same numbers as a Biden policy failure, and the DHS primary source showing the raw figure all three were citing."}, {"post_id": 6863, "ts": "2026-06-11T14:49:32Z", "hours": 15.2831, "text": "I started with SerpAPI for web search and spent the first two hours realizing every result it returned was months old because of aggressive free-tier caching, then switched to Brave Search API and got current results immediately. My first verification approach was a single prompt passing the claim and search results to Claude at once, but the outputs were shallow and the first search query was usually wrong anyway, so I built an iterative loop where Claude picks a query, I run the search, and Claude decides whether to go deeper or return a result. The loop ran forever in early testing until I added a hard stopping rule to the prompt: “If you have at least 2 independent sources that confirm or deny the claim, stop searching and return your assessment now.” By the end of the day, the pipeline surfaced CNN and Fox both citing the same BLS statistic with completely different framings alongside the actual BLS.gov primary source, which was exactly the output I had been trying to build toward."}, {"post_id": 6434, "ts": "2026-06-10T20:24:08Z", "hours": 1.1289, "text": "I caught a bad bug where the extractor was hallucinating numbers: I ran the same AP unemployment article three times and the reported rate came out as 4.2%, 4.1%, and 3.9% across the three runs when the article clearly says 4.2%. The model was filling in from training data instead of reading the text in front of it, which is a subtle failure mode because the numbers look plausible enough that you would never notice without explicitly checking. The fix was adding a verbatim extraction instruction to the system prompt and setting temperature to 0."}, {"post_id": 6305, "ts": "2026-06-10T16:37:57Z", "hours": 5.8567, "text": "I started this after my dad and I spent 45 minutes arguing over an immigration article where we were both citing different sources reporting the same statistic at different numbers, and neither of us could figure out who was right because we couldn’t agree on which source to trust. My first instinct was a binary fact-checker that returns TRUE or FALSE, but the first time I prompted Claude that way I got confident verdicts with no sources and realized immediately that a confidently wrong answer with no citations is worse than no answer at all. I tried GPT-4 for claim extraction and kept getting paragraph-length analysis instead of a JSON array, then switched to Claude and got clean structured output on the first attempt once I tightened the prompt. Extract factual claims from the article below. Return ONLY a JSON array of strings. No explanation before the array. No explanation after. No markdown fences. I finished the session with a Python script that takes pasted article text and returns a JSON array of 5-8 discrete factual claims, all traceable to specific sentences in the article."}]...
|
Title: VeritasAI by @rianchad | Stardance
Devlogs Title: VeritasAI by @rianchad | Stardance
Devlogs:
I started this after my dad and I spent 45 minutes arguing over an immigration article where we were both citing different sources reporting the same statistic at different numbers, and neither of us could figure out who was right because we couldn’t agree on which source to trust. My first instinct was a binary fact-checker that returns TRUE or FALSE, but the first time I prompted Claude that way I got confident verdicts with no sources and realized immediately that a confidently wrong answer with no citations is worse than no answer at all. I tried GPT-4 for claim extraction and kept getting paragraph-length analysis instead of a JSON array, then switched to Claude and got clean structured output on the first attempt once I tightened the prompt. Extract factual claims from the article below. Return ONLY a JSON array of strings. No explanation before the array. No explanation after. No markdown fences. I finished the session with a Python script that takes pasted article text and returns a JSON array of 5-8 discrete factual claims, all traceable to specific sentences in the article.
I caught a bad bug where the extractor was hallucinating numbers: I ran the same AP unemployment article three times and the reported rate came out as 4.2%, 4.1%, and 3.9% across the three runs when the article clearly says 4.2%. The model was filling in from training data instead of reading the text in front of it, which is a subtle failure mode because the numbers look plausible enough that you would never notice without explicitly checking. The fix was adding a verbatim extraction instruction to the system prompt and setting temperature to 0.
I started with SerpAPI for web search and spent the first two hours realizing every result it returned was months old because of aggressive free-tier caching, then switched to Brave Search API and got current results immediately. My first verification approach was a single prompt passing the claim and search results to Claude at once, but the outputs were shallow and the first search query was usually wrong anyway, so I built an iterative loop where Claude picks a query, I run the search, and Claude decides whether to go deeper or return a result. The loop ran forever in early testing until I added a hard stopping rule to the prompt: “If you have at least 2 independent sources that confirm or deny the claim, stop searching and return your assessment now.” By the end of the day, the pipeline surfaced CNN and Fox both citing the same BLS statistic with completely different framings alongside the actual BLS.gov primary source, which was exactly the output I had been trying to build toward.
I added the divergence layer today, which surfaces how outlets with different political leans frame the same underlying fact rather than just whether the fact is accurate. I first tried scraping lean ratings from AllSides at runtime but scrapped it after 45 minutes because it was fragile, probably against their ToS, and too slow for a per-request lookup. I replaced it with a hardcoded lookup table sourced from Ad Fontes Media data covering about 40 major outlets, where anything not in the table returns “Unknown” rather than a guess. Testing it on a border crossings story came back with CNN describing the encounter numbers as a humanitarian crisis, Fox describing the same numbers as a Biden policy failure, and the DHS primary source showing the raw figure all three were citing.
Two things kept crashing longer test runs so I fixed them both today. Claude was returning malformed JSON about one in fifteen runs despite explicit instructions, either wrapping output in backticks or adding a trailing comma, so I added a cleanup step before JSON.parse and a retry that sends the raw response back with “this was not valid JSON, return only the array with no other text.” The second issue was unverifiable claims burning three full search iterations and returning nothing, so I added a classification step upfront where subjective claims skip the loop entirely and return a subjective_claim flag instead.
I rewrote the whole pipeline in Node.js and parallelized all the agents because the Python sequential version was timing a 7-claim article at 68 seconds, which is not usable. The rewrite took about 90 minutes and the rest of the session was debugging differences between the Python and Node versions, mostly around how I had structured the retry logic. Running 14 concurrent API requests at once got me rate-limited immediately, so I added a concurrency queue capped at 4 simultaneous calls, and the same article that took 68 seconds dropped to 14 seconds.
This session was supposed to take two hours and took seven because I assumed fetching and parsing a news article from a URL would be straightforward. It is not: axios plus cheerio works fine for AP and Reuters, NYT and WaPo render their bodies client-side so the raw HTML comes back nearly empty, Puppeteer solved that but added 5 seconds of headless Chrome startup time to every run, and @mozilla/readability worked better across most sites but choked on paywalls. I ended up with a three-layer fallback that tries readability first, then the longest <article> tag, then the largest div by text length, which covers about 70% of sites. The session ended with a clean formatted terminal report using chalk for color-coded confidence labels, which was the first time the tool looked like something a person would actually use.
I did a cleanup session today: moved hardcoded API keys from config.js into .env , added a startup check that exits immediately with a clear message if any required key is missing, and split a 650-line index.js into pipeline.js , cli.js , and utils.js . The tool runs cleanly on my machine and I have been using it on articles I read this past week, but it requires setting up two API keys to run so nobody else can actually use it yet, and figuring out distribution is probably the next real question.
refactoring some logic
did some work
devpost will update later
Devlog will update later
devlog will update later
devlog will update later
long day will update later
Will update later
wll do later
i was on vacaiton so i forgot to write...
|
1792634109.5329611
|
1793238909.5329611
|
|
43023
|
Worlds Unbound - Terrain Engine by @alpeka | Stard Worlds Unbound - Terrain Engine by @alpeka | Stardance...
|
alpeka
|
1
|
125.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-25T01:05:30Z", "hours": 125.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "— SHIP No.1 — I spent the last couple of months making a model terrain, which I will use for my game that I will continue to build after this competition. My game idea is quite ambitious, and given how long it took for me to get this basic terrain to work properly and well, that won’t even be coming with the extra month added one. I lot of you may be thinking though, what on earth were you doing for 125 hours, when all you came up with is a glorified green and grey piece of paper you could walk on. Well, not only was I learning and using Godot for the first time, it was the first time I learnt anything as complicated as this. I had to wrap my head around complex (at least for me) maths and computer science topics, like vectors and cross product, noise and FBM, TBN model, and UVs, not to mention just the sheer amount of logic I had to get through. It was so tiring to keep getting bugs for the chunking system I had, or the collisions. But thankfully, all that is behind me 😼. I’ll give you a more indepth look into what I’ve done over the past couple months. Devlogs 1-12: This period was the general beginning of my project. Not only was I learning Godot, and watching tutorials on it, I was also spending time on the player character, the camera system, and the world environment. Devlogs 13-15: I tried to implement LODs into my chunks, since the performance was simply too bad. Somehow this made it worse, possibly because of more chunks (the ones at the broder of LOD borders) being forced to be unloaded and loaded back in. Devlogs 16-21: I used my current technique, heavily based from devmars video on youtube about procedural terrain during this period. School had also started, so I spent less and less time on it, being significantly burnt out and tired. So I basically went through 3 iterations of terrain for my game, so that is why it took so long to get to this point.", "repo": "https://github.com/jona-mtw/Celestial", "demo": "https://alpeka.itch.io/worlds-unbound-terrain-engine"}]...
|
[{"post_id": 73370, "ts": "202 [{"post_id": 73370, "ts": "2026-09-25T00:42:51Z", "hours": 2.2056, "text": "Devlog 21 - Ship Prep!!! Colours I added colours to the terrain depending on how high the vertex is. This does create a very harsh border between the two colours, but I didn’t want to learn lerping, ik how to larp enough. Cleaned up my commits My commits were, and probably are still messy, and when I went ahead to revert some changes it said there were errors, but now thankfully that’s all fixed. :) I also updated quite small normals and some technical stuff."}, {"post_id": 72564, "ts": "2026-09-23T07:21:06Z", "hours": 3.9622, "text": "Devlog 20: GPU noise I found a way to make noise using a Godot addon called FastNoiseLite Runtime Shader . It was apparently identical to the FastNoiseLite in GDScript. So I gave it a try. I knew it was a gamble, given how much time I got left to ship an decent project, but I gave it a try since it seemed interesting. It wasn’t that hard to get the noise working, but to get it to sync with the collisions was a nightmare. In the end, I decided that even though the README stated it was 99.9% the same, the output seed by seed was different. So I decided to scrap it and now I’m going back to the old version with heightmaps. Why did I really want to switch? Because of the limited colour depth in images (has to be 8-bit for GDShader to read), theres not enough heights for each vertex to be at, so every so often, there’s this massive wall. It looks fine from afar, but thats probably because my terrain is 20km x 20km, so of course an 8m tall wall would look fine. (the image is from the addon readme)"}, {"post_id": 70779, "ts": "2026-09-19T19:04:39Z", "hours": 6.5594, "text": "Devlog 19 - Main Menu Added (and other things)! I spent quite a lot of time making the background for the main menu in Blender. After just copy and pasting the player model used in the game, I went ahead and made the main attraction: ✨ the planet in the background ✨ . My knowledge of noise that I gained from my previous attempts at the terrain generation helped me create the stars in the background, and the texture for the actual planet in the shader editor. I also added a slight atmosphere, which is (somewhat?) noticeable. I also went ahead and updated the shader code. Before, I used to use the visual shaders, since it was quite similar to the shader editor in Blender, which I was familiar with. But then I realised there’s just more flexibility with using GLSL . I can group uniforms in the inspector, making it clearer and less cluttered if I want to add textures in the future, including different images for the same texture (like Ambient Occlusion, Normals, Colours, and Roughness). Thus being able to group those different types images for the same texture was very important for future usability. Thankfully, Godot allows you to see the shader code that is generated from the visual shaders. Unfortunately, it was not readable at all. The generated code used a random(ish) collection of numbers and letters, and it was too long. Look below for the comparision for just the vertex shader, but it was something like 84 lines that was shruken down to 10 for the vertex shader. Even if you account for spaces in the generated code (which then it might be like 50-60 lines) thats a huge difference. So it took quite some time to get it to a readable state. edit: idk why the actual background looks so bumcheeks compared to the banner, hopefully itll be fixed by then 🤞"}, {"post_id": 67802, "ts": "2026-09-14T01:51:22Z", "hours": 4.0497, "text": "Devlog 18 - I am happy once again!! I FINALLY got the collisions to work!! Basically, it looks at the terrain model that is imported into Godot, and aligns the vertices of the CollisionShape3D with it. It also updates its position every time the player moves 1 unit (whatever the size of a quad of the mesh is). Then it looks at the heightmap, looks up the height of its coresponding pixel, multiplies that by the height shader param (2000, like in the vertex shaders), and thats the collision shape done. I noticed while walking around the world, that there were these massive ridges on the terrain. This is due to the lack of precision in the heightmap. The heightmap only has 256 shades of grey, and I need 2000 values. It is quite impossible to make a image file with that much precision, so instead, I’ll make it so that the CPU will just send an array to the vertex shader. Also, I’ve rebranded my project to Worlds Unbound, and this specific Stardance project will just be handling the terrain stuff for the game. p.s, it never goes above 16ms, i think thats probably because i was recording"}, {"post_id": 65723, "ts": "2026-09-11T02:05:18Z", "hours": 6.0086, "text": "Devlog 17 - I am incredibly frustrated. No matter what I do it feels like I just can’t get the collisions to work. Basically, I’m trying to fetch the heights from the height map to input into the CollisionShape3D, but the coordinates are always offset in some way or the other. I even used AI my friend to basically rewrite the entire script over and over again, but that didn’t work either. Maybe it’s cos school has started now, and I haven’t been able to spend that much time on this project than I would like to As you can see in the photo, the collision mesh (in blue) is offset from the normal terrain (in white)"}, {"post_id": 63142, "ts": "2026-09-06T19:41:46Z", "hours": 7.2203, "text": "Devlog 16 - AMAZING PROGRESS!! I’ve managed to get a massive 20km render distance with huge mountains and ridges using FastNoiseLite and vertex shaders. I used devmar ’s terrain technique, which he named the “Wandering Clipmap Terrain Technique”. The reason why the technique is called the “ Wandering Clipmap Terrain Technique” is because a flat plane that is subdivided a bunch (to make varrying levels of detail (LODs)) that follows the player. The vertex shaders then offset the heightmap so it gives off the illusions that your moving about in a massive world. All the displacement is done by the vertex shaders, which looks at a heightmap. In the future, I might make this heightmap be generated in gdscript instead of in the inspector, to deal with texture resolutions. Currently, from afar, the terrain looks amazing (except from the fact its not textured) but upclose, you can see rings in the terrain, which is caused by the heightmap’s resolution being too low. In fact each ring is about 8m tall so I really need to fix that 😭 The normals are calculated by just copying the heightmap and setting it ‘as normals’ in the inspector. They also are multiplied by a normal basis matrix, which allows me to configure the specific normal settings. I’ll need to calculate the normals in the fragment shader as well in the future for more convincing shadows, but for the mean time, the vertex shaders should do just fine. I’m planning on adding collisions, then maybe textures, biomes and vegetation soon!!"}, {"post_id": 61230, "ts": "2026-09-04T01:57:24Z", "hours": 4.8533, "text": "Devlog 15 - I’m an Idiot For the past 95ish hours, I’ve been working on a way to make procedural terrain for my game. I tried 2 main methods, one centred round the CPU, and one I was building centred around the GPU. The endless chunk seam bugs caused me to burnout/get tired of the entire project, and there was so many stuff (that I won’t really be explaining for the sake of my poor reader’s sanity) leading to me ✨ youtube ✨ I saw this AMAZINGLY smart video by devmar, showing an alternate way of generating terrain. I urge you to watch the video as well, the whole technique is very very clever, and he even goes on to make further videos on making collisions, recalculating normals and adding vegetation, especially if your interested in procedural generation. After watching this video however, I became incredibly frustrated. I spent nearly 100hrs of my summer making this procedural terrain which I know hadn’t gotten anywhere and theres this incredibly smart video from 4yrs ago that pops up on my feed. Welp, now ig i gotta try out this way, and quick cos my parents are on my tail talking about me finishing this project before school starts 🙏 (its my gcse year so ig its valid but still ) Now what I actually did that counted to my time Experimented with vertex shaders, and sending heightmaps to vertex shaders to displace. This however caused immense lag and caused VERY ANNOYING chunk seams. #epicfails"}, {"post_id": 59673, "ts": "2026-09-01T16:27:07Z", "hours": 9.5572, "text": "Devlog 14 - LOD chunks ——— OPTIMISATION IS SOO HARDD 10hrs to do practically do something I’ve already done? (i had already made a chunk system in previous devlogs) Well, whilst some of that time was transferring code from my old commits to the current one and making sure it works, most of the time I spent on this devlog was spent on ✨ “optimisation” ✨ Optimisation First of all, I added LODs into the chunk mesh. What this means is that since further away chunks take up less of your screen, the level of detail (LOD) is reduced the further away it is. I had already made the script that handled the creation of those different meshes with different LODs, so in this devlog, I added it to the main terrain generation script, and assigned each LOD to a certain distance, so that any chunk with a certain distance has a certain LOD. In my last version of the terrain generation, I relied on the name of the MeshInstance3d nodes created to identify what chunk they were. I realised when making this updated version that it was prone to failure, since if the node did not exist or a node with the same name were some how added to the scene tree, errors would be raised or at the very least, a logic error would occur. To recetify this, I switched to using dictionaries to house all the information of all the chunks: chunks : Dictionary [ Vector2i , int ] = { Vector2i ( 0 , 0 ): 0 , Vector2i ( 0 , 1 ): 0 , #etc } The key is chunk coordinate, and the value is the LOD (0 being the highest, 4 being the lowest) Every time I wanted to update the terrain, I would search the scene tree if a particular node was unwanted (again, by looking at the name) and then generating the rest of the ones wanted. This way would not work with LODs, since some chunks may still exist, but may have to change LOD depending on where the player is. So I made use of the dictionary and also created a new one that would store the chunks that I want created. It would loop through the dictionarys, checking certain conditions, and the terrain would be updated. All this looping is somewhat inefficient, and did cause some lag spikes, so I will try to fix that next devlog by only checking the chunks that would be affected based on which way the player moved. To help with the looping, I created chunk and lod lookup tables, that can be offset based on the players_position. These lookup tables are only changed when the render distance is changed, so the same calculation doesn’t have to run hundreds of times in 16ms (60 fps)."}, {"post_id": 57389, "ts": "2026-08-29T15:03:50Z", "hours": 3.8103, "text": "Devlog 13 - LOD template I basically deleted all the old code, and started over, by making a function where the noise will be given to the vertex shader, and one that will generate the actual flat mesh for it (which is going to be changed by the vertex shader). I made the template for making flat planes with different levels of detail (LOD), which will be changed by the vertex shaders, applying the noise to the mesh. I created a new script called lod.gd and gave it a class name, so that I can call multiple instances of it in the main terrain generation program. Every time the program wants to make another chunk, I have to pass the arguements: resolution - what ive defined as a synoymn of LOD chunk_pos - where the chunk is The function then loads an ArrayMesh from a pre-generated list of possible meshes and creates a new MeshInstance3D node to display it. Extra stuff I also added player coords and chunk position in the debug_screen :)"}, {"post_id": 56938, "ts": "2026-08-28T23:24:46Z", "hours": 4.2589, "text": "Devlog 12 - General updates 3.0 I PROMISE THIS IS THE LAST ONE GUYS 🙏 Performance Stats I added a little HUD showing the FPS, the time it takes to make one frame (has to be below 16.67ms (60fps) or there will be noticeable lag), and the memory usage. Lighting, Shadows, and World Environment I slightly changed the shadow bias and normal bias so that shadow artifacts are to a minimum. On top of that, I set it so that shadows aren’t cast for the terrain, which unintentionally handles with some of the artifacts, whilst keeping the “shadows” by illuminating the terrain depending on where the DirectionalLight3d is, making the “shadows” reponsive to a future day-night cycle. Also the volumetric fog and lighting looks better Camera Issues 2.0 So previously I had the player hide() when you go into first person, but that also effects the shadows. So instead I made the visor disappear when you go into first person. But then there was another problem. The head would move during the idle and walking animations, which is quite distracting and could be problematic for some players. So I stopped the animtions whilst in first person. It is a very rudimentary fix, since players can look at their shadows and see the lack of animation. Furthermore if I want to add multiplayer in the future, it’ll look very weird. Performance checks In preparation of the biome generation, I wanted to make sure the performance is fine. It takes a bit for the terrain to generate at the start, but thats common across nearly every game. And this will be lightened a bit when I implement LODs. Once the game is running, it runs relatively fine, except with (very quick) lag spikes when the chunks update. To address this, I’m planning of offloading some of the terrain generation to the GPU, which can calculate normals a LOT more effeciently and quicker than the CPU. Current, the CPU calculates all the vertices, indices, normals, and then compiles it into an ArrayMesh , which is given to the GPU for rendering. This can put a lot of strain on the CPU, especially later down the line, so it’s better and more effiecient if the GPU does the very repetetive calculations, by making it do all the normal calculations, including other stuff."}, {"post_id": 56302, "ts": "2026-08-28T01:02:37Z", "hours": 5.1292, "text": "Devlog 11 - General updates 2.0 Editor Tools!! - (to see the terrain in the editor) So in a previous devlog, I think I talked about how I added @tool in my terrain generation program to be able to see it in the editor. Once I made it dependent on the player position, it didn’t generate in the editor because the player wasn’t loaded in. So now I made it so that if the script was running while the editor (not the game) is open, the terrain would generate around (0, 0) based on how ever big the render distance is. Also I made it so that if you tweak the value of any of the primary noise settings in the editor, it updates in the editor. On top of that, I set the viewport to display wireframe so that I can see the triangles at different resolutions, which is where I came across:…. FLOATING POINT ERRORS!!! (yay ) I noticed that if I set the resolution to a decimal value that was not a power of 2, the triangles would be off by some amount, causing neighbouring triangles to overlap each other, causing normal and collision problems. The resolution variable is going to be eventually used for LODs, so since I’ll be the only setting it, I’ll just make sure to use a value thats a power of 2 The reason why this happens is because 16 (my chunk size) can be multplied and divided by 0.125 (2^-3) evenly to create an integer, compared to 0.1 which results in 1.6. Any smaller power of two is rounded it to the nearest 3dp, so 0.0625 (2^-4) doesn’t work. Camera Issues So I made functionality with the camera where you can scroll to zoom the camera in and out, and if you scroll far enough in, you’ll be in first person, much like how it works in Roblox. There was one problem though. Since the material for the visor on the player model was somewhat transluscent, your view would get darker. Also, you could free look inside the helmet, looking at the areas I wasn’t bothered to model and texture hadn’t modelled. So I disabled that in first person. The biggest timewaste of my life In an attempt to offload some of the generation to the GPU for more effecient parallel processing, I tried to figure out which parts of the algorthim were going to be handled by the CPU and GPU. There were some that had to be handled by the CPU, and there was no choice about those, and they were: collisions and figuring out what chunks should be rendered. At first I thought, how about I offload nearly everything to the GPU, including the noise function. Then I learnt that FastNoiseLite didn’t exist in .gdshader . So I did what any normal person would do, and CODE PERLIN NOISE BY HAND. I spent HOURS learning everything my dumbass could about it: vectors, normals, gradients, deviation, erosional generation, and finite difference approximation. At least I probably learnt something useful for FSMQ 🤷 (a British maths exam most students do in yr11 along with their other GCSEs)."}, {"post_id": 55266, "ts": "2026-08-26T23:25:21Z", "hours": 4.5936, "text": "Devlog 10 - General updates Alright, so ik I said I would work on the procedural terrain, but instead I worked on:… Debugging Tools!! (yayy! ) When tab is pressed, it toggles on debug mode, where all meshes turn into wireframes (to check LOD) and chunk boudaries are shown. There are problems with chunk boundaries not despawning when the terrain its on is gone, but that’s fixed when you toggle debug mode again :). I could fix it but icba I have other stuff that needs to be prioritsed. Resizabile UI So before, if you resized the window, the pause menu and settings menu would be offset from the centre and wouldn’t scale with the window. Now when you scale it, the pause and settings menu stay in the centre and scale accordingly. (the flickering in the video is just an artifact created by the godot editor, and will apparently be fixed once exported)"}, {"post_id": 55025, "ts": "2026-08-26T13:34:07Z", "hours": 7.725, "text": "Devlog 9 - Player Animation!! Walking and Idle Animations I finished a basic walking and idle animation for the player. The walking animation is also somewhat inspired from the kerbals from KSP. Both the animations are kinda choppy, especially when the animation loops round, but frankly icba I didn’t have enough time to fix them rn (mbmb 😭 ). Thankfully the walking animation is timed properly so that the player doesn’t look like its sliding around. Camera updates I added functionality to the camera where you can freelook around the player when holding the right mouse button. Once released, it goes back to the normal position (motion is lerped). Prepartions for next steps For the next steps, I want to go back to the terrain_generation program and start to add variation across the world (like biomes, mountains, etc.). I’m also looking to optimise it, making it generate terrain and collisions faster in prepartion for any future implementation of faster travel. So I added functionality that can allow me to make LODs, which will likely be implemented next devlog."}, {"post_id": 53506, "ts": "2026-08-24T02:34:01Z", "hours": 9.7758, "text": "Devlog 8 - Player Model and other assets! Player Model I finished with texturing, rigging and weight painting. Next Step is to make the walking and jumping animations. Worked on the settings menu I updated the setting menu layout to account for different settings I’ll add in the future Stupid Bugs So when trying to break the terrain generation, I set the speed of the player to like 300 (which it will never be in the game except when in a space ship) but when I tried to do that, the game kept crashing, spitting out an error saying that something didn’t exist. It was coming from my unload_terrain() function. Basically how it works is it checks for all the instances of the MeshInstance3D node, and checks the name of it. For every chunk that is created, I assigned a unique name to it on creation based on the x and y coordinates of it. The function would checking all the nodes, and seeing which ones were out of the “ collision_chunk_size ” radius, and then would delete them. But when going super fast, the processing of things got all weird, meaning that when it tried to delete a chunk, and if it didn’t exist, it would crash. So I added a simple if statement if len(child_name_array) > 2: (basically it would check if the length of the name was long enough to see if there was the coord data). Stupidly I wrote the greater than sign the wrong way round, which led to me being stumped for SO long on why the terrain was just not unloading. tldr: > was the wrong way round and cost me hours."}, {"post_id": 48656, "ts": "2026-08-17T04:20:08Z", "hours": 6.7203, "text": "Devlog 7 - Chunks # 2: PROCEDURAL GENERATION DONE (mostly) Bugs Managed to fix all the bugs related to this part of terrain generation. Weird chunk errors There was an if statement (I changed it out for something else that’s more efficient) that was like: if abs(player_position.x - chunk_pos.x) > collision_chunk_size or abs(player_position.y - chunk_pos.y) > collision_chunk_size This logic error create weird stuttering issues and lag. The fix was to switch or with and . Normals DEFINITELY the bane of my existence. I know roughly what normals are due to me doing 3D modelling/rendering, but I have no clue how it actually works. And plus, I’ve barely covered the maths I need for this in school, so I spent sooo much time (much of which wasn’t recorded) just researching about normals and how they work. I think that definitely helped me find a solution to the annoying chunk borders and random artifacts found inside each chunk. Chunk Sizing I stupidly and randomly changed the chunk size from 16 to 10, which worked completely fine, except for the fact that the player script was still using the 16x16 chunk system, causing the generation to lag behind, eventually leading to the player falling off the map. New Features There were also some ✨ features ✨ that I added. Colour I added colour to the world, and if I match it to the fog and sky, I think it would look AMAZING I will make it so that the colour does vary across the planet. Player I added the rig and refined the topology for animation."}, {"post_id": 47230, "ts": "2026-08-15T00:41:31Z", "hours": 7.1208, "text": "Devlog 6 - Chunks # 1 Previously, I had it so that the entire world was one big mesh, that could not be expanded without unloading and reloading the whole thing and more. This is obviously very inefficient, especially if I want the terrain to load in and out based on where the player is. Chunks is the answer to that. Split the world into chunks of your choice (I chose 16x16), and load/unload just the chunks you need to, not the whole thing. It seemed easy for me at first, clearly it wasn’t (the #1 for the header, ik this isnt gonna be the only devlog on this 😭 ). Bug 1 - The Normals aren’t normal Last devlog, I talked about calculating the normals, which went smoothly… For the old mesh… You see, to calculate normals, you need the vertices surrounding the vertex your trying to find out, and with chunks, that meant every 16 vertices, the normals were being calculated incorrectly, causing seams to be found in the terrain. However, since we did calculate the normals (for the most part) some pretty nice shadows have been cast on our terrain. Despite it being a bug, it is useful to find out where the chunk boundaries are, which is EXTREMELY useful for debugging, so I haven’t tried fixing it just yet. Bug 2 - Not so Good Performance After dividing the terrain into chunks, and making new chunks generate when the player moved into a new chunk, I tested it out. And every time I tried to cross a chunk border, there would be a huge lag spike. This would be caused by the fact the game prioritised the generation of chunks instead of the game. Thankfully I was able to make it so that the chunks would load whenever the processor was ready, to make sure not to overload it too much. Bug 3 - (Lack of) Collisions Another reason why chunks are useful is for limiting the area with active collisions. When the terrain was one big mesh, the entire mesh had active collisions, which would all be checking if something hit it, which is very resource intensive. Which is why I limited the area with collisions to a small radius around the player. While coding it, many logic erros came up, such as one that caused the collisions to just not work."}, {"post_id": 46583, "ts": "2026-08-13T22:19:41Z", "hours": 8.0178, "text": "Devlog 5 - Procedural Terrain (FINALLY!!) I made a start at making the procedural terrain, made some progress with the player model, and with configuring the basic shaders of the game. Elephant in the Room - Procedural Terrain Technically calling it procedural terrain is cheating a bit, cos really all it is right now is perlin noise applied to each vertex’s height. And with that, you can change the shape of the terrain by changing the values of some variables, like the seed, frequency, and octaves. I exported these variables so I could change them in the editor, and added @tool at the start so I can see it in the editor. I’m starting to work on a chunk system at the moment, which will load and unload chunks of the world as the player moves about. Player Model I finished modelling the player (added this version to the game) and added the bones for rigging, except when I move the arm bone, the helmet deforms, so next time I will be doing some weight painting Thankfully UV unwrapping is done as well so I should be able to texture everything before the next devlog. Also, addressing my last devlog, I said Lapse wasn’t syncing with hackatime. Turns out, if I just told it to create a new project called Celestial (which is what my project is called on hackatime), it’ll just add the time to it, so thats amazing!!! The WorldEnvironment Node I accidentally deleted my old configuration of this node while experimenting with stuff, and so I made some changes to the shading of the world. Next up is to recalculate all the normals of each triangle so shadows can be cast properly. I tried using SSAO, but every time I used that to make some sort of shadow, it changed depending on where the camera was and it made the terrain very pixelated. As you can see in the video, you can see the outlines of the terrain. That is because of the volumetric fog added. It sounds resource intensive, so if it starts to lag out my game I might remove it, which is a shame cos it looks really nice."}, {"post_id": 45513, "ts": "2026-08-12T01:47:27Z", "hours": 6.4792, "text": "Devlog 4 - A little bit of a few things I mostly did a combination of small bits, which is probably bad in terms of github commits and actual progress, but at least it’s not burning me out because I’m doing whatever part of the project I fancy at the time. UI I spent most of the time making a (hopefully) futuristic(?) looking pause menu that can also redirect you to a settings page, where I’m planning to hold the settings for terrain generation for the player to manipulate. Much of this time was spent experimenting with different Control nodes, finding out what they do and what they’re helpful for and manipulating the styles of them. I ended up with a style shown below 👇👇👇 Player Model I think I’ve finalised on a particular style, now I basically just have to make it and then texture it. The sad thing is that for some reason lapse doesn’t recognise my hackclub project anymore (already logged 5+ hrs on lapse), so all the time I spent on Blender wasn’t actually logged. If someone could please tell me how to fix this or if theres an extension for blender that would be SO helpful 🙏. Extras I also added the devlogs to my repository, it should appear there when I next commit, which should be soon!! I realise that the popular devlogs have assets from the get-go, so I probably might focus more on that, despite lapse not working if I wanna record time on Blender or Affinity. Again, if someone could please tell me if something is up with lapse or if there’s an extension that I can download for Blender or Affinity, that would be SOO helpful!! 🙏"}, {"post_id": 44908, "ts": "2026-08-10T23:37:53Z", "hours": 2.1228, "text": "Devlog 3 - Flat Plane I know this sounds INCREDIBLY trivial, but I finally figured out how to make a flat plane in Godot, that can be used to make an actual terrain. There were 2 main ways that I could have used to make this: Method 1: I can use a PlaneMesh and then subdivide it down into triangles. Then use vertex shaders or custom scripts to displace the plane as a whole based on noise. It is faster to make the flat plane using this method since you give Godot most of the control over the tessellation, and the individual vertex placement. This means however that it is a lot harder to load and unload certain parts of the terrain, and it is generally harder to add noise to the terrain since you do not have control over each vertex. Method 2: I can use an ArrayMesh , where I create the grid from scratch, telling Godot how to connect every single vertex to create triangles. The downside to this is how long this took. I know it seems short compared to my first devlog (I think the main reason I took so long in that one was not only because I was learning Godot, but it was also because I was experimenting with player models on Blender but hopefully now I’ll be more time efficient) but it is still more time consuming to tell Godot how to connect each and every vertex. I was in fact so stumped on how to go about doing this that it suddenly came to me when I was playing with my little cousin. I even noted down how to do it on my phones notes app (excuse my bad handwriting I was in the car writing with my finger) :/ Despite it being longer to setup, it is overall better for the needs of my game, since I’ll not only need to be able to change the height of each vertex based on a heightmap, but it can also aid with making biomes, by adding custom values to each vertex, which is simply not possible with PlaneMesh . It is also easier to load and unload certain parts of the mesh, and it is better for larger maps, since your CPU isnt doing all the hard work of choosing all the vertices and indexing them. In order to make the actually interesting part of the terrain (which btw I haven’t done in this devlog, I guess this is just like a future plans part) I can use either vertex shaders or custom scripts to make noise in the terrain. Both of these have their respective use cases, and I wouldn’t be able to say one is better than the other for my case. Vertex Shaders: GPU based no collisions (purely visual) written in Godot Shader Language (which is written in C, which is terrifying for me who practically only knows Python ( GDScript and Python are similar enough for me)) Custom Scripts: CPU based can create collisions (actually changes the vertex’s height) written in GDScript (happy days (ik I can write it in C# , but I’m staying far away from that)) Despite my fear of anything not similar to Python , I will still need to use vertex shaders. And I will explain that in my next devlog because this is getting too long. Now onto my struggles incredible skill when making a.. flat plane in Godot. I chose to do Method 2, because of it’s functionality later down the line. But that means I have to tell Godot what vertices to make, and how to connect them up. Obviously that was as simple as could be.. (you can see my failures in the screen recordings below)"}, {"post_id": 44630, "ts": "2026-08-10T15:03:15Z", "hours": 1.7508, "text": "Devlog 2 - One Lone Triangle I spent 2ish hours trying to make a triangle. In GDScript.. Absoutely terrible progress. I see people on Stardance making whole ass projects in 2 hours, and I’m spending those 2 hours making a simple triangle. I have no idea why decided to do a game with procedural terrain generation as my FIRST Godot project. I somewhat understand the theory behind procedural generation, mainly from watching a video on the breakdown of Minecraft’s code when I was like 10, but yeah 🤷 Unfortunately, I have no clue how to do it in practise.. so I guess hours of looking through the Godot docs awaits me yay -_-. (jk the docs are extremely helpful tysm godot 🙏)"}, {"post_id": 43355, "ts": "2026-08-08T15:43:46Z", "hours": 12.8333, "text": "Devlog 1 - Player Movement Okay I know what your thinking. 12 hours for just player movement. Surely you must be wasting time just to get as much stardust as possible. The thing is.. I’ve never used Godot before. Everything from the node tree, to project settings was all pretty much new to me. I should have honestly done the WarioWave Godot mission thingy, so that I would have at least been fimilarised with how Godot worked in 3D. And here I am thinking about making a game where you explore a procedurally generated world. Never before have I touched Godot, and I’m dreaming of making a game with procedural terrain, like in Minecraft or No Mans Sky. Time Waste No. 1 - Learning Godot I had to look through the docs just to figure out how to assign a key to going forwards, mind you all the code needed is given to you when you use the PlayerCharacter3D class. This is on of the many things I struggled with in Godot. 😭 Time Waste No. 2 - Experimenting with player models in blender I experiemented with different styles of player models to use in the game, and I landed on one inspired from the infamous space game Kerbal Space Program. Time Waste No. 3 - Being petty about a camera system 📷 I think this is what took up most of my time. As soon as I made a moveable player that doesn’t fall through the ground (a very quickly made glorified cube in blender), I thought about adding a third person camera. I initially thought of making it toggleable, like in Minecraft, where you press F5, it toggles between first, second(?) and third person. But you can’t change the distance away the camera is from the player in third person. Besides, my stupid ass made it so that each time you pressed F, the camera would keep zooming out endlessly instead of toggling between first and third person. So instead I made it zoomable, like in Roblox. First I tried to manually change the offset based on the scroll wheel (that took me so much time because I had no clue how to get inputs from the scroll wheel). But that posed a problem, which was that the player could clip through walls. Then I found there was a literal node called SpringArm3D to do all of this for me 😭 And its so useful, like I can change how much it zoom’s out by my just changing one variable, and it automatically detects collisions an stops clipping through them. This may seem like somehting that is really basic to some of you who have actually cared to read this far (ty btw :)) but this was crazy for me. And now, I realised you can’t orbit around the camera without the player moving. But that’s something to add next time 🤷 lmao this feels like smth to convince ppl that i wasnt afk or smth to farm stardust. i PROMISE im not trying to farm them, although i would love to get some, im not trying to cheat the system guys 😭"}]...
|
Title: Worlds Unbound - Terrain Engine by @alpeka Title: Worlds Unbound - Terrain Engine by @alpeka | Stardance
Devlogs:
Devlog 1 - Player Movement Okay I know what your thinking. 12 hours for just player movement. Surely you must be wasting time just to get as much stardust as possible. The thing is.. I’ve never used Godot before. Everything from the node tree, to project settings was all pretty much new to me. I should have honestly done the WarioWave Godot mission thingy, so that I would have at least been fimilarised with how Godot worked in 3D. And here I am thinking about making a game where you explore a procedurally generated world. Never before have I touched Godot, and I’m dreaming of making a game with procedural terrain, like in Minecraft or No Mans Sky. Time Waste No. 1 - Learning Godot I had to look through the docs just to figure out how to assign a key to going forwards, mind you all the code needed is given to you when you use the PlayerCharacter3D class. This is on of the many things I struggled with in Godot. 😭 Time Waste No. 2 - Experimenting with player models in blender I experiemented with different styles of player models to use in the game, and I landed on one inspired from the infamous space game Kerbal Space Program. Time Waste No. 3 - Being petty about a camera system 📷 I think this is what took up most of my time. As soon as I made a moveable player that doesn’t fall through the ground (a very quickly made glorified cube in blender), I thought about adding a third person camera. I initially thought of making it toggleable, like in Minecraft, where you press F5, it toggles between first, second(?) and third person. But you can’t change the distance away the camera is from the player in third person. Besides, my stupid ass made it so that each time you pressed F, the camera would keep zooming out endlessly instead of toggling between first and third person. So instead I made it zoomable, like in Roblox. First I tried to manually change the offset based on the scroll wheel (that took me so much time because I had no clue how to get inputs from the scroll wheel). But that posed a problem, which was that the player could clip through walls. Then I found there was a literal node called SpringArm3D to do all of this for me 😭 And its so useful, like I can change how much it zoom’s out by my just changing one variable, and it automatically detects collisions an stops clipping through them. This may seem like somehting that is really basic to some of you who have actually cared to read this far (ty btw :)) but this was crazy for me. And now, I realised you can’t orbit around the camera without the player moving. But that’s something to add next time 🤷 lmao this feels like smth to convince ppl that i wasnt afk or smth to farm stardust. i PROMISE im not trying to farm them, although i would love to get some, im not trying to cheat the system guys 😭
Devlog 2 - One Lone Triangle I spent 2ish hours trying to make a triangle. In GDScript.. Absoutely terrible progress. I see people on Stardance making whole ass projects in 2 hours, and I’m spending those 2 hours making a simple triangle. I have no idea why decided to do a game with procedural terrain generation as my FIRST Godot project. I somewhat understand the theory behind procedural generation, mainly from watching a video on the breakdown of Minecraft’s code when I was like 10, but yeah 🤷 Unfortunately, I have no clue how to do it in practise.. so I guess hours of looking through the Godot docs awaits me yay -_-. (jk the docs are extremely helpful tysm godot 🙏)
Devlog 3 - Flat Plane I know this sounds INCREDIBLY trivial, but I finally figured out how to make a flat plane in Godot, that can be used to make an actual terrain. There were 2 main ways that I could have used to make this: Method 1: I can use a PlaneMesh and then subdivide it down into triangles. Then use vertex shaders or custom scripts to displace the plane as a whole based on noise. It is faster to make the flat plane using this method since you give Godot most of the control over the tessellation, and the individual vertex placement. This means however that it is a lot harder to load and unload certain parts of the terrain, and it is generally harder to add noise to the terrain since you do not have control over each vertex. Method 2: I can use an ArrayMesh , where I create the grid from scratch, telling Godot how to connect every single vertex to create triangles. The downside to this is how long this took. I know it seems short compared to my first devlog (I think the main reason I took so long in that one was not only because I was learning Godot, but it was also because I was experimenting with player models on Blender but hopefully now I’ll be more time efficient) but it is still more time consuming to tell Godot how to connect each and every vertex. I was in fact so stumped on how to go about doing this that it suddenly came to me when I was playing with my little cousin. I even noted down how to do it on my phones notes app (excuse my bad handwriting I was in the car writing with my finger) :/ Despite it being longer to setup, it is overall better for the needs of my game, since I’ll not only need to be able to change the height of each vertex based on a heightmap, but it can also aid with making biomes, by adding custom values to each vertex, which is simply not possible with PlaneMesh . It is also easier to load and unload certain parts of the mesh, and it is better for larger maps, since your CPU isnt doing all the hard work of choosing all the vertices and indexing them. In order to make the actually interesting part of the terrain (which btw I haven’t done in this devlog, I guess this is just like a future plans part) I can use either vertex shaders or custom scripts to make noise in the terrain. Both of these have their respective use cases, and I wouldn’t be able to say one is better than the other for my case. Vertex Shaders: GPU based no collisions (purely visual) written in Godot Shader Language (which is written in C, which is terrifying for me who practically only knows Python ( GDScript and Python are similar enough for me)) Custom Scripts: CPU based can create collisions (actually changes the vertex’s height) written in GDScript (happy days (ik I can write it in C# , but I’m staying far away from that)) Despite my fear of anything not similar to Python , I will still need to use vertex shaders. And I will explain that in my next devlog because this is getting too long. Now onto my struggles incredible skill when making a.. flat plane in Godot. I chose to do Method 2, because of it’s functionality later down the line. But that means I have to tell Godot what vertices to make, and how to connect them up. Obviously that was as simple as could be.. (you can see my failures in the screen recordings below)
Devlog 4 - A little bit of a few things I mostly did a combination of small bits, which is probably bad in terms of github commits and actual progress, but at least it’s not burning me out because I’m doing whatever part of the project I fancy at the time. UI I spent most of the time making a (hopefully) futuristic(?) looking pause menu that can also redirect you to a settings page, where I’m planning to hold the settings for terrain generation for the player to manipulate. Much of this time was spent experimenting with different Control nodes, finding out what they do and what they’re helpful for and manipulating the styles of them. I ended up with a style shown below 👇👇👇 Player Model I think I’ve finalised on a particular style, now I basically just have to make it and then texture it. The sad thing is that for some reason lapse doesn’t recognise my hackclub project anymore (already logged 5+ hrs on lapse), so all the time I spent on Blender wasn’t actually logged. If someone could please tell me how to fix this or if theres an extension for blender that would be SO helpful 🙏. Extras I also added the devlogs to my repository, it should appear there when I next commit, which should be soon!! I realise that the popular devlogs have assets from the get-go, so I probably might focus more on that, despite lapse not working if I wanna record time on Blender or Affinity. Again, if someone could please tell me if something is up with lapse or if there’s an extension that I can download for Blender or Affinity, that would be SOO helpful!! 🙏
Devlog 5 - Procedural Terrain (FINALLY!!) I made a start at making the procedural terrain, made some progress with the player model, and with configuring the basic shaders of the game. Elephant in the Room - Procedural Terrain Technically calling it procedural terrain is cheating a bit, cos really all it is right now is perlin noise applied to each vertex’s height. And with that, you can change the shape of the terrain by changing the values of some variables, like the seed, frequency, and octaves. I exported these variables so I could change them in the editor, and added @tool at the start so I can see it in the editor. I’m starting to work on a chunk system at the moment, which will load and unload chunks of the world as the player moves about. Player Model I finished modelling the player (added this version to the game) and added the bones for rigging, except when I move the arm bone, the helmet deforms, so next time I will be doing some weight painting Thankfully UV unwrapping is done as well so I should be able to texture everything before the next devlog. Also, addressing my last devlog, I said Lapse wasn’t syncing with hackatime. Turns out, if I just told it to create a new project called Celestial (which is what my project is called on hackatime), it’ll just add the time to it, so thats amazing!!! The WorldEnvironment Node I accidentally deleted my old configuration of this node while experimenting with stuff, and so I made some changes to the shading of the world. Next up is to recalculate all the normals of each triangle so shadows can be cast properly. I tried using SSAO, but every time I used that to make some sort of shadow, it changed depending on where the camera was and it made the terrain very pixelated. As you can see in the video, you can see the outlines of the terrain. That is because of the volumetric fog added. It sounds resource intensive, so if it starts to lag out my game I might remove it, which is a shame cos it looks really nice.
Devlog 6 - Chunks # 1 Previously, I had it so that the entire world was one big mesh, that could not be expanded without unloading and reloading the whole thing and more. This is obviously very inefficient, especially if I want the terrain to load in and out based on where the player is. Chunks is the answer to that. Split the world into chunks of your choice (I chose 16x16), and load/unload just the chunks you need to, not the whole thing. It seemed easy for me at first, clearly it wasn’t (the #1 for the header, ik this isnt gonna be the only devlog on this 😭 ). Bug 1 - The Normals aren’t normal Last devlog, I talked about calculating the normals, which went smoothly… For the old mesh… You see, to calculate normals, you need the vertices surrounding the vertex your trying to find out, and with chunks, that meant every 16 vertices, the normals were being calculated incorrectly, causing seams to be found in the terrain. However, since we did calculate the normals (for the most part) some pretty nice shadows have been cast on our terrain. Despite it being a bug, it is useful to find out where the chunk boundaries are, which is EXTREMELY useful for debugging, so I haven’t tried fixing it just yet. Bug 2 - Not so Good Performance After dividing the terrain into chunks, and making new chunks generate when the player moved into a new chunk, I tested it out. And every time I tried to cross a chunk border, there would be a huge lag spike. This would be caused by the fact the game prioritised the generation of chunks instead of the game. Thankfully I was able to make it so that the chunks would load whenever the processor was ready, to make sure not to overload it too much. Bug 3 - (Lack of) Collisions Another reason why chunks are useful is for limiting the area with active collisions. When the terrain was one big mesh, the entire mesh had active collisions, which would all be checking if something hit it, which is very resource intensive. Which is why I limited the area with collisions to a small radius around the player. While coding it, many logic erros came up, such as one that caused the collisions to just not work.
Devlog 7 - Chunks # 2: PROCEDURAL GENERATION DONE (mostly) Bugs Managed to fix all the bugs related to this part of terrain generation. Weird chunk errors There was an if statement (I changed it out for something else that’s more efficient) that was like: if abs(player_position.x - chunk_pos.x) > collision_chunk_size or abs(player_position.y - chunk_pos.y) > collision_chunk_size This logic error create weird stuttering issues and lag. The fix was to switch or with and . Normals DEFINITELY the bane of my existence. I know roughly what normals are due to me doing 3D modelling/rendering, but I have no clue how it actually works. And plus, I’ve barely covered the maths I need for this in school, so I spent sooo much time (much of which wasn’t recorded) just researching about normals and how they work. I think that definitely helped me find a solution to the annoying chunk borders and random artifacts found inside each chunk. Chunk Sizing I stupidly and randomly changed the chunk size from 16 to 10, which worked completely fine, except for the fact that the player script was still using the 16x16 chunk system, causing the generation to lag behind, eventually leading to the player falling off the map. New Features There were also some ✨ features ✨ that I added. Colour I added colour to the world, and if I match it to the fog and sky, I think it would look AMAZING I will make it so that the colour does vary across the planet. Player I added the rig and refined the topology for animation.
Devlog 8 - Player Model and other assets! Player Model I finished with texturing, rigging and weight painting. Next Step is to make the walking and jumping animations. Worked on the settings menu I updated the setting menu layout to account for different settings I’ll add in the future Stupid Bugs So when trying to break the terrain generation, I set the speed of the player to like 300 (which it will never be in the game except when in a space ship) but when I tried to do that, the game kept crashing, spitting out an error saying that something didn’t exist. It was coming from my unload_terrain() function. Basically how it works is it checks for all the instances of the MeshInstance3D node, and checks the name of it. For every chunk that is created, I assigned a unique name to it on creation based on the x and y coordinates of it. The function would checking all the nodes, and seeing which ones were out of the “ collision_chunk_size ” radius, and then would delete them. But when going super fast, the processing of things got all weird, meaning that when it tried to delete a chunk, and if it didn’t exist, it would crash. So I added a simple if statement if len(child_name_array) > 2: (basically it would check if the length of the name was long enough to see if there was the coord data). Stupidly I wrote the greater than sign the wrong way round, which led to me being stumped for SO long on why the terrain was just not unloading. tldr: > was the wrong way round and cost me hours.
Devlog 9 - Player Animation!! Walking and Idle Animations I finished a basic walking and idle animation for the player. The walking animation is also somewhat inspired from the kerbals from KSP. Both the animations are kinda choppy, especially when the animation loops round, but frankly icba I didn’t have enough time to fix them rn (mbmb 😭 ). Thankfully the walking animation is timed properly so that the player doesn’t look like its sliding around. Camera updates I added functionality to the camera where you can freelook around the player when holding the right mouse button. Once released, it goes back to the normal position (motion is lerped). Prepartions for next steps For the next steps, I want to go back to the terrain_generation program and start to add variation across the world (like biomes, mountains, etc.). I’m also looking to optimise it, making it generate terrain and collisions faster in prepartion for any future implementation of faster travel. So I added functionality that can allow me to make LODs, which will likely be implemented next devlog.
Devlog 10 - General updates Alright, so ik I said I would work on the procedural terrain, but instead I worked on:… Debugging Tools!! (yayy! ) When tab is pressed, it toggles on debug mode, where all meshes turn into wireframes (to check LOD) and chunk boudaries are shown. There are problems with chunk boundaries not despawning when the terrain its on is gone, but that’s fixed when you toggle debug mode again :). I could fix it but icba I have other stuff that needs to be prioritsed. Resizabile UI So before, if you resized the window, the pause menu and settings menu would be offset from the centre and wouldn’t scale with the window. Now when you scale it, the pause and settings menu stay in the centre and scale accordingly. (the flickering in the video is just an artifact created by the godot editor, and will apparently be fixed once exported)
Devlog 11 - General updates 2.0 Editor Tools!! - (to see the terrain in the editor) So in a previous devlog, I think I talked about how I added @tool in my terrain generation program to be able to see it in the editor. Once I made it dependent on the player position, it didn’t generate in the editor because the player wasn’t loaded in. So now I made it so that if the script was running while the editor (not the game) is open, the terrain would generate around (0, 0) based on how ever big the render distance is. Also I made it so that if you tweak the value of any of the primary noise settings in the editor, it updates in the editor. On top of that, I set the viewport to display wireframe so that I can see the triangles at different resolutions, which is where I came across:…. FLOATING POINT ERRORS!!! (yay ) I noticed that if I set the resolution to a decimal value that was not a power of 2, the triangles would be off by some amount, causing neighbouring triangles to overlap each other, causing normal and collision problems. The resolution variable is going to be eventually used for LODs, so since I’ll be the only setting it, I’ll just make sure to use a value thats a power of 2 The reason why this happens is because 16 (my chunk size) can be multplied and divided by 0.125 (2^-3) evenly to create an integer, compared to 0.1 which results in 1.6. Any smaller power of two is rounded it to the nearest 3dp, so 0.0625 (2^-4) doesn’t work. Camera Issues So I made functionality with the camera where you can scroll to zoom the camera in and out, and if you scroll far enough in, you’ll be in first person, much like how it works in Roblox. There was one problem though. Since the material for the visor on the player model was somewhat transluscent, your view would get darker. Also, you could free look inside the helmet, looking at the areas I wasn’t bothered to model and texture hadn’t modelled. So I disabled that in first person. The biggest timewaste of my life In an attempt to offload some of the generation to the GPU for more effecient parallel processing, I tried to figure out which parts of the algorthim were going to be handled by the CPU and GPU. There were some that had to be handled by the CPU, and there was no choice about those, and they were: collisions and figuring out what chunks should be rendered. At first I thought, how about I offload nearly everything to the GPU, including the noise function. Then I learnt that FastNoiseLite didn’t exist in .gdshader . So I did what any normal person would do, and CODE PERLIN NOISE BY HAND. I spent HOURS learning everything my dumbass could about it: vectors, normals, gradients, deviation, erosional generation, and finite difference approximation. At least I probably learnt something useful for FSMQ 🤷 (a British maths exam most students do in yr11 along with their other GCSEs).
Devlog 12 - General updates 3.0 I PROMISE THIS IS THE LAST ONE GUYS 🙏 Performance Stats I added a little HUD showing the FPS, the time it takes to make one frame (has to be below 16.67ms (60fps) or there will be noticeable lag), and the memory usage. Lighting, Shadows, and World Environment I slightly changed the shadow bias and normal bias so that shadow artifacts are to a minimum. On top of that, I set it so that shadows aren’t cast for the terrain, which unintentionally handles with some of the artifacts, whilst keeping the “shadows” by illuminating the terrain depending on where the DirectionalLight3d is, making the “shadows” reponsive to a future day-night cycle. Also the volumetric fog and lighting looks better Camera Issues 2.0 So previously I had the player hide() when you go into first person, but that also effects the shadows. So instead I made the visor disappear when you go into first person. But then there was another problem. The head would move during the idle and walking animations, which is quite distracting and could be problematic for some players. So I stopped the animtions whilst in first person. It is a very rudimentary fix, since players can look at their shadows and see the lack of animation. Furthermore if I want to add multiplayer in the future, it’ll look very weird. Performance checks In preparation of the biome generation, I wanted to make sure the performance is fine. It takes a bit for the terrain to generate at the start, but thats common across nearly every game. And this will be lightened a bit when I implement LODs. Once the game is running, it runs relatively fine, except with (very quick) lag spikes when the chunks update. To address this, I’m planning of offloading some of the terrain generation to the GPU, which can calculate normals a LOT more effeciently and quicker than the CPU. Current, the CPU calculates all the vertices, indices, normals, and then compiles it into an ArrayMesh , which is given to the GPU for rendering. This can put a lot of strain on the CPU, especially later down the line, so it’s better and more effiecient if the GPU does the very repetetive calculations, by making it do all the normal calculations, including other stuff.
Devlog 13 - LOD template I basically deleted all the old code, and started over, by making a function where the noise will be given to the vertex shader, and one that will generate the actual flat mesh for it (which is going to be changed by the vertex shader). I made the template for making flat planes with different levels of detail (LOD), which will be changed by the vertex shaders, applying the noise to the mesh. I created a new script called lod.gd and gave it a class name, so that I can call multiple instances of it in the main terrain generation program. Every time the program wants to make another chunk, I have to pass the arguements: resolution - what ive defined as a synoymn of LOD chunk_pos - where the chunk is The function then loads an ArrayMesh from a pre-generated list of possible meshes and creates a new MeshInstance3D node to display it. Extra stuff I also added player coords and chunk position in the debug_screen :)
Devlog 14 - LOD chunks ——— OPTIMISATION IS SOO HARDD 10hrs to do practically do something I’ve already done? (i had already made a chunk system in previous devlogs) Well, whilst some of that time was transferring code from my old commits to the current one and making sure it works, most of the time I spent on this devlog was spent on ✨ “optimisation” ✨ Optimisation First of all, I added LODs into the chunk mesh. What this means is that since further away chunks take up less of your screen, the level of detail (LOD) is reduced the further away it is. I had already made the script that handled the creation of those different meshes with different LODs, so in this devlog, I added it to the main terrain generation script, and assigned each LOD to a certain distance, so that any chunk with a certain distance has a certain LOD. In my last version of the terrain generation, I relied on the name of the MeshInstance3d nodes created to identify what chunk they were. I realised when making this updated version that it was prone to failure, since if the node did not exist or a node with the same name were some how added to the scene tree, errors would be raised or at the very least, a logic error would occur. To recetify this, I switched to using dictionaries to house all the information of all the chunks: chunks : Dictionary [ Vector2i , int ] = { Vector2i ( 0 , 0 ): 0 , Vector2i ( 0 , 1 ): 0 , #etc } The key is chunk coordinate, and the value is the LOD (0 being the highest, 4 being the lowest) Every time I wanted to update the terrain, I would search the scene tree if a particular node was unwanted (again, by looking at the name) and then generating the rest of the ones wanted. This way would not work with LODs, since some chunks may still exist, but may have to change LOD depending on where the player is. So I made use of the dictionary and also created a new one that would store the chunks that I want created. It would loop through the dictionarys, checking certain conditions, and the terrain would be updated. All this looping is somewhat inefficient, and did cause some lag spikes, so I will try to fix that next devlog by only checking the chunks that would be affected based on which way the player moved. To help with the looping, I created chunk and lod lookup tables, that can be offset based on the players_position. These lookup tables are only changed when the render distance is changed, so the same calculation doesn’t have to run hundreds of times in 16ms (60 fps).
Devlog 15 - I’m an Idiot For the past 95ish hours, I’ve been working on a way to make procedural terrain for my game. I tried 2 main methods, one centred round the CPU, and one I was building centred around the GPU. The endless chunk seam bugs caused me to burnout/get tired of the entire project, and there was so many stuff (that I won’t really be explaining for the sake of my poor reader’s sanity) leading to me ✨ youtube ✨ I saw this AMAZINGLY smart video by devmar, showing an alternate way of generating terrain. I urge you to watch the video as well, the whole technique is very very clever, and he even goes on to make further videos on making collisions, recalculating normals and adding vegetation, especially if your interested in procedural generation. After watching this video however, I became incredibly frustrated. I spent nearly 100hrs of my summer making this procedural terrain which I know hadn’t gotten anywhere and theres this incredibly smart video from 4yrs ago that pops up on my feed. Welp, now ig i gotta try out this way, and quick cos my parents are on my tail talking about me finishing this project before school starts 🙏 (its my gcse year so ig its valid but still ) Now what I actually did that counted to my time Experimented with vertex shaders, and sending heightmaps to vertex shaders to displace. This however caused immense lag and caused VERY ANNOYING chunk seams. #epicfails
Devlog 16 - AMAZING PROGRESS!! I’ve managed to get a massive 20km render distance with huge mountains and ridges using FastNoiseLite and vertex shaders. I used devmar ’s terrain technique, which he named the “Wandering Clipmap Terrain Technique”. The reason why the technique is called the “ Wandering Clipmap Terrain Technique” is because a flat plane that is subdivided a bunch (to make varrying levels of detail (LODs)) that follows the player. The vertex shaders then offset the heightmap so it gives off the illusions that your moving about in a massive world. All the displacement is done by the vertex shaders, which looks at a heightmap. In the future, I might make this heightmap be generated in gdscript instead of in the inspector, to deal with texture resolutions. Currently, from afar, the terrain looks amazing (except from the fact its not textured) but upclose, you can see rings in the terrain, which is caused by the heightmap’s resolution being too low. In fact each ring is about 8m tall so I really need to fix that 😭 The normals are calculated by just copying the heightmap and setting it ‘as normals’ in the inspector. They also are multiplied by a normal basis matrix, which allows me to configure the specific normal settings. I’ll need to calculate the normals in the fragment shader as well in the future for more convincing shadows, but for the mean time, the vertex shaders should do just fine. I’m planning on adding collisions, then maybe textures, biomes and vegetation soon!!
Devlog 17 - I am incredibly frustrated. No matter what I do it feels like I just can’t get the collisions to work. Basically, I’m trying to fetch the heights from the height map to input into the CollisionShape3D, but the coordinates are always offset in some way or the other. I even used AI my friend to basically rewrite the entire script over and over again, but that didn’t work either. Maybe it’s cos school has started now, and I haven’t been able to spend that much time on this project than I would like to As you can see in the photo, the collision mesh (in blue) is offset from the normal terrain (in white)
Devlog 18 - I am happy once again!! I FINALLY got the collisions to work!! Basically, it looks at the terrain model that is imported into Godot, and aligns the vertices of the CollisionShape3D with it. It also updates its position every time the player moves 1 unit (whatever the size of a quad of the mesh is). Then it looks at the heightmap, looks up the height of its coresponding pixel, multiplies that by the height shader param (2000, like in the vertex shaders), and thats the collision shape done. I noticed while walking around the world, that there were these massive ridges on the terrain. This is due to the lack of precision in the heightmap. The heightmap only has 256 shades of grey, and I need 2000 values. It is quite impossible to make a image file with that much precision, so instead, I’ll make it so that the CPU will just send an array to the vertex shader. Also, I’ve rebranded my project to Worlds Unbound, and this specific Stardance project will just be handling the terrain stuff for the game. p.s, it never goes above 16ms, i think thats probably because i was recording
Devlog 19 - Main Menu Added (and other things)! I spent quite a lot of time making the background for the main menu in Blender. After just copy and pasting the player model used in the game, I went ahead and made the main attraction: ✨ the planet in the background ✨ . My knowledge of noise that I gained from my previous attempts at the terrain generation helped me create the stars in the background, and the texture for the actual planet in the shader editor. I also added a slight atmosphere, which is (somewhat?) noticeable. I also went ahead and updated the shader code. Before, I used to use the visual shaders, since it was quite similar to the shader editor in Blender, which I was familiar with. But then I realised there’s just more flexibility with using GLSL . I can group uniforms in the inspector, making it clearer and less cluttered if I want to add textures in the future, including different images for the same texture (like Ambient Occlusion, Normals, Colours, and Roughness). Thus being able to group those different types images for the same texture was very important for future usability. Thankfully, Godot allows you to see the shader code that is generated from the visual shaders. Unfortunately, it was not readable at all. The generated code used a random(ish) collection of numbers and letters, and it was too long. Look below for the comparision for just the vertex shader, but it was something like 84 lines that was shruken down to 10 for the vertex shader. Even if you account for spaces in the generated code (which then it might be like 50-60 lines) thats a huge difference. So it took quite some time to get it to a readable state. edit: idk why the actual background looks so bumcheeks compared to the banner, hopefully itll be fixed by then 🤞
Devlog 20: GPU noise I found a way to make noise using a Godot addon called FastNoiseLite Runtime Shader . It was apparently identical to the FastNoiseLite in GDScript. So I gave it a try. I knew it was a gamble, given how much time I got left to ship an decent project, but I gave it a try since it seemed interesting. It wasn’t that hard to get the noise working, but to get it to sync with the collisions was a nightmare. In the end, I decided that even though the README stated it was 99.9% the same, the output seed by seed was different. So I decided to scrap it and now I’m going back to the old version with heightmaps. Why did I really want to switch? Because of the limited colour depth in images (has to be 8-bit for GDShader to read), theres not enough heights for each vertex to be at, so every so often, there’s this massive wall. It looks fine from afar, but thats probably because my terrain is 20km x 20km, so of course an 8m tall wall would look fine. (the image is from the addon readme)
Devlog 21 - Ship Prep!!! Colours I added colours to the terrain depending on how high the vertex is. This does create a very harsh border between the two colours, but I didn’t want to learn lerping, ik how to larp enough. Cleaned up my commits My commits were, and probably are still messy, and when I went ahead to revert some changes it said there were errors, but now thankfully that’s all fixed. :) I also updated quite small normals and some technical stuff.
Ships:
— SHIP No.1 — I spent the last couple of months making a model terrain, which I will use for my game that I will continue to build after this competition. My game idea is quite ambitious, and given how long it took for me to get this basic terrain to work properly and well, that won’t even be coming with the extra month added one. I lot of you may be thinking though, what on earth were you doing for 125 hours, when all you came up with is a glorified green and grey piece of paper you could walk on. Well, not only was I learning and using Godot for the first time, it was the first time I learnt anything as complicated as this. I had to wrap my head around complex (at least for me) maths and computer science topics, like vectors and cross product, noise and FBM, TBN model, and UVs, not to mention just the sheer amount of logic I had to get through. It was so tiring to keep getting bugs for the chunking system I had, or the collisions. But thankfully, all that is behind me 😼. I’ll give you a more indepth look into what I’ve done over the past couple months. Devlogs 1-12: This period was the general beginning of my project. Not only was I learning Godot, and watching tutorials on it, I was also spending time on the player character, the camera system, and the world environment. Devlogs 13-15: I tried to implement LODs into my chunks, since the performance was simply too bad. Somehow this made it worse, possibly because of more chunks (the ones at the broder of LOD borders) being forced to be unloaded and loaded back in. Devlogs 16-21: I used my current technique, heavily based from devmars video on youtube about procedural terrain during this period. School had also started, so I spent less and less time on it, being significantly burnt out and tired. So I basically went through 3 iterations of terrain for my game, so that is why it took so long to get to this point....
|
1793004561.5073767
|
1793090961.5073767
|
|
52241
|
DDSim by @yaasshh | Stardance
|
yaasshh
|
1
|
124.76
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-24T16:51:16Z", "hours": 87.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I built DDSim, a program that simulates what happens inside the tiny parts that computer chips are made of, ie diodes, capacitors and transistors. You describe a device by its shape and which parts of the silicon have extra electrons or holes. DDSim then works out how those electrons and holes move, and draws the current and voltage curves. I didn’t fit anything to make the graphs look right. Everything comes straight from the physics equations. (NOTE: ITS STILL VERY CLUNKY SO ITS NOT GOING TO BE PERFECT AS OF RIGHT NOW. IF YOU FACE ANY TROUBLES IM REALLY SORRY) To make sure everything accurate, I checked it against textbook formulas and against DEVSIM, a simulator other people wrote. They agree to within a few percent, and the project has about 2,700 automated tests. You can try it in your browser at ddsim.fly.dev. Pick a device, press solve, and watch the answer draw itself. Every button and graph has a little “i” that explains what it means, and there are guided lessons if you’re new to this. It’s a school-level instrument, not a chip design tool. Below about 50 nanometers the physics it uses stops being accurate, so I didn’t go beyond that", "repo": "https://github.com/yaasshh09/DDSim", "demo": "https://ddsim.fly.dev"}]...
|
[{"post_id": 82276, "ts": "202 [{"post_id": 82276, "ts": "2026-10-24T13:22:27Z", "hours": 9.6742, "text": "Devlog #23 The trick for the MOS capacitor worked. Making the electrons react faster put the slow wiggles at a speed the computer can handle, and the answers came out right. That FINALLY finished the AC phase. I also added noise, a tiny random jitter in current that every device has. Next I added time. Now its possible to flip a diode from on to off and watch it recover. When you switch a diode off, it keeps conducting for a moment because of all the charge stored inside it. I compared that against DEVSIM, and our results were within 0.03% of each other which is quite frankly something im really proud off. Then I added a feature where the simulator shows how inaccurate it may be. It now checks its own answer against a finer mesh and puts a little error bar on every point in the plots. It can also improve its own mesh by adding points only where they’re needed. On 5 of my 8 test devices it hit the target accuracy with fewer points than my hand-made meshes. I was aiming for around 6, so that’s still doable. The newest addition is a bipolar transistor, where a small current into the middle layer controls a much bigger current through the whole device. I built a simple 1D version and a more realistic 2D one. The 1D version matches the textbook formula to within 0.03%. The best part is that its gain drops off at both very low and very high current, the way real transistors do, and I never told it to. It figured that out from the physics."}, {"post_id": 80341, "ts": "2026-10-17T10:12:36Z", "hours": 1.9553, "text": "Devlog #22 The long DEVSIM run finally finished. It took about 6 hours and matched the expert result almost exactly, which closes out the scoreboard phase. Then I started the next phase, which is about AC. That essentially means wiggling the voltage back and forth and watching how the device reacts at different speeds. Before, my simulator could only handle super slow wiggles, or fast ones where I froze some electrons by hand. Now it can handle any speed. To get there, I first taught the simulator how fast electrons and holes pile up or drain away over time. Then I wrote the part that works out how much current flows into each contact when one of them gets wiggled. I tested it on diodes, since they have textbook formulas to compare against. A long diode matched within about 1%, and a short one within 1.3%. Along the way I found a bug where my mesh maker gave up on very long devices, so I fixed that too. The MOS capacitor is giving me some trouble. At really slow wiggles, the math needs more precision than normal computer numbers have, so the answers came out wrong by up to 46%. Fast wiggles work fine. Right now I’m trying a trick where I make the electrons react faster, so the slow case happens at a speed the computer can handle. Below are some of the DEVSIM scoreboard values"}, {"post_id": 80105, "ts": "2026-10-16T07:52:45Z", "hours": 4.8328, "text": "Devlog #21 Since the last devlog I finished most of the temperature phases. First I compared the diode at 400 K against DEVSIM. I saved that result so my other tests compare with it from now on. Then I added two new sliders to the website. One sets the temperature, from 200 to 500 K. The other sets the fixed charge where the silicon meets the oxide. I picked both ranges by running the simulator across them. Each slider also has a short lesson that explains what it does. While I was writing those, I found some broken math formatting in the temperature lesson and fixed it. The biggest addition is freeze-out. To make silicon conduct, we add extra atoms that give up electrons. When it gets really cold, those atoms stop giving up their electrons. Before, my simulator assumed they always did. Now there’s a switch for it, and it works. At 100, 200 and 300 K it matches the textbook formula almost exactly. I also checked that a plain frozen silicon bar still follows Ohm’s law, and that the capacitance results still work at 150 K."}, {"post_id": 79306, "ts": "2026-10-13T13:29:32Z", "hours": 4.9631, "text": "Devlog #20 In this devlog i firstly fixed up the website. It now has a little icon in the browser tab, a terms page, a privacy page and a footer with a contact button. The icon didn’t show up on the live site at first, so I fixed that too. Then I started the next phase, which is all about fixing temperature related stuff. A lot of the calculations of the simulator took room temperature which might have led to some wrong calculations, so I’ve been fixing that. The gate’s energy level was stuck at its room-temperature value. it was a real bug and its fixed now. When the silicon gets hotter, electrons now max out at a lower speed, just like in real-life chips. From 250 to 400 K, the junction’s built-in voltage matches the textbook formula. From 300 to 400 K, the diode’s leakage current stays within 0.3% of the formula. I also added a fixed charge that sits where the silicon meets the oxide layer. Real chips always have some, and it changes the voltage where a transistor turns on. Next up are the big jobs. A long DEVSIM run is still going, and after that I’ll test the temperature effects on a full 2D transistor. I also still need to put the website changes live."}, {"post_id": 76513, "ts": "2026-10-03T19:43:47Z", "hours": 7.6606, "text": "Devlog #19 The speed and robustness numbers are now saved on the scoreboard. On the first 8 benchmarks, my solver takes about 1.6x less time per bias point than DEVSIM. I also added a test that reads the README and fails if the README claims anything the data doesn’t back up (I hate getting 100% vibe code assumptions on my readme btw). I renamed a lot of variables across the code (to pass the 30% ai rule that im apparently violating) to shorter names. That kind of change can break the tests if some of the variables reference each other across multiple files, so I checked that python turns the old code and the new code into exactly the same instructions. Thankfully it did. I also moved all the settings into one file. Things like how many tries the solver gets, how small the mesh can get, and the server limits used to be scattered across about 20 files. I checked that every single value stayed exactly the same after the move. I also deleted the last few leftover comments. Then I pushed everything. The tests ran on three Python versions, and 2,723 of 2,724 passed. The one that failed was a browser test on Python 3.11 that waited too long for the page to load. The same test passed on the other two versions, so it’s probably just a slow test machine, but I’m going to rerun it to make sure. My laptop ran out of memory again, which stopped me from finishing the type hints in the tests. That’s next, once I’m not running a bunch of other stuff at the same time."}, {"post_id": 74357, "ts": "2026-09-27T07:21:49Z", "hours": 2.1619, "text": "Devlog #18 The robustness runs are almost done. Robustness checks a simple concept, if I give the solver a device cold, with no warm-up, does it actually finish? I ran 200 test cases through my solver and through DEVSIM, each in a few different setups. The robustness numbers aren’t final yet. One DEVSIM result is still missing. The first time my laptop ran out of memory, and the second time it went to sleep overnight, so it’s running again now. I also found out DEVSIM acts much differently depending on how many CPU threads it gets. With only one, some solves failed or took forever which was kinda interesting to see. On the cleanup side, I turned on the strictest type checking across the whole project and fixed what it found. Every color on the website now comes from one file. I also deleted a bunch of old files nobody used and cut the README down."}, {"post_id": 73883, "ts": "2026-09-26T07:55:09Z", "hours": 4.0261, "text": "Devlog #17 I restarted the scoreboard runs, and before looking/mentioning any of the results I checked my own setup for DEVSIM. That showed a few bugs on my side. My starting guess for the voltage inside the device did a log of zero on heavily doped chips, so DEVSIM crashed INSTANTLY. I also wasn’t giving it enough steps to settle on some devices. I fixed both, because it wouldn’t be fair to count my mistakes as DEVSIM’s. I also cleaned up the code, I tried to ship all progress so far but there was just too much AI (guilty) so I am working on redoing the python, css and javascript code again mainly from scratch. (The image shows all the values from the DDSim tests)"}, {"post_id": 73631, "ts": "2026-09-25T15:22:18Z", "hours": 2.4842, "text": "Devlog #16 Now that DDSim is live, my next goal is to make it better than DEVSIM, a free, open-source simulator a lot of people already use. “Better” doesn’t count unless I can measure it, so I planned out the next 11 stages of the project, and the first one is a scoreboard. The scoreboard runs both simulators on the same set of devices and compares them in four ways: how often each one finishes a solve without crashing, how accurate the answers are, how fast they run, and what each one can do at all. Some of these runs take hours, and my laptop ran out of memory partway through, so I paused them. I’ll post the results once they’re done, even the parts where DEVSIM is better than mine. While building the accuracy check, I found a bug in my own math. Sometimes it reported numbers that didn’t make physical sense, so now it throws those out instead of trusting them. I also went through all the style files for the website. They’re about a third smaller now, and I checked that the page still looks exactly the same. Then I found a small bug that had been there all along. The little “i” buttons that explain each setting were supposed to turn blue when you hover over them, but a different style rule was overriding it. Last, I cleaned up the README again. The pictures are centered now, I took out the GIF, and I rewrote some of the text so it reads more naturally."}, {"post_id": 73215, "ts": "2026-09-24T16:47:16Z", "hours": 1.6669, "text": "Devlog #15 DDSim is FINALLY deployed and live! You can try it at ddsim.fly.dev Getting it online took one extra step. The cheap shared server was too slow: the hardest transistor solve takes about 50 seconds on my laptop and would have taken around 7 minutes there. That’s past the 5-minute limit I set, so it would have been stopped every time. I moved it to a faster server, and now it finishes in under a minute. Once it was up, I found a bug. When every contact on a transistor was at the same voltage, the picture still drew current flowing through it. That’s impossible, because with no voltage difference nothing moves. I fixed it, and now the page says “no current flows” instead of showing an empty plot with no explanation. Then I rewrote the README from scratch. The old one was over 500 lines and way too dense. The new one is about 200 lines, mostly screenshots from the live site plus a few tables, so someone can see what the project does in a couple of minutes. While doing that, I caught a mistake. One number in my results table didn’t match the graph right next to it. I reran the full simulation, which took 20 minutes, and fixed the table so it matches. Last, I took the deployment files out of the public code. Anyone who downloads it gets everything they need to run it on their own computer, but not the setup for putting it online. Next up, I might be thinking of getting a custom name for this simulator and my other atom simulator. If anyone knows where I can get free domains, lmk in the comments"}, {"post_id": 72803, "ts": "2026-09-23T19:24:31Z", "hours": 2.5789, "text": "Devlog #14 Since then, most of my work has been getting DDSim ready for other people to use. First I cleaned up the controls. Some sliders and number boxes let you pick values that made the solver fail, which just showed up as a red error. I went through the diode, the MOS capacitor, the transistor and the draw-your-own device and found the range where each setting actually works. The sliders now stay inside those ranges, so a beginner can’t break things by accident. Then I cleaned up the code. I deleted about 2,400 lines of comments that just repeated what the code already said and kept the ones that explain something nessessary. Next came the writing. The site has about 40 short articles that explain the physics, and a lot of them sounded stiff, so I rewrote all of them. I did the same for the project docs, and on the way I found a few places where the docs no longer matched what the code does, so I fixed those too. Now I’m working on putting it online. I picked Fly.io to host it, and I’m hoping to get a free custom name. Since anyone will be able to use it, I’m adding some safety limits first. Only a couple of solves can run at the same time, old results get cleared out after a while, and a solve that runs too long gets stopped with a message explaining why. I tested each limit by breaking it on purpose to make sure the test catches it. It isn’t live yet, but it’s close! [lazy pic, i dont wanna open server again :( ]"}, {"post_id": 72407, "ts": "2026-09-22T21:05:00Z", "hours": 1.9161, "text": "Devlog #13 This one is all about the page itself. The physics didn’t change, but you’ll notice everything else did. I rebuilt the whole look from scratch. The old version was only friendly if you already knew semiconductors, and I want someone who has never heard of a diode to open it and get somewhere. Now it opens by asking you to pick a device: a diode, a MOS capacitor, a transistor, or draw your own. Each one comes with a sentence or two on what it is. Every number and switch has a little “i” next to it that explains it, and an empty plot tells you what it’s waiting for instead of sitting blank. Drawing your own device used to happen in a tiny box off to the side. Now it gets the whole screen. Some layers are so thin they basically disappeared, so I stretch the picture up and down until you can see them, and a label says when it’s stretched. Doped areas get a soft color so you can tell them apart. I also changed the font a couple of times. It started in a terminal style that felt cold. I tried one replacement and ended on Poppins, which just feels warmer. My favorite change is in the runs panel. It used to list your old runs as text, like “doping 1e17.” Now every solve saves a little picture of its own curve, and they all share the same scale, so you can see at a glance how each change moved the result. I switched the license to CC BY-NC so that it still stays technically open source but I own intellectual property for commercial use. Anyone can use it and change it for free, as long as they credit me and don’t sell it. A bit of AI usage in the frontend i will agree but not overkill in terms of it."}, {"post_id": 72227, "ts": "2026-09-22T14:20:14Z", "hours": 2.8683, "text": "Devlog #12 Last time I left off with a transistor sitting on oxide that would not solve. I think ive fixed it. The silicon body had no contact touching it anywhere, so the solver had no idea what voltage that body should sit at. There is no single right answer, so it just wanders. That is not a bug I can fix, it is the physics of the thing, so now the simulator refuses that drawing up front and says why instead of grinding away at it. Then I went hunting for every other way someone could break it. I wrote something that tries every combination of settings the page can send and watched what fell over. A few things did: A gate metal with a work function no real metal has. Surface scattering asked for on a 1D device, which has no surface to scatter off. A shape so thin the grid ends up dividing by zero. All of them now get refused before the solve starts, with a sentence saying what to change. A few smaller ones. The device picture was drawn half a grid cell off, which threw off the line you drag across it to read values. That same line returned nothing at all where silicon meets oxide. And the explanations could load out of order and show you the wrong one. I think now i should wrap the version 1 of the project and finish polishing the frontend considering stardance is getting over soon. another lazy code pic btw cause i dont wanna open the servers again"}, {"post_id": 70662, "ts": "2026-09-19T15:24:06Z", "hours": 2.4228, "text": "Devlog #11 Since the last devlog, you can draw your own 2D devices, not just stack layers in a line. You draw rectangles of silicon and oxide, paint doping onto them, and place metal contacts along the edges. The simulator builds a grid that fits your drawing and solves it. Before it solves, it checks for mistakes and tells you what’s wrong in plain words: a piece of silicon with no contact touching it, a gate sitting right on silicon, or a shape too small for the grid to see. To make sure drawing works, I redrew the MOS capacitor and the transistor I already had and checked that they give the same answers. The capacitor matched almost exactly and the transistor was within about 1%. Testing it in a real browser caught two bugs. One made every solve hang forever. The other made the picture of the device grow every time it redrew on high resolution screens. Both seem to be fixed now but I’ll be on the lookout for similar bugs. Then I tried something new, a transistor sitting on a layer of oxide, the way a lot of modern chips are built. It won’t solve yet. I narrowed it down to the oxide underneath the silicon, and I’m still wondering how breaks things. More on that next time. random picture cause im too lazy to start the servers again"}, {"post_id": 70075, "ts": "2026-09-18T12:25:44Z", "hours": 3.6847, "text": "Devlog #10 Since the last devlog, the simulator has gone from explaining things to letting you play with them. First, you can now compare runs. Every time you solve, the curve stays on the plot, so you can change one thing and see exactly what moved. The diode also got live sliders. Drag the doping or voltage and the answer updates while you drag. The 2D devices like the MOSFET are too slow for that, so I added a quick mode that uses a rougher grid. It’s a little less accurate, and I wrote down exactly how much. Then I built five guided lessons: a diode sitting at rest, a diode with voltage on it, a MOS capacitor, a transistor turning on, and what goes wrong when transistors get really small. Each lesson walks you through experiments step by step. The important part is that every claim a lesson makes is checked by a test against the solver I developed as part of the project. For example: if a lesson says “the current goes up,” a test runs it and makes sure it actually does. The biggest addition is a device builder. You stack layers of doped silicon however you want, and the simulator solves whatever you made. You can also save a design and load it again later. I agree I used AI for the frontend but I did not go VERY heavy on it. Only to build upon the frontend base I coded"}, {"post_id": 69600, "ts": "2026-09-17T12:07:30Z", "hours": 6.0439, "text": "Devlog #9 Since my last devlog, my solver and DEVSIM have started to cooperate. All ten benchmark devices match, the MOSFETs included, so the physics phase is done. THANK THE LORD Now I’m working on the part I care about most personally, which is making the simulator teach. The browser used to be a wall of knobs and plots with no explanation. Now every knob and every plot has a small “i” button. Click it and a drawer slides out with a plain explanation first, then the real equations for anyone who wants to go deeper. I wrote 35 of these explanations covering the physics, how the solver works, the devices, and how to read each plot. Then I checked them against the code. One credited the diodes with an accuracy number that actually belonged to a different device. Another claimed that one failed point in a sweep doesn’t ruin the rest, but the code stops at the first failure. The equations turned out to be hard to figure. The markdown reader treated the backslashes inside the math as its own escape characters and deleted them, so 92 bits of spacing and notation came out messed up. Now I pull the math out before the markdown step and put it back after. I also bundled the math and markdown libraries into the project, so the page works with no internet. Next up are band diagrams, which show the energy levels electrons can sit at. The page will draw them straight from the solved device."}, {"post_id": 68669, "ts": "2026-09-15T14:33:26Z", "hours": 1.7181, "text": "Devlog #8 Really tired today. Just ran a bunch of tests today and got a bunch of values ill sort through tomorrow."}, {"post_id": 67223, "ts": "2026-09-13T08:42:33Z", "hours": 3.7983, "text": "Devlog #7 Since my last devlog I have been teaching DEVSIM to run the same physics my own solver runs. Before this it was on a stripped down model set, so the two codes had similar geometry and nothing about mobility. Now it runs the real thing: doping dependent mobility, surface scattering at the oxide, velocity saturation, and proper Fermi-Dirac statistics. Getting there meant three more small lies. DEVSIM will easily chain a derivative through one kind of model and silently return zero for another. No error, no warning. My solver just diverged on the first step. It took a dump of every derivative on the device to see a column of exact zeros where numbers should have been. Then a field magnitude written as a square root of a square. Mathematically, sounds good but numerically it produces a nan wherever the field is exactly zero, which in a neutral chunk of silicon is nearly every edge. Then the surface mobility. I was refreshing it on every pass, forever. That is not a converging loop, that is two numbers chasing each other. The gate walk climbed to 0.50 V and then refused 0.55 V at every step size I gave it, down to a tenth of a millivolt. A failure that ignores step size is not a step size problem. I gave the refresh a stopping rule and re-ran it. Same answer to the last digit, just reachable now. The 1 micron device now agrees between the two codes to under 3.3 percent at low drain and under 1.3 percent at high drain, across four decades of current. The remaining blocker is not code. My browser is holding 15 of the machine’s 16 GB."}, {"post_id": 66590, "ts": "2026-09-12T13:16:11Z", "hours": 3.9589, "text": "Devlog #6 Im not going to say much this devlog. I hate Github CI errors with a passion and everybody that creates software relates."}, {"post_id": 65940, "ts": "2026-09-11T12:39:46Z", "hours": 2.6142, "text": "Devlog #5 Since the license was added, all my time has gone into one stubborn thing, that is getting DEVSIM simulator, to produce trustworthy MOSFET curves. It has been a long journey of small lies the application tells you. DEVSIM’s solve doesn’t take a device argument, so it solves everything you’ve ever built in that process at once. I was building one device per curve and leaving them around, so the second curve was dragging a finished device along with it and ruining the shared error check. Deleting each device when its curve finishes fixed a whole family of weird failures. Then I found the equilibrium solve was starting from all zeros, which on this device is 0.6 V off. I supply it from charge neutrality now. Same final output but far less trouble getting there. 2 of my own ideas turned out wrong and got reverted, but I wrote the measurements rather than dropping them. Capping the solver’s pass budget moved the current by 0.4%. Pinning the math library to one thread made a four second step take three minutes. Big Ouch. Currently, the 1 micron transfer curve at 50 mV of drain runs end to end and confirms with my simulator to within 0.23% above threshold. The 1 V curve still stalls at 0.4 V of gate, and I checked it properly rather than simply loosening the tolerance, because it turns out DEVSIM isn’t converging there at all. My own code, for contrast, does the same curve in 4.6 seconds."}, {"post_id": 65618, "ts": "2026-09-10T21:14:24Z", "hours": 1.4086, "text": "Dev log #4 After the last devlog I pushed and CI went red on all three Python versions. One test, one solver that would not converge. I guessed this before and fixed the wrong line. Last time I saw the residual and assumed a gate step was missing the convergence basin, so I put continuation on the gate ramp. That was a real improvement, just not this bug. This time I actually read the CI log The failing solve was the one before the ramp even starts. Gate at zero, drain already at 1 V, starting from a cold guess. So I measured it instead of guessing. Cold at 0 V drain takes 1 step. At 1 V it takes 22, and 12 of those get clipped by the step limiter, which means the solver is being dragged the whole way instead of converging properly The fix walks the bias in from zero using the continuation I already had. I regenerated the whole roll-off table through the new path and every digit came out identical. Only the path changed, not the answer. Also added the Open-Source MIT license, and cleaned the commit history."}, {"post_id": 65362, "ts": "2026-09-10T13:29:09Z", "hours": 2.1169, "text": "Dev log #3 I found a bug that made every 2D current in the simulator wrong by a factor of about 245, WAY too big. The cause, i believe, was one missing conversion. The code turns an internal number into a real current, and in 2D that conversion needs an extra length factor that I never included. In 1D it happened to be right, which is why it went un-noticed. I fixed it and then wrote a test that compares a 2D current against Ohm’s law, worked out by hand with no solver involved. This test was missing before. The reassuring part: I measure the turn-on voltage two completely different ways. They used to differ by 180 mV, which I didnt pay much attention to previously. After the fix they agree to about 2 mV. I did not tune anything to make that happen, so I might have to start believing in miracles. I also fixed two divide-by-zero crashes in the surface mobility code that were blocking a whole test combination. Also updated the README numbers and the decisions log. The full test suite is still running, and I will push to github once done."}, {"post_id": 64702, "ts": "2026-09-09T10:05:49Z", "hours": 15.2131, "text": "Devlog #2 Two things this stretch, and both started as “that’s odd” rather than “that’s broken.” First, the solver was crawling. Every step up in voltage cost more than the last, and past a point it just gave up. I traced it back to the starting guess, which was asking what makes glass electrically neutral. That question has no answer, because glass has no charges to balance in the first place. The solver was grinding away at something stupid before it ever got to the real problem. I gave it a proper starting answer instead, and the slowdown disappeared entirely. Second, I stopped trusting my tests and went to check them. I broke my own code ten different ways on purpose, one at a time, and watched to see which breakages the suite would catch. 9/10 failed, which is what I wanted. 1 slipped through clean, and that is the interesting one, because a test that cannot fail is not a test. Chasing the one that got away turned up a real bug hiding underneath it. Setting the voltage on the bottom contact was silently doing nothing at all. The code ran, reported success, and ignored the value. One line to fix, and it would have been very hard to find any other way, since nothing about the output looked wrong. Heads up! Light AI usage to debug the tests and break code to find errors"}, {"post_id": 54968, "ts": "2026-08-26T12:21:42Z", "hours": 35.26, "text": "DDSim Devlog I’m building a chip simulator from scratch. Today I got it to simulate a MOS capacitor, a silicon slab with a thin glass layer and a metal plate on top. It’s the heart of every transistor ever made. What I built: I stacked two grids together: a fine one near the silicon surface where all the action is, and a coarse one for the glass where nothing happens. Then I wrote one function that builds the whole sandwich. I wrote every test before the code. This kind of maths loves to give you wrong answers that look perfectly reasonable, so I only trust it when it matches something I can work out on paper. I’m happy that the “flatband” voltage came out exact to 15 decimal places. The threshold voltage matched the textbook to 0.13 millivolts, 50 times better than I needed. I also identified a few problems; the solver was getting slower and slower at high voltage, then giving up. The starting guess was asking “what makes glass electrically neutral?”, a meaningless question, since glass has no charges. I gave it a proper answer instead and the slowdown vanished completely. Then I deliberately broke my own code ten ways to check the tests would catch it. Nine got caught. One didn’t. Chasing that turned up a real bug: the bottom-contact voltage setting was silently doing nothing. One line to fix. Current Position: 1339 tests passing, everything clean, C-V curve working across all three regimes."}]...
|
Title: DDSim by @yaasshh | Stardance
Devlogs:
DDS Title: DDSim by @yaasshh | Stardance
Devlogs:
DDSim Devlog I’m building a chip simulator from scratch. Today I got it to simulate a MOS capacitor, a silicon slab with a thin glass layer and a metal plate on top. It’s the heart of every transistor ever made. What I built: I stacked two grids together: a fine one near the silicon surface where all the action is, and a coarse one for the glass where nothing happens. Then I wrote one function that builds the whole sandwich. I wrote every test before the code. This kind of maths loves to give you wrong answers that look perfectly reasonable, so I only trust it when it matches something I can work out on paper. I’m happy that the “flatband” voltage came out exact to 15 decimal places. The threshold voltage matched the textbook to 0.13 millivolts, 50 times better than I needed. I also identified a few problems; the solver was getting slower and slower at high voltage, then giving up. The starting guess was asking “what makes glass electrically neutral?”, a meaningless question, since glass has no charges. I gave it a proper answer instead and the slowdown vanished completely. Then I deliberately broke my own code ten ways to check the tests would catch it. Nine got caught. One didn’t. Chasing that turned up a real bug: the bottom-contact voltage setting was silently doing nothing. One line to fix. Current Position: 1339 tests passing, everything clean, C-V curve working across all three regimes.
Devlog #2 Two things this stretch, and both started as “that’s odd” rather than “that’s broken.” First, the solver was crawling. Every step up in voltage cost more than the last, and past a point it just gave up. I traced it back to the starting guess, which was asking what makes glass electrically neutral. That question has no answer, because glass has no charges to balance in the first place. The solver was grinding away at something stupid before it ever got to the real problem. I gave it a proper starting answer instead, and the slowdown disappeared entirely. Second, I stopped trusting my tests and went to check them. I broke my own code ten different ways on purpose, one at a time, and watched to see which breakages the suite would catch. 9/10 failed, which is what I wanted. 1 slipped through clean, and that is the interesting one, because a test that cannot fail is not a test. Chasing the one that got away turned up a real bug hiding underneath it. Setting the voltage on the bottom contact was silently doing nothing at all. The code ran, reported success, and ignored the value. One line to fix, and it would have been very hard to find any other way, since nothing about the output looked wrong. Heads up! Light AI usage to debug the tests and break code to find errors
Dev log #3 I found a bug that made every 2D current in the simulator wrong by a factor of about 245, WAY too big. The cause, i believe, was one missing conversion. The code turns an internal number into a real current, and in 2D that conversion needs an extra length factor that I never included. In 1D it happened to be right, which is why it went un-noticed. I fixed it and then wrote a test that compares a 2D current against Ohm’s law, worked out by hand with no solver involved. This test was missing before. The reassuring part: I measure the turn-on voltage two completely different ways. They used to differ by 180 mV, which I didnt pay much attention to previously. After the fix they agree to about 2 mV. I did not tune anything to make that happen, so I might have to start believing in miracles. I also fixed two divide-by-zero crashes in the surface mobility code that were blocking a whole test combination. Also updated the README numbers and the decisions log. The full test suite is still running, and I will push to github once done.
Dev log #4 After the last devlog I pushed and CI went red on all three Python versions. One test, one solver that would not converge. I guessed this before and fixed the wrong line. Last time I saw the residual and assumed a gate step was missing the convergence basin, so I put continuation on the gate ramp. That was a real improvement, just not this bug. This time I actually read the CI log The failing solve was the one before the ramp even starts. Gate at zero, drain already at 1 V, starting from a cold guess. So I measured it instead of guessing. Cold at 0 V drain takes 1 step. At 1 V it takes 22, and 12 of those get clipped by the step limiter, which means the solver is being dragged the whole way instead of converging properly The fix walks the bias in from zero using the continuation I already had. I regenerated the whole roll-off table through the new path and every digit came out identical. Only the path changed, not the answer. Also added the Open-Source MIT license, and cleaned the commit history.
Devlog #5 Since the license was added, all my time has gone into one stubborn thing, that is getting DEVSIM simulator, to produce trustworthy MOSFET curves. It has been a long journey of small lies the application tells you. DEVSIM’s solve doesn’t take a device argument, so it solves everything you’ve ever built in that process at once. I was building one device per curve and leaving them around, so the second curve was dragging a finished device along with it and ruining the shared error check. Deleting each device when its curve finishes fixed a whole family of weird failures. Then I found the equilibrium solve was starting from all zeros, which on this device is 0.6 V off. I supply it from charge neutrality now. Same final output but far less trouble getting there. 2 of my own ideas turned out wrong and got reverted, but I wrote the measurements rather than dropping them. Capping the solver’s pass budget moved the current by 0.4%. Pinning the math library to one thread made a four second step take three minutes. Big Ouch. Currently, the 1 micron transfer curve at 50 mV of drain runs end to end and confirms with my simulator to within 0.23% above threshold. The 1 V curve still stalls at 0.4 V of gate, and I checked it properly rather than simply loosening the tolerance, because it turns out DEVSIM isn’t converging there at all. My own code, for contrast, does the same curve in 4.6 seconds.
Devlog #6 Im not going to say much this devlog. I hate Github CI errors with a passion and everybody that creates software relates.
Devlog #7 Since my last devlog I have been teaching DEVSIM to run the same physics my own solver runs. Before this it was on a stripped down model set, so the two codes had similar geometry and nothing about mobility. Now it runs the real thing: doping dependent mobility, surface scattering at the oxide, velocity saturation, and proper Fermi-Dirac statistics. Getting there meant three more small lies. DEVSIM will easily chain a derivative through one kind of model and silently return zero for another. No error, no warning. My solver just diverged on the first step. It took a dump of every derivative on the device to see a column of exact zeros where numbers should have been. Then a field magnitude written as a square root of a square. Mathematically, sounds good but numerically it produces a nan wherever the field is exactly zero, which in a neutral chunk of silicon is nearly every edge. Then the surface mobility. I was refreshing it on every pass, forever. That is not a converging loop, that is two numbers chasing each other. The gate walk climbed to 0.50 V and then refused 0.55 V at every step size I gave it, down to a tenth of a millivolt. A failure that ignores step size is not a step size problem. I gave the refresh a stopping rule and re-ran it. Same answer to the last digit, just reachable now. The 1 micron device now agrees between the two codes to under 3.3 percent at low drain and under 1.3 percent at high drain, across four decades of current. The remaining blocker is not code. My browser is holding 15 of the machine’s 16 GB.
Devlog #8 Really tired today. Just ran a bunch of tests today and got a bunch of values ill sort through tomorrow.
Devlog #9 Since my last devlog, my solver and DEVSIM have started to cooperate. All ten benchmark devices match, the MOSFETs included, so the physics phase is done. THANK THE LORD Now I’m working on the part I care about most personally, which is making the simulator teach. The browser used to be a wall of knobs and plots with no explanation. Now every knob and every plot has a small “i” button. Click it and a drawer slides out with a plain explanation first, then the real equations for anyone who wants to go deeper. I wrote 35 of these explanations covering the physics, how the solver works, the devices, and how to read each plot. Then I checked them against the code. One credited the diodes with an accuracy number that actually belonged to a different device. Another claimed that one failed point in a sweep doesn’t ruin the rest, but the code stops at the first failure. The equations turned out to be hard to figure. The markdown reader treated the backslashes inside the math as its own escape characters and deleted them, so 92 bits of spacing and notation came out messed up. Now I pull the math out before the markdown step and put it back after. I also bundled the math and markdown libraries into the project, so the page works with no internet. Next up are band diagrams, which show the energy levels electrons can sit at. The page will draw them straight from the solved device.
Devlog #10 Since the last devlog, the simulator has gone from explaining things to letting you play with them. First, you can now compare runs. Every time you solve, the curve stays on the plot, so you can change one thing and see exactly what moved. The diode also got live sliders. Drag the doping or voltage and the answer updates while you drag. The 2D devices like the MOSFET are too slow for that, so I added a quick mode that uses a rougher grid. It’s a little less accurate, and I wrote down exactly how much. Then I built five guided lessons: a diode sitting at rest, a diode with voltage on it, a MOS capacitor, a transistor turning on, and what goes wrong when transistors get really small. Each lesson walks you through experiments step by step. The important part is that every claim a lesson makes is checked by a test against the solver I developed as part of the project. For example: if a lesson says “the current goes up,” a test runs it and makes sure it actually does. The biggest addition is a device builder. You stack layers of doped silicon however you want, and the simulator solves whatever you made. You can also save a design and load it again later. I agree I used AI for the frontend but I did not go VERY heavy on it. Only to build upon the frontend base I coded
Devlog #11 Since the last devlog, you can draw your own 2D devices, not just stack layers in a line. You draw rectangles of silicon and oxide, paint doping onto them, and place metal contacts along the edges. The simulator builds a grid that fits your drawing and solves it. Before it solves, it checks for mistakes and tells you what’s wrong in plain words: a piece of silicon with no contact touching it, a gate sitting right on silicon, or a shape too small for the grid to see. To make sure drawing works, I redrew the MOS capacitor and the transistor I already had and checked that they give the same answers. The capacitor matched almost exactly and the transistor was within about 1%. Testing it in a real browser caught two bugs. One made every solve hang forever. The other made the picture of the device grow every time it redrew on high resolution screens. Both seem to be fixed now but I’ll be on the lookout for similar bugs. Then I tried something new, a transistor sitting on a layer of oxide, the way a lot of modern chips are built. It won’t solve yet. I narrowed it down to the oxide underneath the silicon, and I’m still wondering how breaks things. More on that next time. random picture cause im too lazy to start the servers again
Devlog #12 Last time I left off with a transistor sitting on oxide that would not solve. I think ive fixed it. The silicon body had no contact touching it anywhere, so the solver had no idea what voltage that body should sit at. There is no single right answer, so it just wanders. That is not a bug I can fix, it is the physics of the thing, so now the simulator refuses that drawing up front and says why instead of grinding away at it. Then I went hunting for every other way someone could break it. I wrote something that tries every combination of settings the page can send and watched what fell over. A few things did: A gate metal with a work function no real metal has. Surface scattering asked for on a 1D device, which has no surface to scatter off. A shape so thin the grid ends up dividing by zero. All of them now get refused before the solve starts, with a sentence saying what to change. A few smaller ones. The device picture was drawn half a grid cell off, which threw off the line you drag across it to read values. That same line returned nothing at all where silicon meets oxide. And the explanations could load out of order and show you the wrong one. I think now i should wrap the version 1 of the project and finish polishing the frontend considering stardance is getting over soon. another lazy code pic btw cause i dont wanna open the servers again
Devlog #13 This one is all about the page itself. The physics didn’t change, but you’ll notice everything else did. I rebuilt the whole look from scratch. The old version was only friendly if you already knew semiconductors, and I want someone who has never heard of a diode to open it and get somewhere. Now it opens by asking you to pick a device: a diode, a MOS capacitor, a transistor, or draw your own. Each one comes with a sentence or two on what it is. Every number and switch has a little “i” next to it that explains it, and an empty plot tells you what it’s waiting for instead of sitting blank. Drawing your own device used to happen in a tiny box off to the side. Now it gets the whole screen. Some layers are so thin they basically disappeared, so I stretch the picture up and down until you can see them, and a label says when it’s stretched. Doped areas get a soft color so you can tell them apart. I also changed the font a couple of times. It started in a terminal style that felt cold. I tried one replacement and ended on Poppins, which just feels warmer. My favorite change is in the runs panel. It used to list your old runs as text, like “doping 1e17.” Now every solve saves a little picture of its own curve, and they all share the same scale, so you can see at a glance how each change moved the result. I switched the license to CC BY-NC so that it still stays technically open source but I own intellectual property for commercial use. Anyone can use it and change it for free, as long as they credit me and don’t sell it. A bit of AI usage in the frontend i will agree but not overkill in terms of it.
Devlog #14 Since then, most of my work has been getting DDSim ready for other people to use. First I cleaned up the controls. Some sliders and number boxes let you pick values that made the solver fail, which just showed up as a red error. I went through the diode, the MOS capacitor, the transistor and the draw-your-own device and found the range where each setting actually works. The sliders now stay inside those ranges, so a beginner can’t break things by accident. Then I cleaned up the code. I deleted about 2,400 lines of comments that just repeated what the code already said and kept the ones that explain something nessessary. Next came the writing. The site has about 40 short articles that explain the physics, and a lot of them sounded stiff, so I rewrote all of them. I did the same for the project docs, and on the way I found a few places where the docs no longer matched what the code does, so I fixed those too. Now I’m working on putting it online. I picked Fly.io to host it, and I’m hoping to get a free custom name. Since anyone will be able to use it, I’m adding some safety limits first. Only a couple of solves can run at the same time, old results get cleared out after a while, and a solve that runs too long gets stopped with a message explaining why. I tested each limit by breaking it on purpose to make sure the test catches it. It isn’t live yet, but it’s close! [lazy pic, i dont wanna open server again :( ]
Devlog #15 DDSim is FINALLY deployed and live! You can try it at ddsim.fly.dev Getting it online took one extra step. The cheap shared server was too slow: the hardest transistor solve takes about 50 seconds on my laptop and would have taken around 7 minutes there. That’s past the 5-minute limit I set, so it would have been stopped every time. I moved it to a faster server, and now it finishes in under a minute. Once it was up, I found a bug. When every contact on a transistor was at the same voltage, the picture still drew current flowing through it. That’s impossible, because with no voltage difference nothing moves. I fixed it, and now the page says “no current flows” instead of showing an empty plot with no explanation. Then I rewrote the README from scratch. The old one was over 500 lines and way too dense. The new one is about 200 lines, mostly screenshots from the live site plus a few tables, so someone can see what the project does in a couple of minutes. While doing that, I caught a mistake. One number in my results table didn’t match the graph right next to it. I reran the full simulation, which took 20 minutes, and fixed the table so it matches. Last, I took the deployment files out of the public code. Anyone who downloads it gets everything they need to run it on their own computer, but not the setup for putting it online. Next up, I might be thinking of getting a custom name for this simulator and my other atom simulator. If anyone knows where I can get free domains, lmk in the comments
Devlog #16 Now that DDSim is live, my next goal is to make it better than DEVSIM, a free, open-source simulator a lot of people already use. “Better” doesn’t count unless I can measure it, so I planned out the next 11 stages of the project, and the first one is a scoreboard. The scoreboard runs both simulators on the same set of devices and compares them in four ways: how often each one finishes a solve without crashing, how accurate the answers are, how fast they run, and what each one can do at all. Some of these runs take hours, and my laptop ran out of memory partway through, so I paused them. I’ll post the results once they’re done, even the parts where DEVSIM is better than mine. While building the accuracy check, I found a bug in my own math. Sometimes it reported numbers that didn’t make physical sense, so now it throws those out instead of trusting them. I also went through all the style files for the website. They’re about a third smaller now, and I checked that the page still looks exactly the same. Then I found a small bug that had been there all along. The little “i” buttons that explain each setting were supposed to turn blue when you hover over them, but a different style rule was overriding it. Last, I cleaned up the README again. The pictures are centered now, I took out the GIF, and I rewrote some of the text so it reads more naturally.
Devlog #17 I restarted the scoreboard runs, and before looking/mentioning any of the results I checked my own setup for DEVSIM. That showed a few bugs on my side. My starting guess for the voltage inside the device did a log of zero on heavily doped chips, so DEVSIM crashed INSTANTLY. I also wasn’t giving it enough steps to settle on some devices. I fixed both, because it wouldn’t be fair to count my mistakes as DEVSIM’s. I also cleaned up the code, I tried to ship all progress so far but there was just too much AI (guilty) so I am working on redoing the python, css and javascript code again mainly from scratch. (The image shows all the values from the DDSim tests)
Devlog #18 The robustness runs are almost done. Robustness checks a simple concept, if I give the solver a device cold, with no warm-up, does it actually finish? I ran 200 test cases through my solver and through DEVSIM, each in a few different setups. The robustness numbers aren’t final yet. One DEVSIM result is still missing. The first time my laptop ran out of memory, and the second time it went to sleep overnight, so it’s running again now. I also found out DEVSIM acts much differently depending on how many CPU threads it gets. With only one, some solves failed or took forever which was kinda interesting to see. On the cleanup side, I turned on the strictest type checking across the whole project and fixed what it found. Every color on the website now comes from one file. I also deleted a bunch of old files nobody used and cut the README down.
Devlog #19 The speed and robustness numbers are now saved on the scoreboard. On the first 8 benchmarks, my solver takes about 1.6x less time per bias point than DEVSIM. I also added a test that reads the README and fails if the README claims anything the data doesn’t back up (I hate getting 100% vibe code assumptions on my readme btw). I renamed a lot of variables across the code (to pass the 30% ai rule that im apparently violating) to shorter names. That kind of change can break the tests if some of the variables reference each other across multiple files, so I checked that python turns the old code and the new code into exactly the same instructions. Thankfully it did. I also moved all the settings into one file. Things like how many tries the solver gets, how small the mesh can get, and the server limits used to be scattered across about 20 files. I checked that every single value stayed exactly the same after the move. I also deleted the last few leftover comments. Then I pushed everything. The tests ran on three Python versions, and 2,723 of 2,724 passed. The one that failed was a browser test on Python 3.11 that waited too long for the page to load. The same test passed on the other two versions, so it’s probably just a slow test machine, but I’m going to rerun it to make sure. My laptop ran out of memory again, which stopped me from finishing the type hints in the tests. That’s next, once I’m not running a bunch of other stuff at the same time.
Devlog #20 In this devlog i firstly fixed up the website. It now has a little icon in the browser tab, a terms page, a privacy page and a footer with a contact button. The icon didn’t show up on the live site at first, so I fixed that too. Then I started the next phase, which is all about fixing temperature related stuff. A lot of the calculations of the simulator took room temperature which might have led to some wrong calculations, so I’ve been fixing that. The gate’s energy level was stuck at its room-temperature value. it was a real bug and its fixed now. When the silicon gets hotter, electrons now max out at a lower speed, just like in real-life chips. From 250 to 400 K, the junction’s built-in voltage matches the textbook formula. From 300 to 400 K, the diode’s leakage current stays within 0.3% of the formula. I also added a fixed charge that sits where the silicon meets the oxide layer. Real chips always have some, and it changes the voltage where a transistor turns on. Next up are the big jobs. A long DEVSIM run is still going, and after that I’ll test the temperature effects on a full 2D transistor. I also still need to put the website changes live.
Devlog #21 Since the last devlog I finished most of the temperature phases. First I compared the diode at 400 K against DEVSIM. I saved that result so my other tests compare with it from now on. Then I added two new sliders to the website. One sets the temperature, from 200 to 500 K. The other sets the fixed charge where the silicon meets the oxide. I picked both ranges by running the simulator across them. Each slider also has a short lesson that explains what it does. While I was writing those, I found some broken math formatting in the temperature lesson and fixed it. The biggest addition is freeze-out. To make silicon conduct, we add extra atoms that give up electrons. When it gets really cold, those atoms stop giving up their electrons. Before, my simulator assumed they always did. Now there’s a switch for it, and it works. At 100, 200 and 300 K it matches the textbook formula almost exactly. I also checked that a plain frozen silicon bar still follows Ohm’s law, and that the capacitance results still work at 150 K.
Devlog #22 The long DEVSIM run finally finished. It took about 6 hours and matched the expert result almost exactly, which closes out the scoreboard phase. Then I started the next phase, which is about AC. That essentially means wiggling the voltage back and forth and watching how the device reacts at different speeds. Before, my simulator could only handle super slow wiggles, or fast ones where I froze some electrons by hand. Now it can handle any speed. To get there, I first taught the simulator how fast electrons and holes pile up or drain away over time. Then I wrote the part that works out how much current flows into each contact when one of them gets wiggled. I tested it on diodes, since they have textbook formulas to compare against. A long diode matched within about 1%, and a short one within 1.3%. Along the way I found a bug where my mesh maker gave up on very long devices, so I fixed that too. The MOS capacitor is giving me some trouble. At really slow wiggles, the math needs more precision than normal computer numbers have, so the answers came out wrong by up to 46%. Fast wiggles work fine. Right now I’m trying a trick where I make the electrons react faster, so the slow case happens at a speed the computer can handle. Below are some of the DEVSIM scoreboard values
Devlog #23 The trick for the MOS capacitor worked. Making the electrons react faster put the slow wiggles at a speed the computer can handle, and the answers came out right. That FINALLY finished the AC phase. I also added noise, a tiny random jitter in current that every device has. Next I added time. Now its possible to flip a diode from on to off and watch it recover. When you switch a diode off, it keeps conducting for a moment because of all the charge stored inside it. I compared that against DEVSIM, and our results were within 0.03% of each other which is quite frankly something im really proud off. Then I added a feature where the simulator shows how inaccurate it may be. It now checks its own answer against a finer mesh and puts a little error bar on every point in the plots. It can also improve its own mesh by adding points only where they’re needed. On 5 of my 8 test devices it hit the target accuracy with fewer points than my hand-made meshes. I was aiming for around 6, so that’s still doable. The newest addition is a bipolar transistor, where a small current into the middle layer controls a much bigger current through the whole device. I built a simple 1D version and a more realistic 2D one. The 1D version matches the textbook formula to within 0.03%. The best part is that its gain drops off at both very low and very high current, the way real transistors do, and I never told it to. It figured that out from the physics.
Ships:
I built DDSim, a program that simulates what happens inside the tiny parts that computer chips are made of, ie diodes, capacitors and transistors. You describe a device by its shape and which parts of the silicon have extra electrons or holes. DDSim then works out how those electrons and holes move, and draws the current and voltage curves. I didn’t fit anything to make the graphs look right. Everything comes straight from the physics equations. (NOTE: ITS STILL VERY CLUNKY SO ITS NOT GOING TO BE PERFECT AS OF RIGHT NOW. IF YOU FACE ANY TROUBLES IM REALLY SORRY) To make sure everything accurate, I checked it against textbook formulas and against DEVSIM, a simulator other people wrote. They agree to within a few percent, and the project has about 2,700 automated tests. You can try it in your browser at ddsim.fly.dev. Pick a device, press solve, and watch the answer draw itself. Every button and graph has a little “i” that explains what it means, and there are guided lessons if you’re new to this. It’s a school-level instrument, not a chip design tool. Below about 50 nanometers the physics it uses stops being accurate, so I didn’t go beyond that...
|
1793004958.5938606
|
1793091358.5938606
|
|
20724
|
CRM by @F3rro_32 | Stardance
|
F3rro_32
|
1
|
124.74
|
0
|
[{"ship_num": 1, "ts": "2026-1 [{"ship_num": 1, "ts": "2026-10-14T16:34:42Z", "hours": 115.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "CRM An open-source CRM for Italian small businesses: contacts, companies, leads, quotes, orders, invoices with VAT, tickets, email campaigns, NPS surveys, reports and a customer portal. It started as a way to manage clients for a friend’s startup and became a working and valuable project. TRY IT (no install) https://crm.alessio.hackclub.app email: [email protected] password: HackClub-Demo-2026! The demo has full access and realistic fake data, so feel free to click everything, create, edit and delete. The data resets occasionally. Outgoing email is switched off on the demo. HEADS UP: the interface is in Italian. Use the translate widget in the corner of the app (or your browser’s translator) to read it in English. Real i18n is on my roadmap, sorry! WHAT TO LOOK AT A quote with line items, discounts and VAT by rate, and the “Print PDF” button. PDFs come from HTML templates you can edit, with a live preview on your last real document. A customer accepting a quote from a signed link, without an account. Full-text search across every module (PostgreSQL). Italian e-invoicing: it builds the FatturaPA XML and validates it against the official government XSD before saving. Invoices lock once sent to the SDI. The MCP server: an AI assistant can use the CRM through an API key, with seven generic tools that work on all 34 modules and respect permissions. 2FA (TOTP) with recovery codes, secrets encrypted at rest, installable PWA. HOW IT WORKS There is no “contacts” or “companies” table. One generic Record entity stores its fields in a jsonb column, and an ObjectType + FieldDef describe each module (39 field types). Adding a module is a configuration record, not a migration or a new controller. Permissions are checked per module and action at runtime. You can have more info in the README, so please check it. I hope you appreciate this project :)", "repo": "https://github.com/AlessioFerrari8/crm", "demo": "https://crm.alessio.hackclub.app"}]...
|
[{"post_id": 81469, "ts": "202 [{"post_id": 81469, "ts": "2026-10-21T11:47:01Z", "hours": 9.7417, "text": "Hey guys, what’s up? I’m finally in the last phase of getting my driving license, so that’s taking up some of my time too. The CRM is now online at crm.alessio.hackclub.app . The VPS has very little RAM, so I build the Docker images locally and transfer them to the server using docker save over SSH. It’s not the fanciest deployment process, but it works with the resources I have, so I’ll stick to it for now. One of the main things I worked on was the customer portal . The backend from last week finally has a frontend: customers can log in, see their tickets and documents, open requests, reply to messages, download PDFs and accept quotes. I also made sure that internal notes stay internal. Notes now have a Visible to customer checkbox, which is disabled by default. The portal only shows notes explicitly marked as visible, so there’s less risk of accidentally exposing something that should stay private. Another feature I added is Google Calendar import . It’s read-only for now, so the CRM can import events without modifying anything in your Google account. Events are created through the same service as normal CRM records, meaning workflows and the audit log still work as expected. Sync runs every 15 minutes, and if something goes wrong with an account, it won’t stop the others from syncing. I also started replacing the Google Translate workaround with proper internationalization (i18n). The translation system is in place, including support for parameters and locale-aware dates and numbers. The dictionary is type-checked, too, so missing English translations can be caught at compile time. There’s still a lot of work here: around 1,200 strings need to be translated by hand. It’s not the most exciting task, but I’d rather have proper translations than rely on Google Translate forever. Obviously that’s my opionion. I also started working on public registration, but it’s not ready yet. There’s one important limitation: the CRM currently has a single shared workspace, so everyone who registers would see the same data. Registration will stay disabled unless explicitly enabled until I decide how to handle that properly. That’s because the idea is to have 1 single DB for each workspace, since the CRM should be self-hosted. There’s still work to do, but the CRM is getting closer to the version I wanted to ship. See you in the next devlog!"}, {"post_id": 79560, "ts": "2026-10-14T16:31:36Z", "hours": 2.4331, "text": "Hey guys, how’s going? This will be a short devlog, and it’s the one before the shipping. I decided to ship the CRM, even if it’s not completely finished. That’s because I still have to do lots of things, but now I have a working product, so, since the changes I have to make are complementary. Unfortunately, I have a big issue: the whole interface is in Italian. The app is made for Italian small businesses (FatturaPA, VAT, SDI…), but if you come from Stardance you can’t read a single menu. Real i18n is still on my list and it is a big job, so for now I added the Google Translate widget in the corner of the app. If your browser is in English it starts translating by itself, otherwise you pick English from the selector. It’s not pretty, but it makes the demo usable today instead of “someday”. I had to widen the CSP in nginx for it, and I loaded the script as an external file so I didn’t need a second hash. I also fixed the README and cleaned the repo. Now everything should work fine, or at least let’s hope so. I hope you enjoy the product."}, {"post_id": 78818, "ts": "2026-10-11T17:58:49Z", "hours": 8.3728, "text": "Hey guys, how’s everythings going? I’m doing pretty well. As always I have lots of things to do, but I still have plenty of time for coding. School is demanding, and preparing for my driving license is also tough, but I’m managing everything little by little. Last time I ended up with an app that wouldn’t even start. Luckily, I fixed all those errors, and all 258 tests are now green and passing on the PostgreSQL db. After that, I added new features. First of all I worked on NPS surveys and quote acceptance. Customers can now receive surveys and answer them through a public link. They can also accept quotes directly from a link, without needing an account. I also made sure these features work with the existing workflows, so automations can still do their job properly. Another interesting addition is the MCP server. AI agents can now interact with the CRM through an API key. Instead of creating a separate set of tools for every module, I went with seven generic tools that can work across all 34 modules. This should make it easier for AI models to understand which actions they can perform, while keeping the CRM’s existing permissions and security rules in place. I also improved search quite a bit. Before, it mostly looked at record titles. Now it uses PostgreSQL full-text search to find relevant information inside the actual record data and rank the results. The audit history is also much easier to read, with related record IDs replaced by their actual titles. I worked on a couple of smaller but important things, too. The trash can now properly handle related files and records when permanently deleting something, while protecting fiscal documents that must be kept for ten years. Finally, I started working on the customer portal. It now has its own backend authentication and permission system, separate from the employee login. Customers will only be able to access records they’re actually allowed to see. The backend is ready, but I still need to connect the frontend pages and routes. There’s still quite a bit to do, but I’m getting closer to the first complete version of the CRM. See you in the next devlog!"}, {"post_id": 77578, "ts": "2026-10-07T15:01:58Z", "hours": 9.0769, "text": "Hey guys, how’s going? I have plenty of things to do, but coding is still one of my favorite activities, so I always try to save some time for it.This time I worked again on FatturaPA, which is the Italian electronic invoice.What I did, is that now, first of all, the CRM can now generate the FatturaPa XML directly from an invoice and validate it against the official XSD, before saving it. I also added the whole invoice lifecycle, from draft, to setn, delivered, accepted or rejected. The CRM can read the recepits from the SDI and show ufseful information when something goes wrong.Another important change is that invoices now become locked once they’re sent to the SDI. If something needs to be changed, the correct way is to create a credit note instead. This is much efficient in my opinion.I also started working on the SDI integration itself. For now there’s only a manual transport, but the system is built so that adding an actual provider later shouldn’t require changing the rest of the CRM. I did it this way, so I can decide which provider use, and not have to change everything.Besides invoicing, I added time tracking. You can start a timer from the top bar and see your hours directly on records. Timers also automatically close after a maximum amount of time, so nobody ends up with a 80-hour ticket because they forgot to stop it.Finally, I worked on email campaigns. You can create a campaign from a saved filter, send emails through a queue and manage unsubscribes. I also added some protections against things like open redirects and accidental unsubscribes.And now, the honest part: before writing this devlog, I ran the tests and guess what, the app didn’t even start.I used claude for debugging, cause I wans’t finding the error. Silly me, it was just a typo."}, {"post_id": 75572, "ts": "2026-09-30T13:58:27Z", "hours": 10.0467, "text": "Hey guys, how’s everything going? I’m alright. I’m so glad hackclub postponed the end of stardance, I have still another month to 1. finish this project 2. do other projects I had on my mind for such a long time. Before doing this devlog, I had to use claude to debug my work, because I had some errors I didn’t understand (I was using a class created for a test in the normal “code”), so bad :( and also other small issues. Lately I worked on one of the most significat features for me, which is 2FA . As my network teacher says \"zero trust, because the world is a place full of bastards\" . 2FA is one of the techniques I use to follow this approach. Basically, now you can press “Enable” in your preferences, scan the QR code with any authenticator app (f.e google), or just type the secret by hand, because half the people can’t frame a QR code at the first time, lol. You also have to confirm with a code. At login, if 2FA is on, there’s a second step for the six digits. You also get ten recovery codes that you can copy or download, shown only once. Turning it off asks for your password, so a stolen open session can’t remove this precaution. You’re probably wondering: are the secrets encrypted? Yes, they are. I mostly use AES-GCM, because it’s pretty simple, but also secure, so it’s the better compromise. The TOTP secret and the mailbox passwords are stored encrypted with AES-GCM. The key lives in an env variable, not in the db, so a database dump alone isn’t enough to generate codes or read someone’s email. I also turned the crm in a PWA . You can install it on your phone or desktop, it has its own icon and window, and when I deploy a new verion, it tells you to reload, instead of silently serving you the old one from cache (it also checks every 6 hours, maybe I’m gonna change it to 10, idk, for the tab you leave open for days) Like in every other devlog, I made some tests and updated the docs. The report engine now has tests against a real Postgres started in docker, and the repo finally has a real README (it’s not finished, just with some basic information, claude, thanks for the suggestion of making it). Oh, I nearly forgot. I also worked on emails. Now I’m currently working on the Italian electronic invoice, which is called FatturaPA. The crm builds the XML from an invoice, and the first test I wrote checks it against the official government XSD: if it doesn’t pass, it isn’t saved. I think I’m gonna study a bit of english / american law, to allow people out of Italy to use this app as well. I hope you like my product, see you soon"}, {"post_id": 71912, "ts": "2026-09-21T19:15:14Z", "hours": 9.0044, "text": "Hey guys, how have you been doing lately? I’m alright. I’m still getting my driver license, so I don’t have much time to code. Last devlog was all about the PDF engine on the backend, and I closed it saying that the UI was next. Here it is: Print button : I added a print button Print PDF on quotes, orders, delivery notes and invoices. The file is downloaded with the document number as its name, so you get for example 2025-47.pdf and not just document.pdf Template editor : I also added to settings a new tab called “Print”. On the left there’s the list of templates, on the right the HTML, the page size and the margin. The preview renders the last real document of that module instead of a fake one, so what you can see is exactly what your customer receives. The default templates can’t be edited you duplicate them: the seeder rewrites them at every boot, so any change would silently disapper on the next restart. I preferred to say it in the interface rather than let someoune lose an afternoon of work. Company data : The company settings now hold also the legal name, VAT number, tax code, address and contact line. That’s what the PDF header prints, and without them the header comes out empty. VAT that adds up to the cent The header discount is spread across the VAT rates and every share gets rounded, so the sum of the shares could end up one or two cents away from the total. On a quote nobody would ever notice. On an electronic invoice it’s rejection 00423. Now the rounding leftover goes on the last rate, so taxable + VAT = total, always. Tests on a real db : The report engine builds SQL at runtime, and mocking a database proves nothing, so its tests now start a throwaway Postgres in Docker and run against it: filters, grouping, ordering and counting. Two bugs closed : Merging two records didn’t look at the bin, so a deleted record could be merged into a live one. And editing a saved report answered 405, because the frontend was sending PUT to an endpoint that only has POST. Right now I’m working on the 2FA (for those who don’t know, the 2 factor auth). I’m writing the TOTP myself instead of pulling in a library: it’s an HMAC-SHA1 of the 30 second counter, and the six digits come out of the dynamic truncation described in the RFC. The secret is encrypted in the database with AES-GCM, because someone who can read the db must not be able to generate the codes, otherwise a second factor is just a second password. There are ten recovery codes, stored hashed and usable once each, and the last accepted counter is saved, so the same code can’t be replayed during its 30 seconds. The tests are the official RFC 6238 vectors: a TOTP written at home always “works” until you compare it with a real auth app, and at that point it’s too late to find out. Two things I know are missing: the second factor has no interface yet, there’s no page to scan the QR code from, and the mailbox that turns incoming emails into tickets is only half written. See you soon, the end of this project is near."}, {"post_id": 67216, "ts": "2026-09-13T08:29:02Z", "hours": 8.6217, "text": "Hey guys, how’s it going? I hope you’re all doing well. School started here in Italy, so I have less time compared to August. I also have to get my driver’s license, so I’m studying for that too. Unfortunately, coding isn’t the first thing I do every day anymore. I’m still working on the PDF generator. Last time I mentioned that relation fields were showing raw IDs and that document totals weren’t formatted properly. I fixed both of those, but I’ll get back to them later. About the PDF The template is HTML, and it lives in the DB. I didn’t hardcode the layout in Java. I created a PdfTemplate entity that stores the HTML, page size and margins. There is one default template for each document type: quote, order, delivery note and invoice. Thymeleaf fills the template with the document data, and OpenHTMLToPDF + PDFBox generate the PDF. Since the HTML is provided by the user, I also had to think about security. A template could try to load something like file:///etc/passwd or access an internal URL. Because of this, external protocols are disabled and only data: URIs are allowed. Page sizes are also checked against a whitelist. I also had to deal with the fact that HTML isn’t always valid XML. OpenHTMLToPDF expects XML, so I use jsoup to normalize the HTML first. Otherwise, perfectly normal HTML can cause a SAXParseException . And finally, fonts have to be embedded in the PDF. Without including DejaVu Sans in the jar, the PDF doesn’t render correctly. VAT summary I also worked on the VAT summary. Lines are grouped by VAT rate, shipping is added to the highest rate, and the document discount is distributed across the rates instead of being applied at the end. VAT is then calculated on the discounted amounts, so everything adds up correctly: taxable + VAT = total This actually fixed a bug where VAT was calculated before applying the document discount. It wasn’t very obvious until I started testing it with real numbers. Three endpoints The PDF system now has three endpoints: print a document preview a template print a batch For the preview, instead of creating a fake document, I use the last real document of that module. This way there is only one PDF generation system to maintain. The batch endpoint combines multiple documents into one PDF, while checking permissions for every document. A few other fixes The two ugly things from last time are also gone. Relation titles are now resolved by a shared backend service, so instead of UUIDs you see things like the company name. The same service is used by the lists, detail pages and PDFs. Amounts in the PDF are also formatted using the user’s preferences. I also added tags to the record lists. Tags are resolved in bulk instead of doing a permission check for every single row, which makes a big difference on larger lists. The backend part is basically done for this cycle. The print button and template editor are already written, but they’re not wired up yet. Right now I’m still using the API to test the generator. So, UI is next. See you in the next devlog!"}, {"post_id": 63513, "ts": "2026-09-07T12:44:46Z", "hours": 6.7903, "text": "Hey guys, how’s going? Soon school is going to start for me, but luckily it’s my last year in high school, so I’m really happy about this. Lately I had much time to code, so I continued working on this project. Last devlog was all backend; I said the engine was there and the screens weren’t. This time it’s quite the opposite. I didn’t really touch the backend, I spent the last 5-6 hours writing the frontend. Here’s the details of what I did: Document lines the grid is finally in the record detail. You can add lines, set quantity, price, discount and VAT, additionaly with the subtotal / VAT / total block, that updates while you type. When you save, the whole set of lines is sent at once. Tags I added the tag picker on the record detail, so you can attach and remove tags from a record as you wish. I also made the page that shows every record with a given tag, from all the modules together. Duplicates The duplicate finder now has its own screen: you choose a module, you get the pairs it thinks are duplicates, and the you see the two records side by side and pick field by field which value to keep before merging them. Reports There’s a page to build a report with a wizard (rows, columns, metrics, filters) and a preview that shows you the result before saving it. Dashboard widgets This is the main thing of this cycle. I wrote all six widget types, which are: - KPI tile - split KPI tile - chart - table - pivot - record list A widget is just a saved report query plus the type of rendering you want, so it runs on the report engine. Dashboards with tabs You can create a dashboard, add tabs to it and put widgets inside, so you can keep for example sales and support separated from each other. Sidebar and topbar The sidebar now has the routes for all the new pages, and the topbar has a quick-create button to make a record from anywhere without opening its module first. Two things are still not nice and I’m aware: in some places the relation fields show the raw id instead of the name of the record, and the totals of the document lines are not formatted with the user preferences yet, so you read 9054.00 instead of 9.054,00 EUR. Both are small and both are on the list to be improved. Now I’m working on the PDF generator See you, I hope you enjoy this project"}, {"post_id": 59674, "ts": "2026-09-01T16:28:33Z", "hours": 8.095, "text": "Hey guys, how it’s going? These days I’ve got quite a lot of work to do, since we’re in the middle of harvest season here in Italy, so I don’t have much time to work on the project. Unfortunately, today it rains, so I’m home, and I can spend some time on the PC. Lately I’ve been working a lot on the backend. The first two things I did are documents and document numbering : I created the model for document rows ( DocumentLine ), with its engine to calculate totals, including subtotals, discounts and VAT. I also added unit tests for the calculator. I also implemented automatic document numbering, so documents like quotes, invoices and tickets are automatically assigned a number when they’re created. Then I worked on quote revisions, with a new QuoteRevisionService to keep track of different versions of the same quote. Another thing I started working on is document conversion. The idea is to be able to convert a quote into an invoice, but this part is still a work in progress. I also spent quite a bit of time on reports and dashboards: added the Report model and the ReportEngine / ’ReportService` added default reports through a ReportSeeder created the Dashboard model, with tabs and widgets added the related controllers, services and repositories On the frontend side I’ve scaffolded the pieces for dashboards and widgets — the widgets/ and dashboard-tabs/ components exist and the dashboard and report services are written — but the components themselves are still empty shells. The data layer is ready, the screens aren’t written yet. That’s what I’ll pick up next. Another big thing I worked on is tags and data quality. I added the tag model and APIs, together with the services and repositories. I also started working on a duplicate finder and record merging system, so duplicate contacts/companies can be detected and merged instead of leaving messy data around. For PostgreSQL, I also enabled pg_trgm to improve fuzzy searches for duplicate detection. Finally, I added user preferences for number and date formats, including a live preview so users can immediately see how their chosen formats will look in the app. I’ve also added icons for the new modules. As you can probably tell, this was a very backend-heavy cycle. Almost everything I built this time: document lines, numbering, quote revisions, reports, dashboards, tags and duplicate detection lives in the models and the services, and the UI for most of it isn’t there yet. So this time there isn’t much to show in screenshots: the engine is in place, the screens come next. I’d rather get the model right first and build the interface on top of something solid than the other way around. Hopefully I’ll be able to find some more time to work on it after harvest, so see you in a while."}, {"post_id": 45652, "ts": "2026-08-12T09:05:39Z", "hours": 4.9961, "text": "Hey guys, back on this project. Last time I said the next round was going to be document lines, my quote was “the only part of this CRM that doesn’t fit the dynamic JSON engine”. That’s what this round was, plus the report engine on top of it. Document Lines : One single table for all four documents: quote, sales order, delivery note, invoice. The line is exactly the samein all of them, the only thing that changes is the document holding it, and a document here is just a Record like any other, so there’s no type constraint on the line at all. A line can be a product line, a free text line (no amounts, just something to say in the middle of the document) or a subtotal. Two things get copied at save time: the description and the vat percentage. The math is its own class, DocumentLineCalculator, and it’s the one piece of this project I wanted testable completely on its own, because it’s the only place where a wrong rounding produces a wrong tax document. The order is fixed: gross = quantity × unit price discount = a percentage of the gross, or a flat amount net = gross - discount, rounded to 2 decimals here vat = net × rate, rounded line total = net + vat Rounding happens after the discount and after the vat, never on the unit price: round the unit price and the error gets multiplied by the quantity. Rounding mode is HALF_UP, which is the commercial rounding used here, not HALF_EVEN. And a flat discount bigger than the line itself gets clamped instead of producing a negative amount, since that’s a typo 100% of the time. Lines are always saved all together. The endpoint is a PUT that replaces the whole set. It deletes and rewrites instead of diffing row by row, because a document has a few dozen lines at most and the diff would cost more code than it’s worth. The reason for this rule is the totals: they depend on every line, so a partial save would leave the header and the lines disagreeing, even if only for a moment. The totals (subtotal, vatTotal, total) get written back into the document’s own JSON, plus the header level discount and shipping cost. They live there so they can be list columns you filter and sort on, which is the whole point of having them. Now I’m working on the dashboard graphs, widget and this kind of things.I hope you like the project. I’m sorry if I don’t have any screenshot of the working website, it’s because I focused only on the backend, the frontend of this part still needs to be written."}, {"post_id": 42597, "ts": "2026-08-07T12:41:14Z", "hours": 6.4236, "text": "Hey guys, still on this project. This round was all about the stuff that sits on top of the modules, instead of new modules. Per-user formatting preferences . There’s a new “My preferences” page in the user menu. Every user picks how they want to see numbers and dates: thousands separator, decimal separator, currency (any ISO code, the symbol gets resolved automatically), how many decimals, whether the symbol goes before or after the number, and whether to cut trailing zeros. Same thing for the date format. There’s a live preview box that updates while you touch the selects, so you see 1.234,50 € turn into $ 1,234.5 as you change this. The setting applies everywhere, lists, record details and so on. Tags . These are cross-module, which is the whole point; a tag can sit on a lead and on a ticket. There are two kinds: shared ones, visible to the whole workspace, and private ones, which only you see. Each one has a color. You can attach and detach them from any record, and there’s a “all records with this tag” view that goes across modules, filtered by your permissions, so if you can see tickets but not opportunities, you only get the tickets.I did not build this as a field type, even though I already have a TAGS one. That one belongs to a single ObjectType with its own fixed options, so it gives you neither the shared catalog nor the cross-module search. Duplicate merge . You pick a module and it gives you back the candidate pairs, ranked by how similar their titles are (there’s a threshold you can move, default 0.6). Then you get the two records side by side and choose, field by field, which value survives. When you confirm: the winner keeps everything you picked, every relation that pointed at the loser now points at the winner, ids of the loser mentioned inside other records get rewritten too, including the ones stored in lists, notes and tags move over (and if the winner already had that tag, the duplicate link is dropped), the loser goes to the trash, not deleted. A wrong merge has to be recoverable, and I already have a bin, so I used it. Document numbering . Documents now number themselves. It’s configurable per module: prefix, whether to include the year, padding, separator. Right now it’s on for three of them: - quotes → 2025-47 - invoices → FT2025-0001 - tickets → TT643 The counter is per module and per year, and it’s locked while it’s being read, so two people creating a quote at the same time can’t get the same number. If you type a number by hand, yours wins, that matters when you’re entering an old document with its original number. On top of that, quotes have revisions. Revising 2025-13 gives you 2025-13_2 , a brand new document that links back to its parent, while the parent moves to the “revised” stage. And you can revise a revision, so 2025-13_2_2 works too, the counter is progressive per parent, not global, which took a bit more care than I expected. Next up is the big one: document lines. Quote → order → delivery note → invoice, with quantities, discounts and VAT per line. It’s the only part of this CRM that doesn’t fit the dynamic JSON engine everything else is built on, so it gets its own real tables. See ya in the next devlog, I hope you like the project. P.S. you’ll see the tag in the next devlog, I still have to implement the frontend"}, {"post_id": 40187, "ts": "2026-08-03T16:19:02Z", "hours": 5.575, "text": "Hey guys, I’m still working on this project, cause there are lots of things to do.Lately I focused on improving and adding things to the ObjectTypes. As you can see in the two images of the sidebar, I added like 10 fields. Among them, the most important are goals , basically contains the possibility of creating a goal, setting an owner, which is responsible for this goal (clearly depends on the situation), the actual goal and the period. Along with that you can set a metric, so if the goal is revenue , opportunities , leads , custom project_task , basically it contains the instruction for each member, on a certain project service_contract , the support, it contains the subject, the company which is referred to, start and end date, the actual status, so active , expiring , expired , terminated , hours spent and so on. Along with these and the other I didn’t cite here, I added 3 object for the sales, where this two are the most important: The first one is the supplier , it contains all the specs, so name, vat, email, phone, website, address, and eventual notes. The second one, the most important, is sales_order , which contains the subject, the number of the order, a relation with the company, and a relation with the contact, a relation with the quote (I don’t know if it’s right, in italian it’s called preventivo), the possibility of setting a status, so created , confirmed , shipped , closed , cancelled , the order date, a relation with the payment Method object, and all the financial part, so the subtotal, with maybe the discount, vat, the total and the infos for the shipping, billing and shipping address. I hope to finish this project asap, since it’s taking me so looong.See ya in the next devlogs"}, {"post_id": 38868, "ts": "2026-08-01T13:05:15Z", "hours": 5.2586, "text": "Hey guys, I have stopped this project for a bit, but here I am again. I’m currently improving the CRM, mostly the security, which, for me, is one of the most important parts, and adding functionalities. Lately I focused on the mails. I added my smtp server, and in the backend, I managed all mails. Here is an example, with the invitation email. It’s in italian, but don’t worry, basically it invites you to the CRM, and then you can create your own account, with password. As you can see in the third screenshot, I can manage the invitation link, whether I want to invite an admin, or a simple employee."}, {"post_id": 26409, "ts": "2026-07-11T05:54:20Z", "hours": 10.4239, "text": "Hey guys, this week was also about making the CRM feel more complete. Alongside several new features, I also spent a good amount of time improving security and fixing one particularly deceptive bug. First of all, I added a new global Calendar page that shows every record with a date in one monthly view. Events, tasks, reminders and subscription renewals are all displayed together, each with its own color. Before this, the calendar only existed inside each record type, so there wasn’t a way to see everything happening at once. I also integrated Cal.com. The booking page can now be embedded directly inside the CRM, and when someone books a meeting, a webhook automatically creates an Event record. If the meeting is rescheduled, the existing record is updated instead of creating a duplicate, and if it’s cancelled, the event is removed. To keep the integration secure, the webhook signature is verified using the raw request body instead of reserializing the JSON. I spent some time looking at features from Pipedrive, HubSpot and Attio, then implemented a few that I really liked. The Kanban board now shows the total value of each column, making it easy to see how much every stage of the pipeline is worth. I also added rotting, which highlights cards that haven’t been updated for more than two weeks so forgotten leads are easier to spot. Another big addition is public forms. Every record type can now expose a public form that can be shared with a link or embedded into any website. When someone submits it, a new record is created automatically and any related workflows are triggered. The feature also includes a honeypot for bots and per-IP rate limiting. Finally, I added a Trash Bin, allowing users to restore accidentally deleted records with a single click. I also added the ability to assign an owner directly from the record page. Passwords now follow the same rules everywhere in the application: at least 8 characters one uppercase letter one lowercase letter one number one special character. The backend enforces the policy, while the frontend shows a live checklist as the user types. I also added a Change Password page. When a password is changed, every other active session is logged out while the current one stays active. At one point login stopped working and always returned “Invalid credentials”. It turned out the password wasn’t the problem at all, the backend was stuck in a crash loop. A new database column was added as “not null” without a default value, so Hibernate couldn’t apply the change to an existing table. The application never finished starting, and the frontend showed a generic login error. I fixed the database manually, added a default value to the migration, and made a note for the future: every new “not null” column should always have a default value. After adding all these features, I went through another security pass. The rate limiter now also protects password changes and the Cal.com webhook. I also added a scheduled cleanup job that removes old expired sessions from the database. Finally, I configured proper security headers, including a CSP. Public forms can still be embedded on external websites, while the rest of the CRM remains protected from being embedded elsewhere. Stay tuned, cause I still have lots to do :)"}, {"post_id": 14329, "ts": "2026-06-23T12:44:44Z", "hours": 5.6103, "text": "I continued working on this wonderful project. The first thing I implemented was the sidebar, designed as a reusable component. You can expand and collapse it to switch between icons only and icons with text. I also added a top bar, which contains the company name (top left), a search bar that will allow users to scan the entire database and quickly find what they’re looking for. I also added translations (2 languages for now), light and dark mode, notifications, and a profile section with the user’s name. Additionally, I implemented a simple dashboard with fake data to start shaping the overall user experience. Stay tuned."}, {"post_id": 13650, "ts": "2026-06-22T12:28:12Z", "hours": 8.3619, "text": "Still working on my project. It’s been really tough so far, I’m still on the backend, which is very hard. I feel lucky to have AI helping me; it would be really difficult without it. Honestly, it’s hard even with AI, so I lean on it a lot. I don’t think using AI is a negative: as long as you understand the code it writes and can modify, fix, and improve it, you’re fine. On the backend I’m currently working on the engine underneath, mainly the database relations. For example, the record table stores its fields generically (as JSON), so users can define whatever fields they want. The catch is that validating the data is on me, since the fields are dynamic, the database can’t enforce their shape, so it all has to be checked in code, mostly in the frontend. I’ve also started on the frontend: first by dockerizing it, then by adding the login form that exercises my backend."}, {"post_id": 11904, "ts": "2026-06-19T12:16:33Z", "hours": 5.9808, "text": "Started working on a very big project, called CRM. I hope you know what a CRM is, but for who doesn’t, a crm is basically an app, or maybe a dashboard, used by companies to keep track of their clients, employees and all this kind of things. It helps growing a company, with integrated tickets and so on. This app will be built in the following tech stack: Angular for the frontend, with daisyUI and tailwindCSS as graphical libraries Java Spring for the backend, able to manage correctly users, types and endpoints. I chose this over nestJS with prisma, because I want to have more control on the db. db, I have still to choose what I want and should use, because now I’m focusing on other things, like JWT auth, creation of users and entities and so on. My idea is to use this as a base, and then for maybe companies who needs it, I could like improve this, add requested features, and optimize everything. My current situation: I started the angular project, but I still have to install all libraries and update determined packages I created backend, and I’m currently focusing on auth (as you can see from the pic), with jwt sessions, users, entities, permissions and this kind of things. db, still in progress The application will be dockerized for best practice."}]...
|
Title: CRM by @F3rro_32 | Stardance
Devlogs:
Star Title: CRM by @F3rro_32 | Stardance
Devlogs:
Started working on a very big project, called CRM. I hope you know what a CRM is, but for who doesn’t, a crm is basically an app, or maybe a dashboard, used by companies to keep track of their clients, employees and all this kind of things. It helps growing a company, with integrated tickets and so on. This app will be built in the following tech stack: Angular for the frontend, with daisyUI and tailwindCSS as graphical libraries Java Spring for the backend, able to manage correctly users, types and endpoints. I chose this over nestJS with prisma, because I want to have more control on the db. db, I have still to choose what I want and should use, because now I’m focusing on other things, like JWT auth, creation of users and entities and so on. My idea is to use this as a base, and then for maybe companies who needs it, I could like improve this, add requested features, and optimize everything. My current situation: I started the angular project, but I still have to install all libraries and update determined packages I created backend, and I’m currently focusing on auth (as you can see from the pic), with jwt sessions, users, entities, permissions and this kind of things. db, still in progress The application will be dockerized for best practice.
Still working on my project. It’s been really tough so far, I’m still on the backend, which is very hard. I feel lucky to have AI helping me; it would be really difficult without it. Honestly, it’s hard even with AI, so I lean on it a lot. I don’t think using AI is a negative: as long as you understand the code it writes and can modify, fix, and improve it, you’re fine. On the backend I’m currently working on the engine underneath, mainly the database relations. For example, the record table stores its fields generically (as JSON), so users can define whatever fields they want. The catch is that validating the data is on me, since the fields are dynamic, the database can’t enforce their shape, so it all has to be checked in code, mostly in the frontend. I’ve also started on the frontend: first by dockerizing it, then by adding the login form that exercises my backend.
I continued working on this wonderful project. The first thing I implemented was the sidebar, designed as a reusable component. You can expand and collapse it to switch between icons only and icons with text. I also added a top bar, which contains the company name (top left), a search bar that will allow users to scan the entire database and quickly find what they’re looking for. I also added translations (2 languages for now), light and dark mode, notifications, and a profile section with the user’s name. Additionally, I implemented a simple dashboard with fake data to start shaping the overall user experience. Stay tuned.
Hey guys, this week was also about making the CRM feel more complete. Alongside several new features, I also spent a good amount of time improving security and fixing one particularly deceptive bug. First of all, I added a new global Calendar page that shows every record with a date in one monthly view. Events, tasks, reminders and subscription renewals are all displayed together, each with its own color. Before this, the calendar only existed inside each record type, so there wasn’t a way to see everything happening at once. I also integrated Cal.com. The booking page can now be embedded directly inside the CRM, and when someone books a meeting, a webhook automatically creates an Event record. If the meeting is rescheduled, the existing record is updated instead of creating a duplicate, and if it’s cancelled, the event is removed. To keep the integration secure, the webhook signature is verified using the raw request body instead of reserializing the JSON. I spent some time looking at features from Pipedrive, HubSpot and Attio, then implemented a few that I really liked. The Kanban board now shows the total value of each column, making it easy to see how much every stage of the pipeline is worth. I also added rotting, which highlights cards that haven’t been updated for more than two weeks so forgotten leads are easier to spot. Another big addition is public forms. Every record type can now expose a public form that can be shared with a link or embedded into any website. When someone submits it, a new record is created automatically and any related workflows are triggered. The feature also includes a honeypot for bots and per-IP rate limiting. Finally, I added a Trash Bin, allowing users to restore accidentally deleted records with a single click. I also added the ability to assign an owner directly from the record page. Passwords now follow the same rules everywhere in the application: at least 8 characters one uppercase letter one lowercase letter one number one special character. The backend enforces the policy, while the frontend shows a live checklist as the user types. I also added a Change Password page. When a password is changed, every other active session is logged out while the current one stays active. At one point login stopped working and always returned “Invalid credentials”. It turned out the password wasn’t the problem at all, the backend was stuck in a crash loop. A new database column was added as “not null” without a default value, so Hibernate couldn’t apply the change to an existing table. The application never finished starting, and the frontend showed a generic login error. I fixed the database manually, added a default value to the migration, and made a note for the future: every new “not null” column should always have a default value. After adding all these features, I went through another security pass. The rate limiter now also protects password changes and the Cal.com webhook. I also added a scheduled cleanup job that removes old expired sessions from the database. Finally, I configured proper security headers, including a CSP. Public forms can still be embedded on external websites, while the rest of the CRM remains protected from being embedded elsewhere. Stay tuned, cause I still have lots to do :)
Hey guys, I have stopped this project for a bit, but here I am again. I’m currently improving the CRM, mostly the security, which, for me, is one of the most important parts, and adding functionalities. Lately I focused on the mails. I added my smtp server, and in the backend, I managed all mails. Here is an example, with the invitation email. It’s in italian, but don’t worry, basically it invites you to the CRM, and then you can create your own account, with password. As you can see in the third screenshot, I can manage the invitation link, whether I want to invite an admin, or a simple employee.
Hey guys, I’m still working on this project, cause there are lots of things to do.Lately I focused on improving and adding things to the ObjectTypes. As you can see in the two images of the sidebar, I added like 10 fields. Among them, the most important are goals , basically contains the possibility of creating a goal, setting an owner, which is responsible for this goal (clearly depends on the situation), the actual goal and the period. Along with that you can set a metric, so if the goal is revenue , opportunities , leads , custom project_task , basically it contains the instruction for each member, on a certain project service_contract , the support, it contains the subject, the company which is referred to, start and end date, the actual status, so active , expiring , expired , terminated , hours spent and so on. Along with these and the other I didn’t cite here, I added 3 object for the sales, where this two are the most important: The first one is the supplier , it contains all the specs, so name, vat, email, phone, website, address, and eventual notes. The second one, the most important, is sales_order , which contains the subject, the number of the order, a relation with the company, and a relation with the contact, a relation with the quote (I don’t know if it’s right, in italian it’s called preventivo), the possibility of setting a status, so created , confirmed , shipped , closed , cancelled , the order date, a relation with the payment Method object, and all the financial part, so the subtotal, with maybe the discount, vat, the total and the infos for the shipping, billing and shipping address. I hope to finish this project asap, since it’s taking me so looong.See ya in the next devlogs
Hey guys, still on this project. This round was all about the stuff that sits on top of the modules, instead of new modules. Per-user formatting preferences . There’s a new “My preferences” page in the user menu. Every user picks how they want to see numbers and dates: thousands separator, decimal separator, currency (any ISO code, the symbol gets resolved automatically), how many decimals, whether the symbol goes before or after the number, and whether to cut trailing zeros. Same thing for the date format. There’s a live preview box that updates while you touch the selects, so you see 1.234,50 € turn into $ 1,234.5 as you change this. The setting applies everywhere, lists, record details and so on. Tags . These are cross-module, which is the whole point; a tag can sit on a lead and on a ticket. There are two kinds: shared ones, visible to the whole workspace, and private ones, which only you see. Each one has a color. You can attach and detach them from any record, and there’s a “all records with this tag” view that goes across modules, filtered by your permissions, so if you can see tickets but not opportunities, you only get the tickets.I did not build this as a field type, even though I already have a TAGS one. That one belongs to a single ObjectType with its own fixed options, so it gives you neither the shared catalog nor the cross-module search. Duplicate merge . You pick a module and it gives you back the candidate pairs, ranked by how similar their titles are (there’s a threshold you can move, default 0.6). Then you get the two records side by side and choose, field by field, which value survives. When you confirm: the winner keeps everything you picked, every relation that pointed at the loser now points at the winner, ids of the loser mentioned inside other records get rewritten too, including the ones stored in lists, notes and tags move over (and if the winner already had that tag, the duplicate link is dropped), the loser goes to the trash, not deleted. A wrong merge has to be recoverable, and I already have a bin, so I used it. Document numbering . Documents now number themselves. It’s configurable per module: prefix, whether to include the year, padding, separator. Right now it’s on for three of them: - quotes → 2025-47 - invoices → FT2025-0001 - tickets → TT643 The counter is per module and per year, and it’s locked while it’s being read, so two people creating a quote at the same time can’t get the same number. If you type a number by hand, yours wins, that matters when you’re entering an old document with its original number. On top of that, quotes have revisions. Revising 2025-13 gives you 2025-13_2 , a brand new document that links back to its parent, while the parent moves to the “revised” stage. And you can revise a revision, so 2025-13_2_2 works too, the counter is progressive per parent, not global, which took a bit more care than I expected. Next up is the big one: document lines. Quote → order → delivery note → invoice, with quantities, discounts and VAT per line. It’s the only part of this CRM that doesn’t fit the dynamic JSON engine everything else is built on, so it gets its own real tables. See ya in the next devlog, I hope you like the project. P.S. you’ll see the tag in the next devlog, I still have to implement the frontend
Hey guys, back on this project. Last time I said the next round was going to be document lines, my quote was “the only part of this CRM that doesn’t fit the dynamic JSON engine”. That’s what this round was, plus the report engine on top of it. Document Lines : One single table for all four documents: quote, sales order, delivery note, invoice. The line is exactly the samein all of them, the only thing that changes is the document holding it, and a document here is just a Record like any other, so there’s no type constraint on the line at all. A line can be a product line, a free text line (no amounts, just something to say in the middle of the document) or a subtotal. Two things get copied at save time: the description and the vat percentage. The math is its own class, DocumentLineCalculator, and it’s the one piece of this project I wanted testable completely on its own, because it’s the only place where a wrong rounding produces a wrong tax document. The order is fixed: gross = quantity × unit price discount = a percentage of the gross, or a flat amount net = gross - discount, rounded to 2 decimals here vat = net × rate, rounded line total = net + vat Rounding happens after the discount and after the vat, never on the unit price: round the unit price and the error gets multiplied by the quantity. Rounding mode is HALF_UP, which is the commercial rounding used here, not HALF_EVEN. And a flat discount bigger than the line itself gets clamped instead of producing a negative amount, since that’s a typo 100% of the time. Lines are always saved all together. The endpoint is a PUT that replaces the whole set. It deletes and rewrites instead of diffing row by row, because a document has a few dozen lines at most and the diff would cost more code than it’s worth. The reason for this rule is the totals: they depend on every line, so a partial save would leave the header and the lines disagreeing, even if only for a moment. The totals (subtotal, vatTotal, total) get written back into the document’s own JSON, plus the header level discount and shipping cost. They live there so they can be list columns you filter and sort on, which is the whole point of having them. Now I’m working on the dashboard graphs, widget and this kind of things.I hope you like the project. I’m sorry if I don’t have any screenshot of the working website, it’s because I focused only on the backend, the frontend of this part still needs to be written.
Hey guys, how it’s going? These days I’ve got quite a lot of work to do, since we’re in the middle of harvest season here in Italy, so I don’t have much time to work on the project. Unfortunately, today it rains, so I’m home, and I can spend some time on the PC. Lately I’ve been working a lot on the backend. The first two things I did are documents and document numbering : I created the model for document rows ( DocumentLine ), with its engine to calculate totals, including subtotals, discounts and VAT. I also added unit tests for the calculator. I also implemented automatic document numbering, so documents like quotes, invoices and tickets are automatically assigned a number when they’re created. Then I worked on quote revisions, with a new QuoteRevisionService to keep track of different versions of the same quote. Another thing I started working on is document conversion. The idea is to be able to convert a quote into an invoice, but this part is still a work in progress. I also spent quite a bit of time on reports and dashboards: added the Report model and the ReportEngine / ’ReportService` added default reports through a ReportSeeder created the Dashboard model, with tabs and widgets added the related controllers, services and repositories On the frontend side I’ve scaffolded the pieces for dashboards and widgets — the widgets/ and dashboard-tabs/ components exist and the dashboard and report services are written — but the components themselves are still empty shells. The data layer is ready, the screens aren’t written yet. That’s what I’ll pick up next. Another big thing I worked on is tags and data quality. I added the tag model and APIs, together with the services and repositories. I also started working on a duplicate finder and record merging system, so duplicate contacts/companies can be detected and merged instead of leaving messy data around. For PostgreSQL, I also enabled pg_trgm to improve fuzzy searches for duplicate detection. Finally, I added user preferences for number and date formats, including a live preview so users can immediately see how their chosen formats will look in the app. I’ve also added icons for the new modules. As you can probably tell, this was a very backend-heavy cycle. Almost everything I built this time: document lines, numbering, quote revisions, reports, dashboards, tags and duplicate detection lives in the models and the services, and the UI for most of it isn’t there yet. So this time there isn’t much to show in screenshots: the engine is in place, the screens come next. I’d rather get the model right first and build the interface on top of something solid than the other way around. Hopefully I’ll be able to find some more time to work on it after harvest, so see you in a while.
Hey guys, how’s going? Soon school is going to start for me, but luckily it’s my last year in high school, so I’m really happy about this. Lately I had much time to code, so I continued working on this project. Last devlog was all backend; I said the engine was there and the screens weren’t. This time it’s quite the opposite. I didn’t really touch the backend, I spent the last 5-6 hours writing the frontend. Here’s the details of what I did: Document lines the grid is finally in the record detail. You can add lines, set quantity, price, discount and VAT, additionaly with the subtotal / VAT / total block, that updates while you type. When you save, the whole set of lines is sent at once. Tags I added the tag picker on the record detail, so you can attach and remove tags from a record as you wish. I also made the page that shows every record with a given tag, from all the modules together. Duplicates The duplicate finder now has its own screen: you choose a module, you get the pairs it thinks are duplicates, and the you see the two records side by side and pick field by field which value to keep before merging them. Reports There’s a page to build a report with a wizard (rows, columns, metrics, filters) and a preview that shows you the result before saving it. Dashboard widgets This is the main thing of this cycle. I wrote all six widget types, which are: - KPI tile - split KPI tile - chart - table - pivot - record list A widget is just a saved report query plus the type of rendering you want, so it runs on the report engine. Dashboards with tabs You can create a dashboard, add tabs to it and put widgets inside, so you can keep for example sales and support separated from each other. Sidebar and topbar The sidebar now has the routes for all the new pages, and the topbar has a quick-create button to make a record from anywhere without opening its module first. Two things are still not nice and I’m aware: in some places the relation fields show the raw id instead of the name of the record, and the totals of the document lines are not formatted with the user preferences yet, so you read 9054.00 instead of 9.054,00 EUR. Both are small and both are on the list to be improved. Now I’m working on the PDF generator See you, I hope you enjoy this project
Hey guys, how’s it going? I hope you’re all doing well. School started here in Italy, so I have less time compared to August. I also have to get my driver’s license, so I’m studying for that too. Unfortunately, coding isn’t the first thing I do every day anymore. I’m still working on the PDF generator. Last time I mentioned that relation fields were showing raw IDs and that document totals weren’t formatted properly. I fixed both of those, but I’ll get back to them later. About the PDF The template is HTML, and it lives in the DB. I didn’t hardcode the layout in Java. I created a PdfTemplate entity that stores the HTML, page size and margins. There is one default template for each document type: quote, order, delivery note and invoice. Thymeleaf fills the template with the document data, and OpenHTMLToPDF + PDFBox generate the PDF. Since the HTML is provided by the user, I also had to think about security. A template could try to load something like file:///etc/passwd or access an internal URL. Because of this, external protocols are disabled and only data: URIs are allowed. Page sizes are also checked against a whitelist. I also had to deal with the fact that HTML isn’t always valid XML. OpenHTMLToPDF expects XML, so I use jsoup to normalize the HTML first. Otherwise, perfectly normal HTML can cause a SAXParseException . And finally, fonts have to be embedded in the PDF. Without including DejaVu Sans in the jar, the PDF doesn’t render correctly. VAT summary I also worked on the VAT summary. Lines are grouped by VAT rate, shipping is added to the highest rate, and the document discount is distributed across the rates instead of being applied at the end. VAT is then calculated on the discounted amounts, so everything adds up correctly: taxable + VAT = total This actually fixed a bug where VAT was calculated before applying the document discount. It wasn’t very obvious until I started testing it with real numbers. Three endpoints The PDF system now has three endpoints: print a document preview a template print a batch For the preview, instead of creating a fake document, I use the last real document of that module. This way there is only one PDF generation system to maintain. The batch endpoint combines multiple documents into one PDF, while checking permissions for every document. A few other fixes The two ugly things from last time are also gone. Relation titles are now resolved by a shared backend service, so instead of UUIDs you see things like the company name. The same service is used by the lists, detail pages and PDFs. Amounts in the PDF are also formatted using the user’s preferences. I also added tags to the record lists. Tags are resolved in bulk instead of doing a permission check for every single row, which makes a big difference on larger lists. The backend part is basically done for this cycle. The print button and template editor are already written, but they’re not wired up yet. Right now I’m still using the API to test the generator. So, UI is next. See you in the next devlog!
Hey guys, how have you been doing lately? I’m alright. I’m still getting my driver license, so I don’t have much time to code. Last devlog was all about the PDF engine on the backend, and I closed it saying that the UI was next. Here it is: Print button : I added a print button Print PDF on quotes, orders, delivery notes and invoices. The file is downloaded with the document number as its name, so you get for example 2025-47.pdf and not just document.pdf Template editor : I also added to settings a new tab called “Print”. On the left there’s the list of templates, on the right the HTML, the page size and the margin. The preview renders the last real document of that module instead of a fake one, so what you can see is exactly what your customer receives. The default templates can’t be edited you duplicate them: the seeder rewrites them at every boot, so any change would silently disapper on the next restart. I preferred to say it in the interface rather than let someoune lose an afternoon of work. Company data : The company settings now hold also the legal name, VAT number, tax code, address and contact line. That’s what the PDF header prints, and without them the header comes out empty. VAT that adds up to the cent The header discount is spread across the VAT rates and every share gets rounded, so the sum of the shares could end up one or two cents away from the total. On a quote nobody would ever notice. On an electronic invoice it’s rejection 00423. Now the rounding leftover goes on the last rate, so taxable + VAT = total, always. Tests on a real db : The report engine builds SQL at runtime, and mocking a database proves nothing, so its tests now start a throwaway Postgres in Docker and run against it: filters, grouping, ordering and counting. Two bugs closed : Merging two records didn’t look at the bin, so a deleted record could be merged into a live one. And editing a saved report answered 405, because the frontend was sending PUT to an endpoint that only has POST. Right now I’m working on the 2FA (for those who don’t know, the 2 factor auth). I’m writing the TOTP myself instead of pulling in a library: it’s an HMAC-SHA1 of the 30 second counter, and the six digits come out of the dynamic truncation described in the RFC. The secret is encrypted in the database with AES-GCM, because someone who can read the db must not be able to generate the codes, otherwise a second factor is just a second password. There are ten recovery codes, stored hashed and usable once each, and the last accepted counter is saved, so the same code can’t be replayed during its 30 seconds. The tests are the official RFC 6238 vectors: a TOTP written at home always “works” until you compare it with a real auth app, and at that point it’s too late to find out. Two things I know are missing: the second factor has no interface yet, there’s no page to scan the QR code from, and the mailbox that turns incoming emails into tickets is only half written. See you soon, the end of this project is near.
Hey guys, how’s everything going? I’m alright. I’m so glad hackclub postponed the end of stardance, I have still another month to 1. finish this project 2. do other projects I had on my mind for such a long time. Before doing this devlog, I had to use claude to debug my work, because I had some errors I didn’t understand (I was using a class created for a test in the normal “code”), so bad :( and also other small issues. Lately I worked on one of the most significat features for me, which is 2FA . As my network teacher says "zero trust, because the world is a place full of bastards" . 2FA is one of the techniques I use to follow this approach. Basically, now you can press “Enable” in your preferences, scan the QR code with any authenticator app (f.e google), or just type the secret by hand, because half the people can’t frame a QR code at the first time, lol. You also have to confirm with a code. At login, if 2FA is on, there’s a second step for the six digits. You also get ten recovery codes that you can copy or download, shown only once. Turning it off asks for your password, so a stolen open session can’t remove this precaution. You’re probably wondering: are the secrets encrypted? Yes, they are. I mostly use AES-GCM, because it’s pretty simple, but also secure, so it’s the better compromise. The TOTP secret and the mailbox passwords are stored encrypted with AES-GCM. The key lives in an env variable, not in the db, so a database dump alone isn’t enough to generate codes or read someone’s email. I also turned the crm in a PWA . You can install it on your phone or desktop, it has its own icon and window, and when I deploy a new verion, it tells you to reload, instead of silently serving you the old one from cache (it also checks every 6 hours, maybe I’m gonna change it to 10, idk, for the tab you leave open for days) Like in every other devlog, I made some tests and updated the docs. The report engine now has tests against a real Postgres started in docker, and the repo finally has a real README (it’s not finished, just with some basic information, claude, thanks for the suggestion of making it). Oh, I nearly forgot. I also worked on emails. Now I’m currently working on the Italian electronic invoice, which is called FatturaPA. The crm builds the XML from an invoice, and the first test I wrote checks it against the official government XSD: if it doesn’t pass, it isn’t saved. I think I’m gonna study a bit of english / american law, to allow people out of Italy to use this app as well. I hope you like my product, see you soon
Hey guys, how’s going? I have plenty of things to do, but coding is still one of my favorite activities, so I always try to save some time for it.This time I worked again on FatturaPA, which is the Italian electronic invoice.What I did, is that now, first of all, the CRM can now generate the FatturaPa XML directly from an invoice and validate it against the official XSD, before saving it. I also added the whole invoice lifecycle, from draft, to setn, delivered, accepted or rejected. The CRM can read the recepits from the SDI and show ufseful information when something goes wrong.Another important change is that invoices now become locked once they’re sent to the SDI. If something needs to be changed, the correct way is to create a credit note instead. This is much efficient in my opinion.I also started working on the SDI integration itself. For now there’s only a manual transport, but the system is built so that adding an actual provider later shouldn’t require changing the rest of the CRM. I did it this way, so I can decide which provider use, and not have to change everything.Besides invoicing, I added time tracking. You can start a timer from the top bar and see your hours directly on records. Timers also automatically close after a maximum amount of time, so nobody ends up with a 80-hour ticket because they forgot to stop it.Finally, I worked on email campaigns. You can create a campaign from a saved filter, send emails through a queue and manage unsubscribes. I also added some protections against things like open redirects and accidental unsubscribes.And now, the honest part: before writing this devlog, I ran the tests and guess what, the app didn’t even start.I used claude for debugging, cause I wans’t finding the error. Silly me, it was just a typo.
Hey guys, how’s everythings going? I’m doing pretty well. As always I have lots of things to do, but I still have plenty of time for coding. School is demanding, and preparing for my driving license is also tough, but I’m managing everything little by little. Last time I ended up with an app that wouldn’t even start. Luckily, I fixed all those errors, and all 258 tests are now green and passing on the PostgreSQL db. After that, I added new features. First of all I worked on NPS surveys and quote acceptance. Customers can now receive surveys and answer them through a public link. They can also accept quotes directly from a link, without needing an account. I also made sure these features work with the existing workflows, so automations can still do their job properly. Another interesting addition is the MCP server. AI agents can now interact with the CRM through an API key. Instead of creating a separate set of tools for every module, I went with seven generic tools that can work across all 34 modules. This should make it easier for AI models to understand which actions they can perform, while keeping the CRM’s existing permissions and security rules in place. I also improved search quite a bit. Before, it mostly looked at record titles. Now it uses PostgreSQL full-text search to find relevant information inside the actual record data and rank the results. The audit history is also much easier to read, with related record IDs replaced by their actual titles. I worked on a couple of smaller but important things, too. The trash can now properly handle related files and records when permanently deleting something, while protecting fiscal documents that must be kept for ten years. Finally, I started working on the customer portal. It now has its own backend authentication and permission system, separate from the employee login. Customers will only be able to access records they’re actually allowed to see. The backend is ready, but I still need to connect the frontend pages and routes. There’s still quite a bit to do, but I’m getting closer to the first complete version of the CRM. See you in the next devlog!
Hey guys, how’s going? This will be a short devlog, and it’s the one before the shipping. I decided to ship the CRM, even if it’s not completely finished. That’s because I still have to do lots of things, but now I have a working product, so, since the changes I have to make are complementary. Unfortunately, I have a big issue: the whole interface is in Italian. The app is made for Italian small businesses (FatturaPA, VAT, SDI…), but if you come from Stardance you can’t read a single menu. Real i18n is still on my list and it is a big job, so for now I added the Google Translate widget in the corner of the app. If your browser is in English it starts translating by itself, otherwise you pick English from the selector. It’s not pretty, but it makes the demo usable today instead of “someday”. I had to widen the CSP in nginx for it, and I loaded the script as an external file so I didn’t need a second hash. I also fixed the README and cleaned the repo. Now everything should work fine, or at least let’s hope so. I hope you enjoy the product.
Hey guys, what’s up? I’m finally in the last phase of getting my driving license, so that’s taking up some of my time too. The CRM is now online at crm.alessio.hackclub.app . The VPS has very little RAM, so I build the Docker images locally and transfer them to the server using docker save over SSH. It’s not the fanciest deployment process, but it works with the resources I have, so I’ll stick to it for now. One of the main things I worked on was the customer portal . The backend from last week finally has a frontend: customers can log in, see their tickets and documents, open requests, reply to messages, download PDFs and accept quotes. I also made sure that internal notes stay internal. Notes now have a Visible to customer checkbox, which is disabled by default. The portal only shows notes explicitly marked as visible, so there’s less risk of accidentally exposing something that should stay private. Another feature I added is Google Calendar import . It’s read-only for now, so the CRM can import events without modifying anything in your Google account. Events are created through the same service as normal CRM records, meaning workflows and the audit log still work as expected. Sync runs every 15 minutes, and if something goes wrong with an account, it won’t stop the others from syncing. I also started replacing the Google Translate workaround with proper internationalization (i18n). The translation system is in place, including support for parameters and locale-aware dates and numbers. The dictionary is type-checked, too, so missing English translations can be caught at compile time. There’s still a lot of work here: around 1,200 strings need to be translated by hand. It’s not the most exciting task, but I’d rather have proper translations than rely on Google Translate forever. Obviously that’s my opionion. I also started working on public registration, but it’s not ready yet. There’s one important limitation: the CRM currently has a single shared workspace, so everyone who registers would see the same data. Registration will stay disabled unless explicitly enabled until I decide how to handle that properly. That’s because the idea is to have 1 single DB for each workspace, since the CRM should be self-hosted. There’s still work to do, but the CRM is getting closer to the version I wanted to ship. See you in the next devlog!
Ships:
CRM An open-source CRM for Italian small businesses: contacts, companies, leads, quotes, orders, invoices with VAT, tickets, email campaigns, NPS surveys, reports and a customer portal. It started as a way to manage clients for a friend’s startup and became a working and valuable project. TRY IT (no install) https://crm.alessio.hackclub.app email: [email protected] password: HackClub-Demo-2026! The demo has full access and realistic fake data, so feel free to click everything, create, edit and delete. The data resets occasionally. Outgoing email is switched off on the demo. HEADS UP: the interface is in Italian. Use the translate widget in the corner of the app (or your browser’s translator) to read it in English. Real i18n is on my roadmap, sorry! WHAT TO LOOK AT A quote with line items, discounts and VAT by rate, and the “Print PDF” button. PDFs come from HTML templates you can edit, with a live preview on your last real document. A customer accepting a quote from a signed link, without an account. Full-text search across every module (PostgreSQL). Italian e-invoicing: it builds the FatturaPA XML and validates it against the official government XSD before saving. Invoices lock once sent to the SDI. The MCP server: an AI assistant can use the CRM through an API key, with seven generic tools that work on all 34 modules and respect permissions. 2FA (TOTP) with recovery codes, secrets encrypted at rest, installable PWA. HOW IT WORKS There is no “contacts” or “companies” table. One generic Record entity stores its fields in a jsonb column, and an ObjectType + FieldDef describe each module (39 field types). Adding a module is a configuration record, not a migration or a new controller. Permissions are checked per module and action at runtime. You can have more info in the README, so please check it. I hope you appreciate this project :)...
|
1793051300.3322272
|
1793137700.3322272
|
|
16885
|
Hackfetch by @xerneas | Stardance
|
|
2
|
124.4
|
1751
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-22T11:04:00Z", "hours": 63.0, "multiplier": 19.6, "payout": 1381, "blessing": "neutral", "text": "HACKFETCH V2.0 it’s been a few weeks since ship #1 and hackfetch is a completely different tool now. faster, smaller, quieter, actually correct, and now lives in places besides your terminal window. v2.0.0 is out. what changed: fits in your tmux status bar with one line of config. same story for lualine. hackfetch -status prints a compact one-liner meant to be shelled out to every minute. fits everywhere else too. now on the AUR (yay -S hackfetch-bin) alongside the existing brew tap, curl installer, powershell installer, and go install. seven install channels total. runs in ~20ms on repeat calls thanks to an on-disk cache. tmux polling every minute is basically free now. was ~700ms cold before. runs in ~0.7s cold thanks to a parallel API fetch. was ~1.7s before. shows a smooth truecolor gradient on any modern terminal. auto-detects $COLORTERM. falls back to 256-color on older ones. -doctor walks a colored checklist of your setup and tells you exactly what’s broken. green if fine, orange if not, non-zero exit if you wanna script it. new pizza logo because hack club runs on pizza. seven logos total. streak is finally correct after silently saying “1 day” for a month. /summaries is gone from hackatime so hackfetch now reconstructs streak from every coding session in your history via /heartbeats/spans. real streak: 9 days for me right now. 7-day sparkline baked into the fetch (with -v) and available as -status –sparkline for the tmux bar. default fetch got leaner. slack handle, machines count, and the sparkline moved behind -v so the normal fetch stays focused on hours + project + language. loading spinner on the api fetch so you know something is happening. and then the cache made it show up almost never. one install: Linux / Mac: curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Windows: irm https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.ps1 | iex Arch family: yay -S hackfetch-bin macOS / Linuxbrew: brew install xerneas3318/tap/hackfetch For more install methods check out the github page: https://github.com/xerneas3318/hackfetch teasing the next big thing: hackfetch -leaderboard is coming next, using the public leaderboard endpoints i found in hackatime’s routes file. compete with friends on daily and weekly hours right from your terminal. private friend groups on a hackclub nest box after that. if you try it, thanks. send me some feedback", "repo": "https://github.com/xerneas3318/hackfetch", "demo": "https://github.com/xerneas3318/hackfetch/releases"}, {"ship_num": 2, "ts": "2026-07-07T00:01:54Z", "hours": 27.0, "multiplier": 17.78, "payout": 370, "blessing": "neutral", "text": "Every fetch tool tells you your OS. Mine tells you your streak. hackfetch is a Hack Club themed terminal fetch tool. Inspired by neofetch (originally bash, now archived) and fastfetch (its C successor), written in pure Go. Instead of just showing your kernel and CPU, it pulls live stats from your Hackatime account: today’s hours, weekly total, current streak, top project, top language. Right in your terminal. Six Hack Club themed ASCII logos (including my GOAT orpheus). Fourteen color schemes (pride, trans, bi, pan included). Live watch mode that refreshes while you code. And as of today, you can export the whole thing as a PNG, JPG, or SVG card and post it anywhere. One line to install: Linux / Mac: curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Windows: irm https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.ps1 | iex Tell me how it was! Follow and like for updates.", "repo": "https://github.com/xerneas3318/hackfetch", "demo": "https://github.com/xerneas3318/hackfetch/releases"}]...
|
[{"post_id": 39919, "ts": "202 [{"post_id": 39919, "ts": "2026-08-03T07:26:53Z", "hours": 6.6894, "text": "Hackfetdch natively in your readme hackfetch -readme it spits out a markdown stats card ready to paste straight into your github profile README. pipe it into a file and commit: hackfetch -readme > stats.md this is the cool bit or drop it in your README.md between two html comments and set up a github action to run it on a schedule so it auto refreshes every day. your profile now has a live coding stats card next to your pinned repos with no cron server, no vercel deploy, no api key stashed in secrets. its literally just markdown. zero extra api calls too. the readme card reads from the same cached hackatime response the normal fetch uses so if you just ran hackfetch it takes ~20ms. the streak emoji is a lil detail i had fun with. 3+ days gets a 🔥 upgrade with brew upgrade hackfetch or yay -S hackfetch-bin (once aur maintenance wraps up) or curl the installer curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh"}, {"post_id": 39223, "ts": "2026-08-02T01:40:31Z", "hours": 7.6967, "text": "HACKFETCH BATTLES??? two features in one release. hackfetch already knows a scary amount about you (thanks hackatime) so why not turn that into more features. hackfetch vs @ someone head to head compare. give it a hackatime username and hackfetch fetches both your histories in parallel, buckets them into today / this week / all time / streak, and prints them side by side with a winner arrow on every row. accepts @name , name , or a full profile url like hackatime.hackclub.com/@name . also works positional: hackfetch vs @you . use it to settle arguments, motivate yourself, or realize your friend has coded 265 hours and you should probably close discord. hackfetch -records personal bests. computed entirely from data hackfetch already fetches (streak + sparkline already use it), so zero new api calls $ hackfetch -records ✦ personal records @you biggest day 12h 41m on 2026-07-18 longest streak 25 days ended 2026-07-01 longest session 43m on 2026-07-17 days coded 86 first day 2026-04-24 99 days ago lifetime 208h 29m the “longest streak” tracks your all time best not just your current one. and “first day” tells you how long ago you started so you can feel old. grab it brew upgrade hackfetch yay -S hackfetch-bin install curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Next devlog is gonna be a fun one, I have an idea cooking up"}, {"post_id": 38323, "ts": "2026-07-31T17:22:26Z", "hours": 9.4408, "text": "big thank you for everyone’s feedback! fresh out of the oven: hackfetch v2.1.1 (aka the reviewer bug fix pass) what got fixed: shell detection used to just read $SHELL which is your login shell. if you log in as bash but run fish, hackfetch was calling you a bash user. it now checks $FISH_VERSION / $ZSH_VERSION / $BASH_VERSION and falls back to asking the OS who your parent process actually is editor detection was two bugs in a trench coat. it wasnt stripping args so zeditor --wait showed up as “zeditor –wait” instead of “Zed”, and if you had no $EDITOR set it defaulted to nano even if you had literally never opened nano. now it strips flags, maps launcher names to human ones (zeditor -> Zed, code -> VS Code, cursor -> Cursor, hx -> Helix etc), and says “-” instead of nano if nothing is set. top project label was ambiguous. it was pulling weekly stats but the row just said “top project” so people thought it meant all time. now weekly rows read top proj 7d , top lang 7d , top ed 7d , top cat 7d . setup dialog was scaring people. it always printed “file exists but has no api_key” whenever it reached the setup flow, even if the api_key line was actually there but just failing to parse. loadConfig is now more forgiving (inline comments, quoted values, case insensitive keys) and setup tells you WHY its stuck instead of gaslighting you about your own config. also short circuits if you run hackfetch -setup when youre already set up. people said they wanted a gay flag color was already there under the name pride but that wasnt obvious. gay is now an alias so both work. grab it: brew upgrade hackfetch or yay -S hackfetch-bin or curl / powershell installer if you don’t have it yet curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh again thank you to everyone who took the time to actually run it and tell me what was broken!"}, {"post_id": 34562, "ts": "2026-07-25T12:00:09Z", "hours": 10.5769, "text": "hackfetch COLLAB?? so my last two devlogs teased two features. shipping both today. -leaderboard last devlog i said “compete with your friends on hackatime hours is coming soon.” i thought i was gonna have to build a whole nest server for it. turns out /api/v1/leaderboard/daily and /api/v1/leaderboard/weekly already exist and are public on hackatime. just a single call!! so hackfetch -leaderboard daily (or weekly) now shows the top 10: ✦ daily leaderboard Last 24 hours 🥇 1. soaphia14 11h 12m 🥈 2. AnastKara 10h 32m 🥉 3. RoSerMar 10h 6m 4. euledone 10h 5. TheShovel 10h 6. Dylhouse 9h 1m 7. Dexrn 8h 59m 8. HexFud 8h 31m 9. zeddash 8h 29m 10. Trtotomotoro 8h 26m every username is an OSC 8 clickable link to that person’s hackatime profile. modern terminals (iterm2, kitty, wezterm, alacritty, gnome-terminal) render it as an actual hyperlink you can click. terminals without OSC 8 just show the plain text so it doesnt look broken. if you’re on the board it highlights your row in orange and adds (you) next to your name. json addon the other thing. someone else competing in stardance messaged me the other day about integrating hackatime into their own project and needed help figuring out the api (YAY). helping them made me realize hackfetch is doing a bunch of work (auth, caching, streak reconstruction, per-day bucketing) that other tools would love to piggyback on. so now: $ hackfetch -json { \"version\": \"2\", \"fetched_at\": \"2026-07-25T17:00: 20.900829+05:30\", \"system\": { \"user\": \"xerneas\", \"host\": \"Macbook-Pro\", \"os\": \"macOS 26.5.2\", ... }, \"hackatime\": { \"slack\": \"@U0B8FHHRQPJ\", \"streak\": 12, \"today_seconds\": 15820, \"week_seconds\": 237501, \"top_project\": { \"name\": \"hackfetch\", \" \"top_language\": { \"name\": \"Go\", \"seconds\": 97418 }, \"week_chart\": [36967, 31651, 33841, 284 \"machines\": 3 } } week_chart is 7 numbers = daily seconds oldest to newest same as the sparkline. top_language skips the unknown/other buckets. everything lines up with what the normal fetch would show, just parseable. ship landed in v2.1.0. brew update && brew upgrade hackfetch or arch: yay -Syu hackfetch-bin then try: hackfetch -leaderboard weekly hackfetch -json | jq For a general install use: curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh"}, {"post_id": 32880, "ts": "2026-07-22T10:20:45Z", "hours": 8.6689, "text": "my streak was lying to me for a month went to add a simple 7-day sparkline. by the end of the night i had rewritten how hackfetch talks to hackatime and my streak field is finally accurate for the first time in weeks. the plan was get the status from the last 7 days. draw ▁▂▃▄▅▆▇█ bars except the endpoint i needed straight up 404s. /users/current/summaries doesnt exist on the current hackatime deployment. Which means every single time i ran hackfetch it was quietly making a 30-day range call that always failed, then falling back to a placeholder that said “if today has activity, streak = 1”. thats it. no matter how long ive actually been on a streak, the fetch would just show 1 day. 🤦 my streak has said 1 day for the last 2 weeks even though ive been coding literally every day. never noticed because 1 day looks kinda plausible (i added 1 day as a fallback so that it didn’t show an error a couple weeks ago and forgot ) the fix: went digging in hackatimes rails routes on github. turns out theres a whole /api/v1/ namespace i was never using. and one of the endpoints is /api/v1/users/:id/heartbeats/spans. one call, ~150kb of json, every coding session ive ever logged with start_time, end_time, duration. 2000+ spans. which is exactly what i need for both features. bucket the timestamps by local calendar day, count unique days for streak, sum durations per day for the sparkline. one request covers both. and while i was already in the api layer i noticed fetchUser was making a whole separate call for my slack handle, which is silly because that data is already in the weekly stats response we cache. so i piggybacked it. weve gone from 4 api calls per fetch to 3. the sparkline: 7-day chart ▄▄▇▅▄▅▃ 65h 28m oldest on the left, newest on the right. that tall bar in the middle is a big lock-in session from earlier in the week. the two shorter ones on the right are today (still coding) and yesterday (took a break). opt in for -status --sparkline if you want it in your tmux bar too: 2h 9m today · streak 9 · ▄▄▇▅▄▅▃ 65h 28m teasing a backend: I’m planning on building a whole leaderboard server on a free hack club nest box so people can compete on their hackatime hours. while i was poking around the routes file for the streak fix i noticed something. /api/v1/leaderboard/daily and /api/v1/leaderboard/weekly already exist. public. no auth needed. no server needed. no cron sync. hackatime literally already has it directly. so hackfetch -leaderboard is coming soon (private friend groups and personal competitions can come later) last devlog before my next ship after the ship the devlogs are going to be huge. stay tuned :P"}, {"post_id": 32268, "ts": "2026-07-21T10:28:54Z", "hours": 9.7706, "text": "caching or i owe hackclub money so heres what my day looked like: nvim was calling hackfetch -status on every redraw for my lualine. tmux was calling it every 60 seconds for the status bar. i had 3 tmux sessions open. and every time i actually opened a new terminal, hackfetch fired again on shell start. quick napkin math: nvim redraws are basically continuous when im typing, tmux was hitting the api 3x/minute across sessions, plus every terminal open = another fetch. we’re talking hundreds of calls to hackatime in a normal work session. from ONE user. me hackatime is a free hack club service and i was starting to feel bad lol. the fix: cache the response ~/.cache/hackfetch/last.json stores the last snapshot with a timestamp. every fetch checks that file first. if its fresh enough, skip the network entirely and just render from disk. TTL is different depending on the caller: hackfetch (one-shot): 30 seconds. long enough that a normal re-run inside a devlog attempt is instant, short enough that you dont get badly stale numbers. hackfetch -status: 60 seconds tmux polls roughly this often anyway so its basically free now. hackfetch -watch: ignores the cache, always fresh (thats the whole point of watch mode). opt out with -no-cache or HACKFETCH_CACHE_TTL=0 if you want. also HACKFETCH_CACHE_TTL=300 to be even more polite. So yea tmux is now basically free . but the real win writing this made me realize the cache does more than save milliseconds: every fetch was a full TLS handshake, wifi radio spin up, etc. now most fetches touch the disk once and nothing else. macbook fan appreciates it. offline. if your wifi drops mid coding session you keep working from the cache instead of showing a spinner forever. tmux bar just keeps saying what it said 40 seconds ago. battery again but for the hackatime server. hackfetch stops asking the api 5-10x more than they need to. multiply by everyone who has it in their tmux config and thats a real thing. atomic write via .tmp + rename so nothing ever reads a half-written file. cache is user-only (0600), because it does contain your top project name. bonus: -doctor while i was fixing the polite-to-the-api stuff i added -doctor , which walks a checklist and tells you whats broken: hackfetch doctor ✓ wakatime config exists /Users/xerneas/.wakatime.cfg ✓ api_key present loaded from config ✓ wakatime-cli found /Users/xerneas/.wakatime/wakatime-cli ✓ hackatime api reachable today: 28m ✓ terminal supports truecolor $COLORTERM=truecolor ✓ browser opener available /usr/bin/open green if its working, orange if its not, and non-zero exit if anything failed so you can script it. this was going to be a small self-diagnosis feature and it caught a real bug in the api client on the very first run i did while writing it lol (a string field where hackatime returns an int, so one of the fields was silently missing from every fetch since v1.0). fixed that too. ship both landed in v1.10.0. update as usual: brew update brew upgrade hackfetch or arch: yay -Syu hackfetch-bin then run hackfetch -doctor first, and if anything is broken it’ll tell you exactly what."}, {"post_id": 31673, "ts": "2026-07-20T08:45:06Z", "hours": 8.4247, "text": "hackfetch is now TMUX + NVIM COMPATIBLE new thing today: hackfetch will just show up wherever you already look. tmux status bar. nvim statusline. any tool that can shell out to a command and put text on a screen. The addition was simple: hackfetch -status prints one line: 2h 11m today · hackfetch (45m) · streak 12 just the numbers, for tools that already have their own rendering. hackfetch is a data source now, not just a display. in tmux two lines in ~/.tmux.conf : set -g status-interval 60 thats it. every tmux session, every window, refreshing once a minute. i dropped it in a pink Catppuccin capsule to the left of my existing date capsule and now i cant stop glancing at it lol. in neovim (lualine) same story, five lines of lua: sections = { lualine_z = { function () return vim . fn . system ( \"hackfetch -status\" ): gsub ( \" \\n \" , \"\" ) end } } } shells out on every redraw. works with airline too, or any custom statusline that lets you plug in a function. the fun part making hackfetch call safe for “something tmux runs every 60s forever” meant fixing three assumptions the normal fetch was making. this was way harder than it should have been ngl. setup cant block. if you dont have ~/.wakatime.cfg, normal hackfetch throws you into an interactive setup wizard (ask me how i know). in status mode that would freeze your tmux bar until you notice and Ctrl+C it. so status mode is fully non interactive now. no config → print nothing → tmux shows nothing → no deadlock 🙏 api errors cant leak into your bar. hackatime offline? old behavior would dump HTTP 500 timeout into your status area which looks INSANE. now status mode exits silently instead so your bar stays clean every call has to be cheap. hackfetch’s parallel fetch alr seconds, and the shared HTTP client keeps connections alive across the 4 API calls it fires, so tmux polling every 60s is easy on the API. a proper local file cache is on the list for later but honestly not needed for now (i’m lazy) ship landed in v1.9.0. if you already have it: brew update brew upgrade hackfetch or arch family: yay -Syu hackfetch-bin (for more installs for ur specific os check out the github pls) then drop the tmux or lualine snippet above into your dotfiles and its just there in every terminal. no plugin. no config. no daemon. just a flag."}, {"post_id": 31042, "ts": "2026-07-19T03:42:21Z", "hours": 8.7494, "text": "Hackfetch Gets Real Colors New thing today: hackfetch now emits 24-bit color when your terminal supports it, and spreads gradients smoothly across each row instead of cycling through the palette one character at a time. Before and after Old behavior: for a per-char scheme like rainbow , each character got exactly one palette entry, wrapping around every N characters. On a 30-column row with a 3-color palette, that looked like ten cycles of red, green, blue, red, green, blue… basically RGB static. New behavior: the palette spreads across the row once, and characters between palette entries get interpolated in-between colors. Same 3-color palette on a 30-column row now shows red, olive, green, teal, blue, magenta, back to red. Why the rebuild Terminals speak two color modes: 256-color ( \\x1b[38;5;Nm ): pick from a fixed palette of 256 preset RGB values. 24-bit / truecolor ( \\x1b[38;2;R;G;Bm ): specify any of ~16 million RGB values directly. The old code always used 256-color. That meant every character had to snap to one of the palette entries. No in-betweens possible. The new code checks $COLORTERM (set to truecolor by iTerm2, kitty, WezTerm, Alacritty, GNOME Terminal, and most modern terminals) and emits 24-bit escapes when supported. When it’s not, it falls back to the old cycled-palette behavior automatically. You can force it either way with HACKFETCH_TRUECOLOR=1 or =0 . Where you’ll notice it The built-in rainbow scheme has 23 palette stops, so the difference on that one is small. You just see a smoother color distribution and less banding. The change is dramatic on: custom themes with few stops (try 3 colors in your ~/.config/hackfetch/colors.json for the wildest gradient) the stardance palette (11 stops, per-char), where sparkles now flow through the spectrum in order instead of landing on random-looking colors any per-line scheme ( pride , trans , bi , pan , sunset , ocean , forest ) since they now emit exact RGB values instead of nearest-256-color Bonus: the SVG, PNG, and JPG export paths use the smooth interpolation too, so exported cards look better regardless of your terminal. Ship Landed in v1.8.0 . brew update brew upgrade hackfetch Or on the Arch family: yay -Syu hackfetch-bin Try hackfetch rocket forest and just watch."}, {"post_id": 30475, "ts": "2026-07-18T02:33:55Z", "hours": 10.1122, "text": "One More Way to Install (and Pizza) Two small things today: hackfetch is now on the AUR, and there’s a new logo. hackfetch on the AUR A reviewer on my last ship said they had a hard time getting hackfetch running on CachyOS (an Arch-based Linux distro). Instead of trying to reproduce their exact issue, I figured the cleanest fix was to publish hackfetch through the package manager Arch users already trust. So hackfetch is now up as hackfetch-bin on the AUR: aur.archlinux.org/packages/hackfetch-bin If you’re on Arch, CachyOS, Manjaro, EndeavourOS, Garuda, or any other Arch-based distro: yay -S hackfetch-bin Or with paru: paru -S hackfetch-bin The package pulls the pre-built binary straight from the GitHub release, so there’s no waiting on a source build. Works on both x86_64 and aarch64 . Add it up and hackfetch is now installable one command from: brew (macOS and Linuxbrew) apt / dnf / yum / pacman / zypper / apk (all through the curl installer) the AUR (Arch family) go install (any platform with Go) the PowerShell installer (Windows) This thing is getting kind of hard to NOT install. Pizza logo Hack Club runs on pizza. Now hackfetch does too. hackfetch pizza It’s a triangular slice viewed from the tip, HACK CLUB baked into the middle, and a rolled crust at the wide edge. The tricky part was the crust. I went through three drafts trying to make it curve at the bottom without breaking the connection to the slice’s diagonal sides (turns out you can’t cleanly connect diagonal characters to horizontal ones in a monospace grid). Landed on a two-row rolled crust where the diagonals keep going and the interior fills with a double horizontal band. Pairs surprisingly well with sunset: hackfetch pizza sunset Turns your terminal into a golden-hour pizza box. Ship Both landed in v1.7.3 . If you’re on Arch-family: yay -S hackfetch-bin Elsewhere: brew update brew upgrade hackfetch Now try hackfetch pizza and tell me if the crust looks right."}, {"post_id": 29524, "ts": "2026-07-16T14:40:13Z", "hours": 3.2108, "text": "Hackfetch Is Now Actually Fast Last log I added a loading spinner so you’d have something to look at while hackfetch was hitting the Hackatime API. This week I made it so you barely have time to see the spinner at all (undoing all my work lol) The problem hackfetch was making four separate calls to Hackatime for every fetch: /users/current/heartbeats/most_recent (for your slack handle) /users/current/summaries (for your streak) /users/current/statusbar/today (for today's coding time) /users/current/stats/last_7_days (for weekly stats) Doing them one after another meant the total wait was the sum of all four. Turns out that’s about 1.7 seconds on a normal connection. Not the end of the world, but very noticeable when you just want to open a terminal. The fix: run them all at the same time Now hackfetch fires all four calls in parallel using goroutines, waits for the slowest one to come back, and then builds the fetch from the responses. Total wait drops from “sum of all four” to “just the slowest one.” Before: ~1.7 seconds After: ~0.7 seconds 60% faster . Every single fetch. Every single time. One tiny bonus optimization While I was in there, I also switched to a single shared HTTP client with a bigger connection pool. The default Go setup caps you at 2 open connections per host, which is fine when you’re calling one endpoint at a time but hurts when you’re firing four at once. Now the parallel calls can share connections instead of stacking up on each other. Nothing about the fetch itself changed. Same info, same layout, same colors. Just faster. Ship Shipped in v1.7.2. If you have hackfetch installed: brew update brew upgrade hackfetch time hackfetch Watch the spinner barely have time to appear."}, {"post_id": 29398, "ts": "2026-07-16T10:18:00Z", "hours": 13.6781, "text": "Loading Spinner and Splitting Up main.go Thanks so much to everyone who took the time to comment, rate, and drop feedback on my latest ship. All of it was genuinely so helpful and I’ve been spending the last couple days fixing things up a bit. I totally forgot to devlog so I’m actually losing a couple hours since it’s been over ten hours since my last one :sob A loading spinner while Hackatime fetches One reviewer pointed out that hackfetch takes a couple of seconds when it’s pulling your Hackatime stats for the first time, and there was no signal that anything was happening. Now there is. ⠋ fetching Hackatime... The spinner cycles through 10 braille frames and the whole line clears out the instant the fetch finishes. Same fetch, way less awkward pause. Two small details that make it feel right: It only shows when stderr is actually a terminal, so it doesn’t spam control codes into your log files if you redirect output. It prints one frame immediately, so fast fetches still flash something instead of nothing. hackfetch runs it around the API calls automatically. No config, no opt-in. It’s just there. Splitting up main.go Another reviewer said the 1.5k-line file was too much. They were completely right. hackfetch had grown into one giant main.go that held the logos, the color schemes, the Hackatime API client, the terminal render, the SVG exporter, the PNG rasterizer, everything. Refactored today into files that each do one thing: logos.go: the ASCII logos colors.go: color schemes and the ANSI → hex table config.go: reads ~/.wakatime.cfg hackatime.go: the API client, caching, and language inference sysinfo.go: OS, shell, editor, terminal setup.go: the -setup flow render.go: terminal render, watch loop, and layout export.go: SVG, PNG, and JPG exporters main.go: just flag parsing and the entry point (~100 lines instead of 1,600) Same binary, same behavior, zero user-visible change. But next time I want to add a new logo or a new color scheme, I know exactly which file to open. Also way friendlier for anyone who wants to hack on it. Ship Both landed in v1.7.1. If you already have it: brew update brew upgrade hackfetch Or the curl installer will pull v1.7.1 the next time you run it. Try it."}, {"post_id": 23812, "ts": "2026-07-06T23:42:52Z", "hours": 7.1119, "text": "New feature today: hackfetch can turn itself into a shareable image. The goal was simple: your terminal fetch should be more than a terminal thing. If it looks cool on your screen, you should be able to post it in a Slack channel or drop it in a devlog without ever having to take a screenshot. hackfetch -export card.svg Run that and instead of printing to your terminal, hackfetch writes an SVG file that looks exactly like the fetch on your screen: logo on the left, stats on the right, rounded corners, monospace font, every color preserved. Getting the general SVG output was the easy part. Draw a rectangle, put text inside it, done. The hard part was preserving the colors. Terminals speak ANSI 256-color codes. SVGs speak hex color strings. They don’t line up one-to-one, so a naive export just drops every color and produces a black-and-white version of the fetch. Not very shareable. The fix: a lookup table from ANSI 256-color codes to hex values, plus a rendering path that emits every styled character as its own SVG element with the correct fill color. That’s actually a lot of tspans. Schemes like per-char, where every single glyph has its own gradient stop, can produce hundreds of colored elements per fetch. But it works. The SVG renders smoothly in any browser and looks identical to what shows up in your terminal. Use It Anywhere Some things you can do with the exported card: open it in a browser to see it drop it into a Slack channel or a devlog convert it to PNG with rsvg-convert if you need a raster image hackfetch -export card.svg trans Open it. Post it. Ship it."}, {"post_id": 19472, "ts": "2026-06-30T20:03:24Z", "hours": 2.2483, "text": "Live Hackfetch New milestone today: hackfetch can now stay open and update itself while you code. The goal was simple: run hackfetch once, leave it in the corner of your terminal, and watch the numbers move in real time as you work. hackfetch -watch Your today-hours tick up. Your top project changes when you switch repos. Your streak rolls over at midnight. All without running the command a second time. The static render was already in place from the regular one-shot fetch. The new part was redrawing without scrolling. That sounds simple. It is not. In a terminal, every time you print something, it appends to the bottom of the screen. By default, refreshing the fetch would just print a second copy of itself underneath the first, then a third, then a fourth. Within a minute you’d have a wall of identical fetches scrolling away into the past. The trick is ANSI escape codes. There’s a sequence that means “move the cursor up N lines” and one that means “clear the rest of the screen from here down.” Together they let you erase the previous fetch and redraw a new one in the same spot. Same screen, fresh data, no scroll. Why every 30 seconds? Two reasons: Hackatime aggregates heartbeats in 1-minute buckets internally, so polling faster than that doesn’t tell you anything new 30 seconds is fast enough to feel “live” without hammering the API for no reason Ctrl+C to quit. Resizing the terminal doesn’t break it. Pair it with a gradient color scheme and the whole thing turns into a tiny dashboard for your coding session: hackfetch -watch sunset"}, {"post_id": 16604, "ts": "2026-06-27T00:38:28Z", "hours": 0.5825, "text": "Hackfetch Installs Itself Anywhere Hackfetch crossed another milestone today: you no longer need Go installed to use it. Or Homebrew. Or anything, really. The goal was simple: one command, any Linux, any Mac, no prerequisites. curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Run that on Ubuntu, Fedora, Alpine, Arch, openSUSE, whatever you have, and a few seconds later hackfetch is on your PATH. Getting the basic installer working was the easy part. Detect your OS, detect your CPU architecture, grab the matching binary from GitHub Releases, drop it in /usr/local/bin. Standard installer stuff. The harder problem was the script itself failing on some Linuxes. I’d written the first version in Bash, with set -euo pipefail at the top and $'\\033[1m' style escape sequences sprinkled through. Worked great on my Mac. Worked great on Ubuntu. Then I checked which shell Alpine Linux ships by default. Not Bash. The whole script would die on line one for anyone on a minimal container. So I rewrote it in POSIX sh, which is the one shell every Unix system actually has. No Bash-isms, no fancy quoting, no pipefail. Smaller, dumber, way more portable. Speaking Seven Package Managers The next problem: the script needs curl and tar to do its job. If you don’t have them, normally you’d just be stuck. Instead, the installer now detects your system’s package manager and installs the missing prereqs for you: apt (Debian, Ubuntu) dnf (Fedora, RHEL) yum (CentOS, older RHEL) pacman (Arch) zypper (openSUSE) apk (Alpine) brew (macOS) They all do the same thing. They all use different words for it. The installer knows all seven. One line. Any Linux. No prereqs."}, {"post_id": 15120, "ts": "2026-06-24T15:57:10Z", "hours": 0.4172, "text": "Hackfetch Meets Orpheus! If you’ve been around Hack Club for more than five minutes, you know Orpheus. The little dinosaur shows up everywhere: stickers, websites, T-shirts, hackathon merch. Until today, he wasn’t in hackfetch. That’s been bugging me since v1.0. The goal was simple: give Orpheus a spot in the logo lineup, the same way flag, bot, and rocket already have one. hackfetch orpheus Drawing him was the harder part. Every logo in hackfetch has to fit inside a fixed width of 33 characters, otherwise the system info column next to it gets pushed off the screen. 33 characters is not a lot of room to draw a recognizable dinosaur, especially one with personality. I tried him head-on first. It didn’t work. Round dinosaur faces in ASCII end up looking like blobs because you don’t have curves, only corners. So I redrew him in profile. The result: a snout sticking out to one side one big eye (◉) that catches the light a HACK CLUB body underneath two tiny stubby legs at the bottom Nine lines tall. No wasted rows. He plays especially well with the gradient color schemes: hackfetch orpheus -color forest hackfetch orpheus -color sunset Forest makes him look like he’s wandering through tall grass. Sunset gives him a “main character in the closing shot” vibe. The mascot finally has a seat at the terminal. Long overdue! Also if any better artists want to have a crack at it, I’m super open to that, and I can credit you in my repo as a collaborator! THNX!"}, {"post_id": 14410, "ts": "2026-06-23T15:08:46Z", "hours": 6.8756, "text": "Hackfetch Can Finally Fetch Hackfetch crossed a pretty big milestone today: it actually fetches things. The goal is simple: build a Neofetch-style dashboard for Hack Club. Run a single command and get a snapshot of your machine alongside your Hack Club activity. hackfetch and instantly see information like: OS Hostname Username Shell Terminal Editor Hackatime stats Getting the system information was the easy part. Go makes it straightforward to grab things like the current user, hostname, operating system, and environment variables. The harder problem was rendering everything cleanly beside an ASCII logo. Each logo has different dimensions and line lengths, so I ended up building a small layout engine that calculates the width of every logo row and pads it dynamically before printing the corresponding information. Without that, the text column slowly drifts into the logo and the entire fetch screen looks broken. Hooking into Hackatime The more interesting work was integrating with the Hackatime API.Hackfetch reads your API key from: ~/.wakatime.cfg authenticates with Hackatime, and pulls fresh coding statistics every time you run the command.Right now it can display: Today’s coding time Weekly coding time Current streak Top project Most-used language No browser. No dashboard. Just a terminal command."}, {"post_id": 7579, "ts": "2026-06-12T17:50:14Z", "hours": 0.5989, "text": "In honor of pride month, I have added a pride color scheme to my custom hackfetch. It is currently installable via brew. On macs, simply run: brew install xerneas3318/tap/hackfetch Currently working on better support for more operating systems. Follow and like to stay updated!"}, {"post_id": 7526, "ts": "2026-06-12T15:50:51Z", "hours": 8.7181, "text": "Introducing hackfetch a tiny terminal fetch tool for hackatime. Run hackfetch and get your hours today, weekly total, streak, top project, and top language right in your terminal. 5 logos. 8 color schemes. mix and match: hackfetch stardance rainbow How it works: hackfetch reads your hackatime key from ~/.wakatime.cfg, fetches your Hackatime summaries and heartbeats, then renders your stats directly in the terminal."}]...
|
Title: Hackfetch by @xerneas | Stardance
Devlogs: Title: Hackfetch by @xerneas | Stardance
Devlogs:
Introducing hackfetch a tiny terminal fetch tool for hackatime. Run hackfetch and get your hours today, weekly total, streak, top project, and top language right in your terminal. 5 logos. 8 color schemes. mix and match: hackfetch stardance rainbow How it works: hackfetch reads your hackatime key from ~/.wakatime.cfg, fetches your Hackatime summaries and heartbeats, then renders your stats directly in the terminal.
In honor of pride month, I have added a pride color scheme to my custom hackfetch. It is currently installable via brew. On macs, simply run: brew install xerneas3318/tap/hackfetch Currently working on better support for more operating systems. Follow and like to stay updated!
Hackfetch Can Finally Fetch Hackfetch crossed a pretty big milestone today: it actually fetches things. The goal is simple: build a Neofetch-style dashboard for Hack Club. Run a single command and get a snapshot of your machine alongside your Hack Club activity. hackfetch and instantly see information like: OS Hostname Username Shell Terminal Editor Hackatime stats Getting the system information was the easy part. Go makes it straightforward to grab things like the current user, hostname, operating system, and environment variables. The harder problem was rendering everything cleanly beside an ASCII logo. Each logo has different dimensions and line lengths, so I ended up building a small layout engine that calculates the width of every logo row and pads it dynamically before printing the corresponding information. Without that, the text column slowly drifts into the logo and the entire fetch screen looks broken. Hooking into Hackatime The more interesting work was integrating with the Hackatime API.Hackfetch reads your API key from: ~/.wakatime.cfg authenticates with Hackatime, and pulls fresh coding statistics every time you run the command.Right now it can display: Today’s coding time Weekly coding time Current streak Top project Most-used language No browser. No dashboard. Just a terminal command.
Hackfetch Meets Orpheus! If you’ve been around Hack Club for more than five minutes, you know Orpheus. The little dinosaur shows up everywhere: stickers, websites, T-shirts, hackathon merch. Until today, he wasn’t in hackfetch. That’s been bugging me since v1.0. The goal was simple: give Orpheus a spot in the logo lineup, the same way flag, bot, and rocket already have one. hackfetch orpheus Drawing him was the harder part. Every logo in hackfetch has to fit inside a fixed width of 33 characters, otherwise the system info column next to it gets pushed off the screen. 33 characters is not a lot of room to draw a recognizable dinosaur, especially one with personality. I tried him head-on first. It didn’t work. Round dinosaur faces in ASCII end up looking like blobs because you don’t have curves, only corners. So I redrew him in profile. The result: a snout sticking out to one side one big eye (◉) that catches the light a HACK CLUB body underneath two tiny stubby legs at the bottom Nine lines tall. No wasted rows. He plays especially well with the gradient color schemes: hackfetch orpheus -color forest hackfetch orpheus -color sunset Forest makes him look like he’s wandering through tall grass. Sunset gives him a “main character in the closing shot” vibe. The mascot finally has a seat at the terminal. Long overdue! Also if any better artists want to have a crack at it, I’m super open to that, and I can credit you in my repo as a collaborator! THNX!
Hackfetch Installs Itself Anywhere Hackfetch crossed another milestone today: you no longer need Go installed to use it. Or Homebrew. Or anything, really. The goal was simple: one command, any Linux, any Mac, no prerequisites. curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Run that on Ubuntu, Fedora, Alpine, Arch, openSUSE, whatever you have, and a few seconds later hackfetch is on your PATH. Getting the basic installer working was the easy part. Detect your OS, detect your CPU architecture, grab the matching binary from GitHub Releases, drop it in /usr/local/bin. Standard installer stuff. The harder problem was the script itself failing on some Linuxes. I’d written the first version in Bash, with set -euo pipefail at the top and $'\033[1m' style escape sequences sprinkled through. Worked great on my Mac. Worked great on Ubuntu. Then I checked which shell Alpine Linux ships by default. Not Bash. The whole script would die on line one for anyone on a minimal container. So I rewrote it in POSIX sh, which is the one shell every Unix system actually has. No Bash-isms, no fancy quoting, no pipefail. Smaller, dumber, way more portable. Speaking Seven Package Managers The next problem: the script needs curl and tar to do its job. If you don’t have them, normally you’d just be stuck. Instead, the installer now detects your system’s package manager and installs the missing prereqs for you: apt (Debian, Ubuntu) dnf (Fedora, RHEL) yum (CentOS, older RHEL) pacman (Arch) zypper (openSUSE) apk (Alpine) brew (macOS) They all do the same thing. They all use different words for it. The installer knows all seven. One line. Any Linux. No prereqs.
Live Hackfetch New milestone today: hackfetch can now stay open and update itself while you code. The goal was simple: run hackfetch once, leave it in the corner of your terminal, and watch the numbers move in real time as you work. hackfetch -watch Your today-hours tick up. Your top project changes when you switch repos. Your streak rolls over at midnight. All without running the command a second time. The static render was already in place from the regular one-shot fetch. The new part was redrawing without scrolling. That sounds simple. It is not. In a terminal, every time you print something, it appends to the bottom of the screen. By default, refreshing the fetch would just print a second copy of itself underneath the first, then a third, then a fourth. Within a minute you’d have a wall of identical fetches scrolling away into the past. The trick is ANSI escape codes. There’s a sequence that means “move the cursor up N lines” and one that means “clear the rest of the screen from here down.” Together they let you erase the previous fetch and redraw a new one in the same spot. Same screen, fresh data, no scroll. Why every 30 seconds? Two reasons: Hackatime aggregates heartbeats in 1-minute buckets internally, so polling faster than that doesn’t tell you anything new 30 seconds is fast enough to feel “live” without hammering the API for no reason Ctrl+C to quit. Resizing the terminal doesn’t break it. Pair it with a gradient color scheme and the whole thing turns into a tiny dashboard for your coding session: hackfetch -watch sunset
New feature today: hackfetch can turn itself into a shareable image. The goal was simple: your terminal fetch should be more than a terminal thing. If it looks cool on your screen, you should be able to post it in a Slack channel or drop it in a devlog without ever having to take a screenshot. hackfetch -export card.svg Run that and instead of printing to your terminal, hackfetch writes an SVG file that looks exactly like the fetch on your screen: logo on the left, stats on the right, rounded corners, monospace font, every color preserved. Getting the general SVG output was the easy part. Draw a rectangle, put text inside it, done. The hard part was preserving the colors. Terminals speak ANSI 256-color codes. SVGs speak hex color strings. They don’t line up one-to-one, so a naive export just drops every color and produces a black-and-white version of the fetch. Not very shareable. The fix: a lookup table from ANSI 256-color codes to hex values, plus a rendering path that emits every styled character as its own SVG element with the correct fill color. That’s actually a lot of tspans. Schemes like per-char, where every single glyph has its own gradient stop, can produce hundreds of colored elements per fetch. But it works. The SVG renders smoothly in any browser and looks identical to what shows up in your terminal. Use It Anywhere Some things you can do with the exported card: open it in a browser to see it drop it into a Slack channel or a devlog convert it to PNG with rsvg-convert if you need a raster image hackfetch -export card.svg trans Open it. Post it. Ship it.
Loading Spinner and Splitting Up main.go Thanks so much to everyone who took the time to comment, rate, and drop feedback on my latest ship. All of it was genuinely so helpful and I’ve been spending the last couple days fixing things up a bit. I totally forgot to devlog so I’m actually losing a couple hours since it’s been over ten hours since my last one :sob A loading spinner while Hackatime fetches One reviewer pointed out that hackfetch takes a couple of seconds when it’s pulling your Hackatime stats for the first time, and there was no signal that anything was happening. Now there is. ⠋ fetching Hackatime... The spinner cycles through 10 braille frames and the whole line clears out the instant the fetch finishes. Same fetch, way less awkward pause. Two small details that make it feel right: It only shows when stderr is actually a terminal, so it doesn’t spam control codes into your log files if you redirect output. It prints one frame immediately, so fast fetches still flash something instead of nothing. hackfetch runs it around the API calls automatically. No config, no opt-in. It’s just there. Splitting up main.go Another reviewer said the 1.5k-line file was too much. They were completely right. hackfetch had grown into one giant main.go that held the logos, the color schemes, the Hackatime API client, the terminal render, the SVG exporter, the PNG rasterizer, everything. Refactored today into files that each do one thing: logos.go: the ASCII logos colors.go: color schemes and the ANSI → hex table config.go: reads ~/.wakatime.cfg hackatime.go: the API client, caching, and language inference sysinfo.go: OS, shell, editor, terminal setup.go: the -setup flow render.go: terminal render, watch loop, and layout export.go: SVG, PNG, and JPG exporters main.go: just flag parsing and the entry point (~100 lines instead of 1,600) Same binary, same behavior, zero user-visible change. But next time I want to add a new logo or a new color scheme, I know exactly which file to open. Also way friendlier for anyone who wants to hack on it. Ship Both landed in v1.7.1. If you already have it: brew update brew upgrade hackfetch Or the curl installer will pull v1.7.1 the next time you run it. Try it.
Hackfetch Is Now Actually Fast Last log I added a loading spinner so you’d have something to look at while hackfetch was hitting the Hackatime API. This week I made it so you barely have time to see the spinner at all (undoing all my work lol) The problem hackfetch was making four separate calls to Hackatime for every fetch: /users/current/heartbeats/most_recent (for your slack handle) /users/current/summaries (for your streak) /users/current/statusbar/today (for today's coding time) /users/current/stats/last_7_days (for weekly stats) Doing them one after another meant the total wait was the sum of all four. Turns out that’s about 1.7 seconds on a normal connection. Not the end of the world, but very noticeable when you just want to open a terminal. The fix: run them all at the same time Now hackfetch fires all four calls in parallel using goroutines, waits for the slowest one to come back, and then builds the fetch from the responses. Total wait drops from “sum of all four” to “just the slowest one.” Before: ~1.7 seconds After: ~0.7 seconds 60% faster . Every single fetch. Every single time. One tiny bonus optimization While I was in there, I also switched to a single shared HTTP client with a bigger connection pool. The default Go setup caps you at 2 open connections per host, which is fine when you’re calling one endpoint at a time but hurts when you’re firing four at once. Now the parallel calls can share connections instead of stacking up on each other. Nothing about the fetch itself changed. Same info, same layout, same colors. Just faster. Ship Shipped in v1.7.2. If you have hackfetch installed: brew update brew upgrade hackfetch time hackfetch Watch the spinner barely have time to appear.
One More Way to Install (and Pizza) Two small things today: hackfetch is now on the AUR, and there’s a new logo. hackfetch on the AUR A reviewer on my last ship said they had a hard time getting hackfetch running on CachyOS (an Arch-based Linux distro). Instead of trying to reproduce their exact issue, I figured the cleanest fix was to publish hackfetch through the package manager Arch users already trust. So hackfetch is now up as hackfetch-bin on the AUR: aur.archlinux.org/packages/hackfetch-bin If you’re on Arch, CachyOS, Manjaro, EndeavourOS, Garuda, or any other Arch-based distro: yay -S hackfetch-bin Or with paru: paru -S hackfetch-bin The package pulls the pre-built binary straight from the GitHub release, so there’s no waiting on a source build. Works on both x86_64 and aarch64 . Add it up and hackfetch is now installable one command from: brew (macOS and Linuxbrew) apt / dnf / yum / pacman / zypper / apk (all through the curl installer) the AUR (Arch family) go install (any platform with Go) the PowerShell installer (Windows) This thing is getting kind of hard to NOT install. Pizza logo Hack Club runs on pizza. Now hackfetch does too. hackfetch pizza It’s a triangular slice viewed from the tip, HACK CLUB baked into the middle, and a rolled crust at the wide edge. The tricky part was the crust. I went through three drafts trying to make it curve at the bottom without breaking the connection to the slice’s diagonal sides (turns out you can’t cleanly connect diagonal characters to horizontal ones in a monospace grid). Landed on a two-row rolled crust where the diagonals keep going and the interior fills with a double horizontal band. Pairs surprisingly well with sunset: hackfetch pizza sunset Turns your terminal into a golden-hour pizza box. Ship Both landed in v1.7.3 . If you’re on Arch-family: yay -S hackfetch-bin Elsewhere: brew update brew upgrade hackfetch Now try hackfetch pizza and tell me if the crust looks right.
Hackfetch Gets Real Colors New thing today: hackfetch now emits 24-bit color when your terminal supports it, and spreads gradients smoothly across each row instead of cycling through the palette one character at a time. Before and after Old behavior: for a per-char scheme like rainbow , each character got exactly one palette entry, wrapping around every N characters. On a 30-column row with a 3-color palette, that looked like ten cycles of red, green, blue, red, green, blue… basically RGB static. New behavior: the palette spreads across the row once, and characters between palette entries get interpolated in-between colors. Same 3-color palette on a 30-column row now shows red, olive, green, teal, blue, magenta, back to red. Why the rebuild Terminals speak two color modes: 256-color ( \x1b[38;5;Nm ): pick from a fixed palette of 256 preset RGB values. 24-bit / truecolor ( \x1b[38;2;R;G;Bm ): specify any of ~16 million RGB values directly. The old code always used 256-color. That meant every character had to snap to one of the palette entries. No in-betweens possible. The new code checks $COLORTERM (set to truecolor by iTerm2, kitty, WezTerm, Alacritty, GNOME Terminal, and most modern terminals) and emits 24-bit escapes when supported. When it’s not, it falls back to the old cycled-palette behavior automatically. You can force it either way with HACKFETCH_TRUECOLOR=1 or =0 . Where you’ll notice it The built-in rainbow scheme has 23 palette stops, so the difference on that one is small. You just see a smoother color distribution and less banding. The change is dramatic on: custom themes with few stops (try 3 colors in your ~/.config/hackfetch/colors.json for the wildest gradient) the stardance palette (11 stops, per-char), where sparkles now flow through the spectrum in order instead of landing on random-looking colors any per-line scheme ( pride , trans , bi , pan , sunset , ocean , forest ) since they now emit exact RGB values instead of nearest-256-color Bonus: the SVG, PNG, and JPG export paths use the smooth interpolation too, so exported cards look better regardless of your terminal. Ship Landed in v1.8.0 . brew update brew upgrade hackfetch Or on the Arch family: yay -Syu hackfetch-bin Try hackfetch rocket forest and just watch.
hackfetch is now TMUX + NVIM COMPATIBLE new thing today: hackfetch will just show up wherever you already look. tmux status bar. nvim statusline. any tool that can shell out to a command and put text on a screen. The addition was simple: hackfetch -status prints one line: 2h 11m today · hackfetch (45m) · streak 12 just the numbers, for tools that already have their own rendering. hackfetch is a data source now, not just a display. in tmux two lines in ~/.tmux.conf : set -g status-interval 60 thats it. every tmux session, every window, refreshing once a minute. i dropped it in a pink Catppuccin capsule to the left of my existing date capsule and now i cant stop glancing at it lol. in neovim (lualine) same story, five lines of lua: sections = { lualine_z = { function () return vim . fn . system ( "hackfetch -status" ): gsub ( " \n " , "" ) end } } } shells out on every redraw. works with airline too, or any custom statusline that lets you plug in a function. the fun part making hackfetch call safe for “something tmux runs every 60s forever” meant fixing three assumptions the normal fetch was making. this was way harder than it should have been ngl. setup cant block. if you dont have ~/.wakatime.cfg, normal hackfetch throws you into an interactive setup wizard (ask me how i know). in status mode that would freeze your tmux bar until you notice and Ctrl+C it. so status mode is fully non interactive now. no config → print nothing → tmux shows nothing → no deadlock 🙏 api errors cant leak into your bar. hackatime offline? old behavior would dump HTTP 500 timeout into your status area which looks INSANE. now status mode exits silently instead so your bar stays clean every call has to be cheap. hackfetch’s parallel fetch alr seconds, and the shared HTTP client keeps connections alive across the 4 API calls it fires, so tmux polling every 60s is easy on the API. a proper local file cache is on the list for later but honestly not needed for now (i’m lazy) ship landed in v1.9.0. if you already have it: brew update brew upgrade hackfetch or arch family: yay -Syu hackfetch-bin (for more installs for ur specific os check out the github pls) then drop the tmux or lualine snippet above into your dotfiles and its just there in every terminal. no plugin. no config. no daemon. just a flag.
caching or i owe hackclub money so heres what my day looked like: nvim was calling hackfetch -status on every redraw for my lualine. tmux was calling it every 60 seconds for the status bar. i had 3 tmux sessions open. and every time i actually opened a new terminal, hackfetch fired again on shell start. quick napkin math: nvim redraws are basically continuous when im typing, tmux was hitting the api 3x/minute across sessions, plus every terminal open = another fetch. we’re talking hundreds of calls to hackatime in a normal work session. from ONE user. me hackatime is a free hack club service and i was starting to feel bad lol. the fix: cache the response ~/.cache/hackfetch/last.json stores the last snapshot with a timestamp. every fetch checks that file first. if its fresh enough, skip the network entirely and just render from disk. TTL is different depending on the caller: hackfetch (one-shot): 30 seconds. long enough that a normal re-run inside a devlog attempt is instant, short enough that you dont get badly stale numbers. hackfetch -status: 60 seconds tmux polls roughly this often anyway so its basically free now. hackfetch -watch: ignores the cache, always fresh (thats the whole point of watch mode). opt out with -no-cache or HACKFETCH_CACHE_TTL=0 if you want. also HACKFETCH_CACHE_TTL=300 to be even more polite. So yea tmux is now basically free . but the real win writing this made me realize the cache does more than save milliseconds: every fetch was a full TLS handshake, wifi radio spin up, etc. now most fetches touch the disk once and nothing else. macbook fan appreciates it. offline. if your wifi drops mid coding session you keep working from the cache instead of showing a spinner forever. tmux bar just keeps saying what it said 40 seconds ago. battery again but for the hackatime server. hackfetch stops asking the api 5-10x more than they need to. multiply by everyone who has it in their tmux config and thats a real thing. atomic write via .tmp + rename so nothing ever reads a half-written file. cache is user-only (0600), because it does contain your top project name. bonus: -doctor while i was fixing the polite-to-the-api stuff i added -doctor , which walks a checklist and tells you whats broken: hackfetch doctor ✓ wakatime config exists /Users/xerneas/.wakatime.cfg ✓ api_key present loaded from config ✓ wakatime-cli found /Users/xerneas/.wakatime/wakatime-cli ✓ hackatime api reachable today: 28m ✓ terminal supports truecolor $COLORTERM=truecolor ✓ browser opener available /usr/bin/open green if its working, orange if its not, and non-zero exit if anything failed so you can script it. this was going to be a small self-diagnosis feature and it caught a real bug in the api client on the very first run i did while writing it lol (a string field where hackatime returns an int, so one of the fields was silently missing from every fetch since v1.0). fixed that too. ship both landed in v1.10.0. update as usual: brew update brew upgrade hackfetch or arch: yay -Syu hackfetch-bin then run hackfetch -doctor first, and if anything is broken it’ll tell you exactly what.
my streak was lying to me for a month went to add a simple 7-day sparkline. by the end of the night i had rewritten how hackfetch talks to hackatime and my streak field is finally accurate for the first time in weeks. the plan was get the status from the last 7 days. draw ▁▂▃▄▅▆▇█ bars except the endpoint i needed straight up 404s. /users/current/summaries doesnt exist on the current hackatime deployment. Which means every single time i ran hackfetch it was quietly making a 30-day range call that always failed, then falling back to a placeholder that said “if today has activity, streak = 1”. thats it. no matter how long ive actually been on a streak, the fetch would just show 1 day. 🤦 my streak has said 1 day for the last 2 weeks even though ive been coding literally every day. never noticed because 1 day looks kinda plausible (i added 1 day as a fallback so that it didn’t show an error a couple weeks ago and forgot ) the fix: went digging in hackatimes rails routes on github. turns out theres a whole /api/v1/ namespace i was never using. and one of the endpoints is /api/v1/users/:id/heartbeats/spans. one call, ~150kb of json, every coding session ive ever logged with start_time, end_time, duration. 2000+ spans. which is exactly what i need for both features. bucket the timestamps by local calendar day, count unique days for streak, sum durations per day for the sparkline. one request covers both. and while i was already in the api layer i noticed fetchUser was making a whole separate call for my slack handle, which is silly because that data is already in the weekly stats response we cache. so i piggybacked it. weve gone from 4 api calls per fetch to 3. the sparkline: 7-day chart ▄▄▇▅▄▅▃ 65h 28m oldest on the left, newest on the right. that tall bar in the middle is a big lock-in session from earlier in the week. the two shorter ones on the right are today (still coding) and yesterday (took a break). opt in for -status --sparkline if you want it in your tmux bar too: 2h 9m today · streak 9 · ▄▄▇▅▄▅▃ 65h 28m teasing a backend: I’m planning on building a whole leaderboard server on a free hack club nest box so people can compete on their hackatime hours. while i was poking around the routes file for the streak fix i noticed something. /api/v1/leaderboard/daily and /api/v1/leaderboard/weekly already exist. public. no auth needed. no server needed. no cron sync. hackatime literally already has it directly. so hackfetch -leaderboard is coming soon (private friend groups and personal competitions can come later) last devlog before my next ship after the ship the devlogs are going to be huge. stay tuned :P
hackfetch COLLAB?? so my last two devlogs teased two features. shipping both today. -leaderboard last devlog i said “compete with your friends on hackatime hours is coming soon.” i thought i was gonna have to build a whole nest server for it. turns out /api/v1/leaderboard/daily and /api/v1/leaderboard/weekly already exist and are public on hackatime. just a single call!! so hackfetch -leaderboard daily (or weekly) now shows the top 10: ✦ daily leaderboard Last 24 hours 🥇 1. soaphia14 11h 12m 🥈 2. AnastKara 10h 32m 🥉 3. RoSerMar 10h 6m 4. euledone 10h 5. TheShovel 10h 6. Dylhouse 9h 1m 7. Dexrn 8h 59m 8. HexFud 8h 31m 9. zeddash 8h 29m 10. Trtotomotoro 8h 26m every username is an OSC 8 clickable link to that person’s hackatime profile. modern terminals (iterm2, kitty, wezterm, alacritty, gnome-terminal) render it as an actual hyperlink you can click. terminals without OSC 8 just show the plain text so it doesnt look broken. if you’re on the board it highlights your row in orange and adds (you) next to your name. json addon the other thing. someone else competing in stardance messaged me the other day about integrating hackatime into their own project and needed help figuring out the api (YAY). helping them made me realize hackfetch is doing a bunch of work (auth, caching, streak reconstruction, per-day bucketing) that other tools would love to piggyback on. so now: $ hackfetch -json { "version": "2", "fetched_at": "2026-07-25T17:00: 20.900829+05:30", "system": { "user": "xerneas", "host": "Macbook-Pro", "os": "macOS 26.5.2", ... }, "hackatime": { "slack": "@U0B8FHHRQPJ", "streak": 12, "today_seconds": 15820, "week_seconds": 237501, "top_project": { "name": "hackfetch", " "top_language": { "name": "Go", "seconds": 97418 }, "week_chart": [36967, 31651, 33841, 284 "machines": 3 } } week_chart is 7 numbers = daily seconds oldest to newest same as the sparkline. top_language skips the unknown/other buckets. everything lines up with what the normal fetch would show, just parseable. ship landed in v2.1.0. brew update && brew upgrade hackfetch or arch: yay -Syu hackfetch-bin then try: hackfetch -leaderboard weekly hackfetch -json | jq For a general install use: curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh
big thank you for everyone’s feedback! fresh out of the oven: hackfetch v2.1.1 (aka the reviewer bug fix pass) what got fixed: shell detection used to just read $SHELL which is your login shell. if you log in as bash but run fish, hackfetch was calling you a bash user. it now checks $FISH_VERSION / $ZSH_VERSION / $BASH_VERSION and falls back to asking the OS who your parent process actually is editor detection was two bugs in a trench coat. it wasnt stripping args so zeditor --wait showed up as “zeditor –wait” instead of “Zed”, and if you had no $EDITOR set it defaulted to nano even if you had literally never opened nano. now it strips flags, maps launcher names to human ones (zeditor -> Zed, code -> VS Code, cursor -> Cursor, hx -> Helix etc), and says “-” instead of nano if nothing is set. top project label was ambiguous. it was pulling weekly stats but the row just said “top project” so people thought it meant all time. now weekly rows read top proj 7d , top lang 7d , top ed 7d , top cat 7d . setup dialog was scaring people. it always printed “file exists but has no api_key” whenever it reached the setup flow, even if the api_key line was actually there but just failing to parse. loadConfig is now more forgiving (inline comments, quoted values, case insensitive keys) and setup tells you WHY its stuck instead of gaslighting you about your own config. also short circuits if you run hackfetch -setup when youre already set up. people said they wanted a gay flag color was already there under the name pride but that wasnt obvious. gay is now an alias so both work. grab it: brew upgrade hackfetch or yay -S hackfetch-bin or curl / powershell installer if you don’t have it yet curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh again thank you to everyone who took the time to actually run it and tell me what was broken!
HACKFETCH BATTLES??? two features in one release. hackfetch already knows a scary amount about you (thanks hackatime) so why not turn that into more features. hackfetch vs @ someone head to head compare. give it a hackatime username and hackfetch fetches both your histories in parallel, buckets them into today / this week / all time / streak, and prints them side by side with a winner arrow on every row. accepts @name , name , or a full profile url like hackatime.hackclub.com/@name . also works positional: hackfetch vs @you . use it to settle arguments, motivate yourself, or realize your friend has coded 265 hours and you should probably close discord. hackfetch -records personal bests. computed entirely from data hackfetch already fetches (streak + sparkline already use it), so zero new api calls $ hackfetch -records ✦ personal records @you biggest day 12h 41m on 2026-07-18 longest streak 25 days ended 2026-07-01 longest session 43m on 2026-07-17 days coded 86 first day 2026-04-24 99 days ago lifetime 208h 29m the “longest streak” tracks your all time best not just your current one. and “first day” tells you how long ago you started so you can feel old. grab it brew upgrade hackfetch yay -S hackfetch-bin install curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Next devlog is gonna be a fun one, I have an idea cooking up
Hackfetdch natively in your readme hackfetch -readme it spits out a markdown stats card ready to paste straight into your github profile README. pipe it into a file and commit: hackfetch -readme > stats.md this is the cool bit or drop it in your README.md between two html comments and set up a github action to run it on a schedule so it auto refreshes every day. your profile now has a live coding stats card next to your pinned repos with no cron server, no vercel deploy, no api key stashed in secrets. its literally just markdown. zero extra api calls too. the readme card reads from the same cached hackatime response the normal fetch uses so if you just ran hackfetch it takes ~20ms. the streak emoji is a lil detail i had fun with. 3+ days gets a 🔥 upgrade with brew upgrade hackfetch or yay -S hackfetch-bin (once aur maintenance wraps up) or curl the installer curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh
Ships:
Every fetch tool tells you your OS. Mine tells you your streak. hackfetch is a Hack Club themed terminal fetch tool. Inspired by neofetch (originally bash, now archived) and fastfetch (its C successor), written in pure Go. Instead of just showing your kernel and CPU, it pulls live stats from your Hackatime account: today’s hours, weekly total, current streak, top project, top language. Right in your terminal. Six Hack Club themed ASCII logos (including my GOAT orpheus). Fourteen color schemes (pride, trans, bi, pan included). Live watch mode that refreshes while you code. And as of today, you can export the whole thing as a PNG, JPG, or SVG card and post it anywhere. One line to install: Linux / Mac: curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Windows: irm https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.ps1 | iex Tell me how it was! Follow and like for updates.
HACKFETCH V2.0 it’s been a few weeks since ship #1 and hackfetch is a completely different tool now. faster, smaller, quieter, actually correct, and now lives in places besides your terminal window. v2.0.0 is out. what changed: fits in your tmux status bar with one line of config. same story for lualine. hackfetch -status prints a compact one-liner meant to be shelled out to every minute. fits everywhere else too. now on the AUR (yay -S hackfetch-bin) alongside the existing brew tap, curl installer, powershell installer, and go install. seven install channels total. runs in ~20ms on repeat calls thanks to an on-disk cache. tmux polling every minute is basically free now. was ~700ms cold before. runs in ~0.7s cold thanks to a parallel API fetch. was ~1.7s before. shows a smooth truecolor gradient on any modern terminal. auto-detects $COLORTERM. falls back to 256-color on older ones. -doctor walks a colored checklist of your setup and tells you exactly what’s broken. green if fine, orange if not, non-zero exit if you wanna script it. new pizza logo because hack club runs on pizza. seven logos total. streak is finally correct after silently saying “1 day” for a month. /summaries is gone from hackatime so hackfetch now reconstructs streak from every coding session in your history via /heartbeats/spans. real streak: 9 days for me right now. 7-day sparkline baked into the fetch (with -v) and available as -status –sparkline for the tmux bar. default fetch got leaner. slack handle, machines count, and the sparkline moved behind -v so the normal fetch stays focused on hours + project + language. loading spinner on the api fetch so you know something is happening. and then the cache made it show up almost never. one install: Linux / Mac: curl -fsSL https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.sh | sh Windows: irm https://raw.githubusercontent.com/xerneas3318/hackfetch/main/install.ps1 | iex Arch family: yay -S hackfetch-bin macOS / Linuxbrew: brew install xerneas3318/tap/hackfetch For more install methods check out the github page: https://github.com/xerneas3318/hackfetch teasing the next big thing: hackfetch -leaderboard is coming next, using the public leaderboard endpoints i found in hackatime’s routes file. compete with friends on daily and weekly hours right from your terminal. private friend groups on a hackclub nest box after that. if you try it, thanks. send me some feedback...
|
1792878603.0227313
|
1793742603.0227313
|
|
25109
|
Into the cosmos by @tejaswa | Stardance
|
tejaswa
|
3
|
124.31
|
2584
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-08-16T04:20:51Z", "hours": 54.0, "multiplier": 19.58, "payout": 1259, "blessing": "neutral", "text": "INTO THE COSMOS This is the game i have designed with inspiration from Spaceflight sim and Kerbal Space program, i wanted to capture the total freedom of roaming in space without the stress of designing a space vehicle for hours just for it to crash into a million pieces. I wanted to make a chill relaxing game that people can come back home after a long day of work to, boot it up and have fun just roaming the eternal space without stressing out. Im quiet proud of how im capturing this vision of mine and im very happy with what im making. Heres some information of what i added this ship: I’ve basically been adding a bunch of systems that I’ve wanted in the game for a while, and the game is starting to feel a lot more like an actual sandbox now. First thing, I finally added electricity. This is probably one of the systems I’m most interested in because now I can actually start making more things depend on power instead of everything magically working forever. This also gives me a lot more stuff I can do with spacecraft and bases in the future. I also added scraps and scrap refining. You can now collect scraps while exploring and actually do something with them instead of them just being random useless objects. I’ve also added the material processing system around this, so scraps can be refined into materials that can actually be used to build useful buildings. This is going to become a much bigger system later on. ROVERS ARE FINALLY HERE You can now actually drive around on planets instead of just landing there and leaving. I really wanted this because the planets were starting to feel a little pointless once you landed on them. Now you can actually get out there and explore the surface properly. I’ve also added planet properties. Planets now have their own properties which means I can start making different planets actually matter instead of them just being randomly generated balls you land on. There’s a lot I can do with this later, especially with resources and exploration. I also did a pretty big overhaul on the visuals. The ambiance shaders have been improved and I’ve added a bunch of new stuff to make the planets and space itself look better. black holes now also have a hidden easter egg…. Ive also given every planet a beautiful atmosphere And yes. Mudfish I don’t know why. They’re still stupid. They just walk around on planets doing absolutely nothing useful. But honestly the universe felt too empty without them so I’m keeping them. A lot of this update was also spent doing optimization because some of the newer systems were starting to get pretty heavy. I’ve been going through different parts of the game and trying to make everything run better without completely murdering the visuals. Overall this update is probably one of the biggest changes to the game so far. And I still have a stupid amount of things I want to add. https://www.youtube.com/watch?v=ZZg3blASmgc This is the link to the youtube video if you dont have time to review the game PLEASE check it out and rate the project I read and appreciate every single one of you reviewing this game, please be as informative as you can be as this is one of the biggest games ive worked on till now, thx and have fun playing the game", "repo": "https://github.com/tejaswa4692/IntoTheCosmos", "demo": "https://tejaswa7692.itch.io/into-the-cosmos"}, {"ship_num": 2, "ts": "2026-07-08T12:04:25Z", "hours": 46.0, "multiplier": 19.75, "payout": 1084, "blessing": "neutral", "text": "Into the Cosmos Join Boney on a journey across the endless cosmos, where every horizon hides another world waiting to be discovered. Launch into the unknown, weave between glowing nebulae, drift past impossible black holes, and set foot on planets no one has ever seen before. Build observatories to mark your path through the stars, refuel your rocket, deploy satellites into orbit, and keep pushing farther into the infinite. And when the day is finally over, come relax with Boney and lose yourself among the stars for a while. I’ve always loved games like Kerbal Space Program and Spaceflight Simulator, but I wanted something where you could jump straight into flying without spending hours designing the perfect rocket first. The result is a sandbox space game built around realistic orbital mechanics, exploration, and simply enjoying the journey. The universe is procedurally generated, meaning there is always another unique planet waiting somewhere beyond the next launch. Every expedition can take you somewhere completely new, and every observatory you build becomes another milestone in your adventure. Satellites aren’t just for show either. Launch them into orbit, revisit them later, and use them as your eyes in the sky while you continue expanding your reach across the universe. If you’re new to orbital mechanics, don’t worry. The game includes detailed instructions, an optional on-screen keybind guide, and a full in-game settings menu that lets you tweak graphics and performance to match your hardware. Whether you’re playing on a high-end gaming PC or something much more modest, I spent a lot of time optimizing the project so as many people as possible could enjoy it smoothly. There is one place, however, that lies farther than anywhere you were ever meant to reach. Most people will never find it. Those who do usually don’t come back with an explanation. I call it The Farlands. Whether it’s a bug, a feature, or something else entirely is for you to decide. I built this game in Godot 4.6.2, spending countless hours refining the physics, procedural generation, shaders, rendering, UI, and gameplay systems. Every optimization, every visual effect, and every mechanic was added with one goal in mind: making space feel like a place you can get lost in for hours without realizing where the time went. So fuel up, trust your trajectory, and see just how far Boney can go. If you decide to give the game a try, I’d really appreciate a detailed review afterwards. The feedback I received on my last project genuinely helped shape this game into what it is today, and I’d love to hear what you think could be improved, what you enjoyed, and what you’d like to see added next. If you enjoy the project, consider starring the GitHub repository and liking the YouTube video. It really helps more people discover the game and motivates me to keep building and improving it. So fuel up, trust your trajectory, and see just how far Boney can go.", "repo": "https://github.com/tejaswa4692/IntoTheCosmos", "demo": "https://tejaswa7692.itch.io/into-the-cosmos"}, {"ship_num": 3, "ts": "2026-06-30T14:45:22Z", "hours": 14.0, "multiplier": 17.81, "payout": 241, "blessing": "neutral", "text": "I made Into the Cosmos, a realistic 3D spaceflight sandbox inspired by Kerbal Space Program and Spaceflight Simulator. The game lets players jump straight into the mission and experience realistic orbital rather than spend hours designing the rocket just for it to fail when launching. This is a relaxing and fun game where players can just sit back and enjoy the physics and thrill of sending rockets to space. The biggest challenge was making somewhat realistic physics with enjoyable gameplay. Getting the gravity, RCS controls, and spacecraft handling to feel both snappy and fun to play with without absolutely broken, writing so many lines of code, and deciding on how im gonna be approaching some problems was quiet fun, i have a lot of fun designing it, i used to go to bed thinking what ill be adding to the game tommrow. I’m most proud of achieving the relaxing experience I originally envisioned. Im quiet glad i was able to fianlly have a direction towards my game and have an idea of what i wanted. And the gameplay is quiet fun aswell, i found myself “playtesting” my games just having fun slamming the rocket into planets, doing interplanetary missions. Setting satellite in different planets To test the project, I recommend reading the in-game controls and instructions first. They explain the basics of reaching orbit and make the experience much more enjoyable.", "repo": "https://github.com/tejaswa4692/IntoTheCosmos", "demo": "https://tejaswa7692.itch.io/into-the-cosmos"}]...
|
[{"post_id": 54490, "ts": "202 [{"post_id": 54490, "ts": "2026-08-25T14:44:08Z", "hours": 0.6006, "text": "SHOUT OUT TO @253_Mathilde_IYKYK For starters i made a lil script so that if a rocket is in the SOI of a planet and then it scans near it by pressing F it shows all the necessary details about the planet, currently they are obvious details but i will work on making them useful. I have a few ideas of what i can do with it Now to the important part @253_Mathilde_IYKYK recommended me to add a song they like SO I ADDED IT TO THE GAME Hope yall like it :) (Sorry for not including video idk why stardance was bugging and throwing error when i was tryna upload a video)"}, {"post_id": 53590, "ts": "2026-08-24T06:27:00Z", "hours": 1.7239, "text": "BOOMBOX!!1! , macondo marketing team too good Last night i spent unhealthy amount of time watching ig posts of macondo on hackclub ig, I lowk feel insane amount of fomo and i wanted to go so bad The songs they used in the marketing reels are still stuck in my head So as any reasonable person would, I added a boombox in my game with with my fav songs from the reels they made @zach PLES FLY ME IN NEXT IRL HC EVENT PLES IM BROKE"}, {"post_id": 51670, "ts": "2026-08-21T14:03:35Z", "hours": 1.3228, "text": "IM RICH!!11!! 2080 sd and top 10 in multi I got all positive reviews from yall and i apprciate every single one of u for rating my project. I have finally added scrap mines to the game, i had already made the 3d model for them i just thought they didnt fit in the game but since im adding automation and electricity to the game i think this would be a great addition. Currently they produce 10 scraps, copper, iron per 10 seconds so 1/ sec i will later randomize this and give them weights, im js too lazy cuz of this clg n shi istg Good thing is tho tmr im going home That does mean my work on hardware projects will start again That being said i need you to give me more recommendation for the game, the reviews didn’t give me any ideas or unique views what i could add to my game."}, {"post_id": 49072, "ts": "2026-08-17T17:51:03Z", "hours": 2.0336, "text": "In these 2 hours i have lost all my sanity But finally the factorio like supply/demand electricity mesh finally works First i thought of using recursion to spread the electricity through every single tower But then i ran into a problem where towers interconnected so to fix that i passed a self parameter that didnt seem to help. Then i decided to make towers only connect once (which was a disaster and brought its own set of bugs) and that to tremendously failed So finally i decided upon a global mesh chain architecture where all the nodes in a chain have similar looking list, and whenever an appliance is connected to it the chain just iterates through its connected devices, This in turn brings the time complexity down to O(n) and makes everything a whole lot more efficient. Finally this is done Currently only the tesla charger works with this new logic, later i will add other electric appliances to this mesh network aswell and give them watt draw Few things to keep in mind, Currently 1 generator makes 50kW and one vehicle charger consumes 40W, If the demand isnt satisfied every node in mesh rejects the connection until the demand IS satisfied I know this might feel stupid for some people but this is only done as a feature so you dont overload the electronics in space"}, {"post_id": 48779, "ts": "2026-08-17T09:55:49Z", "hours": 2.4833, "text": "TESLA SUPER CHARGING So for starters i forgot to tell yall that i DIDNT get slimed by senior my clg department helped me and scared tf outta bro and i got to fight bro too And in this update i added set battery capacity to rovers They use supercapacitors to store charge so that means they can be charged and discharged for eternity Then i added charging stations to the game and made them use power grid electricity. I think players might abuse electricity by only placing 1 generator to power an entire city so i will be implementing complex wattage draw logic like they have in factorio to get some supply/demand action rolling. Then i worked on implementing save game in the game and i failed terribly (this will be a hurdle for later) I spent like solid half an hour trying to implement it just for my save file to be completely empty Idk whats going wrong but i will eventually figure it out. For now tho i will be working on factorio like supply/demand logic for electricity wish me luck"}, {"post_id": 48283, "ts": "2026-08-16T16:23:11Z", "hours": 2.1503, "text": "Some really cool additions For starters today i implemented a little list at bottom of the screen that can be used to store the coordinates of player rn Yall might be wondering what tis could be used for, But i have something really cool cooking up in my head lets hope i am able to express it properly. EXPRESSING MY LOVE OF YAGI ANTENNAS I ADDED A YAGI ANTENNA TO THE GAME!1!!! It has a search feature that looks around for strongest signal and then does nothing But in future i will be making a whole mechanic out of this. Then i made a little web release it butchered the visuals i worked hard on. Its okay tho cuz i added a warning label like last time on that release too. Linked the web release as playable link for the game I want YOU to tell me what should i add to this game as im running into a roadblock where i dont know what i could add for the electrical update for the game that would actually be a useful addition, Comment down below to drop your ideas the best one will make it into the game"}, {"post_id": 47469, "ts": "2026-08-15T12:12:27Z", "hours": 4.2428, "text": "YAYAYAYAYAYA 3RD SHIP INCOMING In the first 2 hours i logged i worked on making the 3d models as refined as possible and made them look good by referring to astroneer as someone commented on my game Also made multiple 3d models for the electric pole and finally used the one that sat right with me. Made a new 3d model for generator and upgrade station aswell In the next 2 hours i made minor tweaks and fixed satellite bugs along with updating the help menu with newer control code, also was thinking of implementing a scrap mine but dropped that idea (maybe later ships) Then i added a little keytip marker near the refinery and chest of observatory to aid the player. Added a bunch of sounds to the electronics of the game and now it sounds a whole lot better (also reduced the main music) FINALLY TIME TO SHIP Thnx to all of the support on this proj i wont disappoint yall at all with future ships"}, {"post_id": 46499, "ts": "2026-08-13T19:09:37Z", "hours": 1.13, "text": "I was aiming for 3 hours today but i lowk got in a fight with a senior in my clg and bro is threatening me to slime me tmr it might be wraps for me gng Putting the sliming part aside, today i made the 3D models for a generator concept (or actual thing) i found online of what they use in space. The i did sm audio editing to have a whrrrrrrrrrrrr looped sound effect and it was quiet easy to make a whrrrrrrrrrr loop, easier than i imagined. Then i added another sound and layered both ontop of each other and now it genuinely sounds kinda peak After that i made the electricity spread across all the electric poles, heres the code for that if body.is_in_group(\"tower\"): towers_closest.append(body) create_lines(body.location_to_connect_wire_to) if has_electricity_running: body.has_electricity_running = true elif body.is_in_group(\"electrical_appliance\"): if body.connected == false: towers_closest.append(body) create_lines(body.location_to_connect_wire_to) body.connected = true if body.is_in_group(\"generator\"): has_electricity_running = true for i in towers_closest: if i.is_in_group(\"tower\"): i.has_electricity_running = true I might lowk be taking AI’s job in writing bad code, they should make a me gpt in which i reply with shit code that DOES work. I also visualized the flow of electricity by hiding/showing a random cylindrical mesh that shows if it has elec flowing through it. Tmr ill be redoing ALL the icons cuz currently they look straight dookey, and also fixing the UI, then if i have time give observatory and everything an electric connection and make them so they dont work without it. This was all i worked on today, yall pray for me lets hope i dont get slimed tmr ."}, {"post_id": 45792, "ts": "2026-08-12T14:42:25Z", "hours": 6.0336, "text": "LETS GO IM FINALLY UNBANNED Unban stuff aside, time to explain the devlog even tho being unbanned feels great and i have insane amount of motivation to work on my proj now In past idk however weeks ive been working on 2 major things, first is that ive finally listened to the last ship reviewers and added upgrades for rocket, with custom 3d models for each rocket tier. currently it uses a separate key to open close the menu which is bad but ill fix later Also only the rockets fuel attribute is updated when you upgrade a rocket so ill fix that too. Also after the ban i was working on electronics update for my game, i have implemented electric poles, 50Kv Generators for now, i am going towards direction of factorio im afraid, but i dont wnana make it very grind-y so ill keep that in mind (hopefully) For future i will be adding better UI/UX its currently embarrassingly bad rn (even tho my degree is Computer science and Design) So yeah that will need a massive revamp Also id like to give a shout out to water #Freewater #heaintdonunwrong"}, {"post_id": 40560, "ts": "2026-08-04T06:09:37Z", "hours": 1.4125, "text": "After getting falsely accused for fraud for using the godot wakatime extension and getting a heart attack I have finally added little homes for these skinny dookeys I hate, HATE behavior trees with every cell in my body I hate to admit but i did take help of claude chat to help me set this shi up, it was js the free version tho so we good. I added so like normally it ran away from player if it sensed one near, but now if the player is close by and it has a home near it runs to that and hides in the home, and if player is far enough it emerges back out. Ill move on to adding more entities now rather than polishing these dudes, i think from the final game i wont even keep them in cuz how ugly and weird they are Aye free me bro i aint do nothing wrong, fix the wakatime extension fr"}, {"post_id": 39489, "ts": "2026-08-02T13:55:59Z", "hours": 1.7764, "text": "REALLY NICE ADDITIONS Ive finally added some life to the game. I have added these weird mudfishes inspired by those weird furless cats. These mud fishes aren’t stupid tho, i ___have implemented a proper behavior tree to them, Each one of them has their own set of actions. Normally like minecraft mobs they roam around look around the world, but if a player is near their vicinity, they RUN away from the player protecting them. Currently i have no clue what ill use them for, but one thing is for sure that they have really nice skin I wonder what will happen to it in the near future Really happy by this addition tbh, the world was getting kinda lonely, this was important, in next updates ill be adding colonies of these things mounds and their homes, along with their baby variant."}, {"post_id": 38887, "ts": "2026-08-01T13:38:58Z", "hours": 1.4058, "text": "Man i hate making 3D models Not my best work yet, but refinery is done, After several iterations, getting inspo from pinterest and then ditching it and drawing one in back of the class, im finally set on a design, it looks pretty good as of rn. (its not) I fixed a bug where the text was glitching out when i tried to craft scraps, and now it works as it should. The logic is perfect for how it should act in game and im hoping i dont have to touch it again in future to fix it. That being said ofcourse ill be making the 3D model better, But for now i just wanna focus on programming stuff and making the loop right. We can always make it prettier later . Im unfortunately still not home and i still have to survive in this godforsaken room, but hopefully ill be home soon as ill get my appli signed to go home, And then ill be working on both this and the plane together"}, {"post_id": 37473, "ts": "2026-07-30T07:46:37Z", "hours": 4.0967, "text": "Finally a devlog after several days of straight struggle For starters ill tell yall why it took me so long I lowk changed places and i live alone in a room now, i had to shift and living conditions here are absolute hell I somehow survive without going wild due to all the bs ive been facing recently. My productivity has taken a severe hit, a feature like this took me way too much time to complete than it should’ve. That being said i did wander off in different directions cuz i was lowk clueless which direction i should take this game (i still havent decided ) In this devlog i added advanced material processing and advanced materials to the game, with a minecraft furnace like cooking mechanics, i made the logic quiet efficient and refined, its not my best work but it can always be better later. I js hope this eternal torture ends and i finally get to have better living conditions. istg ive been boiled alive, breathing is a struggle in this place Ill keep serving yall with most banger updates so keep me followed, this game is gonna be the next big thing lowk Now i will be makig the 3d model for refinery, before this i made a failure ahh model in whcih i js made a complete simithing room inside a space bubble 😭 Gotta make something better than that so time to lock in"}, {"post_id": 35113, "ts": "2026-07-26T10:39:31Z", "hours": 2.3589, "text": "OKAYAYAYAYAYA UPDATE TIME I have graves implemented in the game now, after careful consideration about which direction i wanna take my game towards, i think graves would be a nice addition without disrespecting the procedural nature of the game. I want to make this game very lore heavy while being fully open world and giving the remote in players hands. I dont wnana confine them with thick story plot, or tedious tasks. Nor do i wanna make the game absolutely boring and pointless. The “Rot” i talk about is a cosmic disease the players universe is going through, unexplainable things are happening, weird inter dimensional gates are popping up at random places, everything is near extension. Im not sure about the role of player in all this tho, i will figure something out tho, i wont disappoint yall thats my promise. Also i worked a bit more on a weird bug where items were being placed not where the raycast was supposed to hit. Also I will be removing the inventory system entirely and just rely on blueprint building aspect lmk if yall think thats a good idea Also shout out to hackclub for getting me so much stuff i really love every single one of yall ❤️ Also progress on this game will go back to high now as i wont be home to work on my plen."}, {"post_id": 32900, "ts": "2026-07-22T11:12:22Z", "hours": 2.2856, "text": "OKAKAKAYAYAY some more cool additions for exploration aspect for the gam I added an arrow that points towards a set direction, which also changes its with respect to how far the rocket is from that point Also I FINALLY FIXED THE WATER WALKING SOUND ISSUE!!!1!!! Turns out it was quiet easy, i was just too stupid and over complicating it, a simple rewrite fixed everything. For next update i will be adding findable clues, maps, coordinates left out to rot by a “past explorer” that you find across the universe, this is gonna require a bit of time and skill but i can deliver that easy with some time Again progress is a bit slow cuz im actively working on my biggest endurance aircraft but i will keep tis game updated nonetheless, and in future u might even find it on steam who knows"}, {"post_id": 31916, "ts": "2026-07-20T18:18:16Z", "hours": 1.595, "text": "AYEEEYEYYE UPDATE ON THE PEAKEST GAME Made a really smart decision and got rid of the ugly hotbar like menu to place items, now da gam has a nice build menu in which most of the time was spent in making my code more cleaner. But it works now, it looks way more clean and immersive. Instead of relying on hardcoded information for items, i finally made a global that can handle all of that, idk why i didnt do that earlier. About the sound engine, i genuinely hate it a lot, i will be redoing it from scratch and figure out wtf is wrong with it Sorry for slow progress, i dont have much time till im at home so im tryna maximise the time i spend on my rc plen, ples follow it aswell"}, {"post_id": 30554, "ts": "2026-07-18T07:09:50Z", "hours": 1.0953, "text": "Oh i did manage to fix the water walking loop a lil more, its not perfect, but i dont understand whats going on. so ill just work on that later Anyways thats that, big changes i made are that now to place observatories or rovers you need to have a specific amount of scrap on you, i will be turning this into a full fledged build menu so its more appealing, and i will have this menu as a quick hotbar to place blueprints of items. I find this gameloop satisfying as it takes away the management hassle and this game is supposed to be relaxing. And bro how long IS the queue my bambu is STILL not shipped Sorry for slow updates on this project, currently working my ass off irl on the UAV project of mine as i have a deadline to finish it. If i did manage to get a good rep towards this proj, ill be taking the reviewers advice and hosting this game on steam. That developer grant might come in handy ngl"}, {"post_id": 29586, "ts": "2026-07-16T16:53:16Z", "hours": 3.3417, "text": "AYEEEEEE DEVLOG TIME So today i redid the observatory 3d model, gave it some clean nasa textures, its not upto my standards but its getting there, also fixed that stupid atmosphere bug now everything looks insanely better. Added a planet to the launch screen to flex aswell, i think it looks awesome there. Oh and also i tried to add water walking sound but am failing miserably but worry not as i will be reworking the soundengine too later Taking a moment to give a shout out to my followers who motivated me to work on tis more also HM all the reviewers who gave incredibly nice feedback"}, {"post_id": 28757, "ts": "2026-07-15T07:07:48Z", "hours": 3.0931, "text": "HOLEE SHIT, ADDED INSANE STUFF TO MY GAME IT LOOKS SO BEAUTIFUL NOW, I CANT BELIVE IT So, for starters, since yesterday I have been learning shaders. I fixed that shitty atmosphere shader that I translated from someone else’s shader to Godot. I had to make a lot of changes to it to get it working properly for my game. ALSO I MADE A SICK ASS WATER SHADER FOR PLANETS TO HAVE. Then I REWROTE THE PLANET GENERATION SCRIPT. Now each planet has unique properties like: Ambient temperature Water availability Air density, which determines water availability too I also tried adding comets and comet trails to the game, but failed tremendously. Oh, and also, dont go near the black hole. OH AND I GOT MY PAYOUT, AND I GOT THE BAMBULAB A1 MINI. THIS DAY JUST KEEPS GETTING BETTER"}, {"post_id": 27829, "ts": "2026-07-13T18:30:42Z", "hours": 3.1256, "text": "Devlog #idk Didn’t get a ton of new content added today, but I spent most of the time cleaning up annoying bugs and polishing the game. The biggest fix was the rocket explosion system. There was a bug where the rocket would slam into the ground at over 300 m/s … and just refuse to explode. I rewrote the logic, and it’s finally behaving properly. I also started modeling the mothership . It honestly looks like absolute dookey right now, but it’ll do as a placeholder. 3D modeling definitely isn’t my strongest skill, so I’m calling this version “good enough” for now. On the graphics side, I added a proper atmosphere around the planets, which makes them look much better. I also experimented with chromatic aberration , but it didn’t really fit the style of the game, so I ended up removing it. Huge thanks to @aloyak for the inspiration and some really helpful rendering tips. He showed me a much better way to increase the render distance without killing performance, so I’ll be implementing those improvements tomorrow. Also… I earned 1085 Stardust on my second ship. Not bad."}, {"post_id": 27157, "ts": "2026-07-12T13:40:03Z", "hours": 4.2947, "text": "OKAY so really cool changes First of all i fixed major inside stuff, instead of having 350 lines of gd script files in which i had to sift through to find the function i need, and then get overwhelmed later, i made everything modular, All the functions are Nodes in the scene that hold scripts. These scripts hold the functions that were earlier stored in the main .gd file, so now everything is a lot less cluttered and makes my life easier. I also did the same for the rocket scene as it was getting cluttered too. I added chests to the game where you can store items in (dont mind the invisible hotbar), They will be locations to store your items which will be scattered inside of observatories, im also thinking of redoing observatories as this model now looks ugly, and i think this has a lot more potential. Oh and also i have decided upon how im gonna make the player create an observatory, you land on a planet, collect scraps, them build an observatory, and then everything in observatory would cost the player X amount of scraps, also abandoned motherships will also provide the player upgrades for rocket. I got 3 ratings which im thrilled about, but also kinda sad because the reviewers prolly playing the itch release of the game and not the actual one but eh i think its fine, as long as my game is peak. Next ill be working on making an actual 3d model for the mothership"}, {"post_id": 26683, "ts": "2026-07-11T16:52:12Z", "hours": 2.1936, "text": "Designed the actual model for the rover, im pretty happy with how it turned out, i think ill keep it. tweaked the settings for the rover to get it just right, the only problem im facing is that due to the curvature of the planet, rover js flys off n start orbiting at high speed, i gotta add down force to tis i think. I removed the inventory cuz it was too wonky, i think ill have a hotbar and a backpack like peak, i think thatll be more immersive than having a stupid inventory. (this is totally not because i went rabid trying to implement it)"}, {"post_id": 26423, "ts": "2026-07-11T06:30:37Z", "hours": 2.1986, "text": "So i changed the Help UI of the game, made it look a lil better than that roblox ahh UI, Added mother stations to the game where u can get rocket upgrades, im slowly trying to figure out the game loop, itll be that you are a lonely astronaut in eternal void of space, your kind has been extinct, these ships are abandoned u can repair them and get a specific upgrade from each of them. Also i made the web version available too, its been 3 days and ive been sitting at 0 ratings just demotivated the hell out of me, the quality of graphics and gameplay is butchered but i had made that clear in the itch page, lets hope people rate it now"}, {"post_id": 25881, "ts": "2026-07-10T11:24:42Z", "hours": 5.6075, "text": "Working on making the game loop more fun, Im thinking ill be taking the game towards single player base building story mode type of game, I made a web version cuz i had 0 reviews after 2 days, the web version isnt good at all but its make do, I added rovers to the game now too its insanely fun driving them around the planet and having fun, i will be adding more stuff to the game, inventory system turns out is way harder than i expected so ill do that later. Enjoy this clip of the game"}, {"post_id": 25202, "ts": "2026-07-09T09:33:14Z", "hours": 2.2953, "text": "Made major game optimizations, Am adding a proper inventory system with crafting, I have designed inventory with crafting in past for my cooking game shouldn’t be that hard, But doing it in preexisting is a bit of a challenge. I have implemented a simple hotbar and item system in the game, I also used Godots IK nodes to control the bones, and god damm was it useful, this might come in handy in future. Switch to this camera does make it look a lot better"}, {"post_id": 24651, "ts": "2026-07-08T11:38:24Z", "hours": 0.5031, "text": "Okay just fixed another tiny bug, im glad i checked it, when i select the satellite for an observatory, the UI doesn’t open again, so it made it impossible to refuel, i fixed that by giving an option to control satellite now. I think im set for the ship now, i reccomplied the binaries, the readme is ready to, along with the latest youtube video https://youtu.be/RQmEh_rwnzQ"}, {"post_id": 24598, "ts": "2026-07-08T09:44:34Z", "hours": 4.72, "text": "Final devlog before ship. I have polished the UI, remade the boney 3d model, Fixed observatory logic, made other tiny gamebreaking improvements, Also i have fixed animations for boney, added a jump animation. Major change is 3rd Person camera now, which makes the whole experince even more immersive. I have playtested it several times, im kinda nervous and hoping it works perfectly as it is on my machine."}, {"post_id": 24288, "ts": "2026-07-07T19:13:44Z", "hours": 4.7478, "text": "Getting the project production-ready. I’ve finally added local storage for the settings menu, so your graphics and gameplay preferences now persist between sessions instead of resetting every time you launch the game. A lot of people mentioned in the last devlog that they couldn’t figure out the controls, so I added a “Show Keybinds” toggle in the settings menu (press ESC to open it). It displays the controls on-screen whenever you need them. I also found a pretty game-breaking bug, so I’m documenting it here for future me: If you’re mounted in the rocket, enable Show Keybinds, and then hit Apply, the player can no longer unmount from the rocket. I’ll be fixing that later. I spent some time messing around with Godot’s built-in graphics settings and realized I’d completely forgotten to enable anti-aliasing. Turning it on made a huge difference, the game looks so much cleaner now. As you can see, I’ve also added a fuel gauge for the rocket. It helps sell the whole “claiming and exploring planets” vibe. I also changed observatories so each planet can only have one. Another gameplay change is that you now have to visit an observatory to dock a satellite onto your rocket instead of doing it anywhere. Finally, I changed how world persistence works. If your rocket crashes and you reset the game, any observatories you’ve already built will still be there instead of disappearing."}, {"post_id": 24002, "ts": "2026-07-07T08:55:54Z", "hours": 4.1525, "text": "Today i have just started refining the 2/3 stage gameplay i made it so you cant just spam sattelites wherever you want, but instead you have to get them docked on your rocket at the research center. I made the ugly loading screen a little better, i will fix it even more by designing custom graphics for it I revamped the 3d model for the research facility, it has interior and the infamous meme toilet where little boneys take a dookie in unison. (This will be a feature in 3/3 version of the game) Currently i have fixed some more gamebreaking bug where the ui just straight up didnt work, turns out it was due to my own stupidity of forgetting to hide an transparent panel in the scene tree."}, {"post_id": 23577, "ts": "2026-07-06T16:46:05Z", "hours": 4.7711, "text": "SO, Im now starting to add everything people complained about or found annoying in my first ship, Someone pointed out i had made the help but the help i made didnt tell what keybinds to use, so i have designed a dynamically UI screen to add guide for button keypress, it was a bit of a tedious job but its done now. Since i understand that not everyone has a good computer, (I have an RTX4050 with Ryzen 7 AMD Ryzen 7 7435HS CPU with 24 gigs of ram so i cant rely on my laptop to be an average computer) but i know not everyone has these specs so i took the time to code more settings in the settings section, now i can select the major factors of FPS drop in this game. Also i redid the noise the planets used, the noise textures is used before if you see from earlier videos looks very choppy, unrealistic and creative, now it looks a LOT better. Currently i haven’t added keybinds UI for the rocket, which ill add later, I will be making a ship soon after fixing more bugs that i delayed for later."}, {"post_id": 23362, "ts": "2026-07-06T09:04:28Z", "hours": 7.4369, "text": "Finally the biggest change ever yet, this took me HOURS of rewriting debugging fixing weird glitches, tried to even recompile Godot at one point, But its done, A truly frame efficient infinite procedural planet generation with randomness and seed integrated in it, this took so much of my sanity, so many broken hairs, but finally i am able to perfectly get it working at 144fps and around 11ms average frame time. I also optimized the rock generation even more to take advantage of godots multi threading capabilities to take the load off the main thread to generate the chunks for rocks. Current limitations of this architecture are not the architecture but the godot engine itself, as it uses 16 bit floats to keep track of transform, so if you’re like 100,000 units away from your home planet you start facing very weird glitches, I personally think im gonna keep this glitch in the game as i have no idea how these glitches will affect the gameplay, its like minecraft farlands, i want to see how the world generation breaks, and i dont want to stop the player from experiencing that aswell. Its not that idk how to fix this, if i recompile godot to use double instead of float i can extend the range of the farlands way beyond that, but its just the matter of personal preference. I have quiet insane ideas and directions for this project now that ive came so far, its kinda funny how all this became what it is just because i wanted to control a rocket in space."}, {"post_id": 22728, "ts": "2026-07-05T09:44:51Z", "hours": 4.8342, "text": "ABSOLUTELY INSANE ADDITIONS FOR MY GAME THIS TIME. First of all my first ship was finally reviewed so i read all the reviews and made a mental note of all of them, they were all positive and im very happy people resonate with my project so i appreciate everyone who wrote a very thoughtful review for me i thank you all a lot. Now in the technical part of the game: I finally fixed my nebula raymarched shader, now it actually has volume and you can go inside it and it looks absolutely ethereal. Reviews told me that they would love it if the planets had more details, so details i added, i made a VERY efficient chunking pipeline to scatter debries, and whatever i want on the planet mesh, i am being able to have the whole planet populated with no noticeable drop to performance. I made the script in a way that its a module, so in case if i ever want a planet with vegetation or trees, i can just drop the 3d obj file for that mesh and boom ill have a proper chunk based scatter for that mesh. I tested the chunks using debug cubes and it works perfectly as it should. I also added spacewalking to the game, you can genuinely just float in the space and enjoy the view from the outside, this was quiet easy but its an addition that i shouldve added a long time ago. Also ive finally added randomly generated textures for planet surfaces, these dont look AS realistic rn, but im sure after changing a few parameters and adding proper debrie 3d models, it’ll look absolutely astonishing. From the reviews i read that i didn’t add any help for what keys to use and genuinely thats on me im too stupid so in future ship ill 100% fix that Also ive added a feature where you can currently place observatories on planets and use them to control the satellites, This is just for now as for future ill make the player do stuff on the planet first to have their base setup, I dont wanna complicate it too much as this is supposed to be a relaxing game, but i think this much is necessary. Ive also 3d modeled a tiny astronaut along with his animations and im calling the player boney, i have decided on boney’s lore yet but i can assure yall one thing, it will be insanely deep, and there will be clues for it all around the game, you just have to notice it. I also have massively optimised the star spawning shader, i am able to have 10s of thousands stars on the screen without having any frame drops at all, i used GPU instancing for this and this is genuinely black magic, I also used GPU bill boarding to help aid the performance even more. Removed the unnecessary calculations and now the sky is denser than ever. I also herd people wanted me to make a web release for it as the download process was quiet tedious, but i think 2 devlogs ago you can see me in godots compatibility mode, it BUTCHERED the visuals completely so i dont think i can bring myself to do that after spending so much time writing complex shaders. TODO: Add wormholes, infinite planet generation, coordinate system."}, {"post_id": 22073, "ts": "2026-07-04T10:05:33Z", "hours": 5.02, "text": "Okay this devogg im glad to announce i have successfully fixed that bug in last devlog which i told yall about, this devlog i added a lot of visual eye candy changes, and a few more functional changes. For starters i added a settings menu and a homepage so users with low end devices can change the settings accordingly, these settings will obviously be updated as the game updates. Secondly, ive added GPU instanced particles all around the player to give to the eyecandy factor of the game. Thirdly i added black holes and their custom ray marched shader to them, they also have the stretch effect of light when u go near them like how they describe “spaghettification” in encyclopedias. I also added ray marched nebula in aswell, they currently dont serve a specific purpose apart from the eyecandy factor, but to be fair not everything has to have a purpose as this is just a relaxing chill game. I also changed the music to a different royalty free music, i was genuinely so tired of listening to that track on loop it was driving me crazy."}, {"post_id": 21430, "ts": "2026-07-03T11:40:44Z", "hours": 5.1097, "text": "I have genuinely lost hairs, sanity and life, i have this insanely annoying gamebreaking bug. Currently if the world has more than 1 active gravity source, the satellite doesnt perfectly orbit the planet it should be orbiting, after a while it looses velocity and crashes, this is absolutely gamebreaking as the main concept of the game is gravity. I have tried so many fixes, managed to break the game multiple times, but in the end i think i have a clue of whats going on, when i introduced SOI for each planet, the orbit was still terminating with a crash on the planet, i had made it so that if the body is outside the sphere of influence,it sets the gravity influence from that planet to 0, but even if im in my own sphere, i still somehow crash, i initially thought that the other planets might be attracting the satellite, but i think its the floating point calculations that are messing the orbit up, currently i have no clue how ill fix it but ik ill figure something out. If you guys have any idea what it could be please comment i lowk need all the ideas i can get Anyways i fixed the satellite observatory logic, refined it a bit more, ran tests, tried to implement multiplayer but stopped cuz other bugs got overwhelming. I think ill focus more on designing a nice clean UI now rather than bug fix, which ill do later, cuz they do say “make it exist first, make it perfect later”."}, {"post_id": 20673, "ts": "2026-07-02T10:15:08Z", "hours": 4.4403, "text": "Devlog 8 of my epic space game: Following the trend of making a relaxing space sim game with multiplayer, i added quiet a lot of stuff this devlog, i first of all laid a foundation for future, redid all the buggy code, made all the functions future proof, and then i added observatories, proper satellite controller, and made the satellites be able to control with their respective observatory, now the player can spawn satellites, send them to space or go on a mission, come land back and control the sattelite they have sent to the space. In future ill be adding dynamic and unique planets that will be randomly generated eveytime you log into the game."}, {"post_id": 19227, "ts": "2026-06-30T14:21:37Z", "hours": 0.8425, "text": "DEVLOG 7 OF INTO THE COSMOS This devlog i made some really important additions of a help menu for newer players, i find this quiet important as making an orbit around the planet is quiet hard, so i handdrew some quick informative help guide that can help you quickstart. Also finally ready for my ship #1, i have setup the readme, and made a release for this project, Also uploaded a lil youtube video cuz the guide said so."}, {"post_id": 18501, "ts": "2026-06-29T17:48:37Z", "hours": 1.6342, "text": "Devlog 6 of my epic space game: This update i added quiet a bunch of stuff i was excited to add. First of all major addition, A Satellite, you can carry it from your rocket, take it it in your low planetary orbit and release it in there, itll keep orbiting the planet if you made your orbit right. RCS and thrust with VFX for the satellite this was essential as real life satellites also have this feature and im trying to nail reality as much as i can with this project Finally a better camera, now camera can switch between 2 registered entities, and the selected entity will only be controlled by the camera so thats pretty neat. In the video i showcase the rocket, the satellite, satellite boosters and rcs, landing the rocket, rendezvous with the satellite back again (not really but eh lets just call it that) For future im planning to add redocking (its gonna be very hard to do it in game tho), the game is actually quiet hard its not as simple to create orbits, if the user doesnt have the knowledge of how orbits are made then itll be quiet hard for them to understand that, so for the final release ill also be making a little tutorial. The video is 1.5x btw"}, {"post_id": 18150, "ts": "2026-06-29T05:15:37Z", "hours": 2.8544, "text": "Devlog 5 of my epic space travel game: Finally added more stuff i was delaying to add RCS thrusters effects, now rcs thrusters also have a thrust cone like the main booster Really nice explpsion vfx, now the explosion doesnt look like a low effort particle, its multilayered particles now with sound effects Balanced the game a bit as currently landing was quiet hard, so i fixed that Game is coming together really well, personally i spend a lot of time playing it myself so i know its a banger project, Moving forward i will be adding satellites, save states, fuel system, multi stage rockets, production level graphics to the game. (not posting video as they dont do as well)"}, {"post_id": 17045, "ts": "2026-06-27T17:51:18Z", "hours": 2.4083, "text": "Devlog for my awesome space game, so today i remade the 3d model for the rocket which i was dreading to do but finally got it off, the insane part is that i added a really nice vfx trail instead of kiddie looking particle trail for the rocket, this one looks like an actual thruster and the real deal. Also added music this time around, i tried to add thruster sound but that wasnt working so left that for some other day. tommrow i think ill add proper 3d models for planets and make a replica mini solar system (not ours) The vfx look so sick tho i cant have enough of them"}, {"post_id": 16377, "ts": "2026-06-26T17:33:15Z", "hours": 1.7225, "text": "KSP style sandbox game: Okay so a lot happened since last time, firstly i switched to arch linux as my daily os, and in the game i added planets, RCS, realistic gravity. a planet is a datatype that has information of the mass and gravity scale of that planet, and it can attract the rocket object, also the cool part is you can have multiple planets and create really creative orbits around them, its almost like were actually in spacec Added RCS thrusters as landing on planets was impossible without it, rcs uses shift + wasdqe keys to move in all 3 axis, this makes it very playable but not extremely easy, in the video you can see i still haven’t got the total hang of it yet myself, but ik ill do. Ik i was gonna make a playable release today but due to me wiping windows thats gotta wait a while before it actually happens, For future plans i think ill add a proper environment that replicates space, have enhanced 3d models with HD textures, rcs particles and stuff, also an actual level to play around in."}, {"post_id": 15657, "ts": "2026-06-25T13:49:03Z", "hours": 2.7311, "text": "Okay game is coming along quiet awesome, i managed to make a proper 3d model this time, it has textures and an ugly ass nose cone which ill fix later, currently i made more quality of life changes, made the rocket more snappier, and made it so you can revive, added a lil bit of juice by adding explosion particles and revamped thrust particles as well. Somehow managed to break the entire camera script, but that was soon fixed too so the game is coming along quiet good. For the direction aspect, i currently think flying the rocket around the map is quiet fun ngl, watching me maneuver the landscape by trying to not hit anything in process, also added a moon map and made it similar to the moon by downloading the hightmap data and texture data from actual nasa, but i gave up on that cuz the low res one was trash and high res hightmap was like a bajillion gigabytes and aint nobody gonna download this game if its that big. I played around with different gravity settings and realised flying the rocket is quiet easy if youre on moon compared to earth (duh). So IF (big if) i add levels to it, this might be a hint of what theyll be, again i dont like level system as theyre not fun and u get tired of it soon, i might add multiplayer capabilities later with a python webserver running on the server machine so you can battle with your friends too, possibilities are endless, and ill serve yall good with this one. Like this project and follow me, in the next devlog ill release exe file for this project."}, {"post_id": 14983, "ts": "2026-06-24T10:25:23Z", "hours": 1.3406, "text": "Making an awesome godot game in which you control a rocket ship and you can basically do anything with it, currently i havent decided the direction i wanna take this game towards, i might make it into a demolition sandbox type game, a space exploration game, or a movement type game where you have to reach the destination, like that one cool math game. till now ive achieved Rigid body rocket with its yaw and pitch controls An animated rocket 3d model A test scene with kennys prototype textures A particle style thrust system In next devlog i might add sounds, explosions, and gasoline"}]...
|
Title: Into the cosmos by @tejaswa | Stardance
De Title: Into the cosmos by @tejaswa | Stardance
Devlogs:
Making an awesome godot game in which you control a rocket ship and you can basically do anything with it, currently i havent decided the direction i wanna take this game towards, i might make it into a demolition sandbox type game, a space exploration game, or a movement type game where you have to reach the destination, like that one cool math game. till now ive achieved Rigid body rocket with its yaw and pitch controls An animated rocket 3d model A test scene with kennys prototype textures A particle style thrust system In next devlog i might add sounds, explosions, and gasoline
Okay game is coming along quiet awesome, i managed to make a proper 3d model this time, it has textures and an ugly ass nose cone which ill fix later, currently i made more quality of life changes, made the rocket more snappier, and made it so you can revive, added a lil bit of juice by adding explosion particles and revamped thrust particles as well. Somehow managed to break the entire camera script, but that was soon fixed too so the game is coming along quiet good. For the direction aspect, i currently think flying the rocket around the map is quiet fun ngl, watching me maneuver the landscape by trying to not hit anything in process, also added a moon map and made it similar to the moon by downloading the hightmap data and texture data from actual nasa, but i gave up on that cuz the low res one was trash and high res hightmap was like a bajillion gigabytes and aint nobody gonna download this game if its that big. I played around with different gravity settings and realised flying the rocket is quiet easy if youre on moon compared to earth (duh). So IF (big if) i add levels to it, this might be a hint of what theyll be, again i dont like level system as theyre not fun and u get tired of it soon, i might add multiplayer capabilities later with a python webserver running on the server machine so you can battle with your friends too, possibilities are endless, and ill serve yall good with this one. Like this project and follow me, in the next devlog ill release exe file for this project.
KSP style sandbox game: Okay so a lot happened since last time, firstly i switched to arch linux as my daily os, and in the game i added planets, RCS, realistic gravity. a planet is a datatype that has information of the mass and gravity scale of that planet, and it can attract the rocket object, also the cool part is you can have multiple planets and create really creative orbits around them, its almost like were actually in spacec Added RCS thrusters as landing on planets was impossible without it, rcs uses shift + wasdqe keys to move in all 3 axis, this makes it very playable but not extremely easy, in the video you can see i still haven’t got the total hang of it yet myself, but ik ill do. Ik i was gonna make a playable release today but due to me wiping windows thats gotta wait a while before it actually happens, For future plans i think ill add a proper environment that replicates space, have enhanced 3d models with HD textures, rcs particles and stuff, also an actual level to play around in.
Devlog for my awesome space game, so today i remade the 3d model for the rocket which i was dreading to do but finally got it off, the insane part is that i added a really nice vfx trail instead of kiddie looking particle trail for the rocket, this one looks like an actual thruster and the real deal. Also added music this time around, i tried to add thruster sound but that wasnt working so left that for some other day. tommrow i think ill add proper 3d models for planets and make a replica mini solar system (not ours) The vfx look so sick tho i cant have enough of them
Devlog 5 of my epic space travel game: Finally added more stuff i was delaying to add RCS thrusters effects, now rcs thrusters also have a thrust cone like the main booster Really nice explpsion vfx, now the explosion doesnt look like a low effort particle, its multilayered particles now with sound effects Balanced the game a bit as currently landing was quiet hard, so i fixed that Game is coming together really well, personally i spend a lot of time playing it myself so i know its a banger project, Moving forward i will be adding satellites, save states, fuel system, multi stage rockets, production level graphics to the game. (not posting video as they dont do as well)
Devlog 6 of my epic space game: This update i added quiet a bunch of stuff i was excited to add. First of all major addition, A Satellite, you can carry it from your rocket, take it it in your low planetary orbit and release it in there, itll keep orbiting the planet if you made your orbit right. RCS and thrust with VFX for the satellite this was essential as real life satellites also have this feature and im trying to nail reality as much as i can with this project Finally a better camera, now camera can switch between 2 registered entities, and the selected entity will only be controlled by the camera so thats pretty neat. In the video i showcase the rocket, the satellite, satellite boosters and rcs, landing the rocket, rendezvous with the satellite back again (not really but eh lets just call it that) For future im planning to add redocking (its gonna be very hard to do it in game tho), the game is actually quiet hard its not as simple to create orbits, if the user doesnt have the knowledge of how orbits are made then itll be quiet hard for them to understand that, so for the final release ill also be making a little tutorial. The video is 1.5x btw
DEVLOG 7 OF INTO THE COSMOS This devlog i made some really important additions of a help menu for newer players, i find this quiet important as making an orbit around the planet is quiet hard, so i handdrew some quick informative help guide that can help you quickstart. Also finally ready for my ship #1, i have setup the readme, and made a release for this project, Also uploaded a lil youtube video cuz the guide said so.
Devlog 8 of my epic space game: Following the trend of making a relaxing space sim game with multiplayer, i added quiet a lot of stuff this devlog, i first of all laid a foundation for future, redid all the buggy code, made all the functions future proof, and then i added observatories, proper satellite controller, and made the satellites be able to control with their respective observatory, now the player can spawn satellites, send them to space or go on a mission, come land back and control the sattelite they have sent to the space. In future ill be adding dynamic and unique planets that will be randomly generated eveytime you log into the game.
I have genuinely lost hairs, sanity and life, i have this insanely annoying gamebreaking bug. Currently if the world has more than 1 active gravity source, the satellite doesnt perfectly orbit the planet it should be orbiting, after a while it looses velocity and crashes, this is absolutely gamebreaking as the main concept of the game is gravity. I have tried so many fixes, managed to break the game multiple times, but in the end i think i have a clue of whats going on, when i introduced SOI for each planet, the orbit was still terminating with a crash on the planet, i had made it so that if the body is outside the sphere of influence,it sets the gravity influence from that planet to 0, but even if im in my own sphere, i still somehow crash, i initially thought that the other planets might be attracting the satellite, but i think its the floating point calculations that are messing the orbit up, currently i have no clue how ill fix it but ik ill figure something out. If you guys have any idea what it could be please comment i lowk need all the ideas i can get Anyways i fixed the satellite observatory logic, refined it a bit more, ran tests, tried to implement multiplayer but stopped cuz other bugs got overwhelming. I think ill focus more on designing a nice clean UI now rather than bug fix, which ill do later, cuz they do say “make it exist first, make it perfect later”.
Okay this devogg im glad to announce i have successfully fixed that bug in last devlog which i told yall about, this devlog i added a lot of visual eye candy changes, and a few more functional changes. For starters i added a settings menu and a homepage so users with low end devices can change the settings accordingly, these settings will obviously be updated as the game updates. Secondly, ive added GPU instanced particles all around the player to give to the eyecandy factor of the game. Thirdly i added black holes and their custom ray marched shader to them, they also have the stretch effect of light when u go near them like how they describe “spaghettification” in encyclopedias. I also added ray marched nebula in aswell, they currently dont serve a specific purpose apart from the eyecandy factor, but to be fair not everything has to have a purpose as this is just a relaxing chill game. I also changed the music to a different royalty free music, i was genuinely so tired of listening to that track on loop it was driving me crazy.
ABSOLUTELY INSANE ADDITIONS FOR MY GAME THIS TIME. First of all my first ship was finally reviewed so i read all the reviews and made a mental note of all of them, they were all positive and im very happy people resonate with my project so i appreciate everyone who wrote a very thoughtful review for me i thank you all a lot. Now in the technical part of the game: I finally fixed my nebula raymarched shader, now it actually has volume and you can go inside it and it looks absolutely ethereal. Reviews told me that they would love it if the planets had more details, so details i added, i made a VERY efficient chunking pipeline to scatter debries, and whatever i want on the planet mesh, i am being able to have the whole planet populated with no noticeable drop to performance. I made the script in a way that its a module, so in case if i ever want a planet with vegetation or trees, i can just drop the 3d obj file for that mesh and boom ill have a proper chunk based scatter for that mesh. I tested the chunks using debug cubes and it works perfectly as it should. I also added spacewalking to the game, you can genuinely just float in the space and enjoy the view from the outside, this was quiet easy but its an addition that i shouldve added a long time ago. Also ive finally added randomly generated textures for planet surfaces, these dont look AS realistic rn, but im sure after changing a few parameters and adding proper debrie 3d models, it’ll look absolutely astonishing. From the reviews i read that i didn’t add any help for what keys to use and genuinely thats on me im too stupid so in future ship ill 100% fix that Also ive added a feature where you can currently place observatories on planets and use them to control the satellites, This is just for now as for future ill make the player do stuff on the planet first to have their base setup, I dont wanna complicate it too much as this is supposed to be a relaxing game, but i think this much is necessary. Ive also 3d modeled a tiny astronaut along with his animations and im calling the player boney, i have decided on boney’s lore yet but i can assure yall one thing, it will be insanely deep, and there will be clues for it all around the game, you just have to notice it. I also have massively optimised the star spawning shader, i am able to have 10s of thousands stars on the screen without having any frame drops at all, i used GPU instancing for this and this is genuinely black magic, I also used GPU bill boarding to help aid the performance even more. Removed the unnecessary calculations and now the sky is denser than ever. I also herd people wanted me to make a web release for it as the download process was quiet tedious, but i think 2 devlogs ago you can see me in godots compatibility mode, it BUTCHERED the visuals completely so i dont think i can bring myself to do that after spending so much time writing complex shaders. TODO: Add wormholes, infinite planet generation, coordinate system.
Finally the biggest change ever yet, this took me HOURS of rewriting debugging fixing weird glitches, tried to even recompile Godot at one point, But its done, A truly frame efficient infinite procedural planet generation with randomness and seed integrated in it, this took so much of my sanity, so many broken hairs, but finally i am able to perfectly get it working at 144fps and around 11ms average frame time. I also optimized the rock generation even more to take advantage of godots multi threading capabilities to take the load off the main thread to generate the chunks for rocks. Current limitations of this architecture are not the architecture but the godot engine itself, as it uses 16 bit floats to keep track of transform, so if you’re like 100,000 units away from your home planet you start facing very weird glitches, I personally think im gonna keep this glitch in the game as i have no idea how these glitches will affect the gameplay, its like minecraft farlands, i want to see how the world generation breaks, and i dont want to stop the player from experiencing that aswell. Its not that idk how to fix this, if i recompile godot to use double instead of float i can extend the range of the farlands way beyond that, but its just the matter of personal preference. I have quiet insane ideas and directions for this project now that ive came so far, its kinda funny how all this became what it is just because i wanted to control a rocket in space.
SO, Im now starting to add everything people complained about or found annoying in my first ship, Someone pointed out i had made the help but the help i made didnt tell what keybinds to use, so i have designed a dynamically UI screen to add guide for button keypress, it was a bit of a tedious job but its done now. Since i understand that not everyone has a good computer, (I have an RTX4050 with Ryzen 7 AMD Ryzen 7 7435HS CPU with 24 gigs of ram so i cant rely on my laptop to be an average computer) but i know not everyone has these specs so i took the time to code more settings in the settings section, now i can select the major factors of FPS drop in this game. Also i redid the noise the planets used, the noise textures is used before if you see from earlier videos looks very choppy, unrealistic and creative, now it looks a LOT better. Currently i haven’t added keybinds UI for the rocket, which ill add later, I will be making a ship soon after fixing more bugs that i delayed for later.
Today i have just started refining the 2/3 stage gameplay i made it so you cant just spam sattelites wherever you want, but instead you have to get them docked on your rocket at the research center. I made the ugly loading screen a little better, i will fix it even more by designing custom graphics for it I revamped the 3d model for the research facility, it has interior and the infamous meme toilet where little boneys take a dookie in unison. (This will be a feature in 3/3 version of the game) Currently i have fixed some more gamebreaking bug where the ui just straight up didnt work, turns out it was due to my own stupidity of forgetting to hide an transparent panel in the scene tree.
Getting the project production-ready. I’ve finally added local storage for the settings menu, so your graphics and gameplay preferences now persist between sessions instead of resetting every time you launch the game. A lot of people mentioned in the last devlog that they couldn’t figure out the controls, so I added a “Show Keybinds” toggle in the settings menu (press ESC to open it). It displays the controls on-screen whenever you need them. I also found a pretty game-breaking bug, so I’m documenting it here for future me: If you’re mounted in the rocket, enable Show Keybinds, and then hit Apply, the player can no longer unmount from the rocket. I’ll be fixing that later. I spent some time messing around with Godot’s built-in graphics settings and realized I’d completely forgotten to enable anti-aliasing. Turning it on made a huge difference, the game looks so much cleaner now. As you can see, I’ve also added a fuel gauge for the rocket. It helps sell the whole “claiming and exploring planets” vibe. I also changed observatories so each planet can only have one. Another gameplay change is that you now have to visit an observatory to dock a satellite onto your rocket instead of doing it anywhere. Finally, I changed how world persistence works. If your rocket crashes and you reset the game, any observatories you’ve already built will still be there instead of disappearing.
Final devlog before ship. I have polished the UI, remade the boney 3d model, Fixed observatory logic, made other tiny gamebreaking improvements, Also i have fixed animations for boney, added a jump animation. Major change is 3rd Person camera now, which makes the whole experince even more immersive. I have playtested it several times, im kinda nervous and hoping it works perfectly as it is on my machine.
Okay just fixed another tiny bug, im glad i checked it, when i select the satellite for an observatory, the UI doesn’t open again, so it made it impossible to refuel, i fixed that by giving an option to control satellite now. I think im set for the ship now, i reccomplied the binaries, the readme is ready to, along with the latest youtube video https://youtu.be/RQmEh_rwnzQ
Made major game optimizations, Am adding a proper inventory system with crafting, I have designed inventory with crafting in past for my cooking game shouldn’t be that hard, But doing it in preexisting is a bit of a challenge. I have implemented a simple hotbar and item system in the game, I also used Godots IK nodes to control the bones, and god damm was it useful, this might come in handy in future. Switch to this camera does make it look a lot better
Working on making the game loop more fun, Im thinking ill be taking the game towards single player base building story mode type of game, I made a web version cuz i had 0 reviews after 2 days, the web version isnt good at all but its make do, I added rovers to the game now too its insanely fun driving them around the planet and having fun, i will be adding more stuff to the game, inventory system turns out is way harder than i expected so ill do that later. Enjoy this clip of the game
So i changed the Help UI of the game, made it look a lil better than that roblox ahh UI, Added mother stations to the game where u can get rocket upgrades, im slowly trying to figure out the game loop, itll be that you are a lonely astronaut in eternal void of space, your kind has been extinct, these ships are abandoned u can repair them and get a specific upgrade from each of them. Also i made the web version available too, its been 3 days and ive been sitting at 0 ratings just demotivated the hell out of me, the quality of graphics and gameplay is butchered but i had made that clear in the itch page, lets hope people rate it now
Designed the actual model for the rover, im pretty happy with how it turned out, i think ill keep it. tweaked the settings for the rover to get it just right, the only problem im facing is that due to the curvature of the planet, rover js flys off n start orbiting at high speed, i gotta add down force to tis i think. I removed the inventory cuz it was too wonky, i think ill have a hotbar and a backpack like peak, i think thatll be more immersive than having a stupid inventory. (this is totally not because i went rabid trying to implement it)
OKAY so really cool changes First of all i fixed major inside stuff, instead of having 350 lines of gd script files in which i had to sift through to find the function i need, and then get overwhelmed later, i made everything modular, All the functions are Nodes in the scene that hold scripts. These scripts hold the functions that were earlier stored in the main .gd file, so now everything is a lot less cluttered and makes my life easier. I also did the same for the rocket scene as it was getting cluttered too. I added chests to the game where you can store items in (dont mind the invisible hotbar), They will be locations to store your items which will be scattered inside of observatories, im also thinking of redoing observatories as this model now looks ugly, and i think this has a lot more potential. Oh and also i have decided upon how im gonna make the player create an observatory, you land on a planet, collect scraps, them build an observatory, and then everything in observatory would cost the player X amount of scraps, also abandoned motherships will also provide the player upgrades for rocket. I got 3 ratings which im thrilled about, but also kinda sad because the reviewers prolly playing the itch release of the game and not the actual one but eh i think its fine, as long as my game is peak. Next ill be working on making an actual 3d model for the mothership
Devlog #idk Didn’t get a ton of new content added today, but I spent most of the time cleaning up annoying bugs and polishing the game. The biggest fix was the rocket explosion system. There was a bug where the rocket would slam into the ground at over 300 m/s … and just refuse to explode. I rewrote the logic, and it’s finally behaving properly. I also started modeling the mothership . It honestly looks like absolute dookey right now, but it’ll do as a placeholder. 3D modeling definitely isn’t my strongest skill, so I’m calling this version “good enough” for now. On the graphics side, I added a proper atmosphere around the planets, which makes them look much better. I also experimented with chromatic aberration , but it didn’t really fit the style of the game, so I ended up removing it. Huge thanks to @aloyak for the inspiration and some really helpful rendering tips. He showed me a much better way to increase the render distance without killing performance, so I’ll be implementing those improvements tomorrow. Also… I earned 1085 Stardust on my second ship. Not bad.
HOLEE SHIT, ADDED INSANE STUFF TO MY GAME IT LOOKS SO BEAUTIFUL NOW, I CANT BELIVE IT So, for starters, since yesterday I have been learning shaders. I fixed that shitty atmosphere shader that I translated from someone else’s shader to Godot. I had to make a lot of changes to it to get it working properly for my game. ALSO I MADE A SICK ASS WATER SHADER FOR PLANETS TO HAVE. Then I REWROTE THE PLANET GENERATION SCRIPT. Now each planet has unique properties like: Ambient temperature Water availability Air density, which determines water availability too I also tried adding comets and comet trails to the game, but failed tremendously. Oh, and also, dont go near the black hole. OH AND I GOT MY PAYOUT, AND I GOT THE BAMBULAB A1 MINI. THIS DAY JUST KEEPS GETTING BETTER
AYEEEEEE DEVLOG TIME So today i redid the observatory 3d model, gave it some clean nasa textures, its not upto my standards but its getting there, also fixed that stupid atmosphere bug now everything looks insanely better. Added a planet to the launch screen to flex aswell, i think it looks awesome there. Oh and also i tried to add water walking sound but am failing miserably but worry not as i will be reworking the soundengine too later Taking a moment to give a shout out to my followers who motivated me to work on tis more also HM all the reviewers who gave incredibly nice feedback
Oh i did manage to fix the water walking loop a lil more, its not perfect, but i dont understand whats going on. so ill just work on that later Anyways thats that, big changes i made are that now to place observatories or rovers you need to have a specific amount of scrap on you, i will be turning this into a full fledged build menu so its more appealing, and i will have this menu as a quick hotbar to place blueprints of items. I find this gameloop satisfying as it takes away the management hassle and this game is supposed to be relaxing. And bro how long IS the queue my bambu is STILL not shipped Sorry for slow updates on this project, currently working my ass off irl on the UAV project of mine as i have a deadline to finish it. If i did manage to get a good rep towards this proj, ill be taking the reviewers advice and hosting this game on steam. That developer grant might come in handy ngl
AYEEEYEYYE UPDATE ON THE PEAKEST GAME Made a really smart decision and got rid of the ugly hotbar like menu to place items, now da gam has a nice build menu in which most of the time was spent in making my code more cleaner. But it works now, it looks way more clean and immersive. Instead of relying on hardcoded information for items, i finally made a global that can handle all of that, idk why i didnt do that earlier. About the sound engine, i genuinely hate it a lot, i will be redoing it from scratch and figure out wtf is wrong with it Sorry for slow progress, i dont have much time till im at home so im tryna maximise the time i spend on my rc plen, ples follow it aswell
OKAKAKAYAYAY some more cool additions for exploration aspect for the gam I added an arrow that points towards a set direction, which also changes its with respect to how far the rocket is from that point Also I FINALLY FIXED THE WATER WALKING SOUND ISSUE!!!1!!! Turns out it was quiet easy, i was just too stupid and over complicating it, a simple rewrite fixed everything. For next update i will be adding findable clues, maps, coordinates left out to rot by a “past explorer” that you find across the universe, this is gonna require a bit of time and skill but i can deliver that easy with some time Again progress is a bit slow cuz im actively working on my biggest endurance aircraft but i will keep tis game updated nonetheless, and in future u might even find it on steam who knows
OKAYAYAYAYAYA UPDATE TIME I have graves implemented in the game now, after careful consideration about which direction i wanna take my game towards, i think graves would be a nice addition without disrespecting the procedural nature of the game. I want to make this game very lore heavy while being fully open world and giving the remote in players hands. I dont wnana confine them with thick story plot, or tedious tasks. Nor do i wanna make the game absolutely boring and pointless. The “Rot” i talk about is a cosmic disease the players universe is going through, unexplainable things are happening, weird inter dimensional gates are popping up at random places, everything is near extension. Im not sure about the role of player in all this tho, i will figure something out tho, i wont disappoint yall thats my promise. Also i worked a bit more on a weird bug where items were being placed not where the raycast was supposed to hit. Also I will be removing the inventory system entirely and just rely on blueprint building aspect lmk if yall think thats a good idea Also shout out to hackclub for getting me so much stuff i really love every single one of yall ❤️ Also progress on this game will go back to high now as i wont be home to work on my plen.
Finally a devlog after several days of straight struggle For starters ill tell yall why it took me so long I lowk changed places and i live alone in a room now, i had to shift and living conditions here are absolute hell I somehow survive without going wild due to all the bs ive been facing recently. My productivity has taken a severe hit, a feature like this took me way too much time to complete than it should’ve. That being said i did wander off in different directions cuz i was lowk clueless which direction i should take this game (i still havent decided ) In this devlog i added advanced material processing and advanced materials to the game, with a minecraft furnace like cooking mechanics, i made the logic quiet efficient and refined, its not my best work but it can always be better later. I js hope this eternal torture ends and i finally get to have better living conditions. istg ive been boiled alive, breathing is a struggle in this place Ill keep serving yall with most banger updates so keep me followed, this game is gonna be the next big thing lowk Now i will be makig the 3d model for refinery, before this i made a failure ahh model in whcih i js made a complete simithing room inside a space bubble 😭 Gotta make something better than that so time to lock in
Man i hate making 3D models Not my best work yet, but refinery is done, After several iterations, getting inspo from pinterest and then ditching it and drawing one in back of the class, im finally set on a design, it looks pretty good as of rn. (its not) I fixed a bug where the text was glitching out when i tried to craft scraps, and now it works as it should. The logic is perfect for how it should act in game and im hoping i dont have to touch it again in future to fix it. That being said ofcourse ill be making the 3D model better, But for now i just wanna focus on programming stuff and making the loop right. We can always make it prettier later . Im unfortunately still not home and i still have to survive in this godforsaken room, but hopefully ill be home soon as ill get my appli signed to go home, And then ill be working on both this and the plane together
REALLY NICE ADDITIONS Ive finally added some life to the game. I have added these weird mudfishes inspired by those weird furless cats. These mud fishes aren’t stupid tho, i ___have implemented a proper behavior tree to them, Each one of them has their own set of actions. Normally like minecraft mobs they roam around look around the world, but if a player is near their vicinity, they RUN away from the player protecting them. Currently i have no clue what ill use them for, but one thing is for sure that they have really nice skin I wonder what will happen to it in the near future Really happy by this addition tbh, the world was getting kinda lonely, this was important, in next updates ill be adding colonies of these things mounds and their homes, along with their baby variant.
After getting falsely accused for fraud for using the godot wakatime extension and getting a heart attack I have finally added little homes for these skinny dookeys I hate, HATE behavior trees with every cell in my body I hate to admit but i did take help of claude chat to help me set this shi up, it was js the free version tho so we good. I added so like normally it ran away from player if it sensed one near, but now if the player is close by and it has a home near it runs to that and hides in the home, and if player is far enough it emerges back out. Ill move on to adding more entities now rather than polishing these dudes, i think from the final game i wont even keep them in cuz how ugly and weird they are Aye free me bro i aint do nothing wrong, fix the wakatime extension fr
LETS GO IM FINALLY UNBANNED Unban stuff aside, time to explain the devlog even tho being unbanned feels great and i have insane amount of motivation to work on my proj now In past idk however weeks ive been working on 2 major things, first is that ive finally listened to the last ship reviewers and added upgrades for rocket, with custom 3d models for each rocket tier. currently it uses a separate key to open close the menu which is bad but ill fix later Also only the rockets fuel attribute is updated when you upgrade a rocket so ill fix that too. Also after the ban i was working on electronics update for my game, i have implemented electric poles, 50Kv Generators for now, i am going towards direction of factorio im afraid, but i dont wnana make it very grind-y so ill keep that in mind (hopefully) For future i will be adding better UI/UX its currently embarrassingly bad rn (even tho my degree is Computer science and Design) So yeah that will need a massive revamp Also id like to give a shout out to water #Freewater #heaintdonunwrong
I was aiming for 3 hours today but i lowk got in a fight with a senior in my clg and bro is threatening me to slime me tmr it might be wraps for me gng Putting the sliming part aside, today i made the 3D models for a generator concept (or actual thing) i found online of what they use in space. The i did sm audio editing to have a whrrrrrrrrrrrr looped sound effect and it was quiet easy to make a whrrrrrrrrrr loop, easier than i imagined. Then i added another sound and layered both ontop of each other and now it genuinely sounds kinda peak After that i made the electricity spread across all the electric poles, heres the code for that if body.is_in_group("tower"): towers_closest.append(body) create_lines(body.location_to_connect_wire_to) if has_electricity_running: body.has_electricity_running = true elif body.is_in_group("electrical_appliance"): if body.connected == false: towers_closest.append(body) create_lines(body.location_to_connect_wire_to) body.connected = true if body.is_in_group("generator"): has_electricity_running = true for i in towers_closest: if i.is_in_group("tower"): i.has_electricity_running = true I might lowk be taking AI’s job in writing bad code, they should make a me gpt in which i reply with shit code that DOES work. I also visualized the flow of electricity by hiding/showing a random cylindrical mesh that shows if it has elec flowing through it. Tmr ill be redoing ALL the icons cuz currently they look straight dookey, and also fixing the UI, then if i have time give observatory and everything an electric connection and make them so they dont work without it. This was all i worked on today, yall pray for me lets hope i dont get slimed tmr .
YAYAYAYAYAYA 3RD SHIP INCOMING In the first 2 hours i logged i worked on making the 3d models as refined as possible and made them look good by referring to astroneer as someone commented on my game Also made multiple 3d models for the electric pole and finally used the one that sat right with me. Made a new 3d model for generator and upgrade station aswell In the next 2 hours i made minor tweaks and fixed satellite bugs along with updating the help menu with newer control code, also was thinking of implementing a scrap mine but dropped that idea (maybe later ships) Then i added a little keytip marker near the refinery and chest of observatory to aid the player. Added a bunch of sounds to the electronics of the game and now it sounds a whole lot better (also reduced the main music) FINALLY TIME TO SHIP Thnx to all of the support on this proj i wont disappoint yall at all with future ships
Some really cool additions For starters today i implemented a little list at bottom of the screen that can be used to store the coordinates of player rn Yall might be wondering what tis could be used for, But i have something really cool cooking up in my head lets hope i am able to express it properly. EXPRESSING MY LOVE OF YAGI ANTENNAS I ADDED A YAGI ANTENNA TO THE GAME!1!!! It has a search feature that looks around for strongest signal and then does nothing But in future i will be making a whole mechanic out of this. Then i made a little web release it butchered the visuals i worked hard on. Its okay tho cuz i added a warning label like last time on that release too. Linked the web release as playable link for the game I want YOU to tell me what should i add to this game as im running into a roadblock where i dont know what i could add for the electrical update for the game that would actually be a useful addition, Comment down below to drop your ideas the best one will make it into the game
TESLA SUPER CHARGING So for starters i forgot to tell yall that i DIDNT get slimed by senior my clg department helped me and scared tf outta bro and i got to fight bro too And in this update i added set battery capacity to rovers They use supercapacitors to store charge so that means they can be charged and discharged for eternity Then i added charging stations to the game and made them use power grid electricity. I think players might abuse electricity by only placing 1 generator to power an entire city so i will be implementing complex wattage draw logic like they have in factorio to get some supply/demand action rolling. Then i worked on implementing save game in the game and i failed terribly (this will be a hurdle for later) I spent like solid half an hour trying to implement it just for my save file to be completely empty Idk whats going wrong but i will eventually figure it out. For now tho i will be working on factorio like supply/demand logic for electricity wish me luck
In these 2 hours i have lost all my sanity But finally the factorio like supply/demand electricity mesh finally works First i thought of using recursion to spread the electricity through every single tower But then i ran into a problem where towers interconnected so to fix that i passed a self parameter that didnt seem to help. Then i decided to make towers only connect once (which was a disaster and brought its own set of bugs) and that to tremendously failed So finally i decided upon a global mesh chain architecture where all the nodes in a chain have similar looking list, and whenever an appliance is connected to it the chain just iterates through its connected devices, This in turn brings the time complexity down to O(n) and makes everything a whole lot more efficient. Finally this is done Currently only the tesla charger works with this new logic, later i will add other electric appliances to this mesh network aswell and give them watt draw Few things to keep in mind, Currently 1 generator makes 50kW and one vehicle charger consumes 40W, If the demand isnt satisfied every node in mesh rejects the connection until the demand IS satisfied I know this might feel stupid for some people but this is only done as a feature so you dont overload the electronics in space
IM RICH!!11!! 2080 sd and top 10 in multi I got all positive reviews from yall and i apprciate every single one of u for rating my project. I have finally added scrap mines to the game, i had already made the 3d model for them i just thought they didnt fit in the game but since im adding automation and electricity to the game i think this would be a great addition. Currently they produce 10 scraps, copper, iron per 10 seconds so 1/ sec i will later randomize this and give them weights, im js too lazy cuz of this clg n shi istg Good thing is tho tmr im going home That does mean my work on hardware projects will start again That being said i need you to give me more recommendation for the game, the reviews didn’t give me any ideas or unique views what i could add to my game.
BOOMBOX!!1! , macondo marketing team too good Last night i spent unhealthy amount of time watching ig posts of macondo on hackclub ig, I lowk feel insane amount of fomo and i wanted to go so bad The songs they used in the marketing reels are still stuck in my head So as any reasonable person would, I added a boombox in my game with with my fav songs from the reels they made @zach PLES FLY ME IN NEXT IRL HC EVENT PLES IM BROKE
SHOUT OUT TO @253_Mathilde_IYKYK For starters i made a lil script so that if a rocket is in the SOI of a planet and then it scans near it by pressing F it shows all the necessary details about the planet, currently they are obvious details but i will work on making them useful. I have a few ideas of what i can do with it Now to the important part @253_Mathilde_IYKYK recommended me to add a song they like SO I ADDED IT TO THE GAME Hope yall like it :) (Sorry for not including video idk why stardance was bugging and throwing error when i was tryna upload a video)
Ships:
I made Into the Cosmos, a realistic 3D spaceflight sandbox inspired by Kerbal Space Program and Spaceflight Simulator. The game lets players jump straight into the mission and experience realistic orbital rather than spend hours designing the rocket just for it to fail when launching. This is a relaxing and fun game where players can just sit back and enjoy the physics and thrill of sending rockets to space. The biggest challenge was making somewhat realistic physics with enjoyable gameplay. Getting the gravity, RCS controls, and spacecraft handling to feel both snappy and fun to play with without absolutely broken, writing so many lines of code, and deciding on how im gonna be approaching some problems was quiet fun, i have a lot of fun designing it, i used to go to bed thinking what ill be adding to the game tommrow. I’m most proud of achieving the relaxing experience I originally envisioned. Im quiet glad i was able to fianlly have a direction towards my game and have an idea of what i wanted. And the gameplay is quiet fun aswell, i found myself “playtesting” my games just having fun slamming the rocket into planets, doing interplanetary missions. Setting satellite in different planets To test the project, I recommend reading the in-game controls and instructions first. They explain the basics of reaching orbit and make the experience much more enjoyable.
Into the Cosmos Join Boney on a journey across the endless cosmos, where every horizon hides another world waiting to be discovered. Launch into the unknown, weave between glowing nebulae, drift past impossible black holes, and set foot on planets no one has ever seen before. Build observatories to mark your path through the stars, refuel your rocket, deploy satellites into orbit, and keep pushing farther into the infinite. And when the day is finally over, come relax with Boney and lose yourself among the stars for a while. I’ve always loved games like Kerbal Space Program and Spaceflight Simulator, but I wanted something where you could jump straight into flying without spending hours designing the perfect rocket first. The result is a sandbox space game built around realistic orbital mechanics, exploration, and simply enjoying the journey. The universe is procedurally generated, meaning there is always another unique planet waiting somewhere beyond the next launch. Every expedition can take you somewhere completely new, and every observatory you build becomes another milestone in your adventure. Satellites aren’t just for show either. Launch them into orbit, revisit them later, and use them as your eyes in the sky while you continue expanding your reach across the universe. If you’re new to orbital mechanics, don’t worry. The game includes detailed instructions, an optional on-screen keybind guide, and a full in-game settings menu that lets you tweak graphics and performance to match your hardware. Whether you’re playing on a high-end gaming PC or something much more modest, I spent a lot of time optimizing the project so as many people as possible could enjoy it smoothly. There is one place, however, that lies farther than anywhere you were ever meant to reach. Most people will never find it. Those who do usually don’t come back with an explanation. I call it The Farlands. Whether it’s a bug, a feature, or something else entirely is for you to decide. I built this game in Godot 4.6.2, spending countless hours refining the physics, procedural generation, shaders, rendering, UI, and gameplay systems. Every optimization, every visual effect, and every mechanic was added with one goal in mind: making space feel like a place you can get lost in for hours without realizing where the time went. So fuel up, trust your trajectory, and see just how far Boney can go. If you decide to give the game a try, I’d really appreciate a detailed review afterwards. The feedback I received on my last project genuinely helped shape this game into what it is today, and I’d love to hear what you think could be improved, what you enjoyed, and what you’d like to see added next. If you enjoy the project, consider starring the GitHub repository and liking the YouTube video. It really helps more people discover the game and motivates me to keep building and improving it. So fuel up, trust your trajectory, and see just how far Boney can go.
INTO THE COSMOS This is the game i have designed with inspiration from Spaceflight sim and Kerbal Space program, i wanted to capture the total freedom of roaming in space without the stress of designing a space vehicle for hours just for it to crash into a million pieces. I wanted to make a chill relaxing game that people can come back home after a long day of work to, boot it up and have fun just roaming the eternal space without stressing out. Im quiet proud of how im capturing this vision of mine and im very happy with what im making. Heres some information of what i added this ship: I’ve basically been adding a bunch of systems that I’ve wanted in the game for a while, and the game is starting to feel a lot more like an actual sandbox now. First thing, I finally added electricity. This is probably one of the systems I’m most interested in because now I can actually start making more things depend on power instead of everything magically working forever. This also gives me a lot more stuff I can do with spacecraft and bases in the future. I also added scraps and scrap refining. You can now collect scraps while exploring and actually do something with them instead of them just being random useless objects. I’ve also added the material processing system around this, so scraps can be refined into materials that can actually be used to build useful buildings. This is going to become a much bigger system later on. ROVERS ARE FINALLY HERE You can now actually drive around on planets instead of just landing there and leaving. I really wanted this because the planets were starting to feel a little pointless once you landed on them. Now you can actually get out there and explore the surface properly. I’ve also added planet properties. Planets now have their own properties which means I can start making different planets actually matter instead of them just being randomly generated balls you land on. There’s a lot I can do with this later, especially with resources and exploration. I also did a pretty big overhaul on the visuals. The ambiance shaders have been improved and I’ve added a bunch of new stuff to make the planets and space itself look better. black holes now also have a hidden easter egg…. Ive also given every planet a beautiful atmosphere And yes. Mudfish I don’t know why. They’re still stupid. They just walk around on planets doing absolutely nothing useful. But honestly the universe felt too empty without them so I’m keeping them. A lot of this update was also spent doing optimization because some of the newer systems were starting to get pretty heavy. I’ve been going through different parts of the game and trying to make everything run better without completely murdering the visuals. Overall this update is probably one of the biggest changes to the game so far. And I still have a stupid amount of things I want to add. https://www.youtube.com/watch?v=ZZg3blASmgc This is the link to the youtube video if you dont have time to review the game PLEASE check it out and rate the project I read and appreciate every single one of you reviewing this game, please be as informative as you can be as this is one of the biggest games ive worked on till now, thx and have fun playing the game...
|
1793000924.2454658
|
1793087324.2454658
|
|
7496
|
soul browser by @soulcloude | Stardance
|
soulcloude
|
1
|
124.0
|
0
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-06-12T09:57:29Z", "hours": 124.0, "multiplier": null, "payout": 0, "blessing": "neutral", "text": "I built the Soul Browser! It’s a high-performance, privacy-first web browser built natively for macOS. Instead of relying on bloated web-wrappers like Electron, I built the entire UI natively in SwiftUI and hooked it into the Chromium Embedded Framework (CEF) backend. This gives it the lightning-fast V8 JavaScript engine and Blink rendering, wrapped in a beautiful, macOS-native shell. The biggest challenge was wrestling with memory optimization and IPC (Inter-Process Communication). Because I avoided Electron, I had to manually manage how the native Swift UI communicated with the underlying Chromium processes. I spent a lot of time stripping down site isolation overhead and tuning the V8 heap limits so the browser stays incredibly lightweight. We also had to build custom retry-logic to stabilize our local AI Codex server connection! I’m incredibly proud of the UI aesthetics and the performance metrics. The browser looks and feels like an expensive Apple product thanks to the frosted glassmorphism and native Swift animations. But more importantly, it runs like a dream. Features like the AI Tab Grouper and native !Bangs integration make it a genuine power-tool for developers. You can download the v1.0.0-beta directly from the Releases tab on GitHub! Since it’s a native macOS app in beta, you may need to right-click and hit “Open” to bypass the unverified developer warning. Try out the !w bangs in the address bar, or open 20 tabs to watch the AI Tab Grouper automatically organize them for you!", "repo": "https://github.com/soulcloude00/soul-browser", "demo": "https://github.com/soulcloude00/soul-browser/releases/tag/v1.0.1-beta"}]...
|
[{"post_id": 7376, "ts": "2026 [{"post_id": 7376, "ts": "2026-06-12T09:36:13Z", "hours": 9.7667, "text": "We just open-sourced the Soul Browser! 🚀 I wanted to build a browser that feels incredibly fast, native to macOS, and respects your privacy—without relying on heavy Electron wrappers. 🛠 The Stack: Built entirely in native Swift & SwiftUI for a buttery smooth UI, powered by the Chromium Embedded Framework (CEF) under the hood for world-class web rendering and V8 JavaScript performance. ✨ Core Features: • !Bangs Integration: Instantly search your favorite sites directly from the address bar (e.g., type !w macOS to jump straight to Wikipedia). • Built for Developers: First-class DevTools support natively integrated, plus aggressive memory optimization so your browser doesn’t compete with your compiler for RAM. • Privacy & Security First: Zero telemetry. No aggressive tracking. We baked in anti-phishing scanners, Tor-proxy support, and secure local keychain integration. If you’re tired of bloated web browsers, come check out the code, leave a ⭐, or contribute! 🔗 GitHub: https://github.com/soulcloude00/soul-browser Let me know what you think of the architecture! 👇 #swiftui #macos #opensource #buildinpublic"}, {"post_id": 6403, "ts": "2026-06-10T19:31:08Z", "hours": 14.0, "text": "done a full setting page for the browser took almost 14 hours , so basically its focused all all the use cases , developers , normal users and so many - planing to make a browser that no other browser has achieved"}, {"post_id": 2945, "ts": "2026-06-05T21:05:35Z", "hours": 0.5053, "text": "made an onboarding pages for the browser"}, {"post_id": 2687, "ts": "2026-06-05T11:17:35Z", "hours": 0.7861, "text": "added local ai assisted chat and navigation panel like comet browser on my browser it took lot of time lol"}, {"post_id": 2653, "ts": "2026-06-05T09:56:11Z", "hours": 13.3472, "text": "soul browser devlog 2 - creating a web page for the browser so that users can download from my website"}, {"post_id": 2372, "ts": "2026-06-04T20:35:41Z", "hours": 85.8667, "text": "crafting my own browser"}]...
|
Title: soul browser by @soulcloude | Stardance
De Title: soul browser by @soulcloude | Stardance
Devlogs:
crafting my own browser
soul browser devlog 2 - creating a web page for the browser so that users can download from my website
added local ai assisted chat and navigation panel like comet browser on my browser it took lot of time lol
made an onboarding pages for the browser
done a full setting page for the browser took almost 14 hours , so basically its focused all all the use cases , developers , normal users and so many - planing to make a browser that no other browser has achieved
We just open-sourced the Soul Browser! 🚀 I wanted to build a browser that feels incredibly fast, native to macOS, and respects your privacy—without relying on heavy Electron wrappers. 🛠 The Stack: Built entirely in native Swift & SwiftUI for a buttery smooth UI, powered by the Chromium Embedded Framework (CEF) under the hood for world-class web rendering and V8 JavaScript performance. ✨ Core Features: • !Bangs Integration: Instantly search your favorite sites directly from the address bar (e.g., type !w macOS to jump straight to Wikipedia). • Built for Developers: First-class DevTools support natively integrated, plus aggressive memory optimization so your browser doesn’t compete with your compiler for RAM. • Privacy & Security First: Zero telemetry. No aggressive tracking. We baked in anti-phishing scanners, Tor-proxy support, and secure local keychain integration. If you’re tired of bloated web browsers, come check out the code, leave a ⭐, or contribute! 🔗 GitHub: https://github.com/soulcloude00/soul-browser Let me know what you think of the architecture! 👇 #swiftui #macos #opensource #buildinpublic
Ships:
I built the Soul Browser! It’s a high-performance, privacy-first web browser built natively for macOS. Instead of relying on bloated web-wrappers like Electron, I built the entire UI natively in SwiftUI and hooked it into the Chromium Embedded Framework (CEF) backend. This gives it the lightning-fast V8 JavaScript engine and Blink rendering, wrapped in a beautiful, macOS-native shell. The biggest challenge was wrestling with memory optimization and IPC (Inter-Process Communication). Because I avoided Electron, I had to manually manage how the native Swift UI communicated with the underlying Chromium processes. I spent a lot of time stripping down site isolation overhead and tuning the V8 heap limits so the browser stays incredibly lightweight. We also had to build custom retry-logic to stabilize our local AI Codex server connection! I’m incredibly proud of the UI aesthetics and the performance metrics. The browser looks and feels like an expensive Apple product thanks to the frosted glassmorphism and native Swift animations. But more importantly, it runs like a dream. Features like the AI Tab Grouper and native !Bangs integration make it a genuine power-tool for developers. You can download the v1.0.0-beta directly from the Releases tab on GitHub! Since it’s a native macOS app in beta, you may need to right-click and hit “Open” to bypass the unverified developer warning. Try out the !w bangs in the address bar, or open 20 tabs to watch the AI Tab Grouper automatically organize them for you!...
|
1792982951.6738513
|
1793069351.6738513
|
|
7702
|
Spark (Build!) by @henry1155 | Stardance
|
henry1155
|
2
|
124.0
|
389
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-09-19T02:24:20Z", "hours": 2.0, "multiplier": 5.0, "payout": 11, "blessing": "neutral", "text": "hey! re-ship with an edited video! (and the bonus updatelog!)(NOTE: EPILEPSY WARNING! (it is an edit after all)) ( https://www.youtube.com/watch?v=ktODngPF7UI ) (i have fond memories of this, it was the saturday before the week of outpost and i stayed up to 6 AM edited, after a full day of getting footage and stuff (and dealing with goofy kdenlive crashes)) i also somehow did 10hrs+ that day so that was pretty insane! anyways, thanks for reviewing :D", "repo": "https://github.com/HenryLi-0/spark", "demo": ""}, {"ship_num": 2, "ts": "2026-07-24T05:33:19Z", "hours": 122.0, "multiplier": 5.0, "payout": 378, "blessing": "neutral", "text": "Well, after 120+ hours of building across some 18 days, and another hundred hours of CAD previously, it’s a good time to present Spark, this time irl! Anyways, after last summer, I fell into a sort of hole of demotivation where I didn’t really see what I was “working towards” in terms of school and just waiting six months for the FRC build season to start. In order to try to get my creativity and to prove to myself I wasn’t washed, I decided to throw myself into the deep end and to create a 3D printer. That said, 9 months later and way too many demotivation breaks, I locked in after exams and fully assembled and programmed and tested the build in 18 days! It features a coreXY gantry system, along with a passive tool changing setup with latches and the friction of the top docking piece. This kept the overall motor count to be 5 (2 for xy, 2 for z, 1 for tool). The tool changing setup and printing is nowhere near perfect (after all, this thing’s mostly made of PLA and was programmed in a week), but it’s definitely able to be tuned and better perfected with more programming time! In the end, Spark did achieve its goal of sparking some figurative sparks for me to continue building! After this, it was shipped off and exhibited at Open Sauce in California as part of Outpost where I’ve met amazing people and learned more about 3D printers and how to design them better!", "repo": "https://github.com/HenryLi-0/spark", "demo": ""}]...
|
[{"post_id": 70376, "ts": "202 [{"post_id": 70376, "ts": "2026-09-19T02:12:33Z", "hours": 2.1469, "text": "7/28/2026 - 81st Update! Note: I wrote this back on 7/28/2026 but never published it here! (What? The return of Spark?) Well, not exactly, this is more of a thing for the latest announcement in #stardance-bulletin ! Here’s the edited video from a while back! It’s kinda for vertical/short form content, also, BIG EPILEPSY WARNING!!! While you’re here, you should definitely check out fermion , the “spark v2” in a way! It has a very different architecture (that’s surprisingly hard to cad), so check that out! Anyways, here’s the log without further ado… There’s really not that much to say. On July 26th, Spark was repackaged into a box and put into storage, almost a week after returning to New York City. It’s still in an operational state, with few wires disconnected, only with the WiFi credentials incorrect. For a logged 9 months and 2 weeks, a total of 287 days, with 80 progress updates in that time, Spark’s been on my mind for a long while, no doubt about that. Across the more than 64k words, 240+ hours, from the definitely overscoped original concept to the rush to finish it before Blueprint ended, Spark has existed between two whole YSWS programs, one used for design and one used for build. I have to say, with more than three quarters of a year, a lot has changed, both outside, in my actual life, and with Spark, as the idea changed through every log, slowly and carefully. There were highs and lows, and really, really, low lows, from feeling lost at the end of day 9 of build, to the excitment of the first motor turning during day 11. But now, it’s all neatly packed in the garage, waiting to be used another day. Spark isn’t gone, it still physically exists. It may not be resting on a giant wooden board I use for soldering next to my bed, but it still exists next to me through all the hard CAD and build days. It’s strange, this sudden change. For the last week, I haven’t really done much besides plan. And that’s probably a good thing, given all the planning Spark took. I haven’t really done much build, I haven’t really felt anything. Post convention depressions, I have to say, is hitting pretty hard. After such insane fun and wonder for a week, it’s suddenly back to a cool, rainy day, here in New York City. Sleeping through the afternoon, after sleeping not enough hours in the morning. As the rain starts pouring from the sky again, I’ve been wondering what the meaning of joy is. Alas, it might just be time. Adapting to such changes is obviously difficult, and the road of projects is too. But that doesn’t mean roadstops aren’t along the way. As I wrap up this update log, I want to leave a quick quote, one of my favorites. It probably sounds like a dumb platitude to say “it’s not the destination, it’s the journey”, but truth is, we’re made up of journeys. You’re never going to be who you’re supposed to be unless you take that road. … There is room in there for surprise, for deviations, for re-evaluations. I wouldn’t dare deprive you of that adventure. You only get one , after all. I know, you’re tired; resting is part of the journey too. But not giving up… Winter, in Housepets! (Rick Griffin, Dec 25, 2020) That said, what’s next? Well, first we’re gonna take a stepping stone. What’s next is still in concept form, but the unique constraints might require a custom PCB, which is where river comes in. First, it’s gonna be a quick project, just a custom PCB music player, just to jog the electrical skills. But after a quick skip over a stream, what’s truly next? What’s the successor to Spark? What’s next to rival its top 1 status? Fermion. See ya around."}, {"post_id": 33890, "ts": "2026-07-24T05:24:31Z", "hours": 1.5761, "text": "7/23/2026 - 80th Update! well. so im back from open sauce! actually, flight entered back to NYC on the morning of 7/21/2026, but the last two days have really just trying to get back in motion lol (turns out having crazy fun and instantly returning to “normal life” is somewhat rough) anyways, it’s 9:18 PM, here’s a recap! i dont think timelapsing all the work there would be reasonable (i estimate probably around 8 hours of work?), but yeah, mostly just config tuning and working on irl stuff, the base plate sort of didnt like the flight (but it’s really alright? basically the screws kinda ripped through the tape a bit) after the return flight, one of the LM2596’s input wires fell out, took a bit to get it in (haha get it screwdriver bit), anyways, still got a lot to do, i think for now im gonna just finish the update log on the stardance site, then update all the graphics over here, and yeah, prepare for something new??? (i have some ideas…) anyways, i think im gonna prep the stardance project to ship, idk if i can? ok, 11:00 PM, updated the front image, gonna work on updating some stuff ok, 11:06 PM (almost typed AM, that would be funny), added the open sauce image to the readme, brb! back at 12:42 AM, yeah, i think it’s a good time to ship? mfw fixing the position so the aspect ratio for the banner and the project banner (the different pages) are so so hard to get correct anyways, yeah, gonna copy this stuff over and we should be good to go? well, 1:22 AM, for now, good night!"}, {"post_id": 33812, "ts": "2026-07-24T01:35:42Z", "hours": 11.3686, "text": "7/11/2026 - 78th Update! in theory, the last one? in reality, probably not. anyways, it’s 3:22 PM, today’s reveal/edit day! of course, i got a bit of table clean up to do and recording, but i also wanted to play around with the settings a little more to get a somewhat better print? (and maybe test another print since this ones a little small) anyways, parent meeting at 5 PM today, gonna be attending on the side while probably editing? im planning on doing two more test prints before then test 1: turned layer speeds from 90mm/s to 70mm/s increase flow ratio from 1.15 to 1.21 decrease skirt loops from 7 to 5 ok, 3:43 PM, sliced and uploaded, heaters all heated, ready to go! gonna use the bathroom, seems to be printing well though! back at 3:55 PM, it printed well and ended well! gonna modify the ending gcode to cool down, analyzing results now! kinda wanna replace the middle tape strip since i kinda messed up and removed a ripped a bit of it while scrapping the skirts off (whoops), gonna go for one more print, im pretty satisfied, this ones gonna be a bigger test print (not a benchy yet though), im thinking calibration cube? test 2: increase flow rate from 1.21 to 1.30 decreae rotation distance from 6.4 to 6.0 increase deretraction speed from 6mm/s to 6.5mm/s decrease jerk for x (5mm/s to 4.5mm/s) y (5mm/s to 4.5mm/s) z (0.2mm/s to 0.175mm/s) x (0.3mm/s to 0.25mm/s) gonna use this makerworld one for this! intrested to see how this one goes! it’s more of a z axis and consistency ending test should have just enough filament? expecting like 2-3cm left on the top after this? might not have enough on the top but that should be fine? hopefully? i mean, if i see the filaments about to run out id rather end the test? idk footage time yeah its kinda… erm. it kinda failed to print beyond the base layer, seems to just struggle with grabbing filament on its side, let me get a straw real quick, nvm, just used a piece of filament taped down for it, i think its just a filament grabbing issue (probably fighting against the curl?), so yeah, this should straighten that out a bit? test 3 (aka, 2 again), decided not to change anything, here we go! gonna focus on footage for this one so that might have been the… worst prints ive seen, but sure ok, just added the filament from the spool, should be ready for a bigger test? test 4: changed max volumetric speed from 5mm^3/s to 3mm^3/s turned flow ratio from 1.3 down to 1.22 rotation distance reverted from 6.0 back to 6.4 oh yeah heres the image of the cube yeah, gonna go for a 50% benchy erm 50 minute print uhh, well, 5:50 PM, now or never, i guess imma setup for a reveal scene ok, created a nice set for filming, gonna be doing mostly footage stuff while this prints, not really any timelapse? i guess i could? ok, hopefully printing and footage done by 7PM, then probably editing or dinner sometime around there (yes, todays the end day i think, at least my goal) ok, quite some time later, gonna speedrun dinner, its 7:31 PM though i was away for a bit before then welcome back, 9:11 PM, did a bit of footage getting earlier, here goes a print so. half way through. turns out our cold end/heatsink or whatever kinda doesnt cool it well enough. essentially, yeah. it just started curling up halfway in. yeah. however, it did successfuly print half of it! test 5: turned layer speeds from 70mm/s to 80mm/s changed max volumetric speed from 4mm^3/s to 3mm^3/s (seems like i forgot to do it whoops) most devious gcode modifications and slicer shenanigans later devious part 2 well, it’s 6:02 AM now, after lots of editing, submitted the forms, time to head off to bed! and yeah, good night!"}, {"post_id": 26773, "ts": "2026-07-11T19:21:48Z", "hours": 7.0922, "text": "7/10/2026 - 77th Update! wow, 77 updates, so it’s now 10:00 PM, idk what happened to this afternoon (basically just vanished, went to some job in the morning, slept when i got home, ate lunch at 4 PM, slept again, ate dinner at 8 PM, then showered and now it’s somehow 10:00 PM) im thinking media is gonna have to be moved to tomorrow, my only goal today is to find diamonds get the printing to work reliably here’s a couple ideas i brainstormed last night increase the extruder heating temperature should make it way easier for the gearing to push as well double check gearing probably not this now that i think about it, but check docs double check rotation distance again, probably correct add extra pressure in the config similar to the first idea as in trying to actually push more filament slow things down even more very sad but self explanatory if we overextrude, that’s ok, we just need to find the tuning sweet spot where it is actually decent, but of course, the more important goal is to actually get some reasonable stream of filament flowing out (constantly extruding is not optimal but it’s whatever) ok, upped the printing temperature by 10C, also decreased a lot of speeds, 10:33 PM, hopefully ready to test? ok, prepping the stuff, gotta clean the nozzle too, ok 10:40 PM, ready to go! well that didnt print anything ok, so shoving filament down the throat extrudes, pushing filament from far above works well (it does slam left and right but still functions fine), the velocity isnt correct AT ALL (might just be from the compression/friction), hmm ive been suggested to look into the heatbreak and stuff, so gonna take a look at that, idk a bit of a break later, the gearing is sus, trying to move it with the top off and only the heatsink attached, seems off it’s been two hours and ive been playing with so so so many configurations (probably at least thirty?), moving spacers, adding rubber bands, readjusting, measuring, and i think ive come to a point where it’s “ok”. it goes out ok (3 rotations of the motor connection results in: ~1.8cm pushing fast, ~1.7cm pushing slow, idk for expected), but it’s basically incapable of going back up for some reason. it also produces a good amount of force out, but, as mentioned before, barely any up (skips a bunch) ok, played around a bit more, idk, retraction worked for a second randomly, idk, installed it back on, ready to test again 3:36 AM, did a couple of cursed things in the config, specifically making it extrude 4x as much, along with making the deretraction speed higher in the slicer, that said, here we go! ey it printed something! its still really fuzzy so i guess we still got more work to do (that was v1.4), ok v1.5 uploaded, let’s see! 4:12 AM, here we go oh yeah also added fancy ending gcode lol hmm, it’s more complete, but stll missing stuff, ok, 4:27 AM, the birds are probably coming out soon, v1.6 going! well that didnt end well huh seems like the issue was just that the filament wasnt fully loaded, whoops ok, v1.7 uploaded with some print skirts on the outside to help with the missing start extruding, flow rate also increased, let’s see, it’s 4:54 AM, so last print of the day! uh oh it seems to be underextruding now, ok, 5:09 AM, here’s v1.8 ow was in the middle of cleaning the print bed and a piece of the skirt just went straight under my fingernail ouch well, with the sun rising, here’s the end of today! imo v1.5/v1.6 is my favorite, but it’s getting there in terms of smaller details, so i think tomorrow one or two more test prints and then a benchy would be a smart move? idk, the benchy’s just for the reveal video (yes i will try to fit in media here!) well, 5:33 AM, that’s it for me tonight (tomorrow morning?), and yeah, good night!"}, {"post_id": 25756, "ts": "2026-07-10T06:22:05Z", "hours": 4.8033, "text": "7/9/2026 - 76th Update! yo and welcome back! it’s 8:57 PM at night, don’t have much time to waste now, today’s hopefully printing day? (with the actual printer of course) saw online last night from like a video from 6 years ago that using blue painters tape is a good idea (why does my s key consistently fall out now aaaaa), well look what i got here (figuratively), it’s a roll of scotch blue 2090 tape! ok, watched a couple of enlightening videos, so, i think we’re just gonna use some blue tape, seems pretty much good enough for our purpose, not sure if i really want to get orca slicer just now, i think i just want the printer to at least extrude something at this point in time? center is roughly (50.00, 77.50, ~) right now, ok, wrote a little something to center the stuff so (0, 0, 0) should hopefully be the center? yeah, close enough! ok, it’s probably a good time to apply the tape ok, tape applied, cleaned the nozzle, planning on doing the paper thing right after, then we need to print like something flat real quick (if it works, since we still need to do the config stuff for the extruder) quick 20 minute break to let it cool down later, it’s 11:07 PM, time for the paper stuff! so it doesnt really do a good job at staying level, but i do have a solution in mind, aka, having weights on both the sides to keep it flat. yeah. or a rubber band thing stretching the entire length. anyways, configs inputted! so at this point, the thing we need to focus on is getting the extruder config up and running! ok, set up the slicer with the stuff, gear ratio is start (14) to mid (28->14) to final (28->12), where it ends ok, gonna do a test “print”! it’s in quotes since it’s actually not gonna have any filament, just gonna make sure the motion works/makes sense ok, 12:31 AM, let’s run it! ok, temperature below min or something (as in the gcode stuff) 12:40 AM and still figuring stuff out, hold on a second… ok, it’s running! at least, the stuffs moving, not sure if it’s printing well? idk, gonna watch it go! it’s going! that looks… fairly realistic? idk why the heatbed’s at 60.7C right now ok, 12:54 AM, filament loaded on the top in a semi precarious matter, things are ready! 12:57 AM, here we go! timelapse running on my phone, let’s see it! heat bed termperature good, extruder temperature rising, oh turns out i have to have the tab active for it to update the graph visually, whoops well, reached the temperature, let’s see something? oh it just stopped itself because axis werent homed, ok, test 2! 1:03 AM, z axis is lifting, here we go! hmm so the extruder didnt really try… anything. like it wasnt running the whole time (unless it’s just a really small amount that the gearing cant handle?) ok the issue might just be i didnt push the filament in enough, since i just gave it multiple aggresive tugs and a whole bunch just came out of the nozzle, 1:14 AM, here we go again! (i do not want to know what the weird vapors or gasses it just released (yes i saw it, which isnt a very good thing)) also, wow, the heating controls are tuned really nicely! ok, 1:17 AM, z axis going up again so wasnt extruding anything, had to push on it to move, and that resulted in an obvious pile of sad sad so i feel like this is a bit of a gearing thing, since small amount arent really wanting to come out at least it got the rough shape correct? hmm i want to try it out without me pushing on the filament, expecting nothing to happen but who knows yeah i think its just really under extruding, probably because of slip inside? 1:43 AM, trying again, yep, nothing good, it’s now 2:00 AM, gonna go to sleep at this point yeah. idk. the one on the left is forced filament, the middle had a bit of push at the beginning, the last one was mostly by itself. yeah, idk what to do at this point. it’s 2:03 AM, idk what to do, and yeah, we’re kinda behind schedule. anyways, good night!"}, {"post_id": 25175, "ts": "2026-07-09T06:59:41Z", "hours": 4.6269, "text": "7/8/2026 - 75th Update! mfw when the stardance bot tells me that only 10 hours per devlog counts now that’s just rude well, welcome back! 5:01 PM today and starting things off in a bad mood. guess we gotta waste our precious time by cleaning stuff up anyways, 15 minutes later and some serious condensing (each day is like 5 sentences max), back to work! got some unfinished business to do while we work on today’s stuff! so a series of event have occured and now it’s 10:13 PM. oops. for a second i got scared something was wrong but turns out the connecting wire to the inlet thing was just a bit disconnected, trying to access the web interface right now… oh it’s because im on downstairs wifi. oh. gonna be following this for calibration! not exactly sure why there’s so many connection issues today. ok, while that’s connecting, gonna print the latch parts so my s key finally fell off. oh. that’s not good (yes im touching the little button under it) ok, w repair, cleaned it up, the key still does the weird tilt thing, but it stays in there, so that’s good so uh it fell out again. not good. ssssssssssssssssssssssssssssssssssssssssssssssssss oh i guess im gonna keep that, i just need to be more mindful of where i press it i guess, problem is currently that the mcu keeps disconnecting whenever i change the extruder temperature, which is kinda weird hmm mightve been an electrical thing? so i just spent an hour trying to come up a solution for the extruder, none of them are reliable or possible (rubber band placement just gets in the way). so yeah. whys it working now i guess the solution is grinding the gears down? whys the “rushed for display” extruder the only working one now, wow ok, latches made, no rubber bands since that just doesnt work (both the track and the thing), idk, later issue, right now i guess we’re gonna tune z stuff or gonna just try to make it as flat as possible? i think for now let’s just assume perfect flatness for time, let’s replace the heater section of 1 with the one of 3 and just basically use tool 3 instead for time (since the gearing apparently works???) (please stay that way) i guess making it as flat as possible is the best idea for now ok so it’s now 2:32 AM, the docking bay and the latches are added (ngl, they are bending because of a fillet), gonna ignore the fact that it’s slightly broken (nothing tape can’t fix), it does work, takes a bit of force though (as always) 7/7/2026: DONE - print, assemble, and add latches 7/8/2026 DONE - heating tuning DONE GOOD - z bed tuning GOOD - either assume perfect flatness or work on bed mesh/calibration g code should be able to run easily (simple commands of course) look into how to print stuff PRINTING WORKING BY EOD it’s 2:50 AM, tested it out, IT EXTRUDES! YAY! (like i let go of the filament after pushing it to the cooling area and then it extruded!!! by itself with its own gearing!!!) the clicking noises are a bit questionable but sure, ill take it! also did the z paper thingy! missed opportunity to call it cerberus, i might just add that somewhere… anyways, here’s the extruded stuff picture! woo! i mean, what a way to end the day! ok, it’s 2:56 AM, that’s about it for tonight, gonna copy paste this into the website for today’s log and yeah, good night!"}, {"post_id": 24973, "ts": "2026-07-08T21:15:36Z", "hours": 37.5192, "text": "I’ve just been told 75% of my time spent on this log doesn’t count (apparently), so instead of dedicating probably an extra two hours of unlogged time to write a clean version, yall gonna get my thoughts DAILY, straight from the source, raw updatelog content. just kidding, there’s now a world limit so im just gonna speedrun this (since no one reads this and i read my own raw thoughts) 7/2/2026 Mostly electronics work, on 7/1/2026 night, realized that I can actually gently pry off the jst connector shells, removed a good amount of them. Wrote a devlog, worked on tuning the extruder filament tgrabbing gears. After dinner, printed some stuffs, then started adding the corexy belting path. Spent a long time, didn’t really feel very motivated at 3:42 AM and ended the day almost finishing assembling the belts and with not working extruders. 7/3/2026 Woke up early, last night wasn’t a fun night, increased the gear scale, finally actually put the corexy belt together. The filament gears now grab, though it does skip when too much filament is put in. After fixing the shaft collar and adding it back, reassembled the test tool and it attaches! The corexy does have quite a bit of friction, but the tool is assembled! However, waiting on terminal stuffs. Rest of the day is starting the electronics stuff. 7/4/2026 Motors not moving? Removed wires from housing and fix phases, motors now moving! Wondered why one motor was faster, then they both became slow. Fans wired, heaters wired, more testing, heaters can heat up! 7/5/2026 Bad sleep schedule strikes again, some soldering and added the limit switches, more stuff sent to print. A bit of config editing later and the corexy moves properly now! With the correct x and y axis! Filament doesnt really grab very well, idk.More intense filament testing, extruder can reach 230C! 7/6/2026 Really late start, more tool printing, more tool assembly, all tools and extruders are assembled now! 7/7/2026 Schedule and todo list made, support bracket set to print, top shaft supports made a printed, belts tensioned again. Some fixing later, two part inlet case CAD done and sent to print and attached, second tool head also wired up. There’s your week of updatelogs compressed into a format because theres a character limit. From now on, all devlogs will be the updatelogs and not be as extra refined, since I don’t get time counted for writing these, and it’s really a pain and insult to just say that more than a whole 24 hour day worth of actual work doesn’t count because someone added a time limit per log out of nowhere."}, {"post_id": 21018, "ts": "2026-07-02T19:40:26Z", "hours": 22.1556, "text": "it’s been four days oops More Assembly and Electronics! 6/28/2026 Ok, it’s z axis day! Gonna try to keep these recaps short since I’ve mostly been writing giant blobs of text with little images recently, since moving photos from my phone to the laptop and into the update log is a bit annoying, but yeah, z axis and motor mounts were started today! 6/29/2026 Realizing that time was really running out, along with the fact that NYC is attempting to reach high temperatures out of nowhere, a schedule was made and coreXY pulley stands were sent to print! First things first though, the z axis lift base thing was added , and some electronics stuff was started! It’s a little different from the wiring diagram, along with the fact we’re using a raspberry pi 4b, and a couple other stuff. Also, the docking bay got redesigned! 6/30/2026 Anyways, coreXY stuff printed and the layer is assembled! The gantry has a bit of wobble (and the bearings aren’t a tight fit), but nothing some hot glue can’t help with! (Well, maybe the wobble). Anyways, mainsail flashed on the raspberry pi 4 and figured out the weird issues! Also, reminder to switch the jumper thing for input form the side to the usb power.. so, the t rods hit the gantry too, along with the fact that the build plate doesn’t exist. Decently productive day, 5 days left. 7/1/2026 go go go New month, and leectronics work continues! Sacrificed the aliexpress USB power cable, split the wires, and attached it to the LM2596, looks good! Also learned how to crimp today, so that’s pretty cool. There’s also a picture of the thermistor of the heater bed in the mainsail graph somewhere down there! Unfortuantely, I don’t have free JST connectors on ahdn, so we’re gonna be doing sketchy stuff with a dupont connector in there (the pitches are a bit different, yes, i know it’s crazy sketchy, shhhhh) Anyways, after setting tool stuff to print, went downstairs and (thanks to my dad) got the t screws cut and a 15x15 build plate out of some aluminum (it’s like 1.3-1.6mm thick?). We did have to make it out of sheet aluminum that was laying around, but it came out alright, the holes are just a little misaligned but that’s a bit on me. Anyways, realized the tool stuff printed was super cursed, had to work on redesigning a lot of parts, specifically the sahft collar, the gearing (no more bearings should be needed, all the stuff should be using filament as deadaxles). Anyways, we have to fix this cad stuff (half way done), then hopefully belt the corexy and do electronics while it prints tomorrow (aka, today)? Well, that’s it for now, gotta go fast (sonic reference?), only four days left…"}, {"post_id": 17873, "ts": "2026-06-28T20:10:07Z", "hours": 14.5661, "text": "What do you mean 14hrs+ passed? Anyways, here’s a quick recap! Frame Assembly and Even More Printing! 6/25/2026 On a kinda windy day in NYC, printing continues! But hold up, what’s this? Yes, it’s also extrusions cutting day! While printing the stands for the bottom of the printer (after printing a whole bunch of gussets the previous day) after optimizing the print settings, I did some quick reviewing of the extrusion and rod cut lengths and then realized that I miscounted the middle frame y extrusions, it should’ve been three instead of two. So there wasn’t enough length for this extra extrusion (the tmm extrusion). Yeah. Anyways, not shortening the print area by 6cm to get the length, so calculated the linear rod cut lengths and headed downstairs. Huge thanks to my dad for cutting all these extrusions and rods! Now that I think about it, I did work with a blade saw up down thing before (idk what its called, a cold saw but its not cold and goes to higher rpms), but not with a handheld grinder before (i think that’s what it’s called?). Anyways, I learned that the little aluminum chips (that you can’t eat unfortunately) is actually the material, since you lose material every time you cut! This means that some extrusions are a little shorter, but the gussets helped work fine with this! Anyways, after seeing real sparks from the rods getting cut and theneating dinner, finished printing the stands and then realized the bmm extrusion doesn’t have any support. Yeah. Anyways, counted the number of extrusions and ended that day starting a little bit of assembly! 6/26/2026 Frame assembly day! Not much to say other than it involved roughly 5 hours of manual screwing with a screwdriver (using a drill did not really end that well, yes, I tried, probably a skill issue though). Anyways, printed a good amount of tool base stuff at the same time (the tool base print fell on my foot off a table (ouch)), and did a lot of frame assembly! In fact, used 203 T-nuts and 128 screws! Mostly just a lot of tedious work, but hey, the main frame’s done! 6/27/2026 Oh that’s yesterday! Anyways, first part of the day was just me at the doctor’s office, so couldn’t get much done, but I did set an x slider block to print, and it came out pretty well! Also, all three extruders got assembled! And the starts of the tool base! Nothing else much though, unfortunately! Well, that’s it for now, not writing today’s (6/28/2026) since that’s still happening right now, see ya after corexy assembly! (hopefully???)"}, {"post_id": 15511, "ts": "2026-06-25T06:29:33Z", "hours": 11.0467, "text": "Well, it’s been another hot second, ya miss me? Jokes aside, here’s the recap of the last three days! 6/21/2026 haha funny number day Anyways, back to CAD fixing! After a quick little script writing for counting words in all the updatelogs (there’s around enough for a small novel, not including anything on the Blueprint site which is actually fully rewritten by the way, so that’s pretty cool!). Oh that’s a big list todo… again, check out the GitHub repo for more details! Anyways, today’s latch day, since, well you kinda need to finalize the latch design before fixing the docking bay… One spring print later, turns out the original idea wasn’t the best. Apart from being really weird to test (both prints weren’t really willing to stretch, and were really easily stretched beyond its maximum), so new design time! This time with rubber bands instead of springs! Oh yeah, we changed the idea, it’s no longer a top down spring locking thing, it’s more sideways, essentially this idea. ( Here’s the original plan, however the space restrictions really didn’t work out…) 6/22/2026 Since the latch design got ready to test… what do you mean it’s not ready… well, yeah, turns out there were quite a good number of oversights in the original version, so two more hours of fixing the structure later, it’s printed! It looked pretty promising, but has its own set of issues. For instance, the slider doesn’t lock since the rails kinda don’t keep it in, the guide does work (which is really good!, but gets a bit caught in a couple areas. The latch also uses filament for the smaller parts and pivot bits, which is a bit annoying but it alright… though, the rubberbands do need to be pretty strong for this to work. Also, a couple of small adjustments and keeping the pivot upwards so it doesn’t enter the latch the wrong way (it doesn’t work through the bottom path), and needs a bit more alignment stuff, but it’s pretty promising for a prototype! 6/24/2026 What happened to yesterday? Well, kinda got tired after an exam and just kinda didn’t do anything for the rest of the day. Anyways, it’s currently 2:19 AM (not counting this for the time by the way!), so this is technically today’s summary! Basically, we’re behind schedule, so we should probably start printing stuff that’s pretty much finalized (gussets, etc.) and isn’t gonna change anytime soon, just so we can CAD at the same time to speed things up (spoiler, not much CAD work was done today…). However, 22 corner gussets and 4 three way gussets were printed today! 4.95 hours of printing later (including a couple of failed prints), roughly 131.3g of filament was used (not including failed prints)! That’s some scary fast usage… Also, opened a fresh roll of white filament! Gotta say, I don’t really like the resulting surface finish of the Inland filament (got it last year at Micro Center and never opened it), but it’s probably something with print settings and what not. I mean, I can also print it out in vibrant pink? (that’s the only unopened one I have from bambulab…) I’d probably just use Polymaker or Bambu filament from now on, the prices are all relatively the same at $20/spool. (If anyone has any cool discounts or cheaper but reliable places, I’m all ears!) Anyways, yeah, quite a lot of writing, wow… anyways, that’s it for now! I think I’m just gonna continue doing logs every couple of days since sometimes I don’t feel like it, but I’ll try to keep up the consistency! Catch y’all in a bit!"}, {"post_id": 12953, "ts": "2026-06-21T06:14:36Z", "hours": 7.57, "text": "Well, it’s been a hot second, Spark progress resumes! (This site editor kinda has text way too big for my liking, gonna write this in notepad first…) Anyways, Blueprint rules still apply here, most of my thinking and extensive writing is going to be located inside the repository itself (under updatelogs), while here serves as a mroe general overview of what’s going on. So, what’s going on? There’s already 3 days worth of stuff done, so let’s go through them! 6/12/2026 Basically a brief recap of some test prints here and there! More importantly, I just drafted up a pretty decently sized todo list of stuff we need to fix in the CAD, before we can start multitasking printing and doing other stuff. Tested prints include the bearing stacks, frame gussets, and tool plates! This basically gave information that some dimensions were a bit off (bearings were 4mm tall, not 3mm, frame gussets could be a bit thicker, tool plate had some sus screw locations (material too thin in some places))! It also suggested other changes to make. 6/19/2026 Giant schedule! Again, see the whole thing over there, basically a really rushed schedule on when stuff needs to get done, the goal is to finish in a bit more than two weeks. After that, a whole bunch of CAD fixes! From the stuff mentioned before to some fixes with screw lengths being somewhat impossible for the top of the tool to fixing the filament not having anywhere to go, to starting work on fixing the docking bay! Overall a really productive day! 6/20/2026 Oh, that’s today… anyways, not as productive, currently trying to implement an actually working spring latch system for it to actual work (the other version just doesn’t work). However, it’s a bit hard to think about, and the space isn’t exactly optimal (it’s kinda tightly packed…). Didn’t finish it, gonna continue with it tomorrow and take some time to think about any possible oversights or anything! And that’s it for now! Decently large first log (not as big as the ones in updatelogs lol), but I’ll try to see if I can do this daily for the site, but no promises! Ok, see ya hopefully tomorrow!"}]...
|
Title: Spark (Build!) by @henry1155 | Stardance
D Title: Spark (Build!) by @henry1155 | Stardance
Devlogs:
Well, it’s been a hot second, Spark progress resumes! (This site editor kinda has text way too big for my liking, gonna write this in notepad first…) Anyways, Blueprint rules still apply here, most of my thinking and extensive writing is going to be located inside the repository itself (under updatelogs), while here serves as a mroe general overview of what’s going on. So, what’s going on? There’s already 3 days worth of stuff done, so let’s go through them! 6/12/2026 Basically a brief recap of some test prints here and there! More importantly, I just drafted up a pretty decently sized todo list of stuff we need to fix in the CAD, before we can start multitasking printing and doing other stuff. Tested prints include the bearing stacks, frame gussets, and tool plates! This basically gave information that some dimensions were a bit off (bearings were 4mm tall, not 3mm, frame gussets could be a bit thicker, tool plate had some sus screw locations (material too thin in some places))! It also suggested other changes to make. 6/19/2026 Giant schedule! Again, see the whole thing over there, basically a really rushed schedule on when stuff needs to get done, the goal is to finish in a bit more than two weeks. After that, a whole bunch of CAD fixes! From the stuff mentioned before to some fixes with screw lengths being somewhat impossible for the top of the tool to fixing the filament not having anywhere to go, to starting work on fixing the docking bay! Overall a really productive day! 6/20/2026 Oh, that’s today… anyways, not as productive, currently trying to implement an actually working spring latch system for it to actual work (the other version just doesn’t work). However, it’s a bit hard to think about, and the space isn’t exactly optimal (it’s kinda tightly packed…). Didn’t finish it, gonna continue with it tomorrow and take some time to think about any possible oversights or anything! And that’s it for now! Decently large first log (not as big as the ones in updatelogs lol), but I’ll try to see if I can do this daily for the site, but no promises! Ok, see ya hopefully tomorrow!
Well, it’s been another hot second, ya miss me? Jokes aside, here’s the recap of the last three days! 6/21/2026 haha funny number day Anyways, back to CAD fixing! After a quick little script writing for counting words in all the updatelogs (there’s around enough for a small novel, not including anything on the Blueprint site which is actually fully rewritten by the way, so that’s pretty cool!). Oh that’s a big list todo… again, check out the GitHub repo for more details! Anyways, today’s latch day, since, well you kinda need to finalize the latch design before fixing the docking bay… One spring print later, turns out the original idea wasn’t the best. Apart from being really weird to test (both prints weren’t really willing to stretch, and were really easily stretched beyond its maximum), so new design time! This time with rubber bands instead of springs! Oh yeah, we changed the idea, it’s no longer a top down spring locking thing, it’s more sideways, essentially this idea. ( Here’s the original plan, however the space restrictions really didn’t work out…) 6/22/2026 Since the latch design got ready to test… what do you mean it’s not ready… well, yeah, turns out there were quite a good number of oversights in the original version, so two more hours of fixing the structure later, it’s printed! It looked pretty promising, but has its own set of issues. For instance, the slider doesn’t lock since the rails kinda don’t keep it in, the guide does work (which is really good!, but gets a bit caught in a couple areas. The latch also uses filament for the smaller parts and pivot bits, which is a bit annoying but it alright… though, the rubberbands do need to be pretty strong for this to work. Also, a couple of small adjustments and keeping the pivot upwards so it doesn’t enter the latch the wrong way (it doesn’t work through the bottom path), and needs a bit more alignment stuff, but it’s pretty promising for a prototype! 6/24/2026 What happened to yesterday? Well, kinda got tired after an exam and just kinda didn’t do anything for the rest of the day. Anyways, it’s currently 2:19 AM (not counting this for the time by the way!), so this is technically today’s summary! Basically, we’re behind schedule, so we should probably start printing stuff that’s pretty much finalized (gussets, etc.) and isn’t gonna change anytime soon, just so we can CAD at the same time to speed things up (spoiler, not much CAD work was done today…). However, 22 corner gussets and 4 three way gussets were printed today! 4.95 hours of printing later (including a couple of failed prints), roughly 131.3g of filament was used (not including failed prints)! That’s some scary fast usage… Also, opened a fresh roll of white filament! Gotta say, I don’t really like the resulting surface finish of the Inland filament (got it last year at Micro Center and never opened it), but it’s probably something with print settings and what not. I mean, I can also print it out in vibrant pink? (that’s the only unopened one I have from bambulab…) I’d probably just use Polymaker or Bambu filament from now on, the prices are all relatively the same at $20/spool. (If anyone has any cool discounts or cheaper but reliable places, I’m all ears!) Anyways, yeah, quite a lot of writing, wow… anyways, that’s it for now! I think I’m just gonna continue doing logs every couple of days since sometimes I don’t feel like it, but I’ll try to keep up the consistency! Catch y’all in a bit!
What do you mean 14hrs+ passed? Anyways, here’s a quick recap! Frame Assembly and Even More Printing! 6/25/2026 On a kinda windy day in NYC, printing continues! But hold up, what’s this? Yes, it’s also extrusions cutting day! While printing the stands for the bottom of the printer (after printing a whole bunch of gussets the previous day) after optimizing the print settings, I did some quick reviewing of the extrusion and rod cut lengths and then realized that I miscounted the middle frame y extrusions, it should’ve been three instead of two. So there wasn’t enough length for this extra extrusion (the tmm extrusion). Yeah. Anyways, not shortening the print area by 6cm to get the length, so calculated the linear rod cut lengths and headed downstairs. Huge thanks to my dad for cutting all these extrusions and rods! Now that I think about it, I did work with a blade saw up down thing before (idk what its called, a cold saw but its not cold and goes to higher rpms), but not with a handheld grinder before (i think that’s what it’s called?). Anyways, I learned that the little aluminum chips (that you can’t eat unfortunately) is actually the material, since you lose material every time you cut! This means that some extrusions are a little shorter, but the gussets helped work fine with this! Anyways, after seeing real sparks from the rods getting cut and theneating dinner, finished printing the stands and then realized the bmm extrusion doesn’t have any support. Yeah. Anyways, counted the number of extrusions and ended that day starting a little bit of assembly! 6/26/2026 Frame assembly day! Not much to say other than it involved roughly 5 hours of manual screwing with a screwdriver (using a drill did not really end that well, yes, I tried, probably a skill issue though). Anyways, printed a good amount of tool base stuff at the same time (the tool base print fell on my foot off a table (ouch)), and did a lot of frame assembly! In fact, used 203 T-nuts and 128 screws! Mostly just a lot of tedious work, but hey, the main frame’s done! 6/27/2026 Oh that’s yesterday! Anyways, first part of the day was just me at the doctor’s office, so couldn’t get much done, but I did set an x slider block to print, and it came out pretty well! Also, all three extruders got assembled! And the starts of the tool base! Nothing else much though, unfortunately! Well, that’s it for now, not writing today’s (6/28/2026) since that’s still happening right now, see ya after corexy assembly! (hopefully???)
it’s been four days oops More Assembly and Electronics! 6/28/2026 Ok, it’s z axis day! Gonna try to keep these recaps short since I’ve mostly been writing giant blobs of text with little images recently, since moving photos from my phone to the laptop and into the update log is a bit annoying, but yeah, z axis and motor mounts were started today! 6/29/2026 Realizing that time was really running out, along with the fact that NYC is attempting to reach high temperatures out of nowhere, a schedule was made and coreXY pulley stands were sent to print! First things first though, the z axis lift base thing was added , and some electronics stuff was started! It’s a little different from the wiring diagram, along with the fact we’re using a raspberry pi 4b, and a couple other stuff. Also, the docking bay got redesigned! 6/30/2026 Anyways, coreXY stuff printed and the layer is assembled! The gantry has a bit of wobble (and the bearings aren’t a tight fit), but nothing some hot glue can’t help with! (Well, maybe the wobble). Anyways, mainsail flashed on the raspberry pi 4 and figured out the weird issues! Also, reminder to switch the jumper thing for input form the side to the usb power.. so, the t rods hit the gantry too, along with the fact that the build plate doesn’t exist. Decently productive day, 5 days left. 7/1/2026 go go go New month, and leectronics work continues! Sacrificed the aliexpress USB power cable, split the wires, and attached it to the LM2596, looks good! Also learned how to crimp today, so that’s pretty cool. There’s also a picture of the thermistor of the heater bed in the mainsail graph somewhere down there! Unfortuantely, I don’t have free JST connectors on ahdn, so we’re gonna be doing sketchy stuff with a dupont connector in there (the pitches are a bit different, yes, i know it’s crazy sketchy, shhhhh) Anyways, after setting tool stuff to print, went downstairs and (thanks to my dad) got the t screws cut and a 15x15 build plate out of some aluminum (it’s like 1.3-1.6mm thick?). We did have to make it out of sheet aluminum that was laying around, but it came out alright, the holes are just a little misaligned but that’s a bit on me. Anyways, realized the tool stuff printed was super cursed, had to work on redesigning a lot of parts, specifically the sahft collar, the gearing (no more bearings should be needed, all the stuff should be using filament as deadaxles). Anyways, we have to fix this cad stuff (half way done), then hopefully belt the corexy and do electronics while it prints tomorrow (aka, today)? Well, that’s it for now, gotta go fast (sonic reference?), only four days left…
I’ve just been told 75% of my time spent on this log doesn’t count (apparently), so instead of dedicating probably an extra two hours of unlogged time to write a clean version, yall gonna get my thoughts DAILY, straight from the source, raw updatelog content. just kidding, there’s now a world limit so im just gonna speedrun this (since no one reads this and i read my own raw thoughts) 7/2/2026 Mostly electronics work, on 7/1/2026 night, realized that I can actually gently pry off the jst connector shells, removed a good amount of them. Wrote a devlog, worked on tuning the extruder filament tgrabbing gears. After dinner, printed some stuffs, then started adding the corexy belting path. Spent a long time, didn’t really feel very motivated at 3:42 AM and ended the day almost finishing assembling the belts and with not working extruders. 7/3/2026 Woke up early, last night wasn’t a fun night, increased the gear scale, finally actually put the corexy belt together. The filament gears now grab, though it does skip when too much filament is put in. After fixing the shaft collar and adding it back, reassembled the test tool and it attaches! The corexy does have quite a bit of friction, but the tool is assembled! However, waiting on terminal stuffs. Rest of the day is starting the electronics stuff. 7/4/2026 Motors not moving? Removed wires from housing and fix phases, motors now moving! Wondered why one motor was faster, then they both became slow. Fans wired, heaters wired, more testing, heaters can heat up! 7/5/2026 Bad sleep schedule strikes again, some soldering and added the limit switches, more stuff sent to print. A bit of config editing later and the corexy moves properly now! With the correct x and y axis! Filament doesnt really grab very well, idk.More intense filament testing, extruder can reach 230C! 7/6/2026 Really late start, more tool printing, more tool assembly, all tools and extruders are assembled now! 7/7/2026 Schedule and todo list made, support bracket set to print, top shaft supports made a printed, belts tensioned again. Some fixing later, two part inlet case CAD done and sent to print and attached, second tool head also wired up. There’s your week of updatelogs compressed into a format because theres a character limit. From now on, all devlogs will be the updatelogs and not be as extra refined, since I don’t get time counted for writing these, and it’s really a pain and insult to just say that more than a whole 24 hour day worth of actual work doesn’t count because someone added a time limit per log out of nowhere.
7/8/2026 - 75th Update! mfw when the stardance bot tells me that only 10 hours per devlog counts now that’s just rude well, welcome back! 5:01 PM today and starting things off in a bad mood. guess we gotta waste our precious time by cleaning stuff up anyways, 15 minutes later and some serious condensing (each day is like 5 sentences max), back to work! got some unfinished business to do while we work on today’s stuff! so a series of event have occured and now it’s 10:13 PM. oops. for a second i got scared something was wrong but turns out the connecting wire to the inlet thing was just a bit disconnected, trying to access the web interface right now… oh it’s because im on downstairs wifi. oh. gonna be following this for calibration! not exactly sure why there’s so many connection issues today. ok, while that’s connecting, gonna print the latch parts so my s key finally fell off. oh. that’s not good (yes im touching the little button under it) ok, w repair, cleaned it up, the key still does the weird tilt thing, but it stays in there, so that’s good so uh it fell out again. not good. ssssssssssssssssssssssssssssssssssssssssssssssssss oh i guess im gonna keep that, i just need to be more mindful of where i press it i guess, problem is currently that the mcu keeps disconnecting whenever i change the extruder temperature, which is kinda weird hmm mightve been an electrical thing? so i just spent an hour trying to come up a solution for the extruder, none of them are reliable or possible (rubber band placement just gets in the way). so yeah. whys it working now i guess the solution is grinding the gears down? whys the “rushed for display” extruder the only working one now, wow ok, latches made, no rubber bands since that just doesnt work (both the track and the thing), idk, later issue, right now i guess we’re gonna tune z stuff or gonna just try to make it as flat as possible? i think for now let’s just assume perfect flatness for time, let’s replace the heater section of 1 with the one of 3 and just basically use tool 3 instead for time (since the gearing apparently works???) (please stay that way) i guess making it as flat as possible is the best idea for now ok so it’s now 2:32 AM, the docking bay and the latches are added (ngl, they are bending because of a fillet), gonna ignore the fact that it’s slightly broken (nothing tape can’t fix), it does work, takes a bit of force though (as always) 7/7/2026: DONE - print, assemble, and add latches 7/8/2026 DONE - heating tuning DONE GOOD - z bed tuning GOOD - either assume perfect flatness or work on bed mesh/calibration g code should be able to run easily (simple commands of course) look into how to print stuff PRINTING WORKING BY EOD it’s 2:50 AM, tested it out, IT EXTRUDES! YAY! (like i let go of the filament after pushing it to the cooling area and then it extruded!!! by itself with its own gearing!!!) the clicking noises are a bit questionable but sure, ill take it! also did the z paper thingy! missed opportunity to call it cerberus, i might just add that somewhere… anyways, here’s the extruded stuff picture! woo! i mean, what a way to end the day! ok, it’s 2:56 AM, that’s about it for tonight, gonna copy paste this into the website for today’s log and yeah, good night!
7/9/2026 - 76th Update! yo and welcome back! it’s 8:57 PM at night, don’t have much time to waste now, today’s hopefully printing day? (with the actual printer of course) saw online last night from like a video from 6 years ago that using blue painters tape is a good idea (why does my s key consistently fall out now aaaaa), well look what i got here (figuratively), it’s a roll of scotch blue 2090 tape! ok, watched a couple of enlightening videos, so, i think we’re just gonna use some blue tape, seems pretty much good enough for our purpose, not sure if i really want to get orca slicer just now, i think i just want the printer to at least extrude something at this point in time? center is roughly (50.00, 77.50, ~) right now, ok, wrote a little something to center the stuff so (0, 0, 0) should hopefully be the center? yeah, close enough! ok, it’s probably a good time to apply the tape ok, tape applied, cleaned the nozzle, planning on doing the paper thing right after, then we need to print like something flat real quick (if it works, since we still need to do the config stuff for the extruder) quick 20 minute break to let it cool down later, it’s 11:07 PM, time for the paper stuff! so it doesnt really do a good job at staying level, but i do have a solution in mind, aka, having weights on both the sides to keep it flat. yeah. or a rubber band thing stretching the entire length. anyways, configs inputted! so at this point, the thing we need to focus on is getting the extruder config up and running! ok, set up the slicer with the stuff, gear ratio is start (14) to mid (28->14) to final (28->12), where it ends ok, gonna do a test “print”! it’s in quotes since it’s actually not gonna have any filament, just gonna make sure the motion works/makes sense ok, 12:31 AM, let’s run it! ok, temperature below min or something (as in the gcode stuff) 12:40 AM and still figuring stuff out, hold on a second… ok, it’s running! at least, the stuffs moving, not sure if it’s printing well? idk, gonna watch it go! it’s going! that looks… fairly realistic? idk why the heatbed’s at 60.7C right now ok, 12:54 AM, filament loaded on the top in a semi precarious matter, things are ready! 12:57 AM, here we go! timelapse running on my phone, let’s see it! heat bed termperature good, extruder temperature rising, oh turns out i have to have the tab active for it to update the graph visually, whoops well, reached the temperature, let’s see something? oh it just stopped itself because axis werent homed, ok, test 2! 1:03 AM, z axis is lifting, here we go! hmm so the extruder didnt really try… anything. like it wasnt running the whole time (unless it’s just a really small amount that the gearing cant handle?) ok the issue might just be i didnt push the filament in enough, since i just gave it multiple aggresive tugs and a whole bunch just came out of the nozzle, 1:14 AM, here we go again! (i do not want to know what the weird vapors or gasses it just released (yes i saw it, which isnt a very good thing)) also, wow, the heating controls are tuned really nicely! ok, 1:17 AM, z axis going up again so wasnt extruding anything, had to push on it to move, and that resulted in an obvious pile of sad sad so i feel like this is a bit of a gearing thing, since small amount arent really wanting to come out at least it got the rough shape correct? hmm i want to try it out without me pushing on the filament, expecting nothing to happen but who knows yeah i think its just really under extruding, probably because of slip inside? 1:43 AM, trying again, yep, nothing good, it’s now 2:00 AM, gonna go to sleep at this point yeah. idk. the one on the left is forced filament, the middle had a bit of push at the beginning, the last one was mostly by itself. yeah, idk what to do at this point. it’s 2:03 AM, idk what to do, and yeah, we’re kinda behind schedule. anyways, good night!
7/10/2026 - 77th Update! wow, 77 updates, so it’s now 10:00 PM, idk what happened to this afternoon (basically just vanished, went to some job in the morning, slept when i got home, ate lunch at 4 PM, slept again, ate dinner at 8 PM, then showered and now it’s somehow 10:00 PM) im thinking media is gonna have to be moved to tomorrow, my only goal today is to find diamonds get the printing to work reliably here’s a couple ideas i brainstormed last night increase the extruder heating temperature should make it way easier for the gearing to push as well double check gearing probably not this now that i think about it, but check docs double check rotation distance again, probably correct add extra pressure in the config similar to the first idea as in trying to actually push more filament slow things down even more very sad but self explanatory if we overextrude, that’s ok, we just need to find the tuning sweet spot where it is actually decent, but of course, the more important goal is to actually get some reasonable stream of filament flowing out (constantly extruding is not optimal but it’s whatever) ok, upped the printing temperature by 10C, also decreased a lot of speeds, 10:33 PM, hopefully ready to test? ok, prepping the stuff, gotta clean the nozzle too, ok 10:40 PM, ready to go! well that didnt print anything ok, so shoving filament down the throat extrudes, pushing filament from far above works well (it does slam left and right but still functions fine), the velocity isnt correct AT ALL (might just be from the compression/friction), hmm ive been suggested to look into the heatbreak and stuff, so gonna take a look at that, idk a bit of a break later, the gearing is sus, trying to move it with the top off and only the heatsink attached, seems off it’s been two hours and ive been playing with so so so many configurations (probably at least thirty?), moving spacers, adding rubber bands, readjusting, measuring, and i think ive come to a point where it’s “ok”. it goes out ok (3 rotations of the motor connection results in: ~1.8cm pushing fast, ~1.7cm pushing slow, idk for expected), but it’s basically incapable of going back up for some reason. it also produces a good amount of force out, but, as mentioned before, barely any up (skips a bunch) ok, played around a bit more, idk, retraction worked for a second randomly, idk, installed it back on, ready to test again 3:36 AM, did a couple of cursed things in the config, specifically making it extrude 4x as much, along with making the deretraction speed higher in the slicer, that said, here we go! ey it printed something! its still really fuzzy so i guess we still got more work to do (that was v1.4), ok v1.5 uploaded, let’s see! 4:12 AM, here we go oh yeah also added fancy ending gcode lol hmm, it’s more complete, but stll missing stuff, ok, 4:27 AM, the birds are probably coming out soon, v1.6 going! well that didnt end well huh seems like the issue was just that the filament wasnt fully loaded, whoops ok, v1.7 uploaded with some print skirts on the outside to help with the missing start extruding, flow rate also increased, let’s see, it’s 4:54 AM, so last print of the day! uh oh it seems to be underextruding now, ok, 5:09 AM, here’s v1.8 ow was in the middle of cleaning the print bed and a piece of the skirt just went straight under my fingernail ouch well, with the sun rising, here’s the end of today! imo v1.5/v1.6 is my favorite, but it’s getting there in terms of smaller details, so i think tomorrow one or two more test prints and then a benchy would be a smart move? idk, the benchy’s just for the reveal video (yes i will try to fit in media here!) well, 5:33 AM, that’s it for me tonight (tomorrow morning?), and yeah, good night!
7/11/2026 - 78th Update! in theory, the last one? in reality, probably not. anyways, it’s 3:22 PM, today’s reveal/edit day! of course, i got a bit of table clean up to do and recording, but i also wanted to play around with the settings a little more to get a somewhat better print? (and maybe test another print since this ones a little small) anyways, parent meeting at 5 PM today, gonna be attending on the side while probably editing? im planning on doing two more test prints before then test 1: turned layer speeds from 90mm/s to 70mm/s increase flow ratio from 1.15 to 1.21 decrease skirt loops from 7 to 5 ok, 3:43 PM, sliced and uploaded, heaters all heated, ready to go! gonna use the bathroom, seems to be printing well though! back at 3:55 PM, it printed well and ended well! gonna modify the ending gcode to cool down, analyzing results now! kinda wanna replace the middle tape strip since i kinda messed up and removed a ripped a bit of it while scrapping the skirts off (whoops), gonna go for one more print, im pretty satisfied, this ones gonna be a bigger test print (not a benchy yet though), im thinking calibration cube? test 2: increase flow rate from 1.21 to 1.30 decreae rotation distance from 6.4 to 6.0 increase deretraction speed from 6mm/s to 6.5mm/s decrease jerk for x (5mm/s to 4.5mm/s) y (5mm/s to 4.5mm/s) z (0.2mm/s to 0.175mm/s) x (0.3mm/s to 0.25mm/s) gonna use this makerworld one for this! intrested to see how this one goes! it’s more of a z axis and consistency ending test should have just enough filament? expecting like 2-3cm left on the top after this? might not have enough on the top but that should be fine? hopefully? i mean, if i see the filaments about to run out id rather end the test? idk footage time yeah its kinda… erm. it kinda failed to print beyond the base layer, seems to just struggle with grabbing filament on its side, let me get a straw real quick, nvm, just used a piece of filament taped down for it, i think its just a filament grabbing issue (probably fighting against the curl?), so yeah, this should straighten that out a bit? test 3 (aka, 2 again), decided not to change anything, here we go! gonna focus on footage for this one so that might have been the… worst prints ive seen, but sure ok, just added the filament from the spool, should be ready for a bigger test? test 4: changed max volumetric speed from 5mm^3/s to 3mm^3/s turned flow ratio from 1.3 down to 1.22 rotation distance reverted from 6.0 back to 6.4 oh yeah heres the image of the cube yeah, gonna go for a 50% benchy erm 50 minute print uhh, well, 5:50 PM, now or never, i guess imma setup for a reveal scene ok, created a nice set for filming, gonna be doing mostly footage stuff while this prints, not really any timelapse? i guess i could? ok, hopefully printing and footage done by 7PM, then probably editing or dinner sometime around there (yes, todays the end day i think, at least my goal) ok, quite some time later, gonna speedrun dinner, its 7:31 PM though i was away for a bit before then welcome back, 9:11 PM, did a bit of footage getting earlier, here goes a print so. half way through. turns out our cold end/heatsink or whatever kinda doesnt cool it well enough. essentially, yeah. it just started curling up halfway in. yeah. however, it did successfuly print half of it! test 5: turned layer speeds from 70mm/s to 80mm/s changed max volumetric speed from 4mm^3/s to 3mm^3/s (seems like i forgot to do it whoops) most devious gcode modifications and slicer shenanigans later devious part 2 well, it’s 6:02 AM now, after lots of editing, submitted the forms, time to head off to bed! and yeah, good night!
7/23/2026 - 80th Update! well. so im back from open sauce! actually, flight entered back to NYC on the morning of 7/21/2026, but the last two days have really just trying to get back in motion lol (turns out having crazy fun and instantly returning to “normal life” is somewhat rough) anyways, it’s 9:18 PM, here’s a recap! i dont think timelapsing all the work there would be reasonable (i estimate probably around 8 hours of work?), but yeah, mostly just config tuning and working on irl stuff, the base plate sort of didnt like the flight (but it’s really alright? basically the screws kinda ripped through the tape a bit) after the return flight, one of the LM2596’s input wires fell out, took a bit to get it in (haha get it screwdriver bit), anyways, still got a lot to do, i think for now im gonna just finish the update log on the stardance site, then update all the graphics over here, and yeah, prepare for something new??? (i have some ideas…) anyways, i think im gonna prep the stardance project to ship, idk if i can? ok, 11:00 PM, updated the front image, gonna work on updating some stuff ok, 11:06 PM (almost typed AM, that would be funny), added the open sauce image to the readme, brb! back at 12:42 AM, yeah, i think it’s a good time to ship? mfw fixing the position so the aspect ratio for the banner and the project banner (the different pages) are so so hard to get correct anyways, yeah, gonna copy this stuff over and we should be good to go? well, 1:22 AM, for now, good night!
7/28/2026 - 81st Update! Note: I wrote this back on 7/28/2026 but never published it here! (What? The return of Spark?) Well, not exactly, this is more of a thing for the latest announcement in #stardance-bulletin ! Here’s the edited video from a while back! It’s kinda for vertical/short form content, also, BIG EPILEPSY WARNING!!! While you’re here, you should definitely check out fermion , the “spark v2” in a way! It has a very different architecture (that’s surprisingly hard to cad), so check that out! Anyways, here’s the log without further ado… There’s really not that much to say. On July 26th, Spark was repackaged into a box and put into storage, almost a week after returning to New York City. It’s still in an operational state, with few wires disconnected, only with the WiFi credentials incorrect. For a logged 9 months and 2 weeks, a total of 287 days, with 80 progress updates in that time, Spark’s been on my mind for a long while, no doubt about that. Across the more than 64k words, 240+ hours, from the definitely overscoped original concept to the rush to finish it before Blueprint ended, Spark has existed between two whole YSWS programs, one used for design and one used for build. I have to say, with more than three quarters of a year, a lot has changed, both outside, in my actual life, and with Spark, as the idea changed through every log, slowly and carefully. There were highs and lows, and really, really, low lows, from feeling lost at the end of day 9 of build, to the excitment of the first motor turning during day 11. But now, it’s all neatly packed in the garage, waiting to be used another day. Spark isn’t gone, it still physically exists. It may not be resting on a giant wooden board I use for soldering next to my bed, but it still exists next to me through all the hard CAD and build days. It’s strange, this sudden change. For the last week, I haven’t really done much besides plan. And that’s probably a good thing, given all the planning Spark took. I haven’t really done much build, I haven’t really felt anything. Post convention depressions, I have to say, is hitting pretty hard. After such insane fun and wonder for a week, it’s suddenly back to a cool, rainy day, here in New York City. Sleeping through the afternoon, after sleeping not enough hours in the morning. As the rain starts pouring from the sky again, I’ve been wondering what the meaning of joy is. Alas, it might just be time. Adapting to such changes is obviously difficult, and the road of projects is too. But that doesn’t mean roadstops aren’t along the way. As I wrap up this update log, I want to leave a quick quote, one of my favorites. It probably sounds like a dumb platitude to say “it’s not the destination, it’s the journey”, but truth is, we’re made up of journeys. You’re never going to be who you’re supposed to be unless you take that road. … There is room in there for surprise, for deviations, for re-evaluations. I wouldn’t dare deprive you of that adventure. You only get one , after all. I know, you’re tired; resting is part of the journey too. But not giving up… Winter, in Housepets! (Rick Griffin, Dec 25, 2020) That said, what’s next? Well, first we’re gonna take a stepping stone. What’s next is still in concept form, but the unique constraints might require a custom PCB, which is where river comes in. First, it’s gonna be a quick project, just a custom PCB music player, just to jog the electrical skills. But after a quick skip over a stream, what’s truly next? What’s the successor to Spark? What’s next to rival its top 1 status? Fermion. See ya around.
Ships:
Well, after 120+ hours of building across some 18 days, and another hundred hours of CAD previously, it’s a good time to present Spark, this time irl! Anyways, after last summer, I fell into a sort of hole of demotivation where I didn’t really see what I was “working towards” in terms of school and just waiting six months for the FRC build season to start. In order to try to get my creativity and to prove to myself I wasn’t washed, I decided to throw myself into the deep end and to create a 3D printer. That said, 9 months later and way too many demotivation breaks, I locked in after exams and fully assembled and programmed and tested the build in 18 days! It features a coreXY gantry system, along with a passive tool changing setup with latches and the friction of the top docking piece. This kept the overall motor count to be 5 (2 for xy, 2 for z, 1 for tool). The tool changing setup and printing is nowhere near perfect (after all, this thing’s mostly made of PLA and was programmed in a week), but it’s definitely able to be tuned and better perfected with more programming time! In the end, Spark did achieve its goal of sparking some figurative sparks for me to continue building! After this, it was shipped off and exhibited at Open Sauce in California as part of Outpost where I’ve met amazing people and learned more about 3D printers and how to design them better!
hey! re-ship with an edited video! (and the bonus updatelog!)(NOTE: EPILEPSY WARNING! (it is an edit after all)) ( https://www.youtube.com/watch?v=ktODngPF7UI ) (i have fond memories of this, it was the saturday before the week of outpost and i stayed up to 6 AM edited, after a full day of getting footage and stuff (and dealing with goofy kdenlive crashes)) i also somehow did 10hrs+ that day so that was pretty insane! anyways, thanks for reviewing :D...
|
1793001023.87465
|
1793087423.87465
|
|
11306
|
Caelestia by @Soramane | Stardance
|
Soramane
|
0
|
123.89
|
0
|
[]
|
[{"post_id": 36428, "ts": "202 [{"post_id": 36428, "ts": "2026-07-28T15:29:17Z", "hours": 15.1136, "text": "Plugins are live! Or well, a tiny bit live at least. I got bar entries and popouts wired up, and hot reloading! And speaking of hot reloading… Hot reloading is the worst in Qt QML. Since there is only ever a single QML engine, and that engine isn’t even controlled by us, we have to resort to some very interesting ways to reload only the plugins themselves. Basically, to hot reload, we could just nuke and recreate the QML engine, but that would reload the entire shell, which is quite heavy and loses transient state. So instead, we need to reload plugins separately. To do this, we create QML modules for each plugin and force plugin authors to explicitly import them instead of relying on implicit imports. This way, we control the modules and can create new ones with higher versions to “reload” them. One “small” issue with this is that the previously generated modules will be leaked as Qt does not provide an API to unregister modules, but that’s a trade off we have to deal with. There is also so much more to deal with for plugins than I initially thought. We need to keep track of having a plugin repository, each plugin’s structure, having multiple plugins being in a single repository, hot reloading plugins, plugin dependencies (this is gonna be a major pain), installing plugins from both the plugin repository and arbitrary Git URLs, and so much more. Let’s just hope my brain doesn’t get (more) shredded by this plugin system of mine…"}, {"post_id": 32529, "ts": "2026-07-21T19:22:16Z", "hours": 12.2458, "text": "Finally, plugins! I’ve been working on adding plugins to the shell for the past week or so, and things are finally taking shape! I got the preliminary structure for plugins and their manifests down, so I could start working on the UI for it. It’s only a placeholder for now, the backend is still in the works, but the browse page is looking pretty good. I also hooked up the bar-entry entry point type and it works well, which is nice. All that’s left to do now is all the other entry types, actually making an example plugin, docs, the plugin info page, actually loading plugin info from the store repo, installing plugins from the store and other external sources, and plugin settings. Oh boy, that’s a lot of things… 😂"}, {"post_id": 30570, "ts": "2026-07-18T08:11:37Z", "hours": 29.3406, "text": "On the way to fill out more pages in my settings app… Finally added ethernet and VPN support to the Nexus for Caelestia! Networking is such a pain… There are so many cases you need to account for, and since everything is async, nothing is straightforward. Qt QML not having great process support definitely doesn’t help either. Anyways, I’m pretty happy with the result! It supports 4 built-in VPN providers (wireguard, warp, netbird and tailscale), and any custom provider you may use. I also added howdy support to the lock screen for facial recognition between this and the last devlog, but that’s less significant imo… I should really make devlogs more often. Aside from that, I’m currently working on plugin support, so hopefully that’ll be the next devlog!"}, {"post_id": 18184, "ts": "2026-06-29T07:29:07Z", "hours": 28.9383, "text": "I haven’t made a devlog for quite a while huh… Anyways, after many hours working on Figma, I finally have a decent base design for my website! It’s still a WIP, but I’m pretty proud of this. Now, to actually implement it…"}, {"post_id": 10485, "ts": "2026-06-17T07:12:31Z", "hours": 28.4778, "text": "Finally decided to revamp the installation process! Previously installation would be done via a shell script which symlinked everything into place. With this new change, files are copied into place and paths are stored in a state file for updating. Also, now users don’t have to manage the dots repo themselves, they can just install the CLI from the AUR and run caelestia install to install it."}, {"post_id": 4745, "ts": "2026-06-08T06:10:09Z", "hours": 9.7714, "text": "Bugfixing… So many bugs, straight after the V2 release 😅. The V2 release was made in kind of a hurry to meet the 1 year anniversary, so it really wasn’t tested all that much."}]...
|
Title: Caelestia by @Soramane | Stardance
Devlogs Title: Caelestia by @Soramane | Stardance
Devlogs:
Bugfixing… So many bugs, straight after the V2 release 😅. The V2 release was made in kind of a hurry to meet the 1 year anniversary, so it really wasn’t tested all that much.
Finally decided to revamp the installation process! Previously installation would be done via a shell script which symlinked everything into place. With this new change, files are copied into place and paths are stored in a state file for updating. Also, now users don’t have to manage the dots repo themselves, they can just install the CLI from the AUR and run caelestia install to install it.
I haven’t made a devlog for quite a while huh… Anyways, after many hours working on Figma, I finally have a decent base design for my website! It’s still a WIP, but I’m pretty proud of this. Now, to actually implement it…
On the way to fill out more pages in my settings app… Finally added ethernet and VPN support to the Nexus for Caelestia! Networking is such a pain… There are so many cases you need to account for, and since everything is async, nothing is straightforward. Qt QML not having great process support definitely doesn’t help either. Anyways, I’m pretty happy with the result! It supports 4 built-in VPN providers (wireguard, warp, netbird and tailscale), and any custom provider you may use. I also added howdy support to the lock screen for facial recognition between this and the last devlog, but that’s less significant imo… I should really make devlogs more often. Aside from that, I’m currently working on plugin support, so hopefully that’ll be the next devlog!
Finally, plugins! I’ve been working on adding plugins to the shell for the past week or so, and things are finally taking shape! I got the preliminary structure for plugins and their manifests down, so I could start working on the UI for it. It’s only a placeholder for now, the backend is still in the works, but the browse page is looking pretty good. I also hooked up the bar-entry entry point type and it works well, which is nice. All that’s left to do now is all the other entry types, actually making an example plugin, docs, the plugin info page, actually loading plugin info from the store repo, installing plugins from the store and other external sources, and plugin settings. Oh boy, that’s a lot of things… 😂
Plugins are live! Or well, a tiny bit live at least. I got bar entries and popouts wired up, and hot reloading! And speaking of hot reloading… Hot reloading is the worst in Qt QML. Since there is only ever a single QML engine, and that engine isn’t even controlled by us, we have to resort to some very interesting ways to reload only the plugins themselves. Basically, to hot reload, we could just nuke and recreate the QML engine, but that would reload the entire shell, which is quite heavy and loses transient state. So instead, we need to reload plugins separately. To do this, we create QML modules for each plugin and force plugin authors to explicitly import them instead of relying on implicit imports. This way, we control the modules and can create new ones with higher versions to “reload” them. One “small” issue with this is that the previously generated modules will be leaked as Qt does not provide an API to unregister modules, but that’s a trade off we have to deal with. There is also so much more to deal with for plugins than I initially thought. We need to keep track of having a plugin repository, each plugin’s structure, having multiple plugins being in a single repository, hot reloading plugins, plugin dependencies (this is gonna be a major pain), installing plugins from both the plugin repository and arbitrary Git URLs, and so much more. Let’s just hope my brain doesn’t get (more) shredded by this plugin system of mine…...
|
1792525779.2735162
|
1793130579.2735162
|
|
27198
|
APT-Gcode by @karlo_ugrin | Stardance
|
karlo_ugrin
|
1
|
123.61
|
25
|
[{"ship_num": 1, "ts": "2026-0 [{"ship_num": 1, "ts": "2026-07-16T08:32:16Z", "hours": 4.0, "multiplier": 5.86, "payout": 25, "blessing": "neutral", "text": "CAM post processor, so far its only suitable for CatiaV5 intoISO 6983, it’s still in development, there are a few non finished commands, but since there is no actual documentation for CATIA APT1.0 it works really good. erm yeah. at some point im going to make work on the web the rest is pretty much written on Git.", "repo": "https://github.com/karlo-c277/ATP-Gcode", "demo": "http://karlougrin.com/apt_gcode-web/index-apt.html"}]...
|
[{"post_id": 78445, "ts": "202 [{"post_id": 78445, "ts": "2026-10-10T20:15:53Z", "hours": 9.4358, "text": "DEVLOG 24 NEW STUFF the parseline v3 is going relatively fast tomorrow it is probablly going to be finished currently the only left syntacs from v2 is to complete cycles, rawG, PSIS, INDIRV, MAXSPNDL, $$, CUTCOM, change tool rework on the SPINDLE syntacs is needed bc i compicated some stuff there and to make a value check by giving a +variable, then if it wasn’t a number it is going to be a NaN which is a false meaning i can make if (+variable) LEFTOVER STUFF (Not in the parseline v3) to do a guide on how to make your own output general overview on the program"}, {"post_id": 77376, "ts": "2026-10-06T18:19:18Z", "hours": 6.9919, "text": "DEVLOG 23 NEW STUFF so the parselinev2 build is working (not on the web but in the git) the parselinev3 build is on the way, why? Because I realized how much the v2 build is leaking the performance and optimisation, so it would be simpler to re-do and make it with more brain this time HOW WILL IT WORK simple, for each command in Catia, there will be a case (switch case stuff) then each switch case will call a function that will do all the work for that case that function will call other function do math etc. the user will simply select a document from which the function will get called therefore giving a different syntacs and thats pretty much it"}, {"post_id": 76514, "ts": "2026-10-03T19:46:21Z", "hours": 10.2128, "text": "DEVLOG 22 New stuff re edited the KK guide so it is written in .md and I SWEAR it looks so much better and it is easier to read rawG new command this one is to be written in the APT or added as an additional command and it bypasses both layers of translation rawKK new command this one is to be written in the APT and it bypasses the first layer of translation (line written in KK) Bug fixes I saw a few bugs in the rapto section of the goto and godlta pretty much all, still haven’t had time to test this changes but it seems to be working ok Leftover stuff make a guide on how to use Catia and CATIA.pptable make an explanation of this program how it works and other and i have written about 3 pages of stuff in catia that i have no idea what that meas and what does it do so research those improve with like code block suggestions for manual code writing BUGS for some reason now the costum panel wint show"}, {"post_id": 69275, "ts": "2026-09-16T18:30:53Z", "hours": 10.2019, "text": "DEVLOG 21 New stuff Catia PPTable so it turns out I can modify the APT output for some commands, which had not only helped in the post processor more accurate but now I understand more stuff so I made the PPtable and it seems to work more on that some other time Logic since I now know what is to be expected for some commands I was able to shave off roughly 200 lines of code which is great COMPENSATION defines what tool correction register is being redefined, what quadrant is the cutting end, xyz corrections, and nose radius END OF PROGRAM is now single meaning CIRCLE output looks like this kk(\"ARCH/CENTER, \"+centar_x+\", \"+centar_y+\", \"+centar_z); kk(\"ARCH/AXIS\"); kk(\"ARCH/TANGENT, \"+this.ls_i+\", \"+this.ls_j+\", \"+this.ls_k); kk(\"ARCH/INFO, \"+radius+\", \"+movement+\", \"+angle); kk(\"ARCH/END, \"+kraj_x+\", \"+kraj_y+\", \"+kraj_z); CYLINDR or sinusoidal movement like this kk(\"SINUS/CENTER, \"+centar_x+\", \"+centar_y+\", \"+centar_z); kk(\"SINUS/AXIS\"); kk(\"SINUS/INFO, \"+amplitude); kk(\"SINUS/TANGENT, \"+this.ls_i+\", \"+this.ls_j+\", \"+this.ls_k); kk(\"SINUS/END,\"+kraj_x+\", \"+kraj_y+\", \"+kraj_z); helix (in APT) HELICAL/CENTER, %MFG_HELICAL_X_CENTER, %MFG_HELICAL_Y_CENTER, %MFG_HELICAL_Z_CENTER HELICAL/TANGENT, %MFG_HELICAL_INDIRV_I, %MFG_HELICAL_INDIRV_J, %MFG_HELICAL_INDIRV_K HELICAL/AXIS, %MFG_HELICAL_I_AXIS, %MFG_HELICAL_J_AXIS, %MFG_HELICAL_K_AXIS HELICAL/INFO, %MFG_HELICAL_PITCH, %MFG_HELICAL_RADIUS, %MFG_HELICAL_HEIGHT, %MFG_HELICAL_ROUND HELICAL/END, %MFG_HELICAL_X_END, %MFG_HELICAL_Y_END, %MFG_HELICAL_Z_END SPINDL is now simply defined FEDRAT is now simply defined COOLANT on the other hand, apparently the coolant is set while defining the tool, which i have accounted on and then just coolant on off, but it seems a bit like it doesn’t make sense that way what if different coolant is wanted??, also the actual syntacs is quite unknown for the coolant sooo yeah DELAY is now simply defined CYCLE now got major upgrades by manipulating the APT lost like a 75 lines of code there spindle rotation limit is now settable CUTCOM pensation is now uncovered but I genuenly have no idea what the stuff means NORMDS or NORMPS, maybe normal to drive / prat surface God knows the answer that I am sure BUGS Yes - I haven’t had a chance to test it yet so I dunno I got the background loading path wrong so that is corrected STUFF LEFT TO DO Make a function for the line split into 3, 4, 5, 6 Rework G-coder to output accordingly to the reworked parser Play with the PPTable The rest of the TO-DO list SUM-UP Found out that I can modify the APT output via PPTable, made a PPTable, now I know much more about The APT, made the parser more precise and thus more correct"}, {"post_id": 62918, "ts": "2026-09-06T13:40:40Z", "hours": 3.5292, "text": "V1.0 is now DEVLOG 20 New stuff Logic now both APT reader and G-code output are in switch case this makes processing much faster, and takes less memory line splitting is now done before actually going into the switch case for both reader and writer, mainly because then element zero in this case is basically line.startsWith, and then later in code I shaved of like 14 line splits invalid cycles are now rejected and aren’t even translated into KK Bug fixes since I switched from line.startsWith I need only the word in the variable, and there is like a $$*CATIA0 in every file and I hadn’t put line split with * so it registered as and error I have had left the incomplete cycles to be completely written causing an undefined variable to be written in KK and forwarded into G-code What if’s? What if I was supposed to like make CYLINDR output 300 points in G-code I honestly don’t wanna do that?"}, {"post_id": 60226, "ts": "2026-09-02T13:46:14Z", "hours": 2.4911, "text": "DEVLOG 19 New stuff Logic helical interpolation in g-coder g-coder now remembers the last coordinate, because CATIA gives, the center, radius, direction, 2D vector for direction of movement, end point and pitch, but WinNC that reads the g-code takes end point center and number of full turns and cw or ccw, so number of turns is calculated speciffically inside the class Bug fixes yes What if’s??? No"}, {"post_id": 58937, "ts": "2026-08-31T14:35:08Z", "hours": 4.0992, "text": "DEVLOG 18 New stuff Input now the default value for APT input is CatiaV5 but only for development and it is not written that it is it just is default value for for G-code output is WinNC Sinumerik Logic added logic for CYLINDR which is essentially just a sinusoidal path, not just one period pr it but can be multiple or just a part of one logic for PSIS which is supposed to be like a sign that the CYLINDR is to be defined and that it starts at this coordinates and then some random vector that defines that the movement will be projected in a PLANE that does not contain that vector logic for ROTABL is incomplete but here I would need to look into it but it seems like it is used in MULTI axial machines, but only when it does 3 axis work idk it is a bit emptly defined TLON,GOFWD is now the new definition for circular movement, so it takes the line in the correct logic for both CIRCLE and CYLINDR I undiscovered what CUTTER with 7 tool data defines but for now it just outputs it as 7 comments Bug fixes for SWITCH or setting tool compensation had .trim instead of .trim() same thing happened on the g coder side for some reason maybe a bad commit, the text enter pop-up window didn’t pop-up, resolved What if’s??? What if the sinusoidal movement isn’t horizontal yet at an angle what would happen then? The angle isn’t specified, but I do have the circle center and the first point that is on that circle Note that the path is on the surface of the cylinder this is a sinusoide What if the sinusoide isn’t set in 2D? since 3D circular intepolation is off it should be just a set of close points What if there was no AI that could by pass the main page and end up to a sub-page that isn’t locked to me, unlike the main page? -Would I be ******?"}, {"post_id": 56696, "ts": "2026-08-28T15:40:08Z", "hours": 8.2294, "text": "NEW VERSION INCOMING once I get to it v0.9 is going to be official and running on my website DEVLOG 17 New stuff Visual re-organised quick settings fine tuned the spacing’s inside and between blocks Input now you can manually write code to test how output would look like mostly for me for developing so I can have some APT code loaded in keyboard cache for Ctrl + v comes with a pop-up text box for a nicer visual Solved bugs Rapid logic is renewed by hand I literally have a page in a notebook filled with possible logic combinations and solutions for it (in APT, RAPID is only for the next line, in G code however it is on until set to work in cutting motion ) some other issues where it would save CYCLE the wrong way, it would have saved 2 number with out spacing I have forgotten that x y z in cycle aren’t always saved as just numbers but rather 2 of em had X Y or Z before written so it would have double letters"}, {"post_id": 55447, "ts": "2026-08-27T09:09:44Z", "hours": 10.4814, "text": "DEVLOG 16 New stuff For Catia TLAXIS now defines which way does the tool need to go to complete the cutting motion MULTAX defines this is a multi axial process SWITCH defines a change in tool compensation *see under DOCUMENTATIONS - Images - Image.png Complete cycle support some cycles are excluded from support due to a possible bug causing to have incomplete information about the cycle GOTO/GODLTA between CYCLE start and the CYCLE/OFF log the coords in a variable CYCLE/ON activates the function to start collecting coords CYCLE/OFF puts out all of collected data for that cycle WinNC Sinum counting that you can set it in ISO-Mode Complete canned cycles for the cycles that are matching with Catias idea how the cycle should look like MULTAX support TLAXIS support Added a fall-back for CYCLES that are not matching, except this one can use any format of the given CYCLE Errors I did AI’s job, which is making sloppy code, and instead of sectioning Catias TLAXIS I replaced the commas, and replaced / with : causing mayhem, i got empty strings a string that contains double data I tought I could use Autodesk,s logic for parsing, They might be onto something but I have no idea what is going on there soo I made ChatGPT quit (I just wanted him to help me with finding out why was I getting bugged lines fed to my g-coder (it was magically fixed I still have no idea what had been happening))"}, {"post_id": 54420, "ts": "2026-08-25T12:57:05Z", "hours": 8.5297, "text": "DEVLOG 15 New stuff Nothing much just did some documentation on Catias apt output Added a few guides on how to set up the APT correctly very likely prone to changes SWITCH As it turns out SWITCH means a change on tools compensation look at image.png in DOCUMENTATIONS Completed output for the g-code on that switch but I think that it might cause problems bc in WinNC sinumerik it look like it doesn’t do that sooo yeah Fun fact, *picture, this is what you get when you set a random curve as a tool path Found out that https://archive.org/details/numericalcontrpol0000stan is tottaly right about every single bit of stuff that I tought wasn’t in Catia so yeah"}, {"post_id": 53297, "ts": "2026-08-23T19:14:03Z", "hours": 5.1833, "text": "I added a background So i have been tinkering with ChatGPT on what to do to up the looks on my project, and I had some ideas for the background but my CSS and JS skill are beyond wanted so he helped to find https://neat.firecms.co/ And it is a MUST have for any project, it just looks SOOO good. But with every edit there are bugs, so erm yeah. CYCLE SYNTACS It is going to be a long one since CATIA V5R21 likes to vary and I feel like an archeologist uncovering this secrets"}, {"post_id": 52268, "ts": "2026-08-22T11:31:00Z", "hours": 3.0536, "text": "Finished editing and preparations for a Ship and launched it on http://karlougrin.com/apt_gcode-web/index-apt.html"}, {"post_id": 39944, "ts": "2026-08-03T08:43:39Z", "hours": 1.72, "text": "Completed some needed bugs and excess output I should prolly add some fire background (any suggestions??)"}, {"post_id": 39569, "ts": "2026-08-02T17:01:22Z", "hours": 4.1064, "text": "Another 4 hours down the drain Pretty much just destroying my brains out why it didn’t want to make an output file, then why it didn’t write anything down<"}, {"post_id": 35418, "ts": "2026-07-26T20:11:41Z", "hours": 5.1631, "text": "DEBUGGING FOR 5 HOURS <(Writing code for +/-9min)>"}, {"post_id": 34642, "ts": "2026-07-25T15:16:16Z", "hours": 7.6756, "text": "I REVERSE ENGINEERED CAM APT CODE So basically what I needed to do was to like just make up my own kind of universal data tranfer standard via JSON so I can translate from different APT into different G-code, and so I made up KK (Karlov Kod). To make it a first ship just need to write another 400 lines but Hey!, this part at least has some documentation. (Unlike CATIA APT1.0)"}, {"post_id": 33534, "ts": "2026-07-23T15:55:30Z", "hours": 2.9978, "text": "Edited the CSS it looks so fire, just need to finish my website firstly. Then there goes the first ship!!"}, {"post_id": 32277, "ts": "2026-07-21T10:46:20Z", "hours": 8.9172, "text": "OH! MY! WORD! (it finnaly works after trouble shooting for 4 hours)"}, {"post_id": 31236, "ts": "2026-07-19T14:15:13Z", "hours": 6.5864, "text": "Made it to display ts, just left to translate like 600 pyhton lines into JavaScript. YAAY cant wait for allat.(lowkey hidden menus wont show up but its ok)"}, {"post_id": 28825, "ts": "2026-07-15T10:14:33Z", "hours": 1.1894, "text": "I did it, rapto comand now works!!>’*’<"}, {"post_id": 28521, "ts": "2026-07-14T20:41:00Z", "hours": 0.8669, "text": "adding code so i might get rapto to work"}, {"post_id": 28410, "ts": "2026-07-14T17:26:50Z", "hours": 1.1178, "text": "The last one before first shipping."}, {"post_id": 28349, "ts": "2026-07-14T15:39:43Z", "hours": 0.7244, "text": "I may or may not have renamed the git repo so i kinda lost some minor time but- a lot left to do"}, {"post_id": 28295, "ts": "2026-07-14T13:41:40Z", "hours": 0.3261, "text": "Yess, finnaly got the wakatime running, exept i have spent like 40hours of my life on this beafore i installed waka. And it says that i used more ai than actual code, not true (bc of those 40h)."}]...
|
Title: APT-Gcode by @karlo_ugrin | Stardance
Devl Title: APT-Gcode by @karlo_ugrin | Stardance
Devlogs:
Yess, finnaly got the wakatime running, exept i have spent like 40hours of my life on this beafore i installed waka. And it says that i used more ai than actual code, not true (bc of those 40h).
I may or may not have renamed the git repo so i kinda lost some minor time but- a lot left to do
The last one before first shipping.
adding code so i might get rapto to work
I did it, rapto comand now works!!>’*’<
Made it to display ts, just left to translate like 600 pyhton lines into JavaScript. YAAY cant wait for allat.(lowkey hidden menus wont show up but its ok)
OH! MY! WORD! (it finnaly works after trouble shooting for 4 hours)
Edited the CSS it looks so fire, just need to finish my website firstly. Then there goes the first ship!!
I REVERSE ENGINEERED CAM APT CODE So basically what I needed to do was to like just make up my own kind of universal data tranfer standard via JSON so I can translate from different APT into different G-code, and so I made up KK (Karlov Kod). To make it a first ship just need to write another 400 lines but Hey!, this part at least has some documentation. (Unlike CATIA APT1.0)
DEBUGGING FOR 5 HOURS <(Writing code for +/-9min)>
Another 4 hours down the drain Pretty much just destroying my brains out why it didn’t want to make an output file, then why it didn’t write anything down<
Completed some needed bugs and excess output I should prolly add some fire background (any suggestions??)
Finished editing and preparations for a Ship and launched it on http://karlougrin.com/apt_gcode-web/index-apt.html
I added a background So i have been tinkering with ChatGPT on what to do to up the looks on my project, and I had some ideas for the background but my CSS and JS skill are beyond wanted so he helped to find https://neat.firecms.co/ And it is a MUST have for any project, it just looks SOOO good. But with every edit there are bugs, so erm yeah. CYCLE SYNTACS It is going to be a long one since CATIA V5R21 likes to vary and I feel like an archeologist uncovering this secrets
DEVLOG 15 New stuff Nothing much just did some documentation on Catias apt output Added a few guides on how to set up the APT correctly very likely prone to changes SWITCH As it turns out SWITCH means a change on tools compensation look at image.png in DOCUMENTATIONS Completed output for the g-code on that switch but I think that it might cause problems bc in WinNC sinumerik it look like it doesn’t do that sooo yeah Fun fact, *picture, this is what you get when you set a random curve as a tool path Found out that https://archive.org/details/numericalcontrpol0000stan is tottaly right about every single bit of stuff that I tought wasn’t in Catia so yeah
DEVLOG 16 New stuff For Catia TLAXIS now defines which way does the tool need to go to complete the cutting motion MULTAX defines this is a multi axial process SWITCH defines a change in tool compensation *see under DOCUMENTATIONS - Images - Image.png Complete cycle support some cycles are excluded from support due to a possible bug causing to have incomplete information about the cycle GOTO/GODLTA between CYCLE start and the CYCLE/OFF log the coords in a variable CYCLE/ON activates the function to start collecting coords CYCLE/OFF puts out all of collected data for that cycle WinNC Sinum counting that you can set it in ISO-Mode Complete canned cycles for the cycles that are matching with Catias idea how the cycle should look like MULTAX support TLAXIS support Added a fall-back for CYCLES that are not matching, except this one can use any format of the given CYCLE Errors I did AI’s job, which is making sloppy code, and instead of sectioning Catias TLAXIS I replaced the commas, and replaced / with : causing mayhem, i got empty strings a string that contains double data I tought I could use Autodesk,s logic for parsing, They might be onto something but I have no idea what is going on there soo I made ChatGPT quit (I just wanted him to help me with finding out why was I getting bugged lines fed to my g-coder (it was magically fixed I still have no idea what had been happening))
NEW VERSION INCOMING once I get to it v0.9 is going to be official and running on my website DEVLOG 17 New stuff Visual re-organised quick settings fine tuned the spacing’s inside and between blocks Input now you can manually write code to test how output would look like mostly for me for developing so I can have some APT code loaded in keyboard cache for Ctrl + v comes with a pop-up text box for a nicer visual Solved bugs Rapid logic is renewed by hand I literally have a page in a notebook filled with possible logic combinations and solutions for it (in APT, RAPID is only for the next line, in G code however it is on until set to work in cutting motion ) some other issues where it would save CYCLE the wrong way, it would have saved 2 number with out spacing I have forgotten that x y z in cycle aren’t always saved as just numbers but rather 2 of em had X Y or Z before written so it would have double letters
DEVLOG 18 New stuff Input now the default value for APT input is CatiaV5 but only for development and it is not written that it is it just is default value for for G-code output is WinNC Sinumerik Logic added logic for CYLINDR which is essentially just a sinusoidal path, not just one period pr it but can be multiple or just a part of one logic for PSIS which is supposed to be like a sign that the CYLINDR is to be defined and that it starts at this coordinates and then some random vector that defines that the movement will be projected in a PLANE that does not contain that vector logic for ROTABL is incomplete but here I would need to look into it but it seems like it is used in MULTI axial machines, but only when it does 3 axis work idk it is a bit emptly defined TLON,GOFWD is now the new definition for circular movement, so it takes the line in the correct logic for both CIRCLE and CYLINDR I undiscovered what CUTTER with 7 tool data defines but for now it just outputs it as 7 comments Bug fixes for SWITCH or setting tool compensation had .trim instead of .trim() same thing happened on the g coder side for some reason maybe a bad commit, the text enter pop-up window didn’t pop-up, resolved What if’s??? What if the sinusoidal movement isn’t horizontal yet at an angle what would happen then? The angle isn’t specified, but I do have the circle center and the first point that is on that circle Note that the path is on the surface of the cylinder this is a sinusoide What if the sinusoide isn’t set in 2D? since 3D circular intepolation is off it should be just a set of close points What if there was no AI that could by pass the main page and end up to a sub-page that isn’t locked to me, unlike the main page? -Would I be ******?
DEVLOG 19 New stuff Logic helical interpolation in g-coder g-coder now remembers the last coordinate, because CATIA gives, the center, radius, direction, 2D vector for direction of movement, end point and pitch, but WinNC that reads the g-code takes end point center and number of full turns and cw or ccw, so number of turns is calculated speciffically inside the class Bug fixes yes What if’s??? No
V1.0 is now DEVLOG 20 New stuff Logic now both APT reader and G-code output are in switch case this makes processing much faster, and takes less memory line splitting is now done before actually going into the switch case for both reader and writer, mainly because then element zero in this case is basically line.startsWith, and then later in code I shaved of like 14 line splits invalid cycles are now rejected and aren’t even translated into KK Bug fixes since I switched from line.startsWith I need only the word in the variable, and there is like a $$*CATIA0 in every file and I hadn’t put line split with * so it registered as and error I have had left the incomplete cycles to be completely written causing an undefined variable to be written in KK and forwarded into G-code What if’s? What if I was supposed to like make CYLINDR output 300 points in G-code I honestly don’t wanna do that?
DEVLOG 21 New stuff Catia PPTable so it turns out I can modify the APT output for some commands, which had not only helped in the post processor more accurate but now I understand more stuff so I made the PPtable and it seems to work more on that some other time Logic since I now know what is to be expected for some commands I was able to shave off roughly 200 lines of code which is great COMPENSATION defines what tool correction register is being redefined, what quadrant is the cutting end, xyz corrections, and nose radius END OF PROGRAM is now single meaning CIRCLE output looks like this kk("ARCH/CENTER, "+centar_x+", "+centar_y+", "+centar_z); kk("ARCH/AXIS"); kk("ARCH/TANGENT, "+this.ls_i+", "+this.ls_j+", "+this.ls_k); kk("ARCH/INFO, "+radius+", "+movement+", "+angle); kk("ARCH/END, "+kraj_x+", "+kraj_y+", "+kraj_z); CYLINDR or sinusoidal movement like this kk("SINUS/CENTER, "+centar_x+", "+centar_y+", "+centar_z); kk("SINUS/AXIS"); kk("SINUS/INFO, "+amplitude); kk("SINUS/TANGENT, "+this.ls_i+", "+this.ls_j+", "+this.ls_k); kk("SINUS/END,"+kraj_x+", "+kraj_y+", "+kraj_z); helix (in APT) HELICAL/CENTER, %MFG_HELICAL_X_CENTER, %MFG_HELICAL_Y_CENTER, %MFG_HELICAL_Z_CENTER HELICAL/TANGENT, %MFG_HELICAL_INDIRV_I, %MFG_HELICAL_INDIRV_J, %MFG_HELICAL_INDIRV_K HELICAL/AXIS, %MFG_HELICAL_I_AXIS, %MFG_HELICAL_J_AXIS, %MFG_HELICAL_K_AXIS HELICAL/INFO, %MFG_HELICAL_PITCH, %MFG_HELICAL_RADIUS, %MFG_HELICAL_HEIGHT, %MFG_HELICAL_ROUND HELICAL/END, %MFG_HELICAL_X_END, %MFG_HELICAL_Y_END, %MFG_HELICAL_Z_END SPINDL is now simply defined FEDRAT is now simply defined COOLANT on the other hand, apparently the coolant is set while defining the tool, which i have accounted on and then just coolant on off, but it seems a bit like it doesn’t make sense that way what if different coolant is wanted??, also the actual syntacs is quite unknown for the coolant sooo yeah DELAY is now simply defined CYCLE now got major upgrades by manipulating the APT lost like a 75 lines of code there spindle rotation limit is now settable CUTCOM pensation is now uncovered but I genuenly have no idea what the stuff means NORMDS or NORMPS, maybe normal to drive / prat surface God knows the answer that I am sure BUGS Yes - I haven’t had a chance to test it yet so I dunno I got the background loading path wrong so that is corrected STUFF LEFT TO DO Make a function for the line split into 3, 4, 5, 6 Rework G-coder to output accordingly to the reworked parser Play with the PPTable The rest of the TO-DO list SUM-UP Found out that I can modify the APT output via PPTable, made a PPTable, now I know much more about The APT, made the parser more precise and thus more correct
DEVLOG 22 New stuff re edited the KK guide so it is written in .md and I SWEAR it looks so much better and it is easier to read rawG new command this one is to be written in the APT or added as an additional command and it bypasses both layers of translation rawKK new command this one is to be written in the APT and it bypasses the first layer of translation (line written in KK) Bug fixes I saw a few bugs in the rapto section of the goto and godlta pretty much all, still haven’t had time to test this changes but it seems to be working ok Leftover stuff make a guide on how to use Catia and CATIA.pptable make an explanation of this program how it works and other and i have written about 3 pages of stuff in catia that i have no idea what that meas and what does it do so research those improve with like code block suggestions for manual code writing BUGS for some reason now the costum panel wint show
DEVLOG 23 NEW STUFF so the parselinev2 build is working (not on the web but in the git) the parselinev3 build is on the way, why? Because I realized how much the v2 build is leaking the performance and optimisation, so it would be simpler to re-do and make it with more brain this time HOW WILL IT WORK simple, for each command in Catia, there will be a case (switch case stuff) then each switch case will call a function that will do all the work for that case that function will call other function do math etc. the user will simply select a document from which the function will get called therefore giving a different syntacs and thats pretty much it
DEVLOG 24 NEW STUFF the parseline v3 is going relatively fast tomorrow it is probablly going to be finished currently the only left syntacs from v2 is to complete cycles, rawG, PSIS, INDIRV, MAXSPNDL, $$, CUTCOM, change tool rework on the SPINDLE syntacs is needed bc i compicated some stuff there and to make a value check by giving a +variable, then if it wasn’t a number it is going to be a NaN which is a false meaning i can make if (+variable) LEFTOVER STUFF (Not in the parseline v3) to do a guide on how to make your own output general overview on the program
Ships:
CAM post processor, so far its only suitable for CatiaV5 intoISO 6983, it’s still in development, there are a few non finished commands, but since there is no actual documentation for CATIA APT1.0 it works really good. erm yeah. at some point im going to make work on the web the rest is pretty much written on Git....
|
1792990123.3916905
|
1793076523.3916905
|
|
46389
|
Street Fighter Model by @elvincheung0321 | Stardan Street Fighter Model by @elvincheung0321 | Stardance...
|
elvincheung0321
|
0
|
123.36
|
0
|
[]
|
[{"post_id": 54469, "ts": "202 [{"post_id": 54469, "ts": "2026-08-25T14:18:23Z", "hours": 2.1628, "text": "Work on hyperparameter tuning"}, {"post_id": 54351, "ts": "2026-08-25T09:40:51Z", "hours": 22.3614, "text": "Trained for a day, bad results due to poorly optimized hyperparameters"}, {"post_id": 51071, "ts": "2026-08-20T15:35:38Z", "hours": 2.3414, "text": "Added rewards for winning rounds"}, {"post_id": 50324, "ts": "2026-08-19T14:25:43Z", "hours": 8.5794, "text": "Street Fighter II Model - Model Regressing After training for another night, my model starting regressing again, now even losing to Guile Next steps The issue is once again my reward function, since its rewarding the model based on its damage, it would have a higher reward if it loses one round out of the three, since it would be able to deal more damage to bloat the rewards. My plan is to tweak the reward function again to incorporate rewarding it when it wins any rounds."}, {"post_id": 49609, "ts": "2026-08-18T14:30:41Z", "hours": 25.1297, "text": "Street Fighter II Model - Beaten Ken!! (Seconds level) After training for a bit more than a day, I was finally able to beat Ken, and move on to the next level to Zangief! (The car is sort of an intermission level)"}, {"post_id": 47960, "ts": "2026-08-16T07:29:56Z", "hours": 9.7558, "text": "Street Fighter II Model - Finally beats Guile!! (The first level) After around 10 hours of overnight training (17M timesteps/frames), the agent can finally beat Guile and reach Ken, but it still falls a bit short beating Ken. Reward bug This was the major bug that was making the model not even damage Guile before. Health resets from 0->176 when the model loses on the first round. This makes the reward become: old frame health - new frame health = damage taken 0 ( dead ) - 176 ( max health ) = - 176 reward = damage_dealt - ( damage_taken ) reward = damage_dealt - ( - 176 ) = damage_dealt + 176 Dying seemed like a large reward to the model, so it learned that dying was good instead of damaging Guile. The Fix damage_dealt = max ( 0 , old_enemy_hp - new_enemy_hp ) damage_taken = max ( 0 , old_player_hp - new_player_hp ) reward = damage_dealt - damage_taken This made it so that if any one of the players died the frame where it recovers health, it would return 0. Since the max function would return the largest value from the parameters given. For example: print ( max ( 0 , - 176 )) This would print: 0"}, {"post_id": 47546, "ts": "2026-08-15T14:59:47Z", "hours": 1.9953, "text": "Coding Hours: 2h Huge reward function bug fix After training my model for 5 million timesteps (basically 5 million frames), I realised a huge flaw in my reward function logic. It would award the players a huge reward after dying once and their health bar replenishing, since I failed to catch the specific case. This was why the previous models weren’t performing well (see the video below) I’m going to train my new model with the reward function fixed overnight today and see how it goes!"}, {"post_id": 47466, "ts": "2026-08-15T12:08:13Z", "hours": 8.9789, "text": "Finished hyperparameter tuning After running the tuning program overnight, I’m going to use those parameters to actually train the model overnight to see how it performs"}, {"post_id": 46947, "ts": "2026-08-14T14:56:42Z", "hours": 3.3322, "text": "Coding Hours: 2h Optimised model even further Stripped down the game window to a way smaller 84x84 resolution and also grayscaled the game. Also set up 4 parallel environments for the model to be able to train even faster than before. Started hyperparameter tuning before training the actual model to ensure it is able to train at the most effective and efficient way. Below is what the AI uses to train (example not the actual windows, they would be scaled down and be grayscaled so it would be easier to process for the model):"}, {"post_id": 46680, "ts": "2026-08-14T03:44:07Z", "hours": 10.3528, "text": "After Training for another million steps overnight, my model has now finally learnt to crouch and block, while it still doesn’t deal any damage, it is still an improvement. This model right now is very unoptimised, I’m working on an improvement to optimise everything to make training a lot faster and way more efficient."}, {"post_id": 46378, "ts": "2026-08-13T15:36:21Z", "hours": 1.8169, "text": "Coding Hours: 1 Hour 50 Mins Started making a custom reward function and also optimised the learning environemnt so that the model can learn more efficiently"}, {"post_id": 46196, "ts": "2026-08-13T08:05:45Z", "hours": 12.9761, "text": "Trained model overnight again, but it still showed little improvement. I will try to create an environment and setup the reward system so it can train more efficiently and also host train it on some free cloud websites rather than my own laptop."}, {"post_id": 45503, "ts": "2026-08-12T01:27:01Z", "hours": 9.4858, "text": "Coding hours: 1.5h Finished training my Street Fighter model for the first time! The model now is only capable of doing very simple actions, it won’t even move and only usually spams one button, but this will improve over time as I spend more time to train the model and tune it. This is just the results so far of training it for around 8 hours overnight on my own laptop."}, {"post_id": 45137, "ts": "2026-08-11T13:09:42Z", "hours": 4.0894, "text": "Coding Hours: 3.5h I’m still learning RL, in the process, I made a simple model that learnt how to play breakout. This was trained for about 30 minutes, I’m sure it can do better if I were to dedicate more time to training it, but this is primarily so I can get myself more familiar with RL before training a more complicated model for Street Fighter."}]...
|
Title: Street Fighter Model by @elvincheung0321 | Title: Street Fighter Model by @elvincheung0321 | Stardance
Devlogs:
Coding Hours: 3.5h I’m still learning RL, in the process, I made a simple model that learnt how to play breakout. This was trained for about 30 minutes, I’m sure it can do better if I were to dedicate more time to training it, but this is primarily so I can get myself more familiar with RL before training a more complicated model for Street Fighter.
Coding hours: 1.5h Finished training my Street Fighter model for the first time! The model now is only capable of doing very simple actions, it won’t even move and only usually spams one button, but this will improve over time as I spend more time to train the model and tune it. This is just the results so far of training it for around 8 hours overnight on my own laptop.
Trained model overnight again, but it still showed little improvement. I will try to create an environment and setup the reward system so it can train more efficiently and also host train it on some free cloud websites rather than my own laptop.
Coding Hours: 1 Hour 50 Mins Started making a custom reward function and also optimised the learning environemnt so that the model can learn more efficiently
After Training for another million steps overnight, my model has now finally learnt to crouch and block, while it still doesn’t deal any damage, it is still an improvement. This model right now is very unoptimised, I’m working on an improvement to optimise everything to make training a lot faster and way more efficient.
Coding Hours: 2h Optimised model even further Stripped down the game window to a way smaller 84x84 resolution and also grayscaled the game. Also set up 4 parallel environments for the model to be able to train even faster than before. Started hyperparameter tuning before training the actual model to ensure it is able to train at the most effective and efficient way. Below is what the AI uses to train (example not the actual windows, they would be scaled down and be grayscaled so it would be easier to process for the model):
Finished hyperparameter tuning After running the tuning program overnight, I’m going to use those parameters to actually train the model overnight to see how it performs
Coding Hours: 2h Huge reward function bug fix After training my model for 5 million timesteps (basically 5 million frames), I realised a huge flaw in my reward function logic. It would award the players a huge reward after dying once and their health bar replenishing, since I failed to catch the specific case. This was why the previous models weren’t performing well (see the video below) I’m going to train my new model with the reward function fixed overnight today and see how it goes!
Street Fighter II Model - Finally beats Guile!! (The first level) After around 10 hours of overnight training (17M timesteps/frames), the agent can finally beat Guile and reach Ken, but it still falls a bit short beating Ken. Reward bug This was the major bug that was making the model not even damage Guile before. Health resets from 0->176 when the model loses on the first round. This makes the reward become: old frame health - new frame health = damage taken 0 ( dead ) - 176 ( max health ) = - 176 reward = damage_dealt - ( damage_taken ) reward = damage_dealt - ( - 176 ) = damage_dealt + 176 Dying seemed like a large reward to the model, so it learned that dying was good instead of damaging Guile. The Fix damage_dealt = max ( 0 , old_enemy_hp - new_enemy_hp ) damage_taken = max ( 0 , old_player_hp - new_player_hp ) reward = damage_dealt - damage_taken This made it so that if any one of the players died the frame where it recovers health, it would return 0. Since the max function would return the largest value from the parameters given. For example: print ( max ( 0 , - 176 )) This would print: 0
Street Fighter II Model - Beaten Ken!! (Seconds level) After training for a bit more than a day, I was finally able to beat Ken, and move on to the next level to Zangief! (The car is sort of an intermission level)
Street Fighter II Model - Model Regressing After training for another night, my model starting regressing again, now even losing to Guile Next steps The issue is once again my reward function, since its rewarding the model based on its damage, it would have a higher reward if it loses one round out of the three, since it would be able to deal more damage to bloat the rewards. My plan is to tweak the reward function again to incorporate rewarding it when it wins any rounds.
Added rewards for winning rounds
Trained for a day, bad results due to poorly optimized hyperparameters
Work on hyperparameter tuning...
|
1792921812.7361066
|
1793785812.7361066
|
|
12498
|
Ferrite by @MarioS271 | Stardance
|
MarioS271
|
0
|
121.88
|
0
|
[]
|
[{"post_id": 72380, "ts": "202 [{"post_id": 72380, "ts": "2026-09-22T19:58:13Z", "hours": 3.6453, "text": "DebugWrite syscall! The userspace process is now able to ask the kernel to write log messages! This means that finally, you can actually properly do something from the userspace program. Next, I’ll be implementing userspace page fault handling"}, {"post_id": 71895, "ts": "2026-09-21T18:32:02Z", "hours": 4.145, "text": "Syscall Dispatching, Syscall returning and Exit Syscall Finally, after all this time: User programs can now interact with the kernel!! :) Changelog Added Syscall enum which represents all possible syscalls and their respective IDs Added SyscallArgs whichs contains syscall number and args in an architecture-independent format Added SyscallResult and SyscallError Added syscall dispatching logic Fixed kernel data leaking into userspace via initial_userspace_jump by clearing CPU registers before the jump the end of stardance is approaching… i wish all of you a lot of fun for the last 9 days."}, {"post_id": 71226, "ts": "2026-09-20T14:09:53Z", "hours": 7.2311, "text": "Syscalls! Changes so far: Added gs_info struct, which saves the user stack and holds a pointer to the kernel stack Added syscall::init which enables the syscall / sysret instructions and sets up the STAR , LSTAR and SFMASK registers Added syscall_entry which builds a UserFrame (a snapshot of the CPU registers on syscall entry) and calls syscall_dispatch Added syscall_dispatch , which currently logs the received syscall number and halts (the system call return path is not implemented YET) Added UserFrame which holds a CPU register snapshot which gets taken upon entering the kernel"}, {"post_id": 68847, "ts": "2026-09-15T21:08:45Z", "hours": 7.6578, "text": "ELF Loading Refactor and improved build system After a week of basically no progress, I’ve finally finished moving the ELF init sequence from main.rs into the proper methods under the sched subsystem. I’ve also simplified and improved the build system ( build.py / docs.py ). They now use a shared lib.py to avoid code duplication. Also, build.py got a few changes: Removed build cache (cargo already does it) Swapped console restore for proper serial control char output filtering Bug Fixes The docker permissions have been fixed, as under Linux, root would own parts of the build files which is of course annoying as you can’t easily interact with those files then. The github-hosted rustdoc was failing to build as it could not find USER-BINARY , so I just faked user-binary via touch user-binary . time to go to bed yippeeeee :D"}, {"post_id": 63879, "ts": "2026-09-07T21:37:33Z", "hours": 6.1186, "text": "Finally… after all that work, we’re back!! After almost 30 hours of work over the last week, I’ve finally finished the big refactor . Changelog of the refactor Rewritten kprint backend Restructured KSTATE Hit my head on the wall A LOT Added a few new datatypes and macros Optimizations all over the place Added quite a few TODOs (more work 🥲) Restructured the source tree Changed the entrypoint (kernel now starts in an arch-specific kernel_entry , which builds a BootInfo and hands to kernel_main ) Moved the userspace/ELF stuff from main.rs into the sched subsystem Rewrote the UART driver … and so much more. and of course i organized it all into one slightly large 144 file commit :)"}, {"post_id": 62991, "ts": "2026-09-06T15:43:08Z", "hours": 9.2244, "text": "Big changes are still happening oh boy this is taking way too long Rewritten kprint kprint , the kernel print macro has been fully rewritten. The public macros have not changed, but internally, the macros now: Construct a kernel writer Call core::fmt::write on the kernel writer The kernel writer collects the text of all calls made to it using core::fmt::write in an internal buffer, and on drop, it pushes a new entry into the kernel log ringbuffer in a format that is (currently only partially) syslog-compatible. Then, the kernel writer dispatches a log header and the full log text to all active log recievers (like UART or the basic framebuffer). New Types PackedU8 : A type which wraps all the bitwise logic for packing multiple pieces of data which are less than one byte into a byte UncheckedCell : A datatype with interior mutability, which can be uninitialized via MaybeUninit . When the cargo feature debug-checks is enabled, this type also checks for double initialization and uninitialized access NicheCell : A datatype with interior mutability, which can be uninitialized via Option . This datatype is designed to be used with values that can take advantage of niche optimization (where the datatype T has a value which is guaranteed to be invalid, like a NonZeroU64 being zero) and oh boy, the big refactor: redid kernel source tree, ... commit is gonna be one hell of a mess…"}, {"post_id": 61699, "ts": "2026-09-04T18:57:23Z", "hours": 7.995, "text": "Big changes upcoming… I’ve decided to change what the kernel aims to be and how it will work. I’ve dropped full linux drop-in compatibility in favour of creating a clean, modern and optimized kernel which tries to fix design mistakes other kernels have already made. New Design The kernel will be POSIX-compatible, feature a namespaced VFS to seperate virtual files or devices like /dev/sda , /sys/class/hwmon , /proc/self/ and more from actual files. It will have namespaces like fs:/ for the actual file system, dev:/ for device files (like dev:/sda ), vdev:/ for virtual devices (like vdev:/urandom ) and more, including hw:/ for a modern hardware info interface, log:/ for a standardized logging interface and reg:/ for a global registry-like configuration system. Internally, the kernel will also feature KSTATE , a central static struct for storing everything the kernel uses. Also, ther kernel will move from strictly limine to a dynamic bootloader format, where each architecture has its own kernel_entry , which prepares the CPU and kernel into a common state (long mode, paging, …) and builds a standardized BootInfo struct, which then gets handed to kernel_main when it is called. New Source Tree I’m also currently working on massively reorganizing and cleaning up the kernel source, by for example standardizing where arch-specific code lands, categorizing and organizing the code better and more. Also, the kernel print system ( kprint ) is currently being rewritten to improve performance and integrate it into KSTATE ."}, {"post_id": 60495, "ts": "2026-09-02T21:21:59Z", "hours": 5.7089, "text": "Refactoring hell is here again! Before I start on syscalls for the userspace binary, I’ve decided to first get most TODOs done, like updating the safety comments and rustdoc, refactoring the ELF loading stuff to properly utilize KSTATE::procs , proper error delegation and more. I’ve finally finished refactoring the TSS, GDT and IDT properly by removing the struct wrapper for GDT and IDT, getting rid of all the Once s and more. Additionally, I refactored KSTATE::cpu to be an arch-independent container of arch-specific structs. holy crap ive got so much left to refactor… and the new bodycam update just came out i wanna play but am stuck doing kernel stuff and some other stuff :’)"}, {"post_id": 59290, "ts": "2026-09-01T00:14:55Z", "hours": 6.2725, "text": "@everyone … WE HAVE USERSPACE!!! 🎉 :D This is something I’ve been waiting for sooo long… a binary is actually executing in USERSPACE now (ring 3 and stuff)!!! How it works Currently, the code is extremely hacked together, or “gepfuscht” as we like to call it in Austria ;). Basically, what should be cleanly integrated with KSTATE::procs , should use a proper userspace and kernel stack and so on, doesn’t. All of this of course won’t stay like that, but it currently is like that to just get something in userspace running. The one thing that is actually done cleanly is the ELF validation and definitions, which live under src/elf . There is a struct representing the ELF header, an ELF PHDR and also an enum for ELF validation errors. All other logic was just thrown into main for now, like creating the processes address space, mapping its memory, copying the binary into the mapped memor, setting up its stack and actually jumping to it. The current testing binary Written in good old assembly of course, the test binary currently has the job to cause some sort of CPU exception, as syscalls or any other way to interact with the kernel or output something doesn’t even exist yet. The current program manages that via just running the hlt instruction, which, when run from userspace (Ring 3) causes a general protection fault ( #GP ). This is because a userspace program shouldn’t just be able to halt the CPU or disable interrupts (via the cli instruction). That would defeat the whole purpose of rings and kernel/userspace. The userspace binary currently lies under src/user-binary.asm , next to src/kernel/ . It is build via running docker exec ferrite_os /ferrite_os/build-user-binary.sh . NASM was also added to the Dockerfile to make building the assembly file possible."}, {"post_id": 58145, "ts": "2026-08-30T14:31:31Z", "hours": 4.1728, "text": "Virtual Memory Management is complete! (for now) I’ve added methods for mapping pages and VMA together. I’ve also improved the kernel VMA granularity and added a kernel paging remap step to mm_init() which applies the kernel VMA permissions to the kernel pages. This is only intermediate until I switch to the linux boot protocol. Next up, I’ll be adding a (very basic) ELF loader!"}, {"post_id": 57670, "ts": "2026-08-29T21:52:52Z", "hours": 7.9519, "text": "Lots of stuff Changelog for the last two days Fixed the clean option in build.py Add kernel VMA setup method Update rustdoc in several places Add panic types to kernel_panic output Move SIMPLE_STATE out of main Improve per-arch code layout … and an INSANE amount of optimizations, including: Marking certain code paths as cold (which signals the compiler to expect that the code path is unlikely to occur and optimize accordingly) Remove a lot of overhead introduced by Once and similar by swapping them for UnsafeCell<MaybeUninit<T>> and others and taking advantage of things like niche optimization Using bit-packing instead of seperate booleans for state tracking Next up, I’ll be doing some more work on the VMM and finally add the full mapping methods, which map pages and VMAs together."}, {"post_id": 55494, "ts": "2026-08-27T11:46:16Z", "hours": 4.5481, "text": "AddressSpace and VMA data structs done! I’ve introduced a struct called AddressSpace which contains the virtual address of the root page table (the PML4 on x86_64) and a BTreeSet of VMAs (virtual memory areas). A BTreeSet is basically a type of set which organizes data in a tree-like structure (in a B-Tree structure to be exact) with a time complexity of O(log n) for inserting, removing and searching for elements. A VMA (virtual memory area) is an area in memory with specific flags, such as READ , WRITE , EXEC or USER . One of their main uses is determining what to do on a #PF (page fault): should we allocate a page here (lazy-mapping)? Or was this truly a faulty operation like trying to execute READ -only memory? Also, I briefly attempted to switch over to the linux boot protocol, but I decided to do that sometime later, because it is slightly complicated and definitely did not break everything ;)"}, {"post_id": 54689, "ts": "2026-08-25T19:03:42Z", "hours": 1.0014, "text": "Finally finished fixing the PMM free method! After needing to quickly relearn the logic of the free method because I somehow forgot it, it finally works again! Additionally, I’ve added a little safeguard to the bootloader memory reclamation. Next, I’ll be continuing on the VMM and refactoring it to support userland page tables too. Also, I’ve added a few core::fmt traits to PhysAddr and VirtAddr and also added a constructor which creates a new address type ( PhysAddr or VirtAddr ) with an address of zero. In addition, PhysAddr got a few new getters like as_ptr or as_mut_ptr ."}, {"post_id": 54565, "ts": "2026-08-25T16:11:33Z", "hours": 8.2356, "text": "Memory Stuff and General Fixes Currently working on the PMM and VMM a little more, also cleaned up the main for better readability. I also moved the PMM and VMM into the mm subsystem of the KState struct. Additionally, I switched from rust 2021 to rust 2024, which also needed a little fixing to get working again. Why? Well to use let chains in if statements of course cause its like a little bit nicer to write! :) Also, I partially upgraded scripts/x86_64/build.py to log to a log file and restore your terminal config on termination. Currently working on getting a bug in the PMM fixed, getting bootloader memory reclaim to work and then I’ll do the VMM’s VMAs."}, {"post_id": 45979, "ts": "2026-08-12T20:18:08Z", "hours": 2.7475, "text": "VMM: Major Refactor aswell as Huge Pages! I’ve refactored the VMM, aswell as added support for huge pages (2 MiB & 1 GiB) to it. Also, I’ve added vmm-debug-logging . Also, I’ve updated the README to reflect the most up-to-date information and to look nicer."}, {"post_id": 44829, "ts": "2026-08-10T21:04:45Z", "hours": 2.47, "text": "Memory Management Updates! (oh and a logo too) VMM Changes I’ve added remap_page aswell as translate to the VMM (virtual memory manager). Also, I’ve added alignment-checking to ensure the VMM doesn’t corrupt memory when an incorrect virt/phys address is given to one of it’s methods. Additionally, I’ve cleaned up the code a little bit by making things like the raw pointer stuff more readable. LOGO!!! :) I’ve painstakingly (hope i spelled it right) put together a handmade logo for the kernel. It’s pretty simple but I still think it looks pretty nice."}, {"post_id": 42930, "ts": "2026-08-07T22:15:35Z", "hours": 3.6658, "text": "PMM Buddy Allocator done! The PMM now uses a buddy allocator which gives us many advantages, including: Tracking overhead doesn’t grow with RAM size Faster (bitmap is always O(n), buddy allocator is O(1) most times, worst case O(log n)) Order-based allocation (group a lot of free space together into one 4 MiB region for order 10 or 16 KiB for order 2 for example) Next is adding a few methods to the VMM, and then I’ll work on the heap allocator to finally be able to work on the kstate struct :)"}, {"post_id": 42031, "ts": "2026-08-06T16:07:23Z", "hours": 1.3044, "text": "funny stuff I’ve added a marker byte to the ring buffer that makes it possible to later properly parse log levels from the buffer. Also, I’ve finally figured out how buddy allocators work meaning I can start work on redoing the PMM :)"}, {"post_id": 36746, "ts": "2026-07-29T00:21:27Z", "hours": 5.9975, "text": "The refactoring hell continues… I’ve refactored PMM and VMM into SIMPLE_STATE , updated the build and docs scripts, enhanced kernel logging via log levels and more, added and fleshed out a Claude Code Skill for writing rustdoc and let Claude re-do a lot of the rust doc to reduce the over-documentation that was done by none other than… Claude. also look at this fancy new fb logging :D"}, {"post_id": 36151, "ts": "2026-07-28T01:41:46Z", "hours": 6.1836, "text": "Refactoring into oblivion! Currently working on improving the kernel a lot to make it robuster for its later stages. What was so far improved Tooling Replace loose markdown docs with proper GitHub Pages hosted rustdoc Add docs.py , refactor build.py to work on linux too Kernel Serial Logging abstracted into trait + per-arch impls Improve panic handlers to give more info and dynamically use what is avail for outputting info (basic fb, serial) Refactor basic framebuffer and PSF2 font into cleaner struct+impl approach Remove text.rs and move its logic into kprint (which has also been refactored to be concurrency-safe) Other Stuff I also tested the kernel on real hardware !! To my suprise, grabbing the ISO from the build folder, flashing it onto a USB drive and plugging it into a laptop just… WORKED?!? well i guess my kernel is real hardware certified now :) I attached a video of the kernel booting on real hardware and IRQ0 (the BIOS-configured 18.2 Hz hardware timer) printing “a” repeatedly. :)"}, {"post_id": 34885, "ts": "2026-07-25T23:28:26Z", "hours": 7.9892, "text": "Big Update :) (sorry for not doing much the past weeks had to get 4th place at the botball competition real quick) Changelog Implemented heap allocator (partially and broken) Implement PIC (Programmable Interrupt Controller) Init + get basic IRQ stuff working Fix GDT (was missing a few entries) Fix TSS (IST1-4 interrupt stacks were missing) Implement interrupts for vectors #0 through #31 Update Panic for most interrupts to give way more details (example: pagefault in attached image) Replace Mutex with IrqMutex for text writing and holding CHAINED_PICS Current State I’ve noticed that my so far work has been kinda sloppy, so I’m currently working on improving everything (as u can see on the changelist above ive already started). I’m doing this because when I started with IRQs, stuff started breaking a lot. My goal is to get everything thread-safe and ready in a way that it’ll work in later stages of the kernel too. Next up? Next, I’ll be working on fixing logging (add a ringbuffer to prevent interrupts creating half-printed or partially drawn logs)"}, {"post_id": 6510, "ts": "2026-06-10T22:49:31Z", "hours": 6.0211, "text": "Had a little fight with github actions and qemu wasm stuff. Tried to implement a live web demo using a wasm implementation of qemu with UEFI and more, but couldnt get it to run. Also, I heavily improved documentation and finished up the virtual memory manager (for now…). Plans? Next, the heap allocator is coming then I’ll finally be able to use dynamic types! was worth it i guess (it was not i gotta get up in 5h 🥲)"}, {"post_id": 5062, "ts": "2026-06-08T18:47:11Z", "hours": 1.5903, "text": "Hi! This is my “main” project, ✨FerriteOS✨! (Well, idk if you can call it a whole OS if im only planning to do a kernel, but anyways) Ferrite is a Linux-ABI compatible kernel, written entirely in Rust, from scratch. My goal My end goal is for it to be able to run systemd, GNOME and more. But thats a very, VERY distant goal. For now, im focusing on getting a statically linked C binary running in userspace. Current State I’ve already managed to get some basic logging via serial and a basic framebuffer going, aswell as x86_64 GDT, IDT, TSS and a physical aswell as a very slim virtual memory manager. Whats next? Next, I’ll be “finishing” up the VMM a little to be able to start work on the heap allocator, which will enable use of datatypes like Vec, Box and more. nerd section For anyone interested in the more technical stuff: The build toolchain works through python scripts, which use docker to build and then QEMU to run the kernel. I’m mainly targeting x86_64, but aarch64 support is also my plan (but I’ll be focusing on x86_64 during this challenge)."}]...
|
Title: Ferrite by @MarioS271 | Stardance
Devlogs: Title: Ferrite by @MarioS271 | Stardance
Devlogs:
Hi! This is my “main” project, ✨FerriteOS✨! (Well, idk if you can call it a whole OS if im only planning to do a kernel, but anyways) Ferrite is a Linux-ABI compatible kernel, written entirely in Rust, from scratch. My goal My end goal is for it to be able to run systemd, GNOME and more. But thats a very, VERY distant goal. For now, im focusing on getting a statically linked C binary running in userspace. Current State I’ve already managed to get some basic logging via serial and a basic framebuffer going, aswell as x86_64 GDT, IDT, TSS and a physical aswell as a very slim virtual memory manager. Whats next? Next, I’ll be “finishing” up the VMM a little to be able to start work on the heap allocator, which will enable use of datatypes like Vec, Box and more. nerd section For anyone interested in the more technical stuff: The build toolchain works through python scripts, which use docker to build and then QEMU to run the kernel. I’m mainly targeting x86_64, but aarch64 support is also my plan (but I’ll be focusing on x86_64 during this challenge).
Had a little fight with github actions and qemu wasm stuff. Tried to implement a live web demo using a wasm implementation of qemu with UEFI and more, but couldnt get it to run. Also, I heavily improved documentation and finished up the virtual memory manager (for now…). Plans? Next, the heap allocator is coming then I’ll finally be able to use dynamic types! was worth it i guess (it was not i gotta get up in 5h 🥲)
Big Update :) (sorry for not doing much the past weeks had to get 4th place at the botball competition real quick) Changelog Implemented heap allocator (partially and broken) Implement PIC (Programmable Interrupt Controller) Init + get basic IRQ stuff working Fix GDT (was missing a few entries) Fix TSS (IST1-4 interrupt stacks were missing) Implement interrupts for vectors #0 through #31 Update Panic for most interrupts to give way more details (example: pagefault in attached image) Replace Mutex with IrqMutex for text writing and holding CHAINED_PICS Current State I’ve noticed that my so far work has been kinda sloppy, so I’m currently working on improving everything (as u can see on the changelist above ive already started). I’m doing this because when I started with IRQs, stuff started breaking a lot. My goal is to get everything thread-safe and ready in a way that it’ll work in later stages of the kernel too. Next up? Next, I’ll be working on fixing logging (add a ringbuffer to prevent interrupts creating half-printed or partially drawn logs)
Refactoring into oblivion! Currently working on improving the kernel a lot to make it robuster for its later stages. What was so far improved Tooling Replace loose markdown docs with proper GitHub Pages hosted rustdoc Add docs.py , refactor build.py to work on linux too Kernel Serial Logging abstracted into trait + per-arch impls Improve panic handlers to give more info and dynamically use what is avail for outputting info (basic fb, serial) Refactor basic framebuffer and PSF2 font into cleaner struct+impl approach Remove text.rs and move its logic into kprint (which has also been refactored to be concurrency-safe) Other Stuff I also tested the kernel on real hardware !! To my suprise, grabbing the ISO from the build folder, flashing it onto a USB drive and plugging it into a laptop just… WORKED?!? well i guess my kernel is real hardware certified now :) I attached a video of the kernel booting on real hardware and IRQ0 (the BIOS-configured 18.2 Hz hardware timer) printing “a” repeatedly. :)
The refactoring hell continues… I’ve refactored PMM and VMM into SIMPLE_STATE , updated the build and docs scripts, enhanced kernel logging via log levels and more, added and fleshed out a Claude Code Skill for writing rustdoc and let Claude re-do a lot of the rust doc to reduce the over-documentation that was done by none other than… Claude. also look at this fancy new fb logging :D
funny stuff I’ve added a marker byte to the ring buffer that makes it possible to later properly parse log levels from the buffer. Also, I’ve finally figured out how buddy allocators work meaning I can start work on redoing the PMM :)
PMM Buddy Allocator done! The PMM now uses a buddy allocator which gives us many advantages, including: Tracking overhead doesn’t grow with RAM size Faster (bitmap is always O(n), buddy allocator is O(1) most times, worst case O(log n)) Order-based allocation (group a lot of free space together into one 4 MiB region for order 10 or 16 KiB for order 2 for example) Next is adding a few methods to the VMM, and then I’ll work on the heap allocator to finally be able to work on the kstate struct :)
Memory Management Updates! (oh and a logo too) VMM Changes I’ve added remap_page aswell as translate to the VMM (virtual memory manager). Also, I’ve added alignment-checking to ensure the VMM doesn’t corrupt memory when an incorrect virt/phys address is given to one of it’s methods. Additionally, I’ve cleaned up the code a little bit by making things like the raw pointer stuff more readable. LOGO!!! :) I’ve painstakingly (hope i spelled it right) put together a handmade logo for the kernel. It’s pretty simple but I still think it looks pretty nice.
VMM: Major Refactor aswell as Huge Pages! I’ve refactored the VMM, aswell as added support for huge pages (2 MiB & 1 GiB) to it. Also, I’ve added vmm-debug-logging . Also, I’ve updated the README to reflect the most up-to-date information and to look nicer.
Memory Stuff and General Fixes Currently working on the PMM and VMM a little more, also cleaned up the main for better readability. I also moved the PMM and VMM into the mm subsystem of the KState struct. Additionally, I switched from rust 2021 to rust 2024, which also needed a little fixing to get working again. Why? Well to use let chains in if statements of course cause its like a little bit nicer to write! :) Also, I partially upgraded scripts/x86_64/build.py to log to a log file and restore your terminal config on termination. Currently working on getting a bug in the PMM fixed, getting bootloader memory reclaim to work and then I’ll do the VMM’s VMAs.
Finally finished fixing the PMM free method! After needing to quickly relearn the logic of the free method because I somehow forgot it, it finally works again! Additionally, I’ve added a little safeguard to the bootloader memory reclamation. Next, I’ll be continuing on the VMM and refactoring it to support userland page tables too. Also, I’ve added a few core::fmt traits to PhysAddr and VirtAddr and also added a constructor which creates a new address type ( PhysAddr or VirtAddr ) with an address of zero. In addition, PhysAddr got a few new getters like as_ptr or as_mut_ptr .
AddressSpace and VMA data structs done! I’ve introduced a struct called AddressSpace which contains the virtual address of the root page table (the PML4 on x86_64) and a BTreeSet of VMAs (virtual memory areas). A BTreeSet is basically a type of set which organizes data in a tree-like structure (in a B-Tree structure to be exact) with a time complexity of O(log n) for inserting, removing and searching for elements. A VMA (virtual memory area) is an area in memory with specific flags, such as READ , WRITE , EXEC or USER . One of their main uses is determining what to do on a #PF (page fault): should we allocate a page here (lazy-mapping)? Or was this truly a faulty operation like trying to execute READ -only memory? Also, I briefly attempted to switch over to the linux boot protocol, but I decided to do that sometime later, because it is slightly complicated and definitely did not break everything ;)
Lots of stuff Changelog for the last two days Fixed the clean option in build.py Add kernel VMA setup method Update rustdoc in several places Add panic types to kernel_panic output Move SIMPLE_STATE out of main Improve per-arch code layout … and an INSANE amount of optimizations, including: Marking certain code paths as cold (which signals the compiler to expect that the code path is unlikely to occur and optimize accordingly) Remove a lot of overhead introduced by Once and similar by swapping them for UnsafeCell<MaybeUninit<T>> and others and taking advantage of things like niche optimization Using bit-packing instead of seperate booleans for state tracking Next up, I’ll be doing some more work on the VMM and finally add the full mapping methods, which map pages and VMAs together.
Virtual Memory Management is complete! (for now) I’ve added methods for mapping pages and VMA together. I’ve also improved the kernel VMA granularity and added a kernel paging remap step to mm_init() which applies the kernel VMA permissions to the kernel pages. This is only intermediate until I switch to the linux boot protocol. Next up, I’ll be adding a (very basic) ELF loader!
@everyone … WE HAVE USERSPACE!!! 🎉 :D This is something I’ve been waiting for sooo long… a binary is actually executing in USERSPACE now (ring 3 and stuff)!!! How it works Currently, the code is extremely hacked together, or “gepfuscht” as we like to call it in Austria ;). Basically, what should be cleanly integrated with KSTATE::procs , should use a proper userspace and kernel stack and so on, doesn’t. All of this of course won’t stay like that, but it currently is like that to just get something in userspace running. The one thing that is actually done cleanly is the ELF validation and definitions, which live under src/elf . There is a struct representing the ELF header, an ELF PHDR and also an enum for ELF validation errors. All other logic was just thrown into main for now, like creating the processes address space, mapping its memory, copying the binary into the mapped memor, setting up its stack and actually jumping to it. The current testing binary Written in good old assembly of course, the test binary currently has the job to cause some sort of CPU exception, as syscalls or any other way to interact with the kernel or output something doesn’t even exist yet. The current program manages that via just running the hlt instruction, which, when run from userspace (Ring 3) causes a general protection fault ( #GP ). This is because a userspace program shouldn’t just be able to halt the CPU or disable interrupts (via the cli instruction). That would defeat the whole purpose of rings and kernel/userspace. The userspace binary currently lies under src/user-binary.asm , next to src/kernel/ . It is build via running docker exec ferrite_os /ferrite_os/build-user-binary.sh . NASM was also added to the Dockerfile to make building the assembly file possible.
Refactoring hell is here again! Before I start on syscalls for the userspace binary, I’ve decided to first get most TODOs done, like updating the safety comments and rustdoc, refactoring the ELF loading stuff to properly utilize KSTATE::procs , proper error delegation and more. I’ve finally finished refactoring the TSS, GDT and IDT properly by removing the struct wrapper for GDT and IDT, getting rid of all the Once s and more. Additionally, I refactored KSTATE::cpu to be an arch-independent container of arch-specific structs. holy crap ive got so much left to refactor… and the new bodycam update just came out i wanna play but am stuck doing kernel stuff and some other stuff :’)
Big changes upcoming… I’ve decided to change what the kernel aims to be and how it will work. I’ve dropped full linux drop-in compatibility in favour of creating a clean, modern and optimized kernel which tries to fix design mistakes other kernels have already made. New Design The kernel will be POSIX-compatible, feature a namespaced VFS to seperate virtual files or devices like /dev/sda , /sys/class/hwmon , /proc/self/ and more from actual files. It will have namespaces like fs:/ for the actual file system, dev:/ for device files (like dev:/sda ), vdev:/ for virtual devices (like vdev:/urandom ) and more, including hw:/ for a modern hardware info interface, log:/ for a standardized logging interface and reg:/ for a global registry-like configuration system. Internally, the kernel will also feature KSTATE , a central static struct for storing everything the kernel uses. Also, ther kernel will move from strictly limine to a dynamic bootloader format, where each architecture has its own kernel_entry , which prepares the CPU and kernel into a common state (long mode, paging, …) and builds a standardized BootInfo struct, which then gets handed to kernel_main when it is called. New Source Tree I’m also currently working on massively reorganizing and cleaning up the kernel source, by for example standardizing where arch-specific code lands, categorizing and organizing the code better and more. Also, the kernel print system ( kprint ) is currently being rewritten to improve performance and integrate it into KSTATE .
Big changes are still happening oh boy this is taking way too long Rewritten kprint kprint , the kernel print macro has been fully rewritten. The public macros have not changed, but internally, the macros now: Construct a kernel writer Call core::fmt::write on the kernel writer The kernel writer collects the text of all calls made to it using core::fmt::write in an internal buffer, and on drop, it pushes a new entry into the kernel log ringbuffer in a format that is (currently only partially) syslog-compatible. Then, the kernel writer dispatches a log header and the full log text to all active log recievers (like UART or the basic framebuffer). New Types PackedU8 : A type which wraps all the bitwise logic for packing multiple pieces of data which are less than one byte into a byte UncheckedCell : A datatype with interior mutability, which can be uninitialized via MaybeUninit . When the cargo feature debug-checks is enabled, this type also checks for double initialization and uninitialized access NicheCell : A datatype with interior mutability, which can be uninitialized via Option . This datatype is designed to be used with values that can take advantage of niche optimization (where the datatype T has a value which is guaranteed to be invalid, like a NonZeroU64 being zero) and oh boy, the big refactor: redid kernel source tree, ... commit is gonna be one hell of a mess…
Finally… after all that work, we’re back!! After almost 30 hours of work over the last week, I’ve finally finished the big refactor . Changelog of the refactor Rewritten kprint backend Restructured KSTATE Hit my head on the wall A LOT Added a few new datatypes and macros Optimizations all over the place Added quite a few TODOs (more work 🥲) Restructured the source tree Changed the entrypoint (kernel now starts in an arch-specific kernel_entry , which builds a BootInfo and hands to kernel_main ) Moved the userspace/ELF stuff from main.rs into the sched subsystem Rewrote the UART driver … and so much more. and of course i organized it all into one slightly large 144 file commit :)
ELF Loading Refactor and improved build system After a week of basically no progress, I’ve finally finished moving the ELF init sequence from main.rs into the proper methods under the sched subsystem. I’ve also simplified and improved the build system ( build.py / docs.py ). They now use a shared lib.py to avoid code duplication. Also, build.py got a few changes: Removed build cache (cargo already does it) Swapped console restore for proper serial control char output filtering Bug Fixes The docker permissions have been fixed, as under Linux, root would own parts of the build files which is of course annoying as you can’t easily interact with those files then. The github-hosted rustdoc was failing to build as it could not find USER-BINARY , so I just faked user-binary via touch user-binary . time to go to bed yippeeeee :D
Syscalls! Changes so far: Added gs_info struct, which saves the user stack and holds a pointer to the kernel stack Added syscall::init which enables the syscall / sysret instructions and sets up the STAR , LSTAR and SFMASK registers Added syscall_entry which builds a UserFrame (a snapshot of the CPU registers on syscall entry) and calls syscall_dispatch Added syscall_dispatch , which currently logs the received syscall number and halts (the system call return path is not implemented YET) Added UserFrame which holds a CPU register snapshot which gets taken upon entering the kernel
Syscall Dispatching, Syscall returning and Exit Syscall Finally, after all this time: User programs can now interact with the kernel!! :) Changelog Added Syscall enum which represents all possible syscalls and their respective IDs Added SyscallArgs whichs contains syscall number and args in an architecture-independent format Added SyscallResult and SyscallError Added syscall dispatching logic Fixed kernel data leaking into userspace via initial_userspace_jump by clearing CPU registers before the jump the end of stardance is approaching… i wish all of you a lot of fun for the last 9 days.
DebugWrite syscall! The userspace process is now able to ask the kernel to write log messages! This means that finally, you can actually properly do something from the userspace program. Next, I’ll be implementing userspace page fault handling...
|
1792594223.004521
|
1793199023.004521
|